nheko/resources/qml/RoomList.qml

600 lines
20 KiB
QML
Raw Normal View History

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