matrixion/resources/qml/RoomList.qml

675 lines
24 KiB
QML
Raw Normal View History

2021-05-15 00:35:34 +03:00
// SPDX-FileCopyrightText: 2021 Nheko Contributors
//
// SPDX-License-Identifier: GPL-3.0-or-later
2021-05-28 18:25:46 +03:00
import "./dialogs"
2021-05-22 16:19:44 +03:00
import Qt.labs.platform 1.1 as Platform
2021-06-13 02:48:11 +03:00
import QtQml 2.12
import QtQuick 2.15
import QtQuick.Controls 2.15
2021-05-15 00:35:34 +03:00
import QtQuick.Layouts 1.3
import im.nheko 1.0
Page {
2021-06-06 00:36:08 +03:00
//leftPadding: Nheko.paddingSmall
//rightPadding: Nheko.paddingSmall
2021-06-08 23:18:51 +03:00
property int avatarSize: Math.ceil(fontMetrics.lineSpacing * 2.3)
property bool collapsed: false
2021-06-06 00:36:08 +03:00
Component {
id: roomDirectoryComponent
RoomDirectory {
}
}
2021-05-19 20:34:10 +03:00
ListView {
2021-05-21 22:19:03 +03:00
id: roomlist
2021-05-19 20:34:10 +03:00
anchors.left: parent.left
anchors.right: parent.right
height: parent.height
model: Rooms
reuseItems: true
2021-05-19 20:34:10 +03:00
ScrollHelper {
flickable: parent
anchors.fill: parent
enabled: !Settings.mobileMode
}
2021-05-21 22:19:03 +03:00
Connections {
function onCurrentRoomChanged() {
2021-08-11 05:16:27 +03:00
if (Rooms.currentRoom)
roomlist.positionViewAtIndex(Rooms.roomidToIndex(Rooms.currentRoom.roomId), ListView.Contain);
2021-05-21 22:19:03 +03:00
}
target: Rooms
2021-05-21 22:19:03 +03:00
}
2021-05-28 18:25:46 +03:00
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("Leave room")
onTriggered: TimelineManager.openLeaveRoomDialog(roomContextMenu.roomid)
2021-05-28 18:25:46 +03:00
}
Platform.MenuSeparator {
text: qsTr("Tag room as:")
2021-05-28 18:25:46 +03:00
}
Instantiator {
2021-06-15 00:40:06 +03:00
model: Communities.tagsWithDefault
onObjectAdded: roomContextMenu.insertItem(index + 2, object)
onObjectRemoved: roomContextMenu.removeItem(object)
2021-05-28 18:25:46 +03:00
delegate: Platform.MenuItem {
property string t: modelData
2021-05-28 18:25:46 +03:00
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
2021-06-10 00:52:28 +03:00
checked: roomContextMenu.tags !== undefined && roomContextMenu.tags.includes(t)
2021-05-28 18:25:46 +03:00
onTriggered: Rooms.toggleTag(roomContextMenu.roomid, t, checked)
}
}
Platform.MenuItem {
text: qsTr("Create new tag...")
onTriggered: newTag.show()
2021-05-28 18:25:46 +03:00
}
}
delegate: ItemDelegate {
2021-05-21 22:19:03 +03:00
id: roomItem
property color backgroundColor: Nheko.colors.window
2021-05-21 22:19:03 +03:00
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
2021-08-31 03:08:47 +03:00
required property bool isDirect
2021-09-05 03:53:33 +03:00
required property string directChatOtherUserId
2021-05-21 22:19:03 +03:00
2021-06-08 23:18:51 +03:00
height: avatarSize + 2 * Nheko.paddingMedium
2021-05-19 20:34:10 +03:00
width: ListView.view.width
2021-05-21 22:19:03 +03:00
state: "normal"
ToolTip.visible: hovered && collapsed
ToolTip.text: roomName
onClicked: {
console.log("tapped " + roomId);
if (!Rooms.currentRoom || Rooms.currentRoom.roomId !== roomId)
Rooms.setCurrentRoom(roomId);
else
Rooms.resetCurrentRoom();
}
onPressAndHold: {
if (!isInvite)
roomContextMenu.show(roomId, tags);
}
2021-05-21 22:19:03 +03:00
states: [
State {
name: "highlight"
when: roomItem.hovered && !((Rooms.currentRoom && roomId == Rooms.currentRoom.roomId) || Rooms.currentRoomPreview.roomid == roomId)
2021-05-21 22:19:03 +03:00
PropertyChanges {
target: roomItem
backgroundColor: Nheko.colors.dark
2021-05-21 22:19:03 +03:00
importantText: Nheko.colors.brightText
unimportantText: Nheko.colors.brightText
bubbleBackground: Nheko.colors.highlight
bubbleText: Nheko.colors.highlightedText
}
2021-05-19 20:34:10 +03:00
2021-05-21 22:19:03 +03:00
},
State {
name: "selected"
2021-07-17 23:16:02 +03:00
when: (Rooms.currentRoom && roomId == Rooms.currentRoom.roomId) || Rooms.currentRoomPreview.roomid == roomId
2021-05-21 22:19:03 +03:00
PropertyChanges {
target: roomItem
backgroundColor: Nheko.colors.highlight
2021-05-21 22:19:03 +03:00
importantText: Nheko.colors.highlightedText
unimportantText: Nheko.colors.highlightedText
bubbleBackground: Nheko.colors.highlightedText
bubbleText: Nheko.colors.highlight
}
}
]
2021-05-19 20:34:10 +03:00
// 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
2021-07-31 16:59:19 +03:00
acceptedDevices: PointerDevice.Mouse | PointerDevice.Stylus | PointerDevice.TouchPad
}
2021-05-28 18:25:46 +03:00
2021-05-21 22:19:03 +03:00
}
RowLayout {
2021-05-19 20:34:10 +03:00
spacing: Nheko.paddingMedium
anchors.fill: parent
anchors.margins: Nheko.paddingMedium
Avatar {
2021-05-21 22:19:03 +03:00
// In the future we could show an online indicator by setting the userid for the avatar
2021-05-19 20:34:10 +03:00
//userid: Nheko.currentUser.userid
id: avatar
2021-05-28 18:25:46 +03:00
enabled: false
2021-05-19 20:34:10 +03:00
Layout.alignment: Qt.AlignVCenter
2021-06-08 23:18:51 +03:00
height: avatarSize
width: avatarSize
url: avatarUrl.replace("mxc://", "image://MxcImage/")
displayName: roomName
2021-09-05 03:53:33 +03:00
userid: isDirect ? directChatOtherUserId : ""
2021-08-31 03:08:47 +03:00
roomid: roomId
2021-06-08 23:18:51 +03:00
Rectangle {
id: collapsedNotificationBubble
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.margins: -Nheko.paddingSmall
visible: collapsed && notificationCount > 0
2021-06-08 23:18:51 +03:00
enabled: false
Layout.alignment: Qt.AlignRight
height: fontMetrics.averageCharacterWidth * 3
width: height
radius: height / 2
color: hasLoudNotification ? Nheko.theme.red : roomItem.bubbleBackground
2021-06-08 23:18:51 +03:00
Label {
anchors.centerIn: parent
width: parent.width * 0.8
height: parent.height * 0.8
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
fontSizeMode: Text.Fit
font.bold: true
font.pixelSize: fontMetrics.font.pixelSize * 0.8
color: hasLoudNotification ? "white" : roomItem.bubbleText
text: notificationCount > 99 ? "99+" : notificationCount
2021-06-08 23:18:51 +03:00
}
}
2021-05-19 20:34:10 +03:00
}
ColumnLayout {
id: textContent
2021-06-08 23:18:51 +03:00
visible: !collapsed
2021-05-19 20:34:10 +03:00
Layout.alignment: Qt.AlignLeft
Layout.fillWidth: true
Layout.minimumWidth: 100
width: parent.width - avatar.width
Layout.preferredWidth: parent.width - avatar.width
2021-05-21 22:19:03 +03:00
spacing: Nheko.paddingSmall
2021-05-19 20:34:10 +03:00
RowLayout {
Layout.fillWidth: true
spacing: 0
ElidedLabel {
Layout.alignment: Qt.AlignBottom
2021-05-21 22:19:03 +03:00
color: roomItem.importantText
2021-05-19 20:34:10 +03:00
elideWidth: textContent.width - timestamp.width - Nheko.paddingMedium
fullText: roomName
2021-05-22 11:16:42 +03:00
textFormat: Text.RichText
2021-05-19 20:34:10 +03:00
}
Item {
Layout.fillWidth: true
}
Label {
id: timestamp
2021-06-18 17:22:06 +03:00
visible: !isInvite && !isSpace
2021-06-18 15:10:45 +03:00
width: visible ? 0 : undefined
2021-05-19 20:34:10 +03:00
Layout.alignment: Qt.AlignRight | Qt.AlignBottom
font.pixelSize: fontMetrics.font.pixelSize * 0.9
2021-05-21 22:19:03 +03:00
color: roomItem.unimportantText
text: time
2021-05-19 20:34:10 +03:00
}
}
RowLayout {
Layout.fillWidth: true
spacing: 0
visible: !isSpace
2021-05-24 15:04:07 +03:00
height: visible ? 0 : undefined
2021-05-19 20:34:10 +03:00
ElidedLabel {
2021-05-21 22:19:03 +03:00
color: roomItem.unimportantText
2021-05-19 20:34:10 +03:00
font.pixelSize: fontMetrics.font.pixelSize * 0.9
2021-05-21 22:19:03 +03:00
elideWidth: textContent.width - (notificationBubble.visible ? notificationBubble.width : 0) - Nheko.paddingSmall
fullText: lastMessage
2021-05-22 11:16:42 +03:00
textFormat: Text.RichText
2021-05-19 20:34:10 +03:00
}
Item {
Layout.fillWidth: true
}
Rectangle {
id: notificationBubble
visible: notificationCount > 0
2021-05-19 20:34:10 +03:00
Layout.alignment: Qt.AlignRight
2021-05-21 22:19:03 +03:00
height: fontMetrics.averageCharacterWidth * 3
2021-05-19 20:34:10 +03:00
width: height
radius: height / 2
color: hasLoudNotification ? Nheko.theme.red : roomItem.bubbleBackground
2021-05-19 20:34:10 +03:00
Label {
2021-05-21 22:19:03 +03:00
anchors.centerIn: parent
width: parent.width * 0.8
height: parent.height * 0.8
2021-05-19 20:34:10 +03:00
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
fontSizeMode: Text.Fit
2021-05-21 22:19:03 +03:00
font.bold: true
font.pixelSize: fontMetrics.font.pixelSize * 0.8
color: hasLoudNotification ? "white" : roomItem.bubbleText
text: notificationCount > 99 ? "99+" : notificationCount
2021-05-19 20:34:10 +03:00
}
}
}
}
}
Rectangle {
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
height: parent.height - Nheko.paddingSmall * 2
width: 3
color: Nheko.colors.highlight
visible: hasUnreadMessages
2021-05-19 20:34:10 +03:00
}
background: Rectangle {
color: backgroundColor
}
2021-05-19 20:34:10 +03:00
}
}
2021-05-15 00:35:34 +03:00
background: Rectangle {
color: Nheko.theme.sidebarBackground
}
header: ColumnLayout {
spacing: 0
Rectangle {
2021-05-22 16:19:44 +03:00
id: userInfoPanel
function openUserProfile() {
Nheko.updateUserProfile();
var userProfile = userProfileComponent.createObject(timelineRoot, {
"profile": Nheko.currentUser
});
userProfile.show();
}
2021-05-15 00:35:34 +03:00
color: Nheko.colors.window
Layout.fillWidth: true
Layout.alignment: Qt.AlignBottom
Layout.preferredHeight: userInfoGrid.implicitHeight + 2 * Nheko.paddingMedium
Layout.minimumHeight: 40
2021-05-28 18:25:46 +03:00
InputDialog {
2021-05-22 16:19:44 +03:00
id: statusDialog
title: qsTr("Status Message")
2021-05-28 18:25:46 +03:00
prompt: qsTr("Enter your status message:")
onAccepted: function(text) {
Nheko.setStatusMessage(text);
2021-05-22 16:19:44 +03:00
}
}
Platform.Menu {
id: userInfoMenu
Platform.MenuItem {
text: qsTr("Profile settings")
onTriggered: userInfoPanel.openUserProfile()
}
Platform.MenuItem {
text: qsTr("Set status message")
onTriggered: statusDialog.show()
}
}
TapHandler {
2021-06-08 23:18:51 +03:00
margin: -Nheko.paddingSmall
2021-05-22 16:19:44 +03:00
acceptedButtons: Qt.LeftButton
onSingleTapped: userInfoPanel.openUserProfile()
onLongPressed: userInfoMenu.open()
gesturePolicy: TapHandler.ReleaseWithinBounds
}
TapHandler {
2021-06-08 23:18:51 +03:00
margin: -Nheko.paddingSmall
2021-05-22 16:19:44 +03:00
acceptedButtons: Qt.RightButton
onSingleTapped: userInfoMenu.open()
gesturePolicy: TapHandler.ReleaseWithinBounds
}
2021-05-15 00:35:34 +03:00
RowLayout {
id: userInfoGrid
property var profile: Nheko.currentUser
2021-05-15 00:35:34 +03:00
spacing: Nheko.paddingMedium
anchors.fill: parent
anchors.margins: Nheko.paddingMedium
Avatar {
id: avatar
Layout.alignment: Qt.AlignVCenter
2021-05-19 20:34:10 +03:00
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 : ""
2021-08-03 14:20:36 +03:00
enabled: false
2021-05-15 00:35:34 +03:00
}
ColumnLayout {
id: col
2021-06-08 23:18:51 +03:00
visible: !collapsed
2021-05-15 00:35:34 +03:00
Layout.alignment: Qt.AlignLeft
Layout.fillWidth: true
2021-05-19 20:34:10 +03:00
width: parent.width - avatar.width - logoutButton.width - Nheko.paddingMedium * 2
Layout.preferredWidth: parent.width - avatar.width - logoutButton.width - Nheko.paddingMedium * 2
2021-05-15 00:35:34 +03:00
spacing: 0
2021-05-19 20:34:10 +03:00
ElidedLabel {
2021-05-15 00:35:34 +03:00
Layout.alignment: Qt.AlignBottom
font.pointSize: fontMetrics.font.pointSize * 1.1
font.weight: Font.DemiBold
fullText: userInfoGrid.profile ? userInfoGrid.profile.displayName : ""
2021-05-19 20:34:10 +03:00
elideWidth: col.width
2021-05-15 00:35:34 +03:00
}
2021-05-19 20:34:10 +03:00
ElidedLabel {
2021-05-15 00:35:34 +03:00
Layout.alignment: Qt.AlignTop
color: Nheko.colors.buttonText
font.pointSize: fontMetrics.font.pointSize * 0.9
2021-05-19 20:34:10 +03:00
elideWidth: col.width
fullText: userInfoGrid.profile ? userInfoGrid.profile.userid : ""
2021-05-15 00:35:34 +03:00
}
}
Item {
}
ImageButton {
id: logoutButton
2021-06-08 23:18:51 +03:00
visible: !collapsed
2021-05-15 00:35:34 +03:00
Layout.alignment: Qt.AlignVCenter
Layout.preferredWidth: fontMetrics.lineSpacing * 2
Layout.preferredHeight: fontMetrics.lineSpacing * 2
2021-11-14 04:23:10 +03:00
image: ":/icons/icons/ui/power-off.svg"
2021-05-15 00:35:34 +03:00
ToolTip.visible: hovered
ToolTip.text: qsTr("Logout")
2021-05-30 13:41:44 +03:00
onClicked: Nheko.openLogoutDialog()
2021-05-15 00:35:34 +03:00
}
}
}
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");
default:
return "";
}
}
textFormat: Text.PlainText
wrapMode: Text.Wrap
}
ImageButton {
id: closeUnverifiedBubble
Layout.rightMargin: Nheko.paddingMedium
Layout.topMargin: Nheko.paddingMedium
2021-11-14 04:23:10 +03:00
Layout.alignment: Qt.AlignRight | Qt.AlignCenter
hoverEnabled: true
width: fontMetrics.font.pixelSize
height: fontMetrics.font.pixelSize
2021-11-14 04:23:10 +03:00
image: ":/icons/icons/ui/dismiss.svg"
ToolTip.visible: closeUnverifiedBubble.hovered
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();
else
SelfVerificationStatus.statusChanged();
}
}
}
Rectangle {
color: Nheko.theme.separator
height: 1
Layout.fillWidth: true
visible: unverifiedStuffBubble.visible
}
2021-05-15 00:35:34 +03:00
}
footer: ColumnLayout {
spacing: 0
Rectangle {
color: Nheko.theme.separator
height: 1
Layout.fillWidth: true
}
Rectangle {
color: Nheko.colors.window
Layout.fillWidth: true
Layout.alignment: Qt.AlignBottom
Layout.preferredHeight: buttonRow.implicitHeight
Layout.minimumHeight: 40
RowLayout {
id: buttonRow
anchors.left: parent.left
anchors.right: parent.right
anchors.margins: Nheko.paddingMedium
ImageButton {
2021-06-13 04:18:31 +03:00
Layout.fillWidth: true
2021-05-15 00:35:34 +03:00
hoverEnabled: true
width: 22
height: 22
2021-11-14 04:23:10 +03:00
image: ":/icons/icons/ui/add-square-button.svg"
2021-05-15 00:35:34 +03:00
ToolTip.visible: hovered
ToolTip.text: qsTr("Start a new chat")
Layout.margins: Nheko.paddingMedium
2021-05-30 13:41:44 +03:00
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")
onTriggered: Nheko.openCreateRoomDialog()
}
}
2021-05-15 00:35:34 +03:00
}
ImageButton {
2021-06-08 23:18:51 +03:00
visible: !collapsed
2021-06-13 04:18:31 +03:00
Layout.fillWidth: true
2021-05-15 00:35:34 +03:00
hoverEnabled: true
width: 22
height: 22
2021-11-14 04:23:10 +03:00
image: ":/icons/icons/ui/speech-bubbles.svg"
2021-05-15 00:35:34 +03:00
ToolTip.visible: hovered
ToolTip.text: qsTr("Room directory")
Layout.margins: Nheko.paddingMedium
onClicked: {
var win = roomDirectoryComponent.createObject(timelineRoot);
win.show();
}
2021-05-15 00:35:34 +03:00
}
ImageButton {
2021-06-08 23:18:51 +03:00
visible: !collapsed
2021-06-13 04:18:31 +03:00
Layout.fillWidth: true
2021-05-15 00:35:34 +03:00
hoverEnabled: true
width: 22
height: 22
2021-11-14 04:23:10 +03:00
image: ":/icons/icons/ui/settings.svg"
2021-05-15 00:35:34 +03:00
ToolTip.visible: hovered
ToolTip.text: qsTr("User settings")
Layout.margins: Nheko.paddingMedium
2021-05-30 13:41:44 +03:00
onClicked: Nheko.showUserSettingsPage()
2021-05-15 00:35:34 +03:00
}
}
}
}
}