From 874002e8e74cd66f58ed6d30392e9b051f2895f5 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 10 Sep 2021 18:19:23 +0530 Subject: [PATCH 01/27] fix(ui): Remove `FittedBox` from actions widget. Signed-off-by: xsahil03x --- .../lib/src/message_input.dart | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/message_input.dart b/packages/stream_chat_flutter/lib/src/message_input.dart index 9646608c..516f6f40 100644 --- a/packages/stream_chat_flutter/lib/src/message_input.dart +++ b/packages/stream_chat_flutter/lib/src/message_input.dart @@ -604,20 +604,18 @@ class MessageInputState extends State { !widget.showCommandsButton && widget.actions?.isNotEmpty != true ? const Offstage() - : FittedBox( - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - if (!widget.disableAttachments) - _buildAttachmentButton(context), - if (widget.showCommandsButton && - widget.editMessage == null && - channel.state != null && - channel.config?.commands.isNotEmpty == true) - _buildCommandButton(context), - ...widget.actions ?? [], - ].insertBetween(const SizedBox(width: 8)), - ), + : Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + if (!widget.disableAttachments) + _buildAttachmentButton(context), + if (widget.showCommandsButton && + widget.editMessage == null && + channel.state != null && + channel.config?.commands.isNotEmpty == true) + _buildCommandButton(context), + ...widget.actions ?? [], + ].insertBetween(const SizedBox(width: 8)), ), duration: const Duration(milliseconds: 300), alignment: Alignment.center, From 9926dc6907ee54e712e0c74ce10e07957a87f264 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 10 Sep 2021 18:23:12 +0530 Subject: [PATCH 02/27] chore(ui): Update CHANGELOG.md Signed-off-by: xsahil03x --- packages/stream_chat_flutter/CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/stream_chat_flutter/CHANGELOG.md b/packages/stream_chat_flutter/CHANGELOG.md index ed8f5e06..7c316bf6 100644 --- a/packages/stream_chat_flutter/CHANGELOG.md +++ b/packages/stream_chat_flutter/CHANGELOG.md @@ -1,3 +1,10 @@ +## Upcoming + +🐞 Fixed + +- [[#668]](https://github.com/GetStream/stream-chat-flutter/issues/668): Fix `MessageInput` rendering errors in case + there are no actions available to show. + ## 2.2.1 🛑️ Breaking Changes from `2.2.1` From 8779341bbd266d8718a56483186dc1ae343d42eb Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Tue, 14 Sep 2021 20:28:00 +0530 Subject: [PATCH 03/27] fix(core): match oldWidget objects using jsonEncode Signed-off-by: xsahil03x --- .../lib/src/channel_list_core.dart | 5 ++--- .../lib/src/message_search_list_core.dart | 12 ++++++------ .../lib/src/user_list_core.dart | 5 ++--- .../test/message_search_bloc_test.dart | 2 +- .../test/message_search_list_core_test.dart | 4 ++-- 5 files changed, 13 insertions(+), 15 deletions(-) diff --git a/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart b/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart index c5d3f69a..e79a7f1f 100644 --- a/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart @@ -214,15 +214,14 @@ class ChannelListCoreState extends State { void didUpdateWidget(ChannelListCore oldWidget) { super.didUpdateWidget(oldWidget); - if (widget.filter?.toString() != oldWidget.filter?.toString() || + if (jsonEncode(widget.filter) != jsonEncode(oldWidget.filter) || jsonEncode(widget.sort) != jsonEncode(oldWidget.sort) || widget.state != oldWidget.state || widget.watch != oldWidget.watch || widget.presence != oldWidget.presence || widget.messageLimit != oldWidget.messageLimit || widget.memberLimit != oldWidget.memberLimit || - widget.pagination.toJson().toString() != - oldWidget.pagination.toJson().toString()) { + jsonEncode(widget.pagination) != jsonEncode(oldWidget.pagination)) { loadData(); } diff --git a/packages/stream_chat_flutter_core/lib/src/message_search_list_core.dart b/packages/stream_chat_flutter_core/lib/src/message_search_list_core.dart index 28e092a7..e5b91b6e 100644 --- a/packages/stream_chat_flutter_core/lib/src/message_search_list_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/message_search_list_core.dart @@ -185,13 +185,13 @@ class MessageSearchListCoreState extends State { @override void didUpdateWidget(MessageSearchListCore oldWidget) { super.didUpdateWidget(oldWidget); - if (widget.filters.toString() != oldWidget.filters.toString() || + if (jsonEncode(widget.filters) != jsonEncode(oldWidget.filters) || jsonEncode(widget.sortOptions) != jsonEncode(oldWidget.sortOptions) || - widget.messageQuery?.toString() != oldWidget.messageQuery?.toString() || - widget.messageFilters?.toString() != - oldWidget.messageFilters?.toString() || - widget.paginationParams.toJson().toString() != - oldWidget.paginationParams.toJson().toString()) { + widget.messageQuery != oldWidget.messageQuery || + jsonEncode(widget.messageFilters) != + jsonEncode(oldWidget.messageFilters) || + jsonEncode(widget.paginationParams) != + jsonEncode(oldWidget.paginationParams)) { loadData(); } diff --git a/packages/stream_chat_flutter_core/lib/src/user_list_core.dart b/packages/stream_chat_flutter_core/lib/src/user_list_core.dart index e403be4e..06ad7d80 100644 --- a/packages/stream_chat_flutter_core/lib/src/user_list_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/user_list_core.dart @@ -209,11 +209,10 @@ class UserListCoreState extends State @override void didUpdateWidget(UserListCore oldWidget) { super.didUpdateWidget(oldWidget); - if (widget.filter?.toString() != oldWidget.filter?.toString() || + if (jsonEncode(widget.filter) != jsonEncode(oldWidget.filter) || jsonEncode(widget.sort) != jsonEncode(oldWidget.sort) || widget.presence != oldWidget.presence || - widget.pagination.toJson().toString() != - oldWidget.pagination.toJson().toString()) { + jsonEncode(widget.pagination) != jsonEncode(oldWidget.pagination)) { loadData(); } diff --git a/packages/stream_chat_flutter_core/test/message_search_bloc_test.dart b/packages/stream_chat_flutter_core/test/message_search_bloc_test.dart index c689d90c..332289ea 100644 --- a/packages/stream_chat_flutter_core/test/message_search_bloc_test.dart +++ b/packages/stream_chat_flutter_core/test/message_search_bloc_test.dart @@ -8,7 +8,7 @@ import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'matchers/get_message_response_matcher.dart'; import 'mocks.dart'; -const testFilter = Filter.custom(operator: '\$test', value: 'testValue'); +const testFilter = Filter.custom(key: 'test', value: 'testValue'); void main() { List _generateMessages({ diff --git a/packages/stream_chat_flutter_core/test/message_search_list_core_test.dart b/packages/stream_chat_flutter_core/test/message_search_list_core_test.dart index 03396513..02a78412 100644 --- a/packages/stream_chat_flutter_core/test/message_search_list_core_test.dart +++ b/packages/stream_chat_flutter_core/test/message_search_list_core_test.dart @@ -6,8 +6,8 @@ import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'mocks.dart'; -const testFilter = Filter.custom(operator: '\$test', value: 'testValue'); -const testMessageFilter = Filter.custom(operator: '\$test', value: 'testValue'); +const testFilter = Filter.custom(key: 'test', value: 'testValue'); +const testMessageFilter = Filter.custom(key: 'test', value: 'testValue'); void main() { List _generateMessages({ From d888f1568c8f7677a48cd329a9564048fa1b2927 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Tue, 14 Sep 2021 20:31:06 +0530 Subject: [PATCH 04/27] chore(core): update CHANGELOG.md Signed-off-by: xsahil03x --- packages/stream_chat_flutter_core/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/stream_chat_flutter_core/CHANGELOG.md b/packages/stream_chat_flutter_core/CHANGELOG.md index d0d89a6b..f5da89c3 100644 --- a/packages/stream_chat_flutter_core/CHANGELOG.md +++ b/packages/stream_chat_flutter_core/CHANGELOG.md @@ -14,6 +14,7 @@ 🐞 Fixed - Fixed `MessageSearchBloc` pagination. +- [[#673]](https://github.com/GetStream/stream-chat-flutter/issues/673): Fix `Core Widgets` not getting rebuild with new data on configuration change. ## 2.2.1 From fb7ede84a3fe8102e087d0bc503f7c9dbbb5aa97 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 14 Sep 2021 22:13:37 +0530 Subject: [PATCH 05/27] attachment tap fixes --- .../stream_chat_flutter/lib/src/message_widget.dart | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/stream_chat_flutter/lib/src/message_widget.dart b/packages/stream_chat_flutter/lib/src/message_widget.dart index 7619f21b..537c088f 100644 --- a/packages/stream_chat_flutter/lib/src/message_widget.dart +++ b/packages/stream_chat_flutter/lib/src/message_widget.dart @@ -214,6 +214,11 @@ class MessageWidget extends StatefulWidget { ), onShowMessage: onShowMessage, onReturnAction: onReturnAction, + onAttachmentTap: onAttachmentTap != null + ? () { + onAttachmentTap(message, attachment); + } + : null, ); }).toList(), ), @@ -243,6 +248,11 @@ class MessageWidget extends StatefulWidget { mediaQueryData.size.width * 0.8, mediaQueryData.size.height * 0.3, ), + onAttachmentTap: onAttachmentTap != null + ? () { + onAttachmentTap(message, attachment); + } + : null, ), border, reverse, From 380e34450f18994d73a1684a961dde4d242f9bef Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 14 Sep 2021 22:14:38 +0530 Subject: [PATCH 06/27] added changelog --- packages/stream_chat_flutter/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/stream_chat_flutter/CHANGELOG.md b/packages/stream_chat_flutter/CHANGELOG.md index ed8f5e06..090a0c55 100644 --- a/packages/stream_chat_flutter/CHANGELOG.md +++ b/packages/stream_chat_flutter/CHANGELOG.md @@ -14,6 +14,7 @@ 🐞 Fixed - Fixed `MessageSearchListView` pagination. +- Fixed `MessageWidget` attachment tap callbacks. ## 2.2.1 From 33b9152d4f5dba5a50d5f7b5100d8244e1a22823 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 15 Sep 2021 12:08:34 +0200 Subject: [PATCH 07/27] feat(ui): add `onAttachmentTap` to `ImageGroup` --- packages/stream_chat_flutter/lib/src/image_group.dart | 8 ++++++++ packages/stream_chat_flutter/lib/src/message_widget.dart | 1 + 2 files changed, 9 insertions(+) diff --git a/packages/stream_chat_flutter/lib/src/image_group.dart b/packages/stream_chat_flutter/lib/src/image_group.dart index 627406d0..88b309fe 100644 --- a/packages/stream_chat_flutter/lib/src/image_group.dart +++ b/packages/stream_chat_flutter/lib/src/image_group.dart @@ -15,6 +15,7 @@ class ImageGroup extends StatelessWidget { required this.size, this.onReturnAction, this.onShowMessage, + this.onAttachmentTap, }) : super(key: key); /// List of attachments to show @@ -23,6 +24,9 @@ class ImageGroup extends StatelessWidget { /// Callback when attachment is returned to from other screens final ValueChanged? onReturnAction; + /// Callback when attachment is tapped + final void Function(Message message, Attachment attachment)? onAttachmentTap; + /// Message which images are attached to final Message message; @@ -117,6 +121,10 @@ class ImageGroup extends StatelessWidget { BuildContext context, int index, ) async { + if (onAttachmentTap != null) { + return onAttachmentTap!(message, images[index]); + } + final channel = StreamChannel.of(context).channel; final res = await Navigator.push( diff --git a/packages/stream_chat_flutter/lib/src/message_widget.dart b/packages/stream_chat_flutter/lib/src/message_widget.dart index 537c088f..7ceca3ad 100644 --- a/packages/stream_chat_flutter/lib/src/message_widget.dart +++ b/packages/stream_chat_flutter/lib/src/message_widget.dart @@ -133,6 +133,7 @@ class MessageWidget extends StatefulWidget { messageTheme: messageTheme, onShowMessage: onShowMessage, onReturnAction: onReturnAction, + onAttachmentTap: onAttachmentTap, ), ), border, From 59aad47789eac90bfa3e2c5e0859d44a4648f381 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 15 Sep 2021 16:01:00 +0530 Subject: [PATCH 08/27] refactor(llc): make `Filter.empty` constructor const. Signed-off-by: xsahil03x --- packages/stream_chat/lib/src/core/models/filter.dart | 9 ++++++--- .../stream_chat/test/src/core/models/filter_test.dart | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/stream_chat/lib/src/core/models/filter.dart b/packages/stream_chat/lib/src/core/models/filter.dart index d4536eab..d5a2c08f 100644 --- a/packages/stream_chat/lib/src/core/models/filter.dart +++ b/packages/stream_chat/lib/src/core/models/filter.dart @@ -102,6 +102,12 @@ class Filter extends Equatable { this.key, }) : operator = operator.rawValue; + /// An empty filter + const Filter.empty() + : value = const {}, + operator = null, + key = null; + /// Combines the provided filters and matches the values /// matched by all filters. factory Filter.and(List filters) => @@ -172,9 +178,6 @@ class Filter extends Equatable { String? key, }) = Filter.__; - /// An empty filter - factory Filter.empty() => const Filter.raw(value: {}); - /// Creates a custom [Filter] from a raw map value /// /// ```dart diff --git a/packages/stream_chat/test/src/core/models/filter_test.dart b/packages/stream_chat/test/src/core/models/filter_test.dart index 6e3dbf64..a62c162e 100644 --- a/packages/stream_chat/test/src/core/models/filter_test.dart +++ b/packages/stream_chat/test/src/core/models/filter_test.dart @@ -139,7 +139,7 @@ void main() { }); test('empty', () { - final filter = Filter.empty(); + const filter = Filter.empty(); expect(filter.value, {}); }); From ea3d10646e578991eb58ac3ddcde85d3d3bcf8ae Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 15 Sep 2021 16:02:05 +0530 Subject: [PATCH 09/27] feat(ui, core): Add default empty filter in `UserListView`. Signed-off-by: xsahil03x --- packages/stream_chat_flutter/lib/src/user_list_view.dart | 3 ++- packages/stream_chat_flutter_core/lib/src/user_list_core.dart | 3 ++- 2 files changed, 4 insertions(+), 2 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 4d650192..12dbb3ec 100644 --- a/packages/stream_chat_flutter/lib/src/user_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/user_list_view.dart @@ -48,7 +48,7 @@ class UserListView extends StatefulWidget { /// Instantiate a new UserListView const UserListView({ Key? key, - this.filter, + this.filter = const Filter.empty(), this.sort, this.presence, this.pagination = const PaginationParams(limit: 30), @@ -76,6 +76,7 @@ class UserListView extends StatefulWidget { /// The query filters to use. /// You can query on any of the custom fields you've defined on the [Channel]. /// You can also filter other built-in channel fields. + // TODO: Make it non-nullable in a future breaking release final Filter? filter; /// The sorting used for the channels matching the filters. diff --git a/packages/stream_chat_flutter_core/lib/src/user_list_core.dart b/packages/stream_chat_flutter_core/lib/src/user_list_core.dart index 06ad7d80..75fc7411 100644 --- a/packages/stream_chat_flutter_core/lib/src/user_list_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/user_list_core.dart @@ -63,7 +63,7 @@ class UserListCore extends StatefulWidget { required this.loadingBuilder, required this.listBuilder, Key? key, - this.filter, + this.filter = const Filter.empty(), this.sort, this.presence, this.pagination = const PaginationParams(limit: 30), @@ -91,6 +91,7 @@ class UserListCore extends StatefulWidget { /// The query filters to use. /// You can query on any of the custom fields you've defined on the [Channel]. /// You can also filter other built-in channel fields. + // TODO: Make it non-nullable in a future breaking release final Filter? filter; /// The sorting used for the channels matching the filters. From 1d142d7697690eb4a0e0a1b905e1ef1737e1b909 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 15 Sep 2021 16:25:32 +0530 Subject: [PATCH 10/27] chore(core, ui): update CHANGELOG.md Signed-off-by: xsahil03x --- packages/stream_chat_flutter/CHANGELOG.md | 7 +++++++ packages/stream_chat_flutter_core/CHANGELOG.md | 10 +++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/packages/stream_chat_flutter/CHANGELOG.md b/packages/stream_chat_flutter/CHANGELOG.md index ed8f5e06..b2ef50cb 100644 --- a/packages/stream_chat_flutter/CHANGELOG.md +++ b/packages/stream_chat_flutter/CHANGELOG.md @@ -11,6 +11,13 @@ pagination = const PaginationParams(limit: 30) ``` +🔄 Changed + +- `UserListViewCore` filter property now has a default value. + ```dart + filter = const Filter.empty() + ``` + 🐞 Fixed - Fixed `MessageSearchListView` pagination. diff --git a/packages/stream_chat_flutter_core/CHANGELOG.md b/packages/stream_chat_flutter_core/CHANGELOG.md index f5da89c3..5ce1eb8b 100644 --- a/packages/stream_chat_flutter_core/CHANGELOG.md +++ b/packages/stream_chat_flutter_core/CHANGELOG.md @@ -11,10 +11,18 @@ pagination = const PaginationParams(limit: 30) ``` +🔄 Changed + +- `UserListViewCore` filter property now has a default value. + ```dart + filter = const Filter.empty() + ``` + 🐞 Fixed - Fixed `MessageSearchBloc` pagination. -- [[#673]](https://github.com/GetStream/stream-chat-flutter/issues/673): Fix `Core Widgets` not getting rebuild with new data on configuration change. +- [[#673]](https://github.com/GetStream/stream-chat-flutter/issues/673): Fix `Core Widgets` not getting rebuild with new + data on configuration change. ## 2.2.1 From abc22f0eb91f14f10d786ac2f4918604976b6aa9 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 15 Sep 2021 17:45:32 +0530 Subject: [PATCH 11/27] fix(llc): Fix `Filter.empty` encoding Signed-off-by: xsahil03x --- packages/stream_chat/CHANGELOG.md | 1 + packages/stream_chat/lib/src/core/models/filter.dart | 2 +- packages/stream_chat/test/src/core/models/filter_test.dart | 6 ++++++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/stream_chat/CHANGELOG.md b/packages/stream_chat/CHANGELOG.md index 90211d07..98aa9782 100644 --- a/packages/stream_chat/CHANGELOG.md +++ b/packages/stream_chat/CHANGELOG.md @@ -19,6 +19,7 @@ 🐞 Fixed - [[#659]](https://github.com/GetStream/stream-chat-flutter/issues/659) Fixed unread count not updating correctly. +- Fix `Filter.empty()` json encoding. ## 2.2.1 diff --git a/packages/stream_chat/lib/src/core/models/filter.dart b/packages/stream_chat/lib/src/core/models/filter.dart index d5a2c08f..ca494bdb 100644 --- a/packages/stream_chat/lib/src/core/models/filter.dart +++ b/packages/stream_chat/lib/src/core/models/filter.dart @@ -104,7 +104,7 @@ class Filter extends Equatable { /// An empty filter const Filter.empty() - : value = const {}, + : value = const {}, operator = null, key = null; diff --git a/packages/stream_chat/test/src/core/models/filter_test.dart b/packages/stream_chat/test/src/core/models/filter_test.dart index a62c162e..e396c2b3 100644 --- a/packages/stream_chat/test/src/core/models/filter_test.dart +++ b/packages/stream_chat/test/src/core/models/filter_test.dart @@ -226,6 +226,12 @@ void main() { json.encode(value), ); }); + + test('empty', () { + const filter = Filter.empty(); + final encoded = json.encode(filter); + expect(encoded, '{}'); + }); }); test('groupedFilter', () { From 6427e34119f8a26952a814e841191a498d997cf6 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 15 Sep 2021 20:50:44 +0530 Subject: [PATCH 12/27] feat(ui, core): deprecate `pagination` in favor of `limit` Signed-off-by: xsahil03x --- .../lib/src/channel_list_view.dart | 25 +++++++++---- .../lib/src/message_search_list_view.dart | 23 +++++++++--- .../lib/src/user_list_view.dart | 21 ++++++++--- .../theme/channel_list_view_theme_test.dart | 2 +- .../src/theme/user_list_view_theme_test.dart | 4 +-- .../lib/src/channel_list_core.dart | 30 +++++++++++----- .../lib/src/message_search_list_core.dart | 36 ++++++++++++++----- .../lib/src/user_list_core.dart | 28 +++++++++++---- .../test/channel_list_core_test.dart | 14 ++++++++ .../test/message_search_list_core_test.dart | 15 ++++++++ .../test/user_list_core_test.dart | 13 +++++++ 11 files changed, 167 insertions(+), 44 deletions(-) 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 35fc6d73..0f06e269 100644 --- a/packages/stream_chat_flutter/lib/src/channel_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/channel_list_view.dart @@ -59,7 +59,7 @@ typedef ViewInfoCallback = void Function(Channel); /// Modify it to change the widget appearance. class ChannelListView extends StatefulWidget { /// Instantiate a new ChannelListView - const ChannelListView({ + ChannelListView({ Key? key, this.filter, this.sort, @@ -68,9 +68,12 @@ class ChannelListView extends StatefulWidget { this.presence = false, this.memberLimit, this.messageLimit, - this.pagination = const PaginationParams( - limit: 25, - ), + @Deprecated( + "'pagination' is deprecated and shouldn't be used. " + "This property is no longer used, Please use 'limit' instead", + ) + this.pagination, + int? limit, this.onChannelTap, this.onChannelLongPress, this.channelWidget, @@ -92,7 +95,8 @@ class ChannelListView extends StatefulWidget { this.onDeletePressed, this.swipeActions, this.channelListController, - }) : super(key: key); + }) : limit = limit ?? pagination?.limit ?? 25, + super(key: key); /// If true a default swipe to action behaviour will be added to this widget final bool swipeToAction; @@ -129,7 +133,14 @@ class ChannelListView extends StatefulWidget { /// limit: the number of channels to return (max is 30) /// offset: the offset (max is 1000) /// message_limit: how many messages should be included to each channel - final PaginationParams pagination; + @Deprecated( + "'pagination' is deprecated and shouldn't be used. " + "This property is no longer used, Please use 'limit' instead", + ) + final PaginationParams? pagination; + + /// The amount of channels requested per API call. + final int limit; /// Function called when tapping on a channel /// By default it calls [Navigator.push] building a [MaterialPageRoute] @@ -218,7 +229,7 @@ class _ChannelListViewState extends State { presence: widget.presence, memberLimit: widget.memberLimit, messageLimit: widget.messageLimit, - pagination: widget.pagination, + limit: widget.limit, channelListController: _channelListController, listBuilder: widget.listBuilder ?? _buildListView, emptyBuilder: widget.emptyBuilder ?? _buildEmptyWidget, 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 f80c688f..ab1a9178 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 @@ -53,12 +53,17 @@ typedef EmptyMessageSearchBuilder = Widget Function( /// Modify it to change the widget appearance. class MessageSearchListView extends StatefulWidget { /// Instantiate a new MessageSearchListView - const MessageSearchListView({ + MessageSearchListView({ Key? key, required this.filters, this.messageQuery, this.sortOptions, - this.paginationParams = const PaginationParams(limit: 30), + @Deprecated( + "'paginationParams' is deprecated and shouldn't be used. " + "This property is no longer used, Please use 'limit' instead", + ) + this.paginationParams, + int? limit, this.messageFilters, this.separatorBuilder, this.itemBuilder, @@ -71,7 +76,8 @@ class MessageSearchListView extends StatefulWidget { this.loadingBuilder, this.childBuilder, this.messageSearchListController, - }) : super(key: key); + }) : limit = limit ?? paginationParams?.limit ?? 30, + super(key: key); /// Message String to search on final String? messageQuery; @@ -93,7 +99,14 @@ class MessageSearchListView extends StatefulWidget { /// limit: the number of users to return (max is 30) /// offset: the offset (max is 1000) /// message_limit: how many messages should be included to each channel - final PaginationParams paginationParams; + @Deprecated( + "'paginationParams' is deprecated and shouldn't be used. " + "This property is no longer used, Please use 'limit' instead", + ) + final PaginationParams? paginationParams; + + /// The amount of messages requested per API call. + final int limit; /// The message query filters to use. /// You can query on any of the custom fields you've defined on the [Channel]. @@ -152,7 +165,7 @@ class _MessageSearchListViewState extends State { filters: widget.filters, sortOptions: widget.sortOptions, messageQuery: widget.messageQuery, - paginationParams: widget.paginationParams, + limit: widget.limit, messageFilters: widget.messageFilters, messageSearchListController: _messageSearchListController, emptyBuilder: widget.emptyBuilder ?? 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 12dbb3ec..b946f800 100644 --- a/packages/stream_chat_flutter/lib/src/user_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/user_list_view.dart @@ -46,12 +46,17 @@ typedef UserItemBuilder = Widget Function(BuildContext, User, bool); /// Modify it to change the widget appearance. class UserListView extends StatefulWidget { /// Instantiate a new UserListView - const UserListView({ + UserListView({ Key? key, this.filter = const Filter.empty(), this.sort, this.presence, - this.pagination = const PaginationParams(limit: 30), + @Deprecated( + "'pagination' is deprecated and shouldn't be used. " + "This property is no longer used, Please use 'limit' instead", + ) + this.pagination, + int? limit, this.onUserTap, this.onUserLongPress, this.userWidget, @@ -71,6 +76,7 @@ class UserListView extends StatefulWidget { crossAxisCount == 1 || groupAlphabetically == false, 'Cannot group alphabetically when crossAxisCount > 1', ), + limit = limit ?? pagination?.limit ?? 30, super(key: key); /// The query filters to use. @@ -94,7 +100,14 @@ class UserListView extends StatefulWidget { /// limit: the number of users to return (max is 30) /// offset: the offset (max is 1000) /// message_limit: how many messages should be included to each channel - final PaginationParams pagination; + @Deprecated( + "'pagination' is deprecated and shouldn't be used. " + "This property is no longer used, Please use 'limit' instead", + ) + final PaginationParams? pagination; + + /// The amount of users requested per API call. + final int limit; /// Function called when tapping on a channel /// By default it calls [Navigator.push] building a [MaterialPageRoute] @@ -185,7 +198,7 @@ class _UserListViewState extends State ), listBuilder: widget.listBuilder ?? (context, list) => _buildListView(list), - pagination: widget.pagination, + limit: widget.limit, sort: widget.sort, filter: widget.filter, presence: widget.presence, diff --git a/packages/stream_chat_flutter/test/src/theme/channel_list_view_theme_test.dart b/packages/stream_chat_flutter/test/src/theme/channel_list_view_theme_test.dart index 38b1c524..079c01e3 100644 --- a/packages/stream_chat_flutter/test/src/theme/channel_list_view_theme_test.dart +++ b/packages/stream_chat_flutter/test/src/theme/channel_list_view_theme_test.dart @@ -62,7 +62,7 @@ void main() { return Scaffold( body: StreamChannel( channel: MockChannel(), - child: const ChannelListView(), + child: ChannelListView(), ), ); }, diff --git a/packages/stream_chat_flutter/test/src/theme/user_list_view_theme_test.dart b/packages/stream_chat_flutter/test/src/theme/user_list_view_theme_test.dart index a22eebd0..3aa20744 100644 --- a/packages/stream_chat_flutter/test/src/theme/user_list_view_theme_test.dart +++ b/packages/stream_chat_flutter/test/src/theme/user_list_view_theme_test.dart @@ -56,7 +56,7 @@ void main() { home: Builder( builder: (BuildContext context) { _context = context; - return const Scaffold( + return Scaffold( body: UsersBloc( child: UserListView(), ), @@ -85,7 +85,7 @@ void main() { home: Builder( builder: (BuildContext context) { _context = context; - return const Scaffold( + return Scaffold( body: UsersBloc( child: UserListView(), ), diff --git a/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart b/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart index e79a7f1f..d3d6c312 100644 --- a/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart @@ -56,7 +56,7 @@ import 'package:stream_chat_flutter_core/src/typedef.dart'; /// information about the channels. class ChannelListCore extends StatefulWidget { /// Instantiate a new ChannelListView - const ChannelListCore({ + ChannelListCore({ Key? key, required this.errorBuilder, required this.emptyBuilder, @@ -69,11 +69,15 @@ class ChannelListCore extends StatefulWidget { this.memberLimit, this.messageLimit, this.sort, - this.pagination = const PaginationParams( - limit: 25, - ), + @Deprecated( + "'pagination' is deprecated and shouldn't be used. " + "This property is no longer used, Please use 'limit' instead", + ) + this.pagination, this.channelListController, - }) : super(key: key); + int? limit, + }) : limit = limit ?? pagination?.limit ?? 25, + super(key: key); /// A [ChannelListController] allows reloading and pagination. /// Use [ChannelListController.loadData] and @@ -124,7 +128,14 @@ class ChannelListCore extends StatefulWidget { /// limit: the number of channels to return (max is 30) /// offset: the offset (max is 1000) /// message_limit: how many messages should be included to each channel - final PaginationParams pagination; + @Deprecated( + "'pagination' is deprecated and shouldn't be used. " + "This property is no longer used, Please use 'limit' instead", + ) + final PaginationParams? pagination; + + /// The amount of channels requested per API call. + final int limit; @override ChannelListCoreState createState() => ChannelListCoreState(); @@ -162,7 +173,7 @@ class ChannelListCoreState extends State { presence: widget.presence, memberLimit: widget.memberLimit, messageLimit: widget.messageLimit, - paginationParams: widget.pagination, + paginationParams: PaginationParams(limit: widget.limit), ); /// Fetches more channels with updated pagination and updates the widget @@ -174,7 +185,8 @@ class ChannelListCoreState extends State { presence: widget.presence, memberLimit: widget.memberLimit, messageLimit: widget.messageLimit, - paginationParams: widget.pagination.copyWith( + paginationParams: PaginationParams( + limit: widget.limit, offset: _channelsBloc.channels?.length ?? 0, ), ); @@ -221,7 +233,7 @@ class ChannelListCoreState extends State { widget.presence != oldWidget.presence || widget.messageLimit != oldWidget.messageLimit || widget.memberLimit != oldWidget.memberLimit || - jsonEncode(widget.pagination) != jsonEncode(oldWidget.pagination)) { + widget.limit != oldWidget.limit) { loadData(); } diff --git a/packages/stream_chat_flutter_core/lib/src/message_search_list_core.dart b/packages/stream_chat_flutter_core/lib/src/message_search_list_core.dart index e5b91b6e..f4d18a0b 100644 --- a/packages/stream_chat_flutter_core/lib/src/message_search_list_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/message_search_list_core.dart @@ -38,7 +38,7 @@ class MessageSearchListCore extends StatefulWidget { /// * [errorBuilder] /// * [loadingBuilder] /// * [childBuilder] - const MessageSearchListCore({ + MessageSearchListCore({ Key? key, required this.emptyBuilder, required this.errorBuilder, @@ -47,9 +47,14 @@ class MessageSearchListCore extends StatefulWidget { required this.filters, this.messageQuery, this.sortOptions, - this.paginationParams = const PaginationParams(limit: 30), + @Deprecated( + "'pagination' is deprecated and shouldn't be used. " + "This property is no longer used, Please use 'limit' instead", + ) + this.paginationParams, this.messageFilters, this.messageSearchListController, + int? limit, }) : assert( messageQuery != null || messageFilters != null, 'Provide at least `query` or `messageFilters`', @@ -58,6 +63,13 @@ class MessageSearchListCore extends StatefulWidget { messageQuery == null || messageFilters == null, "Can't provide both `query` and `messageFilters` at the same time", ), + assert( + paginationParams?.offset == null || + paginationParams?.offset == 0 || + sortOptions == null, + 'Cannot specify `offset` with `sortOptions` parameter', + ), + limit = limit ?? paginationParams?.limit ?? 30, super(key: key); /// A [MessageSearchListController] allows reloading and pagination. @@ -84,7 +96,14 @@ class MessageSearchListCore extends StatefulWidget { /// Pagination parameters /// limit: the number of messages to return (max is 30) /// offset: the offset (max is 1000) - final PaginationParams paginationParams; + @Deprecated( + "'pagination' is deprecated and shouldn't be used. " + "This property is no longer used, Please use 'limit' instead", + ) + final PaginationParams? paginationParams; + + /// The amount of messages requested per API call. + final int limit; /// The message query filters to use. /// You can query on any of the custom fields you've defined on the [Channel]. @@ -157,19 +176,19 @@ class MessageSearchListCoreState extends State { filter: widget.filters, sort: widget.sortOptions, query: widget.messageQuery, - pagination: widget.paginationParams, messageFilter: widget.messageFilters, + pagination: PaginationParams(limit: widget.limit), ); /// Fetches more messages with updated pagination and updates the widget Future paginateData() { - PaginationParams pagination; + var pagination = PaginationParams(limit: widget.limit); if (widget.sortOptions != null) { - pagination = widget.paginationParams.copyWith( + pagination = pagination.copyWith( next: _messageSearchBloc?.nextId, ); } else { - pagination = widget.paginationParams.copyWith( + pagination = pagination.copyWith( offset: _messageSearchBloc?.messageResponses?.length, ); } @@ -190,8 +209,7 @@ class MessageSearchListCoreState extends State { widget.messageQuery != oldWidget.messageQuery || jsonEncode(widget.messageFilters) != jsonEncode(oldWidget.messageFilters) || - jsonEncode(widget.paginationParams) != - jsonEncode(oldWidget.paginationParams)) { + widget.limit != oldWidget.limit) { loadData(); } diff --git a/packages/stream_chat_flutter_core/lib/src/user_list_core.dart b/packages/stream_chat_flutter_core/lib/src/user_list_core.dart index 75fc7411..839067bf 100644 --- a/packages/stream_chat_flutter_core/lib/src/user_list_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/user_list_core.dart @@ -57,7 +57,7 @@ import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; /// [errorBuilder] must all be supplied and not null. class UserListCore extends StatefulWidget { /// Instantiate a new [UserListCore] - const UserListCore({ + UserListCore({ required this.errorBuilder, required this.emptyBuilder, required this.loadingBuilder, @@ -66,10 +66,16 @@ class UserListCore extends StatefulWidget { this.filter = const Filter.empty(), this.sort, this.presence, - this.pagination = const PaginationParams(limit: 30), + @Deprecated( + "'pagination' is deprecated and shouldn't be used. " + "This property is no longer used, Please use 'limit' instead", + ) + this.pagination, this.groupAlphabetically = false, this.userListController, - }) : super(key: key); + int? limit, + }) : limit = limit ?? pagination?.limit ?? 30, + super(key: key); /// A [UserListController] allows reloading and pagination. /// Use [UserListController.loadData] and [UserListController.paginateData] @@ -107,7 +113,14 @@ class UserListCore extends StatefulWidget { /// limit: the number of users to return (max is 30) /// offset: the offset (max is 1000) /// message_limit: how many messages should be included to each channel - final PaginationParams pagination; + @Deprecated( + "'pagination' is deprecated and shouldn't be used. " + "This property is no longer used, Please use 'limit' instead", + ) + final PaginationParams? pagination; + + /// The amount of users requested per API call. + final int limit; /// Set it to true to group users by their first character /// @@ -194,7 +207,7 @@ class UserListCoreState extends State filter: widget.filter, sort: widget.sort, presence: widget.presence, - pagination: widget.pagination, + pagination: PaginationParams(limit: widget.limit), ); /// Fetches more users with updated pagination and updates the widget @@ -202,7 +215,8 @@ class UserListCoreState extends State filter: widget.filter, sort: widget.sort, presence: widget.presence, - pagination: widget.pagination.copyWith( + pagination: PaginationParams( + limit: widget.limit, offset: _usersBloc!.users?.length ?? 0, ), ); @@ -213,7 +227,7 @@ class UserListCoreState extends State if (jsonEncode(widget.filter) != jsonEncode(oldWidget.filter) || jsonEncode(widget.sort) != jsonEncode(oldWidget.sort) || widget.presence != oldWidget.presence || - jsonEncode(widget.pagination) != jsonEncode(oldWidget.pagination)) { + widget.limit != oldWidget.limit) { loadData(); } diff --git a/packages/stream_chat_flutter_core/test/channel_list_core_test.dart b/packages/stream_chat_flutter_core/test/channel_list_core_test.dart index 47aa2bf9..8e8755aa 100644 --- a/packages/stream_chat_flutter_core/test/channel_list_core_test.dart +++ b/packages/stream_chat_flutter_core/test/channel_list_core_test.dart @@ -508,4 +508,18 @@ void main() { )).called(1); }, ); + + test('`widget.limit` should match `widget.pagination.limit`', () { + const pagination = PaginationParams(limit: 30); + final channelListCore = ChannelListCore( + listBuilder: (_, __) => const Offstage(), + loadingBuilder: (BuildContext context) => const Offstage(), + emptyBuilder: (BuildContext context) => const Offstage(), + errorBuilder: (BuildContext context, Object error) => const Offstage(), + pagination: pagination, + ); + + expect(channelListCore.limit, pagination.limit); + }); + } diff --git a/packages/stream_chat_flutter_core/test/message_search_list_core_test.dart b/packages/stream_chat_flutter_core/test/message_search_list_core_test.dart index 02a78412..ca416595 100644 --- a/packages/stream_chat_flutter_core/test/message_search_list_core_test.dart +++ b/packages/stream_chat_flutter_core/test/message_search_list_core_test.dart @@ -551,4 +551,19 @@ void main() { )).called(1); }, ); + + test('`widget.limit` should match `widget.pagination.limit`', () { + const pagination = PaginationParams(limit: 30); + final messageSearchListCore = MessageSearchListCore( + childBuilder: (List messages) => const Offstage(), + loadingBuilder: (BuildContext context) => const Offstage(), + emptyBuilder: (BuildContext context) => const Offstage(), + errorBuilder: (BuildContext context, Object? error) => const Offstage(), + filters: testFilter, + messageFilters: testMessageFilter, + paginationParams: pagination, + ); + + expect(messageSearchListCore.limit, pagination.limit); + }); } diff --git a/packages/stream_chat_flutter_core/test/user_list_core_test.dart b/packages/stream_chat_flutter_core/test/user_list_core_test.dart index 77977bb8..ade58e0f 100644 --- a/packages/stream_chat_flutter_core/test/user_list_core_test.dart +++ b/packages/stream_chat_flutter_core/test/user_list_core_test.dart @@ -520,4 +520,17 @@ void main() { )).called(1); }, ); + + test('`widget.limit` should match `widget.pagination.limit`', () { + const pagination = PaginationParams(limit: 30); + final userListCore = UserListCore( + listBuilder: (_, __) => const Offstage(), + loadingBuilder: (BuildContext context) => const Offstage(), + emptyBuilder: (BuildContext context) => const Offstage(), + errorBuilder: (BuildContext context, Object error) => const Offstage(), + pagination: pagination, + ); + + expect(userListCore.limit, pagination.limit); + }); } From d9ced67f80f6dfcc1a981ff4c878942cc05a4df7 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 15 Sep 2021 21:02:29 +0530 Subject: [PATCH 13/27] chore(ui, core): update CHANGELOG.md Signed-off-by: xsahil03x --- packages/stream_chat_flutter/CHANGELOG.md | 22 ++++++++++++++++--- .../stream_chat_flutter_core/CHANGELOG.md | 22 ++++++++++++++++--- 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/packages/stream_chat_flutter/CHANGELOG.md b/packages/stream_chat_flutter/CHANGELOG.md index b2ef50cb..16db1398 100644 --- a/packages/stream_chat_flutter/CHANGELOG.md +++ b/packages/stream_chat_flutter/CHANGELOG.md @@ -1,14 +1,30 @@ ## 2.2.1 -🛑️ Breaking Changes from `2.2.1` +⚠️ Deprecated -- `MessageSearchListView` paginationParams property is now non-nullable with a default value. +- `MessageSearchListView` `paginationParams` property is now deprecated in favor of `limit`. ```dart + // previous paginationParams = const PaginationParams(limit: 30) + + // new + limit = 30 ``` -- `UserListView` pagination property is now non-nullable with a default value. +- `UserListView` `pagination` property is now deprecated in favor of `limit`. ```dart + // previous pagination = const PaginationParams(limit: 30) + + // new + limit = 30 + ``` +- `ChannelListView` `pagination` property is now deprecated in favor of `limit`. + ```dart + // previous + pagination = const PaginationParams(limit: 30) + + // new + limit = 30 ``` 🔄 Changed diff --git a/packages/stream_chat_flutter_core/CHANGELOG.md b/packages/stream_chat_flutter_core/CHANGELOG.md index 5ce1eb8b..c4287a09 100644 --- a/packages/stream_chat_flutter_core/CHANGELOG.md +++ b/packages/stream_chat_flutter_core/CHANGELOG.md @@ -1,14 +1,30 @@ ## Upcoming -🛑️ Breaking Changes from `2.2.1` +⚠️ Deprecated -- `MessageSearchListViewCore` paginationParams property is now non-nullable with a default value. +- `MessageSearchListViewCore` `paginationParams` property is now deprecated in favor of `limit`. ```dart + // previous paginationParams = const PaginationParams(limit: 30) + + // new + limit = 30 ``` -- `UserListViewCore` pagination property is now non-nullable with a default value. +- `UserListViewCore` `pagination` property is now deprecated in favor of `limit`. ```dart + // previous pagination = const PaginationParams(limit: 30) + + // new + limit = 30 + ``` +- `ChannelListViewCore` `pagination` property is now deprecated in favor of `limit`. + ```dart + // previous + pagination = const PaginationParams(limit: 30) + + // new + limit = 30 ``` 🔄 Changed From 9a70beb33dae74c523248f3cbe737e6a925e6de2 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 16 Sep 2021 11:43:04 +0200 Subject: [PATCH 14/27] chore(core): fix format --- .../stream_chat_flutter_core/test/channel_list_core_test.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/stream_chat_flutter_core/test/channel_list_core_test.dart b/packages/stream_chat_flutter_core/test/channel_list_core_test.dart index 8e8755aa..dd87d2cf 100644 --- a/packages/stream_chat_flutter_core/test/channel_list_core_test.dart +++ b/packages/stream_chat_flutter_core/test/channel_list_core_test.dart @@ -521,5 +521,4 @@ void main() { expect(channelListCore.limit, pagination.limit); }); - } From b23d86fc5561515d504fac551dbafe786889d95d Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Thu, 16 Sep 2021 14:47:25 +0530 Subject: [PATCH 15/27] ref(llc): add `fileSize`, `mimeType` in attachment.dart Signed-off-by: xsahil03x --- .../lib/src/core/models/attachment.dart | 23 +++++++- .../lib/src/core/models/attachment_file.dart | 26 ++++++--- .../test/src/core/models/attachment_test.dart | 55 +++++++++++++++++++ 3 files changed, 93 insertions(+), 11 deletions(-) diff --git a/packages/stream_chat/lib/src/core/models/attachment.dart b/packages/stream_chat/lib/src/core/models/attachment.dart index 8973aee2..0ef9db7a 100644 --- a/packages/stream_chat/lib/src/core/models/attachment.dart +++ b/packages/stream_chat/lib/src/core/models/attachment.dart @@ -33,13 +33,20 @@ class Attachment extends Equatable { this.authorIcon, this.assetUrl, List? actions, - this.extraData = const {}, + Map extraData = const {}, this.file, UploadState? uploadState, }) : id = id ?? const Uuid().v4(), title = title ?? file?.name, localUri = file?.path != null ? Uri.parse(file!.path!) : null, - actions = actions ?? [] { + actions = actions ?? [], + // For backwards compatibility, + // set 'file_size', 'mime_type' in [extraData]. + extraData = { + ...extraData, + if (file?.size != null) 'file_size': file?.size, + if (file?.mimeType != null) 'mime_type': file?.mimeType?.mimeType, + } { this.uploadState = uploadState ?? ((assetUrl != null || imageUrl != null) ? const UploadState.success() @@ -121,6 +128,18 @@ class Attachment extends Equatable { /// This is created locally for uniquely identifying a attachment. final String id; + /// Shortcut for file size. + /// + /// {@macro fileSize} + @JsonKey(ignore: true) + int? get fileSize => extraData['file_size'] as int?; + + /// Shortcut for file mimeType. + /// + /// {@macro mimeType} + @JsonKey(ignore: true) + String? get mimeType => extraData['mime_type'] as String?; + /// Known top level fields. /// Useful for [Serializer] methods. static const topLevelFields = [ diff --git a/packages/stream_chat/lib/src/core/models/attachment_file.dart b/packages/stream_chat/lib/src/core/models/attachment_file.dart index 7bff5806..c6983b74 100644 --- a/packages/stream_chat/lib/src/core/models/attachment_file.dart +++ b/packages/stream_chat/lib/src/core/models/attachment_file.dart @@ -2,6 +2,7 @@ import 'dart:typed_data'; import 'package:dio/dio.dart' show MultipartFile; import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:http_parser/http_parser.dart'; import 'package:meta/meta.dart'; import 'package:stream_chat/src/core/platform_detector/platform_detector.dart'; import 'package:stream_chat/src/core/util/extension.dart'; @@ -65,7 +66,7 @@ class AttachmentFile { AttachmentFile({ required this.size, this.path, - this.name, + String? name, this.bytes, }) : assert( path != null || bytes != null, @@ -74,7 +75,12 @@ class AttachmentFile { assert( !CurrentPlatform.isWeb || bytes != null, 'File by path is not supported in web, Please provide bytes', - ); + ), + assert( + name?.contains('.') ?? true, + 'Invalid file name, should also contain file extension', + ), + _name = name; /// Create a new instance from a json factory AttachmentFile.fromJson(Map json) => @@ -87,8 +93,10 @@ class AttachmentFile { /// ``` final String? path; + final String? _name; + /// File name including its extension. - final String? name; + String? get name => _name ?? path?.split('/').last; /// Byte data for this file. Particularly useful if you want to manipulate /// its data or easily upload to somewhere else. @@ -101,26 +109,26 @@ class AttachmentFile { /// File extension for this file. String? get extension => name?.split('.').last; + /// The mime type of this file. + MediaType? get mimeType => name?.mimeType; + /// Serialize to json Map toJson() => _$AttachmentFileToJson(this); /// Converts this into a [MultipartFile] Future toMultipartFile() async { - final filename = path?.split('/').last ?? name; - final mimeType = filename?.mimeType; - - late MultipartFile multiPartFile; + MultipartFile multiPartFile; if (CurrentPlatform.isWeb) { multiPartFile = MultipartFile.fromBytes( bytes!, - filename: filename, + filename: name, contentType: mimeType, ); } else { multiPartFile = await MultipartFile.fromFile( path!, - filename: filename, + filename: name, contentType: mimeType, ); } diff --git a/packages/stream_chat/test/src/core/models/attachment_test.dart b/packages/stream_chat/test/src/core/models/attachment_test.dart index 37716656..eb6b72a1 100644 --- a/packages/stream_chat/test/src/core/models/attachment_test.dart +++ b/packages/stream_chat/test/src/core/models/attachment_test.dart @@ -1,5 +1,6 @@ import 'package:stream_chat/src/core/models/action.dart'; import 'package:stream_chat/src/core/models/attachment.dart'; +import 'package:stream_chat/src/core/models/attachment_file.dart'; import 'package:test/test.dart'; import '../../utils.dart'; @@ -41,5 +42,59 @@ void main() { }, ); }); + + test('name property and extraData manipulation', () { + final file = AttachmentFile(size: 3, path: 'myfolder/myfile.txt'); + final attachment = Attachment(file: file); + + expect(attachment.fileSize, 3); + expect(attachment.mimeType, 'text/plain'); + expect(attachment.toJson(), { + 'title': 'myfile.txt', + 'actions': [], + 'file_size': 3, + 'mime_type': 'text/plain' + }); + expect(Attachment.fromJson(attachment.toJson()).toJson(), { + 'title': 'myfile.txt', + 'actions': [], + 'file_size': 3, + 'mime_type': 'text/plain' + }); + + // Setting the size and mimeType using extraData should work fine + var newAttachment = Attachment( + extraData: const { + 'file_size': 6, + 'mime_type': 'application/pdf', + }, + ); + + expect(newAttachment.extraData['file_size'], 6); + expect(newAttachment.extraData['mime_type'], 'application/pdf'); + expect(newAttachment.fileSize, 6); + expect(newAttachment.mimeType, 'application/pdf'); + + // switching a new file should update size and mimeType + final fileTwo = AttachmentFile(size: 12, path: 'myfolder/fileTwo.pdf'); + newAttachment = attachment.copyWith(file: fileTwo); + + expect(newAttachment.extraData['file_size'], 12); + expect(newAttachment.extraData['mime_type'], 'application/pdf'); + expect(newAttachment.fileSize, 12); + expect(newAttachment.mimeType, 'application/pdf'); + + // if file is available, should override size and mimeType. + final fileThree = AttachmentFile(size: 9, path: 'myfolder/fileThree.png'); + newAttachment = attachment.copyWith(file: fileThree, extraData: { + 'file_size': 88, + 'mime_type': 'application/pdf', + }); + + expect(newAttachment.extraData['file_size'], 9); + expect(newAttachment.extraData['mime_type'], 'image/png'); + expect(newAttachment.fileSize, 9); + expect(newAttachment.mimeType, 'image/png'); + }); }); } From e7f531c857f8af6c62a2288055053fa32f93b78a Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Thu, 16 Sep 2021 14:56:02 +0530 Subject: [PATCH 16/27] chore(llc): update CHANGELOG.md Signed-off-by: xsahil03x --- packages/stream_chat/CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/stream_chat/CHANGELOG.md b/packages/stream_chat/CHANGELOG.md index 98aa9782..6b480d88 100644 --- a/packages/stream_chat/CHANGELOG.md +++ b/packages/stream_chat/CHANGELOG.md @@ -15,6 +15,9 @@ - Added `Filter.contains` and `Filter.empty` - Added support for `next`, `previous` value pagination in `client.search` , [read more.](https://getstream.io/chat/docs/other-rest/search/#pagination) +- `Attachment` class now have a `fileSize` and `mimeType` property. Setting an `file` will also set the `file_size` + , `mime_type` key on `extraData`, so `user.fileSize`, `user.mimetype` and `user.extraData['file_size']` + , `user.extraData['mime_type]` is same respectively. 🐞 Fixed From dc3f864d348160c1cc36b1b365c2c2bb5b1cd93a Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Thu, 16 Sep 2021 15:42:40 +0530 Subject: [PATCH 17/27] Update packages/stream_chat/test/src/core/models/attachment_test.dart --- packages/stream_chat/test/src/core/models/attachment_test.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/stream_chat/test/src/core/models/attachment_test.dart b/packages/stream_chat/test/src/core/models/attachment_test.dart index eb6b72a1..4e08f7f2 100644 --- a/packages/stream_chat/test/src/core/models/attachment_test.dart +++ b/packages/stream_chat/test/src/core/models/attachment_test.dart @@ -43,7 +43,7 @@ void main() { ); }); - test('name property and extraData manipulation', () { + test('fileName, mimeType property and extraData manipulation', () { final file = AttachmentFile(size: 3, path: 'myfolder/myfile.txt'); final attachment = Attachment(file: file); From 1179c6a109832339fc45a33beed3e41c36b0e213 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 16 Sep 2021 15:51:51 +0530 Subject: [PATCH 18/27] corrected attachment builders --- packages/stream_chat_flutter/lib/src/message_widget.dart | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/message_widget.dart b/packages/stream_chat_flutter/lib/src/message_widget.dart index 7ceca3ad..4025337c 100644 --- a/packages/stream_chat_flutter/lib/src/message_widget.dart +++ b/packages/stream_chat_flutter/lib/src/message_widget.dart @@ -96,7 +96,7 @@ class MessageWidget extends StatefulWidget { this.bottomRowBuilder, this.deletedBottomRowBuilder, this.onReturnAction, - Map? customAttachmentBuilders, + this.customAttachmentBuilders, this.readList, this.padding, this.textPadding = const EdgeInsets.symmetric( @@ -406,6 +406,9 @@ class MessageWidget extends StatefulWidget { /// Builder for respective attachment types final Map attachmentBuilders; + /// Builder for respective attachment types (user facing builder) + final Map? customAttachmentBuilders; + /// Center user avatar with bottom of the message final bool translateUserAvatar; @@ -530,7 +533,7 @@ class MessageWidget extends StatefulWidget { showPinButton: showPinButton ?? this.showPinButton, showPinHighlight: showPinHighlight ?? this.showPinHighlight, customAttachmentBuilders: - customAttachmentBuilders ?? attachmentBuilders, + customAttachmentBuilders ?? this.customAttachmentBuilders, translateUserAvatar: translateUserAvatar ?? this.translateUserAvatar, onQuotedMessageTap: onQuotedMessageTap ?? this.onQuotedMessageTap, onMessageTap: onMessageTap ?? this.onMessageTap, From 99e4d724d6979282d9f92f931570cc50ab94a2ce Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 16 Sep 2021 12:20:30 +0200 Subject: [PATCH 19/27] fix(ui): fix giphy attachment tap callback --- .../lib/src/attachment/giphy_attachment.dart | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) 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 7eb2606e..2210ef39 100644 --- a/packages/stream_chat_flutter/lib/src/attachment/giphy_attachment.dart +++ b/packages/stream_chat_flutter/lib/src/attachment/giphy_attachment.dart @@ -253,22 +253,7 @@ class GiphyAttachment extends AttachmentWidget { 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); - }, + onTap: () => onAttachmentTap ?? _onImageTap(context), child: Stack( children: [ CachedNetworkImage( From eac4085090addc6b87b2ce608dba29d262b16f1f Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 16 Sep 2021 12:24:42 +0200 Subject: [PATCH 20/27] fix(ui): fix giphy attachment tap callback --- .../lib/src/attachment/giphy_attachment.dart | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) 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 2210ef39..e165fc6d 100644 --- a/packages/stream_chat_flutter/lib/src/attachment/giphy_attachment.dart +++ b/packages/stream_chat_flutter/lib/src/attachment/giphy_attachment.dart @@ -98,7 +98,13 @@ class GiphyAttachment extends AttachmentWidget { Padding( padding: const EdgeInsets.all(2), child: GestureDetector( - onTap: () => onAttachmentTap ?? _onImageTap(context), + onTap: () { + if (onAttachmentTap != null) { + onAttachmentTap?.call(); + } else { + _onImageTap(context); + } + }, child: CachedNetworkImage( height: size?.height, width: size?.width, @@ -253,7 +259,13 @@ class GiphyAttachment extends AttachmentWidget { Widget _buildSentAttachment(BuildContext context, String imageUrl) => SizedBox( child: GestureDetector( - onTap: () => onAttachmentTap ?? _onImageTap(context), + onTap: () { + if (onAttachmentTap != null) { + onAttachmentTap?.call(); + } else { + _onImageTap(context); + } + }, child: Stack( children: [ CachedNetworkImage( From b30dcb8342507e3d1ef2dcbc283e4800de798775 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Thu, 16 Sep 2021 16:06:33 +0530 Subject: [PATCH 21/27] Update packages/stream_chat/CHANGELOG.md Co-authored-by: Salvatore Giordano --- packages/stream_chat/CHANGELOG.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/stream_chat/CHANGELOG.md b/packages/stream_chat/CHANGELOG.md index 6b480d88..9c925f88 100644 --- a/packages/stream_chat/CHANGELOG.md +++ b/packages/stream_chat/CHANGELOG.md @@ -15,9 +15,9 @@ - Added `Filter.contains` and `Filter.empty` - Added support for `next`, `previous` value pagination in `client.search` , [read more.](https://getstream.io/chat/docs/other-rest/search/#pagination) -- `Attachment` class now have a `fileSize` and `mimeType` property. Setting an `file` will also set the `file_size` - , `mime_type` key on `extraData`, so `user.fileSize`, `user.mimetype` and `user.extraData['file_size']` - , `user.extraData['mime_type]` is same respectively. +- `Attachment` class now has a `fileSize` and `mimeType` property. Setting a `file` will also set the `file_size` + , `mime_type` key on `extraData`, so `attachment.fileSize`, `attachment.mimetype` and `attachment.extraData['file_size']` + , `attachment.extraData['mime_type]` is same respectively. 🐞 Fixed From 6af4e0778795709e49ce68f5bd3441a145089dd2 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Thu, 16 Sep 2021 16:41:17 +0530 Subject: [PATCH 22/27] ref(ui): Use `titleLink` instead of `ogScrapeUrl` for handling link attachment. Signed-off-by: xsahil03x --- .../lib/src/attachment/attachment_title.dart | 66 +++++++++---------- .../lib/src/attachment/file_attachment.dart | 3 +- .../lib/src/message_input.dart | 2 +- .../lib/src/message_list_view.dart | 2 +- .../lib/src/message_widget.dart | 13 ++-- .../lib/src/quoted_message_widget.dart | 10 +-- .../lib/src/url_attachment.dart | 6 +- .../stream_chat_flutter/lib/src/utils.dart | 4 +- 8 files changed, 49 insertions(+), 57 deletions(-) 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 a7d4d2e3..df134250 100644 --- a/packages/stream_chat_flutter/lib/src/attachment/attachment_title.dart +++ b/packages/stream_chat_flutter/lib/src/attachment/attachment_title.dart @@ -19,42 +19,36 @@ class AttachmentTitle extends StatelessWidget { final Attachment attachment; @override - 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.messageTextStyle?.copyWith( - color: StreamChatTheme.of(context).colorTheme.accentPrimary, - fontWeight: FontWeight.bold, - ), + Widget build(BuildContext context) { + final normalizedTitleLink = attachment.titleLink?.replaceFirst( + RegExp(r'https?://(www\.)?'), + '', + ); + return GestureDetector( + onTap: () { + final titleLink = attachment.titleLink; + if (titleLink != null) launchURL(context, 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.messageTextStyle?.copyWith( + color: StreamChatTheme.of(context).colorTheme.accentPrimary, + 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.messageTextStyle, - ), - ], - ), + ), + if (normalizedTitleLink != null) + Text(normalizedTitleLink, style: messageTheme.messageTextStyle), + ], ), - ); + ), + ); + } } 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 f57e1ee6..6045539f 100644 --- a/packages/stream_chat_flutter/lib/src/attachment/file_attachment.dart +++ b/packages/stream_chat_flutter/lib/src/attachment/file_attachment.dart @@ -258,7 +258,8 @@ class FileAttachment extends AttachmentWidget { visualDensity: VisualDensity.compact, splashRadius: 16, onPressed: () { - launchURL(context, attachment.assetUrl); + final assetUrl = attachment.assetUrl; + if (assetUrl != null) launchURL(context, assetUrl); }, ); } diff --git a/packages/stream_chat_flutter/lib/src/message_input.dart b/packages/stream_chat_flutter/lib/src/message_input.dart index 9646608c..f5f51b46 100644 --- a/packages/stream_chat_flutter/lib/src/message_input.dart +++ b/packages/stream_chat_flutter/lib/src/message_input.dart @@ -1575,7 +1575,7 @@ class MessageInputState extends State { Widget _buildReplyToMessage() { if (!_hasQuotedMessage) return const Offstage(); final containsUrl = widget.quotedMessage!.attachments - .any((element) => element.ogScrapeUrl != null) == + .any((element) => element.titleLink != null) == true; return QuotedMessageWidget( reverse: true, 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 ab4ae04f..e325598d 100644 --- a/packages/stream_chat_flutter/lib/src/message_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/message_list_view.dart @@ -991,7 +991,7 @@ class _MessageListViewState extends State { final isOnlyEmoji = message.text?.isOnlyEmoji ?? false; final hasUrlAttachment = - message.attachments.any((it) => it.ogScrapeUrl != null) == true; + message.attachments.any((it) => it.titleLink != null) == true; final borderSide = isOnlyEmoji || hasUrlAttachment || (isMyMessage && !hasFileAttachment) diff --git a/packages/stream_chat_flutter/lib/src/message_widget.dart b/packages/stream_chat_flutter/lib/src/message_widget.dart index 7619f21b..e60353ad 100644 --- a/packages/stream_chat_flutter/lib/src/message_widget.dart +++ b/packages/stream_chat_flutter/lib/src/message_widget.dart @@ -566,12 +566,11 @@ class _MessageWidgetState extends State bool get isOnlyEmoji => widget.message.text?.isOnlyEmoji == true; - bool get hasNonUrlAttachments => widget.message.attachments - .where((it) => it.ogScrapeUrl == null) - .isNotEmpty; + bool get hasNonUrlAttachments => + widget.message.attachments.where((it) => it.titleLink == null).isNotEmpty; bool get hasUrlAttachments => - widget.message.attachments.any((it) => it.ogScrapeUrl != null) == true; + widget.message.attachments.any((it) => it.titleLink != null) == true; bool get showBottomRow => showThreadReplyIndicator || @@ -975,9 +974,9 @@ class _MessageWidgetState extends State Widget _buildUrlAttachment() { final urlAttachment = widget.message.attachments - .firstWhere((element) => element.ogScrapeUrl != null); + .firstWhere((element) => element.titleLink != null); - final host = Uri.parse(urlAttachment.ogScrapeUrl!).host; + final host = Uri.parse(urlAttachment.titleLink!).host; final splitList = host.split('.'); final hostName = splitList.length == 3 ? splitList[1] : splitList[0]; final hostDisplayName = urlAttachment.authorName?.capitalize() ?? @@ -1143,7 +1142,7 @@ class _MessageWidgetState extends State final attachmentGroups = >{}; widget.message.attachments - .where((element) => element.ogScrapeUrl == null && element.type != null) + .where((element) => element.titleLink == null && element.type != null) .forEach((e) { if (attachmentGroups[e.type] == null) { attachmentGroups[e.type!] = []; 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 ad3d936a..01068abd 100644 --- a/packages/stream_chat_flutter/lib/src/quoted_message_widget.dart +++ b/packages/stream_chat_flutter/lib/src/quoted_message_widget.dart @@ -97,8 +97,8 @@ class QuotedMessageWidget extends StatelessWidget { bool get _hasAttachments => message.attachments.isNotEmpty == true; - bool get _containsScrapeUrl => - message.attachments.any((element) => element.ogScrapeUrl != null) == true; + bool get _containsLinkAttachment => + message.attachments.any((element) => element.titleLink != null) == true; bool get _containsText => message.text?.isNotEmpty == true; @@ -198,9 +198,9 @@ class QuotedMessageWidget extends StatelessWidget { Widget _parseAttachments(BuildContext context) { Widget child; Attachment attachment; - if (_containsScrapeUrl) { + if (_containsLinkAttachment) { attachment = message.attachments.firstWhere( - (element) => element.ogScrapeUrl != null, + (element) => element.titleLink != null, ); child = _buildUrlAttachment(attachment); } else { @@ -280,7 +280,7 @@ class QuotedMessageWidget extends StatelessWidget { }; Color? _getBackgroundColor(BuildContext context) { - if (_containsScrapeUrl) { + if (_containsLinkAttachment) { return StreamChatTheme.of(context).colorTheme.linkBg; } return messageTheme.messageBackgroundColor; diff --git a/packages/stream_chat_flutter/lib/src/url_attachment.dart b/packages/stream_chat_flutter/lib/src/url_attachment.dart index 5d5ca489..b940f227 100644 --- a/packages/stream_chat_flutter/lib/src/url_attachment.dart +++ b/packages/stream_chat_flutter/lib/src/url_attachment.dart @@ -30,10 +30,8 @@ class UrlAttachment extends StatelessWidget { final chatThemeData = StreamChatTheme.of(context); return GestureDetector( onTap: () { - launchURL( - context, - urlAttachment.ogScrapeUrl, - ); + final titleLink = urlAttachment.titleLink; + if (titleLink != null) launchURL(context, titleLink); }, child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, diff --git a/packages/stream_chat_flutter/lib/src/utils.dart b/packages/stream_chat_flutter/lib/src/utils.dart index d97ea6a1..4dc9fee7 100644 --- a/packages/stream_chat_flutter/lib/src/utils.dart +++ b/packages/stream_chat_flutter/lib/src/utils.dart @@ -7,8 +7,8 @@ import 'package:url_launcher/url_launcher.dart'; import 'package:stream_chat_flutter/src/extension.dart'; /// Launch URL -Future launchURL(BuildContext context, String? url) async { - if (url != null && await canLaunch(url)) { +Future launchURL(BuildContext context, String url) async { + if (await canLaunch(url)) { await launch(url); } else { ScaffoldMessenger.of(context).showSnackBar( From 28b8d3bac059af80ae52633cd05d514e02ca2425 Mon Sep 17 00:00:00 2001 From: Gordon Hayes Date: Thu, 16 Sep 2021 14:01:44 +0200 Subject: [PATCH 23/27] fix: attachment buttons render overflow --- packages/stream_chat_flutter/lib/src/message_input.dart | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/message_input.dart b/packages/stream_chat_flutter/lib/src/message_input.dart index 516f6f40..fd431701 100644 --- a/packages/stream_chat_flutter/lib/src/message_input.dart +++ b/packages/stream_chat_flutter/lib/src/message_input.dart @@ -604,8 +604,7 @@ class MessageInputState extends State { !widget.showCommandsButton && widget.actions?.isNotEmpty != true ? const Offstage() - : Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, + : Wrap( children: [ if (!widget.disableAttachments) _buildAttachmentButton(context), From 58d8b0843333b421392704f1dbd744d37ac65cb0 Mon Sep 17 00:00:00 2001 From: Gordon Hayes Date: Thu, 16 Sep 2021 14:02:40 +0200 Subject: [PATCH 24/27] feat: update attachment buttons animation curve --- packages/stream_chat_flutter/lib/src/message_input.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/stream_chat_flutter/lib/src/message_input.dart b/packages/stream_chat_flutter/lib/src/message_input.dart index fd431701..f3032cf4 100644 --- a/packages/stream_chat_flutter/lib/src/message_input.dart +++ b/packages/stream_chat_flutter/lib/src/message_input.dart @@ -578,6 +578,8 @@ class MessageInputState extends State { crossFadeState: _actionsShrunk ? CrossFadeState.showFirst : CrossFadeState.showSecond, + firstCurve: Curves.easeOut, + secondCurve: Curves.easeIn, firstChild: IconButton( onPressed: () { if (_actionsShrunk) { @@ -1086,6 +1088,7 @@ class MessageInputState extends State { return AnimatedContainer( duration: const Duration(milliseconds: 300), + curve: Curves.easeOut, height: _openFilePickerSection ? _kMinMediaPickerSize : 0, child: Material( color: _streamChatTheme.colorTheme.inputBg, From 2b0588c9d8ce7c55ae198b82984a4ab07890e8d1 Mon Sep 17 00:00:00 2001 From: Gordon Hayes Date: Thu, 16 Sep 2021 14:04:07 +0200 Subject: [PATCH 25/27] fix(ui): flickering loading indicator --- packages/stream_chat_flutter/lib/src/message_input.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/stream_chat_flutter/lib/src/message_input.dart b/packages/stream_chat_flutter/lib/src/message_input.dart index f3032cf4..cbfe6e5d 100644 --- a/packages/stream_chat_flutter/lib/src/message_input.dart +++ b/packages/stream_chat_flutter/lib/src/message_input.dart @@ -2315,7 +2315,7 @@ class _PickerWidgetState extends State<_PickerWidget> { future: requestPermission, builder: (context, snapshot) { if (!snapshot.hasData) { - return const Center(child: CircularProgressIndicator()); + return const Offstage(); } if (snapshot.data!) { From ec6c6632899d59a84c996891314e5616d2820a86 Mon Sep 17 00:00:00 2001 From: Gordon Hayes Date: Thu, 16 Sep 2021 14:05:27 +0200 Subject: [PATCH 26/27] fix(ui): render overflow for image attachements --- .../lib/src/message_input.dart | 201 +++++++++--------- 1 file changed, 106 insertions(+), 95 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/message_input.dart b/packages/stream_chat_flutter/lib/src/message_input.dart index cbfe6e5d..ead14671 100644 --- a/packages/stream_chat_flutter/lib/src/message_input.dart +++ b/packages/stream_chat_flutter/lib/src/message_input.dart @@ -1090,107 +1090,118 @@ class MessageInputState extends State { duration: const Duration(milliseconds: 300), curve: Curves.easeOut, height: _openFilePickerSection ? _kMinMediaPickerSize : 0, - child: Material( - color: _streamChatTheme.colorTheme.inputBg, - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Row( + child: SingleChildScrollView( + child: SizedBox( + height: _kMinMediaPickerSize, + child: Material( + color: _streamChatTheme.colorTheme.inputBg, + child: Column( + mainAxisSize: MainAxisSize.min, children: [ - IconButton( - icon: StreamSvgIcon.pictures( - color: _getIconColor(0), + Row( + children: [ + IconButton( + icon: StreamSvgIcon.pictures( + color: _getIconColor(0), + ), + onPressed: + _attachmentContainsFile && _attachments.isNotEmpty + ? null + : () { + setState(() { + _filePickerIndex = 0; + }); + }, + ), + IconButton( + iconSize: 32, + icon: StreamSvgIcon.files( + color: _getIconColor(1), + ), + onPressed: + !_attachmentContainsFile && _attachments.isNotEmpty + ? null + : () { + pickFile(DefaultAttachmentTypes.file); + }, + ), + IconButton( + icon: StreamSvgIcon.camera( + color: _getIconColor(2), + ), + onPressed: attachmentLimitCrossed || + (_attachmentContainsFile && + _attachments.isNotEmpty) + ? null + : () { + pickFile(DefaultAttachmentTypes.image, + camera: true); + }, + ), + IconButton( + padding: const EdgeInsets.all(0), + icon: StreamSvgIcon.record( + color: _getIconColor(3), + ), + onPressed: attachmentLimitCrossed || + (_attachmentContainsFile && + _attachments.isNotEmpty) + ? null + : () { + pickFile(DefaultAttachmentTypes.video, + camera: true); + }, + ), + ], + ), + DecoratedBox( + decoration: BoxDecoration( + color: _streamChatTheme.colorTheme.barsBg, + borderRadius: const BorderRadius.only( + topLeft: Radius.circular(16), + topRight: Radius.circular(16), + ), ), - onPressed: _attachmentContainsFile && _attachments.isNotEmpty - ? null - : () { - setState(() { - _filePickerIndex = 0; - }); - }, - ), - IconButton( - iconSize: 32, - icon: StreamSvgIcon.files( - color: _getIconColor(1), - ), - onPressed: !_attachmentContainsFile && _attachments.isNotEmpty - ? null - : () { - pickFile(DefaultAttachmentTypes.file); - }, - ), - IconButton( - icon: StreamSvgIcon.camera( - color: _getIconColor(2), - ), - onPressed: attachmentLimitCrossed || - (_attachmentContainsFile && _attachments.isNotEmpty) - ? null - : () { - pickFile(DefaultAttachmentTypes.image, camera: true); - }, - ), - IconButton( - padding: const EdgeInsets.all(0), - icon: StreamSvgIcon.record( - color: _getIconColor(3), - ), - onPressed: attachmentLimitCrossed || - (_attachmentContainsFile && _attachments.isNotEmpty) - ? null - : () { - pickFile(DefaultAttachmentTypes.video, camera: true); - }, - ), - ], - ), - DecoratedBox( - decoration: BoxDecoration( - color: _streamChatTheme.colorTheme.barsBg, - borderRadius: const BorderRadius.only( - topLeft: Radius.circular(16), - topRight: Radius.circular(16), - ), - ), - child: Center( - child: Padding( - padding: const EdgeInsets.all(8), - child: Container( - width: 40, - height: 4, - decoration: BoxDecoration( - color: _streamChatTheme.colorTheme.inputBg, - borderRadius: BorderRadius.circular(4), + child: Center( + child: Padding( + padding: const EdgeInsets.all(8), + child: Container( + width: 40, + height: 4, + decoration: BoxDecoration( + color: _streamChatTheme.colorTheme.inputBg, + borderRadius: BorderRadius.circular(4), + ), + ), ), ), ), - ), + if (_openFilePickerSection) + Expanded( + child: DecoratedBox( + decoration: BoxDecoration( + color: _streamChatTheme.colorTheme.barsBg, + borderRadius: BorderRadius.circular(8), + ), + child: _PickerWidget( + filePickerIndex: _filePickerIndex, + streamChatTheme: _streamChatTheme, + containsFile: _attachmentContainsFile, + selectedMedias: _attachments.keys.toList(), + onAddMoreFilesClick: pickFile, + onMediaSelected: (media) { + if (_attachments.containsKey(media.id)) { + setState(() => _attachments.remove(media.id)); + } else { + _addAssetAttachment(media); + } + }, + ), + ), + ), + ], ), - if (_openFilePickerSection) - Expanded( - child: DecoratedBox( - decoration: BoxDecoration( - color: _streamChatTheme.colorTheme.barsBg, - borderRadius: BorderRadius.circular(8), - ), - child: _PickerWidget( - filePickerIndex: _filePickerIndex, - streamChatTheme: _streamChatTheme, - containsFile: _attachmentContainsFile, - selectedMedias: _attachments.keys.toList(), - onAddMoreFilesClick: pickFile, - onMediaSelected: (media) { - if (_attachments.containsKey(media.id)) { - setState(() => _attachments.remove(media.id)); - } else { - _addAssetAttachment(media); - } - }, - ), - ), - ), - ], + ), ), ), ); From aa68a257984dd1b9369b1781b5a464bf5f1de26c Mon Sep 17 00:00:00 2001 From: Gordon Hayes Date: Thu, 16 Sep 2021 14:10:16 +0200 Subject: [PATCH 27/27] chore(ui): update CHANGELOG.md --- packages/stream_chat_flutter/CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/stream_chat_flutter/CHANGELOG.md b/packages/stream_chat_flutter/CHANGELOG.md index 7c316bf6..5dbe7d48 100644 --- a/packages/stream_chat_flutter/CHANGELOG.md +++ b/packages/stream_chat_flutter/CHANGELOG.md @@ -4,6 +4,11 @@ - [[#668]](https://github.com/GetStream/stream-chat-flutter/issues/668): Fix `MessageInput` rendering errors in case there are no actions available to show. +- [[#349]](https://github.com/GetStream/stream-chat-flutter/issues/349): Fix `MessageInput` attachment render overflow error. + +🔄 Changed + +- Animation curves changed from default `Curves.linear` to `Curves.easeOut` and `Curves.easeIn` for attachment controls. ## 2.2.1