diff --git a/qml/main.qml b/qml/main.qml
index 3c3b6f7..98724f9 100644
--- a/qml/main.qml
+++ b/qml/main.qml
@@ -6,6 +6,7 @@ import QtQuick.Layouts 1.3
import QtQuick.Window 2.11
import "fonts/Twemoji.js" as T
+import "overlays"
import "panes"
import "widgets"
@@ -117,7 +118,7 @@ Item {
}
}
- Rectangle { // THE RIGHT PANE WHERE THE MESSAGES AND STuFF GO
+ Rectangle { // THE RIGHT PANE WHERE THE MESSAGES AND STUFF GO
color: "#EEEEFF"
Layout.fillWidth: true
Layout.fillHeight: true
@@ -139,7 +140,7 @@ Item {
Item {} // empty
- MessageList { // messagePane
+ OverlayPane { // messagePane
anchors.fill: parent
}
diff --git a/qml/overlays/BulletinOverlay.qml b/qml/overlays/BulletinOverlay.qml
new file mode 100644
index 0000000..d6679a8
--- /dev/null
+++ b/qml/overlays/BulletinOverlay.qml
@@ -0,0 +1,85 @@
+import QtGraphicalEffects 1.0
+import QtQuick 2.7
+import QtQuick.Controls 2.4
+import QtQuick.Controls.Material 2.0
+import QtQuick.Layouts 1.3
+
+import "../widgets"
+import "../widgets/controls" as Awesome
+import "../fonts/Twemoji.js" as T
+
+ColumnLayout {
+ Layout.fillWidth: true
+
+
+ Flickable { // THE MESSAGE LIST ITSELF
+ id: sv
+ clip: true
+ Layout.alignment: Qt.AlignLeft | Qt.AlignTop
+ Layout.fillHeight: true
+ Layout.minimumWidth: parent.width
+ Layout.maximumWidth: parent.width
+ Layout.fillWidth: true
+ contentWidth: colMessages.width
+ contentHeight: colMessages.height
+ boundsBehavior: Flickable.StopAtBounds
+ maximumFlickVelocity: 800
+
+
+ Connections {
+ target: gcd
+
+ onClearMessages: function() {
+ messagesModel.clear()
+ }
+
+ onAppendMessage: function(handle, from, displayName, message, image, mid, fromMe, ts) {
+ messagesModel.append({
+ "_handle": handle,
+ "_from": from,
+ "_displayName": displayName,
+ "_message": parse(message, 12),
+ "_image": image,
+ "_mid": mid,
+ "_fromMe": fromMe,
+ "_ts": ts,
+ })
+
+ if (sv.contentY + sv.height >= sv.contentHeight - colMessages.height && sv.contentHeight > sv.height) {
+ sv.contentY = sv.contentHeight - sv.height
+ }
+ }
+ }
+
+
+ ScrollBar.vertical: ScrollBar{
+ policy: ScrollBar.AlwaysOn
+ }
+
+ ColumnLayout {
+ id: colMessages
+ width: sv.width
+
+
+ ListModel { // MESSAGE OBJECTS ARE STORED HERE ...
+ id: messagesModel
+ }
+
+ Item { height: 6 }
+
+ Repeater { // ... AND DISPLAYED HERE
+ model: messagesModel
+ delegate: Message {
+ handle: _handle
+ from: _from
+ displayName: _displayName
+ message: "bulletinbulletinbulletin"
+ image: _image
+ messageID: _mid
+ fromMe: _fromMe
+ timestamp: _ts
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/qml/widgets/MessageList.qml b/qml/overlays/ChatOverlay.qml
similarity index 93%
rename from qml/widgets/MessageList.qml
rename to qml/overlays/ChatOverlay.qml
index 494a289..02e3dfc 100644
--- a/qml/widgets/MessageList.qml
+++ b/qml/overlays/ChatOverlay.qml
@@ -4,22 +4,14 @@ import QtQuick.Controls 2.4
import QtQuick.Controls.Material 2.0
import QtQuick.Layouts 1.3
-import "controls" as Awesome
+import "../widgets"
+import "../widgets/controls" as Awesome
import "../fonts/Twemoji.js" as T
ColumnLayout {
Layout.fillWidth: true
- StackToolbar {
- text: "open privacy exec"
-
- aux.onClicked: {
- theStack.pane = gcd.currentOpenConversation.length == 32 ? theStack.groupProfilePane : theStack.userProfilePane
- gcd.requestGroupSettings()
- }
- }
-
Flickable { // THE MESSAGE LIST ITSELF
id: sv
clip: true
@@ -42,11 +34,19 @@ ColumnLayout {
}
onAppendMessage: function(handle, from, displayName, message, image, mid, fromMe, ts) {
+ var msg
+ try {
+ msg = JSON.parse(message)
+ } catch (e) {
+ msg = {"o": 1, "d": "(legacy message type) " + message}
+ }
+ if (msg.o != 1) return
+
messagesModel.append({
"_handle": handle,
"_from": from,
"_displayName": displayName,
- "_message": parse(message, 12),
+ "_message": parse(msg.d, 12),
"_image": image,
"_mid": mid,
"_fromMe": fromMe,
@@ -226,7 +226,8 @@ ColumnLayout {
onClicked: {
if (txtMessage.text != "") {
txtHidden.text = restoreEmoji(txtMessage.text)
- gcd.sendMessage(txtHidden.getText(0, txtHidden.text.length), nextMessageID++)
+ var msg = JSON.stringify({"o":1, "d":txtHidden.getText(0, txtHidden.text.length)})
+ gcd.sendMessage(msg, nextMessageID++)
}
txtMessage.text = ""
}
diff --git a/qml/overlays/Game1Overlay.qml b/qml/overlays/Game1Overlay.qml
new file mode 100644
index 0000000..b534919
--- /dev/null
+++ b/qml/overlays/Game1Overlay.qml
@@ -0,0 +1,18 @@
+import QtGraphicalEffects 1.0
+import QtQuick 2.7
+import QtQuick.Controls 2.4
+import QtQuick.Controls.Material 2.0
+import QtQuick.Layouts 1.3
+
+import "../widgets"
+import "../widgets/controls" as Awesome
+import "../fonts/Twemoji.js" as T
+
+ColumnLayout {
+ Layout.fillWidth: true
+
+
+ ScalingLabel {
+ text: "gardening game or maybe some other cool cwtch-enabled game"
+ }
+}
\ No newline at end of file
diff --git a/qml/overlays/Game2Overlay.qml b/qml/overlays/Game2Overlay.qml
new file mode 100644
index 0000000..4cae0c4
--- /dev/null
+++ b/qml/overlays/Game2Overlay.qml
@@ -0,0 +1,18 @@
+import QtGraphicalEffects 1.0
+import QtQuick 2.7
+import QtQuick.Controls 2.4
+import QtQuick.Controls.Material 2.0
+import QtQuick.Layouts 1.3
+
+import "../widgets"
+import "../widgets/controls" as Awesome
+import "../fonts/Twemoji.js" as T
+
+ColumnLayout {
+ Layout.fillWidth: true
+
+
+ ScalingLabel {
+ text: "rock paper scissors. or chess? basically the same thing"
+ }
+}
\ No newline at end of file
diff --git a/qml/overlays/ListOverlay.qml b/qml/overlays/ListOverlay.qml
new file mode 100644
index 0000000..b53ddd9
--- /dev/null
+++ b/qml/overlays/ListOverlay.qml
@@ -0,0 +1,262 @@
+import QtGraphicalEffects 1.0
+import QtQuick 2.7
+import QtQuick.Controls 2.4
+import QtQuick.Controls.Material 2.0
+import QtQuick.Layouts 1.3
+
+import "../widgets"
+import "../widgets/controls" as Awesome
+import "../fonts/Twemoji.js" as T
+
+ColumnLayout {
+ Layout.fillWidth: true
+
+
+ Flickable { // THE MESSAGE LIST ITSELF
+ id: sv
+ clip: true
+ Layout.alignment: Qt.AlignLeft | Qt.AlignTop
+ Layout.fillHeight: true
+ Layout.minimumWidth: parent.width
+ Layout.maximumWidth: parent.width
+ Layout.fillWidth: true
+ contentWidth: colMessages.width
+ contentHeight: colMessages.height
+ boundsBehavior: Flickable.StopAtBounds
+ maximumFlickVelocity: 800
+
+
+ Connections {
+ target: gcd
+
+ onClearMessages: function() {
+ messagesModel.clear()
+ }
+
+ onAppendMessage: function(handle, from, displayName, message, image, mid, fromMe, ts) {
+ var msg
+ try {
+ msg = JSON.parse(message)
+ } catch (e) {
+ msg = {"o": 1, "d": "(legacy message type) " + message}
+ }
+ if (msg.o != 2) return
+
+ messagesModel.append({
+ "_handle": handle,
+ "_from": from,
+ "_displayName": displayName,
+ "_message": parse(msg.d, 12),
+ "_image": image,
+ "_mid": mid,
+ "_fromMe": fromMe,
+ "_ts": ts,
+ })
+
+ if (sv.contentY + sv.height >= sv.contentHeight - colMessages.height && sv.contentHeight > sv.height) {
+ sv.contentY = sv.contentHeight - sv.height
+ }
+ }
+ }
+
+
+ ScrollBar.vertical: ScrollBar{
+ policy: ScrollBar.AlwaysOn
+ }
+
+ ColumnLayout {
+ id: colMessages
+ width: sv.width
+
+
+ ListModel { // MESSAGE OBJECTS ARE STORED HERE ...
+ id: messagesModel
+ }
+
+ Item { height: 6 }
+
+ Repeater { // ... AND DISPLAYED HERE
+ model: messagesModel
+ delegate: Message {
+ handle: _handle
+ from: _from
+ displayName: _displayName
+ message: "be gay, do crimes, and make lists"
+ image: _image
+ messageID: _mid
+ fromMe: _fromMe
+ timestamp: _ts
+ }
+ }
+ }
+ }
+
+ RowLayout { // THE BOTTOM DRAWER
+ Rectangle { // MESSAGE ENTRY TEXTFIELD
+ id: rectMessage
+ Layout.fillWidth: true
+ Layout.minimumHeight: 40 * gcd.themeScale
+ Layout.maximumHeight: 40 * gcd.themeScale
+ color: "#EDEDED"
+ border.color: "#AAAAAA"
+ radius: 10
+
+
+ Flickable {
+ id: flkMessage
+ anchors.fill: parent//this does nothing! bug in qt
+ Layout.minimumWidth: parent.width
+ Layout.maximumWidth: parent.width
+ Layout.minimumHeight: rectMessage.height
+ Layout.maximumHeight: rectMessage.height
+ contentWidth: txtMessage.width
+ contentHeight: txtMessage.height
+ boundsBehavior: Flickable.StopAtBounds
+ clip:true
+ maximumFlickVelocity: 300
+
+
+ ScrollBar.vertical: ScrollBar{}
+
+ TextEdit {
+ id: txtMessage
+ font.pixelSize: 10
+ text: ""
+ padding: 6
+ wrapMode: TextEdit.Wrap
+ textFormat: Text.RichText
+ width: rectMessage.width
+ //height: parent.height
+
+ property bool skipOneUpdate: false
+
+ Keys.onReturnPressed: { // CTRL+ENTER = LINEBREAK
+ if (event.modifiers & Qt.ControlModifier) {
+ txtMessage.insert(txtMessage.cursorPosition, "
")
+ } else if (event.modifiers == Qt.NoModifier) {
+ btnSend.clicked()
+ }
+ }
+
+ // welcome to the emoji parser! it is horrifying code that needs to leave in
+ // while also stripping any other tag, including other images.
+ // TODO: this probably breaks if people actually do want to paste html
+ onTextChanged: {
+ //console.log("onTextChanged()")
+
+ // we're taking advantage of TextEdit.getText()'s parsing capability, which means occasionally
+ // passing text into it to be filtered. this prevents recursive calls putting us into an
+ // infinite loop
+ if (skipOneUpdate) {
+ console.log("skipping one update")
+ skipOneUpdate = false
+ return
+ }
+
+ //console.log("1: " + txtMessage.getText(0, txtMessage.text.length))
+
+ // convert tags back to their emoji form
+ var nt = restoreEmoji(txtMessage.text)
+ if (nt != txtMessage.text) {
+ skipOneUpdate = true
+ txtMessage.text = nt
+ }
+
+ //console.log("2: " + txtMessage.getText(0, txtMessage.text.length))
+
+ // strip all HTML tags
+ var theText = txtMessage.getText(0, txtMessage.text.length)
+ //console.log("3: " + theText)
+
+ // convert emoji back to tags
+ nt = parse(theText, 10)
+ //console.log("4: " + nt)
+
+ // if there were changes...
+ if (nt != txtMessage.getText(0, txtMessage.text.length)) {
+ // first we need to update the cursor position to be the same distance from the end
+ var oldcursor = txtMessage.cursorPosition
+ var oldlen = txtMessage.getText(0, txtMessage.text.length).length
+
+ // then we actually put the updated text in
+ skipOneUpdate = true
+ txtMessage.text = nt
+
+ // and then restore the cursor
+ var newlen = txtMessage.getText(0, txtMessage.text.length).length
+ txtMessage.cursorPosition = newlen - (oldlen - oldcursor)
+ }
+
+ // autoscroll down only when the scrollbar is already all the way down
+ if (flkMessage.contentY + flkMessage.height >= flkMessage.contentHeight - txtMessage.height && flkMessage.contentHeight > flkMessage.height) {
+ flkMessage.contentY = flkMessage.contentHeight - flkMessage.height
+ }
+ }
+ }
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: txtMessage.focus = true
+ }
+ }
+
+ ColumnLayout {
+ id: colRight
+ spacing: 1
+
+
+ SimpleButton { // SEND MESSAGE BUTTON
+ id: btnSend
+ icon: "regular/paper-plane"
+ text: "send"
+ Layout.minimumWidth: btnEmoji.width + btnAttach.width + 2
+ Layout.maximumWidth: btnEmoji.width + btnAttach.width + 2
+ anchors.right: parent.right
+ anchors.rightMargin: 2
+
+ property int nextMessageID: 1
+
+ TextEdit {
+ id: txtHidden
+ visible: false
+ textFormat: Text.RichText
+ }
+
+ onClicked: {
+ if (txtMessage.text != "") {
+ txtHidden.text = restoreEmoji(txtMessage.text)
+ var msg = JSON.stringify({"o":2, "d":txtHidden.getText(0, txtHidden.text.length)})
+ gcd.sendMessage(msg, nextMessageID++)
+ }
+ txtMessage.text = ""
+ }
+ }
+
+ RowLayout {
+ spacing: 1
+
+
+ SimpleButton { // EMOJI DRAWER BUTTON
+ id: btnEmoji
+ icon: "regular/smile"
+ anchors.right: btnAttach.left
+ anchors.rightMargin: 2
+
+ onClicked: gcd.popup("emoji not yet implemented, sorry")
+ }
+
+ SimpleButton {
+ id: btnAttach
+ icon: "solid/paperclip"
+ anchors.right: parent.right
+ anchors.rightMargin: 2
+
+ onClicked: {
+ gcd.popup("attachments not yet implemented, sorry")
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/qml/panes/OverlayPane.qml b/qml/panes/OverlayPane.qml
new file mode 100644
index 0000000..c8b83fd
--- /dev/null
+++ b/qml/panes/OverlayPane.qml
@@ -0,0 +1,89 @@
+import QtGraphicalEffects 1.0
+import QtQuick 2.7
+import QtQuick.Controls 2.4
+import QtQuick.Controls.Material 2.0
+import QtQuick.Layouts 1.3
+
+import "../widgets"
+import "../overlays"
+
+ColumnLayout {
+ Layout.fillWidth: true
+
+
+ StackToolbar {
+ text: "open privacy exec"
+
+ aux.onClicked: {
+ theStack.pane = gcd.currentOpenConversation.length == 32 ? theStack.groupProfilePane : theStack.userProfilePane
+ gcd.requestGroupSettings()
+ }
+ }
+
+ Row {
+ id: switcher
+
+
+ SimpleButton {
+ text: "Chat"
+
+
+ onClicked: overlayStack.overlay = overlayStack.chatOverlay
+ }
+
+ SimpleButton {
+ text: "Lists"
+
+
+ onClicked: overlayStack.overlay = overlayStack.listOverlay
+ }
+
+ SimpleButton {
+ text: "Bulletins"
+
+
+ onClicked: overlayStack.overlay = overlayStack.bulletinOverlay
+ }
+
+ SimpleButton {
+ text: "Game 1"
+
+
+ onClicked: overlayStack.overlay = overlayStack.game1Overlay
+ }
+
+ SimpleButton {
+ text: "Game 2"
+
+
+ onClicked: overlayStack.overlay = overlayStack.game2Overlay
+ }
+ }
+
+ StackLayout {
+ id: overlayStack
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+ anchors.top: switcher.bottom
+ currentIndex: 0
+
+ property alias overlay: overlayStack.currentIndex
+ readonly property int chatOverlay: 0
+ readonly property int listOverlay: 1
+ readonly property int bulletinOverlay: 2
+ readonly property int game1Overlay: 3
+ readonly property int game2Overlay: 4
+
+
+ ChatOverlay {} //0
+
+ ListOverlay{} //1
+
+ BulletinOverlay{} //2
+
+ Game1Overlay{} //3
+
+ Game2Overlay{} //4
+ }
+}
\ No newline at end of file