Warning, /network/neochat/src/qml/RoomListPage.qml is written in an unsupported language. File is not indexed.
0001 // SPDX-FileCopyrightText: 2019 Black Hat <bhat@encom.eu.org> 0002 // SPDX-FileCopyrightText: 2020 Carl Schwan <carl@carlschwan.eu> 0003 // SPDX-License-Identifier: GPL-3.0-only 0004 0005 import QtQuick 0006 import QtQuick.Controls as QQC2 0007 import QtQuick.Layouts 0008 import QtQml.Models 0009 0010 import org.kde.kirigami as Kirigami 0011 import org.kde.kirigamiaddons.components as KirigamiComponents 0012 0013 import org.kde.neochat 0014 import org.kde.neochat.config 0015 import org.kde.neochat.accounts 0016 0017 Kirigami.Page { 0018 id: root 0019 0020 /** 0021 * @brief The current width of the room list. 0022 * 0023 * @note Other objects can access the value but the private function makes sure 0024 * that only the internal members can modify it. 0025 */ 0026 readonly property int currentWidth: _private.currentWidth + spaceListWidth 0027 readonly property alias spaceListWidth: spaceDrawer.width 0028 0029 required property NeoChatConnection connection 0030 0031 readonly property RoomListModel roomListModel: RoomListModel { 0032 connection: root.connection 0033 } 0034 0035 readonly property bool collapsed: Config.collapsed 0036 0037 property var enteredRoom: null 0038 0039 onCollapsedChanged: if (collapsed) { 0040 sortFilterRoomListModel.filterText = ""; 0041 } 0042 0043 Component.onCompleted: Runner.roomListModel = root.roomListModel 0044 0045 Connections { 0046 target: RoomManager 0047 function onCurrentRoomChanged() { 0048 itemSelection.setCurrentIndex(roomListModel.index(roomListModel.rowForRoom(RoomManager.currentRoom), 0), ItemSelectionModel.SelectCurrent) 0049 } 0050 } 0051 0052 function goToNextRoomFiltered(condition) { 0053 let index = listView.currentIndex; 0054 while (index++ !== listView.count - 1) { 0055 if (condition(listView.itemAtIndex(index))) { 0056 listView.currentIndex = index; 0057 listView.currentItem.clicked(); 0058 return; 0059 } 0060 } 0061 } 0062 0063 function goToPreviousRoomFiltered(condition) { 0064 let index = listView.currentIndex; 0065 while (index-- !== 0) { 0066 if (condition(listView.itemAtIndex(index))) { 0067 listView.currentIndex = index; 0068 listView.currentItem.clicked(); 0069 return; 0070 } 0071 } 0072 } 0073 0074 function goToNextRoom() { 0075 goToNextRoomFiltered((item) => item.visible); 0076 } 0077 0078 function goToPreviousRoom() { 0079 goToPreviousRoomFiltered((item) => item.visible); 0080 } 0081 0082 function goToNextUnreadRoom() { 0083 goToNextRoomFiltered((item) => (item.visible && item.hasUnread)); 0084 } 0085 0086 function goToPreviousUnreadRoom() { 0087 goToPreviousRoomFiltered((item) => (item.visible && item.hasUnread)); 0088 } 0089 0090 titleDelegate: Loader { 0091 Layout.fillWidth: true 0092 sourceComponent: Kirigami.Settings.isMobile ? userInfo : exploreComponent 0093 } 0094 0095 padding: 0 0096 0097 RowLayout { 0098 anchors.fill: parent 0099 spacing: 0 0100 0101 SpaceDrawer { 0102 id: spaceDrawer 0103 Layout.preferredWidth: spaceDrawer.enabled ? Kirigami.Units.gridUnit * 3 : 0 0104 Layout.fillHeight: true 0105 0106 connection: root.connection 0107 } 0108 0109 Kirigami.Separator { 0110 Layout.fillHeight: true 0111 Layout.preferredWidth: 1 0112 } 0113 0114 QQC2.ScrollView { 0115 id: scrollView 0116 Layout.fillWidth: true 0117 Layout.fillHeight: true 0118 0119 background: Rectangle { 0120 color: Kirigami.Theme.backgroundColor 0121 Kirigami.Theme.colorSet: Kirigami.Theme.View 0122 } 0123 0124 ListView { 0125 id: listView 0126 0127 activeFocusOnTab: true 0128 clip: true 0129 0130 topMargin: Math.round(Kirigami.Units.smallSpacing / 2) 0131 0132 KirigamiComponents.FloatingButton { 0133 icon.name: "notifications" 0134 text: i18n("View notifications") 0135 anchors.right: parent.right 0136 anchors.rightMargin: Kirigami.Units.largeSpacing 0137 anchors.bottom: parent.bottom 0138 anchors.bottomMargin: Kirigami.Units.largeSpacing 0139 width: Kirigami.Units.gridUnit * 2 0140 height: width 0141 visible: !root.collapsed 0142 QQC2.ToolTip.text: text 0143 QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay 0144 QQC2.ToolTip.visible: hovered 0145 onClicked: pageStack.pushDialogLayer("qrc:/org/kde/neochat/qml/NotificationsView.qml", {connection: root.connection}, { 0146 title: i18nc("@title", "Notifications") 0147 }); 0148 } 0149 0150 header: QQC2.ItemDelegate { 0151 width: visible ? ListView.view.width : 0 0152 height: visible ? Kirigami.Units.gridUnit * 2 : 0 0153 0154 visible: root.collapsed 0155 0156 topPadding: Kirigami.Units.largeSpacing 0157 leftPadding: Kirigami.Units.largeSpacing 0158 rightPadding: Kirigami.Units.largeSpacing 0159 bottomPadding: Kirigami.Units.largeSpacing 0160 0161 onClicked: quickView.item.open(); 0162 0163 Kirigami.Icon { 0164 anchors.centerIn: parent 0165 width: Kirigami.Units.iconSizes.smallMedium 0166 height: Kirigami.Units.iconSizes.smallMedium 0167 source: "search" 0168 } 0169 0170 Kirigami.Separator { 0171 width: parent.width 0172 anchors.bottom: parent.bottom 0173 } 0174 } 0175 0176 Kirigami.PlaceholderMessage { 0177 anchors.centerIn: parent 0178 width: parent.width - (Kirigami.Units.largeSpacing * 4) 0179 visible: listView.count == 0 0180 text: sortFilterRoomListModel.filterText.length > 0 ? i18n("No rooms found") : i18n("Join some rooms to get started") 0181 helpfulAction: Kirigami.Action { 0182 icon.name: sortFilterRoomListModel.filterText.length > 0 ? "search" : "list-add" 0183 text: sortFilterRoomListModel.filterText.length > 0 ? i18n("Search in room directory") : i18n("Explore rooms") 0184 onTriggered: { 0185 let dialog = pageStack.layers.push("qrc:/org/kde/neochat/qml/JoinRoomPage.qml", { 0186 connection: root.connection, 0187 keyword: sortFilterRoomListModel.filterText 0188 }, { 0189 title: i18nc("@title", "Explore Rooms") 0190 }) 0191 dialog.roomSelected.connect((roomId, displayName, avatarUrl, alias, topic, memberCount, isJoined) => { 0192 if (isJoined) { 0193 RoomManager.enterRoom(root.connection.room(roomId)) 0194 } else { 0195 RoomManager.resolveResource(roomId, "join") 0196 } 0197 }) 0198 } 0199 } 0200 } 0201 0202 ItemSelectionModel { 0203 id: itemSelection 0204 model: root.roomListModel 0205 onCurrentChanged: (current, previous) => listView.currentIndex = sortFilterRoomListModel.mapFromSource(current).row 0206 } 0207 0208 model: SortFilterRoomListModel { 0209 id: sortFilterRoomListModel 0210 0211 sourceModel: root.roomListModel 0212 roomSortOrder: Config.mergeRoomList ? SortFilterRoomListModel.LastActivity : SortFilterRoomListModel.Categories 0213 onLayoutChanged: { 0214 listView.currentIndex = sortFilterRoomListModel.mapFromSource(itemSelection.currentIndex).row 0215 } 0216 activeSpaceId: spaceDrawer.selectedSpaceId 0217 } 0218 0219 section { 0220 property: sortFilterRoomListModel.filterText.length === 0 && !Config.mergeRoomList ? "category" : null 0221 delegate: root.collapsed ? foldButton : sectionHeader 0222 } 0223 0224 Component { 0225 id: sectionHeader 0226 Kirigami.ListSectionHeader { 0227 height: implicitHeight 0228 width: listView.width 0229 label: roomListModel.categoryName(section) 0230 action: Kirigami.Action { 0231 onTriggered: roomListModel.setCategoryVisible(section, !roomListModel.categoryVisible(section)) 0232 } 0233 0234 QQC2.ToolButton { 0235 icon { 0236 name: roomListModel.categoryVisible(section) ? "go-up" : "go-down" 0237 width: Kirigami.Units.iconSizes.small 0238 height: Kirigami.Units.iconSizes.small 0239 } 0240 text: roomListModel.categoryVisible(section) ? i18nc("Collapse <section name>", "Collapse %1", roomListModel.categoryName(section)) : i18nc("Expand <section name", "Expand %1", roomListModel.categoryName(section)) 0241 display: QQC2.Button.IconOnly 0242 0243 QQC2.ToolTip.text: text 0244 QQC2.ToolTip.visible: hovered 0245 QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay 0246 0247 onClicked: roomListModel.setCategoryVisible(section, !roomListModel.categoryVisible(section)) 0248 } 0249 } 0250 } 0251 Component { 0252 id: foldButton 0253 Item { 0254 width: ListView.view.width 0255 height: visible ? width : 0 0256 QQC2.ToolButton { 0257 id: button 0258 anchors.centerIn: parent 0259 0260 icon { 0261 name: hovered ? (roomListModel.categoryVisible(section) ? "go-up" : "go-down") : roomListModel.categoryIconName(section) 0262 width: Kirigami.Units.iconSizes.smallMedium 0263 height: Kirigami.Units.iconSizes.smallMedium 0264 } 0265 0266 onClicked: roomListModel.setCategoryVisible(section, !roomListModel.categoryVisible(section)) 0267 0268 QQC2.ToolTip.text: roomListModel.categoryName(section) 0269 QQC2.ToolTip.visible: hovered 0270 QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay 0271 } 0272 } 0273 } 0274 0275 reuseItems: true 0276 currentIndex: -1 // we don't want any room highlighted by default 0277 0278 delegate: root.collapsed ? collapsedModeListComponent : normalModeListComponent 0279 0280 Component { 0281 id: collapsedModeListComponent 0282 0283 CollapsedRoomDelegate { 0284 filterText: sortFilterRoomListModel.filterText 0285 } 0286 } 0287 0288 Component { 0289 id: normalModeListComponent 0290 0291 RoomDelegate { 0292 filterText: sortFilterRoomListModel.filterText 0293 0294 connection: root.connection 0295 0296 height: visible ? implicitHeight : 0 0297 0298 visible: categoryVisible || filterText.length > 0 || Config.mergeRoomList 0299 0300 onSelected: RoomManager.enterRoom(currentRoom) 0301 0302 Keys.onEnterPressed: RoomManager.enterRoom(currentRoom) 0303 Keys.onReturnPressed: RoomManager.enterRoom(currentRoom) 0304 } 0305 } 0306 } 0307 } 0308 } 0309 0310 footer: Loader { 0311 width: parent.width 0312 sourceComponent: Kirigami.Settings.isMobile ? exploreComponentMobile : userInfoDesktop 0313 } 0314 0315 MouseArea { 0316 anchors.top: parent.top 0317 anchors.bottom: parent.bottom 0318 parent: applicationWindow().overlay.parent 0319 0320 x: root.currentWidth - width / 2 0321 width: Kirigami.Units.smallSpacing * 2 0322 z: root.z + 1 0323 enabled: RoomManager.hasOpenRoom && applicationWindow().width >= Kirigami.Units.gridUnit * 35 0324 visible: enabled 0325 cursorShape: Qt.SplitHCursor 0326 0327 property int _lastX 0328 0329 onPressed: mouse => { 0330 _lastX = mouse.x; 0331 } 0332 onPositionChanged: mouse => { 0333 if (_lastX == -1) { 0334 return; 0335 } 0336 if (mouse.x > _lastX) { 0337 // we moved to the right 0338 if (_private.currentWidth < _private.collapseWidth && _private.currentWidth + (mouse.x - _lastX) >= _private.collapseWidth) { 0339 // Here we get back directly to a more wide mode. 0340 _private.currentWidth = _private.defaultWidth; 0341 Config.collapsed = false; 0342 } else if (_private.currentWidth >= _private.collapseWidth) { 0343 // Increase page width 0344 _private.currentWidth = Math.min(_private.defaultWidth, _private.currentWidth + (mouse.x - _lastX)); 0345 } 0346 } else if (mouse.x < _lastX) { 0347 const tmpWidth = _private.currentWidth - (_lastX - mouse.x); 0348 if (tmpWidth < _private.collapseWidth) { 0349 _private.currentWidth = Qt.binding(() => _private.collapsedSize); 0350 Config.collapsed = true; 0351 } else { 0352 _private.currentWidth = tmpWidth; 0353 } 0354 } 0355 } 0356 } 0357 0358 Component { 0359 id: userInfo 0360 UserInfo { 0361 visible: !root.collapsed 0362 bottomEdge: false 0363 connection: root.connection 0364 } 0365 } 0366 0367 Component { 0368 id: userInfoDesktop 0369 UserInfoDesktop { 0370 visible: !root.collapsed 0371 connection: root.connection 0372 } 0373 } 0374 0375 Component { 0376 id: exploreComponent 0377 ExploreComponent { 0378 desiredWidth: root.width - Kirigami.Units.largeSpacing 0379 collapsed: root.collapsed 0380 connection: root.connection 0381 } 0382 } 0383 0384 Component { 0385 id: exploreComponentMobile 0386 ExploreComponentMobile { 0387 connection: root.connection 0388 0389 onTextChanged: (newText) => { 0390 sortFilterRoomListModel.filterText = newText 0391 } 0392 } 0393 } 0394 0395 /* 0396 * Hold the modifiable currentWidth in a private object so that only internal 0397 * members can modify it. 0398 */ 0399 QtObject { 0400 id: _private 0401 property int currentWidth: Config.collapsed ? collapsedSize : defaultWidth 0402 readonly property int defaultWidth: Kirigami.Units.gridUnit * 17 0403 readonly property int collapseWidth: Kirigami.Units.gridUnit * 10 0404 readonly property int collapsedSize: Kirigami.Units.gridUnit * 3 - Kirigami.Units.smallSpacing * 3 + (scrollView.QQC2.ScrollBar.vertical.visible ? scrollView.QQC2.ScrollBar.vertical.width : 0) 0405 } 0406 }