diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListPresenter.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListPresenter.kt index 572484bfb3..7254b7b88b 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListPresenter.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListPresenter.kt @@ -156,7 +156,6 @@ class RoomListPresenter( } } } - val blapSpaceChildIds = blapSpaceChildren[selectedSpaceId].orEmpty() // Blap: union of everything owned by any space (real children + SDK descendants), // persisted so Home is clean right away on cold start. Grows immediately as spaces // report in; replaced exactly once every space has reported (so rooms removed from @@ -333,12 +332,29 @@ class RoomListPresenter( } } - LaunchedEffect(filtersState.filterSelectionStates, spaceFiltersState.selectedFilter(), blapSpaceChildIds) { + LaunchedEffect(filtersState.filterSelectionStates, spaceFiltersState.selectedFilter(), blapSpaceChildren, spaceFilters) { val selectedFilters = filtersState.selectedFilters().map { filter -> filter.into() } // Blap: union the space's real child list into the SDK's descendants — bridge // spaces whose children are DM portals (mautrix-telegram) otherwise come up empty. + // Expansion is RECURSIVE like desktop's SpaceStore: container spaces (mautrix-discord + // nests server/DM spaces inside a top space) contribute their sub-spaces' rooms too, + // otherwise selecting the container matches no rooms at all. val selectedSpaceFilter = spaceFiltersState.selectedFilter()?.let { filter -> - RoomListFilter.Identifiers((filter.descendants.toSet() + blapSpaceChildIds).toList()) + val descendantsBySpace = spaceFilters.associate { it.spaceRoom.roomId to it.descendants } + val ids = mutableSetOf() + val visited = mutableSetOf() + val queue = ArrayDeque(listOf(filter.spaceRoom.roomId)) + while (queue.isNotEmpty()) { + val spaceId = queue.removeFirst() + if (!visited.add(spaceId)) continue + val direct = blapSpaceChildren[spaceId].orEmpty() + descendantsBySpace[spaceId].orEmpty() + for (id in direct) { + ids += id + // Known space → recurse into its children as well. + if (id in blapSpaceChildren || id in descendantsBySpace) queue += id + } + } + RoomListFilter.Identifiers(ids.toList()) } val allFilters = RoomListFilter.All(selectedFilters + listOfNotNull(selectedSpaceFilter)) roomListDataSource.updateFilter(allFilters)