From 6ee5b7305231c03ea0ebe2e58965a59a43233593 Mon Sep 17 00:00:00 2001 From: Brian Whelan Date: Fri, 21 Jun 2024 18:44:44 +0100 Subject: [PATCH] Add new module "reply" for canned responses Adds a new module that enables replying to messages --- apps/reply/ChangeLog | 1 + apps/reply/README.md | 23 +++++++ apps/reply/app.png | Bin 0 -> 720 bytes apps/reply/interface.html | 125 ++++++++++++++++++++++++++++++++++++++ apps/reply/lib.js | 75 +++++++++++++++++++++++ apps/reply/metadata.json | 16 +++++ 6 files changed, 240 insertions(+) create mode 100644 apps/reply/ChangeLog create mode 100644 apps/reply/README.md create mode 100644 apps/reply/app.png create mode 100644 apps/reply/interface.html create mode 100644 apps/reply/lib.js create mode 100644 apps/reply/metadata.json diff --git a/apps/reply/ChangeLog b/apps/reply/ChangeLog new file mode 100644 index 000000000..f3c7b0d2c --- /dev/null +++ b/apps/reply/ChangeLog @@ -0,0 +1 @@ +0.01: New Library! \ No newline at end of file diff --git a/apps/reply/README.md b/apps/reply/README.md new file mode 100644 index 000000000..dc874d183 --- /dev/null +++ b/apps/reply/README.md @@ -0,0 +1,23 @@ +# Canned Replies Library + +A library that handles replying to messages received from Gadgetbridge/Messages apps. + +## Replying to a message +The user can define a set of canned responses via the customise page after installing the app, or alternatively if they have a keyboard installed, they can type a response back. The requesting app will receive either an object containing the full reply for GadgetBridge, or a string with the response from the user, depending on how they wish to handle the response. + +## Integrating in your app +To use this in your app, simply call + +```js +require("reply").reply(/*options*/{...}).then(result => ...); +``` + +The ```options``` object can contain the following: + +- ```msg```: A message object containing a field ```id```, the ID to respond to. If this is included in options, the result of the promise will be an object as follows: ```{t: "notify", id: msg.id, n: "REPLY", msg: "USER REPLY"}```. If not included, the result of the promise will be an object, ```{msg: "USER REPLY"}``` +- ```shouldReply```: Whether or not the library should send the response over Bluetooth with ```Bluetooth.println(...```. Useful if the calling app wants to handle the response a different way. Default is true. +- ```title```: The title to show at the top of the menu. Defaults to ```"Reply with:"```. +- ```fileOverride```: An override file to read canned responses from, which is an array of objects each with a ```text``` property. Default is ```replies.json```. Useful for apps which might want to make use of custom canned responses. + +## Known Issues +Emojis are currently not supported. \ No newline at end of file diff --git a/apps/reply/app.png b/apps/reply/app.png new file mode 100644 index 0000000000000000000000000000000000000000..bef8338cfda0a069115cd86d0978301ec2a01156 GIT binary patch literal 720 zcmV;>0x$iEP)Ou!sS{ zQUwVs+6*>cr3f}!iG`qtjTT9xjfjF0NUNYAVxvJ5BpO0o8JLA-oY|Y*o6XLJ{oz5l zoq6y7ax-&p7HZY1RjXF5|1}J>fkhy$I2M5?zu22oJagSVp0yKr-~&L$58xuOv3%cb049KM7B3x@wTWH;2g0d51^JR08u2w>Tver|y4z<0yvUx0BB=0|{!mSua>2S5`z4Lk+@S~mIa z0>*b)HmR)f0yv{;djUw|67az=<`)nFn;i1XgWx={V94_cn9^!`1&}cY+yj0a#?Asq zGIAdTUK{2u0}p`{hI-xsk~nKQF;;=QKz}OdR-mO00Db&h;9N$X(g2cZS-RKH>f0Jq zf9ucXoR&lW(g9?gR9)<g|rFG4d z@dfptx0>$+kv=jHsU>H6>2!kt6lDPDul-(X?+5Je6EQdcy9 z=LDq40idA)d?hf64$rr10P^bCbBZ1JOt6Zp1o#KcD)dHzb{Sp(0000 + + + + + + + +
+ + + +
+
+
+ +
+
+
+
+
+
+

Loading

+

Syncing custom replies with your watch

+
+
+
+
+
+ +
+

No custom replies

+

Use the field above to add a custom reply

+
+
+ +
+
+ + + + + + \ No newline at end of file diff --git a/apps/reply/lib.js b/apps/reply/lib.js new file mode 100644 index 000000000..7bd4780a5 --- /dev/null +++ b/apps/reply/lib.js @@ -0,0 +1,75 @@ +exports.reply = function (options) { + var keyboard = "textinput"; + try { + keyboard = require(keyboard); + } catch (e) { + keyboard = null; + } + + function constructReply(msg, replyText, resolve) { + var responseMessage = {msg: replyText}; + if (msg.id) { + responseMessage = { t: "notify", id: msg.id, n: "REPLY", msg: replyText }; + } + E.showMenu(); + layout.setUI(); + layout.render(); + if (options.sendReply == null || options.sendReply) { + Bluetooth.println(JSON.stringify(result)); + } + resolve(responseMessage); + } + + return new Promise((resolve, reject) => { + var menu = { + "": { + title: options.title || /*LANG*/ "Reply with:", + back: function () { + E.showMenu(); + layout.setUI(); + layout.render(); + reject("User pressed back"); + }, + }, // options + /*LANG*/ "Compose": function () { + keyboard.input().then((result) => { + constructReply(options.msg ?? {}, result, resolve); + }); + }, + }; + var replies = + require("Storage").readJSON( + options.fileOverride || "replies.json", + true + ) || {}; + replies.forEach((reply) => { + menu = Object.defineProperty(menu, reply.text, { + value: () => constructReply(options.msg ?? {}, reply.text, resolve), + }); + }); + if (!keyboard) delete menu[/*LANG*/ "Compose"]; + + if (replies.length == 0) { + if (!keyboard) { + E.showPrompt( + /*LANG*/ "Please install a keyboard app, or set a custom reply via the app loader!", + { + buttons: { Ok: true }, + remove: function () { + layout.setUI(); + layout.render(); + reject( + "Please install a keyboard app, or set a custom reply via the app loader!" + ); + }, + } + ); + } else { + keyboard.input().then((result) => { + constructReply(options.msg.id, result, resolve); + }); + } + } + E.showMenu(menu); + }); +}; diff --git a/apps/reply/metadata.json b/apps/reply/metadata.json new file mode 100644 index 000000000..34843edd4 --- /dev/null +++ b/apps/reply/metadata.json @@ -0,0 +1,16 @@ +{ "id": "reply", + "name": "Reply Library", + "version": "0.01", + "description": "A library for replying to text messages via predefined responses or keyboard", + "icon": "app.png", + "type": "module", + "provides_modules" : ["reply"], + "tags": "", + "supports" : ["BANGLEJS2"], + "readme": "README.md", + "interface": "interface.html", + "storage": [ + {"name":"reply","url":"lib.js"} + ], + "data": [{"name":"replies.json"}] +} \ No newline at end of file