diff --git a/imports/Spectral/Component/Emoji/EmojiPicker.qml b/imports/Spectral/Component/Emoji/EmojiPicker.qml
index aa64a7be2..c4b9cd4bc 100644
--- a/imports/Spectral/Component/Emoji/EmojiPicker.qml
+++ b/imports/Spectral/Component/Emoji/EmojiPicker.qml
@@ -3,84 +3,105 @@ import QtQuick.Controls 2.2
import QtQuick.Layouts 1.3
import QtQuick.Controls.Material 2.2
+import Spectral.Component 2.0
+
import Spectral 0.1
+import Spectral.Setting 0.1
-Popup {
- property var emojiModel
- property var textArea
+ColumnLayout {
property string emojiCategory: "people"
+ property var textArea
+ property var emojiModel
- ColumnLayout {
- anchors.fill: parent
+ spacing: 0
- GridView {
- Layout.fillWidth: true
- Layout.fillHeight: true
+ ListView {
+ Layout.fillWidth: true
+ Layout.preferredHeight: 48
+ Layout.leftMargin: 24
+ Layout.rightMargin: 24
- cellWidth: 36
- cellHeight: 36
+ boundsBehavior: Flickable.DragOverBounds
- boundsBehavior: Flickable.DragOverBounds
+ clip: true
- clip: true
+ orientation: ListView.Horizontal
- model: emojiModel.model[emojiCategory]
-
- delegate: ItemDelegate {
- width: 36
- height: 36
-
- contentItem: Text {
- horizontalAlignment: Text.AlignHCenter
- verticalAlignment: Text.AlignVCenter
-
- font.pointSize: 20
- font.family: "Emoji"
- text: modelData.unicode
- }
-
- onClicked: textArea.insert(textArea.cursorPosition, modelData.unicode)
- }
-
- ScrollBar.vertical: ScrollBar {}
+ model: ListModel {
+ ListElement { label: "😏"; category: "people" }
+ ListElement { label: "🌲"; category: "nature" }
+ ListElement { label: "🍛"; category: "food"}
+ ListElement { label: "🚁"; category: "activity" }
+ ListElement { label: "🚅"; category: "travel" }
+ ListElement { label: "💡"; category: "objects" }
+ ListElement { label: "🔣"; category: "symbols" }
+ ListElement { label: "🏁"; category: "flags" }
}
- Rectangle {
- Layout.fillWidth: true
- Layout.preferredHeight: 2
+ delegate: ItemDelegate {
+ width: 64
+ height: 48
- color: Material.accent
- }
+ contentItem: Text {
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
- Row {
- Repeater {
- model: ListModel {
- ListElement { label: "😏"; category: "people" }
- ListElement { label: "🌲"; category: "nature" }
- ListElement { label: "🍛"; category: "food"}
- ListElement { label: "🚁"; category: "activity" }
- ListElement { label: "🚅"; category: "travel" }
- ListElement { label: "💡"; category: "objects" }
- ListElement { label: "🔣"; category: "symbols" }
- ListElement { label: "🏁"; category: "flags" }
- }
-
- delegate: ItemDelegate {
- width: 36
- height: 36
-
- contentItem: Text {
- horizontalAlignment: Text.AlignHCenter
- verticalAlignment: Text.AlignVCenter
-
- font.pointSize: 20
- font.family: "Emoji"
- text: label
- }
-
- onClicked: emojiCategory = category
- }
+ font.pointSize: 24
+ font.family: "Emoji"
+ text: label
}
+
+ Rectangle {
+ anchors.bottom: parent.bottom
+
+ width: parent.width
+ height: 2
+
+ visible: emojiCategory === category
+
+ color: Material.accent
+ }
+
+ onClicked: emojiCategory = category
}
}
+
+ Rectangle {
+ Layout.fillWidth: true
+ Layout.preferredHeight: 1
+
+ color: MSettings.darkTheme ? "#424242" : "#e7ebeb"
+ }
+
+ GridView {
+ Layout.fillWidth: true
+ Layout.preferredHeight: 180
+
+ cellWidth: 48
+ cellHeight: 48
+
+ boundsBehavior: Flickable.DragOverBounds
+
+ clip: true
+
+ model: emojiModel.model[emojiCategory]
+
+ delegate: ItemDelegate {
+ width: 48
+ height: 48
+
+ contentItem: Text {
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+
+ font.pointSize: 20
+ font.family: "Emoji"
+ text: modelData.unicode
+ }
+
+ onClicked: textArea.insert(textArea.cursorPosition, modelData.unicode)
+ }
+
+ ScrollBar.vertical: ScrollBar {}
+ }
}
diff --git a/imports/Spectral/Panel/RoomListPanel.qml b/imports/Spectral/Panel/RoomListPanel.qml
index f1cb284bb..c35beb9e3 100644
--- a/imports/Spectral/Panel/RoomListPanel.qml
+++ b/imports/Spectral/Panel/RoomListPanel.qml
@@ -151,6 +151,8 @@ Rectangle {
Layout.fillWidth: true
Layout.fillHeight: true
+ clip: true
+
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
ColumnLayout {
diff --git a/imports/Spectral/Panel/RoomPanelInput.qml b/imports/Spectral/Panel/RoomPanelInput.qml
index 2450b4889..30e839f29 100644
--- a/imports/Spectral/Panel/RoomPanelInput.qml
+++ b/imports/Spectral/Panel/RoomPanelInput.qml
@@ -23,6 +23,8 @@ Control {
property int autoCompleteBeginPosition
property int autoCompleteEndPosition
+ id: root
+
padding: 0
background: Rectangle {
@@ -105,228 +107,241 @@ Control {
}
}
- contentItem: RowLayout {
+ contentItem: Column {
spacing: 0
- ToolButton {
- Layout.alignment: Qt.AlignTop
-
- id: uploadButton
- visible: !isReply
-
- contentItem: MaterialIcon {
- icon: "\ue226"
- }
-
- onClicked: currentRoom.chooseAndUploadFile()
-
- BusyIndicator {
- anchors.fill: parent
-
- running: currentRoom && currentRoom.hasFileUploading
- }
+ add: Transition {
+ NumberAnimation { property: "opacity"; from: 0; to: 1.0; duration: 250 }
}
- ToolButton {
- id: cancelReplyButton
- visible: isReply
+ EmojiPicker {
+ width: parent.width
- contentItem: MaterialIcon {
- icon: "\ue5cd"
- }
+ id: emojiPicker
- onClicked: clearReply()
- }
+ visible: false
- TextArea {
- property real progress: 0
-
- Layout.fillWidth: true
- Layout.minimumHeight: 48
-
- id: inputField
-
- wrapMode: Text.Wrap
- placeholderText: isReply ? "Reply to " + replyUserID : "Send a Message"
- topPadding: 0
- bottomPadding: 0
- selectByMouse: true
- verticalAlignment: TextEdit.AlignVCenter
-
- text: currentRoom ? currentRoom.cachedInput : ""
-
- background: Item {
- }
+ textArea: inputField
+ emojiModel: EmojiModel { id: emojiModel }
Rectangle {
- width: currentRoom && currentRoom.hasFileUploading ? parent.width * currentRoom.fileUploadingProgress / 100 : 0
- height: parent.height
+ Layout.fillWidth: true
+ Layout.preferredHeight: 1
- opacity: 0.2
- color: Material.accent
- }
-
- 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
- text: currentRoom ? currentRoom.usersTyping : ""
-
- Material.foreground: "white"
- }
-
- Keys.onReturnPressed: {
- if (event.modifiers & Qt.ShiftModifier) {
- insert(cursorPosition, "\n")
- } else {
- postMessage(text)
- text = ""
- }
- }
-
- Keys.onBacktabPressed: if (isAutoCompleting) autoCompleteListView.decrementCurrentIndex()
-
- Keys.onTabPressed: {
- if (isAutoCompleting) {
- autoCompleteListView.incrementCurrentIndex()
- } else {
- autoCompleteBeginPosition = text.substring(0, cursorPosition).lastIndexOf(" ") + 1
- var autoCompletePrefix = text.substring(0, cursorPosition).split(" ").pop()
- if (!autoCompletePrefix) return
- if (autoCompletePrefix.startsWith(":")) {
- autoCompleteBeginPosition = text.substring(0, cursorPosition).lastIndexOf(" ") + 1
- autoCompleteModel = emojiModel.filterModel(autoCompletePrefix)
- if (autoCompleteModel.length === 0) return
- isAutoCompleting = true
- autoCompleteEndPosition = cursorPosition
- } else {
- autoCompleteModel = currentRoom.getUsers(autoCompletePrefix)
- if (autoCompleteModel.length === 0) return
- isAutoCompleting = true
- autoCompleteEndPosition = cursorPosition
- }
- }
- replaceAutoComplete(autoCompleteListView.currentItem.autoCompleteText)
- }
-
- onTextChanged: {
- timeoutTimer.restart()
- repeatTimer.start()
- currentRoom.cachedInput = text
-
- if (cursorPosition !== autoCompleteBeginPosition && cursorPosition !== autoCompleteEndPosition) {
- isAutoCompleting = false
- autoCompleteListView.currentIndex = 0
- }
- }
-
- function replaceAutoComplete(word) {
- remove(autoCompleteBeginPosition, autoCompleteEndPosition)
- autoCompleteEndPosition = autoCompleteBeginPosition + word.length
- insert(cursorPosition, word)
- }
-
- function postMessage(text) {
- if (text.trim().length === 0) { return }
- if(!currentRoom) { return }
-
- var PREFIX_ME = '/me '
- var PREFIX_NOTICE = '/notice '
- var PREFIX_RAINBOW = '/rainbow '
- var PREFIX_HTML = '/html '
- var PREFIX_MARKDOWN = '/md '
-
- if (isReply) {
- currentRoom.sendReply(replyUserID, replyEventID, replyContent, text)
- clearReply()
- 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)
+ color: MSettings.darkTheme ? "#424242" : "#e7ebeb"
}
}
- ToolButton {
- Layout.alignment: Qt.AlignTop
+ RowLayout {
+ width: parent.width
- id: emojiButton
+ spacing: 0
- contentItem: MaterialIcon {
- icon: "\ue24e"
- }
+ ToolButton {
+ Layout.alignment: Qt.AlignBottom
- onClicked: emojiPicker.visible ? emojiPicker.close() : emojiPicker.open()
+ id: uploadButton
+ visible: !isReply
- EmojiPicker {
- x: -width + parent.width
- y: -height - 16
-
- width: 360
- height: 320
-
- id: emojiPicker
-
- emojiModel: EmojiModel {
- id: emojiModel
+ contentItem: MaterialIcon {
+ icon: "\ue226"
}
- Material.elevation: 2
+ onClicked: currentRoom.chooseAndUploadFile()
- textArea: inputField
+ BusyIndicator {
+ anchors.fill: parent
+
+ running: currentRoom && currentRoom.hasFileUploading
+ }
+ }
+
+ ToolButton {
+ Layout.alignment: Qt.AlignBottom
+
+ id: cancelReplyButton
+
+ visible: isReply
+
+ contentItem: MaterialIcon {
+ icon: "\ue5cd"
+ }
+
+ onClicked: clearReply()
+ }
+
+ TextArea {
+ property real progress: 0
+
+ Layout.fillWidth: true
+ Layout.minimumHeight: 48
+
+ id: inputField
+
+ wrapMode: Text.Wrap
+ placeholderText: isReply ? "Reply to " + replyUserID : "Send a Message"
+ topPadding: 0
+ bottomPadding: 0
+ selectByMouse: true
+ verticalAlignment: TextEdit.AlignVCenter
+
+ text: currentRoom ? currentRoom.cachedInput : ""
+
+ background: Item {
+ }
+
+ Rectangle {
+ width: currentRoom && currentRoom.hasFileUploading ? parent.width * currentRoom.fileUploadingProgress / 100 : 0
+ height: parent.height
+
+ opacity: 0.2
+ color: Material.accent
+ }
+
+ 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
+ text: currentRoom ? currentRoom.usersTyping : ""
+
+ Material.foreground: "white"
+ }
+
+ Keys.onReturnPressed: {
+ if (event.modifiers & Qt.ShiftModifier) {
+ insert(cursorPosition, "\n")
+ } else {
+ postMessage(text)
+ text = ""
+ }
+ }
+
+ Keys.onBacktabPressed: if (isAutoCompleting) autoCompleteListView.decrementCurrentIndex()
+
+ Keys.onTabPressed: {
+ if (isAutoCompleting) {
+ autoCompleteListView.incrementCurrentIndex()
+ } else {
+ autoCompleteBeginPosition = text.substring(0, cursorPosition).lastIndexOf(" ") + 1
+ var autoCompletePrefix = text.substring(0, cursorPosition).split(" ").pop()
+ if (!autoCompletePrefix) return
+ if (autoCompletePrefix.startsWith(":")) {
+ autoCompleteBeginPosition = text.substring(0, cursorPosition).lastIndexOf(" ") + 1
+ autoCompleteModel = emojiModel.filterModel(autoCompletePrefix)
+ if (autoCompleteModel.length === 0) return
+ isAutoCompleting = true
+ autoCompleteEndPosition = cursorPosition
+ } else {
+ autoCompleteModel = currentRoom.getUsers(autoCompletePrefix)
+ if (autoCompleteModel.length === 0) return
+ isAutoCompleting = true
+ autoCompleteEndPosition = cursorPosition
+ }
+ }
+ replaceAutoComplete(autoCompleteListView.currentItem.autoCompleteText)
+ }
+
+ onTextChanged: {
+ timeoutTimer.restart()
+ repeatTimer.start()
+ currentRoom.cachedInput = text
+
+ if (cursorPosition !== autoCompleteBeginPosition && cursorPosition !== autoCompleteEndPosition) {
+ isAutoCompleting = false
+ autoCompleteListView.currentIndex = 0
+ }
+ }
+
+ function replaceAutoComplete(word) {
+ remove(autoCompleteBeginPosition, autoCompleteEndPosition)
+ autoCompleteEndPosition = autoCompleteBeginPosition + word.length
+ insert(cursorPosition, word)
+ }
+
+ function postMessage(text) {
+ if (text.trim().length === 0) { return }
+ if(!currentRoom) { return }
+
+ var PREFIX_ME = '/me '
+ var PREFIX_NOTICE = '/notice '
+ var PREFIX_RAINBOW = '/rainbow '
+ var PREFIX_HTML = '/html '
+ var PREFIX_MARKDOWN = '/md '
+
+ if (isReply) {
+ currentRoom.sendReply(replyUserID, replyEventID, replyContent, text)
+ clearReply()
+ 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)
+ }
+ }
+
+ ToolButton {
+ Layout.alignment: Qt.AlignBottom
+
+ id: emojiButton
+
+ contentItem: MaterialIcon {
+ icon: "\ue24e"
+ }
+
+ onClicked: emojiPicker.visible = !emojiPicker.visible
}
}
}
diff --git a/qml/main.qml b/qml/main.qml
index 487ae7117..a6eb9d15e 100644
--- a/qml/main.qml
+++ b/qml/main.qml
@@ -28,8 +28,8 @@ ApplicationWindow {
visible: true
title: qsTr("Spectral")
- Material.foreground: Material.theme == Material.Dark ? "#FFFFFF" : "#1D333E"
- Material.background: Material.theme == Material.Dark ? "#303030" : "#FFFFFF"
+ Material.foreground: MSettings.darkTheme ? "#FFFFFF" : "#1D333E"
+ Material.background: MSettings.darkTheme ? "#303030" : "#FFFFFF"
Platform.SystemTrayIcon {
visible: MSettings.showTray