Merge branch 'espruino:master' into master
|
|
@ -18,3 +18,4 @@
|
|||
0.16: Correct date for all day events in negative timezones, improve locale display
|
||||
0.17: Fixed "Today" and "Tomorrow" labels displaying in non-current weeks
|
||||
0.18: Correct date in clockinfo for all-day events in negative timezones
|
||||
0.19: Change clockinfo title truncation to preserve images
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@
|
|||
|
||||
agenda.forEach((entry, i) => {
|
||||
|
||||
var title = entry.title.slice(0,12);
|
||||
var title = g.setFont("6x8").wrapString(entry.title,100)[0];
|
||||
// All day events are always in UTC and always start at 00:00:00, so we
|
||||
// need to "undo" the timezone offsetting to make sure that the day is
|
||||
// correct.
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "agenda",
|
||||
"name": "Agenda",
|
||||
"version": "0.18",
|
||||
"version": "0.19",
|
||||
"description": "Simple agenda",
|
||||
"icon": "agenda.png",
|
||||
"screenshots": [{"url":"screenshot_agenda_overview.png"}, {"url":"screenshot_agenda_event1.png"}, {"url":"screenshot_agenda_event2.png"}],
|
||||
|
|
|
|||
|
|
@ -2,3 +2,4 @@
|
|||
0.02: Actually upload correct code
|
||||
0.03: Display sea-level pressure, too, and allow calibration
|
||||
0.04: Switch to using system code for pressure calibration
|
||||
0.05: Prompt before resetting calibration (stops long-press of button resetting calibration)
|
||||
|
|
@ -7,6 +7,7 @@ var R = Bangle.appRect;
|
|||
var y = R.y + R.h/2;
|
||||
var MEDIANLENGTH = 20;
|
||||
var avr = [];
|
||||
var updateDisplay = true;
|
||||
|
||||
function fmt(t) {
|
||||
if ((t > -100) && (t < 1000))
|
||||
|
|
@ -19,48 +20,57 @@ function fmt(t) {
|
|||
Bangle.on('pressure', function(e) {
|
||||
while (avr.length>MEDIANLENGTH) avr.pop();
|
||||
avr.unshift(e.altitude);
|
||||
let median = avr.slice().sort();
|
||||
if (!updateDisplay) return;
|
||||
let median = avr.slice().sort(), value;
|
||||
g.reset().clearRect(0,y-30,g.getWidth()-10,R.h);
|
||||
if (median.length>10) {
|
||||
var mid = median.length>>1;
|
||||
var value = E.sum(median.slice(mid-4,mid+5)) / 9;
|
||||
value = E.sum(median.slice(mid-4,mid+5)) / 9;
|
||||
} else {
|
||||
var value = median[median.length>>1];
|
||||
value = median[median.length>>1];
|
||||
}
|
||||
t = fmt(value);
|
||||
var t = fmt(value);
|
||||
|
||||
g.setFont("Vector",50).setFontAlign(0,0).drawString(t, g.getWidth()/2, y);
|
||||
|
||||
let o = Bangle.getOptions();
|
||||
let sea = o.seaLevelPressure;
|
||||
t = sea.toFixed(1) + " " + e.temperature.toFixed(1);
|
||||
if (0) {
|
||||
/*if (0) {
|
||||
print("alt raw:", value.toFixed(1));
|
||||
print("temperature:", e.temperature);
|
||||
print("pressure:", e.pressure);
|
||||
print("sea pressure:", sea);
|
||||
}
|
||||
}*/
|
||||
g.setFont("Vector",25).setFontAlign(-1,0).drawString(t, 10, R.y+R.h - 35);
|
||||
});
|
||||
|
||||
function setPressure(m, a) {
|
||||
o = Bangle.getOptions();
|
||||
print(o);
|
||||
var o = Bangle.getOptions();
|
||||
//print(o);
|
||||
o.seaLevelPressure = o.seaLevelPressure * m + a;
|
||||
Bangle.setOptions(o);
|
||||
avr = [];
|
||||
}
|
||||
|
||||
print(g.getFonts());
|
||||
g.reset();
|
||||
g.setFont("Vector:15");
|
||||
g.setFontAlign(0,0);
|
||||
g.drawString(/*LANG*/"ALTITUDE (m)", g.getWidth()/2, y-40);
|
||||
g.drawString(/*LANG*/"SEA L (hPa) TEMP (C)", g.getWidth()/2, y+62);
|
||||
g.flip();
|
||||
g.setFont("6x8").setFontAlign(0,0,3).drawString(/*LANG*/"STD", g.getWidth()-5, g.getHeight()/2);
|
||||
Bangle.setUI("updown", btn=> {
|
||||
if (!btn) setPressure(0, 1013.25);
|
||||
if (btn<0) setPressure(1, 1);
|
||||
if (btn>0) setPressure(1, -1);
|
||||
});
|
||||
function start() {
|
||||
g.reset();
|
||||
g.setFont("Vector:15");
|
||||
g.setFontAlign(0,0);
|
||||
g.drawString(/*LANG*/"ALTITUDE (m)", g.getWidth()/2, y-40);
|
||||
g.drawString(/*LANG*/"SEA L (hPa) TEMP (C)", g.getWidth()/2, y+62);
|
||||
g.setFont("6x8").setFontAlign(0,0,3).drawString(/*LANG*/"STD", g.getWidth()-5, g.getHeight()/2);
|
||||
updateDisplay = true;
|
||||
Bangle.setUI("updown", btn => {
|
||||
if (!btn) {
|
||||
updateDisplay = false;
|
||||
E.showPrompt(/*LANG*/"Set calibration to default?",{title:/*LANG*/"Altitude"}).then(function(reset) {
|
||||
start();
|
||||
if (reset) setPressure(0, 1013.25);
|
||||
});
|
||||
}
|
||||
if (btn<0) setPressure(1, 1);
|
||||
if (btn>0) setPressure(1, -1);
|
||||
});
|
||||
}
|
||||
start();
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
{ "id": "altimeter",
|
||||
"name": "Altimeter",
|
||||
"version":"0.04",
|
||||
"version":"0.05",
|
||||
"description": "Simple altimeter that can display height changed using Bangle.js 2's built in pressure sensor.",
|
||||
"icon": "app.png",
|
||||
"tags": "tool,outdoors",
|
||||
|
|
|
|||
|
|
@ -75,4 +75,5 @@
|
|||
0.64: Automatically create .widcache and .clkinfocache to speed up loads
|
||||
Bangle.loadWidgets overwritten with fast version on success
|
||||
Refuse to work on firmware <2v16 and remove old polyfills
|
||||
0.65: Only display interpreter errors if log is nonzero
|
||||
0.65: Only display interpreter errors if log is nonzero
|
||||
0.66: Ensure __FILE__ is set even after a fresh boot (fix #3857)
|
||||
|
|
@ -23,7 +23,8 @@ if (!_clkApp) {
|
|||
require("Storage").writeJSON("setting.json", s);
|
||||
}
|
||||
}
|
||||
if (s.clock) __FILE__=s.clock;
|
||||
delete s;
|
||||
if (!_clkApp) _clkApp=`E.showMessage("No Clock Found");setWatch(()=>{Bangle.showLauncher();}, global.BTN2||BTN, {repeat:false,edge:"falling"});`;
|
||||
eval(_clkApp);
|
||||
delete _clkApp;
|
||||
delete _clkApp;
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "boot",
|
||||
"name": "Bootloader",
|
||||
"version": "0.65",
|
||||
"version": "0.66",
|
||||
"description": "This is needed by Bangle.js to automatically load the clock, menu, widgets and settings",
|
||||
"icon": "bootloader.png",
|
||||
"type": "bootloader",
|
||||
|
|
|
|||
|
|
@ -1,2 +1,3 @@
|
|||
0.01: New App!
|
||||
0.02: Bangle.js 2 compatibility
|
||||
0.03: Add settings menu for showing time and battery percent with animation.
|
||||
|
|
|
|||
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
|
@ -1,8 +1,19 @@
|
|||
|
||||
var settings = Object.assign({
|
||||
// default values
|
||||
showBatPercent: true,
|
||||
showTime: true,
|
||||
|
||||
|
||||
}, require("Storage").readJSON("chargeAnimSettings.json", true) || {});
|
||||
|
||||
|
||||
g.setBgColor(0, 0, 0);
|
||||
g.clear().flip();
|
||||
var imgbat = require("heatshrink").decompress(atob("nFYhBC/AH4A/AGUeACA22HEo3/G8YrTAC422HBQ2tHBI3/G/43/G/43/G/43/G/43/G/43/G+fTG+vSN+w326Q31GwI3/G9g2WG742CG/43rGwY3yGwg33RKo3bNzQ3bGwo3/G9A2GG942dG/43QGw43uGxA34IKw3VGyY3iG0I3pb8pBRG+wYPG8wYQG/42uG8oZSG/43bDKY3iDKg3cNzI3iRKo3gGyo3/G7A2WG7g2aG/43WGzA3dGzI3/G6fTGzRvcG/43/G/43/G/43/G/43/G/43/G/437HFw2IHFo2KAH4A/AH4Aa"));
|
||||
var imgbubble = require("heatshrink").decompress(atob("i0UhAebgoAFCaYXNBocjAAIWNCYoVHCw4UFIZwqELJQWFKZQVOChYVzABwVaCx7wKCqIWNCg4WMChIXJCZgAnA=="));
|
||||
|
||||
require("Font8x12").add(Graphics);
|
||||
var batteryPercentStr="";
|
||||
var W=g.getWidth(),H=g.getHeight();
|
||||
var b2v = (W != 240)?-1:1;
|
||||
var b2rot = (W != 240)?Math.PI:0;
|
||||
|
|
@ -12,11 +23,50 @@ for (var i=0;i<10;i++) {
|
|||
bubbles.push({y:Math.random()*H,ly:0,x:(0.5+(i<5?i:i+8))*W/18,v:0.6+Math.random(),s:0.5+Math.random()});
|
||||
}
|
||||
|
||||
g.setFont("Vector",22);
|
||||
g.setFontAlign(0,0);
|
||||
|
||||
var clockStr="";
|
||||
var x=g.getWidth()/2;
|
||||
var cy=g.getHeight()-(g.getHeight()/7)
|
||||
var by=g.getHeight()-(g.getHeight()/3.500)
|
||||
|
||||
|
||||
function calculateTime(){
|
||||
|
||||
var d=new Date();
|
||||
clockStr = require("locale").time(d, 1); // Hour and minute
|
||||
var meridian=require("locale").meridian(d);
|
||||
if(meridian!=""){
|
||||
//Meridian active
|
||||
clockStr=clockStr+" "+meridian;
|
||||
}
|
||||
|
||||
}
|
||||
function calculate(){
|
||||
if(settings.showTime==true){
|
||||
calculateTime();
|
||||
}
|
||||
if(settings.showBatPercent==true){
|
||||
batteryPercentStr=E.getBattery()+"%";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
function anim() {
|
||||
/* we don't use any kind of buffering here. Just draw one image
|
||||
at a time (image contains a background) too, and there is minimal
|
||||
flicker. */
|
||||
var mx = W/2.0, my = H/2.0;
|
||||
var mx = W/2.0;
|
||||
var my;
|
||||
if(settings.showBatPercent){
|
||||
var my = H/2.5;
|
||||
}else{
|
||||
var my = H/2.0;
|
||||
}
|
||||
|
||||
|
||||
bubbles.forEach(f=>{
|
||||
f.y-=f.v * b2v;
|
||||
if (f.y<-24)
|
||||
|
|
@ -26,10 +76,25 @@ function anim() {
|
|||
g.drawImage(imgbubble,f.y,f.x,{scale:f.s * b2scale, rotate:b2rot});
|
||||
});
|
||||
g.drawImage(imgbat, mx,my,{scale:b2scale, rotate:Math.sin(getTime()*2)*0.5-Math.PI/2 + b2rot});
|
||||
if(settings.showTime==true){
|
||||
g.drawString(clockStr,x,cy);
|
||||
}
|
||||
if(settings.showBatPercent==true){
|
||||
g.drawString(batteryPercentStr,x,by,true);
|
||||
}
|
||||
g.flip();
|
||||
|
||||
|
||||
}
|
||||
|
||||
if(settings.showBatPercent||settings.showTime){
|
||||
//Eliminate unnesccesary need for calculation
|
||||
calculate();
|
||||
setInterval(calculate,20000);
|
||||
}
|
||||
|
||||
setInterval(anim,20);
|
||||
setInterval(anim,22);
|
||||
|
||||
|
||||
Bangle.on("charging", isCharging => {
|
||||
if (!isCharging) load();
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
|
|
@ -1,16 +1,21 @@
|
|||
{
|
||||
"id": "chargeanim",
|
||||
"name": "Charge Animation",
|
||||
"version": "0.02",
|
||||
"description": "When charging, show a sideways charging animation and keep the screen on. When removed from the charger load the clock again.",
|
||||
"version": "0.03",
|
||||
"description": "When charging, show a sideways charging animation and optionally, show time, or show battery percentage. When removed from the charger, clock loads again.",
|
||||
"icon": "icon.png",
|
||||
"tags": "battery",
|
||||
"supports": ["BANGLEJS", "BANGLEJS2"],
|
||||
"allow_emulator": true,
|
||||
"screenshots": [{"url":"bangle2-charge-animation-screenshot.png"},{"url":"bangle-charge-animation-screenshot.png"}],
|
||||
"screenshots": [
|
||||
{"url":"Screenshot1.png"},
|
||||
{"url":"Screenshot2.png"},
|
||||
{"url":"Screenshot3.png"}],
|
||||
"storage": [
|
||||
{"name":"chargeanim.app.js","url":"app.js"},
|
||||
{"name":"chargeanim.boot.js","url":"boot.js"},
|
||||
{"name":"chargeanim.settings.js","url":"settings.js"},
|
||||
{"name":"chargeanim.img","url":"app-icon.js","evaluate":true}
|
||||
]
|
||||
],
|
||||
"data": [{"name":"chargeAnimSettings.json"}]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
(function(back) {
|
||||
var FILE = "chargeAnimSettings.json";
|
||||
// Load settings
|
||||
|
||||
var settings = Object.assign({
|
||||
// default values
|
||||
showBatPercent: true,
|
||||
showTime: true,
|
||||
|
||||
|
||||
}, require('Storage').readJSON(FILE, true) || {});
|
||||
|
||||
function writeSettings() {
|
||||
require('Storage').writeJSON(FILE, settings);
|
||||
}
|
||||
|
||||
// Show the menu
|
||||
E.showMenu({
|
||||
"" : { "title" : "Charge Animation" },
|
||||
"< Back" : () => back(),
|
||||
'Show Percent Charged': {
|
||||
value: !!settings.showBatPercent, // !! converts undefined to false
|
||||
onchange: v => {
|
||||
settings.showBatPercent = v;
|
||||
writeSettings();
|
||||
}
|
||||
// format: ... may be specified as a function which converts the value to a string
|
||||
// if the value is a boolean, showMenu() will convert this automatically, which
|
||||
// keeps settings menus consistent
|
||||
},
|
||||
'Show Time': {
|
||||
value: !!settings.showTime, // !! converts undefined to false
|
||||
onchange: v => {
|
||||
settings.showTime = v;
|
||||
writeSettings();
|
||||
}
|
||||
// format: ... may be specified as a function which converts the value to a string
|
||||
// if the value is a boolean, showMenu() will convert this automatically, which
|
||||
// keeps settings menus consistent
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
})
|
||||
|
|
@ -15,3 +15,4 @@
|
|||
0.14: Check for .clkinfocache and use that if exists (from boot 0.64)
|
||||
0.15: Fix error when displaying a category with only one clockinfo (fix #3728)
|
||||
0.16: Add BLE clkinfo entry
|
||||
0.17: Fix BLE icon alignment and border on some clocks
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ exports.load = function() {
|
|||
get: function() {
|
||||
return {
|
||||
text: this.isOn() ? "On" : "Off",
|
||||
img: atob("CxQBBgDgFgJgR4jZMawfAcA4D4NYybEYIwTAsBwDAA==")
|
||||
img: atob("GBiBAAAAAAAAAAAYAAAcAAAWAAATAAARgAMRgAGTAADWAAB8AAA4AAA4AAB8AADWAAGTAAMRgAARgAATAAAWAAAcAAAYAAAAAAAAAA==")
|
||||
};
|
||||
},
|
||||
run: function() {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{ "id": "clock_info",
|
||||
"name": "Clock Info Module",
|
||||
"shortName": "Clock Info",
|
||||
"version":"0.16",
|
||||
"version":"0.17",
|
||||
"description": "A library used by clocks to provide extra information on the clock face (Altitude, BPM, etc)",
|
||||
"icon": "app.png",
|
||||
"type": "module",
|
||||
|
|
|
|||
|
|
@ -113,6 +113,8 @@ Unless otherwise stated, this project is released under the MIT license.
|
|||
Use of the patented method may be subject to licensing or permission.
|
||||
For inquiries, contact the author.
|
||||
|
||||
Note: The patented method does not require licensing for non-commercial, research, educational, or personal use within the open-source community. Commercial or broad distribution beyond these uses may require permission or licensing. For such use cases, please contact the author.
|
||||
|
||||
### **Summary**
|
||||
|
||||
The Circadian Rhythm Clock transforms the Bangle.js 2 into a **bio-aware, personalized circadian dashboard**, guiding users toward better alignment with their biological clock and modern life.
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ const STATS_FONT_SIZE = 16;
|
|||
function getSleepWindowStr() {
|
||||
let a = ("0"+S.sleepStart).substr(-2) + ":00";
|
||||
let b = ("0"+S.sleepEnd).substr(-2) + ":00";
|
||||
return a + "–" + b;
|
||||
return a + "-" + b;
|
||||
}
|
||||
|
||||
function stability(arr, key, hours) {
|
||||
|
|
@ -518,7 +518,7 @@ function confirmResetAllData() {
|
|||
});
|
||||
}
|
||||
|
||||
// Menu logic: Sleep window, hydration, BT calibration, theme, notifications, bio ref, about — unchanged, use as before
|
||||
// Menu logic: Sleep window, hydration, BT calibration, theme, notifications, bio ref, about - unchanged, use as before
|
||||
|
||||
function setSleepWindow() {
|
||||
let menu = { "": { title: "Select Start Hour" } };
|
||||
|
|
@ -610,7 +610,7 @@ function calibrateBT() {
|
|||
Bangle.setUI(uiOpts);
|
||||
});
|
||||
})(d);
|
||||
m["−" + d + "h"] = (() => () => {
|
||||
m["-" + d + "h"] = (() => () => {
|
||||
S.phaseOffset -= d;
|
||||
saveSettings();
|
||||
E.showAlert("Offset now: " + (S.phaseOffset>=0? "+"+S.phaseOffset : S.phaseOffset) + "h").then(() => {
|
||||
|
|
@ -711,7 +711,7 @@ function setBioTimeReference() {
|
|||
E.showMenu(m);
|
||||
|
||||
function promptRefTime() {
|
||||
E.showPrompt("Hour (0–23)?").then(h => {
|
||||
E.showPrompt("Hour (0-23)?").then(h => {
|
||||
if (h===undefined || h<0 || h>23) {
|
||||
E.showAlert("Invalid hour").then(() => {
|
||||
drawClock();
|
||||
|
|
@ -720,7 +720,7 @@ function setBioTimeReference() {
|
|||
return;
|
||||
}
|
||||
S.bioTimeRefHour = h;
|
||||
E.showPrompt("Minute (0–59)?").then(m => {
|
||||
E.showPrompt("Minute (0-59)?").then(m => {
|
||||
if (m===undefined || m<0 || m>59) {
|
||||
E.showAlert("Invalid minute").then(() => {
|
||||
drawClock();
|
||||
|
|
@ -743,7 +743,7 @@ function showAbout() {
|
|||
E.showAlert(
|
||||
"Circadian Wellness Clock v" + VERSION + "\n" +
|
||||
"Displays your CRS and BioTime.\n" +
|
||||
"© 2025"
|
||||
"Copyright 2025"
|
||||
).then(()=>{
|
||||
drawClock();
|
||||
Bangle.setUI(uiOpts);
|
||||
|
|
|
|||
|
|
@ -16,4 +16,5 @@
|
|||
0.15: Enable calendar and weather updates via custom notifications (via shortcuts app)
|
||||
0.16: Always request Current Time service from iOS
|
||||
0.17: Default to passing full UTF8 strings into messages app (which can now process them with an international font)
|
||||
0.18: Fix UTF8 conversion (check for `font` library, not `fonts`)
|
||||
0.18: Fix UTF8 conversion (check for `font` library, not `fonts`)
|
||||
0.19: Convert numeric weather values to int from BangleDumpWeather shortcut
|
||||
|
|
@ -191,6 +191,11 @@ E.on('notify',msg=>{
|
|||
wdir: d.wdir,
|
||||
loc: d.loc
|
||||
}
|
||||
// Convert string fields to numbers for iOS weather shortcut
|
||||
const numFields = ['code', 'wdir', 'temp', 'hi', 'lo', 'hum', 'wind', 'uv', 'rain'];
|
||||
numFields.forEach(field => {
|
||||
if (weatherEvent[field] != null) weatherEvent[field] = +weatherEvent[field];
|
||||
});
|
||||
require("weather").update(weatherEvent);
|
||||
NRF.ancsAction(msg.uid, false);
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "ios",
|
||||
"name": "iOS Integration",
|
||||
"version": "0.18",
|
||||
"version": "0.19",
|
||||
"description": "Display notifications/music/etc from iOS devices",
|
||||
"icon": "app.png",
|
||||
"tags": "tool,system,ios,apple,messages,notifications",
|
||||
|
|
|
|||
|
|
@ -925,12 +925,6 @@ module.exports = {
|
|||
"no-undef"
|
||||
]
|
||||
},
|
||||
"apps/fileman/fileman.app.js": {
|
||||
"hash": "f378179e7dd3655ba7e9ce03e1f7fd5a2d1768ad7d9083b22e7d740405be842a",
|
||||
"rules": [
|
||||
"no-undef"
|
||||
]
|
||||
},
|
||||
"apps/flappy/app.js": {
|
||||
"hash": "e24b0c5e0469070e02dae00887bf50569c2c141a80c7c356b36987ddf68ce9cc",
|
||||
"rules": [
|
||||
|
|
@ -1051,12 +1045,6 @@ module.exports = {
|
|||
"no-undef"
|
||||
]
|
||||
},
|
||||
"apps/altimeter/app.js": {
|
||||
"hash": "054ac328db51034aa339f1d10b4d264badd49438b95f08bc6fbfb90bd88c6ae0",
|
||||
"rules": [
|
||||
"no-undef"
|
||||
]
|
||||
},
|
||||
"apps/alpinenav/app.js": {
|
||||
"hash": "f8e59724d282f7c5c989adf64974a3728dc521aa8fbe047b7c37dae09213095a",
|
||||
"rules": [
|
||||
|
|
|
|||
|
|
@ -6,4 +6,5 @@
|
|||
0.05: Add message icon for 'jira'
|
||||
0.06: Add message icon for 'molly' and 'threema libre'
|
||||
0.07: Minor code improvements
|
||||
0.08: Add more icons including GMail, Google Messages, Google Agenda
|
||||
0.08: Add more icons including GMail, Google Messages, Google Agenda
|
||||
0.09: Add Bereal, Nextcloud, Thunderbird, Davx⁵, Kleinanzeigen, Element X
|
||||
|
|
|
|||
|
After Width: | Height: | Size: 184 B |
|
|
@ -102,6 +102,7 @@ exports.getColor = function(msg,options) {
|
|||
*/""}
|
||||
"bibel": "#54342c",
|
||||
"bring": "#455a64",
|
||||
"davx⁵": "#8bc34a",
|
||||
"discord": "#5865f2", // https://discord.com/branding
|
||||
"etar": "#36a18b",
|
||||
"facebook": "#1877f2", // https://www.facebook.com/brand/resources/facebookapp/logo
|
||||
|
|
@ -111,7 +112,8 @@ exports.getColor = function(msg,options) {
|
|||
"google home": "#fbbc05",
|
||||
// "home assistant": "#41bdf5", // ha-blue is #41bdf5, but that's the background
|
||||
"instagram": "#ff0069", // https://about.instagram.com/brand/gradient
|
||||
"jira": "#0052cc", //https://atlassian.design/resources/logo-library
|
||||
"jira": "#0052cc", // https://atlassian.design/resources/logo-library
|
||||
"kleinanzeigen": "#69bd2f", // https://themen.kleinanzeigen.de/medien/mediathek/kleinanzeigen-guideline-nutzung-logo/
|
||||
"leboncoin": "#fa7321",
|
||||
"lieferando": "#ff8000",
|
||||
"linkedin": "#0a66c2", // https://brand.linkedin.com/
|
||||
|
|
@ -121,6 +123,7 @@ exports.getColor = function(msg,options) {
|
|||
"mattermost": "#00f",
|
||||
"n26": "#36a18b",
|
||||
"nextbike": "#00f",
|
||||
"nextcloud": "#0082c9", // https://nextcloud.com/brand/
|
||||
"newpipe": "#f00",
|
||||
"nina": "#e57004",
|
||||
"opentasks": "#409f8f",
|
||||
|
|
@ -137,6 +140,7 @@ exports.getColor = function(msg,options) {
|
|||
"teams": "#6264a7", // https://developer.microsoft.com/en-us/fluentui#/styles/web/colors/products
|
||||
"telegram": "#0088cc",
|
||||
"telegram foss": "#0088cc",
|
||||
"thunderbird": "#1582e4",
|
||||
"to do": "#3999e5",
|
||||
"twitch": "#9146ff", // https://brand.twitch.tv/
|
||||
"twitter": "#1d9bf0", // https://about.twitter.com/en/who-we-are/brand-toolkit
|
||||
|
|
|
|||
|
|
@ -3,38 +3,41 @@
|
|||
{ "app":"airbnb", "icon":"airbnb.png" },
|
||||
{ "app":"agenda", "icon":"agenda.png" },
|
||||
{ "app":"alarm", "icon":"alarm.png" },
|
||||
{ "app":"alarmclockreceiver", "icon":"alarm.png" },
|
||||
{ "app":"alarmclockreceiver", "icon":"alarm.png" },
|
||||
{ "app":"amazon shopping", "icon":"amazon.png" },
|
||||
{ "app":"bereal.", "icon":"bereal.png" },
|
||||
{ "app":"bibel", "icon":"bibel.png" },
|
||||
{ "app":"bitwarden", "icon":"security.png" },
|
||||
{ "app":"1password", "icon":"security.png" },
|
||||
{ "app":"lastpass", "icon":"security.png" },
|
||||
{ "app":"dashlane", "icon":"security.png" },
|
||||
{ "app":"1password", "icon":"security.png" },
|
||||
{ "app":"lastpass", "icon":"security.png" },
|
||||
{ "app":"dashlane", "icon":"security.png" },
|
||||
{ "app":"bring", "icon":"bring.png" },
|
||||
{ "app":"calendar", "icon":"etar.png" },
|
||||
{ "app":"etar", "icon":"etar.png" },
|
||||
{ "app":"etar", "icon":"etar.png" },
|
||||
{ "app":"chat", "icon":"google chat.png" },
|
||||
{ "app":"chrome", "icon":"chrome.png" },
|
||||
{ "app":"clock", "icon":"alarm.png" },
|
||||
{ "app":"corona-warn", "icon":"coronavirus.png" },
|
||||
{ "app":"bmo", "icon":"bank.png" },
|
||||
{ "app":"desjardins", "icon":"bank.png" },
|
||||
{ "app":"rbc mobile", "icon":"bank.png" },
|
||||
{ "app":"nbc", "icon":"bank.png" },
|
||||
{ "app":"rabobank", "icon":"bank.png" },
|
||||
{ "app":"scotiabank", "icon":"bank.png" },
|
||||
{ "app":"td (canada)", "icon":"bank.png" },
|
||||
{ "app":"desjardins", "icon":"bank.png" },
|
||||
{ "app":"rbc mobile", "icon":"bank.png" },
|
||||
{ "app":"nbc", "icon":"bank.png" },
|
||||
{ "app":"rabobank", "icon":"bank.png" },
|
||||
{ "app":"scotiabank", "icon":"bank.png" },
|
||||
{ "app":"td (canada)", "icon":"bank.png" },
|
||||
{ "app":"davx⁵", "icon":"sync.png" },
|
||||
{ "app":"discord", "icon":"discord.png" },
|
||||
{ "app":"drive", "icon":"google drive.png" },
|
||||
{ "app":"element", "icon":"matrix element.png" },
|
||||
{ "app":"element x", "icon":"matrix element.png" },
|
||||
{ "app":"facebook", "icon":"facebook.png" },
|
||||
{ "app":"messenger", "icon":"facebook messenger.png" },
|
||||
{ "app":"firefox", "icon":"firefox.png" },
|
||||
{ "app":"firefox beta", "icon":"firefox.png" },
|
||||
{ "app":"firefox nightly", "icon":"firefox.png" },
|
||||
{ "app":"firefox beta", "icon":"firefox.png" },
|
||||
{ "app":"firefox nightly", "icon":"firefox.png" },
|
||||
{ "app":"f-droid", "icon":"security.png" },
|
||||
{ "app":"neo store", "icon":"security.png" },
|
||||
{ "app":"aurora droid", "icon":"security.png" },
|
||||
{ "app":"neo store", "icon":"security.png" },
|
||||
{ "app":"aurora droid", "icon":"security.png" },
|
||||
{ "app":"github", "icon":"github.png" },
|
||||
{ "app":"gitlab", "icon":"gitlab.png" },
|
||||
{ "app":"gmail", "icon":"gmail.png" },
|
||||
|
|
@ -47,28 +50,30 @@
|
|||
{ "app":"jira", "icon":"jira.png" },
|
||||
{ "app":"kalender", "icon":"kalender.png" },
|
||||
{ "app":"keep notes", "icon":"google keep.png" },
|
||||
{ "app":"kleinanzeigen", "icon":"kleinanzeigen.png" },
|
||||
{ "app":"leboncoin", "icon":"leboncoin.png" },
|
||||
{ "app":"lieferando", "icon":"lieferando.png" },
|
||||
{ "app":"linkedin", "icon":"linkedin.png" },
|
||||
{ "app":"maps", "icon":"map.png" },
|
||||
{ "app":"organic maps", "icon":"map.png" },
|
||||
{ "app":"osmand", "icon":"map.png" },
|
||||
{ "app":"organic maps", "icon":"map.png" },
|
||||
{ "app":"osmand", "icon":"map.png" },
|
||||
{ "app":"mastodon", "icon":"mastodon.png" },
|
||||
{ "app":"fedilab", "icon":"mastodon.png" },
|
||||
{ "app":"tooot", "icon":"mastodon.png" },
|
||||
{ "app":"tusky", "icon":"mastodon.png" },
|
||||
{ "app":"fedilab", "icon":"mastodon.png" },
|
||||
{ "app":"tooot", "icon":"mastodon.png" },
|
||||
{ "app":"tusky", "icon":"mastodon.png" },
|
||||
{ "app":"mattermost", "icon":"mattermost.png" },
|
||||
{ "app":"messages", "icon":"messages.png" },
|
||||
{ "app":"n26", "icon":"n26.png" },
|
||||
{ "app":"netflix", "icon":"netflix.png" },
|
||||
{ "app":"news", "icon":"news.png" },
|
||||
{ "app":"cbc news", "icon":"news.png" },
|
||||
{ "app":"rc info", "icon":"news.png" },
|
||||
{ "app":"reuters", "icon":"news.png" },
|
||||
{ "app":"ap news", "icon":"news.png" },
|
||||
{ "app":"la presse", "icon":"news.png" },
|
||||
{ "app":"nbc news", "icon":"news.png" },
|
||||
{ "app":"cbc news", "icon":"news.png" },
|
||||
{ "app":"rc info", "icon":"news.png" },
|
||||
{ "app":"reuters", "icon":"news.png" },
|
||||
{ "app":"ap news", "icon":"news.png" },
|
||||
{ "app":"la presse", "icon":"news.png" },
|
||||
{ "app":"nbc news", "icon":"news.png" },
|
||||
{ "app":"nextbike", "icon":"nextbike.png" },
|
||||
{ "app":"nextcloud", "icon":"nextcloud.png" },
|
||||
{ "app":"nina", "icon":"nina.png" },
|
||||
{ "app":"outlook mail", "icon":"outlook.png" },
|
||||
{ "app":"paypal", "icon":"paypal.png" },
|
||||
|
|
@ -78,11 +83,11 @@
|
|||
{ "app":"post & dhl", "icon":"delivery.png" },
|
||||
{ "app":"proton mail", "icon":"protonmail.png" },
|
||||
{ "app":"reddit", "icon":"reddit.png" },
|
||||
{ "app":"sync pro", "icon":"reddit.png" },
|
||||
{ "app":"sync dev", "icon":"reddit.png" },
|
||||
{ "app":"boost", "icon":"reddit.png" },
|
||||
{ "app":"infinity", "icon":"reddit.png" },
|
||||
{ "app":"slide", "icon":"reddit.png" },
|
||||
{ "app":"sync pro", "icon":"reddit.png" },
|
||||
{ "app":"sync dev", "icon":"reddit.png" },
|
||||
{ "app":"boost", "icon":"reddit.png" },
|
||||
{ "app":"infinity", "icon":"reddit.png" },
|
||||
{ "app":"slide", "icon":"reddit.png" },
|
||||
{ "app":"signal", "icon":"signal.png" },
|
||||
{ "app":"molly", "icon":"signal.png" },
|
||||
{ "app":"skype", "icon":"skype.png" },
|
||||
|
|
@ -92,27 +97,28 @@
|
|||
{ "app":"steam", "icon":"steam.png" },
|
||||
{ "app":"teams", "icon":"teams.png" },
|
||||
{ "app":"telegram", "icon":"telegram.png" },
|
||||
{ "app":"telegram foss", "icon":"telegram.png" },
|
||||
{ "app":"telegram foss", "icon":"telegram.png" },
|
||||
{ "app":"threema", "icon":"threema.png" },
|
||||
{ "app":"threema libre", "icon":"threema.png" },
|
||||
{ "app":"thunderbird", "icon":"mail.png" },
|
||||
{ "app":"tiktok", "icon":"tiktok.png" },
|
||||
{ "app":"to do", "icon":"task.png" },
|
||||
{ "app":"opentasks", "icon":"task.png" },
|
||||
{ "app":"tasks", "icon":"task.png" },
|
||||
{ "app":"opentasks", "icon":"task.png" },
|
||||
{ "app":"tasks", "icon":"task.png" },
|
||||
{ "app":"transit", "icon":"transit.png" },
|
||||
{ "app":"twitch", "icon":"twitch.png" },
|
||||
{ "app":"twitter", "icon":"twitter.png" },
|
||||
{ "app":"uber", "icon":"taxi.png" },
|
||||
{ "app":"lyft", "icon":"taxi.png" },
|
||||
{ "app":"lyft", "icon":"taxi.png" },
|
||||
{ "app":"vlc", "icon":"vlc.png" },
|
||||
{ "app":"warnapp", "icon":"warnapp.png" },
|
||||
{ "app":"whatsapp", "icon":"whatsapp.png" },
|
||||
{ "app":"wordfeud", "icon":"wordfeud.png" },
|
||||
{ "app":"youtube", "icon":"youtube.png" },
|
||||
{ "app":"newpipe", "icon":"youtube.png" },
|
||||
{ "app":"newpipe", "icon":"youtube.png" },
|
||||
{ "app":"zoom", "icon":"videoconf.png" },
|
||||
{ "app":"meet", "icon":"videoconf.png" },
|
||||
{ "app":"meet", "icon":"videoconf.png" },
|
||||
{ "app":"music", "icon":"music.png" },
|
||||
{ "app":"sms message", "icon":"default.png" },
|
||||
{ "app":"mail", "icon":"default.png" }
|
||||
{ "app":"mail", "icon":"default.png" }
|
||||
]
|
||||
|
|
|
|||
|
After Width: | Height: | Size: 248 B |
|
After Width: | Height: | Size: 195 B |
|
After Width: | Height: | Size: 448 B |
|
|
@ -4,7 +4,7 @@ exports.getImage = function(msg) {
|
|||
if (msg.img) return atob(msg.img);
|
||||
let s = (("string"=== typeof msg) ? msg : (msg.src || "")).toLowerCase();
|
||||
if (msg.id=="music") s="music";
|
||||
let match = ",default|0,airbnb|1,agenda|2,alarm|3,alarmclockreceiver|3,amazon shopping|4,bibel|5,bitwarden|6,1password|6,lastpass|6,dashlane|6,bring|7,calendar|8,etar|8,chat|9,chrome|10,clock|3,corona-warn|11,bmo|12,desjardins|12,rbc mobile|12,nbc|12,rabobank|12,scotiabank|12,td (canada)|12,discord|13,drive|14,element|15,facebook|16,messenger|17,firefox|18,firefox beta|18,firefox nightly|18,f-droid|6,neo store|6,aurora droid|6,github|19,gitlab|20,gmail|21,gmx|22,google|23,google home|24,google play store|25,home assistant|26,instagram|27,jira|28,kalender|29,keep notes|30,leboncoin|31,lieferando|32,linkedin|33,maps|34,organic maps|34,osmand|34,mastodon|35,fedilab|35,tooot|35,tusky|35,mattermost|36,messages|37,n26|38,netflix|39,news|40,cbc news|40,rc info|40,reuters|40,ap news|40,la presse|40,nbc news|40,nextbike|41,nina|42,outlook mail|43,paypal|44,phone|45,plex|46,pocket|47,post & dhl|48,proton mail|49,reddit|50,sync pro|50,sync dev|50,boost|50,infinity|50,slide|50,signal|51,molly|51,skype|52,slack|53,snapchat|54,starbucks|55,steam|56,teams|57,telegram|58,telegram foss|58,threema|59,threema libre|59,tiktok|60,to do|61,opentasks|61,tasks|61,transit|62,twitch|63,twitter|64,uber|65,lyft|65,vlc|66,warnapp|67,whatsapp|68,wordfeud|69,youtube|70,newpipe|70,zoom|71,meet|71,music|72,sms message|0,mail|0,".match(new RegExp(`,${s}\\|(\\d+)`))
|
||||
let match = ",default|0,airbnb|1,agenda|2,alarm|3,alarmclockreceiver|3,amazon shopping|4,bereal.|5,bibel|6,bitwarden|7,1password|7,lastpass|7,dashlane|7,bring|8,calendar|9,etar|9,chat|10,chrome|11,clock|3,corona-warn|12,bmo|13,desjardins|13,rbc mobile|13,nbc|13,rabobank|13,scotiabank|13,td (canada)|13,davx⁵|14,discord|15,drive|16,element|17,element x|17,facebook|18,messenger|19,firefox|20,firefox beta|20,firefox nightly|20,f-droid|7,neo store|7,aurora droid|7,github|21,gitlab|22,gmail|23,gmx|24,google|25,google home|26,google play store|27,home assistant|28,instagram|29,jira|30,kalender|31,keep notes|32,kleinanzeigen|33,leboncoin|34,lieferando|35,linkedin|36,maps|37,organic maps|37,osmand|37,mastodon|38,fedilab|38,tooot|38,tusky|38,mattermost|39,messages|40,n26|41,netflix|42,news|43,cbc news|43,rc info|43,reuters|43,ap news|43,la presse|43,nbc news|43,nextbike|44,nextcloud|45,nina|46,outlook mail|47,paypal|48,phone|49,plex|50,pocket|51,post & dhl|52,proton mail|53,reddit|54,sync pro|54,sync dev|54,boost|54,infinity|54,slide|54,signal|55,molly|55,skype|56,slack|57,snapchat|58,starbucks|59,steam|60,teams|61,telegram|62,telegram foss|62,threema|63,threema libre|63,thunderbird|64,tiktok|65,to do|66,opentasks|66,tasks|66,transit|67,twitch|68,twitter|69,uber|70,lyft|70,vlc|71,warnapp|72,whatsapp|73,wordfeud|74,youtube|75,newpipe|75,zoom|76,meet|76,music|77,sms message|0,mail|0,".match(new RegExp(`,${s}\\|(\\d+)`))
|
||||
return require("Storage").read("messageicons.img", (match===null)?0:match[1]*76, 76);
|
||||
};
|
||||
|
||||
|
|
@ -24,6 +24,7 @@ exports.getColor = function(msg,options) {
|
|||
"sms message": "#0ff",
|
||||
"bibel": "#54342c",
|
||||
"bring": "#455a64",
|
||||
"davx⁵": "#8bc34a",
|
||||
"discord": "#5865f2", // https://discord.com/branding
|
||||
"etar": "#36a18b",
|
||||
"facebook": "#1877f2", // https://www.facebook.com/brand/resources/facebookapp/logo
|
||||
|
|
@ -33,7 +34,8 @@ exports.getColor = function(msg,options) {
|
|||
"google home": "#fbbc05",
|
||||
// "home assistant": "#41bdf5", // ha-blue is #41bdf5, but that's the background
|
||||
"instagram": "#ff0069", // https://about.instagram.com/brand/gradient
|
||||
"jira": "#0052cc", //https://atlassian.design/resources/logo-library
|
||||
"jira": "#0052cc", // https://atlassian.design/resources/logo-library
|
||||
"kleinanzeigen": "#69bd2f", // https://themen.kleinanzeigen.de/medien/mediathek/kleinanzeigen-guideline-nutzung-logo/
|
||||
"leboncoin": "#fa7321",
|
||||
"lieferando": "#ff8000",
|
||||
"linkedin": "#0a66c2", // https://brand.linkedin.com/
|
||||
|
|
@ -43,6 +45,7 @@ exports.getColor = function(msg,options) {
|
|||
"mattermost": "#00f",
|
||||
"n26": "#36a18b",
|
||||
"nextbike": "#00f",
|
||||
"nextcloud": "#0082c9", // https://nextcloud.com/brand/
|
||||
"newpipe": "#f00",
|
||||
"nina": "#e57004",
|
||||
"opentasks": "#409f8f",
|
||||
|
|
@ -59,6 +62,7 @@ exports.getColor = function(msg,options) {
|
|||
"teams": "#6264a7", // https://developer.microsoft.com/en-us/fluentui#/styles/web/colors/products
|
||||
"telegram": "#0088cc",
|
||||
"telegram foss": "#0088cc",
|
||||
"thunderbird": "#1582e4",
|
||||
"to do": "#3999e5",
|
||||
"twitch": "#9146ff", // https://brand.twitch.tv/
|
||||
"twitter": "#1d9bf0", // https://about.twitter.com/en/who-we-are/brand-toolkit
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "messageicons",
|
||||
"name": "Message Icons",
|
||||
"version": "0.08",
|
||||
"version": "0.09",
|
||||
"description": "Library containing a list of icons and colors for apps",
|
||||
"icon": "app.png",
|
||||
"type": "module",
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
0.01: New App!
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
# Message Twist to Scroll
|
||||
|
||||
Temporarily activate scroll on twist function when a new message triggers the message app. This way it's possible to scroll through a message in the message scroller hands free.
|
||||
|
||||
## Usage
|
||||
|
||||
This is a bootloader app and only needs to be installed to add the functionality to the watch.
|
||||
|
||||
## Requests
|
||||
|
||||
Mention @thyttan in an issue on the espruino/BangleApps repository.
|
||||
|
||||
## Creator
|
||||
|
||||
thyttan
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
|
|
@ -0,0 +1,63 @@
|
|||
{
|
||||
// twistThreshold How much acceleration to register a twist of the watch strap? Can be negative for opposite direction. default = 800
|
||||
// twistMaxY Maximum acceleration in Y to trigger a twist (low Y means watch is facing the right way up). default = -800
|
||||
// twistTimeout How little time (in ms) must a twist take from low->high acceleration? default = 1000
|
||||
let onTwistEmitDrag = ()=>{
|
||||
Bangle.setOptions({twistThreshold:2500, twistMaxY:-800, twistTimeout:400});
|
||||
let isTwistDragging = false;
|
||||
let twistHandler = ()=>{
|
||||
if (!isTwistDragging) {
|
||||
isTwistDragging = true;
|
||||
Bangle.setLocked(false);
|
||||
Bangle.setLCDPower(true);
|
||||
let i = 25;
|
||||
const int = setInterval(() => {
|
||||
Bangle.emit("drag", {dy:-3, b:i===0?0:1})
|
||||
i--;
|
||||
if (i<0) {
|
||||
clearInterval(int);
|
||||
isTwistDragging = false;
|
||||
}
|
||||
}, 10);
|
||||
}
|
||||
}
|
||||
Bangle.on("twist", twistHandler);
|
||||
// Give messagegui some extra time to add its remove function to
|
||||
// Bangle.uiRemove, then attach msgtwscr remove logic.
|
||||
setTimeout(
|
||||
()=>{if (Bangle.uiRemove) {
|
||||
let showMessageUIRemove = Bangle.uiRemove;
|
||||
Bangle.uiRemove = function () {
|
||||
Bangle.removeListener("twist", twistHandler)
|
||||
showMessageUIRemove();
|
||||
// Reset twist drag logic if we go to next message.
|
||||
attachAfterTimeout();
|
||||
}
|
||||
}},
|
||||
800)
|
||||
}
|
||||
|
||||
// If doing regular loads, not Bangle.load, this is used:
|
||||
if (global.__FILE__=="messagegui.new.js") {
|
||||
onTwistEmitDrag();
|
||||
}
|
||||
|
||||
let attachAfterTimeout = ()=>{
|
||||
setTimeout(()=>{
|
||||
if (global.__FILE__=="messagegui.new.js") {
|
||||
onTwistEmitDrag();
|
||||
}
|
||||
},700)
|
||||
// It feels like there's a more elegant solution than checking the filename
|
||||
// after 700 milliseconds. But this at least seems to work w/o sometimes
|
||||
// activating when it shouldn't.
|
||||
// Maybe we could add events for when fast load and/or Bangle.uiRemove occurs?
|
||||
// Then that could be used similarly to boot code and/or the `kill` event.
|
||||
}
|
||||
|
||||
// If Fastload Utils is installed this is used:
|
||||
Bangle.on("message", (_, msg)=>{if (Bangle.CLOCK && msg.new) {
|
||||
attachAfterTimeout();
|
||||
}});
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
{ "id": "msgtwscr",
|
||||
"name": "Message Twist to Scroll",
|
||||
"version":"0.01",
|
||||
"description": "Temporarily activate scroll on twist function when a new message triggers the message app.",
|
||||
"icon": "app.png",
|
||||
"tags": "messages,tweak,scroll",
|
||||
"type": "bootloader",
|
||||
"supports" : ["BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
"storage": [
|
||||
{"name":"msgtwscr.boot.js","url":"boot.js"}
|
||||
]
|
||||
}
|
||||
|
|
@ -6,4 +6,5 @@
|
|||
0.06: Fix One Call API 3.0 not returning city names, which are required by the weather app
|
||||
0.07: Update weather after reconnecting bluetooth if update is due, refactor code
|
||||
0.08: Undo change to One Call API 3.0
|
||||
0.09: Fix infinite loop when settings.updated is not defined
|
||||
0.09: Fix infinite loop when settings.updated is not defined
|
||||
0.10: Fix settings.updated being updated even when OWM call failed
|
||||
|
|
@ -18,6 +18,13 @@
|
|||
timeoutRef = setTimeout(loadIfDueAndReschedule, refreshMillis());
|
||||
};
|
||||
|
||||
let onError = function(e) {
|
||||
console.log("owmweather error:", e);
|
||||
loading = false;
|
||||
if (timeoutRef) clearTimeout(timeoutRef);
|
||||
timeoutRef = setTimeout(loadIfDueAndReschedule, refreshMillis());
|
||||
};
|
||||
|
||||
let loadIfDueAndReschedule = function () {
|
||||
// also check if the weather.json file has been updated (e.g. force refresh)
|
||||
let weather = require("Storage").readJSON('weather.json') || {};
|
||||
|
|
@ -30,7 +37,7 @@
|
|||
if (!MillisUntilDue || MillisUntilDue <= 0) {
|
||||
if (!loading) {
|
||||
loading = true;
|
||||
require("owmweather").pull(onCompleted);
|
||||
require("owmweather").pull(onCompleted, onError);
|
||||
}
|
||||
} else {
|
||||
// called to early, reschedule
|
||||
|
|
|
|||
|
|
@ -27,13 +27,12 @@ function parseWeather(response) {
|
|||
json.weather = weather;
|
||||
require("Storage").writeJSON('weather.json', json);
|
||||
if (require("Storage").read("weather")!==undefined) require("weather").emit("update", json.weather);
|
||||
return undefined;
|
||||
} else {
|
||||
return /*LANG*/"Not OWM data";
|
||||
throw /*LANG*/"Not OWM data";
|
||||
}
|
||||
}
|
||||
|
||||
exports.pull = function(completionCallback) {
|
||||
exports.pull = function(completionCallback, errorCallback) {
|
||||
let location = require("Storage").readJSON("mylocation.json", 1) || {
|
||||
"lat": 51.50,
|
||||
"lon": 0.12,
|
||||
|
|
@ -43,12 +42,12 @@ exports.pull = function(completionCallback) {
|
|||
let uri = "https://api.openweathermap.org/data/2.5/weather?lat=" + location.lat.toFixed(2) + "&lon=" + location.lon.toFixed(2) + "&exclude=hourly,daily&appid=" + settings.apikey;
|
||||
if (Bangle.http){
|
||||
Bangle.http(uri, {timeout:10000}).then(event => {
|
||||
let result = parseWeather(event.resp);
|
||||
if (completionCallback) completionCallback(result);
|
||||
parseWeather(event.resp);
|
||||
if (completionCallback) completionCallback();
|
||||
}).catch((e)=>{
|
||||
if (completionCallback) completionCallback(e);
|
||||
if (errorCallback) errorCallback(e);
|
||||
});
|
||||
} else {
|
||||
if (completionCallback) completionCallback(/*LANG*/"No http method found");
|
||||
if (errorCallback) errorCallback(/*LANG*/"No http method found");
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{ "id": "owmweather",
|
||||
"name": "OpenWeatherMap weather provider",
|
||||
"shortName":"OWM Weather",
|
||||
"version": "0.09",
|
||||
"version": "0.10",
|
||||
"description": "Pulls weather from OpenWeatherMap (OWM) API",
|
||||
"icon": "app.png",
|
||||
"type": "bootloader",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
0.01: First release
|
||||
0.02: clock_info now uses app name to maintain settings specifically for this clock face
|
||||
ensure clockinfo text is usppercase (font doesn't render lowercase)
|
||||
ensure clockinfo text is uppercase (font doesn't render lowercase)
|
||||
0.03: Use smaller font if clock_info test doesn't fit in area
|
||||
0.04: Ensure we only scale down clockinfo text if it really won't fit
|
||||
0.05: Minor code improvements
|
||||
|
|
@ -10,4 +10,6 @@
|
|||
0.09: Add date on the bottom
|
||||
0.10: Fix size of bottom bar after 0.09
|
||||
Make date toggleable with settings
|
||||
Optional border around clockinfos (available from settings)
|
||||
Optional border around clockinfos (available from settings)
|
||||
0.11: Make the border on clockinfos the default
|
||||
Fix clockinfos when too long (previously just output '...')
|
||||
|
|
@ -20,7 +20,7 @@ Graphics.prototype.setFontLECO1976Regular14 = function() {
|
|||
|
||||
{
|
||||
const SETTINGS_FILE = "pebblepp.json";
|
||||
let settings = Object.assign({'theme':'System', 'showdate':true, 'clkinfoborder': false}, require("Storage").readJSON(SETTINGS_FILE,1)||{});
|
||||
let settings = Object.assign({'theme':'System', 'showdate':true, 'clkinfoborder': true}, require("Storage").readJSON(SETTINGS_FILE,1)||{});
|
||||
let background = require("clockbg");
|
||||
let theme;
|
||||
let drawTimeout;
|
||||
|
|
@ -102,7 +102,7 @@ let clockInfoDraw = (itm, info, options) => {
|
|||
g.setFontLECO1976Regular14();
|
||||
if (g.stringWidth(txt) > options.w) {// if still too big, split to 2 lines
|
||||
var l = g.wrapString(txt, options.w);
|
||||
txt = l.slice(0,2).join("\n") + (l.length>2)?"...":"";
|
||||
txt = l.slice(0,2).join("\n") + ((l.length>2)?"...":"");
|
||||
}
|
||||
y = options.y+options.h-12;
|
||||
if (settings.clkinfoborder) {
|
||||
|
|
@ -147,4 +147,4 @@ background.fillRect(Bangle.appRect); // start off with completely clear backgrou
|
|||
g.setColor(theme.fg).fillRect(0, h2 - 6, w, h3 + 6);
|
||||
|
||||
draw();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"id": "pebblepp",
|
||||
"name": "Pebble++ Clock",
|
||||
"shortName": "Pebble++",
|
||||
"version": "0.10",
|
||||
"version": "0.11",
|
||||
"description": "A Pebble style clock (based on the 'Pebble Clock' app) but with two configurable ClockInfo items at the top and custom backgrounds. Date/theme/borders be reconfigured using settings page.",
|
||||
"icon": "app.png",
|
||||
"screenshots": [{"url":"screenshot.png"},{"url":"screenshot2.png"}],
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
const SETTINGS_FILE = "pebblepp.json";
|
||||
|
||||
// Initialize with default settings...
|
||||
let settings = {'theme':'System', 'showdate':true, 'clkinfoborder':false}
|
||||
let settings = {'theme':'System', 'showdate':true, 'clkinfoborder':true}
|
||||
// ...and overwrite them with any saved values
|
||||
// This way saved values are preserved if a new version adds more settings
|
||||
const storage = require('Storage');
|
||||
|
|
|
|||
|
|
@ -7,3 +7,7 @@
|
|||
0.13: Improve pattern rendering by HughB http://forum.espruino.com/profiles/167235/
|
||||
0.14: Update setUI to work with new Bangle.js 2v13 menu style
|
||||
0.15: Update to support clocks in custom setUI mode
|
||||
0.16: Fix issue adding new patterns (fix #3858)
|
||||
Display message if tapping manage when there are no patterns
|
||||
Speed improvements
|
||||
Add widgets to app (work around E.showMenu(back) bug with no widgets in Espruino 2v27)
|
||||
|
|
@ -9,10 +9,10 @@ var showMainMenu = () => {
|
|||
var mainmenu = {
|
||||
"": {
|
||||
title: "Pattern Launcher",
|
||||
},
|
||||
"< Back": () => {
|
||||
log("cancel");
|
||||
load();
|
||||
back: () => {
|
||||
log("showMainMenu cancel");
|
||||
load();
|
||||
}
|
||||
},
|
||||
"Add Pattern": () => {
|
||||
log("creating pattern");
|
||||
|
|
@ -83,11 +83,11 @@ var showMainMenu = () => {
|
|||
var settingsmenu = {
|
||||
"": {
|
||||
title: "Pattern Settings",
|
||||
},
|
||||
"< Back": () => {
|
||||
log("cancel");
|
||||
load();
|
||||
},
|
||||
back: () => {
|
||||
log("settings cancel");
|
||||
showMainMenu();
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
if (settings.lockDisabled) {
|
||||
|
|
@ -116,12 +116,7 @@ var showMainMenu = () => {
|
|||
|
||||
var recognizeAndDrawPattern = () => {
|
||||
return new Promise((resolve) => {
|
||||
E.showMenu();
|
||||
g.clear();
|
||||
drawCirclesWithPattern([]);
|
||||
|
||||
var pattern = [];
|
||||
|
||||
var isFinished = false;
|
||||
var finishHandler = () => {
|
||||
if (pattern.length === 0 || isFinished) {
|
||||
|
|
@ -129,15 +124,14 @@ var recognizeAndDrawPattern = () => {
|
|||
}
|
||||
log("Pattern is finished.");
|
||||
isFinished = true;
|
||||
Bangle.removeListener("drag", dragHandler);
|
||||
Bangle.removeListener("tap", finishHandler);
|
||||
g.clear();
|
||||
require("widget_utils").show();
|
||||
Bangle.setUI();
|
||||
resolve(pattern.join(""));
|
||||
};
|
||||
setWatch(() => finishHandler(), BTN);
|
||||
// setTimeout(() => Bangle.on("tap", finishHandler), 250);
|
||||
|
||||
var positions = [];
|
||||
var getPattern = (positions) => {
|
||||
var getPattern = (positions) => { "ram";/*faster*/
|
||||
var circles = [
|
||||
{ x: 25, y: 25, i: 0 },
|
||||
{ x: 87, y: 25, i: 1 },
|
||||
|
|
@ -151,18 +145,8 @@ var recognizeAndDrawPattern = () => {
|
|||
];
|
||||
return positions.reduce((pattern, p, i, arr) => {
|
||||
var idx = circles.findIndex((c) => {
|
||||
var dx = p.x > c.x ? p.x - c.x : c.x - p.x;
|
||||
if (dx > CIRCLE_RADIUS) {
|
||||
return false;
|
||||
}
|
||||
var dy = p.y > c.y ? p.y - c.y : c.y - p.y;
|
||||
if (dy > CIRCLE_RADIUS) {
|
||||
return false;
|
||||
}
|
||||
if (dx + dy <= CIRCLE_RADIUS) {
|
||||
return true;
|
||||
}
|
||||
return dx * dx + dy * dy <= CIRCLE_RADIUS_2;
|
||||
var dx = p.x - c.x, dy = p.y - c.y;
|
||||
return dx*dx + dy*dy <= CIRCLE_RADIUS_2;
|
||||
});
|
||||
if (idx >= 0) {
|
||||
pattern += circles[idx].i;
|
||||
|
|
@ -183,7 +167,10 @@ var recognizeAndDrawPattern = () => {
|
|||
positions = [];
|
||||
}
|
||||
};
|
||||
Bangle.on("drag", dragHandler);
|
||||
require("widget_utils").hide();
|
||||
g.clear();
|
||||
drawCirclesWithPattern([]);
|
||||
Bangle.setUI({mode:"custom", drag:dragHandler, btn :finishHandler});
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -215,14 +202,14 @@ var getAppList = () => {
|
|||
};
|
||||
|
||||
var getSelectedApp = () => {
|
||||
E.showMessage("Loading apps...");
|
||||
E.showMessage(/*LANG*/"Loading apps...");
|
||||
return new Promise((resolve) => {
|
||||
var selectAppMenu = {
|
||||
"": {
|
||||
title: "Select App",
|
||||
title: /*LANG*/"Select App",
|
||||
},
|
||||
"< Cancel": () => {
|
||||
log("cancel");
|
||||
log("getSelectedApp cancel");
|
||||
showMainMenu();
|
||||
},
|
||||
};
|
||||
|
|
@ -286,6 +273,8 @@ var drawAppWithPattern = (i, r, storedPatterns) => {
|
|||
|
||||
var showScrollerContainingAppsWithPatterns = () => {
|
||||
var storedPatternsArray = getStoredPatternsArray();
|
||||
if (!storedPatternsArray.length)
|
||||
return E.showAlert(/*LANG*/"No Patterns",{title:/*LANG*/"Patterns"}).then(() => ({ pattern: "back", appName:"" }));
|
||||
log("drawing scroller for stored patterns");
|
||||
log(storedPatternsArray);
|
||||
log(storedPatternsArray.length);
|
||||
|
|
@ -485,4 +474,6 @@ var log = (message) => {
|
|||
// run main function
|
||||
//////
|
||||
|
||||
showMainMenu();
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
showMainMenu();
|
||||
|
|
@ -24,18 +24,8 @@
|
|||
];
|
||||
return positions.reduce((pattern, p, i, arr) => {
|
||||
var idx = circles.findIndex((c) => {
|
||||
var dx = p.x > c.x ? p.x - c.x : c.x - p.x;
|
||||
if (dx > CIRCLE_RADIUS) {
|
||||
return false;
|
||||
}
|
||||
var dy = p.y > c.y ? p.y - c.y : c.y - p.y;
|
||||
if (dy > CIRCLE_RADIUS) {
|
||||
return false;
|
||||
}
|
||||
if (dx + dy <= CIRCLE_RADIUS) {
|
||||
return true;
|
||||
}
|
||||
return dx * dx + dy * dy <= CIRCLE_RADIUS_2;
|
||||
var dx = p.x - c.x, dy = p.y - c.y;
|
||||
return dx*dx + dy*dy <= CIRCLE_RADIUS_2;
|
||||
});
|
||||
if (idx >= 0) {
|
||||
pattern += circles[idx].i;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"id": "ptlaunch",
|
||||
"name": "Pattern Launcher",
|
||||
"shortName": "Pattern Launcher",
|
||||
"version": "0.15",
|
||||
"version": "0.16",
|
||||
"description": "Directly launch apps from the clock screen with custom patterns.",
|
||||
"icon": "app.png",
|
||||
"screenshots": [{"url":"manage_patterns_light.png"}],
|
||||
|
|
|
|||
|
|
@ -55,4 +55,9 @@
|
|||
0.43: Fix interaction on clocks without widgets
|
||||
0.44: List tracks in reverse chronological order.
|
||||
0.45: Move recorder from widget into library
|
||||
Improve recorder ClockInfo icons
|
||||
Improve recorder ClockInfo icons
|
||||
0.46: Ensure altitude graph draws properly (or any graph using the last column of CSV data)
|
||||
Lower accuracy of barometer data to ~1cm (saves about 15b/record)
|
||||
0.47: Fix 'blip' on speed map on some recordings
|
||||
Ensure Battery voltage is only stored to 0.01v
|
||||
Add graphs for Steps+Battery
|
||||
|
|
@ -197,6 +197,14 @@ function viewTrack(filename, info) {
|
|||
menu[/*LANG*/'Plot HRM'] = function() {
|
||||
plotGraph(info, "Heartrate");
|
||||
};
|
||||
if (info.fields.includes("Steps"))
|
||||
menu[/*LANG*/'Plot Steps'] = function() {
|
||||
plotGraph(info, "Steps");
|
||||
};
|
||||
if (info.fields.includes("Battery Percentage"))
|
||||
menu[/*LANG*/'Plot Battery'] = function() {
|
||||
plotGraph(info, "Battery");
|
||||
};
|
||||
// TODO: steps, heart rate?
|
||||
menu[/*LANG*/'Erase'] = function() {
|
||||
E.showPrompt(/*LANG*/"Delete Track?").then(function(v) {
|
||||
|
|
@ -325,6 +333,7 @@ function plotGraph(info, style) { "ram"
|
|||
var lt = 0; // last time
|
||||
//var tn = 0; // count for each time period
|
||||
var strt, dur = info.duration;
|
||||
if (dur<1) dur=1;
|
||||
var f = require("Storage").open(filename,"r");
|
||||
if (f===undefined) return;
|
||||
var l = f.readLine(f);
|
||||
|
|
@ -333,14 +342,14 @@ function plotGraph(info, style) { "ram"
|
|||
var factor = 1; // multiplier used for values when graphing
|
||||
var timeIdx = info.fields.indexOf("Time");
|
||||
if (l!==undefined) {
|
||||
c = l.split(",");
|
||||
c = l.trim().split(",");
|
||||
strt = c[timeIdx];
|
||||
}
|
||||
if (style=="Heartrate") {
|
||||
title = /*LANG*/"Heartrate (bpm)";
|
||||
var hrmIdx = info.fields.indexOf("Heartrate");
|
||||
while(l!==undefined) {
|
||||
c=l.split(",");l = f.readLine(f);
|
||||
c=l.trim().split(",");l = f.readLine(f);
|
||||
if (c[hrmIdx]=="") continue;
|
||||
i = Math.round(80*(c[timeIdx] - strt)/dur);
|
||||
infn[i]+=+c[hrmIdx];
|
||||
|
|
@ -351,45 +360,63 @@ function plotGraph(info, style) { "ram"
|
|||
var altIdx = info.fields.indexOf("Barometer Altitude");
|
||||
if (altIdx<0) altIdx = info.fields.indexOf("Altitude");
|
||||
while(l!==undefined) {
|
||||
c=l.split(",");l = f.readLine(f);
|
||||
c=l.trim().split(",");l = f.readLine(f);
|
||||
if (c[altIdx]=="") continue;
|
||||
i = Math.round(80*(c[timeIdx] - strt)/dur);
|
||||
infn[i]+=+c[altIdx];
|
||||
infc[i]++;
|
||||
}
|
||||
} else if (style=="Steps") {
|
||||
title = /*LANG*/"Steps/min";
|
||||
var stpIdx = info.fields.indexOf("Steps");
|
||||
var t,lt = c[timeIdx];
|
||||
while(l!==undefined) {
|
||||
c=l.trim().split(",");l = f.readLine(f);
|
||||
if (c[stpIdx]=="") continue;
|
||||
t = c[timeIdx];
|
||||
i = Math.round(80*(t - strt)/dur);
|
||||
infn[i]+=60*c[stpIdx];
|
||||
infc[i]+=t-lt;
|
||||
lt = t;
|
||||
}
|
||||
} else if (style=="Battery") {
|
||||
title = /*LANG*/"Battery %";
|
||||
var batIdx = info.fields.indexOf("Battery Percentage");
|
||||
while(l!==undefined) {
|
||||
c=l.trim().split(",");l = f.readLine(f);
|
||||
if (c[batIdx]=="") continue;
|
||||
i = Math.round(80*(c[timeIdx] - strt)/dur);
|
||||
infn[i]+=+c[batIdx];
|
||||
infc[i]++;
|
||||
}
|
||||
} else if (style=="Speed") {
|
||||
// use locate to work out units
|
||||
var localeStr = require("locale").speed(1,5); // get what 1kph equates to
|
||||
let units = localeStr.replace(/[0-9.]*/,"");
|
||||
factor = parseFloat(localeStr)*3.6; // m/sec to whatever out units are
|
||||
// title
|
||||
title = /*LANG*/"Speed"+` (${units})`;
|
||||
var latIdx = info.fields.indexOf("Latitude");
|
||||
var lonIdx = info.fields.indexOf("Longitude");
|
||||
// skip until we find our first data
|
||||
while(l!==undefined && c[latIdx]=="") {
|
||||
c = l.split(",");
|
||||
c = l.trim().split(",");
|
||||
l = f.readLine(f);
|
||||
}
|
||||
// now iterate
|
||||
var p,lp = Bangle.project({lat:c[1],lon:c[2]});
|
||||
var p,lp = Bangle.project({lat:c[latIdx],lon:c[lonIdx]});
|
||||
var t,dx,dy,d,lt = c[timeIdx];
|
||||
while(l!==undefined) {
|
||||
c=l.split(",");
|
||||
c=l.trim().split(",");
|
||||
l = f.readLine(f);
|
||||
if (c[latIdx] == "") {
|
||||
continue;
|
||||
}
|
||||
if (c[latIdx] == "") continue;
|
||||
t = c[timeIdx];
|
||||
i = Math.round(80*(t - strt)/dur);
|
||||
p = Bangle.project({lat:c[latIdx],lon:c[lonIdx]});
|
||||
dx = p.x-lp.x;
|
||||
dy = p.y-lp.y;
|
||||
d = Math.sqrt(dx*dx+dy*dy);
|
||||
if (t!=lt) {
|
||||
infn[i]+=d / (t-lt); // speed
|
||||
infc[i]++;
|
||||
}
|
||||
infn[i]+=d; // speed
|
||||
infc[i]+=t-lt;
|
||||
lp = p;
|
||||
lt = t;
|
||||
}
|
||||
|
|
@ -405,6 +432,7 @@ function plotGraph(info, style) { "ram"
|
|||
if (n>max) max=n;
|
||||
if (n<min) min=n;
|
||||
}
|
||||
if (style=="Battery") {min=0;max=100;}
|
||||
// work out a nice grid value
|
||||
var heightDiff = max-min;
|
||||
var grid = 1;
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ exports.getRecorders = function() {
|
|||
name : "BAT",
|
||||
fields : ["Battery Percentage", "Battery Voltage", "Charging"],
|
||||
getValues : () => {
|
||||
return [E.getBattery(), NRF.getBattery(), Bangle.isCharging()];
|
||||
return [E.getBattery(), NRF.getBattery().toFixed(2), Bangle.isCharging()];
|
||||
},
|
||||
start : () => {
|
||||
},
|
||||
|
|
@ -120,9 +120,9 @@ exports.getRecorders = function() {
|
|||
recorders['baro'] = function() {
|
||||
var temp="",press="",alt="";
|
||||
function onPress(c) {
|
||||
temp=c.temperature;
|
||||
press=c.pressure;
|
||||
alt=c.altitude;
|
||||
temp=c.temperature.toFixed(1);
|
||||
press=c.pressure.toFixed(2);
|
||||
alt=c.altitude.toFixed(2);
|
||||
}
|
||||
return {
|
||||
name : "Baro",
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"id": "recorder",
|
||||
"name": "Recorder",
|
||||
"shortName": "Recorder",
|
||||
"version": "0.45",
|
||||
"version": "0.47",
|
||||
"description": "Record GPS position, heart rate and more in the background, then download to your PC.",
|
||||
"icon": "app.png",
|
||||
"tags": "tool,outdoors,gps,widget,clkinfo",
|
||||
|
|
|
|||
|
|
@ -87,3 +87,4 @@ of 'Select Clock'
|
|||
0.76: Add altitude calibration menu (and update README after menu changed)
|
||||
0.77: Save altitude calibration when user exits via reset
|
||||
0.78: Fix menu scroll restore on BangleJS1
|
||||
0.79: Ensure that tapping on pressure/altitude doesn't cause a menu to display temporarily
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "setting",
|
||||
"name": "Settings",
|
||||
"version": "0.78",
|
||||
"version": "0.79",
|
||||
"description": "A menu for setting up Bangle.js",
|
||||
"icon": "settings.png",
|
||||
"tags": "tool,system",
|
||||
|
|
|
|||
|
|
@ -1033,8 +1033,8 @@ function showTouchscreenCalibration() {
|
|||
// Calibrate altitude - Bangle.js2 only
|
||||
function showAltitude() {
|
||||
function onPressure(pressure) {
|
||||
menuPressure.value = Math.round(pressure.pressure);
|
||||
menuAltitude.value = Math.round(pressure.altitude);
|
||||
menuPressure.value = Math.round(pressure.pressure).toString(); // toString stops tapping on the item bringing up an adjustment menu
|
||||
menuAltitude.value = Math.round(pressure.altitude).toString();
|
||||
m.draw();
|
||||
}
|
||||
function altitudeDone() {
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
"name":"Sleep Log",
|
||||
"shortName": "SleepLog",
|
||||
"version": "0.19",
|
||||
"description": "Log and view your sleeping habits. This app is using the built in movement calculation.",
|
||||
"description": "Log and view your sleeping habits. This app uses built in movement calculations. View data from Bangle, or from the web app.",
|
||||
"icon": "app.png",
|
||||
"type": "app",
|
||||
"tags": "tool,boot",
|
||||
"tags": "tool,boot,health",
|
||||
"supports": ["BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
"interface": "interface.html",
|
||||
|
|
|
|||
2
core
|
|
@ -1 +1 @@
|
|||
Subproject commit 7e7475ba3ab253099481a81e487aaacb9384f974
|
||||
Subproject commit 0916756932699d626555171ce8e0a2989b151c89
|
||||