forked from FOSS/BangleApps
Merge branch 'espruino:master' into master
commit
cdc2fb12ad
|
@ -1,2 +1,4 @@
|
|||
0.01: First, proof of concept
|
||||
0.02: Load AGPS data on app start and automatically in background
|
||||
0.03: Do not load AGPS data on boot
|
||||
Increase minimum interval to 6 hours
|
||||
|
|
|
@ -16,13 +16,6 @@
|
|||
}
|
||||
|
||||
if (settings.enabled) {
|
||||
let lastUpdate = settings.lastUpdate;
|
||||
if (!lastUpdate || lastUpdate + settings.refresh * 1000 * 60 < Date.now()){
|
||||
if (!waiting){
|
||||
waiting = true;
|
||||
require("agpsdata").pull(successCallback, errorCallback);
|
||||
}
|
||||
}
|
||||
setInterval(() => {
|
||||
if (!waiting && NRF.getSecurityStatus().connected){
|
||||
waiting = true;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"name": "A-GPS Data Downloader App",
|
||||
"shortName":"A-GPS Data",
|
||||
"icon": "agpsdata.png",
|
||||
"version":"0.02",
|
||||
"version":"0.03",
|
||||
"description": "Once installed, this app allows you to download assisted GPS (A-GPS) data directly to your Bangle.js **via Gadgetbridge on an Android phone** when you run the app. If you just want to upload the latest AGPS data from this app loader, please use the `Assisted GPS Update (AGPS)` app.",
|
||||
"tags": "boot,tool,assisted,gps,agps,http",
|
||||
"allow_emulator":true,
|
||||
|
|
|
@ -35,7 +35,7 @@ function buildMainMenu() {
|
|||
},
|
||||
"Refresh every" : {
|
||||
value : settings.refresh / 60,
|
||||
min : 1,
|
||||
min : 6,
|
||||
max : 168,
|
||||
step : 1,
|
||||
format : v => v + "h",
|
||||
|
|
|
@ -13,3 +13,4 @@
|
|||
0.13: Added Bangle.http function (see Readme file for more info)
|
||||
0.14: Fix timeout of http function not being cleaned up
|
||||
0.15: Allow method/body/headers to be specified for `http` (needs Gadgetbridge 0.68.0b or later)
|
||||
0.16: Bangle.http now fails immediately if there is no Bluetooth connection (fix #2152)
|
||||
|
|
|
@ -139,6 +139,8 @@
|
|||
// options = {id,timeout,xpath}
|
||||
Bangle.http = (url,options)=>{
|
||||
options = options||{};
|
||||
if (!NRF.getSecurityStatus().connected)
|
||||
return Promise.reject("Not connected to Bluetooth");
|
||||
if (Bangle.httpRequest === undefined)
|
||||
Bangle.httpRequest={};
|
||||
if (options.id === undefined) {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"id": "android",
|
||||
"name": "Android Integration",
|
||||
"shortName": "Android",
|
||||
"version": "0.15",
|
||||
"version": "0.16",
|
||||
"description": "Display notifications/music/etc sent from the Gadgetbridge app on Android. This replaces the old 'Gadgetbridge' Bangle.js widget.",
|
||||
"icon": "app.png",
|
||||
"tags": "tool,system,messages,notifications,gadgetbridge",
|
||||
|
|
|
@ -4,3 +4,4 @@
|
|||
0.04: bug fix
|
||||
0.05: proper fix for the race condition in queueDraw()
|
||||
0.06: Tell clock widgets to hide.
|
||||
0.07: Better battery graphic - now has green, yellow and red sections; battery status reflected in the bar across the middle of the screen; current battery state checked only once every 15 minutes, leading to longer-lasting battery charge
|
||||
|
|
|
@ -11,6 +11,8 @@ Graphics.prototype.setFontOpenSans = function(scale) {
|
|||
};
|
||||
|
||||
var drawTimeout;
|
||||
var lastBattCheck = 0;
|
||||
var width = 0;
|
||||
|
||||
function queueDraw(millis_now) {
|
||||
if (drawTimeout) clearTimeout(drawTimeout);
|
||||
|
@ -24,12 +26,15 @@ function draw() {
|
|||
var date = new Date();
|
||||
var h = date.getHours(),
|
||||
m = date.getMinutes();
|
||||
var d = date.getDate(),
|
||||
w = date.getDay(); // d=1..31; w=0..6
|
||||
const level = E.getBattery();
|
||||
const width = level + (level/2);
|
||||
var d = date.getDate();
|
||||
var is12Hour = (require("Storage").readJSON("setting.json", 1) || {})["12hour"];
|
||||
var dows = require("date_utils").dows(0,1);
|
||||
var dow = require("date_utils").dows(0,1)[date.getDay()];
|
||||
|
||||
if ((date.getTime() >= lastBattCheck + 15*60000) || Bangle.isCharging()) {
|
||||
lastBattcheck = date.getTime();
|
||||
width = E.getBattery();
|
||||
width += width/2;
|
||||
}
|
||||
|
||||
g.reset();
|
||||
g.clear();
|
||||
|
@ -47,24 +52,35 @@ function draw() {
|
|||
g.drawString(d, g.getWidth() -6, 98);
|
||||
g.setFont('Vector', 52);
|
||||
g.setFontAlign(-1, -1);
|
||||
g.drawString(dows[w].slice(0,2).toUpperCase(), 6, 103);
|
||||
g.drawString(dow.slice(0,2).toUpperCase(), 6, 103);
|
||||
|
||||
g.fillRect(9,159,166,171);
|
||||
g.fillRect(167,163,170,167);
|
||||
if (Bangle.isCharging()) {
|
||||
g.setColor(1,1,0);
|
||||
} else if (level > 40) {
|
||||
g.setColor(0,1,0);
|
||||
g.fillRect(12,162,12+width,168);
|
||||
} else {
|
||||
g.setColor(1,0,0);
|
||||
g.fillRect(12,162,57,168);
|
||||
g.setColor(1,1,0);
|
||||
g.fillRect(58,162,72,168);
|
||||
g.setColor(0,1,0);
|
||||
g.fillRect(73,162,162,168);
|
||||
}
|
||||
g.fillRect(12,162,12+width,168);
|
||||
if (level < 100) {
|
||||
if (width < 150) {
|
||||
g.setColor(g.theme.bg);
|
||||
g.fillRect(12+width+1,162,162,168);
|
||||
}
|
||||
|
||||
g.setColor(0, 1, 0);
|
||||
if (Bangle.isCharging()) {
|
||||
g.setColor(1,1,0);
|
||||
} else if (width <= 45) {
|
||||
g.setColor(1,0,0);
|
||||
} else if (width <= 60) {
|
||||
g.setColor(1,1,0);
|
||||
} else {
|
||||
g.setColor(0, 1, 0);
|
||||
}
|
||||
g.fillRect(0, 90, g.getWidth(), 94);
|
||||
|
||||
// widget redraw
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{ "id": "bigdclock",
|
||||
"name": "Big digit clock containing just the essentials",
|
||||
"shortName":"Big digit clk",
|
||||
"version":"0.06",
|
||||
"version":"0.07",
|
||||
"description": "A clock containing just the essentials, made as easy to read as possible for those of us that need glasses. It contains the time, the day-of-week, the day-of-month, and the current battery state-of-charge.",
|
||||
"icon": "bigdclock.png",
|
||||
"type": "clock",
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.0 KiB |
|
@ -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());
|
||||
})();
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
0.01: Initial release
|
||||
0.02: Removed accelerometer poll interval adjustment, fixed a few issues with detecting the current app
|
|
@ -0,0 +1,25 @@
|
|||
# Power Saver
|
||||
|
||||
Save your watch's battery power by halting foreground app execution while the screen is off.
|
||||
|
||||
## Features
|
||||
- Stops foreground app processes
|
||||
- Background processes still run
|
||||
- Clears screen
|
||||
- Foreground app is returned to when screen is turned back on (app state is not preserved)
|
||||
|
||||
## Controls
|
||||
- Automatically activates when screen times out, timing can be adjusted using normal timeout settings
|
||||
- Deactivates when screen is turned back on
|
||||
|
||||
## Warnings
|
||||
- This is not compatible with apps that need to run in the foreground even while the screen is off, such as most stopwatch apps and some health trackers.
|
||||
- If you check your watch super often (like multiple times per minute), this may end of costing you more power than it saves since the app you are using will have to restart everytime you check it.
|
||||
|
||||
## Requests
|
||||
|
||||
[Contact information is on my website](https://kyleplo.com/#contact)
|
||||
|
||||
## Creator
|
||||
|
||||
[kyleplo](https://kyleplo.com)
|
|
@ -0,0 +1,20 @@
|
|||
var Storage = Storage || require("Storage");
|
||||
Bangle.on("lock", locked => {
|
||||
if(locked){
|
||||
load("powersave.screen.js");
|
||||
}else{
|
||||
const data = JSON.parse(Storage.read("powersave.json") || Storage.read("setting.json"));
|
||||
load(data.app || data.clock);
|
||||
}
|
||||
});
|
||||
E.on("init", () => {
|
||||
if("__FILE__" in global && __FILE__ !== "powersave.screen.js"){
|
||||
Storage.write("powersave.json", {
|
||||
app: __FILE__
|
||||
});
|
||||
}else{
|
||||
Storage.write("powersave.json", {
|
||||
app: null
|
||||
});
|
||||
}
|
||||
});
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"id": "powersave",
|
||||
"name": "Power Save",
|
||||
"version": "0.02",
|
||||
"description": "Halts foreground app execution while screen is off while still allowing background processes.",
|
||||
"readme": "README.md",
|
||||
"icon": "powersave.png",
|
||||
"type": "bootloader",
|
||||
"tags": "tool",
|
||||
"supports": ["BANGLEJS2"],
|
||||
"storage": [
|
||||
{"name":"powersave.boot.js","url":"boot.js"},
|
||||
{"name":"powersave.screen.js","url":"boot.js"}
|
||||
],
|
||||
"data": [
|
||||
{"name": "powersave.json"}
|
||||
]
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
|
@ -0,0 +1,7 @@
|
|||
g.clear();
|
||||
Bangle.setLCDBrightness(0);
|
||||
if(!Bangle.isLocked()){
|
||||
var Storage = Storage || require("Storage");
|
||||
const data = JSON.parse(Storage.read("powersave.json") || Storage.read("setting.json"));
|
||||
load(data.app || data.clock);
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
0.01: New Widget!
|
||||
0.02: Fix calling null on draw
|
||||
0.03: Only vibrate during work
|
||||
0.04: Convert to boot code
|
|
@ -0,0 +1,17 @@
|
|||
# Twenties
|
||||
|
||||
Follow the [20-20-20 rule](https://www.aoa.org/AOA/Images/Patients/Eye%20Conditions/20-20-20-rule.pdf) with discrete reminders. Your Bangle will buzz every 20 minutes for you to look away from your screen, and then buzz 20 seconds later to look back. Additionally, alternate between standing and sitting every 20 minutes to be standing for [more than 30 minutes](https://uwaterloo.ca/kinesiology-health-sciences/how-long-should-you-stand-rather-sit-your-work-station) per hour.
|
||||
|
||||
## Usage
|
||||
|
||||
Download this app and it will automatically run in the background.
|
||||
|
||||
## Features
|
||||
|
||||
Vibrates to remind you to stand up and look away for healthy living.
|
||||
|
||||
Only vibrates during work days and hours.
|
||||
|
||||
## Creator
|
||||
|
||||
[@splch](https://github.com/splch/)
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
|
@ -0,0 +1,19 @@
|
|||
(() => {
|
||||
const move = 20 * 60 * 1000; // 20 minutes
|
||||
const look = 20 * 1000; // 20 seconds
|
||||
|
||||
const buzz = _ => {
|
||||
const date = new Date();
|
||||
const day = date.getDay();
|
||||
const hour = date.getHours();
|
||||
// buzz at work
|
||||
if (day >= 1 && day <= 5 &&
|
||||
hour >= 8 && hour <= 17) {
|
||||
Bangle.buzz().then(_ => {
|
||||
setTimeout(Bangle.buzz, look);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
setInterval(buzz, move); // buzz to stand / sit
|
||||
})();
|
|
@ -1,13 +1,13 @@
|
|||
{
|
||||
"id": "widtwenties",
|
||||
"id": "twenties",
|
||||
"name": "Twenties",
|
||||
"shortName": "twenties",
|
||||
"version": "0.03",
|
||||
"version": "0.04",
|
||||
"description": "Buzzes every 20m to stand / sit and look 20ft away for 20s.",
|
||||
"icon": "widget.png",
|
||||
"type": "widget",
|
||||
"tags": "widget,tools",
|
||||
"icon": "app.png",
|
||||
"type": "bootloader",
|
||||
"tags": "alarm,tool",
|
||||
"supports": ["BANGLEJS", "BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
"storage": [{ "name": "widtwenties.wid.js", "url": "widget.js" }]
|
||||
"storage": [{ "name": "twenties.boot.js", "url": "boot.js" }]
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
0.01: New Widget!
|
||||
0.02: Fix calling null on draw
|
||||
0.03: Only vibrate during work
|
|
@ -1,15 +0,0 @@
|
|||
# Twenties
|
||||
|
||||
Follow the [20-20-20 rule](https://www.aoa.org/AOA/Images/Patients/Eye%20Conditions/20-20-20-rule.pdf) with discrete reminders. Your BangleJS will buzz every 20 minutes for you to look away from your screen, and then buzz 20 seconds later to look back. Additionally, alternate between standing and sitting every 20 minutes to be standing for [more than 30 minutes](https://uwaterloo.ca/kinesiology-health-sciences/how-long-should-you-stand-rather-sit-your-work-station) per hour.
|
||||
|
||||
## Usage
|
||||
|
||||
Download this widget and, as long as your watch-face supports widgets, it will automatically run in the background.
|
||||
|
||||
## Features
|
||||
|
||||
Vibrate to remind you to stand up and look away for healthy living.
|
||||
|
||||
## Creator
|
||||
|
||||
[@splch](https://github.com/splch/)
|
|
@ -1,30 +0,0 @@
|
|||
// WIDGETS = {}; // <-- for development only
|
||||
|
||||
/* run widgets in their own function scope so
|
||||
they don't interfere with currently-running apps */
|
||||
(() => {
|
||||
const move = 20 * 60 * 1000; // 20 minutes
|
||||
const look = 20 * 1000; // 20 seconds
|
||||
|
||||
buzz = _ => {
|
||||
const date = new Date();
|
||||
const day = date.getDay();
|
||||
const hour = date.getHours();
|
||||
// buzz at work
|
||||
if (day <= 5 && hour >= 8 && hour <= 17) {
|
||||
Bangle.buzz().then(_ => {
|
||||
setTimeout(Bangle.buzz, look);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// add widget
|
||||
WIDGETS.twenties = {
|
||||
buzz: buzz,
|
||||
draw: _ => { return null; },
|
||||
};
|
||||
|
||||
setInterval(WIDGETS.twenties.buzz, move); // buzz to stand / sit
|
||||
})();
|
||||
|
||||
// Bangle.drawWidgets(); // <-- for development only
|
Loading…
Reference in New Issue