diff --git a/lib/pages/chat_list/space_view.dart b/lib/pages/chat_list/space_view.dart index 7d48fa52f..3aff52a5e 100644 --- a/lib/pages/chat_list/space_view.dart +++ b/lib/pages/chat_list/space_view.dart @@ -7,6 +7,7 @@ import 'package:fluffychat/pages/chat_list/chat_list_item.dart'; import 'package:fluffychat/pages/chat_list/search_title.dart'; import 'package:fluffychat/pangea/constants/class_default_values.dart'; import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart'; +import 'package:fluffychat/pangea/extensions/sync_update_extension.dart'; import 'package:fluffychat/pangea/utils/archive_space.dart'; import 'package:fluffychat/pangea/utils/chat_list_handle_space_tap.dart'; import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart'; @@ -82,6 +83,24 @@ class _SpaceViewState extends State { if (result.error != null) return; _refresh(); } + // #Pangea + else { + final room = client.getRoomById(spaceChild.roomId)!; + if (room.membership != Membership.leave) return; + final joinResult = await showFutureLoadingDialog( + context: context, + future: () async { + final waitForRoom = room.client.waitForRoomInSync( + room.id, + join: true, + ); + await room.join(); + await waitForRoom; + }, + ); + if (joinResult.error != null) return; + } + // Pangea# if (spaceChild.roomType == 'm.space') { if (spaceChild.roomId == widget.controller.activeSpaceId) { // #Pangea @@ -310,23 +329,18 @@ class _SpaceViewState extends State { } // #Pangea - _roomSubscription = client.onSync.stream - .where((event) => event.rooms?.join?.isNotEmpty ?? false) - .listen((event) { - if (mounted) { - final List joinedRoomIds = event.rooms!.join!.keys.toList(); - final joinedRoomFutures = joinedRoomIds.map( - (joinedRoomId) => client.waitForRoomInSync( - joinedRoomId, - join: true, - ), - ); - Future.wait(joinedRoomFutures).then((_) { - _refresh(); - }); + void refreshOnUpdate(SyncUpdate event) { + if (event.isMembershipUpdate(Matrix.of(context).client.userID!) || + event.isSpaceChildUpdate(activeSpaceId)) { + _refresh(); } - }); + } + + _roomSubscription ??= client.onSync.stream + .where((event) => event.hasRoomUpdate) + .listen(refreshOnUpdate); // Pangea# + return FutureBuilder( future: getFuture(activeSpaceId), builder: (context, snapshot) { @@ -459,7 +473,13 @@ class _SpaceViewState extends State { } final spaceChild = spaceChildren[i]; final room = client.getRoomById(spaceChild.roomId); - if (room != null && !room.isSpace) { + if (room != null && + !room.isSpace + // #Pangea + && + room.membership != Membership.leave + // Pangea# + ) { return ChatListItem( room, onLongPress: () => diff --git a/lib/pangea/extensions/sync_update_extension.dart b/lib/pangea/extensions/sync_update_extension.dart new file mode 100644 index 000000000..931568243 --- /dev/null +++ b/lib/pangea/extensions/sync_update_extension.dart @@ -0,0 +1,85 @@ +import 'package:matrix/matrix.dart'; + +extension MembershipUpdate on SyncUpdate { + bool isMembershipUpdate(String userId) { + return isMembershipUpdateByType(Membership.join, userId) || + isMembershipUpdateByType(Membership.leave, userId) || + isMembershipUpdateByType(Membership.invite, userId); + } + + bool isMembershipUpdateByType(Membership type, String userId) { + final List? updates = getRoomUpdates(type); + if (updates?.isEmpty ?? true) { + return false; + } + + for (final SyncRoomUpdate update in updates!) { + final List? events = getRoomUpdateEvents(type, update); + if (hasMembershipUpdate( + events, + type.name, + userId, + )) { + return true; + } + } + return false; + } + + List? getRoomUpdates(Membership type) { + switch (type) { + case Membership.join: + return rooms?.join?.values.toList(); + case Membership.leave: + return rooms?.leave?.values.toList(); + case Membership.invite: + return rooms?.invite?.values.toList(); + default: + return null; + } + } + + bool isSpaceChildUpdate(String activeSpaceId) { + if (rooms?.join?.isEmpty ?? true) { + return false; + } + for (final update in rooms!.join!.entries) { + final String spaceId = update.key; + final List? timelineEvents = update.value.timeline?.events; + final bool isUpdate = timelineEvents != null && + spaceId == activeSpaceId && + timelineEvents.any((event) => event.type == EventTypes.spaceChild); + if (isUpdate) return true; + } + return false; + } +} + +List? getRoomUpdateEvents(Membership type, SyncRoomUpdate update) { + switch (type) { + case Membership.join: + return (update as JoinedRoomUpdate).timeline?.events; + case Membership.leave: + return (update as LeftRoomUpdate).timeline?.events; + case Membership.invite: + return (update as InvitedRoomUpdate).inviteState; + default: + return null; + } +} + +bool hasMembershipUpdate( + List? events, + String membershipType, + String userId, +) { + if (events == null) { + return false; + } + return events.any( + (event) => + event.type == EventTypes.RoomMember && + event.stateKey == userId && + event.content['membership'] == membershipType, + ); +}