From 62a97d2b4be26c18a65bceb7087f464a3eaaa875 Mon Sep 17 00:00:00 2001 From: "pls.153" Date: Mon, 11 Sep 2023 14:23:52 +0200 Subject: [PATCH] example 'meshtastic': add broadcast messages --- examples/meshtastic/lisp/group.lisp | 32 +++++++++++++------- examples/meshtastic/lisp/lora.lisp | 11 +++++-- examples/meshtastic/lisp/package.lisp | 2 ++ examples/meshtastic/qml/ext/Group.qml | 34 +++++++++++++++------- examples/meshtastic/qml/ext/MainView.qml | 2 ++ examples/meshtastic/qml/img/broadcast.png | Bin 0 -> 12346 bytes 6 files changed, 56 insertions(+), 25 deletions(-) create mode 100644 examples/meshtastic/qml/img/broadcast.png diff --git a/examples/meshtastic/lisp/group.lisp b/examples/meshtastic/lisp/group.lisp index 00842dc..f2138f5 100644 --- a/examples/meshtastic/lisp/group.lisp +++ b/examples/meshtastic/lisp/group.lisp @@ -13,6 +13,14 @@ "Adds passed PERSON (a PLIST) to QML item model. The model keys are: :radio-name :custom-name :node-num :unread :current" + (when (zerop (q< |count| ui:*group*)) + ;; special item 'Broadcast' + (qjs |addPerson| ui:*group* + (list :radio-name lora:*broadcast-name* + :custom-name (tr "Broadcast") + :node-num lora:+broadcast-id+ + :current (equal (app:setting :latest-receiver) + lora:*broadcast-name*)))) (qjs |addPerson| ui:*group* person)) (defun clear () @@ -31,18 +39,20 @@ (q> |visible| ui:*unread-messages* state)) (defun set-unread (name n) - (qjs |setUnread| ui:*group* - name n) - (when (plusp n) - (set-unread-state t))) + (unless (string= lora:*broadcast-name* name) + (qjs |setUnread| ui:*group* + name n) + (when (plusp n) + (set-unread-state t)))) (defun receiver-changed () (let ((curr-name (app:setting :latest-receiver))) - (app:change-setting curr-name 0 :sub-key :unread-messages) - (set-unread curr-name 0) - (dolist (name (radio-names)) - (x:when-it (app:setting name :unread-messages) - (unless (zerop x:it) - (return-from receiver-changed)))) - (set-unread-state nil))) + (unless (string= lora:*broadcast-name* curr-name) + (app:change-setting curr-name 0 :sub-key :unread-messages) + (set-unread curr-name 0) + (dolist (name (radio-names)) + (x:when-it (app:setting name :unread-messages) + (unless (zerop x:it) + (return-from receiver-changed)))) + (set-unread-state nil)))) diff --git a/examples/meshtastic/lisp/lora.lisp b/examples/meshtastic/lisp/lora.lisp index 85b83f8..99698e2 100644 --- a/examples/meshtastic/lisp/lora.lisp +++ b/examples/meshtastic/lisp/lora.lisp @@ -28,6 +28,9 @@ ;;; ini/send/receive +(defconstant +broadcast-id+ #xffffffff) +(defparameter *broadcast-name* "ffff") + (defvar *config-id* 0) (defvar *config-complete* nil) (defvar *notify-id* nil) @@ -162,9 +165,11 @@ (values)) (defun node-to-name (num) - (dolist (info *node-infos*) - (when (= num (me:num info)) - (return (me:short-name (me:user info)))))) + (if (= +broadcast-id+ num) + *broadcast-name* + (dolist (info *node-infos*) + (when (= num (me:num info)) + (return (me:short-name (me:user info))))))) (defun name-to-node (name) (dolist (info *node-infos*) diff --git a/examples/meshtastic/lisp/package.lisp b/examples/meshtastic/lisp/package.lisp index 52066fa..2914059 100644 --- a/examples/meshtastic/lisp/package.lisp +++ b/examples/meshtastic/lisp/package.lisp @@ -26,6 +26,8 @@ (:local-nicknames (:pr :cl-protobufs) (:me :cl-protobufs.meshtastic)) (:export + #:+broadcast-id+ + #:*broadcast-name* #:*channel* #:*channels* #:*config-complete* diff --git a/examples/meshtastic/qml/ext/Group.qml b/examples/meshtastic/qml/ext/Group.qml index f79afeb..f5ba51e 100644 --- a/examples/meshtastic/qml/ext/Group.qml +++ b/examples/meshtastic/qml/ext/Group.qml @@ -54,27 +54,28 @@ Rectangle { function addPerson(person) { // insert sorted - var i = 0; + var i = 1; // 0 is broadcast + var broadcast = (count === 0) for (; i < count; i++) { if (person.customName < get(i).customName) { insert(i, person) break } } - if (i === count) { + if (broadcast || (i === count)) { append(person) } if (person.current) { - view.currentIndex = i + view.currentIndex = broadcast ? 0 : i view.positionViewAtIndex(view.currentIndex, ListView.Contain) } } function sortRenamed(name, index) { var to = -1 - if (name < get(0).customName) { - to = 0 + if (name < get(1).customName) { // 0 is broadcast + to = 1 } else if (name >= get(count - 1).customName) { to = count - 1 } else { @@ -124,13 +125,21 @@ Rectangle { Rectangle { id: rectRadio - x: 10 - width: 42 - height: 15 + x: (index === 0) ? 18 : 10 + width: (index === 0) ? 28 : 42 + height: (index === 0) ? width : 15 anchors.verticalCenter: parent.verticalCenter color: "#f0f0f0" radius: height / 2 + Image { + anchors.centerIn: parent + width: 20 + height: width + source: "../img/broadcast.png" + visible: (index === 0) + } + Text { anchors.centerIn: parent font.pixelSize: 12 @@ -138,6 +147,7 @@ Rectangle { font.weight: Font.DemiBold color: "black" text: model.radioName + visible: (index !== 0) } } @@ -178,9 +188,11 @@ Rectangle { } onPressAndHold: { - readOnly = false - selectAll() - forceActiveFocus() + if (index !== 0) { + readOnly = false + selectAll() + forceActiveFocus() + } } onEditingFinished: { diff --git a/examples/meshtastic/qml/ext/MainView.qml b/examples/meshtastic/qml/ext/MainView.qml index 00a23e1..c366ce0 100644 --- a/examples/meshtastic/qml/ext/MainView.qml +++ b/examples/meshtastic/qml/ext/MainView.qml @@ -5,6 +5,8 @@ import "." as Ext Item { anchors.fill: parent + property alias currentIndex: swipeView.currentIndex + Rectangle { id: header width: parent.width diff --git a/examples/meshtastic/qml/img/broadcast.png b/examples/meshtastic/qml/img/broadcast.png new file mode 100644 index 0000000000000000000000000000000000000000..251b97f63297f7f42197548a86dda154c1b08d3d GIT binary patch literal 12346 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