diff --git a/lib/pages/chat_list/space_view.dart b/lib/pages/chat_list/space_view.dart index fae04dcff..856bed7d1 100644 --- a/lib/pages/chat_list/space_view.dart +++ b/lib/pages/chat_list/space_view.dart @@ -8,6 +8,7 @@ import 'package:fluffychat/pages/chat_list/chat_list_item.dart'; import 'package:fluffychat/pages/chat_list/search_title.dart'; import 'package:fluffychat/pages/chat_list/utils/on_chat_tap.dart'; import 'package:fluffychat/pangea/constants/class_default_values.dart'; +import 'package:fluffychat/pangea/constants/pangea_room_types.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'; @@ -47,11 +48,23 @@ class _SpaceViewState extends State { // #Pangea StreamSubscription? _roomSubscription; bool refreshing = false; + + final String _chatCountsKey = 'chatCounts'; + Map get chatCounts => Map.from( + widget.controller.pangeaController.pStoreService.read( + _chatCountsKey, + local: true, + ) ?? + {}, + ); // Pangea# @override void initState() { loadHierarchy(); + // #Pangea + loadChatCounts(); + // Pangea# super.initState(); } @@ -74,9 +87,15 @@ class _SpaceViewState extends State { // Pangea# } - Future loadHierarchy([String? prevBatch]) async { + Future loadHierarchy([ + String? prevBatch, // #Pangea - if (widget.controller.activeSpaceId == null || loading) { + String? spaceId, + // Pangea# + ]) async { + // #Pangea + if ((widget.controller.activeSpaceId == null && spaceId == null) || + loading) { return GetSpaceHierarchyResponse( rooms: [], nextBatch: null, @@ -89,7 +108,10 @@ class _SpaceViewState extends State { }); // Pangea# - final activeSpaceId = widget.controller.activeSpaceId!; + // #Pangea + // final activeSpaceId = widget.controller.activeSpaceId!; + final activeSpaceId = (widget.controller.activeSpaceId ?? spaceId)!; + // Pangea# final client = Matrix.of(context).client; final activeSpace = client.getRoomById(activeSpaceId); @@ -122,6 +144,14 @@ class _SpaceViewState extends State { }); rethrow; } finally { + // #Pangea + if (activeSpace != null) { + await setChatCount( + activeSpace, + _lastResponse[activeSpaceId], + ); + } + // Pangea# setState(() { loading = false; }); @@ -387,6 +417,14 @@ class _SpaceViewState extends State { } // #Pangea + Future loadChatCounts() async { + for (final Room room in Matrix.of(context).client.rooms) { + if (room.isSpace && !chatCounts.containsKey(room.id)) { + await loadHierarchy(null, room.id); + } + } + } + Future refreshOnUpdate(SyncUpdate event) async { /* refresh on leave, invite, and space child update not join events, because there's already a listener on @@ -412,6 +450,90 @@ class _SpaceViewState extends State { } setState(() => refreshing = false); } + + bool includeSpaceChild(sc, matchingSpaceChildren) { + final bool isAnalyticsRoom = sc.roomType == PangeaRoomTypes.analytics; + final bool isMember = [Membership.join, Membership.invite] + .contains(Matrix.of(context).client.getRoomById(sc.roomId)?.membership); + final bool isSuggested = matchingSpaceChildren.any( + (matchingSpaceChild) => + matchingSpaceChild.roomId == sc.roomId && + matchingSpaceChild.suggested == true, + ); + return !isAnalyticsRoom && (isMember || isSuggested); + } + + List filterSpaceChildren( + Room space, + List spaceChildren, + ) { + final childIds = + spaceChildren.map((hierarchyMember) => hierarchyMember.roomId); + + final matchingSpaceChildren = space.spaceChildren + .where((spaceChild) => childIds.contains(spaceChild.roomId)) + .toList(); + + final filteredSpaceChildren = spaceChildren + .where( + (sc) => includeSpaceChild( + sc, + matchingSpaceChildren, + ), + ) + .toList(); + return filteredSpaceChildren; + } + + int sortSpaceChildren( + SpaceRoomsChunk a, + SpaceRoomsChunk b, + ) { + final bool aIsSpace = a.roomType == 'm.space'; + final bool bIsSpace = b.roomType == 'm.space'; + + if (aIsSpace && !bIsSpace) { + return -1; + } else if (!aIsSpace && bIsSpace) { + return 1; + } + return 0; + } + + Future setChatCount( + Room space, + GetSpaceHierarchyResponse? response, + ) async { + final Map updatedChatCounts = Map.from(chatCounts); + final List spaceChildren = response?.rooms ?? []; + final filteredChildren = filterSpaceChildren(space, spaceChildren) + .where((sc) => sc.roomId != space.id) + .toList(); + updatedChatCounts[space.id] = filteredChildren.length; + + await widget.controller.pangeaController.pStoreService.save( + _chatCountsKey, + updatedChatCounts, + local: true, + ); + } + + bool roomCountLoading(Room space) => + space.membership == Membership.join && !chatCounts.containsKey(space.id); + + Widget spaceSubtitle(Room space) { + if (roomCountLoading(space)) { + return const CircularProgressIndicator.adaptive(); + } + + return Text( + space.membership == Membership.join + ? L10n.of(context)!.numChats( + chatCounts[space.id].toString(), + ) + : L10n.of(context)!.youreInvited, + ); + } // Pangea# @override @@ -473,14 +595,8 @@ class _SpaceViewState extends State { // #Pangea subtitle: Row( children: [ - Text( - rootSpace.membership == Membership.join - ? L10n.of(context)!.numChats( - rootSpace.spaceChildren.length.toString(), - ) - : L10n.of(context)!.youreInvited, - ), - if (rootSpace.locked ?? false) + spaceSubtitle(rootSpace), + if (rootSpace.locked) const Padding( padding: EdgeInsets.only(left: 4.0), child: Icon( @@ -625,42 +741,9 @@ class _SpaceViewState extends State { final space = Matrix.of(context).client.getRoomById(activeSpaceId); if (space != null) { - final matchingSpaceChildren = space.spaceChildren - .where( - (spaceChild) => spaceChildren - .map((hierarchyMember) => hierarchyMember.roomId) - .contains(spaceChild.roomId), - ) - .toList(); - spaceChildren = spaceChildren - .where( - (spaceChild) => - matchingSpaceChildren.any( - (matchingSpaceChild) => - matchingSpaceChild.roomId == - spaceChild.roomId && - matchingSpaceChild.suggested == true, - ) || - [Membership.join, Membership.invite].contains( - Matrix.of(context) - .client - .getRoomById(spaceChild.roomId) - ?.membership, - ), - ) - .toList(); + spaceChildren = filterSpaceChildren(space, spaceChildren); } - spaceChildren.sort((a, b) { - final bool aIsSpace = a.roomType == 'm.space'; - final bool bIsSpace = b.roomType == 'm.space'; - - if (aIsSpace && !bIsSpace) { - return -1; - } else if (!aIsSpace && bIsSpace) { - return 1; - } - return 0; - }); + spaceChildren.sort(sortSpaceChildren); // Pangea# final canLoadMore = response.nextBatch != null; return SliverList(