lqml/examples/Qt6/meshtastic/qml/ext/messages/Messages.qml
pls.153 dc29ac9084 add Qt6 version of some examples (see below); revisions
'9999', 'advanced-qml-auto-reload', 'planets', 'sokoban'
2024-10-22 13:27:56 +02:00

331 lines
8.1 KiB
QML

import QtQuick
import QtQuick.Controls
import QtQuick.Controls.Basic
import "." as Msg
Rectangle {
id: main
color: hourglass.visible ? "#d2eecc" : "#e5d8bd"
ListView {
id: view
objectName: "message_view"
anchors.topMargin: rectFind.height + 4
anchors.fill: parent
anchors.bottomMargin: rectEdit.height + 3
anchors.margins: 5
model: messages
clip: true
visible: false
property int fontSize: 18
delegate: SwipeDelegate {
id: swipeDelegate
width: view.width
height: delegate.height
clip: true
onPressAndHold: Lisp.call("msg:message-press-and-hold", model.text)
onDoubleClicked: Lisp.call("msg:swipe-to-left")
background: Item {
id: delegate
width: Math.max(text.paintedWidth, rowSender.width + view.fontSize / 4 * text.padding)
+ 2 * text.padding + view.fontSize / 4
height: model.hidden ? 0 : (text.contentHeight + 2 * text.padding + sender.contentHeight + 8)
Rectangle {
anchors.centerIn: parent
width: parent.width
height: parent.height - 4
color: model.me ? "#f2f2f2" : "#ffffcc"
radius: 12
Row {
id: rowSender
padding: text.padding
spacing: padding - 2
AnimatedImage {
id: semaphore
anchors.verticalCenter: sender.verticalCenter
anchors.verticalCenterOffset: -0.5
width: view.fontSize / 2 - 1
height: width
playing: false
source: "../../img/semaphore.gif"
currentFrame: model.ackState ? parseInt(model.ackState.substr(2), 16) : 0 // see 'qml:hex'
visible: model.me
}
Text {
id: sender
font.pixelSize: 2/3 * view.fontSize
font.family: fontText.name
color: "#8B0000"
text: model.senderName ? model.senderName : model.sender
}
}
Text {
id: timestamp
x: delegate.width - contentWidth - text.padding
y: text.padding
font.pixelSize: 2/3 * view.fontSize
font.family: fontText.name
color: "#505050"
text: model.hour
MouseArea {
anchors.fill: parent
onClicked: Lisp.call("msg:show-date", model.timestamp)
}
}
Text {
id: text
y: sender.contentHeight
width: main.width - 10
padding: 5
wrapMode: Text.Wrap
font.pixelSize: view.fontSize
font.family: fontText.name
color: "#303030"
textFormat: Text.StyledText // for 'paintedWidth' to always work
text: model.text
}
}
}
ListView.onRemove: SequentialAnimation {
PropertyAction {
target: swipeDelegate
property: "ListView.delayRemove"
value: true
}
NumberAnimation {
target: swipeDelegate
property: "height"
to: 0
easing.type: Easing.InOutQuad
}
PropertyAction {
target: swipeDelegate
property: "ListView.delayRemove"
value: false
}
}
swipe.left: Rectangle {
y: 2
width: 35
height: parent.height - 2 * y
color: "#dd4141"
radius: 12
Image {
anchors.centerIn: parent
width: 12
height: width
source: "../../img/delete.png"
}
MouseArea {
anchors.fill: parent
onClicked: {
var mid = model.mid
view.model.remove(index)
Lisp.call("db:delete-message", mid)
}
}
}
}
}
ListModel {
id: messages
objectName: "messages"
// hack to define all model key _types_
ListElement {
receiver: ""; sender: ""; senderName: ""; timestamp: ""; hour: "";
text: ""; text2: ""; mid: ""; ackState: ""; me: true; hidden: false
}
function addMessage(message) { append(message) }
function changeState(state, mid) {
for (var i = count - 1; i >= 0; i--) {
if (get(i).mid === mid) {
setProperty(i, "ackState", state)
break
}
}
}
function find(term) {
for (var i = 0; i < count; i++) {
var text = get(i).text
var highlighted = Lisp.call("msg:highlight-term", text, term)
if (highlighted) {
if (!get(i).text2) {
setProperty(i, "text2", text)
}
setProperty(i, "text", highlighted)
}
setProperty(i, "hidden", !highlighted)
}
view.positionViewAtBeginning()
}
function clearFind() {
for (var i = 0; i < count; i++) {
var text2 = get(i).text2
if (text2) {
setProperty(i, "text", text2)
setProperty(i, "text2", "")
}
setProperty(i, "hidden", false)
}
}
Component.onCompleted: remove(0) // see hack above
}
// find text
TextField {
id: findText
objectName: "find_text"
y: 1
width: parent.width
height: visible ? (edit.paintedHeight + 14) : 0
font.pixelSize: view.fontSize
font.family: fontText.name
selectionColor: "#228ae3"
selectedTextColor: "white"
placeholderText: qsTr("search")
visible: false
background: Rectangle {
id: rectFind
color: "white"
border.width: 3
border.color: findText.focus ? "dodgerblue" : "#c0c0c0"
radius: 12
}
onEditingFinished: Lisp.call("msg:find-text", text)
}
// send text
Rectangle {
id: rectEdit
anchors.bottom: parent.bottom
anchors.bottomMargin: 1
width: parent.width
height: edit.paintedHeight + 14
color: "white"
border.width: 3
border.color: edit.focus ? (edit.tooLong ? "#ff5f57" : "dodgerblue") : "#c0c0c0"
radius: 12
TextArea {
id: edit
objectName: "edit"
anchors.fill: parent
textFormat: TextEdit.PlainText
font.pixelSize: view.fontSize
font.family: fontText.name
selectionColor: "#228ae3"
selectedTextColor: "white"
wrapMode: TextEdit.Wrap
textMargin: 0
placeholderText: qsTr("message")
property bool tooLong: false
onLengthChanged: if (length > 150) Lisp.call("msg:check-utf8-length", text)
Keys.onEscapePressed: emojis.visible = false
Image {
y: 8
anchors.right: parent.right
anchors.rightMargin: 7
width: edit.font.pixelSize + 1
height: width
source: "../../img/emoji.png"
opacity: 0.55
visible: edit.focus && (Qt.platform.os !== "android") && (Qt.platform.os !== "ios")
MouseArea {
anchors.fill: parent
onClicked: emojis.visible = !emojis.visible
}
}
}
Image {
id: send
anchors.right: parent.right
anchors.bottom: parent.top
anchors.margins: 3
width: 38
height: width
source: "../../img/send.png"
visible: edit.focus && !edit.tooLong
MouseArea {
anchors.fill: parent
onClicked: {
edit.focus = Qt.NoFocus
Lisp.call("lora:send-message", edit.text)
edit.clear()
}
}
}
Image {
id: broadcast
anchors.right: send.left
anchors.bottom: parent.top
anchors.margins: 3
width: 38
height: width
opacity: 0.7
source: "../../img/broadcast.png"
visible: send.visible && animation.running
SequentialAnimation {
id: animation
loops: Animation.Infinite
running: rootItem.broadcast
ScaleAnimator {
target: broadcast
from: 0.8; to: 1.0
duration: 500
easing.type: Easing.InOutSine
}
ScaleAnimator {
target: broadcast
from: 1.0; to: 0.8
duration: 500
easing.type: Easing.InOutSine
}
}
}
}
Msg.Emojis {
id: emojis
anchors.bottom: rectEdit.top
anchors.bottomMargin: -1
width: main.width
visible: false
}
}