diff --git a/matrique.pro b/matrique.pro
index 5a6d65a2a..f27d296f3 100644
--- a/matrique.pro
+++ b/matrique.pro
@@ -1,7 +1,9 @@
QT += quick widgets multimedia
CONFIG += c++14
CONFIG += object_parallel_to_source
-CONFIG += qtquickcompiler
+
+# Enable this to use QtQuick Compiler.
+#CONFIG += qtquickcompiler
TARGET = matrique
@@ -75,10 +77,9 @@ DISTFILES += \
ButtonDelegate.qml \
SideNav.qml \
RoomListForm.qml \
- RoomDetailForm.qml \
Room.qml \
Setting.qml \
- qml/js/md.js
+ qml/js/md.js \
HEADERS += \
src/controller.h \
diff --git a/qml/Login.qml b/qml/Login.qml
index 811955bd6..25b6db972 100644
--- a/qml/Login.qml
+++ b/qml/Login.qml
@@ -57,17 +57,19 @@ Page {
Pane {
width: parent.width / 2
height: parent.height
+
padding: 64
ColumnLayout {
- id: mainCol
width: parent.width
- TextField {
- id: serverField
+ id: mainCol
+ TextField {
Layout.fillWidth: true
+ id: serverField
+
leftPadding: 16
topPadding: 0
bottomPadding: 0
@@ -85,10 +87,10 @@ Page {
}
TextField {
- id: usernameField
-
Layout.fillWidth: true
+ id: usernameField
+
leftPadding: 16
topPadding: 0
bottomPadding: 0
@@ -105,10 +107,10 @@ Page {
}
TextField {
- id: passwordField
-
Layout.fillWidth: true
+ id: passwordField
+
leftPadding: 16
topPadding: 0
bottomPadding: 0
@@ -126,10 +128,10 @@ Page {
}
Button {
- id: loginButton
-
Layout.fillWidth: true
+ id: loginButton
+
text: "LOGIN"
highlighted: true
diff --git a/qml/MatriqueSettings.qml b/qml/MatriqueSettings.qml
index 6bcdbb560..1c8ead167 100644
--- a/qml/MatriqueSettings.qml
+++ b/qml/MatriqueSettings.qml
@@ -4,7 +4,6 @@ import Qt.labs.settings 1.0
Settings {
property bool lazyLoad: true
- property bool asyncMessageDelegate
property bool richText
property bool pressAndHold
property bool rearrangeByActivity
diff --git a/qml/Room.qml b/qml/Room.qml
index 5e7217503..3c16583f4 100644
--- a/qml/Room.qml
+++ b/qml/Room.qml
@@ -18,28 +18,42 @@ Page {
onNewMessage: if (!window.active) matriqueController.showMessage(roomName, content, icon)
}
- RowLayout {
+ Rectangle {
anchors.fill: parent
- spacing: 0
- RoomListForm {
- id: roomListForm
+ color: MSettings.darkTheme ? "#323232" : "#f3f3f3"
- Layout.fillHeight: true
- Layout.preferredWidth: MSettings.miniMode ? 80 : page.width * 0.35
- Layout.minimumWidth: 80
- Layout.maximumWidth: 360
+ RowLayout {
+ anchors.fill: parent
- listModel: roomListModel
- }
+ spacing: 0
- RoomForm {
- id: roomForm
+ RoomListForm {
+ Layout.fillHeight: true
+ Layout.preferredWidth: MSettings.miniMode ? 64 : page.width * 0.35
+ Layout.minimumWidth: 64
+ Layout.maximumWidth: 360
- Layout.fillWidth: true
- Layout.fillHeight: true
+ id: roomListForm
- currentRoom: roomListForm.enteredRoom
+ listModel: roomListModel
+ }
+
+ Rectangle {
+ Layout.preferredWidth: 1
+ Layout.fillHeight: true
+
+ color: MSettings.darkTheme ? "#363636" : "#ececec"
+ }
+
+ RoomForm {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+
+ id: roomForm
+
+ currentRoom: roomListForm.enteredRoom
+ }
}
}
}
diff --git a/qml/Setting.qml b/qml/Setting.qml
index 1b739f419..2fcf0806a 100644
--- a/qml/Setting.qml
+++ b/qml/Setting.qml
@@ -58,57 +58,59 @@ Page {
Page {
id: generalForm
+
parent: null
+
Column {
Switch {
text: "Lazy load at initial sync"
checked: MSettings.lazyLoad
+
onCheckedChanged: MSettings.lazyLoad = checked
}
- Switch {
- text: "Force loading message delegates asynchronously"
- checked: MSettings.asyncMessageDelegate
- onCheckedChanged: MSettings.asyncMessageDelegate = checked
- }
+
Switch {
text: "Use RichText instead of StyledText"
checked: MSettings.richText
+
onCheckedChanged: MSettings.richText = checked
}
+
Switch {
text: "Use press and hold instead of right click"
checked: MSettings.pressAndHold
- onCheckedChanged: MSettings.pressAndHold = checked
- }
- Switch {
- text: "Rearrange rooms by activity"
- checked: MSettings.rearrangeByActivity
- onCheckedChanged: MSettings.rearrangeByActivity = checked
- }
- Button {
- text: "Invoke GC"
- highlighted: true
- onClicked: gc()
+ onCheckedChanged: MSettings.pressAndHold = checked
}
}
}
Page {
id: appearanceForm
+
parent: null
+
Column {
Switch {
text: "Dark theme"
checked: MSettings.darkTheme
+
onCheckedChanged: MSettings.darkTheme = checked
}
Switch {
text: "Mini Room List"
checked: MSettings.miniMode
+
onCheckedChanged: MSettings.miniMode = checked
}
+
+ Switch {
+ text: "Rearrange rooms by activity"
+ checked: MSettings.rearrangeByActivity
+
+ onCheckedChanged: MSettings.rearrangeByActivity = checked
+ }
}
}
@@ -126,12 +128,8 @@ Page {
source: "qrc:/asset/img/icon.png"
}
- Label {
- text: "Matrique, an IM client for the Matrix protocol."
- }
- Label {
- text: "Released under GNU General Public License, version 3."
- }
+ Label { text: "Matrique, an IM client for the Matrix protocol." }
+ Label { text: "Released under GNU General Public License, version 3." }
}
}
diff --git a/qml/component/AudioBubble.qml b/qml/component/AudioBubble.qml
deleted file mode 100644
index e01f5aeca..000000000
--- a/qml/component/AudioBubble.qml
+++ /dev/null
@@ -1,50 +0,0 @@
-import QtQuick 2.9
-import QtQuick.Controls 2.2
-import QtQuick.Controls.Material 2.2
-import QtMultimedia 5.9
-import Qt.labs.platform 1.0
-
-AvatarContainer {
- readonly property var downloadAndOpen: downloadable.downloadAndOpen
- readonly property var saveFileAs: downloadable.saveFileAs
-
- property bool playOnFinished: false
-
- id: messageRow
-
- DownloadableContent {
- id: downloadable
-
- width: downloadDelegate.width
- height: downloadDelegate.height
-
- TextDelegate {
- id: downloadDelegate
-
- maximumWidth: messageListView.width
- highlighted: !sentByMe
- timeLabelVisible: false
- authorLabelVisible: false
-
- displayText: content.info.duration / 1000 + '"'
-
- MouseArea {
- anchors.fill: parent
-
- propagateComposedEvents: true
-
- onClicked: {
- if (downloadable.downloaded)
- matriqueController.playAudio(progressInfo.localPath)
- else
- {
- playOnFinished = true
- currentRoom.downloadFile(eventId, StandardPaths.writableLocation(StandardPaths.CacheLocation) + "/" + eventId.replace(":", "_") + ".tmp")
- }
- }
- }
- }
- onDownloadedChanged: downloaded && playOnFinished ? matriqueController.playAudio(progressInfo.localPath) : {}
- }
-
-}
diff --git a/qml/component/AutoImage.qml b/qml/component/AutoImage.qml
index 75fbc618f..c7050de5a 100644
--- a/qml/component/AutoImage.qml
+++ b/qml/component/AutoImage.qml
@@ -6,22 +6,22 @@ Item {
property alias sourceSize: baseImage.sourceSize.width
readonly property bool loading: baseImage.status == Image.Loading
- signal clicked()
- id: rekt
+ signal clicked()
width: loading ? 128 : baseImage.implicitWidth
height: loading ? progressBar.height : baseImage.implicitHeight
- Image {
- id: baseImage
- }
+ id: rekt
+
+ Image { id: baseImage }
ProgressBar {
- id: progressBar
width: parent.width
visible: loading
+ id: progressBar
+
indeterminate: true
}
diff --git a/qml/component/AutoLabel.qml b/qml/component/AutoLabel.qml
new file mode 100644
index 000000000..684f8927c
--- /dev/null
+++ b/qml/component/AutoLabel.qml
@@ -0,0 +1,16 @@
+import QtQuick 2.9
+import QtQuick.Controls 2.2
+import QtQuick.Controls.Material 2.2
+import Matrique.Settings 0.1
+
+Label {
+ property bool coloredBackground
+
+ color: coloredBackground ? "white": Material.foreground
+
+ wrapMode: Label.Wrap
+ linkColor: coloredBackground ? "white" : Material.accent
+ textFormat: MSettings.richText ? Text.RichText : Text.StyledText
+
+ onLinkActivated: Qt.openUrlExternally(link)
+}
diff --git a/qml/component/AutoMouseArea.qml b/qml/component/AutoMouseArea.qml
index 270ee255c..7d0cc0e26 100644
--- a/qml/component/AutoMouseArea.qml
+++ b/qml/component/AutoMouseArea.qml
@@ -6,6 +6,7 @@ MouseArea {
signal secondaryClicked()
acceptedButtons: MSettings.pressAndHold ? Qt.LeftButton : (Qt.LeftButton | Qt.RightButton)
+
onClicked: mouse.button == Qt.RightButton ? secondaryClicked() : primaryClicked()
onPressAndHold: MSettings.pressAndHold ? secondaryClicked() : {}
}
diff --git a/qml/component/AvatarContainer.qml b/qml/component/AvatarContainer.qml
deleted file mode 100644
index 64c4599be..000000000
--- a/qml/component/AvatarContainer.qml
+++ /dev/null
@@ -1,26 +0,0 @@
-import QtQuick 2.9
-import QtQuick.Controls 2.2
-
-Row {
- readonly property bool avatarVisible: !(sentByMe || (aboveAuthor === author && section === aboveSection))
-
- spacing: 6
-
- ImageStatus {
- id: avatar
-
- width: height
- height: 40
- round: false
- visible: avatarVisible
- source: author.avatarUrl != "" ? "image://mxc/" + author.avatarUrl : null
- displayText: author.displayName
- }
-
- Rectangle {
- width: height
- height: 40
- color: "transparent"
- visible: !avatarVisible
- }
-}
diff --git a/qml/component/DownloadableContent.qml b/qml/component/DownloadableContent.qml
index a0f10720b..e2bbaea95 100644
--- a/qml/component/DownloadableContent.qml
+++ b/qml/component/DownloadableContent.qml
@@ -11,20 +11,18 @@ Item {
z: -2
height: parent.height
width: progressInfo.active && !progressInfo.completed ? progressInfo.progress / progressInfo.total * parent.width : 0
+
color: Material.accent
opacity: 0.4
}
- onDownloadedChanged: downloaded && openOnFinished ? openSavedFile() : {}
+ onDownloadedChanged: if (downloaded && openOnFinished) openSavedFile()
- function saveFileAs() {
- currentRoom.saveFileAs(eventId)
- }
+ function saveFileAs() { currentRoom.saveFileAs(eventId) }
function downloadAndOpen()
{
- if (downloaded)
- openSavedFile()
+ if (downloaded) openSavedFile()
else
{
openOnFinished = true
@@ -34,10 +32,7 @@ Item {
function openSavedFile()
{
- if (Qt.openUrlExternally(progressInfo.localPath))
- return;
-
- if (Qt.openUrlExternally(progressInfo.localDir))
- return;
+ if (Qt.openUrlExternally(progressInfo.localPath)) return;
+ if (Qt.openUrlExternally(progressInfo.localDir)) return;
}
}
diff --git a/qml/component/EmojiPicker.qml b/qml/component/EmojiPicker.qml
index 78605392f..f58189a87 100644
--- a/qml/component/EmojiPicker.qml
+++ b/qml/component/EmojiPicker.qml
@@ -52,6 +52,7 @@ Popup {
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: 2
+
color: Material.accent
}
diff --git a/qml/component/FileBubble.qml b/qml/component/FileBubble.qml
deleted file mode 100644
index 4ff77bd21..000000000
--- a/qml/component/FileBubble.qml
+++ /dev/null
@@ -1,28 +0,0 @@
-import QtQuick 2.9
-import QtQuick.Controls 2.2
-import QtQuick.Controls.Material 2.2
-
-AvatarContainer {
- readonly property var downloadAndOpen: downloadable.downloadAndOpen
- readonly property var saveFileAs: downloadable.saveFileAs
-
- id: messageRow
-
- DownloadableContent {
- id: downloadable
-
- width: downloadDelegate.width
- height: downloadDelegate.height
-
- TextDelegate {
- id: downloadDelegate
-
- maximumWidth: messageListView.width
- highlighted: !sentByMe
- timeLabelVisible: false
- authorLabelVisible: false
-
- displayText: "File: " + content.body
- }
- }
-}
diff --git a/qml/component/GenericBubble.qml b/qml/component/GenericBubble.qml
new file mode 100644
index 000000000..3c754be2d
--- /dev/null
+++ b/qml/component/GenericBubble.qml
@@ -0,0 +1,22 @@
+import QtQuick 2.9
+import QtQuick.Controls 2.2
+import QtQuick.Controls.Material 2.2
+import Matrique.Settings 0.1
+
+Control {
+ property bool highlighted: false
+ property bool colored: false
+
+ readonly property bool darkBackground: highlighted ? true : MSettings.darkTheme
+ readonly property color backgroundColor: MSettings.darkTheme ? "#242424" : "lightgrey"
+
+ padding: 12
+
+ AutoMouseArea {
+ anchors.fill: parent
+
+ onSecondaryClicked: Qt.createComponent("qrc:/qml/menu/MessageContextMenu.qml").createObject(this)
+ }
+
+ background: Rectangle { color: colored ? Material.accent : highlighted ? Material.primary : backgroundColor }
+}
diff --git a/qml/component/ImageBubble.qml b/qml/component/ImageBubble.qml
deleted file mode 100644
index 887b37e31..000000000
--- a/qml/component/ImageBubble.qml
+++ /dev/null
@@ -1,34 +0,0 @@
-import QtQuick 2.9
-import QtQuick.Controls 2.2
-import QtQuick.Controls.Material 2.2
-
-AvatarContainer {
- readonly property var downloadAndOpen: downloadable.downloadAndOpen
- readonly property var saveFileAs: downloadable.saveFileAs
-
- Rectangle {
- id: messageRect
-
- width: messageImage.width + 24
- height: messageImage.height + 24
-
- color: sentByMe ? background : Material.accent
-
- DownloadableContent {
- id: downloadable
-
- width: messageImage.width
- height: messageImage.height
- anchors.centerIn: parent
-
- AutoImage {
- id: messageImage
- z: -4
- sourceSize: 128
- source: "image://mxc/" + (content.thumbnail_url ? content.thumbnail_url : content.url)
-
- onClicked: downloadAndOpen()
- }
- }
- }
-}
diff --git a/qml/component/ImageStatus.qml b/qml/component/ImageStatus.qml
index 137bb0645..21447838d 100644
--- a/qml/component/ImageStatus.qml
+++ b/qml/component/ImageStatus.qml
@@ -13,9 +13,11 @@ Item {
id: item
Image {
- id: avatar
width: item.width
height: item.width
+
+ id: avatar
+
visible: showImage
source: item.source
@@ -40,6 +42,7 @@ Item {
Label {
anchors.fill: parent
+
color: "white"
visible: showInitial
text: showInitial ? getInitials(displayText)[0] : ""
diff --git a/qml/component/MaterialIcon.qml b/qml/component/MaterialIcon.qml
index bfb4ca6b2..d1b2f0ed6 100644
--- a/qml/component/MaterialIcon.qml
+++ b/qml/component/MaterialIcon.qml
@@ -10,8 +10,9 @@ Item {
id: item
Text {
- id: iconText
anchors.fill: parent
+
+ id: iconText
font.pointSize: 16
font.family: materialFont.name
color: item.color
diff --git a/qml/component/MessageBubble.qml b/qml/component/MessageBubble.qml
deleted file mode 100644
index 7e87caef1..000000000
--- a/qml/component/MessageBubble.qml
+++ /dev/null
@@ -1,20 +0,0 @@
-import QtQuick 2.9
-import QtQuick.Controls 2.2
-import QtQuick.Layouts 1.3
-import QtQuick.Controls.Material 2.2
-
-AvatarContainer {
- readonly property bool isNotice: eventType === "notice"
-
- id: messageRow
-
- TextDelegate {
- maximumWidth: messageListView.width - (!sentByMe ? 40 + messageRow.spacing : 0)
- flat: isNotice
- highlighted: !sentByMe
- timeLabelVisible: Math.abs(time - aboveTime) > 600000 || index == 0
- authorLabelVisible: messageRow.avatarVisible
-
- displayText: display
- }
-}
diff --git a/qml/component/MessageDelegate.qml b/qml/component/MessageDelegate.qml
index e007cbf33..745212d53 100644
--- a/qml/component/MessageDelegate.qml
+++ b/qml/component/MessageDelegate.qml
@@ -1,53 +1,186 @@
import QtQuick 2.9
import QtQuick.Controls 2.2
+import QtQuick.Layouts 1.3
import QtQuick.Controls.Material 2.2
import Matrique 0.1
import Matrique.Settings 0.1
-Item {
- readonly property bool hidden: marks === EventStatus.Redacted || marks === EventStatus.Hidden
- readonly property color background: MSettings.darkTheme ? "#242424" : "lightgrey"
+RowLayout {
+ readonly property bool avatarVisible: !(sentByMe || (aboveAuthor === author && section === aboveSection))
+ readonly property bool highlighted: !sentByMe
readonly property bool sentByMe: author === currentRoom.localUser
- readonly property bool isState: eventType === "state" || eventType === "emote"
+ readonly property bool isText: eventType === "notice" || eventType === "message"
- id: messageDelegate
+ signal saveFileAs()
+ signal openExternally()
z: -5
- width: delegateLoader.width
- height: delegateLoader.height
- anchors.right: !isState && sentByMe ? parent.right : undefined
- anchors.horizontalCenter: isState ? parent.horizontalCenter : undefined
+ id: messageRow
- AutoMouseArea {
- anchors.fill: parent
+ Layout.alignment: sentByMe ? Qt.AlignRight : Qt.AlignLeft
- onSecondaryClicked: Qt.createComponent("qrc:/qml/menu/MessageContextMenu.qml").createObject(this)
+ spacing: 6
+
+ ImageStatus {
+ Layout.preferredWidth: 40
+ Layout.preferredHeight: 40
+ Layout.alignment: Qt.AlignTop
+
+ round: false
+ visible: avatarVisible
+ source: author.avatarUrl != "" ? "image://mxc/" + author.avatarUrl : null
+ displayText: author.displayName
}
- Loader {
- id: delegateLoader
+ Rectangle {
+ Layout.preferredWidth: 40
+ Layout.preferredHeight: 40
+ Layout.alignment: Qt.AlignTop
- asynchronous: MSettings.asyncMessageDelegate
+ color: "transparent"
+ visible: !(sentByMe || avatarVisible)
+ }
- source: {
- if (eventType == "redaction" || hidden) return ""
- switch (eventType) {
- case "state":
- case "emote":
- return "StateBubble.qml"
- case "message":
- case "notice":
- return "MessageBubble.qml"
- case "image":
- return "ImageBubble.qml"
- case "audio":
- return "AudioBubble.qml"
- case "video":
- case "file":
- return "FileBubble.qml"
+ GenericBubble {
+ Layout.maximumWidth: messageListView.width - (!sentByMe ? 40 + messageRow.spacing : 0)
+
+ id: genericBubble
+
+ highlighted: !sentByMe
+ colored: highlighted && eventType === "notice"
+
+ contentItem: ColumnLayout {
+ id: messageColumn
+
+ spacing: 0
+
+ AutoLabel {
+ visible: messageRow.avatarVisible
+ text: author.displayName
+ Material.foreground: Material.accent
+ coloredBackground: highlighted
+ font.bold: true
+ }
+
+ AutoLabel {
+ Layout.fillWidth: true
+
+ text: display
+ visible: isText
+ coloredBackground: highlighted
+ }
+
+ Loader {
+ sourceComponent: {
+ switch (eventType) {
+ case "image":
+ return imageComponent
+ case "file":
+ return fileComponent
+ case "audio":
+ return audioComponent
+ }
+ }
+
+ active: eventType === "image" || eventType === "file" || eventType === "audio"
+ }
+
+ AutoLabel {
+ Layout.alignment: Qt.AlignRight
+ visible: Math.abs(time - aboveTime) > 600000 || index == 0
+ text: Qt.formatTime(time, "hh:mm")
+ coloredBackground: highlighted
+ Material.foreground: "grey"
+ font.pointSize: 8
+ }
+ }
+
+ Component {
+ id: imageComponent
+
+ DownloadableContent {
+ width: messageImage.width
+ height: messageImage.height
+
+ id: downloadable
+
+ AutoImage {
+ z: -4
+
+ id: messageImage
+
+ sourceSize: 128
+ source: "image://mxc/" + (content.thumbnail_url ? content.thumbnail_url : content.url)
+
+ onClicked: downloadAndOpen()
+ }
+
+ Component.onCompleted: {
+ messageRow.saveFileAs.connect(saveFileAs)
+ messageRow.openExternally.connect(downloadAndOpen)
+ }
+ }
+ }
+
+ Component {
+ id: fileComponent
+
+ AutoLabel {
+ Layout.fillWidth: true
+
+ id: downloadDelegate
+
+ text: "File: " + content.body
+ coloredBackground: highlighted
+
+ background: DownloadableContent {
+ id: downloadable
+
+ Component.onCompleted: {
+ messageRow.saveFileAs.connect(saveFileAs)
+ messageRow.openExternally.connect(downloadAndOpen)
+ }
+ }
+ }
+ }
+
+ Component {
+ id: audioComponent
+
+ AutoLabel {
+ id: downloadDelegate
+
+ text: content.info.duration / 1000 + '"'
+ coloredBackground: highlighted
+
+ MouseArea {
+ anchors.fill: parent
+
+ propagateComposedEvents: true
+
+ onClicked: {
+ if (downloadable.downloaded)
+ matriqueController.playAudio(progressInfo.localPath)
+ else
+ {
+ playOnFinished = true
+ currentRoom.downloadFile(eventId, StandardPaths.writableLocation(StandardPaths.CacheLocation) + "/" + eventId.replace(":", "_") + ".tmp")
+ }
+ }
+ }
+
+ background: DownloadableContent {
+ id: downloadable
+
+ onDownloadedChanged: downloaded && playOnFinished ? matriqueController.playAudio(progressInfo.localPath) : {}
+
+ Component.onCompleted: {
+ messageRow.saveFileAs.connect(saveFileAs)
+ messageRow.openExternally.connect(downloadAndOpen)
+ }
+ }
}
- return ""
}
}
}
diff --git a/qml/component/SideNavButton.qml b/qml/component/SideNavButton.qml
index e57d1bce9..8c9bf2749 100644
--- a/qml/component/SideNavButton.qml
+++ b/qml/component/SideNavButton.qml
@@ -3,41 +3,29 @@ import QtQuick.Controls 2.2
import QtQuick.Layouts 1.3
import QtQuick.Controls.Material 2.2
-Item {
+ItemDelegate {
property var page
- property alias contentItem: buttonDelegate.contentItem
- signal clicked
-
- id: sideNavButton
-
- Layout.fillWidth: true
- Layout.preferredHeight: width
+ readonly property bool selected: stackView.currentItem === page
Rectangle {
- width: stackView.currentItem === page ? parent.width : 0
+ width: selected ? 4 : 0
height: parent.height
- anchors.bottom: buttonDelegate.bottom
- color: Qt.lighter(Material.accent)
+
+ color: Material.accent
Behavior on width {
PropertyAnimation { easing.type: Easing.InOutCubic; duration: 200 }
}
}
- ItemDelegate {
- id: buttonDelegate
- anchors.fill: parent
-
- onClicked: {
- if(page && stackView.currentItem !== page) {
- if(stackView.depth === 1) {
- stackView.replace(page)
- } else {
- stackView.clear()
- stackView.push(page)
- }
+ onClicked: {
+ if(page && stackView.currentItem !== page) {
+ if(stackView.depth === 1) {
+ stackView.replace(page)
+ } else {
+ stackView.clear()
+ stackView.push(page)
}
- sideNavButton.clicked()
}
}
}
diff --git a/qml/component/StateBubble.qml b/qml/component/StateBubble.qml
deleted file mode 100644
index 693c6770c..000000000
--- a/qml/component/StateBubble.qml
+++ /dev/null
@@ -1,12 +0,0 @@
-import QtQuick 2.9
-import QtQuick.Controls 2.2
-import QtQuick.Controls.Material 2.2
-
-TextDelegate {
- maximumWidth: messageListView.width
- highlighted: eventType === "emote"
- timeLabelVisible: false
- authorLabelVisible: false
-
- displayText: "" + author.displayName + " " + display
-}
diff --git a/qml/component/StateDelegate.qml b/qml/component/StateDelegate.qml
new file mode 100644
index 000000000..376763fed
--- /dev/null
+++ b/qml/component/StateDelegate.qml
@@ -0,0 +1,23 @@
+import QtQuick 2.9
+import QtQuick.Controls 2.2
+import QtQuick.Layouts 1.3
+import QtQuick.Controls.Material 2.2
+import Matrique.Settings 0.1
+
+Label {
+ Layout.alignment: Qt.AlignHCenter
+
+ text: "" + author.displayName + " " + display
+ color: "white"
+
+ padding: 8
+
+ wrapMode: Label.Wrap
+ linkColor: "white"
+ textFormat: MSettings.richText ? Text.RichText : Text.StyledText
+ onLinkActivated: Qt.openUrlExternally(link)
+
+ background: Rectangle {
+ color: MSettings.darkTheme ? "#484848" : "grey"
+ }
+}
diff --git a/qml/component/TextDelegate.qml b/qml/component/TextDelegate.qml
deleted file mode 100644
index f0077324b..000000000
--- a/qml/component/TextDelegate.qml
+++ /dev/null
@@ -1,61 +0,0 @@
-import QtQuick 2.9
-import QtQuick.Controls 2.2
-import QtQuick.Controls.Material 2.2
-import QtQuick.Layouts 1.3
-import Matrique.Settings 0.1
-
-Rectangle {
- property bool flat: false
- property bool highlighted: false
- property string displayText: ""
- property alias timeLabelVisible: timeText.visible
- property alias authorLabelVisible: authorText.visible
-
- property int maximumWidth
-
- readonly property bool darkBackground: highlighted && !flat
-
- id: messageRect
-
- width: Math.min(Math.max(messageText.implicitWidth, (timeText.visible ? timeText.implicitWidth : 0), (authorLabelVisible ? authorText.implicitWidth : 0)) + 24, maximumWidth)
- height: (authorText.visible ? authorText.implicitHeight : 0) + messageText.implicitHeight + (timeText.visible ? timeText.implicitHeight : 0) + 24
-
- color: flat ? "transparent" : highlighted ? Material.accent : background
- border.color: Material.accent
- border.width: flat ? 2 : 0
-
- ColumnLayout {
- id: messageColumn
-
- anchors.fill: parent
- anchors.margins: 12
- spacing: 0
-
- Label {
- id: authorText
- text: author.displayName
- color: darkBackground ? "white" : Material.accent
- font.bold: true
- }
-
- Label {
- id: messageText
- Layout.maximumWidth: parent.width
- text: displayText
- color: darkBackground ? "white": Material.foreground
-
- wrapMode: Label.Wrap
- linkColor: darkBackground ? "white" : Material.accent
- textFormat: MSettings.richText ? Text.RichText : Text.StyledText
- onLinkActivated: Qt.openUrlExternally(link)
- }
-
- Label {
- id: timeText
- Layout.alignment: Qt.AlignRight
- text: Qt.formatTime(time, "hh:mm")
- color: darkBackground ? "white" : "grey"
- font.pointSize: 8
- }
- }
-}
diff --git a/qml/form/RoomForm.qml b/qml/form/RoomForm.qml
index 6e9335331..4ec648d22 100644
--- a/qml/form/RoomForm.qml
+++ b/qml/form/RoomForm.qml
@@ -22,11 +22,11 @@ Item {
}
Drawer {
- id: roomDrawer
-
width: Math.min(item.width * 0.7, 480)
height: item.height
+ id: roomDrawer
+
edge: Qt.RightEdge
interactive: false
@@ -39,7 +39,6 @@ Item {
ColumnLayout {
anchors.fill: parent
anchors.margins: 32
- spacing: 16
ImageStatus {
Layout.preferredWidth: 64
@@ -52,12 +51,14 @@ Item {
Label {
Layout.fillWidth: true
+
horizontalAlignment: Text.AlignHCenter
text: currentRoom && currentRoom.id ? currentRoom.id : ""
}
Label {
Layout.fillWidth: true
+
horizontalAlignment: Text.AlignHCenter
text: currentRoom && currentRoom.canonicalAlias ? currentRoom.canonicalAlias : "No Canonical Alias"
}
@@ -66,8 +67,9 @@ Item {
Layout.fillWidth: true
TextField {
- id: roomNameField
Layout.fillWidth: true
+
+ id: roomNameField
text: currentRoom && currentRoom.name ? currentRoom.name : ""
}
@@ -85,9 +87,10 @@ Item {
Layout.fillWidth: true
TextField {
+ Layout.fillWidth: true
+
id: roomTopicField
- Layout.fillWidth: true
text: currentRoom && currentRoom.topic ? currentRoom.topic : ""
}
@@ -116,7 +119,7 @@ Item {
RowLayout {
anchors.fill: parent
anchors.margins: 8
- spacing: 16
+ spacing: 12
ImageStatus {
Layout.preferredWidth: height
@@ -159,9 +162,9 @@ Item {
Rectangle {
Layout.fillWidth: true
- Layout.preferredHeight: 80
+ Layout.preferredHeight: 64
- color: MSettings.darkTheme ? "#242424" : "#eaeaea"
+ color: Material.accent
ItemDelegate {
anchors.fill: parent
@@ -170,13 +173,14 @@ Item {
RowLayout {
anchors.fill: parent
- anchors.margins: 16
+ anchors.margins: 12
- spacing: 16
+ spacing: 12
ImageStatus {
Layout.preferredWidth: height
Layout.fillHeight: true
+
source: currentRoom && currentRoom.avatarUrl != "" ? "image://mxc/" + currentRoom.avatarUrl : null
displayText: currentRoom ? currentRoom.displayName : ""
}
@@ -186,14 +190,15 @@ Item {
Layout.fillHeight: true
Layout.alignment: Qt.AlignHCenter
- visible: parent.width > 80
+ visible: parent.width > 64
Label {
Layout.fillWidth: true
Layout.fillHeight: true
text: currentRoom ? currentRoom.displayName : ""
- font.pointSize: 16
+ color: "white"
+ font.pointSize: 12
elide: Text.ElideRight
wrapMode: Text.NoWrap
}
@@ -203,6 +208,7 @@ Item {
Layout.fillHeight: true
text: currentRoom ? currentRoom.topic : ""
+ color: "white"
elide: Text.ElideRight
wrapMode: Text.NoWrap
}
@@ -221,80 +227,79 @@ Item {
spacing: 0
ListView {
- id: messageListView
-
Layout.fillWidth: true
Layout.fillHeight: true
+
+ id: messageListView
+
+ clip: true
displayMarginBeginning: 40
displayMarginEnd: 40
verticalLayoutDirection: ListView.BottomToTop
spacing: 8
boundsBehavior: Flickable.DragOverBounds
+ maximumFlickVelocity: 2048
model: MessageEventModel {
id: messageEventModel
room: currentRoom
}
- delegate: Column {
+ delegate: ColumnLayout {
readonly property bool hidden: marks === EventStatus.Redacted || marks === EventStatus.Hidden
width: parent.width
height: hidden ? -8 : undefined
+
+ id: delegateColumn
+
+ clip: true
spacing: 8
- RowLayout {
- width: parent.width * 0.8
+ Label {
+ Layout.alignment: Qt.AlignHCenter
+
visible: section !== aboveSection && !hidden
- anchors.horizontalCenter: parent.horizontalCenter
- spacing: 8
- Rectangle {
- Layout.fillWidth: true
- height:2
- color: Material.accent
- }
+ text: section
+ color: "white"
+ verticalAlignment: Text.AlignVCenter
+ leftPadding: 8
+ rightPadding: 8
+ topPadding: 4
+ bottomPadding: 4
- Label {
- text: section
- color: Material.accent
- verticalAlignment: Text.AlignVCenter
- }
-
- Rectangle {
- Layout.fillWidth: true
- height:2
- color: Material.accent
+ background: Rectangle {
+ color: MSettings.darkTheme ? "#484848" : "grey"
}
}
- RowLayout {
- width: parent.width * 0.8
+ Label {
+ Layout.alignment: Qt.AlignHCenter
+
visible: readMarker === true && index !== 0
- anchors.horizontalCenter: parent.horizontalCenter
- spacing: 8
- Rectangle {
- Layout.fillWidth: true
- height:2
- color: Material.accent
- }
+ text: "And Now"
+ color: "white"
+ verticalAlignment: Text.AlignVCenter
+ leftPadding: 8
+ rightPadding: 8
+ topPadding: 4
+ bottomPadding: 4
- Label {
- text: "And Now"
- color: Material.accent
- verticalAlignment: Text.AlignVCenter
- }
-
- Rectangle {
- Layout.fillWidth: true
- height:2
- color: Material.accent
- }
+ background: Rectangle { color: MSettings.darkTheme ? "#484848" : "grey" }
}
- MessageDelegate {}
+ MessageDelegate {
+ visible: eventType === "notice" || eventType === "message" || eventType === "image" || eventType === "video" || eventType === "audio" || eventType === "file"
+ }
+
+ StateDelegate {
+ Layout.maximumWidth: messageListView.width * 0.8
+
+ visible: eventType === "emote" || eventType === "state"
+ }
}
ScrollBar.vertical: messageListViewScrollBar
@@ -303,9 +308,11 @@ Item {
onAtYEndChanged: atYEnd && currentRoom ? currentRoom.markAllMessagesAsRead() : {}
RoundButton {
- id: goTopFab
- width: height
+ width: 64
height: 64
+
+ id: goTopFab
+
visible: !parent.atYEnd
anchors.right: parent.right
@@ -313,12 +320,12 @@ Item {
contentItem: MaterialIcon {
anchors.fill: parent
+
icon: "\ue313"
color: "white"
}
- opacity: pressed ? 1 : hovered ? 0.7 : 0.4
- Material.background: Qt.lighter(Material.accent)
+ Material.background: Material.accent
onClicked: parent.positionViewAtBeginning()
@@ -327,159 +334,158 @@ Item {
}
ScrollBar {
- id: messageListViewScrollBar
-
Layout.preferredWidth: 16
Layout.fillHeight: true
+
+ id: messageListViewScrollBar
}
}
- Pane {
- padding: 16
-
+ RowLayout {
Layout.fillWidth: true
- Layout.preferredHeight: 80
+ Layout.preferredHeight: 48
+ Layout.margins: 16
- Timer {
- id: timeoutTimer
+ spacing: 0
- repeat: false
- interval: 2000
- onTriggered: {
- repeatTimer.stop()
- currentRoom.sendTypingNotification(false)
+ ItemDelegate {
+ Layout.preferredWidth: 48
+ Layout.preferredHeight: 48
+
+ contentItem: MaterialIcon { icon: "\ue226" }
+
+ onClicked: currentRoom.chooseAndUploadFile()
+ }
+
+ TextField {
+ property real progress: 0
+
+ Layout.fillWidth: true
+ Layout.preferredHeight: 48
+
+ id: inputField
+
+ placeholderText: "Send a Message"
+ leftPadding: 16
+ topPadding: 0
+ bottomPadding: 0
+ selectByMouse: true
+
+ text: currentRoom ? currentRoom.cachedInput : ""
+
+ onTextChanged: {
+ timeoutTimer.restart()
+ repeatTimer.start()
+ currentRoom.cachedInput = text
+ }
+
+ Keys.onReturnPressed: {
+ if (inputField.text) {
+ inputField.postMessage(inputField.text)
+ inputField.text = ""
+ }
+ }
+
+ background: Rectangle {
+ color: MSettings.darkTheme ? "#282828" : "#eaeaea"
+ }
+
+ ToolTip.visible: currentRoom && currentRoom.hasUsersTyping
+ ToolTip.text: currentRoom ? currentRoom.usersTyping : ""
+
+ Timer {
+ id: timeoutTimer
+
+ repeat: false
+ interval: 2000
+ onTriggered: {
+ repeatTimer.stop()
+ currentRoom.sendTypingNotification(false)
+ }
+ }
+
+ Timer {
+ id: repeatTimer
+
+ repeat: true
+ interval: 5000
+ triggeredOnStart: true
+ onTriggered: currentRoom.sendTypingNotification(true)
+ }
+
+ function postMessage(text) {
+ if (text.trim().length === 0) { return }
+ if(!currentRoom) { return }
+
+ var PREFIX_ME = '/me '
+ var PREFIX_NOTICE = '/notice '
+ var PREFIX_RAINBOW = '/rainbow '
+ var PREFIX_HTML = '/html '
+ var PREFIX_MARKDOWN = '/md '
+
+ if (text.indexOf(PREFIX_ME) === 0) {
+ text = text.substr(PREFIX_ME.length)
+ currentRoom.postMessage(text, RoomMessageEvent.Emote)
+ return
+ }
+ if (text.indexOf(PREFIX_NOTICE) === 0) {
+ text = text.substr(PREFIX_NOTICE.length)
+ currentRoom.postMessage(text, RoomMessageEvent.Notice)
+ return
+ }
+ if (text.indexOf(PREFIX_RAINBOW) === 0) {
+ text = text.substr(PREFIX_RAINBOW.length)
+
+ var parsedText = ""
+ var rainbowColor = ["#ff2b00", "#ff5500", "#ff8000", "#ffaa00", "#ffd500", "#ffff00", "#d4ff00", "#aaff00", "#80ff00", "#55ff00", "#2bff00", "#00ff00", "#00ff2b", "#00ff55", "#00ff80", "#00ffaa", "#00ffd5", "#00ffff", "#00d4ff", "#00aaff", "#007fff", "#0055ff", "#002bff", "#0000ff", "#2a00ff", "#5500ff", "#7f00ff", "#aa00ff", "#d400ff", "#ff00ff", "#ff00d4", "#ff00aa", "#ff0080", "#ff0055", "#ff002b", "#ff0000"]
+ for (var i = 0; i < text.length; i++) {
+ parsedText = parsedText + "" + text.charAt(i) + ""
+ }
+ currentRoom.postHtmlMessage(text, parsedText, RoomMessageEvent.Text)
+ return
+ }
+ if (text.indexOf(PREFIX_HTML) === 0) {
+ text = text.substr(PREFIX_HTML.length)
+ var re = new RegExp("<.*?>")
+ var plainText = text.replace(re, "")
+ currentRoom.postHtmlMessage(plainText, text, RoomMessageEvent.Text)
+ return
+ }
+ if (text.indexOf(PREFIX_MARKDOWN) === 0) {
+ text = text.substr(PREFIX_MARKDOWN.length)
+ var parsedText = Markdown.markdown_parser(text)
+ currentRoom.postHtmlMessage(text, parsedText, RoomMessageEvent.Text)
+ return
+ }
+
+ currentRoom.postPlainText(text)
}
}
- Timer {
- id: repeatTimer
+ ItemDelegate {
+ Layout.preferredWidth: 48
+ Layout.preferredHeight: 48
- repeat: true
- interval: 5000
- triggeredOnStart: true
- onTriggered: currentRoom.sendTypingNotification(true)
- }
+ id: emojiButton
- RowLayout {
- anchors.fill: parent
- spacing: 0
+ contentItem: MaterialIcon { icon: "\ue24e" }
- ItemDelegate {
- Layout.preferredWidth: height
- Layout.fillHeight: true
+ background: Rectangle { color: MSettings.darkTheme ? "#282828" : "#eaeaea" }
- contentItem: MaterialIcon { icon: "\ue226" }
+ onClicked: emojiPicker.visible ? emojiPicker.close() : emojiPicker.open()
- onClicked: currentRoom.chooseAndUploadFile()
- }
+ EmojiPicker {
+ x: window.width - 370
+ y: window.height - 440
- TextField {
- property real progress: 0
+ width: 360
+ height: 360
- id: inputField
- Layout.fillWidth: true
- Layout.fillHeight: true
- placeholderText: "Send a Message"
- leftPadding: 16
- topPadding: 0
- bottomPadding: 0
- selectByMouse: true
+ id: emojiPicker
- text: currentRoom ? currentRoom.cachedInput : ""
- onTextChanged: {
- timeoutTimer.restart()
- repeatTimer.start()
- currentRoom.cachedInput = text
- }
+ parent: ApplicationWindow.overlay
- Keys.onReturnPressed: {
- if (inputField.text) {
- inputField.postMessage(inputField.text)
- inputField.text = ""
- }
- }
-
- background: Rectangle {
- color: MSettings.darkTheme ? "#242424" : "#eaeaea"
- }
-
- ToolTip.visible: currentRoom && currentRoom.hasUsersTyping
- ToolTip.text: currentRoom ? currentRoom.usersTyping : ""
-
- function postMessage(text) {
- if (text.trim().length === 0) { return }
- if(!currentRoom) { return }
-
- var PREFIX_ME = '/me '
- var PREFIX_NOTICE = '/notice '
- var PREFIX_RAINBOW = '/rainbow '
- var PREFIX_HTML = '/html '
- var PREFIX_MARKDOWN = '/md '
-
- if (text.indexOf(PREFIX_ME) === 0) {
- text = text.substr(PREFIX_ME.length)
- currentRoom.postMessage(text, RoomMessageEvent.Emote)
- return
- }
- if (text.indexOf(PREFIX_NOTICE) === 0) {
- text = text.substr(PREFIX_NOTICE.length)
- currentRoom.postMessage(text, RoomMessageEvent.Notice)
- return
- }
- if (text.indexOf(PREFIX_RAINBOW) === 0) {
- text = text.substr(PREFIX_RAINBOW.length)
-
- var parsedText = ""
- var rainbowColor = ["#ff2b00", "#ff5500", "#ff8000", "#ffaa00", "#ffd500", "#ffff00", "#d4ff00", "#aaff00", "#80ff00", "#55ff00", "#2bff00", "#00ff00", "#00ff2b", "#00ff55", "#00ff80", "#00ffaa", "#00ffd5", "#00ffff", "#00d4ff", "#00aaff", "#007fff", "#0055ff", "#002bff", "#0000ff", "#2a00ff", "#5500ff", "#7f00ff", "#aa00ff", "#d400ff", "#ff00ff", "#ff00d4", "#ff00aa", "#ff0080", "#ff0055", "#ff002b", "#ff0000"]
- for (var i = 0; i < text.length; i++) {
- parsedText = parsedText + "" + text.charAt(i) + ""
- }
- currentRoom.postHtmlMessage(text, parsedText, RoomMessageEvent.Text)
- return
- }
- if (text.indexOf(PREFIX_HTML) === 0) {
- text = text.substr(PREFIX_HTML.length)
- var re = new RegExp("<.*?>")
- var plainText = text.replace(re, "")
- currentRoom.postHtmlMessage(plainText, text, RoomMessageEvent.Text)
- return
- }
- if (text.indexOf(PREFIX_MARKDOWN) === 0) {
- text = text.substr(PREFIX_MARKDOWN.length)
- var parsedText = Markdown.markdown_parser(text)
- currentRoom.postHtmlMessage(text, parsedText, RoomMessageEvent.Text)
- return
- }
-
- currentRoom.postPlainText(text)
- }
- }
-
- ItemDelegate {
- id: emojiButton
-
- Layout.preferredWidth: height
- Layout.fillHeight: true
-
- contentItem: MaterialIcon { icon: "\ue24e" }
-
- background: Rectangle { color: MSettings.darkTheme ? "#242424" : "#eaeaea" }
-
- onClicked: emojiPicker.visible ? emojiPicker.close() : emojiPicker.open()
-
- EmojiPicker {
- id: emojiPicker
-
- parent: ApplicationWindow.overlay
-
- x: window.width - 370
- y: window.height - 440
-
- width: 360
- height: 360
-
- textArea: inputField
- }
+ textArea: inputField
}
}
}
diff --git a/qml/form/RoomListForm.qml b/qml/form/RoomListForm.qml
index bab3097ab..8448898ea 100644
--- a/qml/form/RoomListForm.qml
+++ b/qml/form/RoomListForm.qml
@@ -14,215 +14,201 @@ Item {
property alias listModel: roomListProxyModel.sourceModel
property var enteredRoom: null
+ Label {
+ z: 10
+
+ text: MSettings.miniMode ? "Empty" : "Here? No, not here."
+ anchors.centerIn: parent
+ visible: listView.count === 0
+ }
+
ColumnLayout {
anchors.fill: parent
spacing: 0
- Rectangle {
- z: 10
+ TextField {
Layout.fillWidth: true
- Layout.preferredHeight: 80
- color: Qt.tint(Material.accent, "#20FFFFFF")
+ Layout.preferredHeight: 40
+ Layout.margins: 12
- TextField {
- id: searchField
- width: parent.width - 18
- height: 36
- color: "white"
- leftPadding: MSettings.miniMode ? 4 : 32
- topPadding: 0
- bottomPadding: 0
- anchors.centerIn: parent
+ id: searchField
- background: Row {
- visible: !parent.text
+ leftPadding: MSettings.miniMode ? 4 : 32
+ topPadding: 0
+ bottomPadding: 0
+ placeholderText: "Search..."
- MaterialIcon {
- icon: "\ue8b6"
- color: "white"
+ background: Rectangle { color: MSettings.darkTheme ? "#282828" : "#fafafa" }
- width: MSettings.miniMode ? parent.width : parent.height
- height: parent.height
- }
-
- Label {
- height: parent.height
- visible: !MSettings.miniMode
- text: "Search"
- color: "white"
- font.pointSize: 12
- horizontalAlignment: Text.AlignHCenter
- verticalAlignment: Text.AlignVCenter
- }
- }
-
- Shortcut {
- sequence: StandardKey.Find
- onActivated: searchField.forceActiveFocus()
- }
+ Shortcut {
+ sequence: StandardKey.Find
+ onActivated: searchField.forceActiveFocus()
}
}
- Rectangle {
+ SortFilterProxyModel {
+ id: roomListProxyModel
+
+ filters: RegExpFilter {
+ roleName: "name"
+ pattern: searchField.text
+ caseSensitivity: Qt.CaseInsensitive
+ }
+ proxyRoles: ExpressionRole {
+ name: "display"
+ expression: {
+ switch (category) {
+ case 1: return "Invited"
+ case 2: return "Favorites"
+ case 3: return "Rooms"
+ case 4: return "People"
+ case 5: return "Low Priorities"
+ }
+ }
+ }
+
+ sorters: [
+ RoleSorter { roleName: "category" },
+ RoleSorter {
+ enabled: MSettings.rearrangeByActivity
+ roleName: "unreadCount"
+ sortOrder: Qt.DescendingOrder
+ },
+ StringSorter { roleName: "name" }
+ ]
+ }
+
+ ListView {
Layout.fillWidth: true
Layout.fillHeight: true
- color: MSettings.darkTheme ? "#242424" : "#eaeaea"
+ id: listView
- Label {
- z: 10
- text: MSettings.miniMode ? "Empty" : "Here? No, not here."
- anchors.centerIn: parent
- visible: listView.count === 0
- }
+ spacing: 1
+ clip: true
- SortFilterProxyModel {
- id: roomListProxyModel
- filters: RegExpFilter {
- roleName: "name"
- pattern: searchField.text
- caseSensitivity: Qt.CaseInsensitive
- }
- proxyRoles: ExpressionRole {
- name: "display"
- expression: {
- switch (category) {
- case 1: return "Invited"
- case 2: return "Favorites"
- case 3: return "Rooms"
- case 4: return "People"
- case 5: return "Low Priorities"
- }
- }
+ model: roomListProxyModel
+
+ currentIndex: -1
+
+ highlightFollowsCurrentItem: true
+
+ highlightMoveDuration: 200
+ highlightResizeDuration: 0
+
+ boundsBehavior: Flickable.DragOverBounds
+
+ ScrollBar.vertical: ScrollBar {}
+
+ delegate: Rectangle {
+ readonly property bool highlighted: currentRoom === enteredRoom
+
+ width: parent.width
+ height: 64
+
+ color: MSettings.darkTheme ? "#282828" : "#fafafa"
+
+ AutoMouseArea {
+ anchors.fill: parent
+
+ hoverEnabled: MSettings.miniMode
+
+ onSecondaryClicked: Qt.createComponent("qrc:/qml/menu/RoomContextMenu.qml").createObject(this)
+ onPrimaryClicked: category === RoomType.Invited ? inviteDialog.open() : enteredRoom = currentRoom
+
+ ToolTip.visible: MSettings.miniMode && containsMouse
+ ToolTip.text: name
}
- sorters: [
- RoleSorter { roleName: "category" },
- RoleSorter {
- enabled: MSettings.rearrangeByActivity
- roleName: "unreadCount"
- sortOrder: Qt.DescendingOrder
- },
- StringSorter { roleName: "name" }
- ]
- }
+ Rectangle {
+ anchors.fill: parent
- ListView {
- id: listView
- anchors.fill: parent
+ visible: highlighted
+ color: Material.accent
+ opacity: 0.1
+ }
- model: roomListProxyModel
+ Rectangle {
+ width: 4
+ height: parent.height
- currentIndex: -1
+ color: Material.accent
+ visible: unreadCount > 0 || highlighted
+ }
- boundsBehavior: Flickable.DragOverBounds
+ RowLayout {
+ anchors.fill: parent
+ anchors.margins: 12
- ScrollBar.vertical: ScrollBar { id: scrollBar }
+ spacing: 12
- delegate: Rectangle {
- readonly property bool highlighted: currentRoom === enteredRoom
+ ImageStatus {
+ Layout.preferredWidth: height
+ Layout.fillHeight: true
- id: swipeDelegate
- width: parent.width
- height: 80
-
- color: highlighted ? Material.background : "transparent"
-
- AutoMouseArea {
- anchors.fill: parent
-
- hoverEnabled: MSettings.miniMode
-
- onSecondaryClicked: Qt.createComponent("qrc:/qml/menu/RoomContextMenu.qml").createObject(this)
- onPrimaryClicked: category === RoomType.Invited ? inviteDialog.open() : enteredRoom = currentRoom
-
- ToolTip.visible: MSettings.miniMode && containsMouse
- ToolTip.text: name
+ source: avatar ? "image://mxc/" + avatar : ""
+ displayText: name
}
- Rectangle {
- width: 4
- height: parent.height
- color: Qt.tint(Material.accent, "#20FFFFFF")
- visible: unreadCount > 0 || highlighted
- }
+ ColumnLayout {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ Layout.alignment: Qt.AlignHCenter
- RowLayout {
- anchors.fill: parent
- anchors.margins: 16
- spacing: 16
+ visible: parent.width > 64
- ImageStatus {
- Layout.preferredWidth: height
- Layout.fillHeight: true
-
- source: avatar ? "image://mxc/" + avatar : ""
- displayText: name
- }
-
- ColumnLayout {
+ Label {
Layout.fillWidth: true
Layout.fillHeight: true
- Layout.alignment: Qt.AlignHCenter
- visible: parent.width > 80
+ text: name || "No Name"
+ font.pointSize: 12
+ elide: Text.ElideRight
+ wrapMode: Text.NoWrap
+ }
- Label {
- Layout.fillWidth: true
- Layout.fillHeight: true
+ Label {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
- text: name || "No Name"
- font.pointSize: 16
- elide: Text.ElideRight
- wrapMode: Text.NoWrap
- }
-
- Label {
- Layout.fillWidth: true
- Layout.fillHeight: true
-
- text: lastEvent || topic
- elide: Text.ElideRight
- wrapMode: Text.NoWrap
- }
+ text: (lastEvent == "" ? topic : lastEvent).replace(/(\r\n\t|\n|\r\t)/gm,"");
+ elide: Text.ElideRight
+ wrapMode: Text.NoWrap
}
}
}
+ }
- section.property: "display"
- section.criteria: ViewSection.FullString
- section.delegate: Label {
- width: parent.width
- height: 24
- text: section
- color: "grey"
- leftPadding: MSettings.miniMode ? undefined : 16
- elide: Text.ElideRight
- verticalAlignment: Text.AlignVCenter
- horizontalAlignment: MSettings.miniMode ? Text.AlignHCenter : undefined
- background: Rectangle {
- anchors.fill: parent
- color: MSettings.darkTheme ? "#363636" : "#dbdbdb"
- }
- }
+ section.property: "display"
+ section.criteria: ViewSection.FullString
+ section.delegate: Label {
+ width: parent.width
+ height: 24
- Dialog {
- id: inviteDialog
- parent: ApplicationWindow.overlay
+ text: section
+ color: "grey"
+ leftPadding: MSettings.miniMode ? undefined : 16
+ elide: Text.ElideRight
+ verticalAlignment: Text.AlignVCenter
+ horizontalAlignment: MSettings.miniMode ? Text.AlignHCenter : undefined
+ }
- x: (window.width - width) / 2
- y: (window.height - height) / 2
- width: 360
+ Dialog {
+ id: inviteDialog
+ parent: ApplicationWindow.overlay
- title: "Action Required"
- modal: true
- standardButtons: Dialog.Ok | Dialog.Cancel
+ x: (window.width - width) / 2
+ y: (window.height - height) / 2
+ width: 360
- contentItem: Label { text: "Accept this invitation?" }
+ title: "Action Required"
+ modal: true
+ standardButtons: Dialog.Ok | Dialog.Cancel
- onAccepted: currentRoom.acceptInvitation()
- onRejected: currentRoom.forget()
- }
+ contentItem: Label { text: "Accept this invitation?" }
+
+ onAccepted: currentRoom.acceptInvitation()
+ onRejected: currentRoom.forget()
}
}
}
diff --git a/qml/main.qml b/qml/main.qml
index 83d917d98..a0a3d0a2c 100644
--- a/qml/main.qml
+++ b/qml/main.qml
@@ -13,12 +13,14 @@ import "form"
ApplicationWindow {
readonly property var connection: matriqueController.connection
- id: window
- visible: true
width: 960
height: 640
minimumWidth: 800
minimumHeight: 480
+
+ id: window
+
+ visible: true
title: qsTr("Matrique")
Material.theme: MSettings.darkTheme ? Material.Dark : Material.Light
@@ -40,10 +42,11 @@ ApplicationWindow {
Popup {
property bool busy: matriqueController.busy
- id: busyPopup
-
x: (window.width - width) / 2
y: (window.height - height) / 2
+
+ id: busyPopup
+
modal: true
focus: true
@@ -65,7 +68,7 @@ ApplicationWindow {
parent: null
- connection: matriqueController.isLogin ? window.connection : null
+ connection: window.connection
}
Setting {
@@ -81,20 +84,24 @@ ApplicationWindow {
spacing: 0
Rectangle {
- id: sideNav
- Layout.preferredWidth: 80
+ Layout.preferredWidth: 64
Layout.fillHeight: true
- color: Material.accent
+
+ id: sideNav
+
+ color: Material.primary
ColumnLayout {
anchors.fill: parent
spacing: 0
SideNavButton {
- id: statusNavButton
- contentItem: ImageStatus {
+ Layout.fillWidth: true
+ Layout.preferredHeight: width
+
+ ImageStatus {
anchors.fill: parent
- anchors.margins: 15
+ anchors.margins: 12
source: matriqueController.isLogin ? connection.localUser && connection.localUser.avatarUrl ? "image://mxc/" + connection.localUser.avatarUrl : "" : "qrc:/asset/img/avatar.png"
displayText: matriqueController.isLogin && connection.localUser.displayName ? connection.localUser.displayName : ""
@@ -104,16 +111,27 @@ ApplicationWindow {
}
Rectangle {
- color: "transparent"
Layout.fillHeight: true
+
+ color: "transparent"
}
SideNavButton {
- contentItem: MaterialIcon { icon: "\ue145"; color: "white" }
+ Layout.fillWidth: true
+ Layout.preferredHeight: width
+
+ MaterialIcon {
+ anchors.fill: parent
+
+ icon: "\ue145"
+ color: "white"
+ }
+
onClicked: addRoomMenu.popup()
Menu {
id: addRoomMenu
+
MenuItem {
text:"New Room"
onTriggered: addRoomDialog.open()
@@ -132,14 +150,17 @@ ApplicationWindow {
contentItem: Column {
TextField {
- id: addRoomDialogNameTextField
width: parent.width
+ id: addRoomDialogNameTextField
+
placeholderText: "Name"
}
TextField {
- id: addRoomDialogTopicTextField
width: parent.width
+
+ id: addRoomDialogTopicTextField
+
placeholderText: "Topic"
}
}
@@ -149,16 +170,18 @@ ApplicationWindow {
}
MenuItem {
text: "Join Room"
+
onTriggered: joinRoomDialog.open()
Dialog {
- id: joinRoomDialog
- parent: ApplicationWindow.overlay
-
x: (window.width - width) / 2
y: (window.height - height) / 2
width: 360
+ id: joinRoomDialog
+
+ parent: ApplicationWindow.overlay
+
title: "Input Room Alias or ID"
modal: true
standardButtons: Dialog.Ok | Dialog.Cancel
@@ -171,18 +194,21 @@ ApplicationWindow {
onAccepted: matriqueController.joinRoom(joinRoomDialogTextField.text)
}
}
+
MenuItem {
text: "Direct Chat"
+
onTriggered: directChatDialog.open()
Dialog {
- id: directChatDialog
- parent: ApplicationWindow.overlay
-
x: (window.width - width) / 2
y: (window.height - height) / 2
width: 360
+ id: directChatDialog
+
+ parent: ApplicationWindow.overlay
+
title: "Input User ID"
modal: true
standardButtons: Dialog.Ok | Dialog.Cancel
@@ -199,23 +225,41 @@ ApplicationWindow {
}
SideNavButton {
- contentItem: MaterialIcon { icon: "\ue8b8"; color: "white" }
+ Layout.fillWidth: true
+ Layout.preferredHeight: width
+
+ MaterialIcon {
+ anchors.fill: parent
+
+ icon: "\ue8b8"
+ color: parent.highlighted ? Material.accent : "white"
+ }
page: settingPage
}
SideNavButton {
- contentItem: MaterialIcon { icon: "\ue879"; color: "white" }
+ Layout.fillWidth: true
+ Layout.preferredHeight: width
+
+ MaterialIcon {
+ anchors.fill: parent
+
+ icon: "\ue879"
+ color: "white"
+ }
+
onClicked: Qt.quit()
}
}
}
StackView {
- id: stackView
- initialItem: roomPage
-
Layout.fillWidth: true
Layout.fillHeight: true
+
+ id: stackView
+
+ initialItem: roomPage
}
}
diff --git a/qml/menu/MessageContextMenu.qml b/qml/menu/MessageContextMenu.qml
index dd2b92de2..1fbfa1194 100644
--- a/qml/menu/MessageContextMenu.qml
+++ b/qml/menu/MessageContextMenu.qml
@@ -8,28 +8,33 @@ Menu {
MenuItem {
text: "Copy"
+
onTriggered: matriqueController.copyToClipboard(plainText)
}
MenuItem {
text: "Copy Source"
+
onTriggered: matriqueController.copyToClipboard(toolTip)
}
MenuItem {
visible: isFile
height: visible ? undefined : 0
text: "Open Externally"
- onTriggered: delegateLoader.item.downloadAndOpen()
+
+ onTriggered: messageRow.openExternally()
}
MenuItem {
visible: isFile
height: visible ? undefined : 0
text: "Save As"
- onTriggered: delegateLoader.item.saveFileAs()
+
+ onTriggered: messageRow.saveFileAs()
}
MenuItem {
visible: sentByMe
height: visible ? undefined : 0
text: "Redact"
+
onTriggered: currentRoom.redactEvent(eventId)
}
diff --git a/qml/menu/RoomContextMenu.qml b/qml/menu/RoomContextMenu.qml
index 280947b28..9aff67fab 100644
--- a/qml/menu/RoomContextMenu.qml
+++ b/qml/menu/RoomContextMenu.qml
@@ -8,21 +8,25 @@ Menu {
text: "Favourite"
checkable: true
checked: currentRoom && currentRoom.isFavourite
+
onTriggered: currentRoom.isFavourite ? currentRoom.removeTag("m.favourite") : currentRoom.addTag("m.favourite", "1")
}
MenuItem {
text: "Deprioritize"
checkable: true
checked: currentRoom && currentRoom.isLowPriority
+
onTriggered: currentRoom.isLowPriority ? currentRoom.removeTag("m.lowpriority") : currentRoom.addTag("m.lowpriority", "1")
}
MenuSeparator {}
MenuItem {
text: "Mark as Read"
+
onTriggered: currentRoom.markAllMessagesAsRead()
}
MenuItem {
text: "Leave Room"
+
onTriggered: currentRoom.forget()
}
diff --git a/qtquickcontrols2.conf b/qtquickcontrols2.conf
index fdec96c3a..0cc53197c 100644
--- a/qtquickcontrols2.conf
+++ b/qtquickcontrols2.conf
@@ -7,9 +7,7 @@ Style=Material
[Material]
Theme=Light
-Primary=#00695c
-Accent=#00695c
-;Primary=#1565c0
-;Accent=#1565c0
+Primary=#344955
+Accent=#498882
;Foreground=Black
;Background=#161616
diff --git a/res.qrc b/res.qrc
index e2c99a155..71c1cf500 100644
--- a/res.qrc
+++ b/res.qrc
@@ -14,16 +14,9 @@
asset/img/icon.png
js/md.js
qml/component/MessageDelegate.qml
- qml/component/MessageBubble.qml
- qml/component/ImageBubble.qml
- qml/component/StateBubble.qml
qml/component/DownloadableContent.qml
- qml/component/FileBubble.qml
- qml/component/AvatarContainer.qml
qml/form/RoomListForm.qml
- qml/component/AudioBubble.qml
qml/Setting.qml
- qml/component/TextDelegate.qml
qml/component/EmojiPicker.qml
qml/component/EmojiButton.qml
qml/component/AutoImage.qml
@@ -33,5 +26,8 @@
qml/MatriqueSettings.qml
qml/menu/MessageContextMenu.qml
qml/menu/RoomContextMenu.qml
+ qml/component/GenericBubble.qml
+ qml/component/StateDelegate.qml
+ qml/component/AutoLabel.qml
diff --git a/src/matriqueroom.cpp b/src/matriqueroom.cpp
index dcd79ae2d..faa36c836 100644
--- a/src/matriqueroom.cpp
+++ b/src/matriqueroom.cpp
@@ -83,6 +83,7 @@ void MatriqueRoom::sendTypingNotification(bool isTyping) {
QString MatriqueRoom::lastEvent() {
if (timelineSize() == 0) return "";
const RoomEvent* lastEvent = messageEvents().rbegin()->get();
+ if (lastEvent->contentJson().value("body").toString() == "") return "";
return user(lastEvent->senderId())->displayname() + ": " +
lastEvent->contentJson().value("body").toString();
}