diff --git a/imports/Spectral/Component/Timeline/AutoImage.qml b/imports/Spectral/Component/AutoImage.qml
similarity index 100%
rename from imports/Spectral/Component/Timeline/AutoImage.qml
rename to imports/Spectral/Component/AutoImage.qml
diff --git a/imports/Spectral/Component/Timeline/AutoLabel.qml b/imports/Spectral/Component/AutoLabel.qml
similarity index 100%
rename from imports/Spectral/Component/Timeline/AutoLabel.qml
rename to imports/Spectral/Component/AutoLabel.qml
diff --git a/imports/Spectral/Component/AutoTextArea.qml b/imports/Spectral/Component/AutoTextArea.qml
new file mode 100644
index 0000000..f59efa9
--- /dev/null
+++ b/imports/Spectral/Component/AutoTextArea.qml
@@ -0,0 +1,113 @@
+import QtQuick 2.9
+import QtQuick.Controls 2.2
+
+TextArea {
+ property real progress: 0
+
+ wrapMode: Text.Wrap
+ placeholderText: "Send a Message"
+ leftPadding: 16
+ topPadding: 0
+ bottomPadding: 0
+ selectByMouse: true
+ verticalAlignment: TextEdit.AlignVCenter
+
+ text: currentRoom ? currentRoom.cachedInput : ""
+
+ background: Item {
+ }
+
+ 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)
+ }
+
+ ToolTip.visible: currentRoom
+ && currentRoom.hasUsersTyping
+ ToolTip.text: currentRoom ? currentRoom.usersTyping : ""
+
+ Keys.onReturnPressed: {
+ if (event.modifiers & Qt.ShiftModifier) {
+ insert(cursorPosition, "\n")
+ } else {
+ postMessage(text)
+ text = ""
+ }
+ }
+
+ onTextChanged: {
+ timeoutTimer.restart()
+ repeatTimer.start()
+ currentRoom.cachedInput = text
+ }
+
+ 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 '
+
+ var replyRe = new RegExp("^> <(.*)><(.*)> (.*)\n\n(.*)")
+ if (text.match(replyRe)) {
+ var matches = text.match(replyRe)
+ currentRoom.sendReply(matches[1], matches[2], matches[3], matches[4])
+ return
+ }
+
+ 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)
+ }
+}
diff --git a/imports/Spectral/Component/Timeline/MessageDelegate.qml b/imports/Spectral/Component/Timeline/MessageDelegate.qml
index b38bc1f..1c9a70b 100644
--- a/imports/Spectral/Component/Timeline/MessageDelegate.qml
+++ b/imports/Spectral/Component/Timeline/MessageDelegate.qml
@@ -6,6 +6,8 @@ import QtQuick.Controls.Material 2.2
import Spectral 0.1
import Spectral.Setting 0.1
+import Spectral.Component 2.0
+
import "qrc:/js/util.js" as Util
RowLayout {
diff --git a/imports/Spectral/Component/qmldir b/imports/Spectral/Component/qmldir
index 09541c6..edf7d5c 100644
--- a/imports/Spectral/Component/qmldir
+++ b/imports/Spectral/Component/qmldir
@@ -2,3 +2,6 @@ module Spectral.Component
AutoMouseArea 2.0 AutoMouseArea.qml
MaterialIcon 2.0 MaterialIcon.qml
SideNavButton 2.0 SideNavButton.qml
+AutoImage 2.0 AutoImage.qml
+AutoLabel 2.0 AutoLabel.qml
+AutoTextArea 2.0 AutoTextArea.qml
diff --git a/imports/Spectral/Form/RoomForm.qml b/imports/Spectral/Form/RoomForm.qml
deleted file mode 100644
index 157a939..0000000
--- a/imports/Spectral/Form/RoomForm.qml
+++ /dev/null
@@ -1,539 +0,0 @@
-import QtQuick 2.9
-import QtQuick.Controls 2.2
-import QtQuick.Layouts 1.3
-import QtQuick.Controls.Material 2.2
-
-import Spectral.Component 2.0
-import Spectral.Component.Emoji 2.0
-import Spectral.Component.Timeline 2.0
-import Spectral.Menu 2.0
-import Spectral.Effect 2.0
-
-import Spectral 0.1
-import Spectral.Setting 0.1
-import SortFilterProxyModel 0.2
-
-import "qrc:/js/md.js" as Markdown
-import "qrc:/js/util.js" as Util
-
-Item {
- property var currentRoom: null
-
- id: item
-
- MessageEventModel {
- id: messageEventModel
- room: currentRoom
- }
-
- RoomDrawer {
- width: Math.min(item.width * 0.7, 480)
- height: item.height
-
- id: roomDrawer
-
- room: currentRoom
- }
-
- Label {
- anchors.centerIn: parent
- visible: !currentRoom
- text: "Please choose a room."
- }
-
- ColumnLayout {
- anchors.fill: parent
- spacing: 0
-
- visible: currentRoom
-
- Rectangle {
- Layout.fillWidth: true
- Layout.preferredHeight: 64
-
- z: 10
-
- color: Material.accent
-
- ItemDelegate {
- anchors.fill: parent
-
- onClicked: roomDrawer.open()
-
- RowLayout {
- anchors.fill: parent
- anchors.margins: 12
-
- spacing: 12
-
- ImageItem {
- Layout.preferredWidth: height
- Layout.fillHeight: true
-
- hint: currentRoom ? currentRoom.displayName : "No name"
- image: spectralController.safeImage(currentRoom ? currentRoom.avatar : null)
- }
-
- ColumnLayout {
- Layout.fillWidth: true
- Layout.fillHeight: true
-
- visible: parent.width > 64
-
- Label {
- Layout.fillWidth: true
- Layout.fillHeight: true
-
- text: currentRoom ? currentRoom.displayName : ""
- color: "white"
- font.pointSize: 12
- elide: Text.ElideRight
- wrapMode: Text.NoWrap
- }
-
- Label {
- Layout.fillWidth: true
- Layout.fillHeight: true
-
- text: currentRoom ? (currentRoom.topic).replace(/(\r\n\t|\n|\r\t)/gm,"") : ""
- color: "white"
- elide: Text.ElideRight
- wrapMode: Text.NoWrap
- }
- }
- }
- }
- }
-
- ProgressBar {
- Layout.fillWidth: true
- z: 10
-
- visible: currentRoom && currentRoom.busy
- indeterminate: true
- }
-
- ListView {
- Layout.fillWidth: true
- Layout.fillHeight: true
- Layout.leftMargin: 16
- Layout.rightMargin: 16
-
- id: messageListView
-
- displayMarginBeginning: 40
- displayMarginEnd: 40
- verticalLayoutDirection: ListView.BottomToTop
- spacing: 8
-
- cacheBuffer: 200
-
- boundsBehavior: Flickable.DragOverBounds
-
- property int largestVisibleIndex: count > 0 ? indexAt(contentX, contentY + height - 1) : -1
-
- onContentYChanged: {
- if(verticalVelocity < 0 && contentY - 5000 < originY)
- currentRoom.getPreviousContent(50);
- }
-
- onMovementEnded: {
- currentRoom.saveViewport(sortedMessageEventModel.mapToSource(indexAt(contentX, contentY)), sortedMessageEventModel.mapToSource(largestVisibleIndex))
- var newReadMarker = sortedMessageEventModel.get(largestVisibleIndex).eventId
- if (newReadMarker) currentRoom.readMarkerEventId = newReadMarker
- }
-
- displaced: Transition {
- NumberAnimation {
- property: "y"; duration: 200
- easing.type: Easing.OutQuad
- }
- }
-
- model: SortFilterProxyModel {
- id: sortedMessageEventModel
-
- sourceModel: messageEventModel
-
- filters: ExpressionFilter {
- expression: marks !== 0x08 && marks !== 0x10
- }
-
- onModelReset: {
- if (currentRoom)
- {
- var lastScrollPosition = mapFromSource(currentRoom.savedTopVisibleIndex())
- if (lastScrollPosition === 0)
- messageListView.positionViewAtBeginning()
- else
- {
- console.log("Scrolling to position", lastScrollPosition)
- messageListView.currentIndex = lastScrollPosition
- }
- if (messageListView.contentY < messageListView.originY + 10 || currentRoom.timelineSize === 0)
- currentRoom.getPreviousContent(100)
- }
- console.log("Model timeline reset")
- }
- }
-
- delegate: ColumnLayout {
- width: parent.width
-
- id: delegateColumn
-
- spacing: 8
-
- Label {
- Layout.alignment: Qt.AlignHCenter
-
- visible: section !== aboveSection
-
- text: section
- color: "white"
- verticalAlignment: Text.AlignVCenter
- leftPadding: 8
- rightPadding: 8
- topPadding: 4
- bottomPadding: 4
-
- background: Rectangle {
- color: MSettings.darkTheme ? "#484848" : "grey"
- }
- }
-
- 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"
- }
-
- Label {
- Layout.alignment: Qt.AlignHCenter
-
- visible: eventType === "other"
-
- text: display
- color: "grey"
- font.italic: true
- }
-
- Label {
- Layout.alignment: Qt.AlignHCenter
-
- visible: readMarker === true && index !== 0
-
- text: "And Now"
- color: "white"
- verticalAlignment: Text.AlignVCenter
- leftPadding: 8
- rightPadding: 8
- topPadding: 4
- bottomPadding: 4
-
- background: Rectangle { color: MSettings.darkTheme ? "#484848" : "grey" }
- }
- }
-
- RoundButton {
- width: 64
- height: 64
-
- id: goTopFab
-
- visible: !(parent.atYEnd || messageListView.moving)
-
- anchors.right: parent.right
- anchors.bottom: parent.bottom
-
- contentItem: MaterialIcon {
- anchors.fill: parent
-
- icon: "\ue313"
- color: "white"
- }
-
- Material.background: Material.accent
-
- onClicked: parent.positionViewAtBeginning()
-
- Behavior on opacity { NumberAnimation { duration: 200 } }
- }
-
- MessageContextMenu { id: messageContextMenu }
-
- Popup {
- property string sourceText
-
- x: (window.width - width) / 2
- y: (window.height - height) / 2
- width: 480
-
- id: sourceDialog
-
- parent: ApplicationWindow.overlay
-
- modal: true
-
- padding: 16
-
- closePolicy: Dialog.CloseOnEscape | Dialog.CloseOnPressOutside
-
- contentItem: ScrollView {
- TextArea {
- readOnly: true
- selectByMouse: true
-
- text: sourceDialog.sourceText
- }
- }
- }
-
- Popup {
- property alias listModel: readMarkerListView.model
-
- x: (window.width - width) / 2
- y: (window.height - height) / 2
- width: 320
-
- id: readMarkerDialog
-
- parent: ApplicationWindow.overlay
-
- modal: true
- padding: 16
-
- closePolicy: Dialog.CloseOnEscape | Dialog.CloseOnPressOutside
-
- contentItem: ListView {
- implicitHeight: Math.min(window.height - 64, readMarkerListView.contentHeight)
-
- id: readMarkerListView
-
- clip: true
- boundsBehavior: Flickable.DragOverBounds
-
- delegate: ItemDelegate {
- width: parent.width
- height: 48
-
- RowLayout {
- anchors.fill: parent
- anchors.margins: 8
- spacing: 12
-
- ImageItem {
- Layout.preferredWidth: height
- Layout.fillHeight: true
-
- image: modelData.avatar
- hint: modelData.displayName
- }
-
- Label {
- Layout.fillWidth: true
-
- text: modelData.displayName
- }
- }
- }
-
- ScrollBar.vertical: ScrollBar {}
- }
- }
- }
-
- Item {
- Layout.fillWidth: true
- Layout.preferredHeight: 40
- }
-
- Rectangle {
- Layout.fillWidth: true
- Layout.preferredHeight: 40
- Layout.leftMargin: 16
- Layout.rightMargin: 16
-
- color: Material.background
-
- Rectangle {
- anchors.verticalCenter: parent.top
- width: parent.width
- height: 48
-
- color: MSettings.darkTheme ? "#303030" : "#fafafa"
-
- layer.enabled: true
- layer.effect: ElevationEffect {
- elevation: 2
- }
-
- RowLayout {
- anchors.fill: parent
-
- spacing: 0
-
- ItemDelegate {
- Layout.preferredWidth: 48
- Layout.preferredHeight: 48
-
- contentItem: MaterialIcon { icon: "\ue226" }
-
- onClicked: currentRoom.chooseAndUploadFile()
- }
-
- ScrollView {
- Layout.fillWidth: true
- Layout.preferredHeight: 48
-
- ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
-
- clip: true
-
- TextArea {
- property real progress: 0
-
- id: inputField
-
- wrapMode: Text.Wrap
- placeholderText: "Send a Message"
- leftPadding: 16
- topPadding: 0
- bottomPadding: 0
- selectByMouse: true
- verticalAlignment: TextEdit.AlignVCenter
-
- text: currentRoom ? currentRoom.cachedInput : ""
-
- background: Item {}
-
- onTextChanged: {
- timeoutTimer.restart()
- repeatTimer.start()
- currentRoom.cachedInput = text
- }
-
- ToolTip.visible: currentRoom && currentRoom.hasUsersTyping
- ToolTip.text: currentRoom ? currentRoom.usersTyping : ""
-
- Keys.onReturnPressed: {
- if (event.modifiers & Qt.ShiftModifier) {
- inputField.insert(inputField.cursorPosition, "\n")
- } else {
- inputField.postMessage(inputField.text)
- inputField.text = ""
- }
- }
-
- 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 '
-
- var replyRe = new RegExp("^> <(.*)><(.*)> (.*)\n\n(.*)")
- if (text.match(replyRe)) {
- var matches = text.match(replyRe)
- currentRoom.sendReply(matches[1], matches[2], matches[3], matches[4])
- return
- }
-
- 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 {
- Layout.preferredWidth: 48
- Layout.preferredHeight: 48
-
- id: emojiButton
-
- contentItem: MaterialIcon { icon: "\ue24e" }
-
- onClicked: emojiPicker.visible ? emojiPicker.close() : emojiPicker.open()
-
- EmojiPicker {
- x: window.width - 370
- y: window.height - 400
-
- width: 360
- height: 320
-
- id: emojiPicker
-
- parent: ApplicationWindow.overlay
-
- Material.elevation: 2
-
- textArea: inputField
- }
- }
- }
- }
- }
- }
-}
diff --git a/imports/Spectral/Form/RoomListForm.qml b/imports/Spectral/Form/RoomListForm.qml
deleted file mode 100644
index 723df91..0000000
--- a/imports/Spectral/Form/RoomListForm.qml
+++ /dev/null
@@ -1,266 +0,0 @@
-import QtQuick 2.9
-import QtQuick.Controls 2.2
-import QtQuick.Layouts 1.3
-import QtGraphicalEffects 1.0
-import QtQuick.Controls.Material 2.2
-import QtQml.Models 2.3
-
-import Spectral.Component 2.0
-import Spectral.Menu 2.0
-import Spectral.Effect 2.0
-
-import Spectral 0.1
-import Spectral.Setting 0.1
-import SortFilterProxyModel 0.2
-
-import "qrc:/js/util.js" as Util
-
-Rectangle {
- property alias listModel: sortedRoomListModel.sourceModel
- property int filter: 0
- property var enteredRoom: null
-
- color: MSettings.darkTheme ? "#323232" : "#f3f3f3"
-
- Label {
- text: MSettings.miniMode ? "Empty" : "Here? No, not here."
- anchors.centerIn: parent
- visible: listView.count === 0
- }
-
- ColumnLayout {
- anchors.fill: parent
- spacing: 0
-
- TextField {
- Layout.fillWidth: true
- Layout.preferredHeight: 40
- Layout.margins: 12
-
- id: searchField
-
- leftPadding: MSettings.miniMode ? 4 : 32
- topPadding: 0
- bottomPadding: 0
- placeholderText: "Search..."
-
- background: Rectangle {
- color: MSettings.darkTheme ? "#303030" : "#fafafa"
- layer.enabled: true
- layer.effect: ElevationEffect {
- elevation: searchField.focus ? 2 : 1
- }
- }
-
- Shortcut {
- sequence: StandardKey.Find
- onActivated: searchField.forceActiveFocus()
- }
- }
-
- SortFilterProxyModel {
- id: sortedRoomListModel
-
- 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 Priority"
- }
- }
- }
-
- sorters: [
- RoleSorter { roleName: "category" },
- RoleSorter {
- roleName: "lastActiveTime"
- sortOrder: Qt.DescendingOrder
- }
- ]
- }
-
- SortFilterProxyModel {
- id: roomListProxyModel
-
- sourceModel: sortedRoomListModel
-
- filters: [
- RegExpFilter {
- roleName: "name"
- pattern: searchField.text
- caseSensitivity: Qt.CaseInsensitive
- },
- ExpressionFilter {
- enabled: filter === 1
- expression: unreadCount > 0
- },
- ExpressionFilter {
- enabled: filter === 2
- expression: category === 1 || category === 2 || category === 4
- },
- ExpressionFilter {
- enabled: filter === 3
- expression: category === 3 || category === 5
- }
- ]
- }
-
- ListView {
- Layout.fillWidth: true
- Layout.fillHeight: true
-
- id: listView
-
- spacing: 1
- clip: true
-
- 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 ? "#303030" : "#fafafa"
-
- AutoMouseArea {
- anchors.fill: parent
-
- hoverEnabled: MSettings.miniMode
-
- onSecondaryClicked: {
- roomContextMenu.model = model
- roomContextMenu.popup()
- }
- onPrimaryClicked: {
- if (category === RoomType.Invited) {
- inviteDialog.currentRoom = currentRoom
- inviteDialog.open()
- } else {
- enteredRoom = currentRoom
- }
- }
-
- ToolTip.visible: MSettings.miniMode && containsMouse
- ToolTip.text: name
- }
-
- Rectangle {
- anchors.fill: parent
-
- visible: highlightCount > 0 || highlighted
- color: Material.accent
- opacity: 0.1
- }
-
- Rectangle {
- width: unreadCount > 0 || highlighted ? 4 : 0
- height: parent.height
-
- color: Material.accent
-
- Behavior on width {
- PropertyAnimation { easing.type: Easing.InOutCubic; duration: 200 }
- }
- }
-
- RowLayout {
- anchors.fill: parent
- anchors.margins: 12
-
- spacing: 12
-
- ImageItem {
- id: imageItem
-
- Layout.preferredWidth: height
- Layout.fillHeight: true
-
- hint: name || "No Name"
-
- image: avatar
- }
-
- ColumnLayout {
- Layout.fillWidth: true
- Layout.fillHeight: true
- Layout.alignment: Qt.AlignHCenter
-
- visible: parent.width > 64
-
- Label {
- Layout.fillWidth: true
- Layout.fillHeight: true
-
- text: name || "No Name"
- font.pointSize: 12
- elide: Text.ElideRight
- wrapMode: Text.NoWrap
- }
-
- Label {
- Layout.fillWidth: true
- Layout.fillHeight: true
-
- text: (lastEvent == "" ? topic : lastEvent).replace(/(\r\n\t|\n|\r\t)/gm,"")
- 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
- }
-
- RoomContextMenu { id: roomContextMenu }
-
- Dialog {
- property var currentRoom
-
- id: inviteDialog
- parent: ApplicationWindow.overlay
-
- x: (window.width - width) / 2
- y: (window.height - height) / 2
- width: 360
-
- title: "Action Required"
- modal: true
- standardButtons: Dialog.Ok | Dialog.Cancel
-
- contentItem: Label { text: "Accept this invitation?" }
-
- onAccepted: currentRoom.acceptInvitation()
- onRejected: currentRoom.forget()
- }
- }
- }
-}
diff --git a/imports/Spectral/Form/qmldir b/imports/Spectral/Form/qmldir
deleted file mode 100644
index b02e012..0000000
--- a/imports/Spectral/Form/qmldir
+++ /dev/null
@@ -1,4 +0,0 @@
-module Spectral.Form
-RoomForm 2.0 RoomForm.qml
-RoomListForm 2.0 RoomListForm.qml
-
diff --git a/imports/Spectral/Menu/qmldir b/imports/Spectral/Menu/qmldir
index 031159a..6892ba8 100644
--- a/imports/Spectral/Menu/qmldir
+++ b/imports/Spectral/Menu/qmldir
@@ -1,4 +1,3 @@
module Spectral.Menu
MessageContextMenu 2.0 MessageContextMenu.qml
RoomContextMenu 2.0 RoomContextMenu.qml
-
diff --git a/imports/Spectral/Page/Login.qml b/imports/Spectral/Page/Login.qml
index 85c83b2..6476ee4 100644
--- a/imports/Spectral/Page/Login.qml
+++ b/imports/Spectral/Page/Login.qml
@@ -1,162 +1,20 @@
import QtQuick 2.9
-import QtQuick.Layouts 1.3
-import QtGraphicalEffects 1.0
-import QtQuick.Controls 2.2
-import QtQuick.Controls.Material 2.2
-import Spectral.Component 2.0
-
-import Spectral.Setting 0.1
-
-Page {
- property var controller
-
- Row {
- anchors.fill: parent
-
- Pane {
- width: parent.width / 2
- height: parent.height
-
- background: Item {
- Image {
- id: background
- anchors.fill: parent
- source: "qrc:/assets/img/background.jpg"
- fillMode: Image.PreserveAspectCrop
- cache: false
- }
-
- ColorOverlay {
- anchors.fill: background
- source: background
- color: Material.accent
- opacity: 0.7
- }
- }
-
- Column {
- x: 32
- anchors.verticalCenter: parent.verticalCenter
-
- Label {
- text: "MATRIX LOGIN."
- font.pointSize: 28
- font.bold: true
- color: "white"
- }
-
- Label {
- text: "A NEW METHOD OF MESSAGING"
- font.pointSize: 12
- color: "white"
- }
- }
+LoginForm {
+ loginButton.onClicked: {
+ if (!(serverField.text.startsWith("http") && serverField.text.includes("://"))) {
+ loginButtonTooltip.text = "Server address should start with http(s)://"
+ loginButtonTooltip.open()
+ return
+ }
+ if (!(usernameField.text.startsWith("@") && usernameField.text.includes(":"))) {
+ loginButtonTooltip.text = "Username should be in format of @example:example.com"
+ loginButtonTooltip.open()
+ return
}
- Pane {
- width: parent.width / 2
- height: parent.height
+ controller.loginWithCredentials(serverField.text, usernameField.text, passwordField.text)
- padding: 64
-
- ColumnLayout {
- width: parent.width
-
- id: mainCol
-
- TextField {
- Layout.fillWidth: true
-
- id: serverField
-
- leftPadding: 16
- topPadding: 0
- bottomPadding: 0
-
- text: "https://matrix.org"
- placeholderText: "Server"
-
- background: Rectangle {
- implicitHeight: 48
-
- color: MSettings.darkTheme ? "#242424" : "#eaeaea"
- border.color: parent.activeFocus ? Material.accent : "transparent"
- border.width: 2
- }
- }
-
- TextField {
- Layout.fillWidth: true
-
- id: usernameField
-
- leftPadding: 16
- topPadding: 0
- bottomPadding: 0
-
- placeholderText: "Username"
-
- background: Rectangle {
- implicitHeight: 48
-
- color: MSettings.darkTheme ? "#242424" : "#eaeaea"
- border.color: parent.activeFocus ? Material.accent : "transparent"
- border.width: 2
- }
- }
-
- TextField {
- Layout.fillWidth: true
-
- id: passwordField
-
- leftPadding: 16
- topPadding: 0
- bottomPadding: 0
-
- placeholderText: "Password"
- echoMode: TextInput.Password
-
- background: Rectangle {
- implicitHeight: 48
-
- color: MSettings.darkTheme ? "#242424" : "#eaeaea"
- border.color: parent.activeFocus ? Material.accent : "transparent"
- border.width: 2
- }
- }
-
- Button {
- Layout.fillWidth: true
-
- id: loginButton
-
- text: "LOGIN"
- highlighted: true
-
- ToolTip {
- id: loginButtonTooltip
- }
-
- onClicked: {
- if (!(serverField.text.startsWith("http") && serverField.text.includes("://"))) {
- loginButtonTooltip.text = "Server address should start with http(s)://"
- loginButtonTooltip.open()
- return
- }
- if (!(usernameField.text.startsWith("@") && usernameField.text.includes(":"))) {
- loginButtonTooltip.text = "Username should be in format of @example:example.com"
- loginButtonTooltip.open()
- return
- }
-
- controller.loginWithCredentials(serverField.text, usernameField.text, passwordField.text)
-
- controller.connectionAdded.connect(function() { stackView.pop() })
- }
- }
- }
- }
+ controller.connectionAdded.connect(function() { stackView.pop() })
}
}
diff --git a/imports/Spectral/Page/LoginForm.ui.qml b/imports/Spectral/Page/LoginForm.ui.qml
new file mode 100644
index 0000000..99b537a
--- /dev/null
+++ b/imports/Spectral/Page/LoginForm.ui.qml
@@ -0,0 +1,147 @@
+import QtQuick 2.9
+import QtQuick.Layouts 1.3
+import QtGraphicalEffects 1.0
+import QtQuick.Controls 2.2
+import QtQuick.Controls.Material 2.2
+
+import Spectral.Component 2.0
+
+import Spectral.Setting 0.1
+
+Page {
+ property var controller
+
+ property alias loginButton: loginButton
+
+ Row {
+ anchors.fill: parent
+
+ Pane {
+ width: parent.width / 2
+ height: parent.height
+
+ background: Item {
+ Image {
+ id: background
+ anchors.fill: parent
+ source: "qrc:/assets/img/background.jpg"
+ fillMode: Image.PreserveAspectCrop
+ cache: false
+ }
+
+ ColorOverlay {
+ anchors.fill: background
+ source: background
+ color: Material.accent
+ opacity: 0.7
+ }
+ }
+
+ Column {
+ x: 32
+ anchors.verticalCenter: parent.verticalCenter
+
+ Label {
+ text: "MATRIX LOGIN."
+ font.pointSize: 28
+ font.bold: true
+ color: "white"
+ }
+
+ Label {
+ text: "A NEW METHOD OF MESSAGING"
+ font.pointSize: 12
+ color: "white"
+ }
+ }
+ }
+
+ Pane {
+ width: parent.width / 2
+ height: parent.height
+
+ padding: 64
+
+ ColumnLayout {
+ width: parent.width
+
+ id: mainCol
+
+ TextField {
+ Layout.fillWidth: true
+
+ id: serverField
+
+ leftPadding: 16
+ topPadding: 0
+ bottomPadding: 0
+
+ text: "https://matrix.org"
+ placeholderText: "Server"
+
+ background: Rectangle {
+ implicitHeight: 48
+
+ color: MSettings.darkTheme ? "#242424" : "#eaeaea"
+ border.color: parent.activeFocus ? Material.accent : "transparent"
+ border.width: 2
+ }
+ }
+
+ TextField {
+ Layout.fillWidth: true
+
+ id: usernameField
+
+ leftPadding: 16
+ topPadding: 0
+ bottomPadding: 0
+
+ placeholderText: "Username"
+
+ background: Rectangle {
+ implicitHeight: 48
+
+ color: MSettings.darkTheme ? "#242424" : "#eaeaea"
+ border.color: parent.activeFocus ? Material.accent : "transparent"
+ border.width: 2
+ }
+ }
+
+ TextField {
+ Layout.fillWidth: true
+
+ id: passwordField
+
+ leftPadding: 16
+ topPadding: 0
+ bottomPadding: 0
+
+ placeholderText: "Password"
+ echoMode: TextInput.Password
+
+ background: Rectangle {
+ implicitHeight: 48
+
+ color: MSettings.darkTheme ? "#242424" : "#eaeaea"
+ border.color: parent.activeFocus ? Material.accent : "transparent"
+ border.width: 2
+ }
+ }
+
+ Button {
+ Layout.fillWidth: true
+
+ id: loginButton
+
+ text: "LOGIN"
+ highlighted: true
+
+ ToolTip {
+ id: loginButtonTooltip
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/imports/Spectral/Page/Room.qml b/imports/Spectral/Page/Room.qml
index dc7b5a7..bd55905 100644
--- a/imports/Spectral/Page/Room.qml
+++ b/imports/Spectral/Page/Room.qml
@@ -1,55 +1,5 @@
import QtQuick 2.9
-import QtQuick.Controls 2.2
-import QtQuick.Layouts 1.3
-import QtQuick.Controls.Material 2.2
-import Spectral.Form 2.0
-import Spectral.Component 2.0
-import Spectral.Effect 2.0
-
-import Spectral 0.1
-import Spectral.Setting 0.1
-
-Page {
- property alias connection: roomListModel.connection
- property alias filter: roomListForm.filter
-
- id: page
-
- RoomListModel {
- id: roomListModel
-
- onNewMessage: if (!window.active) spectralController.showMessage(roomName, content, icon)
- }
-
- RowLayout {
- anchors.fill: parent
-
- spacing: 0
-
- RoomListForm {
- Layout.fillHeight: true
- Layout.preferredWidth: MSettings.miniMode ? 64 : page.width * 0.35
- Layout.minimumWidth: 64
- Layout.maximumWidth: 360
-
- id: roomListForm
-
- listModel: roomListModel
-
- layer.enabled: true
- layer.effect: ElevationEffect {
- elevation: 2
- }
- }
-
- RoomForm {
- Layout.fillWidth: true
- Layout.fillHeight: true
-
- id: roomForm
-
- currentRoom: roomListForm.enteredRoom
- }
- }
+RoomForm {
+ roomListModel.onNewMessage: if (!window.active) spectralController.showMessage(roomName, content, icon)
}
diff --git a/imports/Spectral/Page/RoomForm.ui.qml b/imports/Spectral/Page/RoomForm.ui.qml
new file mode 100644
index 0000000..0c35fd4
--- /dev/null
+++ b/imports/Spectral/Page/RoomForm.ui.qml
@@ -0,0 +1,61 @@
+import QtQuick 2.9
+import QtQuick.Controls 2.2
+import QtQuick.Layouts 1.3
+import QtQuick.Controls.Material 2.2
+
+import Spectral.Panel 2.0
+import Spectral.Component 2.0
+import Spectral.Effect 2.0
+
+import Spectral 0.1
+import Spectral.Setting 0.1
+
+Page {
+ property alias connection: roomListModel.connection
+ property alias filter: roomListForm.filter
+
+ property alias roomListModel: roomListModel
+
+ id: page
+
+ RoomListModel {
+ id: roomListModel
+ }
+
+ RowLayout {
+ anchors.fill: parent
+
+ spacing: 0
+
+ RoomListPanel {
+ Layout.fillHeight: true
+ Layout.preferredWidth: MSettings.miniMode ? 64 : page.width * 0.35
+ Layout.minimumWidth: 64
+ Layout.maximumWidth: 360
+
+ id: roomListForm
+
+ listModel: roomListModel
+
+ layer.enabled: true
+ layer.effect: ElevationEffect {
+ elevation: 2
+ }
+ }
+
+ RoomPanel {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+
+ id: roomForm
+
+ currentRoom: roomListForm.enteredRoom
+ }
+ }
+}
+
+
+/*##^## Designer {
+ D{i:0;autoSize:false;height:480;width:640}
+}
+ ##^##*/
diff --git a/imports/Spectral/Page/Setting.qml b/imports/Spectral/Page/Setting.qml
index c2523e6..0385eaf 100644
--- a/imports/Spectral/Page/Setting.qml
+++ b/imports/Spectral/Page/Setting.qml
@@ -1,297 +1,5 @@
import QtQuick 2.9
-import QtQuick.Controls 2.2
-import QtQuick.Controls.Material 2.2
-import QtQuick.Layouts 1.3
-import Spectral.Component 2.0
-import Spectral.Effect 2.0
-
-import Spectral 0.1
-import Spectral.Setting 0.1
-
-import "qrc:/js/util.js" as Util
-
-Page {
- property alias listModel: accountSettingsListView.model
-
- Page {
- id: accountForm
-
- parent: null
-
- padding: 64
-
- ColumnLayout {
- anchors.fill: parent
-
- ListView {
- Layout.fillWidth: true
- Layout.fillHeight: true
-
- id: accountSettingsListView
-
- boundsBehavior: Flickable.DragOverBounds
-
- clip: true
-
- delegate: Column {
- property bool expanded: false
-
- spacing: 8
-
- ItemDelegate {
- width: accountSettingsListView.width
- height: 64
-
- Row {
- anchors.fill: parent
- anchors.margins: 8
-
- spacing: 8
-
- ImageItem {
- width: parent.height
- height: parent.height
-
- hint: user.displayName
- image: user.avatar
- }
-
- ColumnLayout {
- Label {
- text: user.displayName
- }
- Label {
- text: user.id
- }
- }
- }
-
- onClicked: expanded = !expanded
- }
-
- ColumnLayout {
- width: parent.width - 32
- height: expanded ? implicitHeight : 0
- anchors.horizontalCenter: parent.horizontalCenter
-
- spacing: 0
-
- clip: true
-
- ListView {
- Layout.fillWidth: true
- Layout.preferredHeight: 24
-
- orientation: ListView.Horizontal
-
- spacing: 8
-
- model: ["#498882", "#42a5f5", "#5c6bc0", "#7e57c2", "#ab47bc", "#ff7043"]
-
- delegate: Rectangle {
- width: parent.height
- height: parent.height
- radius: width / 2
-
- color: modelData
-
- MouseArea {
- anchors.fill: parent
-
- onClicked: spectralController.setColor(connection.localUserId, modelData)
- }
- }
- }
-
- RowLayout {
- Layout.fillWidth: true
-
- Label { text: "Homeserver:" }
- TextField {
- Layout.fillWidth: true
-
- text: connection.homeserver
- selectByMouse: true
- readOnly: true
- }
- }
-
- RowLayout {
- Layout.fillWidth: true
-
- spacing: 16
-
- Label { text: "Device ID:" }
- TextField {
- Layout.fillWidth: true
-
- text: connection.deviceId
- selectByMouse: true
- readOnly: true
- }
- }
-
- RowLayout {
- Layout.fillWidth: true
-
- spacing: 16
-
- Label { text: "Access Token:" }
- TextField {
- Layout.fillWidth: true
-
- text: connection.accessToken
- selectByMouse: true
- readOnly: true
- }
- }
-
- Button {
- Layout.fillWidth: true
-
- highlighted: true
- text: "Logout"
-
- onClicked: spectralController.logout(connection)
- }
-
- Behavior on height {
- PropertyAnimation { easing.type: Easing.InOutCubic; duration: 200 }
- }
- }
- }
- }
-
- Button {
- Layout.fillWidth: true
-
- text: "Add Account"
- flat: true
- highlighted: true
-
- onClicked: stackView.push(loginPage)
- }
- }
- }
-
- Page {
- id: generalForm
-
- parent: null
-
- padding: 64
-
- Column {
- Switch {
- text: "Use press and hold instead of right click"
- checked: MSettings.pressAndHold
-
- onCheckedChanged: MSettings.pressAndHold = checked
- }
- }
- }
-
- Page {
- id: appearanceForm
-
- parent: null
-
- padding: 64
-
- Column {
- Switch {
- text: "Dark theme"
- checked: MSettings.darkTheme
-
- onCheckedChanged: MSettings.darkTheme = checked
- }
-
- Switch {
- text: "Mini Room List"
- checked: MSettings.miniMode
-
- onCheckedChanged: MSettings.miniMode = checked
- }
- }
- }
-
- Page {
- id: aboutForm
-
- parent: null
-
- padding: 64
-
- ColumnLayout {
- spacing: 16
- Image {
- Layout.preferredWidth: 64
- Layout.preferredHeight: 64
-
- source: "qrc:/assets/img/icon.png"
- }
- Label { text: "Spectral, an IM client for the Matrix protocol." }
- Label { text: "Released under GNU General Public License, version 3." }
- }
- }
-
- Rectangle {
- width: 240
- height: parent.height
- z: 10
-
- id: settingDrawer
-
- color: MSettings.darkTheme ? "#323232" : "#f3f3f3"
-
- layer.enabled: true
- layer.effect: ElevationEffect {
- elevation: 4
- }
-
- Column {
- anchors.fill: parent
-
- ItemDelegate {
- width: parent.width
-
- text: "Account"
- onClicked: pushToStack(accountForm)
- }
-
- ItemDelegate {
- width: parent.width
-
- text: "General"
- onClicked: pushToStack(generalForm)
- }
-
- ItemDelegate {
- width: parent.width
-
- text: "Appearance"
- onClicked: pushToStack(appearanceForm)
- }
-
- ItemDelegate {
- width: parent.width
-
- text: "About"
- onClicked: pushToStack(aboutForm)
- }
- }
- }
-
- StackView {
- anchors.fill: parent
- anchors.leftMargin: settingDrawer.width
-
- id: settingStackView
- }
-
- function pushToStack(item) {
- settingStackView.clear()
- settingStackView.push(item)
- }
+SettingForm {
+ addAccountButton.onClicked: stackView.push(loginPage)
}
diff --git a/imports/Spectral/Page/SettingAccountDelegate.qml b/imports/Spectral/Page/SettingAccountDelegate.qml
new file mode 100644
index 0000000..869bf58
--- /dev/null
+++ b/imports/Spectral/Page/SettingAccountDelegate.qml
@@ -0,0 +1,136 @@
+import QtQuick 2.9
+import QtQuick.Controls 2.2
+import QtQuick.Layouts 1.3
+
+import Spectral.Component 2.0
+
+import Spectral 0.1
+import Spectral.Setting 0.1
+
+Column {
+ property bool expanded: false
+
+ spacing: 8
+
+ ItemDelegate {
+ width: accountSettingsListView.width
+ height: 64
+
+ Row {
+ anchors.fill: parent
+ anchors.margins: 8
+
+ spacing: 8
+
+ ImageItem {
+ width: parent.height
+ height: parent.height
+
+ hint: user.displayName
+ image: user.avatar
+ }
+
+ ColumnLayout {
+ Label {
+ text: user.displayName
+ }
+ Label {
+ text: user.id
+ }
+ }
+ }
+
+ onClicked: expanded = !expanded
+ }
+
+ ColumnLayout {
+ width: parent.width - 32
+ height: expanded ? implicitHeight : 0
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ spacing: 0
+
+ clip: true
+
+ ListView {
+ Layout.fillWidth: true
+ Layout.preferredHeight: 24
+
+ orientation: ListView.Horizontal
+
+ spacing: 8
+
+ model: ["#498882", "#42a5f5", "#5c6bc0", "#7e57c2", "#ab47bc", "#ff7043"]
+
+ delegate: Rectangle {
+ width: parent.height
+ height: parent.height
+ radius: width / 2
+
+ color: modelData
+
+ MouseArea {
+ anchors.fill: parent
+
+ onClicked: spectralController.setColor(connection.localUserId, modelData)
+ }
+ }
+ }
+
+ RowLayout {
+ Layout.fillWidth: true
+
+ Label {
+ text: "Homeserver:"
+ }
+ TextField {
+ Layout.fillWidth: true
+
+ text: connection.homeserver
+ selectByMouse: true
+ readOnly: true
+ }
+ }
+
+ RowLayout {
+ Layout.fillWidth: true
+
+ spacing: 16
+
+ Label {
+ text: "Device ID:"
+ }
+ TextField {
+ Layout.fillWidth: true
+
+ text: connection.deviceId
+ selectByMouse: true
+ readOnly: true
+ }
+ }
+
+ RowLayout {
+ Layout.fillWidth: true
+
+ spacing: 16
+
+ Label {
+ text: "Access Token:"
+ }
+ TextField {
+ Layout.fillWidth: true
+
+ text: connection.accessToken
+ selectByMouse: true
+ readOnly: true
+ }
+ }
+
+ Button {
+ Layout.fillWidth: true
+
+ highlighted: true
+ text: "Logout"
+ }
+ }
+}
diff --git a/imports/Spectral/Page/SettingCategoryDelegate.qml b/imports/Spectral/Page/SettingCategoryDelegate.qml
new file mode 100644
index 0000000..e78bfbb
--- /dev/null
+++ b/imports/Spectral/Page/SettingCategoryDelegate.qml
@@ -0,0 +1,11 @@
+import QtQuick 2.9
+import QtQuick.Controls 2.2
+
+ItemDelegate {
+ text: category
+
+ onClicked: {
+ settingStackView.clear()
+ settingStackView.push([accountForm, generalForm, appearanceForm, aboutForm][form])
+ }
+}
diff --git a/imports/Spectral/Page/SettingForm.ui.qml b/imports/Spectral/Page/SettingForm.ui.qml
new file mode 100644
index 0000000..af39118
--- /dev/null
+++ b/imports/Spectral/Page/SettingForm.ui.qml
@@ -0,0 +1,178 @@
+import QtQuick 2.9
+import QtQuick.Controls 2.2
+import QtQuick.Controls.Material 2.2
+import QtQuick.Layouts 1.3
+
+import Spectral.Component 2.0
+import Spectral.Effect 2.0
+
+import Spectral 0.1
+import Spectral.Setting 0.1
+
+Page {
+ property alias listModel: accountSettingsListView.model
+
+ property alias addAccountButton: addAccountButton
+
+ implicitWidth: 400
+ implicitHeight: 300
+
+ Page {
+ id: accountForm
+
+ parent: null
+
+ padding: 64
+
+ ColumnLayout {
+ anchors.fill: parent
+
+ ListView {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+
+ id: accountSettingsListView
+
+ boundsBehavior: Flickable.DragOverBounds
+
+ clip: true
+
+ delegate: SettingAccountDelegate {}
+ }
+
+ Button {
+ Layout.fillWidth: true
+
+ id: addAccountButton
+
+ text: "Add Account"
+ flat: true
+ highlighted: true
+ }
+ }
+ }
+
+ Page {
+ id: generalForm
+
+ parent: null
+
+ padding: 64
+
+ Column {
+ Switch {
+ text: "Use press and hold instead of right click"
+ checked: MSettings.pressAndHold
+
+ onCheckedChanged: MSettings.pressAndHold = checked
+ }
+ }
+ }
+
+ Page {
+ id: appearanceForm
+
+ parent: null
+
+ padding: 64
+
+ Column {
+ Switch {
+ text: "Dark theme"
+ checked: MSettings.darkTheme
+
+ onCheckedChanged: MSettings.darkTheme = checked
+ }
+
+ Switch {
+ text: "Mini Room List"
+ checked: MSettings.miniMode
+
+ onCheckedChanged: MSettings.miniMode = checked
+ }
+ }
+ }
+
+ Page {
+ id: aboutForm
+
+ parent: null
+
+ padding: 64
+
+ ColumnLayout {
+ spacing: 16
+ Image {
+ Layout.preferredWidth: 64
+ Layout.preferredHeight: 64
+
+ source: "qrc:/assets/img/icon.png"
+ }
+ Label {
+ text: "Spectral, an IM client for the Matrix protocol."
+ }
+ Label {
+ text: "Released under GNU General Public License, version 3."
+ }
+ }
+ }
+
+ Rectangle {
+ width: 240
+ height: parent.height
+ z: 10
+
+ id: settingDrawer
+
+ color: MSettings.darkTheme ? "#323232" : "#f3f3f3"
+
+ layer.enabled: true
+ layer.effect: ElevationEffect {
+ elevation: 4
+ }
+
+ Column {
+ anchors.fill: parent
+
+ Repeater {
+ model: ListModel {
+ ListElement {
+ category: "Account"
+ form: 0
+ }
+ ListElement {
+ category: "General"
+ form: 1
+ }
+ ListElement {
+ category: "Appearance"
+ form: 2
+ }
+ ListElement {
+ category: "About"
+ form: 3
+ }
+ }
+
+ delegate: SettingCategoryDelegate {
+ width: parent.width
+ }
+ }
+ }
+ }
+
+ StackView {
+ anchors.fill: parent
+ anchors.leftMargin: settingDrawer.width
+
+ id: settingStackView
+
+ initialItem: aboutForm
+ }
+}
+
+
+/*##^## Designer {
+ D{i:0;autoSize:true;height:480;width:640}
+}
+ ##^##*/
diff --git a/imports/Spectral/Page/qmldir b/imports/Spectral/Page/qmldir
index 4ebdb69..af81264 100644
--- a/imports/Spectral/Page/qmldir
+++ b/imports/Spectral/Page/qmldir
@@ -2,4 +2,3 @@ module Spectral.Page
Login 2.0 Login.qml
Room 2.0 Room.qml
Setting 2.0 Setting.qml
-
diff --git a/imports/Spectral/Form/RoomDrawer.qml b/imports/Spectral/Panel/RoomDrawer.qml
similarity index 99%
rename from imports/Spectral/Form/RoomDrawer.qml
rename to imports/Spectral/Panel/RoomDrawer.qml
index a63bd09..17d8871 100644
--- a/imports/Spectral/Form/RoomDrawer.qml
+++ b/imports/Spectral/Panel/RoomDrawer.qml
@@ -203,4 +203,3 @@ Drawer {
}
}
}
-
diff --git a/imports/Spectral/Panel/RoomHeader.qml b/imports/Spectral/Panel/RoomHeader.qml
new file mode 100644
index 0000000..5532967
--- /dev/null
+++ b/imports/Spectral/Panel/RoomHeader.qml
@@ -0,0 +1,69 @@
+import QtQuick 2.9
+import QtQuick.Controls 2.2
+import QtQuick.Layouts 1.3
+import QtQuick.Controls.Material 2.2
+
+import Spectral 0.1
+
+Rectangle {
+ property alias image: headerImage.image
+ property alias topic: headerTopicLabel.text
+ signal clicked()
+
+ id: header
+
+ color: Material.accent
+
+ ItemDelegate {
+ anchors.fill: parent
+
+ id: roomHeader
+
+ onClicked: header.clicked()
+
+ RowLayout {
+ anchors.fill: parent
+ anchors.margins: 12
+
+ spacing: 12
+
+ ImageItem {
+ Layout.preferredWidth: height
+ Layout.fillHeight: true
+
+ id: headerImage
+
+ hint: currentRoom ? currentRoom.displayName : "No name"
+ }
+
+ ColumnLayout {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+
+ visible: parent.width > 64
+
+ Label {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+
+ text: currentRoom ? currentRoom.displayName : ""
+ color: "white"
+ font.pointSize: 12
+ elide: Text.ElideRight
+ wrapMode: Text.NoWrap
+ }
+
+ Label {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+
+ id: headerTopicLabel
+
+ color: "white"
+ elide: Text.ElideRight
+ wrapMode: Text.NoWrap
+ }
+ }
+ }
+ }
+}
diff --git a/imports/Spectral/Panel/RoomListDelegate.qml b/imports/Spectral/Panel/RoomListDelegate.qml
new file mode 100644
index 0000000..f1759d5
--- /dev/null
+++ b/imports/Spectral/Panel/RoomListDelegate.qml
@@ -0,0 +1,101 @@
+import QtQuick 2.9
+import QtQuick.Controls 2.2
+import QtQuick.Layouts 1.3
+import QtQuick.Controls.Material 2.2
+
+import Spectral 0.1
+import Spectral.Setting 0.1
+
+import Spectral.Component 2.0
+
+Rectangle {
+ readonly property bool highlighted: currentRoom === enteredRoom
+
+ color: MSettings.darkTheme ? "#303030" : "#fafafa"
+
+ AutoMouseArea {
+ anchors.fill: parent
+
+ hoverEnabled: MSettings.miniMode
+
+ onSecondaryClicked: {
+ roomContextMenu.model = model
+ roomContextMenu.popup()
+ }
+ onPrimaryClicked: {
+ if (category === RoomType.Invited) {
+ inviteDialog.currentRoom = currentRoom
+ inviteDialog.open()
+ } else {
+ enteredRoom = currentRoom
+ }
+ }
+
+ ToolTip.visible: MSettings.miniMode && containsMouse
+ ToolTip.text: name
+ }
+
+ Rectangle {
+ anchors.fill: parent
+
+ visible: highlightCount > 0 || highlighted
+ color: Material.accent
+ opacity: 0.1
+ }
+
+ Rectangle {
+ width: unreadCount > 0 || highlighted ? 4 : 0
+ height: parent.height
+
+ color: Material.accent
+
+ Behavior on width {
+ PropertyAnimation { easing.type: Easing.InOutCubic; duration: 200 }
+ }
+ }
+
+ RowLayout {
+ anchors.fill: parent
+ anchors.margins: 12
+
+ spacing: 12
+
+ ImageItem {
+ id: imageItem
+
+ Layout.preferredWidth: height
+ Layout.fillHeight: true
+
+ hint: name || "No Name"
+
+ image: avatar
+ }
+
+ ColumnLayout {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ Layout.alignment: Qt.AlignHCenter
+
+ visible: parent.width > 64
+
+ Label {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+
+ text: name || "No Name"
+ font.pointSize: 12
+ elide: Text.ElideRight
+ wrapMode: Text.NoWrap
+ }
+
+ Label {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+
+ text: (lastEvent == "" ? topic : lastEvent).replace(/(\r\n\t|\n|\r\t)/gm,"")
+ elide: Text.ElideRight
+ wrapMode: Text.NoWrap
+ }
+ }
+ }
+}
diff --git a/imports/Spectral/Panel/RoomListPanel.qml b/imports/Spectral/Panel/RoomListPanel.qml
new file mode 100644
index 0000000..d89313a
--- /dev/null
+++ b/imports/Spectral/Panel/RoomListPanel.qml
@@ -0,0 +1,44 @@
+import QtQuick 2.9
+import QtQuick.Controls 2.2
+
+import SortFilterProxyModel 0.2
+
+RoomListPanelForm {
+ sortedRoomListModel.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 Priority"
+ }
+ }
+ }
+
+ Shortcut {
+ sequence: StandardKey.Find
+ onActivated: searchField.forceActiveFocus()
+ }
+
+ Dialog {
+ property var currentRoom
+
+ id: inviteDialog
+ parent: ApplicationWindow.overlay
+
+ x: (window.width - width) / 2
+ y: (window.height - height) / 2
+ width: 360
+
+ title: "Action Required"
+ modal: true
+ standardButtons: Dialog.Ok | Dialog.Cancel
+
+ contentItem: Label { text: "Accept this invitation?" }
+
+ onAccepted: currentRoom.acceptInvitation()
+ onRejected: currentRoom.forget()
+ }
+}
diff --git a/imports/Spectral/Panel/RoomListPanelForm.ui.qml b/imports/Spectral/Panel/RoomListPanelForm.ui.qml
new file mode 100644
index 0000000..7d43f0e
--- /dev/null
+++ b/imports/Spectral/Panel/RoomListPanelForm.ui.qml
@@ -0,0 +1,141 @@
+import QtQuick 2.9
+import QtQuick.Controls 2.2
+import QtQuick.Layouts 1.3
+import QtGraphicalEffects 1.0
+import QtQuick.Controls.Material 2.2
+import QtQml.Models 2.3
+
+import Spectral.Component 2.0
+import Spectral.Menu 2.0
+import Spectral.Effect 2.0
+
+import Spectral 0.1
+import Spectral.Setting 0.1
+import SortFilterProxyModel 0.2
+
+import "qrc:/js/util.js" as Util
+
+Rectangle {
+ property alias listModel: sortedRoomListModel.sourceModel
+ property int filter: 0
+ property var enteredRoom: null
+
+ property alias searchField: searchField
+ property alias sortedRoomListModel: sortedRoomListModel
+
+ color: MSettings.darkTheme ? "#323232" : "#f3f3f3"
+
+ Label {
+ text: MSettings.miniMode ? "Empty" : "Here? No, not here."
+ anchors.centerIn: parent
+ visible: listView.count === 0
+ }
+
+ ColumnLayout {
+ anchors.fill: parent
+ spacing: 0
+
+ TextField {
+ Layout.fillWidth: true
+ Layout.preferredHeight: 40
+ Layout.margins: 12
+
+ id: searchField
+
+ leftPadding: MSettings.miniMode ? 4 : 32
+ topPadding: 0
+ bottomPadding: 0
+ placeholderText: "Search..."
+
+ background: Rectangle {
+ color: MSettings.darkTheme ? "#303030" : "#fafafa"
+ layer.enabled: true
+ layer.effect: ElevationEffect {
+ elevation: searchField.focus ? 2 : 1
+ }
+ }
+ }
+
+ SortFilterProxyModel {
+ id: sortedRoomListModel
+
+ sorters: [
+ RoleSorter { roleName: "category" },
+ RoleSorter {
+ roleName: "lastActiveTime"
+ sortOrder: Qt.DescendingOrder
+ }
+ ]
+ }
+
+ SortFilterProxyModel {
+ id: roomListProxyModel
+
+ sourceModel: sortedRoomListModel
+
+ filters: [
+ RegExpFilter {
+ roleName: "name"
+ pattern: searchField.text
+ caseSensitivity: Qt.CaseInsensitive
+ },
+ ExpressionFilter {
+ enabled: filter === 1
+ expression: unreadCount > 0
+ },
+ ExpressionFilter {
+ enabled: filter === 2
+ expression: category === 1 || category === 2 || category === 4
+ },
+ ExpressionFilter {
+ enabled: filter === 3
+ expression: category === 3 || category === 5
+ }
+ ]
+ }
+
+ ListView {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+
+ id: listView
+
+ spacing: 1
+ clip: true
+
+ model: roomListProxyModel
+
+ currentIndex: -1
+
+ highlightFollowsCurrentItem: true
+
+ highlightMoveDuration: 200
+ highlightResizeDuration: 0
+
+ boundsBehavior: Flickable.DragOverBounds
+
+ ScrollBar.vertical: ScrollBar {}
+
+ delegate: RoomListDelegate {
+ width: parent.width
+ height: 64
+ }
+
+ 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
+ }
+
+ RoomContextMenu { id: roomContextMenu }
+ }
+ }
+}
diff --git a/imports/Spectral/Panel/RoomPanel.qml b/imports/Spectral/Panel/RoomPanel.qml
new file mode 100644
index 0000000..317c975
--- /dev/null
+++ b/imports/Spectral/Panel/RoomPanel.qml
@@ -0,0 +1,56 @@
+import QtQuick 2.9
+
+RoomPanelForm {
+ roomHeader.onClicked: roomDrawer.open()
+ roomHeader.image: spectralController.safeImage(currentRoom ? currentRoom.avatar : null)
+ roomHeader.topic: currentRoom ? (currentRoom.topic).replace(/(\r\n\t|\n|\r\t)/gm,"") : ""
+
+ sortedMessageEventModel.onModelReset: {
+ if (currentRoom)
+ {
+ var lastScrollPosition = sortedMessageEventModel.mapFromSource(currentRoom.savedTopVisibleIndex())
+ if (lastScrollPosition === 0)
+ messageListView.positionViewAtBeginning()
+ else
+ {
+ console.log("Scrolling to position", lastScrollPosition)
+ messageListView.currentIndex = lastScrollPosition
+ }
+ if (messageListView.contentY < messageListView.originY + 10 || currentRoom.timelineSize === 0)
+ currentRoom.getPreviousContent(100)
+ }
+ console.log("Model timeline reset")
+ }
+
+ messageListView {
+ property int largestVisibleIndex: messageListView.count > 0 ? messageListView.indexAt(messageListView.contentX, messageListView.contentY + height - 1) : -1
+
+ onContentYChanged: {
+ if(messageListView.verticalVelocity < 0 && messageListView.contentY - 5000 < messageListView.originY)
+ currentRoom.getPreviousContent(50);
+ }
+
+ onMovementEnded: {
+ currentRoom.saveViewport(sortedMessageEventModel.mapToSource(messageListView.indexAt(messageListView.contentX, messageListView.contentY)), sortedMessageEventModel.mapToSource(largestVisibleIndex))
+ var newReadMarker = sortedMessageEventModel.get(largestVisibleIndex).eventId
+ if (newReadMarker) currentRoom.readMarkerEventId = newReadMarker
+ }
+
+ displaced: Transition {
+ NumberAnimation {
+ property: "y"; duration: 200
+ easing.type: Easing.OutQuad
+ }
+ }
+ }
+
+ goTopFab {
+ onClicked: messageListView.positionViewAtBeginning()
+
+ Behavior on opacity { NumberAnimation { duration: 200 } }
+ }
+
+ uploadButton.onClicked: currentRoom.chooseAndUploadFile()
+
+ emojiButton.onClicked: emojiPicker.visible ? emojiPicker.close() : emojiPicker.open()
+}
diff --git a/imports/Spectral/Panel/RoomPanelForm.ui.qml b/imports/Spectral/Panel/RoomPanelForm.ui.qml
new file mode 100644
index 0000000..692bd49
--- /dev/null
+++ b/imports/Spectral/Panel/RoomPanelForm.ui.qml
@@ -0,0 +1,364 @@
+import QtQuick 2.9
+import QtQuick.Controls 2.2
+import QtQuick.Layouts 1.3
+import QtQuick.Controls.Material 2.2
+
+import Spectral.Component 2.0
+import Spectral.Component.Emoji 2.0
+import Spectral.Component.Timeline 2.0
+import Spectral.Menu 2.0
+import Spectral.Effect 2.0
+
+import Spectral 0.1
+import Spectral.Setting 0.1
+import SortFilterProxyModel 0.2
+
+import "qrc:/js/md.js" as Markdown
+import "qrc:/js/util.js" as Util
+
+Item {
+ property var currentRoom: null
+
+ property alias roomHeader: roomHeader
+ property alias messageListView: messageListView
+ property alias goTopFab: goTopFab
+ property alias uploadButton: uploadButton
+ property alias emojiButton: emojiButton
+ property alias emojiPicker: emojiPicker
+ property alias sortedMessageEventModel: sortedMessageEventModel
+ property alias inputField: inputField
+ property alias roomDrawer: roomDrawer
+
+ id: root
+
+ MessageEventModel {
+ id: messageEventModel
+ room: currentRoom
+ }
+
+ RoomDrawer {
+ width: Math.min(root.width * 0.7, 480)
+ height: root.height
+
+ id: roomDrawer
+
+ room: currentRoom
+ }
+
+ Label {
+ anchors.centerIn: parent
+ visible: !currentRoom
+ text: "Please choose a room."
+ }
+
+ ColumnLayout {
+ anchors.fill: parent
+ spacing: 0
+
+ visible: currentRoom
+
+ RoomHeader {
+ Layout.fillWidth: true
+ Layout.preferredHeight: 64
+ z: 10
+
+ id: roomHeader
+ }
+
+ ProgressBar {
+ Layout.fillWidth: true
+ z: 10
+
+ visible: currentRoom && currentRoom.busy
+ indeterminate: true
+ }
+
+ ListView {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ Layout.leftMargin: 16
+ Layout.rightMargin: 16
+
+ id: messageListView
+
+ displayMarginBeginning: 40
+ displayMarginEnd: 40
+ verticalLayoutDirection: ListView.BottomToTop
+ spacing: 8
+
+ boundsBehavior: Flickable.DragOverBounds
+
+ model: SortFilterProxyModel {
+ id: sortedMessageEventModel
+
+ sourceModel: messageEventModel
+
+ filters: ExpressionFilter {
+ expression: marks !== 0x08 && marks !== 0x10
+ }
+ }
+
+ delegate: ColumnLayout {
+ width: parent.width
+
+ id: delegateColumn
+
+ spacing: 8
+
+ Label {
+ Layout.alignment: Qt.AlignHCenter
+
+ visible: section !== aboveSection
+
+ text: section
+ color: "white"
+ verticalAlignment: Text.AlignVCenter
+ leftPadding: 8
+ rightPadding: 8
+ topPadding: 4
+ bottomPadding: 4
+
+ background: Rectangle {
+ color: MSettings.darkTheme ? "#484848" : "grey"
+ }
+ }
+
+ 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"
+ }
+
+ Label {
+ Layout.alignment: Qt.AlignHCenter
+
+ visible: eventType === "other"
+
+ text: display
+ color: "grey"
+ font.italic: true
+ }
+
+ Label {
+ Layout.alignment: Qt.AlignHCenter
+
+ visible: readMarker === true && index !== 0
+
+ text: "And Now"
+ color: "white"
+ verticalAlignment: Text.AlignVCenter
+ leftPadding: 8
+ rightPadding: 8
+ topPadding: 4
+ bottomPadding: 4
+
+ background: Rectangle {
+ color: MSettings.darkTheme ? "#484848" : "grey"
+ }
+ }
+ }
+
+ RoundButton {
+ width: 64
+ height: 64
+
+ id: goTopFab
+
+ visible: !(parent.atYEnd || messageListView.moving)
+
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+
+ contentItem: MaterialIcon {
+ anchors.fill: parent
+
+ icon: "\ue313"
+ color: "white"
+ }
+
+ Material.background: Material.accent
+ }
+
+ MessageContextMenu {
+ id: messageContextMenu
+ }
+
+ Popup {
+ property string sourceText
+
+ x: (window.width - width) / 2
+ y: (window.height - height) / 2
+ width: 480
+
+ id: sourceDialog
+
+ parent: ApplicationWindow.overlay
+
+ modal: true
+
+ padding: 16
+
+ closePolicy: Dialog.CloseOnEscape | Dialog.CloseOnPressOutside
+
+ contentItem: ScrollView {
+ TextArea {
+ readOnly: true
+ selectByMouse: true
+
+ text: sourceDialog.sourceText
+ }
+ }
+ }
+
+ Popup {
+ property alias listModel: readMarkerListView.model
+
+ x: (window.width - width) / 2
+ y: (window.height - height) / 2
+ width: 320
+
+ id: readMarkerDialog
+
+ parent: ApplicationWindow.overlay
+
+ modal: true
+ padding: 16
+
+ closePolicy: Dialog.CloseOnEscape | Dialog.CloseOnPressOutside
+
+ contentItem: ListView {
+ implicitHeight: Math.min(window.height - 64,
+ readMarkerListView.contentHeight)
+
+ id: readMarkerListView
+
+ clip: true
+ boundsBehavior: Flickable.DragOverBounds
+
+ delegate: ItemDelegate {
+ width: parent.width
+ height: 48
+
+ RowLayout {
+ anchors.fill: parent
+ anchors.margins: 8
+ spacing: 12
+
+ ImageItem {
+ Layout.preferredWidth: height
+ Layout.fillHeight: true
+
+ image: modelData.avatar
+ hint: modelData.displayName
+ }
+
+ Label {
+ Layout.fillWidth: true
+
+ text: modelData.displayName
+ }
+ }
+ }
+
+ ScrollBar.vertical: ScrollBar {}
+ }
+ }
+ }
+
+ Item {
+ Layout.fillWidth: true
+ Layout.preferredHeight: 40
+ }
+
+ Rectangle {
+ Layout.fillWidth: true
+ Layout.preferredHeight: 40
+ Layout.leftMargin: 16
+ Layout.rightMargin: 16
+
+ color: Material.background
+
+ Rectangle {
+ anchors.verticalCenter: parent.top
+ width: parent.width
+ height: 48
+
+ color: MSettings.darkTheme ? "#303030" : "#fafafa"
+
+ layer.enabled: true
+ layer.effect: ElevationEffect {
+ elevation: 2
+ }
+
+ RowLayout {
+ anchors.fill: parent
+
+ spacing: 0
+
+ ItemDelegate {
+ Layout.preferredWidth: 48
+ Layout.preferredHeight: 48
+
+ id: uploadButton
+
+ contentItem: MaterialIcon {
+ icon: "\ue226"
+ }
+ }
+
+ ScrollView {
+ Layout.fillWidth: true
+ Layout.preferredHeight: 48
+
+ ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
+
+ clip: true
+
+ AutoTextArea {
+ id: inputField
+ }
+ }
+
+ ItemDelegate {
+ Layout.preferredWidth: 48
+ Layout.preferredHeight: 48
+
+ id: emojiButton
+
+ contentItem: MaterialIcon {
+ icon: "\ue24e"
+ }
+
+ EmojiPicker {
+ x: window.width - 370
+ y: window.height - 400
+
+ width: 360
+ height: 320
+
+ id: emojiPicker
+
+ parent: ApplicationWindow.overlay
+
+ Material.elevation: 2
+
+ textArea: inputField
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+
+/*##^## Designer {
+ D{i:0;autoSize:true;height:480;width:640}
+}
+ ##^##*/
diff --git a/imports/Spectral/Panel/qmldir b/imports/Spectral/Panel/qmldir
new file mode 100644
index 0000000..3e9cc65
--- /dev/null
+++ b/imports/Spectral/Panel/qmldir
@@ -0,0 +1,3 @@
+module Spectral.Panel
+RoomPanel 2.0 RoomPanel.qml
+RoomListPanel 2.0 RoomListPanel.qml
diff --git a/res.qrc b/res.qrc
index 560dcb0..2bd1e2c 100644
--- a/res.qrc
+++ b/res.qrc
@@ -7,8 +7,6 @@
imports/Spectral/Component/Emoji/EmojiButton.qml
imports/Spectral/Component/Emoji/EmojiPicker.qml
imports/Spectral/Component/Emoji/qmldir
- imports/Spectral/Component/Timeline/AutoImage.qml
- imports/Spectral/Component/Timeline/AutoLabel.qml
imports/Spectral/Component/Timeline/DownloadableContent.qml
imports/Spectral/Component/Timeline/GenericBubble.qml
imports/Spectral/Component/Timeline/MessageDelegate.qml
@@ -20,17 +18,12 @@
imports/Spectral/Component/SideNavButton.qml
imports/Spectral/Effect/ElevationEffect.qml
imports/Spectral/Effect/qmldir
- imports/Spectral/Form/qmldir
- imports/Spectral/Form/RoomDrawer.qml
- imports/Spectral/Form/RoomForm.qml
- imports/Spectral/Form/RoomListForm.qml
imports/Spectral/Menu/MessageContextMenu.qml
imports/Spectral/Menu/qmldir
imports/Spectral/Menu/RoomContextMenu.qml
imports/Spectral/Page/Login.qml
imports/Spectral/Page/qmldir
imports/Spectral/Page/Room.qml
- imports/Spectral/Page/Setting.qml
assets/font/material.ttf
assets/img/avatar.png
assets/img/background.jpg
@@ -41,5 +34,22 @@
imports/Spectral/Font/MaterialFont.qml
imports/Spectral/Font/qmldir
imports/Spectral/Setting/qmldir
+ imports/Spectral/Page/Setting.qml
+ imports/Spectral/Page/SettingForm.ui.qml
+ imports/Spectral/Page/SettingCategoryDelegate.qml
+ imports/Spectral/Page/SettingAccountDelegate.qml
+ imports/Spectral/Page/RoomForm.ui.qml
+ imports/Spectral/Page/LoginForm.ui.qml
+ imports/Spectral/Panel/qmldir
+ imports/Spectral/Panel/RoomDrawer.qml
+ imports/Spectral/Panel/RoomListPanel.qml
+ imports/Spectral/Panel/RoomListPanelForm.ui.qml
+ imports/Spectral/Panel/RoomPanel.qml
+ imports/Spectral/Panel/RoomPanelForm.ui.qml
+ imports/Spectral/Panel/RoomHeader.qml
+ imports/Spectral/Panel/RoomListDelegate.qml
+ imports/Spectral/Component/AutoImage.qml
+ imports/Spectral/Component/AutoLabel.qml
+ imports/Spectral/Component/AutoTextArea.qml
diff --git a/src/spectralroom.cpp b/src/spectralroom.cpp
index 1a5526d..9fabd0d 100644
--- a/src/spectralroom.cpp
+++ b/src/spectralroom.cpp
@@ -9,6 +9,7 @@
#include
#include
+#include
SpectralRoom::SpectralRoom(Connection* connection, QString roomId,
JoinState joinState)
@@ -180,5 +181,8 @@ void SpectralRoom::saveViewport(int topIndex, int bottomIndex) {
void SpectralRoom::getPreviousContent(int limit) {
setBusy(true);
- Room::getPreviousContent(limit);
+ QMetaObject::invokeMethod(
+ this,
+ [=] { Room::getPreviousContent(limit); },
+ Qt::QueuedConnection);
}