diff --git a/CHANGELOG.md b/CHANGELOG.md index 1de3bc7f..ef2bb9d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.1.1 + +- Add ThreadHeader + ## 0.0.1 - First release \ No newline at end of file diff --git a/README.md b/README.md index 77454051..cf1dda04 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ TODO ```yaml dependencies: - stream_chat_flutter: ^0.0.1 + stream_chat_flutter: ^0.1.1 ``` You should then run `flutter packages get` diff --git a/example/lib/custom_theme.dart b/example/lib/custom_theme.dart new file mode 100644 index 00000000..0f2a57d1 --- /dev/null +++ b/example/lib/custom_theme.dart @@ -0,0 +1,124 @@ +import 'package:flutter/material.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; + +void main() async { + final client = Client('qk4nn7rpcn75', logLevel: Level.INFO); + + await client.setUser( + User(id: 'wild-breeze-7'), + 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoid2lsZC1icmVlemUtNyJ9.VM2EX1EXOfgqa-bTH_3JzeY0T99ngWzWahSauP3dBMo', + ); + + runApp(MyApp(client)); +} + +class MyApp extends StatelessWidget { + final Client client; + + MyApp(this.client); + + @override + Widget build(BuildContext context) { + final theme = ThemeData( + primarySwatch: Colors.green, + ); + + return MaterialApp( + theme: theme, + home: Container( + child: StreamChat( + streamChatThemeData: StreamChatThemeData.fromTheme(theme).copyWith( + ownMessageTheme: MessageTheme( + messageBackgroundColor: Colors.black, + messageText: TextStyle( + color: Colors.white, + ), + avatarTheme: AvatarTheme( + borderRadius: BorderRadius.circular(8), + ), + ), + ), + client: client, + child: ChannelListPage(), + ), + ), + ); + } +} + +class ChannelListPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + body: ChannelListView( + filter: { + 'members': { + '\$in': [StreamChat.of(context).user.id], + } + }, + sort: [SortOption('last_message_at')], + pagination: PaginationParams( + limit: 20, + ), + channelWidget: ChannelPage(), + ), + ); + } +} + +class ChannelPage extends StatelessWidget { + const ChannelPage({ + Key key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: ChannelHeader(), + body: Column( + children: [ + Expanded( + child: MessageListView( + threadBuilder: (_, parentMessage) { + return ThreadPage( + parent: parentMessage, + ); + }, + ), + ), + MessageInput(), + ], + ), + ); + } +} + +class ThreadPage extends StatelessWidget { + final Message parent; + + ThreadPage({ + Key key, + this.parent, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: ThreadHeader( + parent: parent, + ), + body: Column( + children: [ + Expanded( + child: MessageListView( + parentMessage: parent, + ), + ), + MessageInput( + parentMessage: parent, + ), + ], + ), + ); + } +} diff --git a/example/lib/threads.dart b/example/lib/threads.dart index 20481baf..20f67f63 100644 --- a/example/lib/threads.dart +++ b/example/lib/threads.dart @@ -88,6 +88,9 @@ class ThreadPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( + appBar: ThreadHeader( + parent: parent, + ), body: Column( children: [ Expanded( diff --git a/lib/src/channel_preview.dart b/lib/src/channel_preview.dart index 14ab6980..669c608b 100644 --- a/lib/src/channel_preview.dart +++ b/lib/src/channel_preview.dart @@ -103,6 +103,8 @@ class ChannelPreview extends StatelessWidget { return '📷'; } else if (e.type == 'video') { return '🎬'; + } else if (e.type == 'giphy') { + return 'GIF'; } return null; }) diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index 4db16f9d..08830143 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -218,7 +218,7 @@ class _MessageListViewState extends State { } Widget _buildBottomMessage( - StreamChannelState channel, + StreamChannelState streamChannel, Message previousMessage, Message message, BuildContext context, @@ -243,9 +243,9 @@ class _MessageListViewState extends State { key: ValueKey('BOTTOM-MESSAGE'), onVisibilityChanged: (visibility) { _isBottom = visibility.visibleBounds != Rect.zero; - if (_isBottom) { - if (channel.channel.state.unreadCount > 0) { - channel.channel.markRead(); + if (_isBottom && streamChannel.channel.config.readEvents) { + if (streamChannel.channel.state.unreadCount > 0) { + streamChannel.channel.markRead(); } } }, diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 9c3aa322..e6ecf5e7 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -41,11 +41,17 @@ class _MessageWidgetState extends State final Map _videoControllers = {}; final Map _chuwieControllers = {}; + MessageTheme messageTheme; + StreamChatState streamChat; + StreamChannelState streamChannel; + @override Widget build(BuildContext context) { super.build(context); - final streamChat = StreamChat.of(context); + streamChat = StreamChat.of(context); + streamChannel = StreamChannel.of(context); + final currentUserId = streamChat.client.state.user.id; final messageUserId = widget.message.user.id; final previousUserId = widget.previousMessage?.user?.id; @@ -56,6 +62,10 @@ class _MessageWidgetState extends State final alignment = isMyMessage ? Alignment.centerRight : Alignment.centerLeft; + messageTheme = isMyMessage + ? StreamChatTheme.of(context).ownMessageTheme + : StreamChatTheme.of(context).otherMessageTheme; + Widget child; if (widget.message.type == 'deleted') { @@ -67,7 +77,9 @@ class _MessageWidgetState extends State isMyMessage ? CrossAxisAlignment.end : CrossAxisAlignment.start, children: [ _buildBubble(context, isMyMessage, isLastUser), - _buildThreadIndicator(context, isMyMessage), + streamChannel.channel.config.replies + ? _buildThreadIndicator(context, isMyMessage) + : SizedBox(), isNextUser ? SizedBox() : _buildTimestamp(isMyMessage, alignment), ], ), @@ -121,9 +133,10 @@ class _MessageWidgetState extends State ), child: Text( 'This message was deleted...', - style: StreamChatTheme.of(context).messageTheme.messageText.copyWith( - fontStyle: FontStyle.italic, - ), + style: messageTheme.messageText.copyWith( + fontStyle: FontStyle.italic, + color: Colors.black, + ), ), ), ); @@ -133,7 +146,7 @@ class _MessageWidgetState extends State var row = [ Text( 'Replies: ${widget.message.replyCount}', - style: StreamChatTheme.of(context).messageTheme.replies, + style: messageTheme.replies, ), Transform( transform: Matrix4.rotationY(isMyMessage ? 0 : pi), @@ -220,13 +233,11 @@ class _MessageWidgetState extends State Text( attachment.title, overflow: TextOverflow.ellipsis, - style: StreamChatTheme.of(context) - .messageTheme - .messageText - .copyWith( - color: Colors.blue, - fontWeight: FontWeight.bold, - ), + style: + messageTheme.messageText.copyWith( + color: Colors.blue, + fontWeight: FontWeight.bold, + ), ), Text( Uri.parse(attachment.thumbUrl) @@ -238,9 +249,7 @@ class _MessageWidgetState extends State .reversed .join('.'), overflow: TextOverflow.ellipsis, - style: StreamChatTheme.of(context) - .messageTheme - .createdAt, + style: messageTheme.createdAt, ), ], ), @@ -284,12 +293,14 @@ class _MessageWidgetState extends State ? CrossAxisAlignment.end : CrossAxisAlignment.start, children: [ - Align( - child: _buildReactions(isMyMessage), - alignment: isMyMessage - ? Alignment.centerLeft - : Alignment.centerRight, - ), + streamChannel.channel.config.reactions + ? Align( + child: _buildReactions(isMyMessage), + alignment: isMyMessage + ? Alignment.centerLeft + : Alignment.centerRight, + ) + : SizedBox(), Stack( overflow: Overflow.visible, children: [ @@ -318,12 +329,22 @@ class _MessageWidgetState extends State onTapLink: (link) { _launchURL(link); }, - styleSheet: - MarkdownStyleSheet.fromTheme(Theme.of(context)) - .copyWith( - p: StreamChatTheme.of(context) - .messageTheme - .messageText, + styleSheet: MarkdownStyleSheet.fromTheme( + Theme.of(context).copyWith( + textTheme: Theme.of(context).textTheme.apply( + bodyColor: messageTheme.messageText.color, + decoration: + messageTheme.messageText.decoration, + decorationColor: messageTheme + .messageText.decorationColor, + decorationStyle: messageTheme + .messageText.decorationStyle, + fontFamily: + messageTheme.messageText.fontFamily, + ), + ), + ).copyWith( + p: messageTheme.messageText, ), ), ), @@ -345,6 +366,11 @@ class _MessageWidgetState extends State } void _showMessageBottomSheet(BuildContext context, bool isMyMessage) { + if (!streamChannel.channel.config.reactions && + !streamChannel.channel.config.replies) { + return; + } + showModalBottomSheet( clipBehavior: Clip.hardEdge, shape: RoundedRectangleBorder( @@ -366,47 +392,52 @@ class _MessageWidgetState extends State children: [ Container( color: Colors.black87, - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.center, - mainAxisSize: MainAxisSize.min, - children: reactionToEmoji.keys.map((reactionType) { - final ownReactionIndex = widget.message.ownReactions - .indexWhere( - (reaction) => reaction.type == reactionType); - return Column( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - IconButton( - iconSize: fontSize + 10, - icon: Text( - reactionToEmoji[reactionType], - style: textStyle, - ), - onPressed: () { - if (ownReactionIndex != -1) { - removeReaction(reactionType); - } else { - sendReaction(reactionType); - } - }, - ), - ownReactionIndex != -1 - ? Padding( - padding: const EdgeInsets.only(bottom: 4.0), - child: Text( - widget.message - .ownReactions[ownReactionIndex].score - .toString(), - style: TextStyle(color: Colors.white), + child: streamChannel.channel.config.reactions + ? Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: reactionToEmoji.keys.map((reactionType) { + final ownReactionIndex = widget.message.ownReactions + .indexWhere((reaction) => + reaction.type == reactionType); + return Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + IconButton( + iconSize: fontSize + 10, + icon: Text( + reactionToEmoji[reactionType], + style: textStyle, ), - ) - : SizedBox(), - ], - ); - }).toList(), - ), + onPressed: () { + if (ownReactionIndex != -1) { + removeReaction(reactionType); + } else { + sendReaction(reactionType); + } + }, + ), + ownReactionIndex != -1 + ? Padding( + padding: + const EdgeInsets.only(bottom: 4.0), + child: Text( + widget + .message + .ownReactions[ownReactionIndex] + .score + .toString(), + style: TextStyle(color: Colors.white), + ), + ) + : SizedBox(), + ], + ); + }).toList(), + ) + : SizedBox(), ), isMyMessage ? FlatButton( @@ -428,19 +459,21 @@ class _MessageWidgetState extends State }, ) : SizedBox(), - FlatButton( - child: Padding( - padding: const EdgeInsets.all(28.0), - child: Text( - 'Start a thread', - style: Theme.of(context).textTheme.headline, - ), - ), - onPressed: () { - Navigator.pop(context); - widget.onThreadTap(widget.message); - }, - ), + streamChannel.channel.config.replies + ? FlatButton( + child: Padding( + padding: const EdgeInsets.all(28.0), + child: Text( + 'Start a thread', + style: Theme.of(context).textTheme.headline, + ), + ), + onPressed: () { + Navigator.pop(context); + widget.onThreadTap(widget.message); + }, + ) + : SizedBox(), ], ), ); @@ -501,16 +534,12 @@ class _MessageWidgetState extends State }; void sendReaction(String reactionType) { - StreamChannel.of(context) - .channel - .sendReaction(widget.message.id, reactionType); + streamChannel.channel.sendReaction(widget.message.id, reactionType); Navigator.of(context).pop(); } void removeReaction(String reactionType) { - StreamChannel.of(context) - .channel - .deleteReaction(widget.message.id, reactionType); + streamChannel.channel.deleteReaction(widget.message.id, reactionType); Navigator.of(context).pop(); } @@ -602,7 +631,7 @@ class _MessageWidgetState extends State padding: const EdgeInsets.only(top: 5.0), child: Text( formatDate(widget.message.createdAt.toLocal(), [HH, ':', nn]), - style: StreamChatTheme.of(context).messageTheme.createdAt, + style: messageTheme.createdAt, ), ); } @@ -616,11 +645,7 @@ class _MessageWidgetState extends State topRight: Radius.circular((isMyMessage && isLastUser) ? 2 : 16), bottomRight: Radius.circular(isMyMessage ? 2 : 16), ), - color: isMyMessage - ? StreamChatTheme.of(context).messageTheme.ownMessageBackgroundColor - : StreamChatTheme.of(context) - .messageTheme - .otherMessageBackgroundColor, + color: messageTheme.messageBackgroundColor, ); } diff --git a/lib/src/stream_chat.dart b/lib/src/stream_chat.dart index 2ce338a5..fddf42de 100644 --- a/lib/src/stream_chat.dart +++ b/lib/src/stream_chat.dart @@ -107,20 +107,30 @@ class StreamChatState extends State { messageInputButtonTheme: themeData?.channelTheme?.messageInputButtonTheme, ), - messageTheme: defaultTheme.messageTheme.copyWith( - replies: themeData?.messageTheme?.replies, - createdAt: themeData?.messageTheme?.createdAt, - messageText: themeData?.messageTheme?.messageText, - otherMessageBackgroundColor: - themeData?.messageTheme?.otherMessageBackgroundColor, - ownMessageBackgroundColor: - themeData?.messageTheme?.ownMessageBackgroundColor, - fontFamily: themeData?.messageTheme?.fontFamily, - messageAuthor: themeData?.messageTheme?.messageAuthor, - messageMention: themeData?.messageTheme?.messageMention, - avatarTheme: defaultTheme.messageTheme.avatarTheme.copyWith( - constraints: themeData?.messageTheme?.avatarTheme?.constraints, - borderRadius: themeData?.messageTheme?.avatarTheme?.borderRadius, + ownMessageTheme: defaultTheme.ownMessageTheme.copyWith( + replies: themeData?.ownMessageTheme?.replies, + createdAt: themeData?.ownMessageTheme?.createdAt, + messageText: themeData?.ownMessageTheme?.messageText, + messageBackgroundColor: + themeData?.ownMessageTheme?.messageBackgroundColor, + messageAuthor: themeData?.ownMessageTheme?.messageAuthor, + messageMention: themeData?.ownMessageTheme?.messageMention, + avatarTheme: defaultTheme.ownMessageTheme.avatarTheme.copyWith( + constraints: themeData?.ownMessageTheme?.avatarTheme?.constraints, + borderRadius: themeData?.ownMessageTheme?.avatarTheme?.borderRadius, + ), + ), + otherMessageTheme: defaultTheme.otherMessageTheme.copyWith( + replies: themeData?.otherMessageTheme?.replies, + createdAt: themeData?.otherMessageTheme?.createdAt, + messageText: themeData?.otherMessageTheme?.messageText, + messageBackgroundColor: + themeData?.otherMessageTheme?.messageBackgroundColor, + messageAuthor: themeData?.otherMessageTheme?.messageAuthor, + messageMention: themeData?.otherMessageTheme?.messageMention, + avatarTheme: defaultTheme.otherMessageTheme.avatarTheme.copyWith( + constraints: themeData?.otherMessageTheme?.avatarTheme?.constraints, + borderRadius: themeData?.otherMessageTheme?.avatarTheme?.borderRadius, ), ), accentColor: themeData?.accentColor, diff --git a/lib/src/stream_chat_theme.dart b/lib/src/stream_chat_theme.dart index c3db901f..6deb8370 100644 --- a/lib/src/stream_chat_theme.dart +++ b/lib/src/stream_chat_theme.dart @@ -28,7 +28,8 @@ class StreamChatThemeData { final Color accentColor; final ChannelPreviewTheme channelPreviewTheme; final ChannelTheme channelTheme; - final MessageTheme messageTheme; + final MessageTheme ownMessageTheme; + final MessageTheme otherMessageTheme; StreamChatThemeData({ this.primaryColor, @@ -36,7 +37,8 @@ class StreamChatThemeData { this.accentColor, this.channelPreviewTheme, this.channelTheme, - this.messageTheme, + this.otherMessageTheme, + this.ownMessageTheme, }); factory StreamChatThemeData.fromTheme(ThemeData theme) { @@ -52,8 +54,13 @@ class StreamChatThemeData { theme.accentColor, ]), ), - messageTheme: MessageTheme( - replies: defaultTheme.messageTheme.replies.copyWith( + ownMessageTheme: MessageTheme( + replies: defaultTheme.ownMessageTheme.replies.copyWith( + color: theme.accentColor, + ), + ), + otherMessageTheme: MessageTheme( + replies: defaultTheme.ownMessageTheme.replies.copyWith( color: theme.accentColor, ), ), @@ -66,7 +73,8 @@ class StreamChatThemeData { Color accentColor, ChannelPreviewTheme channelPreviewTheme, ChannelTheme channelTheme, - MessageTheme messageTheme, + MessageTheme ownMessageTheme, + MessageTheme otherMessageTheme, }) => StreamChatThemeData( primaryColor: primaryColor ?? this.primaryColor, @@ -97,27 +105,40 @@ class StreamChatThemeData { this.channelTheme.inputBackground, ) ?? this.channelTheme, - messageTheme: messageTheme?.copyWith( - messageText: - messageTheme?.messageText ?? this.messageTheme.messageText, - messageAuthor: messageTheme?.messageAuthor ?? - this.messageTheme.messageAuthor, - messageMention: messageTheme?.messageMention ?? - this.messageTheme.messageMention, - createdAt: messageTheme?.createdAt ?? this.messageTheme.createdAt, - replies: messageTheme?.replies ?? this.messageTheme.replies, - fontFamily: - messageTheme?.fontFamily ?? this.messageTheme.fontFamily, - ownMessageBackgroundColor: - messageTheme?.ownMessageBackgroundColor ?? - this.messageTheme.ownMessageBackgroundColor, - otherMessageBackgroundColor: - messageTheme?.otherMessageBackgroundColor ?? - this.messageTheme.otherMessageBackgroundColor, - avatarTheme: - messageTheme?.avatarTheme ?? this.messageTheme.avatarTheme, + ownMessageTheme: ownMessageTheme?.copyWith( + messageText: ownMessageTheme?.messageText ?? + this.ownMessageTheme.messageText, + messageAuthor: ownMessageTheme?.messageAuthor ?? + this.ownMessageTheme.messageAuthor, + messageMention: ownMessageTheme?.messageMention ?? + this.ownMessageTheme.messageMention, + createdAt: + ownMessageTheme?.createdAt ?? this.ownMessageTheme.createdAt, + replies: ownMessageTheme?.replies ?? this.ownMessageTheme.replies, + messageBackgroundColor: ownMessageTheme?.messageBackgroundColor ?? + this.ownMessageTheme.messageBackgroundColor, + avatarTheme: ownMessageTheme?.avatarTheme ?? + this.ownMessageTheme.avatarTheme, ) ?? - this.messageTheme, + this.ownMessageTheme, + otherMessageTheme: otherMessageTheme?.copyWith( + messageText: otherMessageTheme?.messageText ?? + this.otherMessageTheme.messageText, + messageAuthor: otherMessageTheme?.messageAuthor ?? + this.otherMessageTheme.messageAuthor, + messageMention: otherMessageTheme?.messageMention ?? + this.otherMessageTheme.messageMention, + createdAt: otherMessageTheme?.createdAt ?? + this.otherMessageTheme.createdAt, + replies: + otherMessageTheme?.replies ?? this.otherMessageTheme.replies, + messageBackgroundColor: + otherMessageTheme?.messageBackgroundColor ?? + this.otherMessageTheme.messageBackgroundColor, + avatarTheme: otherMessageTheme?.avatarTheme ?? + this.otherMessageTheme.avatarTheme, + ) ?? + this.otherMessageTheme, ); static StreamChatThemeData getDefaultTheme(ThemeData theme) { @@ -174,7 +195,7 @@ class StreamChatThemeData { Color(0xFF0076FF), ]), ), - messageTheme: MessageTheme( + ownMessageTheme: MessageTheme( messageText: TextStyle( fontSize: 15, color: Colors.black, @@ -188,8 +209,30 @@ class StreamChatThemeData { fontWeight: FontWeight.bold, fontSize: 12, ), - ownMessageBackgroundColor: Color(0xffebebeb), - otherMessageBackgroundColor: Colors.white, + messageBackgroundColor: Color(0xffebebeb), + avatarTheme: AvatarTheme( + borderRadius: BorderRadius.circular(20), + constraints: BoxConstraints.tightFor( + height: 32, + width: 32, + ), + ), + ), + otherMessageTheme: MessageTheme( + messageText: TextStyle( + fontSize: 15, + color: Colors.black, + ), + createdAt: TextStyle( + color: Colors.black.withOpacity(.5), + fontSize: 11, + ), + replies: TextStyle( + color: accentColor, + fontWeight: FontWeight.bold, + fontSize: 12, + ), + messageBackgroundColor: Colors.white, avatarTheme: AvatarTheme( borderRadius: BorderRadius.circular(20), constraints: BoxConstraints.tightFor( @@ -268,9 +311,7 @@ class MessageTheme { final TextStyle messageMention; final TextStyle createdAt; final TextStyle replies; - final String fontFamily; - final Color ownMessageBackgroundColor; - final Color otherMessageBackgroundColor; + final Color messageBackgroundColor; final AvatarTheme avatarTheme; const MessageTheme({ @@ -278,9 +319,7 @@ class MessageTheme { this.messageText, this.messageAuthor, this.messageMention, - this.fontFamily, - this.ownMessageBackgroundColor, - this.otherMessageBackgroundColor, + this.messageBackgroundColor, this.avatarTheme, this.createdAt, }); @@ -291,8 +330,7 @@ class MessageTheme { TextStyle messageMention, TextStyle createdAt, TextStyle replies, - String fontFamily, - Color ownMessageBackgroundColor, + Color messageBackgroundColor, Color otherMessageBackgroundColor, AvatarTheme avatarTheme, }) => @@ -301,11 +339,8 @@ class MessageTheme { messageAuthor: messageAuthor ?? this.messageAuthor, messageMention: messageMention ?? this.messageMention, createdAt: createdAt ?? this.createdAt, - fontFamily: fontFamily ?? this.fontFamily, - ownMessageBackgroundColor: - ownMessageBackgroundColor ?? this.ownMessageBackgroundColor, - otherMessageBackgroundColor: - otherMessageBackgroundColor ?? this.otherMessageBackgroundColor, + messageBackgroundColor: + messageBackgroundColor ?? this.messageBackgroundColor, avatarTheme: avatarTheme ?? this.avatarTheme, replies: replies ?? this.replies, ); diff --git a/lib/src/thread_header.dart b/lib/src/thread_header.dart new file mode 100644 index 00000000..3421fa0a --- /dev/null +++ b/lib/src/thread_header.dart @@ -0,0 +1,87 @@ +import 'package:flutter/material.dart'; +import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; + +import 'stream_channel.dart'; + +class ThreadHeader extends StatelessWidget implements PreferredSizeWidget { + final bool showBackButton; + final VoidCallback onBackPressed; + final Message parent; + + ThreadHeader({ + Key key, + @required this.parent, + this.showBackButton = true, + this.onBackPressed, + }) : preferredSize = Size.fromHeight(kToolbarHeight), + super(key: key); + + @override + Widget build(BuildContext context) { + final channel = StreamChannel.of(context).channel; + return AppBar( + automaticallyImplyLeading: false, + elevation: 1, + backgroundColor: + StreamChatTheme.of(context).channelTheme.channelHeaderTheme.color, + actions: [ + Container( + child: showBackButton ? _buildBackButton(context) : Container(), + ), + ], + centerTitle: false, + title: Text.rich( + TextSpan( + text: 'Thread', + children: [ + TextSpan( + text: + ' ${parent.replyCount} ${parent.replyCount == 1 ? 'reply' : 'replies'}', + style: StreamChatTheme.of(context) + .channelTheme + .channelHeaderTheme + .lastMessageAt, + ), + ], + ), + style: + StreamChatTheme.of(context).channelTheme.channelHeaderTheme.title, + ), + ); + } + + Padding _buildBackButton(BuildContext context) { + return Padding( + padding: const EdgeInsets.all(14.0), + child: AspectRatio( + aspectRatio: 1, + child: RawMaterialButton( + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(4)), + elevation: 0, + highlightElevation: 0, + focusElevation: 0, + disabledElevation: 0, + hoverElevation: 0, + onPressed: () { + if (onBackPressed != null) { + onBackPressed(); + } else { + Navigator.of(context).pop(); + } + }, + fillColor: Colors.black.withOpacity(.1), + padding: EdgeInsets.all(4), + child: Icon( + Icons.close, + size: 15, + color: Colors.black, + ), + ), + ), + ); + } + + @override + final Size preferredSize; +} diff --git a/lib/src/user_avatar.dart b/lib/src/user_avatar.dart index e0650b62..4c78b254 100644 --- a/lib/src/user_avatar.dart +++ b/lib/src/user_avatar.dart @@ -19,10 +19,12 @@ class UserAvatar extends StatelessWidget { return Container( padding: const EdgeInsets.all(4), constraints: - StreamChatTheme.of(context).messageTheme.avatarTheme.constraints, + StreamChatTheme.of(context).ownMessageTheme.avatarTheme.constraints, decoration: BoxDecoration( - borderRadius: - StreamChatTheme.of(context).messageTheme.avatarTheme.borderRadius, + borderRadius: StreamChatTheme.of(context) + .ownMessageTheme + .avatarTheme + .borderRadius, color: StreamChatTheme.of(context).accentColor, ), child: user.extraData?.containsKey('image') ?? false diff --git a/lib/stream_chat_flutter.dart b/lib/stream_chat_flutter.dart index 1f164781..3c41b7f0 100644 --- a/lib/stream_chat_flutter.dart +++ b/lib/stream_chat_flutter.dart @@ -11,3 +11,4 @@ export 'src/message_widget.dart'; export 'src/stream_channel.dart'; export 'src/stream_chat.dart'; export 'src/stream_chat_theme.dart'; +export 'src/thread_header.dart'; diff --git a/pubspec.yaml b/pubspec.yaml index 3ee0f8b4..3f13ea59 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: stream_chat_flutter homepage: https://github.com/GetStream/stream-chat-flutter description: Stream Chat official Flutter SDK. Build your own chat experience using Dart and Flutter. -version: 0.0.1 +version: 0.1.1 environment: sdk: ">=2.1.0 <3.0.0" @@ -18,8 +18,7 @@ dependencies: url_launcher: ^5.4.1 video_player: ^0.10.7 chewie: ^0.9.8+1 - animations: ^1.0.0+3 - stream_chat: ^0.1.10 + stream_chat: ^0.1.11 dev_dependencies: pedantic: ^1.8.0+1