From da1e21ca9b28c1a89dff1522c3eb83b4f564d9f2 Mon Sep 17 00:00:00 2001 From: Black Hat Date: Thu, 27 Sep 2018 19:44:34 +0800 Subject: [PATCH] Simplify UI code. --- qml/form/RoomForm.qml | 884 +++++++++++++++++++++--------------------- 1 file changed, 439 insertions(+), 445 deletions(-) diff --git a/qml/form/RoomForm.qml b/qml/form/RoomForm.qml index 9fd91c0..0b826b7 100644 --- a/qml/form/RoomForm.qml +++ b/qml/form/RoomForm.qml @@ -2,7 +2,6 @@ import QtQuick 2.9 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 import QtQuick.Controls.Material 2.2 -import QtGraphicalEffects 1.0 import Spectral 0.1 import Spectral.Settings 0.1 import SortFilterProxyModel 0.2 @@ -31,485 +30,480 @@ Item { room: currentRoom } - Control { - anchors.fill: parent - padding: 0 + Label { + anchors.centerIn: parent + visible: !currentRoom + text: "Please choose a room." + } - background: 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 + + color: Material.accent + + layer.enabled: true + layer.effect: ElevationEffect { + elevation: 2 + } + + 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 + } + } + } + } } - ColumnLayout { - anchors.fill: parent + RowLayout { + Layout.fillWidth: true + Layout.fillHeight: true + Layout.leftMargin: 16 + + z: -10 + spacing: 0 - visible: currentRoom + ListView { + Layout.fillWidth: true + Layout.fillHeight: true + + id: messageListView + + displayMarginBeginning: 40 + displayMarginEnd: 40 + verticalLayoutDirection: ListView.BottomToTop + spacing: 8 + + boundsBehavior: Flickable.DragOverBounds + // flickDeceleration: 4096 + + // cacheBuffer: 200 + + model: SortFilterProxyModel { + id: sortedRoomListModel + + 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" } + } + } + + ScrollBar.vertical: messageListViewScrollBar + + onAtYBeginningChanged: atYBeginning && currentRoom ? currentRoom.getPreviousContent(20) : {} + onAtYEndChanged: atYEnd && currentRoom ? currentRoom.markAllMessagesAsRead() : {} + + 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 {} + } + } + } + + ScrollBar { + Layout.preferredWidth: 16 + Layout.fillHeight: true + + id: messageListViewScrollBar + } + } + + Item { + Layout.fillWidth: true + Layout.preferredHeight: 40 + } + + Rectangle { + Layout.fillWidth: true + Layout.preferredHeight: 40 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + color: Material.background Rectangle { - Layout.fillWidth: true - Layout.preferredHeight: 64 + anchors.verticalCenter: parent.top + width: parent.width + height: 48 - color: Material.accent + color: MSettings.darkTheme ? "#303030" : "#fafafa" layer.enabled: true layer.effect: ElevationEffect { elevation: 2 } - ItemDelegate { + RowLayout { anchors.fill: parent - onClicked: roomDrawer.open() + spacing: 0 - RowLayout { - anchors.fill: parent - anchors.margins: 12 + ItemDelegate { + Layout.preferredWidth: 48 + Layout.preferredHeight: 48 - spacing: 12 + contentItem: MaterialIcon { icon: "\ue226" } - ImageItem { - Layout.preferredWidth: height - Layout.fillHeight: true + onClicked: currentRoom.chooseAndUploadFile() + } - hint: currentRoom ? currentRoom.displayName : "No name" - image: spectralController.safeImage(currentRoom ? currentRoom.avatar : null) - } + ScrollView { + Layout.fillWidth: true + Layout.preferredHeight: 48 - ColumnLayout { - Layout.fillWidth: true - Layout.fillHeight: true + ScrollBar.horizontal.policy: ScrollBar.AlwaysOff - visible: parent.width > 64 + clip: true - Label { - Layout.fillWidth: true - Layout.fillHeight: true + TextArea { + property real progress: 0 - text: currentRoom ? currentRoom.displayName : "" - color: "white" - font.pointSize: 12 - elide: Text.ElideRight - wrapMode: Text.NoWrap + 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 } - 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 - } - } - } - } - } - - RowLayout { - Layout.fillWidth: true - Layout.fillHeight: true - Layout.leftMargin: 16 - - z: -10 - - spacing: 0 - - ListView { - Layout.fillWidth: true - Layout.fillHeight: true - - id: messageListView - - displayMarginBeginning: 40 - displayMarginEnd: 40 - verticalLayoutDirection: ListView.BottomToTop - spacing: 8 - - boundsBehavior: Flickable.DragOverBounds - flickDeceleration: 4096 - - cacheBuffer: 200 - - model: SortFilterProxyModel { - id: sortedRoomListModel - - 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" } - } - } - - ScrollBar.vertical: messageListViewScrollBar - - onAtYBeginningChanged: atYBeginning && currentRoom ? currentRoom.getPreviousContent(20) : {} - onAtYEndChanged: atYEnd && currentRoom ? currentRoom.markAllMessagesAsRead() : {} - - 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 - } + 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 = "" } } - ScrollBar.vertical: ScrollBar {} - } - } - } + Timer { + id: timeoutTimer - ScrollBar { - Layout.preferredWidth: 16 - Layout.fillHeight: true - - id: messageListViewScrollBar - } - } - - 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) + repeat: false + interval: 2000 + onTriggered: { + repeatTimer.stop() + currentRoom.sendTypingNotification(false) } } - } - ItemDelegate { - Layout.preferredWidth: 48 - Layout.preferredHeight: 48 + Timer { + id: repeatTimer - 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 + 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 } } }