From cb890e6fc586e5efc5a26f1019c7384482d4ff12 Mon Sep 17 00:00:00 2001 From: Lubomir Date: Tue, 24 May 2022 22:08:43 +1000 Subject: [PATCH 01/12] android: Fix SMS bug --- apps/android/ChangeLog | 1 + apps/android/boot.js | 13 ++++++++++++- apps/android/metadata.json | 2 +- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/apps/android/ChangeLog b/apps/android/ChangeLog index 55f456795..f13ccd95c 100644 --- a/apps/android/ChangeLog +++ b/apps/android/ChangeLog @@ -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 diff --git a/apps/android/boot.js b/apps/android/boot.js index fb2101aa4..efd7e7e46 100644 --- a/apps/android/boot.js +++ b/apps/android/boot.js @@ -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 diff --git a/apps/android/metadata.json b/apps/android/metadata.json index 4051a344b..bf37b8407 100644 --- a/apps/android/metadata.json +++ b/apps/android/metadata.json @@ -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", From 68edab1a18ef817bfd47f3531c5c51adf0b1b4e9 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 25 May 2022 09:58:02 +0100 Subject: [PATCH 02/12] Move getMessageImage/getMessageImageCol to the library as per https://github.com/espruino/BangleApps/pull/1872 No version bump as no functionality changes --- apps/messages/app.js | 95 +++----------------------------------------- apps/messages/lib.js | 81 +++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 90 deletions(-) diff --git a/apps/messages/app.js b/apps/messages/app.js index 93c8ebf3e..63154c4b4 100644 --- a/apps/messages/app.js +++ b/apps/messages/app.js @@ -67,99 +67,14 @@ 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"; @@ -411,7 +326,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 +382,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; } diff --git a/apps/messages/lib.js b/apps/messages/lib.js index c39c8886c..3f801e101 100644 --- a/apps/messages/lib.js +++ b/apps/messages/lib.js @@ -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); +}; From a6d92c11151b4e0127bdc9fcccea7fa13098ba05 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 25 May 2022 10:00:27 +0100 Subject: [PATCH 03/12] inline tick/cross images to save some space --- apps/messages/app.js | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/apps/messages/app.js b/apps/messages/app.js index 63154c4b4..745f7d208 100644 --- a/apps/messages/app.js +++ b/apps/messages/app.js @@ -67,15 +67,6 @@ function saveMessages() { require("Storage").writeJSON("messages.json",MESSAGES) } -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="); -} - - - function showMapMessage(msg) { active = "map"; var m; @@ -302,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); @@ -311,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); From f0e262757109e83bb3b6bf77e4aba3c2658fd067 Mon Sep 17 00:00:00 2001 From: Alessandro Cocco Date: Tue, 24 May 2022 22:25:44 +0200 Subject: [PATCH 04/12] Move Layout docs to a separate file --- modules/Layout.js | 70 +--------------------------------------- modules/Layout.md | 81 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 69 deletions(-) create mode 100644 modules/Layout.md diff --git a/modules/Layout.js b/modules/Layout.js index 43419a397..19cfabe11 100644 --- a/modules/Layout.js +++ b/modules/Layout.js @@ -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; diff --git a/modules/Layout.md b/modules/Layout.md new file mode 100644 index 000000000..7a4177957 --- /dev/null +++ b/modules/Layout.md @@ -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) From 4cbc80ddbb4e065e0aa7a5f1b4f28a54a9bcadb4 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 25 May 2022 14:12:55 +0100 Subject: [PATCH 05/12] oops - disable battery calibration for Bangle.js 1 --- apps/setting/settings.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/apps/setting/settings.js b/apps/setting/settings.js index 5c14e914d..73cb4b497 100644 --- a/apps/setting/settings.js +++ b/apps/setting/settings.js @@ -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"); @@ -558,7 +560,7 @@ function showUtilMenu() { } }); }, - /*LANG*/'Reset Settings': () => { + menu[/*LANG*/'Reset Settings'] = () => { E.showPrompt(/*LANG*/'Reset to Defaults?',{title:/*LANG*/"Settings"}).then((v) => { if (v) { E.showMessage('Resetting'); @@ -567,8 +569,8 @@ function showUtilMenu() { } 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) => { From 280fd5e665249ea92256c30a36ed25d74bffaee6 Mon Sep 17 00:00:00 2001 From: Alessandro Cocco Date: Wed, 25 May 2022 23:13:37 +0200 Subject: [PATCH 06/12] [Alarms & Timers] Fix dow handling for timers --- apps/alarm/app.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/alarm/app.js b/apps/alarm/app.js index 8e2e2b0a6..fe0f67dbb 100644 --- a/apps/alarm/app.js +++ b/apps/alarm/app.js @@ -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) { From 2fd5ec8f37dd860db57da2e98d373b2f6ceedb3b Mon Sep 17 00:00:00 2001 From: Alessandro Cocco Date: Wed, 25 May 2022 23:20:00 +0200 Subject: [PATCH 07/12] [Alarms & Timers] Update metadata and changelog --- apps/alarm/ChangeLog | 1 + apps/alarm/metadata.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/alarm/ChangeLog b/apps/alarm/ChangeLog index 3d75e1209..b00055334 100644 --- a/apps/alarm/ChangeLog +++ b/apps/alarm/ChangeLog @@ -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 diff --git a/apps/alarm/metadata.json b/apps/alarm/metadata.json index b38ab1ef1..cac837b5e 100644 --- a/apps/alarm/metadata.json +++ b/apps/alarm/metadata.json @@ -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", From 182743a0e3649a311cb0beaf485103bfd6798d4b Mon Sep 17 00:00:00 2001 From: Noah Howard <3317164+nh-99@users.noreply.github.com> Date: Wed, 25 May 2022 17:33:40 -0400 Subject: [PATCH 08/12] Add screenshot of R2D2 clock to metadata for app store --- apps/r2d2clk/metadata.json | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/r2d2clk/metadata.json b/apps/r2d2clk/metadata.json index f2cde76f4..249180ac8 100644 --- a/apps/r2d2clk/metadata.json +++ b/apps/r2d2clk/metadata.json @@ -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"], From 211af92a41a5d167f9a42d5c73b4c3f09004234d Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Thu, 26 May 2022 09:58:59 +0100 Subject: [PATCH 09/12] bangle.js 2 compat --- apps/rndmclk/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/rndmclk/metadata.json b/apps/rndmclk/metadata.json index e837c4bce..bb8e92f95 100644 --- a/apps/rndmclk/metadata.json +++ b/apps/rndmclk/metadata.json @@ -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"} From 6f202bc9254a96de7bccba21fe75ce75d00cf95b Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Thu, 26 May 2022 09:59:11 +0100 Subject: [PATCH 10/12] fix locale errors after recent PRs --- apps/locale/locales.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/locale/locales.js b/apps/locale/locales.js index d1ac7687f..de56503fd 100644 --- a/apps/locale/locales.js +++ b/apps/locale/locales.js @@ -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 }; From ed56c9142742eb3e7a132c730a4769a028396dde Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Thu, 26 May 2022 09:59:18 +0100 Subject: [PATCH 11/12] add relevant interface code to customize.js, and add checks to ensure the right file is used --- core | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core b/core index 404e98183..2054537a9 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 404e981834f2e8df9c505a8fab12ae12fe3bd562 +Subproject commit 2054537a9958f9812ae2cad908b6597ff01e449d From 6b8cf13f6c635efc1392c82c8a95f2927ba65e4f Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Thu, 26 May 2022 10:07:04 +0100 Subject: [PATCH 12/12] 0.46: Fix regression after making 'calibrate battery' only for Bangle.js 2 --- apps/setting/ChangeLog | 1 + apps/setting/metadata.json | 2 +- apps/setting/settings.js | 6 +++--- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/setting/ChangeLog b/apps/setting/ChangeLog index 6d3bbb468..eca2b7938 100644 --- a/apps/setting/ChangeLog +++ b/apps/setting/ChangeLog @@ -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 diff --git a/apps/setting/metadata.json b/apps/setting/metadata.json index c5c368fae..183290a85 100644 --- a/apps/setting/metadata.json +++ b/apps/setting/metadata.json @@ -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", diff --git a/apps/setting/settings.js b/apps/setting/settings.js index 73cb4b497..150251e7d 100644 --- a/apps/setting/settings.js +++ b/apps/setting/settings.js @@ -559,7 +559,7 @@ function showUtilMenu() { E.showAlert(/*LANG*/"Please charge Bangle.js for 3 hours and try again").then(() => load("settings.app.js")); } }); - }, + }; menu[/*LANG*/'Reset Settings'] = () => { E.showPrompt(/*LANG*/'Reset to Defaults?',{title:/*LANG*/"Settings"}).then((v) => { if (v) { @@ -568,8 +568,8 @@ function showUtilMenu() { setTimeout(showMainMenu, 50); } else showUtilMenu(); }); - }, - menu[/*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'] = ()=>{