overlay framework

This commit is contained in:
erinn 2019-01-26 14:54:08 -08:00
parent 9357f184ba
commit e620d48bc8
7 changed files with 488 additions and 14 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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, "<br>")
} else if (event.modifiers == Qt.NoModifier) {
btnSend.clicked()
}
}
// welcome to the emoji parser! it is horrifying code that needs to leave in <img src="[emoji]">
// 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 <img> 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 <img> 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")
}
}
}
}
}
}

89
qml/panes/OverlayPane.qml Normal file
View File

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