added lint changes, started migrating

This commit is contained in:
Deven Joshi
2021-05-04 16:11:28 +05:30
parent 88b8818e45
commit eb57c6eb9f
55 changed files with 884 additions and 885 deletions
@@ -13,52 +13,138 @@ linter:
# these rules are documented on and in the same order as # these rules are documented on and in the same order as
# the Dart Lint rules page to make maintenance easier # the Dart Lint rules page to make maintenance easier
# https://github.com/dart-lang/linter/blob/master/example/all.yaml # https://github.com/dart-lang/linter/blob/master/example/all.yaml
# - always_declare_return_types - always_use_package_imports
# - always_specify_types
# - annotate_overrides
# - avoid_as
- avoid_empty_else - avoid_empty_else
- avoid_init_to_null - avoid_relative_lib_imports
- avoid_return_types_on_setters - avoid_slow_async_io
- avoid_web_libraries_in_flutter - avoid_types_as_parameter_names
- await_only_futures
- camel_case_types
- cancel_subscriptions - cancel_subscriptions
- close_sinks - close_sinks
# - comment_references # we do not presume as to what people want to reference in their dartdocs
# - constant_identifier_names # https://github.com/dart-lang/linter/issues/204
- control_flow_in_finally - control_flow_in_finally
- empty_constructor_bodies
- empty_statements - empty_statements
- hash_and_equals - hash_and_equals
- implementation_imports - invariant_booleans
# - invariant_booleans - iterable_contains_unrelated_type
# - iterable_contains_unrelated_type - list_remove_unrelated_type
- library_names - literal_only_boolean_expressions
# - library_prefixes - no_adjacent_strings_in_list
# - list_remove_unrelated_type - no_duplicate_case_values
# - literal_only_boolean_expressions - no_logic_in_create_state
- non_constant_identifier_names - prefer_void_to_null
# - one_member_abstracts
# - only_throw_errors
# - overridden_fields
# - package_api_docs
- package_names
- package_prefixed_library_names
- prefer_is_not_empty
# - prefer_mixin # https://github.com/dart-lang/language/issues/32
# - public_member_api_docs
- slash_for_doc_comments
# - sort_constructors_first
# - sort_unnamed_constructors_first
# - super_goes_last # no longer needed w/ Dart 2
- test_types_in_equals - test_types_in_equals
- throw_in_finally - throw_in_finally
# - type_annotate_public_apis # subset of always_specify_types
- type_init_formals
# - unawaited_futures
- unnecessary_brace_in_string_interps
- unnecessary_getters_setters
- unnecessary_statements - unnecessary_statements
- unrelated_type_equality_checks - unrelated_type_equality_checks
- omit_local_variable_types
- use_key_in_widget_constructors
- valid_regexps - valid_regexps
- always_declare_return_types
- always_require_non_null_named_parameters
- annotate_overrides
- avoid_bool_literals_in_conditional_expressions
- avoid_catching_errors
- avoid_init_to_null
- avoid_null_checks_in_equality_operators
- avoid_positional_boolean_parameters
- avoid_private_typedef_functions
- avoid_redundant_argument_values
- avoid_return_types_on_setters
- avoid_returning_null_for_void
- avoid_shadowing_type_parameters
- avoid_single_cascade_in_expression_statements
- avoid_unnecessary_containers
- avoid_unused_constructor_parameters
- await_only_futures
- camel_case_extensions
- camel_case_types
- cascade_invocations
- constant_identifier_names
- curly_braces_in_flow_control_structures
- directives_ordering
- empty_catches
- empty_constructor_bodies
- exhaustive_cases
- file_names
- implementation_imports
- join_return_with_assignment
- leading_newlines_in_multiline_strings
- library_names
- library_prefixes
- lines_longer_than_80_chars
- missing_whitespace_between_adjacent_strings
- non_constant_identifier_names
- null_closures
- one_member_abstracts
- only_throw_errors
- package_api_docs
- package_prefixed_library_names
- parameter_assignments
- prefer_adjacent_string_concatenation
- prefer_asserts_in_initializer_lists
- prefer_asserts_with_message
- prefer_collection_literals
- prefer_conditional_assignment
- prefer_const_constructors
- prefer_const_constructors_in_immutables
- prefer_const_declarations
- prefer_const_literals_to_create_immutables
- prefer_constructors_over_static_methods
- prefer_contains
- prefer_equal_for_default_values
- prefer_expression_function_bodies
- prefer_final_fields
- prefer_final_in_for_each
- prefer_final_locals
- prefer_function_declarations_over_variables
- prefer_generic_function_type_aliases
- prefer_if_elements_to_conditional_expressions
- prefer_if_null_operators
- prefer_initializing_formals
- prefer_inlined_adds
- prefer_int_literals
- prefer_interpolation_to_compose_strings
- prefer_is_empty
- prefer_is_not_empty
- prefer_is_not_operator
- prefer_null_aware_operators
- prefer_single_quotes
- prefer_spread_collections
- prefer_typing_uninitialized_variables
- provide_deprecation_message
- public_member_api_docs
- recursive_getters
- sized_box_for_whitespace
- slash_for_doc_comments
- sort_child_properties_last
- sort_constructors_first
- sort_unnamed_constructors_first
- type_annotate_public_apis
- type_init_formals
- unnecessary_await_in_return
- unnecessary_brace_in_string_interps
- unnecessary_const
- unnecessary_getters_setters
- unnecessary_lambdas
- unnecessary_new
- unnecessary_null_aware_assignments
- unnecessary_null_in_if_null_operators
- unnecessary_nullable_for_final_variable_declarations
- unnecessary_parenthesis
- unnecessary_raw_strings
- unnecessary_string_escapes
- unnecessary_string_interpolations
- unnecessary_this
- use_is_even_rather_than_modulo
- use_late_for_private_fields_and_variables
- use_rethrow_when_possible
- use_setters_to_change_properties
- use_to_and_as_if_applicable
- package_names
- sort_pub_dependencies
- cast_nullable_to_non_nullable
- unnecessary_null_checks
- tighten_type_of_initializing_formals
- null_check_on_nullable_type_parameter
@@ -1,7 +1,7 @@
export 'attachment_upload_state_builder.dart';
export 'attachment_widget.dart'
show AttachmentError, AttachmentSource, AttachmentSourceX;
export 'file_attachment.dart'; export 'file_attachment.dart';
export 'giphy_attachment.dart'; export 'giphy_attachment.dart';
export 'image_attachment.dart'; export 'image_attachment.dart';
export 'video_attachment.dart'; export 'video_attachment.dart';
export 'attachment_upload_state_builder.dart';
export 'attachment_widget.dart'
show AttachmentError, AttachmentSource, AttachmentSourceX;
@@ -1,57 +1,59 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
import '../stream_chat_theme.dart'; /// Title for attachments
import '../utils.dart';
class AttachmentTitle extends StatelessWidget { class AttachmentTitle extends StatelessWidget {
/// Supply attachment and theme for constructing title
const AttachmentTitle({ const AttachmentTitle({
Key? key, Key? key,
required this.attachment, required this.attachment,
required this.messageTheme, required this.messageTheme,
}) : super(key: key); }) : super(key: key);
/// Theme to apply to text
final MessageTheme messageTheme; final MessageTheme messageTheme;
/// Attachment data to display
final Attachment attachment; final Attachment attachment;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) => GestureDetector(
return GestureDetector( onTap: () {
onTap: () { if (attachment.titleLink != null) {
if (attachment.titleLink != null) { launchURL(context, attachment.titleLink);
launchURL(context, attachment.titleLink!); }
} },
}, child: Padding(
child: Padding( padding: const EdgeInsets.all(8),
padding: const EdgeInsets.all(8.0), child: Column(
child: Column( mainAxisSize: MainAxisSize.min,
mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch,
crossAxisAlignment: CrossAxisAlignment.stretch, children: <Widget>[
children: <Widget>[ if (attachment.title != null)
if (attachment.title != null) Text(
Text( attachment.title!,
attachment.title!, overflow: TextOverflow.ellipsis,
overflow: TextOverflow.ellipsis, style: messageTheme.messageText?.copyWith(
style: messageTheme.messageText?.copyWith( color: StreamChatTheme.of(context).colorTheme.accentBlue,
color: StreamChatTheme.of(context).colorTheme.accentBlue, fontWeight: FontWeight.bold,
fontWeight: FontWeight.bold, ),
), ),
), if (attachment.titleLink != null ||
if (attachment.titleLink != null || attachment.ogScrapeUrl != null) attachment.ogScrapeUrl != null)
Text( Text(
Uri.parse(attachment.titleLink ?? attachment.ogScrapeUrl!) Uri.parse(attachment.titleLink ?? attachment.ogScrapeUrl!)
.authority .authority
.split('.') .split('.')
.reversed .reversed
.take(2) .take(2)
.toList() .toList()
.reversed .reversed
.join('.'), .join('.'),
style: messageTheme.messageText, style: messageTheme.messageText,
), ),
], ],
),
), ),
), );
);
}
} }
@@ -2,9 +2,13 @@ import 'package:flutter/material.dart';
import 'package:stream_chat_flutter/src/upload_progress_indicator.dart'; import 'package:stream_chat_flutter/src/upload_progress_indicator.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// Widget to build in progress
typedef InProgressBuilder = Widget Function(BuildContext, int, int); typedef InProgressBuilder = Widget Function(BuildContext, int, int);
/// Widget to build on failure
typedef FailedBuilder = Widget Function(BuildContext, String); typedef FailedBuilder = Widget Function(BuildContext, String);
/// Widget to display attachment upload state
class AttachmentUploadStateBuilder extends StatelessWidget { class AttachmentUploadStateBuilder extends StatelessWidget {
final Message message; final Message message;
final Attachment attachment; final Attachment attachment;
@@ -87,7 +91,6 @@ class _IconButton extends StatelessWidget {
elevation: 0, elevation: 0,
highlightElevation: 0, highlightElevation: 0,
focusElevation: 0, focusElevation: 0,
disabledElevation: 0,
hoverElevation: 0, hoverElevation: 0,
onPressed: onPressed, onPressed: onPressed,
fillColor: fillColor:
@@ -237,7 +240,7 @@ class _SuccessState extends StatelessWidget {
alignment: Alignment.topRight, alignment: Alignment.topRight,
child: CircleAvatar( child: CircleAvatar(
backgroundColor: StreamChatTheme.of(context).colorTheme.overlayDark, backgroundColor: StreamChatTheme.of(context).colorTheme.overlayDark,
maxRadius: 12.0, maxRadius: 12,
child: StreamSvgIcon.check( child: StreamSvgIcon.check(
color: StreamChatTheme.of(context).colorTheme.white, color: StreamChatTheme.of(context).colorTheme.white,
), ),
@@ -42,7 +42,7 @@ class FileAttachment extends AttachmentWidget {
onTap: onAttachmentTap, onTap: onAttachmentTap,
child: Container( child: Container(
width: size?.width ?? 100, width: size?.width ?? 100,
height: 56.0, height: 56,
decoration: BoxDecoration( decoration: BoxDecoration(
color: colorTheme.white, color: colorTheme.white,
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
@@ -54,12 +54,12 @@ class FileAttachment extends AttachmentWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Container( Container(
height: 40.0, height: 40,
width: 33.33, width: 33.33,
margin: EdgeInsets.all(8.0), margin: EdgeInsets.all(8),
child: _getFileTypeImage(context), child: _getFileTypeImage(context),
), ),
SizedBox(width: 8.0), SizedBox(width: 8),
Expanded( Expanded(
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
@@ -71,12 +71,12 @@ class FileAttachment extends AttachmentWidget {
maxLines: 1, maxLines: 1,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
), ),
SizedBox(height: 3.0), SizedBox(height: 3),
_buildSubtitle(context), _buildSubtitle(context),
], ],
), ),
), ),
SizedBox(width: 8.0), SizedBox(width: 8),
_buildTrailing(context), _buildTrailing(context),
], ],
), ),
@@ -87,7 +87,7 @@ class FileAttachment extends AttachmentWidget {
ShapeBorder _getDefaultShape(BuildContext context) { ShapeBorder _getDefaultShape(BuildContext context) {
return RoundedRectangleBorder( return RoundedRectangleBorder(
side: BorderSide(width: 0.0, color: Colors.transparent), side: BorderSide(width: 0, color: Colors.transparent),
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
); );
} }
@@ -159,8 +159,8 @@ class FileAttachment extends AttachmentWidget {
placeholderBuilder: (_) { placeholderBuilder: (_) {
return Center( return Center(
child: Container( child: Container(
width: 20.0, width: 20,
height: 20.0, height: 20,
child: const CircularProgressIndicator(), child: const CircularProgressIndicator(),
), ),
); );
@@ -171,8 +171,8 @@ class FileAttachment extends AttachmentWidget {
placeholderBuilder: (_) { placeholderBuilder: (_) {
return Center( return Center(
child: Container( child: Container(
width: 20.0, width: 20,
height: 20.0, height: 20,
child: const CircularProgressIndicator(), child: const CircularProgressIndicator(),
), ),
); );
@@ -197,7 +197,6 @@ class FileAttachment extends AttachmentWidget {
elevation: 0, elevation: 0,
highlightElevation: 0, highlightElevation: 0,
focusElevation: 0, focusElevation: 0,
disabledElevation: 0,
hoverElevation: 0, hoverElevation: 0,
onPressed: onPressed, onPressed: onPressed,
fillColor: fillColor, fillColor: fillColor,
@@ -214,7 +213,7 @@ class FileAttachment extends AttachmentWidget {
var trailingWidget = trailing; var trailingWidget = trailing;
trailingWidget ??= attachment.uploadState.when( trailingWidget ??= attachment.uploadState.when(
preparing: () => Padding( preparing: () => Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8),
child: _buildButton( child: _buildButton(
icon: StreamSvgIcon.close(color: theme.colorTheme.white), icon: StreamSvgIcon.close(color: theme.colorTheme.white),
fillColor: theme.colorTheme.overlayDark, fillColor: theme.colorTheme.overlayDark,
@@ -222,7 +221,7 @@ class FileAttachment extends AttachmentWidget {
), ),
), ),
inProgress: (_, __) => Padding( inProgress: (_, __) => Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8),
child: _buildButton( child: _buildButton(
icon: StreamSvgIcon.close(color: theme.colorTheme.white), icon: StreamSvgIcon.close(color: theme.colorTheme.white),
fillColor: theme.colorTheme.overlayDark, fillColor: theme.colorTheme.overlayDark,
@@ -230,15 +229,15 @@ class FileAttachment extends AttachmentWidget {
), ),
), ),
success: () => Padding( success: () => Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8),
child: CircleAvatar( child: CircleAvatar(
backgroundColor: theme.colorTheme.accentBlue, backgroundColor: theme.colorTheme.accentBlue,
maxRadius: 12.0, maxRadius: 12,
child: StreamSvgIcon.check(color: theme.colorTheme.white), child: StreamSvgIcon.check(color: theme.colorTheme.white),
), ),
), ),
failed: (_) => Padding( failed: (_) => Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8),
child: _buildButton( child: _buildButton(
icon: StreamSvgIcon.retry(color: theme.colorTheme.white), icon: StreamSvgIcon.retry(color: theme.colorTheme.white),
fillColor: theme.colorTheme.overlayDark, fillColor: theme.colorTheme.overlayDark,
@@ -251,7 +250,6 @@ class FileAttachment extends AttachmentWidget {
) ?? ) ??
IconButton( IconButton(
icon: StreamSvgIcon.cloudDownload(color: theme.colorTheme.black), icon: StreamSvgIcon.cloudDownload(color: theme.colorTheme.black),
padding: const EdgeInsets.all(8),
visualDensity: VisualDensity.compact, visualDensity: VisualDensity.compact,
splashRadius: 16, splashRadius: 16,
onPressed: () { onPressed: () {
@@ -262,7 +260,6 @@ class FileAttachment extends AttachmentWidget {
if (message.status == MessageSendingStatus.sent) { if (message.status == MessageSendingStatus.sent) {
trailingWidget = IconButton( trailingWidget = IconButton(
icon: StreamSvgIcon.cloudDownload(color: theme.colorTheme.black), icon: StreamSvgIcon.cloudDownload(color: theme.colorTheme.black),
padding: const EdgeInsets.all(8),
visualDensity: VisualDensity.compact, visualDensity: VisualDensity.compact,
splashRadius: 16, splashRadius: 16,
onPressed: () { onPressed: () {
@@ -304,9 +301,9 @@ class FileAttachment extends AttachmentWidget {
progressIndicatorColor: theme.colorTheme.accentBlue, progressIndicatorColor: theme.colorTheme.accentBlue,
); );
}, },
success: () => Text('${fileSize(size, 2)}', style: textStyle), success: () => Text(fileSize(size), style: textStyle),
failed: (_) => Text('UPLOAD ERROR', style: textStyle), failed: (_) => Text('UPLOAD ERROR', style: textStyle),
) ?? ) ??
Text('${fileSize(size)}', style: textStyle); Text(fileSize(size), style: textStyle);
} }
} }
@@ -52,10 +52,10 @@ class GiphyAttachment extends AttachmentWidget {
clipBehavior: Clip.antiAlias, clipBehavior: Clip.antiAlias,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only( borderRadius: BorderRadius.only(
topRight: Radius.circular(16.0), topRight: Radius.circular(16),
bottomRight: Radius.circular(0.0), bottomRight: Radius.circular(0),
topLeft: Radius.circular(16.0), topLeft: Radius.circular(16),
bottomLeft: Radius.circular(16.0), bottomLeft: Radius.circular(16),
), ),
), ),
child: Column( child: Column(
@@ -63,7 +63,7 @@ class GiphyAttachment extends AttachmentWidget {
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[ children: <Widget>[
Padding( Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8),
child: Row( child: Row(
children: [ children: [
StreamSvgIcon.giphyIcon(), StreamSvgIcon.giphyIcon(),
@@ -91,7 +91,7 @@ class GiphyAttachment extends AttachmentWidget {
), ),
), ),
Padding( Padding(
padding: const EdgeInsets.all(2.0), padding: const EdgeInsets.all(2),
child: GestureDetector( child: GestureDetector(
onTap: () => onAttachmentTap ?? _onImageTap(context), onTap: () => onAttachmentTap ?? _onImageTap(context),
child: CachedNetworkImage( child: CachedNetworkImage(
@@ -123,8 +123,6 @@ class GiphyAttachment extends AttachmentWidget {
height: 0.5, height: 0.5,
), ),
Row( Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
Expanded( Expanded(
child: Container( child: Container(
@@ -156,7 +154,7 @@ class GiphyAttachment extends AttachmentWidget {
.colorTheme .colorTheme
.black .black
.withOpacity(0.2), .withOpacity(0.2),
height: 50.0, height: 50,
), ),
Expanded( Expanded(
child: Container( child: Container(
@@ -189,7 +187,7 @@ class GiphyAttachment extends AttachmentWidget {
.colorTheme .colorTheme
.black .black
.withOpacity(0.2), .withOpacity(0.2),
height: 50.0, height: 50,
), ),
Expanded( Expanded(
child: Container( child: Container(
@@ -217,11 +215,11 @@ class GiphyAttachment extends AttachmentWidget {
], ],
), ),
), ),
SizedBox(height: 4.0), SizedBox(height: 4),
Align( Align(
alignment: Alignment.centerRight, alignment: Alignment.centerRight,
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4.0), padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
child: Row( child: Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
@@ -230,10 +228,10 @@ class GiphyAttachment extends AttachmentWidget {
.colorTheme .colorTheme
.black .black
.withOpacity(0.5), .withOpacity(0.5),
size: 16.0, size: 16,
), ),
SizedBox( SizedBox(
width: 8.0, width: 8,
), ),
Text( Text(
'Only visible to you', 'Only visible to you',
@@ -332,8 +330,8 @@ class GiphyAttachment extends AttachmentWidget {
), ),
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
horizontal: 8.0, horizontal: 8,
vertical: 4.0, vertical: 4,
), ),
child: Row( child: Row(
children: [ children: [
@@ -34,137 +34,131 @@ class ImageAttachment extends AttachmentWidget {
); );
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) => source.when(
return source.when( local: () {
local: () { if (attachment.localUri == null || attachment.file?.bytes == null) {
if (attachment.localUri == null || attachment.file?.bytes == null) { return AttachmentError(size: size);
return AttachmentError(size: size); }
} return _buildImageAttachment(
return _buildImageAttachment( context,
context, Image.memory(
Image.memory( attachment.file!.bytes!,
attachment.file!.bytes!, height: size?.height,
height: size?.height, width: size?.width,
width: size?.width, fit: BoxFit.cover,
fit: BoxFit.cover, errorBuilder: (context, _, __) => Image.asset(
errorBuilder: (context, _, __) {
return Image.asset(
'images/placeholder.png', 'images/placeholder.png',
package: 'stream_chat_flutter', package: 'stream_chat_flutter',
);
},
),
);
},
network: () {
var imageUrl =
attachment.thumbUrl ?? attachment.imageUrl ?? attachment.assetUrl;
if (imageUrl == null) {
return AttachmentError(size: size);
}
var imageUri = Uri.parse(imageUrl);
if (imageUri.host == 'stream-io-cdn.com') {
imageUri = imageUri.replace(queryParameters: {
...imageUri.queryParameters,
'h': '500',
'w': '500',
'crop': 'center',
'resize': 'crop',
});
} else if (imageUri.host == 'stream-cloud-uploads.imgix.net') {
imageUri = imageUri.replace(queryParameters: {
...imageUri.queryParameters,
'height': '500',
'width': '500',
'fit': 'crop',
});
}
imageUrl = imageUri.toString();
return _buildImageAttachment(
context,
CachedNetworkImage(
cacheKey: imageUri.path,
height: size?.height,
width: size?.width,
placeholder: (_, __) {
final image = Image.asset(
'images/placeholder.png',
fit: BoxFit.cover,
package: 'stream_chat_flutter',
);
final colorTheme = StreamChatTheme.of(context).colorTheme;
return Shimmer.fromColors(
baseColor: colorTheme.greyGainsboro,
highlightColor: colorTheme.whiteSmoke,
child: image,
);
},
imageUrl: imageUrl,
errorWidget: (context, url, error) {
return AttachmentError(size: size);
},
fit: BoxFit.cover,
),
);
},
);
}
Widget _buildImageAttachment(BuildContext context, Widget imageWidget) {
return ConstrainedBox(
constraints: BoxConstraints.loose(size!),
child: Column(
children: <Widget>[
Expanded(
child: Stack(
children: [
GestureDetector(
onTap: onAttachmentTap ??
() async {
final result = await Navigator.push(
context,
MaterialPageRoute(
builder: (_) {
final channel = StreamChannel.of(context).channel;
return StreamChannel(
channel: channel,
child: FullScreenMedia(
mediaAttachments: [attachment],
userName: message.user?.name,
message: message,
onShowMessage: onShowMessage,
),
);
},
),
);
if (result != null) onReturnAction?.call(result);
},
child: imageWidget,
),
Padding(
padding: const EdgeInsets.all(8.0),
child: AttachmentUploadStateBuilder(
message: message,
attachment: attachment,
),
),
],
),
),
if (showTitle && attachment.title != null)
Material(
color: messageTheme.messageBackgroundColor,
child: AttachmentTitle(
messageTheme: messageTheme,
attachment: attachment,
), ),
), ),
], );
), },
); network: () {
} var imageUrl =
attachment.thumbUrl ?? attachment.imageUrl ?? attachment.assetUrl;
if (imageUrl == null) {
return AttachmentError(size: size);
}
var imageUri = Uri.parse(imageUrl);
if (imageUri.host == 'stream-io-cdn.com') {
imageUri = imageUri.replace(queryParameters: {
...imageUri.queryParameters,
'h': '500',
'w': '500',
'crop': 'center',
'resize': 'crop',
});
} else if (imageUri.host == 'stream-cloud-uploads.imgix.net') {
imageUri = imageUri.replace(queryParameters: {
...imageUri.queryParameters,
'height': '500',
'width': '500',
'fit': 'crop',
});
}
imageUrl = imageUri.toString();
return _buildImageAttachment(
context,
CachedNetworkImage(
cacheKey: imageUri.path,
height: size?.height,
width: size?.width,
placeholder: (_, __) {
final image = Image.asset(
'images/placeholder.png',
fit: BoxFit.cover,
package: 'stream_chat_flutter',
);
final colorTheme = StreamChatTheme.of(context).colorTheme;
return Shimmer.fromColors(
baseColor: colorTheme.greyGainsboro,
highlightColor: colorTheme.whiteSmoke,
child: image,
);
},
imageUrl: imageUrl,
errorWidget: (context, url, error) => AttachmentError(size: size),
fit: BoxFit.cover,
),
);
},
);
Widget _buildImageAttachment(BuildContext context, Widget imageWidget) =>
ConstrainedBox(
constraints: BoxConstraints.loose(size!),
child: Column(
children: <Widget>[
Expanded(
child: Stack(
children: [
GestureDetector(
onTap: onAttachmentTap ??
() async {
final result = await Navigator.push(
context,
MaterialPageRoute(
builder: (_) {
final channel =
StreamChannel.of(context).channel;
return StreamChannel(
channel: channel,
child: FullScreenMedia(
mediaAttachments: [attachment],
userName: message.user?.name,
message: message,
onShowMessage: onShowMessage,
),
);
},
),
);
if (result != null) onReturnAction?.call(result);
},
child: imageWidget,
),
Padding(
padding: const EdgeInsets.all(8),
child: AttachmentUploadStateBuilder(
message: message,
attachment: attachment,
),
),
],
),
),
if (showTitle && attachment.title != null)
Material(
color: messageTheme.messageBackgroundColor,
child: AttachmentTitle(
messageTheme: messageTheme,
attachment: attachment,
),
),
],
),
);
} }
@@ -30,100 +30,97 @@ class VideoAttachment extends AttachmentWidget {
); );
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) => source.when(
return source.when( local: () {
local: () { if (attachment.file == null) {
if (attachment.file == null) { return AttachmentError(size: size);
return AttachmentError(size: size); }
} return _buildVideoAttachment(
return _buildVideoAttachment( context,
context, VideoThumbnailImage(
VideoThumbnailImage( video: attachment.file!.path!,
video: attachment.file!.path!, height: size?.height,
height: size?.height, width: size?.width,
width: size?.width, fit: BoxFit.cover,
fit: BoxFit.cover, errorBuilder: (_, __) => AttachmentError(size: size),
errorBuilder: (_, __) => AttachmentError(size: size), ),
), );
); },
}, network: () {
network: () { if (attachment.assetUrl == null) {
if (attachment.assetUrl == null) { return AttachmentError(size: size);
return AttachmentError(size: size); }
} return _buildVideoAttachment(
return _buildVideoAttachment( context,
context, VideoThumbnailImage(
VideoThumbnailImage( video: attachment.assetUrl!,
video: attachment.assetUrl!, height: size?.height,
height: size?.height, width: size?.width,
width: size?.width, fit: BoxFit.cover,
fit: BoxFit.cover, errorBuilder: (_, __) => AttachmentError(size: size),
errorBuilder: (_, __) => AttachmentError(size: size), ),
), );
); },
}, );
);
}
Widget _buildVideoAttachment(BuildContext context, Widget videoWidget) { Widget _buildVideoAttachment(BuildContext context, Widget videoWidget) =>
return ConstrainedBox( ConstrainedBox(
constraints: BoxConstraints.loose(size ?? Size.infinite), constraints: BoxConstraints.loose(size ?? Size.infinite),
child: Column( child: Column(
children: <Widget>[ children: <Widget>[
Expanded( Expanded(
child: GestureDetector( child: GestureDetector(
onTap: onAttachmentTap ?? onTap: onAttachmentTap ??
() async { () async {
final channel = StreamChannel.of(context).channel; final channel = StreamChannel.of(context).channel;
final res = await Navigator.push( final res = await Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: (_) => StreamChannel( builder: (_) => StreamChannel(
channel: channel, channel: channel,
child: FullScreenMedia( child: FullScreenMedia(
mediaAttachments: [attachment], mediaAttachments: [attachment],
userName: message.user?.name, userName: message.user?.name,
message: message, message: message,
onShowMessage: onShowMessage, onShowMessage: onShowMessage,
),
), ),
), ),
), );
); if (res != null) onReturnAction?.call(res);
if (res != null) onReturnAction?.call(res); },
}, child: Stack(
child: Stack( children: [
children: [ videoWidget,
videoWidget, const Center(
Center( child: Material(
child: Material( shape: CircleBorder(),
shape: CircleBorder(), child: Padding(
child: Padding( padding: EdgeInsets.all(16),
padding: const EdgeInsets.all(16.0), child: Icon(Icons.play_arrow),
child: Icon(Icons.play_arrow), ),
), ),
), ),
), Padding(
Padding( padding: const EdgeInsets.all(8),
padding: const EdgeInsets.all(8.0), child: AttachmentUploadStateBuilder(
child: AttachmentUploadStateBuilder( message: message,
message: message, attachment: attachment,
attachment: attachment, ),
), ),
), ],
], ),
), ),
), ),
), if (attachment.title != null)
if (attachment.title != null) Material(
Material( color: messageTheme.messageBackgroundColor,
color: messageTheme.messageBackgroundColor, child: AttachmentTitle(
child: AttachmentTitle( messageTheme: messageTheme,
messageTheme: messageTheme, attachment: attachment,
attachment: attachment, ),
), ),
), ],
], ),
), );
);
}
} }
@@ -42,27 +42,25 @@ class AttachmentActionsModal extends StatelessWidget {
}); });
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) => GestureDetector(
return GestureDetector( behavior: HitTestBehavior.translucent,
behavior: HitTestBehavior.translucent, onTap: () => Navigator.maybePop(context),
onTap: () => Navigator.maybePop(context), child: _buildPage(context),
child: _buildPage(context), );
);
}
Widget _buildPage(context) { Widget _buildPage(context) {
final theme = StreamChatTheme.of(context); final theme = StreamChatTheme.of(context);
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end,
children: [ children: [
SizedBox(height: kToolbarHeight), const SizedBox(height: kToolbarHeight),
Padding( Padding(
padding: const EdgeInsets.only(right: 8.0), padding: const EdgeInsets.only(right: 8),
child: Container( child: Container(
width: MediaQuery.of(context).size.width * 0.5, width: MediaQuery.of(context).size.width * 0.5,
clipBehavior: Clip.hardEdge, clipBehavior: Clip.hardEdge,
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16.0), borderRadius: BorderRadius.circular(16),
), ),
child: Container( child: Container(
child: Column( child: Column(
@@ -73,7 +71,7 @@ class AttachmentActionsModal extends StatelessWidget {
context, context,
'Reply', 'Reply',
StreamSvgIcon.iconCurveLineLeftUp( StreamSvgIcon.iconCurveLineLeftUp(
size: 24.0, size: 24,
color: theme.colorTheme.grey, color: theme.colorTheme.grey,
), ),
() { () {
@@ -84,7 +82,7 @@ class AttachmentActionsModal extends StatelessWidget {
context, context,
'Show in Chat', 'Show in Chat',
StreamSvgIcon.eye( StreamSvgIcon.eye(
size: 24.0, size: 24,
color: theme.colorTheme.black, color: theme.colorTheme.black,
), ),
onShowMessage, onShowMessage,
@@ -93,7 +91,7 @@ class AttachmentActionsModal extends StatelessWidget {
context, context,
'Save ${message.attachments[currentIndex].type == 'video' ? 'Video' : 'Image'}', 'Save ${message.attachments[currentIndex].type == 'video' ? 'Video' : 'Image'}',
StreamSvgIcon.iconSave( StreamSvgIcon.iconSave(
size: 24.0, size: 24,
color: theme.colorTheme.grey, color: theme.colorTheme.grey,
), ),
() { () {
@@ -144,7 +142,7 @@ class AttachmentActionsModal extends StatelessWidget {
context, context,
'Delete', 'Delete',
StreamSvgIcon.delete( StreamSvgIcon.delete(
size: 24.0, size: 24,
color: theme.colorTheme.accentRed, color: theme.colorTheme.accentRed,
), ),
() { () {
@@ -201,7 +199,7 @@ class AttachmentActionsModal extends StatelessWidget {
child: InkWell( child: InkWell(
onTap: onTap, onTap: onTap,
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0), padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16),
child: Row( child: Row(
children: [ children: [
icon, icon,
@@ -271,7 +269,7 @@ class AttachmentActionsModal extends StatelessWidget {
children: [ children: [
CircularProgressIndicator( CircularProgressIndicator(
value: progress.toProgressIndicatorValue, value: progress.toProgressIndicatorValue,
strokeWidth: 8.0, strokeWidth: 8,
valueColor: AlwaysStoppedAnimation( valueColor: AlwaysStoppedAnimation(
theme.colorTheme.accentBlue, theme.colorTheme.accentBlue,
), ),
@@ -30,7 +30,6 @@ class StreamBackButton extends StatelessWidget {
elevation: 0, elevation: 0,
highlightElevation: 0, highlightElevation: 0,
focusElevation: 0, focusElevation: 0,
disabledElevation: 0,
hoverElevation: 0, hoverElevation: 0,
onPressed: () { onPressed: () {
if (onPressed != null) { if (onPressed != null) {
@@ -39,7 +38,7 @@ class StreamBackButton extends StatelessWidget {
Navigator.maybePop(context); Navigator.maybePop(context);
} }
}, },
padding: const EdgeInsets.all(14.0), padding: const EdgeInsets.all(14),
child: StreamSvgIcon.left( child: StreamSvgIcon.left(
size: 24, size: 24,
color: StreamChatTheme.of(context).colorTheme.black, color: StreamChatTheme.of(context).colorTheme.black,
@@ -7,7 +7,7 @@ import 'option_list_tile.dart';
class ChannelBottomSheet extends StatefulWidget { class ChannelBottomSheet extends StatefulWidget {
final VoidCallback? onViewInfoTap; final VoidCallback? onViewInfoTap;
ChannelBottomSheet({this.onViewInfoTap}); const ChannelBottomSheet({this.onViewInfoTap});
@override @override
_ChannelBottomSheetState createState() => _ChannelBottomSheetState(); _ChannelBottomSheetState createState() => _ChannelBottomSheetState();
@@ -31,29 +31,29 @@ class _ChannelBottomSheetState extends State<ChannelBottomSheet> {
clipBehavior: Clip.antiAlias, clipBehavior: Clip.antiAlias,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only( borderRadius: BorderRadius.only(
topLeft: Radius.circular(16.0), topLeft: Radius.circular(16),
topRight: Radius.circular(16.0), topRight: Radius.circular(16),
), ),
), ),
child: !_showActions child: !_showActions
? SizedBox() ? const SizedBox()
: ListView( : ListView(
shrinkWrap: true, shrinkWrap: true,
children: [ children: [
SizedBox( const SizedBox(
height: 24.0, height: 24,
), ),
Center( Center(
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0), padding: const EdgeInsets.symmetric(horizontal: 16),
child: ChannelName( child: ChannelName(
textStyle: textStyle:
StreamChatTheme.of(context).textTheme.headlineBold, StreamChatTheme.of(context).textTheme.headlineBold,
), ),
), ),
), ),
SizedBox( const SizedBox(
height: 5.0, height: 5,
), ),
Center( Center(
child: ChannelInfo( child: ChannelInfo(
@@ -64,8 +64,8 @@ class _ChannelBottomSheetState extends State<ChannelBottomSheet> {
.subtitle, .subtitle,
), ),
), ),
SizedBox( const SizedBox(
height: 17.0, height: 17,
), ),
if (channel.isDistinct && channel.memberCount == 2) if (channel.isDistinct && channel.memberCount == 2)
Column( Column(
@@ -75,16 +75,16 @@ class _ChannelBottomSheetState extends State<ChannelBottomSheet> {
.firstWhere( .firstWhere(
(e) => e.user?.id != userAsMember.user?.id) (e) => e.user?.id != userAsMember.user?.id)
.user!, .user!,
constraints: BoxConstraints( constraints: const BoxConstraints(
maxHeight: 64.0, maxHeight: 64,
maxWidth: 64.0, maxWidth: 64,
), ),
borderRadius: BorderRadius.circular(32.0), borderRadius: BorderRadius.circular(32),
onlineIndicatorConstraints: onlineIndicatorConstraints:
BoxConstraints.tight(Size(12.0, 12.0)), BoxConstraints.tight(const Size(12, 12)),
), ),
SizedBox( const SizedBox(
height: 6.0, height: 6,
), ),
Text( Text(
members members
@@ -102,50 +102,48 @@ class _ChannelBottomSheetState extends State<ChannelBottomSheet> {
), ),
if (!(channel.isDistinct && channel.memberCount == 2)) if (!(channel.isDistinct && channel.memberCount == 2))
Container( Container(
height: 94.0, height: 94,
alignment: Alignment.center, alignment: Alignment.center,
child: ListView.builder( child: ListView.builder(
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
itemCount: members.length, itemCount: members.length,
shrinkWrap: true, shrinkWrap: true,
itemBuilder: (context, index) { itemBuilder: (context, index) => Padding(
return Padding( padding: const EdgeInsets.symmetric(horizontal: 8),
padding: const EdgeInsets.symmetric(horizontal: 8.0), child: Column(
child: Column( children: [
children: [ UserAvatar(
UserAvatar( user: members[index].user!,
user: members[index].user!, constraints: const BoxConstraints.tightFor(
constraints: BoxConstraints.tightFor( height: 64,
height: 64.0, width: 64,
width: 64.0,
),
borderRadius: BorderRadius.circular(32.0),
onlineIndicatorConstraints:
BoxConstraints.tight(Size(12.0, 12.0)),
), ),
SizedBox( borderRadius: BorderRadius.circular(32),
height: 6.0, onlineIndicatorConstraints:
), BoxConstraints.tight(Size(12, 12)),
Text( ),
members[index].user?.name ?? '', const SizedBox(
style: StreamChatTheme.of(context) height: 6,
.textTheme ),
.footnoteBold, Text(
maxLines: 1, members[index].user?.name ?? '',
overflow: TextOverflow.ellipsis, style: StreamChatTheme.of(context)
), .textTheme
], .footnoteBold,
), maxLines: 1,
); overflow: TextOverflow.ellipsis,
}, ),
],
),
),
), ),
), ),
SizedBox( const SizedBox(
height: 24.0, height: 24,
), ),
OptionListTile( OptionListTile(
leading: Padding( leading: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0), padding: const EdgeInsets.symmetric(horizontal: 16),
child: StreamSvgIcon.user( child: StreamSvgIcon.user(
color: StreamChatTheme.of(context).colorTheme.grey, color: StreamChatTheme.of(context).colorTheme.grey,
), ),
@@ -156,7 +154,7 @@ class _ChannelBottomSheetState extends State<ChannelBottomSheet> {
if (!channel.isDistinct) if (!channel.isDistinct)
OptionListTile( OptionListTile(
leading: Padding( leading: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0), padding: const EdgeInsets.symmetric(horizontal: 16),
child: StreamSvgIcon.userRemove( child: StreamSvgIcon.userRemove(
color: StreamChatTheme.of(context).colorTheme.grey, color: StreamChatTheme.of(context).colorTheme.grey,
), ),
@@ -175,7 +173,7 @@ class _ChannelBottomSheetState extends State<ChannelBottomSheet> {
if (isOwner) if (isOwner)
OptionListTile( OptionListTile(
leading: Padding( leading: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0), padding: const EdgeInsets.symmetric(horizontal: 16),
child: StreamSvgIcon.delete( child: StreamSvgIcon.delete(
color: StreamChatTheme.of(context).colorTheme.accentRed, color: StreamChatTheme.of(context).colorTheme.accentRed,
), ),
@@ -195,7 +193,7 @@ class _ChannelBottomSheetState extends State<ChannelBottomSheet> {
), ),
OptionListTile( OptionListTile(
leading: Padding( leading: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0), padding: const EdgeInsets.symmetric(horizontal: 16),
child: StreamSvgIcon.closeSmall( child: StreamSvgIcon.closeSmall(
color: StreamChatTheme.of(context).colorTheme.grey, color: StreamChatTheme.of(context).colorTheme.grey,
), ),
@@ -144,7 +144,7 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget {
actions: actions ?? actions: actions ??
<Widget>[ <Widget>[
Padding( Padding(
padding: const EdgeInsets.only(right: 10.0), padding: const EdgeInsets.only(right: 10),
child: Center( child: Center(
child: ChannelImage( child: ChannelImage(
borderRadius: StreamChatTheme.of(context) borderRadius: StreamChatTheme.of(context)
@@ -169,7 +169,6 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget {
height: preferredSize.height, height: preferredSize.height,
width: preferredSize.width, width: preferredSize.width,
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[ children: <Widget>[
title ?? title ??
@@ -158,30 +158,29 @@ class ChannelImage extends StatelessWidget {
alignment: Alignment.center, alignment: Alignment.center,
fit: StackFit.expand, fit: StackFit.expand,
children: <Widget>[ children: <Widget>[
image != null if (image != null)
? CachedNetworkImage( CachedNetworkImage(
imageUrl: image, imageUrl: image,
errorWidget: (_, __, ___) { errorWidget: (_, __, ___) {
return Center( return Center(
child: Text( child: Text(
snapshot.data?.containsKey('name') ?? false snapshot.data?.containsKey('name') ?? false
? snapshot.data!['name'][0] ? snapshot.data!['name'][0]
: '', : '',
style: TextStyle( style: TextStyle(
color: StreamChatTheme.of(context) color: StreamChatTheme.of(context).colorTheme.white,
.colorTheme fontWeight: FontWeight.bold,
.white, ),
fontWeight: FontWeight.bold, ),
), );
), },
); fit: BoxFit.cover,
}, )
fit: BoxFit.cover, else
) StreamChatTheme.of(context).defaultChannelImage(
: StreamChatTheme.of(context).defaultChannelImage( context,
context, channel,
channel, ),
),
Material( Material(
color: Colors.transparent, color: Colors.transparent,
child: InkWell( child: InkWell(
@@ -27,28 +27,26 @@ class ChannelInfo extends StatelessWidget {
return StreamBuilder<List<Member>>( return StreamBuilder<List<Member>>(
stream: channel.state?.membersStream, stream: channel.state?.membersStream,
initialData: channel.state?.members, initialData: channel.state?.members,
builder: (context, snapshot) { builder: (context, snapshot) => ConnectionStatusBuilder(
return ConnectionStatusBuilder( statusBuilder: (context, status) {
statusBuilder: (context, status) { switch (status) {
switch (status) { case ConnectionStatus.connected:
case ConnectionStatus.connected: return _buildConnectedTitleState(context, snapshot.data);
return _buildConnectedTitleState(context, snapshot.data); case ConnectionStatus.connecting:
case ConnectionStatus.connecting: return _buildConnectingTitleState(context);
return _buildConnectingTitleState(context); case ConnectionStatus.disconnected:
case ConnectionStatus.disconnected: return _buildDisconnectedTitleState(context, client);
return _buildDisconnectedTitleState(context, client); default:
default: return const Offstage();
return Offstage(); }
} },
}, ),
);
},
); );
} }
Widget _buildConnectedTitleState( Widget _buildConnectedTitleState(
BuildContext context, List<Member>? members) { BuildContext context, List<Member>? members) {
var alternativeWidget; Widget? alternativeWidget;
if (channel.memberCount != null && channel.memberCount! > 2) { if (channel.memberCount != null && channel.memberCount! > 2) {
var text = '${channel.memberCount} Members'; var text = '${channel.memberCount} Members';
@@ -82,7 +80,7 @@ class ChannelInfo extends StatelessWidget {
} }
if (!showTypingIndicator) { if (!showTypingIndicator) {
return alternativeWidget ?? Offstage(); return alternativeWidget ?? const Offstage();
} }
return TypingIndicator( return TypingIndicator(
@@ -92,58 +90,55 @@ class ChannelInfo extends StatelessWidget {
); );
} }
Widget _buildConnectingTitleState(BuildContext context) { Widget _buildConnectingTitleState(BuildContext context) => Row(
return Row( mainAxisAlignment: MainAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center, children: [
children: [ Container(
Container( height: 16,
height: 16, width: 16,
width: 16, child: const Center(
child: Center( child: CircularProgressIndicator(),
child: CircularProgressIndicator(), ),
), ),
), SizedBox(width: 10),
SizedBox(width: 10), Text(
Text( 'Searching for Network',
'Searching for Network', style: textStyle,
style: textStyle, ),
), ],
], );
);
}
Widget _buildDisconnectedTitleState( Widget _buildDisconnectedTitleState(
BuildContext context, BuildContext context,
StreamChatClient client, StreamChatClient client,
) { ) =>
return Row( Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Text( Text(
'Offline...', 'Offline...',
style: textStyle, style: textStyle,
), ),
TextButton( TextButton(
style: TextButton.styleFrom( style: TextButton.styleFrom(
padding: const EdgeInsets.all(0), padding: const EdgeInsets.all(0),
tapTargetSize: MaterialTapTargetSize.shrinkWrap, tapTargetSize: MaterialTapTargetSize.shrinkWrap,
visualDensity: VisualDensity( visualDensity: const VisualDensity(
horizontal: VisualDensity.minimumDensity, horizontal: VisualDensity.minimumDensity,
vertical: VisualDensity.minimumDensity, vertical: VisualDensity.minimumDensity,
),
),
onPressed: () async {
await client.disconnect();
await client.connect();
},
child: Text(
'Try Again',
style: textStyle?.copyWith(
color: StreamChatTheme.of(context).colorTheme.accentBlue,
),
), ),
), ),
onPressed: () async { ],
await client.disconnect(); );
await client.connect();
},
child: Text(
'Try Again',
style: textStyle?.copyWith(
color: StreamChatTheme.of(context).colorTheme.accentBlue,
),
),
),
],
);
}
} }
@@ -168,8 +168,8 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget {
return SvgPicture.asset( return SvgPicture.asset(
'svgs/icon_pen_write.svg', 'svgs/icon_pen_write.svg',
package: 'stream_chat_flutter', package: 'stream_chat_flutter',
width: 24.0, width: 24,
height: 24.0, height: 24,
color: color, color: color,
); );
}, },
@@ -54,7 +54,7 @@ typedef ViewInfoCallback = void Function(Channel);
/// Modify it to change the widget appearance. /// Modify it to change the widget appearance.
class ChannelListView extends StatefulWidget { class ChannelListView extends StatefulWidget {
/// Instantiate a new ChannelListView /// Instantiate a new ChannelListView
ChannelListView({ const ChannelListView({
Key? key, Key? key,
this.filter, this.filter,
this.options, this.options,
@@ -248,7 +248,7 @@ class _ChannelListViewState extends State<ChannelListView> {
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Padding( Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8),
child: StreamSvgIcon.message( child: StreamSvgIcon.message(
size: 136, size: 136,
color: StreamChatTheme.of(context) color: StreamChatTheme.of(context)
@@ -257,7 +257,7 @@ class _ChannelListViewState extends State<ChannelListView> {
), ),
), ),
Padding( Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8),
child: Text( child: Text(
'Lets start chatting!', 'Lets start chatting!',
style: StreamChatTheme.of(context).textTheme.headline, style: StreamChatTheme.of(context).textTheme.headline,
@@ -265,7 +265,7 @@ class _ChannelListViewState extends State<ChannelListView> {
), ),
Padding( Padding(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
vertical: 8.0, vertical: 8,
horizontal: 52, horizontal: 52,
), ),
child: Text( child: Text(
@@ -340,7 +340,7 @@ class _ChannelListViewState extends State<ChannelListView> {
highlightColor: StreamChatTheme.of(context).colorTheme.whiteSmoke, highlightColor: StreamChatTheme.of(context).colorTheme.whiteSmoke,
child: Column( child: Column(
children: [ children: [
SizedBox(height: 4.0), SizedBox(height: 4),
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [ children: [
@@ -358,7 +358,7 @@ class _ChannelListViewState extends State<ChannelListView> {
], ],
), ),
SizedBox( SizedBox(
height: 16.0, height: 16,
), ),
], ],
), ),
@@ -441,7 +441,7 @@ class _ChannelListViewState extends State<ChannelListView> {
WidgetSpan( WidgetSpan(
child: Padding( child: Padding(
padding: const EdgeInsets.only( padding: const EdgeInsets.only(
right: 2.0, right: 2,
), ),
child: Icon(Icons.error_outline), child: Icon(Icons.error_outline),
), ),
@@ -477,7 +477,6 @@ class _ChannelListViewState extends State<ChannelListView> {
enabled: widget.swipeToAction, enabled: widget.swipeToAction,
actionPane: SlidableBehindActionPane(), actionPane: SlidableBehindActionPane(),
actionExtentRatio: 0.12, actionExtentRatio: 0.12,
closeOnScroll: true,
secondaryActions: <Widget>[ secondaryActions: <Widget>[
IconSlideAction( IconSlideAction(
color: backgroundColor, color: backgroundColor,
@@ -589,7 +588,6 @@ class _ChannelListViewState extends State<ChannelListView> {
key: ValueKey<String>('CHANNEL-${channel.id}'), key: ValueKey<String>('CHANNEL-${channel.id}'),
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
ChannelImage( ChannelImage(
channel: channel, channel: channel,
@@ -634,7 +632,7 @@ class _ChannelListViewState extends State<ChannelListView> {
.accentRed .accentRed
.withOpacity(.2), .withOpacity(.2),
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0), padding: const EdgeInsets.symmetric(vertical: 16),
child: Center( child: Center(
child: Text('Error loading channels'), child: Text('Error loading channels'),
), ),
@@ -644,7 +642,7 @@ class _ChannelListViewState extends State<ChannelListView> {
return snapshot.data! return snapshot.data!
? Center( ? Center(
child: Padding( child: Padding(
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16),
child: const CircularProgressIndicator(), child: const CircularProgressIndicator(),
), ),
) )
@@ -653,7 +651,7 @@ class _ChannelListViewState extends State<ChannelListView> {
} }
Widget _separatorBuilder(context, i) { Widget _separatorBuilder(context, i) {
var effect = StreamChatTheme.of(context).colorTheme.borderBottom; final effect = StreamChatTheme.of(context).colorTheme.borderBottom;
return Container( return Container(
height: 1, height: 1,
@@ -47,7 +47,7 @@ class ChannelPreview extends StatelessWidget {
/// Widget rendering the sending indicator, by default it uses the [SendingIndicator] widget /// Widget rendering the sending indicator, by default it uses the [SendingIndicator] widget
final Widget? sendingIndicator; final Widget? sendingIndicator;
ChannelPreview({ const ChannelPreview({
required this.channel, required this.channel,
Key? key, Key? key,
this.onTap, this.onTap,
@@ -128,7 +128,7 @@ class ChannelPreview extends StatelessWidget {
if (lastMessage?.user?.id == if (lastMessage?.user?.id ==
StreamChat.of(context).user?.id) { StreamChat.of(context).user?.id) {
return Padding( return Padding(
padding: const EdgeInsets.only(right: 4.0), padding: const EdgeInsets.only(right: 4),
child: SendingIndicator( child: SendingIndicator(
message: lastMessage!, message: lastMessage!,
size: channelPreviewTheme.indicatorIconSize, size: channelPreviewTheme.indicatorIconSize,
@@ -167,7 +167,7 @@ class ChannelPreview extends StatelessWidget {
String stringDate; String stringDate;
final now = DateTime.now(); final now = DateTime.now();
var startOfDay = DateTime(now.year, now.month, now.day); final startOfDay = DateTime(now.year, now.month, now.day);
if (lastMessageAt.millisecondsSinceEpoch >= if (lastMessageAt.millisecondsSinceEpoch >=
startOfDay.millisecondsSinceEpoch) { startOfDay.millisecondsSinceEpoch) {
@@ -298,7 +298,7 @@ class ChannelPreview extends StatelessWidget {
)); ));
} else { } else {
resList.add(TextSpan( resList.add(TextSpan(
text: e == textList.last ? '$e' : '$e ', text: e == textList.last ? e : '$e ',
style: normalTextStyle, style: normalTextStyle,
)); ));
} }
@@ -53,7 +53,7 @@ class DeletedMessage extends StatelessWidget {
), ),
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
vertical: 8.0, vertical: 8,
horizontal: 16, horizontal: 16,
), ),
child: Transform( child: Transform(
@@ -150,7 +150,7 @@ class _FullScreenMediaState extends State<FullScreenMedia>
}, },
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
vertical: 50.0, vertical: 50,
), ),
child: Chewie( child: Chewie(
controller: controller.chewieController!, controller: controller.chewieController!,
@@ -113,8 +113,8 @@ class GroupImage extends StatelessWidget {
child: Container( child: Container(
color: selectionColor ?? color: selectionColor ??
StreamChatTheme.of(context).colorTheme.accentBlue, StreamChatTheme.of(context).colorTheme.accentBlue,
height: 64.0, height: 64,
width: 64.0, width: 64,
child: Padding( child: Padding(
padding: EdgeInsets.all(selectionThickness), padding: EdgeInsets.all(selectionThickness),
child: avatar, child: avatar,
@@ -82,47 +82,45 @@ class _ImageFooterState extends State<ImageFooter> {
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
!showShareButton if (!showShareButton)
? Container( Container(
width: 48, width: 48,
) )
: IconButton( else
icon: StreamSvgIcon.iconShare( IconButton(
size: 24.0, icon: StreamSvgIcon.iconShare(
color: StreamChatTheme.of(context).colorTheme.black, size: 24,
), color: StreamChatTheme.of(context).colorTheme.black,
onPressed: () async { ),
final attachment = onPressed: () async {
widget.mediaAttachments[widget.currentPage]; final attachment =
final url = attachment.imageUrl ?? widget.mediaAttachments[widget.currentPage];
attachment.assetUrl ?? final url = attachment.imageUrl ??
attachment.thumbUrl!; attachment.assetUrl ??
final type = attachment.type == 'image' attachment.thumbUrl!;
? 'jpg' final type = attachment.type == 'image'
: url.split('?').first.split('.').last; ? 'jpg'
final request = : url.split('?').first.split('.').last;
await HttpClient().getUrl(Uri.parse(url)); final request = await HttpClient().getUrl(Uri.parse(url));
final response = await request.close(); final response = await request.close();
final bytes = final bytes =
await consolidateHttpClientResponseBytes(response); await consolidateHttpClientResponseBytes(response);
final tmpPath = await getTemporaryDirectory(); final tmpPath = await getTemporaryDirectory();
final filePath = final filePath = '${tmpPath.path}/${attachment.id}.$type';
'${tmpPath.path}/${attachment.id}.$type'; final file = File(filePath);
final file = File(filePath); await file.writeAsBytes(bytes);
await file.writeAsBytes(bytes); await Share.shareFiles(
await Share.shareFiles( [filePath],
[filePath], mimeTypes: [
mimeTypes: [ 'image/$type',
'image/$type', ],
], );
); },
}, ),
),
InkWell( InkWell(
onTap: widget.onTitleTap, onTap: widget.onTitleTap,
child: Container( child: Container(
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: <Widget>[ children: <Widget>[
@@ -156,12 +154,12 @@ class _ImageFooterState extends State<ImageFooter> {
isScrollControlled: true, isScrollControlled: true,
shape: const RoundedRectangleBorder( shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only( borderRadius: BorderRadius.only(
topLeft: Radius.circular(16.0), topLeft: Radius.circular(16),
topRight: Radius.circular(16.0), topRight: Radius.circular(16),
), ),
), ),
builder: (context) { builder: (context) {
final crossAxisCount = 3; const crossAxisCount = 3;
final noOfRowToShowInitially = final noOfRowToShowInitially =
widget.mediaAttachments.length > crossAxisCount ? 2 : 1; widget.mediaAttachments.length > crossAxisCount ? 2 : 1;
final size = MediaQuery.of(context).size; final size = MediaQuery.of(context).size;
@@ -181,7 +179,7 @@ class _ImageFooterState extends State<ImageFooter> {
children: [ children: [
Center( Center(
child: Padding( child: Padding(
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16),
child: Text( child: Text(
'Photos', 'Photos',
style: StreamChatTheme.of(context) style: StreamChatTheme.of(context)
@@ -209,8 +207,8 @@ class _ImageFooterState extends State<ImageFooter> {
padding: const EdgeInsets.all(1), padding: const EdgeInsets.all(1),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: crossAxisCount, crossAxisCount: crossAxisCount,
mainAxisSpacing: 2.0, mainAxisSpacing: 2,
crossAxisSpacing: 2.0, crossAxisSpacing: 2,
), ),
itemBuilder: (context, index) { itemBuilder: (context, index) {
Widget media; Widget media;
@@ -230,7 +228,7 @@ class _ImageFooterState extends State<ImageFooter> {
media = InkWell( media = InkWell(
onTap: () => widget.mediaSelectedCallBack!(index), onTap: () => widget.mediaSelectedCallBack!(index),
child: AspectRatio( child: AspectRatio(
aspectRatio: 1.0, aspectRatio: 1,
child: CachedNetworkImage( child: CachedNetworkImage(
imageUrl: attachment.imageUrl ?? imageUrl: attachment.imageUrl ??
attachment.assetUrl ?? attachment.assetUrl ??
@@ -246,7 +244,7 @@ class _ImageFooterState extends State<ImageFooter> {
media, media,
if (widget.message.user != null) if (widget.message.user != null)
Padding( Padding(
padding: EdgeInsets.all(8.0), padding: EdgeInsets.all(8),
child: Container( child: Container(
clipBehavior: Clip.antiAlias, clipBehavior: Clip.antiAlias,
decoration: BoxDecoration( decoration: BoxDecoration(
@@ -254,7 +252,7 @@ class _ImageFooterState extends State<ImageFooter> {
color: Colors.white.withOpacity(0.6), color: Colors.white.withOpacity(0.6),
boxShadow: [ boxShadow: [
BoxShadow( BoxShadow(
blurRadius: 8.0, blurRadius: 8,
color: StreamChatTheme.of(context) color: StreamChatTheme.of(context)
.colorTheme .colorTheme
.black .black
@@ -287,7 +285,7 @@ class _ImageFooterState extends State<ImageFooter> {
/// Sends the current message /// Sends the current message
Future sendMessage() async { Future sendMessage() async {
var text = _messageController.text.trim(); final text = _messageController.text.trim();
final attachments = widget.message.attachments; final attachments = widget.message.attachments;
@@ -311,10 +309,10 @@ class _ImageFooterState extends State<ImageFooter> {
class IconClipper extends CustomClipper<Path> { class IconClipper extends CustomClipper<Path> {
@override @override
Path getClip(Size size) { Path getClip(Size size) {
var leftX = size.width / 5; final leftX = size.width / 5;
var rightX = 4 * size.width / 5; final rightX = 4 * size.width / 5;
var topY = size.height / 5; final topY = size.height / 5;
var bottomY = 4 * size.height / 5; final bottomY = 4 * size.height / 5;
final path = Path(); final path = Path();
path.moveTo(leftX, topY); path.moveTo(leftX, topY);
@@ -322,7 +320,7 @@ class IconClipper extends CustomClipper<Path> {
path.lineTo(rightX, bottomY); path.lineTo(rightX, bottomY);
path.lineTo(rightX, topY); path.lineTo(rightX, topY);
path.lineTo(leftX, topY); path.lineTo(leftX, topY);
path.lineTo(0.0, 0.0); path.lineTo(0, 0);
path.close(); path.close();
return path; return path;
} }
@@ -27,22 +27,19 @@ class ImageGroup extends StatelessWidget {
direction: Axis.vertical, direction: Axis.vertical,
children: <Widget>[ children: <Widget>[
Flexible( Flexible(
flex: 1,
fit: FlexFit.tight, fit: FlexFit.tight,
child: Flex( child: Flex(
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
direction: Axis.horizontal, direction: Axis.horizontal,
children: [ children: [
Flexible( Flexible(
flex: 1,
fit: FlexFit.tight, fit: FlexFit.tight,
child: _buildImage(context, 0), child: _buildImage(context, 0),
), ),
Flexible( Flexible(
flex: 1,
fit: FlexFit.tight, fit: FlexFit.tight,
child: Padding( child: Padding(
padding: const EdgeInsets.only(left: 2.0), padding: const EdgeInsets.only(left: 2),
child: _buildImage(context, 1), child: _buildImage(context, 1),
), ),
), ),
@@ -52,24 +49,21 @@ class ImageGroup extends StatelessWidget {
if (images.length >= 3) if (images.length >= 3)
Flexible( Flexible(
fit: FlexFit.tight, fit: FlexFit.tight,
flex: 1,
child: Padding( child: Padding(
padding: const EdgeInsets.only(top: 2.0), padding: const EdgeInsets.only(top: 2),
child: Flex( child: Flex(
direction: Axis.horizontal, direction: Axis.horizontal,
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[ children: <Widget>[
Flexible( Flexible(
fit: FlexFit.tight, fit: FlexFit.tight,
flex: 1,
child: _buildImage(context, 2), child: _buildImage(context, 2),
), ),
if (images.length >= 4) if (images.length >= 4)
Flexible( Flexible(
fit: FlexFit.tight, fit: FlexFit.tight,
flex: 1,
child: Padding( child: Padding(
padding: const EdgeInsets.only(left: 2.0), padding: const EdgeInsets.only(left: 2),
child: Stack( child: Stack(
fit: StackFit.expand, fit: StackFit.expand,
children: <Widget>[ children: <Widget>[
@@ -53,7 +53,7 @@ class ImageHeader extends StatelessWidget implements PreferredSizeWidget {
? IconButton( ? IconButton(
icon: StreamSvgIcon.close( icon: StreamSvgIcon.close(
color: StreamChatTheme.of(context).colorTheme.black, color: StreamChatTheme.of(context).colorTheme.black,
size: 24.0, size: 24,
), ),
onPressed: onBackPressed, onPressed: onBackPressed,
) )
@@ -79,7 +79,6 @@ class ImageHeader extends StatelessWidget implements PreferredSizeWidget {
height: preferredSize.height, height: preferredSize.height,
width: preferredSize.width, width: preferredSize.width,
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: <Widget>[ children: <Widget>[
@@ -11,7 +11,7 @@ class InfoTile extends StatelessWidget {
final TextStyle? textStyle; final TextStyle? textStyle;
final Color? backgroundColor; final Color? backgroundColor;
InfoTile({ const InfoTile({
required this.message, required this.message,
required this.child, required this.child,
required this.showMessage, required this.showMessage,
@@ -28,7 +28,7 @@ class InfoTile extends StatelessWidget {
portalAnchor: tileAnchor ?? Alignment.topCenter, portalAnchor: tileAnchor ?? Alignment.topCenter,
childAnchor: childAnchor ?? Alignment.bottomCenter, childAnchor: childAnchor ?? Alignment.bottomCenter,
portal: Container( portal: Container(
height: 25.0, height: 25,
color: backgroundColor ?? color: backgroundColor ??
StreamChatTheme.of(context).colorTheme.grey.withOpacity(0.9), StreamChatTheme.of(context).colorTheme.grey.withOpacity(0.9),
child: Center( child: Center(
@@ -54,7 +54,7 @@ class _MediaListViewState extends State<MediaListView> {
) { ) {
final media = _media.elementAt(position); final media = _media.elementAt(position);
return Padding( return Padding(
padding: const EdgeInsets.symmetric(horizontal: 1.0, vertical: 1.0), padding: const EdgeInsets.symmetric(horizontal: 1, vertical: 1),
child: InkWell( child: InkWell(
onTap: () { onTap: () {
if (widget.onSelect != null) { if (widget.onSelect != null) {
@@ -64,7 +64,7 @@ class _MediaListViewState extends State<MediaListView> {
child: Stack( child: Stack(
children: [ children: [
AspectRatio( AspectRatio(
aspectRatio: 1.0, aspectRatio: 1,
child: FadeInImage( child: FadeInImage(
fadeInDuration: Duration(milliseconds: 300), fadeInDuration: Duration(milliseconds: 300),
placeholder: AssetImage( placeholder: AssetImage(
@@ -144,9 +144,7 @@ class _MediaListViewState extends State<MediaListView> {
} }
void _getMedia() async { void _getMedia() async {
final assetList = await PhotoManager.getAssetPathList( final assetList = await PhotoManager.getAssetPathList().then((value) {
hasAll: true,
).then((value) {
if (value.isNotEmpty == true) { if (value.isNotEmpty == true) {
return value.singleWhere((element) => element.isAll); return value.singleWhere((element) => element.isAll);
} }
@@ -178,7 +176,7 @@ class MediaThumbnailProvider extends ImageProvider<MediaThumbnailProvider> {
ImageStreamCompleter load(key, decode) { ImageStreamCompleter load(key, decode) {
return MultiFrameImageStreamCompleter( return MultiFrameImageStreamCompleter(
codec: _loadAsync(key, decode), codec: _loadAsync(key, decode),
scale: 1.0, scale: 1,
informationCollector: () sync* { informationCollector: () sync* {
yield ErrorDescription('Id: ${media.id}'); yield ErrorDescription('Id: ${media.id}');
}, },
@@ -20,7 +20,7 @@ class MentionTile extends StatelessWidget {
/// Widget at the end of tile /// Widget at the end of tile
final Widget? trailing; final Widget? trailing;
MentionTile( const MentionTile(
this.member, { this.member, {
this.title, this.title,
this.subtitle, this.subtitle,
@@ -31,12 +31,11 @@ class MentionTile extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return Container(
height: 56.0, height: 56,
child: Row( child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
SizedBox( SizedBox(
width: 16.0, width: 16,
), ),
leading ?? leading ??
UserAvatar( UserAvatar(
@@ -49,7 +48,7 @@ class MentionTile extends StatelessWidget {
user: member.user!, user: member.user!,
), ),
SizedBox( SizedBox(
width: 8.0, width: 8,
), ),
Expanded( Expanded(
child: Align( child: Align(
@@ -60,13 +59,13 @@ class MentionTile extends StatelessWidget {
children: [ children: [
title ?? title ??
Text( Text(
'${member.user!.name}', member.user!.name,
maxLines: 1, maxLines: 1,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
style: StreamChatTheme.of(context).textTheme.bodyBold, style: StreamChatTheme.of(context).textTheme.bodyBold,
), ),
SizedBox( SizedBox(
height: 2.0, height: 2,
), ),
subtitle ?? subtitle ??
Text( Text(
@@ -88,8 +87,8 @@ class MentionTile extends StatelessWidget {
trailing ?? trailing ??
Padding( Padding(
padding: const EdgeInsets.only( padding: const EdgeInsets.only(
right: 18.0, right: 18,
left: 8.0, left: 8,
), ),
child: StreamSvgIcon.mentions( child: StreamSvgIcon.mentions(
color: StreamChatTheme.of(context).colorTheme.accentBlue, color: StreamChatTheme.of(context).colorTheme.accentBlue,
@@ -119,7 +119,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
), ),
if (_showActions) if (_showActions)
TweenAnimationBuilder<double>( TweenAnimationBuilder<double>(
tween: Tween(begin: 0.0, end: 1.0), tween: Tween(begin: 0, end: 1),
duration: Duration(milliseconds: 300), duration: Duration(milliseconds: 300),
curve: Curves.easeInOutBack, curve: Curves.easeInOutBack,
builder: (context, val, snapshot) { builder: (context, val, snapshot) {
@@ -128,7 +128,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
child: Center( child: Center(
child: SingleChildScrollView( child: SingleChildScrollView(
child: Padding( child: Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8),
child: Column( child: Column(
crossAxisAlignment: widget.reverse crossAxisAlignment: widget.reverse
? CrossAxisAlignment.end ? CrossAxisAlignment.end
@@ -146,7 +146,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
: (divFactor > 1.0 : (divFactor > 1.0
? 0.0 ? 0.0
: -(1.0 - divFactor)), : -(1.0 - divFactor)),
0.0), 0),
child: ReactionPicker( child: ReactionPicker(
message: widget.message, message: widget.message,
), ),
@@ -166,7 +166,6 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
messageTheme: widget.messageTheme, messageTheme: widget.messageTheme,
showReactions: false, showReactions: false,
showUsername: false, showUsername: false,
showThreadReplyIndicator: false,
showReplyMessage: false, showReplyMessage: false,
showUserAvatar: widget.showUserAvatar, showUserAvatar: widget.showUserAvatar,
attachmentPadding: EdgeInsets.all( attachmentPadding: EdgeInsets.all(
@@ -176,7 +175,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
translateUserAvatar: false, translateUserAvatar: false,
padding: const EdgeInsets.all(0), padding: const EdgeInsets.all(0),
textPadding: EdgeInsets.symmetric( textPadding: EdgeInsets.symmetric(
vertical: 8.0, vertical: 8,
horizontal: widget.message.text!.isOnlyEmoji horizontal: widget.message.text!.isOnlyEmoji
? 0 ? 0
: 16.0, : 16.0,
@@ -185,7 +184,6 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
widget.showReactions && widget.showReactions &&
(widget.message.status == (widget.message.status ==
MessageSendingStatus.sent), MessageSendingStatus.sent),
showInChannelIndicator: false,
showSendingIndicator: false, showSendingIndicator: false,
shape: widget.messageShape, shape: widget.messageShape,
attachmentShape: widget.attachmentShape, attachmentShape: widget.attachmentShape,
@@ -269,7 +267,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
messageAction.onTap?.call(widget.message); messageAction.onTap?.call(widget.message);
}, },
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(vertical: 11.0, horizontal: 16.0), padding: const EdgeInsets.symmetric(vertical: 11, horizontal: 16),
child: Row( child: Row(
children: [ children: [
messageAction.leading ?? Offstage(), messageAction.leading ?? Offstage(),
@@ -289,7 +287,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
title: 'Flag Message', title: 'Flag Message',
icon: StreamSvgIcon.flag( icon: StreamSvgIcon.flag(
color: StreamChatTheme.of(context).colorTheme.accentRed, color: StreamChatTheme.of(context).colorTheme.accentRed,
size: 24.0, size: 24,
), ),
question: question:
'Do you want to send a copy of this message to a\nmoderator for further investigation?', 'Do you want to send a copy of this message to a\nmoderator for further investigation?',
@@ -305,7 +303,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
context, context,
icon: StreamSvgIcon.flag( icon: StreamSvgIcon.flag(
color: theme.colorTheme.accentRed, color: theme.colorTheme.accentRed,
size: 24.0, size: 24,
), ),
details: 'The message has been reported to a moderator.', details: 'The message has been reported to a moderator.',
title: 'Message flagged', title: 'Message flagged',
@@ -317,7 +315,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
context, context,
icon: StreamSvgIcon.flag( icon: StreamSvgIcon.flag(
color: theme.colorTheme.accentRed, color: theme.colorTheme.accentRed,
size: 24.0, size: 24,
), ),
details: 'The message has been reported to a moderator.', details: 'The message has been reported to a moderator.',
title: 'Message flagged', title: 'Message flagged',
@@ -339,7 +337,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
title: 'Delete message', title: 'Delete message',
icon: StreamSvgIcon.flag( icon: StreamSvgIcon.flag(
color: StreamChatTheme.of(context).colorTheme.accentRed, color: StreamChatTheme.of(context).colorTheme.accentRed,
size: 24.0, size: 24,
), ),
question: 'Are you sure you want to permanently delete this\nmessage?', question: 'Are you sure you want to permanently delete this\nmessage?',
okText: 'DELETE', okText: 'DELETE',
@@ -365,7 +363,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
context, context,
icon: StreamSvgIcon.error( icon: StreamSvgIcon.error(
color: StreamChatTheme.of(context).colorTheme.accentRed, color: StreamChatTheme.of(context).colorTheme.accentRed,
size: 24.0, size: 24,
), ),
details: 'The operation couldn\'t be completed.', details: 'The operation couldn\'t be completed.',
title: 'Something went wrong', title: 'Something went wrong',
@@ -382,7 +380,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
} }
}, },
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(vertical: 11.0, horizontal: 16.0), padding: const EdgeInsets.symmetric(vertical: 11, horizontal: 16),
child: Row( child: Row(
children: [ children: [
StreamSvgIcon.reply( StreamSvgIcon.reply(
@@ -401,9 +399,9 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
Widget _buildFlagButton(BuildContext context) { Widget _buildFlagButton(BuildContext context) {
return InkWell( return InkWell(
onTap: () => _showFlagDialog(), onTap: _showFlagDialog,
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(vertical: 11.0, horizontal: 16.0), padding: const EdgeInsets.symmetric(vertical: 11, horizontal: 16),
child: Row( child: Row(
children: [ children: [
StreamSvgIcon.iconFlag( StreamSvgIcon.iconFlag(
@@ -424,9 +422,9 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
final isDeleteFailed = final isDeleteFailed =
widget.message.status == MessageSendingStatus.failed_delete; widget.message.status == MessageSendingStatus.failed_delete;
return InkWell( return InkWell(
onTap: () => _showDeleteDialog(), onTap: _showDeleteDialog,
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(vertical: 11.0, horizontal: 16.0), padding: const EdgeInsets.symmetric(vertical: 11, horizontal: 16),
child: Row( child: Row(
children: [ children: [
StreamSvgIcon.delete( StreamSvgIcon.delete(
@@ -453,7 +451,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
Navigator.pop(context); Navigator.pop(context);
}, },
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(vertical: 11.0, horizontal: 16.0), padding: const EdgeInsets.symmetric(vertical: 11, horizontal: 16),
child: Row( child: Row(
children: [ children: [
StreamSvgIcon.copy( StreamSvgIcon.copy(
@@ -478,7 +476,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
_showEditBottomSheet(context); _showEditBottomSheet(context);
}, },
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(vertical: 11.0, horizontal: 16.0), padding: const EdgeInsets.symmetric(vertical: 11, horizontal: 16),
child: Row( child: Row(
children: [ children: [
StreamSvgIcon.edit( StreamSvgIcon.edit(
@@ -509,7 +507,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
} }
}, },
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(vertical: 11.0, horizontal: 16.0), padding: const EdgeInsets.symmetric(vertical: 11, horizontal: 16),
child: Row( child: Row(
children: [ children: [
StreamSvgIcon.circleUp( StreamSvgIcon.circleUp(
@@ -555,7 +553,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[ children: <Widget>[
Padding( Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8),
child: StreamSvgIcon.edit( child: StreamSvgIcon.edit(
color: StreamChatTheme.of(context) color: StreamChatTheme.of(context)
.colorTheme .colorTheme
@@ -574,16 +572,17 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
], ],
), ),
), ),
widget.editMessageInputBuilder != null if (widget.editMessageInputBuilder != null)
? widget.editMessageInputBuilder!(context, widget.message) widget.editMessageInputBuilder!(context, widget.message)
: MessageInput( else
editMessage: widget.message, MessageInput(
preMessageSending: (m) { editMessage: widget.message,
FocusScope.of(context).unfocus(); preMessageSending: (m) {
Navigator.pop(context); FocusScope.of(context).unfocus();
return m; Navigator.pop(context);
}, return m;
), },
),
], ],
), ),
); );
@@ -600,7 +599,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
} }
}, },
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(vertical: 11.0, horizontal: 16.0), padding: const EdgeInsets.symmetric(vertical: 11, horizontal: 16),
child: Row( child: Row(
children: [ children: [
StreamSvgIcon.thread( StreamSvgIcon.thread(
@@ -109,7 +109,7 @@ const _kMaxAttachmentSize = 20971520; // 20MB in Bytes
/// Modify it to change the widget appearance. /// Modify it to change the widget appearance.
class MessageInput extends StatefulWidget { class MessageInput extends StatefulWidget {
/// Instantiate a new MessageInput /// Instantiate a new MessageInput
MessageInput({ const MessageInput({
Key? key, Key? key,
this.onMessageSent, this.onMessageSent,
this.preMessageSending, this.preMessageSending,
@@ -306,7 +306,7 @@ class MessageInputState extends State<MessageInput> {
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Padding( Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8),
child: StreamSvgIcon.reply( child: StreamSvgIcon.reply(
color: StreamChatTheme.of(context) color: StreamChatTheme.of(context)
.colorTheme .colorTheme
@@ -326,15 +326,15 @@ class MessageInputState extends State<MessageInput> {
), ),
), ),
Padding( Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0), padding: const EdgeInsets.symmetric(vertical: 8),
child: _buildTextField(context), child: _buildTextField(context),
), ),
if (widget.parentMessage != null && !widget.hideSendAsDm) if (widget.parentMessage != null && !widget.hideSendAsDm)
Padding( Padding(
padding: const EdgeInsets.only( padding: const EdgeInsets.only(
right: 12.0, right: 12,
left: 12.0, left: 12,
bottom: 12.0, bottom: 12,
), ),
child: _buildDmCheckbox(), child: _buildDmCheckbox(),
), ),
@@ -356,7 +356,6 @@ class MessageInputState extends State<MessageInput> {
Flex _buildTextField(BuildContext context) { Flex _buildTextField(BuildContext context) {
return Flex( return Flex(
direction: Axis.horizontal, direction: Axis.horizontal,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[ children: <Widget>[
if (!_commandEnabled && widget.actionsLocation == ActionsLocation.left) if (!_commandEnabled && widget.actionsLocation == ActionsLocation.left)
_buildExpandActionsButton(), _buildExpandActionsButton(),
@@ -371,7 +370,6 @@ class MessageInputState extends State<MessageInput> {
Widget _buildDmCheckbox() { Widget _buildDmCheckbox() {
return Row( return Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
Container( Container(
height: 16, height: 16,
@@ -407,7 +405,7 @@ class MessageInputState extends State<MessageInput> {
? CrossFadeState.showFirst ? CrossFadeState.showFirst
: CrossFadeState.showSecond, : CrossFadeState.showSecond,
firstChild: StreamSvgIcon.check( firstChild: StreamSvgIcon.check(
size: 16.0, size: 16,
color: StreamChatTheme.of(context).colorTheme.white, color: StreamChatTheme.of(context).colorTheme.white,
), ),
secondChild: SizedBox( secondChild: SizedBox(
@@ -420,7 +418,7 @@ class MessageInputState extends State<MessageInput> {
), ),
), ),
Padding( Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0), padding: const EdgeInsets.symmetric(horizontal: 12),
child: Text( child: Text(
'Also send as direct message', 'Also send as direct message',
style: StreamChatTheme.of(context).textTheme.footnote.copyWith( style: StreamChatTheme.of(context).textTheme.footnote.copyWith(
@@ -456,7 +454,7 @@ class MessageInputState extends State<MessageInput> {
Widget _buildExpandActionsButton() { Widget _buildExpandActionsButton() {
return Padding( return Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0), padding: const EdgeInsets.symmetric(horizontal: 8),
child: AnimatedCrossFade( child: AnimatedCrossFade(
crossFadeState: _actionsShrunk crossFadeState: _actionsShrunk
? CrossFadeState.showFirst ? CrossFadeState.showFirst
@@ -464,7 +462,6 @@ class MessageInputState extends State<MessageInput> {
firstChild: IconButton( firstChild: IconButton(
onPressed: () => setState(() => _actionsShrunk = false), onPressed: () => setState(() => _actionsShrunk = false),
icon: Transform.rotate( icon: Transform.rotate(
alignment: Alignment.center,
angle: (widget.actionsLocation == ActionsLocation.right || angle: (widget.actionsLocation == ActionsLocation.right ||
widget.actionsLocation == ActionsLocation.rightInside) widget.actionsLocation == ActionsLocation.rightInside)
? pi ? pi
@@ -484,7 +481,6 @@ class MessageInputState extends State<MessageInput> {
), ),
secondChild: FittedBox( secondChild: FittedBox(
child: Row( child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceEvenly, mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[ children: <Widget>[
if (!widget.disableAttachments) _buildAttachmentButton(), if (!widget.disableAttachments) _buildAttachmentButton(),
@@ -510,10 +506,10 @@ class MessageInputState extends State<MessageInput> {
Expanded _buildTextInput(BuildContext context) { Expanded _buildTextInput(BuildContext context) {
final theme = StreamChatTheme.of(context); final theme = StreamChatTheme.of(context);
final margin = (widget.sendButtonLocation == SendButtonLocation.inside final margin = (widget.sendButtonLocation == SendButtonLocation.inside
? const EdgeInsets.only(right: 8.0) ? const EdgeInsets.only(right: 8)
: EdgeInsets.zero) + : EdgeInsets.zero) +
(widget.actionsLocation != ActionsLocation.left (widget.actionsLocation != ActionsLocation.left
? const EdgeInsets.only(left: 8.0) ? const EdgeInsets.only(left: 8)
: EdgeInsets.zero); : EdgeInsets.zero);
return Expanded( return Expanded(
child: Center( child: Center(
@@ -545,7 +541,6 @@ class MessageInputState extends State<MessageInput> {
child: TextField( child: TextField(
key: Key('messageInputText'), key: Key('messageInputText'),
enabled: _inputEnabled, enabled: _inputEnabled,
minLines: null,
maxLines: null, maxLines: null,
onSubmitted: (_) => sendMessage(), onSubmitted: (_) => sendMessage(),
keyboardType: widget.keyboardType, keyboardType: widget.keyboardType,
@@ -607,7 +602,7 @@ class MessageInputState extends State<MessageInput> {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Padding( Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8),
child: Container( child: Container(
constraints: BoxConstraints.tight(Size(64, 24)), constraints: BoxConstraints.tight(Size(64, 24)),
decoration: BoxDecoration( decoration: BoxDecoration(
@@ -620,7 +615,7 @@ class MessageInputState extends State<MessageInput> {
children: [ children: [
StreamSvgIcon.lightning( StreamSvgIcon.lightning(
color: Colors.white, color: Colors.white,
size: 16.0, size: 16,
), ),
Text( Text(
_chosenCommand?.name.toUpperCase() ?? '', _chosenCommand?.name.toUpperCase() ?? '',
@@ -640,7 +635,6 @@ class MessageInputState extends State<MessageInput> {
: (widget.actionsLocation == ActionsLocation.leftInside : (widget.actionsLocation == ActionsLocation.leftInside
? Row( ? Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
_buildExpandActionsButton(), _buildExpandActionsButton(),
], ],
@@ -650,11 +644,10 @@ class MessageInputState extends State<MessageInput> {
prefixIconConstraints: BoxConstraints.tightFor(height: 40), prefixIconConstraints: BoxConstraints.tightFor(height: 40),
suffixIcon: Row( suffixIcon: Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
if (_commandEnabled) if (_commandEnabled)
Padding( Padding(
padding: const EdgeInsets.only(right: 8.0), padding: const EdgeInsets.only(right: 8),
child: IconButton( child: IconButton(
icon: StreamSvgIcon.closeSmall(), icon: StreamSvgIcon.closeSmall(),
splashRadius: 24, splashRadius: 24,
@@ -776,7 +769,7 @@ class MessageInputState extends State<MessageInput> {
void _checkCommands(String s, BuildContext context) { void _checkCommands(String s, BuildContext context) {
if (s.startsWith('/')) { if (s.startsWith('/')) {
var matchedCommandsList = StreamChannel.of(context) final matchedCommandsList = StreamChannel.of(context)
.channel .channel
.config .config
?.commands ?.commands
@@ -825,19 +818,18 @@ class MessageInputState extends State<MessageInput> {
left: 0, left: 0,
right: 0, right: 0,
child: TweenAnimationBuilder<double>( child: TweenAnimationBuilder<double>(
tween: Tween(begin: 0.0, end: 1.0), tween: Tween(begin: 0, end: 1),
duration: Duration(milliseconds: 300), duration: Duration(milliseconds: 300),
curve: Curves.easeInOutExpo, curve: Curves.easeInOutExpo,
builder: (context, val, wid) { builder: (context, val, wid) {
return Transform.scale( return Transform.scale(
alignment: Alignment.center,
scale: val, scale: val,
child: Padding( child: Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8),
child: Card( child: Card(
elevation: 2.0, elevation: 2,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.0), borderRadius: BorderRadius.circular(8),
), ),
color: StreamChatTheme.of(context).colorTheme.white, color: StreamChatTheme.of(context).colorTheme.white,
clipBehavior: Clip.antiAlias, clipBehavior: Clip.antiAlias,
@@ -845,20 +837,19 @@ class MessageInputState extends State<MessageInput> {
constraints: BoxConstraints.loose(Size.fromHeight(400)), constraints: BoxConstraints.loose(Size.fromHeight(400)),
decoration: BoxDecoration( decoration: BoxDecoration(
color: StreamChatTheme.of(context).colorTheme.white, color: StreamChatTheme.of(context).colorTheme.white,
borderRadius: BorderRadius.circular(8.0)), borderRadius: BorderRadius.circular(8)),
child: ListView( child: ListView(
padding: const EdgeInsets.all(0), padding: const EdgeInsets.all(0),
shrinkWrap: true, shrinkWrap: true,
children: [ children: [
if (commands.isNotEmpty) if (commands.isNotEmpty)
Padding( Padding(
padding: padding: const EdgeInsets.only(top: 8),
const EdgeInsets.only(left: 0.0, top: 8.0),
child: Row( child: Row(
children: [ children: [
Padding( Padding(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
horizontal: 8.0, horizontal: 8,
), ),
child: StreamSvgIcon.lightning( child: StreamSvgIcon.lightning(
color: StreamChatTheme.of(context) color: StreamChatTheme.of(context)
@@ -879,7 +870,7 @@ class MessageInputState extends State<MessageInput> {
), ),
), ),
SizedBox( SizedBox(
height: 10.0, height: 10,
), ),
...commands ...commands
.map( .map(
@@ -888,19 +879,19 @@ class MessageInputState extends State<MessageInput> {
_setCommand(c); _setCommand(c);
}, },
child: Container( child: Container(
height: 40.0, height: 40,
child: Row( child: Row(
children: [ children: [
SizedBox( SizedBox(
width: 16.0, width: 16,
), ),
_buildCommandIcon(c.name), _buildCommandIcon(c.name),
SizedBox( SizedBox(
width: 8.0, width: 8,
), ),
Text.rich( Text.rich(
TextSpan( TextSpan(
text: '${c.name.capitalize()}', text: c.name.capitalize(),
style: TextStyle( style: TextStyle(
fontWeight: FontWeight.bold), fontWeight: FontWeight.bold),
children: [ children: [
@@ -987,10 +978,8 @@ class MessageInputState extends State<MessageInput> {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Row( Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [ children: [
IconButton( IconButton(
iconSize: 24,
icon: StreamSvgIcon.pictures( icon: StreamSvgIcon.pictures(
color: _getIconColor(0), color: _getIconColor(0),
), ),
@@ -1010,11 +999,10 @@ class MessageInputState extends State<MessageInput> {
onPressed: !_attachmentContainsFile && _attachments.isNotEmpty onPressed: !_attachmentContainsFile && _attachments.isNotEmpty
? null ? null
: () { : () {
pickFile(DefaultAttachmentTypes.file, false); pickFile(DefaultAttachmentTypes.file);
}, },
), ),
IconButton( IconButton(
iconSize: 24,
icon: StreamSvgIcon.camera( icon: StreamSvgIcon.camera(
color: _getIconColor(2), color: _getIconColor(2),
), ),
@@ -1026,7 +1014,6 @@ class MessageInputState extends State<MessageInput> {
), ),
IconButton( IconButton(
padding: const EdgeInsets.all(0), padding: const EdgeInsets.all(0),
iconSize: 24,
icon: StreamSvgIcon.record( icon: StreamSvgIcon.record(
color: _getIconColor(3), color: _getIconColor(3),
), ),
@@ -1052,22 +1039,22 @@ class MessageInputState extends State<MessageInput> {
decoration: BoxDecoration( decoration: BoxDecoration(
color: StreamChatTheme.of(context).colorTheme.white, color: StreamChatTheme.of(context).colorTheme.white,
borderRadius: BorderRadius.only( borderRadius: BorderRadius.only(
topLeft: Radius.circular(16.0), topLeft: Radius.circular(16),
topRight: Radius.circular(16.0), topRight: Radius.circular(16),
), ),
), ),
child: Container( child: Container(
width: double.infinity, width: double.infinity,
child: Center( child: Center(
child: Padding( child: Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8),
child: Container( child: Container(
width: 40.0, width: 40,
height: 4.0, height: 4,
decoration: BoxDecoration( decoration: BoxDecoration(
color: color:
StreamChatTheme.of(context).colorTheme.whiteSmoke, StreamChatTheme.of(context).colorTheme.whiteSmoke,
borderRadius: BorderRadius.circular(4.0), borderRadius: BorderRadius.circular(4),
), ),
), ),
), ),
@@ -1080,7 +1067,7 @@ class MessageInputState extends State<MessageInput> {
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: StreamChatTheme.of(context).colorTheme.white, color: StreamChatTheme.of(context).colorTheme.white,
borderRadius: BorderRadius.circular(8.0), borderRadius: BorderRadius.circular(8),
), ),
child: _PickerWidget( child: _PickerWidget(
filePickerIndex: _filePickerIndex, filePickerIndex: _filePickerIndex,
@@ -1159,7 +1146,7 @@ class MessageInputState extends State<MessageInput> {
return CircleAvatar( return CircleAvatar(
radius: 12, radius: 12,
child: StreamSvgIcon.giphyIcon( child: StreamSvgIcon.giphyIcon(
size: 24.0, size: 24,
), ),
); );
case 'ban': case 'ban':
@@ -1167,7 +1154,7 @@ class MessageInputState extends State<MessageInput> {
backgroundColor: StreamChatTheme.of(context).colorTheme.accentBlue, backgroundColor: StreamChatTheme.of(context).colorTheme.accentBlue,
radius: 12, radius: 12,
child: StreamSvgIcon.iconUserDelete( child: StreamSvgIcon.iconUserDelete(
size: 16.0, size: 16,
color: Colors.white, color: Colors.white,
), ),
); );
@@ -1176,7 +1163,7 @@ class MessageInputState extends State<MessageInput> {
backgroundColor: StreamChatTheme.of(context).colorTheme.accentBlue, backgroundColor: StreamChatTheme.of(context).colorTheme.accentBlue,
radius: 12, radius: 12,
child: StreamSvgIcon.flag( child: StreamSvgIcon.flag(
size: 14.0, size: 14,
color: Colors.white, color: Colors.white,
), ),
); );
@@ -1186,7 +1173,7 @@ class MessageInputState extends State<MessageInput> {
radius: 12, radius: 12,
child: ClipOval( child: ClipOval(
child: StreamSvgIcon.imgur( child: StreamSvgIcon.imgur(
size: 24.0, size: 24,
), ),
), ),
); );
@@ -1195,7 +1182,7 @@ class MessageInputState extends State<MessageInput> {
backgroundColor: StreamChatTheme.of(context).colorTheme.accentBlue, backgroundColor: StreamChatTheme.of(context).colorTheme.accentBlue,
radius: 12, radius: 12,
child: StreamSvgIcon.mute( child: StreamSvgIcon.mute(
size: 16.0, size: 16,
color: Colors.white, color: Colors.white,
), ),
); );
@@ -1204,7 +1191,7 @@ class MessageInputState extends State<MessageInput> {
backgroundColor: StreamChatTheme.of(context).colorTheme.accentBlue, backgroundColor: StreamChatTheme.of(context).colorTheme.accentBlue,
radius: 12, radius: 12,
child: StreamSvgIcon.userAdd( child: StreamSvgIcon.userAdd(
size: 16.0, size: 16,
color: Colors.white, color: Colors.white,
), ),
); );
@@ -1213,7 +1200,7 @@ class MessageInputState extends State<MessageInput> {
backgroundColor: StreamChatTheme.of(context).colorTheme.accentBlue, backgroundColor: StreamChatTheme.of(context).colorTheme.accentBlue,
radius: 12, radius: 12,
child: StreamSvgIcon.volumeUp( child: StreamSvgIcon.volumeUp(
size: 16.0, size: 16,
color: Colors.white, color: Colors.white,
), ),
); );
@@ -1222,7 +1209,7 @@ class MessageInputState extends State<MessageInput> {
backgroundColor: StreamChatTheme.of(context).colorTheme.accentBlue, backgroundColor: StreamChatTheme.of(context).colorTheme.accentBlue,
radius: 12, radius: 12,
child: StreamSvgIcon.lightning( child: StreamSvgIcon.lightning(
size: 16.0, size: 16,
color: Colors.white, color: Colors.white,
), ),
); );
@@ -1263,18 +1250,18 @@ class MessageInputState extends State<MessageInput> {
left: 0, left: 0,
right: 0, right: 0,
child: TweenAnimationBuilder<double>( child: TweenAnimationBuilder<double>(
tween: Tween(begin: 0.0, end: 1.0), tween: Tween(begin: 0, end: 1),
duration: Duration(milliseconds: 300), duration: Duration(milliseconds: 300),
curve: Curves.easeInOutExpo, curve: Curves.easeInOutExpo,
builder: (context, val, wid) { builder: (context, val, wid) {
return Transform.scale( return Transform.scale(
scale: val, scale: val,
child: Card( child: Card(
margin: EdgeInsets.all(8.0), margin: EdgeInsets.all(8),
elevation: 2.0, elevation: 2,
color: StreamChatTheme.of(context).colorTheme.white, color: StreamChatTheme.of(context).colorTheme.white,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.0), borderRadius: BorderRadius.circular(8),
), ),
clipBehavior: Clip.antiAlias, clipBehavior: Clip.antiAlias,
child: Container( child: Container(
@@ -1291,7 +1278,7 @@ class MessageInputState extends State<MessageInput> {
shrinkWrap: true, shrinkWrap: true,
children: [ children: [
SizedBox( SizedBox(
height: 8.0, height: 8,
), ),
...snapshot.data! ...snapshot.data!
.where((it) => it.user != null) .where((it) => it.user != null)
@@ -1333,7 +1320,7 @@ class MessageInputState extends State<MessageInput> {
}, },
).toList(), ).toList(),
SizedBox( SizedBox(
height: 8.0, height: 8,
), ),
], ],
); );
@@ -1361,7 +1348,7 @@ class MessageInputState extends State<MessageInput> {
final emojis = _emojiNames final emojis = _emojiNames
.where((e) => e.contains(query)) .where((e) => e.contains(query))
.map((e) => Emoji.byName(e)) .map(Emoji.byName)
.where((e) => e != null); .where((e) => e != null);
if (emojis.isEmpty) { if (emojis.isEmpty) {
@@ -1377,11 +1364,11 @@ class MessageInputState extends State<MessageInput> {
left: 0, left: 0,
right: 0, right: 0,
child: Card( child: Card(
margin: EdgeInsets.all(8.0), margin: EdgeInsets.all(8),
elevation: 2.0, elevation: 2,
color: StreamChatTheme.of(context).colorTheme.white, color: StreamChatTheme.of(context).colorTheme.white,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.0), borderRadius: BorderRadius.circular(8),
), ),
clipBehavior: Clip.antiAlias, clipBehavior: Clip.antiAlias,
child: Container( child: Container(
@@ -1390,7 +1377,7 @@ class MessageInputState extends State<MessageInput> {
boxShadow: [ boxShadow: [
BoxShadow( BoxShadow(
spreadRadius: -8, spreadRadius: -8,
blurRadius: 5.0, blurRadius: 5,
offset: Offset(0, -4), offset: Offset(0, -4),
), ),
], ],
@@ -1403,12 +1390,11 @@ class MessageInputState extends State<MessageInput> {
itemBuilder: (context, i) { itemBuilder: (context, i) {
if (i == 0) { if (i == 0) {
return Padding( return Padding(
padding: const EdgeInsets.only(left: 8.0, top: 8.0), padding: const EdgeInsets.only(left: 8, top: 8),
child: Row( child: Row(
children: [ children: [
Padding( Padding(
padding: padding: const EdgeInsets.symmetric(horizontal: 8),
const EdgeInsets.symmetric(horizontal: 8.0),
child: StreamSvgIcon.smile( child: StreamSvgIcon.smile(
color: StreamChatTheme.of(context) color: StreamChatTheme.of(context)
.colorTheme .colorTheme
@@ -1516,7 +1502,7 @@ class MessageInputState extends State<MessageInput> {
Padding( Padding(
padding: const EdgeInsets.fromLTRB(8, 8, 8, 0), padding: const EdgeInsets.fromLTRB(8, 8, 8, 0),
child: LimitedBox( child: LimitedBox(
maxHeight: 136.0, maxHeight: 136,
child: ListView( child: ListView(
reverse: true, reverse: true,
shrinkWrap: true, shrinkWrap: true,
@@ -1524,16 +1510,15 @@ class MessageInputState extends State<MessageInput> {
.map<Widget>( .map<Widget>(
(e) => ClipRRect( (e) => ClipRRect(
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(10),
clipBehavior: Clip.antiAlias,
child: FileAttachment( child: FileAttachment(
message: Message(), // dummy message message: Message(), // dummy message
attachment: e, attachment: e,
size: Size( size: Size(
MediaQuery.of(context).size.width * 0.65, MediaQuery.of(context).size.width * 0.65,
56.0, 56,
), ),
trailing: Padding( trailing: Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8),
child: _buildRemoveButton(e), child: _buildRemoveButton(e),
), ),
), ),
@@ -1547,18 +1532,17 @@ class MessageInputState extends State<MessageInput> {
Padding( Padding(
padding: const EdgeInsets.fromLTRB(8, 8, 8, 0), padding: const EdgeInsets.fromLTRB(8, 8, 8, 0),
child: LimitedBox( child: LimitedBox(
maxHeight: 104.0, maxHeight: 104,
child: ListView( child: ListView(
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
children: remainingAttachments children: remainingAttachments
.map<Widget>( .map<Widget>(
(attachment) => ClipRRect( (attachment) => ClipRRect(
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(10),
clipBehavior: Clip.antiAlias,
child: Stack( child: Stack(
children: <Widget>[ children: <Widget>[
AspectRatio( AspectRatio(
aspectRatio: 1.0, aspectRatio: 1,
child: Container( child: Container(
height: 104, height: 104,
width: 104, width: 104,
@@ -1593,7 +1577,6 @@ class MessageInputState extends State<MessageInput> {
elevation: 0, elevation: 0,
highlightElevation: 0, highlightElevation: 0,
focusElevation: 0, focusElevation: 0,
disabledElevation: 0,
hoverElevation: 0, hoverElevation: 0,
onPressed: () { onPressed: () {
setState(() => _attachments.remove(attachment.id)); setState(() => _attachments.remove(attachment.id));
@@ -1803,7 +1786,7 @@ class MessageInputState extends State<MessageInput> {
leading: Icon(Icons.image), leading: Icon(Icons.image),
title: Text('Upload a photo'), title: Text('Upload a photo'),
onTap: () { onTap: () {
pickFile(DefaultAttachmentTypes.image, false); pickFile(DefaultAttachmentTypes.image);
Navigator.pop(context); Navigator.pop(context);
}, },
), ),
@@ -1811,7 +1794,7 @@ class MessageInputState extends State<MessageInput> {
leading: Icon(Icons.video_library), leading: Icon(Icons.video_library),
title: Text('Upload a video'), title: Text('Upload a video'),
onTap: () { onTap: () {
pickFile(DefaultAttachmentTypes.video, false); pickFile(DefaultAttachmentTypes.video);
Navigator.pop(context); Navigator.pop(context);
}, },
), ),
@@ -1837,7 +1820,7 @@ class MessageInputState extends State<MessageInput> {
leading: Icon(Icons.insert_drive_file), leading: Icon(Icons.insert_drive_file),
title: Text('Upload a file'), title: Text('Upload a file'),
onTap: () { onTap: () {
pickFile(DefaultAttachmentTypes.file, false); pickFile(DefaultAttachmentTypes.file);
Navigator.pop(context); Navigator.pop(context);
}, },
), ),
@@ -1967,7 +1950,7 @@ class MessageInputState extends State<MessageInput> {
Widget _buildIdleSendButton(BuildContext context) { Widget _buildIdleSendButton(BuildContext context) {
return Padding( return Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8),
child: StreamSvgIcon( child: StreamSvgIcon(
assetName: _getIdleSendIcon(), assetName: _getIdleSendIcon(),
color: color:
@@ -1978,7 +1961,7 @@ class MessageInputState extends State<MessageInput> {
Widget _buildSendButton(BuildContext context) { Widget _buildSendButton(BuildContext context) {
return Padding( return Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8),
child: IconButton( child: IconButton(
onPressed: sendMessage, onPressed: sendMessage,
padding: const EdgeInsets.all(0), padding: const EdgeInsets.all(0),
@@ -2112,44 +2095,44 @@ class MessageInputState extends State<MessageInput> {
context: context, context: context,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only( borderRadius: BorderRadius.only(
topLeft: Radius.circular(16.0), topLeft: Radius.circular(16),
topRight: Radius.circular(16.0), topRight: Radius.circular(16),
)), )),
builder: (context) { builder: (context) {
return Column( return Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
SizedBox( SizedBox(
height: 26.0, height: 26,
), ),
StreamSvgIcon.error( StreamSvgIcon.error(
color: StreamChatTheme.of(context).colorTheme.accentRed, color: StreamChatTheme.of(context).colorTheme.accentRed,
size: 24.0, size: 24,
), ),
SizedBox( SizedBox(
height: 26.0, height: 26,
), ),
Text( Text(
'Something went wrong', 'Something went wrong',
style: StreamChatTheme.of(context).textTheme.headlineBold, style: StreamChatTheme.of(context).textTheme.headlineBold,
), ),
SizedBox( SizedBox(
height: 7.0, height: 7,
), ),
Padding( Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0), padding: const EdgeInsets.symmetric(horizontal: 16),
child: Text( child: Text(
description, description,
textAlign: TextAlign.center, textAlign: TextAlign.center,
), ),
), ),
SizedBox( SizedBox(
height: 36.0, height: 36,
), ),
Container( Container(
color: color:
StreamChatTheme.of(context).colorTheme.black.withOpacity(.08), StreamChatTheme.of(context).colorTheme.black.withOpacity(.08),
height: 1.0, height: 1,
), ),
Row( Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
@@ -2345,7 +2328,7 @@ class __PickerWidgetState extends State<_PickerWidget> {
color: StreamChatTheme.of(context).colorTheme.grey), color: StreamChatTheme.of(context).colorTheme.grey),
textAlign: TextAlign.center, textAlign: TextAlign.center,
), ),
SizedBox(height: 6.0), SizedBox(height: 6),
Center( Center(
child: Text( child: Text(
'Allow access to your gallery', 'Allow access to your gallery',
@@ -111,7 +111,7 @@ class MessageDetails {
/// Modify it to change the widget appearance. /// Modify it to change the widget appearance.
class MessageListView extends StatefulWidget { class MessageListView extends StatefulWidget {
/// Instantiate a new MessageListView /// Instantiate a new MessageListView
MessageListView({ const MessageListView({
Key? key, Key? key,
this.showScrollToBottom = true, this.showScrollToBottom = true,
this.messageBuilder, this.messageBuilder,
@@ -418,7 +418,6 @@ class _MessageListViewState extends State<MessageListView> {
child: ScrollablePositionedList.separated( child: ScrollablePositionedList.separated(
key: ValueKey(initialIndex! + initialAlignment!), key: ValueKey(initialIndex! + initialAlignment!),
itemPositionsListener: _itemPositionListener, itemPositionsListener: _itemPositionListener,
addAutomaticKeepAlives: true,
initialScrollIndex: initialIndex ?? 0, initialScrollIndex: initialIndex ?? 0,
initialAlignment: initialAlignment ?? 0, initialAlignment: initialAlignment ?? 0,
physics: widget.scrollPhysics, physics: widget.scrollPhysics,
@@ -437,7 +436,7 @@ class _MessageListViewState extends State<MessageListView> {
StreamChatTheme.of(context).colorTheme.bgGradient, StreamChatTheme.of(context).colorTheme.bgGradient,
), ),
child: Padding( child: Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8),
child: Text( child: Text(
'$replyCount ${replyCount == 1 ? 'Reply' : 'Replies'}', '$replyCount ${replyCount == 1 ? 'Reply' : 'Replies'}',
textAlign: TextAlign.center, textAlign: TextAlign.center,
@@ -464,7 +463,7 @@ class _MessageListViewState extends State<MessageListView> {
dateTime: nextMessage.createdAt.toLocal(), dateTime: nextMessage.createdAt.toLocal(),
); );
return Padding( return Padding(
padding: const EdgeInsets.symmetric(vertical: 12.0), padding: const EdgeInsets.symmetric(vertical: 12),
child: divider, child: divider,
); );
} }
@@ -554,7 +553,7 @@ class _MessageListViewState extends State<MessageListView> {
), ),
if (widget.showScrollToBottom) _buildScrollToBottom(), if (widget.showScrollToBottom) _buildScrollToBottom(),
Positioned( Positioned(
top: 20.0, top: 20,
child: ValueListenableBuilder<Iterable<ItemPosition>>( child: ValueListenableBuilder<Iterable<ItemPosition>>(
valueListenable: _itemPositionListener.itemPositions, valueListenable: _itemPositionListener.itemPositions,
builder: (context, values, _) { builder: (context, values, _) {
@@ -660,7 +659,7 @@ class _MessageListViewState extends State<MessageListView> {
top: -10, top: -10,
child: CircleAvatar( child: CircleAvatar(
child: Padding( child: Padding(
padding: const EdgeInsets.all(3.0), padding: const EdgeInsets.all(3),
child: Text( child: Text(
'$unreadCount', '$unreadCount',
style: TextStyle( style: TextStyle(
@@ -712,7 +711,7 @@ class _MessageListViewState extends State<MessageListView> {
} }
return Center( return Center(
child: Padding( child: Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8),
child: const CircularProgressIndicator(), child: const CircularProgressIndicator(),
), ),
); );
@@ -799,8 +798,6 @@ class _MessageListViewState extends State<MessageListView> {
final isOnlyEmoji = message.text!.isOnlyEmoji; final isOnlyEmoji = message.text!.isOnlyEmoji;
return MessageWidget( return MessageWidget(
showThreadReplyIndicator: false,
showInChannelIndicator: false,
showReplyMessage: false, showReplyMessage: false,
showResendMessage: false, showResendMessage: false,
showThreadReplyMessage: false, showThreadReplyMessage: false,
@@ -810,7 +807,7 @@ class _MessageListViewState extends State<MessageListView> {
message: message, message: message,
reverse: isMyMessage, reverse: isMyMessage,
showUsername: !isMyMessage, showUsername: !isMyMessage,
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8),
showSendingIndicator: false, showSendingIndicator: false,
onThreadTap: _onThreadTap as void Function(Message)?, onThreadTap: _onThreadTap as void Function(Message)?,
borderRadiusGeometry: BorderRadius.only( borderRadiusGeometry: BorderRadius.only(
@@ -820,7 +817,7 @@ class _MessageListViewState extends State<MessageListView> {
bottomRight: Radius.circular(16), bottomRight: Radius.circular(16),
), ),
textPadding: EdgeInsets.symmetric( textPadding: EdgeInsets.symmetric(
vertical: 8.0, vertical: 8,
horizontal: isOnlyEmoji ? 0 : 16.0, horizontal: isOnlyEmoji ? 0 : 16.0,
), ),
borderSide: isMyMessage || isOnlyEmoji ? BorderSide.none : null, borderSide: isMyMessage || isOnlyEmoji ? BorderSide.none : null,
@@ -940,7 +937,7 @@ class _MessageListViewState extends State<MessageListView> {
message: message, message: message,
reverse: isMyMessage, reverse: isMyMessage,
showReactions: !message.isDeleted, showReactions: !message.isDeleted,
padding: const EdgeInsets.symmetric(horizontal: 8.0), padding: const EdgeInsets.symmetric(horizontal: 8),
showInChannelIndicator: showInChannelIndicator, showInChannelIndicator: showInChannelIndicator,
showThreadReplyIndicator: showThreadReplyIndicator, showThreadReplyIndicator: showThreadReplyIndicator,
showUsername: showUsername, showUsername: showUsername,
@@ -997,7 +994,7 @@ class _MessageListViewState extends State<MessageListView> {
bottomRight: Radius.circular(16), bottomRight: Radius.circular(16),
), ),
textPadding: EdgeInsets.symmetric( textPadding: EdgeInsets.symmetric(
vertical: 8.0, vertical: 8,
horizontal: isOnlyEmoji ? 0 : 16.0, horizontal: isOnlyEmoji ? 0 : 16.0,
), ),
messageTheme: isMyMessage messageTheme: isMyMessage
@@ -1069,7 +1066,7 @@ class _MessageListViewState extends State<MessageListView> {
); );
}, },
child: Padding( child: Padding(
padding: const EdgeInsets.only(top: 4.0), padding: const EdgeInsets.only(top: 4),
child: child, child: child,
), ),
); );
@@ -59,7 +59,7 @@ class MessageReactionsModal extends StatelessWidget {
: (roughSentenceSize == 0 ? 1 : (roughSentenceSize / roughMaxSize)); : (roughSentenceSize == 0 ? 1 : (roughSentenceSize / roughMaxSize));
return TweenAnimationBuilder<double>( return TweenAnimationBuilder<double>(
tween: Tween(begin: 0.0, end: 1.0), tween: Tween(begin: 0, end: 1),
duration: Duration(milliseconds: 300), duration: Duration(milliseconds: 300),
curve: Curves.easeInOutBack, curve: Curves.easeInOutBack,
builder: (context, val, snapshot) { builder: (context, val, snapshot) {
@@ -86,7 +86,7 @@ class MessageReactionsModal extends StatelessWidget {
child: Center( child: Center(
child: SingleChildScrollView( child: SingleChildScrollView(
child: Padding( child: Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8),
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
@@ -102,7 +102,7 @@ class MessageReactionsModal extends StatelessWidget {
: (divFactor > 1.0 : (divFactor > 1.0
? 0.0 ? 0.0
: -(1.0 - divFactor)), : -(1.0 - divFactor)),
0.0), 0),
child: ReactionPicker( child: ReactionPicker(
message: message, message: message,
), ),
@@ -121,7 +121,6 @@ class MessageReactionsModal extends StatelessWidget {
showReactions: false, showReactions: false,
showUsername: false, showUsername: false,
showUserAvatar: showUserAvatar, showUserAvatar: showUserAvatar,
showThreadReplyIndicator: false,
showTimestamp: false, showTimestamp: false,
translateUserAvatar: false, translateUserAvatar: false,
showSendingIndicator: false, showSendingIndicator: false,
@@ -133,9 +132,8 @@ class MessageReactionsModal extends StatelessWidget {
attachmentPadding: EdgeInsets.all( attachmentPadding: EdgeInsets.all(
hasFileAttachment ? 4 : 2, hasFileAttachment ? 4 : 2,
), ),
showInChannelIndicator: false,
textPadding: EdgeInsets.symmetric( textPadding: EdgeInsets.symmetric(
vertical: 8.0, vertical: 8,
horizontal: horizontal:
message.text!.isOnlyEmoji ? 0 : 16.0, message.text!.isOnlyEmoji ? 0 : 16.0,
), ),
@@ -184,7 +182,6 @@ class MessageReactionsModal extends StatelessWidget {
child: Wrap( child: Wrap(
spacing: 16, spacing: 16,
runSpacing: 16, runSpacing: 16,
alignment: WrapAlignment.start,
children: message.latestReactions! children: message.latestReactions!
.map((e) => _buildReaction( .map((e) => _buildReaction(
e, e,
@@ -214,8 +211,6 @@ class MessageReactionsModal extends StatelessWidget {
)), )),
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
Stack( Stack(
clipBehavior: Clip.none, clipBehavior: Clip.none,
@@ -147,8 +147,8 @@ class MessageSearchItem extends StatelessWidget {
List<Attachment> attachments, List<Attachment> attachments,
TextStyle? normalTextStyle, TextStyle? normalTextStyle,
TextStyle? mentionsTextStyle) { TextStyle? mentionsTextStyle) {
var textList = text.split(' '); final textList = text.split(' ');
var resList = <TextSpan>[]; final resList = <TextSpan>[];
for (var e in textList) { for (var e in textList) {
if (mentions.isNotEmpty && if (mentions.isNotEmpty &&
mentions.any((element) => '@${element.name}' == e)) { mentions.any((element) => '@${element.name}' == e)) {
@@ -166,7 +166,7 @@ class MessageSearchItem extends StatelessWidget {
)); ));
} else { } else {
resList.add(TextSpan( resList.add(TextSpan(
text: e == textList.last ? '$e' : '$e ', text: e == textList.last ? e : '$e ',
style: normalTextStyle, style: normalTextStyle,
)); ));
} }
@@ -189,10 +189,7 @@ class _MessageSearchListViewState extends State<MessageSearchListView> {
}, },
); );
}, },
childBuilder: widget.childBuilder ?? childBuilder: widget.childBuilder ?? _buildListView,
(list) {
return _buildListView(list);
},
); );
} }
@@ -228,7 +225,7 @@ class _MessageSearchListViewState extends State<MessageSearchListView> {
.accentRed .accentRed
.withOpacity(.2), .withOpacity(.2),
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0), padding: const EdgeInsets.symmetric(vertical: 16),
child: Center( child: Center(
child: Text('Error loading messages'), child: Text('Error loading messages'),
), ),
@@ -201,8 +201,8 @@ class MessageWidget extends StatefulWidget {
this.readList, this.readList,
this.padding, this.padding,
this.textPadding = const EdgeInsets.symmetric( this.textPadding = const EdgeInsets.symmetric(
horizontal: 16.0, horizontal: 16,
vertical: 8.0, vertical: 8,
), ),
this.attachmentPadding = EdgeInsets.zero, this.attachmentPadding = EdgeInsets.zero,
this.allRead = false, this.allRead = false,
@@ -211,8 +211,7 @@ class MessageWidget extends StatefulWidget {
this.onAttachmentTap, this.onAttachmentTap,
}) : attachmentBuilders = { }) : attachmentBuilders = {
'image': (context, message, attachments) { 'image': (context, message, attachments) {
var border = RoundedRectangleBorder( final border = RoundedRectangleBorder(
side: BorderSide.none,
borderRadius: attachmentBorderRadiusGeometry ?? BorderRadius.zero, borderRadius: attachmentBorderRadiusGeometry ?? BorderRadius.zero,
); );
@@ -267,8 +266,7 @@ class MessageWidget extends StatefulWidget {
); );
}, },
'video': (context, message, attachments) { 'video': (context, message, attachments) {
var border = RoundedRectangleBorder( final border = RoundedRectangleBorder(
side: BorderSide.none,
borderRadius: attachmentBorderRadiusGeometry ?? BorderRadius.zero, borderRadius: attachmentBorderRadiusGeometry ?? BorderRadius.zero,
); );
@@ -302,7 +300,6 @@ class MessageWidget extends StatefulWidget {
}, },
'giphy': (context, message, attachments) { 'giphy': (context, message, attachments) {
final border = RoundedRectangleBorder( final border = RoundedRectangleBorder(
side: BorderSide.none,
borderRadius: attachmentBorderRadiusGeometry ?? BorderRadius.zero, borderRadius: attachmentBorderRadiusGeometry ?? BorderRadius.zero,
); );
@@ -329,7 +326,7 @@ class MessageWidget extends StatefulWidget {
); );
}, },
'file': (context, message, attachments) { 'file': (context, message, attachments) {
var border = RoundedRectangleBorder( final border = RoundedRectangleBorder(
side: attachmentBorderSide ?? side: attachmentBorderSide ??
BorderSide( BorderSide(
color: StreamChatTheme.of(context).colorTheme.greyWhisper, color: StreamChatTheme.of(context).colorTheme.greyWhisper,
@@ -426,7 +423,7 @@ class _MessageWidgetState extends State<MessageWidget>
super.build(context); super.build(context);
final avatarWidth = final avatarWidth =
widget.messageTheme.avatarTheme?.constraints.maxWidth ?? 40; widget.messageTheme.avatarTheme?.constraints.maxWidth ?? 40;
var leftPadding = final leftPadding =
widget.showUserAvatar != DisplayWidget.gone ? avatarWidth + 8.5 : 0.5; widget.showUserAvatar != DisplayWidget.gone ? avatarWidth + 8.5 : 0.5;
return Material( return Material(
@@ -460,7 +457,6 @@ class _MessageWidgetState extends State<MessageWidget>
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Row( Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end,
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: <Widget>[ children: <Widget>[
@@ -481,8 +477,8 @@ class _MessageWidgetState extends State<MessageWidget>
BoxConstraints(maxWidth: 22 * 6.0), BoxConstraints(maxWidth: 22 * 6.0),
child: _buildReactionIndicator(context), child: _buildReactionIndicator(context),
), ),
portalAnchor: Alignment(-1.0, -1.0), portalAnchor: Alignment(-1, -1),
childAnchor: Alignment(1, -1.0), childAnchor: Alignment(1, -1),
child: Stack( child: Stack(
clipBehavior: Clip.none, clipBehavior: Clip.none,
children: [ children: [
@@ -526,7 +522,7 @@ class _MessageWidgetState extends State<MessageWidget>
) )
: Card( : Card(
clipBehavior: Clip.antiAlias, clipBehavior: Clip.antiAlias,
elevation: 0.0, elevation: 0,
margin: EdgeInsets.symmetric( margin: EdgeInsets.symmetric(
horizontal: (isFailedState horizontal: (isFailedState
? 15.0 ? 15.0
@@ -650,9 +646,9 @@ class _MessageWidgetState extends State<MessageWidget>
children: [ children: [
StreamSvgIcon.eye( StreamSvgIcon.eye(
color: StreamChatTheme.of(context).colorTheme.grey, color: StreamChatTheme.of(context).colorTheme.grey,
size: 16.0, size: 16,
), ),
SizedBox(width: 8.0), SizedBox(width: 8),
Text( Text(
'Only visible to you', 'Only visible to you',
style: StreamChatTheme.of(context) style: StreamChatTheme.of(context)
@@ -665,7 +661,7 @@ class _MessageWidgetState extends State<MessageWidget>
); );
} }
var children = <Widget>[]; final children = <Widget>[];
final threadParticipants = widget.message.threadParticipants?.take(2); final threadParticipants = widget.message.threadParticipants?.take(2);
final showThreadParticipants = threadParticipants?.isNotEmpty == true; final showThreadParticipants = threadParticipants?.isNotEmpty == true;
@@ -757,18 +753,18 @@ class _MessageWidgetState extends State<MessageWidget>
return mappedChild; return mappedChild;
}, },
), ),
].insertBetween(const SizedBox(width: 8.0)), ].insertBetween(const SizedBox(width: 8)),
); );
} }
Widget _buildUrlAttachment() { Widget _buildUrlAttachment() {
var urlAttachment = widget.message.attachments final urlAttachment = widget.message.attachments
.firstWhere((element) => element.ogScrapeUrl != null); .firstWhere((element) => element.ogScrapeUrl != null);
var host = Uri.parse(urlAttachment.ogScrapeUrl!).host; final host = Uri.parse(urlAttachment.ogScrapeUrl!).host;
var splitList = host.split('.'); final splitList = host.split('.');
var hostName = splitList.length == 3 ? splitList[1] : splitList[0]; final hostName = splitList.length == 3 ? splitList[1] : splitList[0];
var hostDisplayName = urlAttachment.authorName?.capitalize() ?? final hostDisplayName = urlAttachment.authorName?.capitalize() ??
getWebsiteName(hostName.toLowerCase()) ?? getWebsiteName(hostName.toLowerCase()) ??
hostName.capitalize(); hostName.capitalize();
@@ -11,7 +11,7 @@ class OptionListTile extends StatelessWidget {
final Color? separatorColor; final Color? separatorColor;
final TextStyle? titleTextStyle; final TextStyle? titleTextStyle;
OptionListTile({ const OptionListTile({
this.title, this.title,
this.leading, this.leading,
this.trailing, this.trailing,
@@ -29,12 +29,12 @@ class OptionListTile extends StatelessWidget {
Container( Container(
color: separatorColor ?? color: separatorColor ??
StreamChatTheme.of(context).colorTheme.greyGainsboro, StreamChatTheme.of(context).colorTheme.greyGainsboro,
height: 1.0, height: 1,
), ),
Material( Material(
color: tileColor ?? StreamChatTheme.of(context).colorTheme.white, color: tileColor ?? StreamChatTheme.of(context).colorTheme.white,
child: Container( child: Container(
height: 63.0, height: 63,
child: InkWell( child: InkWell(
onTap: onTap, onTap: onTap,
child: Row( child: Row(
@@ -42,7 +42,7 @@ class OptionListTile extends StatelessWidget {
if (leading != null) Center(child: leading), if (leading != null) Center(child: leading),
if (leading == null) if (leading == null)
SizedBox( SizedBox(
width: 16.0, width: 16,
), ),
Expanded( Expanded(
flex: 4, flex: 4,
@@ -62,7 +62,7 @@ class OptionListTile extends StatelessWidget {
Expanded( Expanded(
flex: 2, flex: 2,
child: Padding( child: Padding(
padding: const EdgeInsets.only(right: 16.0), padding: const EdgeInsets.only(right: 16),
child: Align( child: Align(
alignment: Alignment.centerRight, alignment: Alignment.centerRight,
child: trailing ?? Container(), child: trailing ?? Container(),
@@ -87,7 +87,7 @@ class QuotedMessageWidget extends StatelessWidget {
final GestureTapCallback? onTap; final GestureTapCallback? onTap;
/// ///
QuotedMessageWidget({ const QuotedMessageWidget({
Key? key, Key? key,
required this.message, required this.message,
required this.messageTheme, required this.messageTheme,
@@ -237,7 +237,7 @@ class QuotedMessageWidget extends StatelessWidget {
ShapeBorder _getDefaultShape(BuildContext context) { ShapeBorder _getDefaultShape(BuildContext context) {
return RoundedRectangleBorder( return RoundedRectangleBorder(
side: BorderSide(width: 0.0, color: Colors.transparent), side: BorderSide(width: 0, color: Colors.transparent),
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
); );
} }
@@ -40,7 +40,6 @@ class ReactionBubble extends StatelessWidget {
alignment: Alignment.center, alignment: Alignment.center,
child: Stack( child: Stack(
alignment: Alignment.center, alignment: Alignment.center,
fit: StackFit.loose,
children: [ children: [
Transform.translate( Transform.translate(
offset: Offset(reverse ? offset : -offset, 0), offset: Offset(reverse ? offset : -offset, 0),
@@ -115,7 +114,7 @@ class ReactionBubble extends StatelessWidget {
return Padding( return Padding(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
horizontal: 4.0, horizontal: 4,
), ),
child: reactionIcon != null child: reactionIcon != null
? StreamSvgIcon( ? StreamSvgIcon(
@@ -239,9 +238,9 @@ class ReactionBubblePainter extends CustomPainter {
..strokeWidth = 1 ..strokeWidth = 1
..style = PaintingStyle.stroke; ..style = PaintingStyle.stroke;
final dy = -2.2; const dy = -2.2;
final startAngle = 1.1; const startAngle = 1.1;
final sweepAngle = 1.2; const sweepAngle = 1.2;
final path = Path(); final path = Path();
path.addArc( path.addArc(
Rect.fromCircle( Rect.fromCircle(
@@ -259,9 +258,9 @@ class ReactionBubblePainter extends CustomPainter {
..color = color ..color = color
..strokeWidth = 1; ..strokeWidth = 1;
final dy = -2.2; const dy = -2.2;
final startAngle = 1; const startAngle = 1;
final sweepAngle = 1.3; const sweepAngle = 1.3;
final path = Path(); final path = Path();
path.addArc( path.addArc(
Rect.fromCircle( Rect.fromCircle(
@@ -280,9 +279,9 @@ class ReactionBubblePainter extends CustomPainter {
..strokeWidth = 1 ..strokeWidth = 1
..style = PaintingStyle.fill; ..style = PaintingStyle.fill;
final dy = -2.2; const dy = -2.2;
final startAngle = 1.1; const startAngle = 1.1;
final sweepAngle = 1.2; const sweepAngle = 1.2;
final path = Path(); final path = Path();
path.addArc( path.addArc(
Rect.fromCircle( Rect.fromCircle(
@@ -49,7 +49,7 @@ class _ReactionPickerState extends State<ReactionPicker>
} }
return TweenAnimationBuilder<double>( return TweenAnimationBuilder<double>(
tween: Tween(begin: 0.0, end: 1.0), tween: Tween(begin: 0, end: 1),
curve: Curves.easeInOutBack, curve: Curves.easeInOutBack,
duration: Duration(milliseconds: 500), duration: Duration(milliseconds: 500),
builder: (context, val, wid) { builder: (context, val, wid) {
@@ -61,8 +61,8 @@ class _ReactionPickerState extends State<ReactionPicker>
clipBehavior: Clip.hardEdge, clipBehavior: Clip.hardEdge,
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
horizontal: 16.0, horizontal: 16,
vertical: 8.0, vertical: 8,
), ),
child: Row( child: Row(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@@ -74,7 +74,7 @@ class _ReactionPickerState extends State<ReactionPicker>
?.indexWhere((reaction) => ?.indexWhere((reaction) =>
reaction.type == reactionIcon.type) ?? reaction.type == reactionIcon.type) ??
-1; -1;
var index = reactionIcons.indexOf(reactionIcon); final index = reactionIcons.indexOf(reactionIcon);
return ConstrainedBox( return ConstrainedBox(
constraints: BoxConstraints.tightFor( constraints: BoxConstraints.tightFor(
@@ -83,8 +83,6 @@ class _ReactionPickerState extends State<ReactionPicker>
), ),
child: RawMaterialButton( child: RawMaterialButton(
elevation: 0, elevation: 0,
padding: const EdgeInsets.all(0),
clipBehavior: Clip.none,
shape: ContinuousRectangleBorder( shape: ContinuousRectangleBorder(
borderRadius: BorderRadius.circular(16), borderRadius: BorderRadius.circular(16),
), ),
@@ -110,7 +108,6 @@ class _ReactionPickerState extends State<ReactionPicker>
animation: animations[index], animation: animations[index],
builder: (context, val) { builder: (context, val) {
return Transform.scale( return Transform.scale(
alignment: Alignment.center,
scale: animations[index].value, scale: animations[index].value,
child: StreamSvgIcon( child: StreamSvgIcon(
assetName: reactionIcon.assetName, assetName: reactionIcon.assetName,
@@ -43,7 +43,7 @@ class StreamChat extends StatefulWidget {
/// upon the [Event.type] /// upon the [Event.type]
final EventHandler? onBackgroundEventReceived; final EventHandler? onBackgroundEventReceived;
StreamChat({ const StreamChat({
Key? key, Key? key,
required this.client, required this.client,
required this.child, required this.child,
@@ -13,7 +13,7 @@ import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
class StreamChatTheme extends InheritedWidget { class StreamChatTheme extends InheritedWidget {
final StreamChatThemeData data; final StreamChatThemeData data;
StreamChatTheme({ const StreamChatTheme({
Key? key, Key? key,
required this.data, required this.data,
required Widget child, required Widget child,
@@ -237,7 +237,7 @@ class StreamChatThemeData {
lastMessageAt: textTheme.footnote.copyWith( lastMessageAt: textTheme.footnote.copyWith(
color: colorTheme.black.withOpacity(.5), color: colorTheme.black.withOpacity(.5),
), ),
indicatorIconSize: 16.0), indicatorIconSize: 16),
channelListHeaderTheme: ChannelListHeaderTheme( channelListHeaderTheme: ChannelListHeaderTheme(
avatarTheme: AvatarTheme( avatarTheme: AvatarTheme(
borderRadius: BorderRadius.circular(20), borderRadius: BorderRadius.circular(20),
@@ -543,17 +543,13 @@ class ColorTheme {
stops: [0, 1], stops: [0, 1],
), ),
this.borderTop = const Effect( this.borderTop = const Effect(
sigmaX: 0, sigmaX: 0, sigmaY: -1, color: Color(0xff000000), blur: 0, alpha: 0.08),
sigmaY: -1,
color: Color(0xff000000),
blur: 0.0,
alpha: 0.08),
this.borderBottom = const Effect( this.borderBottom = const Effect(
sigmaX: 0, sigmaY: 1, color: Color(0xff000000), blur: 0.0, alpha: 0.08), sigmaX: 0, sigmaY: 1, color: Color(0xff000000), blur: 0, alpha: 0.08),
this.shadowIconButton = const Effect( this.shadowIconButton = const Effect(
sigmaX: 0, sigmaY: 2, color: Color(0xff000000), alpha: 0.5, blur: 4.0), sigmaX: 0, sigmaY: 2, color: Color(0xff000000), alpha: 0.5, blur: 4),
this.modalShadow = const Effect( this.modalShadow = const Effect(
sigmaX: 0, sigmaY: 0, color: Color(0xff000000), alpha: 1, blur: 8.0), sigmaX: 0, sigmaY: 0, color: Color(0xff000000), alpha: 1, blur: 8),
}) : brightness = Brightness.light; }) : brightness = Brightness.light;
ColorTheme.dark({ ColorTheme.dark({
@@ -572,28 +568,28 @@ class ColorTheme {
sigmaX: 0, sigmaX: 0,
sigmaY: -1, sigmaY: -1,
color: Color(0xff141924), color: Color(0xff141924),
blur: 0.0, blur: 0,
), ),
this.borderBottom = const Effect( this.borderBottom = const Effect(
sigmaX: 0, sigmaX: 0,
sigmaY: 1, sigmaY: 1,
color: Color(0xff141924), color: Color(0xff141924),
blur: 0.0, blur: 0,
alpha: 1.0, alpha: 1,
), ),
this.shadowIconButton = const Effect( this.shadowIconButton = const Effect(
sigmaX: 0, sigmaX: 0,
sigmaY: 2, sigmaY: 2,
color: Color(0xff000000), color: Color(0xff000000),
alpha: 0.5, alpha: 0.5,
blur: 4.0, blur: 4,
), ),
this.modalShadow = const Effect( this.modalShadow = const Effect(
sigmaX: 0, sigmaX: 0,
sigmaY: 0, sigmaY: 0,
color: Color(0xff000000), color: Color(0xff000000),
alpha: 1, alpha: 1,
blur: 8.0, blur: 8,
), ),
this.highlight = const Color(0xff302d22), this.highlight = const Color(0xff302d22),
this.overlay = const Color.fromRGBO(0, 0, 0, 0.4), this.overlay = const Color.fromRGBO(0, 0, 0, 0.4),
@@ -13,7 +13,7 @@ class StreamNeumorphicButton extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return Container(
margin: EdgeInsets.all(8.0), margin: EdgeInsets.all(8),
height: 40, height: 40,
width: 40, width: 40,
decoration: BoxDecoration( decoration: BoxDecoration(
@@ -22,15 +22,12 @@ class StreamNeumorphicButton extends StatelessWidget {
boxShadow: [ boxShadow: [
BoxShadow( BoxShadow(
color: Colors.grey.shade700, color: Colors.grey.shade700,
offset: Offset(0, 1.0), offset: Offset(0, 1),
blurRadius: 0.5, blurRadius: 0.5,
spreadRadius: 0,
), ),
BoxShadow( BoxShadow(
color: Colors.white, color: Colors.white,
offset: Offset.zero,
blurRadius: 0.5, blurRadius: 0.5,
spreadRadius: 0,
), ),
], ],
), ),
@@ -25,7 +25,6 @@ class StreamSvgIcon extends StatelessWidget {
width: width, width: width,
height: height, height: height,
color: color, color: color,
alignment: Alignment.center,
); );
} }
@@ -28,7 +28,7 @@ class Swipeable extends StatefulWidget {
} }
class _SwipeableState extends State<Swipeable> with TickerProviderStateMixin { class _SwipeableState extends State<Swipeable> with TickerProviderStateMixin {
double _dragExtent = 0.0; double _dragExtent = 0;
late AnimationController _moveController; late AnimationController _moveController;
late AnimationController _iconMoveController; late AnimationController _iconMoveController;
late Animation<Offset> _moveAnimation; late Animation<Offset> _moveAnimation;
@@ -45,15 +45,15 @@ class _SwipeableState extends State<Swipeable> with TickerProviderStateMixin {
AnimationController(duration: _animationDuration, vsync: this); AnimationController(duration: _animationDuration, vsync: this);
_iconMoveController = _iconMoveController =
AnimationController(duration: _animationDuration, vsync: this); AnimationController(duration: _animationDuration, vsync: this);
_moveAnimation = Tween<Offset>(begin: Offset.zero, end: Offset(1.0, 0.0)) _moveAnimation = Tween<Offset>(begin: Offset.zero, end: Offset(1, 0))
.animate(_moveController); .animate(_moveController);
_iconTransitionAnimation = _iconTransitionAnimation =
Tween<Offset>(begin: Offset(-0.1, 0.0), end: Offset(0.4, 0.0)) Tween<Offset>(begin: Offset(-0.1, 0), end: Offset(0.4, 0))
.animate(_moveController); .animate(_moveController);
_iconFadeAnimation = _iconFadeAnimation =
Tween<double>(begin: 0.7, end: 1.0).animate(_iconMoveController); Tween<double>(begin: 0.7, end: 1).animate(_iconMoveController);
final controllerValue = 0.0; const controllerValue = 0.0;
_moveController.animateTo(controllerValue); _moveController.animateTo(controllerValue);
_iconMoveController.animateTo(controllerValue); _iconMoveController.animateTo(controllerValue);
} }
@@ -77,19 +77,19 @@ class _SwipeableState extends State<Swipeable> with TickerProviderStateMixin {
if (_dragExtent.isNegative) return; if (_dragExtent.isNegative) return;
var movePastThresholdPixels = widget.threshold; final movePastThresholdPixels = widget.threshold;
var newPos = _dragExtent.abs() / context.size!.width; var newPos = _dragExtent.abs() / context.size!.width;
if (_dragExtent.abs() > movePastThresholdPixels) { if (_dragExtent.abs() > movePastThresholdPixels) {
// how many "thresholds" past the threshold we are. 1 = the threshold 2 // how many "thresholds" past the threshold we are. 1 = the threshold 2
// = two thresholds. // = two thresholds.
var n = _dragExtent.abs() / movePastThresholdPixels; final n = _dragExtent.abs() / movePastThresholdPixels;
// Take the number of thresholds past the threshold, and reduce this // Take the number of thresholds past the threshold, and reduce this
// number // number
var reducedThreshold = math.pow(n, 0.3); final reducedThreshold = math.pow(n, 0.3);
var adjustedPixelPos = movePastThresholdPixels * reducedThreshold; final adjustedPixelPos = movePastThresholdPixels * reducedThreshold;
newPos = adjustedPixelPos / context.size!.width; newPos = adjustedPixelPos / context.size!.width;
if (_dragExtent > 0 && !_pastThreshold) { if (_dragExtent > 0 && !_pastThreshold) {
@@ -111,8 +111,8 @@ class _SwipeableState extends State<Swipeable> with TickerProviderStateMixin {
} }
void _handleDragEnd(DragEndDetails details) { void _handleDragEnd(DragEndDetails details) {
_moveController.animateTo(0.0, duration: _animationDuration); _moveController.animateTo(0, duration: _animationDuration);
_iconMoveController.animateTo(0.0, duration: _animationDuration); _iconMoveController.animateTo(0, duration: _animationDuration);
_dragExtent = 0.0; _dragExtent = 0.0;
if (_pastThreshold && widget.onSwipeEnd != null) { if (_pastThreshold && widget.onSwipeEnd != null) {
widget.onSwipeEnd!(); widget.onSwipeEnd!();
@@ -118,7 +118,6 @@ class ThreadHeader extends StatelessWidget implements PreferredSizeWidget {
child: Container( child: Container(
height: preferredSize.height, height: preferredSize.height,
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
title ?? title ??
@@ -133,7 +132,6 @@ class ThreadHeader extends StatelessWidget implements PreferredSizeWidget {
subtitle ?? subtitle ??
Row( Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Text( Text(
@@ -33,8 +33,8 @@ class UnreadIndicator extends StatelessWidget {
.unreadCounterColor, .unreadCounterColor,
child: Padding( child: Padding(
padding: const EdgeInsets.only( padding: const EdgeInsets.only(
left: 5.0, left: 5,
right: 5.0, right: 5,
top: 2, top: 2,
bottom: 1, bottom: 1,
), ),
@@ -10,7 +10,7 @@ class UploadProgressIndicator extends StatelessWidget {
final bool showBackground; final bool showBackground;
final TextStyle? textStyle; final TextStyle? textStyle;
UploadProgressIndicator({ const UploadProgressIndicator({
Key? key, Key? key,
required this.uploaded, required this.uploaded,
required this.total, required this.total,
@@ -8,12 +8,12 @@ class UrlAttachment extends StatelessWidget {
final String hostDisplayName; final String hostDisplayName;
final EdgeInsets textPadding; final EdgeInsets textPadding;
UrlAttachment({ const UrlAttachment({
required this.urlAttachment, required this.urlAttachment,
required this.hostDisplayName, required this.hostDisplayName,
this.textPadding = const EdgeInsets.symmetric( this.textPadding = const EdgeInsets.symmetric(
horizontal: 16.0, horizontal: 16,
vertical: 8.0, vertical: 8,
), ),
}); });
@@ -32,9 +32,9 @@ class UrlAttachment extends StatelessWidget {
if (urlAttachment.imageUrl != null) if (urlAttachment.imageUrl != null)
Container( Container(
clipBehavior: Clip.antiAliasWithSaveLayer, clipBehavior: Clip.antiAliasWithSaveLayer,
margin: EdgeInsets.symmetric(horizontal: 8.0), margin: EdgeInsets.symmetric(horizontal: 8),
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8.0), borderRadius: BorderRadius.circular(8),
), ),
child: Stack( child: Stack(
children: [ children: [
@@ -44,20 +44,20 @@ class UrlAttachment extends StatelessWidget {
fit: BoxFit.cover, fit: BoxFit.cover,
), ),
Positioned( Positioned(
left: 0.0, left: 0,
bottom: -1, bottom: -1,
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.only( borderRadius: BorderRadius.only(
topRight: Radius.circular(16.0), topRight: Radius.circular(16),
), ),
color: StreamChatTheme.of(context).colorTheme.blueAlice, color: StreamChatTheme.of(context).colorTheme.blueAlice,
), ),
child: Padding( child: Padding(
padding: const EdgeInsets.only( padding: const EdgeInsets.only(
top: 8.0, top: 8,
left: 8.0, left: 8,
right: 8.0, right: 8,
), ),
child: Text( child: Text(
hostDisplayName, hostDisplayName,
@@ -42,7 +42,6 @@ class UserAvatar extends StatelessWidget {
Widget avatar = FittedBox( Widget avatar = FittedBox(
fit: BoxFit.cover, fit: BoxFit.cover,
child: ClipRRect( child: ClipRRect(
clipBehavior: Clip.antiAlias,
borderRadius: borderRadius ?? borderRadius: borderRadius ??
streamChatTheme.ownMessageTheme.avatarTheme?.borderRadius, streamChatTheme.ownMessageTheme.avatarTheme?.borderRadius,
child: Container( child: Container(
@@ -97,7 +96,7 @@ class UserAvatar extends StatelessWidget {
type: MaterialType.circle, type: MaterialType.circle,
color: streamChatTheme.colorTheme.white, color: streamChatTheme.colorTheme.white,
child: Container( child: Container(
margin: const EdgeInsets.all(2.0), margin: const EdgeInsets.all(2),
constraints: onlineIndicatorConstraints ?? constraints: onlineIndicatorConstraints ??
BoxConstraints.tightFor( BoxConstraints.tightFor(
width: 8, width: 8,
@@ -61,7 +61,6 @@ class UserItem extends StatelessWidget {
}, },
leading: UserAvatar( leading: UserAvatar(
user: user, user: user,
showOnlineStatus: true,
onTap: (user) { onTap: (user) {
if (onImageTap != null) { if (onImageTap != null) {
onImageTap!(user); onImageTap!(user);
@@ -151,7 +151,7 @@ class _UserListViewState extends State<UserListView>
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var child = UserListCore( final child = UserListCore(
errorBuilder: widget.errorBuilder as Widget Function(Object)? ?? errorBuilder: widget.errorBuilder as Widget Function(Object)? ??
(err) { (err) {
return _buildError(err as Error); return _buildError(err as Error);
@@ -225,7 +225,7 @@ class _UserListViewState extends State<UserListView>
WidgetSpan( WidgetSpan(
child: Padding( child: Padding(
padding: const EdgeInsets.only( padding: const EdgeInsets.only(
right: 2.0, right: 2,
), ),
child: Icon(Icons.error_outline), child: Icon(Icons.error_outline),
), ),
@@ -237,7 +237,7 @@ class _UserListViewState extends State<UserListView>
), ),
Padding( Padding(
padding: const EdgeInsets.only( padding: const EdgeInsets.only(
top: 16.0, top: 16,
), ),
child: Text(message), child: Text(message),
), ),
@@ -313,7 +313,7 @@ class _UserListViewState extends State<UserListView>
color: color:
StreamChatTheme.of(context).colorTheme.black.withOpacity(0.05), StreamChatTheme.of(context).colorTheme.black.withOpacity(0.05),
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 6), padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 6),
child: Text( child: Text(
header, header,
style: TextStyle( style: TextStyle(
@@ -360,7 +360,6 @@ class _UserListViewState extends State<UserListView>
? widget.userItemBuilder!(context, user, selected) ? widget.userItemBuilder!(context, user, selected)
: Column( : Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
UserAvatar( UserAvatar(
user: user, user: user,
@@ -414,7 +413,7 @@ class _UserListViewState extends State<UserListView>
.accentRed .accentRed
.withOpacity(.2), .withOpacity(.2),
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0), padding: const EdgeInsets.symmetric(vertical: 16),
child: Center( child: Center(
child: Text('Error loading users'), child: Text('Error loading users'),
), ),
@@ -23,7 +23,7 @@ class UserReactionDisplay extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: reactionToEmoji.keys.map((reactionType) { children: reactionToEmoji.keys.map((reactionType) {
var firstUserReaction = message.latestReactions! final firstUserReaction = message.latestReactions!
.firstWhere((element) => element.type == reactionType, .firstWhere((element) => element.type == reactionType,
orElse: () { orElse: () {
return null; return null;
+18 -18
View File
@@ -33,8 +33,8 @@ Future<bool?> showConfirmationDialog(
context: context, context: context,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only( borderRadius: BorderRadius.only(
topLeft: Radius.circular(16.0), topLeft: Radius.circular(16),
topRight: Radius.circular(16.0), topRight: Radius.circular(16),
)), )),
builder: (context) { builder: (context) {
final effect = StreamChatTheme.of(context).colorTheme.borderTop; final effect = StreamChatTheme.of(context).colorTheme.borderTop;
@@ -42,20 +42,20 @@ Future<bool?> showConfirmationDialog(
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
SizedBox(height: 26.0), SizedBox(height: 26),
if (icon != null) icon, if (icon != null) icon,
SizedBox(height: 26.0), SizedBox(height: 26),
Text( Text(
title, title,
style: StreamChatTheme.of(context).textTheme.headlineBold, style: StreamChatTheme.of(context).textTheme.headlineBold,
), ),
SizedBox(height: 7.0), SizedBox(height: 7),
if (question != null) if (question != null)
Text( Text(
question, question,
textAlign: TextAlign.center, textAlign: TextAlign.center,
), ),
SizedBox(height: 36.0), SizedBox(height: 36),
Container( Container(
color: effect.color!.withOpacity(effect.alpha ?? 1), color: effect.color!.withOpacity(effect.alpha ?? 1),
height: 1, height: 1,
@@ -126,8 +126,8 @@ Future<bool?> showInfoDialog(
context: context, context: context,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only( borderRadius: BorderRadius.only(
topLeft: Radius.circular(16.0), topLeft: Radius.circular(16),
topRight: Radius.circular(16.0), topRight: Radius.circular(16),
)), )),
builder: (context) { builder: (context) {
return SafeArea( return SafeArea(
@@ -135,11 +135,11 @@ Future<bool?> showInfoDialog(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
SizedBox( SizedBox(
height: 26.0, height: 26,
), ),
if (icon != null) icon, if (icon != null) icon,
SizedBox( SizedBox(
height: 26.0, height: 26,
), ),
Text( Text(
title, title,
@@ -147,16 +147,16 @@ Future<bool?> showInfoDialog(
StreamChatTheme.of(context).textTheme.headlineBold, StreamChatTheme.of(context).textTheme.headlineBold,
), ),
SizedBox( SizedBox(
height: 7.0, height: 7,
), ),
if (details != null) Text(details), if (details != null) Text(details),
SizedBox( SizedBox(
height: 36.0, height: 36,
), ),
Container( Container(
color: theme?.colorTheme.black.withOpacity(.08) ?? color: theme?.colorTheme.black.withOpacity(.08) ??
StreamChatTheme.of(context).colorTheme.black.withOpacity(.08), StreamChatTheme.of(context).colorTheme.black.withOpacity(.08),
height: 1.0, height: 1,
), ),
Center( Center(
child: TextButton( child: TextButton(
@@ -236,7 +236,7 @@ String fileSize(dynamic size, [int round = 2]) {
* the optional parameter [round] specifies the number * the optional parameter [round] specifies the number
* of digits after comma/point (default is 2) * of digits after comma/point (default is 2)
*/ */
final divider = 1024; const divider = 1024;
int _size; int _size;
try { try {
_size = int.parse(size.toString()); _size = int.parse(size.toString());
@@ -274,21 +274,21 @@ String fileSize(dynamic size, [int round = 2]) {
if (_size < divider * divider * divider * divider * divider && if (_size < divider * divider * divider * divider * divider &&
_size % divider == 0) { _size % divider == 0) {
num r = _size / divider / divider / divider / divider; final num r = _size / divider / divider / divider / divider;
return '${r.toStringAsFixed(0)} TB'; return '${r.toStringAsFixed(0)} TB';
} }
if (_size < divider * divider * divider * divider * divider) { if (_size < divider * divider * divider * divider * divider) {
num r = _size / divider / divider / divider / divider; final num r = _size / divider / divider / divider / divider;
return '${r.toStringAsFixed(round)} TB'; return '${r.toStringAsFixed(round)} TB';
} }
if (_size < divider * divider * divider * divider * divider * divider && if (_size < divider * divider * divider * divider * divider * divider &&
_size % divider == 0) { _size % divider == 0) {
num r = _size / divider / divider / divider / divider / divider; final num r = _size / divider / divider / divider / divider / divider;
return '${r.toStringAsFixed(0)} PB'; return '${r.toStringAsFixed(0)} PB';
} else { } else {
num r = _size / divider / divider / divider / divider / divider; final num r = _size / divider / divider / divider / divider / divider;
return '${r.toStringAsFixed(round)} PB'; return '${r.toStringAsFixed(round)} PB';
} }
} }
@@ -239,7 +239,7 @@ void main() {
), ),
); );
await tester.tap(find.text('Show in Chat')); await tester.tap(find.text('Show in Chat'));
verify(() => onShowMessage.call()).called(1); verify(onShowMessage.call).called(1);
}, },
); );
@@ -26,8 +26,8 @@ void main() {
child: Container( child: Container(
child: FileAttachment( child: FileAttachment(
size: Size( size: Size(
300.0, 300,
300.0, 300,
), ),
message: Message(), message: Message(),
attachment: Attachment( attachment: Attachment(
@@ -318,7 +318,6 @@ void main() {
body: ChannelHeader( body: ChannelHeader(
showTypingIndicator: false, showTypingIndicator: false,
showBackButton: false, showBackButton: false,
showConnectionStateTile: false,
), ),
), ),
), ),
@@ -224,7 +224,6 @@ void main() {
borderColor: Colors.red, borderColor: Colors.red,
backgroundColor: Colors.blue, backgroundColor: Colors.blue,
maskColor: Colors.green, maskColor: Colors.green,
highlightOwnReactions: true,
reverse: true, reverse: true,
flipTail: true, flipTail: true,
tailCirclesSpacing: 4, tailCirclesSpacing: 4,