Skip to content

Commit

Permalink
TW-2165: Improve tag suggestion with members in room (#2200)
Browse files Browse the repository at this point in the history
  • Loading branch information
nqhhdev authored Jan 6, 2025
1 parent be080c4 commit 94a4a6e
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 16 deletions.
Original file line number Diff line number Diff line change
@@ -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<void> _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`
16 changes: 15 additions & 1 deletion lib/pages/chat/chat.dart
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,19 @@ class ChatController extends State<Chat>
}
}

Future<void> _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) !=
Expand Down Expand Up @@ -1995,13 +2008,14 @@ class ChatController extends State<Chat>
_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();
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,31 +7,30 @@ import 'package:matrix/matrix.dart';
class ChatDetailsMembersPage extends StatelessWidget {
static const int addMemberItemCount = 1;

final ValueNotifier<List<User>?> membersNotifier;
final ValueNotifier<List<User>?> 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,
});

@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(
Expand Down
47 changes: 38 additions & 9 deletions lib/presentation/mixins/chat_details_tab_mixin.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -36,6 +35,9 @@ mixin ChatDetailsTabMixin<T extends StatefulWidget>

final ValueNotifier<List<User>?> _membersNotifier = ValueNotifier(null);

final ValueNotifier<List<User>?> _displayMembersNotifier =
ValueNotifier(null);

late final List<ChatDetailsPage> tabList;

Room? get room;
Expand All @@ -59,6 +61,8 @@ mixin ChatDetailsTabMixin<T extends StatefulWidget>
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');
Expand Down Expand Up @@ -109,11 +113,36 @@ mixin ChatDetailsTabMixin<T extends StatefulWidget>
}

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 = [];
}
}

Expand Down Expand Up @@ -188,6 +217,7 @@ mixin ChatDetailsTabMixin<T extends StatefulWidget>
void _initMembers() {
if (chatType == ChatDetailsScreenEnum.group) {
_membersNotifier.value ??= room?.getParticipants();
_initDisplayMembers();
}
}

Expand Down Expand Up @@ -236,10 +266,8 @@ mixin ChatDetailsTabMixin<T extends StatefulWidget>
page: page,
child: ChatDetailsMembersPage(
key: _memberPageKey,
membersNotifier: _membersNotifier,
displayMembersNotifier: _displayMembersNotifier,
actualMembersCount: actualMembersCount,
canRequestMoreMembers:
(_membersNotifier.value?.length ?? 0) < actualMembersCount,
requestMoreMembersAction: _requestMoreMembersAction,
openDialogInvite: _openDialogInvite,
isMobileAndTablet: isMobileAndTablet,
Expand Down Expand Up @@ -308,6 +336,7 @@ mixin ChatDetailsTabMixin<T extends StatefulWidget>
void dispose() {
_disposeControllers();
_membersNotifier.dispose();
_displayMembersNotifier.dispose();
_onRoomEventChangedSubscription?.cancel();
nestedScrollViewState.currentState?.innerController.dispose();
super.dispose();
Expand Down
2 changes: 1 addition & 1 deletion pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1877,7 +1877,7 @@ packages:
description:
path: "."
ref: "twake-supported-0.22.6"
resolved-ref: "58585a19abc4693d96eab4f8dad9c56bf8699cc1"
resolved-ref: ff95aa820c383baf7b808d8df6ebf4d25a3c6c33
url: "[email protected]:linagora/matrix-dart-sdk.git"
source: git
version: "0.22.6"
Expand Down

0 comments on commit 94a4a6e

Please sign in to comment.