diff --git a/src/models/roomlistmodel.cpp b/src/models/roomlistmodel.cpp index 2f79bad4f..94659d46d 100644 --- a/src/models/roomlistmodel.cpp +++ b/src/models/roomlistmodel.cpp @@ -361,7 +361,7 @@ QVariant RoomListModel::data(const QModelIndex &index, int role) const return room->isSpace(); } if (role == IsChildSpaceRole) { - return SpaceHierarchyCache::instance().isChildSpace(room->id()); + return SpaceHierarchyCache::instance().isChild(room->id()); } if (role == ReplacementIdRole) { return room->successorId(); diff --git a/src/models/sortfilterroomlistmodel.cpp b/src/models/sortfilterroomlistmodel.cpp index 044b36c9a..97d6df43a 100644 --- a/src/models/sortfilterroomlistmodel.cpp +++ b/src/models/sortfilterroomlistmodel.cpp @@ -106,7 +106,10 @@ bool SortFilterRoomListModel::filterAcceptsRow(int source_row, const QModelIndex } if (m_activeSpaceId.isEmpty()) { - return acceptRoom; + if (!SpaceHierarchyCache::instance().isChild(sourceModel()->data(sourceModel()->index(source_row, 0), RoomListModel::RoomIdRole).toString())) { + return acceptRoom; + } + return false; } else { const auto &rooms = SpaceHierarchyCache::instance().getRoomListForSpace(m_activeSpaceId, false); return std::find(rooms.begin(), rooms.end(), sourceModel()->data(sourceModel()->index(source_row, 0), RoomListModel::RoomIdRole).toString()) diff --git a/src/qml/RoomListPage.qml b/src/qml/RoomListPage.qml index 1134514c1..abd18d82d 100644 --- a/src/qml/RoomListPage.qml +++ b/src/qml/RoomListPage.qml @@ -105,6 +105,8 @@ Kirigami.Page { Layout.fillHeight: true connection: root.connection + + onSpacesUpdated: sortFilterRoomListModel.invalidate() } Kirigami.Separator { @@ -204,12 +206,24 @@ Kirigami.Page { sourceModel: root.roomListModel roomSortOrder: SortFilterRoomListModel.Categories onLayoutChanged: { + layoutTimer.restart() listView.currentIndex = sortFilterRoomListModel.mapFromSource(itemSelection.currentIndex).row } activeSpaceId: spaceDrawer.selectedSpaceId mode: spaceDrawer.showDirectChats ? SortFilterRoomListModel.DirectChats : SortFilterRoomListModel.Rooms } + // HACK: This is the only way to guarantee the correct choice when + // there are multiple property changes that invalidate the filter. I.e. + // in this case activeSpaceId followed by mode. + Timer { + id: layoutTimer + interval: 100 + onTriggered: if (spaceDrawer.showDirectChats || spaceDrawer.selectedSpaceId.length < 1) { + RoomManager.enterRoom(listView.itemAtIndex(0).currentRoom) + } + } + section { property: "category" delegate: root.collapsed ? foldButton : sectionHeader diff --git a/src/qml/SpaceDrawer.qml b/src/qml/SpaceDrawer.qml index 8c23aa786..97688d157 100644 --- a/src/qml/SpaceDrawer.qml +++ b/src/qml/SpaceDrawer.qml @@ -25,6 +25,8 @@ QQC2.Control { property bool showDirectChats: false + signal spacesUpdated() + contentItem: Loader { id: sidebarColumn z: 0 @@ -83,9 +85,9 @@ QQC2.Control { Layout.maximumHeight: width - Kirigami.Units.smallSpacing Layout.topMargin: Kirigami.Units.smallSpacing / 2 - text: i18n("All Rooms") + text: i18n("Home") contentItem: Kirigami.Icon { - source: "globe" + source: "user-home-symbolic" } checked: root.selectedSpaceId === "" && root.showDirectChats === false @@ -145,6 +147,7 @@ QQC2.Control { sourceModel: RoomListModel { connection: root.connection } + onLayoutChanged: root.spacesUpdated() } onCountChanged: { if (!root.connection.room(root.selectedSpaceId)) { @@ -169,6 +172,9 @@ QQC2.Control { onSelected: { root.showDirectChats = false + if (!SpaceHierarchyCache.isSpaceChild(roomId, RoomManager.currentRoom.id) || root.selectedSpaceId == roomId) { + RoomManager.enterSpaceHome(currentRoom) + } root.selectedSpaceId = roomId } checked: root.selectedSpaceId === roomId diff --git a/src/spacehierarchycache.cpp b/src/spacehierarchycache.cpp index db8331745..e8a3984f7 100644 --- a/src/spacehierarchycache.cpp +++ b/src/spacehierarchycache.cpp @@ -74,6 +74,11 @@ void SpaceHierarchyCache::removeSpaceFromHierarchy(Quotient::Room *room) } } +bool SpaceHierarchyCache::isSpaceChild(const QString &spaceId, const QString &roomId) +{ + return getRoomListForSpace(spaceId, false).contains(roomId); +} + QList &SpaceHierarchyCache::getRoomListForSpace(const QString &spaceId, bool updateCache) { if (updateCache) { @@ -82,11 +87,11 @@ QList &SpaceHierarchyCache::getRoomListForSpace(const QString &spaceId, return m_spaceHierarchy[spaceId]; } -bool SpaceHierarchyCache::isChildSpace(const QString &spaceId) const +bool SpaceHierarchyCache::isChild(const QString &roomId) const { const auto childrens = m_spaceHierarchy.values(); for (const auto &children : childrens) { - if (children.contains(spaceId)) { + if (children.contains(roomId)) { return true; } } diff --git a/src/spacehierarchycache.h b/src/spacehierarchycache.h index 17b8e5314..a95a10af9 100644 --- a/src/spacehierarchycache.h +++ b/src/spacehierarchycache.h @@ -44,15 +44,24 @@ public: return &instance(); } + /** + * @brief Whether the given room is a member of the given space. + */ + Q_INVOKABLE bool isSpaceChild(const QString &spaceId, const QString &roomId); + /** * @brief Return the list of child rooms for the given space ID. */ [[nodiscard]] QList &getRoomListForSpace(const QString &spaceId, bool updateCache); /** - * @brief Returns whether the space is a child space of any other space. + * @brief Returns whether the room is a child space of any space. + * + * @note We need to do this from the hierarchy as it is not guaranteed that the + * child knows it's in a space. See + * https://spec.matrix.org/v1.8/client-server-api/#managing-roomsspaces-included-in-a-space */ - [[nodiscard]] bool isChildSpace(const QString &spaceId) const; + [[nodiscard]] bool isChild(const QString &roomId) const; NeoChatConnection *connection() const; void setConnection(NeoChatConnection *connection);