forked from cwtch.im/ui
Merge branch 'textfix' of cwtch.im/ui into master
This commit is contained in:
commit
b9211272dd
|
@ -2,26 +2,52 @@ import QtGraphicalEffects 1.0
|
||||||
import QtQuick 2.7
|
import QtQuick 2.7
|
||||||
import QtQuick.Controls 2.4
|
import QtQuick.Controls 2.4
|
||||||
import QtQuick.Controls.Material 2.0
|
import QtQuick.Controls.Material 2.0
|
||||||
|
import QtQuick.Controls 1.4
|
||||||
import QtQuick.Layouts 1.3
|
import QtQuick.Layouts 1.3
|
||||||
|
|
||||||
import "../widgets"
|
import "../widgets"
|
||||||
import "../widgets/controls" as Awesome
|
import "../widgets/controls" as Awesome
|
||||||
import "../fonts/Twemoji.js" as T
|
import "../fonts/Twemoji.js" as T
|
||||||
|
import "../utils.js" as Utils
|
||||||
|
import "../styles"
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
width:parent.width
|
||||||
|
|
||||||
|
Text {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: parent.toolbar.text + " Lists"
|
||||||
|
}
|
||||||
|
|
||||||
|
TextField {
|
||||||
|
id: filter
|
||||||
|
|
||||||
|
placeholderText: "Search.."
|
||||||
|
|
||||||
|
style: CwtchTextFieldStyle{}
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
|
anchors.margins: 10
|
||||||
|
|
||||||
|
onTextChanged: {
|
||||||
|
bulletinView.filter = text
|
||||||
|
if (bulletinView.model.get(bulletinView.currentIndex).title.indexOf(text) == -1) {
|
||||||
|
bulletinView.currentIndex = -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Flickable { // THE MESSAGE LIST ITSELF
|
Flickable { // THE MESSAGE LIST ITSELF
|
||||||
id: sv
|
id: sv
|
||||||
clip: true
|
clip: true
|
||||||
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
|
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
Layout.minimumWidth: parent.width
|
|
||||||
Layout.maximumWidth: parent.width
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
contentWidth: colMessages.width
|
contentWidth: bulletin.width
|
||||||
contentHeight: colMessages.height
|
contentHeight: bulletin.height
|
||||||
boundsBehavior: Flickable.StopAtBounds
|
boundsBehavior: Flickable.StopAtBounds
|
||||||
maximumFlickVelocity: 800
|
maximumFlickVelocity: 800
|
||||||
|
|
||||||
|
@ -30,28 +56,34 @@ ColumnLayout {
|
||||||
target: gcd
|
target: gcd
|
||||||
|
|
||||||
onClearMessages: function() {
|
onClearMessages: function() {
|
||||||
messagesModel.clear()
|
jsonModel4.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
onAppendMessage: function(handle, from, displayName, message, image, mid, fromMe, ts) {
|
onAppendMessage: function(handle, from, displayName, message, image, mid, fromMe, ts) {
|
||||||
var msg
|
var msg
|
||||||
try {
|
try {
|
||||||
msg = JSON.parse(message)
|
msg = JSON.parse(message)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
msg = {"o": 1, "d": "(legacy message type) " + message}
|
return
|
||||||
}
|
}
|
||||||
if (msg.o != 2) return
|
if (msg.o != 4) return
|
||||||
|
|
||||||
messagesModel.append({
|
if (msg.t != undefined) {
|
||||||
"_handle": handle,
|
jsonModel4.insert(0,{
|
||||||
"_from": from,
|
"title":msg.t,
|
||||||
"_displayName": displayName,
|
"selected":false,
|
||||||
"_message": parse(msg.d, 12),
|
"from": from,
|
||||||
"_image": image,
|
"displayName": displayName,
|
||||||
"_mid": mid,
|
"timestamp": ts,
|
||||||
"_fromMe": fromMe,
|
"complete": false
|
||||||
"_ts": ts,
|
})
|
||||||
})
|
}
|
||||||
|
|
||||||
|
if(msg.c != undefined) {
|
||||||
|
console.log("Checking off " + msg.c)
|
||||||
|
console.log(jsonModel4.get(msg.c).title)
|
||||||
|
jsonModel4.get(msg.c).complete = true
|
||||||
|
}
|
||||||
|
|
||||||
if (sv.contentY + sv.height >= sv.contentHeight - colMessages.height && sv.contentHeight > sv.height) {
|
if (sv.contentY + sv.height >= sv.contentHeight - colMessages.height && sv.contentHeight > sv.height) {
|
||||||
sv.contentY = sv.contentHeight - sv.height
|
sv.contentY = sv.contentHeight - sv.height
|
||||||
|
@ -59,204 +91,123 @@ ColumnLayout {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ScrollBar.vertical: ScrollBar{
|
ScrollBar.vertical: ScrollBar{
|
||||||
policy: ScrollBar.AlwaysOn
|
policy: ScrollBar.AlwaysOn
|
||||||
}
|
}
|
||||||
|
|
||||||
ColumnLayout {
|
ListView {
|
||||||
id: colMessages
|
id: bulletinView
|
||||||
width: sv.width
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: 10
|
||||||
|
anchors.topMargin: 10
|
||||||
|
|
||||||
|
width: parent.width - 50
|
||||||
|
height: parent.height - 20
|
||||||
|
orientation: Qt.Vertical
|
||||||
|
spacing: 10
|
||||||
|
model: jsonModel4
|
||||||
|
property string filter: ""
|
||||||
|
delegate:
|
||||||
|
|
||||||
|
Item {
|
||||||
|
width: parent.width
|
||||||
|
height: title.indexOf(bulletinView.filter) >= 0 ? texttitle.height : 0
|
||||||
|
visible: title.indexOf(bulletinView.filter) >= 0
|
||||||
|
|
||||||
|
Column {
|
||||||
|
width: parent.width
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
CheckBox {
|
||||||
|
checked: complete
|
||||||
|
checkedState: complete ? Qt.Checked : Qt.UnChecked
|
||||||
|
onClicked: {
|
||||||
|
var msg = JSON.stringify({"o":4, "c":index})
|
||||||
|
gcd.sendMessage(msg, btnSend.nextMessageID++)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Text {
|
||||||
|
id: texttitle
|
||||||
|
text: '<b>' + Utils.htmlEscaped(title) + '</b> by ' + from + "<br/>" + timestamp
|
||||||
|
leftPadding: 10
|
||||||
|
topPadding: 5
|
||||||
|
bottomPadding:5
|
||||||
|
color: windowItem.cwtch_dark_color
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ListModel { // MESSAGE OBJECTS ARE STORED HERE ...
|
Rectangle {
|
||||||
id: messagesModel
|
height: 1
|
||||||
}
|
color: windowItem.cwtch_color
|
||||||
|
anchors {
|
||||||
|
left: parent.left
|
||||||
|
right: parent.right
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Item { height: 6 }
|
|
||||||
|
|
||||||
Repeater { // ... AND DISPLAYED HERE
|
}
|
||||||
model: messagesModel
|
|
||||||
delegate: Message {
|
}
|
||||||
handle: _handle
|
|
||||||
from: _from
|
focus: true
|
||||||
displayName: _displayName
|
ListModel {
|
||||||
message: "be gay, do crimes, and make lists"
|
id: jsonModel4
|
||||||
image: _image
|
|
||||||
messageID: _mid
|
|
||||||
fromMe: _fromMe
|
|
||||||
timestamp: _ts
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RowLayout { // THE BOTTOM DRAWER
|
GroupBox {
|
||||||
Rectangle { // MESSAGE ENTRY TEXTFIELD
|
title: qsTr("Add a New List Item")
|
||||||
id: rectMessage
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.minimumHeight: 40 * gcd.themeScale
|
width: parent.width
|
||||||
Layout.maximumHeight: 40 * gcd.themeScale
|
ColumnLayout {
|
||||||
color: "#EDEDED"
|
Layout.fillWidth: true
|
||||||
border.color: "#AAAAAA"
|
|
||||||
radius: 10
|
|
||||||
|
|
||||||
|
|
||||||
Flickable {
|
Text {
|
||||||
id: flkMessage
|
text: "Add a new item to the list"
|
||||||
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: {
|
TextField {
|
||||||
if (txtMessage.text != "") {
|
id: newposttitle
|
||||||
txtHidden.text = restoreEmoji(txtMessage.text)
|
placeholderText: "Todo.."
|
||||||
var msg = JSON.stringify({"o":2, "d":txtHidden.getText(0, txtHidden.text.length)})
|
Layout.fillWidth: true
|
||||||
gcd.sendMessage(msg, nextMessageID++)
|
style: CwtchTextFieldStyle{}
|
||||||
}
|
|
||||||
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 {
|
SimpleButton { // SEND MESSAGE BUTTON
|
||||||
id: btnAttach
|
id: btnSend
|
||||||
icon: "solid/paperclip"
|
icon: "regular/paper-plane"
|
||||||
|
text: "add"
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.rightMargin: 2
|
anchors.rightMargin: 2
|
||||||
|
|
||||||
|
property int nextMessageID: 1
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
gcd.popup("attachments not yet implemented, sorry")
|
if (newposttitle.text != "") {
|
||||||
|
var msg = JSON.stringify({"o":4, "t":newposttitle.text})
|
||||||
|
gcd.sendMessage(msg, nextMessageID++)
|
||||||
|
}
|
||||||
|
newposttitle.text = ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue