From eb57c6eb9f8f03feb741f4b95699fba528c990ae Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 4 May 2021 16:11:28 +0530 Subject: [PATCH 01/31] added lint changes, started migrating --- .../stream_chat_flutter/analysis_options.yaml | 162 ++++++++--- .../lib/src/attachment/attachment.dart | 6 +- .../lib/src/attachment/attachment_title.dart | 82 +++--- .../attachment_upload_state_builder.dart | 7 +- .../lib/src/attachment/file_attachment.dart | 39 ++- .../lib/src/attachment/giphy_attachment.dart | 30 +-- .../lib/src/attachment/image_attachment.dart | 252 +++++++++--------- .../lib/src/attachment/video_attachment.dart | 171 ++++++------ .../lib/src/attachment_actions_modal.dart | 30 +-- .../lib/src/back_button.dart | 3 +- .../lib/src/channel_bottom_sheet.dart | 106 ++++---- .../lib/src/channel_header.dart | 3 +- .../lib/src/channel_image.dart | 47 ++-- .../lib/src/channel_info.dart | 125 +++++---- .../lib/src/channel_list_header.dart | 4 +- .../lib/src/channel_list_view.dart | 22 +- .../lib/src/channel_preview.dart | 8 +- .../lib/src/deleted_message.dart | 2 +- .../lib/src/full_screen_media.dart | 2 +- .../lib/src/group_image.dart | 4 +- .../lib/src/image_footer.dart | 102 ++++--- .../lib/src/image_group.dart | 12 +- .../lib/src/image_header.dart | 3 +- .../lib/src/info_tile.dart | 4 +- .../lib/src/media_list_view.dart | 10 +- .../lib/src/mention_tile.dart | 17 +- .../lib/src/message_actions_modal.dart | 63 +++-- .../lib/src/message_input.dart | 169 ++++++------ .../lib/src/message_list_view.dart | 25 +- .../lib/src/message_reactions_modal.dart | 13 +- .../lib/src/message_search_item.dart | 6 +- .../lib/src/message_search_list_view.dart | 7 +- .../lib/src/message_widget.dart | 40 ++- .../lib/src/option_list_tile.dart | 10 +- .../lib/src/quoted_message_widget.dart | 4 +- .../lib/src/reaction_bubble.dart | 21 +- .../lib/src/reaction_picker.dart | 11 +- .../lib/src/stream_chat.dart | 2 +- .../lib/src/stream_chat_theme.dart | 26 +- .../lib/src/stream_neumorphic_button.dart | 7 +- .../lib/src/stream_svg_icon.dart | 1 - .../lib/src/swipeable.dart | 22 +- .../lib/src/thread_header.dart | 2 - .../lib/src/unread_indicator.dart | 4 +- .../lib/src/upload_progress_indicator.dart | 2 +- .../lib/src/url_attachment.dart | 20 +- .../lib/src/user_avatar.dart | 3 +- .../lib/src/user_item.dart | 1 - .../lib/src/user_list_view.dart | 11 +- .../lib/src/user_reaction_display.dart | 2 +- .../stream_chat_flutter/lib/src/utils.dart | 36 +-- .../src/attachment_actions_modal_test.dart | 2 +- .../test/src/attachment_widgets_test.dart | 4 +- .../test/src/channel_header_test.dart | 1 - .../test/src/reaction_bubble_test.dart | 1 - 55 files changed, 884 insertions(+), 885 deletions(-) diff --git a/packages/stream_chat_flutter/analysis_options.yaml b/packages/stream_chat_flutter/analysis_options.yaml index 370654dc..3c78646a 100644 --- a/packages/stream_chat_flutter/analysis_options.yaml +++ b/packages/stream_chat_flutter/analysis_options.yaml @@ -13,52 +13,138 @@ linter: # these rules are documented on and in the same order as # the Dart Lint rules page to make maintenance easier # https://github.com/dart-lang/linter/blob/master/example/all.yaml - # - always_declare_return_types - # - always_specify_types - # - annotate_overrides - # - avoid_as + - always_use_package_imports - avoid_empty_else - - avoid_init_to_null - - avoid_return_types_on_setters - - avoid_web_libraries_in_flutter - - await_only_futures - - camel_case_types + - avoid_relative_lib_imports + - avoid_slow_async_io + - avoid_types_as_parameter_names - cancel_subscriptions - 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 - - empty_constructor_bodies - empty_statements - hash_and_equals - - implementation_imports - # - invariant_booleans - # - iterable_contains_unrelated_type - - library_names - # - library_prefixes - # - list_remove_unrelated_type - # - literal_only_boolean_expressions - - non_constant_identifier_names - # - 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 + - invariant_booleans + - iterable_contains_unrelated_type + - list_remove_unrelated_type + - literal_only_boolean_expressions + - no_adjacent_strings_in_list + - no_duplicate_case_values + - no_logic_in_create_state + - prefer_void_to_null - test_types_in_equals - 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 - unrelated_type_equality_checks + - omit_local_variable_types + - use_key_in_widget_constructors - 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 diff --git a/packages/stream_chat_flutter/lib/src/attachment/attachment.dart b/packages/stream_chat_flutter/lib/src/attachment/attachment.dart index 96ec9ed3..fb771317 100644 --- a/packages/stream_chat_flutter/lib/src/attachment/attachment.dart +++ b/packages/stream_chat_flutter/lib/src/attachment/attachment.dart @@ -1,7 +1,7 @@ +export 'attachment_upload_state_builder.dart'; +export 'attachment_widget.dart' + show AttachmentError, AttachmentSource, AttachmentSourceX; export 'file_attachment.dart'; export 'giphy_attachment.dart'; export 'image_attachment.dart'; export 'video_attachment.dart'; -export 'attachment_upload_state_builder.dart'; -export 'attachment_widget.dart' - show AttachmentError, AttachmentSource, AttachmentSourceX; diff --git a/packages/stream_chat_flutter/lib/src/attachment/attachment_title.dart b/packages/stream_chat_flutter/lib/src/attachment/attachment_title.dart index e2686638..ba369e5d 100644 --- a/packages/stream_chat_flutter/lib/src/attachment/attachment_title.dart +++ b/packages/stream_chat_flutter/lib/src/attachment/attachment_title.dart @@ -1,57 +1,59 @@ 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 '../stream_chat_theme.dart'; -import '../utils.dart'; - +/// Title for attachments class AttachmentTitle extends StatelessWidget { + /// Supply attachment and theme for constructing title const AttachmentTitle({ Key? key, required this.attachment, required this.messageTheme, }) : super(key: key); + /// Theme to apply to text final MessageTheme messageTheme; + + /// Attachment data to display final Attachment attachment; @override - Widget build(BuildContext context) { - return GestureDetector( - onTap: () { - if (attachment.titleLink != null) { - launchURL(context, attachment.titleLink!); - } - }, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - if (attachment.title != null) - Text( - attachment.title!, - overflow: TextOverflow.ellipsis, - style: messageTheme.messageText?.copyWith( - color: StreamChatTheme.of(context).colorTheme.accentBlue, - fontWeight: FontWeight.bold, + Widget build(BuildContext context) => GestureDetector( + onTap: () { + if (attachment.titleLink != null) { + launchURL(context, attachment.titleLink); + } + }, + child: Padding( + padding: const EdgeInsets.all(8), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + if (attachment.title != null) + Text( + attachment.title!, + overflow: TextOverflow.ellipsis, + style: messageTheme.messageText?.copyWith( + color: StreamChatTheme.of(context).colorTheme.accentBlue, + fontWeight: FontWeight.bold, + ), ), - ), - if (attachment.titleLink != null || attachment.ogScrapeUrl != null) - Text( - Uri.parse(attachment.titleLink ?? attachment.ogScrapeUrl!) - .authority - .split('.') - .reversed - .take(2) - .toList() - .reversed - .join('.'), - style: messageTheme.messageText, - ), - ], + if (attachment.titleLink != null || + attachment.ogScrapeUrl != null) + Text( + Uri.parse(attachment.titleLink ?? attachment.ogScrapeUrl!) + .authority + .split('.') + .reversed + .take(2) + .toList() + .reversed + .join('.'), + style: messageTheme.messageText, + ), + ], + ), ), - ), - ); - } + ); } diff --git a/packages/stream_chat_flutter/lib/src/attachment/attachment_upload_state_builder.dart b/packages/stream_chat_flutter/lib/src/attachment/attachment_upload_state_builder.dart index 2aa71516..e7abac74 100644 --- a/packages/stream_chat_flutter/lib/src/attachment/attachment_upload_state_builder.dart +++ b/packages/stream_chat_flutter/lib/src/attachment/attachment_upload_state_builder.dart @@ -2,9 +2,13 @@ import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/src/upload_progress_indicator.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; +/// Widget to build in progress typedef InProgressBuilder = Widget Function(BuildContext, int, int); + +/// Widget to build on failure typedef FailedBuilder = Widget Function(BuildContext, String); +/// Widget to display attachment upload state class AttachmentUploadStateBuilder extends StatelessWidget { final Message message; final Attachment attachment; @@ -87,7 +91,6 @@ class _IconButton extends StatelessWidget { elevation: 0, highlightElevation: 0, focusElevation: 0, - disabledElevation: 0, hoverElevation: 0, onPressed: onPressed, fillColor: @@ -237,7 +240,7 @@ class _SuccessState extends StatelessWidget { alignment: Alignment.topRight, child: CircleAvatar( backgroundColor: StreamChatTheme.of(context).colorTheme.overlayDark, - maxRadius: 12.0, + maxRadius: 12, child: StreamSvgIcon.check( color: StreamChatTheme.of(context).colorTheme.white, ), diff --git a/packages/stream_chat_flutter/lib/src/attachment/file_attachment.dart b/packages/stream_chat_flutter/lib/src/attachment/file_attachment.dart index 90ef92b1..0ef78d85 100644 --- a/packages/stream_chat_flutter/lib/src/attachment/file_attachment.dart +++ b/packages/stream_chat_flutter/lib/src/attachment/file_attachment.dart @@ -42,7 +42,7 @@ class FileAttachment extends AttachmentWidget { onTap: onAttachmentTap, child: Container( width: size?.width ?? 100, - height: 56.0, + height: 56, decoration: BoxDecoration( color: colorTheme.white, borderRadius: BorderRadius.circular(12), @@ -54,12 +54,12 @@ class FileAttachment extends AttachmentWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( - height: 40.0, + height: 40, width: 33.33, - margin: EdgeInsets.all(8.0), + margin: EdgeInsets.all(8), child: _getFileTypeImage(context), ), - SizedBox(width: 8.0), + SizedBox(width: 8), Expanded( child: Column( mainAxisAlignment: MainAxisAlignment.center, @@ -71,12 +71,12 @@ class FileAttachment extends AttachmentWidget { maxLines: 1, overflow: TextOverflow.ellipsis, ), - SizedBox(height: 3.0), + SizedBox(height: 3), _buildSubtitle(context), ], ), ), - SizedBox(width: 8.0), + SizedBox(width: 8), _buildTrailing(context), ], ), @@ -87,7 +87,7 @@ class FileAttachment extends AttachmentWidget { ShapeBorder _getDefaultShape(BuildContext context) { return RoundedRectangleBorder( - side: BorderSide(width: 0.0, color: Colors.transparent), + side: BorderSide(width: 0, color: Colors.transparent), borderRadius: BorderRadius.circular(8), ); } @@ -159,8 +159,8 @@ class FileAttachment extends AttachmentWidget { placeholderBuilder: (_) { return Center( child: Container( - width: 20.0, - height: 20.0, + width: 20, + height: 20, child: const CircularProgressIndicator(), ), ); @@ -171,8 +171,8 @@ class FileAttachment extends AttachmentWidget { placeholderBuilder: (_) { return Center( child: Container( - width: 20.0, - height: 20.0, + width: 20, + height: 20, child: const CircularProgressIndicator(), ), ); @@ -197,7 +197,6 @@ class FileAttachment extends AttachmentWidget { elevation: 0, highlightElevation: 0, focusElevation: 0, - disabledElevation: 0, hoverElevation: 0, onPressed: onPressed, fillColor: fillColor, @@ -214,7 +213,7 @@ class FileAttachment extends AttachmentWidget { var trailingWidget = trailing; trailingWidget ??= attachment.uploadState.when( preparing: () => Padding( - padding: const EdgeInsets.all(8.0), + padding: const EdgeInsets.all(8), child: _buildButton( icon: StreamSvgIcon.close(color: theme.colorTheme.white), fillColor: theme.colorTheme.overlayDark, @@ -222,7 +221,7 @@ class FileAttachment extends AttachmentWidget { ), ), inProgress: (_, __) => Padding( - padding: const EdgeInsets.all(8.0), + padding: const EdgeInsets.all(8), child: _buildButton( icon: StreamSvgIcon.close(color: theme.colorTheme.white), fillColor: theme.colorTheme.overlayDark, @@ -230,15 +229,15 @@ class FileAttachment extends AttachmentWidget { ), ), success: () => Padding( - padding: const EdgeInsets.all(8.0), + padding: const EdgeInsets.all(8), child: CircleAvatar( backgroundColor: theme.colorTheme.accentBlue, - maxRadius: 12.0, + maxRadius: 12, child: StreamSvgIcon.check(color: theme.colorTheme.white), ), ), failed: (_) => Padding( - padding: const EdgeInsets.all(8.0), + padding: const EdgeInsets.all(8), child: _buildButton( icon: StreamSvgIcon.retry(color: theme.colorTheme.white), fillColor: theme.colorTheme.overlayDark, @@ -251,7 +250,6 @@ class FileAttachment extends AttachmentWidget { ) ?? IconButton( icon: StreamSvgIcon.cloudDownload(color: theme.colorTheme.black), - padding: const EdgeInsets.all(8), visualDensity: VisualDensity.compact, splashRadius: 16, onPressed: () { @@ -262,7 +260,6 @@ class FileAttachment extends AttachmentWidget { if (message.status == MessageSendingStatus.sent) { trailingWidget = IconButton( icon: StreamSvgIcon.cloudDownload(color: theme.colorTheme.black), - padding: const EdgeInsets.all(8), visualDensity: VisualDensity.compact, splashRadius: 16, onPressed: () { @@ -304,9 +301,9 @@ class FileAttachment extends AttachmentWidget { progressIndicatorColor: theme.colorTheme.accentBlue, ); }, - success: () => Text('${fileSize(size, 2)}', style: textStyle), + success: () => Text(fileSize(size), style: textStyle), failed: (_) => Text('UPLOAD ERROR', style: textStyle), ) ?? - Text('${fileSize(size)}', style: textStyle); + Text(fileSize(size), style: textStyle); } } diff --git a/packages/stream_chat_flutter/lib/src/attachment/giphy_attachment.dart b/packages/stream_chat_flutter/lib/src/attachment/giphy_attachment.dart index 8e2ede71..27e98f10 100644 --- a/packages/stream_chat_flutter/lib/src/attachment/giphy_attachment.dart +++ b/packages/stream_chat_flutter/lib/src/attachment/giphy_attachment.dart @@ -52,10 +52,10 @@ class GiphyAttachment extends AttachmentWidget { clipBehavior: Clip.antiAlias, shape: RoundedRectangleBorder( borderRadius: BorderRadius.only( - topRight: Radius.circular(16.0), - bottomRight: Radius.circular(0.0), - topLeft: Radius.circular(16.0), - bottomLeft: Radius.circular(16.0), + topRight: Radius.circular(16), + bottomRight: Radius.circular(0), + topLeft: Radius.circular(16), + bottomLeft: Radius.circular(16), ), ), child: Column( @@ -63,7 +63,7 @@ class GiphyAttachment extends AttachmentWidget { crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Padding( - padding: const EdgeInsets.all(8.0), + padding: const EdgeInsets.all(8), child: Row( children: [ StreamSvgIcon.giphyIcon(), @@ -91,7 +91,7 @@ class GiphyAttachment extends AttachmentWidget { ), ), Padding( - padding: const EdgeInsets.all(2.0), + padding: const EdgeInsets.all(2), child: GestureDetector( onTap: () => onAttachmentTap ?? _onImageTap(context), child: CachedNetworkImage( @@ -123,8 +123,6 @@ class GiphyAttachment extends AttachmentWidget { height: 0.5, ), Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.center, children: [ Expanded( child: Container( @@ -156,7 +154,7 @@ class GiphyAttachment extends AttachmentWidget { .colorTheme .black .withOpacity(0.2), - height: 50.0, + height: 50, ), Expanded( child: Container( @@ -189,7 +187,7 @@ class GiphyAttachment extends AttachmentWidget { .colorTheme .black .withOpacity(0.2), - height: 50.0, + height: 50, ), Expanded( child: Container( @@ -217,11 +215,11 @@ class GiphyAttachment extends AttachmentWidget { ], ), ), - SizedBox(height: 4.0), + SizedBox(height: 4), Align( alignment: Alignment.centerRight, child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4.0), + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), child: Row( mainAxisSize: MainAxisSize.min, children: [ @@ -230,10 +228,10 @@ class GiphyAttachment extends AttachmentWidget { .colorTheme .black .withOpacity(0.5), - size: 16.0, + size: 16, ), SizedBox( - width: 8.0, + width: 8, ), Text( 'Only visible to you', @@ -332,8 +330,8 @@ class GiphyAttachment extends AttachmentWidget { ), child: Padding( padding: const EdgeInsets.symmetric( - horizontal: 8.0, - vertical: 4.0, + horizontal: 8, + vertical: 4, ), child: Row( children: [ diff --git a/packages/stream_chat_flutter/lib/src/attachment/image_attachment.dart b/packages/stream_chat_flutter/lib/src/attachment/image_attachment.dart index 1ff9b8a9..652a6826 100644 --- a/packages/stream_chat_flutter/lib/src/attachment/image_attachment.dart +++ b/packages/stream_chat_flutter/lib/src/attachment/image_attachment.dart @@ -34,137 +34,131 @@ class ImageAttachment extends AttachmentWidget { ); @override - Widget build(BuildContext context) { - return source.when( - local: () { - if (attachment.localUri == null || attachment.file?.bytes == null) { - return AttachmentError(size: size); - } - return _buildImageAttachment( - context, - Image.memory( - attachment.file!.bytes!, - height: size?.height, - width: size?.width, - fit: BoxFit.cover, - errorBuilder: (context, _, __) { - return Image.asset( + Widget build(BuildContext context) => source.when( + local: () { + if (attachment.localUri == null || attachment.file?.bytes == null) { + return AttachmentError(size: size); + } + return _buildImageAttachment( + context, + Image.memory( + attachment.file!.bytes!, + height: size?.height, + width: size?.width, + fit: BoxFit.cover, + errorBuilder: (context, _, __) => Image.asset( 'images/placeholder.png', 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: [ - 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: [ + 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, + ), + ), + ], + ), + ); } diff --git a/packages/stream_chat_flutter/lib/src/attachment/video_attachment.dart b/packages/stream_chat_flutter/lib/src/attachment/video_attachment.dart index 4ffbee1b..f74bba14 100644 --- a/packages/stream_chat_flutter/lib/src/attachment/video_attachment.dart +++ b/packages/stream_chat_flutter/lib/src/attachment/video_attachment.dart @@ -30,100 +30,97 @@ class VideoAttachment extends AttachmentWidget { ); @override - Widget build(BuildContext context) { - return source.when( - local: () { - if (attachment.file == null) { - return AttachmentError(size: size); - } - return _buildVideoAttachment( - context, - VideoThumbnailImage( - video: attachment.file!.path!, - height: size?.height, - width: size?.width, - fit: BoxFit.cover, - errorBuilder: (_, __) => AttachmentError(size: size), - ), - ); - }, - network: () { - if (attachment.assetUrl == null) { - return AttachmentError(size: size); - } - return _buildVideoAttachment( - context, - VideoThumbnailImage( - video: attachment.assetUrl!, - height: size?.height, - width: size?.width, - fit: BoxFit.cover, - errorBuilder: (_, __) => AttachmentError(size: size), - ), - ); - }, - ); - } + Widget build(BuildContext context) => source.when( + local: () { + if (attachment.file == null) { + return AttachmentError(size: size); + } + return _buildVideoAttachment( + context, + VideoThumbnailImage( + video: attachment.file!.path!, + height: size?.height, + width: size?.width, + fit: BoxFit.cover, + errorBuilder: (_, __) => AttachmentError(size: size), + ), + ); + }, + network: () { + if (attachment.assetUrl == null) { + return AttachmentError(size: size); + } + return _buildVideoAttachment( + context, + VideoThumbnailImage( + video: attachment.assetUrl!, + height: size?.height, + width: size?.width, + fit: BoxFit.cover, + errorBuilder: (_, __) => AttachmentError(size: size), + ), + ); + }, + ); - Widget _buildVideoAttachment(BuildContext context, Widget videoWidget) { - return ConstrainedBox( - constraints: BoxConstraints.loose(size ?? Size.infinite), - child: Column( - children: [ - Expanded( - child: GestureDetector( - onTap: onAttachmentTap ?? - () async { - final channel = StreamChannel.of(context).channel; - final res = await Navigator.push( - context, - MaterialPageRoute( - builder: (_) => StreamChannel( - channel: channel, - child: FullScreenMedia( - mediaAttachments: [attachment], - userName: message.user?.name, - message: message, - onShowMessage: onShowMessage, + Widget _buildVideoAttachment(BuildContext context, Widget videoWidget) => + ConstrainedBox( + constraints: BoxConstraints.loose(size ?? Size.infinite), + child: Column( + children: [ + Expanded( + child: GestureDetector( + onTap: onAttachmentTap ?? + () async { + final channel = StreamChannel.of(context).channel; + final res = await Navigator.push( + context, + MaterialPageRoute( + builder: (_) => StreamChannel( + channel: channel, + child: FullScreenMedia( + mediaAttachments: [attachment], + userName: message.user?.name, + message: message, + onShowMessage: onShowMessage, + ), ), ), - ), - ); - if (res != null) onReturnAction?.call(res); - }, - child: Stack( - children: [ - videoWidget, - Center( - child: Material( - shape: CircleBorder(), - child: Padding( - padding: const EdgeInsets.all(16.0), - child: Icon(Icons.play_arrow), + ); + if (res != null) onReturnAction?.call(res); + }, + child: Stack( + children: [ + videoWidget, + const Center( + child: Material( + shape: CircleBorder(), + child: Padding( + padding: EdgeInsets.all(16), + child: Icon(Icons.play_arrow), + ), ), ), - ), - Padding( - padding: const EdgeInsets.all(8.0), - child: AttachmentUploadStateBuilder( - message: message, - attachment: attachment, + Padding( + padding: const EdgeInsets.all(8), + child: AttachmentUploadStateBuilder( + message: message, + attachment: attachment, + ), ), - ), - ], + ], + ), ), ), - ), - if (attachment.title != null) - Material( - color: messageTheme.messageBackgroundColor, - child: AttachmentTitle( - messageTheme: messageTheme, - attachment: attachment, + if (attachment.title != null) + Material( + color: messageTheme.messageBackgroundColor, + child: AttachmentTitle( + messageTheme: messageTheme, + attachment: attachment, + ), ), - ), - ], - ), - ); - } + ], + ), + ); } diff --git a/packages/stream_chat_flutter/lib/src/attachment_actions_modal.dart b/packages/stream_chat_flutter/lib/src/attachment_actions_modal.dart index a91c18df..98aa8d48 100644 --- a/packages/stream_chat_flutter/lib/src/attachment_actions_modal.dart +++ b/packages/stream_chat_flutter/lib/src/attachment_actions_modal.dart @@ -42,27 +42,25 @@ class AttachmentActionsModal extends StatelessWidget { }); @override - Widget build(BuildContext context) { - return GestureDetector( - behavior: HitTestBehavior.translucent, - onTap: () => Navigator.maybePop(context), - child: _buildPage(context), - ); - } + Widget build(BuildContext context) => GestureDetector( + behavior: HitTestBehavior.translucent, + onTap: () => Navigator.maybePop(context), + child: _buildPage(context), + ); Widget _buildPage(context) { final theme = StreamChatTheme.of(context); return Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ - SizedBox(height: kToolbarHeight), + const SizedBox(height: kToolbarHeight), Padding( - padding: const EdgeInsets.only(right: 8.0), + padding: const EdgeInsets.only(right: 8), child: Container( width: MediaQuery.of(context).size.width * 0.5, clipBehavior: Clip.hardEdge, decoration: BoxDecoration( - borderRadius: BorderRadius.circular(16.0), + borderRadius: BorderRadius.circular(16), ), child: Container( child: Column( @@ -73,7 +71,7 @@ class AttachmentActionsModal extends StatelessWidget { context, 'Reply', StreamSvgIcon.iconCurveLineLeftUp( - size: 24.0, + size: 24, color: theme.colorTheme.grey, ), () { @@ -84,7 +82,7 @@ class AttachmentActionsModal extends StatelessWidget { context, 'Show in Chat', StreamSvgIcon.eye( - size: 24.0, + size: 24, color: theme.colorTheme.black, ), onShowMessage, @@ -93,7 +91,7 @@ class AttachmentActionsModal extends StatelessWidget { context, 'Save ${message.attachments[currentIndex].type == 'video' ? 'Video' : 'Image'}', StreamSvgIcon.iconSave( - size: 24.0, + size: 24, color: theme.colorTheme.grey, ), () { @@ -144,7 +142,7 @@ class AttachmentActionsModal extends StatelessWidget { context, 'Delete', StreamSvgIcon.delete( - size: 24.0, + size: 24, color: theme.colorTheme.accentRed, ), () { @@ -201,7 +199,7 @@ class AttachmentActionsModal extends StatelessWidget { child: InkWell( onTap: onTap, child: Padding( - padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0), + padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16), child: Row( children: [ icon, @@ -271,7 +269,7 @@ class AttachmentActionsModal extends StatelessWidget { children: [ CircularProgressIndicator( value: progress.toProgressIndicatorValue, - strokeWidth: 8.0, + strokeWidth: 8, valueColor: AlwaysStoppedAnimation( theme.colorTheme.accentBlue, ), diff --git a/packages/stream_chat_flutter/lib/src/back_button.dart b/packages/stream_chat_flutter/lib/src/back_button.dart index 3d38364a..faf08fe8 100644 --- a/packages/stream_chat_flutter/lib/src/back_button.dart +++ b/packages/stream_chat_flutter/lib/src/back_button.dart @@ -30,7 +30,6 @@ class StreamBackButton extends StatelessWidget { elevation: 0, highlightElevation: 0, focusElevation: 0, - disabledElevation: 0, hoverElevation: 0, onPressed: () { if (onPressed != null) { @@ -39,7 +38,7 @@ class StreamBackButton extends StatelessWidget { Navigator.maybePop(context); } }, - padding: const EdgeInsets.all(14.0), + padding: const EdgeInsets.all(14), child: StreamSvgIcon.left( size: 24, color: StreamChatTheme.of(context).colorTheme.black, diff --git a/packages/stream_chat_flutter/lib/src/channel_bottom_sheet.dart b/packages/stream_chat_flutter/lib/src/channel_bottom_sheet.dart index c4218632..911b306b 100644 --- a/packages/stream_chat_flutter/lib/src/channel_bottom_sheet.dart +++ b/packages/stream_chat_flutter/lib/src/channel_bottom_sheet.dart @@ -7,7 +7,7 @@ import 'option_list_tile.dart'; class ChannelBottomSheet extends StatefulWidget { final VoidCallback? onViewInfoTap; - ChannelBottomSheet({this.onViewInfoTap}); + const ChannelBottomSheet({this.onViewInfoTap}); @override _ChannelBottomSheetState createState() => _ChannelBottomSheetState(); @@ -31,29 +31,29 @@ class _ChannelBottomSheetState extends State { clipBehavior: Clip.antiAlias, shape: RoundedRectangleBorder( borderRadius: BorderRadius.only( - topLeft: Radius.circular(16.0), - topRight: Radius.circular(16.0), + topLeft: Radius.circular(16), + topRight: Radius.circular(16), ), ), child: !_showActions - ? SizedBox() + ? const SizedBox() : ListView( shrinkWrap: true, children: [ - SizedBox( - height: 24.0, + const SizedBox( + height: 24, ), Center( child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), + padding: const EdgeInsets.symmetric(horizontal: 16), child: ChannelName( textStyle: StreamChatTheme.of(context).textTheme.headlineBold, ), ), ), - SizedBox( - height: 5.0, + const SizedBox( + height: 5, ), Center( child: ChannelInfo( @@ -64,8 +64,8 @@ class _ChannelBottomSheetState extends State { .subtitle, ), ), - SizedBox( - height: 17.0, + const SizedBox( + height: 17, ), if (channel.isDistinct && channel.memberCount == 2) Column( @@ -75,16 +75,16 @@ class _ChannelBottomSheetState extends State { .firstWhere( (e) => e.user?.id != userAsMember.user?.id) .user!, - constraints: BoxConstraints( - maxHeight: 64.0, - maxWidth: 64.0, + constraints: const BoxConstraints( + maxHeight: 64, + maxWidth: 64, ), - borderRadius: BorderRadius.circular(32.0), + borderRadius: BorderRadius.circular(32), onlineIndicatorConstraints: - BoxConstraints.tight(Size(12.0, 12.0)), + BoxConstraints.tight(const Size(12, 12)), ), - SizedBox( - height: 6.0, + const SizedBox( + height: 6, ), Text( members @@ -102,50 +102,48 @@ class _ChannelBottomSheetState extends State { ), if (!(channel.isDistinct && channel.memberCount == 2)) Container( - height: 94.0, + height: 94, alignment: Alignment.center, child: ListView.builder( scrollDirection: Axis.horizontal, itemCount: members.length, shrinkWrap: true, - itemBuilder: (context, index) { - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 8.0), - child: Column( - children: [ - UserAvatar( - user: members[index].user!, - constraints: BoxConstraints.tightFor( - height: 64.0, - width: 64.0, - ), - borderRadius: BorderRadius.circular(32.0), - onlineIndicatorConstraints: - BoxConstraints.tight(Size(12.0, 12.0)), + itemBuilder: (context, index) => Padding( + padding: const EdgeInsets.symmetric(horizontal: 8), + child: Column( + children: [ + UserAvatar( + user: members[index].user!, + constraints: const BoxConstraints.tightFor( + height: 64, + width: 64, ), - SizedBox( - height: 6.0, - ), - Text( - members[index].user?.name ?? '', - style: StreamChatTheme.of(context) - .textTheme - .footnoteBold, - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - ], - ), - ); - }, + borderRadius: BorderRadius.circular(32), + onlineIndicatorConstraints: + BoxConstraints.tight(Size(12, 12)), + ), + const SizedBox( + height: 6, + ), + Text( + members[index].user?.name ?? '', + style: StreamChatTheme.of(context) + .textTheme + .footnoteBold, + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + ], + ), + ), ), ), - SizedBox( - height: 24.0, + const SizedBox( + height: 24, ), OptionListTile( leading: Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), + padding: const EdgeInsets.symmetric(horizontal: 16), child: StreamSvgIcon.user( color: StreamChatTheme.of(context).colorTheme.grey, ), @@ -156,7 +154,7 @@ class _ChannelBottomSheetState extends State { if (!channel.isDistinct) OptionListTile( leading: Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), + padding: const EdgeInsets.symmetric(horizontal: 16), child: StreamSvgIcon.userRemove( color: StreamChatTheme.of(context).colorTheme.grey, ), @@ -175,7 +173,7 @@ class _ChannelBottomSheetState extends State { if (isOwner) OptionListTile( leading: Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), + padding: const EdgeInsets.symmetric(horizontal: 16), child: StreamSvgIcon.delete( color: StreamChatTheme.of(context).colorTheme.accentRed, ), @@ -195,7 +193,7 @@ class _ChannelBottomSheetState extends State { ), OptionListTile( leading: Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), + padding: const EdgeInsets.symmetric(horizontal: 16), child: StreamSvgIcon.closeSmall( color: StreamChatTheme.of(context).colorTheme.grey, ), diff --git a/packages/stream_chat_flutter/lib/src/channel_header.dart b/packages/stream_chat_flutter/lib/src/channel_header.dart index 82270e3b..1882c5b0 100644 --- a/packages/stream_chat_flutter/lib/src/channel_header.dart +++ b/packages/stream_chat_flutter/lib/src/channel_header.dart @@ -144,7 +144,7 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget { actions: actions ?? [ Padding( - padding: const EdgeInsets.only(right: 10.0), + padding: const EdgeInsets.only(right: 10), child: Center( child: ChannelImage( borderRadius: StreamChatTheme.of(context) @@ -169,7 +169,6 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget { height: preferredSize.height, width: preferredSize.width, child: Column( - crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, children: [ title ?? diff --git a/packages/stream_chat_flutter/lib/src/channel_image.dart b/packages/stream_chat_flutter/lib/src/channel_image.dart index e24fe08b..74983505 100644 --- a/packages/stream_chat_flutter/lib/src/channel_image.dart +++ b/packages/stream_chat_flutter/lib/src/channel_image.dart @@ -158,30 +158,29 @@ class ChannelImage extends StatelessWidget { alignment: Alignment.center, fit: StackFit.expand, children: [ - image != null - ? CachedNetworkImage( - imageUrl: image, - errorWidget: (_, __, ___) { - return Center( - child: Text( - snapshot.data?.containsKey('name') ?? false - ? snapshot.data!['name'][0] - : '', - style: TextStyle( - color: StreamChatTheme.of(context) - .colorTheme - .white, - fontWeight: FontWeight.bold, - ), - ), - ); - }, - fit: BoxFit.cover, - ) - : StreamChatTheme.of(context).defaultChannelImage( - context, - channel, - ), + if (image != null) + CachedNetworkImage( + imageUrl: image, + errorWidget: (_, __, ___) { + return Center( + child: Text( + snapshot.data?.containsKey('name') ?? false + ? snapshot.data!['name'][0] + : '', + style: TextStyle( + color: StreamChatTheme.of(context).colorTheme.white, + fontWeight: FontWeight.bold, + ), + ), + ); + }, + fit: BoxFit.cover, + ) + else + StreamChatTheme.of(context).defaultChannelImage( + context, + channel, + ), Material( color: Colors.transparent, child: InkWell( diff --git a/packages/stream_chat_flutter/lib/src/channel_info.dart b/packages/stream_chat_flutter/lib/src/channel_info.dart index dfcaa749..493729b9 100644 --- a/packages/stream_chat_flutter/lib/src/channel_info.dart +++ b/packages/stream_chat_flutter/lib/src/channel_info.dart @@ -27,28 +27,26 @@ class ChannelInfo extends StatelessWidget { return StreamBuilder>( stream: channel.state?.membersStream, initialData: channel.state?.members, - builder: (context, snapshot) { - return ConnectionStatusBuilder( - statusBuilder: (context, status) { - switch (status) { - case ConnectionStatus.connected: - return _buildConnectedTitleState(context, snapshot.data); - case ConnectionStatus.connecting: - return _buildConnectingTitleState(context); - case ConnectionStatus.disconnected: - return _buildDisconnectedTitleState(context, client); - default: - return Offstage(); - } - }, - ); - }, + builder: (context, snapshot) => ConnectionStatusBuilder( + statusBuilder: (context, status) { + switch (status) { + case ConnectionStatus.connected: + return _buildConnectedTitleState(context, snapshot.data); + case ConnectionStatus.connecting: + return _buildConnectingTitleState(context); + case ConnectionStatus.disconnected: + return _buildDisconnectedTitleState(context, client); + default: + return const Offstage(); + } + }, + ), ); } Widget _buildConnectedTitleState( BuildContext context, List? members) { - var alternativeWidget; + Widget? alternativeWidget; if (channel.memberCount != null && channel.memberCount! > 2) { var text = '${channel.memberCount} Members'; @@ -82,7 +80,7 @@ class ChannelInfo extends StatelessWidget { } if (!showTypingIndicator) { - return alternativeWidget ?? Offstage(); + return alternativeWidget ?? const Offstage(); } return TypingIndicator( @@ -92,58 +90,55 @@ class ChannelInfo extends StatelessWidget { ); } - Widget _buildConnectingTitleState(BuildContext context) { - return Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - height: 16, - width: 16, - child: Center( - child: CircularProgressIndicator(), + Widget _buildConnectingTitleState(BuildContext context) => Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + height: 16, + width: 16, + child: const Center( + child: CircularProgressIndicator(), + ), ), - ), - SizedBox(width: 10), - Text( - 'Searching for Network', - style: textStyle, - ), - ], - ); - } + SizedBox(width: 10), + Text( + 'Searching for Network', + style: textStyle, + ), + ], + ); Widget _buildDisconnectedTitleState( BuildContext context, StreamChatClient client, - ) { - return Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - 'Offline...', - style: textStyle, - ), - TextButton( - style: TextButton.styleFrom( - padding: const EdgeInsets.all(0), - tapTargetSize: MaterialTapTargetSize.shrinkWrap, - visualDensity: VisualDensity( - horizontal: VisualDensity.minimumDensity, - vertical: VisualDensity.minimumDensity, + ) => + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'Offline...', + style: textStyle, + ), + TextButton( + style: TextButton.styleFrom( + padding: const EdgeInsets.all(0), + tapTargetSize: MaterialTapTargetSize.shrinkWrap, + visualDensity: const VisualDensity( + horizontal: 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, - ), - ), - ), - ], - ); - } + ], + ); } diff --git a/packages/stream_chat_flutter/lib/src/channel_list_header.dart b/packages/stream_chat_flutter/lib/src/channel_list_header.dart index f3889e22..bb103f7b 100644 --- a/packages/stream_chat_flutter/lib/src/channel_list_header.dart +++ b/packages/stream_chat_flutter/lib/src/channel_list_header.dart @@ -168,8 +168,8 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { return SvgPicture.asset( 'svgs/icon_pen_write.svg', package: 'stream_chat_flutter', - width: 24.0, - height: 24.0, + width: 24, + height: 24, color: color, ); }, diff --git a/packages/stream_chat_flutter/lib/src/channel_list_view.dart b/packages/stream_chat_flutter/lib/src/channel_list_view.dart index 6d317d97..473007db 100644 --- a/packages/stream_chat_flutter/lib/src/channel_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/channel_list_view.dart @@ -54,7 +54,7 @@ typedef ViewInfoCallback = void Function(Channel); /// Modify it to change the widget appearance. class ChannelListView extends StatefulWidget { /// Instantiate a new ChannelListView - ChannelListView({ + const ChannelListView({ Key? key, this.filter, this.options, @@ -248,7 +248,7 @@ class _ChannelListViewState extends State { mainAxisAlignment: MainAxisAlignment.center, children: [ Padding( - padding: const EdgeInsets.all(8.0), + padding: const EdgeInsets.all(8), child: StreamSvgIcon.message( size: 136, color: StreamChatTheme.of(context) @@ -257,7 +257,7 @@ class _ChannelListViewState extends State { ), ), Padding( - padding: const EdgeInsets.all(8.0), + padding: const EdgeInsets.all(8), child: Text( 'Let’s start chatting!', style: StreamChatTheme.of(context).textTheme.headline, @@ -265,7 +265,7 @@ class _ChannelListViewState extends State { ), Padding( padding: const EdgeInsets.symmetric( - vertical: 8.0, + vertical: 8, horizontal: 52, ), child: Text( @@ -340,7 +340,7 @@ class _ChannelListViewState extends State { highlightColor: StreamChatTheme.of(context).colorTheme.whiteSmoke, child: Column( children: [ - SizedBox(height: 4.0), + SizedBox(height: 4), Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ @@ -358,7 +358,7 @@ class _ChannelListViewState extends State { ], ), SizedBox( - height: 16.0, + height: 16, ), ], ), @@ -441,7 +441,7 @@ class _ChannelListViewState extends State { WidgetSpan( child: Padding( padding: const EdgeInsets.only( - right: 2.0, + right: 2, ), child: Icon(Icons.error_outline), ), @@ -477,7 +477,6 @@ class _ChannelListViewState extends State { enabled: widget.swipeToAction, actionPane: SlidableBehindActionPane(), actionExtentRatio: 0.12, - closeOnScroll: true, secondaryActions: [ IconSlideAction( color: backgroundColor, @@ -589,7 +588,6 @@ class _ChannelListViewState extends State { key: ValueKey('CHANNEL-${channel.id}'), child: Column( mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.center, children: [ ChannelImage( channel: channel, @@ -634,7 +632,7 @@ class _ChannelListViewState extends State { .accentRed .withOpacity(.2), child: Padding( - padding: const EdgeInsets.symmetric(vertical: 16.0), + padding: const EdgeInsets.symmetric(vertical: 16), child: Center( child: Text('Error loading channels'), ), @@ -644,7 +642,7 @@ class _ChannelListViewState extends State { return snapshot.data! ? Center( child: Padding( - padding: const EdgeInsets.all(16.0), + padding: const EdgeInsets.all(16), child: const CircularProgressIndicator(), ), ) @@ -653,7 +651,7 @@ class _ChannelListViewState extends State { } Widget _separatorBuilder(context, i) { - var effect = StreamChatTheme.of(context).colorTheme.borderBottom; + final effect = StreamChatTheme.of(context).colorTheme.borderBottom; return Container( height: 1, diff --git a/packages/stream_chat_flutter/lib/src/channel_preview.dart b/packages/stream_chat_flutter/lib/src/channel_preview.dart index f28e9368..9c396065 100644 --- a/packages/stream_chat_flutter/lib/src/channel_preview.dart +++ b/packages/stream_chat_flutter/lib/src/channel_preview.dart @@ -47,7 +47,7 @@ class ChannelPreview extends StatelessWidget { /// Widget rendering the sending indicator, by default it uses the [SendingIndicator] widget final Widget? sendingIndicator; - ChannelPreview({ + const ChannelPreview({ required this.channel, Key? key, this.onTap, @@ -128,7 +128,7 @@ class ChannelPreview extends StatelessWidget { if (lastMessage?.user?.id == StreamChat.of(context).user?.id) { return Padding( - padding: const EdgeInsets.only(right: 4.0), + padding: const EdgeInsets.only(right: 4), child: SendingIndicator( message: lastMessage!, size: channelPreviewTheme.indicatorIconSize, @@ -167,7 +167,7 @@ class ChannelPreview extends StatelessWidget { String stringDate; 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 >= startOfDay.millisecondsSinceEpoch) { @@ -298,7 +298,7 @@ class ChannelPreview extends StatelessWidget { )); } else { resList.add(TextSpan( - text: e == textList.last ? '$e' : '$e ', + text: e == textList.last ? e : '$e ', style: normalTextStyle, )); } diff --git a/packages/stream_chat_flutter/lib/src/deleted_message.dart b/packages/stream_chat_flutter/lib/src/deleted_message.dart index b3071904..31a9995e 100644 --- a/packages/stream_chat_flutter/lib/src/deleted_message.dart +++ b/packages/stream_chat_flutter/lib/src/deleted_message.dart @@ -53,7 +53,7 @@ class DeletedMessage extends StatelessWidget { ), child: Padding( padding: const EdgeInsets.symmetric( - vertical: 8.0, + vertical: 8, horizontal: 16, ), child: Transform( diff --git a/packages/stream_chat_flutter/lib/src/full_screen_media.dart b/packages/stream_chat_flutter/lib/src/full_screen_media.dart index f960b5ee..4b56adc5 100644 --- a/packages/stream_chat_flutter/lib/src/full_screen_media.dart +++ b/packages/stream_chat_flutter/lib/src/full_screen_media.dart @@ -150,7 +150,7 @@ class _FullScreenMediaState extends State }, child: Padding( padding: const EdgeInsets.symmetric( - vertical: 50.0, + vertical: 50, ), child: Chewie( controller: controller.chewieController!, diff --git a/packages/stream_chat_flutter/lib/src/group_image.dart b/packages/stream_chat_flutter/lib/src/group_image.dart index f39abf59..3e56eeae 100644 --- a/packages/stream_chat_flutter/lib/src/group_image.dart +++ b/packages/stream_chat_flutter/lib/src/group_image.dart @@ -113,8 +113,8 @@ class GroupImage extends StatelessWidget { child: Container( color: selectionColor ?? StreamChatTheme.of(context).colorTheme.accentBlue, - height: 64.0, - width: 64.0, + height: 64, + width: 64, child: Padding( padding: EdgeInsets.all(selectionThickness), child: avatar, diff --git a/packages/stream_chat_flutter/lib/src/image_footer.dart b/packages/stream_chat_flutter/lib/src/image_footer.dart index 27c92674..f660bad7 100644 --- a/packages/stream_chat_flutter/lib/src/image_footer.dart +++ b/packages/stream_chat_flutter/lib/src/image_footer.dart @@ -82,47 +82,45 @@ class _ImageFooterState extends State { child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - !showShareButton - ? Container( - width: 48, - ) - : IconButton( - icon: StreamSvgIcon.iconShare( - size: 24.0, - color: StreamChatTheme.of(context).colorTheme.black, - ), - onPressed: () async { - final attachment = - widget.mediaAttachments[widget.currentPage]; - final url = attachment.imageUrl ?? - attachment.assetUrl ?? - attachment.thumbUrl!; - final type = attachment.type == 'image' - ? 'jpg' - : url.split('?').first.split('.').last; - final request = - await HttpClient().getUrl(Uri.parse(url)); - final response = await request.close(); - final bytes = - await consolidateHttpClientResponseBytes(response); - final tmpPath = await getTemporaryDirectory(); - final filePath = - '${tmpPath.path}/${attachment.id}.$type'; - final file = File(filePath); - await file.writeAsBytes(bytes); - await Share.shareFiles( - [filePath], - mimeTypes: [ - 'image/$type', - ], - ); - }, - ), + if (!showShareButton) + Container( + width: 48, + ) + else + IconButton( + icon: StreamSvgIcon.iconShare( + size: 24, + color: StreamChatTheme.of(context).colorTheme.black, + ), + onPressed: () async { + final attachment = + widget.mediaAttachments[widget.currentPage]; + final url = attachment.imageUrl ?? + attachment.assetUrl ?? + attachment.thumbUrl!; + final type = attachment.type == 'image' + ? 'jpg' + : url.split('?').first.split('.').last; + final request = await HttpClient().getUrl(Uri.parse(url)); + final response = await request.close(); + final bytes = + await consolidateHttpClientResponseBytes(response); + final tmpPath = await getTemporaryDirectory(); + final filePath = '${tmpPath.path}/${attachment.id}.$type'; + final file = File(filePath); + await file.writeAsBytes(bytes); + await Share.shareFiles( + [filePath], + mimeTypes: [ + 'image/$type', + ], + ); + }, + ), InkWell( onTap: widget.onTitleTap, child: Container( child: Column( - crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.min, children: [ @@ -156,12 +154,12 @@ class _ImageFooterState extends State { isScrollControlled: true, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.only( - topLeft: Radius.circular(16.0), - topRight: Radius.circular(16.0), + topLeft: Radius.circular(16), + topRight: Radius.circular(16), ), ), builder: (context) { - final crossAxisCount = 3; + const crossAxisCount = 3; final noOfRowToShowInitially = widget.mediaAttachments.length > crossAxisCount ? 2 : 1; final size = MediaQuery.of(context).size; @@ -181,7 +179,7 @@ class _ImageFooterState extends State { children: [ Center( child: Padding( - padding: const EdgeInsets.all(16.0), + padding: const EdgeInsets.all(16), child: Text( 'Photos', style: StreamChatTheme.of(context) @@ -209,8 +207,8 @@ class _ImageFooterState extends State { padding: const EdgeInsets.all(1), gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: crossAxisCount, - mainAxisSpacing: 2.0, - crossAxisSpacing: 2.0, + mainAxisSpacing: 2, + crossAxisSpacing: 2, ), itemBuilder: (context, index) { Widget media; @@ -230,7 +228,7 @@ class _ImageFooterState extends State { media = InkWell( onTap: () => widget.mediaSelectedCallBack!(index), child: AspectRatio( - aspectRatio: 1.0, + aspectRatio: 1, child: CachedNetworkImage( imageUrl: attachment.imageUrl ?? attachment.assetUrl ?? @@ -246,7 +244,7 @@ class _ImageFooterState extends State { media, if (widget.message.user != null) Padding( - padding: EdgeInsets.all(8.0), + padding: EdgeInsets.all(8), child: Container( clipBehavior: Clip.antiAlias, decoration: BoxDecoration( @@ -254,7 +252,7 @@ class _ImageFooterState extends State { color: Colors.white.withOpacity(0.6), boxShadow: [ BoxShadow( - blurRadius: 8.0, + blurRadius: 8, color: StreamChatTheme.of(context) .colorTheme .black @@ -287,7 +285,7 @@ class _ImageFooterState extends State { /// Sends the current message Future sendMessage() async { - var text = _messageController.text.trim(); + final text = _messageController.text.trim(); final attachments = widget.message.attachments; @@ -311,10 +309,10 @@ class _ImageFooterState extends State { class IconClipper extends CustomClipper { @override Path getClip(Size size) { - var leftX = size.width / 5; - var rightX = 4 * size.width / 5; - var topY = size.height / 5; - var bottomY = 4 * size.height / 5; + final leftX = size.width / 5; + final rightX = 4 * size.width / 5; + final topY = size.height / 5; + final bottomY = 4 * size.height / 5; final path = Path(); path.moveTo(leftX, topY); @@ -322,7 +320,7 @@ class IconClipper extends CustomClipper { path.lineTo(rightX, bottomY); path.lineTo(rightX, topY); path.lineTo(leftX, topY); - path.lineTo(0.0, 0.0); + path.lineTo(0, 0); path.close(); return path; } diff --git a/packages/stream_chat_flutter/lib/src/image_group.dart b/packages/stream_chat_flutter/lib/src/image_group.dart index a08d13de..600b7867 100644 --- a/packages/stream_chat_flutter/lib/src/image_group.dart +++ b/packages/stream_chat_flutter/lib/src/image_group.dart @@ -27,22 +27,19 @@ class ImageGroup extends StatelessWidget { direction: Axis.vertical, children: [ Flexible( - flex: 1, fit: FlexFit.tight, child: Flex( crossAxisAlignment: CrossAxisAlignment.stretch, direction: Axis.horizontal, children: [ Flexible( - flex: 1, fit: FlexFit.tight, child: _buildImage(context, 0), ), Flexible( - flex: 1, fit: FlexFit.tight, child: Padding( - padding: const EdgeInsets.only(left: 2.0), + padding: const EdgeInsets.only(left: 2), child: _buildImage(context, 1), ), ), @@ -52,24 +49,21 @@ class ImageGroup extends StatelessWidget { if (images.length >= 3) Flexible( fit: FlexFit.tight, - flex: 1, child: Padding( - padding: const EdgeInsets.only(top: 2.0), + padding: const EdgeInsets.only(top: 2), child: Flex( direction: Axis.horizontal, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Flexible( fit: FlexFit.tight, - flex: 1, child: _buildImage(context, 2), ), if (images.length >= 4) Flexible( fit: FlexFit.tight, - flex: 1, child: Padding( - padding: const EdgeInsets.only(left: 2.0), + padding: const EdgeInsets.only(left: 2), child: Stack( fit: StackFit.expand, children: [ diff --git a/packages/stream_chat_flutter/lib/src/image_header.dart b/packages/stream_chat_flutter/lib/src/image_header.dart index 6837722c..18c78770 100644 --- a/packages/stream_chat_flutter/lib/src/image_header.dart +++ b/packages/stream_chat_flutter/lib/src/image_header.dart @@ -53,7 +53,7 @@ class ImageHeader extends StatelessWidget implements PreferredSizeWidget { ? IconButton( icon: StreamSvgIcon.close( color: StreamChatTheme.of(context).colorTheme.black, - size: 24.0, + size: 24, ), onPressed: onBackPressed, ) @@ -79,7 +79,6 @@ class ImageHeader extends StatelessWidget implements PreferredSizeWidget { height: preferredSize.height, width: preferredSize.width, child: Column( - crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.min, children: [ diff --git a/packages/stream_chat_flutter/lib/src/info_tile.dart b/packages/stream_chat_flutter/lib/src/info_tile.dart index deb30877..53a9755f 100644 --- a/packages/stream_chat_flutter/lib/src/info_tile.dart +++ b/packages/stream_chat_flutter/lib/src/info_tile.dart @@ -11,7 +11,7 @@ class InfoTile extends StatelessWidget { final TextStyle? textStyle; final Color? backgroundColor; - InfoTile({ + const InfoTile({ required this.message, required this.child, required this.showMessage, @@ -28,7 +28,7 @@ class InfoTile extends StatelessWidget { portalAnchor: tileAnchor ?? Alignment.topCenter, childAnchor: childAnchor ?? Alignment.bottomCenter, portal: Container( - height: 25.0, + height: 25, color: backgroundColor ?? StreamChatTheme.of(context).colorTheme.grey.withOpacity(0.9), child: Center( diff --git a/packages/stream_chat_flutter/lib/src/media_list_view.dart b/packages/stream_chat_flutter/lib/src/media_list_view.dart index 703fb092..a34dc8dd 100644 --- a/packages/stream_chat_flutter/lib/src/media_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/media_list_view.dart @@ -54,7 +54,7 @@ class _MediaListViewState extends State { ) { final media = _media.elementAt(position); return Padding( - padding: const EdgeInsets.symmetric(horizontal: 1.0, vertical: 1.0), + padding: const EdgeInsets.symmetric(horizontal: 1, vertical: 1), child: InkWell( onTap: () { if (widget.onSelect != null) { @@ -64,7 +64,7 @@ class _MediaListViewState extends State { child: Stack( children: [ AspectRatio( - aspectRatio: 1.0, + aspectRatio: 1, child: FadeInImage( fadeInDuration: Duration(milliseconds: 300), placeholder: AssetImage( @@ -144,9 +144,7 @@ class _MediaListViewState extends State { } void _getMedia() async { - final assetList = await PhotoManager.getAssetPathList( - hasAll: true, - ).then((value) { + final assetList = await PhotoManager.getAssetPathList().then((value) { if (value.isNotEmpty == true) { return value.singleWhere((element) => element.isAll); } @@ -178,7 +176,7 @@ class MediaThumbnailProvider extends ImageProvider { ImageStreamCompleter load(key, decode) { return MultiFrameImageStreamCompleter( codec: _loadAsync(key, decode), - scale: 1.0, + scale: 1, informationCollector: () sync* { yield ErrorDescription('Id: ${media.id}'); }, diff --git a/packages/stream_chat_flutter/lib/src/mention_tile.dart b/packages/stream_chat_flutter/lib/src/mention_tile.dart index 37e4e9ad..186e1f16 100644 --- a/packages/stream_chat_flutter/lib/src/mention_tile.dart +++ b/packages/stream_chat_flutter/lib/src/mention_tile.dart @@ -20,7 +20,7 @@ class MentionTile extends StatelessWidget { /// Widget at the end of tile final Widget? trailing; - MentionTile( + const MentionTile( this.member, { this.title, this.subtitle, @@ -31,12 +31,11 @@ class MentionTile extends StatelessWidget { @override Widget build(BuildContext context) { return Container( - height: 56.0, + height: 56, child: Row( - crossAxisAlignment: CrossAxisAlignment.center, children: [ SizedBox( - width: 16.0, + width: 16, ), leading ?? UserAvatar( @@ -49,7 +48,7 @@ class MentionTile extends StatelessWidget { user: member.user!, ), SizedBox( - width: 8.0, + width: 8, ), Expanded( child: Align( @@ -60,13 +59,13 @@ class MentionTile extends StatelessWidget { children: [ title ?? Text( - '${member.user!.name}', + member.user!.name, maxLines: 1, overflow: TextOverflow.ellipsis, style: StreamChatTheme.of(context).textTheme.bodyBold, ), SizedBox( - height: 2.0, + height: 2, ), subtitle ?? Text( @@ -88,8 +87,8 @@ class MentionTile extends StatelessWidget { trailing ?? Padding( padding: const EdgeInsets.only( - right: 18.0, - left: 8.0, + right: 18, + left: 8, ), child: StreamSvgIcon.mentions( color: StreamChatTheme.of(context).colorTheme.accentBlue, diff --git a/packages/stream_chat_flutter/lib/src/message_actions_modal.dart b/packages/stream_chat_flutter/lib/src/message_actions_modal.dart index b737bd09..ecff8799 100644 --- a/packages/stream_chat_flutter/lib/src/message_actions_modal.dart +++ b/packages/stream_chat_flutter/lib/src/message_actions_modal.dart @@ -119,7 +119,7 @@ class _MessageActionsModalState extends State { ), if (_showActions) TweenAnimationBuilder( - tween: Tween(begin: 0.0, end: 1.0), + tween: Tween(begin: 0, end: 1), duration: Duration(milliseconds: 300), curve: Curves.easeInOutBack, builder: (context, val, snapshot) { @@ -128,7 +128,7 @@ class _MessageActionsModalState extends State { child: Center( child: SingleChildScrollView( child: Padding( - padding: const EdgeInsets.all(8.0), + padding: const EdgeInsets.all(8), child: Column( crossAxisAlignment: widget.reverse ? CrossAxisAlignment.end @@ -146,7 +146,7 @@ class _MessageActionsModalState extends State { : (divFactor > 1.0 ? 0.0 : -(1.0 - divFactor)), - 0.0), + 0), child: ReactionPicker( message: widget.message, ), @@ -166,7 +166,6 @@ class _MessageActionsModalState extends State { messageTheme: widget.messageTheme, showReactions: false, showUsername: false, - showThreadReplyIndicator: false, showReplyMessage: false, showUserAvatar: widget.showUserAvatar, attachmentPadding: EdgeInsets.all( @@ -176,7 +175,7 @@ class _MessageActionsModalState extends State { translateUserAvatar: false, padding: const EdgeInsets.all(0), textPadding: EdgeInsets.symmetric( - vertical: 8.0, + vertical: 8, horizontal: widget.message.text!.isOnlyEmoji ? 0 : 16.0, @@ -185,7 +184,6 @@ class _MessageActionsModalState extends State { widget.showReactions && (widget.message.status == MessageSendingStatus.sent), - showInChannelIndicator: false, showSendingIndicator: false, shape: widget.messageShape, attachmentShape: widget.attachmentShape, @@ -269,7 +267,7 @@ class _MessageActionsModalState extends State { messageAction.onTap?.call(widget.message); }, child: Padding( - padding: const EdgeInsets.symmetric(vertical: 11.0, horizontal: 16.0), + padding: const EdgeInsets.symmetric(vertical: 11, horizontal: 16), child: Row( children: [ messageAction.leading ?? Offstage(), @@ -289,7 +287,7 @@ class _MessageActionsModalState extends State { title: 'Flag Message', icon: StreamSvgIcon.flag( color: StreamChatTheme.of(context).colorTheme.accentRed, - size: 24.0, + size: 24, ), question: 'Do you want to send a copy of this message to a\nmoderator for further investigation?', @@ -305,7 +303,7 @@ class _MessageActionsModalState extends State { context, icon: StreamSvgIcon.flag( color: theme.colorTheme.accentRed, - size: 24.0, + size: 24, ), details: 'The message has been reported to a moderator.', title: 'Message flagged', @@ -317,7 +315,7 @@ class _MessageActionsModalState extends State { context, icon: StreamSvgIcon.flag( color: theme.colorTheme.accentRed, - size: 24.0, + size: 24, ), details: 'The message has been reported to a moderator.', title: 'Message flagged', @@ -339,7 +337,7 @@ class _MessageActionsModalState extends State { title: 'Delete message', icon: StreamSvgIcon.flag( color: StreamChatTheme.of(context).colorTheme.accentRed, - size: 24.0, + size: 24, ), question: 'Are you sure you want to permanently delete this\nmessage?', okText: 'DELETE', @@ -365,7 +363,7 @@ class _MessageActionsModalState extends State { context, icon: StreamSvgIcon.error( color: StreamChatTheme.of(context).colorTheme.accentRed, - size: 24.0, + size: 24, ), details: 'The operation couldn\'t be completed.', title: 'Something went wrong', @@ -382,7 +380,7 @@ class _MessageActionsModalState extends State { } }, child: Padding( - padding: const EdgeInsets.symmetric(vertical: 11.0, horizontal: 16.0), + padding: const EdgeInsets.symmetric(vertical: 11, horizontal: 16), child: Row( children: [ StreamSvgIcon.reply( @@ -401,9 +399,9 @@ class _MessageActionsModalState extends State { Widget _buildFlagButton(BuildContext context) { return InkWell( - onTap: () => _showFlagDialog(), + onTap: _showFlagDialog, child: Padding( - padding: const EdgeInsets.symmetric(vertical: 11.0, horizontal: 16.0), + padding: const EdgeInsets.symmetric(vertical: 11, horizontal: 16), child: Row( children: [ StreamSvgIcon.iconFlag( @@ -424,9 +422,9 @@ class _MessageActionsModalState extends State { final isDeleteFailed = widget.message.status == MessageSendingStatus.failed_delete; return InkWell( - onTap: () => _showDeleteDialog(), + onTap: _showDeleteDialog, child: Padding( - padding: const EdgeInsets.symmetric(vertical: 11.0, horizontal: 16.0), + padding: const EdgeInsets.symmetric(vertical: 11, horizontal: 16), child: Row( children: [ StreamSvgIcon.delete( @@ -453,7 +451,7 @@ class _MessageActionsModalState extends State { Navigator.pop(context); }, child: Padding( - padding: const EdgeInsets.symmetric(vertical: 11.0, horizontal: 16.0), + padding: const EdgeInsets.symmetric(vertical: 11, horizontal: 16), child: Row( children: [ StreamSvgIcon.copy( @@ -478,7 +476,7 @@ class _MessageActionsModalState extends State { _showEditBottomSheet(context); }, child: Padding( - padding: const EdgeInsets.symmetric(vertical: 11.0, horizontal: 16.0), + padding: const EdgeInsets.symmetric(vertical: 11, horizontal: 16), child: Row( children: [ StreamSvgIcon.edit( @@ -509,7 +507,7 @@ class _MessageActionsModalState extends State { } }, child: Padding( - padding: const EdgeInsets.symmetric(vertical: 11.0, horizontal: 16.0), + padding: const EdgeInsets.symmetric(vertical: 11, horizontal: 16), child: Row( children: [ StreamSvgIcon.circleUp( @@ -555,7 +553,7 @@ class _MessageActionsModalState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Padding( - padding: const EdgeInsets.all(8.0), + padding: const EdgeInsets.all(8), child: StreamSvgIcon.edit( color: StreamChatTheme.of(context) .colorTheme @@ -574,16 +572,17 @@ class _MessageActionsModalState extends State { ], ), ), - widget.editMessageInputBuilder != null - ? widget.editMessageInputBuilder!(context, widget.message) - : MessageInput( - editMessage: widget.message, - preMessageSending: (m) { - FocusScope.of(context).unfocus(); - Navigator.pop(context); - return m; - }, - ), + if (widget.editMessageInputBuilder != null) + widget.editMessageInputBuilder!(context, widget.message) + else + MessageInput( + editMessage: widget.message, + preMessageSending: (m) { + FocusScope.of(context).unfocus(); + Navigator.pop(context); + return m; + }, + ), ], ), ); @@ -600,7 +599,7 @@ class _MessageActionsModalState extends State { } }, child: Padding( - padding: const EdgeInsets.symmetric(vertical: 11.0, horizontal: 16.0), + padding: const EdgeInsets.symmetric(vertical: 11, horizontal: 16), child: Row( children: [ StreamSvgIcon.thread( diff --git a/packages/stream_chat_flutter/lib/src/message_input.dart b/packages/stream_chat_flutter/lib/src/message_input.dart index aa14882e..4c58f312 100644 --- a/packages/stream_chat_flutter/lib/src/message_input.dart +++ b/packages/stream_chat_flutter/lib/src/message_input.dart @@ -109,7 +109,7 @@ const _kMaxAttachmentSize = 20971520; // 20MB in Bytes /// Modify it to change the widget appearance. class MessageInput extends StatefulWidget { /// Instantiate a new MessageInput - MessageInput({ + const MessageInput({ Key? key, this.onMessageSent, this.preMessageSending, @@ -306,7 +306,7 @@ class MessageInputState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Padding( - padding: const EdgeInsets.all(8.0), + padding: const EdgeInsets.all(8), child: StreamSvgIcon.reply( color: StreamChatTheme.of(context) .colorTheme @@ -326,15 +326,15 @@ class MessageInputState extends State { ), ), Padding( - padding: const EdgeInsets.symmetric(vertical: 8.0), + padding: const EdgeInsets.symmetric(vertical: 8), child: _buildTextField(context), ), if (widget.parentMessage != null && !widget.hideSendAsDm) Padding( padding: const EdgeInsets.only( - right: 12.0, - left: 12.0, - bottom: 12.0, + right: 12, + left: 12, + bottom: 12, ), child: _buildDmCheckbox(), ), @@ -356,7 +356,6 @@ class MessageInputState extends State { Flex _buildTextField(BuildContext context) { return Flex( direction: Axis.horizontal, - crossAxisAlignment: CrossAxisAlignment.center, children: [ if (!_commandEnabled && widget.actionsLocation == ActionsLocation.left) _buildExpandActionsButton(), @@ -371,7 +370,6 @@ class MessageInputState extends State { Widget _buildDmCheckbox() { return Row( - crossAxisAlignment: CrossAxisAlignment.center, children: [ Container( height: 16, @@ -407,7 +405,7 @@ class MessageInputState extends State { ? CrossFadeState.showFirst : CrossFadeState.showSecond, firstChild: StreamSvgIcon.check( - size: 16.0, + size: 16, color: StreamChatTheme.of(context).colorTheme.white, ), secondChild: SizedBox( @@ -420,7 +418,7 @@ class MessageInputState extends State { ), ), Padding( - padding: const EdgeInsets.symmetric(horizontal: 12.0), + padding: const EdgeInsets.symmetric(horizontal: 12), child: Text( 'Also send as direct message', style: StreamChatTheme.of(context).textTheme.footnote.copyWith( @@ -456,7 +454,7 @@ class MessageInputState extends State { Widget _buildExpandActionsButton() { return Padding( - padding: const EdgeInsets.symmetric(horizontal: 8.0), + padding: const EdgeInsets.symmetric(horizontal: 8), child: AnimatedCrossFade( crossFadeState: _actionsShrunk ? CrossFadeState.showFirst @@ -464,7 +462,6 @@ class MessageInputState extends State { firstChild: IconButton( onPressed: () => setState(() => _actionsShrunk = false), icon: Transform.rotate( - alignment: Alignment.center, angle: (widget.actionsLocation == ActionsLocation.right || widget.actionsLocation == ActionsLocation.rightInside) ? pi @@ -484,7 +481,6 @@ class MessageInputState extends State { ), secondChild: FittedBox( child: Row( - crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ if (!widget.disableAttachments) _buildAttachmentButton(), @@ -510,10 +506,10 @@ class MessageInputState extends State { Expanded _buildTextInput(BuildContext context) { final theme = StreamChatTheme.of(context); final margin = (widget.sendButtonLocation == SendButtonLocation.inside - ? const EdgeInsets.only(right: 8.0) + ? const EdgeInsets.only(right: 8) : EdgeInsets.zero) + (widget.actionsLocation != ActionsLocation.left - ? const EdgeInsets.only(left: 8.0) + ? const EdgeInsets.only(left: 8) : EdgeInsets.zero); return Expanded( child: Center( @@ -545,7 +541,6 @@ class MessageInputState extends State { child: TextField( key: Key('messageInputText'), enabled: _inputEnabled, - minLines: null, maxLines: null, onSubmitted: (_) => sendMessage(), keyboardType: widget.keyboardType, @@ -607,7 +602,7 @@ class MessageInputState extends State { mainAxisSize: MainAxisSize.min, children: [ Padding( - padding: const EdgeInsets.all(8.0), + padding: const EdgeInsets.all(8), child: Container( constraints: BoxConstraints.tight(Size(64, 24)), decoration: BoxDecoration( @@ -620,7 +615,7 @@ class MessageInputState extends State { children: [ StreamSvgIcon.lightning( color: Colors.white, - size: 16.0, + size: 16, ), Text( _chosenCommand?.name.toUpperCase() ?? '', @@ -640,7 +635,6 @@ class MessageInputState extends State { : (widget.actionsLocation == ActionsLocation.leftInside ? Row( mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.center, children: [ _buildExpandActionsButton(), ], @@ -650,11 +644,10 @@ class MessageInputState extends State { prefixIconConstraints: BoxConstraints.tightFor(height: 40), suffixIcon: Row( mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.center, children: [ if (_commandEnabled) Padding( - padding: const EdgeInsets.only(right: 8.0), + padding: const EdgeInsets.only(right: 8), child: IconButton( icon: StreamSvgIcon.closeSmall(), splashRadius: 24, @@ -776,7 +769,7 @@ class MessageInputState extends State { void _checkCommands(String s, BuildContext context) { if (s.startsWith('/')) { - var matchedCommandsList = StreamChannel.of(context) + final matchedCommandsList = StreamChannel.of(context) .channel .config ?.commands @@ -825,19 +818,18 @@ class MessageInputState extends State { left: 0, right: 0, child: TweenAnimationBuilder( - tween: Tween(begin: 0.0, end: 1.0), + tween: Tween(begin: 0, end: 1), duration: Duration(milliseconds: 300), curve: Curves.easeInOutExpo, builder: (context, val, wid) { return Transform.scale( - alignment: Alignment.center, scale: val, child: Padding( - padding: const EdgeInsets.all(8.0), + padding: const EdgeInsets.all(8), child: Card( - elevation: 2.0, + elevation: 2, shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8.0), + borderRadius: BorderRadius.circular(8), ), color: StreamChatTheme.of(context).colorTheme.white, clipBehavior: Clip.antiAlias, @@ -845,20 +837,19 @@ class MessageInputState extends State { constraints: BoxConstraints.loose(Size.fromHeight(400)), decoration: BoxDecoration( color: StreamChatTheme.of(context).colorTheme.white, - borderRadius: BorderRadius.circular(8.0)), + borderRadius: BorderRadius.circular(8)), child: ListView( padding: const EdgeInsets.all(0), shrinkWrap: true, children: [ if (commands.isNotEmpty) Padding( - padding: - const EdgeInsets.only(left: 0.0, top: 8.0), + padding: const EdgeInsets.only(top: 8), child: Row( children: [ Padding( padding: const EdgeInsets.symmetric( - horizontal: 8.0, + horizontal: 8, ), child: StreamSvgIcon.lightning( color: StreamChatTheme.of(context) @@ -879,7 +870,7 @@ class MessageInputState extends State { ), ), SizedBox( - height: 10.0, + height: 10, ), ...commands .map( @@ -888,19 +879,19 @@ class MessageInputState extends State { _setCommand(c); }, child: Container( - height: 40.0, + height: 40, child: Row( children: [ SizedBox( - width: 16.0, + width: 16, ), _buildCommandIcon(c.name), SizedBox( - width: 8.0, + width: 8, ), Text.rich( TextSpan( - text: '${c.name.capitalize()}', + text: c.name.capitalize(), style: TextStyle( fontWeight: FontWeight.bold), children: [ @@ -987,10 +978,8 @@ class MessageInputState extends State { mainAxisSize: MainAxisSize.min, children: [ Row( - mainAxisAlignment: MainAxisAlignment.start, children: [ IconButton( - iconSize: 24, icon: StreamSvgIcon.pictures( color: _getIconColor(0), ), @@ -1010,11 +999,10 @@ class MessageInputState extends State { onPressed: !_attachmentContainsFile && _attachments.isNotEmpty ? null : () { - pickFile(DefaultAttachmentTypes.file, false); + pickFile(DefaultAttachmentTypes.file); }, ), IconButton( - iconSize: 24, icon: StreamSvgIcon.camera( color: _getIconColor(2), ), @@ -1026,7 +1014,6 @@ class MessageInputState extends State { ), IconButton( padding: const EdgeInsets.all(0), - iconSize: 24, icon: StreamSvgIcon.record( color: _getIconColor(3), ), @@ -1052,22 +1039,22 @@ class MessageInputState extends State { decoration: BoxDecoration( color: StreamChatTheme.of(context).colorTheme.white, borderRadius: BorderRadius.only( - topLeft: Radius.circular(16.0), - topRight: Radius.circular(16.0), + topLeft: Radius.circular(16), + topRight: Radius.circular(16), ), ), child: Container( width: double.infinity, child: Center( child: Padding( - padding: const EdgeInsets.all(8.0), + padding: const EdgeInsets.all(8), child: Container( - width: 40.0, - height: 4.0, + width: 40, + height: 4, decoration: BoxDecoration( color: StreamChatTheme.of(context).colorTheme.whiteSmoke, - borderRadius: BorderRadius.circular(4.0), + borderRadius: BorderRadius.circular(4), ), ), ), @@ -1080,7 +1067,7 @@ class MessageInputState extends State { child: Container( decoration: BoxDecoration( color: StreamChatTheme.of(context).colorTheme.white, - borderRadius: BorderRadius.circular(8.0), + borderRadius: BorderRadius.circular(8), ), child: _PickerWidget( filePickerIndex: _filePickerIndex, @@ -1159,7 +1146,7 @@ class MessageInputState extends State { return CircleAvatar( radius: 12, child: StreamSvgIcon.giphyIcon( - size: 24.0, + size: 24, ), ); case 'ban': @@ -1167,7 +1154,7 @@ class MessageInputState extends State { backgroundColor: StreamChatTheme.of(context).colorTheme.accentBlue, radius: 12, child: StreamSvgIcon.iconUserDelete( - size: 16.0, + size: 16, color: Colors.white, ), ); @@ -1176,7 +1163,7 @@ class MessageInputState extends State { backgroundColor: StreamChatTheme.of(context).colorTheme.accentBlue, radius: 12, child: StreamSvgIcon.flag( - size: 14.0, + size: 14, color: Colors.white, ), ); @@ -1186,7 +1173,7 @@ class MessageInputState extends State { radius: 12, child: ClipOval( child: StreamSvgIcon.imgur( - size: 24.0, + size: 24, ), ), ); @@ -1195,7 +1182,7 @@ class MessageInputState extends State { backgroundColor: StreamChatTheme.of(context).colorTheme.accentBlue, radius: 12, child: StreamSvgIcon.mute( - size: 16.0, + size: 16, color: Colors.white, ), ); @@ -1204,7 +1191,7 @@ class MessageInputState extends State { backgroundColor: StreamChatTheme.of(context).colorTheme.accentBlue, radius: 12, child: StreamSvgIcon.userAdd( - size: 16.0, + size: 16, color: Colors.white, ), ); @@ -1213,7 +1200,7 @@ class MessageInputState extends State { backgroundColor: StreamChatTheme.of(context).colorTheme.accentBlue, radius: 12, child: StreamSvgIcon.volumeUp( - size: 16.0, + size: 16, color: Colors.white, ), ); @@ -1222,7 +1209,7 @@ class MessageInputState extends State { backgroundColor: StreamChatTheme.of(context).colorTheme.accentBlue, radius: 12, child: StreamSvgIcon.lightning( - size: 16.0, + size: 16, color: Colors.white, ), ); @@ -1263,18 +1250,18 @@ class MessageInputState extends State { left: 0, right: 0, child: TweenAnimationBuilder( - tween: Tween(begin: 0.0, end: 1.0), + tween: Tween(begin: 0, end: 1), duration: Duration(milliseconds: 300), curve: Curves.easeInOutExpo, builder: (context, val, wid) { return Transform.scale( scale: val, child: Card( - margin: EdgeInsets.all(8.0), - elevation: 2.0, + margin: EdgeInsets.all(8), + elevation: 2, color: StreamChatTheme.of(context).colorTheme.white, shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8.0), + borderRadius: BorderRadius.circular(8), ), clipBehavior: Clip.antiAlias, child: Container( @@ -1291,7 +1278,7 @@ class MessageInputState extends State { shrinkWrap: true, children: [ SizedBox( - height: 8.0, + height: 8, ), ...snapshot.data! .where((it) => it.user != null) @@ -1333,7 +1320,7 @@ class MessageInputState extends State { }, ).toList(), SizedBox( - height: 8.0, + height: 8, ), ], ); @@ -1361,7 +1348,7 @@ class MessageInputState extends State { final emojis = _emojiNames .where((e) => e.contains(query)) - .map((e) => Emoji.byName(e)) + .map(Emoji.byName) .where((e) => e != null); if (emojis.isEmpty) { @@ -1377,11 +1364,11 @@ class MessageInputState extends State { left: 0, right: 0, child: Card( - margin: EdgeInsets.all(8.0), - elevation: 2.0, + margin: EdgeInsets.all(8), + elevation: 2, color: StreamChatTheme.of(context).colorTheme.white, shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8.0), + borderRadius: BorderRadius.circular(8), ), clipBehavior: Clip.antiAlias, child: Container( @@ -1390,7 +1377,7 @@ class MessageInputState extends State { boxShadow: [ BoxShadow( spreadRadius: -8, - blurRadius: 5.0, + blurRadius: 5, offset: Offset(0, -4), ), ], @@ -1403,12 +1390,11 @@ class MessageInputState extends State { itemBuilder: (context, i) { if (i == 0) { return Padding( - padding: const EdgeInsets.only(left: 8.0, top: 8.0), + padding: const EdgeInsets.only(left: 8, top: 8), child: Row( children: [ Padding( - padding: - const EdgeInsets.symmetric(horizontal: 8.0), + padding: const EdgeInsets.symmetric(horizontal: 8), child: StreamSvgIcon.smile( color: StreamChatTheme.of(context) .colorTheme @@ -1516,7 +1502,7 @@ class MessageInputState extends State { Padding( padding: const EdgeInsets.fromLTRB(8, 8, 8, 0), child: LimitedBox( - maxHeight: 136.0, + maxHeight: 136, child: ListView( reverse: true, shrinkWrap: true, @@ -1524,16 +1510,15 @@ class MessageInputState extends State { .map( (e) => ClipRRect( borderRadius: BorderRadius.circular(10), - clipBehavior: Clip.antiAlias, child: FileAttachment( message: Message(), // dummy message attachment: e, size: Size( MediaQuery.of(context).size.width * 0.65, - 56.0, + 56, ), trailing: Padding( - padding: const EdgeInsets.all(8.0), + padding: const EdgeInsets.all(8), child: _buildRemoveButton(e), ), ), @@ -1547,18 +1532,17 @@ class MessageInputState extends State { Padding( padding: const EdgeInsets.fromLTRB(8, 8, 8, 0), child: LimitedBox( - maxHeight: 104.0, + maxHeight: 104, child: ListView( scrollDirection: Axis.horizontal, children: remainingAttachments .map( (attachment) => ClipRRect( borderRadius: BorderRadius.circular(10), - clipBehavior: Clip.antiAlias, child: Stack( children: [ AspectRatio( - aspectRatio: 1.0, + aspectRatio: 1, child: Container( height: 104, width: 104, @@ -1593,7 +1577,6 @@ class MessageInputState extends State { elevation: 0, highlightElevation: 0, focusElevation: 0, - disabledElevation: 0, hoverElevation: 0, onPressed: () { setState(() => _attachments.remove(attachment.id)); @@ -1803,7 +1786,7 @@ class MessageInputState extends State { leading: Icon(Icons.image), title: Text('Upload a photo'), onTap: () { - pickFile(DefaultAttachmentTypes.image, false); + pickFile(DefaultAttachmentTypes.image); Navigator.pop(context); }, ), @@ -1811,7 +1794,7 @@ class MessageInputState extends State { leading: Icon(Icons.video_library), title: Text('Upload a video'), onTap: () { - pickFile(DefaultAttachmentTypes.video, false); + pickFile(DefaultAttachmentTypes.video); Navigator.pop(context); }, ), @@ -1837,7 +1820,7 @@ class MessageInputState extends State { leading: Icon(Icons.insert_drive_file), title: Text('Upload a file'), onTap: () { - pickFile(DefaultAttachmentTypes.file, false); + pickFile(DefaultAttachmentTypes.file); Navigator.pop(context); }, ), @@ -1967,7 +1950,7 @@ class MessageInputState extends State { Widget _buildIdleSendButton(BuildContext context) { return Padding( - padding: const EdgeInsets.all(8.0), + padding: const EdgeInsets.all(8), child: StreamSvgIcon( assetName: _getIdleSendIcon(), color: @@ -1978,7 +1961,7 @@ class MessageInputState extends State { Widget _buildSendButton(BuildContext context) { return Padding( - padding: const EdgeInsets.all(8.0), + padding: const EdgeInsets.all(8), child: IconButton( onPressed: sendMessage, padding: const EdgeInsets.all(0), @@ -2112,44 +2095,44 @@ class MessageInputState extends State { context: context, shape: RoundedRectangleBorder( borderRadius: BorderRadius.only( - topLeft: Radius.circular(16.0), - topRight: Radius.circular(16.0), + topLeft: Radius.circular(16), + topRight: Radius.circular(16), )), builder: (context) { return Column( mainAxisSize: MainAxisSize.min, children: [ SizedBox( - height: 26.0, + height: 26, ), StreamSvgIcon.error( color: StreamChatTheme.of(context).colorTheme.accentRed, - size: 24.0, + size: 24, ), SizedBox( - height: 26.0, + height: 26, ), Text( 'Something went wrong', style: StreamChatTheme.of(context).textTheme.headlineBold, ), SizedBox( - height: 7.0, + height: 7, ), Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), + padding: const EdgeInsets.symmetric(horizontal: 16), child: Text( description, textAlign: TextAlign.center, ), ), SizedBox( - height: 36.0, + height: 36, ), Container( color: StreamChatTheme.of(context).colorTheme.black.withOpacity(.08), - height: 1.0, + height: 1, ), Row( mainAxisAlignment: MainAxisAlignment.center, @@ -2345,7 +2328,7 @@ class __PickerWidgetState extends State<_PickerWidget> { color: StreamChatTheme.of(context).colorTheme.grey), textAlign: TextAlign.center, ), - SizedBox(height: 6.0), + SizedBox(height: 6), Center( child: Text( 'Allow access to your gallery', diff --git a/packages/stream_chat_flutter/lib/src/message_list_view.dart b/packages/stream_chat_flutter/lib/src/message_list_view.dart index 01c067da..5b3b0359 100644 --- a/packages/stream_chat_flutter/lib/src/message_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/message_list_view.dart @@ -111,7 +111,7 @@ class MessageDetails { /// Modify it to change the widget appearance. class MessageListView extends StatefulWidget { /// Instantiate a new MessageListView - MessageListView({ + const MessageListView({ Key? key, this.showScrollToBottom = true, this.messageBuilder, @@ -418,7 +418,6 @@ class _MessageListViewState extends State { child: ScrollablePositionedList.separated( key: ValueKey(initialIndex! + initialAlignment!), itemPositionsListener: _itemPositionListener, - addAutomaticKeepAlives: true, initialScrollIndex: initialIndex ?? 0, initialAlignment: initialAlignment ?? 0, physics: widget.scrollPhysics, @@ -437,7 +436,7 @@ class _MessageListViewState extends State { StreamChatTheme.of(context).colorTheme.bgGradient, ), child: Padding( - padding: const EdgeInsets.all(8.0), + padding: const EdgeInsets.all(8), child: Text( '$replyCount ${replyCount == 1 ? 'Reply' : 'Replies'}', textAlign: TextAlign.center, @@ -464,7 +463,7 @@ class _MessageListViewState extends State { dateTime: nextMessage.createdAt.toLocal(), ); return Padding( - padding: const EdgeInsets.symmetric(vertical: 12.0), + padding: const EdgeInsets.symmetric(vertical: 12), child: divider, ); } @@ -554,7 +553,7 @@ class _MessageListViewState extends State { ), if (widget.showScrollToBottom) _buildScrollToBottom(), Positioned( - top: 20.0, + top: 20, child: ValueListenableBuilder>( valueListenable: _itemPositionListener.itemPositions, builder: (context, values, _) { @@ -660,7 +659,7 @@ class _MessageListViewState extends State { top: -10, child: CircleAvatar( child: Padding( - padding: const EdgeInsets.all(3.0), + padding: const EdgeInsets.all(3), child: Text( '$unreadCount', style: TextStyle( @@ -712,7 +711,7 @@ class _MessageListViewState extends State { } return Center( child: Padding( - padding: const EdgeInsets.all(8.0), + padding: const EdgeInsets.all(8), child: const CircularProgressIndicator(), ), ); @@ -799,8 +798,6 @@ class _MessageListViewState extends State { final isOnlyEmoji = message.text!.isOnlyEmoji; return MessageWidget( - showThreadReplyIndicator: false, - showInChannelIndicator: false, showReplyMessage: false, showResendMessage: false, showThreadReplyMessage: false, @@ -810,7 +807,7 @@ class _MessageListViewState extends State { message: message, reverse: isMyMessage, showUsername: !isMyMessage, - padding: const EdgeInsets.all(8.0), + padding: const EdgeInsets.all(8), showSendingIndicator: false, onThreadTap: _onThreadTap as void Function(Message)?, borderRadiusGeometry: BorderRadius.only( @@ -820,7 +817,7 @@ class _MessageListViewState extends State { bottomRight: Radius.circular(16), ), textPadding: EdgeInsets.symmetric( - vertical: 8.0, + vertical: 8, horizontal: isOnlyEmoji ? 0 : 16.0, ), borderSide: isMyMessage || isOnlyEmoji ? BorderSide.none : null, @@ -940,7 +937,7 @@ class _MessageListViewState extends State { message: message, reverse: isMyMessage, showReactions: !message.isDeleted, - padding: const EdgeInsets.symmetric(horizontal: 8.0), + padding: const EdgeInsets.symmetric(horizontal: 8), showInChannelIndicator: showInChannelIndicator, showThreadReplyIndicator: showThreadReplyIndicator, showUsername: showUsername, @@ -997,7 +994,7 @@ class _MessageListViewState extends State { bottomRight: Radius.circular(16), ), textPadding: EdgeInsets.symmetric( - vertical: 8.0, + vertical: 8, horizontal: isOnlyEmoji ? 0 : 16.0, ), messageTheme: isMyMessage @@ -1069,7 +1066,7 @@ class _MessageListViewState extends State { ); }, child: Padding( - padding: const EdgeInsets.only(top: 4.0), + padding: const EdgeInsets.only(top: 4), child: child, ), ); diff --git a/packages/stream_chat_flutter/lib/src/message_reactions_modal.dart b/packages/stream_chat_flutter/lib/src/message_reactions_modal.dart index 9fa35cb6..937cf681 100644 --- a/packages/stream_chat_flutter/lib/src/message_reactions_modal.dart +++ b/packages/stream_chat_flutter/lib/src/message_reactions_modal.dart @@ -59,7 +59,7 @@ class MessageReactionsModal extends StatelessWidget { : (roughSentenceSize == 0 ? 1 : (roughSentenceSize / roughMaxSize)); return TweenAnimationBuilder( - tween: Tween(begin: 0.0, end: 1.0), + tween: Tween(begin: 0, end: 1), duration: Duration(milliseconds: 300), curve: Curves.easeInOutBack, builder: (context, val, snapshot) { @@ -86,7 +86,7 @@ class MessageReactionsModal extends StatelessWidget { child: Center( child: SingleChildScrollView( child: Padding( - padding: const EdgeInsets.all(8.0), + padding: const EdgeInsets.all(8), child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.stretch, @@ -102,7 +102,7 @@ class MessageReactionsModal extends StatelessWidget { : (divFactor > 1.0 ? 0.0 : -(1.0 - divFactor)), - 0.0), + 0), child: ReactionPicker( message: message, ), @@ -121,7 +121,6 @@ class MessageReactionsModal extends StatelessWidget { showReactions: false, showUsername: false, showUserAvatar: showUserAvatar, - showThreadReplyIndicator: false, showTimestamp: false, translateUserAvatar: false, showSendingIndicator: false, @@ -133,9 +132,8 @@ class MessageReactionsModal extends StatelessWidget { attachmentPadding: EdgeInsets.all( hasFileAttachment ? 4 : 2, ), - showInChannelIndicator: false, textPadding: EdgeInsets.symmetric( - vertical: 8.0, + vertical: 8, horizontal: message.text!.isOnlyEmoji ? 0 : 16.0, ), @@ -184,7 +182,6 @@ class MessageReactionsModal extends StatelessWidget { child: Wrap( spacing: 16, runSpacing: 16, - alignment: WrapAlignment.start, children: message.latestReactions! .map((e) => _buildReaction( e, @@ -214,8 +211,6 @@ class MessageReactionsModal extends StatelessWidget { )), child: Column( mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.center, children: [ Stack( clipBehavior: Clip.none, diff --git a/packages/stream_chat_flutter/lib/src/message_search_item.dart b/packages/stream_chat_flutter/lib/src/message_search_item.dart index 87b55aaa..7be8893b 100644 --- a/packages/stream_chat_flutter/lib/src/message_search_item.dart +++ b/packages/stream_chat_flutter/lib/src/message_search_item.dart @@ -147,8 +147,8 @@ class MessageSearchItem extends StatelessWidget { List attachments, TextStyle? normalTextStyle, TextStyle? mentionsTextStyle) { - var textList = text.split(' '); - var resList = []; + final textList = text.split(' '); + final resList = []; for (var e in textList) { if (mentions.isNotEmpty && mentions.any((element) => '@${element.name}' == e)) { @@ -166,7 +166,7 @@ class MessageSearchItem extends StatelessWidget { )); } else { resList.add(TextSpan( - text: e == textList.last ? '$e' : '$e ', + text: e == textList.last ? e : '$e ', style: normalTextStyle, )); } diff --git a/packages/stream_chat_flutter/lib/src/message_search_list_view.dart b/packages/stream_chat_flutter/lib/src/message_search_list_view.dart index 358623e1..b88af62e 100644 --- a/packages/stream_chat_flutter/lib/src/message_search_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/message_search_list_view.dart @@ -189,10 +189,7 @@ class _MessageSearchListViewState extends State { }, ); }, - childBuilder: widget.childBuilder ?? - (list) { - return _buildListView(list); - }, + childBuilder: widget.childBuilder ?? _buildListView, ); } @@ -228,7 +225,7 @@ class _MessageSearchListViewState extends State { .accentRed .withOpacity(.2), child: Padding( - padding: const EdgeInsets.symmetric(vertical: 16.0), + padding: const EdgeInsets.symmetric(vertical: 16), child: Center( child: Text('Error loading messages'), ), diff --git a/packages/stream_chat_flutter/lib/src/message_widget.dart b/packages/stream_chat_flutter/lib/src/message_widget.dart index b05762ba..32801cd1 100644 --- a/packages/stream_chat_flutter/lib/src/message_widget.dart +++ b/packages/stream_chat_flutter/lib/src/message_widget.dart @@ -201,8 +201,8 @@ class MessageWidget extends StatefulWidget { this.readList, this.padding, this.textPadding = const EdgeInsets.symmetric( - horizontal: 16.0, - vertical: 8.0, + horizontal: 16, + vertical: 8, ), this.attachmentPadding = EdgeInsets.zero, this.allRead = false, @@ -211,8 +211,7 @@ class MessageWidget extends StatefulWidget { this.onAttachmentTap, }) : attachmentBuilders = { 'image': (context, message, attachments) { - var border = RoundedRectangleBorder( - side: BorderSide.none, + final border = RoundedRectangleBorder( borderRadius: attachmentBorderRadiusGeometry ?? BorderRadius.zero, ); @@ -267,8 +266,7 @@ class MessageWidget extends StatefulWidget { ); }, 'video': (context, message, attachments) { - var border = RoundedRectangleBorder( - side: BorderSide.none, + final border = RoundedRectangleBorder( borderRadius: attachmentBorderRadiusGeometry ?? BorderRadius.zero, ); @@ -302,7 +300,6 @@ class MessageWidget extends StatefulWidget { }, 'giphy': (context, message, attachments) { final border = RoundedRectangleBorder( - side: BorderSide.none, borderRadius: attachmentBorderRadiusGeometry ?? BorderRadius.zero, ); @@ -329,7 +326,7 @@ class MessageWidget extends StatefulWidget { ); }, 'file': (context, message, attachments) { - var border = RoundedRectangleBorder( + final border = RoundedRectangleBorder( side: attachmentBorderSide ?? BorderSide( color: StreamChatTheme.of(context).colorTheme.greyWhisper, @@ -426,7 +423,7 @@ class _MessageWidgetState extends State super.build(context); final avatarWidth = widget.messageTheme.avatarTheme?.constraints.maxWidth ?? 40; - var leftPadding = + final leftPadding = widget.showUserAvatar != DisplayWidget.gone ? avatarWidth + 8.5 : 0.5; return Material( @@ -460,7 +457,6 @@ class _MessageWidgetState extends State mainAxisSize: MainAxisSize.min, children: [ Row( - mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.end, mainAxisSize: MainAxisSize.min, children: [ @@ -481,8 +477,8 @@ class _MessageWidgetState extends State BoxConstraints(maxWidth: 22 * 6.0), child: _buildReactionIndicator(context), ), - portalAnchor: Alignment(-1.0, -1.0), - childAnchor: Alignment(1, -1.0), + portalAnchor: Alignment(-1, -1), + childAnchor: Alignment(1, -1), child: Stack( clipBehavior: Clip.none, children: [ @@ -526,7 +522,7 @@ class _MessageWidgetState extends State ) : Card( clipBehavior: Clip.antiAlias, - elevation: 0.0, + elevation: 0, margin: EdgeInsets.symmetric( horizontal: (isFailedState ? 15.0 @@ -650,9 +646,9 @@ class _MessageWidgetState extends State children: [ StreamSvgIcon.eye( color: StreamChatTheme.of(context).colorTheme.grey, - size: 16.0, + size: 16, ), - SizedBox(width: 8.0), + SizedBox(width: 8), Text( 'Only visible to you', style: StreamChatTheme.of(context) @@ -665,7 +661,7 @@ class _MessageWidgetState extends State ); } - var children = []; + final children = []; final threadParticipants = widget.message.threadParticipants?.take(2); final showThreadParticipants = threadParticipants?.isNotEmpty == true; @@ -757,18 +753,18 @@ class _MessageWidgetState extends State return mappedChild; }, ), - ].insertBetween(const SizedBox(width: 8.0)), + ].insertBetween(const SizedBox(width: 8)), ); } Widget _buildUrlAttachment() { - var urlAttachment = widget.message.attachments + final urlAttachment = widget.message.attachments .firstWhere((element) => element.ogScrapeUrl != null); - var host = Uri.parse(urlAttachment.ogScrapeUrl!).host; - var splitList = host.split('.'); - var hostName = splitList.length == 3 ? splitList[1] : splitList[0]; - var hostDisplayName = urlAttachment.authorName?.capitalize() ?? + final host = Uri.parse(urlAttachment.ogScrapeUrl!).host; + final splitList = host.split('.'); + final hostName = splitList.length == 3 ? splitList[1] : splitList[0]; + final hostDisplayName = urlAttachment.authorName?.capitalize() ?? getWebsiteName(hostName.toLowerCase()) ?? hostName.capitalize(); diff --git a/packages/stream_chat_flutter/lib/src/option_list_tile.dart b/packages/stream_chat_flutter/lib/src/option_list_tile.dart index 03af584b..a4463389 100644 --- a/packages/stream_chat_flutter/lib/src/option_list_tile.dart +++ b/packages/stream_chat_flutter/lib/src/option_list_tile.dart @@ -11,7 +11,7 @@ class OptionListTile extends StatelessWidget { final Color? separatorColor; final TextStyle? titleTextStyle; - OptionListTile({ + const OptionListTile({ this.title, this.leading, this.trailing, @@ -29,12 +29,12 @@ class OptionListTile extends StatelessWidget { Container( color: separatorColor ?? StreamChatTheme.of(context).colorTheme.greyGainsboro, - height: 1.0, + height: 1, ), Material( color: tileColor ?? StreamChatTheme.of(context).colorTheme.white, child: Container( - height: 63.0, + height: 63, child: InkWell( onTap: onTap, child: Row( @@ -42,7 +42,7 @@ class OptionListTile extends StatelessWidget { if (leading != null) Center(child: leading), if (leading == null) SizedBox( - width: 16.0, + width: 16, ), Expanded( flex: 4, @@ -62,7 +62,7 @@ class OptionListTile extends StatelessWidget { Expanded( flex: 2, child: Padding( - padding: const EdgeInsets.only(right: 16.0), + padding: const EdgeInsets.only(right: 16), child: Align( alignment: Alignment.centerRight, child: trailing ?? Container(), diff --git a/packages/stream_chat_flutter/lib/src/quoted_message_widget.dart b/packages/stream_chat_flutter/lib/src/quoted_message_widget.dart index 43b198eb..9d489dab 100644 --- a/packages/stream_chat_flutter/lib/src/quoted_message_widget.dart +++ b/packages/stream_chat_flutter/lib/src/quoted_message_widget.dart @@ -87,7 +87,7 @@ class QuotedMessageWidget extends StatelessWidget { final GestureTapCallback? onTap; /// - QuotedMessageWidget({ + const QuotedMessageWidget({ Key? key, required this.message, required this.messageTheme, @@ -237,7 +237,7 @@ class QuotedMessageWidget extends StatelessWidget { ShapeBorder _getDefaultShape(BuildContext context) { return RoundedRectangleBorder( - side: BorderSide(width: 0.0, color: Colors.transparent), + side: BorderSide(width: 0, color: Colors.transparent), borderRadius: BorderRadius.circular(8), ); } diff --git a/packages/stream_chat_flutter/lib/src/reaction_bubble.dart b/packages/stream_chat_flutter/lib/src/reaction_bubble.dart index bcf3127c..d71c395a 100644 --- a/packages/stream_chat_flutter/lib/src/reaction_bubble.dart +++ b/packages/stream_chat_flutter/lib/src/reaction_bubble.dart @@ -40,7 +40,6 @@ class ReactionBubble extends StatelessWidget { alignment: Alignment.center, child: Stack( alignment: Alignment.center, - fit: StackFit.loose, children: [ Transform.translate( offset: Offset(reverse ? offset : -offset, 0), @@ -115,7 +114,7 @@ class ReactionBubble extends StatelessWidget { return Padding( padding: const EdgeInsets.symmetric( - horizontal: 4.0, + horizontal: 4, ), child: reactionIcon != null ? StreamSvgIcon( @@ -239,9 +238,9 @@ class ReactionBubblePainter extends CustomPainter { ..strokeWidth = 1 ..style = PaintingStyle.stroke; - final dy = -2.2; - final startAngle = 1.1; - final sweepAngle = 1.2; + const dy = -2.2; + const startAngle = 1.1; + const sweepAngle = 1.2; final path = Path(); path.addArc( Rect.fromCircle( @@ -259,9 +258,9 @@ class ReactionBubblePainter extends CustomPainter { ..color = color ..strokeWidth = 1; - final dy = -2.2; - final startAngle = 1; - final sweepAngle = 1.3; + const dy = -2.2; + const startAngle = 1; + const sweepAngle = 1.3; final path = Path(); path.addArc( Rect.fromCircle( @@ -280,9 +279,9 @@ class ReactionBubblePainter extends CustomPainter { ..strokeWidth = 1 ..style = PaintingStyle.fill; - final dy = -2.2; - final startAngle = 1.1; - final sweepAngle = 1.2; + const dy = -2.2; + const startAngle = 1.1; + const sweepAngle = 1.2; final path = Path(); path.addArc( Rect.fromCircle( diff --git a/packages/stream_chat_flutter/lib/src/reaction_picker.dart b/packages/stream_chat_flutter/lib/src/reaction_picker.dart index cd358b2a..aaa2c040 100644 --- a/packages/stream_chat_flutter/lib/src/reaction_picker.dart +++ b/packages/stream_chat_flutter/lib/src/reaction_picker.dart @@ -49,7 +49,7 @@ class _ReactionPickerState extends State } return TweenAnimationBuilder( - tween: Tween(begin: 0.0, end: 1.0), + tween: Tween(begin: 0, end: 1), curve: Curves.easeInOutBack, duration: Duration(milliseconds: 500), builder: (context, val, wid) { @@ -61,8 +61,8 @@ class _ReactionPickerState extends State clipBehavior: Clip.hardEdge, child: Padding( padding: const EdgeInsets.symmetric( - horizontal: 16.0, - vertical: 8.0, + horizontal: 16, + vertical: 8, ), child: Row( crossAxisAlignment: CrossAxisAlignment.start, @@ -74,7 +74,7 @@ class _ReactionPickerState extends State ?.indexWhere((reaction) => reaction.type == reactionIcon.type) ?? -1; - var index = reactionIcons.indexOf(reactionIcon); + final index = reactionIcons.indexOf(reactionIcon); return ConstrainedBox( constraints: BoxConstraints.tightFor( @@ -83,8 +83,6 @@ class _ReactionPickerState extends State ), child: RawMaterialButton( elevation: 0, - padding: const EdgeInsets.all(0), - clipBehavior: Clip.none, shape: ContinuousRectangleBorder( borderRadius: BorderRadius.circular(16), ), @@ -110,7 +108,6 @@ class _ReactionPickerState extends State animation: animations[index], builder: (context, val) { return Transform.scale( - alignment: Alignment.center, scale: animations[index].value, child: StreamSvgIcon( assetName: reactionIcon.assetName, diff --git a/packages/stream_chat_flutter/lib/src/stream_chat.dart b/packages/stream_chat_flutter/lib/src/stream_chat.dart index f5461895..2c22dde3 100644 --- a/packages/stream_chat_flutter/lib/src/stream_chat.dart +++ b/packages/stream_chat_flutter/lib/src/stream_chat.dart @@ -43,7 +43,7 @@ class StreamChat extends StatefulWidget { /// upon the [Event.type] final EventHandler? onBackgroundEventReceived; - StreamChat({ + const StreamChat({ Key? key, required this.client, required this.child, diff --git a/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart b/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart index 9b28d1f6..1e1eb089 100644 --- a/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart +++ b/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart @@ -13,7 +13,7 @@ import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; class StreamChatTheme extends InheritedWidget { final StreamChatThemeData data; - StreamChatTheme({ + const StreamChatTheme({ Key? key, required this.data, required Widget child, @@ -237,7 +237,7 @@ class StreamChatThemeData { lastMessageAt: textTheme.footnote.copyWith( color: colorTheme.black.withOpacity(.5), ), - indicatorIconSize: 16.0), + indicatorIconSize: 16), channelListHeaderTheme: ChannelListHeaderTheme( avatarTheme: AvatarTheme( borderRadius: BorderRadius.circular(20), @@ -543,17 +543,13 @@ class ColorTheme { stops: [0, 1], ), this.borderTop = 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.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( - 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( - 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; ColorTheme.dark({ @@ -572,28 +568,28 @@ class ColorTheme { sigmaX: 0, sigmaY: -1, color: Color(0xff141924), - blur: 0.0, + blur: 0, ), this.borderBottom = const Effect( sigmaX: 0, sigmaY: 1, color: Color(0xff141924), - blur: 0.0, - alpha: 1.0, + blur: 0, + alpha: 1, ), this.shadowIconButton = const Effect( sigmaX: 0, sigmaY: 2, color: Color(0xff000000), alpha: 0.5, - blur: 4.0, + blur: 4, ), this.modalShadow = const Effect( sigmaX: 0, sigmaY: 0, color: Color(0xff000000), alpha: 1, - blur: 8.0, + blur: 8, ), this.highlight = const Color(0xff302d22), this.overlay = const Color.fromRGBO(0, 0, 0, 0.4), diff --git a/packages/stream_chat_flutter/lib/src/stream_neumorphic_button.dart b/packages/stream_chat_flutter/lib/src/stream_neumorphic_button.dart index 95b3c70e..157d2940 100644 --- a/packages/stream_chat_flutter/lib/src/stream_neumorphic_button.dart +++ b/packages/stream_chat_flutter/lib/src/stream_neumorphic_button.dart @@ -13,7 +13,7 @@ class StreamNeumorphicButton extends StatelessWidget { @override Widget build(BuildContext context) { return Container( - margin: EdgeInsets.all(8.0), + margin: EdgeInsets.all(8), height: 40, width: 40, decoration: BoxDecoration( @@ -22,15 +22,12 @@ class StreamNeumorphicButton extends StatelessWidget { boxShadow: [ BoxShadow( color: Colors.grey.shade700, - offset: Offset(0, 1.0), + offset: Offset(0, 1), blurRadius: 0.5, - spreadRadius: 0, ), BoxShadow( color: Colors.white, - offset: Offset.zero, blurRadius: 0.5, - spreadRadius: 0, ), ], ), diff --git a/packages/stream_chat_flutter/lib/src/stream_svg_icon.dart b/packages/stream_chat_flutter/lib/src/stream_svg_icon.dart index 8dc38ba2..f115617c 100644 --- a/packages/stream_chat_flutter/lib/src/stream_svg_icon.dart +++ b/packages/stream_chat_flutter/lib/src/stream_svg_icon.dart @@ -25,7 +25,6 @@ class StreamSvgIcon extends StatelessWidget { width: width, height: height, color: color, - alignment: Alignment.center, ); } diff --git a/packages/stream_chat_flutter/lib/src/swipeable.dart b/packages/stream_chat_flutter/lib/src/swipeable.dart index 90146e4c..3d195e4f 100644 --- a/packages/stream_chat_flutter/lib/src/swipeable.dart +++ b/packages/stream_chat_flutter/lib/src/swipeable.dart @@ -28,7 +28,7 @@ class Swipeable extends StatefulWidget { } class _SwipeableState extends State with TickerProviderStateMixin { - double _dragExtent = 0.0; + double _dragExtent = 0; late AnimationController _moveController; late AnimationController _iconMoveController; late Animation _moveAnimation; @@ -45,15 +45,15 @@ class _SwipeableState extends State with TickerProviderStateMixin { AnimationController(duration: _animationDuration, vsync: this); _iconMoveController = AnimationController(duration: _animationDuration, vsync: this); - _moveAnimation = Tween(begin: Offset.zero, end: Offset(1.0, 0.0)) + _moveAnimation = Tween(begin: Offset.zero, end: Offset(1, 0)) .animate(_moveController); _iconTransitionAnimation = - Tween(begin: Offset(-0.1, 0.0), end: Offset(0.4, 0.0)) + Tween(begin: Offset(-0.1, 0), end: Offset(0.4, 0)) .animate(_moveController); _iconFadeAnimation = - Tween(begin: 0.7, end: 1.0).animate(_iconMoveController); + Tween(begin: 0.7, end: 1).animate(_iconMoveController); - final controllerValue = 0.0; + const controllerValue = 0.0; _moveController.animateTo(controllerValue); _iconMoveController.animateTo(controllerValue); } @@ -77,19 +77,19 @@ class _SwipeableState extends State with TickerProviderStateMixin { if (_dragExtent.isNegative) return; - var movePastThresholdPixels = widget.threshold; + final movePastThresholdPixels = widget.threshold; var newPos = _dragExtent.abs() / context.size!.width; if (_dragExtent.abs() > movePastThresholdPixels) { // how many "thresholds" past the threshold we are. 1 = the threshold 2 // = two thresholds. - var n = _dragExtent.abs() / movePastThresholdPixels; + final n = _dragExtent.abs() / movePastThresholdPixels; // Take the number of thresholds past the threshold, and reduce this // 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; if (_dragExtent > 0 && !_pastThreshold) { @@ -111,8 +111,8 @@ class _SwipeableState extends State with TickerProviderStateMixin { } void _handleDragEnd(DragEndDetails details) { - _moveController.animateTo(0.0, duration: _animationDuration); - _iconMoveController.animateTo(0.0, duration: _animationDuration); + _moveController.animateTo(0, duration: _animationDuration); + _iconMoveController.animateTo(0, duration: _animationDuration); _dragExtent = 0.0; if (_pastThreshold && widget.onSwipeEnd != null) { widget.onSwipeEnd!(); diff --git a/packages/stream_chat_flutter/lib/src/thread_header.dart b/packages/stream_chat_flutter/lib/src/thread_header.dart index 9dc8f98c..0157791e 100644 --- a/packages/stream_chat_flutter/lib/src/thread_header.dart +++ b/packages/stream_chat_flutter/lib/src/thread_header.dart @@ -118,7 +118,6 @@ class ThreadHeader extends StatelessWidget implements PreferredSizeWidget { child: Container( height: preferredSize.height, child: Column( - crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, children: [ title ?? @@ -133,7 +132,6 @@ class ThreadHeader extends StatelessWidget implements PreferredSizeWidget { subtitle ?? Row( mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, children: [ Text( diff --git a/packages/stream_chat_flutter/lib/src/unread_indicator.dart b/packages/stream_chat_flutter/lib/src/unread_indicator.dart index d55cd4f1..8d2c996a 100644 --- a/packages/stream_chat_flutter/lib/src/unread_indicator.dart +++ b/packages/stream_chat_flutter/lib/src/unread_indicator.dart @@ -33,8 +33,8 @@ class UnreadIndicator extends StatelessWidget { .unreadCounterColor, child: Padding( padding: const EdgeInsets.only( - left: 5.0, - right: 5.0, + left: 5, + right: 5, top: 2, bottom: 1, ), diff --git a/packages/stream_chat_flutter/lib/src/upload_progress_indicator.dart b/packages/stream_chat_flutter/lib/src/upload_progress_indicator.dart index e0e7e306..1175237e 100644 --- a/packages/stream_chat_flutter/lib/src/upload_progress_indicator.dart +++ b/packages/stream_chat_flutter/lib/src/upload_progress_indicator.dart @@ -10,7 +10,7 @@ class UploadProgressIndicator extends StatelessWidget { final bool showBackground; final TextStyle? textStyle; - UploadProgressIndicator({ + const UploadProgressIndicator({ Key? key, required this.uploaded, required this.total, diff --git a/packages/stream_chat_flutter/lib/src/url_attachment.dart b/packages/stream_chat_flutter/lib/src/url_attachment.dart index e8e7b8a8..e924746d 100644 --- a/packages/stream_chat_flutter/lib/src/url_attachment.dart +++ b/packages/stream_chat_flutter/lib/src/url_attachment.dart @@ -8,12 +8,12 @@ class UrlAttachment extends StatelessWidget { final String hostDisplayName; final EdgeInsets textPadding; - UrlAttachment({ + const UrlAttachment({ required this.urlAttachment, required this.hostDisplayName, this.textPadding = const EdgeInsets.symmetric( - horizontal: 16.0, - vertical: 8.0, + horizontal: 16, + vertical: 8, ), }); @@ -32,9 +32,9 @@ class UrlAttachment extends StatelessWidget { if (urlAttachment.imageUrl != null) Container( clipBehavior: Clip.antiAliasWithSaveLayer, - margin: EdgeInsets.symmetric(horizontal: 8.0), + margin: EdgeInsets.symmetric(horizontal: 8), decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8.0), + borderRadius: BorderRadius.circular(8), ), child: Stack( children: [ @@ -44,20 +44,20 @@ class UrlAttachment extends StatelessWidget { fit: BoxFit.cover, ), Positioned( - left: 0.0, + left: 0, bottom: -1, child: Container( decoration: BoxDecoration( borderRadius: BorderRadius.only( - topRight: Radius.circular(16.0), + topRight: Radius.circular(16), ), color: StreamChatTheme.of(context).colorTheme.blueAlice, ), child: Padding( padding: const EdgeInsets.only( - top: 8.0, - left: 8.0, - right: 8.0, + top: 8, + left: 8, + right: 8, ), child: Text( hostDisplayName, diff --git a/packages/stream_chat_flutter/lib/src/user_avatar.dart b/packages/stream_chat_flutter/lib/src/user_avatar.dart index 96753b99..0833b1a3 100644 --- a/packages/stream_chat_flutter/lib/src/user_avatar.dart +++ b/packages/stream_chat_flutter/lib/src/user_avatar.dart @@ -42,7 +42,6 @@ class UserAvatar extends StatelessWidget { Widget avatar = FittedBox( fit: BoxFit.cover, child: ClipRRect( - clipBehavior: Clip.antiAlias, borderRadius: borderRadius ?? streamChatTheme.ownMessageTheme.avatarTheme?.borderRadius, child: Container( @@ -97,7 +96,7 @@ class UserAvatar extends StatelessWidget { type: MaterialType.circle, color: streamChatTheme.colorTheme.white, child: Container( - margin: const EdgeInsets.all(2.0), + margin: const EdgeInsets.all(2), constraints: onlineIndicatorConstraints ?? BoxConstraints.tightFor( width: 8, diff --git a/packages/stream_chat_flutter/lib/src/user_item.dart b/packages/stream_chat_flutter/lib/src/user_item.dart index 258855d8..ff51fea3 100644 --- a/packages/stream_chat_flutter/lib/src/user_item.dart +++ b/packages/stream_chat_flutter/lib/src/user_item.dart @@ -61,7 +61,6 @@ class UserItem extends StatelessWidget { }, leading: UserAvatar( user: user, - showOnlineStatus: true, onTap: (user) { if (onImageTap != null) { onImageTap!(user); diff --git a/packages/stream_chat_flutter/lib/src/user_list_view.dart b/packages/stream_chat_flutter/lib/src/user_list_view.dart index 2f0e13b9..f1053e58 100644 --- a/packages/stream_chat_flutter/lib/src/user_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/user_list_view.dart @@ -151,7 +151,7 @@ class _UserListViewState extends State @override Widget build(BuildContext context) { - var child = UserListCore( + final child = UserListCore( errorBuilder: widget.errorBuilder as Widget Function(Object)? ?? (err) { return _buildError(err as Error); @@ -225,7 +225,7 @@ class _UserListViewState extends State WidgetSpan( child: Padding( padding: const EdgeInsets.only( - right: 2.0, + right: 2, ), child: Icon(Icons.error_outline), ), @@ -237,7 +237,7 @@ class _UserListViewState extends State ), Padding( padding: const EdgeInsets.only( - top: 16.0, + top: 16, ), child: Text(message), ), @@ -313,7 +313,7 @@ class _UserListViewState extends State color: StreamChatTheme.of(context).colorTheme.black.withOpacity(0.05), child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 6), + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 6), child: Text( header, style: TextStyle( @@ -360,7 +360,6 @@ class _UserListViewState extends State ? widget.userItemBuilder!(context, user, selected) : Column( mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, children: [ UserAvatar( user: user, @@ -414,7 +413,7 @@ class _UserListViewState extends State .accentRed .withOpacity(.2), child: Padding( - padding: const EdgeInsets.symmetric(vertical: 16.0), + padding: const EdgeInsets.symmetric(vertical: 16), child: Center( child: Text('Error loading users'), ), diff --git a/packages/stream_chat_flutter/lib/src/user_reaction_display.dart b/packages/stream_chat_flutter/lib/src/user_reaction_display.dart index 492baef5..fe61caad 100644 --- a/packages/stream_chat_flutter/lib/src/user_reaction_display.dart +++ b/packages/stream_chat_flutter/lib/src/user_reaction_display.dart @@ -23,7 +23,7 @@ class UserReactionDisplay extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.min, children: reactionToEmoji.keys.map((reactionType) { - var firstUserReaction = message.latestReactions! + final firstUserReaction = message.latestReactions! .firstWhere((element) => element.type == reactionType, orElse: () { return null; diff --git a/packages/stream_chat_flutter/lib/src/utils.dart b/packages/stream_chat_flutter/lib/src/utils.dart index 79bd210e..4233dd2f 100644 --- a/packages/stream_chat_flutter/lib/src/utils.dart +++ b/packages/stream_chat_flutter/lib/src/utils.dart @@ -33,8 +33,8 @@ Future showConfirmationDialog( context: context, shape: RoundedRectangleBorder( borderRadius: BorderRadius.only( - topLeft: Radius.circular(16.0), - topRight: Radius.circular(16.0), + topLeft: Radius.circular(16), + topRight: Radius.circular(16), )), builder: (context) { final effect = StreamChatTheme.of(context).colorTheme.borderTop; @@ -42,20 +42,20 @@ Future showConfirmationDialog( child: Column( mainAxisSize: MainAxisSize.min, children: [ - SizedBox(height: 26.0), + SizedBox(height: 26), if (icon != null) icon, - SizedBox(height: 26.0), + SizedBox(height: 26), Text( title, style: StreamChatTheme.of(context).textTheme.headlineBold, ), - SizedBox(height: 7.0), + SizedBox(height: 7), if (question != null) Text( question, textAlign: TextAlign.center, ), - SizedBox(height: 36.0), + SizedBox(height: 36), Container( color: effect.color!.withOpacity(effect.alpha ?? 1), height: 1, @@ -126,8 +126,8 @@ Future showInfoDialog( context: context, shape: RoundedRectangleBorder( borderRadius: BorderRadius.only( - topLeft: Radius.circular(16.0), - topRight: Radius.circular(16.0), + topLeft: Radius.circular(16), + topRight: Radius.circular(16), )), builder: (context) { return SafeArea( @@ -135,11 +135,11 @@ Future showInfoDialog( mainAxisSize: MainAxisSize.min, children: [ SizedBox( - height: 26.0, + height: 26, ), if (icon != null) icon, SizedBox( - height: 26.0, + height: 26, ), Text( title, @@ -147,16 +147,16 @@ Future showInfoDialog( StreamChatTheme.of(context).textTheme.headlineBold, ), SizedBox( - height: 7.0, + height: 7, ), if (details != null) Text(details), SizedBox( - height: 36.0, + height: 36, ), Container( color: theme?.colorTheme.black.withOpacity(.08) ?? StreamChatTheme.of(context).colorTheme.black.withOpacity(.08), - height: 1.0, + height: 1, ), Center( child: TextButton( @@ -236,7 +236,7 @@ String fileSize(dynamic size, [int round = 2]) { * the optional parameter [round] specifies the number * of digits after comma/point (default is 2) */ - final divider = 1024; + const divider = 1024; int _size; try { _size = int.parse(size.toString()); @@ -274,21 +274,21 @@ String fileSize(dynamic size, [int round = 2]) { if (_size < divider * divider * divider * divider * divider && _size % divider == 0) { - num r = _size / divider / divider / divider / divider; + final num r = _size / divider / divider / divider / divider; return '${r.toStringAsFixed(0)} TB'; } 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'; } if (_size < divider * divider * divider * divider * divider * divider && _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'; } else { - num r = _size / divider / divider / divider / divider / divider; + final num r = _size / divider / divider / divider / divider / divider; return '${r.toStringAsFixed(round)} PB'; } } diff --git a/packages/stream_chat_flutter/test/src/attachment_actions_modal_test.dart b/packages/stream_chat_flutter/test/src/attachment_actions_modal_test.dart index 762d4fe9..53516e9a 100644 --- a/packages/stream_chat_flutter/test/src/attachment_actions_modal_test.dart +++ b/packages/stream_chat_flutter/test/src/attachment_actions_modal_test.dart @@ -239,7 +239,7 @@ void main() { ), ); await tester.tap(find.text('Show in Chat')); - verify(() => onShowMessage.call()).called(1); + verify(onShowMessage.call).called(1); }, ); diff --git a/packages/stream_chat_flutter/test/src/attachment_widgets_test.dart b/packages/stream_chat_flutter/test/src/attachment_widgets_test.dart index b1eb70e2..e8dcdd53 100644 --- a/packages/stream_chat_flutter/test/src/attachment_widgets_test.dart +++ b/packages/stream_chat_flutter/test/src/attachment_widgets_test.dart @@ -26,8 +26,8 @@ void main() { child: Container( child: FileAttachment( size: Size( - 300.0, - 300.0, + 300, + 300, ), message: Message(), attachment: Attachment( diff --git a/packages/stream_chat_flutter/test/src/channel_header_test.dart b/packages/stream_chat_flutter/test/src/channel_header_test.dart index c284cad5..4e99daf5 100644 --- a/packages/stream_chat_flutter/test/src/channel_header_test.dart +++ b/packages/stream_chat_flutter/test/src/channel_header_test.dart @@ -318,7 +318,6 @@ void main() { body: ChannelHeader( showTypingIndicator: false, showBackButton: false, - showConnectionStateTile: false, ), ), ), diff --git a/packages/stream_chat_flutter/test/src/reaction_bubble_test.dart b/packages/stream_chat_flutter/test/src/reaction_bubble_test.dart index fd5d31ce..10e0f45c 100644 --- a/packages/stream_chat_flutter/test/src/reaction_bubble_test.dart +++ b/packages/stream_chat_flutter/test/src/reaction_bubble_test.dart @@ -224,7 +224,6 @@ void main() { borderColor: Colors.red, backgroundColor: Colors.blue, maskColor: Colors.green, - highlightOwnReactions: true, reverse: true, flipTail: true, tailCirclesSpacing: 4, From f236d92840fbb6b1558bea34fd07df0602f8f4c5 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 4 May 2021 16:48:57 +0530 Subject: [PATCH 02/31] attachment lint --- .../attachment_upload_state_builder.dart | 136 +++++------ .../lib/src/attachment/attachment_widget.dart | 69 +++--- .../lib/src/attachment/file_attachment.dart | 146 ++++++------ .../lib/src/attachment/giphy_attachment.dart | 214 +++++++++--------- .../lib/src/attachment/image_attachment.dart | 31 ++- .../lib/src/attachment/video_attachment.dart | 25 +- .../lib/src/channel_info.dart | 2 +- 7 files changed, 324 insertions(+), 299 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/attachment/attachment_upload_state_builder.dart b/packages/stream_chat_flutter/lib/src/attachment/attachment_upload_state_builder.dart index e7abac74..825def58 100644 --- a/packages/stream_chat_flutter/lib/src/attachment/attachment_upload_state_builder.dart +++ b/packages/stream_chat_flutter/lib/src/attachment/attachment_upload_state_builder.dart @@ -10,13 +10,7 @@ typedef FailedBuilder = Widget Function(BuildContext, String); /// Widget to display attachment upload state class AttachmentUploadStateBuilder extends StatelessWidget { - final Message message; - final Attachment attachment; - final FailedBuilder? failedBuilder; - final WidgetBuilder? successBuilder; - final InProgressBuilder? inProgressBuilder; - final WidgetBuilder? preparingBuilder; - + /// Constructor for creating an [AttachmentUploadStateBuilder] widget const AttachmentUploadStateBuilder({ Key? key, required this.message, @@ -27,32 +21,46 @@ class AttachmentUploadStateBuilder extends StatelessWidget { this.preparingBuilder, }) : super(key: key); + /// Message which attachment is added to + final Message message; + + /// Attachment in concern + final Attachment attachment; + + /// Widget to display when failed + final FailedBuilder? failedBuilder; + + /// Widget to display when succeeded + final WidgetBuilder? successBuilder; + + /// Widget to display when in progress + final InProgressBuilder? inProgressBuilder; + + /// Widget to display when in prep + final WidgetBuilder? preparingBuilder; + @override Widget build(BuildContext context) { if (message.status == MessageSendingStatus.sent) { - return Offstage(); + return const Offstage(); } final messageId = message.id; final attachmentId = attachment.id; final inProgress = inProgressBuilder ?? - (context, int sent, int total) { - return _InProgressState( - sent: sent, - total: total, - attachmentId: attachmentId, - ); - }; + (context, int sent, int total) => _InProgressState( + sent: sent, + total: total, + attachmentId: attachmentId, + ); final failed = failedBuilder ?? - (context, error) { - return _FailedState( - error: error, - messageId: messageId, - attachmentId: attachmentId, - ); - }; + (context, error) => _FailedState( + error: error, + messageId: messageId, + attachmentId: attachmentId, + ); final success = successBuilder ?? (context) => _SuccessState(); @@ -69,11 +77,6 @@ class AttachmentUploadStateBuilder extends StatelessWidget { } class _IconButton extends StatelessWidget { - final Widget? icon; - final double iconSize; - final VoidCallback? onPressed; - final Color? fillColor; - const _IconButton({ Key? key, this.icon, @@ -82,36 +85,39 @@ class _IconButton extends StatelessWidget { this.fillColor, }) : super(key: key); + final Widget? icon; + final double iconSize; + final VoidCallback? onPressed; + final Color? fillColor; + @override - Widget build(BuildContext context) { - return Container( - height: iconSize, - width: iconSize, - child: RawMaterialButton( - elevation: 0, - highlightElevation: 0, - focusElevation: 0, - hoverElevation: 0, - onPressed: onPressed, - fillColor: - fillColor ?? StreamChatTheme.of(context).colorTheme.overlayDark, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16), + Widget build(BuildContext context) => SizedBox( + height: iconSize, + width: iconSize, + child: RawMaterialButton( + elevation: 0, + highlightElevation: 0, + focusElevation: 0, + hoverElevation: 0, + onPressed: onPressed, + fillColor: + fillColor ?? StreamChatTheme.of(context).colorTheme.overlayDark, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + ), + child: icon, ), - child: icon, - ), - ); - } + ); } class _PreparingState extends StatelessWidget { - final String attachmentId; - const _PreparingState({ Key? key, required this.attachmentId, }) : super(key: key); + final String attachmentId; + @override Widget build(BuildContext context) { final channel = StreamChannel.of(context).channel; @@ -141,10 +147,6 @@ class _PreparingState extends StatelessWidget { } class _InProgressState extends StatelessWidget { - final int sent; - final int total; - final String attachmentId; - const _InProgressState({ Key? key, required this.sent, @@ -152,6 +154,10 @@ class _InProgressState extends StatelessWidget { required this.attachmentId, }) : super(key: key); + final int sent; + final int total; + final String attachmentId; + @override Widget build(BuildContext context) { final channel = StreamChannel.of(context).channel; @@ -181,10 +187,6 @@ class _InProgressState extends StatelessWidget { } class _FailedState extends StatelessWidget { - final String? error; - final String messageId; - final String attachmentId; - const _FailedState({ Key? key, this.error, @@ -192,6 +194,10 @@ class _FailedState extends StatelessWidget { required this.attachmentId, }) : super(key: key); + final String? error; + final String messageId; + final String attachmentId; + @override Widget build(BuildContext context) { final channel = StreamChannel.of(context).channel; @@ -235,16 +241,14 @@ class _FailedState extends StatelessWidget { class _SuccessState extends StatelessWidget { @override - Widget build(BuildContext context) { - return Align( - alignment: Alignment.topRight, - child: CircleAvatar( - backgroundColor: StreamChatTheme.of(context).colorTheme.overlayDark, - maxRadius: 12, - child: StreamSvgIcon.check( - color: StreamChatTheme.of(context).colorTheme.white, + Widget build(BuildContext context) => Align( + alignment: Alignment.topRight, + child: CircleAvatar( + backgroundColor: StreamChatTheme.of(context).colorTheme.overlayDark, + maxRadius: 12, + child: StreamSvgIcon.check( + color: StreamChatTheme.of(context).colorTheme.white, + ), ), - ), - ); - } + ); } diff --git a/packages/stream_chat_flutter/lib/src/attachment/attachment_widget.dart b/packages/stream_chat_flutter/lib/src/attachment/attachment_widget.dart index d80109c2..74769057 100644 --- a/packages/stream_chat_flutter/lib/src/attachment/attachment_widget.dart +++ b/packages/stream_chat_flutter/lib/src/attachment/attachment_widget.dart @@ -1,13 +1,17 @@ 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 '../stream_chat_theme.dart'; - +/// Enum for identifying type of attachment enum AttachmentSource { + /// Attachment is attached local, + + /// Attachment is uploaded network, } +/// Extension for identifying type of attachment extension AttachmentSourceX on AttachmentSource { /// The [when] method is the equivalent to pattern matching. /// Its prototype depends on the AttachmentSource defined. @@ -25,18 +29,9 @@ extension AttachmentSourceX on AttachmentSource { } } +/// Abstract class for deriving attachment types abstract class AttachmentWidget extends StatelessWidget { - final Size? size; - final AttachmentSource? _source; - final Message message; - final Attachment attachment; - - AttachmentSource get source => - _source ?? - (attachment.file != null - ? AttachmentSource.local - : AttachmentSource.network); - + /// Constructor for creating attachment widget const AttachmentWidget({ Key? key, required this.message, @@ -45,30 +40,48 @@ abstract class AttachmentWidget extends StatelessWidget { AttachmentSource? source, }) : _source = source, super(key: key); + + /// Size of attachments + final Size? size; + final AttachmentSource? _source; + + /// Message which attachment is attached to + final Message message; + + /// Attachment to display + final Attachment attachment; + + /// Getter for source of attachment + AttachmentSource get source => + _source ?? + (attachment.file != null + ? AttachmentSource.local + : AttachmentSource.network); } +/// Widget for building in case of error class AttachmentError extends StatelessWidget { - final Size? size; - + /// Constructor for creating AttachmentError const AttachmentError({ Key? key, this.size, }) : super(key: key); + final Size? size; + @override - Widget build(BuildContext context) { - return Center( - child: Container( - width: size?.width, - height: size?.height, - color: StreamChatTheme.of(context).colorTheme.accentRed.withOpacity(.1), - child: Center( - child: Icon( - Icons.error_outline, - color: StreamChatTheme.of(context).colorTheme.black, + Widget build(BuildContext context) => Center( + child: Container( + width: size?.width, + height: size?.height, + color: + StreamChatTheme.of(context).colorTheme.accentRed.withOpacity(.1), + child: Center( + child: Icon( + Icons.error_outline, + color: StreamChatTheme.of(context).colorTheme.black, + ), ), ), - ), - ); - } + ); } diff --git a/packages/stream_chat_flutter/lib/src/attachment/file_attachment.dart b/packages/stream_chat_flutter/lib/src/attachment/file_attachment.dart index 0ef78d85..c68d72f9 100644 --- a/packages/stream_chat_flutter/lib/src/attachment/file_attachment.dart +++ b/packages/stream_chat_flutter/lib/src/attachment/file_attachment.dart @@ -11,10 +11,7 @@ import '../upload_progress_indicator.dart'; import 'attachment_widget.dart'; class FileAttachment extends AttachmentWidget { - final Widget? title; - final Widget? trailing; - final VoidCallback? onAttachmentTap; - + /// Constructor for creating a widget when attachment is of type 'file' const FileAttachment({ Key? key, required Message message, @@ -30,8 +27,19 @@ class FileAttachment extends AttachmentWidget { size: size, ); + /// Title for attachment + final Widget? title; + + /// Widget for displaying at the end of attachment (such as a download button) + final Widget? trailing; + + /// Callback called when attachment widget is tapped + final VoidCallback? onAttachmentTap; + + /// Check if attachment is a video bool get isVideoAttachment => attachment.title?.mimeType?.type == 'video'; + /// Check if attachment is an image bool get isImageAttachment => attachment.title?.mimeType?.type == 'image'; @override @@ -56,10 +64,10 @@ class FileAttachment extends AttachmentWidget { Container( height: 40, width: 33.33, - margin: EdgeInsets.all(8), + margin: const EdgeInsets.all(8), child: _getFileTypeImage(context), ), - SizedBox(width: 8), + const SizedBox(width: 8), Expanded( child: Column( mainAxisAlignment: MainAxisAlignment.center, @@ -71,12 +79,12 @@ class FileAttachment extends AttachmentWidget { maxLines: 1, overflow: TextOverflow.ellipsis, ), - SizedBox(height: 3), + const SizedBox(height: 3), _buildSubtitle(context), ], ), ), - SizedBox(width: 8), + const SizedBox(width: 8), _buildTrailing(context), ], ), @@ -85,12 +93,10 @@ class FileAttachment extends AttachmentWidget { ); } - ShapeBorder _getDefaultShape(BuildContext context) { - return RoundedRectangleBorder( - side: BorderSide(width: 0, color: Colors.transparent), - borderRadius: BorderRadius.circular(8), - ); - } + ShapeBorder _getDefaultShape(BuildContext context) => RoundedRectangleBorder( + side: const BorderSide(width: 0, color: Colors.transparent), + borderRadius: BorderRadius.circular(8), + ); Widget _getFileTypeImage(BuildContext context) { if (isImageAttachment) { @@ -106,10 +112,8 @@ class FileAttachment extends AttachmentWidget { return Image.memory( attachment.file!.bytes!, fit: BoxFit.cover, - errorBuilder: (_, obj, trace) { - return getFileTypeImage( - attachment.extraData['other'] as String?); - }, + errorBuilder: (_, obj, trace) => + getFileTypeImage(attachment.extraData['other'] as String?), ); }, network: () { @@ -124,10 +128,8 @@ class FileAttachment extends AttachmentWidget { attachment.assetUrl ?? attachment.thumbUrl!, fit: BoxFit.cover, - errorWidget: (_, obj, trace) { - return getFileTypeImage( - attachment.extraData['other'] as String?); - }, + errorWidget: (_, obj, trace) => + getFileTypeImage(attachment.extraData['other'] as String?), placeholder: (_, __) { final image = Image.asset( 'images/placeholder.png', @@ -156,27 +158,23 @@ class FileAttachment extends AttachmentWidget { child: source.when( local: () => VideoThumbnailImage( video: attachment.file!.path!, - placeholderBuilder: (_) { - return Center( - child: Container( - width: 20, - height: 20, - child: const CircularProgressIndicator(), - ), - ); - }, + placeholderBuilder: (_) => const Center( + child: SizedBox( + width: 20, + height: 20, + child: CircularProgressIndicator(), + ), + ), ), network: () => VideoThumbnailImage( video: attachment.assetUrl!, - placeholderBuilder: (_) { - return Center( - child: Container( - width: 20, - height: 20, - child: const CircularProgressIndicator(), - ), - ); - }, + placeholderBuilder: (_) => const Center( + child: SizedBox( + width: 20, + height: 20, + child: CircularProgressIndicator(), + ), + ), ), ), ); @@ -189,22 +187,22 @@ class FileAttachment extends AttachmentWidget { double iconSize = 24.0, VoidCallback? onPressed, Color? fillColor, - }) { - return Container( - height: iconSize, - width: iconSize, - child: RawMaterialButton( - elevation: 0, - highlightElevation: 0, - focusElevation: 0, - hoverElevation: 0, - onPressed: onPressed, - fillColor: fillColor, - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), - child: icon, - ), - ); - } + }) => + SizedBox( + height: iconSize, + width: iconSize, + child: RawMaterialButton( + elevation: 0, + highlightElevation: 0, + focusElevation: 0, + hoverElevation: 0, + onPressed: onPressed, + fillColor: fillColor, + shape: + RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), + child: icon, + ), + ); Widget _buildTrailing(BuildContext context) { final theme = StreamChatTheme.of(context); @@ -281,26 +279,22 @@ class FileAttachment extends AttachmentWidget { color: theme.colorTheme.grey, ); return attachment.uploadState.when( - preparing: () { - return UploadProgressIndicator( - uploaded: 0, - total: double.maxFinite.toInt(), - showBackground: false, - padding: EdgeInsets.zero, - textStyle: textStyle, - progressIndicatorColor: theme.colorTheme.accentBlue, - ); - }, - inProgress: (sent, total) { - return UploadProgressIndicator( - uploaded: sent, - total: total, - showBackground: false, - padding: EdgeInsets.zero, - textStyle: textStyle, - progressIndicatorColor: theme.colorTheme.accentBlue, - ); - }, + preparing: () => UploadProgressIndicator( + uploaded: 0, + total: double.maxFinite.toInt(), + showBackground: false, + padding: EdgeInsets.zero, + textStyle: textStyle, + progressIndicatorColor: theme.colorTheme.accentBlue, + ), + inProgress: (sent, total) => UploadProgressIndicator( + uploaded: sent, + total: total, + showBackground: false, + padding: EdgeInsets.zero, + textStyle: textStyle, + progressIndicatorColor: theme.colorTheme.accentBlue, + ), success: () => Text(fileSize(size), style: textStyle), failed: (_) => Text('UPLOAD ERROR', style: textStyle), ) ?? diff --git a/packages/stream_chat_flutter/lib/src/attachment/giphy_attachment.dart b/packages/stream_chat_flutter/lib/src/attachment/giphy_attachment.dart index 27e98f10..1bbbd54f 100644 --- a/packages/stream_chat_flutter/lib/src/attachment/giphy_attachment.dart +++ b/packages/stream_chat_flutter/lib/src/attachment/giphy_attachment.dart @@ -1,18 +1,13 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:shimmer/shimmer.dart'; +import 'package:stream_chat_flutter/src/attachment/attachment_widget.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; -import '../full_screen_media.dart'; -import '../stream_chat_theme.dart'; -import '../stream_svg_icon.dart'; -import 'attachment_widget.dart'; - +/// Widget for showing a GIF attachment class GiphyAttachment extends AttachmentWidget { - final ShowMessageCallback? onShowMessage; - final ValueChanged? onReturnAction; - final VoidCallback? onAttachmentTap; - + /// Constructor for creating a [GiphyAttachment] widget const GiphyAttachment({ Key? key, required Message message, @@ -28,12 +23,21 @@ class GiphyAttachment extends AttachmentWidget { size: size, ); + /// Callback when show message is tapped + final ShowMessageCallback? onShowMessage; + + /// Callback when attachment is returned to from other screens + final ValueChanged? onReturnAction; + + /// Callback when attachment is tapped + final VoidCallback? onAttachmentTap; + @override Widget build(BuildContext context) { final imageUrl = attachment.thumbUrl ?? attachment.imageUrl ?? attachment.assetUrl; if (imageUrl == null) { - return AttachmentError(); + return const AttachmentError(); } if (attachment.actions.isNotEmpty) { return _buildSendingAttachment(context, imageUrl); @@ -50,10 +54,9 @@ class GiphyAttachment extends AttachmentWidget { color: StreamChatTheme.of(context).colorTheme.white, elevation: 2, clipBehavior: Clip.antiAlias, - shape: RoundedRectangleBorder( + shape: const RoundedRectangleBorder( borderRadius: BorderRadius.only( topRight: Radius.circular(16), - bottomRight: Radius.circular(0), topLeft: Radius.circular(16), bottomLeft: Radius.circular(16), ), @@ -67,12 +70,12 @@ class GiphyAttachment extends AttachmentWidget { child: Row( children: [ StreamSvgIcon.giphyIcon(), - SizedBox(width: 8), - Text( + const SizedBox(width: 8), + const Text( 'Giphy', style: TextStyle(fontWeight: FontWeight.bold), ), - SizedBox(width: 8), + const SizedBox(width: 8), if (attachment.title != null) Flexible( child: Text( @@ -97,19 +100,16 @@ class GiphyAttachment extends AttachmentWidget { child: CachedNetworkImage( height: size?.height, width: size?.width, - placeholder: (_, __) { - return Container( - width: size?.width, - height: size?.height, - child: Center( - child: CircularProgressIndicator(), - ), - ); - }, + placeholder: (_, __) => SizedBox( + width: size?.width, + height: size?.height, + child: const Center( + child: CircularProgressIndicator(), + ), + ), imageUrl: imageUrl, - errorWidget: (context, url, error) { - return AttachmentError(size: size); - }, + errorWidget: (context, url, error) => + AttachmentError(size: size), fit: BoxFit.cover, ), ), @@ -125,7 +125,7 @@ class GiphyAttachment extends AttachmentWidget { Row( children: [ Expanded( - child: Container( + child: SizedBox( height: 50, child: TextButton( onPressed: () { @@ -157,7 +157,7 @@ class GiphyAttachment extends AttachmentWidget { height: 50, ), Expanded( - child: Container( + child: SizedBox( height: 50, child: TextButton( onPressed: () { @@ -190,7 +190,7 @@ class GiphyAttachment extends AttachmentWidget { height: 50, ), Expanded( - child: Container( + child: SizedBox( height: 50, child: TextButton( onPressed: () { @@ -215,7 +215,7 @@ class GiphyAttachment extends AttachmentWidget { ], ), ), - SizedBox(height: 4), + const SizedBox(height: 4), Align( alignment: Alignment.centerRight, child: Padding( @@ -230,7 +230,7 @@ class GiphyAttachment extends AttachmentWidget { .withOpacity(0.5), size: 16, ), - SizedBox( + const SizedBox( width: 8, ), Text( @@ -273,88 +273,86 @@ class GiphyAttachment extends AttachmentWidget { if (res != null) onReturnAction?.call(res); } - Widget _buildSentAttachment(BuildContext context, String imageUrl) { - return Container( - child: GestureDetector( - onTap: () async { - final res = - 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 (res != null) onReturnAction!(res); - }, - child: Stack( - children: [ - CachedNetworkImage( - height: size?.height, - width: size?.width, - placeholder: (_, __) { - final image = Image.asset( - 'images/placeholder.png', - fit: BoxFit.cover, - package: 'stream_chat_flutter', - ); + Widget _buildSentAttachment(BuildContext context, String imageUrl) => + SizedBox( + child: GestureDetector( + onTap: () async { + final res = + 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 (res != null) onReturnAction!(res); + }, + child: Stack( + children: [ + CachedNetworkImage( + 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, - ), - Positioned( - bottom: 8, - left: 8, - child: Material( - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(.5), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: 8, - vertical: 4, + 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, + ), + Positioned( + bottom: 8, + left: 8, + child: Material( + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), ), - child: Row( - children: [ - StreamSvgIcon.lightning( - color: StreamChatTheme.of(context).colorTheme.white, - size: 16, - ), - Text( - 'GIPHY', - style: TextStyle( + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 8, + vertical: 4, + ), + child: Row( + children: [ + StreamSvgIcon.lightning( color: StreamChatTheme.of(context).colorTheme.white, - fontWeight: FontWeight.bold, - fontSize: 11, + size: 16, ), - ), - ], + Text( + 'GIPHY', + style: TextStyle( + color: StreamChatTheme.of(context).colorTheme.white, + fontWeight: FontWeight.bold, + fontSize: 11, + ), + ), + ], + ), ), ), ), - ), - ], + ], + ), ), - ), - ); - } + ); } diff --git a/packages/stream_chat_flutter/lib/src/attachment/image_attachment.dart b/packages/stream_chat_flutter/lib/src/attachment/image_attachment.dart index 652a6826..5c431d6e 100644 --- a/packages/stream_chat_flutter/lib/src/attachment/image_attachment.dart +++ b/packages/stream_chat_flutter/lib/src/attachment/image_attachment.dart @@ -1,21 +1,15 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:shimmer/shimmer.dart'; +import 'package:stream_chat_flutter/src/attachment/attachment_title.dart'; import 'package:stream_chat_flutter/src/attachment/attachment_upload_state_builder.dart'; +import 'package:stream_chat_flutter/src/attachment/attachment_widget.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; -import '../full_screen_media.dart'; -import '../stream_chat_theme.dart'; -import 'attachment_title.dart'; -import 'attachment_widget.dart'; - +/// Widget for showing an image attachment class ImageAttachment extends AttachmentWidget { - final MessageTheme messageTheme; - final bool showTitle; - final ShowMessageCallback? onShowMessage; - final ValueChanged? onReturnAction; - final VoidCallback? onAttachmentTap; - + /// Constructor for creating a [ImageAttachment] widget const ImageAttachment({ Key? key, required Message message, @@ -33,6 +27,21 @@ class ImageAttachment extends AttachmentWidget { size: size, ); + /// [MessageTheme] for showing image title + final MessageTheme messageTheme; + + /// Flag for showing title + final bool showTitle; + + /// Callback when show message is tapped + final ShowMessageCallback? onShowMessage; + + /// Callback when attachment is returned to from other screens + final ValueChanged? onReturnAction; + + /// Callback when attachment is tapped + final VoidCallback? onAttachmentTap; + @override Widget build(BuildContext context) => source.when( local: () { diff --git a/packages/stream_chat_flutter/lib/src/attachment/video_attachment.dart b/packages/stream_chat_flutter/lib/src/attachment/video_attachment.dart index f74bba14..b743cda1 100644 --- a/packages/stream_chat_flutter/lib/src/attachment/video_attachment.dart +++ b/packages/stream_chat_flutter/lib/src/attachment/video_attachment.dart @@ -1,18 +1,13 @@ import 'package:flutter/material.dart'; +import 'package:stream_chat_flutter/src/attachment/attachment_title.dart'; +import 'package:stream_chat_flutter/src/attachment/attachment_widget.dart'; import 'package:stream_chat_flutter/src/full_screen_media.dart'; import 'package:stream_chat_flutter/src/video_thumbnail_image.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; -import 'attachment_title.dart'; -import 'attachment_upload_state_builder.dart'; -import 'attachment_widget.dart'; - +/// Widget for showing a video attachment class VideoAttachment extends AttachmentWidget { - final MessageTheme messageTheme; - final ShowMessageCallback? onShowMessage; - final ValueChanged? onReturnAction; - final VoidCallback? onAttachmentTap; - + /// Constructor for creating a [VideoAttachment] widget const VideoAttachment({ Key? key, required Message message, @@ -29,6 +24,18 @@ class VideoAttachment extends AttachmentWidget { size: size, ); + /// [MessageTheme] for showing title + final MessageTheme messageTheme; + + /// Callback when show message is tapped + final ShowMessageCallback? onShowMessage; + + /// Callback when attachment is returned to from other screens + final ValueChanged? onReturnAction; + + /// Callback when attachment is tapped + final VoidCallback? onAttachmentTap; + @override Widget build(BuildContext context) => source.when( local: () { diff --git a/packages/stream_chat_flutter/lib/src/channel_info.dart b/packages/stream_chat_flutter/lib/src/channel_info.dart index 493729b9..abd1680c 100644 --- a/packages/stream_chat_flutter/lib/src/channel_info.dart +++ b/packages/stream_chat_flutter/lib/src/channel_info.dart @@ -100,7 +100,7 @@ class ChannelInfo extends StatelessWidget { child: CircularProgressIndicator(), ), ), - SizedBox(width: 10), + const SizedBox(width: 10), Text( 'Searching for Network', style: textStyle, From edba3d2ad5fc2dbd6607508f22e06d474f1aa2b5 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 4 May 2021 16:58:03 +0530 Subject: [PATCH 03/31] attachment lint --- .../lib/src/attachment_actions_modal.dart | 10 +++---- .../lib/src/message_input.dart | 26 ++++++++----------- 2 files changed, 15 insertions(+), 21 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/attachment_actions_modal.dart b/packages/stream_chat_flutter/lib/src/attachment_actions_modal.dart index 98aa8d48..a8d1bddd 100644 --- a/packages/stream_chat_flutter/lib/src/attachment_actions_modal.dart +++ b/packages/stream_chat_flutter/lib/src/attachment_actions_modal.dart @@ -192,8 +192,7 @@ class AttachmentActionsModal extends StatelessWidget { VoidCallback? onTap, { Color? color, Key? key, - }) { - return Material( + }) => Material( key: key, color: StreamChatTheme.of(context).colorTheme.white, child: InkWell( @@ -216,7 +215,6 @@ class AttachmentActionsModal extends StatelessWidget { ), ), ); - } Widget _buildDownloadProgressDialog( BuildContext context, @@ -245,7 +243,7 @@ class AttachmentActionsModal extends StatelessWidget { ), child: Center( child: progress == null - ? Container( + ? SizedBox( height: 100, width: 100, child: StreamSvgIcon.error( @@ -253,7 +251,7 @@ class AttachmentActionsModal extends StatelessWidget { ), ) : progress.toProgressIndicatorValue == 1.0 - ? Container( + ? SizedBox( key: Key('completedIcon'), height: 160, width: 160, @@ -261,7 +259,7 @@ class AttachmentActionsModal extends StatelessWidget { color: theme.colorTheme.greyGainsboro, ), ) - : Container( + : SizedBox( height: 100, width: 100, child: Stack( diff --git a/packages/stream_chat_flutter/lib/src/message_input.dart b/packages/stream_chat_flutter/lib/src/message_input.dart index 4c58f312..b0335e52 100644 --- a/packages/stream_chat_flutter/lib/src/message_input.dart +++ b/packages/stream_chat_flutter/lib/src/message_input.dart @@ -812,8 +812,7 @@ class MessageInputState extends State { final renderBox = context.findRenderObject() as RenderBox; final size = renderBox.size; - return OverlayEntry(builder: (context) { - return Positioned( + return OverlayEntry(builder: (context) => Positioned( bottom: size.height + MediaQuery.of(context).viewInsets.bottom, left: 0, right: 0, @@ -821,8 +820,7 @@ class MessageInputState extends State { tween: Tween(begin: 0, end: 1), duration: Duration(milliseconds: 300), curve: Curves.easeInOutExpo, - builder: (context, val, wid) { - return Transform.scale( + builder: (context, val, wid) => Transform.scale( scale: val, child: Padding( padding: const EdgeInsets.all(8), @@ -869,7 +867,7 @@ class MessageInputState extends State { ], ), ), - SizedBox( + const SizedBox( height: 10, ), ...commands @@ -878,21 +876,21 @@ class MessageInputState extends State { onTap: () { _setCommand(c); }, - child: Container( + child: SizedBox( height: 40, child: Row( children: [ - SizedBox( + const SizedBox( width: 16, ), _buildCommandIcon(c.name), - SizedBox( + const SizedBox( width: 8, ), Text.rich( TextSpan( text: c.name.capitalize(), - style: TextStyle( + style: const TextStyle( fontWeight: FontWeight.bold), children: [ TextSpan( @@ -922,10 +920,8 @@ class MessageInputState extends State { ), ), ), - ); - }), - ); - }); + )), + )); } Widget _buildFilePickerSection() { @@ -1038,12 +1034,12 @@ class MessageInputState extends State { child: Container( decoration: BoxDecoration( color: StreamChatTheme.of(context).colorTheme.white, - borderRadius: BorderRadius.only( + borderRadius: const BorderRadius.only( topLeft: Radius.circular(16), topRight: Radius.circular(16), ), ), - child: Container( + child: SizedBox( width: double.infinity, child: Center( child: Padding( From 9acf8d103763a606ecc8e932edb06422f8275b07 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 4 May 2021 17:58:29 +0530 Subject: [PATCH 04/31] lint changes --- .../lib/src/back_button.dart | 13 +- .../lib/src/channel_bottom_sheet.dart | 17 +- .../lib/src/channel_header.dart | 58 +-- .../lib/src/channel_image.dart | 23 +- .../lib/src/channel_info.dart | 19 +- .../lib/src/channel_list_header.dart | 39 +- .../lib/src/channel_list_view.dart | 352 ++++++++------- .../lib/src/channel_name.dart | 85 ++-- .../lib/src/channel_preview.dart | 406 +++++++++--------- .../lib/src/connection_status_builder.dart | 11 +- .../lib/src/date_divider.dart | 13 +- .../lib/src/deleted_message.dart | 7 +- .../lib/src/extension.dart | 8 +- 13 files changed, 533 insertions(+), 518 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/back_button.dart b/packages/stream_chat_flutter/lib/src/back_button.dart index faf08fe8..acb3d1ec 100644 --- a/packages/stream_chat_flutter/lib/src/back_button.dart +++ b/packages/stream_chat_flutter/lib/src/back_button.dart @@ -1,10 +1,12 @@ import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import 'package:stream_chat_flutter/src/unread_indicator.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; -import '../stream_chat_flutter.dart'; - +/// Back button implementation class StreamBackButton extends StatelessWidget { + + /// Constructor for creating back button const StreamBackButton({ Key? key, this.onPressed, @@ -12,15 +14,17 @@ class StreamBackButton extends StatelessWidget { this.cid, }) : super(key: key); + /// Callback for when button is pressed final VoidCallback? onPressed; + + /// Show unread count final bool showUnreads; /// Channel cid used to retrieve unread count final String? cid; @override - Widget build(BuildContext context) { - return Stack( + Widget build(BuildContext context) => Stack( alignment: Alignment.center, children: [ RawMaterialButton( @@ -54,5 +58,4 @@ class StreamBackButton extends StatelessWidget { ), ], ); - } } diff --git a/packages/stream_chat_flutter/lib/src/channel_bottom_sheet.dart b/packages/stream_chat_flutter/lib/src/channel_bottom_sheet.dart index 911b306b..89f19466 100644 --- a/packages/stream_chat_flutter/lib/src/channel_bottom_sheet.dart +++ b/packages/stream_chat_flutter/lib/src/channel_bottom_sheet.dart @@ -1,13 +1,14 @@ import 'package:flutter/material.dart'; +import 'package:stream_chat_flutter/src/channel_info.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; -import '../stream_chat_flutter.dart'; -import 'channel_info.dart'; -import 'option_list_tile.dart'; - +/// Bottom Sheet with options class ChannelBottomSheet extends StatefulWidget { - final VoidCallback? onViewInfoTap; + /// Constructor for creating bottom sheet + const ChannelBottomSheet({Key? key, this.onViewInfoTap}) : super(key: key); - const ChannelBottomSheet({this.onViewInfoTap}); + /// Callback when 'View Info' is tapped + final VoidCallback? onViewInfoTap; @override _ChannelBottomSheetState createState() => _ChannelBottomSheetState(); @@ -29,7 +30,7 @@ class _ChannelBottomSheetState extends State { return Material( color: StreamChatTheme.of(context).colorTheme.white, clipBehavior: Clip.antiAlias, - shape: RoundedRectangleBorder( + shape: const RoundedRectangleBorder( borderRadius: BorderRadius.only( topLeft: Radius.circular(16), topRight: Radius.circular(16), @@ -120,7 +121,7 @@ class _ChannelBottomSheetState extends State { ), borderRadius: BorderRadius.circular(32), onlineIndicatorConstraints: - BoxConstraints.tight(Size(12, 12)), + BoxConstraints.tight(const Size(12, 12)), ), const SizedBox( height: 6, diff --git a/packages/stream_chat_flutter/lib/src/channel_header.dart b/packages/stream_chat_flutter/lib/src/channel_header.dart index 1882c5b0..8b0eb8fb 100644 --- a/packages/stream_chat_flutter/lib/src/channel_header.dart +++ b/packages/stream_chat_flutter/lib/src/channel_header.dart @@ -4,13 +4,9 @@ import 'package:stream_chat_flutter/src/channel_info.dart'; import 'package:stream_chat_flutter/src/channel_name.dart'; import 'package:stream_chat_flutter/src/info_tile.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; -import './channel_name.dart'; -import '../stream_chat_flutter.dart'; -import 'channel_image.dart'; -import 'connection_status_builder.dart'; - /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/channel_header.png) /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/channel_header_paint.png) /// @@ -43,16 +39,36 @@ import 'connection_status_builder.dart'; /// Usually you would use this widget as an [AppBar] inside a [Scaffold]. /// However you can also use it as a normal widget. /// -/// Make sure to have a [StreamChannel] ancestor in order to provide the information about the channel. -/// Every part of the widget uses a [StreamBuilder] to render the channel information as soon as it updates. +/// Make sure to have a [StreamChannel] ancestor in order to provide the +/// information about the channel. +/// Every part of the widget uses a [StreamBuilder] to render the channel +/// information as soon as it updates. /// /// By default the widget shows a backButton that calls [Navigator.pop]. -/// You can disable this button using the [showBackButton] property of just override the behaviour +/// You can disable this button using the [showBackButton] property of just +/// override the behaviour /// with [onBackPressed]. /// -/// The widget components render the ui based on the first ancestor of type [StreamChatTheme] and on its [ChannelTheme.channelHeaderTheme] property. +/// The widget components render the ui based on the first ancestor of type +/// [StreamChatTheme] and on its [ChannelTheme.channelHeaderTheme] property. /// Modify it to change the widget appearance. class ChannelHeader extends StatelessWidget implements PreferredSizeWidget { + /// Creates a channel header + const ChannelHeader({ + Key? key, + this.showBackButton = true, + this.onBackPressed, + this.onTitleTap, + this.showTypingIndicator = true, + this.onImageTap, + this.showConnectionStateTile = false, + this.title, + this.subtitle, + this.leading, + this.actions, + }) : preferredSize = const Size.fromHeight(kToolbarHeight), + super(key: key); + /// True if this header shows the leading back button final bool showBackButton; @@ -69,6 +85,7 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget { /// If true the typing indicator will be rendered if a user is typing final bool showTypingIndicator; + /// Show connection tile on header final bool showConnectionStateTile; /// Title widget @@ -84,22 +101,6 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget { /// By default it shows the [ChannelImage] final List? actions; - /// Creates a channel header - ChannelHeader({ - Key? key, - this.showBackButton = true, - this.onBackPressed, - this.onTitleTap, - this.showTypingIndicator = true, - this.onImageTap, - this.showConnectionStateTile = false, - this.title, - this.subtitle, - this.leading, - this.actions, - }) : preferredSize = Size.fromHeight(kToolbarHeight), - super(key: key); - @override Widget build(BuildContext context) { final channel = StreamChannel.of(context).channel; @@ -110,7 +111,7 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget { onPressed: onBackPressed, showUnreads: true, ) - : SizedBox()); + : const SizedBox()); return ConnectionStatusBuilder( statusBuilder: (context, status) { @@ -131,6 +132,7 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget { } return InfoTile( + // ignore: avoid_bool_literals_in_conditional_expressions showMessage: showConnectionStateTile ? showStatus : false, message: statusString, child: AppBar( @@ -165,7 +167,7 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget { centerTitle: true, title: InkWell( onTap: onTitleTap, - child: Container( + child: SizedBox( height: preferredSize.height, width: preferredSize.width, child: Column( @@ -178,7 +180,7 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget { .channelHeaderTheme .title, ), - SizedBox(height: 2), + const SizedBox(height: 2), subtitle ?? ChannelInfo( showTypingIndicator: showTypingIndicator, diff --git a/packages/stream_chat_flutter/lib/src/channel_image.dart b/packages/stream_chat_flutter/lib/src/channel_image.dart index 74983505..3f3a38be 100644 --- a/packages/stream_chat_flutter/lib/src/channel_image.dart +++ b/packages/stream_chat_flutter/lib/src/channel_image.dart @@ -36,12 +36,14 @@ import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; /// } /// ``` /// -/// The widget uses a [StreamBuilder] to render the channel information image as soon as it updates. +/// The widget uses a [StreamBuilder] to render the channel information +/// image as soon as it updates. /// /// By default the widget radius size is 40x40 pixels. /// Set the property [constraints] to set a custom dimension. /// -/// The widget renders the ui based on the first ancestor of type [StreamChatTheme]. +/// The widget renders the ui based on the first ancestor of type +/// [StreamChatTheme]. /// Modify it to change the widget appearance. class ChannelImage extends StatelessWidget { /// Instantiate a new ChannelImage @@ -56,6 +58,7 @@ class ChannelImage extends StatelessWidget { this.selectionThickness = 4, }) : super(key: key); + /// [BorderRadius] to display the widget final BorderRadius? borderRadius; /// The channel to show the image of @@ -67,10 +70,13 @@ class ChannelImage extends StatelessWidget { /// The function called when the image is tapped final VoidCallback? onTap; + /// If image is selected final bool selected; + /// Selection color for image final Color? selectionColor; + /// Thickness of selection image final double selectionThickness; @override @@ -91,8 +97,7 @@ class ChannelImage extends StatelessWidget { stream: streamChat.client.state.usersStream.map( (users) => users[otherMember?.userId] ?? otherMember!.user!), initialData: otherMember!.user, - builder: (context, snapshot) { - return UserAvatar( + builder: (context, snapshot) => UserAvatar( borderRadius: borderRadius ?? StreamChatTheme.of(context) .channelPreviewTheme @@ -109,14 +114,14 @@ class ChannelImage extends StatelessWidget { selectionColor: selectionColor ?? StreamChatTheme.of(context).colorTheme.accentBlue, selectionThickness: selectionThickness, - ); - }); + )); } else { final images = channel.state?.members .where((member) => member.user?.id != streamChat.user?.id && member.user?.extraData['image'] != null) .take(4) + // ignore: cast_nullable_to_non_nullable .map((e) => e.user?.extraData['image'] as String) .toList(); return GroupImage( @@ -161,8 +166,7 @@ class ChannelImage extends StatelessWidget { if (image != null) CachedNetworkImage( imageUrl: image, - errorWidget: (_, __, ___) { - return Center( + errorWidget: (_, __, ___) => Center( child: Text( snapshot.data?.containsKey('name') ?? false ? snapshot.data!['name'][0] @@ -172,8 +176,7 @@ class ChannelImage extends StatelessWidget { fontWeight: FontWeight.bold, ), ), - ); - }, + ), fit: BoxFit.cover, ) else diff --git a/packages/stream_chat_flutter/lib/src/channel_info.dart b/packages/stream_chat_flutter/lib/src/channel_info.dart index abd1680c..72f6cf18 100644 --- a/packages/stream_chat_flutter/lib/src/channel_info.dart +++ b/packages/stream_chat_flutter/lib/src/channel_info.dart @@ -6,6 +6,14 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'connection_status_builder.dart'; class ChannelInfo extends StatelessWidget { + const ChannelInfo({ + Key? key, + required this.channel, + this.textStyle, + this.showTypingIndicator = true, + }) : super(key: key); + + /// The channel about which the info is to be displayed final Channel channel; /// The style of the text displayed @@ -14,13 +22,6 @@ class ChannelInfo extends StatelessWidget { /// If true the typing indicator will be rendered if a user is typing final bool showTypingIndicator; - const ChannelInfo({ - Key? key, - required this.channel, - this.textStyle, - this.showTypingIndicator = true, - }) : super(key: key); - @override Widget build(BuildContext context) { final client = StreamChat.of(context).client; @@ -93,10 +94,10 @@ class ChannelInfo extends StatelessWidget { Widget _buildConnectingTitleState(BuildContext context) => Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - Container( + const SizedBox( height: 16, width: 16, - child: const Center( + child: Center( child: CircularProgressIndicator(), ), ), diff --git a/packages/stream_chat_flutter/lib/src/channel_list_header.dart b/packages/stream_chat_flutter/lib/src/channel_list_header.dart index bb103f7b..c8d2aa69 100644 --- a/packages/stream_chat_flutter/lib/src/channel_list_header.dart +++ b/packages/stream_chat_flutter/lib/src/channel_list_header.dart @@ -6,10 +6,7 @@ import 'package:stream_chat_flutter/src/stream_neumorphic_button.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; -import 'connection_status_builder.dart'; -import 'info_tile.dart'; -import 'stream_chat.dart'; - +/// Widget builder for title typedef TitleBuilder = Widget Function( BuildContext context, ConnectionStatus status, @@ -42,10 +39,13 @@ typedef TitleBuilder = Widget Function( /// Usually you would use this widget as an [AppBar] inside a [Scaffold]. /// However you can also use it as a normal widget. /// -/// The widget by default uses the inherited [StreamChatClient] to fetch information about the status. -/// However you can also pass your own [StreamChatClient] if you don't have it in the widget tree. +/// The widget by default uses the inherited [StreamChatClient] +/// to fetch information about the status. +/// However you can also pass your own [StreamChatClient] +/// if you don't have it in the widget tree. /// -/// The widget components render the ui based on the first ancestor of type [StreamChatTheme] and on its [ChannelListHeaderTheme] property. +/// The widget components render the ui based on the first ancestor of type +/// [StreamChatTheme] and on its [ChannelListHeaderTheme] property. /// Modify it to change the widget appearance. class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { /// Instantiates a ChannelListHeader @@ -75,8 +75,10 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { /// Callback to call when pressing the new chat button. final VoidCallback? onNewChatButtonTap; + /// Show connection state tile final bool showConnectionStateTile; + /// Callback before navigation is performed final VoidCallback? preNavigationCallback; /// Subtitle widget @@ -113,6 +115,7 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { } return InfoTile( + // ignore: avoid_bool_literals_in_conditional_expressions showMessage: showConnectionStateTile ? showStatus : false, message: statusString, child: AppBar( @@ -143,7 +146,7 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { .avatarTheme ?.constraints, ) - : Offstage(), + : const Offstage(), ), actions: actions ?? [ @@ -151,7 +154,7 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { child: IconButton( icon: ConnectionStatusBuilder( statusBuilder: (context, status) { - var color; + Color? color; switch (status) { case ConnectionStatus.connected: color = StreamChatTheme.of(context) @@ -193,11 +196,11 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { case ConnectionStatus.disconnected: return _buildDisconnectedTitleState(context, _client); default: - return Offstage(); + return const Offstage(); } }, ), - subtitle ?? Offstage(), + subtitle ?? const Offstage(), ], ), ), @@ -213,18 +216,17 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { ), ); - Widget _buildConnectingTitleState(BuildContext context) { - return Row( + Widget _buildConnectingTitleState(BuildContext context) => Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - Container( + const SizedBox( height: 16, width: 16, child: Center( child: CircularProgressIndicator(), ), ), - SizedBox(width: 10), + const SizedBox(width: 10), Text( 'Searching for Network', style: StreamChatTheme.of(context) @@ -237,13 +239,11 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { ), ], ); - } Widget _buildDisconnectedTitleState( BuildContext context, StreamChatClient client, - ) { - return Row( + ) => Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( @@ -275,8 +275,7 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { ), ], ); - } @override - Size get preferredSize => Size.fromHeight(kToolbarHeight); + Size get preferredSize => const Size.fromHeight(kToolbarHeight); } diff --git a/packages/stream_chat_flutter/lib/src/channel_list_view.dart b/packages/stream_chat_flutter/lib/src/channel_list_view.dart index 473007db..c58ed42f 100644 --- a/packages/stream_chat_flutter/lib/src/channel_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/channel_list_view.dart @@ -3,13 +3,12 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_slidable/flutter_slidable.dart'; import 'package:shimmer/shimmer.dart'; +import 'package:stream_chat_flutter/src/channel_bottom_sheet.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import 'package:stream_chat_flutter/src/utils.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; -import '../stream_chat_flutter.dart'; -import 'channel_bottom_sheet.dart'; -import 'channel_preview.dart'; /// Callback called when tapping on a channel typedef ChannelTapCallback = void Function(Channel, Widget?); @@ -17,6 +16,7 @@ typedef ChannelTapCallback = void Function(Channel, Widget?); /// Builder used to create a custom [ChannelPreview] from a [Channel] typedef ChannelPreviewBuilder = Widget Function(BuildContext, Channel); +/// Callback for when 'View Info' is tapped typedef ViewInfoCallback = void Function(Channel); /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/channel_list_view.png) @@ -47,10 +47,12 @@ typedef ViewInfoCallback = void Function(Channel); /// ``` /// /// -/// Make sure to have a [StreamChat] ancestor in order to provide the information about the channels. +/// Make sure to have a [StreamChat] ancestor in order to provide the +/// information about the channels. /// The widget uses a [ListView.custom] to render the list of channels. /// -/// The widget components render the ui based on the first ancestor of type [StreamChatTheme]. +/// The widget components render the ui based on the first ancestor of +/// type [StreamChatTheme]. /// Modify it to change the widget appearance. class ChannelListView extends StatefulWidget { /// Instantiate a new ChannelListView @@ -94,8 +96,10 @@ class ChannelListView extends StatefulWidget { final Map? options; /// The sorting used for the channels matching the filters. - /// Sorting is based on field and direction, multiple sorting options can be provided. - /// You can sort based on last_updated, last_message_at, updated_at, created_at or member_count. + /// Sorting is based on field and direction, multiple sorting options + /// can be provided. + /// You can sort based on last_updated, last_message_at, updated_at, + /// created_at or member_count. /// Direction can be ascending or descending. final List>? sort; @@ -137,8 +141,10 @@ class ChannelListView extends StatefulWidget { /// The amount of space by which to inset the children. final EdgeInsetsGeometry? padding; + /// List of selected channels which are displayed differently final List selectedChannels; + /// Callback for when 'View Info' is tapped final ViewInfoCallback? onViewInfoTap; /// The builder that will be used in case of error @@ -203,15 +209,14 @@ class _ChannelListViewState extends State { crossAxisCount: widget.crossAxisCount, ), itemCount: channels.length, - physics: AlwaysScrollableScrollPhysics(), - itemBuilder: (context, index) { - return _gridItemBuilder(context, index, channels); - }, + physics: const AlwaysScrollableScrollPhysics(), + itemBuilder: (context, index) => + _gridItemBuilder(context, index, channels), ); } else { child = ListView.separated( padding: widget.padding, - physics: AlwaysScrollableScrollPhysics(), + physics: const AlwaysScrollableScrollPhysics(), itemCount: channels.isNotEmpty ? channels.length + 1 : channels.length, separatorBuilder: (_, index) { @@ -220,9 +225,8 @@ class _ChannelListViewState extends State { } return _separatorBuilder(context, index); }, - itemBuilder: (context, index) { - return _listItemBuilder(context, index, channels); - }, + itemBuilder: (context, index) => + _listItemBuilder(context, index, channels), ); } } @@ -233,11 +237,9 @@ class _ChannelListViewState extends State { ); } - Widget _buildEmptyWidget(BuildContext context) { - return LayoutBuilder( - builder: (context, viewportConstraints) { - return SingleChildScrollView( - physics: AlwaysScrollableScrollPhysics(), + Widget _buildEmptyWidget(BuildContext context) => LayoutBuilder( + builder: (context, viewportConstraints) => SingleChildScrollView( + physics: const AlwaysScrollableScrollPhysics(), child: Stack( children: [ ConstrainedBox( @@ -307,31 +309,27 @@ class _ChannelListViewState extends State { ), ], ), - ); - }, - ); - } + ), + ); - Widget _buildLoadingWidget(BuildContext context) { - return ListView( - padding: widget.padding, - physics: AlwaysScrollableScrollPhysics(), - children: List.generate( - 25, - (i) { - if (widget.crossAxisCount == 1) { - if (i % 2 != 0) { - if (widget.separatorBuilder != null) { - return widget.separatorBuilder!(context, i); + Widget _buildLoadingWidget(BuildContext context) => ListView( + padding: widget.padding, + physics: const AlwaysScrollableScrollPhysics(), + children: List.generate( + 25, + (i) { + if (widget.crossAxisCount == 1) { + if (i % 2 != 0) { + if (widget.separatorBuilder != null) { + return widget.separatorBuilder!(context, i); + } + return _separatorBuilder(context, i); } - return _separatorBuilder(context, i); } - } - return _buildLoadingItem(context); - }, - ), - ); - } + return _buildLoadingItem(context); + }, + ), + ); Shimmer _buildLoadingItem(BuildContext context) { if (widget.crossAxisCount > 1) { @@ -340,24 +338,24 @@ class _ChannelListViewState extends State { highlightColor: StreamChatTheme.of(context).colorTheme.whiteSmoke, child: Column( children: [ - SizedBox(height: 4), + const SizedBox(height: 4), Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ for (int i = 0; i < widget.crossAxisCount; i++) Container( - decoration: BoxDecoration( + decoration: const BoxDecoration( color: Colors.white, shape: BoxShape.circle, ), - constraints: BoxConstraints.tightFor( + constraints: const BoxConstraints.tightFor( height: 70, width: 70, ), ), ], ), - SizedBox( + const SizedBox( height: 16, ), ], @@ -373,7 +371,7 @@ class _ChannelListViewState extends State { color: StreamChatTheme.of(context).colorTheme.white, shape: BoxShape.circle, ), - constraints: BoxConstraints.tightFor( + constraints: const BoxConstraints.tightFor( height: 40, width: 40, ), @@ -389,7 +387,7 @@ class _ChannelListViewState extends State { color: StreamChatTheme.of(context).colorTheme.white, borderRadius: BorderRadius.circular(11), ), - constraints: BoxConstraints.tightFor( + constraints: const BoxConstraints.tightFor( height: 16, width: 82, ), @@ -406,7 +404,7 @@ class _ChannelListViewState extends State { color: StreamChatTheme.of(context).colorTheme.white, borderRadius: BorderRadius.circular(11), ), - constraints: BoxConstraints.expand( + constraints: const BoxConstraints.expand( height: 16, ), ), @@ -418,7 +416,7 @@ class _ChannelListViewState extends State { color: StreamChatTheme.of(context).colorTheme.white, borderRadius: BorderRadius.circular(11), ), - constraints: BoxConstraints.tightFor( + constraints: const BoxConstraints.tightFor( height: 16, width: 42, ), @@ -430,35 +428,33 @@ class _ChannelListViewState extends State { } } - Widget _buildErrorWidget(BuildContext context, Object error) { - return Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text.rich( - TextSpan( - children: [ - WidgetSpan( - child: Padding( - padding: const EdgeInsets.only( - right: 2, + Widget _buildErrorWidget(BuildContext context, Object error) => Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text.rich( + const TextSpan( + children: [ + WidgetSpan( + child: Padding( + padding: EdgeInsets.only( + right: 2, + ), + child: Icon(Icons.error_outline), ), - child: Icon(Icons.error_outline), ), - ), - TextSpan(text: 'Error loading channels'), - ], + TextSpan(text: 'Error loading channels'), + ], + ), + style: Theme.of(context).textTheme.headline6, ), - style: Theme.of(context).textTheme.headline6, - ), - TextButton( - onPressed: () => _channelListController.loadData!(), - child: Text('Retry'), - ), - ], - ), - ); - } + TextButton( + onPressed: () => _channelListController.loadData!(), + child: const Text('Retry'), + ), + ], + ), + ); Widget _listItemBuilder(BuildContext context, int i, List channels) { final channelsProvider = ChannelsBloc.of(context); @@ -471,82 +467,77 @@ class _ChannelListViewState extends State { key: ValueKey('CHANNEL-${channel.id}'), channel: channel, child: Builder( - builder: (context) { - return Slidable( - controller: _slideController, - enabled: widget.swipeToAction, - actionPane: SlidableBehindActionPane(), - actionExtentRatio: 0.12, - secondaryActions: [ + builder: (context) => Slidable( + controller: _slideController, + enabled: widget.swipeToAction, + actionPane: const SlidableBehindActionPane(), + actionExtentRatio: 0.12, + secondaryActions: [ + IconSlideAction( + color: backgroundColor, + icon: Icons.more_horiz, + onTap: () { + showModalBottomSheet( + clipBehavior: Clip.hardEdge, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(32), + topRight: Radius.circular(32), + ), + ), + context: context, + builder: (context) => StreamChannel( + channel: channel, + child: ChannelBottomSheet( + onViewInfoTap: () { + widget.onViewInfoTap?.call(channel); + }, + ), + ), + ); + }, + ), + if ([ + 'admin', + 'owner', + ].contains(channel.state!.members + .firstWhereOrNull( + (m) => m.userId == channel.client.state.user?.id) + ?.role)) IconSlideAction( color: backgroundColor, - icon: Icons.more_horiz, - onTap: () { - showModalBottomSheet( - clipBehavior: Clip.hardEdge, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.only( - topLeft: Radius.circular(32), - topRight: Radius.circular(32), - ), + iconWidget: StreamSvgIcon.delete( + color: StreamChatTheme.of(context).colorTheme.accentRed, + ), + onTap: () async { + final res = await showConfirmationDialog( + context, + title: 'Delete Conversation', + okText: 'DELETE', + question: + 'Are you sure you want to delete this conversation?', + cancelText: 'CANCEL', + icon: StreamSvgIcon.delete( + color: StreamChatTheme.of(context).colorTheme.accentRed, ), - context: context, - builder: (context) { - return StreamChannel( - channel: channel, - child: ChannelBottomSheet( - onViewInfoTap: () { - widget.onViewInfoTap?.call(channel); - }, - ), - ); - }, ); + if (res == true) { + await channel.delete(); + } }, ), - if ([ - 'admin', - 'owner', - ].contains(channel.state!.members - .firstWhereOrNull( - (m) => m.userId == channel.client.state.user?.id) - ?.role)) - IconSlideAction( - color: backgroundColor, - iconWidget: StreamSvgIcon.delete( - color: StreamChatTheme.of(context).colorTheme.accentRed, - ), - onTap: () async { - final res = await showConfirmationDialog( - context, - title: 'Delete Conversation', - okText: 'DELETE', - question: - 'Are you sure you want to delete this conversation?', - cancelText: 'CANCEL', - icon: StreamSvgIcon.delete( - color: - StreamChatTheme.of(context).colorTheme.accentRed, - ), - ); - if (res == true) { - await channel.delete(); - } - }, + ], + child: Container( + color: StreamChatTheme.of(context).colorTheme.whiteSnow, + child: widget.channelPreviewBuilder?.call(context, channel) ?? + ChannelPreview( + onLongPress: widget.onChannelLongPress, + channel: channel, + onImageTap: () => widget.onImageTap?.call(channel), + onTap: (channel) => onTap(channel, widget.channelWidget), ), - ], - child: Container( - color: StreamChatTheme.of(context).colorTheme.whiteSnow, - child: widget.channelPreviewBuilder?.call(context, channel) ?? - ChannelPreview( - onLongPress: widget.onChannelLongPress, - channel: channel, - onImageTap: () => widget.onImageTap?.call(channel), - onTap: (channel) => onTap(channel, widget.channelWidget), - ), - ), - ); - }, + ), + ), ), ); } else { @@ -566,12 +557,10 @@ class _ChannelListViewState extends State { Navigator.push( context, MaterialPageRoute( - builder: (context) { - return StreamChannel( - channel: client, - child: widget.channelWidget!, - ); - }, + builder: (context) => StreamChannel( + channel: client, + child: widget.channelWidget!, + ), ), ); }; @@ -593,18 +582,18 @@ class _ChannelListViewState extends State { channel: channel, borderRadius: BorderRadius.circular(32), selected: selected, - constraints: BoxConstraints.tightFor( + constraints: const BoxConstraints.tightFor( width: 64, height: 64, ), onTap: () => _getChannelTap(context), ), - SizedBox(height: 7), + const SizedBox(height: 7), Padding( padding: const EdgeInsets.symmetric(horizontal: 8), child: StreamChannel( channel: channel, - child: ChannelName( + child: const ChannelName( textStyle: TextStyle( fontSize: 12, fontWeight: FontWeight.w600, @@ -620,35 +609,34 @@ class _ChannelListViewState extends State { Widget _buildQueryProgressIndicator( context, ChannelsBlocState channelsProvider, - ) { - return StreamBuilder( - stream: channelsProvider.queryChannelsLoading, - initialData: false, - builder: (context, snapshot) { - if (snapshot.hasError) { - return Container( - color: StreamChatTheme.of(context) - .colorTheme - .accentRed - .withOpacity(.2), - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 16), - child: Center( - child: Text('Error loading channels'), - ), - ), - ); - } - return snapshot.data! - ? Center( - child: Padding( - padding: const EdgeInsets.all(16), - child: const CircularProgressIndicator(), + ) => + StreamBuilder( + stream: channelsProvider.queryChannelsLoading, + initialData: false, + builder: (context, snapshot) { + if (snapshot.hasError) { + return Container( + color: StreamChatTheme.of(context) + .colorTheme + .accentRed + .withOpacity(.2), + child: const Padding( + padding: EdgeInsets.symmetric(vertical: 16), + child: Center( + child: Text('Error loading channels'), ), - ) - : Offstage(); - }); - } + ), + ); + } + return snapshot.data! + ? const Center( + child: Padding( + padding: EdgeInsets.all(16), + child: CircularProgressIndicator(), + ), + ) + : const Offstage(); + }); Widget _separatorBuilder(context, i) { final effect = StreamChatTheme.of(context).colorTheme.borderBottom; diff --git a/packages/stream_chat_flutter/lib/src/channel_name.dart b/packages/stream_chat_flutter/lib/src/channel_name.dart index 48657419..d76bca0c 100644 --- a/packages/stream_chat_flutter/lib/src/channel_name.dart +++ b/packages/stream_chat_flutter/lib/src/channel_name.dart @@ -1,12 +1,13 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; -import '../stream_chat_flutter.dart'; /// It shows the current [Channel] name using a [Text] widget. /// -/// The widget uses a [StreamBuilder] to render the channel information image as soon as it updates. +/// The widget uses a [StreamBuilder] to render the channel information +/// image as soon as it updates. class ChannelName extends StatelessWidget { /// Instantiate a new ChannelName const ChannelName({ @@ -25,9 +26,8 @@ class ChannelName extends StatelessWidget { return StreamBuilder>( stream: channel.extraDataStream, initialData: channel.extraData, - builder: (context, snapshot) { - return _buildName(snapshot.data!, channel.state?.members, client); - }, + builder: (context, snapshot) => + _buildName(snapshot.data!, channel.state?.members, client), ); } @@ -35,45 +35,46 @@ class ChannelName extends StatelessWidget { Map extraData, List? members, StreamChatState client, - ) { - return LayoutBuilder( - builder: (context, constraints) { - String? title; - if (extraData['name'] == null) { - final otherMembers = - members?.where((member) => member.userId != client.user!.id); - if (otherMembers?.length == 1) { - title = otherMembers!.first.user?.name; - } else if (otherMembers?.isNotEmpty == true) { - final maxWidth = constraints.maxWidth; - final maxChars = maxWidth / (textStyle?.fontSize ?? 1); - var currentChars = 0; - final currentMembers = []; - otherMembers!.forEach((element) { - final newLength = currentChars + (element.user?.name.length ?? 0); - if (newLength < maxChars) { - currentChars = newLength; - currentMembers.add(element); - } - }); + ) => + LayoutBuilder( + builder: (context, constraints) { + String? title; + if (extraData['name'] == null) { + final otherMembers = + members?.where((member) => member.userId != client.user!.id); + if (otherMembers?.length == 1) { + title = otherMembers!.first.user?.name; + } else if (otherMembers?.isNotEmpty == true) { + final maxWidth = constraints.maxWidth; + final maxChars = maxWidth / (textStyle?.fontSize ?? 1); + var currentChars = 0; + final currentMembers = []; + otherMembers!.forEach((element) { + final newLength = + currentChars + (element.user?.name.length ?? 0); + if (newLength < maxChars) { + currentChars = newLength; + currentMembers.add(element); + } + }); - final exceedingMembers = - otherMembers.length - currentMembers.length; - title = - '${currentMembers.map((e) => e.user?.name).join(', ')} ${exceedingMembers > 0 ? '+ $exceedingMembers' : ''}'; + final exceedingMembers = + otherMembers.length - currentMembers.length; + title = + '${currentMembers.map((e) => e.user?.name).join(', ')} ' + '${exceedingMembers > 0 ? '+ $exceedingMembers' : ''}'; + } else { + title = 'No title'; + } } else { - title = 'No title'; + title = extraData['name']; } - } else { - title = extraData['name']; - } - return Text( - title!, - style: textStyle, - overflow: TextOverflow.ellipsis, - ); - }, - ); - } + return Text( + title!, + style: textStyle, + overflow: TextOverflow.ellipsis, + ); + }, + ); } diff --git a/packages/stream_chat_flutter/lib/src/channel_preview.dart b/packages/stream_chat_flutter/lib/src/channel_preview.dart index 9c396065..9c793ba6 100644 --- a/packages/stream_chat_flutter/lib/src/channel_preview.dart +++ b/packages/stream_chat_flutter/lib/src/channel_preview.dart @@ -3,23 +3,39 @@ import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:jiffy/jiffy.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; -import '../stream_chat_flutter.dart'; -import 'channel_name.dart'; - /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/channel_preview.png) /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/channel_preview_paint.png) /// /// It shows the current [Channel] preview. /// -/// The widget uses a [StreamBuilder] to render the channel information image as soon as it updates. +/// The widget uses a [StreamBuilder] to render the channel information +/// image as soon as it updates. /// -/// Usually you don't use this widget as it's the default channel preview used by [ChannelListView]. +/// Usually you don't use this widget as it's the default channel preview +/// used by [ChannelListView]. /// -/// The widget renders the ui based on the first ancestor of type [StreamChatTheme]. +/// The widget renders the ui based on the first ancestor of type +/// [StreamChatTheme]. /// Modify it to change the widget appearance. class ChannelPreview extends StatelessWidget { + + /// Constructor for creating [ChannelPreview] + const ChannelPreview({ + required this.channel, + Key? key, + this.onTap, + this.onLongPress, + this.onImageTap, + this.title, + this.subtitle, + this.leading, + this.sendingIndicator, + this.trailing, + }) : super(key: key); + /// Function called when tapping this widget final void Function(Channel)? onTap; @@ -38,156 +54,145 @@ class ChannelPreview extends StatelessWidget { /// Widget rendering the subtitle final Widget? subtitle; - /// Widget rendering the leading element, by default it shows the [ChannelImage] + /// Widget rendering the leading element, by default + /// it shows the [ChannelImage] final Widget? leading; - /// Widget rendering the trailing element, by default it shows the last message date + /// Widget rendering the trailing element, + /// by default it shows the last message date final Widget? trailing; - /// 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; - const ChannelPreview({ - required this.channel, - Key? key, - this.onTap, - this.onLongPress, - this.onImageTap, - this.title, - this.subtitle, - this.leading, - this.sendingIndicator, - this.trailing, - }) : super(key: key); - @override Widget build(BuildContext context) { final channelPreviewTheme = StreamChatTheme.of(context).channelPreviewTheme; return StreamBuilder( stream: channel.isMutedStream, initialData: channel.isMuted, - builder: (context, snapshot) { - return Opacity( - opacity: snapshot.data! ? 0.5 : 1, - child: ListTile( - visualDensity: VisualDensity.compact, - contentPadding: const EdgeInsets.symmetric( - horizontal: 8, - ), - onTap: () { - if (onTap != null) { - onTap!(channel); - } - }, - onLongPress: () { - if (onLongPress != null) { - onLongPress!(channel); - } - }, - leading: leading ?? - ChannelImage( - onTap: onImageTap, - ), - title: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Flexible( - child: title ?? - ChannelName( - textStyle: channelPreviewTheme.title, - ), - ), - StreamBuilder>( - stream: channel.state?.membersStream, - initialData: channel.state?.members, - builder: (context, snapshot) { - if (!snapshot.hasData || - snapshot.data!.isEmpty || - !snapshot.data!.any((Member e) => - e.user!.id == channel.client.state.user?.id)) { - return SizedBox(); - } - return UnreadIndicator( - cid: channel.cid, - ); - }, - ), - ], - ), - subtitle: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Flexible(child: subtitle ?? _buildSubtitle(context)), - sendingIndicator ?? - Builder( - builder: (context) { - final lastMessage = - channel.state?.messages.lastWhereOrNull( - (m) => !m.isDeleted && m.shadowed != true, - ); - if (lastMessage?.user?.id == - StreamChat.of(context).user?.id) { - return Padding( - padding: const EdgeInsets.only(right: 4), - child: SendingIndicator( - message: lastMessage!, - size: channelPreviewTheme.indicatorIconSize, - isMessageRead: channel.state!.read - ?.where((element) => - element.user.id != - channel.client.state.user!.id) - .where((element) => element.lastRead - .isAfter(lastMessage.createdAt)) - .isNotEmpty == - true, - ), + builder: (context, snapshot) => Opacity( + opacity: snapshot.data! ? 0.5 : 1, + child: ListTile( + visualDensity: VisualDensity.compact, + contentPadding: const EdgeInsets.symmetric( + horizontal: 8, + ), + onTap: () { + if (onTap != null) { + onTap!(channel); + } + }, + onLongPress: () { + if (onLongPress != null) { + onLongPress!(channel); + } + }, + leading: leading ?? + ChannelImage( + onTap: onImageTap, + ), + title: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Flexible( + child: title ?? + ChannelName( + textStyle: channelPreviewTheme.title, + ), + ), + StreamBuilder>( + stream: channel.state?.membersStream, + initialData: channel.state?.members, + builder: (context, snapshot) { + if (!snapshot.hasData || + snapshot.data!.isEmpty || + !snapshot.data!.any((Member e) => + e.user!.id == channel.client.state.user?.id)) { + return const SizedBox(); + } + return UnreadIndicator( + cid: channel.cid, + ); + }, + ), + ], + ), + subtitle: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Flexible(child: subtitle ?? _buildSubtitle(context)), + sendingIndicator ?? + Builder( + builder: (context) { + final lastMessage = + channel.state?.messages.lastWhereOrNull( + (m) => !m.isDeleted && m.shadowed != true, ); - } - return SizedBox(); - }, - ), - trailing ?? _buildDate(context), - ], + if (lastMessage?.user?.id == + StreamChat.of(context).user?.id) { + return Padding( + padding: const EdgeInsets.only(right: 4), + child: SendingIndicator( + message: lastMessage!, + size: channelPreviewTheme.indicatorIconSize, + isMessageRead: channel.state!.read + ?.where((element) => + element.user.id != + channel.client.state.user!.id) + .where((element) => element.lastRead + .isAfter(lastMessage.createdAt)) + .isNotEmpty == + true, + ), + ); + } + return const SizedBox(); + }, + ), + trailing ?? _buildDate(context), + ], + ), ), - ), + )); + } + + Widget _buildDate(BuildContext context) => StreamBuilder( + stream: channel.lastMessageAtStream, + initialData: channel.lastMessageAt, + builder: (context, snapshot) { + if (!snapshot.hasData) { + return const SizedBox(); + } + final lastMessageAt = snapshot.data!.toLocal(); + + String stringDate; + final now = DateTime.now(); + + final startOfDay = DateTime(now.year, now.month, now.day); + + if (lastMessageAt.millisecondsSinceEpoch >= + startOfDay.millisecondsSinceEpoch) { + stringDate = Jiffy(lastMessageAt.toLocal()).jm; + } else if (lastMessageAt.millisecondsSinceEpoch >= + startOfDay + .subtract(const Duration(days: 1)) + .millisecondsSinceEpoch) { + stringDate = 'Yesterday'; + } else if (startOfDay.difference(lastMessageAt).inDays < 7) { + stringDate = Jiffy(lastMessageAt.toLocal()).EEEE; + } else { + stringDate = Jiffy(lastMessageAt.toLocal()).yMd; + } + + return Text( + stringDate, + style: + StreamChatTheme.of(context).channelPreviewTheme.lastMessageAt, ); - }); - } - - Widget _buildDate(BuildContext context) { - return StreamBuilder( - stream: channel.lastMessageAtStream, - initialData: channel.lastMessageAt, - builder: (context, snapshot) { - if (!snapshot.hasData) { - return SizedBox(); - } - final lastMessageAt = snapshot.data!.toLocal(); - - String stringDate; - final now = DateTime.now(); - - final startOfDay = DateTime(now.year, now.month, now.day); - - if (lastMessageAt.millisecondsSinceEpoch >= - startOfDay.millisecondsSinceEpoch) { - stringDate = Jiffy(lastMessageAt.toLocal()).jm; - } else if (lastMessageAt.millisecondsSinceEpoch >= - startOfDay.subtract(Duration(days: 1)).millisecondsSinceEpoch) { - stringDate = 'Yesterday'; - } else if (startOfDay.difference(lastMessageAt).inDays < 7) { - stringDate = Jiffy(lastMessageAt.toLocal()).EEEE; - } else { - stringDate = Jiffy(lastMessageAt.toLocal()).yMd; - } - - return Text( - stringDate, - style: StreamChatTheme.of(context).channelPreviewTheme.lastMessageAt, - ); - }, - ); - } + }, + ); Widget _buildSubtitle(BuildContext context) { if (channel.isMuted) { @@ -211,66 +216,71 @@ class ChannelPreview extends StatelessWidget { ); } - Widget _buildLastMessage(BuildContext context) { - return StreamBuilder?>( - stream: channel.state!.messagesStream, - initialData: channel.state!.messages, - builder: (context, snapshot) { - final lastMessage = snapshot.data - ?.lastWhereOrNull((m) => m.shadowed != true && !m.isDeleted); - if (lastMessage == null) { - return SizedBox(); - } + Widget _buildLastMessage(BuildContext context) => + StreamBuilder?>( + stream: channel.state!.messagesStream, + initialData: channel.state!.messages, + builder: (context, snapshot) { + final lastMessage = snapshot.data + ?.lastWhereOrNull((m) => m.shadowed != true && !m.isDeleted); + if (lastMessage == null) { + return const SizedBox(); + } - var text = lastMessage.text; - final parts = [ - ...lastMessage.attachments.map((e) { - if (e.type == 'image') { - return '📷'; - } else if (e.type == 'video') { - return '🎬'; - } else if (e.type == 'giphy') { - return '[GIF]'; - } - return e == lastMessage.attachments.last - ? (e.title ?? 'File') - : '${e.title ?? 'File'} , '; - }), - lastMessage.text ?? '', - ]; + var text = lastMessage.text; + final parts = [ + ...lastMessage.attachments.map((e) { + if (e.type == 'image') { + return '📷'; + } else if (e.type == 'video') { + return '🎬'; + } else if (e.type == 'giphy') { + return '[GIF]'; + } + return e == lastMessage.attachments.last + ? (e.title ?? 'File') + : '${e.title ?? 'File'} , '; + }), + lastMessage.text ?? '', + ]; - text = parts.join(' '); + text = parts.join(' '); - return Text.rich( - _getDisplayText( - text, - lastMessage.mentionedUsers, - lastMessage.attachments, - StreamChatTheme.of(context).channelPreviewTheme.subtitle?.copyWith( - color: StreamChatTheme.of(context) - .channelPreviewTheme - .subtitle - ?.color, - fontStyle: (lastMessage.isSystem || lastMessage.isDeleted) - ? FontStyle.italic - : FontStyle.normal), - StreamChatTheme.of(context).channelPreviewTheme.subtitle?.copyWith( - color: StreamChatTheme.of(context) - .channelPreviewTheme - .subtitle - ?.color, - fontStyle: (lastMessage.isSystem || lastMessage.isDeleted) - ? FontStyle.italic - : FontStyle.normal, - fontWeight: FontWeight.bold, - ), - ), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ); - }, - ); - } + return Text.rich( + _getDisplayText( + text, + lastMessage.mentionedUsers, + lastMessage.attachments, + StreamChatTheme.of(context) + .channelPreviewTheme + .subtitle + ?.copyWith( + color: StreamChatTheme.of(context) + .channelPreviewTheme + .subtitle + ?.color, + fontStyle: (lastMessage.isSystem || lastMessage.isDeleted) + ? FontStyle.italic + : FontStyle.normal), + StreamChatTheme.of(context) + .channelPreviewTheme + .subtitle + ?.copyWith( + color: StreamChatTheme.of(context) + .channelPreviewTheme + .subtitle + ?.color, + fontStyle: (lastMessage.isSystem || lastMessage.isDeleted) + ? FontStyle.italic + : FontStyle.normal, + fontWeight: FontWeight.bold, + ), + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ); + }, + ); TextSpan _getDisplayText( String text, diff --git a/packages/stream_chat_flutter/lib/src/connection_status_builder.dart b/packages/stream_chat_flutter/lib/src/connection_status_builder.dart index 620c41ac..7e4e7f8e 100644 --- a/packages/stream_chat_flutter/lib/src/connection_status_builder.dart +++ b/packages/stream_chat_flutter/lib/src/connection_status_builder.dart @@ -1,13 +1,12 @@ 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 'stream_chat.dart'; - /// Widget that builds itself based on the latest snapshot of interaction with /// a [Stream] of type [ConnectionStatus]. /// -/// The widget will use the closest [StreamChatClient.wsConnectionStatusStream] in case no -/// stream is provided. +/// The widget will use the closest [StreamChatClient.wsConnectionStatusStream] +/// in case no stream is provided. class ConnectionStatusBuilder extends StatelessWidget { /// Creates a new ConnectionStatusBuilder const ConnectionStatusBuilder({ @@ -47,11 +46,11 @@ class ConnectionStatusBuilder extends StatelessWidget { if (errorBuilder != null) { return errorBuilder!(context, snapshot.error); } - return Offstage(); + return const Offstage(); } if (!snapshot.hasData) { if (loadingBuilder != null) return loadingBuilder!(context); - return Offstage(); + return const Offstage(); } return statusBuilder(context, snapshot.data!); }, diff --git a/packages/stream_chat_flutter/lib/src/date_divider.dart b/packages/stream_chat_flutter/lib/src/date_divider.dart index 3674e085..e1b9cfea 100644 --- a/packages/stream_chat_flutter/lib/src/date_divider.dart +++ b/packages/stream_chat_flutter/lib/src/date_divider.dart @@ -4,15 +4,20 @@ import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; /// It shows a date divider depending on the date difference class DateDivider extends StatelessWidget { - final DateTime dateTime; - final bool uppercase; + /// Constructor for creating a [DateDivider] const DateDivider({ Key? key, required this.dateTime, this.uppercase = false, }) : super(key: key); + /// [DateTime] to display + final DateTime dateTime; + + /// If text is uppercase + final bool uppercase; + @override Widget build(BuildContext context) { final createdAt = Jiffy(dateTime); @@ -22,10 +27,10 @@ class DateDivider extends StatelessWidget { if (Jiffy(createdAt).isSame(now, Units.DAY)) { dayInfo = 'Today'; } else if (Jiffy(createdAt) - .isSame(now.subtract(Duration(days: 1)), Units.DAY)) { + .isSame(now.subtract(const Duration(days: 1)), Units.DAY)) { dayInfo = 'Yesterday'; } else if (Jiffy(createdAt).isAfter( - now.subtract(Duration(days: 7)), + now.subtract(const Duration(days: 7)), Units.DAY, )) { dayInfo = createdAt.EEEE; diff --git a/packages/stream_chat_flutter/lib/src/deleted_message.dart b/packages/stream_chat_flutter/lib/src/deleted_message.dart index 31a9995e..47a5f2ee 100644 --- a/packages/stream_chat_flutter/lib/src/deleted_message.dart +++ b/packages/stream_chat_flutter/lib/src/deleted_message.dart @@ -3,7 +3,10 @@ import 'dart:math'; import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; +/// Widget to display deleted message class DeletedMessage extends StatelessWidget { + + /// Constructor to create [DeletedMessage] const DeletedMessage({ Key? key, required this.messageTheme, @@ -29,8 +32,7 @@ class DeletedMessage extends StatelessWidget { final bool reverse; @override - Widget build(BuildContext context) { - return Transform( + Widget build(BuildContext context) => Transform( transform: Matrix4.rotationY(reverse ? pi : 0), alignment: Alignment.center, child: Material( @@ -70,5 +72,4 @@ class DeletedMessage extends StatelessWidget { ), ), ); - } } diff --git a/packages/stream_chat_flutter/lib/src/extension.dart b/packages/stream_chat_flutter/lib/src/extension.dart index 11ff3253..a65272c3 100644 --- a/packages/stream_chat_flutter/lib/src/extension.dart +++ b/packages/stream_chat_flutter/lib/src/extension.dart @@ -9,9 +9,7 @@ final _emojis = Emoji.all(); /// String extension extension StringExtension on String { /// Returns the capitalized string - String capitalize() { - return '${this[0].toUpperCase()}${substring(1)}'; - } + String capitalize() => '${this[0].toUpperCase()}${substring(1)}'; /// Returns whether the string contains only emoji's or not. /// @@ -46,7 +44,9 @@ extension PlatformFileX on PlatformFile { ); } +/// extension InputDecorationX on InputDecoration { + /// InputDecoration merge(InputDecoration? other) { if (other == null) return this; return copyWith( @@ -98,7 +98,9 @@ extension InputDecorationX on InputDecoration { } } +/// Gets text scale factor through context extension BuildContextX on BuildContext { + // ignore: public_member_api_docs double get textScaleFactor => MediaQuery.maybeOf(this)?.textScaleFactor ?? 1.0; } From c7b7618edf8e79c90eab1592e0bd1c74bbc252ed Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 5 May 2021 14:24:24 +0530 Subject: [PATCH 05/31] lint changes media --- .../lib/src/full_screen_media.dart | 357 +++++++++--------- .../lib/src/group_image.dart | 20 +- 2 files changed, 204 insertions(+), 173 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/full_screen_media.dart b/packages/stream_chat_flutter/lib/src/full_screen_media.dart index 4b56adc5..edebfa09 100644 --- a/packages/stream_chat_flutter/lib/src/full_screen_media.dart +++ b/packages/stream_chat_flutter/lib/src/full_screen_media.dart @@ -8,24 +8,24 @@ import 'package:jiffy/jiffy.dart'; import 'package:photo_view/photo_view.dart'; import 'package:stream_chat_flutter/src/image_footer.dart'; import 'package:stream_chat_flutter/src/image_header.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:video_player/video_player.dart'; -import '../stream_chat_flutter.dart'; +/// Return action for coming back from pages +enum ReturnActionType { -enum ReturnActionType { none, reply } + /// No return action + none, + /// Go to reply message action + reply, +} + +/// Callback when show message is tapped typedef ShowMessageCallback = void Function(Message message, Channel channel); /// A full screen image widget class FullScreenMedia extends StatefulWidget { - /// The url of the image - final List mediaAttachments; - final Message message; - - final int startIndex; - final String userName; - final ShowMessageCallback? onShowMessage; - /// Instantiate a new FullScreenImage const FullScreenMedia({ Key? key, @@ -37,6 +37,21 @@ class FullScreenMedia extends StatefulWidget { }) : userName = userName ?? '', super(key: key); + /// The url of the image + final List mediaAttachments; + + /// Message where attachments are attached + final Message message; + + /// First index of media shown + final int startIndex; + + /// Username of sender + final String userName; + + /// Callback for when show message is tapped + final ShowMessageCallback? onShowMessage; + @override _FullScreenMediaState createState() => _FullScreenMediaState(); } @@ -57,7 +72,7 @@ class _FullScreenMediaState extends State super.initState(); _controller = AnimationController( vsync: this, - duration: Duration(milliseconds: 300), + duration: const Duration(milliseconds: 300), ); _pageController = PageController(initialPage: widget.startIndex); _currentPage = widget.startIndex; @@ -77,139 +92,136 @@ class _FullScreenMediaState extends State } @override - Widget build(BuildContext context) { - return Scaffold( - resizeToAvoidBottomInset: false, - body: Stack( - children: [ - AnimatedBuilder( - animation: _controller, - builder: (context, snapshot) { - return PageView.builder( - controller: _pageController, - onPageChanged: (val) { - setState(() { - _currentPage = val; - }); - }, - itemBuilder: (context, index) { - final attachment = widget.mediaAttachments[index]; - if (attachment.type == 'image' || - attachment.type == 'giphy') { - final imageUrl = attachment.imageUrl ?? - attachment.assetUrl ?? - attachment.thumbUrl; - return PhotoView( - imageProvider: (imageUrl == null && - attachment.localUri != null && - attachment.file?.bytes != null) - ? Image.memory(attachment.file!.bytes!).image - : CachedNetworkImageProvider(imageUrl!), - maxScale: PhotoViewComputedScale.covered, - minScale: PhotoViewComputedScale.contained, - heroAttributes: PhotoViewHeroAttributes( - tag: widget.mediaAttachments, - ), - backgroundDecoration: BoxDecoration( - color: ColorTween( - begin: StreamChatTheme.of(context) - .channelTheme - .channelHeaderTheme - .color, - end: Colors.black, - ).lerp(_controller.value), - ), - onTapUp: (a, b, c) { - setState(() { - _optionsShown = !_optionsShown; - }); - if (_controller.isCompleted) { - _controller.reverse(); - } else { - _controller.forward(); + Widget build(BuildContext context) => Scaffold( + resizeToAvoidBottomInset: false, + body: Stack( + children: [ + AnimatedBuilder( + animation: _controller, + builder: (context, snapshot) => PageView.builder( + controller: _pageController, + onPageChanged: (val) { + setState(() { + _currentPage = val; + }); + }, + itemBuilder: (context, index) { + final attachment = widget.mediaAttachments[index]; + if (attachment.type == 'image' || + attachment.type == 'giphy') { + final imageUrl = attachment.imageUrl ?? + attachment.assetUrl ?? + attachment.thumbUrl; + return PhotoView( + imageProvider: (imageUrl == null && + attachment.localUri != null && + attachment.file?.bytes != null) + ? Image.memory(attachment.file!.bytes!).image + : CachedNetworkImageProvider(imageUrl!), + maxScale: PhotoViewComputedScale.covered, + minScale: PhotoViewComputedScale.contained, + heroAttributes: PhotoViewHeroAttributes( + tag: widget.mediaAttachments, + ), + backgroundDecoration: BoxDecoration( + color: ColorTween( + begin: StreamChatTheme.of(context) + .channelTheme + .channelHeaderTheme + .color, + end: Colors.black, + ).lerp(_controller.value), + ), + onTapUp: (a, b, c) { + setState(() { + _optionsShown = !_optionsShown; + }); + if (_controller.isCompleted) { + _controller.reverse(); + } else { + _controller.forward(); + } + }, + ); + } else if (attachment.type == 'video') { + final controller = videoPackages[attachment.id]!; + if (!controller.initialized) { + return const Center( + child: CircularProgressIndicator(), + ); } - }, - ); - } else if (attachment.type == 'video') { - final controller = videoPackages[attachment.id]!; - if (!controller.initialized) { - return Center( - child: CircularProgressIndicator(), - ); - } - return InkWell( - onTap: () { - setState(() { - _optionsShown = !_optionsShown; - }); - if (_controller.isCompleted) { - _controller.reverse(); - } else { - _controller.forward(); - } - }, - child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 50, - ), - child: Chewie( - controller: controller.chewieController!, - ), - ), - ); - } - return Container(); - }, - itemCount: widget.mediaAttachments.length, - ); - }), - AnimatedOpacity( - opacity: _optionsShown ? 1.0 : 0.0, - duration: Duration(milliseconds: 300), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - ImageHeader( - userName: widget.userName, - sentAt: - 'Sent ${getDay(widget.message.createdAt.toLocal())} at ${Jiffy(widget.message.createdAt.toLocal()).format('HH:mm')}', - onBackPressed: () { - Navigator.of(context).pop(); - }, - message: widget.message, - currentIndex: _currentPage, - onShowMessage: () { - widget.onShowMessage?.call( - widget.message, - StreamChannel.of(context).channel, - ); - }, - ), - if (widget.message.type != 'ephemeral') - ImageFooter( - currentPage: _currentPage, - totalPages: widget.mediaAttachments.length, - mediaAttachments: widget.mediaAttachments, + return InkWell( + onTap: () { + setState(() { + _optionsShown = !_optionsShown; + }); + if (_controller.isCompleted) { + _controller.reverse(); + } else { + _controller.forward(); + } + }, + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 50, + ), + child: Chewie( + controller: controller.chewieController!, + ), + ), + ); + } + return Container(); + }, + itemCount: widget.mediaAttachments.length, + )), + AnimatedOpacity( + opacity: _optionsShown ? 1.0 : 0.0, + duration: const Duration(milliseconds: 300), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + ImageHeader( + userName: widget.userName, + sentAt: + // ignore: lines_longer_than_80_chars + 'Sent ${getDay(widget.message.createdAt.toLocal())} at ${Jiffy(widget.message.createdAt.toLocal()).format('HH:mm')}', + onBackPressed: () { + Navigator.of(context).pop(); + }, message: widget.message, - mediaSelectedCallBack: (val) { - setState(() { - _currentPage = val; - _pageController.animateToPage( - val, - duration: Duration(milliseconds: 300), - curve: Curves.easeInOut, - ); - Navigator.pop(context); - }); + currentIndex: _currentPage, + onShowMessage: () { + widget.onShowMessage?.call( + widget.message, + StreamChannel.of(context).channel, + ); }, ), - ], + if (widget.message.type != 'ephemeral') + ImageFooter( + currentPage: _currentPage, + totalPages: widget.mediaAttachments.length, + mediaAttachments: widget.mediaAttachments, + message: widget.message, + mediaSelectedCallBack: (val) { + setState(() { + _currentPage = val; + _pageController.animateToPage( + val, + duration: const Duration(milliseconds: 300), + curve: Curves.easeInOut, + ); + Navigator.pop(context); + }); + }, + ), + ], + ), ), - ), - ], - ), - ); - } + ], + ), + ); String getDay(DateTime dateTime) { final now = DateTime.now(); @@ -236,47 +248,52 @@ class _FullScreenMediaState extends State } } +/// Class for packaging up things required for videos class VideoPackage { - final bool _showControls; - final bool _autoInitialize; - final VideoPlayerController _videoPlayerController; - ChewieController? _chewieController; - - VideoPlayerController get videoPlayer => _videoPlayerController; - - ChewieController? get chewieController => _chewieController; - - bool get initialized => _videoPlayerController.value.isInitialized; - + /// Constructor for creating [VideoPackage] VideoPackage( - Attachment attachment, { - bool showControls = false, - bool autoInitialize = true, - }) : _showControls = showControls, + Attachment attachment, { + bool showControls = false, + bool autoInitialize = true, + }) : _showControls = showControls, _autoInitialize = autoInitialize, _videoPlayerController = attachment.localUri != null ? VideoPlayerController.file(File.fromUri(attachment.localUri!)) : VideoPlayerController.network(attachment.assetUrl!); - Future initialize() { - return _videoPlayerController.initialize().then((_) { - _chewieController = ChewieController( - videoPlayerController: _videoPlayerController, - autoInitialize: _autoInitialize, - showControls: _showControls, - aspectRatio: _videoPlayerController.value.aspectRatio, - ); - }); - } + final bool _showControls; + final bool _autoInitialize; + final VideoPlayerController _videoPlayerController; + ChewieController? _chewieController; - void addListener(VoidCallback listener) { - return _videoPlayerController.addListener(listener); - } + /// Get video player for video + VideoPlayerController get videoPlayer => _videoPlayerController; - void removeListener(VoidCallback listener) { - return _videoPlayerController.removeListener(listener); - } + /// Get [ChewieController] for video + ChewieController? get chewieController => _chewieController; + /// Check if controller is initialised + bool get initialized => _videoPlayerController.value.isInitialized; + + /// Initialize all things required for [VideoPackage] + Future initialize() => _videoPlayerController.initialize().then((_) { + _chewieController = ChewieController( + videoPlayerController: _videoPlayerController, + autoInitialize: _autoInitialize, + showControls: _showControls, + aspectRatio: _videoPlayerController.value.aspectRatio, + ); + }); + + /// Add a listener to video player controller + void addListener(VoidCallback listener) => + _videoPlayerController.addListener(listener); + + /// Remove a listener to video player controller + void removeListener(VoidCallback listener) => + _videoPlayerController.removeListener(listener); + + /// Dispose controllers Future dispose() { _chewieController?.dispose(); return _videoPlayerController.dispose(); diff --git a/packages/stream_chat_flutter/lib/src/group_image.dart b/packages/stream_chat_flutter/lib/src/group_image.dart index 3e56eeae..e5c6ecd2 100644 --- a/packages/stream_chat_flutter/lib/src/group_image.dart +++ b/packages/stream_chat_flutter/lib/src/group_image.dart @@ -1,9 +1,10 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; -import '../stream_chat_flutter.dart'; - +/// Widget for constructing a group of images class GroupImage extends StatelessWidget { + /// Constructor for creating a [GroupImage] const GroupImage({ Key? key, required this.images, @@ -15,17 +16,30 @@ class GroupImage extends StatelessWidget { this.selectionThickness = 4, }) : super(key: key); + /// List of images to display final List images; + + /// Constraints on the widget final BoxConstraints? constraints; + + /// Callback when widget is tapped final VoidCallback? onTap; + + /// Highlights if selected final bool selected; + + /// [BorderRadius] to pass to the widget final BorderRadius? borderRadius; + + /// Color of selection if selected final Color? selectionColor; + + /// Thickness with which color of selection is shown final double selectionThickness; @override Widget build(BuildContext context) { - var avatar; + Widget? avatar; final streamChatTheme = StreamChatTheme.of(context); avatar = GestureDetector( From a688ab3a1097426a33a3c2d31ad8a217a3fb2e28 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 5 May 2021 14:59:21 +0530 Subject: [PATCH 06/31] lint changes image --- .../lib/src/attachment_actions_modal.dart | 43 +-- .../lib/src/back_button.dart | 63 +++-- .../lib/src/channel_image.dart | 50 ++-- .../lib/src/channel_list_header.dart | 99 +++---- .../lib/src/channel_list_view.dart | 1 - .../lib/src/channel_name.dart | 6 +- .../lib/src/channel_preview.dart | 1 - .../lib/src/date_divider.dart | 1 - .../lib/src/deleted_message.dart | 69 +++-- .../lib/src/full_screen_media.dart | 9 +- .../lib/src/image_footer.dart | 262 ++++++++---------- .../lib/src/image_group.dart | 153 +++++----- .../lib/src/image_header.dart | 160 +++++------ .../lib/src/message_input.dart | 213 +++++++------- 14 files changed, 561 insertions(+), 569 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/attachment_actions_modal.dart b/packages/stream_chat_flutter/lib/src/attachment_actions_modal.dart index a8d1bddd..a9ea651b 100644 --- a/packages/stream_chat_flutter/lib/src/attachment_actions_modal.dart +++ b/packages/stream_chat_flutter/lib/src/attachment_actions_modal.dart @@ -192,29 +192,30 @@ class AttachmentActionsModal extends StatelessWidget { VoidCallback? onTap, { Color? color, Key? key, - }) => Material( - key: key, - color: StreamChatTheme.of(context).colorTheme.white, - child: InkWell( - onTap: onTap, - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16), - child: Row( - children: [ - icon, - SizedBox(width: 16), - Text( - title, - style: StreamChatTheme.of(context) - .textTheme - .body - .copyWith(color: color), - ), - ], + }) => + Material( + key: key, + color: StreamChatTheme.of(context).colorTheme.white, + child: InkWell( + onTap: onTap, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16), + child: Row( + children: [ + icon, + SizedBox(width: 16), + Text( + title, + style: StreamChatTheme.of(context) + .textTheme + .body + .copyWith(color: color), + ), + ], + ), ), ), - ), - ); + ); Widget _buildDownloadProgressDialog( BuildContext context, diff --git a/packages/stream_chat_flutter/lib/src/back_button.dart b/packages/stream_chat_flutter/lib/src/back_button.dart index acb3d1ec..e8fe7e31 100644 --- a/packages/stream_chat_flutter/lib/src/back_button.dart +++ b/packages/stream_chat_flutter/lib/src/back_button.dart @@ -5,7 +5,6 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; /// Back button implementation class StreamBackButton extends StatelessWidget { - /// Constructor for creating back button const StreamBackButton({ Key? key, @@ -25,37 +24,37 @@ class StreamBackButton extends StatelessWidget { @override Widget build(BuildContext context) => Stack( - alignment: Alignment.center, - children: [ - RawMaterialButton( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(4), - ), - elevation: 0, - highlightElevation: 0, - focusElevation: 0, - hoverElevation: 0, - onPressed: () { - if (onPressed != null) { - onPressed!(); - } else { - Navigator.maybePop(context); - } - }, - padding: const EdgeInsets.all(14), - child: StreamSvgIcon.left( - size: 24, - color: StreamChatTheme.of(context).colorTheme.black, - ), - ), - if (showUnreads) - Positioned( - top: 7, - right: 7, - child: UnreadIndicator( - cid: cid, + alignment: Alignment.center, + children: [ + RawMaterialButton( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(4), + ), + elevation: 0, + highlightElevation: 0, + focusElevation: 0, + hoverElevation: 0, + onPressed: () { + if (onPressed != null) { + onPressed!(); + } else { + Navigator.maybePop(context); + } + }, + padding: const EdgeInsets.all(14), + child: StreamSvgIcon.left( + size: 24, + color: StreamChatTheme.of(context).colorTheme.black, ), ), - ], - ); + if (showUnreads) + Positioned( + top: 7, + right: 7, + child: UnreadIndicator( + cid: cid, + ), + ), + ], + ); } diff --git a/packages/stream_chat_flutter/lib/src/channel_image.dart b/packages/stream_chat_flutter/lib/src/channel_image.dart index 3f3a38be..8116ca83 100644 --- a/packages/stream_chat_flutter/lib/src/channel_image.dart +++ b/packages/stream_chat_flutter/lib/src/channel_image.dart @@ -98,23 +98,23 @@ class ChannelImage extends StatelessWidget { (users) => users[otherMember?.userId] ?? otherMember!.user!), initialData: otherMember!.user, builder: (context, snapshot) => UserAvatar( - borderRadius: borderRadius ?? - StreamChatTheme.of(context) - .channelPreviewTheme - .avatarTheme - ?.borderRadius, - user: snapshot.data ?? otherMember.user!, - constraints: constraints ?? - StreamChatTheme.of(context) - .channelPreviewTheme - .avatarTheme - ?.constraints, - onTap: onTap != null ? (_) => onTap!() : null, - selected: selected, - selectionColor: selectionColor ?? - StreamChatTheme.of(context).colorTheme.accentBlue, - selectionThickness: selectionThickness, - )); + borderRadius: borderRadius ?? + StreamChatTheme.of(context) + .channelPreviewTheme + .avatarTheme + ?.borderRadius, + user: snapshot.data ?? otherMember.user!, + constraints: constraints ?? + StreamChatTheme.of(context) + .channelPreviewTheme + .avatarTheme + ?.constraints, + onTap: onTap != null ? (_) => onTap!() : null, + selected: selected, + selectionColor: selectionColor ?? + StreamChatTheme.of(context).colorTheme.accentBlue, + selectionThickness: selectionThickness, + )); } else { final images = channel.state?.members .where((member) => @@ -167,16 +167,16 @@ class ChannelImage extends StatelessWidget { CachedNetworkImage( imageUrl: image, errorWidget: (_, __, ___) => Center( - child: Text( - snapshot.data?.containsKey('name') ?? false - ? snapshot.data!['name'][0] - : '', - style: TextStyle( - color: StreamChatTheme.of(context).colorTheme.white, - fontWeight: FontWeight.bold, - ), + child: Text( + snapshot.data?.containsKey('name') ?? false + ? snapshot.data!['name'][0] + : '', + style: TextStyle( + color: StreamChatTheme.of(context).colorTheme.white, + fontWeight: FontWeight.bold, ), ), + ), fit: BoxFit.cover, ) else diff --git a/packages/stream_chat_flutter/lib/src/channel_list_header.dart b/packages/stream_chat_flutter/lib/src/channel_list_header.dart index c8d2aa69..afc1884c 100644 --- a/packages/stream_chat_flutter/lib/src/channel_list_header.dart +++ b/packages/stream_chat_flutter/lib/src/channel_list_header.dart @@ -217,64 +217,65 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { ); Widget _buildConnectingTitleState(BuildContext context) => Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const SizedBox( - height: 16, - width: 16, - child: Center( - child: CircularProgressIndicator(), + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const SizedBox( + height: 16, + width: 16, + child: Center( + child: CircularProgressIndicator(), + ), ), - ), - const SizedBox(width: 10), - Text( - 'Searching for Network', - style: StreamChatTheme.of(context) - .channelListHeaderTheme - .title - ?.copyWith( - fontSize: 16, - fontWeight: FontWeight.bold, - ), - ), - ], - ); - - Widget _buildDisconnectedTitleState( - BuildContext context, - StreamChatClient client, - ) => Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - 'Offline...', - style: StreamChatTheme.of(context) - .channelListHeaderTheme - .title - ?.copyWith( - fontSize: 16, - fontWeight: FontWeight.bold, - ), - ), - TextButton( - onPressed: () async { - await client.disconnect(); - await client.connect(); - }, - child: Text( - 'Try Again', + const SizedBox(width: 10), + Text( + 'Searching for Network', style: StreamChatTheme.of(context) .channelListHeaderTheme .title ?.copyWith( fontSize: 16, fontWeight: FontWeight.bold, - color: StreamChatTheme.of(context).colorTheme.accentBlue, ), ), - ), - ], - ); + ], + ); + + Widget _buildDisconnectedTitleState( + BuildContext context, + StreamChatClient client, + ) => + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'Offline...', + style: StreamChatTheme.of(context) + .channelListHeaderTheme + .title + ?.copyWith( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + TextButton( + onPressed: () async { + await client.disconnect(); + await client.connect(); + }, + child: Text( + 'Try Again', + style: StreamChatTheme.of(context) + .channelListHeaderTheme + .title + ?.copyWith( + fontSize: 16, + fontWeight: FontWeight.bold, + color: StreamChatTheme.of(context).colorTheme.accentBlue, + ), + ), + ), + ], + ); @override Size get preferredSize => const Size.fromHeight(kToolbarHeight); diff --git a/packages/stream_chat_flutter/lib/src/channel_list_view.dart b/packages/stream_chat_flutter/lib/src/channel_list_view.dart index c58ed42f..fb713ea8 100644 --- a/packages/stream_chat_flutter/lib/src/channel_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/channel_list_view.dart @@ -9,7 +9,6 @@ import 'package:stream_chat_flutter/src/utils.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; - /// Callback called when tapping on a channel typedef ChannelTapCallback = void Function(Channel, Widget?); diff --git a/packages/stream_chat_flutter/lib/src/channel_name.dart b/packages/stream_chat_flutter/lib/src/channel_name.dart index d76bca0c..1cc510af 100644 --- a/packages/stream_chat_flutter/lib/src/channel_name.dart +++ b/packages/stream_chat_flutter/lib/src/channel_name.dart @@ -3,7 +3,6 @@ import 'package:flutter/rendering.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; - /// It shows the current [Channel] name using a [Text] widget. /// /// The widget uses a [StreamBuilder] to render the channel information @@ -60,9 +59,8 @@ class ChannelName extends StatelessWidget { final exceedingMembers = otherMembers.length - currentMembers.length; - title = - '${currentMembers.map((e) => e.user?.name).join(', ')} ' - '${exceedingMembers > 0 ? '+ $exceedingMembers' : ''}'; + title = '${currentMembers.map((e) => e.user?.name).join(', ')} ' + '${exceedingMembers > 0 ? '+ $exceedingMembers' : ''}'; } else { title = 'No title'; } diff --git a/packages/stream_chat_flutter/lib/src/channel_preview.dart b/packages/stream_chat_flutter/lib/src/channel_preview.dart index 9c793ba6..70ad0e3f 100644 --- a/packages/stream_chat_flutter/lib/src/channel_preview.dart +++ b/packages/stream_chat_flutter/lib/src/channel_preview.dart @@ -21,7 +21,6 @@ import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; /// [StreamChatTheme]. /// Modify it to change the widget appearance. class ChannelPreview extends StatelessWidget { - /// Constructor for creating [ChannelPreview] const ChannelPreview({ required this.channel, diff --git a/packages/stream_chat_flutter/lib/src/date_divider.dart b/packages/stream_chat_flutter/lib/src/date_divider.dart index e1b9cfea..f409872b 100644 --- a/packages/stream_chat_flutter/lib/src/date_divider.dart +++ b/packages/stream_chat_flutter/lib/src/date_divider.dart @@ -4,7 +4,6 @@ import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; /// It shows a date divider depending on the date difference class DateDivider extends StatelessWidget { - /// Constructor for creating a [DateDivider] const DateDivider({ Key? key, diff --git a/packages/stream_chat_flutter/lib/src/deleted_message.dart b/packages/stream_chat_flutter/lib/src/deleted_message.dart index 47a5f2ee..96f5606a 100644 --- a/packages/stream_chat_flutter/lib/src/deleted_message.dart +++ b/packages/stream_chat_flutter/lib/src/deleted_message.dart @@ -5,7 +5,6 @@ import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; /// Widget to display deleted message class DeletedMessage extends StatelessWidget { - /// Constructor to create [DeletedMessage] const DeletedMessage({ Key? key, @@ -33,43 +32,43 @@ class DeletedMessage extends StatelessWidget { @override Widget build(BuildContext context) => Transform( - transform: Matrix4.rotationY(reverse ? pi : 0), - alignment: Alignment.center, - child: Material( - color: messageTheme.messageBackgroundColor, - shape: shape ?? - RoundedRectangleBorder( - borderRadius: borderRadiusGeometry ?? BorderRadius.zero, - side: borderSide ?? - BorderSide( - color: Theme.of(context).brightness == Brightness.dark - ? StreamChatTheme.of(context) - .colorTheme - .white - .withAlpha(24) - : StreamChatTheme.of(context) - .colorTheme - .black - .withAlpha(24), - ), + transform: Matrix4.rotationY(reverse ? pi : 0), + alignment: Alignment.center, + child: Material( + color: messageTheme.messageBackgroundColor, + shape: shape ?? + RoundedRectangleBorder( + borderRadius: borderRadiusGeometry ?? BorderRadius.zero, + side: borderSide ?? + BorderSide( + color: Theme.of(context).brightness == Brightness.dark + ? StreamChatTheme.of(context) + .colorTheme + .white + .withAlpha(24) + : StreamChatTheme.of(context) + .colorTheme + .black + .withAlpha(24), + ), + ), + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 8, + horizontal: 16, ), - child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 8, - horizontal: 16, - ), - child: Transform( - transform: Matrix4.rotationY(reverse ? pi : 0), - alignment: Alignment.center, - child: Text( - 'Message deleted', - style: messageTheme.messageText?.copyWith( - fontStyle: FontStyle.italic, - color: messageTheme.createdAt?.color, + child: Transform( + transform: Matrix4.rotationY(reverse ? pi : 0), + alignment: Alignment.center, + child: Text( + 'Message deleted', + style: messageTheme.messageText?.copyWith( + fontStyle: FontStyle.italic, + color: messageTheme.createdAt?.color, + ), ), ), ), ), - ), - ); + ); } diff --git a/packages/stream_chat_flutter/lib/src/full_screen_media.dart b/packages/stream_chat_flutter/lib/src/full_screen_media.dart index edebfa09..f86ac60b 100644 --- a/packages/stream_chat_flutter/lib/src/full_screen_media.dart +++ b/packages/stream_chat_flutter/lib/src/full_screen_media.dart @@ -13,7 +13,6 @@ import 'package:video_player/video_player.dart'; /// Return action for coming back from pages enum ReturnActionType { - /// No return action none, @@ -252,10 +251,10 @@ class _FullScreenMediaState extends State class VideoPackage { /// Constructor for creating [VideoPackage] VideoPackage( - Attachment attachment, { - bool showControls = false, - bool autoInitialize = true, - }) : _showControls = showControls, + Attachment attachment, { + bool showControls = false, + bool autoInitialize = true, + }) : _showControls = showControls, _autoInitialize = autoInitialize, _videoPlayerController = attachment.localUri != null ? VideoPlayerController.file(File.fromUri(attachment.localUri!)) diff --git a/packages/stream_chat_flutter/lib/src/image_footer.dart b/packages/stream_chat_flutter/lib/src/image_footer.dart index f660bad7..9298e73b 100644 --- a/packages/stream_chat_flutter/lib/src/image_footer.dart +++ b/packages/stream_chat_flutter/lib/src/image_footer.dart @@ -12,7 +12,22 @@ import 'package:stream_chat_flutter/src/video_thumbnail_image.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; +/// Footer widget for media display class ImageFooter extends StatefulWidget implements PreferredSizeWidget { + /// Creates a channel header + const ImageFooter({ + Key? key, + required this.message, + this.onBackPressed, + this.onTitleTap, + this.onImageTap, + this.currentPage = 0, + this.totalPages = 0, + this.mediaAttachments = const [], + this.mediaSelectedCallBack, + }) : preferredSize = const Size.fromHeight(kToolbarHeight), + super(key: key); + /// Callback to call when pressing the back button. /// By default it calls [Navigator.pop] final VoidCallback? onBackPressed; @@ -23,28 +38,21 @@ class ImageFooter extends StatefulWidget implements PreferredSizeWidget { /// Callback to call when the image is tapped. final VoidCallback? onImageTap; + /// Stores the current index of media shown final int currentPage; + + /// Total number of pages of media final int totalPages; + /// All attachments to show final List mediaAttachments; + + /// Message which attachments are attached to final Message message; + /// Callback when media is selected final ValueChanged? mediaSelectedCallBack; - /// Creates a channel header - ImageFooter({ - Key? key, - required this.message, - this.onBackPressed, - this.onTitleTap, - this.onImageTap, - this.currentPage = 0, - this.totalPages = 0, - this.mediaAttachments = const [], - this.mediaSelectedCallBack, - }) : preferredSize = Size.fromHeight(kToolbarHeight), - super(key: key); - @override _ImageFooterState createState() => _ImageFooterState(); @@ -119,7 +127,7 @@ class _ImageFooterState extends State { ), InkWell( onTap: widget.onTitleTap, - child: Container( + child: SizedBox( child: Column( mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.min, @@ -169,115 +177,115 @@ class _ImageFooterState extends State { expand: false, initialChildSize: initialChildSize / size.height, minChildSize: initialChildSize / size.height, - builder: (context, scrollController) { - return SingleChildScrollView( - controller: scrollController, - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Stack( - children: [ - Center( - child: Padding( - padding: const EdgeInsets.all(16), - child: Text( - 'Photos', - style: StreamChatTheme.of(context) - .textTheme - .headlineBold, - ), + builder: (context, scrollController) => SingleChildScrollView( + controller: scrollController, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Stack( + children: [ + Center( + child: Padding( + padding: const EdgeInsets.all(16), + child: Text( + 'Photos', + style: StreamChatTheme.of(context) + .textTheme + .headlineBold, ), ), - Align( - alignment: Alignment.centerRight, - child: IconButton( - icon: StreamSvgIcon.close( - color: StreamChatTheme.of(context).colorTheme.black, - ), - onPressed: () => Navigator.maybePop(context), + ), + Align( + alignment: Alignment.centerRight, + child: IconButton( + icon: StreamSvgIcon.close( + color: StreamChatTheme.of(context).colorTheme.black, ), + onPressed: () => Navigator.maybePop(context), ), - ], - ), - Flexible( - child: GridView.builder( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemCount: widget.mediaAttachments.length, - padding: const EdgeInsets.all(1), - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: crossAxisCount, - mainAxisSpacing: 2, - crossAxisSpacing: 2, - ), - itemBuilder: (context, index) { - Widget media; - final attachment = widget.mediaAttachments[index]; - if (attachment.type == 'video') { - media = InkWell( - onTap: () => widget.mediaSelectedCallBack!(index), - child: FittedBox( + ), + ], + ), + Flexible( + child: GridView.builder( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemCount: widget.mediaAttachments.length, + padding: const EdgeInsets.all(1), + // ignore: lines_longer_than_80_chars + gridDelegate: + const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: crossAxisCount, + mainAxisSpacing: 2, + crossAxisSpacing: 2, + ), + itemBuilder: (context, index) { + Widget media; + final attachment = widget.mediaAttachments[index]; + if (attachment.type == 'video') { + media = InkWell( + onTap: () => widget.mediaSelectedCallBack!(index), + child: FittedBox( + fit: BoxFit.cover, + child: VideoThumbnailImage( + video: (attachment.file?.path ?? + attachment.assetUrl)!, + ), + ), + ); + } else { + media = InkWell( + onTap: () => widget.mediaSelectedCallBack!(index), + child: AspectRatio( + aspectRatio: 1, + child: CachedNetworkImage( + imageUrl: attachment.imageUrl ?? + attachment.assetUrl ?? + attachment.thumbUrl!, fit: BoxFit.cover, - child: VideoThumbnailImage( - video: (attachment.file?.path ?? - attachment.assetUrl)!, - ), ), - ); - } else { - media = InkWell( - onTap: () => widget.mediaSelectedCallBack!(index), - child: AspectRatio( - aspectRatio: 1, - child: CachedNetworkImage( - imageUrl: attachment.imageUrl ?? - attachment.assetUrl ?? - attachment.thumbUrl!, - fit: BoxFit.cover, - ), - ), - ); - } + ), + ); + } - return Stack( - children: [ - media, - if (widget.message.user != null) - Padding( - padding: EdgeInsets.all(8), - child: Container( - clipBehavior: Clip.antiAlias, - decoration: BoxDecoration( - shape: BoxShape.circle, - color: Colors.white.withOpacity(0.6), - boxShadow: [ - BoxShadow( - blurRadius: 8, - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(0.3), - ), - ], - ), - padding: const EdgeInsets.all(2), - child: UserAvatar( - user: widget.message.user!, - constraints: - BoxConstraints.tight(Size(24, 24)), - showOnlineStatus: false, - ), + return Stack( + children: [ + media, + if (widget.message.user != null) + Padding( + padding: const EdgeInsets.all(8), + child: Container( + clipBehavior: Clip.antiAlias, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Colors.white.withOpacity(0.6), + boxShadow: [ + BoxShadow( + blurRadius: 8, + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.3), + ), + ], + ), + padding: const EdgeInsets.all(2), + child: UserAvatar( + user: widget.message.user!, + constraints: + BoxConstraints.tight(const Size(24, 24)), + showOnlineStatus: false, ), ), - ], - ); - }, - ), + ), + ], + ); + }, ), - ], - ), - ); - }, + ), + ], + ), + ), ); }, ); @@ -304,29 +312,3 @@ class _ImageFooterState extends State { Navigator.pop(context); } } - -/// Used for clipping textfield prefix icon -class IconClipper extends CustomClipper { - @override - Path getClip(Size size) { - final leftX = size.width / 5; - final rightX = 4 * size.width / 5; - final topY = size.height / 5; - final bottomY = 4 * size.height / 5; - - final path = Path(); - path.moveTo(leftX, topY); - path.lineTo(leftX, bottomY); - path.lineTo(rightX, bottomY); - path.lineTo(rightX, topY); - path.lineTo(leftX, topY); - path.lineTo(0, 0); - path.close(); - return path; - } - - @override - bool shouldReclip(CustomClipper oldClipper) { - return false; - } -} diff --git a/packages/stream_chat_flutter/lib/src/image_group.dart b/packages/stream_chat_flutter/lib/src/image_group.dart index 600b7867..51c686c3 100644 --- a/packages/stream_chat_flutter/lib/src/image_group.dart +++ b/packages/stream_chat_flutter/lib/src/image_group.dart @@ -3,7 +3,9 @@ import 'package:stream_chat_flutter/src/full_screen_media.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; +/// Widget for constructing a group of images in message class ImageGroup extends StatelessWidget { + /// Constructor for creating [ImageGroup] widget const ImageGroup({ Key? key, required this.images, @@ -13,91 +15,98 @@ class ImageGroup extends StatelessWidget { this.onShowMessage, }) : super(key: key); + /// List of attachments to show final List images; + + /// Message which images are attached to final Message message; + + /// [MessageTheme] to apply to message final MessageTheme messageTheme; + + /// Size of iamges final Size size; + + /// Callback for when show message is tapped final ShowMessageCallback? onShowMessage; @override - Widget build(BuildContext context) { - return ConstrainedBox( - constraints: BoxConstraints.loose(size), - child: Flex( - direction: Axis.vertical, - children: [ - Flexible( - fit: FlexFit.tight, - child: Flex( - crossAxisAlignment: CrossAxisAlignment.stretch, - direction: Axis.horizontal, - children: [ - Flexible( - fit: FlexFit.tight, - child: _buildImage(context, 0), - ), - Flexible( - fit: FlexFit.tight, - child: Padding( - padding: const EdgeInsets.only(left: 2), - child: _buildImage(context, 1), - ), - ), - ], - ), - ), - if (images.length >= 3) + Widget build(BuildContext context) => ConstrainedBox( + constraints: BoxConstraints.loose(size), + child: Flex( + direction: Axis.vertical, + children: [ Flexible( fit: FlexFit.tight, - child: Padding( - padding: const EdgeInsets.only(top: 2), - child: Flex( - direction: Axis.horizontal, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Flexible( - fit: FlexFit.tight, - child: _buildImage(context, 2), + child: Flex( + crossAxisAlignment: CrossAxisAlignment.stretch, + direction: Axis.horizontal, + children: [ + Flexible( + fit: FlexFit.tight, + child: _buildImage(context, 0), + ), + Flexible( + fit: FlexFit.tight, + child: Padding( + padding: const EdgeInsets.only(left: 2), + child: _buildImage(context, 1), ), - if (images.length >= 4) + ), + ], + ), + ), + if (images.length >= 3) + Flexible( + fit: FlexFit.tight, + child: Padding( + padding: const EdgeInsets.only(top: 2), + child: Flex( + direction: Axis.horizontal, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ Flexible( fit: FlexFit.tight, - child: Padding( - padding: const EdgeInsets.only(left: 2), - child: Stack( - fit: StackFit.expand, - children: [ - _buildImage(context, 3), - if (images.length > 4) - Positioned.fill( - child: GestureDetector( - onTap: () => _onTap(context, 3), - child: Material( - color: Colors.black38, - child: Center( - child: Text( - '+ ${images.length - 4}', - style: TextStyle( - color: Colors.white, - fontSize: 26, + child: _buildImage(context, 2), + ), + if (images.length >= 4) + Flexible( + fit: FlexFit.tight, + child: Padding( + padding: const EdgeInsets.only(left: 2), + child: Stack( + fit: StackFit.expand, + children: [ + _buildImage(context, 3), + if (images.length > 4) + Positioned.fill( + child: GestureDetector( + onTap: () => _onTap(context, 3), + child: Material( + color: Colors.black38, + child: Center( + child: Text( + '+ ${images.length - 4}', + style: const TextStyle( + color: Colors.white, + fontSize: 26, + ), ), ), ), ), ), - ), - ], + ], + ), ), ), - ), - ], + ], + ), ), ), - ), - ], - ), - ); - } + ], + ), + ); void _onTap( BuildContext context, @@ -122,13 +131,11 @@ class ImageGroup extends StatelessWidget { ); } - Widget _buildImage(BuildContext context, int index) { - return ImageAttachment( - attachment: images[index], - size: size, - message: message, - messageTheme: messageTheme, - onAttachmentTap: () => _onTap(context, index), - ); - } + Widget _buildImage(BuildContext context, int index) => ImageAttachment( + attachment: images[index], + size: size, + message: message, + messageTheme: messageTheme, + onAttachmentTap: () => _onTap(context, index), + ); } diff --git a/packages/stream_chat_flutter/lib/src/image_header.dart b/packages/stream_chat_flutter/lib/src/image_header.dart index 18c78770..0b876aa1 100644 --- a/packages/stream_chat_flutter/lib/src/image_header.dart +++ b/packages/stream_chat_flutter/lib/src/image_header.dart @@ -1,11 +1,26 @@ import 'package:flutter/material.dart'; +import 'package:stream_chat_flutter/src/attachment_actions_modal.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; -import 'attachment_actions_modal.dart'; - +/// Header/AppBar widget for media display screen class ImageHeader extends StatelessWidget implements PreferredSizeWidget { + /// Creates a channel header + const ImageHeader({ + Key? key, + required this.message, + this.currentIndex = 0, + this.showBackButton = true, + this.onBackPressed, + this.onShowMessage, + this.onTitleTap, + this.onImageTap, + this.userName = '', + this.sentAt = '', + }) : preferredSize = const Size.fromHeight(kToolbarHeight), + super(key: key); + /// True if this header shows the leading back button final bool showBackButton; @@ -22,83 +37,72 @@ class ImageHeader extends StatelessWidget implements PreferredSizeWidget { /// Callback to call when the image is tapped. final VoidCallback? onImageTap; + /// Message which attachments are attached to final Message message; + /// Username of sender final String userName; + + /// Text which connotes the time the message was sent final String sentAt; + /// Stores the current index of media shown final int currentIndex; - /// Creates a channel header - ImageHeader({ - Key? key, - required this.message, - this.currentIndex = 0, - this.showBackButton = true, - this.onBackPressed, - this.onShowMessage, - this.onTitleTap, - this.onImageTap, - this.userName = '', - this.sentAt = '', - }) : preferredSize = Size.fromHeight(kToolbarHeight), - super(key: key); - @override - Widget build(BuildContext context) { - return AppBar( - brightness: Theme.of(context).brightness, - elevation: 1, - leading: showBackButton - ? IconButton( - icon: StreamSvgIcon.close( - color: StreamChatTheme.of(context).colorTheme.black, - size: 24, - ), - onPressed: onBackPressed, - ) - : SizedBox(), - backgroundColor: - StreamChatTheme.of(context).channelTheme.channelHeaderTheme.color, - actions: [ - if (message.type != 'ephemeral') - IconButton( - icon: StreamSvgIcon.iconMenuPoint( - color: StreamChatTheme.of(context).colorTheme.black, - ), - onPressed: () { - _showMessageActionModalBottomSheet(context); - }, - ), - ], - centerTitle: true, - title: message.type != 'ephemeral' - ? InkWell( - onTap: onTitleTap, - child: Container( - height: preferredSize.height, - width: preferredSize.width, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - mainAxisSize: MainAxisSize.min, - children: [ - Text( - userName, - style: StreamChatTheme.of(context).textTheme.headlineBold, - ), - Text( - sentAt, - style: StreamChatTheme.of(context) - .channelPreviewTheme - .subtitle, - ), - ], + Widget build(BuildContext context) => AppBar( + brightness: Theme.of(context).brightness, + elevation: 1, + leading: showBackButton + ? IconButton( + icon: StreamSvgIcon.close( + color: StreamChatTheme.of(context).colorTheme.black, + size: 24, ), + onPressed: onBackPressed, + ) + : const SizedBox(), + backgroundColor: + StreamChatTheme.of(context).channelTheme.channelHeaderTheme.color, + actions: [ + if (message.type != 'ephemeral') + IconButton( + icon: StreamSvgIcon.iconMenuPoint( + color: StreamChatTheme.of(context).colorTheme.black, ), - ) - : SizedBox(), - ); - } + onPressed: () { + _showMessageActionModalBottomSheet(context); + }, + ), + ], + centerTitle: true, + title: message.type != 'ephemeral' + ? InkWell( + onTap: onTitleTap, + child: SizedBox( + height: preferredSize.height, + width: preferredSize.width, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + userName, + style: + StreamChatTheme.of(context).textTheme.headlineBold, + ), + Text( + sentAt, + style: StreamChatTheme.of(context) + .channelPreviewTheme + .subtitle, + ), + ], + ), + ), + ) + : const SizedBox(), + ); @override final Size preferredSize; @@ -109,16 +113,14 @@ class ImageHeader extends StatelessWidget implements PreferredSizeWidget { final result = await showDialog( context: context, barrierColor: StreamChatTheme.of(context).colorTheme.overlay, - builder: (context) { - return StreamChannel( - channel: channel, - child: AttachmentActionsModal( - message: message, - currentIndex: currentIndex, - onShowMessage: onShowMessage, - ), - ); - }, + builder: (context) => StreamChannel( + channel: channel, + child: AttachmentActionsModal( + message: message, + currentIndex: currentIndex, + onShowMessage: onShowMessage, + ), + ), ); if (result != null) { diff --git a/packages/stream_chat_flutter/lib/src/message_input.dart b/packages/stream_chat_flutter/lib/src/message_input.dart index b0335e52..638c7769 100644 --- a/packages/stream_chat_flutter/lib/src/message_input.dart +++ b/packages/stream_chat_flutter/lib/src/message_input.dart @@ -812,116 +812,123 @@ class MessageInputState extends State { final renderBox = context.findRenderObject() as RenderBox; final size = renderBox.size; - return OverlayEntry(builder: (context) => Positioned( - bottom: size.height + MediaQuery.of(context).viewInsets.bottom, - left: 0, - right: 0, - child: TweenAnimationBuilder( - tween: Tween(begin: 0, end: 1), - duration: Duration(milliseconds: 300), - curve: Curves.easeInOutExpo, - builder: (context, val, wid) => Transform.scale( - scale: val, - child: Padding( - padding: const EdgeInsets.all(8), - child: Card( - elevation: 2, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), - color: StreamChatTheme.of(context).colorTheme.white, - clipBehavior: Clip.antiAlias, - child: Container( - constraints: BoxConstraints.loose(Size.fromHeight(400)), - decoration: BoxDecoration( - color: StreamChatTheme.of(context).colorTheme.white, - borderRadius: BorderRadius.circular(8)), - child: ListView( - padding: const EdgeInsets.all(0), - shrinkWrap: true, - children: [ - if (commands.isNotEmpty) - Padding( - padding: const EdgeInsets.only(top: 8), - child: Row( + return OverlayEntry( + builder: (context) => Positioned( + bottom: size.height + MediaQuery.of(context).viewInsets.bottom, + left: 0, + right: 0, + child: TweenAnimationBuilder( + tween: Tween(begin: 0, end: 1), + duration: Duration(milliseconds: 300), + curve: Curves.easeInOutExpo, + builder: (context, val, wid) => Transform.scale( + scale: val, + child: Padding( + padding: const EdgeInsets.all(8), + child: Card( + elevation: 2, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + color: StreamChatTheme.of(context).colorTheme.white, + clipBehavior: Clip.antiAlias, + child: Container( + constraints: + BoxConstraints.loose(Size.fromHeight(400)), + decoration: BoxDecoration( + color: StreamChatTheme.of(context) + .colorTheme + .white, + borderRadius: BorderRadius.circular(8)), + child: ListView( + padding: const EdgeInsets.all(0), + shrinkWrap: true, children: [ - Padding( - padding: const EdgeInsets.symmetric( - horizontal: 8, - ), - child: StreamSvgIcon.lightning( - color: StreamChatTheme.of(context) - .colorTheme - .accentBlue, + if (commands.isNotEmpty) + Padding( + padding: const EdgeInsets.only(top: 8), + child: Row( + children: [ + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 8, + ), + child: StreamSvgIcon.lightning( + color: StreamChatTheme.of(context) + .colorTheme + .accentBlue, + ), + ), + Text( + 'Instant Commands', + style: TextStyle( + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5), + ), + ) + ], + ), ), + const SizedBox( + height: 10, ), - Text( - 'Instant Commands', - style: TextStyle( - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(.5), - ), - ) + ...commands + .map( + (c) => InkWell( + onTap: () { + _setCommand(c); + }, + child: SizedBox( + height: 40, + child: Row( + children: [ + const SizedBox( + width: 16, + ), + _buildCommandIcon(c.name), + const SizedBox( + width: 8, + ), + Text.rich( + TextSpan( + text: c.name.capitalize(), + style: const TextStyle( + fontWeight: + FontWeight.bold), + children: [ + TextSpan( + text: + ' /${c.name} ${c.args}', + style: + StreamChatTheme.of( + context) + .textTheme + .body + .copyWith( + color: StreamChatTheme.of( + context) + .colorTheme + .grey, + ), + ), + ], + ), + ), + ], + ), + ), + ), + ) + .toList(), ], ), ), - const SizedBox( - height: 10, ), - ...commands - .map( - (c) => InkWell( - onTap: () { - _setCommand(c); - }, - child: SizedBox( - height: 40, - child: Row( - children: [ - const SizedBox( - width: 16, - ), - _buildCommandIcon(c.name), - const SizedBox( - width: 8, - ), - Text.rich( - TextSpan( - text: c.name.capitalize(), - style: const TextStyle( - fontWeight: FontWeight.bold), - children: [ - TextSpan( - text: ' /${c.name} ${c.args}', - style: - StreamChatTheme.of(context) - .textTheme - .body - .copyWith( - color: StreamChatTheme - .of(context) - .colorTheme - .grey, - ), - ), - ], - ), - ), - ], - ), - ), - ), - ) - .toList(), - ], - ), - ), - ), - ), - )), - )); + ), + )), + )); } Widget _buildFilePickerSection() { From 5ad74b8f2b1184384e999f440a1cf40b90ee375a Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 5 May 2021 15:10:46 +0530 Subject: [PATCH 07/31] lint changes --- .../lib/src/info_tile.dart | 76 +++--- .../lib/src/media_list_view.dart | 218 +++++++++--------- .../lib/src/mention_tile.dart | 147 ++++++------ .../lib/src/message_action.dart | 14 +- 4 files changed, 238 insertions(+), 217 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/info_tile.dart b/packages/stream_chat_flutter/lib/src/info_tile.dart index 53a9755f..81a701c0 100644 --- a/packages/stream_chat_flutter/lib/src/info_tile.dart +++ b/packages/stream_chat_flutter/lib/src/info_tile.dart @@ -2,16 +2,11 @@ import 'package:flutter/material.dart'; import 'package:flutter_portal/flutter_portal.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; +/// Tile to display a message, used in stream chat to display connection status class InfoTile extends StatelessWidget { - final String message; - final Widget child; - final bool showMessage; - final Alignment? tileAnchor; - final Alignment? childAnchor; - final TextStyle? textStyle; - final Color? backgroundColor; - + /// Constructor for creating an [InfoTile] widget const InfoTile({ + Key? key, required this.message, required this.child, required this.showMessage, @@ -19,31 +14,50 @@ class InfoTile extends StatelessWidget { this.childAnchor, this.textStyle, this.backgroundColor, - }); + }) : super(key: key); + + /// String to display + final String message; + + /// Widget to display over + final Widget child; + + /// Flag to show message + final bool showMessage; + + /// Anchor for tile - [portalAnchor] for [PortalEntry] + final Alignment? tileAnchor; + + /// Alignment for child - [childAnchor] for [PortalEntry] + final Alignment? childAnchor; + + /// [TextStyle] for message + final TextStyle? textStyle; + + /// Background color for tile + final Color? backgroundColor; @override - Widget build(BuildContext context) { - return PortalEntry( - visible: showMessage, - portalAnchor: tileAnchor ?? Alignment.topCenter, - childAnchor: childAnchor ?? Alignment.bottomCenter, - portal: Container( - height: 25, - color: backgroundColor ?? - StreamChatTheme.of(context).colorTheme.grey.withOpacity(0.9), - child: Center( - child: Text( - message, - style: textStyle ?? - StreamChatTheme.of(context).textTheme.body.copyWith( - color: Colors.white, - ), - maxLines: 1, - overflow: TextOverflow.ellipsis, + Widget build(BuildContext context) => PortalEntry( + visible: showMessage, + portalAnchor: tileAnchor ?? Alignment.topCenter, + childAnchor: childAnchor ?? Alignment.bottomCenter, + portal: Container( + height: 25, + color: backgroundColor ?? + StreamChatTheme.of(context).colorTheme.grey.withOpacity(0.9), + child: Center( + child: Text( + message, + style: textStyle ?? + StreamChatTheme.of(context).textTheme.body.copyWith( + color: Colors.white, + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), ), ), - ), - child: child, - ); - } + child: child, + ); } diff --git a/packages/stream_chat_flutter/lib/src/media_list_view.dart b/packages/stream_chat_flutter/lib/src/media_list_view.dart index a34dc8dd..e0d0c27e 100644 --- a/packages/stream_chat_flutter/lib/src/media_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/media_list_view.dart @@ -5,8 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:photo_manager/photo_manager.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; - -import '../stream_chat_flutter.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; extension on Duration { String format() { @@ -19,16 +18,21 @@ extension on Duration { } } +/// Constructs a list of media class MediaListView extends StatefulWidget { - final List selectedIds; - final void Function(AssetEntity media)? onSelect; - + /// Constructor for creating a [MediaListView] widget const MediaListView({ Key? key, this.selectedIds = const [], this.onSelect, }) : super(key: key); + /// Stores the media selected + final List selectedIds; + + /// Callback for on media selected + final void Function(AssetEntity media)? onSelect; + @override _MediaListViewState createState() => _MediaListViewState(); } @@ -39,103 +43,103 @@ class _MediaListViewState extends State { int _currentPage = 0; @override - Widget build(BuildContext context) { - return LazyLoadScrollView( - onEndOfPage: () async => _getMedia(), - child: GridView.builder( - itemCount: _media.length, - controller: _scrollController, - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 3, - ), - itemBuilder: ( - context, - position, - ) { - final media = _media.elementAt(position); - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 1, vertical: 1), - child: InkWell( - onTap: () { - if (widget.onSelect != null) { - widget.onSelect!(media); - } - }, - child: Stack( - children: [ - AspectRatio( - aspectRatio: 1, - child: FadeInImage( - fadeInDuration: Duration(milliseconds: 300), - placeholder: AssetImage( - 'images/placeholder.png', - package: 'stream_chat_flutter', + Widget build(BuildContext context) => LazyLoadScrollView( + onEndOfPage: () async => _getMedia(), + child: GridView.builder( + itemCount: _media.length, + controller: _scrollController, + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 3, + ), + itemBuilder: ( + context, + position, + ) { + final media = _media.elementAt(position); + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 1, vertical: 1), + child: InkWell( + onTap: () { + if (widget.onSelect != null) { + widget.onSelect!(media); + } + }, + child: Stack( + children: [ + AspectRatio( + aspectRatio: 1, + child: FadeInImage( + fadeInDuration: const Duration(milliseconds: 300), + placeholder: const AssetImage( + 'images/placeholder.png', + package: 'stream_chat_flutter', + ), + image: MediaThumbnailProvider( + media: media, + ), + fit: BoxFit.cover, ), - image: MediaThumbnailProvider( - media: media, - ), - fit: BoxFit.cover, ), - ), - Positioned.fill( - child: IgnorePointer( - child: AnimatedOpacity( - duration: Duration(milliseconds: 300), - opacity: widget.selectedIds.any((id) => id == media.id) - ? 1.0 - : 0.0, - child: Container( - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(0.5), - alignment: Alignment.topRight, - padding: const EdgeInsets.only( - top: 8, - right: 8, - ), - child: CircleAvatar( - radius: 12, - backgroundColor: - StreamChatTheme.of(context).colorTheme.white, - child: StreamSvgIcon.check( - size: 24, - color: - StreamChatTheme.of(context).colorTheme.black, + Positioned.fill( + child: IgnorePointer( + child: AnimatedOpacity( + duration: const Duration(milliseconds: 300), + opacity: + widget.selectedIds.any((id) => id == media.id) + ? 1.0 + : 0.0, + child: Container( + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5), + alignment: Alignment.topRight, + padding: const EdgeInsets.only( + top: 8, + right: 8, + ), + child: CircleAvatar( + radius: 12, + backgroundColor: + StreamChatTheme.of(context).colorTheme.white, + child: StreamSvgIcon.check( + size: 24, + color: StreamChatTheme.of(context) + .colorTheme + .black, + ), ), ), ), ), ), - ), - if (media.type == AssetType.video) ...[ - Positioned( - left: 8, - bottom: 10, - child: SvgPicture.asset( - 'svgs/video_call_icon.svg', - package: 'stream_chat_flutter', - ), - ), - Positioned( - right: 4, - bottom: 10, - child: Text( - media.videoDuration.format(), - style: TextStyle( - color: StreamChatTheme.of(context).colorTheme.white, + if (media.type == AssetType.video) ...[ + Positioned( + left: 8, + bottom: 10, + child: SvgPicture.asset( + 'svgs/video_call_icon.svg', + package: 'stream_chat_flutter', ), ), - ), - ] - ], + Positioned( + right: 4, + bottom: 10, + child: Text( + media.videoDuration.format(), + style: TextStyle( + color: StreamChatTheme.of(context).colorTheme.white, + ), + ), + ), + ] + ], + ), ), - ), - ); - }, - ), - ); - } + ); + }, + ), + ); @override void initState() { @@ -165,36 +169,38 @@ class _MediaListViewState extends State { } } +/// ImageProvider implementation class MediaThumbnailProvider extends ImageProvider { + /// Constructor for creating a [MediaThumbnailProvider] const MediaThumbnailProvider({ required this.media, }); + /// Media to load final AssetEntity media; @override - ImageStreamCompleter load(key, decode) { - return MultiFrameImageStreamCompleter( - codec: _loadAsync(key, decode), - scale: 1, - informationCollector: () sync* { - yield ErrorDescription('Id: ${media.id}'); - }, - ); - } + ImageStreamCompleter load( + MediaThumbnailProvider key, DecoderCallback decode) => + MultiFrameImageStreamCompleter( + codec: _loadAsync(key, decode), + scale: 1, + informationCollector: () sync* { + yield ErrorDescription('Id: ${media.id}'); + }, + ); Future _loadAsync( MediaThumbnailProvider key, DecoderCallback decode) async { - assert(key == this); + assert(key == this, 'Checks MediaThumbnailProvider'); final bytes = await media.thumbData; - return await decode(bytes!); + return decode(bytes!); } @override - Future obtainKey(ImageConfiguration configuration) { - return SynchronousFuture(this); - } + Future obtainKey(ImageConfiguration configuration) => + SynchronousFuture(this); @override bool operator ==(dynamic other) { diff --git a/packages/stream_chat_flutter/lib/src/mention_tile.dart b/packages/stream_chat_flutter/lib/src/mention_tile.dart index 186e1f16..e8859946 100644 --- a/packages/stream_chat_flutter/lib/src/mention_tile.dart +++ b/packages/stream_chat_flutter/lib/src/mention_tile.dart @@ -3,8 +3,19 @@ import 'package:flutter/material.dart'; import '../stream_chat_flutter.dart'; /// This widget is used for showing user tiles for mentions -/// Use [title], [subtitle], [leading], [trailing] for substituting widgets in respective positions +/// Use [title], [subtitle], [leading], [trailing] for +/// substituting widgets in respective positions class MentionTile extends StatelessWidget { + /// Constructor for creating a [MentionTile] widget + const MentionTile( + this.member, { + Key? key, + this.title, + this.subtitle, + this.leading, + this.trailing, + }) : super(key: key); + /// Member to display in the tile final Member member; @@ -20,82 +31,72 @@ class MentionTile extends StatelessWidget { /// Widget at the end of tile final Widget? trailing; - const MentionTile( - this.member, { - this.title, - this.subtitle, - this.leading, - this.trailing, - }); - @override - Widget build(BuildContext context) { - return Container( - height: 56, - child: Row( - children: [ - SizedBox( - width: 16, - ), - leading ?? - UserAvatar( - constraints: BoxConstraints.tight( - Size( - 40, - 40, + Widget build(BuildContext context) => SizedBox( + height: 56, + child: Row( + children: [ + const SizedBox( + width: 16, + ), + leading ?? + UserAvatar( + constraints: BoxConstraints.tight( + const Size( + 40, + 40, + ), ), + user: member.user!, + ), + const SizedBox( + width: 8, + ), + Expanded( + child: Align( + alignment: Alignment.centerLeft, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + title ?? + Text( + member.user!.name, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: StreamChatTheme.of(context).textTheme.bodyBold, + ), + const SizedBox( + height: 2, + ), + subtitle ?? + Text( + '@${member.userId}', + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: StreamChatTheme.of(context) + .textTheme + .footnoteBold + .copyWith( + color: + StreamChatTheme.of(context).colorTheme.grey, + ), + ), + ], ), - user: member.user!, - ), - SizedBox( - width: 8, - ), - Expanded( - child: Align( - alignment: Alignment.centerLeft, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - title ?? - Text( - member.user!.name, - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: StreamChatTheme.of(context).textTheme.bodyBold, - ), - SizedBox( - height: 2, - ), - subtitle ?? - Text( - '@${member.userId}', - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: StreamChatTheme.of(context) - .textTheme - .footnoteBold - .copyWith( - color: - StreamChatTheme.of(context).colorTheme.grey, - ), - ), - ], ), ), - ), - trailing ?? - Padding( - padding: const EdgeInsets.only( - right: 18, - left: 8, + trailing ?? + Padding( + padding: const EdgeInsets.only( + right: 18, + left: 8, + ), + child: StreamSvgIcon.mentions( + color: StreamChatTheme.of(context).colorTheme.accentBlue, + ), ), - child: StreamSvgIcon.mentions( - color: StreamChatTheme.of(context).colorTheme.accentBlue, - ), - ), - ], - ), - ); - } + ], + ), + ); } diff --git a/packages/stream_chat_flutter/lib/src/message_action.dart b/packages/stream_chat_flutter/lib/src/message_action.dart index 6d4bd93c..49a57b1e 100644 --- a/packages/stream_chat_flutter/lib/src/message_action.dart +++ b/packages/stream_chat_flutter/lib/src/message_action.dart @@ -3,6 +3,13 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; /// Class describing a message action class MessageAction { + /// returns a new instance of a [MessageAction] + MessageAction({ + this.leading, + this.title, + this.onTap, + }); + /// leading widget final Widget? leading; @@ -11,11 +18,4 @@ class MessageAction { /// callback called on tap final OnMessageTap? onTap; - - /// returns a new instance of a [MessageAction] - MessageAction({ - this.leading, - this.title, - this.onTap, - }); } From bda64e87649d1eb8e3fc61baf17053afb46dedee Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 5 May 2021 15:33:42 +0530 Subject: [PATCH 08/31] lint changes message --- .../lib/src/message_actions_modal.dart | 666 +++++----- .../lib/src/message_input.dart | 1111 +++++++++-------- 2 files changed, 899 insertions(+), 878 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/message_actions_modal.dart b/packages/stream_chat_flutter/lib/src/message_actions_modal.dart index ecff8799..767cdc76 100644 --- a/packages/stream_chat_flutter/lib/src/message_actions_modal.dart +++ b/packages/stream_chat_flutter/lib/src/message_actions_modal.dart @@ -8,37 +8,11 @@ import 'package:stream_chat_flutter/src/reaction_picker.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import 'package:stream_chat_flutter/src/utils.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; +import 'package:stream_chat_flutter/src/extension.dart'; -import 'extension.dart'; -import 'message_input.dart'; -import 'message_widget.dart'; -import 'stream_chat.dart'; -import 'stream_chat_theme.dart'; - +/// Constructs a modal with actions for a message class MessageActionsModal extends StatefulWidget { - final Widget Function(BuildContext, Message)? editMessageInputBuilder; - final OnMessageTap? onThreadReplyTap; - final OnMessageTap? onReplyTap; - final Message message; - final MessageTheme messageTheme; - final bool showReactions; - final OnMessageTap? onCopyTap; - final bool showDeleteMessage; - final bool showCopyMessage; - final bool showEditMessage; - final bool showResendMessage; - final bool showReplyMessage; - final bool showThreadReplyMessage; - final bool showFlagButton; - final bool reverse; - final ShapeBorder? messageShape; - final ShapeBorder? attachmentShape; - final DisplayWidget showUserAvatar; - final BorderRadius? attachmentBorderRadiusGeometry; - - /// List of custom actions - final List customActions; - + /// Constructor for creating a [MessageActionsModal] widget const MessageActionsModal({ Key? key, required this.message, @@ -63,6 +37,66 @@ class MessageActionsModal extends StatefulWidget { this.onCopyTap, }) : super(key: key); + /// Builder for edit message + final Widget Function(BuildContext, Message)? editMessageInputBuilder; + + /// Callback for when thread reply is tapped + final OnMessageTap? onThreadReplyTap; + + /// Callback for when reply is tapped + final OnMessageTap? onReplyTap; + + /// Message in focus for actions + final Message message; + + /// [MessageTheme] for message + final MessageTheme messageTheme; + + /// Flag for showing reactions + final bool showReactions; + + /// Callback when copy is tapped + final OnMessageTap? onCopyTap; + + /// Callback when delete is tapped + final bool showDeleteMessage; + + /// Flag for showing copy action + final bool showCopyMessage; + + /// Flag for showing edit action + final bool showEditMessage; + + /// Flag for showing resend action + final bool showResendMessage; + + /// Flag for showing reply action + final bool showReplyMessage; + + /// Flag for showing thread reply action + final bool showThreadReplyMessage; + + /// Flag for showing flag action + final bool showFlagButton; + + /// Flag for reversing message + final bool reverse; + + /// [ShapeBorder] to apply to the widget + final ShapeBorder? messageShape; + + /// [ShapeBorder] to apply to attachment + final ShapeBorder? attachmentShape; + + /// Enum for displaying user avatar + final DisplayWidget showUserAvatar; + + /// [BorderRadius] for attachment border + final BorderRadius? attachmentBorderRadiusGeometry; + + /// List of custom actions + final List customActions; + @override _MessageActionsModalState createState() => _MessageActionsModalState(); } @@ -71,9 +105,7 @@ class _MessageActionsModalState extends State { bool _showActions = true; @override - Widget build(BuildContext context) { - return _showMessageOptionsModal(); - } + Widget build(BuildContext context) => _showMessageOptionsModal(); Widget _showMessageOptionsModal() { final size = MediaQuery.of(context).size; @@ -120,138 +152,135 @@ class _MessageActionsModalState extends State { if (_showActions) TweenAnimationBuilder( tween: Tween(begin: 0, end: 1), - duration: Duration(milliseconds: 300), + duration: const Duration(milliseconds: 300), curve: Curves.easeInOutBack, - builder: (context, val, snapshot) { - return Transform.scale( - scale: val, - child: Center( - child: SingleChildScrollView( - child: Padding( - padding: const EdgeInsets.all(8), - child: Column( - crossAxisAlignment: widget.reverse - ? CrossAxisAlignment.end - : CrossAxisAlignment.start, - children: [ - if (widget.showReactions && - (widget.message.status == - MessageSendingStatus.sent)) - Align( - alignment: Alignment( - user?.id == widget.message.user?.id - ? (divFactor > 1.0 - ? 0.0 - : (1.0 - divFactor)) - : (divFactor > 1.0 - ? 0.0 - : -(1.0 - divFactor)), - 0), - child: ReactionPicker( - message: widget.message, - ), - ), - SizedBox(height: 8), - IgnorePointer( - child: MessageWidget( - key: Key('MessageWidget'), - reverse: widget.reverse, - attachmentBorderRadiusGeometry: - widget.attachmentBorderRadiusGeometry, - message: widget.message.copyWith( - text: widget.message.text!.length > 200 - ? '${widget.message.text!.substring(0, 200)}...' - : widget.message.text, - ), - messageTheme: widget.messageTheme, - showReactions: false, - showUsername: false, - showReplyMessage: false, - showUserAvatar: widget.showUserAvatar, - attachmentPadding: EdgeInsets.all( - hasFileAttachment ? 4 : 2, - ), - showTimestamp: false, - translateUserAvatar: false, - padding: const EdgeInsets.all(0), - textPadding: EdgeInsets.symmetric( - vertical: 8, - horizontal: widget.message.text!.isOnlyEmoji - ? 0 - : 16.0, - ), - showReactionPickerIndicator: - widget.showReactions && - (widget.message.status == - MessageSendingStatus.sent), - showSendingIndicator: false, - shape: widget.messageShape, - attachmentShape: widget.attachmentShape, + builder: (context, val, snapshot) => Transform.scale( + scale: val, + child: Center( + child: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(8), + child: Column( + crossAxisAlignment: widget.reverse + ? CrossAxisAlignment.end + : CrossAxisAlignment.start, + children: [ + if (widget.showReactions && + (widget.message.status == + MessageSendingStatus.sent)) + Align( + alignment: Alignment( + user?.id == widget.message.user?.id + ? (divFactor > 1.0 + ? 0.0 + : (1.0 - divFactor)) + : (divFactor > 1.0 + ? 0.0 + : -(1.0 - divFactor)), + 0), + child: ReactionPicker( + message: widget.message, ), ), - SizedBox(height: 8), - Padding( - padding: EdgeInsets.only( - left: widget.reverse ? 0 : 40, + const SizedBox(height: 8), + IgnorePointer( + child: MessageWidget( + key: const Key('MessageWidget'), + reverse: widget.reverse, + attachmentBorderRadiusGeometry: + widget.attachmentBorderRadiusGeometry, + message: widget.message.copyWith( + text: widget.message.text!.length > 200 + // ignore: lines_longer_than_80_chars + ? '${widget.message.text!.substring(0, 200)}...' + : widget.message.text, ), - child: SizedBox( - width: MediaQuery.of(context).size.width * 0.75, - child: Material( - color: StreamChatTheme.of(context) - .colorTheme - .whiteSnow, - clipBehavior: Clip.hardEdge, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16), - ), - child: Column( - crossAxisAlignment: - CrossAxisAlignment.stretch, - children: [ - if (widget.showReplyMessage && - widget.message.status == - MessageSendingStatus.sent) - _buildReplyButton(context), - if (widget.showThreadReplyMessage && - (widget.message.status == - MessageSendingStatus.sent) && - widget.message.parentId == null) - _buildThreadReplyButton(context), - if (widget.showResendMessage) - _buildResendMessage(context), - if (widget.showEditMessage) - _buildEditMessage(context), - if (widget.showCopyMessage) - _buildCopyButton(context), - if (widget.showFlagButton) - _buildFlagButton(context), - if (widget.showDeleteMessage) - _buildDeleteButton(context), - ...widget.customActions.map((action) { - return _buildCustomAction( - context, - action, - ); - }) - ].insertBetween( - Container( - height: 1, - color: StreamChatTheme.of(context) - .colorTheme - .greyWhisper, - ), + messageTheme: widget.messageTheme, + showReactions: false, + showUsername: false, + showReplyMessage: false, + showUserAvatar: widget.showUserAvatar, + attachmentPadding: EdgeInsets.all( + hasFileAttachment ? 4 : 2, + ), + showTimestamp: false, + translateUserAvatar: false, + padding: const EdgeInsets.all(0), + textPadding: EdgeInsets.symmetric( + vertical: 8, + horizontal: + widget.message.text!.isOnlyEmoji ? 0 : 16.0, + ), + showReactionPickerIndicator: + widget.showReactions && + (widget.message.status == + MessageSendingStatus.sent), + showSendingIndicator: false, + shape: widget.messageShape, + attachmentShape: widget.attachmentShape, + ), + ), + const SizedBox(height: 8), + Padding( + padding: EdgeInsets.only( + left: widget.reverse ? 0 : 40, + ), + child: SizedBox( + width: MediaQuery.of(context).size.width * 0.75, + child: Material( + color: StreamChatTheme.of(context) + .colorTheme + .whiteSnow, + clipBehavior: Clip.hardEdge, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + ), + child: Column( + crossAxisAlignment: + CrossAxisAlignment.stretch, + children: [ + if (widget.showReplyMessage && + widget.message.status == + MessageSendingStatus.sent) + _buildReplyButton(context), + if (widget.showThreadReplyMessage && + (widget.message.status == + MessageSendingStatus.sent) && + widget.message.parentId == null) + _buildThreadReplyButton(context), + if (widget.showResendMessage) + _buildResendMessage(context), + if (widget.showEditMessage) + _buildEditMessage(context), + if (widget.showCopyMessage) + _buildCopyButton(context), + if (widget.showFlagButton) + _buildFlagButton(context), + if (widget.showDeleteMessage) + _buildDeleteButton(context), + ...widget.customActions + .map((action) => _buildCustomAction( + context, + action, + )) + ].insertBetween( + Container( + height: 1, + color: StreamChatTheme.of(context) + .colorTheme + .greyWhisper, ), ), ), ), ), - ], - ), + ), + ], ), ), ), - ); - }, + ), + ), ), ], ), @@ -261,23 +290,22 @@ class _MessageActionsModalState extends State { InkWell _buildCustomAction( BuildContext context, MessageAction messageAction, - ) { - return InkWell( - onTap: () { - messageAction.onTap?.call(widget.message); - }, - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 11, horizontal: 16), - child: Row( - children: [ - messageAction.leading ?? Offstage(), - const SizedBox(width: 16), - messageAction.title ?? Offstage(), - ], + ) => + InkWell( + onTap: () { + messageAction.onTap?.call(widget.message); + }, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 11, horizontal: 16), + child: Row( + children: [ + messageAction.leading ?? const Offstage(), + const SizedBox(width: 16), + messageAction.title ?? const Offstage(), + ], + ), ), - ), - ); - } + ); void _showFlagDialog() async { final client = StreamChat.of(context).client; @@ -290,6 +318,7 @@ class _MessageActionsModalState extends State { size: 24, ), question: + // ignore: lines_longer_than_80_chars 'Do you want to send a copy of this message to a\nmoderator for further investigation?', okText: 'FLAG', cancelText: 'CANCEL', @@ -371,52 +400,48 @@ class _MessageActionsModalState extends State { ); } - Widget _buildReplyButton(BuildContext context) { - return InkWell( - onTap: () { - Navigator.pop(context); - if (widget.onReplyTap != null) { - widget.onReplyTap!(widget.message); - } - }, - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 11, horizontal: 16), - child: Row( - children: [ - StreamSvgIcon.reply( - color: StreamChatTheme.of(context).primaryIconTheme.color, - ), - const SizedBox(width: 16), - Text( - 'Reply', - style: StreamChatTheme.of(context).textTheme.body, - ), - ], + Widget _buildReplyButton(BuildContext context) => InkWell( + onTap: () { + Navigator.pop(context); + if (widget.onReplyTap != null) { + widget.onReplyTap!(widget.message); + } + }, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 11, horizontal: 16), + child: Row( + children: [ + StreamSvgIcon.reply( + color: StreamChatTheme.of(context).primaryIconTheme.color, + ), + const SizedBox(width: 16), + Text( + 'Reply', + style: StreamChatTheme.of(context).textTheme.body, + ), + ], + ), ), - ), - ); - } + ); - Widget _buildFlagButton(BuildContext context) { - return InkWell( - onTap: _showFlagDialog, - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 11, horizontal: 16), - child: Row( - children: [ - StreamSvgIcon.iconFlag( - color: StreamChatTheme.of(context).primaryIconTheme.color, - ), - const SizedBox(width: 16), - Text( - 'Flag Message', - style: StreamChatTheme.of(context).textTheme.body, - ), - ], + Widget _buildFlagButton(BuildContext context) => InkWell( + onTap: _showFlagDialog, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 11, horizontal: 16), + child: Row( + children: [ + StreamSvgIcon.iconFlag( + color: StreamChatTheme.of(context).primaryIconTheme.color, + ), + const SizedBox(width: 16), + Text( + 'Flag Message', + style: StreamChatTheme.of(context).textTheme.body, + ), + ], + ), ), - ), - ); - } + ); Widget _buildDeleteButton(BuildContext context) { final isDeleteFailed = @@ -444,54 +469,50 @@ class _MessageActionsModalState extends State { ); } - Widget _buildCopyButton(BuildContext context) { - return InkWell( - onTap: () async { - widget.onCopyTap?.call(widget.message); - Navigator.pop(context); - }, - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 11, horizontal: 16), - child: Row( - children: [ - StreamSvgIcon.copy( - size: 24, - color: StreamChatTheme.of(context).primaryIconTheme.color, - ), - const SizedBox(width: 16), - Text( - 'Copy Message', - style: StreamChatTheme.of(context).textTheme.body, - ), - ], + Widget _buildCopyButton(BuildContext context) => InkWell( + onTap: () async { + widget.onCopyTap?.call(widget.message); + Navigator.pop(context); + }, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 11, horizontal: 16), + child: Row( + children: [ + StreamSvgIcon.copy( + size: 24, + color: StreamChatTheme.of(context).primaryIconTheme.color, + ), + const SizedBox(width: 16), + Text( + 'Copy Message', + style: StreamChatTheme.of(context).textTheme.body, + ), + ], + ), ), - ), - ); - } + ); - Widget _buildEditMessage(BuildContext context) { - return InkWell( - onTap: () async { - Navigator.pop(context); - _showEditBottomSheet(context); - }, - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 11, horizontal: 16), - child: Row( - children: [ - StreamSvgIcon.edit( - color: StreamChatTheme.of(context).primaryIconTheme.color, - ), - const SizedBox(width: 16), - Text( - 'Edit Message', - style: StreamChatTheme.of(context).textTheme.body, - ), - ], + Widget _buildEditMessage(BuildContext context) => InkWell( + onTap: () async { + Navigator.pop(context); + _showEditBottomSheet(context); + }, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 11, horizontal: 16), + child: Row( + children: [ + StreamSvgIcon.edit( + color: StreamChatTheme.of(context).primaryIconTheme.color, + ), + const SizedBox(width: 16), + Text( + 'Edit Message', + style: StreamChatTheme.of(context).textTheme.body, + ), + ], + ), ), - ), - ); - } + ); Widget _buildResendMessage(BuildContext context) { final isUpdateFailed = @@ -533,86 +554,81 @@ class _MessageActionsModalState extends State { isScrollControlled: true, backgroundColor: StreamChatTheme.of(context).messageInputTheme.inputBackground, - shape: RoundedRectangleBorder( + shape: const RoundedRectangleBorder( borderRadius: BorderRadius.only( topLeft: Radius.circular(16), topRight: Radius.circular(16), ), ), - builder: (context) { - return StreamChannel( - channel: channel, - child: Flex( - direction: Axis.vertical, - mainAxisAlignment: MainAxisAlignment.end, - mainAxisSize: MainAxisSize.min, - children: [ - Padding( - padding: const EdgeInsets.fromLTRB(8, 8, 8, 0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Padding( - padding: const EdgeInsets.all(8), - child: StreamSvgIcon.edit( - color: StreamChatTheme.of(context) - .colorTheme - .greyGainsboro, - ), + builder: (context) => StreamChannel( + channel: channel, + child: Flex( + direction: Axis.vertical, + mainAxisAlignment: MainAxisAlignment.end, + mainAxisSize: MainAxisSize.min, + children: [ + Padding( + padding: const EdgeInsets.fromLTRB(8, 8, 8, 0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Padding( + padding: const EdgeInsets.all(8), + child: StreamSvgIcon.edit( + color: + StreamChatTheme.of(context).colorTheme.greyGainsboro, ), - Text( - 'Edit Message', - style: TextStyle(fontWeight: FontWeight.bold), - ), - IconButton( - visualDensity: VisualDensity.compact, - icon: StreamSvgIcon.closeSmall(), - onPressed: Navigator.of(context).pop, - ), - ], - ), + ), + const Text( + 'Edit Message', + style: TextStyle(fontWeight: FontWeight.bold), + ), + IconButton( + visualDensity: VisualDensity.compact, + icon: StreamSvgIcon.closeSmall(), + onPressed: Navigator.of(context).pop, + ), + ], ), - if (widget.editMessageInputBuilder != null) - widget.editMessageInputBuilder!(context, widget.message) - else - MessageInput( - editMessage: widget.message, - preMessageSending: (m) { - FocusScope.of(context).unfocus(); - Navigator.pop(context); - return m; - }, - ), - ], - ), - ); - }, - ); - } - - Widget _buildThreadReplyButton(BuildContext context) { - return InkWell( - onTap: () { - Navigator.pop(context); - if (widget.onThreadReplyTap != null) { - widget.onThreadReplyTap!(widget.message); - } - }, - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 11, horizontal: 16), - child: Row( - children: [ - StreamSvgIcon.thread( - color: StreamChatTheme.of(context).primaryIconTheme.color, - ), - const SizedBox(width: 16), - Text( - 'Thread Reply', - style: StreamChatTheme.of(context).textTheme.body, ), + if (widget.editMessageInputBuilder != null) + widget.editMessageInputBuilder!(context, widget.message) + else + MessageInput( + editMessage: widget.message, + preMessageSending: (m) { + FocusScope.of(context).unfocus(); + Navigator.pop(context); + return m; + }, + ), ], ), ), ); } + + Widget _buildThreadReplyButton(BuildContext context) => InkWell( + onTap: () { + Navigator.pop(context); + if (widget.onThreadReplyTap != null) { + widget.onThreadReplyTap!(widget.message); + } + }, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 11, horizontal: 16), + child: Row( + children: [ + StreamSvgIcon.thread( + color: StreamChatTheme.of(context).primaryIconTheme.color, + ), + const SizedBox(width: 16), + Text( + 'Thread Reply', + style: StreamChatTheme.of(context).textTheme.body, + ), + ], + ), + ), + ); } diff --git a/packages/stream_chat_flutter/lib/src/message_input.dart b/packages/stream_chat_flutter/lib/src/message_input.dart index 638c7769..3091043c 100644 --- a/packages/stream_chat_flutter/lib/src/message_input.dart +++ b/packages/stream_chat_flutter/lib/src/message_input.dart @@ -14,19 +14,18 @@ import 'package:shimmer/shimmer.dart'; import 'package:stream_chat_flutter/src/emoji/emoji.dart'; import 'package:stream_chat_flutter/src/media_list_view.dart'; import 'package:stream_chat_flutter/src/message_list_view.dart'; +import 'package:stream_chat_flutter/src/quoted_message_widget.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import 'package:stream_chat_flutter/src/video_service.dart'; +import 'package:stream_chat_flutter/src/video_thumbnail_image.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:substring_highlight/substring_highlight.dart'; import 'package:video_compress/video_compress.dart'; +import 'package:stream_chat_flutter/src/extension.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; -import '../stream_chat_flutter.dart'; -import 'attachment/attachment.dart'; -import 'extension.dart'; -import 'quoted_message_widget.dart'; -import 'video_thumbnail_image.dart'; - +/// Builder for attachment thumbnails typedef AttachmentThumbnailBuilder = Widget Function( BuildContext, Attachment, @@ -39,16 +38,30 @@ typedef MentionTileBuilder = Widget Function( Member member, ); +/// Location for actions on the [MessageInput] enum ActionsLocation { + /// Align to left left, + + /// Align to right right, + + /// Align to left but inside the [TextField] leftInside, + + /// Align to right but inside the [TextField] rightInside, } +/// Default attachments for widget enum DefaultAttachmentTypes { + /// Image Attachment image, + + /// Video Attachment video, + + /// File Attachment file, } @@ -103,9 +116,11 @@ const _kMaxAttachmentSize = 20971520; // 20MB in Bytes /// } /// ``` /// -/// You usually put this widget in the same page of a [MessageListView] as the bottom widget. +/// You usually put this widget in the same page of a [MessageListView] +/// as the bottom widget. /// -/// The widget renders the ui based on the first ancestor of type [StreamChatTheme]. +/// The widget renders the ui based on the first ancestor of +/// type [StreamChatTheme]. /// Modify it to change the widget appearance. class MessageInput extends StatefulWidget { /// Instantiate a new MessageInput @@ -213,6 +228,7 @@ class MessageInput extends StatefulWidget { if (messageInputState == null) { throw Exception( + // ignore: lines_longer_than_80_chars 'You must have a MessageInput widget as ancestor of your widget tree'); } @@ -220,6 +236,7 @@ class MessageInput extends StatefulWidget { } } +/// State of [MessageInput] class MessageInputState extends State { final _attachments = {}; final List _mentionedUsers = []; @@ -313,7 +330,7 @@ class MessageInputState extends State { .greyGainsboro, ), ), - Text( + const Text( 'Reply to Message', style: TextStyle(fontWeight: FontWeight.bold), ), @@ -353,85 +370,83 @@ class MessageInputState extends State { return child; } - Flex _buildTextField(BuildContext context) { - return Flex( - direction: Axis.horizontal, - children: [ - if (!_commandEnabled && widget.actionsLocation == ActionsLocation.left) - _buildExpandActionsButton(), - _buildTextInput(context), - if (!_commandEnabled && widget.actionsLocation == ActionsLocation.right) - _buildExpandActionsButton(), - if (widget.sendButtonLocation == SendButtonLocation.outside) - _animateSendButton(context), - ], - ); - } + Flex _buildTextField(BuildContext context) => Flex( + direction: Axis.horizontal, + children: [ + if (!_commandEnabled && + widget.actionsLocation == ActionsLocation.left) + _buildExpandActionsButton(), + _buildTextInput(context), + if (!_commandEnabled && + widget.actionsLocation == ActionsLocation.right) + _buildExpandActionsButton(), + if (widget.sendButtonLocation == SendButtonLocation.outside) + _animateSendButton(context), + ], + ); - Widget _buildDmCheckbox() { - return Row( - children: [ - Container( - height: 16, - width: 16, - foregroundDecoration: BoxDecoration( - border: _sendAsDm - ? null - : Border.all( - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(.5), - width: 2, - ), - borderRadius: BorderRadius.circular(3), - ), - child: Center( - child: Material( + Widget _buildDmCheckbox() => Row( + children: [ + Container( + height: 16, + width: 16, + foregroundDecoration: BoxDecoration( + border: _sendAsDm + ? null + : Border.all( + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5), + width: 2, + ), borderRadius: BorderRadius.circular(3), - color: _sendAsDm - ? StreamChatTheme.of(context).colorTheme.accentBlue - : StreamChatTheme.of(context).colorTheme.white, - child: InkWell( - onTap: () { - setState(() { - _sendAsDm = !_sendAsDm; - }); - }, - child: AnimatedCrossFade( - duration: Duration(milliseconds: 300), - reverseDuration: Duration(milliseconds: 300), - crossFadeState: _sendAsDm - ? CrossFadeState.showFirst - : CrossFadeState.showSecond, - firstChild: StreamSvgIcon.check( - size: 16, - color: StreamChatTheme.of(context).colorTheme.white, - ), - secondChild: SizedBox( - height: 16, - width: 16, + ), + child: Center( + child: Material( + borderRadius: BorderRadius.circular(3), + color: _sendAsDm + ? StreamChatTheme.of(context).colorTheme.accentBlue + : StreamChatTheme.of(context).colorTheme.white, + child: InkWell( + onTap: () { + setState(() { + _sendAsDm = !_sendAsDm; + }); + }, + child: AnimatedCrossFade( + duration: const Duration(milliseconds: 300), + reverseDuration: const Duration(milliseconds: 300), + crossFadeState: _sendAsDm + ? CrossFadeState.showFirst + : CrossFadeState.showSecond, + firstChild: StreamSvgIcon.check( + size: 16, + color: StreamChatTheme.of(context).colorTheme.white, + ), + secondChild: const SizedBox( + height: 16, + width: 16, + ), ), ), ), ), ), - ), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 12), - child: Text( - 'Also send as direct message', - style: StreamChatTheme.of(context).textTheme.footnote.copyWith( - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(0.5), - ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 12), + child: Text( + 'Also send as direct message', + style: StreamChatTheme.of(context).textTheme.footnote.copyWith( + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5), + ), + ), ), - ), - ], - ); - } + ], + ); Widget _animateSendButton(BuildContext context) { final sendButton = widget.activeSendButton != null @@ -452,56 +467,54 @@ class MessageInputState extends State { ); } - Widget _buildExpandActionsButton() { - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 8), - child: AnimatedCrossFade( - crossFadeState: _actionsShrunk - ? CrossFadeState.showFirst - : CrossFadeState.showSecond, - firstChild: IconButton( - onPressed: () => setState(() => _actionsShrunk = false), - icon: Transform.rotate( - angle: (widget.actionsLocation == ActionsLocation.right || - widget.actionsLocation == ActionsLocation.rightInside) - ? pi - : 0, - child: StreamSvgIcon.emptyCircleLeft( - color: StreamChatTheme.of(context) - .messageInputTheme - .expandButtonColor, + Widget _buildExpandActionsButton() => Padding( + padding: const EdgeInsets.symmetric(horizontal: 8), + child: AnimatedCrossFade( + crossFadeState: _actionsShrunk + ? CrossFadeState.showFirst + : CrossFadeState.showSecond, + firstChild: IconButton( + onPressed: () => setState(() => _actionsShrunk = false), + icon: Transform.rotate( + angle: (widget.actionsLocation == ActionsLocation.right || + widget.actionsLocation == ActionsLocation.rightInside) + ? pi + : 0, + child: StreamSvgIcon.emptyCircleLeft( + color: StreamChatTheme.of(context) + .messageInputTheme + .expandButtonColor, + ), + ), + padding: const EdgeInsets.all(0), + constraints: const BoxConstraints.tightFor( + height: 24, + width: 24, + ), + splashRadius: 24, + ), + secondChild: FittedBox( + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + if (!widget.disableAttachments) _buildAttachmentButton(), + if (widget.showCommandsButton && + widget.editMessage == null && + StreamChannel.of(context) + .channel + .config + ?.commands + .isNotEmpty == + true) + _buildCommandButton(), + ...widget.actions ?? [], + ].insertBetween(const SizedBox(width: 8)), ), ), - padding: const EdgeInsets.all(0), - constraints: BoxConstraints.tightFor( - height: 24, - width: 24, - ), - splashRadius: 24, + duration: const Duration(milliseconds: 300), + alignment: Alignment.center, ), - secondChild: FittedBox( - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - if (!widget.disableAttachments) _buildAttachmentButton(), - if (widget.showCommandsButton && - widget.editMessage == null && - StreamChannel.of(context) - .channel - .config - ?.commands - .isNotEmpty == - true) - _buildCommandButton(), - ...widget.actions ?? [], - ].insertBetween(const SizedBox(width: 8)), - ), - ), - duration: Duration(milliseconds: 300), - alignment: Alignment.center, - ), - ); - } + ); Expanded _buildTextInput(BuildContext context) { final theme = StreamChatTheme.of(context); @@ -539,7 +552,7 @@ class MessageInputState extends State { LimitedBox( maxHeight: widget.maxHeight, child: TextField( - key: Key('messageInputText'), + key: const Key('messageInputText'), enabled: _inputEnabled, maxLines: null, onSubmitted: (_) => sendMessage(), @@ -571,27 +584,27 @@ class MessageInputState extends State { hintStyle: theme.messageInputTheme.inputTextStyle!.copyWith( color: theme.colorTheme.grey, ), - border: OutlineInputBorder( + border: const OutlineInputBorder( borderSide: BorderSide( color: Colors.transparent, ), ), - focusedBorder: OutlineInputBorder( + focusedBorder: const OutlineInputBorder( borderSide: BorderSide( color: Colors.transparent, ), ), - enabledBorder: OutlineInputBorder( + enabledBorder: const OutlineInputBorder( borderSide: BorderSide( color: Colors.transparent, ), ), - errorBorder: OutlineInputBorder( + errorBorder: const OutlineInputBorder( borderSide: BorderSide( color: Colors.transparent, ), ), - disabledBorder: OutlineInputBorder( + disabledBorder: const OutlineInputBorder( borderSide: BorderSide( color: Colors.transparent, ), @@ -604,7 +617,7 @@ class MessageInputState extends State { Padding( padding: const EdgeInsets.all(8), child: Container( - constraints: BoxConstraints.tight(Size(64, 24)), + constraints: BoxConstraints.tight(const Size(64, 24)), decoration: BoxDecoration( borderRadius: BorderRadius.circular(12), color: theme.colorTheme.accentBlue, @@ -640,8 +653,8 @@ class MessageInputState extends State { ], ) : null), - suffixIconConstraints: BoxConstraints.tightFor(height: 40), - prefixIconConstraints: BoxConstraints.tightFor(height: 40), + suffixIconConstraints: const BoxConstraints.tightFor(height: 40), + prefixIconConstraints: const BoxConstraints.tightFor(height: 40), suffixIcon: Row( mainAxisSize: MainAxisSize.min, children: [ @@ -652,7 +665,7 @@ class MessageInputState extends State { icon: StreamSvgIcon.closeSmall(), splashRadius: 24, padding: const EdgeInsets.all(0), - constraints: BoxConstraints.tightFor( + constraints: const BoxConstraints.tightFor( height: 24, width: 24, ), @@ -809,6 +822,7 @@ class MessageInputState extends State { return null; } + // ignore: cast_nullable_to_non_nullable final renderBox = context.findRenderObject() as RenderBox; final size = renderBox.size; @@ -819,7 +833,7 @@ class MessageInputState extends State { right: 0, child: TweenAnimationBuilder( tween: Tween(begin: 0, end: 1), - duration: Duration(milliseconds: 300), + duration: const Duration(milliseconds: 300), curve: Curves.easeInOutExpo, builder: (context, val, wid) => Transform.scale( scale: val, @@ -833,8 +847,8 @@ class MessageInputState extends State { color: StreamChatTheme.of(context).colorTheme.white, clipBehavior: Clip.antiAlias, child: Container( - constraints: - BoxConstraints.loose(Size.fromHeight(400)), + constraints: BoxConstraints.loose( + const Size.fromHeight(400)), decoration: BoxDecoration( color: StreamChatTheme.of(context) .colorTheme @@ -907,8 +921,11 @@ class MessageInputState extends State { .textTheme .body .copyWith( + // ignore: lines_longer_than_80_chars color: StreamChatTheme.of( + // ignore: lines_longer_than_80_chars context) + // ignore: lines_longer_than_80_chars .colorTheme .grey, ), @@ -932,9 +949,8 @@ class MessageInputState extends State { } Widget _buildFilePickerSection() { - final _attachmentContainsFile = _attachments.values.any((it) { - return it.type == 'file'; - }); + final _attachmentContainsFile = + _attachments.values.any((it) => it.type == 'file'); Color _getIconColor(int index) { switch (index) { @@ -973,7 +989,8 @@ class MessageInputState extends State { } return AnimatedContainer( - duration: _animateContainer ? Duration(milliseconds: 300) : Duration.zero, + duration: + _animateContainer ? const Duration(milliseconds: 300) : Duration.zero, height: _openFilePickerSection ? _filePickerSize : 0, child: Material( color: StreamChatTheme.of(context).colorTheme.whiteSmoke, @@ -1095,7 +1112,7 @@ class MessageInputState extends State { void _addAttachment(AssetEntity medium) async { final mediaFile = await medium.originFile.timeout( - Duration(seconds: 5), + const Duration(seconds: 5), onTimeout: () => medium.originFile, ); @@ -1116,13 +1133,14 @@ class MessageInputState extends State { if (mediaInfo.filesize! > _kMaxAttachmentSize) { _showErrorAlert( + // ignore: lines_longer_than_80_chars 'The file is too large to upload. The file size limit is 20MB. We tried compressing it, but it was not enough.', ); return; } file = AttachmentFile( name: file.name, - size: mediaInfo.filesize!, + size: mediaInfo.filesize, bytes: await mediaInfo.file?.readAsBytes(), path: mediaInfo.path, ); @@ -1234,108 +1252,103 @@ class MessageInputState extends State { .then((res) => res.members); } - final members = StreamChannel.of(context).channel.state?.members.where((m) { - return m.user?.name.toLowerCase().contains(query) == true; - }).toList() ?? + final members = StreamChannel.of(context) + .channel + .state + ?.members + .where((m) => m.user?.name.toLowerCase().contains(query) == true) + .toList() ?? []; if (members.isEmpty) { return null; } + // ignore: cast_nullable_to_non_nullable final renderBox = context.findRenderObject() as RenderBox; final size = renderBox.size; return OverlayEntry( - builder: (context) { - return Positioned( - bottom: size.height + MediaQuery.of(context).viewInsets.bottom, - left: 0, - right: 0, - child: TweenAnimationBuilder( - tween: Tween(begin: 0, end: 1), - duration: Duration(milliseconds: 300), - curve: Curves.easeInOutExpo, - builder: (context, val, wid) { - return Transform.scale( - scale: val, - child: Card( - margin: EdgeInsets.all(8), - elevation: 2, + builder: (context) => Positioned( + bottom: size.height + MediaQuery.of(context).viewInsets.bottom, + left: 0, + right: 0, + child: TweenAnimationBuilder( + tween: Tween(begin: 0, end: 1), + duration: const Duration(milliseconds: 300), + curve: Curves.easeInOutExpo, + builder: (context, val, wid) => Transform.scale( + scale: val, + child: Card( + margin: const EdgeInsets.all(8), + elevation: 2, + color: StreamChatTheme.of(context).colorTheme.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + clipBehavior: Clip.antiAlias, + child: Container( + constraints: BoxConstraints.loose(const Size.fromHeight(240)), + decoration: BoxDecoration( color: StreamChatTheme.of(context).colorTheme.white, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), - clipBehavior: Clip.antiAlias, - child: Container( - constraints: BoxConstraints.loose(Size.fromHeight(240)), - decoration: BoxDecoration( - color: StreamChatTheme.of(context).colorTheme.white, - ), - child: FutureBuilder>( - future: queryMembers ?? Future.value(members), - initialData: members, - builder: (context, snapshot) { - return ListView( - padding: const EdgeInsets.all(0), - shrinkWrap: true, - children: [ - SizedBox( - height: 8, - ), - ...snapshot.data! - .where((it) => it.user != null) - .map( - (m) { - return Material( - color: StreamChatTheme.of(context) - .colorTheme - .white, - child: InkWell( - onTap: () { - if (m.user != null) { - _mentionedUsers.add(m.user!); - } + ), + child: FutureBuilder>( + future: queryMembers ?? Future.value(members), + initialData: members, + builder: (context, snapshot) => ListView( + padding: const EdgeInsets.all(0), + shrinkWrap: true, + children: [ + const SizedBox( + height: 8, + ), + ...snapshot.data! + .where((it) => it.user != null) + .map( + (m) => Material( + color: + StreamChatTheme.of(context).colorTheme.white, + child: InkWell( + onTap: () { + if (m.user != null) { + _mentionedUsers.add(m.user!); + } - splits[splits.length - 1] = m.user!.name; - final rejoin = splits.join('@'); + splits[splits.length - 1] = m.user!.name; + final rejoin = splits.join('@'); - textEditingController.value = - TextEditingValue( - text: rejoin + - textEditingController.text - .substring(textEditingController - .selection.start), - selection: TextSelection.collapsed( - offset: rejoin.length, - ), - ); - _debounce!.cancel(); - _mentionsOverlay?.remove(); - _mentionsOverlay = null; - }, - child: widget.mentionsTileBuilder != null - ? widget.mentionsTileBuilder!( - context, m) - : MentionTile(m), - ), - ); - }, - ).toList(), - SizedBox( - height: 8, + textEditingController.value = + TextEditingValue( + text: rejoin + + textEditingController.text.substring( + textEditingController + .selection.start), + selection: TextSelection.collapsed( + offset: rejoin.length, + ), + ); + _debounce!.cancel(); + _mentionsOverlay?.remove(); + _mentionsOverlay = null; + }, + child: widget.mentionsTileBuilder != null + ? widget.mentionsTileBuilder!(context, m) + : MentionTile(m), + ), ), - ], - ); - }, - ), + ) + .toList(), + const SizedBox( + height: 8, + ), + ], ), ), - ); - }, + ), + ), ), - ); - }, + ), + ), ); } @@ -1358,92 +1371,95 @@ class MessageInputState extends State { return null; } + // ignore: cast_nullable_to_non_nullable final renderBox = context.findRenderObject() as RenderBox; final size = renderBox.size; - return OverlayEntry(builder: (context) { - return Positioned( - bottom: size.height + MediaQuery.of(context).viewInsets.bottom, - left: 0, - right: 0, - child: Card( - margin: EdgeInsets.all(8), - elevation: 2, - color: StreamChatTheme.of(context).colorTheme.white, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), - clipBehavior: Clip.antiAlias, - child: Container( - constraints: BoxConstraints.loose(Size.fromHeight(200)), - decoration: BoxDecoration( - boxShadow: [ - BoxShadow( - spreadRadius: -8, - blurRadius: 5, - offset: Offset(0, -4), + return OverlayEntry( + builder: (context) => Positioned( + bottom: size.height + MediaQuery.of(context).viewInsets.bottom, + left: 0, + right: 0, + child: Card( + margin: const EdgeInsets.all(8), + elevation: 2, + color: StreamChatTheme.of(context).colorTheme.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), ), - ], - color: StreamChatTheme.of(context).colorTheme.white, - ), - child: ListView.builder( - padding: const EdgeInsets.all(0), - shrinkWrap: true, - itemCount: emojis.length + 1, - itemBuilder: (context, i) { - if (i == 0) { - return Padding( - padding: const EdgeInsets.only(left: 8, top: 8), - child: Row( - children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 8), - child: StreamSvgIcon.smile( - color: StreamChatTheme.of(context) - .colorTheme - .accentBlue, - ), - ), - Flexible( - child: Text( - 'Emoji matching "$query"', - style: TextStyle( - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(.5), - ), - ), - ) - ], + clipBehavior: Clip.antiAlias, + child: Container( + constraints: BoxConstraints.loose(const Size.fromHeight(200)), + decoration: BoxDecoration( + boxShadow: const [ + BoxShadow( + spreadRadius: -8, + blurRadius: 5, + offset: Offset(0, -4), ), - ); - } + ], + color: StreamChatTheme.of(context).colorTheme.white, + ), + child: ListView.builder( + padding: const EdgeInsets.all(0), + shrinkWrap: true, + itemCount: emojis.length + 1, + itemBuilder: (context, i) { + if (i == 0) { + return Padding( + padding: const EdgeInsets.only(left: 8, top: 8), + child: Row( + children: [ + Padding( + padding: + const EdgeInsets.symmetric(horizontal: 8), + child: StreamSvgIcon.smile( + color: StreamChatTheme.of(context) + .colorTheme + .accentBlue, + ), + ), + Flexible( + child: Text( + 'Emoji matching "$query"', + style: TextStyle( + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5), + ), + ), + ) + ], + ), + ); + } - final emoji = emojis.elementAt(i - 1)!; - return ListTile( - title: SubstringHighlight( - text: "${emoji.char} ${emoji.name!.replaceAll('_', ' ')}", - term: query, - textStyleHighlight: - Theme.of(context).textTheme.headline6!.copyWith( - fontSize: 14.5, - fontWeight: FontWeight.bold, - ), - textStyle: - Theme.of(context).textTheme.headline6!.copyWith( - fontSize: 14.5, - ), - ), - onTap: () { - _chooseEmoji(splits, emoji); - }, - ); - }), - ), - ), - ); - }); + final emoji = emojis.elementAt(i - 1)!; + return ListTile( + title: SubstringHighlight( + text: + // ignore: lines_longer_than_80_chars + "${emoji.char} ${emoji.name!.replaceAll('_', ' ')}", + term: query, + textStyleHighlight: + Theme.of(context).textTheme.headline6!.copyWith( + fontSize: 14.5, + fontWeight: FontWeight.bold, + ), + textStyle: + Theme.of(context).textTheme.headline6!.copyWith( + fontSize: 14.5, + ), + ), + onTap: () { + _chooseEmoji(splits, emoji); + }, + ); + }), + ), + ), + )); } void _chooseEmoji(List splits, Emoji emoji) { @@ -1474,7 +1490,7 @@ class MessageInputState extends State { } Widget _buildReplyToMessage() { - if (!_hasQuotedMessage) return Offstage(); + if (!_hasQuotedMessage) return const Offstage(); final containsUrl = widget.quotedMessage!.attachments .any((element) => element.ogScrapeUrl != null) == true; @@ -1492,7 +1508,7 @@ class MessageInputState extends State { } Widget _buildAttachments() { - if (_attachments.isEmpty) return Offstage(); + if (_attachments.isEmpty) return const Offstage(); final fileAttachments = _attachments.values .where((it) => it.type == 'file') .toList(growable: false); @@ -1546,7 +1562,7 @@ class MessageInputState extends State { children: [ AspectRatio( aspectRatio: 1, - child: Container( + child: SizedBox( height: 104, width: 104, child: _buildAttachment(attachment), @@ -1569,31 +1585,30 @@ class MessageInputState extends State { ); } - Widget _buildRemoveButton(Attachment attachment) { - return Container( - height: 24, - width: 24, - child: RawMaterialButton( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16), - ), - elevation: 0, - highlightElevation: 0, - focusElevation: 0, - hoverElevation: 0, - onPressed: () { - setState(() => _attachments.remove(attachment.id)); - }, - fillColor: StreamChatTheme.of(context).colorTheme.black.withOpacity(.5), - child: Center( - child: StreamSvgIcon.close( - size: 24, - color: StreamChatTheme.of(context).colorTheme.white, + Widget _buildRemoveButton(Attachment attachment) => SizedBox( + height: 24, + width: 24, + child: RawMaterialButton( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + ), + elevation: 0, + highlightElevation: 0, + focusElevation: 0, + hoverElevation: 0, + onPressed: () { + setState(() => _attachments.remove(attachment.id)); + }, + fillColor: + StreamChatTheme.of(context).colorTheme.black.withOpacity(.5), + child: Center( + child: StreamSvgIcon.close( + size: 24, + color: StreamChatTheme.of(context).colorTheme.white, + ), ), ), - ), - ); - } + ); Widget _buildAttachment(Attachment attachment) { if (widget.attachmentThumbnailBuilders?.containsKey(attachment.type) == @@ -1611,35 +1626,30 @@ class MessageInputState extends State { ? Image.memory( attachment.file!.bytes!, fit: BoxFit.cover, - errorBuilder: (context, _, __) { - return Image.asset( - 'images/placeholder.png', - package: 'stream_chat_flutter', - ); - }, + errorBuilder: (context, _, __) => Image.asset( + 'images/placeholder.png', + package: 'stream_chat_flutter', + ), ) : CachedNetworkImage( imageUrl: attachment.imageUrl ?? attachment.assetUrl ?? attachment.thumbUrl!, fit: BoxFit.cover, - errorWidget: (_, obj, trace) { - return getFileTypeImage( - attachment.extraData['other'] as String?); - }, - progressIndicatorBuilder: (context, _, progress) { - return Shimmer.fromColors( - baseColor: - StreamChatTheme.of(context).colorTheme.greyGainsboro, - highlightColor: - StreamChatTheme.of(context).colorTheme.whiteSmoke, - child: Image.asset( - 'images/placeholder.png', - fit: BoxFit.cover, - package: 'stream_chat_flutter', - ), - ); - }, + errorWidget: (_, obj, trace) => + getFileTypeImage(attachment.extraData['other'] as String?), + progressIndicatorBuilder: (context, _, progress) => + Shimmer.fromColors( + baseColor: + StreamChatTheme.of(context).colorTheme.greyGainsboro, + highlightColor: + StreamChatTheme.of(context).colorTheme.whiteSmoke, + child: Image.asset( + 'images/placeholder.png', + fit: BoxFit.cover, + package: 'stream_chat_flutter', + ), + ), ); case 'video': return Stack( @@ -1663,7 +1673,7 @@ class MessageInputState extends State { default: return Container( color: Colors.black26, - child: Icon(Icons.insert_drive_file), + child: const Icon(Icons.insert_drive_file), ); } } @@ -1684,7 +1694,7 @@ class MessageInputState extends State { .actionButtonIdleColor), ), padding: const EdgeInsets.all(0), - constraints: BoxConstraints.tightFor( + constraints: const BoxConstraints.tightFor( height: 24, width: 24, ), @@ -1696,7 +1706,7 @@ class MessageInputState extends State { _openFilePickerSection = false; _filePickerSize = _kMinMediaPickerSize; }); - await Future.delayed(Duration(milliseconds: 300)); + await Future.delayed(const Duration(milliseconds: 300)); } if (_commandsOverlay == null) { @@ -1716,43 +1726,42 @@ class MessageInputState extends State { ); } - Widget _buildAttachmentButton() { - return IconButton( - icon: StreamSvgIcon.attach( - color: _openFilePickerSection - ? StreamChatTheme.of(context).messageInputTheme.actionButtonColor - : StreamChatTheme.of(context) - .messageInputTheme - .actionButtonIdleColor, - ), - padding: const EdgeInsets.all(0), - constraints: BoxConstraints.tightFor( - height: 24, - width: 24, - ), - splashRadius: 24, - onPressed: () async { - _emojiOverlay?.remove(); - _emojiOverlay = null; - _commandsOverlay?.remove(); - _commandsOverlay = null; - _mentionsOverlay?.remove(); - _mentionsOverlay = null; + Widget _buildAttachmentButton() => IconButton( + icon: StreamSvgIcon.attach( + color: _openFilePickerSection + ? StreamChatTheme.of(context).messageInputTheme.actionButtonColor + : StreamChatTheme.of(context) + .messageInputTheme + .actionButtonIdleColor, + ), + padding: const EdgeInsets.all(0), + constraints: const BoxConstraints.tightFor( + height: 24, + width: 24, + ), + splashRadius: 24, + onPressed: () async { + _emojiOverlay?.remove(); + _emojiOverlay = null; + _commandsOverlay?.remove(); + _commandsOverlay = null; + _mentionsOverlay?.remove(); + _mentionsOverlay = null; - if (_openFilePickerSection) { - setState(() { - _animateContainer = true; - _openFilePickerSection = false; - _filePickerSize = _kMinMediaPickerSize; - }); - } else { - showAttachmentModal(); - } - }, - ); - } + if (_openFilePickerSection) { + setState(() { + _animateContainer = true; + _openFilePickerSection = false; + _filePickerSize = _kMinMediaPickerSize; + }); + } else { + showAttachmentModal(); + } + }, + ); - /// Show the attachment modal, making the user choose where to pick a media from + /// Show the attachment modal, making the user choose where to + /// pick a media from void showAttachmentModal() { if (_focusNode.hasFocus) { _focusNode.unfocus(); @@ -1765,7 +1774,7 @@ class MessageInputState extends State { } else { showModalBottomSheet( clipBehavior: Clip.hardEdge, - shape: RoundedRectangleBorder( + shape: const RoundedRectangleBorder( borderRadius: BorderRadius.only( topLeft: Radius.circular(32), topRight: Radius.circular(32), @@ -1773,63 +1782,61 @@ class MessageInputState extends State { ), context: context, isScrollControlled: true, - builder: (_) { - return Column( - mainAxisSize: MainAxisSize.min, - children: [ - ListTile( - title: Text( - 'Add a file', - style: TextStyle( - fontWeight: FontWeight.bold, + builder: (_) => Column( + mainAxisSize: MainAxisSize.min, + children: [ + const ListTile( + title: Text( + 'Add a file', + style: TextStyle( + fontWeight: FontWeight.bold, + ), ), ), - ), - ListTile( - leading: Icon(Icons.image), - title: Text('Upload a photo'), - onTap: () { - pickFile(DefaultAttachmentTypes.image); - Navigator.pop(context); - }, - ), - ListTile( - leading: Icon(Icons.video_library), - title: Text('Upload a video'), - onTap: () { - pickFile(DefaultAttachmentTypes.video); - Navigator.pop(context); - }, - ), - if (!kIsWeb) ListTile( - leading: Icon(Icons.camera_alt), - title: Text('Photo from camera'), + leading: const Icon(Icons.image), + title: const Text('Upload a photo'), onTap: () { - pickFile(DefaultAttachmentTypes.image, true); + pickFile(DefaultAttachmentTypes.image); Navigator.pop(context); }, ), - if (!kIsWeb) ListTile( - leading: Icon(Icons.videocam), - title: Text('Video from camera'), + leading: const Icon(Icons.video_library), + title: const Text('Upload a video'), onTap: () { - pickFile(DefaultAttachmentTypes.video, true); + pickFile(DefaultAttachmentTypes.video); Navigator.pop(context); }, ), - ListTile( - leading: Icon(Icons.insert_drive_file), - title: Text('Upload a file'), - onTap: () { - pickFile(DefaultAttachmentTypes.file); - Navigator.pop(context); - }, - ), - ], - ); - }); + if (!kIsWeb) + ListTile( + leading: const Icon(Icons.camera_alt), + title: const Text('Photo from camera'), + onTap: () { + pickFile(DefaultAttachmentTypes.image, true); + Navigator.pop(context); + }, + ), + if (!kIsWeb) + ListTile( + leading: const Icon(Icons.videocam), + title: const Text('Video from camera'), + onTap: () { + pickFile(DefaultAttachmentTypes.video, true); + Navigator.pop(context); + }, + ), + ListTile( + leading: const Icon(Icons.insert_drive_file), + title: const Text('Upload a file'), + onTap: () { + pickFile(DefaultAttachmentTypes.file); + Navigator.pop(context); + }, + ), + ], + )); } } @@ -1845,6 +1852,7 @@ class MessageInputState extends State { /// Pick a file from the device /// If [camera] is true then the camera will open + // ignore: avoid_positional_boolean_parameters void pickFile(DefaultAttachmentTypes fileType, [bool camera = false]) async { setState(() => _inputEnabled = false); @@ -1920,13 +1928,14 @@ class MessageInputState extends State { if (mediaInfo.filesize! > _kMaxAttachmentSize) { _showErrorAlert( + // ignore: lines_longer_than_80_chars 'The file is too large to upload. The file size limit is 20MB. We tried compressing it, but it was not enough.', ); return; } file = AttachmentFile( name: file.name, - size: mediaInfo.filesize!, + size: mediaInfo.filesize, bytes: await mediaInfo.file!.readAsBytes(), path: mediaInfo.path, ); @@ -1941,45 +1950,42 @@ class MessageInputState extends State { _attachments[attachment.id] = attachment; setState(() { - _attachments.update(attachment.id, (it) { - return it.copyWith( - file: file, - extraData: {...it.extraData} - ..update('file_size', ((_) => file!.size!)), - ); - }); + _attachments.update( + attachment.id, + (it) => it.copyWith( + file: file, + extraData: {...it.extraData} + ..update('file_size', ((_) => file!.size!)), + )); }); } - Widget _buildIdleSendButton(BuildContext context) { - return Padding( - padding: const EdgeInsets.all(8), - child: StreamSvgIcon( - assetName: _getIdleSendIcon(), - color: - StreamChatTheme.of(context).messageInputTheme.sendButtonIdleColor, - ), - ); - } + Widget _buildIdleSendButton(BuildContext context) => Padding( + padding: const EdgeInsets.all(8), + child: StreamSvgIcon( + assetName: _getIdleSendIcon(), + color: + StreamChatTheme.of(context).messageInputTheme.sendButtonIdleColor, + ), + ); - Widget _buildSendButton(BuildContext context) { - return Padding( - padding: const EdgeInsets.all(8), - child: IconButton( - onPressed: sendMessage, - padding: const EdgeInsets.all(0), - splashRadius: 24, - constraints: BoxConstraints.tightFor( - height: 24, - width: 24, + Widget _buildSendButton(BuildContext context) => Padding( + padding: const EdgeInsets.all(8), + child: IconButton( + onPressed: sendMessage, + padding: const EdgeInsets.all(0), + splashRadius: 24, + constraints: const BoxConstraints.tightFor( + height: 24, + width: 24, + ), + icon: StreamSvgIcon( + assetName: _getSendIcon(), + color: + StreamChatTheme.of(context).messageInputTheme.sendButtonColor, + ), ), - icon: StreamSvgIcon( - assetName: _getSendIcon(), - color: StreamChatTheme.of(context).messageInputTheme.sendButtonColor, - ), - ), - ); - } + ); String _getIdleSendIcon() { if (_commandEnabled) { @@ -2009,7 +2015,7 @@ class MessageInputState extends State { final shouldUnfocus = _commandEnabled; if (_commandEnabled) { - text = '/${_chosenCommand!.name} ' + text; + text = '${'/${_chosenCommand!.name} '}$text'; } final attachments = [..._attachments.values]; @@ -2096,70 +2102,68 @@ class MessageInputState extends State { showModalBottomSheet( backgroundColor: StreamChatTheme.of(context).colorTheme.white, context: context, - shape: RoundedRectangleBorder( + shape: const RoundedRectangleBorder( borderRadius: BorderRadius.only( topLeft: Radius.circular(16), topRight: Radius.circular(16), )), - builder: (context) { - return Column( - mainAxisSize: MainAxisSize.min, - children: [ - SizedBox( - height: 26, + builder: (context) => Column( + mainAxisSize: MainAxisSize.min, + children: [ + const SizedBox( + height: 26, + ), + StreamSvgIcon.error( + color: StreamChatTheme.of(context).colorTheme.accentRed, + size: 24, + ), + const SizedBox( + height: 26, + ), + Text( + 'Something went wrong', + style: StreamChatTheme.of(context).textTheme.headlineBold, + ), + const SizedBox( + height: 7, + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Text( + description, + textAlign: TextAlign.center, ), - StreamSvgIcon.error( - color: StreamChatTheme.of(context).colorTheme.accentRed, - size: 24, - ), - SizedBox( - height: 26, - ), - Text( - 'Something went wrong', - style: StreamChatTheme.of(context).textTheme.headlineBold, - ), - SizedBox( - height: 7, - ), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16), - child: Text( - description, - textAlign: TextAlign.center, - ), - ), - SizedBox( - height: 36, - ), - Container( - color: - StreamChatTheme.of(context).colorTheme.black.withOpacity(.08), - height: 1, - ), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - TextButton( - onPressed: () { - Navigator.of(context).pop(); - }, - child: Text( - 'OK', - style: StreamChatTheme.of(context) - .textTheme - .bodyBold - .copyWith( - color: StreamChatTheme.of(context) - .colorTheme - .accentBlue), - ), + ), + const SizedBox( + height: 36, + ), + Container( + color: + StreamChatTheme.of(context).colorTheme.black.withOpacity(.08), + height: 1, + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + TextButton( + onPressed: () { + Navigator.of(context).pop(); + }, + child: Text( + 'OK', + style: StreamChatTheme.of(context) + .textTheme + .bodyBold + .copyWith( + color: StreamChatTheme.of(context) + .colorTheme + .accentBlue), ), - ], - ), - ], - ); - }, + ), + ], + ), + ], + ), ); } @@ -2196,12 +2200,6 @@ class MessageInputState extends State { /// Represents a 2-tuple, or pair. class Tuple2 { - /// Returns the first item of the tuple - final T1 item1; - - /// Returns the second item of the tuple - final T2 item2; - /// Creates a new tuple value with the specified items. const Tuple2(this.item1, this.item2); @@ -2214,6 +2212,12 @@ class Tuple2 { return Tuple2(items[0] as T1, items[1] as T2); } + /// Returns the first item of the tuple + final T1 item1; + + /// Returns the second item of the tuple + final T2 item2; + /// Returns a tuple with the first item set to the specified value. Tuple2 withItem1(T1 v) => Tuple2(v, item2); @@ -2243,12 +2247,6 @@ class Tuple2 { } class _PickerWidget extends StatefulWidget { - final int filePickerIndex; - final bool containsFile; - final List selectedMedias; - final void Function(DefaultAttachmentTypes) onAddMoreFilesClick; - final void Function(AssetEntity) onMediaSelected; - const _PickerWidget({ Key? key, required this.filePickerIndex, @@ -2258,6 +2256,12 @@ class _PickerWidget extends StatefulWidget { required this.onMediaSelected, }) : super(key: key); + final int filePickerIndex; + final bool containsFile; + final List selectedMedias; + final void Function(DefaultAttachmentTypes) onAddMoreFilesClick; + final void Function(AssetEntity) onMediaSelected; + @override __PickerWidgetState createState() => __PickerWidgetState(); } @@ -2274,7 +2278,7 @@ class __PickerWidgetState extends State<_PickerWidget> { @override Widget build(BuildContext context) { if (widget.filePickerIndex != 0) { - return Offstage(); + return const Offstage(); } return FutureBuilder( future: requestPermission, @@ -2290,7 +2294,7 @@ class __PickerWidgetState extends State<_PickerWidget> { widget.onAddMoreFilesClick(DefaultAttachmentTypes.file); }, child: Container( - constraints: BoxConstraints.expand(), + constraints: const BoxConstraints.expand(), color: StreamChatTheme.of(context).colorTheme.whiteSmoke, alignment: Alignment.center, child: Text( @@ -2326,12 +2330,13 @@ class __PickerWidgetState extends State<_PickerWidget> { color: StreamChatTheme.of(context).colorTheme.greyGainsboro, ), Text( + // ignore: lines_longer_than_80_chars 'Please enable access to your photos \nand videos so you can share them with friends.', style: StreamChatTheme.of(context).textTheme.body.copyWith( color: StreamChatTheme.of(context).colorTheme.grey), textAlign: TextAlign.center, ), - SizedBox(height: 6), + const SizedBox(height: 6), Center( child: Text( 'Allow access to your gallery', From 160baa5d956a2d9b3c54b914609c8714d562a317 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 5 May 2021 15:53:08 +0530 Subject: [PATCH 09/31] lint changes mlv --- .../lib/src/message_list_view.dart | 410 +++++++++--------- 1 file changed, 211 insertions(+), 199 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/message_list_view.dart b/packages/stream_chat_flutter/lib/src/message_list_view.dart index 5b3b0359..2800a041 100644 --- a/packages/stream_chat_flutter/lib/src/message_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/message_list_view.dart @@ -12,34 +12,60 @@ import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import 'package:stream_chat_flutter/src/system_message.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:visibility_detector/visibility_detector.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; +import 'package:stream_chat_flutter/src/extension.dart'; +import 'package:stream_chat_flutter/src/swipeable.dart'; -import '../stream_chat_flutter.dart'; -import 'connection_status_builder.dart'; -import 'date_divider.dart'; -import 'extension.dart'; -import 'swipeable.dart'; - +/// Widget builder for message typedef MessageBuilder = Widget Function( BuildContext, MessageDetails, List, ); + +/// Widget builder for parent message typedef ParentMessageBuilder = Widget Function( BuildContext, Message?, ); + +/// Widget builder for system message typedef SystemMessageBuilder = Widget Function( BuildContext, Message, ); + +/// Widget builder for thread typedef ThreadBuilder = Widget Function(BuildContext context, Message? parent); + +/// Callback for thread taps typedef ThreadTapCallback = void Function(Message, Widget?); +/// Callback on message swiped typedef OnMessageSwiped = void Function(Message); + +/// Callback on message tapped typedef OnMessageTap = void Function(Message); + +/// Callback on reply tapped typedef ReplyTapCallback = void Function(Message); +/// Class for message details class MessageDetails { + /// Constructor for creating [MessageDetails] + MessageDetails( + BuildContext context, + this.message, + List messages, + this.index, + ) { + isMyMessage = message.user?.id == StreamChat.of(context).user?.id; + isLastUser = index + 1 < messages.length && + message.user?.id == messages[index + 1].user?.id; + isNextUser = + index - 1 >= 0 && message.user!.id == messages[index - 1].user?.id; + } + /// True if the message belongs to the current user bool? isMyMessage; @@ -54,19 +80,6 @@ class MessageDetails { /// The index of the message int index; - - MessageDetails( - BuildContext context, - this.message, - List messages, - this.index, - ) { - isMyMessage = message.user?.id == StreamChat.of(context).user?.id; - isLastUser = index + 1 < messages.length && - message.user?.id == messages[index + 1].user?.id; - isNextUser = - index - 1 >= 0 && message.user!.id == messages[index - 1].user?.id; - } } /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/message_listview.png) @@ -104,10 +117,12 @@ class MessageDetails { /// ``` /// /// -/// Make sure to have a [StreamChannel] ancestor in order to provide the information about the channels. +/// Make sure to have a [StreamChannel] ancestor in order to +/// provide the information about the channels. /// The widget uses a [ListView.custom] to render the list of channels. /// -/// The widget components render the ui based on the first ancestor of type [StreamChatTheme]. +/// The widget components render the ui based on the first +/// ancestor of type [StreamChatTheme]. /// Modify it to change the widget appearance. class MessageListView extends StatefulWidget { /// Instantiate a new MessageListView @@ -158,10 +173,12 @@ class MessageListView extends StatefulWidget { final ThreadBuilder? threadBuilder; /// Function called when tapping on a thread - /// By default it calls [Navigator.push] using the widget built using [threadBuilder] + /// By default it calls [Navigator.push] using the widget + /// built using [threadBuilder] final ThreadTapCallback? onThreadTap; - /// If true will show a scroll to bottom message when there are new messages and the scroll offset is not zero + /// If true will show a scroll to bottom message when there are new + /// messages and the scroll offset is not zero final bool showScrollToBottom; /// Parent message in case of a thread @@ -201,8 +218,10 @@ class MessageListView extends StatefulWidget { /// Color used while highlighting initial message final Color? messageHighlightColor; + /// Callback when show message is tapped final ShowMessageCallback? onShowMessage; + /// Flag for showing tile on header final bool showConnectionStateTile; /// Function called when messages are fetched @@ -214,8 +233,10 @@ class MessageListView extends StatefulWidget { /// Function used to build an empty widget final WidgetBuilder? emptyBuilder; - /// Callback triggered when an error occurs while performing the given request. - /// This parameter can be used to display an error message to users in the event + /// Callback triggered when an error occurs while performing the + /// given request. + /// This parameter can be used to display an error message to + /// users in the event /// of a connection failure. final ErrorBuilder? errorWidgetBuilder; @@ -223,10 +244,12 @@ class MessageListView extends StatefulWidget { final bool Function(Message)? messageFilter; /// Attachment builders for the default message widget - /// Please change this in the [MessageWidget] if you are using a custom implementation + /// Please change this in the [MessageWidget] if you are using a + /// custom implementation final Map? customAttachmentBuilders; - /// Called when any message is tapped except a system message (use [onSystemMessageTap] instead) + /// Called when any message is tapped except a system message + /// (use [onSystemMessageTap] instead) final OnMessageTap? onMessageTap; /// Called when system message is tapped @@ -238,6 +261,7 @@ class MessageListView extends StatefulWidget { /// Customize the MessageWidget textBuilder final void Function(BuildContext context, Message message)? textBuilder; + /// Callback for when link is tapped final void Function(String link)? onLinkTap; @override @@ -257,9 +281,8 @@ class _MessageListViewState extends State { if (streamChannel!.initialMessageId != null) { final messages = streamChannel!.channel.state!.messages; final totalMessages = messages.length; - final messageIndex = messages.indexWhere((e) { - return e.id == streamChannel!.initialMessageId; - }); + final messageIndex = + messages.indexWhere((e) => e.id == streamChannel!.initialMessageId); final index = totalMessages - messageIndex; if (index != 0) return index - 1; return index; @@ -272,9 +295,7 @@ class _MessageListViewState extends State { return 0; } - bool _isInitialMessage(String id) { - return streamChannel!.initialMessageId == id; - } + bool _isInitialMessage(String id) => streamChannel!.initialMessageId == id; bool get _upToDate => streamChannel!.channel.state!.isUpToDate; @@ -295,50 +316,46 @@ class _MessageListViewState extends State { final MessageListController _messageListController = MessageListController(); @override - Widget build(BuildContext context) { - return MessageListCore( - messageFilter: widget.messageFilter, - loadingBuilder: widget.loadingBuilder ?? - (context) { - return Center( - child: const CircularProgressIndicator(), - ); - }, - emptyBuilder: widget.emptyBuilder ?? - (context) { - return Center( - child: Text( - 'No chats here yet...', - style: StreamChatTheme.of(context).textTheme.footnote.copyWith( - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(.5)), - ), - ); - }, - messageListBuilder: widget.messageListBuilder ?? - (context, list) { - return _buildListView(list); - }, - messageListController: _messageListController, - parentMessage: widget.parentMessage, - showScrollToBottom: widget.showScrollToBottom, - errorWidgetBuilder: widget.errorWidgetBuilder ?? - (BuildContext context, Object error) { - return Center( - child: Text( - 'Something went wrong', - style: StreamChatTheme.of(context).textTheme.footnote.copyWith( - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(.5)), - ), - ); - }, - ); - } + Widget build(BuildContext context) => MessageListCore( + messageFilter: widget.messageFilter, + loadingBuilder: widget.loadingBuilder ?? + (context) => const Center( + child: CircularProgressIndicator(), + ), + emptyBuilder: widget.emptyBuilder ?? + (context) => Center( + child: Text( + 'No chats here yet...', + style: StreamChatTheme.of(context) + .textTheme + .footnote + .copyWith( + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5)), + ), + ), + messageListBuilder: widget.messageListBuilder ?? + (context, list) => _buildListView(list), + messageListController: _messageListController, + parentMessage: widget.parentMessage, + showScrollToBottom: widget.showScrollToBottom, + errorWidgetBuilder: widget.errorWidgetBuilder ?? + (BuildContext context, Object error) => Center( + child: Text( + 'Something went wrong', + style: StreamChatTheme.of(context) + .textTheme + .footnote + .copyWith( + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5)), + ), + ), + ); Widget _buildListView(List data) { messages = data; @@ -384,6 +401,7 @@ class _MessageListViewState extends State { } return InfoTile( + // ignore: avoid_bool_literals_in_conditional_expressions showMessage: widget.showConnectionStateTile ? showStatus : false, tileAnchor: Alignment.topCenter, childAnchor: Alignment.topCenter, @@ -426,8 +444,8 @@ class _MessageListViewState extends State { itemCount: messages.length + 2 + (_isThreadConversation ? 1 : 0), separatorBuilder: (context, i) { - if (i == messages.length) return Offstage(); - if (i == 0) return SizedBox(height: 30); + if (i == messages.length) return const Offstage(); + if (i == 0) return const SizedBox(height: 30); if (i == messages.length + 1) { final replyCount = widget.parentMessage!.replyCount; return Container( @@ -438,6 +456,7 @@ class _MessageListViewState extends State { child: Padding( padding: const EdgeInsets.all(8), child: Text( + // ignore: lines_longer_than_80_chars '$replyCount ${replyCount == 1 ? 'Reply' : 'Replies'}', textAlign: TextAlign.center, style: StreamChatTheme.of(context) @@ -481,9 +500,9 @@ class _MessageListViewState extends State { !isNextUserSame || isThread || isDeleted) { - return SizedBox(height: 8); + return const SizedBox(height: 8); } - return SizedBox(height: 2); + return const SizedBox(height: 2); }, itemBuilder: (context, i) { if (i == messages.length + 2) { @@ -559,13 +578,13 @@ class _MessageListViewState extends State { builder: (context, values, _) { final items = _itemPositionListener.itemPositions.value; if (items.isEmpty || messages.isEmpty) { - return SizedBox(); + return const SizedBox(); } var index = _getTopElement(values).index; if (index > messages.length) { - return SizedBox(); + return const SizedBox(); } if (index == messages.length) { @@ -587,95 +606,90 @@ class _MessageListViewState extends State { } Future _paginateData( - StreamChannelState? channel, QueryDirection direction) { - return _messageListController.paginateData!(direction: direction); - } + StreamChannelState? channel, QueryDirection direction) => + _messageListController.paginateData!(direction: direction); - ItemPosition _getTopElement(Iterable values) { - return values - .where((ItemPosition position) => position.itemLeadingEdge < 0.9) - .reduce((ItemPosition max, ItemPosition position) => - position.itemLeadingEdge > max.itemLeadingEdge ? position : max); - } + ItemPosition _getTopElement(Iterable values) => values + .where((ItemPosition position) => position.itemLeadingEdge < 0.9) + .reduce((ItemPosition max, ItemPosition position) => + position.itemLeadingEdge > max.itemLeadingEdge ? position : max); - Widget _buildScrollToBottom() { - return StreamBuilder>( - stream: Rx.combineLatest2( - streamChannel!.channel.state!.isUpToDateStream, - streamChannel!.channel.state!.unreadCountStream, - (bool isUpToDate, int unreadCount) => Tuple2(isUpToDate, unreadCount), - ), - builder: (_, snapshot) { - if (snapshot.hasError) { - return Offstage(); - } else if (!snapshot.hasData) { - return Offstage(); - } - final isUpToDate = snapshot.data!.item1; - final showScrollToBottom = !isUpToDate || _showScrollToBottom; - if (!showScrollToBottom) { - return Offstage(); - } - final unreadCount = snapshot.data!.item2; - final showUnreadCount = unreadCount > 0 && - streamChannel!.channel.state!.members.any((e) => - e.userId == streamChannel!.channel.client.state.user!.id); - return Positioned( - bottom: 8, - right: 8, - width: 40, - height: 40, - child: Stack( - clipBehavior: Clip.none, - children: [ - FloatingActionButton( - backgroundColor: StreamChatTheme.of(context).colorTheme.white, - onPressed: () { - if (unreadCount > 0) { - streamChannel!.channel.markRead(); - } - if (!_upToDate) { - _bottomPaginationActive = false; - _topPaginationActive = false; - streamChannel!.reloadChannel(); - } else { - setState(() => _showScrollToBottom = false); - _scrollController!.scrollTo( - index: 0, - duration: Duration(seconds: 1), - curve: Curves.easeInOut, - ); - } - }, - child: StreamSvgIcon.down( - color: StreamChatTheme.of(context).colorTheme.black, + Widget _buildScrollToBottom() => StreamBuilder>( + stream: Rx.combineLatest2( + streamChannel!.channel.state!.isUpToDateStream, + streamChannel!.channel.state!.unreadCountStream, + (bool isUpToDate, int unreadCount) => Tuple2(isUpToDate, unreadCount), + ), + builder: (_, snapshot) { + if (snapshot.hasError) { + return const Offstage(); + } else if (!snapshot.hasData) { + return const Offstage(); + } + final isUpToDate = snapshot.data!.item1; + final showScrollToBottom = !isUpToDate || _showScrollToBottom; + if (!showScrollToBottom) { + return const Offstage(); + } + final unreadCount = snapshot.data!.item2; + final showUnreadCount = unreadCount > 0 && + streamChannel!.channel.state!.members.any((e) => + e.userId == streamChannel!.channel.client.state.user!.id); + return Positioned( + bottom: 8, + right: 8, + width: 40, + height: 40, + child: Stack( + clipBehavior: Clip.none, + children: [ + FloatingActionButton( + backgroundColor: StreamChatTheme.of(context).colorTheme.white, + onPressed: () { + if (unreadCount > 0) { + streamChannel!.channel.markRead(); + } + if (!_upToDate) { + _bottomPaginationActive = false; + _topPaginationActive = false; + streamChannel!.reloadChannel(); + } else { + setState(() => _showScrollToBottom = false); + _scrollController!.scrollTo( + index: 0, + duration: const Duration(seconds: 1), + curve: Curves.easeInOut, + ); + } + }, + child: StreamSvgIcon.down( + color: StreamChatTheme.of(context).colorTheme.black, + ), ), - ), - if (showUnreadCount) - Positioned( - width: 20, - height: 20, - left: 10, - top: -10, - child: CircleAvatar( - child: Padding( - padding: const EdgeInsets.all(3), - child: Text( - '$unreadCount', - style: TextStyle( - fontSize: 11, - fontWeight: FontWeight.bold, + if (showUnreadCount) + Positioned( + width: 20, + height: 20, + left: 10, + top: -10, + child: CircleAvatar( + child: Padding( + padding: const EdgeInsets.all(3), + child: Text( + '$unreadCount', + style: const TextStyle( + fontSize: 11, + fontWeight: FontWeight.bold, + ), ), ), ), ), - ), - ], - ), - ); - }, - ); - } + ], + ), + ); + }, + ); Widget _buildLoadingIndicator( StreamChannelState? streamChannel, @@ -685,7 +699,7 @@ class _MessageListViewState extends State { ? streamChannel!.queryTopMessages : streamChannel!.queryBottomMessages; return StreamBuilder( - key: Key('LOADING-INDICATOR'), + key: const Key('LOADING-INDICATOR'), stream: stream, initialData: false, builder: (context, snapshot) { @@ -695,24 +709,24 @@ class _MessageListViewState extends State { .colorTheme .accentRed .withOpacity(.2), - child: Center( + child: const Center( child: Text('Error loading messages'), ), ); } if (!snapshot.data!) { if (!_isThreadConversation && direction == QueryDirection.top) { - return Container( + return const SizedBox( height: 52, width: double.infinity, ); } - return Offstage(); + return const Offstage(); } - return Center( + return const Center( child: Padding( - padding: const EdgeInsets.all(8), - child: const CircularProgressIndicator(), + padding: EdgeInsets.all(8), + child: CircularProgressIndicator(), ), ); }, @@ -728,7 +742,7 @@ class _MessageListViewState extends State { Widget messageWidget; if (widget.messageBuilder != null) { messageWidget = Builder( - key: ValueKey('TOP-MESSAGE'), + key: const ValueKey('TOP-MESSAGE'), builder: (_) => widget.messageBuilder!( context, MessageDetails( @@ -810,7 +824,7 @@ class _MessageListViewState extends State { padding: const EdgeInsets.all(8), showSendingIndicator: false, onThreadTap: _onThreadTap as void Function(Message)?, - borderRadiusGeometry: BorderRadius.only( + borderRadiusGeometry: const BorderRadius.only( topLeft: Radius.circular(16), bottomLeft: Radius.circular(2), topRight: Radius.circular(16), @@ -886,8 +900,8 @@ class _MessageListViewState extends State { final channel = streamChannel!.channel; final readList = channel.state?.read?.where((read) { if (read.user.id == userId) return false; - return (read.lastRead.isAfter(message.createdAt) || - read.lastRead.isAtSameMomentAs(message.createdAt)); + return read.lastRead.isAfter(message.createdAt) || + read.lastRead.isAtSameMomentAs(message.createdAt); }).toList() ?? []; @@ -945,6 +959,7 @@ class _MessageListViewState extends State { showSendingIndicator: showSendingIndicator, showUserAvatar: showUserAvatar, onQuotedMessageTap: (quotedMessageId) async { + // ignore: prefer_function_declarations_over_variables final scrollToIndex = () { final index = messages.indexWhere((m) => m.id == quotedMessageId); _scrollController?.scrollTo( @@ -984,14 +999,14 @@ class _MessageListViewState extends State { ), attachmentPadding: EdgeInsets.all(hasFileAttachment ? 4 : 2), borderRadiusGeometry: BorderRadius.only( - topLeft: Radius.circular(16), + topLeft: const Radius.circular(16), bottomLeft: Radius.circular( (timeDiff >= 1 || !isNextUserSame) && !(hasReplies || isThreadMessage) ? 0 : 16, ), - topRight: Radius.circular(16), - bottomRight: Radius.circular(16), + topRight: const Radius.circular(16), + bottomRight: const Radius.circular(16), ), textPadding: EdgeInsets.symmetric( vertical: 8, @@ -1031,7 +1046,7 @@ class _MessageListViewState extends State { !message.isEphemeral && widget.onMessageSwiped != null) { child = Container( - decoration: BoxDecoration(), + decoration: const BoxDecoration(), clipBehavior: Clip.hardEdge, child: Swipeable( onSwipeEnd: () { @@ -1059,12 +1074,10 @@ class _MessageListViewState extends State { ), duration: const Duration(seconds: 3), onEnd: () => initialMessageHighlightComplete = true, - builder: (_, color, child) { - return Container( - color: color, - child: child, - ); - }, + builder: (_, color, child) => Container( + color: color, + child: child, + ), child: Padding( padding: const EdgeInsets.only(top: 4), child: child, @@ -1124,19 +1137,18 @@ class _MessageListViewState extends State { _onThreadTap = (Message message) { Navigator.push( context, - MaterialPageRoute(builder: (_) { - return StreamBuilder( - stream: streamChannel!.channel.state!.messagesStream.map( - (messages) => - messages!.firstWhere((m) => m.id == message.id)), - initialData: message, - builder: (_, snapshot) { - return StreamChannel( - channel: streamChannel!.channel, - child: widget.threadBuilder!(context, snapshot.data), - ); - }); - }), + MaterialPageRoute( + builder: (_) => StreamBuilder( + stream: streamChannel!.channel.state!.messagesStream.map( + (messages) => + messages!.firstWhere((m) => m.id == message.id)), + initialData: message, + builder: (_, snapshot) => StreamChannel( + channel: streamChannel!.channel, + child: widget.threadBuilder!(context, snapshot.data), + ), + ), + ), ); }; } From 3812eadf53a634200b75d41deeaa58639560bb56 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 5 May 2021 15:58:20 +0530 Subject: [PATCH 10/31] lint changes mrm --- .../lib/src/message_reactions_modal.dart | 54 ++++++++++++------- 1 file changed, 35 insertions(+), 19 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/message_reactions_modal.dart b/packages/stream_chat_flutter/lib/src/message_reactions_modal.dart index 937cf681..e2392b50 100644 --- a/packages/stream_chat_flutter/lib/src/message_reactions_modal.dart +++ b/packages/stream_chat_flutter/lib/src/message_reactions_modal.dart @@ -7,22 +7,11 @@ import 'package:stream_chat_flutter/src/stream_chat.dart'; import 'package:stream_chat_flutter/src/user_avatar.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/src/extension.dart'; -import 'extension.dart'; -import 'message_widget.dart'; -import 'stream_chat_theme.dart'; - +/// Modal widget for displaying message reactions class MessageReactionsModal extends StatelessWidget { - final Message message; - final MessageTheme messageTheme; - final bool reverse; - final bool showReactions; - final DisplayWidget showUserAvatar; - final ShapeBorder? messageShape; - final ShapeBorder? attachmentShape; - final void Function(User)? onUserAvatarTap; - final BorderRadius? attachmentBorderRadiusGeometry; - + /// Constructor for creating a [MessageReactionsModal] reactions const MessageReactionsModal({ Key? key, required this.message, @@ -36,6 +25,33 @@ class MessageReactionsModal extends StatelessWidget { this.attachmentBorderRadiusGeometry, }) : super(key: key); + /// Message to display reactions of + final Message message; + + /// [MessageTheme] to apply to [message] + final MessageTheme messageTheme; + + /// Flag to reverse message + final bool reverse; + + /// Flag to show reactions on message + final bool showReactions; + + /// Enum to change user avatar config + final DisplayWidget showUserAvatar; + + /// [ShapeBorder] to apply to message + final ShapeBorder? messageShape; + + /// [ShapeBorder] to apply to attachment + final ShapeBorder? attachmentShape; + + /// Callback when user avatar is tapped + final void Function(User)? onUserAvatarTap; + + /// [BorderRadius] to apply to attachments + final BorderRadius? attachmentBorderRadiusGeometry; + @override Widget build(BuildContext context) { final size = MediaQuery.of(context).size; @@ -60,7 +76,7 @@ class MessageReactionsModal extends StatelessWidget { return TweenAnimationBuilder( tween: Tween(begin: 0, end: 1), - duration: Duration(milliseconds: 300), + duration: const Duration(milliseconds: 300), curve: Curves.easeInOutBack, builder: (context, val, snapshot) { final hasFileAttachment = @@ -110,7 +126,7 @@ class MessageReactionsModal extends StatelessWidget { const SizedBox(height: 8), IgnorePointer( child: MessageWidget( - key: Key('MessageWidget'), + key: const Key('MessageWidget'), reverse: reverse, message: message.copyWith( text: message.text!.length > 200 @@ -205,7 +221,7 @@ class MessageReactionsModal extends StatelessWidget { ) { final isCurrentUser = reaction.user?.id == currentUser.id; return ConstrainedBox( - constraints: BoxConstraints.loose(Size( + constraints: BoxConstraints.loose(const Size( 64, 98, )), @@ -218,11 +234,11 @@ class MessageReactionsModal extends StatelessWidget { UserAvatar( onTap: onUserAvatarTap, user: reaction.user!, - constraints: BoxConstraints.tightFor( + constraints: const BoxConstraints.tightFor( height: 64, width: 64, ), - onlineIndicatorConstraints: BoxConstraints.tightFor( + onlineIndicatorConstraints: const BoxConstraints.tightFor( height: 12, width: 12, ), From 3976ac7f4f3e23dc65ae27537faf5c0b184a453f Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 5 May 2021 16:03:00 +0530 Subject: [PATCH 11/31] lint changes message --- .../lib/src/message_search_item.dart | 12 +- .../lib/src/message_search_list_view.dart | 142 +++++++++--------- .../lib/src/message_text.dart | 14 +- 3 files changed, 88 insertions(+), 80 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/message_search_item.dart b/packages/stream_chat_flutter/lib/src/message_search_item.dart index 7be8893b..dc276cb3 100644 --- a/packages/stream_chat_flutter/lib/src/message_search_item.dart +++ b/packages/stream_chat_flutter/lib/src/message_search_item.dart @@ -5,9 +5,11 @@ import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; /// It shows the current [Message] preview. /// -/// Usually you don't use this widget as it's the default item used by [MessageSearchListView]. +/// Usually you don't use this widget as it's the default item used by +/// [MessageSearchListView]. /// -/// The widget renders the ui based on the first ancestor of type [StreamChatTheme]. +/// The widget renders the ui based on the first ancestor of type +/// [StreamChatTheme]. /// Modify it to change the widget appearance. class MessageSearchItem extends StatelessWidget { /// Instantiate a new MessageSearchItem @@ -38,7 +40,7 @@ class MessageSearchItem extends StatelessWidget { leading: UserAvatar( user: user, showOnlineStatus: showOnlineStatus, - constraints: BoxConstraints.tightFor( + constraints: const BoxConstraints.tightFor( height: 40, width: 40, ), @@ -69,7 +71,7 @@ class MessageSearchItem extends StatelessWidget { subtitle: Row( children: [ Expanded(child: _buildSubtitle(context, message)), - SizedBox(width: 16), + const SizedBox(width: 16), _buildDate(context, message), ], ), @@ -149,7 +151,7 @@ class MessageSearchItem extends StatelessWidget { TextStyle? mentionsTextStyle) { final textList = text.split(' '); final resList = []; - for (var e in textList) { + for (final e in textList) { if (mentions.isNotEmpty && mentions.any((element) => '@${element.name}' == e)) { resList.add(TextSpan( diff --git a/packages/stream_chat_flutter/lib/src/message_search_list_view.dart b/packages/stream_chat_flutter/lib/src/message_search_list_view.dart index b88af62e..1d9ef272 100644 --- a/packages/stream_chat_flutter/lib/src/message_search_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/message_search_list_view.dart @@ -2,8 +2,7 @@ import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/src/info_tile.dart'; import 'package:stream_chat_flutter/src/message_search_item.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; - -import '../stream_chat_flutter.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; /// Callback called when tapping on a user typedef MessageSearchItemTapCallback = void Function(GetMessageResponse); @@ -43,10 +42,12 @@ typedef EmptyMessageSearchBuilder = Widget Function( /// ``` /// /// -/// Make sure to have a [MessageSearchBloc] ancestor in order to provide the information about the messages. +/// Make sure to have a [MessageSearchBloc] ancestor in order to provide the +/// information about the messages. /// The widget uses a [ListView.separated] to render the list of messages. /// -/// The widget components render the ui based on the first ancestor of type [StreamChatTheme]. +/// The widget components render the ui based on the first ancestor of type +/// [StreamChatTheme]. /// Modify it to change the widget appearance. class MessageSearchListView extends StatefulWidget { /// Instantiate a new MessageSearchListView @@ -78,8 +79,10 @@ class MessageSearchListView extends StatefulWidget { final Filter filters; /// The sorting used for the channels matching the filters. - /// Sorting is based on field and direction, multiple sorting options can be provided. - /// You can sort based on last_updated, last_message_at, updated_at, created_at or member_count. + /// Sorting is based on field and direction, multiple sorting options + /// can be provided. + /// You can sort based on last_updated, last_message_at, updated_at, + /// created_at or member_count. /// Direction can be ascending or descending. final List? sortOptions; @@ -109,6 +112,7 @@ class MessageSearchListView extends StatefulWidget { /// Set it to false to disable the pull-to-refresh widget final bool pullToRefresh; + /// Show error tile on top final bool showErrorTile; /// The builder that is used when the search messages are fetched @@ -132,73 +136,63 @@ class _MessageSearchListViewState extends State { MessageSearchListController(); @override - Widget build(BuildContext context) { - return MessageSearchListCore( - filters: widget.filters, - sortOptions: widget.sortOptions, - messageQuery: widget.messageQuery, - paginationParams: widget.paginationParams, - messageFilters: widget.messageFilters, - messageSearchListController: _messageSearchListController, - emptyBuilder: widget.emptyBuilder ?? - (context) { - return LayoutBuilder( - builder: (context, viewportConstraints) { - return SingleChildScrollView( - physics: AlwaysScrollableScrollPhysics(), - child: ConstrainedBox( - constraints: BoxConstraints( - minHeight: viewportConstraints.maxHeight, - ), - child: Center( - child: Text('There are no messages currently'), + Widget build(BuildContext context) => MessageSearchListCore( + filters: widget.filters, + sortOptions: widget.sortOptions, + messageQuery: widget.messageQuery, + paginationParams: widget.paginationParams, + messageFilters: widget.messageFilters, + messageSearchListController: _messageSearchListController, + emptyBuilder: widget.emptyBuilder ?? + (context) => LayoutBuilder( + builder: (context, viewportConstraints) => + SingleChildScrollView( + physics: const AlwaysScrollableScrollPhysics(), + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: viewportConstraints.maxHeight, + ), + child: const Center( + child: Text('There are no messages currently'), + ), ), ), - ); - }, - ); - }, - errorBuilder: widget.errorBuilder ?? - (BuildContext context, dynamic error) { - if (error is Error) { - print(error.stackTrace); - } - return InfoTile( - showMessage: widget.showErrorTile, - tileAnchor: Alignment.topCenter, - childAnchor: Alignment.topCenter, - message: 'An error occurred.', - child: Container(), - ); - }, - loadingBuilder: widget.loadingBuilder ?? - (context) { - return LayoutBuilder( - builder: (context, viewportConstraints) { - return SingleChildScrollView( - physics: AlwaysScrollableScrollPhysics(), - child: ConstrainedBox( - constraints: BoxConstraints( - minHeight: viewportConstraints.maxHeight, - ), - child: Center( - child: CircularProgressIndicator(), + ), + errorBuilder: widget.errorBuilder ?? + (BuildContext context, dynamic error) { + if (error is Error) { + print(error.stackTrace); + } + return InfoTile( + showMessage: widget.showErrorTile, + tileAnchor: Alignment.topCenter, + childAnchor: Alignment.topCenter, + message: 'An error occurred.', + child: Container(), + ); + }, + loadingBuilder: widget.loadingBuilder ?? + (context) => LayoutBuilder( + builder: (context, viewportConstraints) => + SingleChildScrollView( + physics: const AlwaysScrollableScrollPhysics(), + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: viewportConstraints.maxHeight, + ), + child: const Center( + child: CircularProgressIndicator(), + ), ), ), - ); - }, - ); - }, - childBuilder: widget.childBuilder ?? _buildListView, - ); - } + ), + childBuilder: widget.childBuilder ?? _buildListView, + ); - Widget _separatorBuilder(BuildContext context, int index) { - return Container( - height: 1, - color: StreamChatTheme.of(context).colorTheme.greyWhisper, - ); - } + Widget _separatorBuilder(BuildContext context, int index) => Container( + height: 1, + color: StreamChatTheme.of(context).colorTheme.greyWhisper, + ); Widget _listItemBuilder( BuildContext context, GetMessageResponse getMessageResponse) { @@ -224,8 +218,8 @@ class _MessageSearchListViewState extends State { .colorTheme .accentRed .withOpacity(.2), - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 16), + child: const Padding( + padding: EdgeInsets.symmetric(vertical: 16), child: Center( child: Text('Error loading messages'), ), @@ -234,9 +228,11 @@ class _MessageSearchListViewState extends State { } return Container( height: 100, - padding: EdgeInsets.all(32), + padding: const EdgeInsets.all(32), child: Center( - child: snapshot.data! ? CircularProgressIndicator() : Container(), + child: snapshot.data! + ? const CircularProgressIndicator() + : Container(), ), ); }); @@ -246,7 +242,7 @@ class _MessageSearchListViewState extends State { final items = data; Widget child = ListView.separated( - physics: AlwaysScrollableScrollPhysics(), + physics: const AlwaysScrollableScrollPhysics(), itemCount: items.isNotEmpty ? items.length + 1 : items.length, separatorBuilder: (_, index) { if (widget.separatorBuilder != null) { diff --git a/packages/stream_chat_flutter/lib/src/message_text.dart b/packages/stream_chat_flutter/lib/src/message_text.dart index b0099eff..8c95120d 100644 --- a/packages/stream_chat_flutter/lib/src/message_text.dart +++ b/packages/stream_chat_flutter/lib/src/message_text.dart @@ -2,11 +2,13 @@ import 'package:collection/collection.dart' show IterableExtension; import 'package:flutter/material.dart'; import 'package:flutter_markdown/flutter_markdown.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; -import 'stream_chat_theme.dart'; -import 'utils.dart'; +import '../stream_chat_flutter.dart'; +/// Text widget to display in message class MessageText extends StatelessWidget { + /// Constructor for creating a [MessageText] widget const MessageText({ Key? key, required this.message, @@ -15,9 +17,16 @@ class MessageText extends StatelessWidget { this.onLinkTap, }) : super(key: key); + /// Message whose text is to be displayed final Message message; + + /// Callback for when mention is tapped final void Function(User)? onMentionTap; + + /// Callback for when link is tapped final void Function(String)? onLinkTap; + + /// [MessageTheme] whose text theme is to be applied final MessageTheme messageTheme; @override @@ -71,6 +80,7 @@ class MessageText extends StatelessWidget { String _replaceMentions(String text) { message.mentionedUsers.map((u) => u.name).toSet().forEach((userName) { + // ignore: parameter_assignments text = text.replaceAll( '@$userName', '[@$userName](@${userName.replaceAll(' ', '')})'); }); From a55af6befb6ca86dafd216801201a300a4864c5d Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 5 May 2021 16:12:36 +0530 Subject: [PATCH 12/31] lint changes message --- .../lib/src/message_widget.dart | 546 +++++++++--------- 1 file changed, 288 insertions(+), 258 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/message_widget.dart b/packages/stream_chat_flutter/lib/src/message_widget.dart index 32801cd1..1866da0b 100644 --- a/packages/stream_chat_flutter/lib/src/message_widget.dart +++ b/packages/stream_chat_flutter/lib/src/message_widget.dart @@ -15,17 +15,17 @@ import 'package:stream_chat_flutter/src/quoted_message_widget.dart'; import 'package:stream_chat_flutter/src/reaction_bubble.dart'; import 'package:stream_chat_flutter/src/url_attachment.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; +import 'package:stream_chat_flutter/src/image_group.dart'; +import 'package:stream_chat_flutter/src/extension.dart'; -import 'attachment/attachment.dart'; -import 'extension.dart'; -import 'image_group.dart'; -import 'message_text.dart'; - +/// Widget builder for building attachments typedef AttachmentBuilder = Widget Function( BuildContext, Message, List, ); + +/// Callback for when quoted message is tapped typedef OnQuotedMessageTap = void Function(String?); /// The display behaviour of a widget @@ -45,119 +45,13 @@ enum DisplayWidget { /// /// It shows a message with reactions, replies and user avatar. /// -/// Usually you don't use this widget as it's the default message widget used by [MessageListView]. +/// Usually you don't use this widget as it's the default message widget used by +/// [MessageListView]. /// -/// The widget components render the ui based on the first ancestor of type [StreamChatTheme]. +/// The widget components render the ui based on the first ancestor of type +/// [StreamChatTheme]. /// Modify it to change the widget appearance. class MessageWidget extends StatefulWidget { - /// Function called on mention tap - final void Function(User)? onMentionTap; - - /// The function called when tapping on replies - final void Function(Message)? onThreadTap; - final void Function(Message)? onReplyTap; - final Widget Function(BuildContext, Message)? editMessageInputBuilder; - final Widget Function(BuildContext, Message)? textBuilder; - - /// Function called on long press - final void Function(BuildContext, Message)? onMessageActions; - - /// The message - final Message message; - - /// The message theme - final MessageTheme messageTheme; - - /// If true the widget will be mirrored - final bool reverse; - - /// The shape of the message text - final ShapeBorder? shape; - - /// The shape of an attachment - final ShapeBorder? attachmentShape; - - /// The borderside of the message text - final BorderSide? borderSide; - - /// The borderside of an attachment - final BorderSide? attachmentBorderSide; - - /// The border radius of the message text - final BorderRadiusGeometry? borderRadiusGeometry; - - /// The border radius of an attachment - final BorderRadiusGeometry? attachmentBorderRadiusGeometry; - - /// The padding of the widget - final EdgeInsetsGeometry? padding; - - /// The internal padding of the message text - final EdgeInsets textPadding; - - /// The internal padding of an attachment - final EdgeInsetsGeometry attachmentPadding; - - /// It controls the display behaviour of the user avatar - final DisplayWidget showUserAvatar; - - /// It controls the display behaviour of the sending indicator - final bool showSendingIndicator; - - /// If true the widget will show the reactions - final bool showReactions; - - final bool allRead; - - /// If true the widget will show the thread reply indicator - final bool showThreadReplyIndicator; - - /// If true the widget will show the show in channel indicator - final bool showInChannelIndicator; - - /// The function called when tapping on UserAvatar - final void Function(User)? onUserAvatarTap; - - /// The function called when tapping on a link - final void Function(String)? onLinkTap; - - /// Used in [MessageReactionsModal] and [MessageActionsModal] - final bool showReactionPickerIndicator; - - final List? readList; - - final ShowMessageCallback? onShowMessage; - final ValueChanged? onReturnAction; - - /// If true show the users username next to the timestamp of the message - final bool showUsername; - final bool showTimestamp; - - final bool showReplyMessage; - final bool showThreadReplyMessage; - final bool showEditMessage; - final bool showCopyMessage; - final bool showDeleteMessage; - final bool showResendMessage; - - final bool showFlagButton; - final Map attachmentBuilders; - - /// Center user avatar with bottom of the message - final bool translateUserAvatar; - - /// Function called when quotedMessage is tapped - final OnQuotedMessageTap? onQuotedMessageTap; - - /// Function called when message is tapped - final void Function(Message)? onMessageTap; - - /// List of custom actions shown on message long tap - final List customActions; - - // Customize onTap on attachment - final void Function(Message message, Attachment attachment)? onAttachmentTap; - /// MessageWidget({ Key? key, @@ -273,24 +167,24 @@ class MessageWidget extends StatefulWidget { return wrapAttachmentWidget( context, Column( - children: attachments.map((attachment) { - return VideoAttachment( - attachment: attachment, - messageTheme: messageTheme, - size: Size( - MediaQuery.of(context).size.width * 0.8, - MediaQuery.of(context).size.height * 0.3, - ), - message: message, - onShowMessage: onShowMessage, - onReturnAction: onReturnAction, - onAttachmentTap: onAttachmentTap != null - ? () { - onAttachmentTap(message, attachment); - } - : null, - ); - }).toList(), + children: attachments + .map((attachment) => VideoAttachment( + attachment: attachment, + messageTheme: messageTheme, + size: Size( + MediaQuery.of(context).size.width * 0.8, + MediaQuery.of(context).size.height * 0.3, + ), + message: message, + onShowMessage: onShowMessage, + onReturnAction: onReturnAction, + onAttachmentTap: onAttachmentTap != null + ? () { + onAttachmentTap(message, attachment); + } + : null, + )) + .toList(), ), border, reverse, @@ -306,18 +200,18 @@ class MessageWidget extends StatefulWidget { return wrapAttachmentWidget( context, Column( - children: attachments.map((attachment) { - return GiphyAttachment( - attachment: attachment, - message: message, - size: Size( - MediaQuery.of(context).size.width * 0.8, - MediaQuery.of(context).size.height * 0.3, - ), - onShowMessage: onShowMessage, - onReturnAction: onReturnAction, - ); - }).toList(), + children: attachments + .map((attachment) => GiphyAttachment( + attachment: attachment, + message: message, + size: Size( + MediaQuery.of(context).size.width * 0.8, + MediaQuery.of(context).size.height * 0.3, + ), + onShowMessage: onShowMessage, + onReturnAction: onReturnAction, + )) + .toList(), ), border, reverse, @@ -336,23 +230,21 @@ class MessageWidget extends StatefulWidget { return Column( children: attachments - .map((attachment) { - return wrapAttachmentWidget( - context, - FileAttachment( - message: message, - attachment: attachment, - size: Size( - MediaQuery.of(context).size.width * 0.8, - MediaQuery.of(context).size.height * 0.3, + .map((attachment) => wrapAttachmentWidget( + context, + FileAttachment( + message: message, + attachment: attachment, + size: Size( + MediaQuery.of(context).size.width * 0.8, + MediaQuery.of(context).size.height * 0.3, + ), ), - ), - border, - reverse, - attachmentBorderRadiusGeometry as BorderRadius? ?? - BorderRadius.zero, - ); - }) + border, + reverse, + attachmentBorderRadiusGeometry as BorderRadius? ?? + BorderRadius.zero, + )) .insertBetween(SizedBox( height: attachmentPadding.vertical / 2, )) @@ -362,6 +254,141 @@ class MessageWidget extends StatefulWidget { }..addAll(customAttachmentBuilders ?? {}), super(key: key); + /// Function called on mention tap + final void Function(User)? onMentionTap; + + /// The function called when tapping on threads + final void Function(Message)? onThreadTap; + + /// The function called when tapping on replies + final void Function(Message)? onReplyTap; + + /// Widget builder for edit message layout + final Widget Function(BuildContext, Message)? editMessageInputBuilder; + + /// Widget builder for building text + final Widget Function(BuildContext, Message)? textBuilder; + + /// Function called on long press + final void Function(BuildContext, Message)? onMessageActions; + + /// The message + final Message message; + + /// The message theme + final MessageTheme messageTheme; + + /// If true the widget will be mirrored + final bool reverse; + + /// The shape of the message text + final ShapeBorder? shape; + + /// The shape of an attachment + final ShapeBorder? attachmentShape; + + /// The borderside of the message text + final BorderSide? borderSide; + + /// The borderside of an attachment + final BorderSide? attachmentBorderSide; + + /// The border radius of the message text + final BorderRadiusGeometry? borderRadiusGeometry; + + /// The border radius of an attachment + final BorderRadiusGeometry? attachmentBorderRadiusGeometry; + + /// The padding of the widget + final EdgeInsetsGeometry? padding; + + /// The internal padding of the message text + final EdgeInsets textPadding; + + /// The internal padding of an attachment + final EdgeInsetsGeometry attachmentPadding; + + /// It controls the display behaviour of the user avatar + final DisplayWidget showUserAvatar; + + /// It controls the display behaviour of the sending indicator + final bool showSendingIndicator; + + /// If true the widget will show the reactions + final bool showReactions; + + /// + final bool allRead; + + /// If true the widget will show the thread reply indicator + final bool showThreadReplyIndicator; + + /// If true the widget will show the show in channel indicator + final bool showInChannelIndicator; + + /// The function called when tapping on UserAvatar + final void Function(User)? onUserAvatarTap; + + /// The function called when tapping on a link + final void Function(String)? onLinkTap; + + /// Used in [MessageReactionsModal] and [MessageActionsModal] + final bool showReactionPickerIndicator; + + /// List of users who read + final List? readList; + + /// Callback when show message is tapped + final ShowMessageCallback? onShowMessage; + + /// Handle return actions like reply message + final ValueChanged? onReturnAction; + + /// If true show the users username next to the timestamp of the message + final bool showUsername; + + /// Show message timestamp + final bool showTimestamp; + + /// Show reply action + final bool showReplyMessage; + + /// Show thread reply action + final bool showThreadReplyMessage; + + /// Show edit action + final bool showEditMessage; + + /// Show copy action + final bool showCopyMessage; + + /// Show delete action + final bool showDeleteMessage; + + /// Show resend action + final bool showResendMessage; + + /// Show flag action + final bool showFlagButton; + + /// Builder for respective attachment types + final Map attachmentBuilders; + + /// Center user avatar with bottom of the message + final bool translateUserAvatar; + + /// Function called when quotedMessage is tapped + final OnQuotedMessageTap? onQuotedMessageTap; + + /// Function called when message is tapped + final void Function(Message)? onMessageTap; + + /// List of custom actions shown on message long tap + final List customActions; + + /// Customize onTap on attachment + final void Function(Message message, Attachment attachment)? onAttachmentTap; + @override _MessageWidgetState createState() => _MessageWidgetState(); } @@ -437,7 +464,7 @@ class _MessageWidgetState extends State ? null : () => onLongPress(context), child: Padding( - padding: widget.padding ?? EdgeInsets.all(8), + padding: widget.padding ?? const EdgeInsets.all(8), child: Transform( alignment: Alignment.center, transform: Matrix4.rotationY(widget.reverse ? pi : 0), @@ -464,7 +491,7 @@ class _MessageWidgetState extends State DisplayWidget.show && widget.message.user != null) ...[ _buildUserAvatar(), - SizedBox(width: 4), + const SizedBox(width: 4), ], if (widget.showUserAvatar == DisplayWidget.hide) SizedBox(width: avatarWidth + 4), @@ -473,12 +500,12 @@ class _MessageWidgetState extends State portal: Container( transform: Matrix4.translationValues(-12, 0, 0), - constraints: - BoxConstraints(maxWidth: 22 * 6.0), + constraints: const BoxConstraints( + maxWidth: 22 * 6.0), child: _buildReactionIndicator(context), ), - portalAnchor: Alignment(-1, -1), - childAnchor: Alignment(1, -1), + portalAnchor: const Alignment(-1, -1), + childAnchor: const Alignment(1, -1), child: Stack( clipBehavior: Clip.none, children: [ @@ -501,15 +528,18 @@ class _MessageWidgetState extends State transform: Matrix4.rotationY( widget.reverse ? pi : 0), child: Container( + // ignore: lines_longer_than_80_chars margin: EdgeInsets.symmetric( horizontal: + // ignore: lines_longer_than_80_chars widget.showUserAvatar == - DisplayWidget - .gone + // ignore: lines_longer_than_80_chars + DisplayWidget.gone ? 0 : 4.0), child: DeletedMessage( reverse: widget.reverse, + // ignore: lines_longer_than_80_chars borderRadiusGeometry: widget .borderRadiusGeometry, borderSide: @@ -527,6 +557,7 @@ class _MessageWidgetState extends State horizontal: (isFailedState ? 15.0 : 0.0) + + // ignore: lines_longer_than_80_chars (widget.showUserAvatar == DisplayWidget .gone @@ -539,11 +570,14 @@ class _MessageWidgetState extends State .borderSide ?? BorderSide( color: widget + // ignore: lines_longer_than_80_chars .messageTheme + // ignore: lines_longer_than_80_chars .messageBorderColor ?? Colors.grey, ), borderRadius: widget + // ignore: lines_longer_than_80_chars .borderRadiusGeometry ?? BorderRadius.zero, ), @@ -648,7 +682,7 @@ class _MessageWidgetState extends State color: StreamChatTheme.of(context).colorTheme.grey, size: 16, ), - SizedBox(width: 8), + const SizedBox(width: 8), Text( 'Only visible to you', style: StreamChatTheme.of(context) @@ -672,6 +706,7 @@ class _MessageWidgetState extends State msg = '$replyCount Thread Replies'; } + // ignore: prefer_function_declarations_over_variables final onThreadTap = () async { try { var message = widget.message; @@ -683,6 +718,7 @@ class _MessageWidgetState extends State } catch (e, stk) { print(e); print(stk); + // ignore: avoid_returning_null_for_void return null; } }; @@ -730,7 +766,7 @@ class _MessageWidgetState extends State ((widget.messageTheme.replies?.fontSize ?? 1) / 2), ), child: CustomPaint( - size: Size(16, 32) * context.textScaleFactor, + size: const Size(16, 32) * context.textScaleFactor, painter: _ThreadReplyPainter( context: context, color: widget.messageTheme.messageBorderColor, @@ -742,7 +778,7 @@ class _MessageWidgetState extends State Widget mappedChild = Transform( transform: Matrix4.rotationY(widget.reverse ? pi : 0), alignment: Alignment.center, - child: Container( + child: SizedBox( height: context.textScaleFactor * 14, child: child, ), @@ -792,7 +828,7 @@ class _MessageWidgetState extends State padding: const EdgeInsets.all(1), child: UserAvatar( user: user, - constraints: BoxConstraints.loose(Size.fromRadius(7)), + constraints: BoxConstraints.loose(const Size.fromRadius(7)), showOnlineStatus: false, ), ), @@ -816,7 +852,7 @@ class _MessageWidgetState extends State ..sort((a, b) => a.user!.id == ownId ? 1 : -1); return AnimatedSwitcher( - duration: Duration(milliseconds: 300), + duration: const Duration(milliseconds: 300), child: (widget.showReactions && (widget.message.reactionCounts?.isNotEmpty == true) && !widget.message.isDeleted) @@ -835,7 +871,7 @@ class _MessageWidgetState extends State reactions: reactionsList, ), ) - : SizedBox(), + : const SizedBox(), ); } @@ -845,78 +881,75 @@ class _MessageWidgetState extends State showDialog( context: context, barrierColor: StreamChatTheme.of(context).colorTheme.overlay, - builder: (context) { - return StreamChannel( - channel: channel, - child: MessageActionsModal( - onCopyTap: (message) => - Clipboard.setData(ClipboardData(text: message.text)), - attachmentBorderRadiusGeometry: - widget.attachmentBorderRadiusGeometry as BorderRadius?, - showUserAvatar: - widget.message.user!.id == channel.client.state.user!.id - ? DisplayWidget.gone - : DisplayWidget.show, - messageTheme: widget.messageTheme, - messageShape: widget.shape ?? _getDefaultShape(context), - attachmentShape: - widget.attachmentShape ?? _getDefaultAttachmentShape(context), - reverse: widget.reverse, - showDeleteMessage: widget.showDeleteMessage || isDeleteFailed, - message: widget.message, - editMessageInputBuilder: widget.editMessageInputBuilder, - onReplyTap: widget.onReplyTap, - onThreadReplyTap: widget.onThreadTap, - showResendMessage: - widget.showResendMessage && (isSendFailed || isUpdateFailed), - showCopyMessage: widget.showCopyMessage && - !isFailedState && - widget.message.text?.trim().isNotEmpty == true, - showEditMessage: widget.showEditMessage && - !isDeleteFailed && - widget.message.attachments - .any((element) => element.type == 'giphy') != - true, - showReactions: widget.showReactions, - showReplyMessage: widget.showReplyMessage && - !isFailedState && - widget.onReplyTap != null, - showThreadReplyMessage: widget.showThreadReplyMessage && - !isFailedState && - widget.onThreadTap != null, - showFlagButton: widget.showFlagButton, - customActions: widget.customActions, - ), - ); - }); + builder: (context) => StreamChannel( + channel: channel, + child: MessageActionsModal( + onCopyTap: (message) => + Clipboard.setData(ClipboardData(text: message.text)), + attachmentBorderRadiusGeometry: + widget.attachmentBorderRadiusGeometry as BorderRadius?, + showUserAvatar: + widget.message.user!.id == channel.client.state.user!.id + ? DisplayWidget.gone + : DisplayWidget.show, + messageTheme: widget.messageTheme, + messageShape: widget.shape ?? _getDefaultShape(context), + attachmentShape: widget.attachmentShape ?? + _getDefaultAttachmentShape(context), + reverse: widget.reverse, + showDeleteMessage: widget.showDeleteMessage || isDeleteFailed, + message: widget.message, + editMessageInputBuilder: widget.editMessageInputBuilder, + onReplyTap: widget.onReplyTap, + onThreadReplyTap: widget.onThreadTap, + showResendMessage: widget.showResendMessage && + (isSendFailed || isUpdateFailed), + showCopyMessage: widget.showCopyMessage && + !isFailedState && + widget.message.text?.trim().isNotEmpty == true, + showEditMessage: widget.showEditMessage && + !isDeleteFailed && + widget.message.attachments + .any((element) => element.type == 'giphy') != + true, + showReactions: widget.showReactions, + showReplyMessage: widget.showReplyMessage && + !isFailedState && + widget.onReplyTap != null, + showThreadReplyMessage: widget.showThreadReplyMessage && + !isFailedState && + widget.onThreadTap != null, + showFlagButton: widget.showFlagButton, + customActions: widget.customActions, + ), + )); } void _showMessageReactionsModalBottomSheet(BuildContext context) { final channel = StreamChannel.of(context).channel; showDialog( - context: context, - barrierColor: StreamChatTheme.of(context).colorTheme.overlay, - builder: (context) { - return StreamChannel( - channel: channel, - child: MessageReactionsModal( - attachmentBorderRadiusGeometry: - widget.attachmentBorderRadiusGeometry as BorderRadius?, - showUserAvatar: - widget.message.user!.id == channel.client.state.user!.id - ? DisplayWidget.gone - : DisplayWidget.show, - onUserAvatarTap: widget.onUserAvatarTap, - messageTheme: widget.messageTheme, - messageShape: widget.shape ?? _getDefaultShape(context), - attachmentShape: - widget.attachmentShape ?? _getDefaultAttachmentShape(context), - reverse: widget.reverse, - message: widget.message, - showReactions: widget.showReactions, - ), - ); - }); + context: context, + barrierColor: StreamChatTheme.of(context).colorTheme.overlay, + builder: (context) => StreamChannel( + channel: channel, + child: MessageReactionsModal( + attachmentBorderRadiusGeometry: + widget.attachmentBorderRadiusGeometry as BorderRadius?, + showUserAvatar: + widget.message.user!.id == channel.client.state.user!.id + ? DisplayWidget.gone + : DisplayWidget.show, + onUserAvatarTap: widget.onUserAvatarTap, + messageTheme: widget.messageTheme, + messageShape: widget.shape ?? _getDefaultShape(context), + attachmentShape: + widget.attachmentShape ?? _getDefaultAttachmentShape(context), + reverse: widget.reverse, + message: widget.message, + showReactions: widget.showReactions, + ), + ), + ); } ShapeBorder _getDefaultAttachmentShape(BuildContext context) { @@ -933,15 +966,13 @@ class _MessageWidgetState extends State ); } - ShapeBorder _getDefaultShape(BuildContext context) { - return RoundedRectangleBorder( - side: widget.borderSide ?? - BorderSide( - color: StreamChatTheme.of(context).colorTheme.greyWhisper, - ), - borderRadius: widget.borderRadiusGeometry ?? BorderRadius.zero, - ); - } + ShapeBorder _getDefaultShape(BuildContext context) => RoundedRectangleBorder( + side: widget.borderSide ?? + BorderSide( + color: StreamChatTheme.of(context).colorTheme.greyWhisper, + ), + borderRadius: widget.borderRadiusGeometry ?? BorderRadius.zero, + ); Widget _parseAttachments() { final attachmentGroups = >{}; @@ -1003,9 +1034,8 @@ class _MessageWidgetState extends State (message.status == MessageSendingStatus.sending || message.status == MessageSendingStatus.updating)) { final totalAttachments = message.attachments.length; - final uploadRemaining = message.attachments.where((it) { - return !it.uploadState.isSuccess; - }).length; + final uploadRemaining = + message.attachments.where((it) => !it.uploadState.isSuccess).length; if (uploadRemaining == 0) { return StreamSvgIcon.check( size: style!.fontSize, @@ -1033,7 +1063,7 @@ class _MessageWidgetState extends State color: StreamChatTheme.of(context).colorTheme.accentBlue, ), ), - SizedBox(width: 2), + const SizedBox(width: 2), child, ], ); @@ -1064,7 +1094,7 @@ class _MessageWidgetState extends State ); Widget _buildTextBubble() { - if (widget.message.text!.trim().isEmpty) return Offstage(); + if (widget.message.text!.trim().isEmpty) return const Offstage(); return Transform( transform: Matrix4.rotationY(widget.reverse ? pi : 0), alignment: Alignment.center, @@ -1135,11 +1165,11 @@ class _MessageWidgetState extends State } class _ThreadReplyPainter extends CustomPainter { + const _ThreadReplyPainter({this.context, required this.color}); + final Color? color; final BuildContext? context; - const _ThreadReplyPainter({this.context, required this.color}); - @override void paint(Canvas canvas, Size size) { final paint = Paint() From ef837a4d7d0eb056197c27ed1de67b2ba1714407 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 5 May 2021 16:19:54 +0530 Subject: [PATCH 13/31] lint changes --- .../lib/src/option_list_tile.dart | 134 ++++++----- .../lib/src/quoted_message_widget.dart | 209 ++++++++---------- 2 files changed, 170 insertions(+), 173 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/option_list_tile.dart b/packages/stream_chat_flutter/lib/src/option_list_tile.dart index a4463389..9a11fd7a 100644 --- a/packages/stream_chat_flutter/lib/src/option_list_tile.dart +++ b/packages/stream_chat_flutter/lib/src/option_list_tile.dart @@ -1,17 +1,11 @@ import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; +/// List tile for [ChannelBottomSheet] class OptionListTile extends StatelessWidget { - final String? title; - final Widget? leading; - final Widget? trailing; - final VoidCallback? onTap; - final Color? titleColor; - final Color? tileColor; - final Color? separatorColor; - final TextStyle? titleTextStyle; - + /// Constructor for creating [OptionListTile] const OptionListTile({ + Key? key, this.title, this.leading, this.trailing, @@ -20,61 +14,83 @@ class OptionListTile extends StatelessWidget { this.tileColor, this.separatorColor, this.titleTextStyle, - }); + }) : super(key: key); + + /// Title for tile + final String? title; + + /// Leading widget (start) + final Widget? leading; + + /// Trailing widget (end) + final Widget? trailing; + + /// Callback when tile is tapped + final VoidCallback? onTap; + + /// Title color + final Color? titleColor; + + /// Background tile color + final Color? tileColor; + + /// Separator color + final Color? separatorColor; + + /// [TextStyle] to apply to [title] + final TextStyle? titleTextStyle; @override - Widget build(BuildContext context) { - return Column( - children: [ - Container( - color: separatorColor ?? - StreamChatTheme.of(context).colorTheme.greyGainsboro, - height: 1, - ), - Material( - color: tileColor ?? StreamChatTheme.of(context).colorTheme.white, - child: Container( - height: 63, - child: InkWell( - onTap: onTap, - child: Row( - children: [ - if (leading != null) Center(child: leading), - if (leading == null) - SizedBox( - width: 16, - ), - Expanded( - flex: 4, - child: Text( - title!, - style: titleTextStyle ?? - (titleColor == null - ? StreamChatTheme.of(context).textTheme.bodyBold - : StreamChatTheme.of(context) - .textTheme - .bodyBold - .copyWith( - color: titleColor, - )), - ), - ), - Expanded( - flex: 2, - child: Padding( - padding: const EdgeInsets.only(right: 16), - child: Align( - alignment: Alignment.centerRight, - child: trailing ?? Container(), + Widget build(BuildContext context) => Column( + children: [ + Container( + color: separatorColor ?? + StreamChatTheme.of(context).colorTheme.greyGainsboro, + height: 1, + ), + Material( + color: tileColor ?? StreamChatTheme.of(context).colorTheme.white, + child: SizedBox( + height: 63, + child: InkWell( + onTap: onTap, + child: Row( + children: [ + if (leading != null) Center(child: leading), + if (leading == null) + const SizedBox( + width: 16, + ), + Expanded( + flex: 4, + child: Text( + title!, + style: titleTextStyle ?? + (titleColor == null + ? StreamChatTheme.of(context).textTheme.bodyBold + : StreamChatTheme.of(context) + .textTheme + .bodyBold + .copyWith( + color: titleColor, + )), ), ), - ), - ], + Expanded( + flex: 2, + child: Padding( + padding: const EdgeInsets.only(right: 16), + child: Align( + alignment: Alignment.centerRight, + child: trailing ?? Container(), + ), + ), + ), + ], + ), ), ), ), - ), - ], - ); - } + ], + ); } diff --git a/packages/stream_chat_flutter/lib/src/quoted_message_widget.dart b/packages/stream_chat_flutter/lib/src/quoted_message_widget.dart index 9d489dab..6be7ded7 100644 --- a/packages/stream_chat_flutter/lib/src/quoted_message_widget.dart +++ b/packages/stream_chat_flutter/lib/src/quoted_message_widget.dart @@ -4,29 +4,25 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:video_player/video_player.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; +import 'package:stream_chat_flutter/src/extension.dart'; -import 'attachment/attachment.dart'; -import 'extension.dart'; -import 'message_text.dart'; -import 'stream_chat_theme.dart'; -import 'user_avatar.dart'; -import 'utils.dart'; - +/// Widget builder for quoted message attachment thumnail typedef QuotedMessageAttachmentThumbnailBuilder = Widget Function( BuildContext, Attachment, ); class _VideoAttachmentThumbnail extends StatefulWidget { - final Size size; - final Attachment attachment; - const _VideoAttachmentThumbnail({ Key? key, required this.attachment, this.size = const Size(32, 32), }) : super(key: key); + final Size size; + final Attachment attachment; + @override _VideoAttachmentThumbnailState createState() => _VideoAttachmentThumbnailState(); @@ -51,18 +47,30 @@ class _VideoAttachmentThumbnailState extends State<_VideoAttachmentThumbnail> { } @override - Widget build(BuildContext context) { - return Container( + Widget build(BuildContext context) => SizedBox( height: widget.size.height, width: widget.size.width, child: _controller.value.isInitialized ? VideoPlayer(_controller) - : CircularProgressIndicator()); - } + : const CircularProgressIndicator(), + ); } /// class QuotedMessageWidget extends StatelessWidget { + /// + const QuotedMessageWidget({ + Key? key, + required this.message, + required this.messageTheme, + this.reverse = false, + this.showBorder = false, + this.textLimit = 170, + this.attachmentThumbnailBuilders, + this.padding = const EdgeInsets.all(8), + this.onTap, + }) : super(key: key); + /// The message final Message message; @@ -82,23 +90,12 @@ class QuotedMessageWidget extends StatelessWidget { final Map? attachmentThumbnailBuilders; + /// Padding around the widget final EdgeInsetsGeometry padding; + /// Callback for tap on widget final GestureTapCallback? onTap; - /// - const QuotedMessageWidget({ - Key? key, - required this.message, - required this.messageTheme, - this.reverse = false, - this.showBorder = false, - this.textLimit = 170, - this.attachmentThumbnailBuilders, - this.padding = const EdgeInsets.all(8), - this.onTap, - }) : super(key: key); - bool get _hasAttachments => message.attachments.isNotEmpty == true; bool get _containsScrapeUrl => @@ -107,23 +104,21 @@ class QuotedMessageWidget extends StatelessWidget { bool get _containsText => message.text?.isNotEmpty == true; @override - Widget build(BuildContext context) { - return Padding( - padding: padding, - child: InkWell( - onTap: onTap, - child: Row( - crossAxisAlignment: CrossAxisAlignment.end, - mainAxisSize: MainAxisSize.min, - children: [ - Flexible(child: _buildMessage(context)), - SizedBox(width: 8), - if (message.user != null) _buildUserAvatar(), - ], + Widget build(BuildContext context) => Padding( + padding: padding, + child: InkWell( + onTap: onTap, + child: Row( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisSize: MainAxisSize.min, + children: [ + Flexible(child: _buildMessage(context)), + const SizedBox(width: 8), + if (message.user != null) _buildUserAvatar(), + ], + ), ), - ), - ); - } + ); Widget _buildMessage(BuildContext context) { final isOnlyEmoji = message.text!.isOnlyEmoji; @@ -165,7 +160,7 @@ class QuotedMessageWidget extends StatelessWidget { color: StreamChatTheme.of(context).colorTheme.greyGainsboro, ) : null, - borderRadius: BorderRadius.only( + borderRadius: const BorderRadius.only( topRight: Radius.circular(12), topLeft: Radius.circular(12), bottomLeft: Radius.circular(12), @@ -183,7 +178,7 @@ class QuotedMessageWidget extends StatelessWidget { } Widget _buildUrlAttachment(Attachment attachment) { - final size = Size(32, 32); + const size = Size(32, 32); if (attachment.thumbUrl != null) { return Container( height: size.height, @@ -198,7 +193,7 @@ class QuotedMessageWidget extends StatelessWidget { ), ); } - return AttachmentError(size: size); + return const AttachmentError(size: size); } Widget _parseAttachments(BuildContext context) { @@ -217,7 +212,7 @@ class QuotedMessageWidget extends StatelessWidget { } attachmentBuilder = _defaultAttachmentBuilder[attachment.type]; if (attachmentBuilder == null) { - child = Offstage(); + child = const Offstage(); } else { child = attachmentBuilder(context, attachment); } @@ -235,77 +230,63 @@ class QuotedMessageWidget extends StatelessWidget { ); } - ShapeBorder _getDefaultShape(BuildContext context) { - return RoundedRectangleBorder( - side: BorderSide(width: 0, color: Colors.transparent), - borderRadius: BorderRadius.circular(8), - ); - } + ShapeBorder _getDefaultShape(BuildContext context) => RoundedRectangleBorder( + side: const BorderSide(width: 0, color: Colors.transparent), + borderRadius: BorderRadius.circular(8), + ); - Widget _buildUserAvatar() { - return Transform( - transform: Matrix4.rotationY(reverse ? pi : 0), - alignment: Alignment.center, - child: UserAvatar( - user: message.user!, - constraints: BoxConstraints.tightFor( - height: 24, - width: 24, + Widget _buildUserAvatar() => Transform( + transform: Matrix4.rotationY(reverse ? pi : 0), + alignment: Alignment.center, + child: UserAvatar( + user: message.user!, + constraints: const BoxConstraints.tightFor( + height: 24, + width: 24, + ), + showOnlineStatus: false, ), - showOnlineStatus: false, - ), - ); - } + ); Map - get _defaultAttachmentBuilder { - return { - 'image': (_, attachment) { - return ImageAttachment( - attachment: attachment, - message: message, - messageTheme: messageTheme, - size: Size(32, 32), - ); - }, - 'video': (_, attachment) { - return _VideoAttachmentThumbnail( - key: ValueKey(attachment.assetUrl), - attachment: attachment, - ); - }, - 'giphy': (_, attachment) { - final size = Size(32, 32); - return CachedNetworkImage( - height: size.height, - width: size.width, - placeholder: (_, __) { - return Container( - width: size.width, - height: size.height, - child: Center( - child: CircularProgressIndicator(), - ), - ); - }, - imageUrl: attachment.thumbUrl ?? - attachment.imageUrl ?? - attachment.assetUrl!, - errorWidget: (context, url, error) { - return AttachmentError(size: size); - }, - fit: BoxFit.cover, - ); - }, - 'file': (_, attachment) { - return Container( - height: 32, - width: 32, - child: getFileTypeImage(attachment.extraData['mime_type'] as String?), - ); - }, - }; - } + get _defaultAttachmentBuilder => { + 'image': (_, attachment) => ImageAttachment( + attachment: attachment, + message: message, + messageTheme: messageTheme, + size: const Size(32, 32), + ), + 'video': (_, attachment) => _VideoAttachmentThumbnail( + key: ValueKey(attachment.assetUrl), + attachment: attachment, + ), + 'giphy': (_, attachment) { + const size = Size(32, 32); + return CachedNetworkImage( + height: size.height, + width: size.width, + placeholder: (_, __) => SizedBox( + width: size.width, + height: size.height, + child: const Center( + child: CircularProgressIndicator(), + ), + ), + imageUrl: attachment.thumbUrl ?? + attachment.imageUrl ?? + attachment.assetUrl!, + errorWidget: (context, url, error) => + const AttachmentError(size: size), + fit: BoxFit.cover, + ); + }, + 'file': (_, attachment) => SizedBox( + height: 32, + width: 32, + child: getFileTypeImage( + attachment.extraData['mime_type'] as String?), + ), + }; Color? _getBackgroundColor(BuildContext context) { if (_containsScrapeUrl) { From d1705c26a329c093b1b7dc8aa60637cd285daa5b Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 5 May 2021 16:29:16 +0530 Subject: [PATCH 14/31] lint changes rb --- .../lib/src/reaction_bubble.dart | 187 ++++++++++-------- 1 file changed, 105 insertions(+), 82 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/reaction_bubble.dart b/packages/stream_chat_flutter/lib/src/reaction_bubble.dart index d71c395a..9b45c248 100644 --- a/packages/stream_chat_flutter/lib/src/reaction_bubble.dart +++ b/packages/stream_chat_flutter/lib/src/reaction_bubble.dart @@ -8,7 +8,9 @@ import 'package:stream_chat_flutter/src/reaction_icon.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; +/// Creates reaction bubble widget for displaying over messages class ReactionBubble extends StatelessWidget { + /// Constructor for creating a [ReactionBubble] const ReactionBubble({ Key? key, required this.reactions, @@ -21,13 +23,28 @@ class ReactionBubble extends StatelessWidget { this.tailCirclesSpacing = 0, }) : super(key: key); + /// Reactions to show final List reactions; + + /// Border color of bubble final Color borderColor; + + /// Background color of bubble final Color backgroundColor; + + /// Mask color final Color maskColor; + + /// Reverse for other side final bool reverse; + + /// Reverse tail for other side final bool flipTail; + + /// Flag for highlighting own reactions final bool highlightOwnReactions; + + /// Spacing for tail circles final double tailCirclesSpacing; @override @@ -47,7 +64,7 @@ class ReactionBubble extends StatelessWidget { padding: const EdgeInsets.all(2), decoration: BoxDecoration( color: maskColor, - borderRadius: BorderRadius.all(Radius.circular(16)), + borderRadius: const BorderRadius.all(Radius.circular(16)), ), child: Container( padding: EdgeInsets.symmetric( @@ -59,35 +76,32 @@ class ReactionBubble extends StatelessWidget { color: borderColor, ), color: backgroundColor, - borderRadius: BorderRadius.all(Radius.circular(14)), + borderRadius: const BorderRadius.all(Radius.circular(14)), ), child: LayoutBuilder( - builder: (context, constraints) { - return Flex( - direction: Axis.horizontal, - mainAxisSize: MainAxisSize.min, - children: [ - if (constraints.maxWidth < double.infinity) - ...reactions - .take((constraints.maxWidth) ~/ 24) - .map((reaction) { - return _buildReaction( - reactionIcons, - reaction, - context, - ); - }).toList(), - if (constraints.maxWidth == double.infinity) - ...reactions.map((reaction) { - return _buildReaction( - reactionIcons, - reaction, - context, - ); - }).toList(), - ], - ); - }, + builder: (context, constraints) => Flex( + direction: Axis.horizontal, + mainAxisSize: MainAxisSize.min, + children: [ + if (constraints.maxWidth < double.infinity) + ...reactions + .take((constraints.maxWidth) ~/ 24) + .map((reaction) => _buildReaction( + reactionIcons, + reaction, + context, + )) + .toList(), + if (constraints.maxWidth == double.infinity) + ...reactions + .map((reaction) => _buildReaction( + reactionIcons, + reaction, + context, + )) + .toList(), + ], + ), ), ), ), @@ -160,12 +174,9 @@ class ReactionBubble extends StatelessWidget { } } +/// Painter widget for a reaction bubble class ReactionBubblePainter extends CustomPainter { - final Color color; - final Color borderColor; - final Color maskColor; - final double tailCirclesSpace; - + /// Constructor for creating a [ReactionBubblePainter] ReactionBubblePainter( this.color, this.borderColor, @@ -173,6 +184,18 @@ class ReactionBubblePainter extends CustomPainter { this.tailCirclesSpace = 0, }); + /// Color of bubble + final Color color; + + /// Border color of bubble + final Color borderColor; + + /// Mask color + final Color maskColor; + + /// Tail circle space + final double tailCirclesSpace; + @override void paint(Canvas canvas, Size size) { _drawOvalMask(size, canvas); @@ -193,13 +216,14 @@ class ReactionBubblePainter extends CustomPainter { ..color = maskColor ..style = PaintingStyle.fill; - final path = Path(); - path.addOval( - Rect.fromCircle( - center: Offset(4, 3) + Offset(tailCirclesSpace, tailCirclesSpace), - radius: 4, - ), - ); + final path = Path() + ..addOval( + Rect.fromCircle( + center: + const Offset(4, 3) + Offset(tailCirclesSpace, tailCirclesSpace), + radius: 4, + ), + ); canvas.drawPath(path, paint); } @@ -209,13 +233,14 @@ class ReactionBubblePainter extends CustomPainter { ..strokeWidth = 1 ..style = PaintingStyle.stroke; - final path = Path(); - path.addOval( - Rect.fromCircle( - center: Offset(4, 3) + Offset(tailCirclesSpace, tailCirclesSpace), - radius: 2, - ), - ); + final path = Path() + ..addOval( + Rect.fromCircle( + center: + const Offset(4, 3) + Offset(tailCirclesSpace, tailCirclesSpace), + radius: 2, + ), + ); canvas.drawPath(path, paint); } @@ -224,11 +249,11 @@ class ReactionBubblePainter extends CustomPainter { ..color = color ..strokeWidth = 1; - final path = Path(); - path.addOval(Rect.fromCircle( - center: Offset(4, 3) + Offset(tailCirclesSpace, tailCirclesSpace), - radius: 2, - )); + final path = Path() + ..addOval(Rect.fromCircle( + center: const Offset(4, 3) + Offset(tailCirclesSpace, tailCirclesSpace), + radius: 2, + )); canvas.drawPath(path, paint); } @@ -241,15 +266,15 @@ class ReactionBubblePainter extends CustomPainter { const dy = -2.2; const startAngle = 1.1; const sweepAngle = 1.2; - final path = Path(); - path.addArc( - Rect.fromCircle( - center: Offset(1, dy), - radius: 4, - ), - -pi * startAngle, - -pi / sweepAngle, - ); + final path = Path() + ..addArc( + Rect.fromCircle( + center: const Offset(1, dy), + radius: 4, + ), + -pi * startAngle, + -pi / sweepAngle, + ); canvas.drawPath(path, paint); } @@ -261,15 +286,15 @@ class ReactionBubblePainter extends CustomPainter { const dy = -2.2; const startAngle = 1; const sweepAngle = 1.3; - final path = Path(); - path.addArc( - Rect.fromCircle( - center: Offset(1, dy), - radius: 4, - ), - -pi * startAngle, - -pi * sweepAngle, - ); + final path = Path() + ..addArc( + Rect.fromCircle( + center: const Offset(1, dy), + radius: 4, + ), + -pi * startAngle, + -pi * sweepAngle, + ); canvas.drawPath(path, paint); } @@ -282,20 +307,18 @@ class ReactionBubblePainter extends CustomPainter { const dy = -2.2; const startAngle = 1.1; const sweepAngle = 1.2; - final path = Path(); - path.addArc( - Rect.fromCircle( - center: Offset(1, dy), - radius: 6, - ), - -pi * startAngle, - -pi / sweepAngle, - ); + final path = Path() + ..addArc( + Rect.fromCircle( + center: const Offset(1, dy), + radius: 6, + ), + -pi * startAngle, + -pi / sweepAngle, + ); canvas.drawPath(path, paint); } @override - bool shouldRepaint(CustomPainter oldDelegate) { - return true; - } + bool shouldRepaint(CustomPainter oldDelegate) => true; } From 645d21503a45b1ad56c1f127cd29402d626a476d Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 5 May 2021 16:32:32 +0530 Subject: [PATCH 15/31] lint changes reactions --- .../lib/src/reaction_icon.dart | 11 +- .../lib/src/reaction_picker.dart | 185 +++++++++--------- 2 files changed, 99 insertions(+), 97 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/reaction_icon.dart b/packages/stream_chat_flutter/lib/src/reaction_icon.dart index 66e19fe7..4466e154 100644 --- a/packages/stream_chat_flutter/lib/src/reaction_icon.dart +++ b/packages/stream_chat_flutter/lib/src/reaction_icon.dart @@ -1,9 +1,14 @@ +/// Reaction icon data class ReactionIcon { - final String type; - final String assetName; - + /// Constructor for creating [ReactionIcon] ReactionIcon({ required this.type, required this.assetName, }); + + /// Type of reaction + final String type; + + /// Asset to display for reaction + final String assetName; } diff --git a/packages/stream_chat_flutter/lib/src/reaction_picker.dart b/packages/stream_chat_flutter/lib/src/reaction_picker.dart index aaa2c040..1308876d 100644 --- a/packages/stream_chat_flutter/lib/src/reaction_picker.dart +++ b/packages/stream_chat_flutter/lib/src/reaction_picker.dart @@ -3,23 +3,24 @@ import 'dart:math'; import 'package:ezanimation/ezanimation.dart'; import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; - -import '../stream_chat_flutter.dart'; -import 'extension.dart'; +import 'package:stream_chat_flutter/src/extension.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/reaction_picker.png) /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/reaction_picker_paint.png) /// /// It shows a reaction picker /// -/// Usually you don't use this widget as it's one of the default widgets used by [MessageWidget.onMessageActions]. - +/// Usually you don't use this widget as it's one of the default widgets used +/// by [MessageWidget.onMessageActions]. class ReactionPicker extends StatefulWidget { + /// Constructor for creating a [ReactionPicker] widget const ReactionPicker({ Key? key, required this.message, }) : super(key: key); + /// Message to attach the reaction to final Message message; @override @@ -39,7 +40,7 @@ class _ReactionPickerState extends State animations.add( EzAnimation.tween( Tween(begin: 0.0, end: 1.0), - Duration(milliseconds: 500), + const Duration(milliseconds: 500), curve: Curves.easeInOutBack, ), ); @@ -51,108 +52,104 @@ class _ReactionPickerState extends State return TweenAnimationBuilder( tween: Tween(begin: 0, end: 1), curve: Curves.easeInOutBack, - duration: Duration(milliseconds: 500), - builder: (context, val, wid) { - return Transform.scale( - scale: val, - child: Material( - borderRadius: BorderRadius.circular(24), - color: StreamChatTheme.of(context).colorTheme.white, - clipBehavior: Clip.hardEdge, - child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: 16, - vertical: 8, - ), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.end, - mainAxisSize: MainAxisSize.min, - children: reactionIcons - .map((reactionIcon) { - final ownReactionIndex = widget.message.ownReactions - ?.indexWhere((reaction) => - reaction.type == reactionIcon.type) ?? - -1; - final index = reactionIcons.indexOf(reactionIcon); + duration: const Duration(milliseconds: 500), + builder: (context, val, wid) => Transform.scale( + scale: val, + child: Material( + borderRadius: BorderRadius.circular(24), + color: StreamChatTheme.of(context).colorTheme.white, + clipBehavior: Clip.hardEdge, + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 16, + vertical: 8, + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.end, + mainAxisSize: MainAxisSize.min, + children: reactionIcons + .map((reactionIcon) { + final ownReactionIndex = widget.message.ownReactions + ?.indexWhere((reaction) => + reaction.type == reactionIcon.type) ?? + -1; + final index = reactionIcons.indexOf(reactionIcon); - return ConstrainedBox( - constraints: BoxConstraints.tightFor( - height: 24, - width: 24, - ), - child: RawMaterialButton( - elevation: 0, - shape: ContinuousRectangleBorder( - borderRadius: BorderRadius.circular(16), - ), - constraints: BoxConstraints.tightFor( + return ConstrainedBox( + constraints: const BoxConstraints.tightFor( height: 24, width: 24, ), - onPressed: () { - if (ownReactionIndex != -1) { - removeReaction( - context, - widget - .message.ownReactions![ownReactionIndex], - ); - } else { - sendReaction( - context, - reactionIcon.type, - ); - } - }, - child: AnimatedBuilder( - animation: animations[index], - builder: (context, val) { - return Transform.scale( - scale: animations[index].value, - child: StreamSvgIcon( - assetName: reactionIcon.assetName, - height: max( - 0, - animations[index].value * 24.0, - ), - width: max( - 0, - animations[index].value * 24.0, - ), - color: ownReactionIndex != -1 - ? StreamChatTheme.of(context) - .colorTheme - .accentBlue - : Theme.of(context) - .iconTheme - .color! - .withOpacity(.5), - ), + child: RawMaterialButton( + elevation: 0, + shape: ContinuousRectangleBorder( + borderRadius: BorderRadius.circular(16), + ), + constraints: const BoxConstraints.tightFor( + height: 24, + width: 24, + ), + onPressed: () { + if (ownReactionIndex != -1) { + removeReaction( + context, + widget.message + .ownReactions![ownReactionIndex], ); - }), - ), - ); - }) - .insertBetween(SizedBox( - width: 16, - )) - .toList(), + } else { + sendReaction( + context, + reactionIcon.type, + ); + } + }, + child: AnimatedBuilder( + animation: animations[index], + builder: (context, val) => Transform.scale( + scale: animations[index].value, + child: StreamSvgIcon( + assetName: reactionIcon.assetName, + height: max( + 0, + animations[index].value * 24.0, + ), + width: max( + 0, + animations[index].value * 24.0, + ), + color: ownReactionIndex != -1 + ? StreamChatTheme.of(context) + .colorTheme + .accentBlue + : Theme.of(context) + .iconTheme + .color! + .withOpacity(.5), + ), + )), + ), + ); + }) + .insertBetween(const SizedBox( + width: 16, + )) + .toList(), + ), ), ), - ), - ); - }); + )); } void triggerAnimations() async { - for (var a in animations) { + for (final a in animations) { a.start(); - await Future.delayed(Duration(milliseconds: 100)); + await Future.delayed(const Duration(milliseconds: 100)); } } void pop() async { - for (var a in animations) { + for (final a in animations) { a.stop(); } Navigator.of(context).pop(); @@ -176,7 +173,7 @@ class _ReactionPickerState extends State @override void dispose() { - for (var a in animations) { + for (final a in animations) { a.dispose(); } super.dispose(); From d55b937364b43f64c5868dfc5d50269406f269b0 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 5 May 2021 16:38:05 +0530 Subject: [PATCH 16/31] lint --- .../lib/src/sending_indicator.dart | 16 +++++--- .../lib/src/stream_chat.dart | 38 +++++++++++-------- 2 files changed, 33 insertions(+), 21 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/sending_indicator.dart b/packages/stream_chat_flutter/lib/src/sending_indicator.dart index 68fc5a0d..88560432 100644 --- a/packages/stream_chat_flutter/lib/src/sending_indicator.dart +++ b/packages/stream_chat_flutter/lib/src/sending_indicator.dart @@ -3,10 +3,7 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; /// Used to show the sending status of the message class SendingIndicator extends StatelessWidget { - final Message message; - final bool isMessageRead; - final double? size; - + /// Constructor for creating a [SendingIndicator] widget const SendingIndicator({ Key? key, required this.message, @@ -14,6 +11,15 @@ class SendingIndicator extends StatelessWidget { this.size = 12, }) : super(key: key); + /// Message for sending indicator + final Message message; + + /// Flag if message is read + final bool isMessageRead; + + /// Size for message + final double? size; + @override Widget build(BuildContext context) { if (isMessageRead) { @@ -35,6 +41,6 @@ class SendingIndicator extends StatelessWidget { size: size, ); } - return SizedBox(); + return const SizedBox(); } } diff --git a/packages/stream_chat_flutter/lib/src/stream_chat.dart b/packages/stream_chat_flutter/lib/src/stream_chat.dart index 2c22dde3..424d4bcf 100644 --- a/packages/stream_chat_flutter/lib/src/stream_chat.dart +++ b/packages/stream_chat_flutter/lib/src/stream_chat.dart @@ -31,18 +31,7 @@ import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; /// /// Use [StreamChat.of] to get the current [StreamChatState] instance. class StreamChat extends StatefulWidget { - final StreamChatClient client; - final Widget? child; - final StreamChatThemeData? streamChatThemeData; - - /// The amount of time that will pass before disconnecting the client in the background - final Duration backgroundKeepAlive; - - /// Handler called whenever the [client] receives a new [Event] while the app - /// is in background. Can be used to display various notifications depending - /// upon the [Event.type] - final EventHandler? onBackgroundEventReceived; - + /// Constructor for creating a [StreamChat] widget const StreamChat({ Key? key, required this.client, @@ -50,9 +39,25 @@ class StreamChat extends StatefulWidget { this.streamChatThemeData, this.onBackgroundEventReceived, this.backgroundKeepAlive = const Duration(minutes: 1), - }) : super( - key: key, - ); + }) : super(key: key); + + /// Client to do chat ops with + final StreamChatClient client; + + /// Child which inherits details + final Widget? child; + + /// Theme to pass on + final StreamChatThemeData? streamChatThemeData; + + /// The amount of time that will pass before disconnecting the client + /// in the background + final Duration backgroundKeepAlive; + + /// Handler called whenever the [client] receives a new [Event] while the app + /// is in background. Can be used to display various notifications depending + /// upon the [Event.type] + final EventHandler? onBackgroundEventReceived; @override StreamChatState createState() => StreamChatState(); @@ -74,6 +79,7 @@ class StreamChat extends StatefulWidget { /// The current state of the StreamChat widget class StreamChatState extends State { + /// Gets client from widget StreamChatClient get client => widget.client; @override @@ -96,7 +102,7 @@ class StreamChatState extends State { client: client, onBackgroundEventReceived: widget.onBackgroundEventReceived, backgroundKeepAlive: widget.backgroundKeepAlive, - child: widget.child ?? Offstage(), + child: widget.child ?? const Offstage(), ), ); }, From dad7bb3f8cd723d570270152a95d5195c9771ca4 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 5 May 2021 17:08:49 +0530 Subject: [PATCH 17/31] lint theme --- .../lib/src/stream_chat_theme.dart | 577 +++++++++++------- 1 file changed, 357 insertions(+), 220 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart b/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart index 1e1eb089..c5646753 100644 --- a/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart +++ b/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart @@ -11,8 +11,7 @@ import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; /// Inherited widget providing the [StreamChatThemeData] to the widget tree class StreamChatTheme extends InheritedWidget { - final StreamChatThemeData data; - + /// Constructor for creating a [StreamChatTheme] const StreamChatTheme({ Key? key, required this.data, @@ -22,10 +21,11 @@ class StreamChatTheme extends InheritedWidget { child: child, ); + /// Theme data + final StreamChatThemeData data; + @override - bool updateShouldNotify(StreamChatTheme old) { - return data != old.data; - } + bool updateShouldNotify(StreamChatTheme old) => data != old.data; /// Use this method to get the current [StreamChatThemeData] instance static StreamChatThemeData of(BuildContext context) { @@ -43,42 +43,6 @@ class StreamChatTheme extends InheritedWidget { /// Theme data class StreamChatThemeData { - /// The text themes used in the widgets - final TextTheme textTheme; - - /// The color themes used in the widgets - final ColorTheme colorTheme; - - /// Theme of the [ChannelPreview] - final ChannelPreviewTheme channelPreviewTheme; - - /// Theme of the [ChannelListHeader] - final ChannelListHeaderTheme channelListHeaderTheme; - - /// Theme of the chat widgets dedicated to a channel - final ChannelTheme channelTheme; - - /// Theme of the current user messages - final MessageTheme ownMessageTheme; - - /// Theme of other users messages - final MessageTheme otherMessageTheme; - - /// Theme dedicated to the [MessageInput] widget - final MessageInputTheme messageInputTheme; - - /// The widget that will be built when the channel image is unavailable - final Widget Function(BuildContext, Channel) defaultChannelImage; - - /// The widget that will be built when the user image is unavailable - final Widget Function(BuildContext, User) defaultUserImage; - - /// Primary icon theme - final IconThemeData primaryIconTheme; - - /// Assets used for rendering reactions - final List reactionIcons; - /// Create a theme from scratch factory StreamChatThemeData({ Brightness? brightness, @@ -121,12 +85,15 @@ class StreamChatThemeData { return defaultData.merge(customizedData); } + /// Theme initialised with light factory StreamChatThemeData.light() => StreamChatThemeData(brightness: Brightness.light); + /// Theme initialised with dark factory StreamChatThemeData.dark() => StreamChatThemeData(brightness: Brightness.dark); + /// Raw theme init const StreamChatThemeData.raw({ required this.textTheme, required this.colorTheme, @@ -154,7 +121,44 @@ class StreamChatThemeData { return defaultTheme.merge(customizedTheme); } - /// Creates a copy of [StreamChatThemeData] with specified attributes overridden. + /// The text themes used in the widgets + final TextTheme textTheme; + + /// The color themes used in the widgets + final ColorTheme colorTheme; + + /// Theme of the [ChannelPreview] + final ChannelPreviewTheme channelPreviewTheme; + + /// Theme of the [ChannelListHeader] + final ChannelListHeaderTheme channelListHeaderTheme; + + /// Theme of the chat widgets dedicated to a channel + final ChannelTheme channelTheme; + + /// Theme of the current user messages + final MessageTheme ownMessageTheme; + + /// Theme of other users messages + final MessageTheme otherMessageTheme; + + /// Theme dedicated to the [MessageInput] widget + final MessageInputTheme messageInputTheme; + + /// The widget that will be built when the channel image is unavailable + final Widget Function(BuildContext, Channel) defaultChannelImage; + + /// The widget that will be built when the user image is unavailable + final Widget Function(BuildContext, User) defaultUserImage; + + /// Primary icon theme + final IconThemeData primaryIconTheme; + + /// Assets used for rendering reactions + final List reactionIcons; + + /// Creates a copy of [StreamChatThemeData] with specified attributes + /// overridden. StreamChatThemeData copyWith({ TextTheme? textTheme, ColorTheme? colorTheme, @@ -185,6 +189,7 @@ class StreamChatThemeData { reactionIcons: reactionIcons ?? this.reactionIcons, ); + /// Merge themes StreamChatThemeData merge(StreamChatThemeData? other) { if (other == null) return this; return copyWith( @@ -204,6 +209,8 @@ class StreamChatThemeData { ); } + /// Create theme from color and text theme + // ignore: prefer_constructors_over_static_methods static StreamChatThemeData fromColorAndTextTheme( ColorTheme colorTheme, TextTheme textTheme, @@ -213,7 +220,7 @@ class StreamChatThemeData { textTheme: textTheme, colorTheme: colorTheme, primaryIconTheme: IconThemeData(color: colorTheme.black.withOpacity(.5)), - defaultChannelImage: (context, channel) => SizedBox(), + defaultChannelImage: (context, channel) => const SizedBox(), defaultUserImage: (context, user) => Center( child: CachedNetworkImage( filterQuality: FilterQuality.high, @@ -225,14 +232,14 @@ class StreamChatThemeData { unreadCounterColor: colorTheme.accentRed, avatarTheme: AvatarTheme( borderRadius: BorderRadius.circular(20), - constraints: BoxConstraints.tightFor( + constraints: const BoxConstraints.tightFor( height: 40, width: 40, ), ), title: textTheme.bodyBold, subtitle: textTheme.footnote.copyWith( - color: Color(0xff7A7A7A), + color: const Color(0xff7A7A7A), ), lastMessageAt: textTheme.footnote.copyWith( color: colorTheme.black.withOpacity(.5), @@ -241,7 +248,7 @@ class StreamChatThemeData { channelListHeaderTheme: ChannelListHeaderTheme( avatarTheme: AvatarTheme( borderRadius: BorderRadius.circular(20), - constraints: BoxConstraints.tightFor( + constraints: const BoxConstraints.tightFor( height: 40, width: 40, ), @@ -253,7 +260,7 @@ class StreamChatThemeData { channelHeaderTheme: ChannelHeaderTheme( avatarTheme: AvatarTheme( borderRadius: BorderRadius.circular(20), - constraints: BoxConstraints.tightFor( + constraints: const BoxConstraints.tightFor( height: 40, width: 40, ), @@ -261,7 +268,7 @@ class StreamChatThemeData { color: colorTheme.white, title: textTheme.headlineBold, subtitle: textTheme.footnote.copyWith( - color: Color(0xff7A7A7A), + color: const Color(0xff7A7A7A), ), ), ), @@ -277,7 +284,7 @@ class StreamChatThemeData { messageBorderColor: colorTheme.greyGainsboro, avatarTheme: AvatarTheme( borderRadius: BorderRadius.circular(20), - constraints: BoxConstraints.tightFor( + constraints: const BoxConstraints.tightFor( height: 32, width: 32, ), @@ -301,7 +308,7 @@ class StreamChatThemeData { messageBorderColor: colorTheme.greyWhisper, avatarTheme: AvatarTheme( borderRadius: BorderRadius.circular(20), - constraints: BoxConstraints.tightFor( + constraints: const BoxConstraints.tightFor( height: 32, width: 32, ), @@ -309,7 +316,7 @@ class StreamChatThemeData { ), messageInputTheme: MessageInputTheme( borderRadius: BorderRadius.circular(20), - sendAnimationDuration: Duration(milliseconds: 300), + sendAnimationDuration: const Duration(milliseconds: 300), actionButtonColor: colorTheme.accentBlue, actionButtonIdleColor: colorTheme.grey, expandButtonColor: colorTheme.accentBlue, @@ -356,16 +363,9 @@ class StreamChatThemeData { } } +/// Class for holding text theme class TextTheme { - final TextStyle title; - final TextStyle headlineBold; - final TextStyle headline; - final TextStyle bodyBold; - final TextStyle body; - final TextStyle footnoteBold; - final TextStyle footnote; - final TextStyle captionBold; - + /// Initialise light text theme TextTheme.light({ this.title = const TextStyle( fontSize: 22, @@ -408,6 +408,7 @@ class TextTheme { ), }); + /// Initialise with dark theme TextTheme.dark({ this.title = const TextStyle( fontSize: 22, @@ -450,6 +451,31 @@ class TextTheme { ), }); + /// Text theme for title + final TextStyle title; + + /// Body Text theme for headline + final TextStyle headlineBold; + + /// Text theme for headline + final TextStyle headline; + + /// Bold Text theme for body + final TextStyle bodyBold; + + /// Text theme body + final TextStyle body; + + /// Bold Text theme for footnote + final TextStyle footnoteBold; + + /// Text theme for footnote + final TextStyle footnote; + + /// Bold Text theme for caption + final TextStyle captionBold; + + /// Copy with theme TextTheme copyWith({ Brightness brightness = Brightness.light, TextStyle? body, @@ -460,30 +486,30 @@ class TextTheme { TextStyle? footnoteBold, TextStyle? footnote, TextStyle? captionBold, - }) { - return brightness == Brightness.light - ? TextTheme.light( - body: body ?? this.body, - title: title ?? this.title, - headlineBold: headlineBold ?? this.headlineBold, - headline: headline ?? this.headline, - bodyBold: bodyBold ?? this.bodyBold, - footnoteBold: footnoteBold ?? this.footnoteBold, - footnote: footnote ?? this.footnote, - captionBold: captionBold ?? this.captionBold, - ) - : TextTheme.dark( - body: body ?? this.body, - title: title ?? this.title, - headlineBold: headlineBold ?? this.headlineBold, - headline: headline ?? this.headline, - bodyBold: bodyBold ?? this.bodyBold, - footnoteBold: footnoteBold ?? this.footnoteBold, - footnote: footnote ?? this.footnote, - captionBold: captionBold ?? this.captionBold, - ); - } + }) => + brightness == Brightness.light + ? TextTheme.light( + body: body ?? this.body, + title: title ?? this.title, + headlineBold: headlineBold ?? this.headlineBold, + headline: headline ?? this.headline, + bodyBold: bodyBold ?? this.bodyBold, + footnoteBold: footnoteBold ?? this.footnoteBold, + footnote: footnote ?? this.footnote, + captionBold: captionBold ?? this.captionBold, + ) + : TextTheme.dark( + body: body ?? this.body, + title: title ?? this.title, + headlineBold: headlineBold ?? this.headlineBold, + headline: headline ?? this.headline, + bodyBold: bodyBold ?? this.bodyBold, + footnoteBold: footnoteBold ?? this.footnoteBold, + footnote: footnote ?? this.footnote, + captionBold: captionBold ?? this.captionBold, + ); + /// Merge text theme TextTheme merge(TextTheme? other) { if (other == null) return this; return copyWith( @@ -499,28 +525,9 @@ class TextTheme { } } +/// Theme that holds colors class ColorTheme { - final Color black; - final Color grey; - final Color greyGainsboro; - final Color greyWhisper; - final Color whiteSmoke; - final Color whiteSnow; - final Color white; - final Color blueAlice; - final Color accentBlue; - final Color accentRed; - final Color accentGreen; - final Effect borderTop; - final Effect borderBottom; - final Effect shadowIconButton; - final Effect modalShadow; - final Color highlight; - final Color overlay; - final Color overlayDark; - final Gradient bgGradient; - final Brightness brightness; - + /// Initialise with light theme ColorTheme.light({ this.black = const Color(0xff000000), this.grey = const Color(0xff7a7a7a), @@ -552,6 +559,7 @@ class ColorTheme { sigmaX: 0, sigmaY: 0, color: Color(0xff000000), alpha: 1, blur: 8), }) : brightness = Brightness.light; + /// Initialise with dark theme ColorTheme.dark({ this.black = const Color(0xffffffff), this.grey = const Color(0xff7a7a7a), @@ -605,6 +613,67 @@ class ColorTheme { ), }) : brightness = Brightness.dark; + /// + final Color black; + + /// + final Color grey; + + /// + final Color greyGainsboro; + + /// + final Color greyWhisper; + + /// + final Color whiteSmoke; + + /// + final Color whiteSnow; + + /// + final Color white; + + /// + final Color blueAlice; + + /// + final Color accentBlue; + + /// + final Color accentRed; + + /// + final Color accentGreen; + + /// + final Effect borderTop; + + /// + final Effect borderBottom; + + /// + final Effect shadowIconButton; + + /// + final Effect modalShadow; + + /// + final Color highlight; + + /// + final Color overlay; + + /// + final Color overlayDark; + + /// + final Gradient bgGradient; + + /// + final Brightness brightness; + + /// Copy with theme ColorTheme copyWith({ Brightness brightness = Brightness.light, Color? black, @@ -626,52 +695,52 @@ class ColorTheme { Color? overlay, Color? overlayDark, Gradient? bgGradient, - }) { - return brightness == Brightness.light - ? ColorTheme.light( - black: black ?? this.black, - grey: grey ?? this.grey, - greyGainsboro: greyGainsboro ?? this.greyGainsboro, - greyWhisper: greyWhisper ?? this.greyWhisper, - whiteSmoke: whiteSmoke ?? this.whiteSmoke, - whiteSnow: whiteSnow ?? this.whiteSnow, - white: white ?? this.white, - blueAlice: blueAlice ?? this.blueAlice, - accentBlue: accentBlue ?? this.accentBlue, - accentRed: accentRed ?? this.accentRed, - accentGreen: accentGreen ?? this.accentGreen, - borderTop: borderTop ?? this.borderTop, - borderBottom: borderBottom ?? this.borderBottom, - shadowIconButton: shadowIconButton ?? this.shadowIconButton, - modalShadow: modalShadow ?? this.modalShadow, - highlight: highlight ?? this.highlight, - overlay: overlay ?? this.overlay, - overlayDark: overlayDark ?? this.overlayDark, - bgGradient: bgGradient ?? this.bgGradient, - ) - : ColorTheme.dark( - black: black ?? this.black, - grey: grey ?? this.grey, - greyGainsboro: greyGainsboro ?? this.greyGainsboro, - greyWhisper: greyWhisper ?? this.greyWhisper, - whiteSmoke: whiteSmoke ?? this.whiteSmoke, - whiteSnow: whiteSnow ?? this.whiteSnow, - white: white ?? this.white, - blueAlice: blueAlice ?? this.blueAlice, - accentBlue: accentBlue ?? this.accentBlue, - accentRed: accentRed ?? this.accentRed, - accentGreen: accentGreen ?? this.accentGreen, - borderTop: borderTop ?? this.borderTop, - borderBottom: borderBottom ?? this.borderBottom, - shadowIconButton: shadowIconButton ?? this.shadowIconButton, - modalShadow: modalShadow ?? this.modalShadow, - highlight: highlight ?? this.highlight, - overlay: overlay ?? this.overlay, - overlayDark: overlayDark ?? this.overlayDark, - bgGradient: bgGradient ?? this.bgGradient, - ); - } + }) => + brightness == Brightness.light + ? ColorTheme.light( + black: black ?? this.black, + grey: grey ?? this.grey, + greyGainsboro: greyGainsboro ?? this.greyGainsboro, + greyWhisper: greyWhisper ?? this.greyWhisper, + whiteSmoke: whiteSmoke ?? this.whiteSmoke, + whiteSnow: whiteSnow ?? this.whiteSnow, + white: white ?? this.white, + blueAlice: blueAlice ?? this.blueAlice, + accentBlue: accentBlue ?? this.accentBlue, + accentRed: accentRed ?? this.accentRed, + accentGreen: accentGreen ?? this.accentGreen, + borderTop: borderTop ?? this.borderTop, + borderBottom: borderBottom ?? this.borderBottom, + shadowIconButton: shadowIconButton ?? this.shadowIconButton, + modalShadow: modalShadow ?? this.modalShadow, + highlight: highlight ?? this.highlight, + overlay: overlay ?? this.overlay, + overlayDark: overlayDark ?? this.overlayDark, + bgGradient: bgGradient ?? this.bgGradient, + ) + : ColorTheme.dark( + black: black ?? this.black, + grey: grey ?? this.grey, + greyGainsboro: greyGainsboro ?? this.greyGainsboro, + greyWhisper: greyWhisper ?? this.greyWhisper, + whiteSmoke: whiteSmoke ?? this.whiteSmoke, + whiteSnow: whiteSnow ?? this.whiteSnow, + white: white ?? this.white, + blueAlice: blueAlice ?? this.blueAlice, + accentBlue: accentBlue ?? this.accentBlue, + accentRed: accentRed ?? this.accentRed, + accentGreen: accentGreen ?? this.accentGreen, + borderTop: borderTop ?? this.borderTop, + borderBottom: borderBottom ?? this.borderBottom, + shadowIconButton: shadowIconButton ?? this.shadowIconButton, + modalShadow: modalShadow ?? this.modalShadow, + highlight: highlight ?? this.highlight, + overlay: overlay ?? this.overlay, + overlayDark: overlayDark ?? this.overlayDark, + bgGradient: bgGradient ?? this.bgGradient, + ); + /// Merge color theme ColorTheme merge(ColorTheme? other) { if (other == null) return this; return copyWith( @@ -700,13 +769,14 @@ class ColorTheme { /// Channel theme data class ChannelTheme { - /// Theme of the [ChannelHeader] widget - final ChannelHeaderTheme channelHeaderTheme; - + /// Constructor for creating [ChannelTheme] ChannelTheme({ required this.channelHeaderTheme, }); + /// Theme of the [ChannelHeader] widget + final ChannelHeaderTheme channelHeaderTheme; + /// Creates a copy of [ChannelTheme] with specified attributes overridden. ChannelTheme copyWith({ ChannelHeaderTheme? channelHeaderTheme, @@ -715,6 +785,7 @@ class ChannelTheme { channelHeaderTheme: channelHeaderTheme ?? this.channelHeaderTheme, ); + /// Merge with theme ChannelTheme merge(ChannelTheme? other) { if (other == null) return this; return copyWith( @@ -723,28 +794,30 @@ class ChannelTheme { } } +/// Theme for avatar class AvatarTheme { - final BoxConstraints? _constraints; - final BorderRadius? _borderRadius; - - BoxConstraints get constraints { - return _constraints ?? - BoxConstraints.tightFor( - height: 32, - width: 32, - ); - } - - BorderRadius get borderRadius { - return _borderRadius ?? BorderRadius.circular(20); - } - + /// Constructor for creating [AvatarTheme] AvatarTheme({ BoxConstraints? constraints, BorderRadius? borderRadius, }) : _constraints = constraints, _borderRadius = borderRadius; + final BoxConstraints? _constraints; + final BorderRadius? _borderRadius; + + /// Get constraints for avatar + BoxConstraints get constraints => + _constraints ?? + const BoxConstraints.tightFor( + height: 32, + width: 32, + ); + + /// Get border radius + BorderRadius get borderRadius => _borderRadius ?? BorderRadius.circular(20); + + /// Copy with another theme AvatarTheme copyWith({ BoxConstraints? constraints, BorderRadius? borderRadius, @@ -754,6 +827,7 @@ class AvatarTheme { borderRadius: borderRadius ?? _borderRadius, ); + /// Merge with another AvatarTheme AvatarTheme merge(AvatarTheme? other) { if (other == null) return this; return copyWith( @@ -763,19 +837,9 @@ class AvatarTheme { } } +/// Class for getting message theme class MessageTheme { - final TextStyle? messageText; - final TextStyle? messageAuthor; - final TextStyle? messageLinks; - final TextStyle? createdAt; - final TextStyle? replies; - final Color? messageBackgroundColor; - final Color? messageBorderColor; - final Color? reactionsBackgroundColor; - final Color? reactionsBorderColor; - final Color? reactionsMaskColor; - final AvatarTheme? avatarTheme; - + /// Constructor into [MessageTheme] const MessageTheme({ this.replies, this.messageText, @@ -790,6 +854,40 @@ class MessageTheme { this.createdAt, }); + /// Text style for message text + final TextStyle? messageText; + + /// Text style for message author + final TextStyle? messageAuthor; + + /// Text style for message links + final TextStyle? messageLinks; + + /// Text style for created at text + final TextStyle? createdAt; + + /// Text style for replies + final TextStyle? replies; + + /// Color for messageBackgroundColor + final Color? messageBackgroundColor; + + /// Color for message border color + final Color? messageBorderColor; + + /// Color for reactions + final Color? reactionsBackgroundColor; + + /// Colors reaction border + final Color? reactionsBorderColor; + + /// Color for reaction mask + final Color? reactionsMaskColor; + + /// Theme of the avatar + final AvatarTheme? avatarTheme; + + /// Copy with a theme MessageTheme copyWith({ TextStyle? messageText, TextStyle? messageAuthor, @@ -819,6 +917,7 @@ class MessageTheme { reactionsMaskColor: reactionsMaskColor ?? this.reactionsMaskColor, ); + /// Merge with a theme MessageTheme merge(MessageTheme? other) { if (other == null) return this; return copyWith( @@ -839,14 +938,9 @@ class MessageTheme { } } +/// Theme for channel preview class ChannelPreviewTheme { - final TextStyle? title; - final TextStyle? subtitle; - final TextStyle? lastMessageAt; - final AvatarTheme? avatarTheme; - final Color? unreadCounterColor; - final double? indicatorIconSize; - + /// Constructor for creating [ChannelPreviewTheme] const ChannelPreviewTheme({ this.title, this.subtitle, @@ -856,6 +950,25 @@ class ChannelPreviewTheme { this.indicatorIconSize, }); + /// Theme for title + final TextStyle? title; + + /// Theme for subtitle + final TextStyle? subtitle; + + /// Theme of last message at + final TextStyle? lastMessageAt; + + /// Avatar theme + final AvatarTheme? avatarTheme; + + /// Unread counter color + final Color? unreadCounterColor; + + /// Indicator icon size + final double? indicatorIconSize; + + /// Copy with theme ChannelPreviewTheme copyWith({ TextStyle? title, TextStyle? subtitle, @@ -873,6 +986,7 @@ class ChannelPreviewTheme { indicatorIconSize: indicatorIconSize ?? this.indicatorIconSize, ); + /// Merge with theme ChannelPreviewTheme merge(ChannelPreviewTheme? other) { if (other == null) return this; return copyWith( @@ -886,12 +1000,9 @@ class ChannelPreviewTheme { } } +/// Theme for [ChannelHeader] class ChannelHeaderTheme { - final TextStyle? title; - final TextStyle? subtitle; - final AvatarTheme? avatarTheme; - final Color? color; - + /// Constructor for creating a [ChannelHeaderTheme] const ChannelHeaderTheme({ this.title, this.subtitle, @@ -899,6 +1010,19 @@ class ChannelHeaderTheme { this.color, }); + /// Theme for title + final TextStyle? title; + + /// Theme for subtitle + final TextStyle? subtitle; + + /// Theme for avatar + final AvatarTheme? avatarTheme; + + /// Color for [ChannelHeaderTheme] + final Color? color; + + /// Copy with theme ChannelHeaderTheme copyWith({ TextStyle? title, TextStyle? subtitle, @@ -912,6 +1036,7 @@ class ChannelHeaderTheme { color: color ?? this.color, ); + /// Merge with other [ChannelHeaderTheme] ChannelHeaderTheme merge(ChannelHeaderTheme? other) { if (other == null) return this; return copyWith( @@ -925,6 +1050,13 @@ class ChannelHeaderTheme { /// Theme dedicated to the [ChannelListHeader] class ChannelListHeaderTheme { + /// Returns a new [ChannelListHeaderTheme] + const ChannelListHeaderTheme({ + this.title, + this.avatarTheme, + this.color, + }); + /// Style of the title text final TextStyle? title; @@ -934,13 +1066,6 @@ class ChannelListHeaderTheme { /// Background color of the appbar final Color? color; - /// Returns a new [ChannelListHeaderTheme] - const ChannelListHeaderTheme({ - this.title, - this.avatarTheme, - this.color, - }); - /// Returns a new [ChannelListHeaderTheme] replacing some of its properties ChannelListHeaderTheme copyWith({ TextStyle? title, @@ -966,6 +1091,22 @@ class ChannelListHeaderTheme { /// Defines the theme dedicated to the [MessageInput] widget class MessageInputTheme { + /// Returns a new [MessageInputTheme] + const MessageInputTheme({ + this.sendAnimationDuration, + this.actionButtonColor, + this.sendButtonColor, + this.actionButtonIdleColor, + this.sendButtonIdleColor, + this.inputBackground, + this.inputTextStyle, + this.inputDecoration, + this.activeBorderGradient, + this.idleBorderGradient, + this.borderRadius, + this.expandButtonColor, + }); + /// Duration of the [MessageInput] send button animation final Duration? sendAnimationDuration; @@ -1002,22 +1143,6 @@ class MessageInputTheme { /// Border radius of [MessageInput] final BorderRadius? borderRadius; - /// Returns a new [MessageInputTheme] - const MessageInputTheme({ - this.sendAnimationDuration, - this.actionButtonColor, - this.sendButtonColor, - this.actionButtonIdleColor, - this.sendButtonIdleColor, - this.inputBackground, - this.inputTextStyle, - this.inputDecoration, - this.activeBorderGradient, - this.idleBorderGradient, - this.borderRadius, - this.expandButtonColor, - }); - /// Returns a new [MessageInputTheme] replacing some of its properties MessageInputTheme copyWith({ Duration? sendAnimationDuration, @@ -1071,13 +1196,9 @@ class MessageInputTheme { } } +/// Effect store class Effect { - final double? sigmaX; - final double? sigmaY; - final Color? color; - final double? alpha; - final double? blur; - + /// Constructor for creating [Effect] const Effect({ this.sigmaX, this.sigmaY, @@ -1086,6 +1207,22 @@ class Effect { this.blur, }); + /// + final double? sigmaX; + + /// + final double? sigmaY; + + /// + final Color? color; + + /// + final double? alpha; + + /// + final double? blur; + + /// Copy with new effect Effect copyWith({ double? sigmaX, double? sigmaY, From d63540ba9b63a44701ea0fb5fc7c022694b840bb Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 5 May 2021 17:18:26 +0530 Subject: [PATCH 18/31] lint theme --- .../lib/src/stream_neumorphic_button.dart | 20 +- .../lib/src/stream_svg_icon.dart | 1774 +++++++++-------- 2 files changed, 904 insertions(+), 890 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/stream_neumorphic_button.dart b/packages/stream_chat_flutter/lib/src/stream_neumorphic_button.dart index 157d2940..947e2265 100644 --- a/packages/stream_chat_flutter/lib/src/stream_neumorphic_button.dart +++ b/packages/stream_chat_flutter/lib/src/stream_neumorphic_button.dart @@ -1,19 +1,24 @@ import 'package:flutter/material.dart'; +/// Neumorphic button class StreamNeumorphicButton extends StatelessWidget { - final Widget child; - final Color backgroundColor; + /// Constructor for creating [StreamNeumorphicButton] const StreamNeumorphicButton({ Key? key, required this.child, this.backgroundColor = Colors.white, }) : super(key: key); + /// Child contained in the button + final Widget child; + + /// Background color of button + final Color backgroundColor; + @override - Widget build(BuildContext context) { - return Container( - margin: EdgeInsets.all(8), + Widget build(BuildContext context) => Container( + margin: const EdgeInsets.all(8), height: 40, width: 40, decoration: BoxDecoration( @@ -22,10 +27,10 @@ class StreamNeumorphicButton extends StatelessWidget { boxShadow: [ BoxShadow( color: Colors.grey.shade700, - offset: Offset(0, 1), + offset: const Offset(0, 1), blurRadius: 0.5, ), - BoxShadow( + const BoxShadow( color: Colors.white, blurRadius: 0.5, ), @@ -33,5 +38,4 @@ class StreamNeumorphicButton extends StatelessWidget { ), child: child, ); - } } diff --git a/packages/stream_chat_flutter/lib/src/stream_svg_icon.dart b/packages/stream_chat_flutter/lib/src/stream_svg_icon.dart index f115617c..78dfba2c 100644 --- a/packages/stream_chat_flutter/lib/src/stream_svg_icon.dart +++ b/packages/stream_chat_flutter/lib/src/stream_svg_icon.dart @@ -2,18 +2,904 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; +/// Icon set of stream chat class StreamSvgIcon extends StatelessWidget { - final String? assetName; - final double? width; - final double? height; - final Color? color; - + /// Constructor for creating a [StreamSvgIcon] const StreamSvgIcon({ + Key? key, this.assetName, this.color, this.width = 24, this.height = 24, - }); + }) : super(key: key); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.settings({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'settings.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.down({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'Icon_down.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.attach({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'Icon_attach.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.smile({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'Icon_smile.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.mentions({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'mentions.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.record({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'Icon_record.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.camera({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'Icon_camera.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.files({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'files.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.pictures({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'pictures.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.left({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'Icon_left.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.user({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'Icon_user.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.userAdd({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'Icon_User_add.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.check({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'Icon_check.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.checkAll({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'Icon_check_all.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.checkSend({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'Icon_check_send.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.penWrite({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'Icon_pen-write.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.contacts({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'Icon_contacts.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.close({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'Icon_close.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.search({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'Icon_search.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.right({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'Icon_right.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.mute({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'Icon_mute.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.userRemove({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'Icon_User_deselect.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.lightning({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'Icon_lightning-command runner.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.emptyCircleLeft({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'Icon_empty_circle_left.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.message({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'Icon_message.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.thread({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'Icon_Thread_Reply.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.reply({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'Icon_curve_line_left_up_big.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.edit({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'Icon_edit.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.download({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'Icon_download.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.cloudDownload({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'Icon_cloud_download.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.copy({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'Icon_copy.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.delete({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'Icon_delete.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.eye({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'Icon_eye-off.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.arrowRight({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'Icon_arrow_right.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.closeSmall({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'Icon_close_sml.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.iconCurveLineLeftUp({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'Icon_curve_line_left_up.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.iconMoon({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'icon_moon.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.iconShare({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'icon_SHARE.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.iconGrid({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'Icon_grid.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.iconSendMessage({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'Icon_send_message.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.iconMenuPoint({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'Icon_menu_point_v.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.iconSave({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'Icon_save.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.shareArrow({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'share_arrow.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.filetype7z({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'filetype_7z.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.filetypeCsv({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'filetype_CSV.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.filetypeDoc({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'filetype_DOC.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.filetypeDocx({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'filetype_DOCX.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.filetypeGeneric({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'filetype_Generic.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.filetypeHtml({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'filetype_html.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.filetypeMd({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'filetype_MD.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.filetypeOdt({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'filetype_ODT.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.filetypePdf({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'filetype_PDF.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.filetypePpt({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'filetype_PPT.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.filetypePptx({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'filetype_PPTX.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.filetypeRar({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'filetype_RAR.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.filetypeRtf({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'filetype_RTF.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.filetypeTar({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'filetype_TAR.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.filetypeTxt({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'filetype_TXT.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.filetypeXls({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'filetype_XLS.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.filetypeXlsx({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'filetype_XLSX.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.filetypeZip({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'filetype_ZIP.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.iconGroup({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'Icon_group.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.iconNotification({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'Icon_notification.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.iconUserDelete({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'Icon_user_delete.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.error({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'Icon_error.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.circleUp({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'Icon_circle_up.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.iconUserSettings({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'Icon_user_settings.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.giphyIcon({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'giphy_icon.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.imgur({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'imgur.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.volumeUp({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'volume-up.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.flag({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'flag.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.iconFlag({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'icon_flag.svg', + color: color, + width: size, + height: size, + ); + + /// [StreamSvgIcon] type + factory StreamSvgIcon.retry({ + double? size, + Color? color, + }) => + StreamSvgIcon( + assetName: 'icon_retry.svg', + color: color, + width: size, + height: size, + ); + + /// Name of icon asset + final String? assetName; + + /// Width of icon + final double? width; + + /// Height of icon + final double? height; + + /// Color of icon + final Color? color; @override Widget build(BuildContext context) { @@ -27,880 +913,4 @@ class StreamSvgIcon extends StatelessWidget { color: color, ); } - - factory StreamSvgIcon.settings({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'settings.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.down({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'Icon_down.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.attach({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'Icon_attach.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.smile({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'Icon_smile.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.mentions({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'mentions.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.record({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'Icon_record.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.camera({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'Icon_camera.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.files({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'files.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.pictures({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'pictures.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.left({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'Icon_left.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.user({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'Icon_user.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.userAdd({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'Icon_User_add.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.check({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'Icon_check.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.checkAll({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'Icon_check_all.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.checkSend({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'Icon_check_send.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.penWrite({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'Icon_pen-write.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.contacts({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'Icon_contacts.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.close({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'Icon_close.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.search({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'Icon_search.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.right({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'Icon_right.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.mute({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'Icon_mute.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.userRemove({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'Icon_User_deselect.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.lightning({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'Icon_lightning-command runner.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.emptyCircleLeft({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'Icon_empty_circle_left.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.message({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'Icon_message.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.thread({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'Icon_Thread_Reply.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.reply({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'Icon_curve_line_left_up_big.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.edit({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'Icon_edit.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.download({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'Icon_download.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.cloudDownload({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'Icon_cloud_download.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.copy({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'Icon_copy.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.delete({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'Icon_delete.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.eye({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'Icon_eye-off.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.arrowRight({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'Icon_arrow_right.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.closeSmall({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'Icon_close_sml.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.iconCurveLineLeftUp({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'Icon_curve_line_left_up.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.iconMoon({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'icon_moon.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.iconShare({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'icon_SHARE.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.iconGrid({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'Icon_grid.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.iconSendMessage({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'Icon_send_message.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.iconMenuPoint({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'Icon_menu_point_v.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.iconSave({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'Icon_save.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.shareArrow({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'share_arrow.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.filetype7z({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'filetype_7z.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.filetypeCsv({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'filetype_CSV.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.filetypeDoc({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'filetype_DOC.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.filetypeDocx({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'filetype_DOCX.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.filetypeGeneric({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'filetype_Generic.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.filetypeHtml({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'filetype_html.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.filetypeMd({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'filetype_MD.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.filetypeOdt({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'filetype_ODT.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.filetypePdf({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'filetype_PDF.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.filetypePpt({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'filetype_PPT.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.filetypePptx({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'filetype_PPTX.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.filetypeRar({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'filetype_RAR.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.filetypeRtf({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'filetype_RTF.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.filetypeTar({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'filetype_TAR.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.filetypeTxt({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'filetype_TXT.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.filetypeXls({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'filetype_XLS.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.filetypeXlsx({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'filetype_XLSX.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.filetypeZip({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'filetype_ZIP.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.iconGroup({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'Icon_group.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.iconNotification({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'Icon_notification.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.iconUserDelete({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'Icon_user_delete.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.error({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'Icon_error.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.circleUp({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'Icon_circle_up.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.iconUserSettings({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'Icon_user_settings.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.giphyIcon({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'giphy_icon.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.imgur({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'imgur.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.volumeUp({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'volume-up.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.flag({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'flag.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.iconFlag({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'icon_flag.svg', - color: color, - width: size, - height: size, - ); - } - - factory StreamSvgIcon.retry({ - double? size, - Color? color, - }) { - return StreamSvgIcon( - assetName: 'icon_retry.svg', - color: color, - width: size, - height: size, - ); - } } From 9d05cd20e02b3506f8e42e1409a47b57c30392c7 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 5 May 2021 17:23:30 +0530 Subject: [PATCH 19/31] lint --- .../lib/src/swipeable.dart | 109 +++++++------ .../lib/src/system_message.dart | 14 +- .../lib/src/thread_header.dart | 151 +++++++++--------- 3 files changed, 142 insertions(+), 132 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/swipeable.dart b/packages/stream_chat_flutter/lib/src/swipeable.dart index 3d195e4f..5895e8b5 100644 --- a/packages/stream_chat_flutter/lib/src/swipeable.dart +++ b/packages/stream_chat_flutter/lib/src/swipeable.dart @@ -1,27 +1,38 @@ import 'dart:math' as math; import 'package:flutter/material.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; -import 'stream_chat_theme.dart'; - -/// +/// Widget to make a swipeable tile class Swipeable extends StatefulWidget { - final Widget child; - final Widget backgroundIcon; - final VoidCallback? onSwipeStart; - final VoidCallback? onSwipeCancel; - final VoidCallback? onSwipeEnd; - final double threshold; - - /// + /// Constructor for creating a [Swipeable] widget const Swipeable({ + Key? key, required this.child, required this.backgroundIcon, this.onSwipeStart, this.onSwipeCancel, this.onSwipeEnd, this.threshold = 82.0, - }); + }) : super(key: key); + + /// Child to make swipeable + final Widget child; + + /// Background icon after swipe + final Widget backgroundIcon; + + /// Callback when swipe starts + final VoidCallback? onSwipeStart; + + /// Callback when swipe is cancelled + final VoidCallback? onSwipeCancel; + + /// Callback when swipe ends + final VoidCallback? onSwipeEnd; + + /// Threshold for swipe + final double threshold; @override State createState() => _SwipeableState(); @@ -45,10 +56,10 @@ class _SwipeableState extends State with TickerProviderStateMixin { AnimationController(duration: _animationDuration, vsync: this); _iconMoveController = AnimationController(duration: _animationDuration, vsync: this); - _moveAnimation = Tween(begin: Offset.zero, end: Offset(1, 0)) + _moveAnimation = Tween(begin: Offset.zero, end: const Offset(1, 0)) .animate(_moveController); _iconTransitionAnimation = - Tween(begin: Offset(-0.1, 0), end: Offset(0.4, 0)) + Tween(begin: const Offset(-0.1, 0), end: const Offset(0.4, 0)) .animate(_moveController); _iconFadeAnimation = Tween(begin: 0.7, end: 1).animate(_iconMoveController); @@ -120,44 +131,42 @@ class _SwipeableState extends State with TickerProviderStateMixin { } @override - Widget build(BuildContext context) { - return GestureDetector( - onHorizontalDragStart: _handleDragStart, - onHorizontalDragUpdate: _handleDragUpdate, - onHorizontalDragEnd: _handleDragEnd, - behavior: HitTestBehavior.opaque, - child: Stack( - alignment: Alignment.center, - fit: StackFit.passthrough, - children: [ - SlideTransition( - position: _iconTransitionAnimation, - child: Row( - children: [ - FadeTransition( - opacity: _iconFadeAnimation, - child: Container( - padding: const EdgeInsets.all(4), - decoration: BoxDecoration( - shape: BoxShape.circle, - border: Border.all( - color: StreamChatTheme.of(context) - .colorTheme - .greyGainsboro, + Widget build(BuildContext context) => GestureDetector( + onHorizontalDragStart: _handleDragStart, + onHorizontalDragUpdate: _handleDragUpdate, + onHorizontalDragEnd: _handleDragEnd, + behavior: HitTestBehavior.opaque, + child: Stack( + alignment: Alignment.center, + fit: StackFit.passthrough, + children: [ + SlideTransition( + position: _iconTransitionAnimation, + child: Row( + children: [ + FadeTransition( + opacity: _iconFadeAnimation, + child: Container( + padding: const EdgeInsets.all(4), + decoration: BoxDecoration( + shape: BoxShape.circle, + border: Border.all( + color: StreamChatTheme.of(context) + .colorTheme + .greyGainsboro, + ), ), + child: widget.backgroundIcon, ), - child: widget.backgroundIcon, ), - ), - ], + ], + ), ), - ), - SlideTransition( - position: _moveAnimation, - child: widget.child, - ), - ], - ), - ); - } + SlideTransition( + position: _moveAnimation, + child: widget.child, + ), + ], + ), + ); } diff --git a/packages/stream_chat_flutter/lib/src/system_message.dart b/packages/stream_chat_flutter/lib/src/system_message.dart index cdb9294f..b847eb3c 100644 --- a/packages/stream_chat_flutter/lib/src/system_message.dart +++ b/packages/stream_chat_flutter/lib/src/system_message.dart @@ -3,18 +3,20 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; /// It shows a date divider depending on the date difference class SystemMessage extends StatelessWidget { - /// This message - final Message message; - - /// The function called when tapping on the message when the message is not failed - final void Function(Message)? onMessageTap; - + /// Constructor for creating a [SystemMessage] const SystemMessage({ Key? key, required this.message, this.onMessageTap, }) : super(key: key); + /// This message + final Message message; + + // ignore: lines_longer_than_80_chars + /// The function called when tapping on the message when the message is not failed + final void Function(Message)? onMessageTap; + @override Widget build(BuildContext context) { final theme = StreamChatTheme.of(context); diff --git a/packages/stream_chat_flutter/lib/src/thread_header.dart b/packages/stream_chat_flutter/lib/src/thread_header.dart index 0157791e..ba94642f 100644 --- a/packages/stream_chat_flutter/lib/src/thread_header.dart +++ b/packages/stream_chat_flutter/lib/src/thread_header.dart @@ -3,9 +3,6 @@ import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; -import 'back_button.dart'; -import 'channel_name.dart'; - /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/thread_header.png) /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/thread_header_paint.png) /// @@ -46,16 +43,34 @@ import 'channel_name.dart'; /// Usually you would use this widget as an [AppBar] inside a [Scaffold]. /// However you can also use it as a normal widget. /// -/// Make sure to have a [StreamChannel] ancestor in order to provide the information about the channel. -/// Every part of the widget uses a [StreamBuilder] to render the channel information as soon as it updates. +/// Make sure to have a [StreamChannel] ancestor in order to provide the +/// information about the channel. +/// Every part of the widget uses a [StreamBuilder] to render the channel +/// information as soon as it updates. /// /// By default the widget shows a backButton that calls [Navigator.pop]. -/// You can disable this button using the [showBackButton] property of just override the behaviour +/// You can disable this button using the [showBackButton] property of just +/// override the behaviour /// with [onBackPressed]. /// -/// The widget components render the ui based on the first ancestor of type [StreamChatTheme] and on its [ChannelTheme.channelHeaderTheme] property. +/// The widget components render the ui based on the first ancestor of type +/// [StreamChatTheme] and on its [ChannelTheme.channelHeaderTheme] property. /// Modify it to change the widget appearance. class ThreadHeader extends StatelessWidget implements PreferredSizeWidget { + /// Instantiate a new ThreadHeader + const ThreadHeader({ + Key? key, + required this.parent, + this.showBackButton = true, + this.onBackPressed, + this.title, + this.subtitle, + this.leading, + this.actions, + this.onTitleTap, + }) : preferredSize = const Size.fromHeight(kToolbarHeight), + super(key: key); + /// True if this header shows the leading back button final bool showBackButton; @@ -81,82 +96,66 @@ class ThreadHeader extends StatelessWidget implements PreferredSizeWidget { /// AppBar actions final List? actions; - /// Instantiate a new ThreadHeader - ThreadHeader({ - Key? key, - required this.parent, - this.showBackButton = true, - this.onBackPressed, - this.title, - this.subtitle, - this.leading, - this.actions, - this.onTitleTap, - }) : preferredSize = Size.fromHeight(kToolbarHeight), - super(key: key); - @override - Widget build(BuildContext context) { - return AppBar( - automaticallyImplyLeading: false, - brightness: Theme.of(context).brightness, - elevation: 1, - leading: leading ?? - (showBackButton - ? StreamBackButton( - cid: StreamChannel.of(context).channel.cid, - onPressed: onBackPressed, - showUnreads: true, - ) - : SizedBox()), - backgroundColor: - StreamChatTheme.of(context).channelTheme.channelHeaderTheme.color, - centerTitle: true, - actions: actions, - title: InkWell( - onTap: onTitleTap, - child: Container( - height: preferredSize.height, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - title ?? - Text( - 'Thread Reply', - style: StreamChatTheme.of(context) - .channelTheme - .channelHeaderTheme - .title, - ), - SizedBox(height: 2), - subtitle ?? - Row( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - 'with ', - style: StreamChatTheme.of(context) - .channelTheme - .channelHeaderTheme - .subtitle, - ), - Flexible( - child: ChannelName( - textStyle: StreamChatTheme.of(context) + Widget build(BuildContext context) => AppBar( + automaticallyImplyLeading: false, + brightness: Theme.of(context).brightness, + elevation: 1, + leading: leading ?? + (showBackButton + ? StreamBackButton( + cid: StreamChannel.of(context).channel.cid, + onPressed: onBackPressed, + showUnreads: true, + ) + : const SizedBox()), + backgroundColor: + StreamChatTheme.of(context).channelTheme.channelHeaderTheme.color, + centerTitle: true, + actions: actions, + title: InkWell( + onTap: onTitleTap, + child: SizedBox( + height: preferredSize.height, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + title ?? + Text( + 'Thread Reply', + style: StreamChatTheme.of(context) + .channelTheme + .channelHeaderTheme + .title, + ), + const SizedBox(height: 2), + subtitle ?? + Row( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'with ', + style: StreamChatTheme.of(context) .channelTheme .channelHeaderTheme .subtitle, ), - ), - ], - ), - ], + Flexible( + child: ChannelName( + textStyle: StreamChatTheme.of(context) + .channelTheme + .channelHeaderTheme + .subtitle, + ), + ), + ], + ), + ], + ), ), ), - ), - ); - } + ); @override final Size preferredSize; From cca2e381034f2987bfd797663c298045f5f0976f Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 5 May 2021 17:23:38 +0530 Subject: [PATCH 20/31] lint --- .../lib/src/stream_neumorphic_button.dart | 41 +++++++++---------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/stream_neumorphic_button.dart b/packages/stream_chat_flutter/lib/src/stream_neumorphic_button.dart index 947e2265..5867a4a1 100644 --- a/packages/stream_chat_flutter/lib/src/stream_neumorphic_button.dart +++ b/packages/stream_chat_flutter/lib/src/stream_neumorphic_button.dart @@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; /// Neumorphic button class StreamNeumorphicButton extends StatelessWidget { - /// Constructor for creating [StreamNeumorphicButton] const StreamNeumorphicButton({ Key? key, @@ -18,24 +17,24 @@ class StreamNeumorphicButton extends StatelessWidget { @override Widget build(BuildContext context) => Container( - margin: const EdgeInsets.all(8), - height: 40, - width: 40, - decoration: BoxDecoration( - color: backgroundColor, - shape: BoxShape.circle, - boxShadow: [ - BoxShadow( - color: Colors.grey.shade700, - offset: const Offset(0, 1), - blurRadius: 0.5, - ), - const BoxShadow( - color: Colors.white, - blurRadius: 0.5, - ), - ], - ), - child: child, - ); + margin: const EdgeInsets.all(8), + height: 40, + width: 40, + decoration: BoxDecoration( + color: backgroundColor, + shape: BoxShape.circle, + boxShadow: [ + BoxShadow( + color: Colors.grey.shade700, + offset: const Offset(0, 1), + blurRadius: 0.5, + ), + const BoxShadow( + color: Colors.white, + blurRadius: 0.5, + ), + ], + ), + child: child, + ); } From 7b482fb5cd593f9c2d32ac7b0267e17157122579 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 5 May 2021 17:27:40 +0530 Subject: [PATCH 21/31] lint --- .../lib/src/typing_indicator.dart | 64 +++++++++---------- .../lib/src/unread_indicator.dart | 6 +- .../lib/src/upload_progress_indicator.dart | 32 +++++++--- 3 files changed, 58 insertions(+), 44 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/typing_indicator.dart b/packages/stream_chat_flutter/lib/src/typing_indicator.dart index aecc3bf1..e9377674 100644 --- a/packages/stream_chat_flutter/lib/src/typing_indicator.dart +++ b/packages/stream_chat_flutter/lib/src/typing_indicator.dart @@ -26,6 +26,7 @@ class TypingIndicator extends StatelessWidget { /// The padding of this widget final EdgeInsets padding; + /// Alignment of the typing indicator final Alignment alignment; @override @@ -35,41 +36,40 @@ class TypingIndicator extends StatelessWidget { return StreamBuilder>( initialData: channelState.typingEvents, stream: channelState.typingEventsStream, - builder: (context, snapshot) { - return AnimatedSwitcher( - duration: Duration(milliseconds: 300), - child: snapshot.data?.isNotEmpty == true - ? Padding( - padding: padding, - child: Align( - key: Key('typings'), - alignment: alignment, - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Lottie.asset( - 'animations/typing_dots.json', - package: 'stream_chat_flutter', - height: 4, - ), - Text( - ' ${snapshot.data![0].name}${snapshot.data!.length == 1 ? '' : ' and ${snapshot.data!.length - 1} more'} ${snapshot.data!.length == 1 ? 'is' : 'are'} typing', - maxLines: 1, - style: style, - ), - ], - ), - ), - ) - : Align( - key: Key('alternative'), + builder: (context, snapshot) => AnimatedSwitcher( + duration: const Duration(milliseconds: 300), + child: snapshot.data?.isNotEmpty == true + ? Padding( + padding: padding, + child: Align( + key: const Key('typings'), alignment: alignment, - child: Container( - child: alternativeWidget ?? Offstage(), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Lottie.asset( + 'animations/typing_dots.json', + package: 'stream_chat_flutter', + height: 4, + ), + Text( + // ignore: lines_longer_than_80_chars + ' ${snapshot.data![0].name}${snapshot.data!.length == 1 ? '' : ' and ${snapshot.data!.length - 1} more'} ${snapshot.data!.length == 1 ? 'is' : 'are'} typing', + maxLines: 1, + style: style, + ), + ], ), ), - ); - }, + ) + : Align( + key: const Key('alternative'), + alignment: alignment, + child: Container( + child: alternativeWidget ?? const Offstage(), + ), + ), + ), ); } } diff --git a/packages/stream_chat_flutter/lib/src/unread_indicator.dart b/packages/stream_chat_flutter/lib/src/unread_indicator.dart index 8d2c996a..9c3a5f88 100644 --- a/packages/stream_chat_flutter/lib/src/unread_indicator.dart +++ b/packages/stream_chat_flutter/lib/src/unread_indicator.dart @@ -2,7 +2,9 @@ import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; +/// Widget for showing an unread indicator class UnreadIndicator extends StatelessWidget { + /// Constructor for creating an [UnreadIndicator] const UnreadIndicator({ Key? key, this.cid, @@ -24,7 +26,7 @@ class UnreadIndicator extends StatelessWidget { : client.state.totalUnreadCount, builder: (context, snapshot) { if (!snapshot.hasData || snapshot.data == 0) { - return SizedBox(); + return const SizedBox(); } return Material( borderRadius: BorderRadius.circular(8), @@ -41,7 +43,7 @@ class UnreadIndicator extends StatelessWidget { child: Center( child: Text( '${snapshot.data! > 99 ? '99+' : snapshot.data}', - style: TextStyle( + style: const TextStyle( fontSize: 11, color: Colors.white, ), diff --git a/packages/stream_chat_flutter/lib/src/upload_progress_indicator.dart b/packages/stream_chat_flutter/lib/src/upload_progress_indicator.dart index 1175237e..9905141a 100644 --- a/packages/stream_chat_flutter/lib/src/upload_progress_indicator.dart +++ b/packages/stream_chat_flutter/lib/src/upload_progress_indicator.dart @@ -1,15 +1,9 @@ import 'package:flutter/material.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; -import 'stream_chat_theme.dart'; - +/// Widget for showing upload progress class UploadProgressIndicator extends StatelessWidget { - final int uploaded; - final int total; - final Color progressIndicatorColor; - final EdgeInsetsGeometry padding; - final bool showBackground; - final TextStyle? textStyle; - + /// Constructor for creating an [UploadProgressIndicator] const UploadProgressIndicator({ Key? key, required this.uploaded, @@ -25,6 +19,24 @@ class UploadProgressIndicator extends StatelessWidget { this.textStyle, }) : super(key: key); + /// Bytes uploaded + final int uploaded; + + /// Total bytes + final int total; + + /// Color of progress indicator + final Color progressIndicatorColor; + + /// Padding for widget + final EdgeInsetsGeometry padding; + + /// Flag for showing background + final bool showBackground; + + /// [TextStyle] to be applied to text + final TextStyle? textStyle; + @override Widget build(BuildContext context) { final theme = StreamChatTheme.of(context); @@ -42,7 +54,7 @@ class UploadProgressIndicator extends StatelessWidget { valueColor: AlwaysStoppedAnimation(progressIndicatorColor), ), ), - SizedBox(width: 8), + const SizedBox(width: 8), Text( '${_percentage.toInt()}%', style: textStyle ?? From 8a28f8c2b3851913917e7889ab26691b1fcccb14 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 5 May 2021 17:32:54 +0530 Subject: [PATCH 22/31] lint --- .../lib/src/url_attachment.dart | 179 +++++++++--------- .../lib/src/user_avatar.dart | 36 +++- .../lib/src/user_item.dart | 92 +++++---- 3 files changed, 167 insertions(+), 140 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/url_attachment.dart b/packages/stream_chat_flutter/lib/src/url_attachment.dart index e924746d..0b91c2ee 100644 --- a/packages/stream_chat_flutter/lib/src/url_attachment.dart +++ b/packages/stream_chat_flutter/lib/src/url_attachment.dart @@ -3,107 +3,114 @@ import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/src/utils.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; +/// Widget to display URL attachment class UrlAttachment extends StatelessWidget { - final Attachment urlAttachment; - final String hostDisplayName; - final EdgeInsets textPadding; - + /// Constructor for creating a [UrlAttachment] const UrlAttachment({ + Key? key, required this.urlAttachment, required this.hostDisplayName, this.textPadding = const EdgeInsets.symmetric( horizontal: 16, vertical: 8, ), - }); + }) : super(key: key); + + /// Attachment to be displayed + final Attachment urlAttachment; + + /// Host name + final String hostDisplayName; + + /// Padding for text + final EdgeInsets textPadding; @override - Widget build(BuildContext context) { - return GestureDetector( - onTap: () { - launchURL( - context, - urlAttachment.ogScrapeUrl, - ); - }, - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - if (urlAttachment.imageUrl != null) - Container( - clipBehavior: Clip.antiAliasWithSaveLayer, - margin: EdgeInsets.symmetric(horizontal: 8), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8), - ), - child: Stack( - children: [ - CachedNetworkImage( - width: double.infinity, - imageUrl: urlAttachment.imageUrl!, - fit: BoxFit.cover, - ), - Positioned( - left: 0, - bottom: -1, - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.only( - topRight: Radius.circular(16), + Widget build(BuildContext context) => GestureDetector( + onTap: () { + launchURL( + context, + urlAttachment.ogScrapeUrl, + ); + }, + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + if (urlAttachment.imageUrl != null) + Container( + clipBehavior: Clip.antiAliasWithSaveLayer, + margin: const EdgeInsets.symmetric(horizontal: 8), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + ), + child: Stack( + children: [ + CachedNetworkImage( + width: double.infinity, + imageUrl: urlAttachment.imageUrl!, + fit: BoxFit.cover, + ), + Positioned( + left: 0, + bottom: -1, + child: Container( + decoration: BoxDecoration( + borderRadius: const BorderRadius.only( + topRight: Radius.circular(16), + ), + color: + StreamChatTheme.of(context).colorTheme.blueAlice, ), - color: StreamChatTheme.of(context).colorTheme.blueAlice, - ), - child: Padding( - padding: const EdgeInsets.only( - top: 8, - left: 8, - right: 8, - ), - child: Text( - hostDisplayName, - style: StreamChatTheme.of(context) - .textTheme - .bodyBold - .copyWith( - color: StreamChatTheme.of(context) - .colorTheme - .accentBlue, - ), + child: Padding( + padding: const EdgeInsets.only( + top: 8, + left: 8, + right: 8, + ), + child: Text( + hostDisplayName, + style: StreamChatTheme.of(context) + .textTheme + .bodyBold + .copyWith( + color: StreamChatTheme.of(context) + .colorTheme + .accentBlue, + ), + ), ), ), ), - ), + ], + ), + ), + Padding( + padding: textPadding, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (urlAttachment.title != null) + Text( + urlAttachment.title!.trim(), + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: StreamChatTheme.of(context) + .textTheme + .body + .copyWith(fontWeight: FontWeight.w700), + ), + if (urlAttachment.text != null) + Text( + urlAttachment.text!, + style: StreamChatTheme.of(context) + .textTheme + .body + .copyWith(fontWeight: FontWeight.w400), + ), ], ), ), - Padding( - padding: textPadding, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - if (urlAttachment.title != null) - Text( - urlAttachment.title!.trim(), - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: StreamChatTheme.of(context) - .textTheme - .body - .copyWith(fontWeight: FontWeight.w700), - ), - if (urlAttachment.text != null) - Text( - urlAttachment.text!, - style: StreamChatTheme.of(context) - .textTheme - .body - .copyWith(fontWeight: FontWeight.w400), - ), - ], - ), - ), - ], - ), - ); - } + ], + ), + ); } diff --git a/packages/stream_chat_flutter/lib/src/user_avatar.dart b/packages/stream_chat_flutter/lib/src/user_avatar.dart index 0833b1a3..cb968527 100644 --- a/packages/stream_chat_flutter/lib/src/user_avatar.dart +++ b/packages/stream_chat_flutter/lib/src/user_avatar.dart @@ -1,10 +1,11 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; -import '../stream_chat_flutter.dart'; - +/// Widget that displays a user avatar class UserAvatar extends StatelessWidget { + /// Constructor to create a [UserAvatar] const UserAvatar({ Key? key, required this.user, @@ -20,16 +21,37 @@ class UserAvatar extends StatelessWidget { this.selectionThickness = 4, }) : super(key: key); + /// User whose avatar is to displayed final User user; + + /// Alignment of the online indicator final Alignment onlineIndicatorAlignment; + + /// Size of the avatar final BoxConstraints? constraints; + + /// [BorderRadius] of the image final BorderRadius? borderRadius; + + /// Size of the online indicator final BoxConstraints? onlineIndicatorConstraints; + + /// Callback when avatar is tapped final void Function(User)? onTap; + + /// Callback when avatar is long pressed final void Function(User)? onLongPress; + + /// Flag for showing online status final bool showOnlineStatus; + + /// Flag for if avatar is selected final bool selected; + + /// Color of selection final Color? selectionColor; + + /// Selection thickness around the avatar final double selectionThickness; @override @@ -53,10 +75,10 @@ class UserAvatar extends StatelessWidget { child: hasImage ? CachedNetworkImage( filterQuality: FilterQuality.high, + // ignore: cast_nullable_to_non_nullable imageUrl: user.extraData['image'] as String, - errorWidget: (_, __, ___) { - return streamChatTheme.defaultUserImage(context, user); - }, + errorWidget: (_, __, ___) => + streamChatTheme.defaultUserImage(context, user), fit: BoxFit.cover, ) : streamChatTheme.defaultUserImage(context, user), @@ -98,12 +120,12 @@ class UserAvatar extends StatelessWidget { child: Container( margin: const EdgeInsets.all(2), constraints: onlineIndicatorConstraints ?? - BoxConstraints.tightFor( + const BoxConstraints.tightFor( width: 8, height: 8, ), child: Material( - shape: CircleBorder(), + shape: const CircleBorder(), color: streamChatTheme.colorTheme.accentGreen, ), ), diff --git a/packages/stream_chat_flutter/lib/src/user_item.dart b/packages/stream_chat_flutter/lib/src/user_item.dart index ff51fea3..290612e1 100644 --- a/packages/stream_chat_flutter/lib/src/user_item.dart +++ b/packages/stream_chat_flutter/lib/src/user_item.dart @@ -5,16 +5,17 @@ import 'package:stream_chat_flutter/src/user_list_view.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; -import 'stream_chat_theme.dart'; - /// /// It shows the current [User] preview. /// -/// The widget uses a [StreamBuilder] to render the user information image as soon as it updates. +/// The widget uses a [StreamBuilder] to render the user information +/// image as soon as it updates. /// -/// Usually you don't use this widget as it's the default user preview used by [UserListView]. +/// Usually you don't use this widget as it's the default user preview used +/// by [UserListView]. /// -/// The widget renders the ui based on the first ancestor of type [StreamChatTheme]. +/// The widget renders the ui based on the first ancestor of type +/// [StreamChatTheme]. /// Modify it to change the widget appearance. class UserItem extends StatelessWidget { /// Instantiate a new UserItem @@ -47,50 +48,47 @@ class UserItem extends StatelessWidget { final bool showLastOnline; @override - Widget build(BuildContext context) { - return ListTile( - onTap: () { - if (onTap != null) { - onTap!(user); - } - }, - onLongPress: () { - if (onLongPress != null) { - onLongPress!(user); - } - }, - leading: UserAvatar( - user: user, - onTap: (user) { - if (onImageTap != null) { - onImageTap!(user); + Widget build(BuildContext context) => ListTile( + onTap: () { + if (onTap != null) { + onTap!(user); } }, - constraints: BoxConstraints.tightFor( - height: 40, - width: 40, + onLongPress: () { + if (onLongPress != null) { + onLongPress!(user); + } + }, + leading: UserAvatar( + user: user, + onTap: (user) { + if (onImageTap != null) { + onImageTap!(user); + } + }, + constraints: const BoxConstraints.tightFor( + height: 40, + width: 40, + ), ), - ), - trailing: selected - ? StreamSvgIcon.checkSend( - color: StreamChatTheme.of(context).colorTheme.accentBlue, - ) - : null, - title: Text( - user.name, - style: StreamChatTheme.of(context).textTheme.bodyBold, - ), - subtitle: showLastOnline ? _buildLastActive(context) : null, - ); - } + trailing: selected + ? StreamSvgIcon.checkSend( + color: StreamChatTheme.of(context).colorTheme.accentBlue, + ) + : null, + title: Text( + user.name, + style: StreamChatTheme.of(context).textTheme.bodyBold, + ), + subtitle: showLastOnline ? _buildLastActive(context) : null, + ); - Widget _buildLastActive(context) { - return Text( - user.online == true - ? 'Online' - : 'Last online ${Jiffy(user.lastActive).fromNow()}', - style: StreamChatTheme.of(context).textTheme.footnote.copyWith( - color: StreamChatTheme.of(context).colorTheme.black.withOpacity(.5)), - ); - } + Widget _buildLastActive(context) => Text( + user.online == true + ? 'Online' + : 'Last online ${Jiffy(user.lastActive).fromNow()}', + style: StreamChatTheme.of(context).textTheme.footnote.copyWith( + color: + StreamChatTheme.of(context).colorTheme.black.withOpacity(.5)), + ); } From dca6b10c41a52e5eb357bce8ee39e9ae32215c4d Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 5 May 2021 17:35:41 +0530 Subject: [PATCH 23/31] lint --- .../lib/src/user_list_view.dart | 189 ++++++++---------- 1 file changed, 88 insertions(+), 101 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/user_list_view.dart b/packages/stream_chat_flutter/lib/src/user_list_view.dart index f1053e58..0c835fbe 100644 --- a/packages/stream_chat_flutter/lib/src/user_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/user_list_view.dart @@ -36,10 +36,13 @@ typedef UserItemBuilder = Widget Function(BuildContext, User, bool); /// ``` /// /// -/// Make sure to have a [UsersBloc] ancestor in order to provide the information about the users. -/// The widget uses a [ListView.separated], [GridView.builder] to render the list, grid of channels. +/// Make sure to have a [UsersBloc] ancestor in order to provide the +/// information about the users. +/// The widget uses a [ListView.separated], [GridView.builder] to render the +/// list, grid of channels. /// -/// The widget components render the ui based on the first ancestor of type [StreamChatTheme]. +/// The widget components render the ui based on the first ancestor of +/// type [StreamChatTheme]. /// Modify it to change the widget appearance. class UserListView extends StatefulWidget { /// Instantiate a new UserListView @@ -81,8 +84,10 @@ class UserListView extends StatefulWidget { final Map? options; /// The sorting used for the channels matching the filters. - /// Sorting is based on field and direction, multiple sorting options can be provided. - /// You can sort based on last_updated, last_message_at, updated_at, created_at or member_count. + /// Sorting is based on field and direction, multiple sorting options can + /// be provided. + /// You can sort based on last_updated, last_message_at, updated_at, created_ + /// at or member_count. /// Direction can be ascending or descending. final List? sort; @@ -115,7 +120,8 @@ class UserListView extends StatefulWidget { /// Set it to false to disable the pull-to-refresh widget final bool pullToRefresh; - /// Sets a blue trailing checkMark in [ListUserItem] for all the [selectedUsers] + /// Sets a blue trailing checkMark in [ListUserItem] for all the + /// [selectedUsers] final Set? selectedUsers; /// Set it to true to group users by their first character @@ -153,35 +159,25 @@ class _UserListViewState extends State Widget build(BuildContext context) { final child = UserListCore( errorBuilder: widget.errorBuilder as Widget Function(Object)? ?? - (err) { - return _buildError(err as Error); - }, - emptyBuilder: widget.emptyBuilder ?? - (context) { - return _buildEmpty(); - }, + (err) => _buildError(err as Error), + emptyBuilder: widget.emptyBuilder ?? (context) => _buildEmpty(), loadingBuilder: widget.loadingBuilder ?? - (context) { - return LayoutBuilder( - builder: (context, viewportConstraints) { - return SingleChildScrollView( - physics: AlwaysScrollableScrollPhysics(), + (context) => LayoutBuilder( + builder: (context, viewportConstraints) => + SingleChildScrollView( + physics: const AlwaysScrollableScrollPhysics(), child: ConstrainedBox( constraints: BoxConstraints( minHeight: viewportConstraints.maxHeight, ), - child: Center( + child: const Center( child: CircularProgressIndicator(), ), ), - ); - }, - ); - }, - listBuilder: widget.listBuilder ?? - (context, list) { - return _buildListView(list); - }, + ), + ), + listBuilder: + widget.listBuilder ?? (context, list) => _buildListView(list), pagination: widget.pagination, options: widget.options, sort: widget.sort, @@ -204,7 +200,7 @@ class _UserListViewState extends State widget.sort?.any((e) => e.field == 'name' && e.direction == 1) ?? false; Widget _buildError(Error error) { - print((error).stackTrace); + print(error.stackTrace); var message = error.toString(); if (error is DioError) { @@ -220,11 +216,11 @@ class _UserListViewState extends State mainAxisAlignment: MainAxisAlignment.center, children: [ Text.rich( - TextSpan( + const TextSpan( children: [ WidgetSpan( child: Padding( - padding: const EdgeInsets.only( + padding: EdgeInsets.only( right: 2, ), child: Icon(Icons.error_outline), @@ -243,37 +239,33 @@ class _UserListViewState extends State ), TextButton( onPressed: () => _userListController.loadData!(), - child: Text('Retry'), + child: const Text('Retry'), ), ], ), ); } - Widget _buildEmpty() { - return LayoutBuilder( - builder: (context, viewportConstraints) { - return SingleChildScrollView( - physics: AlwaysScrollableScrollPhysics(), + Widget _buildEmpty() => LayoutBuilder( + builder: (context, viewportConstraints) => SingleChildScrollView( + physics: const AlwaysScrollableScrollPhysics(), child: ConstrainedBox( constraints: BoxConstraints( minHeight: viewportConstraints.maxHeight, ), - child: Center( + child: const Center( child: Text('There are no users currently'), ), ), - ); - }, - ); - } + ), + ); Widget _buildListView( List items, ) { final child = _isListView ? ListView.separated( - physics: AlwaysScrollableScrollPhysics(), + physics: const AlwaysScrollableScrollPhysics(), itemCount: items.isNotEmpty ? items.length + 1 : items.length, separatorBuilder: (_, index) { if (widget.separatorBuilder != null) { @@ -281,19 +273,17 @@ class _UserListViewState extends State } return _separatorBuilder(context, index); }, - itemBuilder: (context, index) { - return _listItemBuilder(context, index, items); - }, + itemBuilder: (context, index) => + _listItemBuilder(context, index, items), ) : GridView.builder( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: widget.crossAxisCount, ), itemCount: items.isNotEmpty ? items.length + 1 : items.length, - physics: AlwaysScrollableScrollPhysics(), - itemBuilder: (context, index) { - return _gridItemBuilder(context, index, items); - }, + physics: const AlwaysScrollableScrollPhysics(), + itemBuilder: (context, index) => + _gridItemBuilder(context, index, items), ); return LazyLoadScrollView( @@ -307,24 +297,21 @@ class _UserListViewState extends State if (i < items.length) { final item = items[i]; return item.when( - headerItem: (header) { - return Container( - key: ValueKey('HEADER-$header'), - color: - StreamChatTheme.of(context).colorTheme.black.withOpacity(0.05), - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 6), - child: Text( - header, - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 14.5, - color: StreamChatTheme.of(context).colorTheme.grey, - ), + headerItem: (header) => Container( + key: ValueKey('HEADER-$header'), + color: StreamChatTheme.of(context).colorTheme.black.withOpacity(0.05), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 6), + child: Text( + header, + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 14.5, + color: StreamChatTheme.of(context).colorTheme.grey, ), ), - ); - }, + ), + ), userItem: (user) { final selected = widget.selectedUsers?.contains(user) ?? false; return Container( @@ -351,7 +338,7 @@ class _UserListViewState extends State if (i < items.length) { final item = items[i]; return item.when( - headerItem: (_) => Offstage(), + headerItem: (_) => const Offstage(), userItem: (user) { final selected = widget.selectedUsers?.contains(user) ?? false; return Container( @@ -365,11 +352,12 @@ class _UserListViewState extends State user: user, borderRadius: BorderRadius.circular(32), selected: selected, - constraints: BoxConstraints.tightFor( + constraints: const BoxConstraints.tightFor( height: 64, width: 64, ), - onlineIndicatorConstraints: BoxConstraints.tightFor( + onlineIndicatorConstraints: + const BoxConstraints.tightFor( height: 12, width: 12, ), @@ -377,7 +365,7 @@ class _UserListViewState extends State widget.onUserTap!(user, widget.userWidget), onLongPress: widget.onUserLongPress, ), - SizedBox(height: 4), + const SizedBox(height: 4), Padding( padding: const EdgeInsets.symmetric(horizontal: 8), child: Text( @@ -385,7 +373,7 @@ class _UserListViewState extends State textAlign: TextAlign.center, maxLines: 2, overflow: TextOverflow.ellipsis, - style: TextStyle( + style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 12, ), @@ -401,39 +389,38 @@ class _UserListViewState extends State } } - Widget _buildQueryProgressIndicator(context, UsersBlocState usersProvider) { - return StreamBuilder( - stream: usersProvider.queryUsersLoading, - initialData: false, - builder: (context, snapshot) { - if (snapshot.hasError) { - return Container( - color: StreamChatTheme.of(context) - .colorTheme - .accentRed - .withOpacity(.2), - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 16), - child: Center( - child: Text('Error loading users'), + Widget _buildQueryProgressIndicator(context, UsersBlocState usersProvider) => + StreamBuilder( + stream: usersProvider.queryUsersLoading, + initialData: false, + builder: (context, snapshot) { + if (snapshot.hasError) { + return Container( + color: StreamChatTheme.of(context) + .colorTheme + .accentRed + .withOpacity(.2), + child: const Padding( + padding: EdgeInsets.symmetric(vertical: 16), + child: Center( + child: Text('Error loading users'), + ), ), + ); + } + return Container( + height: 100, + padding: const EdgeInsets.all(32), + child: Center( + child: snapshot.data! + ? const CircularProgressIndicator() + : Container(), ), ); - } - return Container( - height: 100, - padding: EdgeInsets.all(32), - child: Center( - child: snapshot.data! ? CircularProgressIndicator() : Container(), - ), - ); - }); - } + }); - Widget _separatorBuilder(context, i) { - return Container( - height: 1, - color: StreamChatTheme.of(context).colorTheme.greyWhisper, - ); - } + Widget _separatorBuilder(context, i) => Container( + height: 1, + color: StreamChatTheme.of(context).colorTheme.greyWhisper, + ); } From 09c6799af84dcf4760843adccd0db5221280f146 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 5 May 2021 17:47:58 +0530 Subject: [PATCH 24/31] lint --- .../lib/src/user_reaction_display.dart | 17 ++++--- .../stream_chat_flutter/lib/src/utils.dart | 45 ++++++++--------- .../lib/src/video_service.dart | 48 ++++++++++--------- .../lib/src/video_thumbnail_image.dart | 40 +++++++++------- 4 files changed, 81 insertions(+), 69 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/user_reaction_display.dart b/packages/stream_chat_flutter/lib/src/user_reaction_display.dart index fe61caad..23c723dd 100644 --- a/packages/stream_chat_flutter/lib/src/user_reaction_display.dart +++ b/packages/stream_chat_flutter/lib/src/user_reaction_display.dart @@ -2,7 +2,10 @@ import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/src/user_avatar.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; +/// Displays a list of users who reacted class UserReactionDisplay extends StatelessWidget { + + /// Constructor for creating a [UserReactionDisplay] const UserReactionDisplay({ Key? key, required this.reactionToEmoji, @@ -10,13 +13,17 @@ class UserReactionDisplay extends StatelessWidget { this.size = 30, }) : super(key: key); + /// Reaction map final Map reactionToEmoji; + + /// Message which is reacted to final Message message; + + /// Size of Icon final double size; @override - Widget build(BuildContext context) { - return Container( + Widget build(BuildContext context) => Container( color: Colors.black87, child: Row( crossAxisAlignment: CrossAxisAlignment.start, @@ -25,9 +32,8 @@ class UserReactionDisplay extends StatelessWidget { children: reactionToEmoji.keys.map((reactionType) { final firstUserReaction = message.latestReactions! .firstWhere((element) => element.type == reactionType, - orElse: () { - return null; - } as Reaction Function()?); + //ignore: unnecessary_parenthesis + orElse: (() => null) as Reaction Function()?); if (firstUserReaction.user == null) { return IconButton( @@ -52,5 +58,4 @@ class UserReactionDisplay extends StatelessWidget { }).toList(), ), ); - } } diff --git a/packages/stream_chat_flutter/lib/src/utils.dart b/packages/stream_chat_flutter/lib/src/utils.dart index 4233dd2f..11a1f3c0 100644 --- a/packages/stream_chat_flutter/lib/src/utils.dart +++ b/packages/stream_chat_flutter/lib/src/utils.dart @@ -13,7 +13,7 @@ Future launchURL(BuildContext context, String? url) async { } else { // ignore: deprecated_member_use Scaffold.of(context).showSnackBar( - SnackBar( + const SnackBar( content: Text('Cannot launch the url'), ), ); @@ -27,11 +27,10 @@ Future showConfirmationDialog( Widget? icon, String? question, String? cancelText, -}) { - return showModalBottomSheet( +}) => showModalBottomSheet( backgroundColor: StreamChatTheme.of(context).colorTheme.white, context: context, - shape: RoundedRectangleBorder( + shape: const RoundedRectangleBorder( borderRadius: BorderRadius.only( topLeft: Radius.circular(16), topRight: Radius.circular(16), @@ -42,20 +41,20 @@ Future showConfirmationDialog( child: Column( mainAxisSize: MainAxisSize.min, children: [ - SizedBox(height: 26), + const SizedBox(height: 26), if (icon != null) icon, - SizedBox(height: 26), + const SizedBox(height: 26), Text( title, style: StreamChatTheme.of(context).textTheme.headlineBold, ), - SizedBox(height: 7), + const SizedBox(height: 7), if (question != null) Text( question, textAlign: TextAlign.center, ), - SizedBox(height: 36), + const SizedBox(height: 36), Container( color: effect.color!.withOpacity(effect.alpha ?? 1), height: 1, @@ -110,8 +109,8 @@ Future showConfirmationDialog( ), ); }); -} +/// Shows info dialog Future showInfoDialog( BuildContext context, { required String title, @@ -119,26 +118,24 @@ Future showInfoDialog( Widget? icon, String? details, StreamChatThemeData? theme, -}) { - return showModalBottomSheet( +}) => showModalBottomSheet( backgroundColor: theme?.colorTheme.white ?? StreamChatTheme.of(context).colorTheme.white, context: context, - shape: RoundedRectangleBorder( + shape: const RoundedRectangleBorder( borderRadius: BorderRadius.only( topLeft: Radius.circular(16), topRight: Radius.circular(16), )), - builder: (context) { - return SafeArea( + builder: (context) => SafeArea( child: Column( mainAxisSize: MainAxisSize.min, children: [ - SizedBox( + const SizedBox( height: 26, ), if (icon != null) icon, - SizedBox( + const SizedBox( height: 26, ), Text( @@ -146,11 +143,11 @@ Future showInfoDialog( style: theme?.textTheme.headlineBold ?? StreamChatTheme.of(context).textTheme.headlineBold, ), - SizedBox( + const SizedBox( height: 7, ), if (details != null) Text(details), - SizedBox( + const SizedBox( height: 36, ), Container( @@ -175,10 +172,8 @@ Future showInfoDialog( ), ], ), - ); - }, + ), ); -} /// Get random png with initials String getRandomPicUrl(User user) => @@ -335,15 +330,16 @@ StreamSvgIcon getFileTypeImage(String? type) { } } +/// Wraps attachment widget with custom shape Widget wrapAttachmentWidget( BuildContext context, Widget attachmentWidget, ShapeBorder attachmentShape, + // ignore: avoid_positional_boolean_parameters bool reverse, BorderRadius borderRadius, -) { - return ClipRRect( - borderRadius: borderRadius, +) => ClipRRect( + borderRadius: borderRadius, child: Material( clipBehavior: Clip.antiAlias, shape: attachmentShape, @@ -355,4 +351,3 @@ Widget wrapAttachmentWidget( ), ), ); -} diff --git a/packages/stream_chat_flutter/lib/src/video_service.dart b/packages/stream_chat_flutter/lib/src/video_service.dart index a4d0d1ff..3b6bb13e 100644 --- a/packages/stream_chat_flutter/lib/src/video_service.dart +++ b/packages/stream_chat_flutter/lib/src/video_service.dart @@ -5,12 +5,14 @@ import 'package:synchronized/synchronized.dart'; import 'package:video_compress/video_compress.dart'; import 'package:video_thumbnail/video_thumbnail.dart'; +/// class IVideoService { + IVideoService._(); + + /// Singleton instance of [IVideoService] static final IVideoService instance = IVideoService._(); final _lock = Lock(); - IVideoService._(); - /// compress video from [path] /// compress video from [path] return [Future] /// @@ -26,18 +28,20 @@ class IVideoService { /// ); /// debugPrint(info.toJson()); /// ``` - Future compressVideo(String? path) async { - return _lock.synchronized(() { - return VideoCompress.compressVideo( - path!, + Future compressVideo(String? path) async => _lock.synchronized( + () => VideoCompress.compressVideo( + path!, + ), ); - }); - } - /// Generates a thumbnail image data in memory as UInt8List, it can be easily used by Image.memory(...). - /// The video can be a local video file, or an URL repreents iOS or Android native supported video format. - /// Speicify the maximum height or width for the thumbnail or 0 for same resolution as the original video. - /// The lower quality value creates lower quality of the thumbnail image, but it gets ignored for PNG format. + /// Generates a thumbnail image data in memory as UInt8List, + /// it can be easily used by Image.memory(...). + /// The video can be a local video file, or an URL repreents iOS or + /// Android native supported video format. + /// Speicify the maximum height or width for the thumbnail or 0 for + /// same resolution as the original video. + /// The lower quality value creates lower quality of the thumbnail image, + /// but it gets ignored for PNG format. Future generateVideoThumbnail({ required String video, ImageFormat imageFormat = ImageFormat.PNG, @@ -45,17 +49,17 @@ class IVideoService { int maxWidth = 0, int timeMs = 0, int quality = 10, - }) { - return VideoThumbnail.thumbnailData( - video: video, - imageFormat: imageFormat, - maxHeight: maxHeight, - maxWidth: maxWidth, - timeMs: timeMs, - quality: quality, - ); - } + }) => + VideoThumbnail.thumbnailData( + video: video, + imageFormat: imageFormat, + maxHeight: maxHeight, + maxWidth: maxWidth, + timeMs: timeMs, + quality: quality, + ); } // ignore: non_constant_identifier_names +/// Get instance of [IVideoService] IVideoService get VideoService => IVideoService.instance; diff --git a/packages/stream_chat_flutter/lib/src/video_thumbnail_image.dart b/packages/stream_chat_flutter/lib/src/video_thumbnail_image.dart index 3d9d5429..cd321ca2 100644 --- a/packages/stream_chat_flutter/lib/src/video_thumbnail_image.dart +++ b/packages/stream_chat_flutter/lib/src/video_thumbnail_image.dart @@ -9,14 +9,7 @@ import 'stream_svg_icon.dart'; import 'video_service.dart'; class VideoThumbnailImage extends StatefulWidget { - final String video; - final double? width; - final double? height; - final BoxFit? fit; - final ImageFormat format; - final Widget Function(BuildContext, Object?)? errorBuilder; - final WidgetBuilder? placeholderBuilder; - + /// Constructor for creating [VideoThumbnailImage] const VideoThumbnailImage({ Key? key, required this.video, @@ -28,6 +21,25 @@ class VideoThumbnailImage extends StatefulWidget { this.placeholderBuilder, }) : super(key: key); + /// Video path + final String video; + + /// Width of widget + final double? width; + + /// Height of widget + final double? height; + + /// Fit of iamge + final BoxFit? fit; + + /// Image format + final ImageFormat format; + + /// Builds widget on error + final Widget Function(BuildContext, Object?)? errorBuilder; + final WidgetBuilder? placeholderBuilder; + @override _VideoThumbnailImageState createState() => _VideoThumbnailImageState(); } @@ -56,11 +68,9 @@ class _VideoThumbnailImageState extends State { } @override - Widget build(BuildContext context) { - return FutureBuilder( + Widget build(BuildContext context) => FutureBuilder( future: thumbnailFuture, - builder: (context, snapshot) { - return AnimatedSwitcher( + builder: (context, snapshot) => AnimatedSwitcher( duration: const Duration(milliseconds: 350), child: Builder( key: ValueKey>(snapshot), @@ -73,7 +83,7 @@ class _VideoThumbnailImageState extends State { } if (!snapshot.hasData) { return Container( - constraints: BoxConstraints.expand(), + constraints: const BoxConstraints.expand(), child: widget.placeholderBuilder?.call(context) ?? Shimmer.fromColors( baseColor: StreamChatTheme.of(context) @@ -97,8 +107,6 @@ class _VideoThumbnailImageState extends State { ); }, ), - ); - }, + ), ); - } } From ad86cf0cd698d2be4a990ddf34cb782b2b34d5f8 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 5 May 2021 17:49:49 +0530 Subject: [PATCH 25/31] lint --- .../lib/src/user_reaction_display.dart | 61 +++--- .../stream_chat_flutter/lib/src/utils.dart | 175 +++++++++--------- .../lib/src/video_thumbnail_image.dart | 13 +- 3 files changed, 126 insertions(+), 123 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/user_reaction_display.dart b/packages/stream_chat_flutter/lib/src/user_reaction_display.dart index 23c723dd..b5ef623e 100644 --- a/packages/stream_chat_flutter/lib/src/user_reaction_display.dart +++ b/packages/stream_chat_flutter/lib/src/user_reaction_display.dart @@ -4,7 +4,6 @@ import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; /// Displays a list of users who reacted class UserReactionDisplay extends StatelessWidget { - /// Constructor for creating a [UserReactionDisplay] const UserReactionDisplay({ Key? key, @@ -24,38 +23,38 @@ class UserReactionDisplay extends StatelessWidget { @override Widget build(BuildContext context) => Container( - color: Colors.black87, - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.center, - mainAxisSize: MainAxisSize.min, - children: reactionToEmoji.keys.map((reactionType) { - final firstUserReaction = message.latestReactions! - .firstWhere((element) => element.type == reactionType, - //ignore: unnecessary_parenthesis - orElse: (() => null) as Reaction Function()?); + color: Colors.black87, + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: reactionToEmoji.keys.map((reactionType) { + final firstUserReaction = message.latestReactions! + .firstWhere((element) => element.type == reactionType, + //ignore: unnecessary_parenthesis + orElse: (() => null) as Reaction Function()?); + + if (firstUserReaction.user == null) { + return IconButton( + iconSize: size, + icon: Container(), + onPressed: null, + ); + } - if (firstUserReaction.user == null) { return IconButton( iconSize: size, - icon: Container(), - onPressed: null, - ); - } - - return IconButton( - iconSize: size, - icon: UserAvatar( - user: firstUserReaction.user!, - constraints: BoxConstraints( - maxHeight: size - 5, - maxWidth: size - 5, + icon: UserAvatar( + user: firstUserReaction.user!, + constraints: BoxConstraints( + maxHeight: size - 5, + maxWidth: size - 5, + ), + onTap: (user) {}, ), - onTap: (user) {}, - ), - onPressed: () {}, - ); - }).toList(), - ), - ); + onPressed: () {}, + ); + }).toList(), + ), + ); } diff --git a/packages/stream_chat_flutter/lib/src/utils.dart b/packages/stream_chat_flutter/lib/src/utils.dart index 11a1f3c0..8f493cec 100644 --- a/packages/stream_chat_flutter/lib/src/utils.dart +++ b/packages/stream_chat_flutter/lib/src/utils.dart @@ -27,88 +27,89 @@ Future showConfirmationDialog( Widget? icon, String? question, String? cancelText, -}) => showModalBottomSheet( - backgroundColor: StreamChatTheme.of(context).colorTheme.white, - context: context, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.only( - topLeft: Radius.circular(16), - topRight: Radius.circular(16), - )), - builder: (context) { - final effect = StreamChatTheme.of(context).colorTheme.borderTop; - return SafeArea( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - const SizedBox(height: 26), - if (icon != null) icon, - const SizedBox(height: 26), - Text( - title, - style: StreamChatTheme.of(context).textTheme.headlineBold, - ), - const SizedBox(height: 7), - if (question != null) +}) => + showModalBottomSheet( + backgroundColor: StreamChatTheme.of(context).colorTheme.white, + context: context, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(16), + topRight: Radius.circular(16), + )), + builder: (context) { + final effect = StreamChatTheme.of(context).colorTheme.borderTop; + return SafeArea( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const SizedBox(height: 26), + if (icon != null) icon, + const SizedBox(height: 26), Text( - question, - textAlign: TextAlign.center, + title, + style: StreamChatTheme.of(context).textTheme.headlineBold, ), - const SizedBox(height: 36), - Container( - color: effect.color!.withOpacity(effect.alpha ?? 1), - height: 1, - ), - Row( - children: [ - if (cancelText != null) + const SizedBox(height: 7), + if (question != null) + Text( + question, + textAlign: TextAlign.center, + ), + const SizedBox(height: 36), + Container( + color: effect.color!.withOpacity(effect.alpha ?? 1), + height: 1, + ), + Row( + children: [ + if (cancelText != null) + Flexible( + child: Container( + alignment: Alignment.center, + child: TextButton( + onPressed: () { + Navigator.of(context).pop(false); + }, + child: Text( + cancelText, + style: StreamChatTheme.of(context) + .textTheme + .bodyBold + .copyWith( + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5)), + ), + ), + ), + ), Flexible( child: Container( alignment: Alignment.center, child: TextButton( onPressed: () { - Navigator.of(context).pop(false); + Navigator.pop(context, true); }, child: Text( - cancelText, + okText, style: StreamChatTheme.of(context) .textTheme .bodyBold .copyWith( color: StreamChatTheme.of(context) .colorTheme - .black - .withOpacity(0.5)), + .accentRed), ), ), ), ), - Flexible( - child: Container( - alignment: Alignment.center, - child: TextButton( - onPressed: () { - Navigator.pop(context, true); - }, - child: Text( - okText, - style: StreamChatTheme.of(context) - .textTheme - .bodyBold - .copyWith( - color: StreamChatTheme.of(context) - .colorTheme - .accentRed), - ), - ), - ), - ), - ], - ), - ], - ), - ); - }); + ], + ), + ], + ), + ); + }); /// Shows info dialog Future showInfoDialog( @@ -118,16 +119,17 @@ Future showInfoDialog( Widget? icon, String? details, StreamChatThemeData? theme, -}) => showModalBottomSheet( - backgroundColor: - theme?.colorTheme.white ?? StreamChatTheme.of(context).colorTheme.white, - context: context, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.only( - topLeft: Radius.circular(16), - topRight: Radius.circular(16), - )), - builder: (context) => SafeArea( +}) => + showModalBottomSheet( + backgroundColor: theme?.colorTheme.white ?? + StreamChatTheme.of(context).colorTheme.white, + context: context, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(16), + topRight: Radius.circular(16), + )), + builder: (context) => SafeArea( child: Column( mainAxisSize: MainAxisSize.min, children: [ @@ -173,7 +175,7 @@ Future showInfoDialog( ], ), ), - ); + ); /// Get random png with initials String getRandomPicUrl(User user) => @@ -338,16 +340,17 @@ Widget wrapAttachmentWidget( // ignore: avoid_positional_boolean_parameters bool reverse, BorderRadius borderRadius, -) => ClipRRect( - borderRadius: borderRadius, - child: Material( - clipBehavior: Clip.antiAlias, - shape: attachmentShape, - type: MaterialType.transparency, - child: Transform( - transform: Matrix4.rotationY(reverse ? pi : 0), - alignment: Alignment.center, - child: attachmentWidget, +) => + ClipRRect( + borderRadius: borderRadius, + child: Material( + clipBehavior: Clip.antiAlias, + shape: attachmentShape, + type: MaterialType.transparency, + child: Transform( + transform: Matrix4.rotationY(reverse ? pi : 0), + alignment: Alignment.center, + child: attachmentWidget, + ), ), - ), - ); + ); diff --git a/packages/stream_chat_flutter/lib/src/video_thumbnail_image.dart b/packages/stream_chat_flutter/lib/src/video_thumbnail_image.dart index cd321ca2..8cafbbff 100644 --- a/packages/stream_chat_flutter/lib/src/video_thumbnail_image.dart +++ b/packages/stream_chat_flutter/lib/src/video_thumbnail_image.dart @@ -4,10 +4,9 @@ import 'package:flutter/material.dart'; import 'package:shimmer/shimmer.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:video_thumbnail/video_thumbnail.dart'; +import 'package:stream_chat_flutter/src/video_service.dart'; -import 'stream_svg_icon.dart'; -import 'video_service.dart'; - +/// Widget for creating video thumbnail image class VideoThumbnailImage extends StatefulWidget { /// Constructor for creating [VideoThumbnailImage] const VideoThumbnailImage({ @@ -38,6 +37,8 @@ class VideoThumbnailImage extends StatefulWidget { /// Builds widget on error final Widget Function(BuildContext, Object?)? errorBuilder; + + /// Builds placeholder final WidgetBuilder? placeholderBuilder; @override @@ -69,8 +70,8 @@ class _VideoThumbnailImageState extends State { @override Widget build(BuildContext context) => FutureBuilder( - future: thumbnailFuture, - builder: (context, snapshot) => AnimatedSwitcher( + future: thumbnailFuture, + builder: (context, snapshot) => AnimatedSwitcher( duration: const Duration(milliseconds: 350), child: Builder( key: ValueKey>(snapshot), @@ -108,5 +109,5 @@ class _VideoThumbnailImageState extends State { }, ), ), - ); + ); } From f5daa8f49ce5f198be7e97f6a2b19ec0501706d9 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 5 May 2021 17:58:50 +0530 Subject: [PATCH 26/31] lint test --- .../src/attachment_actions_modal_test.dart | 74 +++++------ .../test/src/attachment_widgets_test.dart | 6 +- .../test/src/back_button_test.dart | 16 +-- .../test/src/channel_header_test.dart | 10 +- .../test/src/channel_image_test.dart | 10 +- .../test/src/channel_list_header_test.dart | 16 +-- .../test/src/channel_name_test.dart | 2 +- .../test/src/deleted_message_test.dart | 8 +- .../test/src/info_tile_test.dart | 8 +- .../test/src/message_action_modal_test.dart | 125 ++++++++---------- .../test/src/message_input_test.dart | 4 +- .../src/message_reactions_modal_test.dart | 13 +- .../stream_chat_flutter/test/src/mocks.dart | 1 + .../test/src/reaction_bubble_test.dart | 2 +- 14 files changed, 129 insertions(+), 166 deletions(-) diff --git a/packages/stream_chat_flutter/test/src/attachment_actions_modal_test.dart b/packages/stream_chat_flutter/test/src/attachment_actions_modal_test.dart index 53516e9a..a1eef962 100644 --- a/packages/stream_chat_flutter/test/src/attachment_actions_modal_test.dart +++ b/packages/stream_chat_flutter/test/src/attachment_actions_modal_test.dart @@ -128,7 +128,7 @@ void main() { home: StreamChat( streamChatThemeData: streamTheme, client: client, - child: Container( + child: SizedBox( child: AttachmentActionsModal( message: Message( text: 'test', @@ -185,7 +185,7 @@ void main() { home: StreamChat( streamChatThemeData: streamTheme, client: client, - child: Container( + child: SizedBox( child: AttachmentActionsModal( message: message, currentIndex: 0, @@ -218,7 +218,7 @@ void main() { home: StreamChat( streamChatThemeData: streamTheme, client: client, - child: Container( + child: SizedBox( child: AttachmentActionsModal( onShowMessage: onShowMessage, message: Message( @@ -250,9 +250,8 @@ void main() { final clientState = MockClientState(); final mockChannel = MockChannel(); - when(() => mockChannel.updateMessage(any())).thenAnswer((_) async { - return UpdateMessageResponse(); - }); + when(() => mockChannel.updateMessage(any())) + .thenAnswer((_) async => UpdateMessageResponse()); when(() => client.state).thenReturn(clientState); when(() => clientState.user).thenReturn(OwnUser(id: 'user-id')); @@ -275,12 +274,10 @@ void main() { await tester.pumpWidget( MaterialApp( - builder: (context, child) { - return StreamChat( - client: client, - child: child!, - ); - }, + builder: (context, child) => StreamChat( + client: client, + child: child, + ), home: StreamChannel( showLoading: false, channel: mockChannel, @@ -307,9 +304,8 @@ void main() { final clientState = MockClientState(); final mockChannel = MockChannel(); - when(() => mockChannel.updateMessage(any())).thenAnswer((_) async { - return UpdateMessageResponse(); - }); + when(() => mockChannel.updateMessage(any())) + .thenAnswer((_) async => UpdateMessageResponse()); when(() => client.state).thenReturn(clientState); when(() => clientState.user).thenReturn(OwnUser(id: 'user-id')); @@ -328,12 +324,10 @@ void main() { await tester.pumpWidget( MaterialApp( - builder: (context, child) { - return StreamChat( - client: client, - child: child!, - ); - }, + builder: (context, child) => StreamChat( + client: client, + child: child, + ), home: StreamChannel( showLoading: false, channel: mockChannel, @@ -352,15 +346,15 @@ void main() { ); testWidgets( + // ignore: lines_longer_than_80_chars 'tapping on delete in chat should remove the message if that\'s the only attachment and there is no text', (WidgetTester tester) async { final client = MockClient(); final clientState = MockClientState(); final mockChannel = MockChannel(); - when(() => mockChannel.deleteMessage(any())).thenAnswer((_) async { - return EmptyResponse(); - }); + when(() => mockChannel.deleteMessage(any())) + .thenAnswer((_) async => EmptyResponse()); when(() => client.state).thenReturn(clientState); when(() => clientState.user).thenReturn(OwnUser(id: 'user-id')); @@ -378,12 +372,10 @@ void main() { await tester.pumpWidget( MaterialApp( - builder: (context, child) { - return StreamChat( + builder: (context, child) => StreamChat( client: client, - child: child!, - ); - }, + child: child, + ), home: StreamChannel( showLoading: false, channel: mockChannel, @@ -412,13 +404,11 @@ void main() { await tester.pumpWidget( MaterialApp( - builder: (context, child) { - return StreamChat( + builder: (context, child) => StreamChat( client: client, - child: child!, - ); - }, - home: Container( + child: child, + ), + home: SizedBox( child: AttachmentActionsModal( imageDownloader: imageDownloader, message: Message( @@ -451,8 +441,8 @@ void main() { imageDownloader.progressCallback!(100, 100); imageDownloader.completer.complete('path'); await tester.pump(); - expect(find.byKey(Key('completedIcon')), findsOneWidget); - await tester.pumpAndSettle(Duration(milliseconds: 500)); + expect(find.byKey(const Key('completedIcon')), findsOneWidget); + await tester.pumpAndSettle(const Duration(milliseconds: 500)); }, ); @@ -469,12 +459,10 @@ void main() { await tester.pumpWidget( MaterialApp( - builder: (context, child) { - return StreamChat( + builder: (context, child) => StreamChat( client: client, child: child!, - ); - }, + ), home: Container( child: AttachmentActionsModal( fileDownloader: fileDownloader, @@ -508,8 +496,8 @@ void main() { fileDownloader.progressCallback!(100, 100); fileDownloader.completer.complete('path'); await tester.pump(); - expect(find.byKey(Key('completedIcon')), findsOneWidget); - await tester.pumpAndSettle(Duration(milliseconds: 500)); + expect(find.byKey(const Key('completedIcon')), findsOneWidget); + await tester.pumpAndSettle(const Duration(milliseconds: 500)); }, ); } diff --git a/packages/stream_chat_flutter/test/src/attachment_widgets_test.dart b/packages/stream_chat_flutter/test/src/attachment_widgets_test.dart index e8dcdd53..ed4ce267 100644 --- a/packages/stream_chat_flutter/test/src/attachment_widgets_test.dart +++ b/packages/stream_chat_flutter/test/src/attachment_widgets_test.dart @@ -23,9 +23,9 @@ void main() { data: streamTheme, child: StreamChannel( channel: channel, - child: Container( + child: SizedBox( child: FileAttachment( - size: Size( + size: const Size( 300, 300, ), @@ -33,7 +33,7 @@ void main() { attachment: Attachment( type: 'file', title: 'example.pdf', - extraData: { + extraData: const { 'mime_type': 'pdf', }, ), diff --git a/packages/stream_chat_flutter/test/src/back_button_test.dart b/packages/stream_chat_flutter/test/src/back_button_test.dart index a9c5f724..dc05867f 100644 --- a/packages/stream_chat_flutter/test/src/back_button_test.dart +++ b/packages/stream_chat_flutter/test/src/back_button_test.dart @@ -15,16 +15,14 @@ void main() { MaterialApp( home: const Material(child: Text('Home')), routes: { - '/next': (BuildContext context) { - return Material( + '/next': (BuildContext context) => Material( child: Center( child: StreamChatTheme( data: StreamChatThemeData.fromTheme(theme), child: StreamBackButton(), ), ), - ); - }, + ), }, ), ); @@ -52,7 +50,7 @@ void main() { child: Center( child: StreamChatTheme( data: StreamChatThemeData.fromTheme(theme), - child: StreamBackButton(), + child: const StreamBackButton(), ), ), ), @@ -78,8 +76,7 @@ void main() { MaterialApp( home: const Material(child: Text('Home')), routes: { - '/next': (BuildContext context) { - return Material( + '/next': (BuildContext context) => Material( child: Center( child: StreamChatTheme( data: StreamChatThemeData.fromTheme(theme), @@ -88,8 +85,7 @@ void main() { ), ), ), - ); - }, + ), }, ), ); @@ -131,7 +127,7 @@ void main() { child: Center( child: StreamChat( client: client, - child: StreamBackButton( + child: const StreamBackButton( showUnreads: true, ), ), diff --git a/packages/stream_chat_flutter/test/src/channel_header_test.dart b/packages/stream_chat_flutter/test/src/channel_header_test.dart index 4e99daf5..6da3e20f 100644 --- a/packages/stream_chat_flutter/test/src/channel_header_test.dart +++ b/packages/stream_chat_flutter/test/src/channel_header_test.dart @@ -54,7 +54,7 @@ void main() { client: client, child: StreamChannel( channel: channel, - child: Scaffold( + child: const Scaffold( body: ChannelHeader(), ), ), @@ -115,7 +115,7 @@ void main() { client: client, child: StreamChannel( channel: channel, - child: Scaffold( + child: const Scaffold( body: ChannelHeader( showConnectionStateTile: true, ), @@ -178,7 +178,7 @@ void main() { child: StreamChannel( channel: channel, showLoading: false, - child: Scaffold( + child: const Scaffold( body: ChannelHeader( showConnectionStateTile: true, ), @@ -242,7 +242,7 @@ void main() { client: client, child: StreamChannel( channel: channel, - child: Scaffold( + child: const Scaffold( body: ChannelHeader( leading: Text('leading'), subtitle: Text('subtitle'), @@ -314,7 +314,7 @@ void main() { client: client, child: StreamChannel( channel: channel, - child: Scaffold( + child: const Scaffold( body: ChannelHeader( showTypingIndicator: false, showBackButton: false, diff --git a/packages/stream_chat_flutter/test/src/channel_image_test.dart b/packages/stream_chat_flutter/test/src/channel_image_test.dart index 1068bb52..ba913a77 100644 --- a/packages/stream_chat_flutter/test/src/channel_image_test.dart +++ b/packages/stream_chat_flutter/test/src/channel_image_test.dart @@ -34,7 +34,7 @@ void main() { client: client, child: StreamChannel( channel: channel, - child: Scaffold( + child: const Scaffold( body: ChannelImage(), ), ), @@ -112,7 +112,7 @@ void main() { client: client, child: StreamChannel( channel: channel, - child: Scaffold( + child: const Scaffold( body: ChannelImage(), ), ), @@ -207,7 +207,7 @@ void main() { client: client, child: StreamChannel( channel: channel, - child: Scaffold( + child: const Scaffold( body: ChannelImage(), ), ), @@ -248,7 +248,7 @@ void main() { client: client, child: StreamChannel( channel: channel, - child: Scaffold( + child: const Scaffold( body: ChannelImage( selected: true, ), @@ -257,7 +257,7 @@ void main() { ), )); - expect(find.byKey(Key('selectedImage')), findsOneWidget); + expect(find.byKey(const Key('selectedImage')), findsOneWidget); }, ); } diff --git a/packages/stream_chat_flutter/test/src/channel_list_header_test.dart b/packages/stream_chat_flutter/test/src/channel_list_header_test.dart index f77ea04a..f2f054d4 100644 --- a/packages/stream_chat_flutter/test/src/channel_list_header_test.dart +++ b/packages/stream_chat_flutter/test/src/channel_list_header_test.dart @@ -21,7 +21,7 @@ void main() { MaterialApp( home: StreamChat( client: client, - child: Scaffold( + child: const Scaffold( body: ChannelListHeader(), ), ), @@ -51,7 +51,7 @@ void main() { MaterialApp( home: StreamChat( client: client, - child: Scaffold( + child: const Scaffold( body: ChannelListHeader( showConnectionStateTile: true, ), @@ -80,7 +80,7 @@ void main() { MaterialApp( home: StreamChat( client: client, - child: Scaffold( + child: const Scaffold( body: ChannelListHeader( showConnectionStateTile: true, ), @@ -111,12 +111,10 @@ void main() { client: client, child: Scaffold( body: ChannelListHeader( - titleBuilder: (context, status, client) { - return Text('TITLE'); - }, - subtitle: Text('SUBTITLE'), - leading: Text('LEADING'), - actions: [ + titleBuilder: (context, status, client) => const Text('TITLE'), + subtitle: const Text('SUBTITLE'), + leading: const Text('LEADING'), + actions: const [ Text('ACTION'), ], client: client, diff --git a/packages/stream_chat_flutter/test/src/channel_name_test.dart b/packages/stream_chat_flutter/test/src/channel_name_test.dart index 586a0776..c8d3df9b 100644 --- a/packages/stream_chat_flutter/test/src/channel_name_test.dart +++ b/packages/stream_chat_flutter/test/src/channel_name_test.dart @@ -61,7 +61,7 @@ void main() { client: client, child: StreamChannel( channel: channel, - child: Scaffold( + child: const Scaffold( body: ChannelName(), ), ), diff --git a/packages/stream_chat_flutter/test/src/deleted_message_test.dart b/packages/stream_chat_flutter/test/src/deleted_message_test.dart index 854c2492..bcf9cf62 100644 --- a/packages/stream_chat_flutter/test/src/deleted_message_test.dart +++ b/packages/stream_chat_flutter/test/src/deleted_message_test.dart @@ -19,7 +19,7 @@ void main() { await tester.pumpWidget(MaterialApp( home: StreamChat( client: client, - child: Scaffold( + child: const Scaffold( body: DeletedMessage( messageTheme: MessageTheme( createdAt: TextStyle( @@ -81,7 +81,7 @@ void main() { ), ), ), - surfaceSize: Size.square(200), + surfaceSize: const Size.square(200), ); await screenMatchesGolden(tester, 'deleted_message_light'); @@ -133,7 +133,7 @@ void main() { ), ), ), - surfaceSize: Size.square(200), + surfaceSize: const Size.square(200), ); await screenMatchesGolden(tester, 'deleted_message_dark'); @@ -189,7 +189,7 @@ void main() { ), ), ), - surfaceSize: Size.square(200), + surfaceSize: const Size.square(200), ); await screenMatchesGolden(tester, 'deleted_message_custom'); diff --git a/packages/stream_chat_flutter/test/src/info_tile_test.dart b/packages/stream_chat_flutter/test/src/info_tile_test.dart index 091c64c7..02387edc 100644 --- a/packages/stream_chat_flutter/test/src/info_tile_test.dart +++ b/packages/stream_chat_flutter/test/src/info_tile_test.dart @@ -19,9 +19,9 @@ void main() { await tester.pumpWidget(MaterialApp( home: StreamChat( client: client, - child: Scaffold( + child: const Scaffold( body: Portal( - child: Container( + child: SizedBox( child: InfoTile( showMessage: true, message: 'message', @@ -49,9 +49,9 @@ void main() { await tester.pumpWidget(MaterialApp( home: StreamChat( client: client, - child: Scaffold( + child: const Scaffold( body: Portal( - child: Container( + child: SizedBox( child: InfoTile( showMessage: false, message: 'message', diff --git a/packages/stream_chat_flutter/test/src/message_action_modal_test.dart b/packages/stream_chat_flutter/test/src/message_action_modal_test.dart index 0be509ae..837065ac 100644 --- a/packages/stream_chat_flutter/test/src/message_action_modal_test.dart +++ b/packages/stream_chat_flutter/test/src/message_action_modal_test.dart @@ -8,7 +8,8 @@ import 'mocks.dart'; void main() { setUpAll(() { - registerFallbackValue(MaterialPageRoute(builder: (context) => SizedBox())); + registerFallbackValue( + MaterialPageRoute(builder: (context) => const SizedBox())); registerFallbackValue(Message()); }); @@ -29,7 +30,7 @@ void main() { home: StreamChat( streamChatThemeData: streamTheme, client: client, - child: Container( + child: SizedBox( child: MessageActionsModal( message: Message( text: 'test', @@ -45,7 +46,7 @@ void main() { ); await tester.pumpAndSettle(); - expect(find.byKey(Key('MessageWidget')), findsOneWidget); + expect(find.byKey(const Key('MessageWidget')), findsOneWidget); expect(find.text('Thread Reply'), findsOneWidget); expect(find.text('Reply'), findsOneWidget); expect(find.text('Edit Message'), findsOneWidget); @@ -71,7 +72,7 @@ void main() { home: StreamChat( streamChatThemeData: streamTheme, client: client, - child: Container( + child: SizedBox( child: MessageActionsModal( showEditMessage: false, showCopyMessage: false, @@ -92,7 +93,7 @@ void main() { ); await tester.pumpAndSettle(); - expect(find.byKey(Key('MessageWidget')), findsOneWidget); + expect(find.byKey(const Key('MessageWidget')), findsOneWidget); expect(find.text('Reply'), findsNothing); expect(find.text('Thread reply'), findsNothing); expect(find.text('Edit message'), findsNothing); @@ -120,7 +121,7 @@ void main() { home: StreamChat( streamChatThemeData: streamTheme, client: client, - child: Container( + child: SizedBox( child: MessageActionsModal( message: Message( text: 'test', @@ -131,8 +132,8 @@ void main() { messageTheme: streamTheme.ownMessageTheme, customActions: [ MessageAction( - leading: Icon(Icons.check), - title: Text('title'), + leading: const Icon(Icons.check), + title: const Text('title'), onTap: (m) { tapped = true; }, @@ -175,7 +176,7 @@ void main() { home: StreamChat( streamChatThemeData: streamTheme, client: client, - child: Container( + child: SizedBox( child: MessageActionsModal( onReplyTap: (m) { tapped = true; @@ -220,7 +221,7 @@ void main() { home: StreamChat( streamChatThemeData: streamTheme, client: client, - child: Container( + child: SizedBox( child: MessageActionsModal( onThreadReplyTap: (m) { tapped = true; @@ -260,18 +261,16 @@ void main() { await tester.pumpWidget( MaterialApp( - builder: (context, child) { - return StreamChat( + builder: (context, child) => StreamChat( client: client, streamChatThemeData: streamTheme, - child: child!, - ); - }, + child: child, + ), theme: themeData, home: StreamChannel( showLoading: false, channel: channel, - child: Container( + child: SizedBox( child: MessageActionsModal( message: Message( text: 'test', @@ -310,22 +309,18 @@ void main() { await tester.pumpWidget( MaterialApp( - builder: (context, child) { - return StreamChat( + builder: (context, child) => StreamChat( client: client, streamChatThemeData: streamTheme, - child: child!, - ); - }, + child: child, + ), theme: themeData, home: StreamChannel( showLoading: false, channel: channel, - child: Container( + child: SizedBox( child: MessageActionsModal( - editMessageInputBuilder: (context, m) { - return Text('test'); - }, + editMessageInputBuilder: (context, m) => const Text('test'), message: Message( text: 'test', user: User( @@ -365,18 +360,16 @@ void main() { await tester.pumpWidget( MaterialApp( - builder: (context, child) { - return StreamChat( + builder: (context, child) => StreamChat( client: client, streamChatThemeData: streamTheme, - child: child!, - ); - }, + child: child, + ), theme: themeData, home: StreamChannel( showLoading: false, channel: channel, - child: Container( + child: SizedBox( child: MessageActionsModal( onCopyTap: (m) => tapped = true, message: Message( @@ -416,18 +409,16 @@ void main() { await tester.pumpWidget( MaterialApp( - builder: (context, child) { - return StreamChat( + builder: (context, child) => StreamChat( client: client, streamChatThemeData: streamTheme, - child: child!, - ); - }, + child: child, + ), theme: themeData, home: StreamChannel( showLoading: false, channel: channel, - child: Container( + child: SizedBox( child: MessageActionsModal( message: Message( status: MessageSendingStatus.failed, @@ -467,18 +458,16 @@ void main() { await tester.pumpWidget( MaterialApp( - builder: (context, child) { - return StreamChat( + builder: (context, child) => StreamChat( client: client, streamChatThemeData: streamTheme, - child: child!, - ); - }, + child: child, + ), theme: themeData, home: StreamChannel( showLoading: false, channel: channel, - child: Container( + child: SizedBox( child: MessageActionsModal( message: Message( status: MessageSendingStatus.failed_update, @@ -516,18 +505,16 @@ void main() { await tester.pumpWidget( MaterialApp( - builder: (context, child) { - return StreamChat( + builder: (context, child) => StreamChat( client: client, streamChatThemeData: streamTheme, - child: child!, - ); - }, + child: child, + ), theme: themeData, home: StreamChannel( showLoading: false, channel: channel, - child: Container( + child: SizedBox( child: MessageActionsModal( message: Message( id: 'testid', @@ -575,18 +562,16 @@ void main() { await tester.pumpWidget( MaterialApp( - builder: (context, child) { - return StreamChat( + builder: (context, child) => StreamChat( client: client, streamChatThemeData: streamTheme, - child: child!, - ); - }, + child: child, + ), theme: themeData, home: StreamChannel( showLoading: false, channel: channel, - child: Container( + child: SizedBox( child: MessageActionsModal( message: Message( id: 'testid', @@ -634,18 +619,16 @@ void main() { await tester.pumpWidget( MaterialApp( - builder: (context, child) { - return StreamChat( + builder: (context, child) => StreamChat( client: client, streamChatThemeData: streamTheme, - child: child!, - ); - }, + child: child, + ), theme: themeData, home: StreamChannel( showLoading: false, channel: channel, - child: Container( + child: SizedBox( child: MessageActionsModal( message: Message( id: 'testid', @@ -689,18 +672,16 @@ void main() { await tester.pumpWidget( MaterialApp( - builder: (context, child) { - return StreamChat( + builder: (context, child) => StreamChat( client: client, streamChatThemeData: streamTheme, - child: child!, - ); - }, + child: child, + ), theme: themeData, home: StreamChannel( showLoading: false, channel: channel, - child: Container( + child: SizedBox( child: MessageActionsModal( message: Message( id: 'testid', @@ -748,18 +729,16 @@ void main() { await tester.pumpWidget( MaterialApp( - builder: (context, child) { - return StreamChat( + builder: (context, child) => StreamChat( client: client, streamChatThemeData: streamTheme, - child: child!, - ); - }, + child: child, + ), theme: themeData, home: StreamChannel( showLoading: false, channel: channel, - child: Container( + child: SizedBox( child: MessageActionsModal( message: Message( id: 'testid', diff --git a/packages/stream_chat_flutter/test/src/message_input_test.dart b/packages/stream_chat_flutter/test/src/message_input_test.dart index 39e7ae3f..63ddb10f 100644 --- a/packages/stream_chat_flutter/test/src/message_input_test.dart +++ b/packages/stream_chat_flutter/test/src/message_input_test.dart @@ -67,7 +67,7 @@ void main() { client: client, child: StreamChannel( channel: channel, - child: Scaffold( + child: const Scaffold( body: MessageInput(), ), ), @@ -76,7 +76,7 @@ void main() { expect(find.byType(TextField), findsOneWidget); expect(find.byType(StreamSvgIcon), findsNWidgets(8)); - expect(find.byKey(Key('messageInputText')), findsOneWidget); + expect(find.byKey(const Key('messageInputText')), findsOneWidget); }, ); } diff --git a/packages/stream_chat_flutter/test/src/message_reactions_modal_test.dart b/packages/stream_chat_flutter/test/src/message_reactions_modal_test.dart index e1136ac5..6bdb72b0 100644 --- a/packages/stream_chat_flutter/test/src/message_reactions_modal_test.dart +++ b/packages/stream_chat_flutter/test/src/message_reactions_modal_test.dart @@ -41,7 +41,7 @@ void main() { ), ); - await tester.pump(Duration(milliseconds: 1000)); + await tester.pump(const Duration(milliseconds: 1000)); expect(find.byType(MessageWidget), findsOneWidget); final messageWidget = @@ -95,6 +95,7 @@ void main() { ], ); + // ignore: prefer_function_declarations_over_variables final onUserAvatarTap = (u) => print('ok'); await tester.pumpWidget( @@ -109,16 +110,16 @@ void main() { showUserAvatar: DisplayWidget.gone, reverse: true, attachmentBorderRadiusGeometry: BorderRadius.circular(1), - attachmentShape: RoundedRectangleBorder(), + attachmentShape: const RoundedRectangleBorder(), showReactions: false, - messageShape: RoundedRectangleBorder(), + messageShape: const RoundedRectangleBorder(), onUserAvatarTap: onUserAvatarTap, ), ), ), ); - await tester.pump(Duration(milliseconds: 1000)); + await tester.pump(const Duration(milliseconds: 1000)); expect(find.byType(MessageWidget), findsOneWidget); final messageWidget = @@ -130,8 +131,8 @@ void main() { expect(messageWidget.showUserAvatar, DisplayWidget.gone); expect(messageWidget.reverse, true); expect(messageWidget.showReactions, false); - expect(messageWidget.attachmentShape, RoundedRectangleBorder()); - expect(messageWidget.shape, RoundedRectangleBorder()); + expect(messageWidget.attachmentShape, const RoundedRectangleBorder()); + expect(messageWidget.shape, const RoundedRectangleBorder()); expect(messageWidget.showReactions, false); expect(messageWidget.showUsername, false); expect(messageWidget.showThreadReplyIndicator, false); diff --git a/packages/stream_chat_flutter/test/src/mocks.dart b/packages/stream_chat_flutter/test/src/mocks.dart index 842c1c2f..083c2ff5 100644 --- a/packages/stream_chat_flutter/test/src/mocks.dart +++ b/packages/stream_chat_flutter/test/src/mocks.dart @@ -11,6 +11,7 @@ class MockChannel extends Mock implements Channel { Future get initialized async => true; @override + // ignore: prefer_expression_function_bodies Future keyStroke([String? parentId]) async { return; } diff --git a/packages/stream_chat_flutter/test/src/reaction_bubble_test.dart b/packages/stream_chat_flutter/test/src/reaction_bubble_test.dart index 10e0f45c..8d575746 100644 --- a/packages/stream_chat_flutter/test/src/reaction_bubble_test.dart +++ b/packages/stream_chat_flutter/test/src/reaction_bubble_test.dart @@ -16,7 +16,7 @@ void main() { SimpleFrame( child: StreamChatTheme( data: StreamChatThemeData(), - child: Container( + child: const SizedBox( child: ReactionBubble( reactions: [], borderColor: Colors.black, From 9b09874df17dafaa6088c32387024ecd4cf07db7 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 5 May 2021 17:59:19 +0530 Subject: [PATCH 27/31] lint test --- .../src/attachment_actions_modal_test.dart | 18 ++--- .../test/src/back_button_test.dart | 22 ++--- .../test/src/message_action_modal_test.dart | 80 +++++++++---------- 3 files changed, 60 insertions(+), 60 deletions(-) diff --git a/packages/stream_chat_flutter/test/src/attachment_actions_modal_test.dart b/packages/stream_chat_flutter/test/src/attachment_actions_modal_test.dart index a1eef962..51ca5c57 100644 --- a/packages/stream_chat_flutter/test/src/attachment_actions_modal_test.dart +++ b/packages/stream_chat_flutter/test/src/attachment_actions_modal_test.dart @@ -373,9 +373,9 @@ void main() { await tester.pumpWidget( MaterialApp( builder: (context, child) => StreamChat( - client: client, - child: child, - ), + client: client, + child: child, + ), home: StreamChannel( showLoading: false, channel: mockChannel, @@ -405,9 +405,9 @@ void main() { await tester.pumpWidget( MaterialApp( builder: (context, child) => StreamChat( - client: client, - child: child, - ), + client: client, + child: child, + ), home: SizedBox( child: AttachmentActionsModal( imageDownloader: imageDownloader, @@ -460,9 +460,9 @@ void main() { await tester.pumpWidget( MaterialApp( builder: (context, child) => StreamChat( - client: client, - child: child!, - ), + client: client, + child: child!, + ), home: Container( child: AttachmentActionsModal( fileDownloader: fileDownloader, diff --git a/packages/stream_chat_flutter/test/src/back_button_test.dart b/packages/stream_chat_flutter/test/src/back_button_test.dart index dc05867f..b991a01e 100644 --- a/packages/stream_chat_flutter/test/src/back_button_test.dart +++ b/packages/stream_chat_flutter/test/src/back_button_test.dart @@ -16,13 +16,13 @@ void main() { home: const Material(child: Text('Home')), routes: { '/next': (BuildContext context) => Material( - child: Center( - child: StreamChatTheme( - data: StreamChatThemeData.fromTheme(theme), - child: StreamBackButton(), + child: Center( + child: StreamChatTheme( + data: StreamChatThemeData.fromTheme(theme), + child: StreamBackButton(), + ), ), ), - ), }, ), ); @@ -77,15 +77,15 @@ void main() { home: const Material(child: Text('Home')), routes: { '/next': (BuildContext context) => Material( - child: Center( - child: StreamChatTheme( - data: StreamChatThemeData.fromTheme(theme), - child: StreamBackButton( - onPressed: () => customCallbackWasCalled = true, + child: Center( + child: StreamChatTheme( + data: StreamChatThemeData.fromTheme(theme), + child: StreamBackButton( + onPressed: () => customCallbackWasCalled = true, + ), ), ), ), - ), }, ), ); diff --git a/packages/stream_chat_flutter/test/src/message_action_modal_test.dart b/packages/stream_chat_flutter/test/src/message_action_modal_test.dart index 837065ac..6118e7d2 100644 --- a/packages/stream_chat_flutter/test/src/message_action_modal_test.dart +++ b/packages/stream_chat_flutter/test/src/message_action_modal_test.dart @@ -262,10 +262,10 @@ void main() { await tester.pumpWidget( MaterialApp( builder: (context, child) => StreamChat( - client: client, - streamChatThemeData: streamTheme, - child: child, - ), + client: client, + streamChatThemeData: streamTheme, + child: child, + ), theme: themeData, home: StreamChannel( showLoading: false, @@ -310,10 +310,10 @@ void main() { await tester.pumpWidget( MaterialApp( builder: (context, child) => StreamChat( - client: client, - streamChatThemeData: streamTheme, - child: child, - ), + client: client, + streamChatThemeData: streamTheme, + child: child, + ), theme: themeData, home: StreamChannel( showLoading: false, @@ -361,10 +361,10 @@ void main() { await tester.pumpWidget( MaterialApp( builder: (context, child) => StreamChat( - client: client, - streamChatThemeData: streamTheme, - child: child, - ), + client: client, + streamChatThemeData: streamTheme, + child: child, + ), theme: themeData, home: StreamChannel( showLoading: false, @@ -410,10 +410,10 @@ void main() { await tester.pumpWidget( MaterialApp( builder: (context, child) => StreamChat( - client: client, - streamChatThemeData: streamTheme, - child: child, - ), + client: client, + streamChatThemeData: streamTheme, + child: child, + ), theme: themeData, home: StreamChannel( showLoading: false, @@ -459,10 +459,10 @@ void main() { await tester.pumpWidget( MaterialApp( builder: (context, child) => StreamChat( - client: client, - streamChatThemeData: streamTheme, - child: child, - ), + client: client, + streamChatThemeData: streamTheme, + child: child, + ), theme: themeData, home: StreamChannel( showLoading: false, @@ -506,10 +506,10 @@ void main() { await tester.pumpWidget( MaterialApp( builder: (context, child) => StreamChat( - client: client, - streamChatThemeData: streamTheme, - child: child, - ), + client: client, + streamChatThemeData: streamTheme, + child: child, + ), theme: themeData, home: StreamChannel( showLoading: false, @@ -563,10 +563,10 @@ void main() { await tester.pumpWidget( MaterialApp( builder: (context, child) => StreamChat( - client: client, - streamChatThemeData: streamTheme, - child: child, - ), + client: client, + streamChatThemeData: streamTheme, + child: child, + ), theme: themeData, home: StreamChannel( showLoading: false, @@ -620,10 +620,10 @@ void main() { await tester.pumpWidget( MaterialApp( builder: (context, child) => StreamChat( - client: client, - streamChatThemeData: streamTheme, - child: child, - ), + client: client, + streamChatThemeData: streamTheme, + child: child, + ), theme: themeData, home: StreamChannel( showLoading: false, @@ -673,10 +673,10 @@ void main() { await tester.pumpWidget( MaterialApp( builder: (context, child) => StreamChat( - client: client, - streamChatThemeData: streamTheme, - child: child, - ), + client: client, + streamChatThemeData: streamTheme, + child: child, + ), theme: themeData, home: StreamChannel( showLoading: false, @@ -730,10 +730,10 @@ void main() { await tester.pumpWidget( MaterialApp( builder: (context, child) => StreamChat( - client: client, - streamChatThemeData: streamTheme, - child: child, - ), + client: client, + streamChatThemeData: streamTheme, + child: child, + ), theme: themeData, home: StreamChannel( showLoading: false, From 0590fe1a76925c80b0af13bb44729fd8930dee5e Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 5 May 2021 19:07:32 +0530 Subject: [PATCH 28/31] lint --- .../lib/src/attachment/attachment_widget.dart | 1 + .../lib/src/attachment/file_attachment.dart | 4 +- .../lib/src/attachment_actions_modal.dart | 42 +++++++++---------- .../lib/src/channel_image.dart | 2 +- .../lib/src/channel_info.dart | 4 +- .../lib/src/mention_tile.dart | 2 +- .../lib/src/message_text.dart | 2 - .../lib/src/user_list_view.dart | 2 - .../stream_chat_flutter/lib/src/utils.dart | 6 +-- .../lib/src/video_service.dart | 2 +- packages/stream_chat_flutter/pubspec.yaml | 6 +-- .../src/attachment_actions_modal_test.dart | 7 ++-- .../test/src/back_button_test.dart | 2 +- .../test/src/reaction_bubble_test.dart | 16 +++---- .../test/src/simple_frame.dart | 22 +++++----- .../test/src/system_message_test.dart | 4 +- .../test/src/thread_header_test.dart | 8 ++-- .../test/src/typing_indicator_test.dart | 4 +- .../test/src/unread_indicator_test.dart | 2 +- 19 files changed, 68 insertions(+), 70 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/attachment/attachment_widget.dart b/packages/stream_chat_flutter/lib/src/attachment/attachment_widget.dart index 74769057..ee79d959 100644 --- a/packages/stream_chat_flutter/lib/src/attachment/attachment_widget.dart +++ b/packages/stream_chat_flutter/lib/src/attachment/attachment_widget.dart @@ -67,6 +67,7 @@ class AttachmentError extends StatelessWidget { this.size, }) : super(key: key); + /// Size of error final Size? size; @override diff --git a/packages/stream_chat_flutter/lib/src/attachment/file_attachment.dart b/packages/stream_chat_flutter/lib/src/attachment/file_attachment.dart index c68d72f9..63bcdd9b 100644 --- a/packages/stream_chat_flutter/lib/src/attachment/file_attachment.dart +++ b/packages/stream_chat_flutter/lib/src/attachment/file_attachment.dart @@ -6,10 +6,12 @@ import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import 'package:stream_chat_flutter/src/utils.dart'; import 'package:stream_chat_flutter/src/video_thumbnail_image.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; +import 'package:stream_chat_flutter/src/upload_progress_indicator.dart'; -import '../upload_progress_indicator.dart'; +// ignore: always_use_package_imports import 'attachment_widget.dart'; +/// Widget for displaying file attachments class FileAttachment extends AttachmentWidget { /// Constructor for creating a widget when attachment is of type 'file' const FileAttachment({ diff --git a/packages/stream_chat_flutter/lib/src/attachment_actions_modal.dart b/packages/stream_chat_flutter/lib/src/attachment_actions_modal.dart index a9ea651b..363fac45 100644 --- a/packages/stream_chat_flutter/lib/src/attachment_actions_modal.dart +++ b/packages/stream_chat_flutter/lib/src/attachment_actions_modal.dart @@ -5,9 +5,8 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:image_gallery_saver/image_gallery_saver.dart'; import 'package:path_provider/path_provider.dart'; - -import '../stream_chat_flutter.dart'; -import 'extension.dart'; +import 'package:stream_chat_flutter/src/extension.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; /// Callback to download an attachment asset typedef AttachmentDownloader = Future Function( @@ -17,6 +16,16 @@ typedef AttachmentDownloader = Future Function( /// Widget that shows the options in the gallery view class AttachmentActionsModal extends StatelessWidget { + /// Returns a new [AttachmentActionsModal] + const AttachmentActionsModal({ + Key? key, + required this.currentIndex, + required this.message, + this.onShowMessage, + this.imageDownloader, + this.fileDownloader, + }) : super(key: key); + /// The message containing the attachments final Message message; @@ -32,15 +41,6 @@ class AttachmentActionsModal extends StatelessWidget { /// Callback to provide download files final AttachmentDownloader? fileDownloader; - /// Returns a new [AttachmentActionsModal] - const AttachmentActionsModal({ - required this.currentIndex, - required this.message, - this.onShowMessage, - this.imageDownloader, - this.fileDownloader, - }); - @override Widget build(BuildContext context) => GestureDetector( behavior: HitTestBehavior.translucent, @@ -62,7 +62,7 @@ class AttachmentActionsModal extends StatelessWidget { decoration: BoxDecoration( borderRadius: BorderRadius.circular(16), ), - child: Container( + child: SizedBox( child: Column( crossAxisAlignment: CrossAxisAlignment.end, mainAxisSize: MainAxisSize.min, @@ -89,6 +89,7 @@ class AttachmentActionsModal extends StatelessWidget { ), _buildButton( context, + // ignore: lines_longer_than_80_chars 'Save ${message.attachments[currentIndex].type == 'video' ? 'Video' : 'Image'}', StreamSvgIcon.iconSave( size: 24, @@ -203,7 +204,7 @@ class AttachmentActionsModal extends StatelessWidget { child: Row( children: [ icon, - SizedBox(width: 16), + const SizedBox(width: 16), Text( title, style: StreamChatTheme.of(context) @@ -253,7 +254,7 @@ class AttachmentActionsModal extends StatelessWidget { ) : progress.toProgressIndicatorValue == 1.0 ? SizedBox( - key: Key('completedIcon'), + key: const Key('completedIcon'), height: 160, width: 160, child: StreamSvgIcon.check( @@ -314,14 +315,13 @@ class AttachmentActionsModal extends StatelessWidget { } class _DownloadProgress { - final int total; - final int received; - const _DownloadProgress(this.total, this.received); - factory _DownloadProgress.initial() { - return _DownloadProgress(double.maxFinite.toInt(), 0); - } + factory _DownloadProgress.initial() => + _DownloadProgress(double.maxFinite.toInt(), 0); + + final int total; + final int received; double get toProgressIndicatorValue => received / total; diff --git a/packages/stream_chat_flutter/lib/src/channel_image.dart b/packages/stream_chat_flutter/lib/src/channel_image.dart index 8116ca83..80e32f07 100644 --- a/packages/stream_chat_flutter/lib/src/channel_image.dart +++ b/packages/stream_chat_flutter/lib/src/channel_image.dart @@ -196,7 +196,7 @@ class ChannelImage extends StatelessWidget { ); if (selected) { child = ClipRRect( - key: Key('selectedImage'), + key: const Key('selectedImage'), borderRadius: (borderRadius ?? StreamChatTheme.of(context) .ownMessageTheme diff --git a/packages/stream_chat_flutter/lib/src/channel_info.dart b/packages/stream_chat_flutter/lib/src/channel_info.dart index 72f6cf18..5fa6f704 100644 --- a/packages/stream_chat_flutter/lib/src/channel_info.dart +++ b/packages/stream_chat_flutter/lib/src/channel_info.dart @@ -3,9 +3,9 @@ import 'package:flutter/material.dart'; import 'package:jiffy/jiffy.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; -import 'connection_status_builder.dart'; - +/// Widget which shows channel info class ChannelInfo extends StatelessWidget { + /// Constructor which creates a [ChannelInfo] widget const ChannelInfo({ Key? key, required this.channel, diff --git a/packages/stream_chat_flutter/lib/src/mention_tile.dart b/packages/stream_chat_flutter/lib/src/mention_tile.dart index e8859946..f3bed355 100644 --- a/packages/stream_chat_flutter/lib/src/mention_tile.dart +++ b/packages/stream_chat_flutter/lib/src/mention_tile.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; -import '../stream_chat_flutter.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; /// This widget is used for showing user tiles for mentions /// Use [title], [subtitle], [leading], [trailing] for diff --git a/packages/stream_chat_flutter/lib/src/message_text.dart b/packages/stream_chat_flutter/lib/src/message_text.dart index 8c95120d..24a32a09 100644 --- a/packages/stream_chat_flutter/lib/src/message_text.dart +++ b/packages/stream_chat_flutter/lib/src/message_text.dart @@ -4,8 +4,6 @@ import 'package:flutter_markdown/flutter_markdown.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; -import '../stream_chat_flutter.dart'; - /// Text widget to display in message class MessageText extends StatelessWidget { /// Constructor for creating a [MessageText] widget diff --git a/packages/stream_chat_flutter/lib/src/user_list_view.dart b/packages/stream_chat_flutter/lib/src/user_list_view.dart index 0c835fbe..4d5d202a 100644 --- a/packages/stream_chat_flutter/lib/src/user_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/user_list_view.dart @@ -2,8 +2,6 @@ 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 'user_item.dart'; - /// Callback called when tapping on a user typedef UserTapCallback = void Function(User, Widget?); diff --git a/packages/stream_chat_flutter/lib/src/utils.dart b/packages/stream_chat_flutter/lib/src/utils.dart index 8f493cec..cdd87e2d 100644 --- a/packages/stream_chat_flutter/lib/src/utils.dart +++ b/packages/stream_chat_flutter/lib/src/utils.dart @@ -3,10 +3,9 @@ import 'dart:math'; import 'package:flutter/material.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:url_launcher/url_launcher.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; -import '../stream_chat_flutter.dart'; -import 'stream_svg_icon.dart'; - +/// Launch URL Future launchURL(BuildContext context, String? url) async { if (url != null && await canLaunch(url)) { await launch(url); @@ -20,6 +19,7 @@ Future launchURL(BuildContext context, String? url) async { } } +/// Shows confirmation dialog Future showConfirmationDialog( BuildContext context, { required String title, diff --git a/packages/stream_chat_flutter/lib/src/video_service.dart b/packages/stream_chat_flutter/lib/src/video_service.dart index 3b6bb13e..ba4761a2 100644 --- a/packages/stream_chat_flutter/lib/src/video_service.dart +++ b/packages/stream_chat_flutter/lib/src/video_service.dart @@ -60,6 +60,6 @@ class IVideoService { ); } -// ignore: non_constant_identifier_names /// Get instance of [IVideoService] +// ignore: non_constant_identifier_names IVideoService get VideoService => IVideoService.instance; diff --git a/packages/stream_chat_flutter/pubspec.yaml b/packages/stream_chat_flutter/pubspec.yaml index 7a2725ed..2ef87189 100644 --- a/packages/stream_chat_flutter/pubspec.yaml +++ b/packages/stream_chat_flutter/pubspec.yaml @@ -12,10 +12,10 @@ dependencies: flutter: sdk: flutter stream_chat_flutter_core: ^2.0.0-nullsafety.0 - photo_view: ^0.11.1 rxdart: ^0.26.0 scrollable_positioned_list: ^0.2.0-nullsafety.0 jiffy: ^4.1.0 + photo_view: ^0.11.1 flutter_svg: ^0.22.0 flutter_portal: ^0.4.0 cached_network_image: ^3.0.0 @@ -57,6 +57,6 @@ dev_dependencies: flutter_test: sdk: flutter mocktail: ^0.1.2 - pedantic: ^1.11.0 golden_toolkit: ^0.9.0 - + pedantic: ^1.11.0 + diff --git a/packages/stream_chat_flutter/test/src/attachment_actions_modal_test.dart b/packages/stream_chat_flutter/test/src/attachment_actions_modal_test.dart index 51ca5c57..3f210742 100644 --- a/packages/stream_chat_flutter/test/src/attachment_actions_modal_test.dart +++ b/packages/stream_chat_flutter/test/src/attachment_actions_modal_test.dart @@ -23,7 +23,8 @@ class MockAttachmentDownloader extends Mock { void main() { setUpAll(() { - registerFallbackValue(MaterialPageRoute(builder: (context) => SizedBox())); + registerFallbackValue( + MaterialPageRoute(builder: (context) => const SizedBox())); registerFallbackValue(Message()); }); @@ -461,9 +462,9 @@ void main() { MaterialApp( builder: (context, child) => StreamChat( client: client, - child: child!, + child: child, ), - home: Container( + home: SizedBox( child: AttachmentActionsModal( fileDownloader: fileDownloader, message: Message( diff --git a/packages/stream_chat_flutter/test/src/back_button_test.dart b/packages/stream_chat_flutter/test/src/back_button_test.dart index b991a01e..3fae1ace 100644 --- a/packages/stream_chat_flutter/test/src/back_button_test.dart +++ b/packages/stream_chat_flutter/test/src/back_button_test.dart @@ -19,7 +19,7 @@ void main() { child: Center( child: StreamChatTheme( data: StreamChatThemeData.fromTheme(theme), - child: StreamBackButton(), + child: const StreamBackButton(), ), ), ), diff --git a/packages/stream_chat_flutter/test/src/reaction_bubble_test.dart b/packages/stream_chat_flutter/test/src/reaction_bubble_test.dart index 8d575746..770a040b 100644 --- a/packages/stream_chat_flutter/test/src/reaction_bubble_test.dart +++ b/packages/stream_chat_flutter/test/src/reaction_bubble_test.dart @@ -26,7 +26,7 @@ void main() { ), ), ), - surfaceSize: Size(100, 100), + surfaceSize: const Size(100, 100), ); await screenMatchesGolden(tester, 'reaction_bubble_0'); }, @@ -47,7 +47,7 @@ void main() { StreamChat( client: client, streamChatThemeData: theme, - child: Container( + child: SizedBox( child: ReactionBubble( reactions: [ Reaction( @@ -61,7 +61,7 @@ void main() { ), ), ), - surfaceSize: Size(100, 100), + surfaceSize: const Size(100, 100), ); await screenMatchesGolden(tester, 'reaction_bubble_like_light'); }, @@ -97,7 +97,7 @@ void main() { ), ), ), - surfaceSize: Size(100, 100), + surfaceSize: const Size(100, 100), ); await screenMatchesGolden(tester, 'reaction_bubble_like_dark'); }, @@ -141,7 +141,7 @@ void main() { ), ), ), - surfaceSize: Size(140, 140), + surfaceSize: const Size(140, 140), ); await screenMatchesGolden(tester, 'reaction_bubble_3_light'); }, @@ -185,7 +185,7 @@ void main() { ), ), ), - surfaceSize: Size(140, 140), + surfaceSize: const Size(140, 140), ); await screenMatchesGolden(tester, 'reaction_bubble_3_dark'); }, @@ -205,7 +205,7 @@ void main() { StreamChat( client: client, streamChatThemeData: StreamChatThemeData.fromTheme(themeData), - child: Container( + child: SizedBox( child: ReactionBubble( reactions: [ Reaction( @@ -230,7 +230,7 @@ void main() { ), ), ), - surfaceSize: Size(200, 200), + surfaceSize: const Size(200, 200), ); await screenMatchesGolden(tester, 'reaction_bubble_2'); diff --git a/packages/stream_chat_flutter/test/src/simple_frame.dart b/packages/stream_chat_flutter/test/src/simple_frame.dart index 18d7ae55..0633a3b8 100644 --- a/packages/stream_chat_flutter/test/src/simple_frame.dart +++ b/packages/stream_chat_flutter/test/src/simple_frame.dart @@ -1,19 +1,17 @@ import 'package:flutter/material.dart'; class SimpleFrame extends StatelessWidget { - final Widget child; - const SimpleFrame({Key? key, required this.child}) : super(key: key); + final Widget child; + @override - Widget build(BuildContext context) { - return Container( - padding: const EdgeInsets.all(4), - decoration: BoxDecoration( - color: const Color(0xFFFFFFFF), - border: Border.all(color: const Color(0xFF9E9E9E)), - ), - child: child, - ); - } + Widget build(BuildContext context) => Container( + padding: const EdgeInsets.all(4), + decoration: BoxDecoration( + color: const Color(0xFFFFFFFF), + border: Border.all(color: const Color(0xFF9E9E9E)), + ), + child: child, + ); } diff --git a/packages/stream_chat_flutter/test/src/system_message_test.dart b/packages/stream_chat_flutter/test/src/system_message_test.dart index 53741864..8fa3ad44 100644 --- a/packages/stream_chat_flutter/test/src/system_message_test.dart +++ b/packages/stream_chat_flutter/test/src/system_message_test.dart @@ -102,7 +102,7 @@ void main() { ), ), ), - surfaceSize: Size.square(200), + surfaceSize: const Size.square(200), ); await screenMatchesGolden(tester, 'system_message_light'); @@ -153,7 +153,7 @@ void main() { ), ), ), - surfaceSize: Size.square(200), + surfaceSize: const Size.square(200), ); await screenMatchesGolden(tester, 'system_message_dark'); diff --git a/packages/stream_chat_flutter/test/src/thread_header_test.dart b/packages/stream_chat_flutter/test/src/thread_header_test.dart index 9e64abb7..578b2ad6 100644 --- a/packages/stream_chat_flutter/test/src/thread_header_test.dart +++ b/packages/stream_chat_flutter/test/src/thread_header_test.dart @@ -117,13 +117,13 @@ void main() { child: Scaffold( body: ThreadHeader( parent: Message(), - subtitle: Text('subtitle'), - leading: Text('leading'), - title: Text('title'), + subtitle: const Text('subtitle'), + leading: const Text('leading'), + title: const Text('title'), onTitleTap: () { tapped = true; }, - actions: [ + actions: const [ Text('action'), ], ), diff --git a/packages/stream_chat_flutter/test/src/typing_indicator_test.dart b/packages/stream_chat_flutter/test/src/typing_indicator_test.dart index 8698de91..cc9af663 100644 --- a/packages/stream_chat_flutter/test/src/typing_indicator_test.dart +++ b/packages/stream_chat_flutter/test/src/typing_indicator_test.dart @@ -67,14 +67,14 @@ void main() { client: client, child: StreamChannel( channel: channel, - child: Scaffold( + child: const Scaffold( body: TypingIndicator(), ), ), ), )); - expect(find.byKey(Key('typings')), findsOneWidget); + expect(find.byKey(const Key('typings')), findsOneWidget); }, ); } diff --git a/packages/stream_chat_flutter/test/src/unread_indicator_test.dart b/packages/stream_chat_flutter/test/src/unread_indicator_test.dart index 9b1b5e1e..29bc0d79 100644 --- a/packages/stream_chat_flutter/test/src/unread_indicator_test.dart +++ b/packages/stream_chat_flutter/test/src/unread_indicator_test.dart @@ -36,7 +36,7 @@ void main() { client: client, child: StreamChannel( channel: channel, - child: Scaffold( + child: const Scaffold( body: UnreadIndicator(), ), ), From 1c5175045d5af5201a7281cd2d919bb64510c4d5 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 6 May 2021 13:55:36 +0530 Subject: [PATCH 29/31] lint --- packages/stream_chat_flutter/pubspec.yaml | 58 +++++++++++------------ 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/packages/stream_chat_flutter/pubspec.yaml b/packages/stream_chat_flutter/pubspec.yaml index 2ef87189..8ac73bbf 100644 --- a/packages/stream_chat_flutter/pubspec.yaml +++ b/packages/stream_chat_flutter/pubspec.yaml @@ -9,41 +9,41 @@ environment: sdk: '>=2.12.0 <3.0.0' dependencies: + cached_network_image: ^3.0.0 + characters: ^1.1.0 + chewie: ^1.0.0 + collection: ^1.15.0 + dio: ^4.0.0 + ezanimation: ^0.5.0 + file_picker: ^3.0.1 flutter: sdk: flutter - stream_chat_flutter_core: ^2.0.0-nullsafety.0 + flutter_keyboard_visibility: ^5.0.1 + flutter_markdown: ^0.6.1 + flutter_portal: ^0.4.0 + flutter_slidable: ^0.6.0 + flutter_svg: ^0.22.0 + http_parser: ^4.0.0 + image_gallery_saver: ^1.6.9 + image_picker: ^0.7.4 + jiffy: ^4.1.0 + lottie: ^1.0.1 + meta: ^1.3.0 + path_provider: ^2.0.1 + photo_manager: ^1.1.4 + photo_view: ^0.11.1 rxdart: ^0.26.0 scrollable_positioned_list: ^0.2.0-nullsafety.0 - jiffy: ^4.1.0 - photo_view: ^0.11.1 - flutter_svg: ^0.22.0 - flutter_portal: ^0.4.0 - cached_network_image: ^3.0.0 - shimmer: ^2.0.0 - flutter_markdown: ^0.6.1 - url_launcher: ^6.0.3 - video_player: ^2.1.1 - chewie: ^1.0.0 - file_picker: ^3.0.1 - image_picker: ^0.7.4 - flutter_keyboard_visibility: ^5.0.1 - video_compress: ^3.0.0 - visibility_detector: ^0.2.0 - http_parser: ^4.0.0 - meta: ^1.3.0 - lottie: ^1.0.1 - substring_highlight: ^1.0.26 - flutter_slidable: ^0.6.0 - image_gallery_saver: ^1.6.9 share_plus: ^2.0.3 - photo_manager: ^1.1.4 - ezanimation: ^0.5.0 + shimmer: ^2.0.0 + stream_chat_flutter_core: ^2.0.0-nullsafety.0 + substring_highlight: ^1.0.26 synchronized: ^3.0.0 - dio: ^4.0.0 - characters: ^1.1.0 - path_provider: ^2.0.1 + url_launcher: ^6.0.3 + video_compress: ^3.0.0 + video_player: ^2.1.1 video_thumbnail: ^0.3.3 - collection: ^1.15.0 + visibility_detector: ^0.2.0 flutter: assets: @@ -56,7 +56,7 @@ flutter: dev_dependencies: flutter_test: sdk: flutter - mocktail: ^0.1.2 golden_toolkit: ^0.9.0 + mocktail: ^0.1.2 pedantic: ^1.11.0 From ba1ab4aed859bf9e4a575514dddcffada0ce1170 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 6 May 2021 14:05:50 +0530 Subject: [PATCH 30/31] lint --- .../lib/src/message_input.dart | 40 +++++++++---------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/message_input.dart b/packages/stream_chat_flutter/lib/src/message_input.dart index 13f553d7..44b54c24 100644 --- a/packages/stream_chat_flutter/lib/src/message_input.dart +++ b/packages/stream_chat_flutter/lib/src/message_input.dart @@ -476,7 +476,6 @@ class MessageInputState extends State { firstChild: IconButton( onPressed: () => setState(() => _actionsShrunk = false), icon: Transform.rotate( - alignment: Alignment.center, angle: (widget.actionsLocation == ActionsLocation.right || widget.actionsLocation == ActionsLocation.rightInside) ? pi @@ -495,28 +494,27 @@ class MessageInputState extends State { splashRadius: 24, ), secondChild: widget.disableAttachments && - !widget.showCommandsButton && - widget.actions?.isNotEmpty != true + !widget.showCommandsButton && + widget.actions?.isNotEmpty != true ? const Offstage() : FittedBox( - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - if (!widget.disableAttachments) _buildAttachmentButton(), - if (widget.showCommandsButton && - widget.editMessage == null && - StreamChannel.of(context) - .channel - .config - ?.commands - .isNotEmpty == - true) - _buildCommandButton(), - ...widget.actions ?? [], - ].insertBetween(const SizedBox(width: 8)), - ), - ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + if (!widget.disableAttachments) _buildAttachmentButton(), + if (widget.showCommandsButton && + widget.editMessage == null && + StreamChannel.of(context) + .channel + .config + ?.commands + .isNotEmpty == + true) + _buildCommandButton(), + ...widget.actions ?? [], + ].insertBetween(const SizedBox(width: 8)), + ), + ), duration: const Duration(milliseconds: 300), alignment: Alignment.center, ), From 18ce268e48da4a420b89eb954fb11aa0a324a76a Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 6 May 2021 11:48:26 +0200 Subject: [PATCH 31/31] use common analysis options --- ...ysis_options.yaml => analysis_options.yaml | 4 +- packages/stream_chat/analysis_options.yaml | 143 ----------------- packages/stream_chat/lib/src/api/channel.dart | 4 +- packages/stream_chat/lib/src/client.dart | 3 +- .../lib/src/db/chat_persistence_client.dart | 5 + .../lib/src/models/channel_model.dart | 2 +- packages/stream_chat/lib/src/models/user.dart | 2 +- .../example/lib/tutorial-part-2.dart | 2 +- .../analysis_options.yaml | 146 ------------------ .../lib/src/stream_channel.dart | 6 +- .../analysis_options.yaml | 145 ----------------- 11 files changed, 16 insertions(+), 446 deletions(-) rename packages/stream_chat_flutter/analysis_options.yaml => analysis_options.yaml (98%) delete mode 100644 packages/stream_chat/analysis_options.yaml delete mode 100644 packages/stream_chat_flutter_core/analysis_options.yaml delete mode 100644 packages/stream_chat_persistence/analysis_options.yaml diff --git a/packages/stream_chat_flutter/analysis_options.yaml b/analysis_options.yaml similarity index 98% rename from packages/stream_chat_flutter/analysis_options.yaml rename to analysis_options.yaml index 3c78646a..f0a87ea5 100644 --- a/packages/stream_chat_flutter/analysis_options.yaml +++ b/analysis_options.yaml @@ -1,5 +1,3 @@ -include: package:pedantic/analysis_options.yaml - analyzer: enable-experiment: - extension-methods @@ -7,6 +5,8 @@ analyzer: - lib/**/*.g.dart - example/** - lib/src/emoji + - lib/**/*.freezed.dart + - test/** linter: rules: diff --git a/packages/stream_chat/analysis_options.yaml b/packages/stream_chat/analysis_options.yaml deleted file mode 100644 index c0e14133..00000000 --- a/packages/stream_chat/analysis_options.yaml +++ /dev/null @@ -1,143 +0,0 @@ -analyzer: - exclude: - - lib/**/*.g.dart - - lib/**/*.freezed.dart - - example/* -linter: - rules: - - always_use_package_imports - - avoid_empty_else - - avoid_relative_lib_imports - - avoid_slow_async_io - - avoid_types_as_parameter_names - - cancel_subscriptions - - close_sinks - - control_flow_in_finally - - empty_statements - - hash_and_equals - - invariant_booleans - - iterable_contains_unrelated_type - - list_remove_unrelated_type - - literal_only_boolean_expressions - - no_adjacent_strings_in_list - - no_duplicate_case_values - - no_logic_in_create_state - - prefer_void_to_null - - test_types_in_equals - - throw_in_finally - - unnecessary_statements - - unrelated_type_equality_checks - - omit_local_variable_types - - use_key_in_widget_constructors - - 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 - - # To be added when null-safe: - # - cast_nullable_to_non_nullable - #- unnecessary_null_checks - # - tighten_type_of_initializing_formals - # - null_check_on_nullable_type_parameter \ No newline at end of file diff --git a/packages/stream_chat/lib/src/api/channel.dart b/packages/stream_chat/lib/src/api/channel.dart index 1674e5eb..a1eab825 100644 --- a/packages/stream_chat/lib/src/api/channel.dart +++ b/packages/stream_chat/lib/src/api/channel.dart @@ -646,7 +646,7 @@ class Channel { messageId: messageId, createdAt: now, type: type, - user: user!, + user: user, score: 1, extraData: extraData, ); @@ -654,7 +654,7 @@ class Channel { // Inserting at the 0th index as it's the latest reaction latestReactions.insert(0, newReaction); final ownReactions = [...latestReactions] - ..removeWhere((it) => it.userId != user.id); + ..removeWhere((it) => it.userId != user!.id); final newMessage = message.copyWith( reactionCounts: {...message.reactionCounts ?? {}} diff --git a/packages/stream_chat/lib/src/client.dart b/packages/stream_chat/lib/src/client.dart index a2bc6f77..c7d29737 100644 --- a/packages/stream_chat/lib/src/client.dart +++ b/packages/stream_chat/lib/src/client.dart @@ -1495,8 +1495,7 @@ class ClientState { Stream get userStream => _userController.stream; /// The current user - Map get users => - _usersController.value as Map; + Map get users => _usersController.value!; /// The current user as a stream Stream> get usersStream => _usersController.stream; diff --git a/packages/stream_chat/lib/src/db/chat_persistence_client.dart b/packages/stream_chat/lib/src/db/chat_persistence_client.dart index e9c21956..8f60482f 100644 --- a/packages/stream_chat/lib/src/db/chat_persistence_client.dart +++ b/packages/stream_chat/lib/src/db/chat_persistence_client.dart @@ -78,10 +78,15 @@ abstract class ChatPersistenceClient { getPinnedMessagesByCid(cid, messagePagination: pinnedMessagePagination), ]); return ChannelState( + // ignore: cast_nullable_to_non_nullable members: data[0] as List, + // ignore: cast_nullable_to_non_nullable read: data[1] as List, + // ignore: cast_nullable_to_non_nullable channel: data[2] as ChannelModel?, + // ignore: cast_nullable_to_non_nullable messages: data[3] as List, + // ignore: cast_nullable_to_non_nullable pinnedMessages: data[4] as List, ); } diff --git a/packages/stream_chat/lib/src/models/channel_model.dart b/packages/stream_chat/lib/src/models/channel_model.dart index 98d86539..14380592 100644 --- a/packages/stream_chat/lib/src/models/channel_model.dart +++ b/packages/stream_chat/lib/src/models/channel_model.dart @@ -112,7 +112,7 @@ class ChannelModel { /// Shortcut for channel name String get name => - extraData.containsKey('name') ? extraData['name'] as String : cid; + extraData.containsKey('name') ? extraData['name']! as String : cid; /// Serialize to json Map toJson() => Serialization.moveFromExtraDataToRoot( diff --git a/packages/stream_chat/lib/src/models/user.dart b/packages/stream_chat/lib/src/models/user.dart index 88a7440c..2cb8f8ed 100644 --- a/packages/stream_chat/lib/src/models/user.dart +++ b/packages/stream_chat/lib/src/models/user.dart @@ -83,7 +83,7 @@ class User { /// Shortcut for user name String get name { if (extraData.containsKey('name')) { - final name = extraData['name'] as String; + final name = extraData['name']! as String; if (name.isNotEmpty) return name; } return id; diff --git a/packages/stream_chat_flutter/example/lib/tutorial-part-2.dart b/packages/stream_chat_flutter/example/lib/tutorial-part-2.dart index d1b39774..1e198d61 100644 --- a/packages/stream_chat_flutter/example/lib/tutorial-part-2.dart +++ b/packages/stream_chat_flutter/example/lib/tutorial-part-2.dart @@ -58,7 +58,7 @@ class ChannelListPage extends StatelessWidget { child: ChannelListView( filter: Filter.in_( 'members', - [StreamChat.of(context).user.id], + [StreamChat.of(context).user!.id], ), sort: [SortOption('last_message_at')], pagination: PaginationParams( diff --git a/packages/stream_chat_flutter_core/analysis_options.yaml b/packages/stream_chat_flutter_core/analysis_options.yaml deleted file mode 100644 index cf09a170..00000000 --- a/packages/stream_chat_flutter_core/analysis_options.yaml +++ /dev/null @@ -1,146 +0,0 @@ -analyzer: - exclude: - - lib/**/*.g.dart - - lib/**/*.freezed.dart - - example/* - - test/* - -linter: - rules: - - always_use_package_imports - - avoid_empty_else - - avoid_relative_lib_imports - - avoid_slow_async_io - - avoid_types_as_parameter_names - - cancel_subscriptions - - close_sinks - - control_flow_in_finally - - empty_statements - - hash_and_equals - - invariant_booleans - - iterable_contains_unrelated_type - - list_remove_unrelated_type - - literal_only_boolean_expressions - - no_adjacent_strings_in_list - - no_duplicate_case_values - - no_logic_in_create_state - - prefer_void_to_null - - test_types_in_equals - - throw_in_finally - - unnecessary_statements - - unrelated_type_equality_checks - - omit_local_variable_types - - use_key_in_widget_constructors - - 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 - - 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 - - # To be added when null-safe: - # - cast_nullable_to_non_nullable - #- unnecessary_null_checks - # - tighten_type_of_initializing_formals - # - null_check_on_nullable_type_parameter \ No newline at end of file diff --git a/packages/stream_chat_flutter_core/lib/src/stream_channel.dart b/packages/stream_chat_flutter_core/lib/src/stream_channel.dart index 34f58faa..a6fd83b2 100644 --- a/packages/stream_chat_flutter_core/lib/src/stream_channel.dart +++ b/packages/stream_chat_flutter_core/lib/src/stream_channel.dart @@ -357,9 +357,9 @@ class StreamChannelState extends State { if (snapshot.hasError) { var message = snapshot.error.toString(); if (snapshot.error is DioError) { - final dioError = snapshot.error as DioError; - if (dioError.type == DioErrorType.response) { - message = dioError.message; + final dioError = snapshot.error as DioError?; + if (dioError?.type == DioErrorType.response) { + message = dioError!.message; } else { message = 'Check your connection and retry'; } diff --git a/packages/stream_chat_persistence/analysis_options.yaml b/packages/stream_chat_persistence/analysis_options.yaml deleted file mode 100644 index ff0fc87c..00000000 --- a/packages/stream_chat_persistence/analysis_options.yaml +++ /dev/null @@ -1,145 +0,0 @@ -analyzer: - exclude: - - lib/**/*.g.dart - - lib/**/*.freezed.dart - - example/* -linter: - rules: - - always_use_package_imports - - avoid_empty_else - - avoid_relative_lib_imports - - avoid_slow_async_io - - avoid_types_as_parameter_names - - cancel_subscriptions - - close_sinks - - control_flow_in_finally - - diagnostic_describe_all_properties - - empty_statements - - hash_and_equals - - invariant_booleans - - iterable_contains_unrelated_type - - list_remove_unrelated_type - - literal_only_boolean_expressions - - no_adjacent_strings_in_list - - no_duplicate_case_values - - no_logic_in_create_state - - prefer_void_to_null - - test_types_in_equals - - throw_in_finally - - unnecessary_statements - - unrelated_type_equality_checks - - omit_local_variable_types - - use_key_in_widget_constructors - - valid_regexps - - always_declare_return_types - - always_put_required_named_parameters_first - - 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 - - # To be added when null-safe: - # - cast_nullable_to_non_nullable - #- unnecessary_null_checks - # - tighten_type_of_initializing_formals - # - null_check_on_nullable_type_parameter \ No newline at end of file