diff --git a/docs/adr/0025-improve-tag-suggesstion-and-dispay-members-in-group-chat-detail.md b/docs/adr/0025-improve-tag-suggesstion-and-dispay-members-in-group-chat-detail.md new file mode 100644 index 000000000..2ff91e1fe --- /dev/null +++ b/docs/adr/0025-improve-tag-suggesstion-and-dispay-members-in-group-chat-detail.md @@ -0,0 +1,69 @@ +# 25. Improve tag suggestion and display members in group chat detail + +**Date:** 2024-12-30 + +## Status + +**Accepted** + +## Context + +- Issue: [#2165](https://github.com/linagora/twake-on-matrix/issues/2165) +- Not all of the members are displayed in the drop-down list when using the tag suggestion feature. +- Can't load more members in the drop-down list when the user scrolls down. + +## Decision + +1.1 **Improve tag suggestion feature** +- When the user go to the group chat, call the func to get the members from server of the group chat. +More details about this logic can be found in the [ADR #0005](https://github.com/linagora/matrix-dart-sdk/blob/cb37032f466004500c98949739720b3b4457cc73/doc/adr/0005-support-store-members-in-hive.md). + +```dart + Future _requestParticipants() async { + if (room == null) return; + try { + await room!.requestParticipants( + at: room!.prev_batch, + notMembership: Membership.leave, + ); + } catch (e) { + Logs() + .e('Chat::_requestParticipants(): Failed to request participants', e); + } + } +``` +- Next time when user go to the group chat, the members will be stored in the hive db and get the members from the hive db to display in the drop-down list. +- When the user types the `@` character, the tag suggestion feature will be triggered. + +1.2 **Display members in the group chat detail** +- When the user clicks on the group chat, how to display the members? + 1. Display members with a maximum size defined by the `_membersPerPage` variable defined in `chat_details_tab_mixin.dart`. + ```dart + static const _membersPerPage = 30; + ``` + 2. If more members can be loaded, display the Load more button at the end of the list. + 3. When the user clicks on the Load more button, call the function to get more members from the Hive database. + ```dart + void _requestMoreMembersAction() async { + final currentMembersCount = _displayMembersNotifier.value?.length ?? 0; + _currentMembersCount += _membersPerPage; + + final members = _membersNotifier.value; + if (members != null && currentMembersCount < members.length) { + final endIndex = _currentMembersCount > members.length + ? members.length + : _currentMembersCount; + final newMembers = members.sublist(currentMembersCount, endIndex); + _displayMembersNotifier.value = [ + ...?_displayMembersNotifier.value, + ...newMembers, + ]; + } else { + _displayMembersNotifier.value = [ + ...?_displayMembersNotifier.value, + ...?members, + ]; + } + } + ``` + 4. Each call only takes a maximum of 30 members according to variable `maxMembers` \ No newline at end of file diff --git a/lib/pages/chat/chat.dart b/lib/pages/chat/chat.dart index e4a8c8392..803bf11cb 100644 --- a/lib/pages/chat/chat.dart +++ b/lib/pages/chat/chat.dart @@ -291,6 +291,19 @@ class ChatController extends State } } + Future _requestParticipants() async { + if (room == null) return; + try { + await room!.requestParticipants( + at: room!.prev_batch, + notMembership: Membership.leave, + ); + } catch (e) { + Logs() + .e('Chat::_requestParticipants(): Failed to request participants', e); + } + } + bool isUnpinEvent(Event event) => room?.pinnedEventIds .firstWhereOrNull((eventId) => eventId == event.eventId) != @@ -1995,13 +2008,14 @@ class ChatController extends State _tryLoadTimeline(); sendController.addListener(updateInputTextNotifier); super.initState(); - SchedulerBinding.instance.addPostFrameCallback((_) { + SchedulerBinding.instance.addPostFrameCallback((_) async { if (room == null) { return context.go("/error"); } _handleReceivedShareFiles(); _listenRoomUpdateEvent(); initCachedPresence(); + await _requestParticipants(); }); } diff --git a/lib/pages/chat_details/chat_details_page_view/chat_details_members_page.dart b/lib/pages/chat_details/chat_details_page_view/chat_details_members_page.dart index 45bc7f1c8..fd6f90057 100644 --- a/lib/pages/chat_details/chat_details_page_view/chat_details_members_page.dart +++ b/lib/pages/chat_details/chat_details_page_view/chat_details_members_page.dart @@ -7,21 +7,19 @@ import 'package:matrix/matrix.dart'; class ChatDetailsMembersPage extends StatelessWidget { static const int addMemberItemCount = 1; - final ValueNotifier?> membersNotifier; + final ValueNotifier?> displayMembersNotifier; final int actualMembersCount; final VoidCallback openDialogInvite; final VoidCallback requestMoreMembersAction; final VoidCallback? onUpdatedMembers; - final bool canRequestMoreMembers; final bool isMobileAndTablet; const ChatDetailsMembersPage({ super.key, - required this.membersNotifier, + required this.displayMembersNotifier, required this.actualMembersCount, required this.openDialogInvite, required this.requestMoreMembersAction, - required this.canRequestMoreMembers, required this.isMobileAndTablet, this.onUpdatedMembers, }); @@ -29,9 +27,10 @@ class ChatDetailsMembersPage extends StatelessWidget { @override Widget build(BuildContext context) { return ValueListenableBuilder( - valueListenable: membersNotifier, + valueListenable: displayMembersNotifier, builder: (context, members, child) { members ??= []; + final canRequestMoreMembers = members.length < actualMembersCount; return Column( children: [ Expanded( diff --git a/lib/presentation/mixins/chat_details_tab_mixin.dart b/lib/presentation/mixins/chat_details_tab_mixin.dart index 739011015..a08e5cd6e 100644 --- a/lib/presentation/mixins/chat_details_tab_mixin.dart +++ b/lib/presentation/mixins/chat_details_tab_mixin.dart @@ -14,7 +14,6 @@ import 'package:fluffychat/presentation/mixins/handle_video_download_mixin.dart' import 'package:fluffychat/presentation/mixins/play_video_action_mixin.dart'; import 'package:fluffychat/presentation/model/chat_details/chat_details_page_model.dart'; import 'package:fluffychat/presentation/same_type_events_builder/same_type_events_controller.dart'; -import 'package:fluffychat/utils/dialog/twake_dialog.dart'; import 'package:fluffychat/utils/matrix_sdk_extensions/event_extension.dart'; import 'package:fluffychat/utils/platform_infos.dart'; import 'package:fluffychat/utils/responsive/responsive_utils.dart'; @@ -36,6 +35,9 @@ mixin ChatDetailsTabMixin final ValueNotifier?> _membersNotifier = ValueNotifier(null); + final ValueNotifier?> _displayMembersNotifier = + ValueNotifier(null); + late final List tabList; Room? get room; @@ -59,6 +61,8 @@ mixin ChatDetailsTabMixin static const _mediaFetchLimit = 20; static const _linksFetchLimit = 20; static const _filesFetchLimit = 20; + static const _membersPerPage = 30; + int _currentMembersCount = _membersPerPage; static const _memberPageKey = PageStorageKey('members'); static const _mediaPageKey = PageStorageKey('media'); @@ -109,11 +113,36 @@ mixin ChatDetailsTabMixin } void _requestMoreMembersAction() async { - final participants = await TwakeDialog.showFutureLoadingDialogFullScreen( - future: () => room!.requestParticipants(), - ); - if (participants.error == null) { - _membersNotifier.value = participants.result; + final currentMembersCount = _displayMembersNotifier.value?.length ?? 0; + _currentMembersCount += _membersPerPage; + + final members = _membersNotifier.value; + if (members != null && currentMembersCount < members.length) { + final endIndex = _currentMembersCount > members.length + ? members.length + : _currentMembersCount; + final newMembers = members.sublist(currentMembersCount, endIndex); + _displayMembersNotifier.value = [ + ...?_displayMembersNotifier.value, + ...newMembers, + ]; + } else { + _displayMembersNotifier.value = [ + ...?_displayMembersNotifier.value, + ...?members, + ]; + } + } + + void _initDisplayMembers() { + final members = _membersNotifier.value; + if (members != null && members.isNotEmpty) { + final endIndex = _currentMembersCount > members.length + ? members.length + : _currentMembersCount; + _displayMembersNotifier.value = members.sublist(0, endIndex); + } else { + _displayMembersNotifier.value = []; } } @@ -188,6 +217,7 @@ mixin ChatDetailsTabMixin void _initMembers() { if (chatType == ChatDetailsScreenEnum.group) { _membersNotifier.value ??= room?.getParticipants(); + _initDisplayMembers(); } } @@ -236,10 +266,8 @@ mixin ChatDetailsTabMixin page: page, child: ChatDetailsMembersPage( key: _memberPageKey, - membersNotifier: _membersNotifier, + displayMembersNotifier: _displayMembersNotifier, actualMembersCount: actualMembersCount, - canRequestMoreMembers: - (_membersNotifier.value?.length ?? 0) < actualMembersCount, requestMoreMembersAction: _requestMoreMembersAction, openDialogInvite: _openDialogInvite, isMobileAndTablet: isMobileAndTablet, @@ -308,6 +336,7 @@ mixin ChatDetailsTabMixin void dispose() { _disposeControllers(); _membersNotifier.dispose(); + _displayMembersNotifier.dispose(); _onRoomEventChangedSubscription?.cancel(); nestedScrollViewState.currentState?.innerController.dispose(); super.dispose(); diff --git a/pubspec.lock b/pubspec.lock index 6663c7865..359006212 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1876,8 +1876,8 @@ packages: dependency: "direct main" description: path: "." - ref: "twake-supported-0.22.6" - resolved-ref: "58585a19abc4693d96eab4f8dad9c56bf8699cc1" + ref: TW-2165-support-store-members-in-local-database + resolved-ref: "5db9aac805dc165508ee10abfe06a4489b98f26a" url: "git@github.com:linagora/matrix-dart-sdk.git" source: git version: "0.22.6" diff --git a/pubspec.yaml b/pubspec.yaml index d168da58e..0de34567d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -12,7 +12,7 @@ dependencies: matrix: git: url: git@github.com:linagora/matrix-dart-sdk.git - ref: twake-supported-0.22.6 + ref: TW-2165-support-store-members-in-local-database receive_sharing_intent: git: