Skip to content

Commit

Permalink
TW-1519: Automatically synchronize pin unpin (#1531)
Browse files Browse the repository at this point in the history
  • Loading branch information
nqhhdev authored Mar 6, 2024
1 parent d485c25 commit 8131dc3
Show file tree
Hide file tree
Showing 5 changed files with 223 additions and 14 deletions.
38 changes: 37 additions & 1 deletion lib/pages/chat/chat.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'dart:async';
import 'dart:io';
import 'package:fluffychat/pages/chat/chat_actions.dart';
import 'package:fluffychat/presentation/extensions/event_update_extension.dart';
import 'package:fluffychat/presentation/mixins/handle_clipboard_action_mixin.dart';
import 'package:fluffychat/presentation/mixins/paste_image_mixin.dart';
import 'package:fluffychat/presentation/model/chat/view_event_list_ui_state.dart';
Expand Down Expand Up @@ -1693,6 +1694,40 @@ class ChatController extends State<Chat>
});
}

void _listenRoomUpdateEvent() {
if (room == null) return;
client.onEvent.stream.listen((eventUpdate) {
Logs().d(
'Chat::_listenRoomUpdateEvent():: Event Update Content ${eventUpdate.content}',
);
if (eventUpdate.isPinnedEventsHasChanged) {
WidgetsBinding.instance.addPostFrameCallback((_) async {
eventUpdate.updatePinnedMessage(
onPinnedMessageUpdated: _handlePinnedMessageCallBack,
);
});
}
});
}

void _handlePinnedMessageCallBack({
required bool isInitial,
required bool isUnpin,
String? eventId,
}) {
if (roomId == null) return;
Logs().d(
'Chat::_handlePinnedMessageCallBack():: eventId - $eventId',
);
_getPinnedEvents(
client: client,
roomId: roomId!,
isInitial: isInitial,
isUnpin: isUnpin,
eventId: eventId,
);
}

@override
void initState() {
_initializePinnedEvents();
Expand All @@ -1704,11 +1739,12 @@ class ChatController extends State<Chat>
_tryLoadTimeline();
sendController.addListener(updateInputTextNotifier);
super.initState();
SchedulerBinding.instance.addPostFrameCallback((_) async {
SchedulerBinding.instance.addPostFrameCallback((_) {
if (room == null) {
return context.go("/error");
}
_handleReceivedShareFiles();
_listenRoomUpdateEvent();
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ class PinnedEventsController {
);
if (index < 0) {
currentPinnedEventNotifier.value = pinnedEvents.first;
return 0;
}
return index;
}
Expand Down
90 changes: 78 additions & 12 deletions lib/pages/chat/chat_pinned_events/pinned_messages.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import 'package:fluffychat/pages/chat/chat_horizontal_action_menu.dart';
import 'package:fluffychat/pages/chat/chat_pinned_events/pinned_messages_screen.dart';
import 'package:fluffychat/pages/chat/chat_pinned_events/pinned_messages_style.dart';
import 'package:fluffychat/pages/chat/context_item_chat_action.dart';
import 'package:fluffychat/presentation/extensions/event_update_extension.dart';
import 'package:fluffychat/presentation/model/forward/forward_argument.dart';
import 'package:fluffychat/resource/image_paths.dart';
import 'package:fluffychat/utils/extension/build_context_extension.dart';
Expand Down Expand Up @@ -53,6 +54,8 @@ class PinnedMessagesController extends State<PinnedMessages>

Room? get room => widget.pinnedEvents.first?.room;

Client get client => Matrix.of(context).client;

ValueNotifier<List<Event>> selectedEvents = ValueNotifier([]);

List<String> get selectedPinnedEventsIds =>
Expand All @@ -67,9 +70,11 @@ class PinnedMessagesController extends State<PinnedMessages>
_showErrorSnackbar(failure);
}, (success) {
if (success is UpdatePinnedEventsSuccess) {
eventsNotifier.value = eventsNotifier.value
.where((event) => event?.eventId != eventId)
.toList();
_updateEventsNotifier(
eventsNotifier.value
.where((event) => event?.eventId != eventId)
.toList(),
);
if (eventsNotifier.value.isEmpty) {
Navigator.of(context).pop(eventsNotifier.value);
}
Expand All @@ -92,7 +97,7 @@ class PinnedMessagesController extends State<PinnedMessages>
},
(success) {
if (success is UpdatePinnedEventsSuccess) {
eventsNotifier.value = [];
_updateEventsNotifier([]);
Navigator.of(context).pop();
}
},
Expand All @@ -114,12 +119,14 @@ class PinnedMessagesController extends State<PinnedMessages>
},
(success) {
if (success is UpdatePinnedEventsSuccess) {
eventsNotifier.value = eventsNotifier.value
.where(
(event) =>
!selectedPinnedEventsIds.contains(event?.eventId),
)
.toList();
_updateEventsNotifier(
eventsNotifier.value
.where(
(event) =>
!selectedPinnedEventsIds.contains(event?.eventId),
)
.toList(),
);
selectedEvents.value = [];
if (eventsNotifier.value.isEmpty) {
Navigator.of(context).pop();
Expand Down Expand Up @@ -184,7 +191,7 @@ class PinnedMessagesController extends State<PinnedMessages>

void _initPinnedEvents() {
if (widget.pinnedEvents.isNotEmpty) {
eventsNotifier.value = widget.pinnedEvents;
_updateEventsNotifier(widget.pinnedEvents);
} else {
final currentRoomId = GoRouterState.of(context).pathParameters['roomid'];
if (currentRoomId != null) {
Expand Down Expand Up @@ -350,11 +357,70 @@ class PinnedMessagesController extends State<PinnedMessages>
);
}

void _listenRoomUpdateEvent() {
if (room == null) return;
client.onEvent.stream.listen((eventUpdate) {
Logs().d(
'PinnedMessages::_listenRoomUpdateEvent():: Event Update Content ${eventUpdate.content}',
);
if (eventUpdate.isPinnedEventsHasChanged) {
WidgetsBinding.instance.addPostFrameCallback((_) {
eventUpdate.updatePinnedMessage(
onPinnedMessageUpdated: ({
required bool isInitial,
required bool isUnpin,
String? eventId,
}) {
_handlePinnedMessageCallBack();
},
);
});
}
});
}

void _handlePinnedMessageCallBack() async {
try {
final result =
(await Future.wait(room!.pinnedEventIds.map(room!.getEventById)))
.nonNulls
.toList();

if (result.isNotEmpty) {
_updateEventsNotifier(result);
}

if (eventsNotifier.value.isNotEmpty && result.isEmpty) {
_updateEventsNotifier(result);
Navigator.of(context).pop();
}
} on MatrixException catch (exception) {
Logs().e(
'PinnedMessages::_handlePinnedMessageCallBack():: ErrorCode ${exception.errcode}: ${exception.errorMessage}',
);
}
}

void _updateEventsNotifier(List<Event?> events) {
try {
eventsNotifier.value = events;
} on FlutterError catch (exception) {
Logs().e(
'PinnedMessages::_updateEventsNotifier():: FlutterError $exception',
);
} catch (exception) {
Logs().e(
'PinnedMessages::_updateEventsNotifier():: ErrorCode $exception',
);
}
}

@override
void initState() {
super.initState();
SchedulerBinding.instance.addPostFrameCallback((_) async {
SchedulerBinding.instance.addPostFrameCallback((_) {
_initPinnedEvents();
_listenRoomUpdateEvent();
});
}

Expand Down
106 changes: 106 additions & 0 deletions lib/presentation/extensions/event_update_extension.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import 'package:collection/collection.dart';
import 'package:matrix/matrix.dart';

typedef OnPinnedMessageUpdated = void Function({
required bool isInitial,
required bool isUnpin,
String? eventId,
});

extension EventUpdateExtension on EventUpdate {
String? get eventId {
final id = content['event_id'];
if (id != null) {
return id;
}
return null;
}

bool get isPinnedEventsHasChanged {
return content['type'] == EventTypes.RoomPinnedEvents;
}

bool _isPinnedListChanged(
Map<String, dynamic> content,
Map<String, dynamic> prevContent,
) {
final pinnedList = content['pinned'];
final prevPinnedList = prevContent['pinned'];

return pinnedList != null || prevPinnedList != null;
}

void updatePinnedMessage({
required OnPinnedMessageUpdated onPinnedMessageUpdated,
}) {
if (!isPinnedEventsHasChanged) return;
final content = this.content['content'];
final unsignedContent = this.content['unsigned'];
final prevContent =
unsignedContent != null ? unsignedContent['prev_content'] : null;
if (content != null && prevContent != null) {
if (!_isPinnedListChanged(content, prevContent)) return;

final pinnedList = content['pinned'];
final prevPinnedList = prevContent['pinned'];

if (pinnedList.length == prevPinnedList.length) return;

if (pinnedList.length > prevPinnedList.length) {
_handlePinnedListIncreased(
pinnedList,
prevPinnedList,
onPinnedMessageUpdated,
);
} else if (pinnedList.length < prevPinnedList.length) {
_handlePinnedListDecreased(
pinnedList,
prevPinnedList,
onPinnedMessageUpdated,
);
}
}
}

void _handlePinnedListIncreased(
List<dynamic> pinnedList,
List<dynamic> prevPinnedList,
OnPinnedMessageUpdated onPinnedMessageUpdated,
) {
if (prevPinnedList.isEmpty) {
return onPinnedMessageUpdated(
isInitial: true,
isUnpin: false,
);
}
final eventId = pinnedList.firstWhereOrNull(
(event) => !prevPinnedList.contains(event),
);
return onPinnedMessageUpdated(
isInitial: false,
isUnpin: false,
eventId: eventId,
);
}

void _handlePinnedListDecreased(
List<dynamic> pinnedList,
List<dynamic> prevPinnedList,
OnPinnedMessageUpdated onPinnedMessageUpdated,
) {
if (pinnedList.isEmpty) {
return onPinnedMessageUpdated(
isInitial: false,
isUnpin: true,
);
}
final eventId = prevPinnedList.firstWhereOrNull(
(event) => !pinnedList.contains(event),
);
return onPinnedMessageUpdated(
isInitial: false,
isUnpin: true,
eventId: eventId,
);
}
}
2 changes: 1 addition & 1 deletion pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1551,7 +1551,7 @@ packages:
description:
path: "."
ref: "twake-supported-0.22.6"
resolved-ref: "599c37af897625f936bdab98d56d3deef789c171"
resolved-ref: "40bab63ea8895015aed935bd3fb6c279c6fe294c"
url: "[email protected]:linagora/matrix-dart-sdk.git"
source: git
version: "0.22.6"
Expand Down

0 comments on commit 8131dc3

Please sign in to comment.