Skip to content
Snippets Groups Projects
RoomList.qml 26.5 KiB
Newer Older
  • Learn to ignore specific revisions
  • // SPDX-FileCopyrightText: 2021 Nheko Contributors
    
    // SPDX-FileCopyrightText: 2022 Nheko Contributors
    
    //
    // SPDX-License-Identifier: GPL-3.0-or-later
    
    
    import "./components"
    
    import "./dialogs"
    
    import Qt.labs.platform 1.1 as Platform
    
    import QtQml 2.12
    
    import QtQuick 2.15
    import QtQuick.Controls 2.15
    
    import QtQuick.Layouts 1.3
    import im.nheko 1.0
    
    Page {
    
        //leftPadding: Nheko.paddingSmall
        //rightPadding: Nheko.paddingSmall
    
        property int avatarSize: Math.ceil(fontMetrics.lineSpacing * 2.3)
        property bool collapsed: false
    
    Malte E's avatar
    Malte E committed
        Component {
            id: createRoomComponent
    
            CreateRoom {
            }
        }
    
    
        Component {
            id: createDirectComponent
    
            CreateDirect {
            }
        }
    
    
    Nicolas Werner's avatar
    Nicolas Werner committed
        ListView {
    
    Nicolas Werner's avatar
    Nicolas Werner committed
            id: roomlist
    
    
    Nicolas Werner's avatar
    Nicolas Werner committed
            anchors.left: parent.left
            anchors.right: parent.right
            height: parent.height
            model: Rooms
    
    Loren Burkholder's avatar
    Loren Burkholder committed
            reuseItems: true
    
    Nicolas Werner's avatar
    Nicolas Werner committed
    
            ScrollHelper {
                flickable: parent
                anchors.fill: parent
            }
    
    
    Nicolas Werner's avatar
    Nicolas Werner committed
            Connections {
    
                function onCurrentRoomChanged() {
    
                    if (Rooms.currentRoom)
                        roomlist.positionViewAtIndex(Rooms.roomidToIndex(Rooms.currentRoom.roomId), ListView.Contain);
    
    
                target: Rooms
    
            Component {
                id: roomWindowComponent
    
                ApplicationWindow {
                    id: roomWindowW
    
                    property var room: null
                    property var roomPreview: null
    
    
    Nicolas Werner's avatar
    Nicolas Werner committed
                    Component.onCompleted: MainWindow.addPerRoomWindow(room.roomId || roomPreview.roomid, roomWindowW)
                    Component.onDestruction: MainWindow.removePerRoomWindow(room.roomId || roomPreview.roomid, roomWindowW)
    
    
                    height: 650
                    width: 420
                    minimumWidth: 150
                    minimumHeight: 150
                    palette: Nheko.colors
                    color: Nheko.colors.window
    
                    modality: Qt.NonModal
                    flags: Qt.Window | Qt.WindowCloseButtonHint | Qt.WindowTitleHint
    
                    Shortcut {
                        sequence: StandardKey.Cancel
                        onActivated: roomWindowW.close()
                    }
    
                    TimelineView {
    
                        id: timelineView
    
                        anchors.fill: parent
                        room: roomWindowW.room
                        roomPreview: roomWindowW.roomPreview.roomid ? roomWindowW.roomPreview : null
                    }
    
    
                    PrivacyScreen {
                        anchors.fill: parent
                        visible: Settings.privacyScreen
                        screenTimeout: Settings.privacyScreenTimeout
                        timelineRoot: timelineView
                        windowTarget: roomWindowW
                    }
    
            Platform.Menu {
                id: roomContextMenu
    
                property string roomid
                property var tags
    
                function show(roomid_, tags_) {
                    roomid = roomid_;
                    tags = tags_;
                    open();
                }
    
                InputDialog {
                    id: newTag
    
                    title: qsTr("New tag")
                    prompt: qsTr("Enter the tag you want to use:")
                    onAccepted: function(text) {
                        Rooms.toggleTag(roomContextMenu.roomid, "u." + text, true);
                    }
                }
    
    
                Platform.MenuItem {
                    text: qsTr("Open separately")
                    onTriggered: {
                        var roomWindow = roomWindowComponent.createObject(null, {
                        "room": Rooms.getRoomById(roomContextMenu.roomid),
                        "roomPreview": Rooms.getRoomPreviewById(roomContextMenu.roomid)
                        });
                        roomWindow.showNormal();
                        destroyOnClose(roomWindow);
                    }
                }
    
    
                Platform.MenuItem {
                    text: qsTr("Leave room")
    
                    onTriggered: TimelineManager.openLeaveRoomDialog(roomContextMenu.roomid)
    
                Platform.MenuItem {
                    text: qsTr("Copy room link")
                    onTriggered: Rooms.copyLink(roomContextMenu.roomid)
                }
    
    
                Platform.MenuSeparator {
                    text: qsTr("Tag room as:")
    
                    model: Communities.tagsWithDefault
    
                    onObjectAdded: roomContextMenu.insertItem(index + 4, object)
    
                    onObjectRemoved: roomContextMenu.removeItem(object)
    
                    delegate: Platform.MenuItem {
                        property string t: modelData
    
    
                        text: {
                            switch (t) {
                            case "m.favourite":
                                return qsTr("Favourite");
                            case "m.lowpriority":
                                return qsTr("Low priority");
                            case "m.server_notice":
                                return qsTr("Server notice");
                            default:
                                return t.substring(2);
                            }
                        }
                        checkable: true
    
                        checked: roomContextMenu.tags !== undefined && roomContextMenu.tags.includes(t)
    
                        onTriggered: Rooms.toggleTag(roomContextMenu.roomid, t, checked)
                    }
    
                }
    
    
                Platform.MenuItem {
                    text: qsTr("Create new tag...")
                    onTriggered: newTag.show()
    
    Nicolas Werner's avatar
    Nicolas Werner committed
                id: roomItem
    
    
                property color backgroundColor: Nheko.colors.window
    
    Nicolas Werner's avatar
    Nicolas Werner committed
                property color importantText: Nheko.colors.text
                property color unimportantText: Nheko.colors.buttonText
                property color bubbleBackground: Nheko.colors.highlight
                property color bubbleText: Nheko.colors.highlightedText
    
                required property string roomName
                required property string roomId
                required property string avatarUrl
                required property string time
                required property string lastMessage
                required property var tags
                required property bool isInvite
                required property bool isSpace
                required property int notificationCount
                required property bool hasLoudNotification
                required property bool hasUnreadMessages
    
                required property bool isDirect
    
                required property string directChatOtherUserId
    
                Ripple {
                    color: Qt.rgba(Nheko.colors.dark.r, Nheko.colors.dark.g, Nheko.colors.dark.b, 0.5)
                }
    
    
                height: avatarSize + 2 * Nheko.paddingMedium
    
    Nicolas Werner's avatar
    Nicolas Werner committed
                width: ListView.view.width
    
    Nicolas Werner's avatar
    Nicolas Werner committed
                state: "normal"
    
    Loren Burkholder's avatar
    Loren Burkholder committed
                ToolTip.visible: hovered && collapsed
    
                ToolTip.delay: Nheko.tooltipDelay
    
                onClicked: {
                    console.log("tapped " + roomId);
    
    
                    if (isSpace && Communities.currentTagId != "space:"+roomId)
                        Communities.currentTagId = "space:"+roomId;
    
    
                    if (!Rooms.currentRoom || Rooms.currentRoom.roomId !== roomId)
                        Rooms.setCurrentRoom(roomId);
                    else
                        Rooms.resetCurrentRoom();
                }
                onPressAndHold: {
                    if (!isInvite)
                        roomContextMenu.show(roomId, tags);
    
                }
    
    Nicolas Werner's avatar
    Nicolas Werner committed
                states: [
                    State {
                        name: "highlight"
    
                        when: roomItem.hovered && !((Rooms.currentRoom && roomId == Rooms.currentRoom.roomId) || Rooms.currentRoomPreview.roomid == roomId)
    
    Nicolas Werner's avatar
    Nicolas Werner committed
    
                        PropertyChanges {
                            target: roomItem
    
                            backgroundColor: Nheko.colors.dark
    
    Nicolas Werner's avatar
    Nicolas Werner committed
                            importantText: Nheko.colors.brightText
                            unimportantText: Nheko.colors.brightText
                            bubbleBackground: Nheko.colors.highlight
                            bubbleText: Nheko.colors.highlightedText
                        }
    
    Nicolas Werner's avatar
    Nicolas Werner committed
                    },
                    State {
                        name: "selected"
    
                        when: (Rooms.currentRoom && roomId == Rooms.currentRoom.roomId) || Rooms.currentRoomPreview.roomid == roomId
    
    Nicolas Werner's avatar
    Nicolas Werner committed
    
                        PropertyChanges {
                            target: roomItem
    
                            backgroundColor: Nheko.colors.highlight
    
    Nicolas Werner's avatar
    Nicolas Werner committed
                            importantText: Nheko.colors.highlightedText
                            unimportantText: Nheko.colors.highlightedText
                            bubbleBackground: Nheko.colors.highlightedText
                            bubbleText: Nheko.colors.highlight
                        }
    
                    }
                ]
    
                // NOTE(Nico): We want to prevent the touch areas from overlapping. For some reason we need to add 1px of padding for that...
                Item {
                    anchors.fill: parent
                    anchors.margins: 1
    
                    TapHandler {
                        acceptedButtons: Qt.RightButton
                        onSingleTapped: {
                            if (!TimelineManager.isInvite)
                                roomContextMenu.show(roomId, tags);
    
                        }
                        gesturePolicy: TapHandler.ReleaseWithinBounds
    
                        acceptedDevices: PointerDevice.Mouse | PointerDevice.Stylus | PointerDevice.TouchPad
    
    Nicolas Werner's avatar
    Nicolas Werner committed
                }
    
                RowLayout {
    
    Nicolas Werner's avatar
    Nicolas Werner committed
                    spacing: Nheko.paddingMedium
                    anchors.fill: parent
                    anchors.margins: Nheko.paddingMedium
    
                    Avatar {
                        id: avatar
    
    
                        enabled: false
    
    Nicolas Werner's avatar
    Nicolas Werner committed
                        Layout.alignment: Qt.AlignVCenter
    
                        height: avatarSize
                        width: avatarSize
    
                        url: avatarUrl.replace("mxc://", "image://MxcImage/")
                        displayName: roomName
    
                        userid: isDirect ? directChatOtherUserId : ""
    
                        roomid: roomId
    
                        NotificationBubble {
    
                            id: collapsedNotificationBubble
    
    
                            notificationCount: roomItem.notificationCount
                            hasLoudNotification: roomItem.hasLoudNotification
                            bubbleBackgroundColor: roomItem.bubbleBackground
                            bubbleTextColor: roomItem.bubbleText
    
                            anchors.right: parent.right
                            anchors.bottom: parent.bottom
                            anchors.margins: -Nheko.paddingSmall
    
                            mayBeVisible: collapsed
    
    Nicolas Werner's avatar
    Nicolas Werner committed
                    }
    
                    ColumnLayout {
                        id: textContent
    
    
                        visible: !collapsed
    
    Nicolas Werner's avatar
    Nicolas Werner committed
                        Layout.alignment: Qt.AlignLeft
                        Layout.fillWidth: true
                        Layout.minimumWidth: 100
                        width: parent.width - avatar.width
                        Layout.preferredWidth: parent.width - avatar.width
    
                        height: avatar.height
                        spacing: Nheko.paddingSmall
    
                        NotificationBubble {
    
                            id: notificationBubble
    
    
                            parent: isSpace ? titleRow : subtextRow
                            notificationCount: roomItem.notificationCount
                            hasLoudNotification: roomItem.hasLoudNotification
                            bubbleBackgroundColor: roomItem.bubbleBackground
                            bubbleTextColor: roomItem.bubbleText
                            Layout.alignment: Qt.AlignRight
                            Layout.leftMargin: Nheko.paddingSmall
                            Layout.preferredWidth: implicitWidth
                            Layout.preferredHeight: implicitHeight
                            mayBeVisible: !collapsed
    
    Nicolas Werner's avatar
    Nicolas Werner committed
                        RowLayout {
    
                            Layout.alignment: Qt.AlignTop
    
    Nicolas Werner's avatar
    Nicolas Werner committed
                            Layout.fillWidth: true
    
                            spacing: Nheko.paddingSmall
    
    Nicolas Werner's avatar
    Nicolas Werner committed
    
                            ElidedLabel {
    
                                id: rN
                                Layout.alignment: Qt.AlignBaseline
    
    Nicolas Werner's avatar
    Nicolas Werner committed
                                color: roomItem.importantText
    
                                elideWidth: width
    
                                textFormat: Text.RichText
    
    Nicolas Werner's avatar
    Nicolas Werner committed
                                Layout.fillWidth: true
                            }
    
                            Label {
                                id: timestamp
    
                                visible: !isInvite && !isSpace
    
                                width: visible ? 0 : undefined
    
                                Layout.alignment: Qt.AlignRight | Qt.AlignBaseline
    
    Nicolas Werner's avatar
    Nicolas Werner committed
                                font.pixelSize: fontMetrics.font.pixelSize * 0.9
    
    Nicolas Werner's avatar
    Nicolas Werner committed
                                color: roomItem.unimportantText
    
    Nicolas Werner's avatar
    Nicolas Werner committed
                            Layout.fillWidth: true
                            spacing: 0
    
    Nicolas Werner's avatar
    Nicolas Werner committed
                            height: visible ? 0 : undefined
    
                            Layout.alignment: Qt.AlignBottom
    
    Nicolas Werner's avatar
    Nicolas Werner committed
    
                            ElidedLabel {
    
    Nicolas Werner's avatar
    Nicolas Werner committed
                                color: roomItem.unimportantText
    
    Nicolas Werner's avatar
    Nicolas Werner committed
                                font.pixelSize: fontMetrics.font.pixelSize * 0.9
    
                                elideWidth: width
    
                                textFormat: Text.RichText
    
    Nicolas Werner's avatar
    Nicolas Werner committed
                                Layout.fillWidth: true
                            }
    
                        }
    
                    }
    
                }
    
                Rectangle {
                    anchors.left: parent.left
                    anchors.verticalCenter: parent.verticalCenter
                    height: parent.height - Nheko.paddingSmall * 2
                    width: 3
                    color: Nheko.colors.highlight
    
                background: Rectangle {
                    color: backgroundColor
                }
    
    
    
        background: Rectangle {
            color: Nheko.theme.sidebarBackground
        }
    
        header: ColumnLayout {
            spacing: 0
    
    
                id: userInfoPanel
    
                function openUserProfile() {
                    Nheko.updateUserProfile();
                    var userProfile = userProfileComponent.createObject(timelineRoot, {
                        "profile": Nheko.currentUser
                    });
                    userProfile.show();
    
    Nicolas Werner's avatar
    Nicolas Werner committed
                    timelineRoot.destroyOnClose(userProfile);
    
                Layout.fillWidth: true
                Layout.alignment: Qt.AlignBottom
    
                //Layout.preferredHeight: userInfoGrid.implicitHeight + 2 * Nheko.paddingMedium
                padding: Nheko.paddingMedium
    
                Layout.minimumHeight: 40
    
    
                background: Rectangle {color: Nheko.colors.window}
    
    
                InputDialog {
    
                    id: statusDialog
    
                    title: qsTr("Status Message")
    
                    prompt: qsTr("Enter your status message:")
                    onAccepted: function(text) {
                        Nheko.setStatusMessage(text);
    
                    }
                }
    
                Platform.Menu {
                    id: userInfoMenu
    
                    Platform.MenuItem {
                        text: qsTr("Profile settings")
                        onTriggered: userInfoPanel.openUserProfile()
                    }
    
                    Platform.MenuItem {
                        text: qsTr("Set status message")
                        onTriggered: statusDialog.show()
                    }
    
                }
    
                TapHandler {
    
                    margin: -Nheko.paddingSmall
    
                    acceptedButtons: Qt.LeftButton
                    onSingleTapped: userInfoPanel.openUserProfile()
                    onLongPressed: userInfoMenu.open()
                    gesturePolicy: TapHandler.ReleaseWithinBounds
                }
    
                TapHandler {
    
                    margin: -Nheko.paddingSmall
    
                    acceptedButtons: Qt.RightButton
                    onSingleTapped: userInfoMenu.open()
                    gesturePolicy: TapHandler.ReleaseWithinBounds
    
                    id: userInfoGrid
    
    
                    property var profile: Nheko.currentUser
    
    
                    spacing: Nheko.paddingMedium
    
                    Avatar {
                        id: avatar
    
                        Layout.alignment: Qt.AlignVCenter
    
    Nicolas Werner's avatar
    Nicolas Werner committed
                        Layout.preferredWidth: fontMetrics.lineSpacing * 2
                        Layout.preferredHeight: fontMetrics.lineSpacing * 2
    
                        url: (userInfoGrid.profile ? userInfoGrid.profile.avatarUrl : "").replace("mxc://", "image://MxcImage/")
                        displayName: userInfoGrid.profile ? userInfoGrid.profile.displayName : ""
                        userid: userInfoGrid.profile ? userInfoGrid.profile.userid : ""
    
                        enabled: false
    
                        visible: !collapsed
    
                        Layout.alignment: Qt.AlignLeft
                        Layout.fillWidth: true
    
    Nicolas Werner's avatar
    Nicolas Werner committed
                        width: parent.width - avatar.width - logoutButton.width - Nheko.paddingMedium * 2
                        Layout.preferredWidth: parent.width - avatar.width - logoutButton.width - Nheko.paddingMedium * 2
    
    Nicolas Werner's avatar
    Nicolas Werner committed
                        ElidedLabel {
    
                            Layout.alignment: Qt.AlignBottom
                            font.pointSize: fontMetrics.font.pointSize * 1.1
                            font.weight: Font.DemiBold
    
                            fullText: userInfoGrid.profile ? userInfoGrid.profile.displayName : ""
    
    Nicolas Werner's avatar
    Nicolas Werner committed
                            elideWidth: col.width
    
    Nicolas Werner's avatar
    Nicolas Werner committed
                        ElidedLabel {
    
                            Layout.alignment: Qt.AlignTop
                            color: Nheko.colors.buttonText
                            font.pointSize: fontMetrics.font.pointSize * 0.9
    
    Nicolas Werner's avatar
    Nicolas Werner committed
                            elideWidth: col.width
    
                            fullText: userInfoGrid.profile ? userInfoGrid.profile.userid : ""
    
                        visible: !collapsed
    
                        Layout.alignment: Qt.AlignVCenter
    
                        Layout.preferredWidth: fontMetrics.lineSpacing * 2
                        Layout.preferredHeight: fontMetrics.lineSpacing * 2
    
                        image: ":/icons/icons/ui/power-off.svg"
    
                        ToolTip.visible: hovered
    
                        ToolTip.delay: Nheko.tooltipDelay
    
                        ToolTip.text: qsTr("Logout")
    
                        onClicked: Nheko.openLogoutDialog()
    
                    }
    
                }
    
            }
    
            Rectangle {
                color: Nheko.theme.separator
                height: 2
                Layout.fillWidth: true
            }
    
    
            Rectangle {
                id: unverifiedStuffBubble
    
    
                color: Qt.lighter(Nheko.theme.orange, verifyButtonHovered.hovered ? 1.2 : 1)
    
                Layout.fillWidth: true
                implicitHeight: explanation.height + Nheko.paddingMedium * 2
                visible: SelfVerificationStatus.status != SelfVerificationStatus.AllVerified
    
                RowLayout {
                    id: unverifiedStuffBubbleContainer
    
                    width: parent.width
                    height: explanation.height + Nheko.paddingMedium * 2
                    spacing: 0
    
                    Label {
                        id: explanation
    
                        Layout.margins: Nheko.paddingMedium
                        Layout.rightMargin: Nheko.paddingSmall
                        color: Nheko.colors.buttonText
                        Layout.fillWidth: true
    
                        text: {
                            switch (SelfVerificationStatus.status) {
    
                            case SelfVerificationStatus.NoMasterKey:
    
                                //: Cross-signing setup has not run yet.
                                return qsTr("Encryption not set up");
    
                            case SelfVerificationStatus.UnverifiedMasterKey:
    
                                //: The user just signed in with this device and hasn't verified their master key.
                                return qsTr("Unverified login");
    
                            case SelfVerificationStatus.UnverifiedDevices:
    
                                //: There are unverified devices signed in to this account.
                                return qsTr("Please verify your other devices");
    
                        }
                        textFormat: Text.PlainText
                        wrapMode: Text.Wrap
                    }
    
                    ImageButton {
                        id: closeUnverifiedBubble
    
                        Layout.rightMargin: Nheko.paddingMedium
    
                        Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
    
                        hoverEnabled: true
                        width: fontMetrics.font.pixelSize
                        height: fontMetrics.font.pixelSize
    
                        image: ":/icons/icons/ui/dismiss.svg"
    
                        ToolTip.visible: closeUnverifiedBubble.hovered
    
                        ToolTip.delay: Nheko.tooltipDelay
    
                        ToolTip.text: qsTr("Close")
                        onClicked: unverifiedStuffBubble.visible = false
                    }
    
                }
    
                HoverHandler {
                    id: verifyButtonHovered
    
    
                    enabled: !closeUnverifiedBubble.hovered
    
                    acceptedDevices: PointerDevice.Mouse | PointerDevice.Stylus | PointerDevice.TouchPad
                }
    
                TapHandler {
                    enabled: !closeUnverifiedBubble.hovered
                    acceptedButtons: Qt.LeftButton
                    onSingleTapped: {
    
                        if (SelfVerificationStatus.status == SelfVerificationStatus.UnverifiedDevices)
    
                            SelfVerificationStatus.verifyUnverifiedDevices();
    
                            SelfVerificationStatus.statusChanged();
                    }
                }
    
            }
    
            Rectangle {
                color: Nheko.theme.separator
                height: 1
                Layout.fillWidth: true
                visible: unverifiedStuffBubble.visible
            }
    
    
        }
    
        footer: ColumnLayout {
            spacing: 0
    
            Rectangle {
                color: Nheko.theme.separator
                height: 1
                Layout.fillWidth: true
            }
    
    
                Layout.fillWidth: true
                Layout.alignment: Qt.AlignBottom
                Layout.minimumHeight: 40
    
    
                horizontalPadding: Nheko.paddingMedium
                verticalPadding: 0
    
                background: Rectangle {color: Nheko.colors.window}
                contentItem: RowLayout {
                    id: buttonRow
    
    Loren Burkholder's avatar
    Loren Burkholder committed
                        Layout.fillWidth: true
    
                        hoverEnabled: true
                        width: 22
                        height: 22
    
                        image: ":/icons/icons/ui/add-square-button.svg"
    
                        ToolTip.visible: hovered
    
                        ToolTip.delay: Nheko.tooltipDelay
    
                        ToolTip.text: qsTr("Start a new chat")
                        Layout.margins: Nheko.paddingMedium
    
                        onClicked: roomJoinCreateMenu.open(parent)
    
                        Platform.Menu {
                            id: roomJoinCreateMenu
    
                            Platform.MenuItem {
                                text: qsTr("Join a room")
                                onTriggered: Nheko.openJoinRoomDialog()
                            }
    
                            Platform.MenuItem {
                                text: qsTr("Create a new room")
    
    Malte E's avatar
    Malte E committed
                                onTriggered: {
                                    var createRoom = createRoomComponent.createObject(timelineRoot);
                                    createRoom.show();
                                    timelineRoot.destroyOnClose(createRoom);
                                }
    
                            Platform.MenuItem {
                                text: qsTr("Start a direct chat")
                                onTriggered: {
                                    var createDirect = createDirectComponent.createObject(timelineRoot);
                                    createDirect.show();
                                    timelineRoot.destroyOnClose(createDirect);
                                }
                            }
    
    
                        visible: !collapsed
    
    Loren Burkholder's avatar
    Loren Burkholder committed
                        Layout.fillWidth: true
    
                        hoverEnabled: true
                        width: 22
                        height: 22
    
                        image: ":/icons/icons/ui/speech-bubbles.svg"
    
                        ToolTip.visible: hovered
    
                        ToolTip.delay: Nheko.tooltipDelay
    
                        ToolTip.text: qsTr("Room directory")
                        Layout.margins: Nheko.paddingMedium
    
                            var win = roomDirectoryComponent.createObject(timelineRoot);
                            win.show();
    
    Nicolas Werner's avatar
    Nicolas Werner committed
                            timelineRoot.destroyOnClose(win);
    
    Malte E's avatar
    Malte E committed
                    ImageButton {
                        visible: !collapsed
                        Layout.fillWidth: true
                        hoverEnabled: true
                        ripple: false
                        width: 22
                        height: 22
                        image: ":/icons/icons/ui/search.svg"
                        ToolTip.visible: hovered
                        ToolTip.delay: Nheko.tooltipDelay
                        ToolTip.text: qsTr("Search rooms (Ctrl+K)")
                        Layout.margins: Nheko.paddingMedium
                        onClicked: {
                            var quickSwitch = quickSwitcherComponent.createObject(timelineRoot);
                            quickSwitch.open();
    
    Nicolas Werner's avatar
    Nicolas Werner committed
                            timelineRoot.destroyOnClose(quickSwitch);
    
                    ImageButton {
    
                        visible: !collapsed
    
    Loren Burkholder's avatar
    Loren Burkholder committed
                        Layout.fillWidth: true
    
                        hoverEnabled: true
    
                        ripple: false
    
                        width: 22
                        height: 22
    
                        image: ":/icons/icons/ui/settings.svg"
    
                        ToolTip.visible: hovered
    
                        ToolTip.delay: Nheko.tooltipDelay
    
                        ToolTip.text: qsTr("User settings")
                        Layout.margins: Nheko.paddingMedium
    
                        onClicked: mainWindow.push(userSettingsPage);