Refactor room list in multiple sub components
Also modernize the codebase where possible (e.g use required properties, reorder properties, fix warnings, don't use Action when not needed) Signed-off-by: Carl Schwan <carl@carlschwan.eu>
This commit is contained in:
@@ -20,8 +20,8 @@ QQC2.Dialog {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
x: Math.round((parent.width - width) / 2)
|
x: parent ? Math.round((parent.width - width) / 2) : 0
|
||||||
y: Math.round((parent.height - height) / 2)
|
y: parent ? Math.round((parent.height - height) / 2) : 0
|
||||||
modal: true
|
modal: true
|
||||||
|
|
||||||
footer: QQC2.DialogButtonBox {
|
footer: QQC2.DialogButtonBox {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import QtQuick.Layouts 1.15
|
|||||||
import org.kde.kirigami 2.19 as Kirigami
|
import org.kde.kirigami 2.19 as Kirigami
|
||||||
|
|
||||||
import org.kde.neochat 1.0
|
import org.kde.neochat 1.0
|
||||||
|
import '../Dialog' as Dialog
|
||||||
|
|
||||||
QQC2.Menu {
|
QQC2.Menu {
|
||||||
id: root
|
id: root
|
||||||
@@ -38,7 +39,7 @@ QQC2.Menu {
|
|||||||
onTriggered: confirmLogoutDialog.open()
|
onTriggered: confirmLogoutDialog.open()
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfirmLogoutDialog {
|
Dialog.ConfirmLogoutDialog {
|
||||||
id: confirmLogoutDialog
|
id: confirmLogoutDialog
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
53
src/qml/Page/RoomList/CollapsedRoomDelegate.qml
Normal file
53
src/qml/Page/RoomList/CollapsedRoomDelegate.qml
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2023 Carl Schwan <carl@carlschwan.eu>
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
import QtQuick 2.15
|
||||||
|
import QtQuick.Controls 2.15 as QQC2
|
||||||
|
import QtQuick.Layouts 1.15
|
||||||
|
import QtQml.Models 2.15
|
||||||
|
|
||||||
|
import org.kde.kirigami 2.15 as Kirigami
|
||||||
|
import org.kde.kitemmodels 1.0
|
||||||
|
|
||||||
|
import org.kde.neochat 1.0
|
||||||
|
|
||||||
|
import './' as RoomList
|
||||||
|
|
||||||
|
QQC2.ItemDelegate {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property var currentRoom
|
||||||
|
required property bool categoryVisible
|
||||||
|
required property string filterText
|
||||||
|
required property string avatar
|
||||||
|
required property string name
|
||||||
|
|
||||||
|
topPadding: Kirigami.Units.largeSpacing
|
||||||
|
leftPadding: Kirigami.Units.largeSpacing
|
||||||
|
rightPadding: Kirigami.Units.largeSpacing
|
||||||
|
bottomPadding: Kirigami.Units.largeSpacing
|
||||||
|
|
||||||
|
width: ListView.view.width
|
||||||
|
height: visible ? ListView.view.width : 0
|
||||||
|
|
||||||
|
visible: root.categoryVisible || filterText.length > 0 || Config.mergeRoomList
|
||||||
|
|
||||||
|
contentItem: Kirigami.Avatar {
|
||||||
|
source: root.avatar ? `image://mxc/${root.avatar}` : ""
|
||||||
|
name: root.name || i18n("No Name")
|
||||||
|
|
||||||
|
sourceSize {
|
||||||
|
width: Kirigami.Units.gridUnit + Kirigami.Units.largeSpacing * 2
|
||||||
|
height: Kirigami.Units.gridUnit + Kirigami.Units.largeSpacing * 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onClicked: RoomManager.enterRoom(root.currentRoom)
|
||||||
|
|
||||||
|
Keys.onEnterPressed: RoomManager.enterRoom(root.currentRoom)
|
||||||
|
Keys.onReturnPressed: RoomManager.enterRoom(root.currentRoom)
|
||||||
|
|
||||||
|
QQC2.ToolTip.visible: text.length > 0 && hovered
|
||||||
|
QQC2.ToolTip.text: root.name ?? ""
|
||||||
|
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
||||||
|
}
|
||||||
301
src/qml/Page/RoomList/Page.qml
Normal file
301
src/qml/Page/RoomList/Page.qml
Normal file
@@ -0,0 +1,301 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2019 Black Hat <bhat@encom.eu.org>
|
||||||
|
// SPDX-FileCopyrightText: 2020 Carl Schwan <carl@carlschwan.eu>
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
|
import QtQuick 2.15
|
||||||
|
import QtQuick.Controls 2.15 as QQC2
|
||||||
|
import QtQuick.Layouts 1.15
|
||||||
|
import QtQml.Models 2.15
|
||||||
|
|
||||||
|
import org.kde.kirigami 2.15 as Kirigami
|
||||||
|
import org.kde.kitemmodels 1.0
|
||||||
|
|
||||||
|
import org.kde.neochat 1.0
|
||||||
|
|
||||||
|
import './' as RoomList
|
||||||
|
|
||||||
|
Kirigami.ScrollablePage {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The current width of the room list.
|
||||||
|
*
|
||||||
|
* @note Other objects can access the value but the private function makes sure
|
||||||
|
* that only the internal members can modify it.
|
||||||
|
*/
|
||||||
|
readonly property int currentWidth: _private.currentWidth
|
||||||
|
|
||||||
|
readonly property RoomListModel roomListModel: RoomListModel {
|
||||||
|
connection: Controller.activeConnection
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly property bool collapsed: Config.collapsed
|
||||||
|
|
||||||
|
property var enteredRoom: null
|
||||||
|
|
||||||
|
onCollapsedChanged: if (collapsed) {
|
||||||
|
sortFilterRoomListModel.filterText = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
header: ColumnLayout {
|
||||||
|
visible: !root.collapsed
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
RoomList.SpaceListView {
|
||||||
|
roomListModel: root.roomListModel
|
||||||
|
}
|
||||||
|
|
||||||
|
Kirigami.Separator {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: spaceListContextMenu
|
||||||
|
SpaceListContextMenu {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: RoomManager
|
||||||
|
function onCurrentRoomChanged() {
|
||||||
|
itemSelection.setCurrentIndex(roomListModel.index(roomListModel.indexForRoom(RoomManager.currentRoom), 0), ItemSelectionModel.SelectCurrent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function goToNextRoomFiltered(condition) {
|
||||||
|
let index = listView.currentIndex;
|
||||||
|
while (index++ !== listView.count - 1) {
|
||||||
|
if (condition(listView.itemAtIndex(index))) {
|
||||||
|
listView.currentIndex = index;
|
||||||
|
listView.currentItem.action.trigger();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function goToPreviousRoomFiltered(condition) {
|
||||||
|
let index = listView.currentIndex;
|
||||||
|
while (index-- !== 0) {
|
||||||
|
if (condition(listView.itemAtIndex(index))) {
|
||||||
|
listView.currentIndex = index;
|
||||||
|
listView.currentItem.action.trigger();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function goToNextRoom() {
|
||||||
|
goToNextRoomFiltered((item) => item.visible);
|
||||||
|
}
|
||||||
|
|
||||||
|
function goToPreviousRoom() {
|
||||||
|
goToPreviousRoomFiltered((item) => item.visible);
|
||||||
|
}
|
||||||
|
|
||||||
|
function goToNextUnreadRoom() {
|
||||||
|
goToNextRoomFiltered((item) => (item.visible && item.hasUnread));
|
||||||
|
}
|
||||||
|
|
||||||
|
function goToPreviousUnreadRoom() {
|
||||||
|
goToPreviousRoomFiltered((item) => (item.visible && item.hasUnread));
|
||||||
|
}
|
||||||
|
|
||||||
|
titleDelegate: ExploreComponent {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
desiredWidth: root.width - Kirigami.Units.largeSpacing
|
||||||
|
collapsed: root.collapsed
|
||||||
|
}
|
||||||
|
|
||||||
|
ListView {
|
||||||
|
id: listView
|
||||||
|
|
||||||
|
activeFocusOnTab: true
|
||||||
|
clip: AccountRegistry.count > 1
|
||||||
|
|
||||||
|
header: QQC2.ItemDelegate {
|
||||||
|
width: visible ? ListView.view.width : 0
|
||||||
|
height: visible ? Kirigami.Units.gridUnit * 2 : 0
|
||||||
|
|
||||||
|
visible: root.collapsed
|
||||||
|
|
||||||
|
topPadding: Kirigami.Units.largeSpacing
|
||||||
|
leftPadding: Kirigami.Units.largeSpacing
|
||||||
|
rightPadding: Kirigami.Units.largeSpacing
|
||||||
|
bottomPadding: Kirigami.Units.largeSpacing
|
||||||
|
|
||||||
|
onClicked: quickView.item.open();
|
||||||
|
|
||||||
|
Kirigami.Icon {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
width: Kirigami.Units.iconSizes.smallMedium
|
||||||
|
height: Kirigami.Units.iconSizes.smallMedium
|
||||||
|
source: "search"
|
||||||
|
}
|
||||||
|
|
||||||
|
Kirigami.Separator {
|
||||||
|
width: parent.width
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
Kirigami.PlaceholderMessage {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
width: parent.width - (Kirigami.Units.largeSpacing * 4)
|
||||||
|
visible: listView.count == 0
|
||||||
|
text: sortFilterRoomListModel.filterText.length > 0 ? i18n("No rooms found") : i18n("Join some rooms to get started")
|
||||||
|
helpfulAction: Kirigami.Action {
|
||||||
|
icon.name: sortFilterRoomListModel.filterText.length > 0 ? "search" : "list-add"
|
||||||
|
text: sortFilterRoomListModel.filterText.length > 0 ? i18n("Search in room directory") : i18n("Explore rooms")
|
||||||
|
onTriggered: pageStack.layers.push("qrc:/JoinRoomPage.qml", {
|
||||||
|
connection: Controller.activeConnection,
|
||||||
|
keyword: sortFilterRoomListModel.filterText
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemSelectionModel {
|
||||||
|
id: itemSelection
|
||||||
|
model: root.roomListModel
|
||||||
|
onCurrentChanged: listView.currentIndex = sortFilterRoomListModel.mapFromSource(current).row
|
||||||
|
}
|
||||||
|
|
||||||
|
model: SortFilterRoomListModel {
|
||||||
|
id: sortFilterRoomListModel
|
||||||
|
|
||||||
|
sourceModel: root.roomListModel
|
||||||
|
roomSortOrder: Config.mergeRoomList ? SortFilterRoomListModel.LastActivity : SortFilterRoomListModel.Categories
|
||||||
|
onLayoutChanged: {
|
||||||
|
listView.currentIndex = sortFilterRoomListModel.mapFromSource(itemSelection.currentIndex).row
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
section.property: sortFilterRoomListModel.filterText.length === 0 && !Config.mergeRoomList ? "category" : null
|
||||||
|
section.delegate: root.collapsed ? foldButton : sectionHeader
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: sectionHeader
|
||||||
|
Kirigami.ListSectionHeader {
|
||||||
|
height: implicitHeight
|
||||||
|
label: roomListModel.categoryName(section)
|
||||||
|
action: Kirigami.Action {
|
||||||
|
onTriggered: roomListModel.setCategoryVisible(section, !roomListModel.categoryVisible(section))
|
||||||
|
}
|
||||||
|
contentItem.children: QQC2.ToolButton {
|
||||||
|
icon {
|
||||||
|
name: roomListModel.categoryVisible(section) ? "go-up" : "go-down"
|
||||||
|
width: Kirigami.Units.iconSizes.small
|
||||||
|
height: Kirigami.Units.iconSizes.small
|
||||||
|
}
|
||||||
|
|
||||||
|
onClicked: roomListModel.setCategoryVisible(section, !roomListModel.categoryVisible(section))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Component {
|
||||||
|
id: foldButton
|
||||||
|
Item {
|
||||||
|
width: ListView.view.width
|
||||||
|
height: visible ? width : 0
|
||||||
|
QQC2.ToolButton {
|
||||||
|
id: button
|
||||||
|
anchors.centerIn: parent
|
||||||
|
|
||||||
|
icon {
|
||||||
|
name: hovered ? (roomListModel.categoryVisible(section) ? "go-up" : "go-down") : roomListModel.categoryIconName(section)
|
||||||
|
width: Kirigami.Units.iconSizes.smallMedium
|
||||||
|
height: Kirigami.Units.iconSizes.smallMedium
|
||||||
|
}
|
||||||
|
|
||||||
|
onClicked: roomListModel.setCategoryVisible(section, !roomListModel.categoryVisible(section))
|
||||||
|
|
||||||
|
QQC2.ToolTip.text: roomListModel.categoryName(section)
|
||||||
|
QQC2.ToolTip.visible: hovered
|
||||||
|
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reuseItems: true
|
||||||
|
currentIndex: -1 // we don't want any room highlighted by default
|
||||||
|
|
||||||
|
delegate: root.collapsed ? collapsedModeListComponent : normalModeListComponent
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: collapsedModeListComponent
|
||||||
|
|
||||||
|
RoomList.CollapsedRoomDelegate {
|
||||||
|
filterText: sortFilterRoomListModel.filterText
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: normalModeListComponent
|
||||||
|
|
||||||
|
RoomList.RoomDelegate {
|
||||||
|
filterText: sortFilterRoomListModel.filterText
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
footer: UserInfo {
|
||||||
|
width: parent.width
|
||||||
|
visible: !root.collapsed
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
parent: applicationWindow().overlay.parent
|
||||||
|
|
||||||
|
x: root.currentWidth - width / 2
|
||||||
|
width: Kirigami.Units.smallSpacing * 2
|
||||||
|
z: root.z + 1
|
||||||
|
enabled: RoomManager.hasOpenRoom && applicationWindow().width >= Kirigami.Units.gridUnit * 35
|
||||||
|
visible: enabled
|
||||||
|
cursorShape: Qt.SplitHCursor
|
||||||
|
|
||||||
|
property int _lastX
|
||||||
|
|
||||||
|
onPressed: mouse => {
|
||||||
|
_lastX = mouse.x;
|
||||||
|
}
|
||||||
|
onPositionChanged: mouse => {
|
||||||
|
if (_lastX == -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mouse.x > _lastX) {
|
||||||
|
// we moved to the right
|
||||||
|
if (_private.currentWidth < _private.collapseWidth && _private.currentWidth + (mouse.x - _lastX) >= _private.collapseWidth) {
|
||||||
|
// Here we get back directly to a more wide mode.
|
||||||
|
_private.currentWidth = _private.collapseWidth;
|
||||||
|
Config.collapsed = false;
|
||||||
|
} else if (_private.currentWidth >= _private.collapseWidth) {
|
||||||
|
// Increase page width
|
||||||
|
_private.currentWidth = Math.min(_private.defaultWidth, _private.currentWidth + (mouse.x - _lastX));
|
||||||
|
}
|
||||||
|
} else if (mouse.x < _lastX) {
|
||||||
|
const tmpWidth = _private.currentWidth - (_lastX - mouse.x);
|
||||||
|
if (tmpWidth < _private.collapseWidth) {
|
||||||
|
_private.currentWidth = Qt.binding(() => _private.collapsedSize + (root.contentItem.QQC2.ScrollBar.vertical.visible ? root.contentItem.QQC2.ScrollBar.vertical.width : 0));
|
||||||
|
Config.collapsed = true;
|
||||||
|
} else {
|
||||||
|
_private.currentWidth = tmpWidth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hold the modifiable currentWidth in a private object so that only internal
|
||||||
|
* members can modify it.
|
||||||
|
*/
|
||||||
|
QtObject {
|
||||||
|
id: _private
|
||||||
|
property int currentWidth: Config.collapsed ? collapsedSize : defaultWidth
|
||||||
|
readonly property int defaultWidth: Kirigami.Units.gridUnit * 17
|
||||||
|
readonly property int collapseWidth: Kirigami.Units.gridUnit * 10
|
||||||
|
readonly property int collapsedSize: Kirigami.Units.gridUnit * 3 - Kirigami.Units.smallSpacing * 3
|
||||||
|
}
|
||||||
|
}
|
||||||
136
src/qml/Page/RoomList/RoomDelegate.qml
Normal file
136
src/qml/Page/RoomList/RoomDelegate.qml
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2023 Carl Schwan <carl@carlschwan.eu>
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
import QtQuick 2.15
|
||||||
|
import QtQuick.Controls 2.15 as QQC2
|
||||||
|
import QtQuick.Layouts 1.15
|
||||||
|
import QtQml.Models 2.15
|
||||||
|
|
||||||
|
import org.kde.kirigami 2.15 as Kirigami
|
||||||
|
import org.kde.kitemmodels 1.0
|
||||||
|
|
||||||
|
import org.kde.neochat 1.0
|
||||||
|
|
||||||
|
import './' as RoomList
|
||||||
|
|
||||||
|
Kirigami.BasicListItem {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property int index
|
||||||
|
required property int unreadCount
|
||||||
|
required property int notificationCount
|
||||||
|
required property int highlightCount
|
||||||
|
required property var currentRoom
|
||||||
|
required property bool categoryVisible
|
||||||
|
required property string filterText
|
||||||
|
required property string avatar
|
||||||
|
required property string subtitleText
|
||||||
|
|
||||||
|
required property string name
|
||||||
|
|
||||||
|
readonly property bool hasUnread: unreadCount > 0
|
||||||
|
|
||||||
|
topPadding: Kirigami.Units.largeSpacing
|
||||||
|
bottomPadding: Kirigami.Units.largeSpacing
|
||||||
|
|
||||||
|
visible: root.categoryVisible || root.filterText.length > 0 || Config.mergeRoomList
|
||||||
|
highlighted: ListView.view.currentIndex === index
|
||||||
|
focus: true
|
||||||
|
icon: undefined
|
||||||
|
bold: root.unreadCount > 0
|
||||||
|
|
||||||
|
label: root.name ?? ""
|
||||||
|
labelItem.textFormat: Text.PlainText
|
||||||
|
|
||||||
|
subtitle: root.subtitleText
|
||||||
|
subtitleItem {
|
||||||
|
textFormat: Text.PlainText
|
||||||
|
visible: !Config.compactRoomList
|
||||||
|
}
|
||||||
|
|
||||||
|
onClicked: RoomManager.enterRoom(root.currentRoom)
|
||||||
|
onPressAndHold: createRoomListContextMenu()
|
||||||
|
|
||||||
|
Keys.onEnterPressed: RoomManager.enterRoom(root.currentRoom)
|
||||||
|
Keys.onReturnPressed: RoomManager.enterRoom(root.currentRoom)
|
||||||
|
|
||||||
|
TapHandler {
|
||||||
|
acceptedButtons: Qt.RightButton
|
||||||
|
acceptedDevices: PointerDevice.Mouse
|
||||||
|
onTapped: createRoomListContextMenu()
|
||||||
|
}
|
||||||
|
|
||||||
|
leading: Kirigami.Avatar {
|
||||||
|
source: root.avatar ? `image://mxc/${root.avatar}` : ""
|
||||||
|
name: root.name || i18n("No Name")
|
||||||
|
implicitWidth: visible ? height : 0
|
||||||
|
visible: Config.showAvatarInRoomDrawer
|
||||||
|
sourceSize {
|
||||||
|
width: Kirigami.Units.gridUnit + Kirigami.Units.largeSpacing * 2
|
||||||
|
height: Kirigami.Units.gridUnit + Kirigami.Units.largeSpacing * 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trailing: RowLayout {
|
||||||
|
Kirigami.Icon {
|
||||||
|
source: "notifications-disabled"
|
||||||
|
enabled: false
|
||||||
|
implicitWidth: Kirigami.Units.iconSizes.smallMedium
|
||||||
|
implicitHeight: Kirigami.Units.iconSizes.smallMedium
|
||||||
|
visible: currentRoom.pushNotificationState === PushNotificationState.Mute && !configButton.visible && unreadCount <= 0
|
||||||
|
Accessible.name: i18n("Muted room")
|
||||||
|
Layout.rightMargin: Kirigami.Units.smallSpacing
|
||||||
|
}
|
||||||
|
QQC2.Label {
|
||||||
|
id: notificationCountLabel
|
||||||
|
text: notificationCount > 0 ? notificationCount : "●"
|
||||||
|
visible: unreadCount > 0
|
||||||
|
color: Kirigami.Theme.textColor
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
background: Rectangle {
|
||||||
|
visible: notificationCount > 0
|
||||||
|
Kirigami.Theme.colorSet: Kirigami.Theme.Button
|
||||||
|
color: highlightCount > 0 ? Kirigami.Theme.positiveTextColor : Kirigami.Theme.disabledTextColor
|
||||||
|
opacity: highlightCount > 0 ? 1 : 0.3
|
||||||
|
radius: height / 2
|
||||||
|
}
|
||||||
|
|
||||||
|
Layout.rightMargin: Kirigami.Units.smallSpacing
|
||||||
|
Layout.minimumHeight: Kirigami.Units.iconSizes.smallMedium
|
||||||
|
Layout.minimumWidth: Math.max(notificationCountTextMetrics.advanceWidth + Kirigami.Units.smallSpacing * 2, height)
|
||||||
|
|
||||||
|
TextMetrics {
|
||||||
|
id: notificationCountTextMetrics
|
||||||
|
text: notificationCountLabel.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QQC2.Button {
|
||||||
|
id: configButton
|
||||||
|
visible: root.hovered && !Kirigami.Settings.isMobile && !Config.compactRoomList
|
||||||
|
text: i18n("Configure room")
|
||||||
|
display: QQC2.Button.IconOnly
|
||||||
|
|
||||||
|
icon.name: "configure"
|
||||||
|
onClicked: createRoomListContextMenu()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createRoomListContextMenu() {
|
||||||
|
const component = Qt.createComponent(Qt.resolvedUrl("./ContextMenu.qml"))
|
||||||
|
const menu = component.createObject(root, {
|
||||||
|
room: root.currentRoom,
|
||||||
|
});
|
||||||
|
if (!Kirigami.Settings.isMobile && !Config.compactRoomList) {
|
||||||
|
configButton.visible = true;
|
||||||
|
configButton.down = true;
|
||||||
|
}
|
||||||
|
menu.closed.connect(function() {
|
||||||
|
configButton.down = undefined;
|
||||||
|
configButton.visible = Qt.binding(() => {
|
||||||
|
return root.hovered && !Kirigami.Settings.isMobile
|
||||||
|
&& !Config.compactRoomList;
|
||||||
|
});
|
||||||
|
})
|
||||||
|
menu.open()
|
||||||
|
}
|
||||||
|
}
|
||||||
47
src/qml/Page/RoomList/SpaceDelegate.qml
Normal file
47
src/qml/Page/RoomList/SpaceDelegate.qml
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2022 Snehit Sah <snehitsah@protonmail.com>
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
import QtQuick 2.15
|
||||||
|
import QtQuick.Controls 2.15 as QQC2
|
||||||
|
import QtQuick.Layouts 1.15
|
||||||
|
|
||||||
|
import org.kde.kirigami 2.20 as Kirigami
|
||||||
|
import org.kde.neochat 1.0
|
||||||
|
|
||||||
|
QQC2.ItemDelegate {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property string avatar
|
||||||
|
required property var currentRoom
|
||||||
|
required property int index
|
||||||
|
required property string id
|
||||||
|
|
||||||
|
signal createContextMenu(currentRoom: var)
|
||||||
|
signal spaceSelected(spaceId: string)
|
||||||
|
|
||||||
|
height: ListView.view.height
|
||||||
|
width: height
|
||||||
|
|
||||||
|
leftPadding: topPadding
|
||||||
|
rightPadding: topPadding
|
||||||
|
|
||||||
|
contentItem: Kirigami.Avatar {
|
||||||
|
name: currentRoom.displayName
|
||||||
|
source: avatar !== "" ? "image://mxc/" + avatar : ""
|
||||||
|
}
|
||||||
|
|
||||||
|
onClicked: root.spaceSelected(id)
|
||||||
|
onPressAndHold: root.createContextMenu(root.currentRoom)
|
||||||
|
|
||||||
|
Accessible.name: currentRoom.displayName
|
||||||
|
|
||||||
|
QQC2.ToolTip.text: currentRoom.displayName
|
||||||
|
QQC2.ToolTip.visible: hovered
|
||||||
|
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
||||||
|
|
||||||
|
TapHandler {
|
||||||
|
acceptedButtons: Qt.RightButton
|
||||||
|
acceptedDevices: PointerDevice.Mouse
|
||||||
|
onTapped: root.createContextMenu(root.currentRoom)
|
||||||
|
}
|
||||||
|
}
|
||||||
64
src/qml/Page/RoomList/SpaceListView.qml
Normal file
64
src/qml/Page/RoomList/SpaceListView.qml
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2022 Snehit Sah <snehitsah@protonmail.com>
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
import QtQuick 2.15
|
||||||
|
import QtQuick.Controls 2.15 as QQC2
|
||||||
|
import QtQuick.Layouts 1.15
|
||||||
|
|
||||||
|
import org.kde.kirigami 2.20 as Kirigami
|
||||||
|
import org.kde.neochat 1.0
|
||||||
|
|
||||||
|
ListView {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property RoomListModel roomListModel
|
||||||
|
|
||||||
|
orientation: Qt.Horizontal
|
||||||
|
spacing: Kirigami.Units.smallSpacing
|
||||||
|
clip: true
|
||||||
|
visible: root.count > 0
|
||||||
|
|
||||||
|
model: SortFilterSpaceListModel {
|
||||||
|
id: sortFilterSpaceListModel
|
||||||
|
sourceModel: root.roomListModel
|
||||||
|
}
|
||||||
|
|
||||||
|
header: QQC2.ItemDelegate {
|
||||||
|
id: homeButton
|
||||||
|
icon.name: "home"
|
||||||
|
text: i18nc("@action:button", "Show All Rooms")
|
||||||
|
height: parent.height
|
||||||
|
width: height
|
||||||
|
leftPadding: topPadding
|
||||||
|
rightPadding: topPadding
|
||||||
|
|
||||||
|
contentItem: Kirigami.Icon {
|
||||||
|
source: "home"
|
||||||
|
}
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
sortFilterRoomListModel.activeSpaceId = "";
|
||||||
|
listView.positionViewAtIndex(0, ListView.Beginning);
|
||||||
|
}
|
||||||
|
|
||||||
|
QQC2.ToolTip.text: homeButton.text
|
||||||
|
QQC2.ToolTip.visible: hovered
|
||||||
|
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
||||||
|
}
|
||||||
|
|
||||||
|
delegate: SpaceDelegate {
|
||||||
|
onSpaceSelected: (spaceId) => {
|
||||||
|
sortFilterRoomListModel.activeSpaceId = spaceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
onCreateContextMenu: () => {
|
||||||
|
const menu = spaceListContextMenu.createObject(page, {
|
||||||
|
room: currentRoom,
|
||||||
|
});
|
||||||
|
menu.open();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Layout.preferredHeight: Kirigami.Units.gridUnit * 2
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
@@ -1,502 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2019 Black Hat <bhat@encom.eu.org>
|
|
||||||
// SPDX-FileCopyrightText: 2020 Carl Schwan <carl@carlschwan.eu>
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
|
||||||
|
|
||||||
import QtQuick 2.15
|
|
||||||
import QtQuick.Controls 2.15 as QQC2
|
|
||||||
import QtQuick.Layouts 1.15
|
|
||||||
import QtQml.Models 2.15
|
|
||||||
|
|
||||||
import org.kde.kirigami 2.15 as Kirigami
|
|
||||||
import org.kde.kitemmodels 1.0
|
|
||||||
|
|
||||||
import org.kde.neochat 1.0
|
|
||||||
|
|
||||||
Kirigami.ScrollablePage {
|
|
||||||
id: page
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The current width of the room list.
|
|
||||||
*
|
|
||||||
* @note Other objects can access the value but the private function makes sure
|
|
||||||
* that only the internal members can modify it.
|
|
||||||
*/
|
|
||||||
readonly property int currentWidth: _private.currentWidth
|
|
||||||
|
|
||||||
readonly property bool collapsed: Config.collapsed
|
|
||||||
onCollapsedChanged: if (collapsed) {
|
|
||||||
sortFilterRoomListModel.filterText = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
header: ColumnLayout {
|
|
||||||
visible: !page.collapsed
|
|
||||||
spacing: 0
|
|
||||||
|
|
||||||
ListView {
|
|
||||||
id: spaceList
|
|
||||||
property string activeSpaceId: ""
|
|
||||||
|
|
||||||
orientation: Qt.Horizontal
|
|
||||||
spacing: Kirigami.Units.smallSpacing
|
|
||||||
clip: true
|
|
||||||
visible: spaceList.count > 0
|
|
||||||
|
|
||||||
Layout.preferredHeight: Kirigami.Units.gridUnit * 2
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
model: SortFilterSpaceListModel {
|
|
||||||
id: sortFilterSpaceListModel
|
|
||||||
sourceModel: roomListModel
|
|
||||||
}
|
|
||||||
|
|
||||||
header: QQC2.ItemDelegate {
|
|
||||||
id: homeButton
|
|
||||||
icon.name: "home"
|
|
||||||
text: i18nc("@action:button", "Show All Rooms")
|
|
||||||
height: parent.height
|
|
||||||
width: height
|
|
||||||
leftPadding: topPadding
|
|
||||||
rightPadding: topPadding
|
|
||||||
|
|
||||||
contentItem: Kirigami.Icon {
|
|
||||||
source: "home"
|
|
||||||
}
|
|
||||||
|
|
||||||
onClicked: {
|
|
||||||
sortFilterRoomListModel.activeSpaceId = "";
|
|
||||||
spaceList.activeSpaceId = '';
|
|
||||||
listView.positionViewAtIndex(0, ListView.Beginning);
|
|
||||||
}
|
|
||||||
|
|
||||||
QQC2.ToolTip.text: homeButton.text
|
|
||||||
QQC2.ToolTip.visible: hovered
|
|
||||||
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
|
||||||
}
|
|
||||||
|
|
||||||
delegate: QQC2.ItemDelegate {
|
|
||||||
required property string avatar
|
|
||||||
required property var currentRoom
|
|
||||||
required property int index
|
|
||||||
required property string id
|
|
||||||
|
|
||||||
height: parent.height
|
|
||||||
width: height
|
|
||||||
leftPadding: topPadding
|
|
||||||
rightPadding: topPadding
|
|
||||||
|
|
||||||
contentItem: Kirigami.Avatar {
|
|
||||||
name: currentRoom.displayName
|
|
||||||
source: avatar !== "" ? "image://mxc/" + avatar : ""
|
|
||||||
}
|
|
||||||
|
|
||||||
onClicked: {
|
|
||||||
spaceList.activeSpaceId = id;
|
|
||||||
sortFilterRoomListModel.activeSpaceId = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
Accessible.name: currentRoom.displayName
|
|
||||||
|
|
||||||
QQC2.ToolTip.text: currentRoom.displayName
|
|
||||||
QQC2.ToolTip.visible: hovered
|
|
||||||
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
|
||||||
|
|
||||||
onPressAndHold: {
|
|
||||||
spaceList.createContextMenu(currentRoom)
|
|
||||||
}
|
|
||||||
TapHandler {
|
|
||||||
acceptedButtons: Qt.RightButton
|
|
||||||
acceptedDevices: PointerDevice.Mouse
|
|
||||||
onTapped: spaceList.createContextMenu(currentRoom)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function createContextMenu(room) {
|
|
||||||
const menu = spaceListContextMenu.createObject(page, {room: room})
|
|
||||||
menu.open()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Kirigami.Separator {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
}
|
|
||||||
|
|
||||||
Component {
|
|
||||||
id: spaceListContextMenu
|
|
||||||
SpaceListContextMenu {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
property var enteredRoom
|
|
||||||
|
|
||||||
Connections {
|
|
||||||
target: RoomManager
|
|
||||||
function onCurrentRoomChanged() {
|
|
||||||
itemSelection.setCurrentIndex(roomListModel.index(roomListModel.indexForRoom(RoomManager.currentRoom), 0), ItemSelectionModel.SelectCurrent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function goToNextRoomFiltered(condition) {
|
|
||||||
let index = listView.currentIndex;
|
|
||||||
while (index++ !== listView.count - 1) {
|
|
||||||
if (condition(listView.itemAtIndex(index))) {
|
|
||||||
listView.currentIndex = index;
|
|
||||||
listView.currentItem.action.trigger();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function goToPreviousRoomFiltered(condition) {
|
|
||||||
let index = listView.currentIndex;
|
|
||||||
while (index-- !== 0) {
|
|
||||||
if (condition(listView.itemAtIndex(index))) {
|
|
||||||
listView.currentIndex = index;
|
|
||||||
listView.currentItem.action.trigger();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function goToNextRoom() {
|
|
||||||
goToNextRoomFiltered((item) => item.visible);
|
|
||||||
}
|
|
||||||
|
|
||||||
function goToPreviousRoom() {
|
|
||||||
goToPreviousRoomFiltered((item) => item.visible);
|
|
||||||
}
|
|
||||||
|
|
||||||
function goToNextUnreadRoom() {
|
|
||||||
goToNextRoomFiltered((item) => (item.visible && item.hasUnread));
|
|
||||||
}
|
|
||||||
|
|
||||||
function goToPreviousUnreadRoom() {
|
|
||||||
goToPreviousRoomFiltered((item) => (item.visible && item.hasUnread));
|
|
||||||
}
|
|
||||||
|
|
||||||
titleDelegate: ExploreComponent {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
desiredWidth: page.width - Kirigami.Units.largeSpacing
|
|
||||||
collapsed: page.collapsed
|
|
||||||
}
|
|
||||||
|
|
||||||
ListView {
|
|
||||||
id: listView
|
|
||||||
|
|
||||||
activeFocusOnTab: true
|
|
||||||
clip: AccountRegistry.count > 1
|
|
||||||
|
|
||||||
header: QQC2.ItemDelegate {
|
|
||||||
visible: page.collapsed
|
|
||||||
action: Kirigami.Action {
|
|
||||||
id: enterRoomAction
|
|
||||||
onTriggered: quickView.item.open();
|
|
||||||
}
|
|
||||||
topPadding: Kirigami.Units.largeSpacing
|
|
||||||
leftPadding: Kirigami.Units.largeSpacing
|
|
||||||
rightPadding: Kirigami.Units.largeSpacing
|
|
||||||
bottomPadding: Kirigami.Units.largeSpacing
|
|
||||||
width: visible ? ListView.view.width : 0
|
|
||||||
height: visible ? Kirigami.Units.gridUnit * 2 : 0
|
|
||||||
|
|
||||||
Kirigami.Icon {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
width: 22
|
|
||||||
height: 22
|
|
||||||
source: "search"
|
|
||||||
}
|
|
||||||
Kirigami.Separator {
|
|
||||||
width: parent.width
|
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
Kirigami.PlaceholderMessage {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
width: parent.width - (Kirigami.Units.largeSpacing * 4)
|
|
||||||
visible: listView.count == 0
|
|
||||||
text: sortFilterRoomListModel.filterText.length > 0 ? i18n("No rooms found") : i18n("Join some rooms to get started")
|
|
||||||
helpfulAction: Kirigami.Action {
|
|
||||||
icon.name: sortFilterRoomListModel.filterText.length > 0 ? "search" : "list-add"
|
|
||||||
text: sortFilterRoomListModel.filterText.length > 0 ? i18n("Search in room directory") : i18n("Explore rooms")
|
|
||||||
onTriggered: pageStack.layers.push("qrc:/JoinRoomPage.qml", {
|
|
||||||
connection: Controller.activeConnection,
|
|
||||||
keyword: sortFilterRoomListModel.filterText
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ItemSelectionModel {
|
|
||||||
id: itemSelection
|
|
||||||
model: roomListModel
|
|
||||||
onCurrentChanged: {
|
|
||||||
listView.currentIndex = sortFilterRoomListModel.mapFromSource(current).row
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
model: SortFilterRoomListModel {
|
|
||||||
id: sortFilterRoomListModel
|
|
||||||
sourceModel: RoomListModel {
|
|
||||||
id: roomListModel
|
|
||||||
connection: Controller.activeConnection
|
|
||||||
}
|
|
||||||
roomSortOrder: Config.mergeRoomList ? SortFilterRoomListModel.LastActivity : SortFilterRoomListModel.Categories
|
|
||||||
onLayoutChanged: {
|
|
||||||
listView.currentIndex = sortFilterRoomListModel.mapFromSource(itemSelection.currentIndex).row
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
section.property: sortFilterRoomListModel.filterText.length === 0 && !Config.mergeRoomList ? "category" : null
|
|
||||||
section.delegate: page.collapsed ? foldButton : sectionHeader
|
|
||||||
|
|
||||||
Component {
|
|
||||||
id: sectionHeader
|
|
||||||
Kirigami.ListSectionHeader {
|
|
||||||
height: implicitHeight
|
|
||||||
label: roomListModel.categoryName(section)
|
|
||||||
action: Kirigami.Action {
|
|
||||||
onTriggered: roomListModel.setCategoryVisible(section, !roomListModel.categoryVisible(section))
|
|
||||||
}
|
|
||||||
contentItem.children: QQC2.ToolButton {
|
|
||||||
icon.name: (roomListModel.categoryVisible(section) ? "go-up" : "go-down")
|
|
||||||
icon.width: Kirigami.Units.iconSizes.small
|
|
||||||
icon.height: Kirigami.Units.iconSizes.small
|
|
||||||
|
|
||||||
onClicked: roomListModel.setCategoryVisible(section, !roomListModel.categoryVisible(section))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Component {
|
|
||||||
id: foldButton
|
|
||||||
Item {
|
|
||||||
width: ListView.view.width
|
|
||||||
height: visible ? width : 0
|
|
||||||
QQC2.ToolButton {
|
|
||||||
id: button
|
|
||||||
anchors.centerIn: parent
|
|
||||||
|
|
||||||
icon.name: hovered ? (roomListModel.categoryVisible(section) ? "go-up" : "go-down") : roomListModel.categoryIconName(section)
|
|
||||||
icon.width: Kirigami.Units.iconSizes.smallMedium
|
|
||||||
icon.height: Kirigami.Units.iconSizes.smallMedium
|
|
||||||
|
|
||||||
onClicked: roomListModel.setCategoryVisible(section, !roomListModel.categoryVisible(section))
|
|
||||||
|
|
||||||
QQC2.ToolTip.text: roomListModel.categoryName(section)
|
|
||||||
QQC2.ToolTip.visible: hovered
|
|
||||||
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
reuseItems: true
|
|
||||||
currentIndex: -1 // we don't want any room highlighted by default
|
|
||||||
|
|
||||||
delegate: page.collapsed ? collapsedModeListComponent : normalModeListComponent
|
|
||||||
|
|
||||||
Component {
|
|
||||||
id: collapsedModeListComponent
|
|
||||||
|
|
||||||
QQC2.ItemDelegate {
|
|
||||||
action: Kirigami.Action {
|
|
||||||
id: enterRoomAction
|
|
||||||
onTriggered: {
|
|
||||||
RoomManager.enterRoom(currentRoom);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Keys.onEnterPressed: enterRoomAction.trigger()
|
|
||||||
Keys.onReturnPressed: enterRoomAction.trigger()
|
|
||||||
topPadding: Kirigami.Units.largeSpacing
|
|
||||||
leftPadding: Kirigami.Units.largeSpacing
|
|
||||||
rightPadding: Kirigami.Units.largeSpacing
|
|
||||||
bottomPadding: Kirigami.Units.largeSpacing
|
|
||||||
width: ListView.view.width
|
|
||||||
height: visible ? ListView.view.width : 0
|
|
||||||
visible: model.categoryVisible || sortFilterRoomListModel.filterText.length > 0 || Config.mergeRoomList
|
|
||||||
|
|
||||||
contentItem: Kirigami.Avatar {
|
|
||||||
source: avatar ? "image://mxc/" + avatar : ""
|
|
||||||
name: model.name || i18n("No Name")
|
|
||||||
sourceSize.width: Kirigami.Units.gridUnit + Kirigami.Units.largeSpacing * 2
|
|
||||||
sourceSize.height: Kirigami.Units.gridUnit + Kirigami.Units.largeSpacing * 2
|
|
||||||
}
|
|
||||||
|
|
||||||
QQC2.ToolTip {
|
|
||||||
enabled: text.length !== 0
|
|
||||||
text: name ?? ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Component {
|
|
||||||
id: roomListContextMenu
|
|
||||||
RoomListContextMenu {}
|
|
||||||
}
|
|
||||||
|
|
||||||
Component {
|
|
||||||
id: normalModeListComponent
|
|
||||||
Kirigami.BasicListItem {
|
|
||||||
id: roomListItem
|
|
||||||
visible: model.categoryVisible || sortFilterRoomListModel.filterText.length > 0 || Config.mergeRoomList
|
|
||||||
topPadding: Kirigami.Units.largeSpacing
|
|
||||||
bottomPadding: Kirigami.Units.largeSpacing
|
|
||||||
highlighted: listView.currentIndex === index
|
|
||||||
focus: true
|
|
||||||
icon: undefined
|
|
||||||
action: Kirigami.Action {
|
|
||||||
id: enterRoomAction
|
|
||||||
onTriggered: {
|
|
||||||
RoomManager.enterRoom(currentRoom);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Keys.onEnterPressed: enterRoomAction.trigger()
|
|
||||||
Keys.onReturnPressed: enterRoomAction.trigger()
|
|
||||||
bold: unreadCount > 0
|
|
||||||
label: name ?? ""
|
|
||||||
labelItem.textFormat: Text.PlainText
|
|
||||||
subtitle: subtitleText
|
|
||||||
subtitleItem.textFormat: Text.PlainText
|
|
||||||
subtitleItem.visible: !Config.compactRoomList
|
|
||||||
onPressAndHold: {
|
|
||||||
createRoomListContextMenu()
|
|
||||||
}
|
|
||||||
TapHandler {
|
|
||||||
acceptedButtons: Qt.RightButton
|
|
||||||
acceptedDevices: PointerDevice.Mouse
|
|
||||||
onTapped: createRoomListContextMenu()
|
|
||||||
}
|
|
||||||
|
|
||||||
leading: Kirigami.Avatar {
|
|
||||||
source: avatar ? "image://mxc/" + avatar : ""
|
|
||||||
name: model.name || i18n("No Name")
|
|
||||||
implicitWidth: visible ? height : 0
|
|
||||||
visible: Config.showAvatarInRoomDrawer
|
|
||||||
sourceSize.width: Kirigami.Units.gridUnit + Kirigami.Units.largeSpacing * 2
|
|
||||||
sourceSize.height: Kirigami.Units.gridUnit + Kirigami.Units.largeSpacing * 2
|
|
||||||
}
|
|
||||||
|
|
||||||
trailing: RowLayout {
|
|
||||||
Kirigami.Icon {
|
|
||||||
source: "notifications-disabled"
|
|
||||||
enabled: false
|
|
||||||
implicitWidth: Kirigami.Units.iconSizes.smallMedium
|
|
||||||
implicitHeight: Kirigami.Units.iconSizes.smallMedium
|
|
||||||
Layout.rightMargin: Kirigami.Units.smallSpacing
|
|
||||||
visible: currentRoom.pushNotificationState === PushNotificationState.Mute && !configButton.visible && unreadCount <= 0
|
|
||||||
Accessible.name: i18n("Muted room")
|
|
||||||
}
|
|
||||||
QQC2.Label {
|
|
||||||
id: notificationCountLabel
|
|
||||||
text: notificationCount > 0 ? notificationCount : "●"
|
|
||||||
visible: unreadCount > 0
|
|
||||||
color: Kirigami.Theme.textColor
|
|
||||||
Layout.rightMargin: Kirigami.Units.smallSpacing
|
|
||||||
Layout.minimumHeight: Kirigami.Units.iconSizes.smallMedium
|
|
||||||
Layout.minimumWidth: Math.max(notificationCountTextMetrics.advanceWidth + Kirigami.Units.smallSpacing * 2, height)
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
background: Rectangle {
|
|
||||||
visible: notificationCount > 0
|
|
||||||
Kirigami.Theme.colorSet: Kirigami.Theme.Button
|
|
||||||
color: highlightCount > 0 ? Kirigami.Theme.positiveTextColor : Kirigami.Theme.disabledTextColor
|
|
||||||
opacity: highlightCount > 0 ? 1 : 0.3
|
|
||||||
radius: height / 2
|
|
||||||
}
|
|
||||||
|
|
||||||
TextMetrics {
|
|
||||||
id: notificationCountTextMetrics
|
|
||||||
text: notificationCountLabel.text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
QQC2.Button {
|
|
||||||
id: configButton
|
|
||||||
visible: roomListItem.hovered && !Kirigami.Settings.isMobile && !Config.compactRoomList
|
|
||||||
Accessible.name: i18n("Configure room")
|
|
||||||
|
|
||||||
action: Kirigami.Action {
|
|
||||||
id: optionAction
|
|
||||||
icon.name: "configure"
|
|
||||||
onTriggered: {
|
|
||||||
createRoomListContextMenu()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function createRoomListContextMenu() {
|
|
||||||
const menu = roomListContextMenu.createObject(page, {room: currentRoom})
|
|
||||||
if (!Kirigami.Settings.isMobile && !Config.compactRoomList) {
|
|
||||||
configButton.visible = true
|
|
||||||
configButton.down = true
|
|
||||||
}
|
|
||||||
menu.closed.connect(function() {
|
|
||||||
configButton.down = undefined
|
|
||||||
configButton.visible = Qt.binding(function() { return roomListItem.hovered && !Kirigami.Settings.isMobile && !Config.compactRoomList })
|
|
||||||
})
|
|
||||||
menu.open()
|
|
||||||
}
|
|
||||||
|
|
||||||
readonly property bool hasUnread: unreadCount > 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
footer: UserInfo {
|
|
||||||
width: parent.width
|
|
||||||
visible: !page.collapsed
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
parent: applicationWindow().overlay.parent
|
|
||||||
|
|
||||||
x: page.currentWidth - width / 2
|
|
||||||
width: Kirigami.Units.smallSpacing * 2
|
|
||||||
z: page.z + 1
|
|
||||||
enabled: RoomManager.hasOpenRoom && applicationWindow().width >= Kirigami.Units.gridUnit * 35
|
|
||||||
visible: enabled
|
|
||||||
cursorShape: Qt.SplitHCursor
|
|
||||||
|
|
||||||
property int _lastX
|
|
||||||
|
|
||||||
onPressed: mouse => {
|
|
||||||
_lastX = mouse.x;
|
|
||||||
}
|
|
||||||
onPositionChanged: mouse => {
|
|
||||||
if (_lastX == -1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (mouse.x > _lastX) {
|
|
||||||
// we moved to the right
|
|
||||||
if (_private.currentWidth < _private.collapseWidth && _private.currentWidth + (mouse.x - _lastX) >= _private.collapseWidth) {
|
|
||||||
// Here we get back directly to a more wide mode.
|
|
||||||
_private.currentWidth = _private.collapseWidth;
|
|
||||||
Config.collapsed = false;
|
|
||||||
} else if (_private.currentWidth >= _private.collapseWidth) {
|
|
||||||
// Increase page width
|
|
||||||
_private.currentWidth = Math.min(_private.defaultWidth, _private.currentWidth + (mouse.x - _lastX));
|
|
||||||
}
|
|
||||||
} else if (mouse.x < _lastX) {
|
|
||||||
const tmpWidth = _private.currentWidth - (_lastX - mouse.x);
|
|
||||||
if (tmpWidth < _private.collapseWidth) {
|
|
||||||
_private.currentWidth = Qt.binding(() => _private.collapsedSize + (page.contentItem.QQC2.ScrollBar.vertical.visible ? page.contentItem.QQC2.ScrollBar.vertical.width : 0));
|
|
||||||
Config.collapsed = true;
|
|
||||||
} else {
|
|
||||||
_private.currentWidth = tmpWidth;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Hold the modifiable currentWidth in a private object so that only internal
|
|
||||||
* members can modify it.
|
|
||||||
*/
|
|
||||||
QtObject {
|
|
||||||
id: _private
|
|
||||||
property int currentWidth: Config.collapsed ? collapsedSize : defaultWidth
|
|
||||||
readonly property int defaultWidth: Kirigami.Units.gridUnit * 17
|
|
||||||
readonly property int collapseWidth: Kirigami.Units.gridUnit * 10
|
|
||||||
readonly property int collapsedSize: Kirigami.Units.gridUnit * 3 - Kirigami.Units.smallSpacing * 3
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -9,6 +9,8 @@ import QtQuick.Layouts 1.15
|
|||||||
import org.kde.kirigami 2.15 as Kirigami
|
import org.kde.kirigami 2.15 as Kirigami
|
||||||
|
|
||||||
import org.kde.neochat 1.0
|
import org.kde.neochat 1.0
|
||||||
|
import './RoomList' as RoomList
|
||||||
|
import './Dialog' as Dialog
|
||||||
|
|
||||||
Kirigami.ApplicationWindow {
|
Kirigami.ApplicationWindow {
|
||||||
id: root
|
id: root
|
||||||
@@ -24,7 +26,7 @@ Kirigami.ApplicationWindow {
|
|||||||
pageStack.initialPage: LoadingPage {}
|
pageStack.initialPage: LoadingPage {}
|
||||||
pageStack.globalToolBar.canContainHandles: true
|
pageStack.globalToolBar.canContainHandles: true
|
||||||
|
|
||||||
property RoomListPage roomListPage
|
property RoomList.Page roomListPage
|
||||||
property bool roomListLoaded: false
|
property bool roomListLoaded: false
|
||||||
|
|
||||||
property RoomPage roomPage
|
property RoomPage roomPage
|
||||||
@@ -167,7 +169,7 @@ Kirigami.ApplicationWindow {
|
|||||||
pageStack.globalToolBar.style: Kirigami.ApplicationHeaderStyle.ToolBar
|
pageStack.globalToolBar.style: Kirigami.ApplicationHeaderStyle.ToolBar
|
||||||
pageStack.globalToolBar.showNavigationButtons: pageStack.currentIndex > 0 || pageStack.layers.depth > 1 ? Kirigami.ApplicationHeaderStyle.ShowBackButton : 0
|
pageStack.globalToolBar.showNavigationButtons: pageStack.currentIndex > 0 || pageStack.layers.depth > 1 ? Kirigami.ApplicationHeaderStyle.ShowBackButton : 0
|
||||||
|
|
||||||
ConfirmLogoutDialog {
|
Dialog.ConfirmLogoutDialog {
|
||||||
id: confirmLogoutDialog
|
id: confirmLogoutDialog
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,7 +202,7 @@ Kirigami.ApplicationWindow {
|
|||||||
|
|
||||||
Component {
|
Component {
|
||||||
id: roomListComponent
|
id: roomListComponent
|
||||||
RoomListPage {
|
RoomList.Page {
|
||||||
id: roomList
|
id: roomList
|
||||||
|
|
||||||
Shortcut {
|
Shortcut {
|
||||||
|
|||||||
21
src/res.qrc
21
src/res.qrc
@@ -2,9 +2,21 @@
|
|||||||
<qresource prefix="/">
|
<qresource prefix="/">
|
||||||
<file alias="icons/org.kde.neochat.svg">../org.kde.neochat.svg</file>
|
<file alias="icons/org.kde.neochat.svg">../org.kde.neochat.svg</file>
|
||||||
<file alias="icons/org.kde.neochat.tray.svg">../org.kde.neochat.tray.svg</file>
|
<file alias="icons/org.kde.neochat.tray.svg">../org.kde.neochat.tray.svg</file>
|
||||||
|
|
||||||
<file alias="main.qml">qml/main.qml</file>
|
<file alias="main.qml">qml/main.qml</file>
|
||||||
|
|
||||||
|
<file alias="RoomList/AccountMenu.qml">qml/Page/RoomList/AccountMenu.qml</file>
|
||||||
|
<file alias="RoomList/ExploreComponent.qml">qml/Page/RoomList/ExploreComponent.qml</file>
|
||||||
|
<file alias="RoomList/ContextMenu.qml">qml/Page/RoomList/ContextMenu.qml</file>
|
||||||
|
<file alias="RoomList/CollapsedRoomDelegate.qml">qml/Page/RoomList/CollapsedRoomDelegate.qml</file>
|
||||||
|
<file alias="RoomList/RoomDelegate.qml">qml/Page/RoomList/RoomDelegate.qml</file>
|
||||||
|
<file alias="RoomList/Page.qml">qml/Page/RoomList/Page.qml</file>
|
||||||
|
<file alias="RoomList/SpaceListContextMenu.qml">qml/Page/RoomList/SpaceListContextMenu.qml</file>
|
||||||
|
<file alias="RoomList/SpaceDelegate.qml">qml/Page/RoomList/SpaceDelegate.qml</file>
|
||||||
|
<file alias="RoomList/SpaceListView.qml">qml/Page/RoomList/SpaceListView.qml</file>
|
||||||
|
<file alias="RoomList/UserInfo.qml">qml/Page/RoomList/UserInfo.qml</file>
|
||||||
|
|
||||||
<file alias="LoadingPage.qml">qml/Page/LoadingPage.qml</file>
|
<file alias="LoadingPage.qml">qml/Page/LoadingPage.qml</file>
|
||||||
<file alias="RoomListPage.qml">qml/Page/RoomListPage.qml</file>
|
|
||||||
<file alias="RoomPage.qml">qml/Page/RoomPage.qml</file>
|
<file alias="RoomPage.qml">qml/Page/RoomPage.qml</file>
|
||||||
<file alias="RoomWindow.qml">qml/Page/RoomWindow.qml</file>
|
<file alias="RoomWindow.qml">qml/Page/RoomWindow.qml</file>
|
||||||
<file alias="JoinRoomPage.qml">qml/Page/JoinRoomPage.qml</file>
|
<file alias="JoinRoomPage.qml">qml/Page/JoinRoomPage.qml</file>
|
||||||
@@ -18,12 +30,10 @@
|
|||||||
<file alias="Categories.qml">qml/RoomSettings/Categories.qml</file>
|
<file alias="Categories.qml">qml/RoomSettings/Categories.qml</file>
|
||||||
<file alias="Permissions.qml">qml/RoomSettings/Permissions.qml</file>
|
<file alias="Permissions.qml">qml/RoomSettings/Permissions.qml</file>
|
||||||
<file alias="FullScreenImage.qml">qml/Component/FullScreenImage.qml</file>
|
<file alias="FullScreenImage.qml">qml/Component/FullScreenImage.qml</file>
|
||||||
<file alias="UserInfo.qml">qml/Component/UserInfo.qml</file>
|
|
||||||
<file alias="FancyEffectsContainer.qml">qml/Component/FancyEffectsContainer.qml</file>
|
<file alias="FancyEffectsContainer.qml">qml/Component/FancyEffectsContainer.qml</file>
|
||||||
<file alias="TypingPane.qml">qml/Component/TypingPane.qml</file>
|
<file alias="TypingPane.qml">qml/Component/TypingPane.qml</file>
|
||||||
<file alias="ShimmerGradient.qml">qml/Component/ShimmerGradient.qml</file>
|
<file alias="ShimmerGradient.qml">qml/Component/ShimmerGradient.qml</file>
|
||||||
<file alias="QuickSwitcher.qml">qml/Component/QuickSwitcher.qml</file>
|
<file alias="QuickSwitcher.qml">qml/Component/QuickSwitcher.qml</file>
|
||||||
<file alias="ExploreComponent.qml">qml/Component/ExploreComponent.qml</file>
|
|
||||||
<file alias="ChatBox.qml">qml/Component/ChatBox/ChatBox.qml</file>
|
<file alias="ChatBox.qml">qml/Component/ChatBox/ChatBox.qml</file>
|
||||||
<file alias="ChatBar.qml">qml/Component/ChatBox/ChatBar.qml</file>
|
<file alias="ChatBar.qml">qml/Component/ChatBox/ChatBar.qml</file>
|
||||||
<file alias="AttachmentPane.qml">qml/Component/ChatBox/AttachmentPane.qml</file>
|
<file alias="AttachmentPane.qml">qml/Component/ChatBox/AttachmentPane.qml</file>
|
||||||
@@ -66,7 +76,7 @@
|
|||||||
<file alias="EmojiDialog.qml">qml/Dialog/EmojiDialog.qml</file>
|
<file alias="EmojiDialog.qml">qml/Dialog/EmojiDialog.qml</file>
|
||||||
<file alias="OpenFileDialog.qml">qml/Dialog/OpenFileDialog.qml</file>
|
<file alias="OpenFileDialog.qml">qml/Dialog/OpenFileDialog.qml</file>
|
||||||
<file alias="KeyVerificationDialog.qml">qml/Dialog/KeyVerification/KeyVerificationDialog.qml</file>
|
<file alias="KeyVerificationDialog.qml">qml/Dialog/KeyVerification/KeyVerificationDialog.qml</file>
|
||||||
<file alias="ConfirmLogoutDialog.qml">qml/Dialog/ConfirmLogoutDialog.qml</file>
|
<file alias="Dialog/ConfirmLogoutDialog.qml">qml/Dialog/ConfirmLogoutDialog.qml</file>
|
||||||
<file alias="PowerLevelDialog.qml">qml/Dialog/PowerLevelDialog.qml</file>
|
<file alias="PowerLevelDialog.qml">qml/Dialog/PowerLevelDialog.qml</file>
|
||||||
<file alias="Message.qml">qml/Dialog/KeyVerification/Message.qml</file>
|
<file alias="Message.qml">qml/Dialog/KeyVerification/Message.qml</file>
|
||||||
<file alias="EmojiItem.qml">qml/Dialog/KeyVerification/EmojiItem.qml</file>
|
<file alias="EmojiItem.qml">qml/Dialog/KeyVerification/EmojiItem.qml</file>
|
||||||
@@ -75,13 +85,10 @@
|
|||||||
<file alias="VerificationCanceled.qml">qml/Dialog/KeyVerification/VerificationCanceled.qml</file>
|
<file alias="VerificationCanceled.qml">qml/Dialog/KeyVerification/VerificationCanceled.qml</file>
|
||||||
<file alias="GlobalMenu.qml">qml/Menu/GlobalMenu.qml</file>
|
<file alias="GlobalMenu.qml">qml/Menu/GlobalMenu.qml</file>
|
||||||
<file alias="EditMenu.qml">qml/Menu/EditMenu.qml</file>
|
<file alias="EditMenu.qml">qml/Menu/EditMenu.qml</file>
|
||||||
<file alias="AccountMenu.qml">qml/Menu/AccountMenu.qml</file>
|
|
||||||
<file alias="MessageDelegateContextMenu.qml">qml/Menu/Timeline/MessageDelegateContextMenu.qml</file>
|
<file alias="MessageDelegateContextMenu.qml">qml/Menu/Timeline/MessageDelegateContextMenu.qml</file>
|
||||||
<file alias="FileDelegateContextMenu.qml">qml/Menu/Timeline/FileDelegateContextMenu.qml</file>
|
<file alias="FileDelegateContextMenu.qml">qml/Menu/Timeline/FileDelegateContextMenu.qml</file>
|
||||||
<file alias="MessageSourceSheet.qml">qml/Menu/Timeline/MessageSourceSheet.qml</file>
|
<file alias="MessageSourceSheet.qml">qml/Menu/Timeline/MessageSourceSheet.qml</file>
|
||||||
<file alias="ReportSheet.qml">qml/Menu/Timeline/ReportSheet.qml</file>
|
<file alias="ReportSheet.qml">qml/Menu/Timeline/ReportSheet.qml</file>
|
||||||
<file alias="RoomListContextMenu.qml">qml/Menu/RoomListContextMenu.qml</file>
|
|
||||||
<file alias="SpaceListContextMenu.qml">qml/Menu/SpaceListContextMenu.qml</file>
|
|
||||||
<file alias="glowdot.png">qml/Component/glowdot.png</file>
|
<file alias="glowdot.png">qml/Component/glowdot.png</file>
|
||||||
<file alias="confetti.png">qml/Component/confetti.png</file>
|
<file alias="confetti.png">qml/Component/confetti.png</file>
|
||||||
<file alias="SettingsPage.qml">qml/Settings/SettingsPage.qml</file>
|
<file alias="SettingsPage.qml">qml/Settings/SettingsPage.qml</file>
|
||||||
|
|||||||
Reference in New Issue
Block a user