Files
neochat/imports/Spectral/Panel/RoomListPanel.qml
2019-07-12 15:37:36 +08:00

559 lines
16 KiB
QML

import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
import QtQuick.Controls.Material 2.12
import Spectral.Component 2.0
import Spectral.Dialog 2.0
import Spectral.Menu 2.0
import Spectral.Effect 2.0
import Spectral 0.1
import Spectral.Setting 0.1
import SortFilterProxyModel 0.2
Item {
property var connection: null
readonly property var user: connection ? connection.localUser : null
property int filter: 0
property var enteredRoom: null
signal enterRoom(var room)
signal leaveRoom(var room)
id: root
RoomListModel {
id: roomListModel
connection: root.connection
onNewMessage: if (!window.active && MSettings.showNotification) notificationsManager.postNotification(roomId, eventId, roomName, senderName, text, icon)
}
Binding {
target: trayIcon
property: "notificationCount"
value: roomListModel.notificationCount
}
SortFilterProxyModel {
id: sortedRoomListModel
sourceModel: roomListModel
proxyRoles: ExpressionRole {
name: "display"
expression: {
switch (category) {
case 1: return "Invited"
case 2: return "Favorites"
case 3: return "People"
case 4: return "Rooms"
case 5: return "Low Priority"
}
}
}
sorters: [
RoleSorter { roleName: "category" },
ExpressionSorter {
expression: {
return modelLeft.highlightCount > 0;
}
},
ExpressionSorter {
expression: {
return modelLeft.notificationCount > 0;
}
},
RoleSorter {
roleName: "lastActiveTime"
sortOrder: Qt.DescendingOrder
}
]
filters: [
ExpressionFilter {
expression: joinState != "upgraded"
},
RegExpFilter {
roleName: "name"
pattern: searchField.text
caseSensitivity: Qt.CaseInsensitive
},
ExpressionFilter {
enabled: filter === 0
expression: category !== 5 && notificationCount > 0 || currentRoom === enteredRoom
},
ExpressionFilter {
enabled: filter === 1
expression: category === 1 || category === 3
},
ExpressionFilter {
enabled: filter === 2
expression: category !== 3
}
]
}
Shortcut {
sequence: "Ctrl+F"
onActivated: searchField.forceActiveFocus()
}
ColumnLayout {
anchors.fill: parent
spacing: 0
Control {
Layout.fillWidth: true
Layout.preferredHeight: 64
id: roomListHeader
topPadding: 12
bottomPadding: 12
leftPadding: 12
rightPadding: 18
contentItem: RowLayout {
ToolButton {
Layout.preferredWidth: height
Layout.fillHeight: true
visible: !searchField.active
contentItem: MaterialIcon {
icon: "\ue8b6"
}
}
ToolButton {
Layout.preferredWidth: height
Layout.fillHeight: true
visible: searchField.active
contentItem: MaterialIcon { icon: "\ue5cd" }
onClicked: searchField.clear()
}
AutoTextField {
readonly property bool active: text
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter
id: searchField
placeholderText: "Search..."
color: MPalette.lighter
}
Avatar {
Layout.preferredWidth: height
Layout.fillHeight: true
Layout.alignment: Qt.AlignRight
visible: !searchField.active
source: root.user ? root.user.avatarMediaId : null
hint: root.user ? root.user.displayName : "?"
RippleEffect {
anchors.fill: parent
circular: true
onClicked: accountDetailDialog.createObject(ApplicationWindow.overlay).open()
}
}
}
background: Rectangle {
color: Material.background
layer.enabled: true
layer.effect: ElevationEffect {
elevation: 2
}
}
}
AutoListView {
Layout.fillWidth: true
Layout.fillHeight: true
id: listView
z: -1
spacing: 0
model: sortedRoomListModel
boundsBehavior: Flickable.DragOverBounds
ScrollBar.vertical: ScrollBar {}
delegate: Item {
width: listView.width
height: 64
Rectangle {
anchors.fill: parent
visible: currentRoom === enteredRoom
color: Material.accent
opacity: 0.1
}
RowLayout {
anchors.fill: parent
anchors.margins: 12
spacing: 12
Avatar {
Layout.preferredWidth: height
Layout.fillHeight: true
source: avatar
hint: name || "No Name"
}
ColumnLayout {
Layout.fillWidth: true
Layout.fillHeight: true
Layout.alignment: Qt.AlignHCenter
Label {
Layout.fillWidth: true
Layout.fillHeight: true
text: name || "No Name"
color: MPalette.foreground
font.pixelSize: 16
font.bold: unreadCount >= 0
elide: Text.ElideRight
wrapMode: Text.NoWrap
}
Label {
Layout.fillWidth: true
Layout.fillHeight: true
text: (lastEvent == "" ? topic : lastEvent).replace(/(\r\n\t|\n|\r\t)/gm," ")
color: MPalette.lighter
font.pixelSize: 13
elide: Text.ElideRight
wrapMode: Text.NoWrap
}
}
Label {
visible: notificationCount > 0 && highlightCount == 0
color: MPalette.background
text: notificationCount
leftPadding: 12
rightPadding: 12
topPadding: 4
bottomPadding: 4
font.bold: true
background: Rectangle {
radius: height / 2
color: MPalette.lighter
}
}
Label {
visible: highlightCount > 0
color: "white"
text: highlightCount
leftPadding: 12
rightPadding: 12
topPadding: 4
bottomPadding: 4
font.bold: true
background: Rectangle {
radius: height / 2
color: MPalette.accent
}
}
}
RippleEffect {
anchors.fill: parent
onPrimaryClicked: {
if (category === RoomType.Invited) {
acceptInvitationDialog.createObject(ApplicationWindow.overlay, {"room": currentRoom}).open()
} else {
if (enteredRoom) {
leaveRoom(enteredRoom)
enteredRoom.displayed = false
}
enterRoom(currentRoom)
enteredRoom = currentRoom
currentRoom.displayed = true
}
}
onSecondaryClicked: roomListContextMenu.createObject(ApplicationWindow.overlay, {"room": currentRoom}).popup()
}
Component {
id: roomListContextMenu
RoomListContextMenu {}
}
}
section.property: "display"
section.criteria: ViewSection.FullString
section.delegate: Label {
width: parent.width
height: 24
text: section
color: MPalette.lighter
leftPadding: 16
elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter
}
ColumnLayout {
anchors.centerIn: parent
visible: sortedRoomListModel.count == 0
MaterialIcon {
Layout.alignment: Qt.AlignHCenter
icon: "\ue5ca"
font.pixelSize: 48
color: MPalette.lighter
}
Label {
Layout.alignment: Qt.AlignHCenter
text: "You're all caught up!"
color: MPalette.foreground
}
}
}
Control {
Layout.fillWidth: true
Layout.preferredHeight: 48
Layout.margins: 16
padding: 8
contentItem: RowLayout {
id: tabBar
spacing: 8
Control {
readonly property bool highlighted: filter === 0
Layout.fillWidth: highlighted
Layout.fillHeight: true
id: newTabControl
horizontalPadding: 8
background: Rectangle {
visible: newTabControl.highlighted
color: Material.accent
border.color: Material.accent
border.width: 2
radius: height / 2
}
contentItem: RowLayout {
spacing: 0
MaterialIcon {
Layout.preferredWidth: 32
Layout.preferredHeight: 32
icon: "\ue7f5"
color: newTabControl.highlighted ? "white" : MPalette.lighter
Rectangle {
anchors.right: parent.right
anchors.top: parent.top
visible: roomListModel.notificationCount > 0
width: 12
height: 12
radius: 6
color: "white"
Rectangle {
anchors.centerIn: parent
width: 8
height: 8
radius: 4
color: "red"
}
}
}
Label {
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter
visible: newTabControl.highlighted
text: "New"
color: "white"
horizontalAlignment: Text.AlignHCenter
}
}
RippleEffect {
anchors.fill: parent
circular: true
onClicked: filter = 0
}
}
Control {
readonly property bool highlighted: filter === 1
Layout.fillWidth: highlighted
Layout.fillHeight: true
id: peopleTabControl
horizontalPadding: 8
background: Rectangle {
visible: peopleTabControl.highlighted
color: Material.accent
border.color: Material.accent
border.width: 2
radius: height / 2
}
contentItem: RowLayout {
spacing: 0
MaterialIcon {
Layout.preferredWidth: 32
Layout.preferredHeight: 32
icon: "\ue7ff"
color: peopleTabControl.highlighted ? "white" : MPalette.lighter
}
Label {
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter
visible: peopleTabControl.highlighted
text: "People"
color: "white"
horizontalAlignment: Text.AlignHCenter
}
}
RippleEffect {
anchors.fill: parent
circular: true
onClicked: filter = 1
}
}
Control {
readonly property bool highlighted: filter === 2
Layout.fillWidth: highlighted
Layout.fillHeight: true
id: groupTabControl
horizontalPadding: 8
background: Rectangle {
visible: groupTabControl.highlighted
color: Material.accent
border.color: Material.accent
border.width: 2
radius: height / 2
}
contentItem: RowLayout {
spacing: 0
MaterialIcon {
Layout.preferredWidth: 32
Layout.preferredHeight: 32
icon: "\ue7fc"
color: groupTabControl.highlighted ? "white" : MPalette.lighter
}
Label {
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter
visible: groupTabControl.highlighted
text: "Group"
color: "white"
horizontalAlignment: Text.AlignHCenter
}
}
RippleEffect {
anchors.fill: parent
circular: true
onClicked: filter = 2
}
}
}
background: Rectangle {
color: MSettings.darkTheme ? "#303030" : "#fafafa"
radius: 24
layer.enabled: true
layer.effect: ElevationEffect {
elevation: 1
}
}
}
}
Component {
id: acceptInvitationDialog
AcceptInvitationDialog {}
}
}