mirror of https://github.com/espruino/BangleApps
commit
85573a9817
|
@ -66,4 +66,8 @@
|
|||
0.50: Add `getMessages` and `status` functions to library
|
||||
Option to disable auto-open of messages
|
||||
Option to make message icons monochrome (not colored)
|
||||
messages widget buzz now returns a promise
|
||||
messages widget buzz now returns a promise
|
||||
0.51: Emit "message events"
|
||||
Setting to hide widget
|
||||
Add custom event handlers to prevent default app form loading
|
||||
Move WIDGETS.messages.buzz() to require("messages").buzz()
|
|
@ -25,7 +25,7 @@ it starts getting clipped.
|
|||
* `Auto-Open Music` - Should the app automatically open when the phone starts playing music?
|
||||
* `Unlock Watch` - Should the app unlock the watch when a new message arrives, so you can touch the buttons at the bottom of the app?
|
||||
* `Flash Icon` - Toggle flashing of the widget icon.
|
||||
* `Widget messages` - The maximum amount of message icons to show on the widget.
|
||||
* `Widget messages` - The maximum amount of message icons to show on the widget, or `Hide` the widget completely.
|
||||
|
||||
## New Messages
|
||||
|
||||
|
@ -56,6 +56,24 @@ _2. What the notify icon looks like (it's touchable on Bangle.js2!)_
|
|||

|
||||
|
||||
|
||||
## Events (for app/widget developers)
|
||||
|
||||
When a new message arrives, a `"message"` event is emitted, you can listen for
|
||||
it like this:
|
||||
|
||||
```js
|
||||
myMessageListener = Bangle.on("message", (type, message)=>{
|
||||
if (message.handled) return; // another app already handled this message
|
||||
// <type> is one of "text", "call", "alarm", "map", "music", or "clearAll"
|
||||
if (type === "clearAll") return; // not a message
|
||||
// see `messages/lib.js` for possible <message> formats
|
||||
// message.t could be "add", "modify" or "remove"
|
||||
E.showMessage(`${message.title}\n${message.body}`, `${message.t} ${type} message`);
|
||||
// You can prevent the default `message` app from loading by setting `message.handled = true`:
|
||||
message.handled = true;
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
## Requests
|
||||
|
||||
|
|
|
@ -54,8 +54,7 @@ var onMessagesModified = function(msg) {
|
|||
// TODO: if new, show this new one
|
||||
if (msg && msg.id!=="music" && msg.new && active!="map" &&
|
||||
!((require('Storage').readJSON('setting.json', 1) || {}).quiet)) {
|
||||
if (WIDGETS["messages"]) WIDGETS["messages"].buzz(msg.src);
|
||||
else Bangle.buzz();
|
||||
require("messages").buzz(msg.src);
|
||||
}
|
||||
if (msg && msg.id=="music") {
|
||||
if (msg.state && msg.state!="play") openMusic = false; // no longer playing music to go back to
|
||||
|
@ -356,13 +355,13 @@ function checkMessages(options) {
|
|||
// If we have a new message, show it
|
||||
if (options.showMsgIfUnread && newMessages.length) {
|
||||
showMessage(newMessages[0].id);
|
||||
// buzz after showMessage, so beingbusy during layout doesn't affect the buzz pattern
|
||||
// buzz after showMessage, so being busy during layout doesn't affect the buzz pattern
|
||||
if (global.BUZZ_ON_NEW_MESSAGE) {
|
||||
// this is set if we entered the messages app by loading `messages.new.js`
|
||||
// ... but only buzz the first time we view a new message
|
||||
global.BUZZ_ON_NEW_MESSAGE = false;
|
||||
// messages.buzz respects quiet mode - no need to check here
|
||||
WIDGETS.messages.buzz(newMessages[0].src);
|
||||
require("messages").buzz(newMessages[0].src);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -8,15 +8,11 @@ function openMusic() {
|
|||
/* Push a new message onto messages queue, event is:
|
||||
{t:"add",id:int, src,title,subject,body,sender,tel, important:bool, new:bool}
|
||||
{t:"add",id:int, id:"music", state, artist, track, etc} // add new
|
||||
{t:"remove-",id:int} // remove
|
||||
{t:"remove",id:int} // remove
|
||||
{t:"modify",id:int, title:string} // modified
|
||||
*/
|
||||
exports.pushMessage = function(event) {
|
||||
var messages, inApp = "undefined"!=typeof MESSAGES;
|
||||
if (inApp)
|
||||
messages = MESSAGES; // we're in an app that has already loaded messages
|
||||
else // no app - load messages
|
||||
messages = require("Storage").readJSON("messages.json",1)||[];
|
||||
var messages = exports.getMessages();
|
||||
// now modify/delete as appropriate
|
||||
var mIdx = messages.findIndex(m=>m.id==event.id);
|
||||
if (event.t=="remove") {
|
||||
|
@ -35,69 +31,81 @@ exports.pushMessage = function(event) {
|
|||
else Object.assign(messages[mIdx], event);
|
||||
if (event.id=="music" && messages[mIdx].state=="play") {
|
||||
messages[mIdx].new = true; // new track, or playback (re)started
|
||||
type = 'music';
|
||||
}
|
||||
}
|
||||
require("Storage").writeJSON("messages.json",messages);
|
||||
var message = mIdx<0 ? {id:event.id, t:'remove'} : messages[mIdx];
|
||||
// if in app, process immediately
|
||||
if (inApp) return onMessagesModified(mIdx<0 ? {id:event.id} : messages[mIdx]);
|
||||
if ("undefined"!=typeof MESSAGES) return onMessagesModified(message);
|
||||
// emit message event
|
||||
var type = 'text';
|
||||
if (["call", "music", "map"].includes(message.id)) type = message.id;
|
||||
if (message.src && message.src.toLowerCase().startsWith("alarm")) type = "alarm";
|
||||
Bangle.emit("message", type, message);
|
||||
// update the widget icons shown
|
||||
if (global.WIDGETS && WIDGETS.messages) WIDGETS.messages.update(messages,true);
|
||||
var handleMessage = () => {
|
||||
// if no new messages now, make sure we don't load the messages app
|
||||
if (event.t=="remove" && exports.messageTimeout && !messages.some(m=>m.new)) {
|
||||
clearTimeout(exports.messageTimeout);
|
||||
delete exports.messageTimeout;
|
||||
}
|
||||
// ok, saved now
|
||||
if (event.id=="music" && Bangle.CLOCK && messages[mIdx].new && openMusic()) {
|
||||
// just load the app to display music: no buzzing
|
||||
load("messages.app.js");
|
||||
} else if (event.t!="add") {
|
||||
// we only care if it's new
|
||||
return;
|
||||
} else if(event.new == false) {
|
||||
return;
|
||||
}
|
||||
// otherwise load messages/show widget
|
||||
var loadMessages = Bangle.CLOCK || event.important;
|
||||
var quiet = (require('Storage').readJSON('setting.json',1)||{}).quiet;
|
||||
var appSettings = require('Storage').readJSON('messages.settings.json',1)||{};
|
||||
var unlockWatch = appSettings.unlockWatch;
|
||||
// don't auto-open messages in quiet mode if quietNoAutOpn is true
|
||||
if((quiet && appSettings.quietNoAutOpn) || appSettings.noAutOpn)
|
||||
loadMessages = false;
|
||||
delete appSettings;
|
||||
// after a delay load the app, to ensure we have all the messages
|
||||
if (exports.messageTimeout) clearTimeout(exports.messageTimeout);
|
||||
exports.messageTimeout = setTimeout(function() {
|
||||
exports.messageTimeout = undefined;
|
||||
// if we're in a clock or it's important, go straight to messages app
|
||||
if (loadMessages){
|
||||
if(!quiet && unlockWatch){
|
||||
Bangle.setLocked(false);
|
||||
Bangle.setLCDPower(1); // turn screen on
|
||||
}
|
||||
// we will buzz when we enter the messages app
|
||||
return load("messages.new.js");
|
||||
if (event.t=="remove" && exports.messageTimeout && !messages.some(m => m.new)) {
|
||||
clearTimeout(exports.messageTimeout);
|
||||
delete exports.messageTimeout;
|
||||
}
|
||||
if (!quiet && (!global.WIDGETS || !WIDGETS.messages)) return Bangle.buzz(); // no widgets - just buzz once to let someone know
|
||||
if (global.WIDGETS && WIDGETS.messages) WIDGETS.messages.update(messages);
|
||||
}, 500);
|
||||
// ok, saved now
|
||||
if (event.id=="music" && Bangle.CLOCK && messages[mIdx].new && openMusic()) {
|
||||
// just load the app to display music: no buzzing
|
||||
load("messages.app.js");
|
||||
} else if (event.t!="add") {
|
||||
// we only care if it's new
|
||||
return;
|
||||
} else if (event.new==false) {
|
||||
return;
|
||||
}
|
||||
// otherwise load messages/show widget
|
||||
var loadMessages = Bangle.CLOCK || event.important;
|
||||
var quiet = (require('Storage').readJSON('setting.json', 1) || {}).quiet;
|
||||
var appSettings = require('Storage').readJSON('messages.settings.json', 1) || {};
|
||||
var unlockWatch = appSettings.unlockWatch;
|
||||
// don't auto-open messages in quiet mode if quietNoAutOpn is true
|
||||
if ((quiet && appSettings.quietNoAutOpn) || appSettings.noAutOpn)
|
||||
loadMessages = false;
|
||||
delete appSettings;
|
||||
// after a delay load the app, to ensure we have all the messages
|
||||
if (exports.messageTimeout) clearTimeout(exports.messageTimeout);
|
||||
exports.messageTimeout = setTimeout(function() {
|
||||
exports.messageTimeout = undefined;
|
||||
// if we're in a clock or it's important, go straight to messages app
|
||||
if (loadMessages) {
|
||||
if (!quiet && unlockWatch) {
|
||||
Bangle.setLocked(false);
|
||||
Bangle.setLCDPower(1); // turn screen on
|
||||
}
|
||||
// we will buzz when we enter the messages app
|
||||
return load("messages.new.js");
|
||||
}
|
||||
if (global.WIDGETS && WIDGETS.messages) WIDGETS.messages.update(messages);
|
||||
exports.buzz(message.src);
|
||||
}, 500);
|
||||
};
|
||||
setTimeout(()=>{
|
||||
if (!message.handled) handleMessage();
|
||||
},0);
|
||||
}
|
||||
/// Remove all messages
|
||||
exports.clearAll = function(event) {
|
||||
var messages, inApp = "undefined"!=typeof MESSAGES;
|
||||
if (inApp) {
|
||||
exports.clearAll = function() {
|
||||
if ("undefined"!= typeof MESSAGES) { // we're in a messages app, clear that as well
|
||||
MESSAGES = [];
|
||||
messages = MESSAGES; // we're in an app that has already loaded messages
|
||||
} else // no app - empty messages
|
||||
messages = [];
|
||||
// Save all messages
|
||||
require("Storage").writeJSON("messages.json",messages);
|
||||
// update app if in app
|
||||
if (inApp) return onMessagesModified();
|
||||
}
|
||||
// Clear all messages
|
||||
require("Storage").writeJSON("messages.json", []);
|
||||
// if we have a widget, update it
|
||||
if (global.WIDGETS && WIDGETS.messages)
|
||||
WIDGETS.messages.update(messages);
|
||||
WIDGETS.messages.update([]);
|
||||
// let message listeners know
|
||||
Bangle.emit("message", "clearAll", {}); // guarantee listeners an object as `message`
|
||||
// clearAll cannot be marked as "handled"
|
||||
// update app if in app
|
||||
if ("function"== typeof onMessagesModified) onMessagesModified();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -126,6 +134,45 @@ exports.getMessages = function() {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Start buzzing for new message
|
||||
* @param {string} msgSrc Message src to buzz for
|
||||
* @return {Promise} Resolves when initial buzz finishes (there might be repeat buzzes later)
|
||||
*/
|
||||
exports.buzz = function(msgSrc) {
|
||||
exports.stopBuzz(); // cancel any previous buzz timeouts
|
||||
if ((require('Storage').readJSON('setting.json',1)||{}).quiet) return Promise.resolve(); // never buzz during Quiet Mode
|
||||
|
||||
var pattern;
|
||||
if (msgSrc && msgSrc.toLowerCase() === "phone") {
|
||||
// special vibration pattern for incoming calls
|
||||
pattern = (require('Storage').readJSON("messages.settings.json", true) || {}).vibrateCalls;
|
||||
} else {
|
||||
pattern = (require('Storage').readJSON("messages.settings.json", true) || {}).vibrate;
|
||||
}
|
||||
if (pattern === undefined) { pattern = ":"; } // pattern may be "", so we can't use || ":" here
|
||||
if (!pattern) return Promise.resolve();
|
||||
|
||||
var repeat = (require('Storage').readJSON("messages.settings.json", true) || {}).repeat;
|
||||
if (repeat===undefined) repeat=4; // repeat may be zero
|
||||
if (repeat) {
|
||||
exports.buzzTimeout = setTimeout(()=>require("buzz").pattern(pattern), repeat*1000);
|
||||
var vibrateTimeout = (require('Storage').readJSON("messages.settings.json", true) || {}).vibrateTimeout;
|
||||
if (vibrateTimeout===undefined) vibrateTimeout=60;
|
||||
if (vibrateTimeout && !exports.stopTimeout) exports.stopTimeout = setTimeout(exports.stopTimeout, vibrateTimeout*1000);
|
||||
}
|
||||
return require("buzz").pattern(pattern);
|
||||
};
|
||||
/**
|
||||
* Stop buzzing
|
||||
*/
|
||||
exports.stopBuzz = function() {
|
||||
if (exports.buzzTimeout) clearTimeout(exports.buzzTimeout);
|
||||
delete exports.buzzTimeout;
|
||||
if (exports.stopTimeout) clearTimeout(exports.stopTimeout);
|
||||
delete exports.stopTimeout;
|
||||
};
|
||||
|
||||
exports.getMessageImage = function(msg) {
|
||||
/*
|
||||
* icons should be 24x24px or less with 1bpp colors and 'Transparency to Color'
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "messages",
|
||||
"name": "Messages",
|
||||
"version": "0.50",
|
||||
"version": "0.51",
|
||||
"description": "App to display notifications from iOS and Gadgetbridge/Android",
|
||||
"icon": "app.png",
|
||||
"type": "app",
|
||||
|
|
|
@ -73,7 +73,8 @@
|
|||
},
|
||||
/*LANG*/'Widget messages': {
|
||||
value:0|settings().maxMessages,
|
||||
min: 1, max: 5,
|
||||
min: 0, max: 5,
|
||||
format: v => v ? v :/*LANG*/"Hide",
|
||||
onchange: v => updateSetting("maxMessages", v)
|
||||
},
|
||||
/*LANG*/'Icon color mode': {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
(() => {
|
||||
if ((require('Storage').readJSON("messages.settings.json", true) || {}).maxMessages===0) return;
|
||||
|
||||
function filterMessages(msgs) {
|
||||
return msgs.filter(msg => msg.new && msg.id != "music")
|
||||
|
@ -14,15 +15,14 @@ WIDGETS["messages"]={area:"tl", width:0, draw:function(recall) {
|
|||
}
|
||||
Bangle.removeListener('touch', this.touch);
|
||||
if (!this.width) return;
|
||||
var c = (Date.now()-this.t)/1000;
|
||||
let settings = Object.assign({flash:true, maxMessages:3, repeat:4, vibrateTimeout:60},require('Storage').readJSON("messages.settings.json", true) || {});
|
||||
let settings = Object.assign({flash:true, maxMessages:3},require('Storage').readJSON("messages.settings.json", true) || {});
|
||||
if (recall !== true || settings.flash) {
|
||||
var msgsShown = E.clip(this.msgs.length, 0, settings.maxMessages);
|
||||
g.reset().clearRect(this.x, this.y, this.x+this.width, this.y+23);
|
||||
for(let i = 0;i < msgsShown;i++) {
|
||||
const msg = this.msgs[i];
|
||||
const colors = [g.theme.bg, g.setColor(require("messages").getMessageImageCol(msg)).getColor()];
|
||||
if (settings.flash && (c&1)) {
|
||||
if (settings.flash && ((Date.now()/1000)&1)) {
|
||||
if (colors[1] == g.theme.fg) {
|
||||
colors.reverse();
|
||||
} else {
|
||||
|
@ -35,38 +35,13 @@ WIDGETS["messages"]={area:"tl", width:0, draw:function(recall) {
|
|||
this.x + 12 + i * 24, this.y + 12, {rotate:0/*force centering*/});
|
||||
}
|
||||
}
|
||||
if (c<settings.vibrateTimeout && // not going on too long...
|
||||
(settings.repeat || c<1) && // repeated, or no repeat and first attempt
|
||||
(Date.now()-this.l)>settings.repeat*1000) { // the period between vibrations
|
||||
this.l = Date.now();
|
||||
WIDGETS["messages"].buzz(); // buzz every 4 seconds
|
||||
}
|
||||
WIDGETS["messages"].i=setTimeout(()=>WIDGETS["messages"].draw(true), 1000);
|
||||
if (process.env.HWVERSION>1) Bangle.on('touch', this.touch);
|
||||
},update:function(rawMsgs, quiet) {
|
||||
},update:function(rawMsgs) {
|
||||
const settings = Object.assign({maxMessages:3},require('Storage').readJSON("messages.settings.json", true) || {});
|
||||
this.msgs = filterMessages(rawMsgs);
|
||||
if (this.msgs.length === 0) {
|
||||
delete this.t;
|
||||
delete this.l;
|
||||
} else {
|
||||
this.t=Date.now(); // first time
|
||||
this.l=Date.now()-10000; // last buzz
|
||||
if (quiet) this.t -= 500000; // if quiet, set last time in the past so there is no buzzing
|
||||
}
|
||||
this.width = 24 * E.clip(this.msgs.length, 0, settings.maxMessages);
|
||||
Bangle.drawWidgets();
|
||||
},buzz:function(msgSrc) { // return a promise
|
||||
if ((require('Storage').readJSON('setting.json',1)||{}).quiet) return Promise.resolve(); // never buzz during Quiet Mode
|
||||
var pattern;
|
||||
if (msgSrc != undefined && msgSrc.toLowerCase() == "phone") {
|
||||
// special vibration pattern for incoming calls
|
||||
pattern = (require('Storage').readJSON("messages.settings.json", true) || {}).vibrateCalls;
|
||||
} else {
|
||||
pattern = (require('Storage').readJSON("messages.settings.json", true) || {}).vibrate;
|
||||
}
|
||||
if (pattern === undefined) { pattern = ":"; } // pattern may be "", so we can't use || ":" here
|
||||
return require("buzz").pattern(pattern);
|
||||
},touch:function(b,c) {
|
||||
var w=WIDGETS["messages"];
|
||||
if (!w||!w.width||c.x<w.x||c.x>w.x+w.width||c.y<w.y||c.y>w.y+24) return;
|
||||
|
@ -74,8 +49,7 @@ WIDGETS["messages"]={area:"tl", width:0, draw:function(recall) {
|
|||
}};
|
||||
|
||||
/* We might have returned here if we were in the Messages app for a
|
||||
message but then the watch was never viewed. In that case we don't
|
||||
want to buzz but should still show that there are unread messages. */
|
||||
message but then the watch was never viewed. */
|
||||
if (global.MESSAGES===undefined)
|
||||
WIDGETS["messages"].update(require("messages").getMessages(), true);
|
||||
WIDGETS["messages"].update(require("messages").getMessages());
|
||||
})();
|
||||
|
|
Loading…
Reference in New Issue