Skip to content
Snippets Groups Projects
TopBar.qml 15.7 KiB
Newer Older
// SPDX-FileCopyrightText: Nheko Contributors
Nicolas Werner's avatar
Nicolas Werner committed
// SPDX-License-Identifier: GPL-3.0-or-later

Nicolas Werner's avatar
Nicolas Werner committed
import Qt.labs.platform 1.1 as Platform
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.2
import QtQuick.Window 2.15
import im.nheko 1.0
Nicolas Werner's avatar
Nicolas Werner committed
import "./delegates"

    property string avatarUrl: room ? room.roomAvatarUrl : ""
    property string directChatOtherUserId: room ? room.directChatOtherUserId : ""
Nicolas Werner's avatar
Nicolas Werner committed
    property bool isDirect: room ? room.isDirect : false
    property bool isEncrypted: room ? room.isEncrypted : false
    property string roomId: room ? room.roomId : ""
    property string roomName: room ? room.roomName : qsTr("No room selected")
    property string roomTopic: room ? room.roomTopic : ""
    property bool searchHasFocus: searchField.focus && searchField.enabled
    property string searchString: ""
Nicolas Werner's avatar
Nicolas Werner committed
    property bool showBackButton: false
    property int trustlevel: room ? room.trustlevel : Crypto.Unverified
    Layout.fillWidth: true
    implicitHeight: topLayout.height + Nheko.paddingMedium * 2
Nicolas Werner's avatar
Nicolas Werner committed
    padding: 0
        color: palette.window
    }
    contentItem: Item {
        GridLayout {
            id: topLayout

            anchors.left: parent.left
            anchors.margins: Nheko.paddingMedium
Nicolas Werner's avatar
Nicolas Werner committed
            anchors.right: parent.right
            anchors.verticalCenter: parent.verticalCenter
            columnSpacing: Nheko.paddingSmall
            rowSpacing: Nheko.paddingSmall

            Avatar {
                id: communityAvatar

                property string avatarUrl: (Settings.groupView && room && room.parentSpace && room.parentSpace.roomAvatarUrl) || ""
                property string communityId: (Settings.groupView && room && room.parentSpace && room.parentSpace.roomid) || ""
                property string communityName: (Settings.groupView && room && room.parentSpace && room.parentSpace.roomName) || ""

Nicolas Werner's avatar
Nicolas Werner committed
                Layout.alignment: Qt.AlignRight
                Layout.column: 1
                Layout.row: 0
                displayName: communityName
                enabled: false
Nicolas Werner's avatar
Nicolas Werner committed
                height: fontMetrics.lineSpacing
                roomid: communityId
                url: avatarUrl.replace("mxc://", "image://MxcImage/")
                visible: roomid && room.parentSpace.isLoaded && ("space:" + room.parentSpace.roomid != Communities.currentTagId)
                width: fontMetrics.lineSpacing
            }
            Label {
                id: communityLabel

                Layout.column: 2
                Layout.fillWidth: true
Nicolas Werner's avatar
Nicolas Werner committed
                Layout.row: 0
                color: palette.text
                elide: Text.ElideRight
Nicolas Werner's avatar
Nicolas Werner committed
                maximumLineCount: 1
                text: qsTr("In %1").arg(communityAvatar.displayName)
                textFormat: Text.RichText
Nicolas Werner's avatar
Nicolas Werner committed
                visible: communityAvatar.visible
            ImageButton {
                id: backToRoomsButton

                Layout.alignment: Qt.AlignVCenter
Nicolas Werner's avatar
Nicolas Werner committed
                Layout.column: 0
                Layout.preferredHeight: Nheko.avatarSize - Nheko.paddingMedium
                Layout.preferredWidth: Nheko.avatarSize - Nheko.paddingMedium
Nicolas Werner's avatar
Nicolas Werner committed
                Layout.row: 1
                Layout.rowSpan: 2
                ToolTip.text: qsTr("Back to room list")
Nicolas Werner's avatar
Nicolas Werner committed
                ToolTip.visible: hovered
                image: ":/icons/icons/ui/angle-arrow-left.svg"
                visible: showBackButton

                onClicked: Rooms.resetCurrentRoom()
            }
            Avatar {
Nicolas Werner's avatar
Nicolas Werner committed
                Layout.alignment: Qt.AlignVCenter
                Layout.row: 1
Nicolas Werner's avatar
Nicolas Werner committed
                displayName: roomName
                enabled: false
Nicolas Werner's avatar
Nicolas Werner committed
                url: avatarUrl.replace("mxc://", "image://MxcImage/")
                userid: isDirect ? directChatOtherUserId : ""
Nicolas Werner's avatar
Nicolas Werner committed
                width: Nheko.avatarSize
Nicolas Werner's avatar
Nicolas Werner committed
                Layout.fillWidth: true
                Layout.row: 1
                color: palette.text
Nicolas Werner's avatar
Nicolas Werner committed
                elide: Text.ElideRight
                font.bold: true
Nicolas Werner's avatar
Nicolas Werner committed
                font.pointSize: fontMetrics.font.pointSize * 1.1
Nicolas Werner's avatar
Nicolas Werner committed
                text: roomName
                textFormat: Text.RichText
            }
            MatrixText {
                id: roomTopicC
Nicolas Werner's avatar
Nicolas Werner committed

Nicolas Werner's avatar
Nicolas Werner committed
                Layout.fillWidth: true
                Layout.maximumHeight: fontMetrics.lineSpacing * 2 // show 2 lines
Nicolas Werner's avatar
Nicolas Werner committed
                Layout.row: 2
Nicolas Werner's avatar
Nicolas Werner committed
                enabled: false
                // don't use the disabled color
                color: topBar.palette.text
Nicolas Werner's avatar
Nicolas Werner committed
                selectByMouse: false
            ImageButton {
                id: pinButton

                property bool pinsShown: !Settings.hiddenPins.includes(roomId)

                Layout.alignment: Qt.AlignVCenter
Nicolas Werner's avatar
Nicolas Werner committed
                Layout.column: 3
                Layout.preferredHeight: Nheko.avatarSize - Nheko.paddingMedium
                Layout.preferredWidth: Nheko.avatarSize - Nheko.paddingMedium
Nicolas Werner's avatar
Nicolas Werner committed
                Layout.row: 1
                Layout.rowSpan: 2
                ToolTip.text: qsTr("Show or hide pinned messages")
Nicolas Werner's avatar
Nicolas Werner committed
                ToolTip.visible: hovered
                image: pinsShown ? ":/icons/icons/ui/pin.svg" : ":/icons/icons/ui/pin-off.svg"
                visible: !!room && room.pinnedMessages.length > 0

                onClicked: {
                    var ps = Settings.hiddenPins;
                    if (pinsShown) {
                        ps.push(roomId);
                    } else {
                        const index = ps.indexOf(roomId);
                        if (index > -1) {
                            ps.splice(index, 1);
                        }
                    }
                    Settings.hiddenPins = ps;
                }
            }
            AbstractButton {
                Layout.column: 4
                Layout.preferredHeight: Nheko.avatarSize - Nheko.paddingMedium
Nicolas Werner's avatar
Nicolas Werner committed
                Layout.preferredWidth: Nheko.avatarSize - Nheko.paddingMedium
Nicolas Werner's avatar
Nicolas Werner committed
                Layout.row: 1
                Layout.rowSpan: 2
                background: null
                    ToolTip.delay: Nheko.tooltipDelay
                    ToolTip.text: {
                        if (!isEncrypted)
Nicolas Werner's avatar
Nicolas Werner committed
                            return qsTr("Show room members.");
                        switch (trustlevel) {
Nicolas Werner's avatar
Nicolas Werner committed
                        case Crypto.Verified:
                            return qsTr("This room contains only verified devices.");
Nicolas Werner's avatar
Nicolas Werner committed
                        case Crypto.TOFU:
                            return qsTr("This room contains verified devices and devices which have never changed their master key.");
Nicolas Werner's avatar
Nicolas Werner committed
                        default:
                            return qsTr("This room contains unverified devices!");
                        }
Nicolas Werner's avatar
Nicolas Werner committed
                    enabled: false
                    encrypted: isEncrypted
                    hovered: parent.hovered
                    trust: trustlevel
                    unencryptedColor: palette.buttonText
                    unencryptedHoverColor: palette.highlight
                    unencryptedIcon: ":/icons/icons/ui/people.svg"

                onClicked: TimelineManager.openRoomMembers(room)
                id: searchButton
                property bool searchActive: false
Nicolas Werner's avatar
Nicolas Werner committed
                Layout.column: 5
                Layout.preferredHeight: Nheko.avatarSize - Nheko.paddingMedium
                Layout.preferredWidth: Nheko.avatarSize - Nheko.paddingMedium
Nicolas Werner's avatar
Nicolas Werner committed
                Layout.row: 1
                Layout.rowSpan: 2
                ToolTip.text: qsTr("Search this room")
Nicolas Werner's avatar
Nicolas Werner committed
                ToolTip.visible: hovered
                image: ":/icons/icons/ui/search.svg"
                visible: !!room
Nicolas Werner's avatar
Nicolas Werner committed
                onClicked: searchActive = !searchActive
                onSearchActiveChanged: {
                    if (searchActive) {
                        searchField.forceActiveFocus();
Nicolas Werner's avatar
Nicolas Werner committed
                    } else {
                        searchField.clear();
                        topBar.searchString = "";
            ImageButton {
                id: roomOptionsButton

                Layout.alignment: Qt.AlignVCenter
Nicolas Werner's avatar
Nicolas Werner committed
                Layout.column: 6
                Layout.preferredHeight: Nheko.avatarSize - Nheko.paddingMedium
                Layout.preferredWidth: Nheko.avatarSize - Nheko.paddingMedium
Nicolas Werner's avatar
Nicolas Werner committed
                Layout.row: 1
                Layout.rowSpan: 2
Nicolas Werner's avatar
Nicolas Werner committed
                ToolTip.visible: hovered
                image: ":/icons/icons/ui/options.svg"
                visible: !!room

                onClicked: roomOptionsMenu.open(roomOptionsButton)

                Platform.Menu {
                    id: roomOptionsMenu

                    Platform.MenuItem {
                        text: qsTr("Invite users")
Nicolas Werner's avatar
Nicolas Werner committed
                        visible: room ? room.permissions.canInvite() : false

                        onTriggered: TimelineManager.openInviteUsers(roomId)
                    }
                    Platform.MenuItem {
                        text: qsTr("Members")
Nicolas Werner's avatar
Nicolas Werner committed

                        onTriggered: TimelineManager.openRoomMembers(room)
                    }
                    Platform.MenuItem {
                        text: qsTr("Leave room")
Nicolas Werner's avatar
Nicolas Werner committed

                        onTriggered: TimelineManager.openLeaveRoomDialog(roomId)
                    }
                    Platform.MenuItem {
                        text: qsTr("Settings")
Nicolas Werner's avatar
Nicolas Werner committed

                        onTriggered: TimelineManager.openRoomSettings(roomId)
                    }
                Layout.columnSpan: 4
                Layout.fillWidth: true
                Layout.preferredHeight: Math.min(contentHeight, Nheko.avatarSize * 4)
Nicolas Werner's avatar
Nicolas Werner committed
                Layout.row: 3
Nicolas Werner's avatar
Nicolas Werner committed
                clip: true
                visible: !!room && room.pinnedMessages.length > 0 && !Settings.hiddenPins.includes(roomId)

                ListView {
                    model: room ? room.pinnedMessages : undefined
Nicolas Werner's avatar
Nicolas Werner committed
                    spacing: Nheko.paddingSmall

                    delegate: RowLayout {
                        required property string modelData

                        height: implicitHeight
Nicolas Werner's avatar
Nicolas Werner committed
                        width: ListView.view.width
Nicolas Werner's avatar
Nicolas Werner committed

                            property var e: room ? room.getDump(modelData, "pins") : {}
Nicolas Werner's avatar
Nicolas Werner committed

                            maxWidth: pinnedMessages.width
Nicolas Werner's avatar
Nicolas Werner committed
                            userColor: TimelineManager.userColor(e.userId, palette.window)
Nicolas Werner's avatar
Nicolas Werner committed
                            Connections {
                                function onPinnedMessagesChanged() {
                                    reply.e = room.getDump(modelData, "pins");
                                }

                                target: room
                            }
                        }
Nicolas Werner's avatar
Nicolas Werner committed
                            Layout.alignment: Qt.AlignTop | Qt.AlignLeft
                            Layout.preferredHeight: 16
                            Layout.preferredWidth: 16
Nicolas Werner's avatar
Nicolas Werner committed
                            ToolTip.text: qsTr("Unpin")
                            ToolTip.visible: hovered
                            hoverEnabled: true
                            image: ":/icons/icons/ui/dismiss.svg"
Nicolas Werner's avatar
Nicolas Werner committed
                            visible: room.permissions.canChange(MtxEvent.PinnedEvents)
Nicolas Werner's avatar
Nicolas Werner committed
                }
            }
            ScrollView {
                id: widgets

                Layout.column: 2
                Layout.columnSpan: 4
Nicolas Werner's avatar
Nicolas Werner committed
                Layout.fillWidth: true
                Layout.preferredHeight: Math.min(contentHeight, Nheko.avatarSize * 1.5)
Nicolas Werner's avatar
Nicolas Werner committed
                Layout.row: 4
Nicolas Werner's avatar
Nicolas Werner committed
                ScrollBar.horizontal.visible: false
Nicolas Werner's avatar
Nicolas Werner committed
                clip: true
                visible: !!room && room.widgetLinks.length > 0 && !Settings.hiddenWidgets.includes(roomId)
Nicolas Werner's avatar
Nicolas Werner committed

                ListView {
                    model: room ? room.widgetLinks : undefined
Nicolas Werner's avatar
Nicolas Werner committed
                    spacing: Nheko.paddingSmall

Nicolas Werner's avatar
Nicolas Werner committed
                    delegate: MatrixText {
                        required property var modelData

                        color: palette.text
Nicolas Werner's avatar
Nicolas Werner committed
                        text: modelData
                    }
            MatrixTextField {
                id: searchField

                Layout.column: 2
                Layout.columnSpan: 4
                Layout.fillWidth: true
Nicolas Werner's avatar
Nicolas Werner committed
                Layout.row: 5
                enabled: visible
                hasClear: true
                placeholderText: qsTr("Enter search query")
Nicolas Werner's avatar
Nicolas Werner committed
                visible: searchButton.searchActive

                onAccepted: topBar.searchString = text
            }
        NhekoCursorShape {
Nicolas Werner's avatar
Nicolas Werner committed
            anchors.bottomMargin: (pinnedMessages.visible ? pinnedMessages.height : 0) + (widgets.visible ? widgets.height : 0)
Nicolas Werner's avatar
Nicolas Werner committed
            anchors.fill: parent
Nicolas Werner's avatar
Nicolas Werner committed

    onRoomIdChanged: {
        searchString = "";
        searchButton.searchActive = false;
        searchField.text = "";
    }

    // HACK: https://bugreports.qt.io/browse/QTBUG-83972, qtwayland cannot auto hide menu
    Connections {
        function onHideMenu() {
            roomOptionsMenu.close();
        }

        target: MainWindow
    }
    Shortcut {
        sequence: StandardKey.Find

        onActivated: searchButton.searchActive = !searchButton.searchActive
    }
    TapHandler {
        gesturePolicy: TapHandler.ReleaseWithinBounds

        onSingleTapped: {
            if (eventPoint.position.y > topBar.height - (pinnedMessages.visible ? pinnedMessages.height : 0) - (widgets.visible ? widgets.height : 0)) {
                eventPoint.accepted = true;
                return;
            }
            if (showBackButton && eventPoint.position.x < Nheko.paddingMedium + backToRoomsButton.width) {
                eventPoint.accepted = true;
                return;
            }
            if (eventPoint.position.x > topBar.width - Nheko.paddingMedium - roomOptionsButton.width) {
                eventPoint.accepted = true;
                return;
            }
            if (communityLabel.visible && eventPoint.position.y < communityAvatar.height + Nheko.paddingMedium + Nheko.paddingSmall / 2) {
                if (!Communities.trySwitchToSpace(room.parentSpace.roomid))
                    room.parentSpace.promptJoin();
                eventPoint.accepted = true;
                return;
            }
            if (room) {
                let p = topBar.mapToItem(roomTopicC, eventPoint.position.x, eventPoint.position.y);
                let link = roomTopicC.linkAt(p.x, p.y);
                if (link) {
                    Nheko.openLink(link);
                } else {
                    TimelineManager.openRoomSettings(room.roomId);
                }
            }
            eventPoint.accepted = true;
        }
    }
    HoverHandler {
        grabPermissions: PointerHandler.TakeOverForbidden | PointerHandler.CanTakeOverFromAnything
    }