matrixion/resources/qml/TopBar.qml

434 lines
16 KiB
QML
Raw Permalink Normal View History

// SPDX-FileCopyrightText: Nheko Contributors
//
2021-03-05 02:35:15 +03:00
// SPDX-License-Identifier: GPL-3.0-or-later
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.2
import QtQuick.Window 2.15
import im.nheko 1.0
2021-12-11 08:10:41 +03:00
import "./delegates"
Pane {
id: topBar
property string avatarUrl: room ? room.roomAvatarUrl : ""
2021-09-08 03:38:39 +03:00
property string directChatOtherUserId: room ? room.directChatOtherUserId : ""
2023-06-02 02:45:24 +03:00
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
2022-10-06 22:59:59 +03:00
property string searchString: ""
2023-06-02 02:45:24 +03:00
property bool showBackButton: false
property int trustlevel: room ? room.trustlevel : Crypto.Unverified
2022-10-07 11:04:08 +03:00
Layout.fillWidth: true
2021-05-15 00:35:34 +03:00
implicitHeight: topLayout.height + Nheko.paddingMedium * 2
2023-06-02 02:45:24 +03:00
padding: 0
z: 3
background: Rectangle {
color: palette.window
}
contentItem: Item {
GridLayout {
id: topLayout
anchors.left: parent.left
anchors.margins: Nheko.paddingMedium
2023-06-02 02:45:24 +03:00
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
columnSpacing: Nheko.paddingSmall
rowSpacing: Nheko.paddingSmall
2022-09-20 22:26:28 +03:00
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) || ""
2023-06-02 02:45:24 +03:00
Layout.alignment: Qt.AlignRight
2022-09-20 22:26:28 +03:00
Layout.column: 1
Layout.row: 0
displayName: communityName
enabled: false
2023-10-26 02:51:45 +03:00
implicitHeight: fontMetrics.lineSpacing
implicitWidth: fontMetrics.lineSpacing
2023-06-02 02:45:24 +03:00
roomid: communityId
url: avatarUrl.replace("mxc://", "image://MxcImage/")
visible: roomid && room.parentSpace.isLoaded && ("space:" + room.parentSpace.roomid != Communities.currentTagId)
2022-09-20 22:26:28 +03:00
}
Label {
id: communityLabel
Layout.column: 2
Layout.fillWidth: true
2023-06-02 02:45:24 +03:00
Layout.row: 0
color: palette.text
2022-09-20 22:26:28 +03:00
elide: Text.ElideRight
2023-06-02 02:45:24 +03:00
maximumLineCount: 1
text: qsTr("In %1").arg(communityAvatar.displayName)
2022-09-20 22:26:28 +03:00
textFormat: Text.RichText
2023-06-02 02:45:24 +03:00
visible: communityAvatar.visible
2022-09-20 22:26:28 +03:00
}
ImageButton {
id: backToRoomsButton
Layout.alignment: Qt.AlignVCenter
2023-06-02 02:45:24 +03:00
Layout.column: 0
Layout.preferredHeight: Nheko.avatarSize - Nheko.paddingMedium
Layout.preferredWidth: Nheko.avatarSize - Nheko.paddingMedium
2023-06-02 02:45:24 +03:00
Layout.row: 1
Layout.rowSpan: 2
ToolTip.text: qsTr("Back to room list")
2023-06-02 02:45:24 +03:00
ToolTip.visible: hovered
image: ":/icons/icons/ui/angle-arrow-left.svg"
visible: showBackButton
onClicked: Rooms.resetCurrentRoom()
}
Avatar {
2023-06-02 02:45:24 +03:00
Layout.alignment: Qt.AlignVCenter
Layout.column: 1
2022-09-20 22:26:28 +03:00
Layout.row: 1
Layout.rowSpan: 2
2024-06-06 02:04:54 +03:00
displayName: room ? room.plainRoomName : roomName
2023-06-02 02:45:24 +03:00
enabled: false
2023-10-26 02:51:45 +03:00
implicitHeight: Nheko.avatarSize
implicitWidth: Nheko.avatarSize
roomid: roomId
2023-06-02 02:45:24 +03:00
url: avatarUrl.replace("mxc://", "image://MxcImage/")
userid: isDirect ? directChatOtherUserId : ""
}
Label {
Layout.column: 2
2023-06-02 02:45:24 +03:00
Layout.fillWidth: true
2022-09-20 22:26:28 +03:00
Layout.row: 1
color: palette.text
2023-06-02 02:45:24 +03:00
elide: Text.ElideRight
2022-09-20 22:26:28 +03:00
font.bold: true
2023-06-02 02:45:24 +03:00
font.pointSize: fontMetrics.font.pointSize * 1.1
maximumLineCount: 1
2023-06-02 02:45:24 +03:00
text: roomName
textFormat: Text.RichText
}
MatrixText {
id: roomTopicC
2023-06-02 02:45:24 +03:00
Layout.column: 2
2023-06-02 02:45:24 +03:00
Layout.fillWidth: true
Layout.maximumHeight: fontMetrics.lineSpacing * 2 // show 2 lines
2023-06-02 02:45:24 +03:00
Layout.row: 2
clip: true
2023-06-02 02:45:24 +03:00
enabled: false
2023-10-10 02:10:10 +03:00
// don't use the disabled color
color: topBar.palette.text
2023-06-02 02:45:24 +03:00
selectByMouse: false
text: roomTopic
}
2022-10-06 22:59:59 +03:00
ImageButton {
id: pinButton
property bool pinsShown: !Settings.hiddenPins.includes(roomId)
Layout.alignment: Qt.AlignVCenter
2023-06-02 02:45:24 +03:00
Layout.column: 3
Layout.preferredHeight: Nheko.avatarSize - Nheko.paddingMedium
Layout.preferredWidth: Nheko.avatarSize - Nheko.paddingMedium
2023-06-02 02:45:24 +03:00
Layout.row: 1
Layout.rowSpan: 2
2022-10-06 22:59:59 +03:00
ToolTip.text: qsTr("Show or hide pinned messages")
2023-06-02 02:45:24 +03:00
ToolTip.visible: hovered
image: pinsShown ? ":/icons/icons/ui/pin.svg" : ":/icons/icons/ui/pin-off.svg"
visible: !!room && room.pinnedMessages.length > 0
2022-10-06 22:59:59 +03:00
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 {
id: memberButton
2022-10-06 22:59:59 +03:00
Layout.column: 4
Layout.preferredHeight: Nheko.avatarSize - Nheko.paddingMedium
2022-12-07 15:09:41 +03:00
Layout.preferredWidth: Nheko.avatarSize - Nheko.paddingMedium
2023-06-02 02:45:24 +03:00
Layout.row: 1
Layout.rowSpan: 2
background: null
contentItem: EncryptionIndicator {
ToolTip.delay: Nheko.tooltipDelay
ToolTip.text: {
if (!isEncrypted)
2023-06-02 02:45:24 +03:00
return qsTr("Show room members.");
switch (trustlevel) {
2023-06-02 02:45:24 +03:00
case Crypto.Verified:
return qsTr("This room contains only verified devices.");
2023-06-02 02:45:24 +03:00
case Crypto.TOFU:
return qsTr("This room contains verified devices and devices which have never changed their master key.");
2023-06-02 02:45:24 +03:00
default:
return qsTr("This room contains unverified devices!");
}
}
2023-06-02 02:45:24 +03:00
enabled: false
encrypted: isEncrypted
hovered: parent.hovered
trust: trustlevel
unencryptedColor: palette.buttonText
unencryptedHoverColor: palette.highlight
unencryptedIcon: ":/icons/icons/ui/people.svg"
sourceSize.height: memberButton.height
sourceSize.width: memberButton.width
}
onClicked: TimelineManager.openRoomMembers(room)
}
ImageButton {
2022-10-06 22:59:59 +03:00
id: searchButton
2022-10-06 22:59:59 +03:00
property bool searchActive: false
Layout.alignment: Qt.AlignVCenter
2023-06-02 02:45:24 +03:00
Layout.column: 5
Layout.preferredHeight: Nheko.avatarSize - Nheko.paddingMedium
Layout.preferredWidth: Nheko.avatarSize - Nheko.paddingMedium
2023-06-02 02:45:24 +03:00
Layout.row: 1
Layout.rowSpan: 2
2022-10-06 22:59:59 +03:00
ToolTip.text: qsTr("Search this room")
2023-06-02 02:45:24 +03:00
ToolTip.visible: hovered
image: ":/icons/icons/ui/search.svg"
visible: !!room
2022-10-07 11:04:08 +03:00
2023-06-02 02:45:24 +03:00
onClicked: searchActive = !searchActive
2022-10-07 11:04:08 +03:00
onSearchActiveChanged: {
2022-10-06 22:59:59 +03:00
if (searchActive) {
searchField.forceActiveFocus();
2023-06-02 02:45:24 +03:00
} else {
2022-10-06 22:59:59 +03:00
searchField.clear();
topBar.searchString = "";
2021-12-11 08:10:41 +03:00
}
}
}
ImageButton {
id: roomOptionsButton
Layout.alignment: Qt.AlignVCenter
2023-06-02 02:45:24 +03:00
Layout.column: 6
Layout.preferredHeight: Nheko.avatarSize - Nheko.paddingMedium
Layout.preferredWidth: Nheko.avatarSize - Nheko.paddingMedium
2023-06-02 02:45:24 +03:00
Layout.row: 1
Layout.rowSpan: 2
ToolTip.text: qsTr("Room options")
2023-06-02 02:45:24 +03:00
ToolTip.visible: hovered
image: ":/icons/icons/ui/options.svg"
visible: !!room
2024-10-09 00:35:13 +03:00
onClicked: roomOptionsMenu.popup(roomOptionsButton)
Menu {
id: roomOptionsMenu
Component.onCompleted: {
if (roomOptionsMenu.popupType != undefined) {
roomOptionsMenu.popupType = 2; // Popup.Native with fallback on older Qt (<6.8.0)
}
}
MenuItem {
text: qsTr("Invite users")
enabled: room ? room.permissions.canInvite() : false
2023-06-02 02:45:24 +03:00
onTriggered: TimelineManager.openInviteUsers(roomId)
}
MenuItem {
text: qsTr("Members")
2023-06-02 02:45:24 +03:00
onTriggered: TimelineManager.openRoomMembers(room)
}
MenuItem {
text: qsTr("Leave room")
2023-06-02 02:45:24 +03:00
onTriggered: TimelineManager.openLeaveRoomDialog(roomId)
}
MenuItem {
text: qsTr("Settings")
2023-06-02 02:45:24 +03:00
onTriggered: TimelineManager.openRoomSettings(roomId)
}
}
}
ScrollView {
id: pinnedMessages
Layout.column: 2
2022-10-06 22:59:59 +03:00
Layout.columnSpan: 4
Layout.fillWidth: true
Layout.preferredHeight: Math.min(contentHeight, Nheko.avatarSize * 4)
2023-06-02 02:45:24 +03:00
Layout.row: 3
ScrollBar.horizontal.visible: false
2023-06-02 02:45:24 +03:00
clip: true
visible: !!room && room.pinnedMessages.length > 0 && !Settings.hiddenPins.includes(roomId)
2024-02-02 18:29:08 +03:00
contentWidth: availableWidth
ListView {
model: room ? room.pinnedMessages : undefined
2023-06-02 02:45:24 +03:00
spacing: Nheko.paddingSmall
delegate: RowLayout {
required property string modelData
height: implicitHeight
2023-06-02 02:45:24 +03:00
width: ListView.view.width
Reply {
id: reply
2023-06-02 02:45:24 +03:00
property var e: room ? room.getDump(modelData, "pins") : {}
2023-06-02 02:45:24 +03:00
2024-02-02 18:29:08 +03:00
maxWidth: pinnedMessages.width - 16
eventId: e.eventId ?? ""
2023-06-02 02:45:24 +03:00
userColor: TimelineManager.userColor(e.userId, palette.window)
2023-06-02 02:45:24 +03:00
Connections {
function onPinnedMessagesChanged() {
reply.e = room.getDump(modelData, "pins");
}
target: room
}
}
ImageButton {
id: deletePinButton
2023-06-02 02:45:24 +03:00
Layout.alignment: Qt.AlignTop | Qt.AlignLeft
Layout.preferredHeight: 16
Layout.preferredWidth: 16
2023-06-02 02:45:24 +03:00
ToolTip.text: qsTr("Unpin")
ToolTip.visible: hovered
hoverEnabled: true
image: ":/icons/icons/ui/dismiss.svg"
2023-06-02 02:45:24 +03:00
visible: room.permissions.canChange(MtxEvent.PinnedEvents)
onClicked: room.unpin(modelData)
}
2021-12-11 08:10:41 +03:00
}
2022-02-04 20:47:17 +03:00
}
}
ScrollView {
id: widgets
Layout.column: 2
2022-10-06 22:59:59 +03:00
Layout.columnSpan: 4
2022-02-04 20:47:17 +03:00
Layout.fillWidth: true
Layout.preferredHeight: Math.min(contentHeight, Nheko.avatarSize * 1.5)
2023-06-02 02:45:24 +03:00
Layout.row: 4
2022-02-04 20:47:17 +03:00
ScrollBar.horizontal.visible: false
2023-06-02 02:45:24 +03:00
clip: true
visible: !!room && room.widgetLinks.length > 0 && !Settings.hiddenWidgets.includes(roomId)
2024-02-02 18:29:08 +03:00
contentWidth: availableWidth
2022-02-04 20:47:17 +03:00
ListView {
model: room ? room.widgetLinks : undefined
2023-06-02 02:45:24 +03:00
spacing: Nheko.paddingSmall
2022-02-04 20:47:17 +03:00
delegate: MatrixText {
2024-02-02 18:29:08 +03:00
width: widgets.width
2022-02-04 20:47:17 +03:00
required property var modelData
color: palette.text
2022-02-04 20:47:17 +03:00
text: modelData
}
2021-12-11 08:10:41 +03:00
}
}
2022-10-06 22:59:59 +03:00
MatrixTextField {
id: searchField
Layout.column: 2
Layout.columnSpan: 4
Layout.fillWidth: true
2023-06-02 02:45:24 +03:00
Layout.row: 5
enabled: visible
hasClear: true
2022-10-06 22:59:59 +03:00
placeholderText: qsTr("Enter search query")
2023-06-02 02:45:24 +03:00
visible: searchButton.searchActive
2022-10-06 22:59:59 +03:00
onAccepted: topBar.searchString = text
}
2021-12-11 08:10:41 +03:00
}
2023-06-19 02:38:40 +03:00
NhekoCursorShape {
2022-02-04 20:47:17 +03:00
anchors.bottomMargin: (pinnedMessages.visible ? pinnedMessages.height : 0) + (widgets.visible ? widgets.height : 0)
2023-06-02 02:45:24 +03:00
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
}
2021-12-11 21:21:01 +03:00
}
2023-06-02 02:45:24 +03:00
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
}
}