Merge branch 'redesign' into 'master'

Redesign

See merge request b0/matrique!16
This commit is contained in:
Black Hat 2018-09-05 23:01:07 +00:00
commit ee6ac3035c
31 changed files with 758 additions and 752 deletions

View File

@ -1,7 +1,9 @@
QT += quick widgets multimedia QT += quick widgets multimedia
CONFIG += c++14 CONFIG += c++14
CONFIG += object_parallel_to_source CONFIG += object_parallel_to_source
CONFIG += qtquickcompiler
# Enable this to use QtQuick Compiler.
#CONFIG += qtquickcompiler
TARGET = matrique TARGET = matrique
@ -75,10 +77,9 @@ DISTFILES += \
ButtonDelegate.qml \ ButtonDelegate.qml \
SideNav.qml \ SideNav.qml \
RoomListForm.qml \ RoomListForm.qml \
RoomDetailForm.qml \
Room.qml \ Room.qml \
Setting.qml \ Setting.qml \
qml/js/md.js qml/js/md.js \
HEADERS += \ HEADERS += \
src/controller.h \ src/controller.h \

View File

@ -57,17 +57,19 @@ Page {
Pane { Pane {
width: parent.width / 2 width: parent.width / 2
height: parent.height height: parent.height
padding: 64 padding: 64
ColumnLayout { ColumnLayout {
id: mainCol
width: parent.width width: parent.width
TextField { id: mainCol
id: serverField
TextField {
Layout.fillWidth: true Layout.fillWidth: true
id: serverField
leftPadding: 16 leftPadding: 16
topPadding: 0 topPadding: 0
bottomPadding: 0 bottomPadding: 0
@ -85,10 +87,10 @@ Page {
} }
TextField { TextField {
id: usernameField
Layout.fillWidth: true Layout.fillWidth: true
id: usernameField
leftPadding: 16 leftPadding: 16
topPadding: 0 topPadding: 0
bottomPadding: 0 bottomPadding: 0
@ -105,10 +107,10 @@ Page {
} }
TextField { TextField {
id: passwordField
Layout.fillWidth: true Layout.fillWidth: true
id: passwordField
leftPadding: 16 leftPadding: 16
topPadding: 0 topPadding: 0
bottomPadding: 0 bottomPadding: 0
@ -126,10 +128,10 @@ Page {
} }
Button { Button {
id: loginButton
Layout.fillWidth: true Layout.fillWidth: true
id: loginButton
text: "LOGIN" text: "LOGIN"
highlighted: true highlighted: true

View File

@ -4,7 +4,6 @@ import Qt.labs.settings 1.0
Settings { Settings {
property bool lazyLoad: true property bool lazyLoad: true
property bool asyncMessageDelegate
property bool richText property bool richText
property bool pressAndHold property bool pressAndHold
property bool rearrangeByActivity property bool rearrangeByActivity

View File

@ -18,28 +18,42 @@ Page {
onNewMessage: if (!window.active) matriqueController.showMessage(roomName, content, icon) onNewMessage: if (!window.active) matriqueController.showMessage(roomName, content, icon)
} }
Rectangle {
anchors.fill: parent
color: MSettings.darkTheme ? "#323232" : "#f3f3f3"
RowLayout { RowLayout {
anchors.fill: parent anchors.fill: parent
spacing: 0 spacing: 0
RoomListForm { RoomListForm {
id: roomListForm
Layout.fillHeight: true Layout.fillHeight: true
Layout.preferredWidth: MSettings.miniMode ? 80 : page.width * 0.35 Layout.preferredWidth: MSettings.miniMode ? 64 : page.width * 0.35
Layout.minimumWidth: 80 Layout.minimumWidth: 64
Layout.maximumWidth: 360 Layout.maximumWidth: 360
id: roomListForm
listModel: roomListModel listModel: roomListModel
} }
RoomForm { Rectangle {
id: roomForm Layout.preferredWidth: 1
Layout.fillHeight: true
color: MSettings.darkTheme ? "#363636" : "#ececec"
}
RoomForm {
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
id: roomForm
currentRoom: roomListForm.enteredRoom currentRoom: roomListForm.enteredRoom
} }
} }
}
} }

View File

@ -58,57 +58,59 @@ Page {
Page { Page {
id: generalForm id: generalForm
parent: null parent: null
Column { Column {
Switch { Switch {
text: "Lazy load at initial sync" text: "Lazy load at initial sync"
checked: MSettings.lazyLoad checked: MSettings.lazyLoad
onCheckedChanged: MSettings.lazyLoad = checked onCheckedChanged: MSettings.lazyLoad = checked
} }
Switch {
text: "Force loading message delegates asynchronously"
checked: MSettings.asyncMessageDelegate
onCheckedChanged: MSettings.asyncMessageDelegate = checked
}
Switch { Switch {
text: "Use RichText instead of StyledText" text: "Use RichText instead of StyledText"
checked: MSettings.richText checked: MSettings.richText
onCheckedChanged: MSettings.richText = checked onCheckedChanged: MSettings.richText = checked
} }
Switch { Switch {
text: "Use press and hold instead of right click" text: "Use press and hold instead of right click"
checked: MSettings.pressAndHold checked: MSettings.pressAndHold
onCheckedChanged: MSettings.pressAndHold = checked
}
Switch {
text: "Rearrange rooms by activity"
checked: MSettings.rearrangeByActivity
onCheckedChanged: MSettings.rearrangeByActivity = checked
}
Button { onCheckedChanged: MSettings.pressAndHold = checked
text: "Invoke GC"
highlighted: true
onClicked: gc()
} }
} }
} }
Page { Page {
id: appearanceForm id: appearanceForm
parent: null parent: null
Column { Column {
Switch { Switch {
text: "Dark theme" text: "Dark theme"
checked: MSettings.darkTheme checked: MSettings.darkTheme
onCheckedChanged: MSettings.darkTheme = checked onCheckedChanged: MSettings.darkTheme = checked
} }
Switch { Switch {
text: "Mini Room List" text: "Mini Room List"
checked: MSettings.miniMode checked: MSettings.miniMode
onCheckedChanged: MSettings.miniMode = checked 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" source: "qrc:/asset/img/icon.png"
} }
Label { Label { text: "Matrique, an IM client for the Matrix protocol." }
text: "Matrique, an IM client for the Matrix protocol." Label { text: "Released under GNU General Public License, version 3." }
}
Label {
text: "Released under GNU General Public License, version 3."
}
} }
} }

View File

@ -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) : {}
}
}

View File

@ -6,22 +6,22 @@ Item {
property alias sourceSize: baseImage.sourceSize.width property alias sourceSize: baseImage.sourceSize.width
readonly property bool loading: baseImage.status == Image.Loading readonly property bool loading: baseImage.status == Image.Loading
signal clicked()
id: rekt signal clicked()
width: loading ? 128 : baseImage.implicitWidth width: loading ? 128 : baseImage.implicitWidth
height: loading ? progressBar.height : baseImage.implicitHeight height: loading ? progressBar.height : baseImage.implicitHeight
Image { id: rekt
id: baseImage
} Image { id: baseImage }
ProgressBar { ProgressBar {
id: progressBar
width: parent.width width: parent.width
visible: loading visible: loading
id: progressBar
indeterminate: true indeterminate: true
} }

View File

@ -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)
}

View File

@ -6,6 +6,7 @@ MouseArea {
signal secondaryClicked() signal secondaryClicked()
acceptedButtons: MSettings.pressAndHold ? Qt.LeftButton : (Qt.LeftButton | Qt.RightButton) acceptedButtons: MSettings.pressAndHold ? Qt.LeftButton : (Qt.LeftButton | Qt.RightButton)
onClicked: mouse.button == Qt.RightButton ? secondaryClicked() : primaryClicked() onClicked: mouse.button == Qt.RightButton ? secondaryClicked() : primaryClicked()
onPressAndHold: MSettings.pressAndHold ? secondaryClicked() : {} onPressAndHold: MSettings.pressAndHold ? secondaryClicked() : {}
} }

View File

@ -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
}
}

View File

@ -11,20 +11,18 @@ Item {
z: -2 z: -2
height: parent.height height: parent.height
width: progressInfo.active && !progressInfo.completed ? progressInfo.progress / progressInfo.total * parent.width : 0 width: progressInfo.active && !progressInfo.completed ? progressInfo.progress / progressInfo.total * parent.width : 0
color: Material.accent color: Material.accent
opacity: 0.4 opacity: 0.4
} }
onDownloadedChanged: downloaded && openOnFinished ? openSavedFile() : {} onDownloadedChanged: if (downloaded && openOnFinished) openSavedFile()
function saveFileAs() { function saveFileAs() { currentRoom.saveFileAs(eventId) }
currentRoom.saveFileAs(eventId)
}
function downloadAndOpen() function downloadAndOpen()
{ {
if (downloaded) if (downloaded) openSavedFile()
openSavedFile()
else else
{ {
openOnFinished = true openOnFinished = true
@ -34,10 +32,7 @@ Item {
function openSavedFile() function openSavedFile()
{ {
if (Qt.openUrlExternally(progressInfo.localPath)) if (Qt.openUrlExternally(progressInfo.localPath)) return;
return; if (Qt.openUrlExternally(progressInfo.localDir)) return;
if (Qt.openUrlExternally(progressInfo.localDir))
return;
} }
} }

View File

@ -52,6 +52,7 @@ Popup {
Rectangle { Rectangle {
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: 2 Layout.preferredHeight: 2
color: Material.accent color: Material.accent
} }

View File

@ -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: "<b>File: </b>" + content.body
}
}
}

View File

@ -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 }
}

View File

@ -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()
}
}
}
}

View File

@ -13,9 +13,11 @@ Item {
id: item id: item
Image { Image {
id: avatar
width: item.width width: item.width
height: item.width height: item.width
id: avatar
visible: showImage visible: showImage
source: item.source source: item.source
@ -40,6 +42,7 @@ Item {
Label { Label {
anchors.fill: parent anchors.fill: parent
color: "white" color: "white"
visible: showInitial visible: showInitial
text: showInitial ? getInitials(displayText)[0] : "" text: showInitial ? getInitials(displayText)[0] : ""

View File

@ -10,8 +10,9 @@ Item {
id: item id: item
Text { Text {
id: iconText
anchors.fill: parent anchors.fill: parent
id: iconText
font.pointSize: 16 font.pointSize: 16
font.family: materialFont.name font.family: materialFont.name
color: item.color color: item.color

View File

@ -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
}
}

View File

@ -1,53 +1,186 @@
import QtQuick 2.9 import QtQuick 2.9
import QtQuick.Controls 2.2 import QtQuick.Controls 2.2
import QtQuick.Layouts 1.3
import QtQuick.Controls.Material 2.2 import QtQuick.Controls.Material 2.2
import Matrique 0.1 import Matrique 0.1
import Matrique.Settings 0.1 import Matrique.Settings 0.1
Item { RowLayout {
readonly property bool hidden: marks === EventStatus.Redacted || marks === EventStatus.Hidden readonly property bool avatarVisible: !(sentByMe || (aboveAuthor === author && section === aboveSection))
readonly property color background: MSettings.darkTheme ? "#242424" : "lightgrey" readonly property bool highlighted: !sentByMe
readonly property bool sentByMe: author === currentRoom.localUser 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 z: -5
width: delegateLoader.width
height: delegateLoader.height
anchors.right: !isState && sentByMe ? parent.right : undefined id: messageRow
anchors.horizontalCenter: isState ? parent.horizontalCenter : undefined
AutoMouseArea { Layout.alignment: sentByMe ? Qt.AlignRight : Qt.AlignLeft
anchors.fill: parent
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
}
Rectangle {
Layout.preferredWidth: 40
Layout.preferredHeight: 40
Layout.alignment: Qt.AlignTop
color: "transparent"
visible: !(sentByMe || avatarVisible)
}
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 { Loader {
id: delegateLoader sourceComponent: {
asynchronous: MSettings.asyncMessageDelegate
source: {
if (eventType == "redaction" || hidden) return ""
switch (eventType) { switch (eventType) {
case "state":
case "emote":
return "StateBubble.qml"
case "message":
case "notice":
return "MessageBubble.qml"
case "image": case "image":
return "ImageBubble.qml" return imageComponent
case "audio":
return "AudioBubble.qml"
case "video":
case "file": case "file":
return "FileBubble.qml" 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: "<b>File: </b>" + 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 ""
} }
} }
} }

View File

@ -3,31 +3,21 @@ import QtQuick.Controls 2.2
import QtQuick.Layouts 1.3 import QtQuick.Layouts 1.3
import QtQuick.Controls.Material 2.2 import QtQuick.Controls.Material 2.2
Item { ItemDelegate {
property var page property var page
property alias contentItem: buttonDelegate.contentItem readonly property bool selected: stackView.currentItem === page
signal clicked
id: sideNavButton
Layout.fillWidth: true
Layout.preferredHeight: width
Rectangle { Rectangle {
width: stackView.currentItem === page ? parent.width : 0 width: selected ? 4 : 0
height: parent.height height: parent.height
anchors.bottom: buttonDelegate.bottom
color: Qt.lighter(Material.accent) color: Material.accent
Behavior on width { Behavior on width {
PropertyAnimation { easing.type: Easing.InOutCubic; duration: 200 } PropertyAnimation { easing.type: Easing.InOutCubic; duration: 200 }
} }
} }
ItemDelegate {
id: buttonDelegate
anchors.fill: parent
onClicked: { onClicked: {
if(page && stackView.currentItem !== page) { if(page && stackView.currentItem !== page) {
if(stackView.depth === 1) { if(stackView.depth === 1) {
@ -37,7 +27,5 @@ Item {
stackView.push(page) stackView.push(page)
} }
} }
sideNavButton.clicked()
}
} }
} }

View File

@ -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: "<b>" + author.displayName + "</b> " + display
}

View File

@ -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: "<b>" + author.displayName + "</b> " + 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"
}
}

View File

@ -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
}
}
}

View File

@ -22,11 +22,11 @@ Item {
} }
Drawer { Drawer {
id: roomDrawer
width: Math.min(item.width * 0.7, 480) width: Math.min(item.width * 0.7, 480)
height: item.height height: item.height
id: roomDrawer
edge: Qt.RightEdge edge: Qt.RightEdge
interactive: false interactive: false
@ -39,7 +39,6 @@ Item {
ColumnLayout { ColumnLayout {
anchors.fill: parent anchors.fill: parent
anchors.margins: 32 anchors.margins: 32
spacing: 16
ImageStatus { ImageStatus {
Layout.preferredWidth: 64 Layout.preferredWidth: 64
@ -52,12 +51,14 @@ Item {
Label { Label {
Layout.fillWidth: true Layout.fillWidth: true
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
text: currentRoom && currentRoom.id ? currentRoom.id : "" text: currentRoom && currentRoom.id ? currentRoom.id : ""
} }
Label { Label {
Layout.fillWidth: true Layout.fillWidth: true
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
text: currentRoom && currentRoom.canonicalAlias ? currentRoom.canonicalAlias : "No Canonical Alias" text: currentRoom && currentRoom.canonicalAlias ? currentRoom.canonicalAlias : "No Canonical Alias"
} }
@ -66,8 +67,9 @@ Item {
Layout.fillWidth: true Layout.fillWidth: true
TextField { TextField {
id: roomNameField
Layout.fillWidth: true Layout.fillWidth: true
id: roomNameField
text: currentRoom && currentRoom.name ? currentRoom.name : "" text: currentRoom && currentRoom.name ? currentRoom.name : ""
} }
@ -85,9 +87,10 @@ Item {
Layout.fillWidth: true Layout.fillWidth: true
TextField { TextField {
Layout.fillWidth: true
id: roomTopicField id: roomTopicField
Layout.fillWidth: true
text: currentRoom && currentRoom.topic ? currentRoom.topic : "" text: currentRoom && currentRoom.topic ? currentRoom.topic : ""
} }
@ -116,7 +119,7 @@ Item {
RowLayout { RowLayout {
anchors.fill: parent anchors.fill: parent
anchors.margins: 8 anchors.margins: 8
spacing: 16 spacing: 12
ImageStatus { ImageStatus {
Layout.preferredWidth: height Layout.preferredWidth: height
@ -159,9 +162,9 @@ Item {
Rectangle { Rectangle {
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: 80 Layout.preferredHeight: 64
color: MSettings.darkTheme ? "#242424" : "#eaeaea" color: Material.accent
ItemDelegate { ItemDelegate {
anchors.fill: parent anchors.fill: parent
@ -170,13 +173,14 @@ Item {
RowLayout { RowLayout {
anchors.fill: parent anchors.fill: parent
anchors.margins: 16 anchors.margins: 12
spacing: 16 spacing: 12
ImageStatus { ImageStatus {
Layout.preferredWidth: height Layout.preferredWidth: height
Layout.fillHeight: true Layout.fillHeight: true
source: currentRoom && currentRoom.avatarUrl != "" ? "image://mxc/" + currentRoom.avatarUrl : null source: currentRoom && currentRoom.avatarUrl != "" ? "image://mxc/" + currentRoom.avatarUrl : null
displayText: currentRoom ? currentRoom.displayName : "" displayText: currentRoom ? currentRoom.displayName : ""
} }
@ -186,14 +190,15 @@ Item {
Layout.fillHeight: true Layout.fillHeight: true
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
visible: parent.width > 80 visible: parent.width > 64
Label { Label {
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
text: currentRoom ? currentRoom.displayName : "" text: currentRoom ? currentRoom.displayName : ""
font.pointSize: 16 color: "white"
font.pointSize: 12
elide: Text.ElideRight elide: Text.ElideRight
wrapMode: Text.NoWrap wrapMode: Text.NoWrap
} }
@ -203,6 +208,7 @@ Item {
Layout.fillHeight: true Layout.fillHeight: true
text: currentRoom ? currentRoom.topic : "" text: currentRoom ? currentRoom.topic : ""
color: "white"
elide: Text.ElideRight elide: Text.ElideRight
wrapMode: Text.NoWrap wrapMode: Text.NoWrap
} }
@ -221,80 +227,79 @@ Item {
spacing: 0 spacing: 0
ListView { ListView {
id: messageListView
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
id: messageListView
clip: true
displayMarginBeginning: 40 displayMarginBeginning: 40
displayMarginEnd: 40 displayMarginEnd: 40
verticalLayoutDirection: ListView.BottomToTop verticalLayoutDirection: ListView.BottomToTop
spacing: 8 spacing: 8
boundsBehavior: Flickable.DragOverBounds boundsBehavior: Flickable.DragOverBounds
maximumFlickVelocity: 2048
model: MessageEventModel { model: MessageEventModel {
id: messageEventModel id: messageEventModel
room: currentRoom room: currentRoom
} }
delegate: Column { delegate: ColumnLayout {
readonly property bool hidden: marks === EventStatus.Redacted || marks === EventStatus.Hidden readonly property bool hidden: marks === EventStatus.Redacted || marks === EventStatus.Hidden
width: parent.width width: parent.width
height: hidden ? -8 : undefined height: hidden ? -8 : undefined
id: delegateColumn
clip: true
spacing: 8 spacing: 8
RowLayout { Label {
width: parent.width * 0.8 Layout.alignment: Qt.AlignHCenter
visible: section !== aboveSection && !hidden visible: section !== aboveSection && !hidden
anchors.horizontalCenter: parent.horizontalCenter
spacing: 8
Rectangle {
Layout.fillWidth: true
height:2
color: Material.accent
}
Label {
text: section text: section
color: Material.accent color: "white"
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
} leftPadding: 8
rightPadding: 8
topPadding: 4
bottomPadding: 4
Rectangle { background: Rectangle {
Layout.fillWidth: true color: MSettings.darkTheme ? "#484848" : "grey"
height:2
color: Material.accent
} }
} }
RowLayout {
width: parent.width * 0.8
visible: readMarker === true && index !== 0
anchors.horizontalCenter: parent.horizontalCenter
spacing: 8
Rectangle {
Layout.fillWidth: true
height:2
color: Material.accent
}
Label { Label {
Layout.alignment: Qt.AlignHCenter
visible: readMarker === true && index !== 0
text: "And Now" text: "And Now"
color: Material.accent color: "white"
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
leftPadding: 8
rightPadding: 8
topPadding: 4
bottomPadding: 4
background: Rectangle { color: MSettings.darkTheme ? "#484848" : "grey" }
} }
Rectangle { MessageDelegate {
Layout.fillWidth: true visible: eventType === "notice" || eventType === "message" || eventType === "image" || eventType === "video" || eventType === "audio" || eventType === "file"
height:2
color: Material.accent
}
} }
MessageDelegate {} StateDelegate {
Layout.maximumWidth: messageListView.width * 0.8
visible: eventType === "emote" || eventType === "state"
}
} }
ScrollBar.vertical: messageListViewScrollBar ScrollBar.vertical: messageListViewScrollBar
@ -303,9 +308,11 @@ Item {
onAtYEndChanged: atYEnd && currentRoom ? currentRoom.markAllMessagesAsRead() : {} onAtYEndChanged: atYEnd && currentRoom ? currentRoom.markAllMessagesAsRead() : {}
RoundButton { RoundButton {
id: goTopFab width: 64
width: height
height: 64 height: 64
id: goTopFab
visible: !parent.atYEnd visible: !parent.atYEnd
anchors.right: parent.right anchors.right: parent.right
@ -313,12 +320,12 @@ Item {
contentItem: MaterialIcon { contentItem: MaterialIcon {
anchors.fill: parent anchors.fill: parent
icon: "\ue313" icon: "\ue313"
color: "white" color: "white"
} }
opacity: pressed ? 1 : hovered ? 0.7 : 0.4 Material.background: Material.accent
Material.background: Qt.lighter(Material.accent)
onClicked: parent.positionViewAtBeginning() onClicked: parent.positionViewAtBeginning()
@ -327,18 +334,64 @@ Item {
} }
ScrollBar { ScrollBar {
id: messageListViewScrollBar
Layout.preferredWidth: 16 Layout.preferredWidth: 16
Layout.fillHeight: true Layout.fillHeight: true
id: messageListViewScrollBar
} }
} }
Pane { RowLayout {
padding: 16 Layout.fillWidth: true
Layout.preferredHeight: 48
Layout.margins: 16
spacing: 0
ItemDelegate {
Layout.preferredWidth: 48
Layout.preferredHeight: 48
contentItem: MaterialIcon { icon: "\ue226" }
onClicked: currentRoom.chooseAndUploadFile()
}
TextField {
property real progress: 0
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: 80 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 { Timer {
id: timeoutTimer id: timeoutTimer
@ -360,52 +413,6 @@ Item {
onTriggered: currentRoom.sendTypingNotification(true) onTriggered: currentRoom.sendTypingNotification(true)
} }
RowLayout {
anchors.fill: parent
spacing: 0
ItemDelegate {
Layout.preferredWidth: height
Layout.fillHeight: true
contentItem: MaterialIcon { icon: "\ue226" }
onClicked: currentRoom.chooseAndUploadFile()
}
TextField {
property real progress: 0
id: inputField
Layout.fillWidth: true
Layout.fillHeight: true
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 ? "#242424" : "#eaeaea"
}
ToolTip.visible: currentRoom && currentRoom.hasUsersTyping
ToolTip.text: currentRoom ? currentRoom.usersTyping : ""
function postMessage(text) { function postMessage(text) {
if (text.trim().length === 0) { return } if (text.trim().length === 0) { return }
if(!currentRoom) { return } if(!currentRoom) { return }
@ -456,35 +463,34 @@ Item {
} }
ItemDelegate { ItemDelegate {
id: emojiButton Layout.preferredWidth: 48
Layout.preferredHeight: 48
Layout.preferredWidth: height id: emojiButton
Layout.fillHeight: true
contentItem: MaterialIcon { icon: "\ue24e" } contentItem: MaterialIcon { icon: "\ue24e" }
background: Rectangle { color: MSettings.darkTheme ? "#242424" : "#eaeaea" } background: Rectangle { color: MSettings.darkTheme ? "#282828" : "#eaeaea" }
onClicked: emojiPicker.visible ? emojiPicker.close() : emojiPicker.open() onClicked: emojiPicker.visible ? emojiPicker.close() : emojiPicker.open()
EmojiPicker { EmojiPicker {
id: emojiPicker
parent: ApplicationWindow.overlay
x: window.width - 370 x: window.width - 370
y: window.height - 440 y: window.height - 440
width: 360 width: 360
height: 360 height: 360
id: emojiPicker
parent: ApplicationWindow.overlay
textArea: inputField textArea: inputField
} }
} }
} }
} }
} }
}
onCurrentRoomChanged: if (currentRoom && currentRoom.timelineSize === 0) currentRoom.getPreviousContent(20) onCurrentRoomChanged: if (currentRoom && currentRoom.timelineSize === 0) currentRoom.getPreviousContent(20)
} }

View File

@ -14,70 +14,41 @@ Item {
property alias listModel: roomListProxyModel.sourceModel property alias listModel: roomListProxyModel.sourceModel
property var enteredRoom: null property var enteredRoom: null
Label {
z: 10
text: MSettings.miniMode ? "Empty" : "Here? No, not here."
anchors.centerIn: parent
visible: listView.count === 0
}
ColumnLayout { ColumnLayout {
anchors.fill: parent anchors.fill: parent
spacing: 0 spacing: 0
Rectangle {
z: 10
Layout.fillWidth: true
Layout.preferredHeight: 80
color: Qt.tint(Material.accent, "#20FFFFFF")
TextField { TextField {
Layout.fillWidth: true
Layout.preferredHeight: 40
Layout.margins: 12
id: searchField id: searchField
width: parent.width - 18
height: 36
color: "white"
leftPadding: MSettings.miniMode ? 4 : 32 leftPadding: MSettings.miniMode ? 4 : 32
topPadding: 0 topPadding: 0
bottomPadding: 0 bottomPadding: 0
anchors.centerIn: parent placeholderText: "Search..."
background: Row { background: Rectangle { color: MSettings.darkTheme ? "#282828" : "#fafafa" }
visible: !parent.text
MaterialIcon {
icon: "\ue8b6"
color: "white"
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 { Shortcut {
sequence: StandardKey.Find sequence: StandardKey.Find
onActivated: searchField.forceActiveFocus() onActivated: searchField.forceActiveFocus()
} }
} }
}
Rectangle {
Layout.fillWidth: true
Layout.fillHeight: true
color: MSettings.darkTheme ? "#242424" : "#eaeaea"
Label {
z: 10
text: MSettings.miniMode ? "Empty" : "Here? No, not here."
anchors.centerIn: parent
visible: listView.count === 0
}
SortFilterProxyModel { SortFilterProxyModel {
id: roomListProxyModel id: roomListProxyModel
filters: RegExpFilter { filters: RegExpFilter {
roleName: "name" roleName: "name"
pattern: searchField.text pattern: searchField.text
@ -108,25 +79,34 @@ Item {
} }
ListView { ListView {
Layout.fillWidth: true
Layout.fillHeight: true
id: listView id: listView
anchors.fill: parent
spacing: 1
clip: true
model: roomListProxyModel model: roomListProxyModel
currentIndex: -1 currentIndex: -1
highlightFollowsCurrentItem: true
highlightMoveDuration: 200
highlightResizeDuration: 0
boundsBehavior: Flickable.DragOverBounds boundsBehavior: Flickable.DragOverBounds
ScrollBar.vertical: ScrollBar { id: scrollBar } ScrollBar.vertical: ScrollBar {}
delegate: Rectangle { delegate: Rectangle {
readonly property bool highlighted: currentRoom === enteredRoom readonly property bool highlighted: currentRoom === enteredRoom
id: swipeDelegate
width: parent.width width: parent.width
height: 80 height: 64
color: highlighted ? Material.background : "transparent" color: MSettings.darkTheme ? "#282828" : "#fafafa"
AutoMouseArea { AutoMouseArea {
anchors.fill: parent anchors.fill: parent
@ -140,17 +120,27 @@ Item {
ToolTip.text: name ToolTip.text: name
} }
Rectangle {
anchors.fill: parent
visible: highlighted
color: Material.accent
opacity: 0.1
}
Rectangle { Rectangle {
width: 4 width: 4
height: parent.height height: parent.height
color: Qt.tint(Material.accent, "#20FFFFFF")
color: Material.accent
visible: unreadCount > 0 || highlighted visible: unreadCount > 0 || highlighted
} }
RowLayout { RowLayout {
anchors.fill: parent anchors.fill: parent
anchors.margins: 16 anchors.margins: 12
spacing: 16
spacing: 12
ImageStatus { ImageStatus {
Layout.preferredWidth: height Layout.preferredWidth: height
@ -165,14 +155,14 @@ Item {
Layout.fillHeight: true Layout.fillHeight: true
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
visible: parent.width > 80 visible: parent.width > 64
Label { Label {
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
text: name || "No Name" text: name || "No Name"
font.pointSize: 16 font.pointSize: 12
elide: Text.ElideRight elide: Text.ElideRight
wrapMode: Text.NoWrap wrapMode: Text.NoWrap
} }
@ -181,7 +171,7 @@ Item {
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
text: lastEvent || topic text: (lastEvent == "" ? topic : lastEvent).replace(/(\r\n\t|\n|\r\t)/gm,"");
elide: Text.ElideRight elide: Text.ElideRight
wrapMode: Text.NoWrap wrapMode: Text.NoWrap
} }
@ -194,16 +184,13 @@ Item {
section.delegate: Label { section.delegate: Label {
width: parent.width width: parent.width
height: 24 height: 24
text: section text: section
color: "grey" color: "grey"
leftPadding: MSettings.miniMode ? undefined : 16 leftPadding: MSettings.miniMode ? undefined : 16
elide: Text.ElideRight elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
horizontalAlignment: MSettings.miniMode ? Text.AlignHCenter : undefined horizontalAlignment: MSettings.miniMode ? Text.AlignHCenter : undefined
background: Rectangle {
anchors.fill: parent
color: MSettings.darkTheme ? "#363636" : "#dbdbdb"
}
} }
Dialog { Dialog {
@ -225,5 +212,4 @@ Item {
} }
} }
} }
}
} }

View File

@ -13,12 +13,14 @@ import "form"
ApplicationWindow { ApplicationWindow {
readonly property var connection: matriqueController.connection readonly property var connection: matriqueController.connection
id: window
visible: true
width: 960 width: 960
height: 640 height: 640
minimumWidth: 800 minimumWidth: 800
minimumHeight: 480 minimumHeight: 480
id: window
visible: true
title: qsTr("Matrique") title: qsTr("Matrique")
Material.theme: MSettings.darkTheme ? Material.Dark : Material.Light Material.theme: MSettings.darkTheme ? Material.Dark : Material.Light
@ -40,10 +42,11 @@ ApplicationWindow {
Popup { Popup {
property bool busy: matriqueController.busy property bool busy: matriqueController.busy
id: busyPopup
x: (window.width - width) / 2 x: (window.width - width) / 2
y: (window.height - height) / 2 y: (window.height - height) / 2
id: busyPopup
modal: true modal: true
focus: true focus: true
@ -65,7 +68,7 @@ ApplicationWindow {
parent: null parent: null
connection: matriqueController.isLogin ? window.connection : null connection: window.connection
} }
Setting { Setting {
@ -81,20 +84,24 @@ ApplicationWindow {
spacing: 0 spacing: 0
Rectangle { Rectangle {
id: sideNav Layout.preferredWidth: 64
Layout.preferredWidth: 80
Layout.fillHeight: true Layout.fillHeight: true
color: Material.accent
id: sideNav
color: Material.primary
ColumnLayout { ColumnLayout {
anchors.fill: parent anchors.fill: parent
spacing: 0 spacing: 0
SideNavButton { SideNavButton {
id: statusNavButton Layout.fillWidth: true
contentItem: ImageStatus { Layout.preferredHeight: width
ImageStatus {
anchors.fill: parent 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" 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 : "" displayText: matriqueController.isLogin && connection.localUser.displayName ? connection.localUser.displayName : ""
@ -104,16 +111,27 @@ ApplicationWindow {
} }
Rectangle { Rectangle {
color: "transparent"
Layout.fillHeight: true Layout.fillHeight: true
color: "transparent"
} }
SideNavButton { SideNavButton {
contentItem: MaterialIcon { icon: "\ue145"; color: "white" } Layout.fillWidth: true
Layout.preferredHeight: width
MaterialIcon {
anchors.fill: parent
icon: "\ue145"
color: "white"
}
onClicked: addRoomMenu.popup() onClicked: addRoomMenu.popup()
Menu { Menu {
id: addRoomMenu id: addRoomMenu
MenuItem { MenuItem {
text:"New Room" text:"New Room"
onTriggered: addRoomDialog.open() onTriggered: addRoomDialog.open()
@ -132,14 +150,17 @@ ApplicationWindow {
contentItem: Column { contentItem: Column {
TextField { TextField {
id: addRoomDialogNameTextField
width: parent.width width: parent.width
id: addRoomDialogNameTextField
placeholderText: "Name" placeholderText: "Name"
} }
TextField { TextField {
id: addRoomDialogTopicTextField
width: parent.width width: parent.width
id: addRoomDialogTopicTextField
placeholderText: "Topic" placeholderText: "Topic"
} }
} }
@ -149,16 +170,18 @@ ApplicationWindow {
} }
MenuItem { MenuItem {
text: "Join Room" text: "Join Room"
onTriggered: joinRoomDialog.open() onTriggered: joinRoomDialog.open()
Dialog { Dialog {
id: joinRoomDialog
parent: ApplicationWindow.overlay
x: (window.width - width) / 2 x: (window.width - width) / 2
y: (window.height - height) / 2 y: (window.height - height) / 2
width: 360 width: 360
id: joinRoomDialog
parent: ApplicationWindow.overlay
title: "Input Room Alias or ID" title: "Input Room Alias or ID"
modal: true modal: true
standardButtons: Dialog.Ok | Dialog.Cancel standardButtons: Dialog.Ok | Dialog.Cancel
@ -171,18 +194,21 @@ ApplicationWindow {
onAccepted: matriqueController.joinRoom(joinRoomDialogTextField.text) onAccepted: matriqueController.joinRoom(joinRoomDialogTextField.text)
} }
} }
MenuItem { MenuItem {
text: "Direct Chat" text: "Direct Chat"
onTriggered: directChatDialog.open() onTriggered: directChatDialog.open()
Dialog { Dialog {
id: directChatDialog
parent: ApplicationWindow.overlay
x: (window.width - width) / 2 x: (window.width - width) / 2
y: (window.height - height) / 2 y: (window.height - height) / 2
width: 360 width: 360
id: directChatDialog
parent: ApplicationWindow.overlay
title: "Input User ID" title: "Input User ID"
modal: true modal: true
standardButtons: Dialog.Ok | Dialog.Cancel standardButtons: Dialog.Ok | Dialog.Cancel
@ -199,23 +225,41 @@ ApplicationWindow {
} }
SideNavButton { 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 page: settingPage
} }
SideNavButton { SideNavButton {
contentItem: MaterialIcon { icon: "\ue879"; color: "white" } Layout.fillWidth: true
Layout.preferredHeight: width
MaterialIcon {
anchors.fill: parent
icon: "\ue879"
color: "white"
}
onClicked: Qt.quit() onClicked: Qt.quit()
} }
} }
} }
StackView { StackView {
id: stackView
initialItem: roomPage
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
id: stackView
initialItem: roomPage
} }
} }

View File

@ -8,28 +8,33 @@ Menu {
MenuItem { MenuItem {
text: "Copy" text: "Copy"
onTriggered: matriqueController.copyToClipboard(plainText) onTriggered: matriqueController.copyToClipboard(plainText)
} }
MenuItem { MenuItem {
text: "Copy Source" text: "Copy Source"
onTriggered: matriqueController.copyToClipboard(toolTip) onTriggered: matriqueController.copyToClipboard(toolTip)
} }
MenuItem { MenuItem {
visible: isFile visible: isFile
height: visible ? undefined : 0 height: visible ? undefined : 0
text: "Open Externally" text: "Open Externally"
onTriggered: delegateLoader.item.downloadAndOpen()
onTriggered: messageRow.openExternally()
} }
MenuItem { MenuItem {
visible: isFile visible: isFile
height: visible ? undefined : 0 height: visible ? undefined : 0
text: "Save As" text: "Save As"
onTriggered: delegateLoader.item.saveFileAs()
onTriggered: messageRow.saveFileAs()
} }
MenuItem { MenuItem {
visible: sentByMe visible: sentByMe
height: visible ? undefined : 0 height: visible ? undefined : 0
text: "Redact" text: "Redact"
onTriggered: currentRoom.redactEvent(eventId) onTriggered: currentRoom.redactEvent(eventId)
} }

View File

@ -8,21 +8,25 @@ Menu {
text: "Favourite" text: "Favourite"
checkable: true checkable: true
checked: currentRoom && currentRoom.isFavourite checked: currentRoom && currentRoom.isFavourite
onTriggered: currentRoom.isFavourite ? currentRoom.removeTag("m.favourite") : currentRoom.addTag("m.favourite", "1") onTriggered: currentRoom.isFavourite ? currentRoom.removeTag("m.favourite") : currentRoom.addTag("m.favourite", "1")
} }
MenuItem { MenuItem {
text: "Deprioritize" text: "Deprioritize"
checkable: true checkable: true
checked: currentRoom && currentRoom.isLowPriority checked: currentRoom && currentRoom.isLowPriority
onTriggered: currentRoom.isLowPriority ? currentRoom.removeTag("m.lowpriority") : currentRoom.addTag("m.lowpriority", "1") onTriggered: currentRoom.isLowPriority ? currentRoom.removeTag("m.lowpriority") : currentRoom.addTag("m.lowpriority", "1")
} }
MenuSeparator {} MenuSeparator {}
MenuItem { MenuItem {
text: "Mark as Read" text: "Mark as Read"
onTriggered: currentRoom.markAllMessagesAsRead() onTriggered: currentRoom.markAllMessagesAsRead()
} }
MenuItem { MenuItem {
text: "Leave Room" text: "Leave Room"
onTriggered: currentRoom.forget() onTriggered: currentRoom.forget()
} }

View File

@ -7,9 +7,7 @@ Style=Material
[Material] [Material]
Theme=Light Theme=Light
Primary=#00695c Primary=#344955
Accent=#00695c Accent=#498882
;Primary=#1565c0
;Accent=#1565c0
;Foreground=Black ;Foreground=Black
;Background=#161616 ;Background=#161616

10
res.qrc
View File

@ -14,16 +14,9 @@
<file>asset/img/icon.png</file> <file>asset/img/icon.png</file>
<file>js/md.js</file> <file>js/md.js</file>
<file>qml/component/MessageDelegate.qml</file> <file>qml/component/MessageDelegate.qml</file>
<file>qml/component/MessageBubble.qml</file>
<file>qml/component/ImageBubble.qml</file>
<file>qml/component/StateBubble.qml</file>
<file>qml/component/DownloadableContent.qml</file> <file>qml/component/DownloadableContent.qml</file>
<file>qml/component/FileBubble.qml</file>
<file>qml/component/AvatarContainer.qml</file>
<file>qml/form/RoomListForm.qml</file> <file>qml/form/RoomListForm.qml</file>
<file>qml/component/AudioBubble.qml</file>
<file>qml/Setting.qml</file> <file>qml/Setting.qml</file>
<file>qml/component/TextDelegate.qml</file>
<file>qml/component/EmojiPicker.qml</file> <file>qml/component/EmojiPicker.qml</file>
<file>qml/component/EmojiButton.qml</file> <file>qml/component/EmojiButton.qml</file>
<file>qml/component/AutoImage.qml</file> <file>qml/component/AutoImage.qml</file>
@ -33,5 +26,8 @@
<file>qml/MatriqueSettings.qml</file> <file>qml/MatriqueSettings.qml</file>
<file>qml/menu/MessageContextMenu.qml</file> <file>qml/menu/MessageContextMenu.qml</file>
<file>qml/menu/RoomContextMenu.qml</file> <file>qml/menu/RoomContextMenu.qml</file>
<file>qml/component/GenericBubble.qml</file>
<file>qml/component/StateDelegate.qml</file>
<file>qml/component/AutoLabel.qml</file>
</qresource> </qresource>
</RCC> </RCC>

View File

@ -83,6 +83,7 @@ void MatriqueRoom::sendTypingNotification(bool isTyping) {
QString MatriqueRoom::lastEvent() { QString MatriqueRoom::lastEvent() {
if (timelineSize() == 0) return ""; if (timelineSize() == 0) return "";
const RoomEvent* lastEvent = messageEvents().rbegin()->get(); const RoomEvent* lastEvent = messageEvents().rbegin()->get();
if (lastEvent->contentJson().value("body").toString() == "") return "";
return user(lastEvent->senderId())->displayname() + ": " + return user(lastEvent->senderId())->displayname() + ": " +
lastEvent->contentJson().value("body").toString(); lastEvent->contentJson().value("body").toString();
} }