Sorry this is a huge commit, this actually includes a ton of stuff. Text color is now readable, multiple accounts are supported alongside end-to-end encryption but no cross-signing yet :-) There's also a whole lot of other small changes, such as choosing the server you want to request a room directory from.
1190 lines
34 KiB
QML
Executable file
1190 lines
34 KiB
QML
Executable file
import QtQuick 2.15
|
|
import QtQuick.Controls 2.3
|
|
import QtGraphicalEffects 1.0
|
|
import QtQuick.Dialogs 1.2
|
|
import QtQuick.Layouts 1.1
|
|
import trinity.matrix 1.0
|
|
|
|
Rectangle {
|
|
id: client
|
|
color: myPalette.window
|
|
|
|
property bool shouldScroll: false
|
|
|
|
property var openProfile: function(member) {
|
|
var popup = Qt.createComponent("qrc:/Profile.qml")
|
|
var popupContainer = popup.createObject(window, {"parent": window, "member": member})
|
|
|
|
popupContainer.open()
|
|
}
|
|
|
|
property var openRoom: function(room) {
|
|
var popup = Qt.createComponent("qrc:/RoomSettings.qml")
|
|
var popupContainer = popup.createObject(window, {"parent": window, "room": room})
|
|
|
|
popupContainer.open()
|
|
}
|
|
|
|
Rectangle {
|
|
anchors.fill: parent
|
|
visible: !matrix.initialSyncComplete
|
|
|
|
z: 1000
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
}
|
|
|
|
BusyIndicator {
|
|
id: syncIndicator
|
|
|
|
anchors.centerIn: parent
|
|
}
|
|
|
|
Text {
|
|
anchors.top: syncIndicator.bottom
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
|
|
text: "Synchronizing events..."
|
|
}
|
|
|
|
Button {
|
|
anchors.bottom: parent.bottom
|
|
anchors.bottomMargin: 15
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
|
|
text: "Log out"
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
id: channels
|
|
|
|
width: 180
|
|
|
|
anchors.left: parent.left
|
|
anchors.top: parent.top
|
|
anchors.bottom: parent.bottom
|
|
|
|
Rectangle {
|
|
id: profileRect
|
|
|
|
anchors.top: parent.top
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
|
|
height: 45
|
|
|
|
color: myPalette.mid
|
|
|
|
Text {
|
|
text: "Placeholder name"
|
|
}
|
|
|
|
Button {
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
anchors.right: parent.right
|
|
anchors.rightMargin: 10
|
|
|
|
text: "Switch"
|
|
|
|
onClicked: accountMenu.popup()
|
|
|
|
Menu {
|
|
id: accountMenu
|
|
|
|
Repeater {
|
|
model: app.accounts
|
|
|
|
MenuItem {
|
|
text: modelData.profileName
|
|
|
|
onClicked: app.switchAccount(modelData.profileName)
|
|
}
|
|
}
|
|
|
|
MenuSeparator {}
|
|
|
|
MenuItem {
|
|
text: "Add new account"
|
|
|
|
onClicked: app.addAccount("test")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ListView {
|
|
id: channelListView
|
|
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
anchors.top: profileRect.bottom
|
|
anchors.bottom: parent.bottom
|
|
anchors.margins: 10
|
|
|
|
spacing: 5
|
|
|
|
model: matrix.roomListModel
|
|
|
|
section.property: "section"
|
|
section.criteria: ViewSection.FullString
|
|
section.delegate: Rectangle {
|
|
width: parent.width
|
|
height: 25
|
|
|
|
color: "transparent"
|
|
|
|
Text {
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
|
|
anchors.left: parent.left
|
|
anchors.leftMargin: 5
|
|
|
|
text: section
|
|
|
|
color: myPalette.text
|
|
|
|
textFormat: Text.PlainText
|
|
}
|
|
}
|
|
|
|
delegate: Rectangle {
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
height: 25
|
|
|
|
property bool selected: channelListView.currentIndex === matrix.roomListModel.getOriginalIndex(index)
|
|
|
|
color: selected ? myPalette.highlight : "transparent"
|
|
|
|
radius: 5
|
|
|
|
RoundedImage {
|
|
id: roomAvatar
|
|
|
|
anchors.top: parent.top
|
|
anchors.topMargin: 5
|
|
anchors.left: parent.left
|
|
anchors.leftMargin: 5
|
|
|
|
width: 18
|
|
height: 18
|
|
|
|
source: avatarURL ? avatarURL : "placeholder.png"
|
|
}
|
|
|
|
Text {
|
|
text: alias
|
|
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
|
|
anchors.left: roomAvatar.right
|
|
anchors.leftMargin: 5
|
|
anchors.right: parent.right
|
|
anchors.rightMargin: 5
|
|
|
|
color: selected ? "white" : (highlightCount > 0 ? "red" : (notificationCount > 0 ? "blue" : myPalette.text))
|
|
|
|
textFormat: Text.PlainText
|
|
elide: Text.ElideRight
|
|
}
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
|
|
cursorShape: Qt.PointingHandCursor
|
|
|
|
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
|
|
|
onReleased: {
|
|
if(mouse.button == Qt.LeftButton) {
|
|
if(!selected) {
|
|
var originalIndex = matrix.roomListModel.getOriginalIndex(index)
|
|
matrix.changeCurrentRoom(originalIndex)
|
|
channelListView.currentIndex = originalIndex
|
|
}
|
|
} else
|
|
contextMenu.popup()
|
|
}
|
|
}
|
|
|
|
Menu {
|
|
id: contextMenu
|
|
|
|
MenuItem {
|
|
text: "Mark As Read"
|
|
|
|
onReleased: matrix.readUpTo(matrix.getRoom(matrix.roomListModel.getOriginalIndex(index)), 0)
|
|
}
|
|
|
|
MenuSeparator {}
|
|
|
|
GroupBox {
|
|
title: "Notification Settings"
|
|
|
|
Column {
|
|
spacing: 10
|
|
|
|
RadioButton {
|
|
text: "All messages"
|
|
|
|
ToolTip.text: "Recieve a notification for all messages in this room."
|
|
ToolTip.visible: hovered
|
|
|
|
onReleased: matrix.getRoom(matrix.roomListModel.getOriginalIndex(index)).notificationLevel = 2
|
|
|
|
checked: matrix.getRoom(matrix.roomListModel.getOriginalIndex(index)).notificationLevel === 2
|
|
}
|
|
|
|
RadioButton {
|
|
text: "Only Mentions"
|
|
|
|
ToolTip.text: "Recieve a notification for mentions in this room."
|
|
ToolTip.visible: hovered
|
|
|
|
onReleased: matrix.getRoom(matrix.roomListModel.getOriginalIndex(index)).notificationLevel = 1
|
|
|
|
checked: matrix.getRoom(matrix.roomListModel.getOriginalIndex(index)).notificationLevel === 1
|
|
}
|
|
|
|
RadioButton {
|
|
text: "Mute"
|
|
|
|
ToolTip.text: "Don't get notifications or unread indicators for this room."
|
|
ToolTip.visible: hovered
|
|
|
|
onReleased: matrix.getRoom(matrix.roomListModel.getOriginalIndex(index)).notificationLevel = 0
|
|
|
|
checked: matrix.getRoom(matrix.roomListModel.getOriginalIndex(index)).notificationLevel === 3
|
|
}
|
|
}
|
|
}
|
|
|
|
MenuSeparator {}
|
|
|
|
MenuItem {
|
|
text: "Settings"
|
|
|
|
onReleased: openRoom(matrix.getRoom(matrix.roomListModel.getOriginalIndex(index)))
|
|
}
|
|
|
|
MenuSeparator {}
|
|
|
|
MenuItem {
|
|
text: "Leave Room"
|
|
|
|
onReleased: {
|
|
showDialog("Leave Confirmation", "Are you sure you want to leave " + alias + "?", [
|
|
{
|
|
text: "Yes",
|
|
onClicked: function(dialog) {
|
|
matrix.leaveRoom(id)
|
|
dialog.close()
|
|
}
|
|
},
|
|
{
|
|
text: "No",
|
|
onClicked: function(dialog) {
|
|
dialog.close()
|
|
}
|
|
}
|
|
])
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Button {
|
|
width: parent.width
|
|
|
|
anchors.bottom: directoryButton.top
|
|
|
|
text: "Switch account"
|
|
|
|
onClicked: app.addAccount("test")
|
|
}
|
|
|
|
Button {
|
|
id: communitiesButton
|
|
|
|
width: parent.width
|
|
|
|
anchors.bottom: parent.bottom
|
|
|
|
text: "Communities"
|
|
|
|
onClicked: stack.push("qrc:/Communities.qml")
|
|
}
|
|
|
|
Button {
|
|
id: directoryButton
|
|
|
|
width: parent.width
|
|
|
|
anchors.bottom: communitiesButton.top
|
|
|
|
text: "Directory"
|
|
|
|
onClicked: stack.push("qrc:/Directory.qml")
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
id: rightArea
|
|
height: parent.height
|
|
anchors.left: channels.right
|
|
anchors.right: parent.right
|
|
|
|
Rectangle {
|
|
id: overlay
|
|
|
|
z: 999
|
|
|
|
anchors.top: roomHeader.bottom
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
anchors.bottom: parent.bottom
|
|
|
|
visible: matrix.currentRoom.guestDenied
|
|
|
|
Text {
|
|
id: invitedByLabel
|
|
|
|
anchors.centerIn: parent
|
|
|
|
color: myPalette.text
|
|
|
|
text: "You have been invited to this room by " + matrix.currentRoom.invitedBy
|
|
|
|
textFormat: Text.PlainText
|
|
}
|
|
|
|
RowLayout {
|
|
anchors.top: invitedByLabel.bottom
|
|
anchors.topMargin: 15
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
|
|
Button {
|
|
text: "Accept"
|
|
|
|
onReleased: {
|
|
matrix.joinRoom(matrix.currentRoom.id)
|
|
}
|
|
}
|
|
|
|
Button {
|
|
text: "Deny"
|
|
|
|
onReleased: {
|
|
matrix.joinRoom(matrix.currentRoom.id)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
id: roomHeader
|
|
height: 45
|
|
|
|
anchors.top: parent.top
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
|
|
color: myPalette.mid
|
|
|
|
RoundedImage {
|
|
id: channelAvatar
|
|
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
anchors.left: parent.left
|
|
anchors.leftMargin: 15
|
|
|
|
width: 33
|
|
height: 33
|
|
|
|
source: matrix.currentRoom.avatar ? matrix.currentRoom.avatar : "placeholder.png"
|
|
}
|
|
|
|
Text {
|
|
id: channelTitle
|
|
|
|
font.pointSize: 12
|
|
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
anchors.leftMargin: 15
|
|
anchors.left: channelAvatar.right
|
|
|
|
text: matrix.currentRoom.name
|
|
|
|
color: myPalette.text
|
|
|
|
textFormat: Text.PlainText
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
|
|
cursorShape: Qt.PointingHandCursor
|
|
|
|
onReleased: openRoom(matrix.currentRoom)
|
|
}
|
|
}
|
|
|
|
Text {
|
|
id: channelTopic
|
|
|
|
font.pointSize: 12
|
|
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
|
|
maximumLineCount: 1
|
|
|
|
anchors.left: channelTitle.right
|
|
anchors.leftMargin: 10
|
|
anchors.right: audioCallButton.left
|
|
|
|
text: {
|
|
if(matrix.currentRoom.direct)
|
|
return "";
|
|
|
|
if(matrix.currentRoom.topic.length == 0)
|
|
return "This room has no topic set."
|
|
else
|
|
return matrix.currentRoom.topic
|
|
}
|
|
|
|
color: myPalette.text
|
|
|
|
elide: Text.ElideRight
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
|
|
cursorShape: Qt.PointingHandCursor
|
|
|
|
onReleased: showDialog(matrix.currentRoom.name, matrix.currentRoom.topic)
|
|
}
|
|
|
|
textFormat: Text.PlainText
|
|
}
|
|
|
|
ToolBarButton {
|
|
id: videoCallButton
|
|
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
|
|
anchors.right: audioCallButton.left
|
|
anchors.rightMargin: 10
|
|
|
|
|
|
name: "Video Call"
|
|
toolIcon: "icons/memberlist.png"
|
|
}
|
|
|
|
ToolBarButton {
|
|
id: audioCallButton
|
|
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
|
|
anchors.right: notificationsButton.left
|
|
anchors.rightMargin: 10
|
|
|
|
name: "Voice Call"
|
|
toolIcon: "icons/memberlist.png"
|
|
}
|
|
|
|
ToolBarButton {
|
|
id: notificationsButton
|
|
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
|
|
anchors.right: roomInfoButton.left
|
|
anchors.rightMargin: 10
|
|
|
|
name: "Notifications"
|
|
toolIcon: "icons/memberlist.png"
|
|
}
|
|
|
|
ToolBarButton {
|
|
id: roomInfoButton
|
|
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
|
|
anchors.right: settingsButton.left
|
|
anchors.rightMargin: 10
|
|
|
|
onPressed: {
|
|
if(memberList.width == 0)
|
|
memberList.width = 200
|
|
else
|
|
memberList.width = 0
|
|
}
|
|
|
|
name: "Room Info"
|
|
toolIcon: "icons/memberlist.png"
|
|
isActivated: memberList.width == 200
|
|
}
|
|
|
|
ToolBarButton {
|
|
id: settingsButton
|
|
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
|
|
anchors.right: parent.right
|
|
anchors.rightMargin: 15
|
|
|
|
onPressed: stack.push("qrc:/Settings.qml")
|
|
name: "Settings"
|
|
toolIcon: "icons/settings.png"
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
id: messagesArea
|
|
|
|
anchors.top: roomHeader.bottom
|
|
anchors.left: parent.left
|
|
anchors.bottom: parent.bottom
|
|
anchors.right: memberList.left
|
|
|
|
Rectangle {
|
|
anchors.top: parent.top
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
anchors.bottom: messageInputParent.top
|
|
|
|
clip: true
|
|
|
|
color: myPalette.light
|
|
|
|
ListView {
|
|
id: messages
|
|
model: matrix.eventModel
|
|
|
|
anchors.fill: parent
|
|
|
|
cacheBuffer: 200
|
|
|
|
delegate: Rectangle {
|
|
anchors.left: messages.contentItem.left
|
|
anchors.right: messages.contentItem.right
|
|
anchors.margins: 10
|
|
|
|
height: (condense ? 5 : 25) + messageArea.height
|
|
|
|
color: "transparent"
|
|
|
|
property string attachment: display.attachment
|
|
property var sender: matrix.resolveMemberId(display.sender)
|
|
property var eventId: display.eventId
|
|
property var msg: display.msg
|
|
|
|
RoundedImage {
|
|
id: avatar
|
|
|
|
width: 33
|
|
height: 33
|
|
|
|
anchors.top: parent.top
|
|
anchors.topMargin: 5
|
|
anchors.left: parent.left
|
|
anchors.leftMargin: 5
|
|
|
|
source: sender == null ? "placeholder.png"
|
|
: (sender.avatarURL ? sender.avatarURL : "placeholder.png")
|
|
|
|
visible: !condense
|
|
}
|
|
|
|
Text {
|
|
id: senderText
|
|
|
|
text: condense || sender == null ? "" : sender.displayName
|
|
|
|
color: myPalette.text
|
|
|
|
font.bold: true
|
|
|
|
anchors.left: avatar.right
|
|
anchors.leftMargin: 10
|
|
|
|
textFormat: Text.PlainText
|
|
}
|
|
|
|
MouseArea {
|
|
id: senderClickArea
|
|
|
|
anchors.left: avatar.left
|
|
anchors.right: senderText.right
|
|
anchors.top: avatar.top
|
|
anchors.bottom: avatar.bottom
|
|
|
|
cursorShape: Qt.PointingHandCursor
|
|
|
|
onClicked: openProfile(sender)
|
|
}
|
|
|
|
Text {
|
|
text: condense ? "" : timestamp
|
|
|
|
color: myPalette.dark
|
|
|
|
anchors.left: senderText.right
|
|
anchors.leftMargin: 10
|
|
|
|
textFormat: Text.PlainText
|
|
}
|
|
|
|
Rectangle {
|
|
id: messageArea
|
|
|
|
y: condense ? 0 : 20
|
|
|
|
height: {
|
|
if(display.msgType === "text")
|
|
return message.contentHeight
|
|
else if(display.msgType === "image")
|
|
return messageThumbnail.height
|
|
else
|
|
return preview.height
|
|
}
|
|
|
|
anchors.left: condense ? parent.left : avatar.right
|
|
anchors.leftMargin: condense ? 48 : 10
|
|
|
|
anchors.right: parent.right
|
|
|
|
color: "transparent"
|
|
|
|
TextEdit {
|
|
id: message
|
|
|
|
width: parent.width
|
|
|
|
text: display.msg
|
|
|
|
wrapMode: Text.WordWrap
|
|
textFormat: Text.RichText
|
|
|
|
readOnly: true
|
|
selectByMouse: true
|
|
|
|
color: display.sent ? myPalette.text : myPalette.mid
|
|
|
|
visible: display.msgType === "text"
|
|
}
|
|
|
|
Image {
|
|
id: messageThumbnail
|
|
|
|
visible: display.msgType === "image"
|
|
|
|
source: display.thumbnail
|
|
|
|
fillMode: Image.PreserveAspectFit
|
|
width: Math.min(sourceSize.width, 400)
|
|
}
|
|
|
|
MouseArea {
|
|
enabled: display.msgType === "image"
|
|
|
|
cursorShape: Qt.PointingHandCursor
|
|
|
|
anchors.fill: messageThumbnail
|
|
|
|
onReleased: showImage(display.attachment)
|
|
}
|
|
|
|
Rectangle {
|
|
id: preview
|
|
|
|
width: 350
|
|
height: 45
|
|
|
|
visible: display.msgType === "file"
|
|
|
|
radius: 5
|
|
|
|
color: Qt.rgba(0.05, 0.05, 0.05, 1.0)
|
|
|
|
Text {
|
|
id: previewFilename
|
|
|
|
x: 15
|
|
y: 7
|
|
|
|
text: display.msg
|
|
|
|
color: "#048dc2"
|
|
}
|
|
|
|
Text {
|
|
id: previewFilesize
|
|
|
|
x: 15
|
|
y: 22
|
|
|
|
font.pointSize: 9
|
|
|
|
text: display.attachmentSize / 1000.0 + " KB"
|
|
|
|
color: "gray"
|
|
}
|
|
|
|
ToolButton {
|
|
id: previewFileDownload
|
|
|
|
width: 25
|
|
height: 25
|
|
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
anchors.right: parent.right
|
|
anchors.rightMargin: 10
|
|
|
|
Image {
|
|
id: downloadButtonImage
|
|
|
|
anchors.fill: parent
|
|
|
|
sourceSize.width: parent.width
|
|
sourceSize.height: parent.height
|
|
|
|
source: "icons/download.png"
|
|
}
|
|
|
|
ColorOverlay {
|
|
anchors.fill: parent
|
|
source: downloadButtonImage
|
|
|
|
color: parent.hovered ? "white" : Qt.rgba(0.8, 0.8, 0.8, 1.0)
|
|
}
|
|
|
|
onClicked: {
|
|
console.log(attachment)
|
|
Qt.openUrlExternally(attachment)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
MouseArea {
|
|
anchors.fill: messageArea
|
|
|
|
acceptedButtons: Qt.RightButton
|
|
|
|
propagateComposedEvents: true
|
|
|
|
onClicked: contextMenu.popup()
|
|
}
|
|
|
|
Menu {
|
|
id: contextMenu
|
|
|
|
MenuItem {
|
|
text: "Remove"
|
|
|
|
onReleased: matrix.removeMessage(eventId)
|
|
}
|
|
|
|
MenuItem {
|
|
text: "Permalink"
|
|
|
|
onReleased: Qt.openUrlExternally("https://matrix.to/#/" + matrix.currentRoom.id + "/" + eventId)
|
|
}
|
|
|
|
MenuItem {
|
|
text: "Quote"
|
|
|
|
onReleased: messageInput.append("> " + msg + "\n\n")
|
|
}
|
|
}
|
|
}
|
|
|
|
ScrollBar.vertical: ScrollBar {}
|
|
|
|
boundsBehavior: Flickable.StopAtBounds
|
|
flickableDirection: Flickable.VerticalFlick
|
|
verticalLayoutDirection: ListView.BottomToTop
|
|
|
|
onMovingVerticallyChanged: {
|
|
if(verticalVelocity < 0)
|
|
matrix.readMessageHistory(matrix.currentRoom)
|
|
}
|
|
|
|
// we scrolled
|
|
onContentYChanged: {
|
|
var index = indexAt(0, contentY + height - 5)
|
|
matrix.readUpTo(matrix.currentRoom, index)
|
|
}
|
|
|
|
// a new message was added
|
|
onContentHeightChanged: {
|
|
var index = indexAt(0, contentY + height - 5)
|
|
matrix.readUpTo(matrix.currentRoom, index)
|
|
|
|
//print(contentHeight + "," + height);
|
|
if(contentHeight < height) {
|
|
matrix.readMessageHistory(matrix.currentRoom)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
id: messageInputParent
|
|
|
|
anchors.bottom: parent.bottom
|
|
|
|
width: parent.width
|
|
height: 55
|
|
|
|
color: "transparent"
|
|
|
|
ToolButton {
|
|
id: attachButton
|
|
|
|
icon.name: "mail-attachment"
|
|
|
|
width: 30
|
|
height: 30
|
|
|
|
anchors.top: parent.top
|
|
anchors.topMargin: 5
|
|
|
|
anchors.left: parent.left
|
|
anchors.leftMargin: 5
|
|
|
|
ToolTip.text: "Attach File"
|
|
ToolTip.visible: hovered
|
|
|
|
onReleased: openAttachmentFileDialog.open()
|
|
}
|
|
|
|
TextArea {
|
|
id: messageInput
|
|
|
|
width: parent.width - attachButton.width - 10
|
|
height: 30
|
|
|
|
anchors.bottom: parent.bottom
|
|
anchors.bottomMargin: 20
|
|
|
|
anchors.left: attachButton.right
|
|
anchors.leftMargin: 5
|
|
|
|
anchors.right: parent.right
|
|
anchors.rightMargin: 5
|
|
|
|
placeholderText: "Send a " + (matrix.currentRoom.encrypted ? "encrypted" : "unencrypted") + " message to " + matrix.currentRoom.name
|
|
|
|
Keys.onReturnPressed: {
|
|
if(event.modifiers & Qt.ShiftModifier) {
|
|
event.accepted = false
|
|
} else {
|
|
event.accepted = true
|
|
matrix.sendMessage(matrix.currentRoom, text)
|
|
clear()
|
|
}
|
|
}
|
|
|
|
onTextChanged: {
|
|
height = Math.max(30, contentHeight + 13)
|
|
parent.height = Math.max(55, contentHeight + 20)
|
|
}
|
|
}
|
|
|
|
ToolButton {
|
|
id: markdownButton
|
|
|
|
icon.name: "text-x-generic"
|
|
|
|
width: 20
|
|
height: 20
|
|
|
|
anchors.top: messageInput.top
|
|
anchors.topMargin: 5
|
|
|
|
anchors.right: emojiButton.left
|
|
anchors.rightMargin: 5
|
|
|
|
ToolTip.text: "Markdown is " + (matrix.markdownEnabled ? "enabled" : "disabled")
|
|
ToolTip.visible: hovered
|
|
|
|
onReleased: matrix.markdownEnabled = !matrix.markdownEnabled
|
|
}
|
|
|
|
ToolButton {
|
|
id: emojiButton
|
|
|
|
icon.name: "face-smile"
|
|
|
|
width: 20
|
|
height: 20
|
|
|
|
anchors.top: messageInput.top
|
|
anchors.topMargin: 5
|
|
|
|
anchors.right: messageInput.right
|
|
anchors.rightMargin: 5
|
|
|
|
ToolTip.text: "Add emoji"
|
|
ToolTip.visible: hovered
|
|
}
|
|
|
|
Text {
|
|
id: typingLabel
|
|
|
|
anchors.bottom: messageInputParent.bottom
|
|
|
|
color: myPalette.text
|
|
|
|
text: matrix.typingText
|
|
|
|
textFormat: Text.PlainText
|
|
}
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
id: memberList
|
|
|
|
anchors.top: roomHeader.bottom
|
|
anchors.right: parent.right
|
|
|
|
color: myPalette.midlight
|
|
|
|
width: matrix.currentRoom.direct ? 0 : 200
|
|
height: parent.height - roomHeader.height
|
|
|
|
ListView {
|
|
id: memberListView
|
|
|
|
model: matrix.memberModel
|
|
|
|
clip: true
|
|
|
|
anchors.top: parent.top
|
|
anchors.bottom: inviteButton.top
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
|
|
section.property: "section"
|
|
section.criteria: ViewSection.FullString
|
|
section.delegate: Rectangle {
|
|
width: parent.width
|
|
height: 25
|
|
|
|
color: "transparent"
|
|
|
|
Text {
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
|
|
anchors.left: parent.left
|
|
anchors.leftMargin: 5
|
|
|
|
text: section
|
|
|
|
color: myPalette.text
|
|
|
|
textFormat: Text.PlainText
|
|
}
|
|
}
|
|
|
|
delegate: Rectangle {
|
|
width: memberListView.contentItem.width
|
|
height: 50
|
|
|
|
color: "transparent"
|
|
|
|
property string memberId: id
|
|
|
|
RoundedImage {
|
|
id: memberAvatar
|
|
|
|
width: 33
|
|
height: 33
|
|
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
anchors.left: parent.left
|
|
anchors.leftMargin: 10
|
|
|
|
source: avatarURL ? avatarURL : "placeholder.png"
|
|
}
|
|
|
|
Text {
|
|
anchors.left: memberAvatar.right
|
|
anchors.leftMargin: 10
|
|
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
|
|
color: myPalette.text
|
|
|
|
text: displayName
|
|
|
|
textFormat: Text.PlainText
|
|
}
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
|
|
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
|
|
|
cursorShape: Qt.PointingHandCursor
|
|
|
|
onClicked: function(mouse) {
|
|
if(mouse.button == Qt.LeftButton) {
|
|
openProfile(matrix.resolveMemberId(id))
|
|
} else {
|
|
memberContextMenu.popup()
|
|
}
|
|
}
|
|
}
|
|
|
|
Menu {
|
|
id: memberContextMenu
|
|
|
|
MenuItem {
|
|
text: "Profile"
|
|
|
|
onReleased: openProfile(matrix.resolveMemberId(id))
|
|
}
|
|
|
|
MenuItem {
|
|
text: "Mention"
|
|
|
|
onReleased: messageInput.append(displayName + ": ")
|
|
}
|
|
|
|
MenuItem {
|
|
text: "Start Direct Chat"
|
|
|
|
onReleased: matrix.startDirectChat(id)
|
|
}
|
|
|
|
MenuSeparator {}
|
|
|
|
Menu {
|
|
title: "Invite to room"
|
|
|
|
Repeater {
|
|
model: matrix.roomListModel
|
|
|
|
MenuItem {
|
|
text: alias
|
|
|
|
onReleased: {
|
|
matrix.inviteToRoom(matrix.resolveRoomId(id), memberId)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ScrollBar.vertical: ScrollBar {}
|
|
|
|
boundsBehavior: Flickable.StopAtBounds
|
|
flickableDirection: Flickable.VerticalFlick
|
|
}
|
|
|
|
Button {
|
|
id: inviteButton
|
|
|
|
anchors.bottom: parent.bottom
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
anchors.margins: 8
|
|
|
|
text: "Invite to room"
|
|
|
|
onClicked: {
|
|
var popup = Qt.createComponent("qrc:/InviteDialog.qml")
|
|
var popupContainer = popup.createObject(window, {"parent": window})
|
|
|
|
popupContainer.open()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Timer {
|
|
id: syncTimer
|
|
interval: 1500
|
|
running: true
|
|
onTriggered: {
|
|
shouldScroll = messages.contentY == messages.contentHeight - messages.height
|
|
|
|
matrix.sync()
|
|
}
|
|
}
|
|
|
|
Timer {
|
|
id: memberTimer
|
|
interval: 60000
|
|
running: true
|
|
onTriggered: matrix.updateMembers(matrix.currentRoom)
|
|
}
|
|
|
|
Timer {
|
|
id: typingTimer
|
|
interval: 15000 //15 seconds
|
|
running: true
|
|
onTriggered: {
|
|
if(messageInput.text.length !== 0)
|
|
matrix.setTyping(matrix.currentRoom)
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: matrix
|
|
|
|
function onSyncFinished() {
|
|
syncTimer.start()
|
|
|
|
if(shouldScroll)
|
|
messages.positionViewAtEnd()
|
|
}
|
|
|
|
function onInitialSyncFinished() {
|
|
matrix.changeCurrentRoom(0)
|
|
}
|
|
|
|
function onCurrentRoomChanged() {
|
|
if(messages.contentY < messages.originY + 5)
|
|
matrix.readMessageHistory(matrix.currentRoom)
|
|
}
|
|
|
|
function onMessage(room, sender, content) {
|
|
var notificationLevel = room.notificationLevel
|
|
var shouldDisplay = false
|
|
|
|
if(notificationLevel === 2) {
|
|
shouldDisplay = true
|
|
} else if(notificationLevel === 1) {
|
|
if(content.includes(matrix.displayName))
|
|
shouldDisplay = true
|
|
}
|
|
|
|
if(shouldDisplay)
|
|
desktop.showMessage(matrix.resolveMemberId(sender).displayName + " (" + room.name + ")", content)
|
|
}
|
|
}
|
|
|
|
FileDialog {
|
|
id: openAttachmentFileDialog
|
|
folder: shortcuts.home
|
|
|
|
selectExisting: true
|
|
selectFolder: false
|
|
selectMultiple: false
|
|
|
|
onAccepted: {
|
|
matrix.uploadAttachment(matrix.currentRoom, fileUrl)
|
|
close()
|
|
}
|
|
|
|
onRejected: close()
|
|
}
|
|
}
|