diff --git a/analysis_options.yaml b/analysis_options.yaml index fedac90d..acc17647 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -1,61 +1,61 @@ -include: package:pedantic/analysis_options.yaml - -analyzer: - exclude: - - lib/**/*.g.dart - - example/* - -linter: - rules: - # 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 - - avoid_empty_else - - avoid_init_to_null - - avoid_return_types_on_setters - - avoid_web_libraries_in_flutter - - await_only_futures - - camel_case_types - - 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 - - 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 - - valid_regexps +#include: package:pedantic/analysis_options.yaml +# +#analyzer: +# exclude: +# - lib/**/*.g.dart +# - example/* +# +#linter: +# rules: +# # 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 +# - avoid_empty_else +# - avoid_init_to_null +# - avoid_return_types_on_setters +# - avoid_web_libraries_in_flutter +# - await_only_futures +# - camel_case_types +# - 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 +# - 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 +# - valid_regexps diff --git a/example/lib/customize_channel_preview.dart b/example/lib/customize_channel_preview.dart index 68022b85..949624d1 100644 --- a/example/lib/customize_channel_preview.dart +++ b/example/lib/customize_channel_preview.dart @@ -72,18 +72,17 @@ class ChannelListPage extends StatelessWidget { } Widget _channelPreviewBuilder(BuildContext context, Channel channel) { - final lastMessage = channel.state.messages.reversed - .firstWhere((message) => message.type != "deleted"); + final lastMessage = channel.state.messages.reversed.firstWhere( + (message) => message.type != "deleted", + orElse: () => null, + ); final subtitle = (lastMessage == null ? "nothing yet" : lastMessage.text); final opacity = channel.state.unreadCount > .0 ? 1.0 : 0.5; return ListTile( - leading: ChannelImage( - channel: channel, - ), + leading: ChannelImage(), title: ChannelName( - channel: channel, textStyle: StreamChatTheme.of(context).channelPreviewTheme.title.copyWith( color: Colors.black.withOpacity(opacity), diff --git a/example/lib/main.dart b/example/lib/main.dart index 3fb47119..2da40b3b 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -65,12 +65,28 @@ class ChannelPage extends StatelessWidget { body: Column( children: [ Expanded( - child: MessageListView( - threadBuilder: (_, parentMessage) { - return ThreadPage( - parent: parentMessage, - ); - }, + child: Stack( + children: [ + MessageListView( + threadBuilder: (_, parentMessage) { + return ThreadPage( + parent: parentMessage, + ); + }, + ), + Positioned.fill( + child: Align( + alignment: Alignment.bottomRight, + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 8.0, + vertical: 4, + ), + child: TypingIndicator(), + ), + ), + ), + ], ), ), MessageInput(), @@ -101,9 +117,10 @@ class ThreadPage extends StatelessWidget { parentMessage: parent, ), ), - MessageInput( - parentMessage: parent, - ), + if (parent.type != 'deleted') + MessageInput( + parentMessage: parent, + ), ], ), ); diff --git a/example/pubspec.yaml b/example/pubspec.yaml index d683e8c6..2968dbca 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -4,12 +4,11 @@ description: A new Flutter project. version: 1.0.0+1 environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.2.2 <3.0.0" dependencies: flutter: sdk: flutter - cupertino_icons: ^0.1.2 stream_chat_flutter: path: ../ diff --git a/lib/src/channel_header.dart b/lib/src/channel_header.dart index 889129b8..f2059c42 100644 --- a/lib/src/channel_header.dart +++ b/lib/src/channel_header.dart @@ -78,7 +78,9 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget { padding: const EdgeInsets.only(right: 10.0), child: Stack( children: [ - Center(child: ChannelImage(channel: channel)), + Center( + child: ChannelImage(), + ), ], ), ), @@ -88,7 +90,6 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget { crossAxisAlignment: CrossAxisAlignment.center, children: [ ChannelName( - channel: channel, textStyle: StreamChatTheme.of(context) .channelTheme .channelHeaderTheme diff --git a/lib/src/channel_image.dart b/lib/src/channel_image.dart index f1c98add..8f624bf0 100644 --- a/lib/src/channel_image.dart +++ b/lib/src/channel_image.dart @@ -45,7 +45,7 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; class ChannelImage extends StatelessWidget { const ChannelImage({ Key key, - @required this.channel, + this.channel, this.size = 40, }) : super(key: key); @@ -57,6 +57,7 @@ class ChannelImage extends StatelessWidget { @override Widget build(BuildContext context) { + final channel = this.channel ?? StreamChannel.of(context).channel; return StreamBuilder>( stream: channel.extraDataStream, initialData: channel.extraData, diff --git a/lib/src/channel_name.dart b/lib/src/channel_name.dart index 63f332d5..f2f27244 100644 --- a/lib/src/channel_name.dart +++ b/lib/src/channel_name.dart @@ -1,13 +1,15 @@ import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; +import 'stream_channel.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. class ChannelName extends StatelessWidget { const ChannelName({ Key key, - @required this.channel, + this.channel, this.textStyle, }) : super(key: key); @@ -19,6 +21,7 @@ class ChannelName extends StatelessWidget { @override Widget build(BuildContext context) { + final channel = this.channel ?? StreamChannel.of(context).channel; return StreamBuilder>( stream: channel.extraDataStream, initialData: channel.extraData, diff --git a/lib/src/channel_preview.dart b/lib/src/channel_preview.dart index 13be1151..5021df5c 100644 --- a/lib/src/channel_preview.dart +++ b/lib/src/channel_preview.dart @@ -37,14 +37,11 @@ class ChannelPreview extends StatelessWidget { onTap: () { onTap(channel); }, - leading: ChannelImage( - channel: channel, - ), + leading: ChannelImage(), title: ChannelName( textStyle: StreamChatTheme.of(context).channelPreviewTheme.title, - channel: channel, ), - subtitle: _buildSubtitle(), + subtitle: _buildSubtitle(context), trailing: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.end, @@ -81,29 +78,23 @@ class ChannelPreview extends StatelessWidget { ); } - Widget _buildSubtitle() { - return StreamBuilder>( - stream: channel.state.typingEventsStream, - initialData: channel.state.typingEvents, - builder: (context, snapshot) { - final typings = snapshot.data; - final opacity = channel.state.unreadCount > 0 ? 1.0 : 0.5; - return typings.isNotEmpty - ? TypingIndicator( - typings: typings, - style: StreamChatTheme.of(context) + Widget _buildSubtitle(BuildContext context) { + final opacity = channel.state.unreadCount > 0 ? 1.0 : 0.5; + return Align( + alignment: Alignment.centerLeft, + child: TypingIndicator( + channel: channel, + alternativeWidget: _buildLastMessage(context, opacity), + style: + StreamChatTheme.of(context).channelPreviewTheme.subtitle.copyWith( + color: StreamChatTheme.of(context) .channelPreviewTheme .subtitle - .copyWith( - color: StreamChatTheme.of(context) - .channelPreviewTheme - .subtitle - .color - .withOpacity(opacity), - ), - ) - : _buildLastMessage(context, opacity); - }); + .color + .withOpacity(opacity), + ), + ), + ); } Widget _buildLastMessage(BuildContext context, double opacity) { diff --git a/lib/src/typing_indicator.dart b/lib/src/typing_indicator.dart index e63601ba..6df9db98 100644 --- a/lib/src/typing_indicator.dart +++ b/lib/src/typing_indicator.dart @@ -1,11 +1,13 @@ import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter/src/stream_channel.dart'; /// Widget to show the current list of typing users class TypingIndicator extends StatelessWidget { const TypingIndicator({ Key key, - @required this.typings, + this.channel, + this.alternativeWidget = const SizedBox(), this.style, }) : super(key: key); @@ -13,14 +15,32 @@ class TypingIndicator extends StatelessWidget { final TextStyle style; /// List of typing users - final List typings; + final Channel channel; + + /// Widget built when no typings is happening + final Widget alternativeWidget; @override Widget build(BuildContext context) { - return Text( - '${typings.map((u) => u.name).join(',')} ${typings.length == 1 ? 'is' : 'are'} typing...', - maxLines: 1, - style: style, + final channelState = + channel?.state ?? StreamChannel.of(context).channel.state; + return StreamBuilder>( + initialData: channelState.typingEvents, + stream: channelState.typingEventsStream, + builder: (context, snapshot) { + return AnimatedSwitcher( + duration: Duration(milliseconds: 300), + child: snapshot.data.isNotEmpty + ? Text( + '${snapshot.data.map((u) => u.name).join(',')} ${snapshot.data.length == 1 ? 'is' : 'are'} typing...', + maxLines: 1, + style: style, + ) + : Container( + child: alternativeWidget, + ), + ); + }, ); } } diff --git a/pubspec.yaml b/pubspec.yaml index 30f50e06..406be90e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -4,18 +4,18 @@ description: Stream Chat official Flutter SDK. Build your own chat experience us version: 0.1.8 environment: - sdk: ">=2.2.2 <3.0.0" + sdk: ">=2.3.0 <3.0.0" dependencies: flutter: sdk: flutter rxdart: ^0.23.1 - flutter_widgets: ^0.1.10 + flutter_widgets: ^0.1.11 jiffy: ^3.0.0 cached_network_image: ^2.0.0 - flutter_markdown: ^0.3.3 - url_launcher: ^5.4.1 - video_player: ^0.10.7 + flutter_markdown: ^0.3.4 + url_launcher: ^5.4.2 + video_player: ^0.10.8+1 chewie: ^0.9.8+1 file_picker: ^1.4.3+2 image_picker: ^0.6.3+4 @@ -23,4 +23,4 @@ dependencies: stream_chat: ^0.1.17 dev_dependencies: - pedantic: ^1.8.0+1 + pedantic: ^1.9.0