1
0
Fork 0

Merge branch 'espruino:master' into sleeplog_v0.10_beta

master
storm64 2022-05-26 12:42:50 +02:00 committed by GitHub
commit d04efb6fe2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 205 additions and 186 deletions

View File

@ -28,3 +28,4 @@
0.26: Add support for Monday as first day of the week (#1780)
0.27: New UI!
0.28: Fix bug with alarms not firing when configured to fire only once
0.29: Fix wrong 'dow' handling in new timer if first day of week is Monday

View File

@ -37,8 +37,8 @@ function handleFirstDayOfWeek(dow) {
return dow;
}
// Check the first day of week and update the dow field accordingly.
alarms.forEach(alarm => alarm.dow = handleFirstDayOfWeek(alarm.dow));
// Check the first day of week and update the dow field accordingly (alarms only!)
alarms.filter(e => e.timer === undefined).forEach(a => a.dow = handleFirstDayOfWeek(a.dow));
function showMainMenu() {
const menu = {
@ -158,14 +158,14 @@ function saveAlarm(alarm, alarmIndex, time) {
}
function saveAndReload() {
// Before saving revert the dow to the standard format
alarms.forEach(a => a.dow = handleFirstDayOfWeek(a.dow, firstDayOfWeek));
// Before saving revert the dow to the standard format (alarms only!)
alarms.filter(e => e.timer === undefined).forEach(a => a.dow = handleFirstDayOfWeek(a.dow));
require("sched").setAlarms(alarms);
require("sched").reload();
// Fix after save
alarms.forEach(a => a.dow = handleFirstDayOfWeek(a.dow, firstDayOfWeek));
alarms.filter(e => e.timer === undefined).forEach(a => a.dow = handleFirstDayOfWeek(a.dow));
}
function decodeDOW(alarm) {

View File

@ -2,7 +2,7 @@
"id": "alarm",
"name": "Alarms & Timers",
"shortName": "Alarms",
"version": "0.28",
"version": "0.29",
"description": "Set alarms and timers on your Bangle",
"icon": "app.png",
"tags": "tool,alarm,widget",

View File

@ -8,3 +8,4 @@
0.07: Include charging state in battery updates to phone
0.08: Handling of alarms
0.09: Alarm vibration, repeat, and auto-snooze now handled by sched
0.10: Fix SMS bug

View File

@ -3,6 +3,7 @@
Bluetooth.println("");
Bluetooth.println(JSON.stringify(message));
}
var lastMsg;
var settings = require("Storage").readJSON("android.settings.json",1)||{};
//default alarm settings
@ -18,7 +19,17 @@
/* TODO: Call handling, fitness */
var HANDLERS = {
// {t:"notify",id:int, src,title,subject,body,sender,tel:string} add
"notify" : function() { Object.assign(event,{t:"add",positive:true, negative:true});require("messages").pushMessage(event); },
"notify" : function() {
Object.assign(event,{t:"add",positive:true, negative:true});
// Detect a weird GadgetBridge bug and fix it
// For some reason SMS messages send two GB notifications, with different sets of info
if (lastMsg && event.body == lastMsg.body && lastMsg.src == undefined && event.src == "Messages") {
// Mutate the other message
event.id = lastMsg.id;
}
lastMsg = event;
require("messages").pushMessage(event);
},
// {t:"notify~",id:int, title:string} // modified
"notify~" : function() { event.t="modify";require("messages").pushMessage(event); },
// {t:"notify-",id:int} // remove

View File

@ -2,7 +2,7 @@
"id": "android",
"name": "Android Integration",
"shortName": "Android",
"version": "0.09",
"version": "0.10",
"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",

View File

@ -11,6 +11,8 @@ const speedUnits = { // how many kph per X?
"kmh": 1,
"kph": 1,
"km/h": 1,
"kmt": 1,
"km/tim": 1,
"mph": 1.60934,
"kts": 1.852
};

View File

@ -67,100 +67,6 @@ function saveMessages() {
require("Storage").writeJSON("messages.json",MESSAGES)
}
function getNotificationImage() {
return atob("HBKBAD///8H///iP//8cf//j4//8f5//j/x/8//j/H//H4//4PB//EYj/44HH/Hw+P4//8fH//44///xH///g////A==");
}
function getFBIcon() {
return atob("GBiBAAAAAAAAAAAYAAD/AAP/wAf/4A/48A/g8B/g+B/j+B/n+D/n/D8A/B8A+B+B+B/n+A/n8A/n8Afn4APnwADnAAAAAAAAAAAAAA==");
}
function getPosImage() {
return atob("GRSBAAAAAYAAAcAAAeAAAfAAAfAAAfAAAfAAAfAAAfBgAfA4AfAeAfAPgfAD4fAA+fAAP/AAD/AAA/AAAPAAADAAAA==");
}
function getNegImage() {
return atob("FhaBADAAMeAB78AP/4B/fwP4/h/B/P4D//AH/4AP/AAf4AB/gAP/AB/+AP/8B/P4P4fx/A/v4B//AD94AHjAAMA=");
}
/*
* icons should be 24x24px with 1bpp colors and 'Transparency to Color'
* http://www.espruino.com/Image+Converter
*/
function getMessageImage(msg) {
if (msg.img) return atob(msg.img);
var s = (msg.src||"").toLowerCase();
if (s=="alarm" || s =="alarmclockreceiver") return atob("GBjBAP////8AAAAAAAACAEAHAOAefng5/5wTgcgHAOAOGHAMGDAYGBgYGBgYGBgYGBgYDhgYBxgMATAOAHAHAOADgcAB/4AAfgAAAAAAAAA=");
if (s=="bibel") return atob("GBgBAAAAA//wD//4D//4H//4H/f4H/f4H+P4H4D4H4D4H/f4H/f4H/f4H/f4H/f4H//4H//4H//4GAAAEAAAEAAACAAAB//4AAAA");
if (s=="calendar") return atob("GBiBAAAAAAAAAAAAAA//8B//+BgAGBgAGBgAGB//+B//+B//+B9m2B//+B//+Btm2B//+B//+Btm+B//+B//+A//8AAAAAAAAAAAAA==");
if (s=="corona-warn") return atob("GBgBAAAAABwAAP+AAf/gA//wB/PwD/PgDzvAHzuAP8EAP8AAPAAAPMAAP8AAH8AAHzsADzuAB/PAB/PgA//wAP/gAH+AAAwAAAAA");
if (s=="discord") return atob("GBgBAAAAAAAAAAAAAIEABwDgDP8wH//4H//4P//8P//8P//8Pjx8fhh+fzz+f//+f//+e//ePH48HwD4AgBAAAAAAAAAAAAAAAAA");
if (s=="facebook") return getFBIcon();
if (s=="gmail") return getNotificationImage();
if (s=="google home") return atob("GBiCAAAAAAAAAAAAAAAAAAAAAoAAAAAACqAAAAAAKqwAAAAAqroAAAACquqAAAAKq+qgAAAqr/qoAACqv/6qAAKq//+qgA6r///qsAqr///6sAqv///6sAqv///6sAqv///6sA6v///6sA6v///qsA6qqqqqsA6qqqqqsA6qqqqqsAP7///vwAAAAAAAAAAAAAAAAA==");
if (s=="hangouts") return atob("FBaBAAH4AH/gD/8B//g//8P//H5n58Y+fGPnxj5+d+fmfj//4//8H//B//gH/4A/8AA+AAHAABgAAAA=");
if (s=="home assistant") return atob("FhaBAAAAAADAAAeAAD8AAf4AD/3AfP8D7fwft/D/P8ec572zbzbNsOEhw+AfD8D8P4fw/z/D/P8P8/w/z/AAAAA=");
if (s=="instagram") return atob("GBiBAAAAAAAAAAAAAAAAAAP/wAYAYAwAMAgAkAh+EAjDEAiBEAiBEAiBEAiBEAjDEAh+EAgAEAwAMAYAYAP/wAAAAAAAAAAAAAAAAA==");
if (s=="kalender") return atob("GBgBBgBgBQCgff++RQCiRgBiQAACf//+QAACQAACR//iRJkiRIEiR//iRNsiRIEiRJkiR//iRIEiRIEiR//iQAACQAACf//+AAAA");
if (s=="lieferando") return atob("GBgBABgAAH5wAP9wAf/4A//4B//4D//4H//4P/88fV8+fV4//V4//Vw/HVw4HVw4HBg4HBg4HBg4HDg4Hjw4Hj84Hj44Hj44Hj44");
if (s=="mail") return getNotificationImage();
if (s=="messenger") return getFBIcon();
if (s=="nina") return atob("GBgBAAAABAAQCAAICAAIEAAEEgAkJAgSJBwSKRxKSj4pUn8lVP+VVP+VUgAlSgApKQBKJAASJAASEgAkEAAECAAICAAIBAAQAAAA");
if (s=="outlook mail") return atob("HBwBAAAAAAAAAAAIAAAfwAAP/gAB/+AAP/5/A//v/D/+/8P/7/g+Pv8Dye/gPd74w5znHDnOB8Oc4Pw8nv/Dwe/8Pj7/w//v/D/+/8P/7/gf/gAA/+AAAfwAAACAAAAAAAAAAAA=");
if (s=="phone") return atob("FxeBABgAAPgAAfAAB/AAD+AAH+AAP8AAP4AAfgAA/AAA+AAA+AAA+AAB+AAB+AAB+OAB//AB//gB//gA//AA/8AAf4AAPAA=");
if (s=="post & dhl") return atob("GBgBAPgAE/5wMwZ8NgN8NgP4NgP4HgP4HgPwDwfgD//AB/+AAf8AAAAABs7AHcdgG4MwAAAAGESAFESAEkSAEnyAEkSAFESAGETw");
if (s=="signal") return atob("GBgBAAAAAGwAAQGAAhggCP8QE//AB//oJ//kL//wD//0D//wT//wD//wL//0J//kB//oA//ICf8ABfxgBYBAADoABMAABAAAAAAA");
if (s=="skype") return atob("GhoBB8AAB//AA//+Af//wH//+D///w/8D+P8Afz/DD8/j4/H4fP5/A/+f4B/n/gP5//B+fj8fj4/H8+DB/PwA/x/A/8P///B///gP//4B//8AD/+AAA+AA==");
if (s=="slack") return atob("GBiBAAAAAAAAAABAAAHvAAHvAADvAAAPAB/PMB/veD/veB/mcAAAABzH8B3v+B3v+B3n8AHgAAHuAAHvAAHvAADGAAAAAAAAAAAAAA==");
if (s=="sms message") return getNotificationImage();
if (s=="snapchat") return atob("GBgBAAAAAAAAAH4AAf+AAf+AA//AA//AA//AA//AA//AH//4D//wB//gA//AB//gD//wH//4f//+P//8D//wAf+AAH4AAAAAAAAA");
if (s=="teams") return atob("GBgBAAAAAAAAAAQAAB4AAD8IAA8cP/M+f/scf/gIeDgAfvvefvvffvvffvvffvvff/vff/veP/PeAA/cAH/AAD+AAD8AAAQAAAAA");
if (s=="telegram" || s=="telegram foss") return atob("GBiBAAAAAAAAAAAAAAAAAwAAHwAA/wAD/wAf3gD/Pgf+fh/4/v/z/P/H/D8P/Acf/AM//AF/+AF/+AH/+ADz+ADh+ADAcAAAMAAAAA==");
if (s=="threema") return atob("GBjB/4Yx//8AAAAAAAAAAAAAfgAB/4AD/8AH/+AH/+AP//AP2/APw/APw/AHw+AH/+AH/8AH/4AH/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=");
if (s=="to do") return atob("GBgBAAAAAAAAAAAwAAB4AAD8AAH+AAP/DAf/Hg//Px/+f7/8///4///wf//gP//AH/+AD/8AB/4AA/wAAfgAAPAAAGAAAAAAAAAA");
if (s=="twitch") return atob("GBgBH//+P//+P//+eAAGeAAGeAAGeDGGeDOGeDOGeDOGeDOGeDOGeDOGeAAOeAAOeAAcf4/4f5/wf7/gf//Af/+AA/AAA+AAAcAA");
if (s=="twitter") return atob("GhYBAABgAAB+JgA/8cAf/ngH/5+B/8P8f+D///h///4f//+D///g///wD//8B//+AP//gD//wAP/8AB/+AB/+AH//AAf/AAAYAAA");
if (s=="whatsapp") return atob("GBiBAAB+AAP/wAf/4A//8B//+D///H9//n5//nw//vw///x///5///4///8e//+EP3/APn/wPn/+/j///H//+H//8H//4H//wMB+AA==");
if (s=="wordfeud") return atob("GBgCWqqqqqqlf//////9v//////+v/////++v/////++v8///Lu+v8///L++v8///P/+v8v//P/+v9v//P/+v+fx/P/+v+Pk+P/+v/PN+f/+v/POuv/+v/Ofdv/+v/NvM//+v/I/Y//+v/k/k//+v/i/w//+v/7/6//+v//////+v//////+f//////9Wqqqqqql");
if (s=="youtube") return atob("GBgBAAAAAAAAAAAAAAAAAf8AH//4P//4P//8P//8P5/8P4/8f4P8f4P8P4/8P5/8P//8P//8P//4H//4Af8AAAAAAAAAAAAAAAAA");
if (msg.id=="music") return atob("FhaBAH//+/////////////h/+AH/4Af/gB/+H3/7/f/v9/+/3/7+f/vB/w8H+Dwf4PD/x/////////////3//+A=");
return getNotificationImage();
}
function getMessageImageCol(msg,def) {
return {
// generic colors, using B2-safe colors
"alarm": "#fff",
"mail": "#ff0",
"music": "#f0f",
"phone": "#0f0",
"sms message": "#0ff",
// brands, according to https://www.schemecolor.com/?s (picking one for multicolored logos)
// all dithered on B2, but we only use the color for the icons. (Could maybe pick the closest 3-bit color for B2?)
"bibel": "#54342c",
"discord": "#738adb",
"facebook": "#4267b2",
"gmail": "#ea4335",
"google home": "#fbbc05",
"hangouts": "#1ba261",
"home assistant": "#fff", // ha-blue is #41bdf5, but that's the background
"instagram": "#dd2a7b",
"liferando": "#ee5c00",
"messenger": "#0078ff",
"nina": "#e57004",
"outlook mail": "#0072c6",
"post & dhl": "#f2c101",
"signal": "#00f",
"skype": "#00aff0",
"slack": "#e51670",
"snapchat": "#ff0",
"teams": "#464eb8",
"telegram": "#0088cc",
"threema": "#000",
"to do": "#3999e5",
"twitch": "#6441A4",
"twitter": "#1da1f2",
"whatsapp": "#4fce5d",
"wordfeud": "#e7d3c7",
"youtube": "#f00",
}[(msg.src||"").toLowerCase()]||(def !== undefined?def:g.theme.fg);
}
function showMapMessage(msg) {
active = "map";
var m;
@ -387,7 +293,7 @@ function showMessage(msgid) {
var buttons = [
];
if (msg.positive) {
buttons.push({type:"btn", src:getPosImage(), cb:()=>{
buttons.push({type:"btn", src:atob("GRSBAAAAAYAAAcAAAeAAAfAAAfAAAfAAAfAAAfAAAfBgAfA4AfAeAfAPgfAD4fAA+fAAP/AAD/AAA/AAAPAAADAAAA=="), cb:()=>{
msg.new = false; saveMessages();
cancelReloadTimeout(); // don't auto-reload to clock now
Bangle.messageResponse(msg,true);
@ -396,7 +302,7 @@ function showMessage(msgid) {
}
if (msg.negative) {
if (buttons.length) buttons.push({width:32}); // nasty hack...
buttons.push({type:"btn", src:getNegImage(), cb:()=>{
buttons.push({type:"btn", src:atob("FhaBADAAMeAB78AP/4B/fwP4/h/B/P4D//AH/4AP/AAf4AB/gAP/AB/+AP/8B/P4P4fx/A/v4B//AD94AHjAAMA="), cb:()=>{
msg.new = false; saveMessages();
cancelReloadTimeout(); // don't auto-reload to clock now
Bangle.messageResponse(msg,false);
@ -411,7 +317,7 @@ function showMessage(msgid) {
{type:"txt", font:fontSmall, label:msg.src||/*LANG*/"Message", bgCol:g.theme.bg2, col: g.theme.fg2, fillx:1, pad:2, halign:1 },
title?{type:"txt", font:titleFont, label:title, bgCol:g.theme.bg2, col: g.theme.fg2, fillx:1, pad:2 }:{},
]},
{ type:"btn", src:getMessageImage(msg), col:getMessageImageCol(msg), pad: 3, cb:()=>{
{ type:"btn", src:require("messages").getMessageImage(msg), col:require("messages").getMessageImageCol(msg), pad: 3, cb:()=>{
cancelReloadTimeout(); // don't auto-reload to clock now
showMessageSettings(msg);
}},
@ -467,14 +373,14 @@ function checkMessages(options) {
g.clearRect(r.x,r.y,r.x+r.w, r.y+r.h);
if (!msg) return;
var x = r.x+2, title = msg.title, body = msg.body;
var img = getMessageImage(msg);
var img = require("messages").getMessageImage(msg);
if (msg.id=="music") {
title = msg.artist || /*LANG*/"Music";
body = msg.track;
}
if (img) {
var fg = g.getColor();
g.setColor(getMessageImageCol(msg,fg)).drawImage(img, x+24, r.y+24, {rotate:0}) // force centering
g.setColor(require("messages").getMessageImageCol(msg,fg)).drawImage(img, x+24, r.y+24, {rotate:0}) // force centering
.setColor(fg); // only color the icon
x += 50;
}

View File

@ -104,3 +104,84 @@ exports.clearAll = function(event) {
if (global.WIDGETS && WIDGETS.messages)
WIDGETS.messages.hide();
}
exports.getMessageImage = function(msg) {
/*
* icons should be 24x24px with 1bpp colors and 'Transparency to Color'
* http://www.espruino.com/Image+Converter
*/
if (msg.img) return atob(msg.img);
var s = (msg.src||"").toLowerCase();
if (s=="alarm" || s =="alarmclockreceiver") return atob("GBjBAP////8AAAAAAAACAEAHAOAefng5/5wTgcgHAOAOGHAMGDAYGBgYGBgYGBgYGBgYDhgYBxgMATAOAHAHAOADgcAB/4AAfgAAAAAAAAA=");
if (s=="bibel") return atob("GBgBAAAAA//wD//4D//4H//4H/f4H/f4H+P4H4D4H4D4H/f4H/f4H/f4H/f4H/f4H//4H//4H//4GAAAEAAAEAAACAAAB//4AAAA");
if (s=="calendar") return atob("GBiBAAAAAAAAAAAAAA//8B//+BgAGBgAGBgAGB//+B//+B//+B9m2B//+B//+Btm2B//+B//+Btm+B//+B//+A//8AAAAAAAAAAAAA==");
if (s=="corona-warn") return atob("GBgBAAAAABwAAP+AAf/gA//wB/PwD/PgDzvAHzuAP8EAP8AAPAAAPMAAP8AAH8AAHzsADzuAB/PAB/PgA//wAP/gAH+AAAwAAAAA");
if (s=="discord") return atob("GBgBAAAAAAAAAAAAAIEABwDgDP8wH//4H//4P//8P//8P//8Pjx8fhh+fzz+f//+f//+e//ePH48HwD4AgBAAAAAAAAAAAAAAAAA");
if (s=="facebook" || s=="messenger") return atob("GBiBAAAAAAAAAAAYAAD/AAP/wAf/4A/48A/g8B/g+B/j+B/n+D/n/D8A/B8A+B+B+B/n+A/n8A/n8Afn4APnwADnAAAAAAAAAAAAAA==");
if (s=="google home") return atob("GBiCAAAAAAAAAAAAAAAAAAAAAoAAAAAACqAAAAAAKqwAAAAAqroAAAACquqAAAAKq+qgAAAqr/qoAACqv/6qAAKq//+qgA6r///qsAqr///6sAqv///6sAqv///6sAqv///6sA6v///6sA6v///qsA6qqqqqsA6qqqqqsA6qqqqqsAP7///vwAAAAAAAAAAAAAAAAA==");
if (s=="hangouts") return atob("FBaBAAH4AH/gD/8B//g//8P//H5n58Y+fGPnxj5+d+fmfj//4//8H//B//gH/4A/8AA+AAHAABgAAAA=");
if (s=="home assistant") return atob("FhaBAAAAAADAAAeAAD8AAf4AD/3AfP8D7fwft/D/P8ec572zbzbNsOEhw+AfD8D8P4fw/z/D/P8P8/w/z/AAAAA=");
if (s=="instagram") return atob("GBiBAAAAAAAAAAAAAAAAAAP/wAYAYAwAMAgAkAh+EAjDEAiBEAiBEAiBEAiBEAjDEAh+EAgAEAwAMAYAYAP/wAAAAAAAAAAAAAAAAA==");
if (s=="kalender") return atob("GBgBBgBgBQCgff++RQCiRgBiQAACf//+QAACQAACR//iRJkiRIEiR//iRNsiRIEiRJkiR//iRIEiRIEiR//iQAACQAACf//+AAAA");
if (s=="lieferando") return atob("GBgBABgAAH5wAP9wAf/4A//4B//4D//4H//4P/88fV8+fV4//V4//Vw/HVw4HVw4HBg4HBg4HBg4HDg4Hjw4Hj84Hj44Hj44Hj44");
if (s=="nina") return atob("GBgBAAAABAAQCAAICAAIEAAEEgAkJAgSJBwSKRxKSj4pUn8lVP+VVP+VUgAlSgApKQBKJAASJAASEgAkEAAECAAICAAIBAAQAAAA");
if (s=="outlook mail") return atob("HBwBAAAAAAAAAAAIAAAfwAAP/gAB/+AAP/5/A//v/D/+/8P/7/g+Pv8Dye/gPd74w5znHDnOB8Oc4Pw8nv/Dwe/8Pj7/w//v/D/+/8P/7/gf/gAA/+AAAfwAAACAAAAAAAAAAAA=");
if (s=="phone") return atob("FxeBABgAAPgAAfAAB/AAD+AAH+AAP8AAP4AAfgAA/AAA+AAA+AAA+AAB+AAB+AAB+OAB//AB//gB//gA//AA/8AAf4AAPAA=");
if (s=="post & dhl") return atob("GBgBAPgAE/5wMwZ8NgN8NgP4NgP4HgP4HgPwDwfgD//AB/+AAf8AAAAABs7AHcdgG4MwAAAAGESAFESAEkSAEnyAEkSAFESAGETw");
if (s=="signal") return atob("GBgBAAAAAGwAAQGAAhggCP8QE//AB//oJ//kL//wD//0D//wT//wD//wL//0J//kB//oA//ICf8ABfxgBYBAADoABMAABAAAAAAA");
if (s=="skype") return atob("GhoBB8AAB//AA//+Af//wH//+D///w/8D+P8Afz/DD8/j4/H4fP5/A/+f4B/n/gP5//B+fj8fj4/H8+DB/PwA/x/A/8P///B///gP//4B//8AD/+AAA+AA==");
if (s=="slack") return atob("GBiBAAAAAAAAAABAAAHvAAHvAADvAAAPAB/PMB/veD/veB/mcAAAABzH8B3v+B3v+B3n8AHgAAHuAAHvAAHvAADGAAAAAAAAAAAAAA==");
if (s=="snapchat") return atob("GBgBAAAAAAAAAH4AAf+AAf+AA//AA//AA//AA//AA//AH//4D//wB//gA//AB//gD//wH//4f//+P//8D//wAf+AAH4AAAAAAAAA");
if (s=="teams") return atob("GBgBAAAAAAAAAAQAAB4AAD8IAA8cP/M+f/scf/gIeDgAfvvefvvffvvffvvffvvff/vff/veP/PeAA/cAH/AAD+AAD8AAAQAAAAA");
if (s=="telegram" || s=="telegram foss") return atob("GBiBAAAAAAAAAAAAAAAAAwAAHwAA/wAD/wAf3gD/Pgf+fh/4/v/z/P/H/D8P/Acf/AM//AF/+AF/+AH/+ADz+ADh+ADAcAAAMAAAAA==");
if (s=="threema") return atob("GBjB/4Yx//8AAAAAAAAAAAAAfgAB/4AD/8AH/+AH/+AP//AP2/APw/APw/AHw+AH/+AH/8AH/4AH/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=");
if (s=="to do") return atob("GBgBAAAAAAAAAAAwAAB4AAD8AAH+AAP/DAf/Hg//Px/+f7/8///4///wf//gP//AH/+AD/8AB/4AA/wAAfgAAPAAAGAAAAAAAAAA");
if (s=="twitch") return atob("GBgBH//+P//+P//+eAAGeAAGeAAGeDGGeDOGeDOGeDOGeDOGeDOGeDOGeAAOeAAOeAAcf4/4f5/wf7/gf//Af/+AA/AAA+AAAcAA");
if (s=="twitter") return atob("GhYBAABgAAB+JgA/8cAf/ngH/5+B/8P8f+D///h///4f//+D///g///wD//8B//+AP//gD//wAP/8AB/+AB/+AH//AAf/AAAYAAA");
if (s=="whatsapp") return atob("GBiBAAB+AAP/wAf/4A//8B//+D///H9//n5//nw//vw///x///5///4///8e//+EP3/APn/wPn/+/j///H//+H//8H//4H//wMB+AA==");
if (s=="wordfeud") return atob("GBgCWqqqqqqlf//////9v//////+v/////++v/////++v8///Lu+v8///L++v8///P/+v8v//P/+v9v//P/+v+fx/P/+v+Pk+P/+v/PN+f/+v/POuv/+v/Ofdv/+v/NvM//+v/I/Y//+v/k/k//+v/i/w//+v/7/6//+v//////+v//////+f//////9Wqqqqqql");
if (s=="youtube") return atob("GBgBAAAAAAAAAAAAAAAAAf8AH//4P//4P//8P//8P5/8P4/8f4P8f4P8P4/8P5/8P//8P//8P//4H//4Af8AAAAAAAAAAAAAAAAA");
if (msg.id=="music") return atob("FhaBAH//+/////////////h/+AH/4Af/gB/+H3/7/f/v9/+/3/7+f/vB/w8H+Dwf4PD/x/////////////3//+A=");
// if (s=="sms message" || s=="mail" || s=="gmail") // .. default icon (below)
return atob("HBKBAD///8H///iP//8cf//j4//8f5//j/x/8//j/H//H4//4PB//EYj/44HH/Hw+P4//8fH//44///xH///g////A==");
};
exports.getMessageImageCol = function(msg,def) {
return {
// generic colors, using B2-safe colors
"alarm": "#fff",
"mail": "#ff0",
"music": "#f0f",
"phone": "#0f0",
"sms message": "#0ff",
// brands, according to https://www.schemecolor.com/?s (picking one for multicolored logos)
// all dithered on B2, but we only use the color for the icons. (Could maybe pick the closest 3-bit color for B2?)
"bibel": "#54342c",
"discord": "#738adb",
"facebook": "#4267b2",
"gmail": "#ea4335",
"google home": "#fbbc05",
"hangouts": "#1ba261",
"home assistant": "#fff", // ha-blue is #41bdf5, but that's the background
"instagram": "#dd2a7b",
"liferando": "#ee5c00",
"messenger": "#0078ff",
"nina": "#e57004",
"outlook mail": "#0072c6",
"post & dhl": "#f2c101",
"signal": "#00f",
"skype": "#00aff0",
"slack": "#e51670",
"snapchat": "#ff0",
"teams": "#464eb8",
"telegram": "#0088cc",
"telegram foss": "#0088cc",
"threema": "#000",
"to do": "#3999e5",
"twitch": "#6441A4",
"twitter": "#1da1f2",
"whatsapp": "#4fce5d",
"wordfeud": "#e7d3c7",
"youtube": "#f00",
}[(msg.src||"").toLowerCase()]||(def !== undefined?def:g.theme.fg);
};

View File

@ -4,6 +4,7 @@
"version":"0.01",
"description": "A clock with R2D2's shiny metal face on it. :)",
"icon": "app.png",
"screenshots": [{"url":"screenshot.png"}],
"type": "clock",
"tags": "clock",
"supports" : ["BANGLEJS2"],

View File

@ -6,7 +6,7 @@
"icon": "rndmclk.png",
"type": "widget",
"tags": "widget,clock",
"supports": ["BANGLEJS"],
"supports": ["BANGLEJS","BANGLEJS2"],
"readme": "README.md",
"storage": [
{"name":"rndmclk.wid.js","url":"widget.js"}

View File

@ -49,3 +49,4 @@
0.44: Add "Start Week On X" option (#1780)
UI improvements to Locale and Date & Time menu
0.45: Add calibrate battery option
0.46: Fix regression after making 'calibrate battery' only for Bangle.js 2

View File

@ -1,7 +1,7 @@
{
"id": "setting",
"name": "Settings",
"version": "0.45",
"version": "0.46",
"description": "A menu for setting up Bangle.js",
"icon": "settings.png",
"tags": "tool,system",

View File

@ -545,8 +545,10 @@ function showUtilMenu() {
setInterval(function() {
var i=1000;while (i--);
}, 1);
},
/*LANG*/'Calibrate Battery': () => {
}
};
if (BANGLEJS2)
menu[/*LANG*/'Calibrate Battery'] = () => {
E.showPrompt(/*LANG*/"Is the battery fully charged?",{title:/*LANG*/"Calibrate"}).then(ok => {
if (ok) {
var s=require("Storage").readJSON("setting.json");
@ -557,8 +559,8 @@ function showUtilMenu() {
E.showAlert(/*LANG*/"Please charge Bangle.js for 3 hours and try again").then(() => load("settings.app.js"));
}
});
},
/*LANG*/'Reset Settings': () => {
};
menu[/*LANG*/'Reset Settings'] = () => {
E.showPrompt(/*LANG*/'Reset to Defaults?',{title:/*LANG*/"Settings"}).then((v) => {
if (v) {
E.showMessage('Resetting');
@ -566,9 +568,9 @@ function showUtilMenu() {
setTimeout(showMainMenu, 50);
} else showUtilMenu();
});
},
/*LANG*/'Turn Off': ()=>{ if (Bangle.softOff) Bangle.softOff(); else Bangle.off() }
};
menu[/*LANG*/'Turn Off'] = ()=>{ if (Bangle.softOff) Bangle.softOff(); else Bangle.off() };
if (Bangle.factoryReset) {
menu[/*LANG*/'Factory Reset'] = ()=>{
E.showPrompt(/*LANG*/'This will remove everything!',{title:/*LANG*/"Factory Reset"}).then((v) => {

2
core

@ -1 +1 @@
Subproject commit 404e981834f2e8df9c505a8fab12ae12fe3bd562
Subproject commit 2054537a9958f9812ae2cad908b6597ff01e449d

View File

@ -1,74 +1,6 @@
/* Copyright (c) 2022 Bangle.js contributors. See the file LICENSE for copying permission. */
/*
Take a look at README.md for hints on developing with this library.
Usage:
```
var Layout = require("Layout");
var layout = new Layout( layoutObject, options )
layout.render(optionalObject);
```
For example:
```
var Layout = require("Layout");
var layout = new Layout( {
type:"v", c: [
{type:"txt", font:"20%", label:"12:00" },
{type:"txt", font:"6x8", label:"The Date" }
]
});
g.clear();
layout.render();
```
layoutObject has:
* A `type` field of:
* `undefined` - blank, can be used for padding
* `"txt"` - a text label, with value `label`. 'font' is required
* `"btn"` - a button, with value `label` and callback `cb`
optional `src` specifies an image (like img) in which case label is ignored
Default font is `6x8`, scale 2. This can be overridden with the `font` or `scale` fields.
* `"img"` - an image where `src` is an image, or a function which is called to return an image to draw.
* `"custom"` - a custom block where `render(layoutObj)` is called to render
* `"h"` - Horizontal layout, `c` is an array of more `layoutObject`
* `"v"` - Vertical layout, `c` is an array of more `layoutObject`
* A `id` field. If specified the object is added with this name to the
returned `layout` object, so can be referenced as `layout.foo`
* A `font` field, eg `6x8` or `30%` to use a percentage of screen height. Set scale with :, e.g. `6x8:2`.
* A `scale` field, eg `2` to set scale of an image
* A `r` field to set rotation of text or images (0: 0°, 1: 90°, 2: 180°, 3: 270°).
* A `wrap` field to enable line wrapping. Requires some combination of `width`/`height`
and `fillx`/`filly` to be set. Not compatible with text rotation.
* A `col` field, eg `#f00` for red
* A `bgCol` field for background color (will automatically fill on render)
* A `halign` field to set horizontal alignment WITHIN a `v` container. `-1`=left, `1`=right, `0`=center
* A `valign` field to set vertical alignment WITHIN a `h` container. `-1`=top, `1`=bottom, `0`=center
* A `pad` integer field to set pixels padding
* A `fillx` int to choose if the object should fill available space in x. 0=no, 1=yes, 2=2x more space
* A `filly` int to choose if the object should fill available space in y. 0=no, 1=yes, 2=2x more space
* `width` and `height` fields to optionally specify minimum size
options is an object containing:
* `lazy` - a boolean specifying whether to enable automatic lazy rendering
* `btns` - array of objects containing:
* `label` - the text on the button
* `cb` - a callback function
* `cbl` - a callback function for long presses
* `back` - a callback function, passed as `back` into Bangle.setUI (which usually adds an icon in the top left)
If automatic lazy rendering is enabled, calls to `layout.render()` will attempt to automatically
determine what objects have changed or moved, clear their previous locations, and re-render just those objects.
Once `layout.update()` is called, the following fields are added
to each object:
* `x` and `y` for the top left position
* `w` and `h` for the width and height
* `_w` and `_h` for the **minimum** width and height
Other functions:
* `layout.update()` - update positions of everything if contents have changed
* `layout.debug(obj)` - draw outlines for objects on screen
* `layout.clear(obj)` - clear the given object (you can also just specify `bgCol` to clear before each render)
* `layout.forgetLazyState()` - if lazy rendering is enabled, makes the next call to `render()` perform a full re-render
* `layout.setUI()` - (called when module initialised) This sets up input (buttons, touch, etc) with Bangle._setUI
This can be useful if you called E.showMenu/showPrompt/etc and those grabbed input away from layour
*/
// See Layout.md for documentation
function Layout(layout, options) {
this._l = this.l = layout;

81
modules/Layout.md Normal file
View File

@ -0,0 +1,81 @@
Bangle.js Layout Library
========================
> Take a look at README.md for hints on developing with this library.
Usage
-----
```JS
var Layout = require("Layout");
var layout = new Layout(layoutObject, options)
layout.render(optionalObject);
```
For example:
```JS
var Layout = require("Layout");
var layout = new Layout({
type:"v",
c: [
{ type: "txt", font: "20%", label: "12:00" },
{ type: "txt", font: "6x8", label: "The Date" }
]
});
g.clear();
layout.render();
```
`layoutObject` has:
- A `type` field of:
- `undefined` - blank, can be used for padding
- `"txt"` - a text label, with value `label`. `font` is required
- `"btn"` - a button, with value `label` and callback `cb`. Optional `src` specifies an image (like img) in which case label is ignored. Default font is `6x8`, scale 2. This can be overridden with the `font` or `scale` fields.
- `"img"` - an image where `src` is an image, or a function which is called to return an image to draw
- `"custom"` - a custom block where `render(layoutObj)` is called to render
- `"h"` - Horizontal layout, `c` is an array of more `layoutObject`
- `"v"` - Vertical layout, `c` is an array of more `layoutObject`
- A `id` field. If specified the object is added with this name to the returned `layout` object, so can be referenced as `layout.foo`
- A `font` field, eg `6x8` or `30%` to use a percentage of screen height. Set scale with :, e.g. `6x8:2`.
- A `scale` field, eg `2` to set scale of an image
- A `r` field to set rotation of text or images (0: 0°, 1: 90°, 2: 180°, 3: 270°).
- A `wrap` field to enable line wrapping. Requires some combination of `width`/`height` and `fillx`/`filly` to be set. Not compatible with text rotation.
- A `col` field, eg `#f00` for red
- A `bgCol` field for background color (will automatically fill on render)
- A `halign` field to set horizontal alignment WITHIN a `v` container. `-1`=left, `1`=right, `0`=center
- A `valign` field to set vertical alignment WITHIN a `h` container. `-1`=top, `1`=bottom, `0`=center
- A `pad` integer field to set pixels padding
- A `fillx` int to choose if the object should fill available space in x. 0=no, 1=yes, 2=2x more space
- A `filly` int to choose if the object should fill available space in y. 0=no, 1=yes, 2=2x more space
- `width` and `height` fields to optionally specify minimum size options is an object containing:
- `lazy` - a boolean specifying whether to enable automatic lazy rendering
- `btns` - array of objects containing:
- `label` - the text on the button
- `cb` - a callback function
- `cbl` - a callback function for long presses
- `back` - a callback function, passed as `back` into Bangle.setUI (which usually adds an icon in the top left)
If automatic lazy rendering is enabled, calls to `layout.render()` will attempt to automatically determine what objects have changed or moved, clear their previous locations, and re-render just those objects.
Once `layout.update()` is called, the following fields are added to each object:
- `x` and `y` for the top left position
- `w` and `h` for the width and height
- `_w` and `_h` for the **minimum** width and height
Other functions:
- `layout.update()` - update positions of everything if contents have changed
- `layout.debug(obj)` - draw outlines for objects on screen
- `layout.clear(obj)` - clear the given object (you can also just specify `bgCol` to clear before each render)
- `layout.forgetLazyState()` - if lazy rendering is enabled, makes the next call to `render()` perform a full re-render
Links
-----
- [Official tutorial](https://www.espruino.com/Bangle.js+Layout)