diff --git a/lib/src/channel_list_view.dart b/lib/src/channel_list_view.dart index 33988b92..51c02611 100644 --- a/lib/src/channel_list_view.dart +++ b/lib/src/channel_list_view.dart @@ -65,6 +65,7 @@ class ChannelListView extends StatefulWidget { this.errorBuilder, this.emptyBuilder, this.onImageTap, + this.loadingBuilder, this.pullToRefresh = true, }) : super(key: key); @@ -79,6 +80,9 @@ class ChannelListView extends StatefulWidget { /// You can also filter other built-in channel fields. final Map filter; + /// The builder used while loading. + final WidgetBuilder loadingBuilder; + /// Query channels options. /// /// state: if true returns the Channel state @@ -224,9 +228,11 @@ class _ChannelListViewState extends State constraints: BoxConstraints( minHeight: viewportConstraints.maxHeight, ), - child: Center( - child: CircularProgressIndicator(), - ), + child: widget.loadingBuilder != null + ? widget.loadingBuilder(context) + : Center( + child: CircularProgressIndicator(), + ), ), ); }, @@ -339,6 +345,9 @@ class _ChannelListViewState extends State ), ); } else { + if (widget.loadingBuilder != null) { + return widget.loadingBuilder(context); + } return _buildQueryProgressIndicator(context, channelsProvider); } } diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index b30028e8..c8d089f1 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -27,6 +27,11 @@ enum ActionsLocation { right, } +enum SendButtonLocation { + inside, + outside, +} + enum DefaultAttachmentTypes { image, video, @@ -96,6 +101,8 @@ class MessageInput extends StatefulWidget { this.inputTextStyle, this.attachmentIconColor, this.autofocus = false, + this.sendButtonLocation = SendButtonLocation.inside, + this.animationDuration = const Duration(milliseconds: 300), }) : super(key: key); /// Message to edit @@ -141,6 +148,9 @@ class MessageInput extends StatefulWidget { /// The location of the custom actions final ActionsLocation actionsLocation; + /// The location of the send button + final SendButtonLocation sendButtonLocation; + /// Map that defines a thumbnail builder for an attachment type final Map attachmentThumbnailBuilders; @@ -148,6 +158,9 @@ class MessageInput extends StatefulWidget { /// `Theme.of(context).textTheme.bodyText2`. final TextStyle inputTextStyle; + /// The duration of the send button animation + final Duration animationDuration; + /// Color used for attachment icon. final Color attachmentIconColor; @@ -194,17 +207,26 @@ class MessageInputState extends State { }, child: Padding( padding: const EdgeInsets.all(8.0), - child: Stack( - clipBehavior: Clip.none, - children: [ - _buildBorder(context), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - _buildAttachments(), - _buildTextField(context), - ], + child: Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Expanded( + child: Stack( + clipBehavior: Clip.none, + children: [ + _buildBorder(context), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildAttachments(), + _buildTextField(context), + ], + ), + ], + ), ), + if (widget.sendButtonLocation == SendButtonLocation.outside) + _animateSendButton(context), ], ), ), @@ -221,14 +243,18 @@ class MessageInputState extends State { if (widget.actionsLocation == ActionsLocation.left) ...widget.actions ?? [], _buildTextInput(context), - _animateSendButton(context), if (widget.actionsLocation == ActionsLocation.right) ...widget.actions ?? [], + if (widget.sendButtonLocation == SendButtonLocation.inside) + _animateSendButton(context), ], ); } - AnimatedCrossFade _animateSendButton(BuildContext context) { + Widget _animateSendButton(BuildContext context) { + if (widget.animationDuration == Duration.zero) { + return _buildSendButton(context); + } return AnimatedCrossFade( crossFadeState: ((_messageIsPresent || _attachments.isNotEmpty) && _attachments.every((a) => a.uploaded == true)) @@ -236,7 +262,7 @@ class MessageInputState extends State { : CrossFadeState.showSecond, firstChild: _buildSendButton(context), secondChild: SizedBox(), - duration: Duration(milliseconds: 300), + duration: widget.animationDuration, alignment: Alignment.center, ); } @@ -851,12 +877,14 @@ class MessageInputState extends State { color: Colors.transparent, child: IconButton( key: Key('sendButton'), - onPressed: () { - sendMessage(); - }, + onPressed: (textEditingController.text.trim().isEmpty && + _attachments.isEmpty) + ? null + : () { + sendMessage(); + }, icon: Icon( Icons.send, - color: StreamChatTheme.of(context).accentColor, ), ), ), diff --git a/pubspec.yaml b/pubspec.yaml index 0da226b7..dd637568 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -23,7 +23,7 @@ dependencies: file_picker: ^2.0.12 image_picker: ^0.6.7+2 flutter_keyboard_visibility: ^4.0.1 - stream_chat: ^0.2.20 + stream_chat: ^0.2.21 mime: ^0.9.6+3 visibility_detector: ^0.1.5 http_parser: ^3.1.4