1
0
Fork 0

Merge branch 'master' of github.com:awkirk71/BangleApps into extended_sliding_clock

master
lu713691 2022-09-26 23:16:20 +01:00
commit f095bb352e
400 changed files with 8921 additions and 4390 deletions

3
.gitignore vendored
View File

@ -11,3 +11,6 @@ tests/Layout/testresult.bmp
apps.local.json apps.local.json
_site _site
.jekyll-cache .jekyll-cache
.owncloudsync.log
Desktop.ini
.sync_*.db*

View File

@ -269,7 +269,7 @@ function actions(v){
} }
// Get Messages status // Get Messages status
var messages = require("Storage").readJSON("messages.json",1)||[]; var messages_installed = require("Storage").read("messages") !== undefined;
//var BTconnected = NRF.getSecurityStatus().connected; //var BTconnected = NRF.getSecurityStatus().connected;
//NRF.on('connect',BTconnected = NRF.getSecurityStatus().connected); //NRF.on('connect',BTconnected = NRF.getSecurityStatus().connected);
@ -318,7 +318,7 @@ function drawWidgeds() {
var x2M = x1M + 25; var x2M = x1M + 25;
var y2M = y2B; var y2M = y2B;
if (messages.some(m=>m.new)) { if (messages_installed && require("messages").status() == "new") {
g.setColor(g.theme.fg); g.setColor(g.theme.fg);
g.fillRect(x1M,y1M,x2M,y2M); g.fillRect(x1M,y1M,x2M,y2M);
g.setColor(g.theme.bg); g.setColor(g.theme.bg);

View File

@ -1,2 +1,3 @@
0.01: Initial version for upload 0.01: Initial version for upload
0.02: better theme support, configurable colors, small improvements 0.02: Better theme support, configurable colors, small improvements
0.03: Use `messages` library to check for new messages

View File

@ -1,7 +1,7 @@
{ "id": "7x7dotsclock", { "id": "7x7dotsclock",
"name": "7x7 Dots Clock", "name": "7x7 Dots Clock",
"shortName":"7x7 Dots Clock", "shortName":"7x7 Dots Clock",
"version":"0.02", "version":"0.03",
"description": "A clock with a big 7x7 dots Font", "description": "A clock with a big 7x7 dots Font",
"icon": "dotsfontclock.png", "icon": "dotsfontclock.png",
"tags": "clock", "tags": "clock",

View File

@ -1,2 +1,3 @@
0.01: New App! 0.01: New App!
0.02: Fullscreen settings. 0.02: Fullscreen settings.
0.03: Tell clock widgets to hide.

View File

@ -115,6 +115,9 @@ function draw() {
} }
} }
// Show launcher when middle button pressed
Bangle.setUI("clock");
Bangle.loadWidgets(); Bangle.loadWidgets();
// Clear the screen once, at startup // Clear the screen once, at startup
@ -140,5 +143,3 @@ Bangle.on('lock', function(isLocked) {
}); });
// Show launcher when middle button pressed
Bangle.setUI("clock");

View File

@ -1,7 +1,7 @@
{ {
"id": "90sclk", "id": "90sclk",
"name": "90s Clock", "name": "90s Clock",
"version": "0.02", "version": "0.03",
"description": "A 90s style watch-face", "description": "A 90s style watch-face",
"readme": "README.md", "readme": "README.md",
"icon": "app.png", "icon": "app.png",

View File

@ -0,0 +1 @@
0.01: Initial version

View File

@ -0,0 +1,13 @@
# a_dndtoggle - Toggle Quiet Mode of the watch
When Quiet mode is off, just start this app to set quiet mode. Start it again to turn off quiet mode.
Work in progress.
#ToDo
Settings page, current status indicator.
## Creator
Hank - contact at http://forum.espruino.com

View File

@ -0,0 +1,43 @@
const modeNames = [/*LANG*/"Noisy", /*LANG*/"Alarms", /*LANG*/"Silent"];
let bSettings = require('Storage').readJSON('setting.json',true)||{};
let current = 0|bSettings.quiet;
//0 off
//1 alarms
//2 silent
console.log("old: " + current);
switch (current) {
case 0:
bSettings.quiet = 2;
Bangle.buzz();
setTimeout('Bangle.buzz();',500);
break;
case 1:
bSettings.quiet = 0;
Bangle.buzz();
break;
case 2:
bSettings.quiet = 0;
Bangle.buzz();
break;
default:
bSettings.quiet = 0;
Bangle.buzz();
}
console.log("new: " + bSettings.quiet);
E.showMessage(modeNames[current] + " -> " + modeNames[bSettings.quiet]);
setTimeout('exitApp();', 2000);
function exitApp(){
require("Storage").writeJSON("setting.json", bSettings);
// reload clocks with new theme, otherwise just wait for user to switch apps
load()
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 486 B

View File

@ -0,0 +1 @@
require("heatshrink").decompress(atob("mEwwJC/AAl/Agf/AAUAgIFDwEHAofgh/g/0Ag/wj+AnwVB/EegEfEIN4nkAh+AgE8vgVBAoV4Aoce/EAgfADQIFcjwpFHYIFCnxBFJopZBn5ZCMopxFPoqJFSowA/gA="))

View File

@ -0,0 +1,16 @@
{
"id": "a_dndtoggle",
"name": "a_dndtoggle - Toggle Quiet Mode of the watch",
"shortName": "A_DND Toggle",
"version": "0.01",
"description": "Toggle Quiet Mode of the watch just by starting this app.",
"icon": "a_dndtoggle.png",
"type": "app",
"tags": "tool",
"supports": ["BANGLEJS","BANGLEJS2"],
"storage": [
{"name":"a_dndtoggle.app.js","url":"a_dndtoggle.app.js"},
{"name":"a_dndtoggle.img","url":"app-icon.js","evaluate":true}
],
"readme": "README.md"
}

View File

@ -10,3 +10,4 @@
0.10: Added separate Bangle.js 2 file with Bangle.js 2 kickstarter pixels (as of 28 Oct 2021) 0.10: Added separate Bangle.js 2 file with Bangle.js 2 kickstarter pixels (as of 28 Oct 2021)
0.11: Bangle.js2: New pixels, btn1 to exit 0.11: Bangle.js2: New pixels, btn1 to exit
0.12: Actual pixels as of 29th Nov 2021 0.12: Actual pixels as of 29th Nov 2021
0.13: Bangle.js 2: Use setUI to add software back button

View File

@ -69,4 +69,7 @@ function drawImage() {
// TODO: a nice little animation before // TODO: a nice little animation before
setTimeout(drawInfo, 1000); setTimeout(drawInfo, 1000);
setWatch(_=>load(), BTN1); Bangle.setUI({
mode : "custom",
back : load
});

View File

@ -1,7 +1,7 @@
{ {
"id": "about", "id": "about",
"name": "About", "name": "About",
"version": "0.12", "version": "0.13",
"description": "Bangle.js About page - showing software version, stats, and a collaborative mural from the Bangle.js KickStarter backers", "description": "Bangle.js About page - showing software version, stats, and a collaborative mural from the Bangle.js KickStarter backers",
"icon": "app.png", "icon": "app.png",
"tags": "tool,system", "tags": "tool,system",

View File

@ -6,3 +6,5 @@
0.06: Add a temperature threshold to detect (and not alert) if the BJS isn't worn. Better support for the peoples using the app at night 0.06: Add a temperature threshold to detect (and not alert) if the BJS isn't worn. Better support for the peoples using the app at night
0.07: Fix bug on the cutting edge firmware 0.07: Fix bug on the cutting edge firmware
0.08: Use default Bangle formatter for booleans 0.08: Use default Bangle formatter for booleans
0.09: New app screen (instead of showing settings or the alert) and some optimisations
0.10: Add software back button via setUI

View File

@ -0,0 +1,37 @@
(function () {
// load variable before defining functions cause it can trigger a ReferenceError
const activityreminder = require("activityreminder");
const storage = require("Storage");
let activityreminder_data = activityreminder.loadData();
function run() {
E.showPrompt("Inactivity detected", {
title: "Activity reminder",
buttons: { "Ok": 1, "Dismiss": 2, "Pause": 3 }
}).then(function (v) {
if (v == 1) {
activityreminder_data.okDate = new Date();
}
if (v == 2) {
activityreminder_data.dismissDate = new Date();
}
if (v == 3) {
activityreminder_data.pauseDate = new Date();
}
activityreminder.saveData(activityreminder_data);
load();
});
// Obey system quiet mode:
if (!(storage.readJSON('setting.json', 1) || {}).quiet) {
Bangle.buzz(400);
}
setTimeout(load, 20000);
}
g.clear();
Bangle.loadWidgets();
Bangle.drawWidgets();
run();
})();

View File

@ -1,46 +1,58 @@
(function () { (function () {
// load variable before defining functions cause it can trigger a ReferenceError // load variable before defining functions cause it can trigger a ReferenceError
const activityreminder = require("activityreminder"); const activityreminder = require("activityreminder");
const storage = require("Storage");
const activityreminder_settings = activityreminder.loadSettings();
let activityreminder_data = activityreminder.loadData(); let activityreminder_data = activityreminder.loadData();
let W = g.getWidth();
// let H = g.getHeight();
function drawAlert() { function getHoursMins(date){
E.showPrompt("Inactivity detected", { var h = date.getHours();
title: "Activity reminder", var m = date.getMinutes();
buttons: { "Ok": 1, "Dismiss": 2, "Pause": 3 } return (""+h).substr(-2) + ":" + ("0"+m).substr(-2);
}).then(function (v) {
if (v == 1) {
activityreminder_data.okDate = new Date();
} }
if (v == 2) {
activityreminder_data.dismissDate = new Date();
}
if (v == 3) {
activityreminder_data.pauseDate = new Date();
}
activityreminder.saveData(activityreminder_data);
load();
});
// Obey system quiet mode: function drawData(name, value, y){
if (!(storage.readJSON('setting.json', 1) || {}).quiet) { g.drawString(name, 10, y);
Bangle.buzz(400); g.drawString(value, 100, y);
} }
setTimeout(load, 20000);
function drawInfo() {
var h=18, y = h;
g.setColor(g.theme.fg);
g.setFont("Vector",h).setFontAlign(-1,-1);
// Header
g.drawLine(0,25,W,25);
g.drawLine(0,26,W,26);
g.drawString("Current Cycle", 10, y+=h);
drawData("Start", getHoursMins(activityreminder_data.stepsDate), y+=h);
drawData("Steps", getCurrentSteps(), y+=h);
/*
g.drawString("Button Press", 10, y+=h*2);
drawData("Ok", getHoursMins(activityreminder_data.okDate), y+=h);
drawData("Dismiss", getHoursMins(activityreminder_data.dismissDate), y+=h);
drawData("Pause", getHoursMins(activityreminder_data.pauseDate), y+=h);
*/
}
function getCurrentSteps(){
let health = Bangle.getHealthStatus("day");
return health.steps - activityreminder_data.stepsOnDate;
} }
function run() { function run() {
if (activityreminder.mustAlert(activityreminder_data, activityreminder_settings)) {
drawAlert();
} else {
eval(storage.read("activityreminder.settings.js"))(() => load());
}
}
g.clear(); g.clear();
Bangle.loadWidgets(); Bangle.loadWidgets();
Bangle.drawWidgets(); Bangle.drawWidgets();
drawInfo();
Bangle.setUI({
mode : "custom",
back : load
})
}
run(); run();
})(); })();

View File

@ -27,8 +27,8 @@
*/ */
} }
if (activityreminder.mustAlert(activityreminder_data, activityreminder_settings)) { if (mustAlert(now)) {
load('activityreminder.app.js'); load('activityreminder.alert.js');
} }
} }
@ -46,6 +46,17 @@
} }
} }
function mustAlert(now) {
if ((now - activityreminder_data.stepsDate) / 60000 > activityreminder_settings.maxInnactivityMin) { // inactivity detected
if ((now - activityreminder_data.okDate) / 60000 > 3 && // last alert anwsered with ok was more than 3 min ago
(now - activityreminder_data.dismissDate) / 60000 > activityreminder_settings.dismissDelayMin && // last alert was more than dismissDelayMin ago
(now - activityreminder_data.pauseDate) / 60000 > activityreminder_settings.pauseDelayMin) { // last alert was more than pauseDelayMin ago
return true;
}
}
return false;
}
Bangle.on('midnight', function () { Bangle.on('midnight', function () {
/* /*
Usefull trick to have the app working smothly for people using it at night Usefull trick to have the app working smothly for people using it at night

View File

@ -31,26 +31,14 @@ exports.loadData = function () {
}, },
require("Storage").readJSON("activityreminder.data.json") || {}); require("Storage").readJSON("activityreminder.data.json") || {});
if(typeof(data.stepsDate) == "string") if (typeof (data.stepsDate) == "string")
data.stepsDate = new Date(data.stepsDate); data.stepsDate = new Date(data.stepsDate);
if(typeof(data.okDate) == "string") if (typeof (data.okDate) == "string")
data.okDate = new Date(data.okDate); data.okDate = new Date(data.okDate);
if(typeof(data.dismissDate) == "string") if (typeof (data.dismissDate) == "string")
data.dismissDate = new Date(data.dismissDate); data.dismissDate = new Date(data.dismissDate);
if(typeof(data.pauseDate) == "string") if (typeof (data.pauseDate) == "string")
data.pauseDate = new Date(data.pauseDate); data.pauseDate = new Date(data.pauseDate);
return data; return data;
}; };
exports.mustAlert = function(activityreminder_data, activityreminder_settings) {
let now = new Date();
if ((now - activityreminder_data.stepsDate) / 60000 > activityreminder_settings.maxInnactivityMin) { // inactivity detected
if ((now - activityreminder_data.okDate) / 60000 > 3 && // last alert anwsered with ok was more than 3 min ago
(now - activityreminder_data.dismissDate) / 60000 > activityreminder_settings.dismissDelayMin && // last alert was more than dismissDelayMin ago
(now - activityreminder_data.pauseDate) / 60000 > activityreminder_settings.pauseDelayMin) { // last alert was more than pauseDelayMin ago
return true;
}
}
return false;
}

View File

@ -3,7 +3,7 @@
"name": "Activity Reminder", "name": "Activity Reminder",
"shortName":"Activity Reminder", "shortName":"Activity Reminder",
"description": "A reminder to take short walks for the ones with a sedentary lifestyle", "description": "A reminder to take short walks for the ones with a sedentary lifestyle",
"version":"0.08", "version":"0.10",
"icon": "app.png", "icon": "app.png",
"type": "app", "type": "app",
"tags": "tool,activity", "tags": "tool,activity",
@ -13,11 +13,12 @@
{"name": "activityreminder.app.js", "url":"app.js"}, {"name": "activityreminder.app.js", "url":"app.js"},
{"name": "activityreminder.boot.js", "url": "boot.js"}, {"name": "activityreminder.boot.js", "url": "boot.js"},
{"name": "activityreminder.settings.js", "url": "settings.js"}, {"name": "activityreminder.settings.js", "url": "settings.js"},
{"name": "activityreminder.alert.js", "url": "alert.js"},
{"name": "activityreminder", "url": "lib.js"}, {"name": "activityreminder", "url": "lib.js"},
{"name": "activityreminder.img", "url": "app-icon.js", "evaluate": true} {"name": "activityreminder.img", "url": "app-icon.js", "evaluate": true}
], ],
"data": [ "data": [
{"name": "activityreminder.s.json"}, {"name": "activityreminder.s.json"},
{"name": "activityreminder.data.json"} {"name": "activityreminder.data.json", "storageFile": true}
] ]
} }

View File

@ -3,8 +3,8 @@
const activityreminder = require("activityreminder"); const activityreminder = require("activityreminder");
let settings = activityreminder.loadSettings(); let settings = activityreminder.loadSettings();
// Show the menu function getMainMenu(){
E.showMenu({ var mainMenu = {
"": { "title": "Activity Reminder" }, "": { "title": "Activity Reminder" },
"< Back": () => back(), "< Back": () => back(),
'Enable': { 'Enable': {
@ -76,5 +76,11 @@
activityreminder.writeSettings(settings); activityreminder.writeSettings(settings);
} }
} }
}); };
return mainMenu;
}
// Show the menu
E.showMenu(getMainMenu());
}) })

View File

@ -1 +1,3 @@
0.01: AdvCasio first version 0.01: AdvCasio first version
0.02: Remove un-needed fonts to improve memory usage
0.03: Tell clock widgets to hide.

View File

@ -1,7 +1,5 @@
const storage = require('Storage'); const storage = require('Storage');
require("Font6x12").add(Graphics);
require("Font6x8").add(Graphics);
require("Font8x12").add(Graphics); require("Font8x12").add(Graphics);
require("Font7x11Numeric7Seg").add(Graphics); require("Font7x11Numeric7Seg").add(Graphics);
@ -257,7 +255,6 @@ function draw() {
g.setColor(0, 0, 0); g.setColor(0, 0, 0);
g.setFont("6x12");
if(dataJson && dataJson.weather) drawWeather(dataJson.weather); if(dataJson && dataJson.weather) drawWeather(dataJson.weather);
if(dataJson && dataJson.tasks) drawTasks(dataJson.tasks); if(dataJson && dataJson.tasks) drawTasks(dataJson.tasks);
@ -297,9 +294,10 @@ Bangle.on("lock", (locked) => {
}); });
Bangle.setUI("clock");
// Load widgets, but don't show them // Load widgets, but don't show them
Bangle.loadWidgets(); Bangle.loadWidgets();
Bangle.setUI("clock");
g.reset(); g.reset();
g.clear(); g.clear();

View File

@ -1,7 +1,7 @@
{ "id": "advcasio", { "id": "advcasio",
"name": "Advanced Casio Clock", "name": "Advanced Casio Clock",
"shortName":"advcasio", "shortName":"advcasio",
"version":"0.01", "version":"0.03",
"description": "An over-engineered clock inspired by Casio watches. It has a 4 days weather, a timer using swipe and a scratchpad. Can be updated using a dedicated webapp.", "description": "An over-engineered clock inspired by Casio watches. It has a 4 days weather, a timer using swipe and a scratchpad. Can be updated using a dedicated webapp.",
"icon": "app.png", "icon": "app.png",
"tags": "clock", "tags": "clock",

View File

@ -1,2 +1,6 @@
0.01: Basic agenda with events from GB 0.01: Basic agenda with events from GB
0.02: Added settings page to force calendar sync 0.02: Added settings page to force calendar sync
0.03: Disable past events display from settings
0.04: Added awareness of allDay field
0.05: Displaying calendar colour and name
0.06: Added clkinfo for clocks.

View File

@ -1,3 +1,20 @@
# Agenda # Agenda
Basic agenda reading the events synchronised from GadgetBridge Basic agenda reading the events synchronised from GadgetBridge.
### Functionalities
* List all events in the next week (or whatever is synchronized)
* Optionally view past events (until GB removes them)
* Show start time and location of the events in the list
* Show the colour of the calendar in the list
* Display description, location and calendar name after tapping on events
### Report a bug
You can easily open an issue in the espruino repo, but I won't be notified and it might take time.
If you want a (hopefully) quicker response, just report [on my fork](https://github.com/glemco/BangleApps).
### Known Problems
Any all-day event lasts just one day: that is a GB limitation that we will likely fix in the future.

View File

@ -0,0 +1,29 @@
(function() {
var agendaItems = {
name: "Agenda",
img: atob("GBiBAf////////85z/AAAPAAAPgAAP////AAAPAAAPAAAPAAAOAAAeAAAeAAAcAAA8AAAoAABgAADP//+P//8PAAAPAAAPgAAf///w=="),
items: []
};
var now = new Date();
var agenda = storage.readJSON("android.calendar.json")
.filter(ev=>ev.timestamp + ev.durationInSeconds > now/1000)
.sort((a,b)=>a.timestamp - b.timestamp);
agenda.forEach((entry, i) => {
var title = entry.title.slice(0,18);
var date = new Date(entry.timestamp*1000);
var dateStr = locale.date(date).replace(/\d\d\d\d/,"");
dateStr += entry.durationInSeconds < 86400 ? "/ " + locale.time(date,1) : "";
agendaItems.items.push({
name: "agendaEntry-" + i,
get: () => ({ text: title + "\n" + dateStr, img: null}),
show: function() { agendaItems.items[i].emit("redraw"); },
hide: function () {}
});
});
return agendaItems;
})

View File

@ -6,6 +6,8 @@
title, title,
description, description,
location, location,
color:int,
calName,
allDay: bool, allDay: bool,
} }
*/ */
@ -24,19 +26,23 @@ var fontLarge = g.getFonts().includes("6x15")?"6x15:2":"6x8:4";
//FIXME maybe write the end from GB already? Not durationInSeconds here (or do while receiving?) //FIXME maybe write the end from GB already? Not durationInSeconds here (or do while receiving?)
var CALENDAR = require("Storage").readJSON("android.calendar.json",true)||[]; var CALENDAR = require("Storage").readJSON("android.calendar.json",true)||[];
var settings = require("Storage").readJSON("agenda.settings.json",true)||{};
CALENDAR=CALENDAR.sort((a,b)=>a.timestamp - b.timestamp) CALENDAR=CALENDAR.sort((a,b)=>a.timestamp - b.timestamp);
function getDate(timestamp) { function getDate(timestamp) {
return new Date(timestamp*1000); return new Date(timestamp*1000);
} }
function formatDateLong(date, includeDay) { function formatDateLong(date, includeDay, allDay) {
if(includeDay) let shortTime = Locale.time(date,1)+Locale.meridian(date);
return Locale.date(date)+" "+Locale.time(date,1); if(allDay) shortTime = "";
return Locale.time(date,1); if(includeDay || allDay)
return Locale.date(date)+" "+shortTime;
return shortTime;
} }
function formatDateShort(date) { function formatDateShort(date, allDay) {
return Locale.date(date).replace(/\d\d\d\d/,"")+Locale.time(date,1); return Locale.date(date).replace(/\d\d\d\d/,"")+(allDay?
"" : Locale.time(date,1)+Locale.meridian(date));
} }
var lines = []; var lines = [];
@ -45,7 +51,7 @@ function showEvent(ev) {
if(!ev) return; if(!ev) return;
g.setFont(bodyFont); g.setFont(bodyFont);
//var lines = []; //var lines = [];
if (ev.title) lines = g.wrapString(ev.title, g.getWidth()-10) if (ev.title) lines = g.wrapString(ev.title, g.getWidth()-10);
var titleCnt = lines.length; var titleCnt = lines.length;
var start = getDate(ev.timestamp); var start = getDate(ev.timestamp);
var end = getDate((+ev.timestamp) + (+ev.durationInSeconds)); var end = getDate((+ev.timestamp) + (+ev.durationInSeconds));
@ -53,22 +59,24 @@ function showEvent(ev) {
if (titleCnt) lines.push(""); // add blank line after title if (titleCnt) lines.push(""); // add blank line after title
if(start.getDay() == end.getDay() && start.getMonth() == end.getMonth()) if(start.getDay() == end.getDay() && start.getMonth() == end.getMonth())
includeDay = false; includeDay = false;
if(includeDay) { if(includeDay || ev.allDay) {
lines = lines.concat( lines = lines.concat(
/*LANG*/"Start:", /*LANG*/"Start:",
g.wrapString(formatDateLong(start, includeDay), g.getWidth()-10), g.wrapString(formatDateLong(start, includeDay, ev.allDay), g.getWidth()-10),
/*LANG*/"End:", /*LANG*/"End:",
g.wrapString(formatDateLong(end, includeDay), g.getWidth()-10)); g.wrapString(formatDateLong(end, includeDay, ev.allDay), g.getWidth()-10));
} else { } else {
lines = lines.concat( lines = lines.concat(
g.wrapString(Locale.date(start), g.getWidth()-10), g.wrapString(Locale.date(start), g.getWidth()-10),
g.wrapString(/*LANG*/"Start"+": "+formatDateLong(start, includeDay), g.getWidth()-10), g.wrapString(/*LANG*/"Start"+": "+formatDateLong(start, includeDay, ev.allDay), g.getWidth()-10),
g.wrapString(/*LANG*/"End"+": "+formatDateLong(end, includeDay), g.getWidth()-10)); g.wrapString(/*LANG*/"End"+": "+formatDateLong(end, includeDay, ev.allDay), g.getWidth()-10));
} }
if(ev.location) if(ev.location)
lines = lines.concat(/*LANG*/"Location"+": ", g.wrapString(ev.location, g.getWidth()-10)); lines = lines.concat(/*LANG*/"Location"+": ", g.wrapString(ev.location, g.getWidth()-10));
if(ev.description) if(ev.description)
lines = lines.concat("",g.wrapString(ev.description, g.getWidth()-10)); lines = lines.concat("",g.wrapString(ev.description, g.getWidth()-10));
if(ev.calName)
lines = lines.concat(/*LANG*/"Calendar"+": ", g.wrapString(ev.calName, g.getWidth()-10));
lines = lines.concat(["",/*LANG*/"< Back"]); lines = lines.concat(["",/*LANG*/"< Back"]);
E.showScroller({ E.showScroller({
h : g.getFontHeight(), // height of each menu item in pixels h : g.getFontHeight(), // height of each menu item in pixels
@ -89,6 +97,12 @@ function showEvent(ev) {
} }
function showList() { function showList() {
//it might take time for GB to delete old events, decide whether to show them grayed out or hide entirely
if(!settings.pastEvents) {
let now = new Date();
//TODO add threshold here?
CALENDAR = CALENDAR.filter(ev=>ev.timestamp + ev.durationInSeconds > now/1000);
}
if(CALENDAR.length == 0) { if(CALENDAR.length == 0) {
E.showMessage("No events"); E.showMessage("No events");
return; return;
@ -101,24 +115,21 @@ function showList() {
g.setColor(g.theme.fg); g.setColor(g.theme.fg);
g.clearRect(r.x,r.y,r.x+r.w, r.y+r.h); g.clearRect(r.x,r.y,r.x+r.w, r.y+r.h);
if (!ev) return; if (!ev) return;
var isPast = ev.timestamp + ev.durationInSeconds < (new Date())/1000; var isPast = false;
var x = r.x+2, title = ev.title; var x = r.x+2, title = ev.title;
var body = formatDateShort(getDate(ev.timestamp))+"\n"+ev.location; var body = formatDateShort(getDate(ev.timestamp),ev.allDay)+"\n"+(ev.location?ev.location:/*LANG*/"No location");
var m = ev.title+"\n"+ev.location, longBody=false; if(settings.pastEvents) isPast = ev.timestamp + ev.durationInSeconds < (new Date())/1000;
if (title) g.setFontAlign(-1,-1).setFont(fontBig) if (title) g.setFontAlign(-1,-1).setFont(fontBig)
.setColor(isPast ? "#888" : g.theme.fg).drawString(title, x,r.y+2); .setColor(isPast ? "#888" : g.theme.fg).drawString(title, x+4,r.y+2);
if (body) { if (body) {
g.setFontAlign(-1,-1).setFont(fontMedium).setColor(isPast ? "#888" : g.theme.fg); g.setFontAlign(-1,-1).setFont(fontMedium).setColor(isPast ? "#888" : g.theme.fg);
var l = g.wrapString(body, r.w-(x+14)); g.drawString(body, x+10,r.y+20);
if (l.length>3) {
l = l.slice(0,3);
l[l.length-1]+="...";
} }
longBody = l.length>2;
g.drawString(l.join("\n"), x+10,r.y+20);
}
//if (!longBody && msg.src) g.setFontAlign(1,1).setFont("6x8").drawString(msg.src, r.x+r.w-2, r.y+r.h-2);
g.setColor("#888").fillRect(r.x,r.y+r.h-1,r.x+r.w-1,r.y+r.h-1); // dividing line between items g.setColor("#888").fillRect(r.x,r.y+r.h-1,r.x+r.w-1,r.y+r.h-1); // dividing line between items
if(ev.color) {
g.setColor("#"+(0x1000000+Number(ev.color)).toString(16).padStart(6,"0"));
g.fillRect(r.x,r.y+4,r.x+3, r.y+r.h-4);
}
}, },
select : idx => showEvent(CALENDAR[idx]), select : idx => showEvent(CALENDAR[idx]),
back : () => load() back : () => load()

View File

@ -1,7 +1,7 @@
{ {
"id": "agenda", "id": "agenda",
"name": "Agenda", "name": "Agenda",
"version": "0.02", "version": "0.06",
"description": "Simple agenda", "description": "Simple agenda",
"icon": "agenda.png", "icon": "agenda.png",
"screenshots": [{"url":"screenshot_agenda_overview.png"}, {"url":"screenshot_agenda_event1.png"}, {"url":"screenshot_agenda_event2.png"}], "screenshots": [{"url":"screenshot_agenda_overview.png"}, {"url":"screenshot_agenda_event1.png"}, {"url":"screenshot_agenda_event2.png"}],
@ -12,6 +12,8 @@
"storage": [ "storage": [
{"name":"agenda.app.js","url":"agenda.js"}, {"name":"agenda.app.js","url":"agenda.js"},
{"name":"agenda.settings.js","url":"settings.js"}, {"name":"agenda.settings.js","url":"settings.js"},
{"name":"agenda.clkinfo.js","url":"agenda.clkinfo.js"},
{"name":"agenda.img","url":"agenda-icon.js","evaluate":true} {"name":"agenda.img","url":"agenda-icon.js","evaluate":true}
] ],
"data": [{"name":"agenda.settings.json"}]
} }

View File

@ -3,6 +3,10 @@
Bluetooth.println(""); Bluetooth.println("");
Bluetooth.println(JSON.stringify(message)); Bluetooth.println(JSON.stringify(message));
} }
var settings = require("Storage").readJSON("agenda.settings.json",1)||{};
function updateSettings() {
require("Storage").writeJSON("agenda.settings.json", settings);
}
var CALENDAR = require("Storage").readJSON("android.calendar.json",true)||[]; var CALENDAR = require("Storage").readJSON("android.calendar.json",true)||[];
var mainmenu = { var mainmenu = {
"" : { "title" : "Agenda" }, "" : { "title" : "Agenda" },
@ -32,6 +36,13 @@
E.showAlert(/*LANG*/"You are not connected").then(()=>E.showMenu(mainmenu)); E.showAlert(/*LANG*/"You are not connected").then(()=>E.showMenu(mainmenu));
} }
}, },
/*LANG*/"Show past events" : {
value : !!settings.pastEvents,
onchange: v => {
settings.pastEvents = v;
updateSettings();
}
},
}; };
E.showMenu(mainmenu); E.showMenu(mainmenu);
}) })

View File

@ -1,9 +1,9 @@
{ "id": "agpsdata", { "id": "agpsdata",
"name": "A-GPS Data", "name": "A-GPS Data Downloader App",
"shortName":"A-GPS Data", "shortName":"A-GPS Data",
"icon": "agpsdata.png", "icon": "agpsdata.png",
"version":"0.02", "version":"0.02",
"description": "Download assisted GPS (A-GPS) data directly to your Bangle.js **using Gadgetbridge**", "description": "Once installed, this app allows you to download assisted GPS (A-GPS) data directly to your Bangle.js **via Gadgetbridge on an Android phone** when you run the app. If you just want to upload the latest AGPS data from this app loader, please use the `Assisted GPS Update (AGPS)` app.",
"tags": "boot,tool,assisted,gps,agps,http", "tags": "boot,tool,assisted,gps,agps,http",
"allow_emulator":true, "allow_emulator":true,
"supports": ["BANGLEJS2"], "supports": ["BANGLEJS2"],

View File

@ -11,4 +11,5 @@
0.10: Fix SMS bug 0.10: Fix SMS bug
0.12: Use default Bangle formatter for booleans 0.12: Use default Bangle formatter for booleans
0.13: Added Bangle.http function (see Readme file for more info) 0.13: Added Bangle.http function (see Readme file for more info)
0.14: Fix timeout of http function not beeing cleaned up 0.14: Fix timeout of http function not being cleaned up
0.15: Allow method/body/headers to be specified for `http` (needs Gadgetbridge 0.68.0b or later)

View File

@ -150,6 +150,9 @@
//send the request //send the request
var req = {t: "http", url:url, id:options.id}; var req = {t: "http", url:url, id:options.id};
if (options.xpath) req.xpath = options.xpath; if (options.xpath) req.xpath = options.xpath;
if (options.method) req.method = options.method;
if (options.body) req.body = options.body;
if (options.headers) req.headers = options.headers;
gbSend(req); gbSend(req);
//create the promise //create the promise
var promise = new Promise(function(resolve,reject) { var promise = new Promise(function(resolve,reject) {

View File

@ -2,7 +2,7 @@
"id": "android", "id": "android",
"name": "Android Integration", "name": "Android Integration",
"shortName": "Android", "shortName": "Android",
"version": "0.14", "version": "0.15",
"description": "Display notifications/music/etc sent from the Gadgetbridge app on Android. This replaces the old 'Gadgetbridge' Bangle.js widget.", "description": "Display notifications/music/etc sent from the Gadgetbridge app on Android. This replaces the old 'Gadgetbridge' Bangle.js widget.",
"icon": "app.png", "icon": "app.png",
"tags": "tool,system,messages,notifications,gadgetbridge", "tags": "tool,system,messages,notifications,gadgetbridge",

View File

@ -1,3 +1,5 @@
0.01: New App! 0.01: New App!
0.02: Fix bug if image clock wasn't installed 0.02: Fix bug if image clock wasn't installed
0.03: Update to use setUI 0.03: Update to use setUI
0.04: Tell clock widgets to hide. Move loadWidgets() so it only runs on
startup and not on every draw.

View File

@ -87,7 +87,6 @@ if (g.drawImages) {
draw(); draw();
var secondInterval = setInterval(draw,100); var secondInterval = setInterval(draw,100);
// load widgets // load widgets
Bangle.loadWidgets();
Bangle.drawWidgets(); Bangle.drawWidgets();
// Stop when LCD goes off // Stop when LCD goes off
Bangle.on('lcdPower',on=>{ Bangle.on('lcdPower',on=>{
@ -104,3 +103,5 @@ if (g.drawImages) {
} }
// Show launcher when button pressed // Show launcher when button pressed
Bangle.setUI("clock"); Bangle.setUI("clock");
Bangle.loadWidgets();

View File

@ -2,7 +2,7 @@
"id": "animclk", "id": "animclk",
"name": "Animated Clock", "name": "Animated Clock",
"shortName": "Anim Clock", "shortName": "Anim Clock",
"version": "0.03", "version": "0.04",
"description": "An animated clock face using Mark Ferrari's amazing 8 bit game art and palette cycling: http://www.markferrari.com/art/8bit-game-art", "description": "An animated clock face using Mark Ferrari's amazing 8 bit game art and palette cycling: http://www.markferrari.com/art/8bit-game-art",
"icon": "app.png", "icon": "app.png",
"type": "clock", "type": "clock",

View File

@ -11,3 +11,4 @@
0.07: align default settings with app.js (otherwise the initial displayed settings will be confusing to users) 0.07: align default settings with app.js (otherwise the initial displayed settings will be confusing to users)
0.08: fixed calendar weeknumber not shortened to two digits 0.08: fixed calendar weeknumber not shortened to two digits
0.09: Use default Bangle formatter for booleans 0.09: Use default Bangle formatter for booleans
0.10: Use Bangle.setUI({remove:...}) to allow loading the launcher without a full reset on 2v16

File diff suppressed because one or more lines are too long

View File

@ -1,7 +1,7 @@
{ {
"id": "antonclk", "id": "antonclk",
"name": "Anton Clock", "name": "Anton Clock",
"version": "0.09", "version": "0.10",
"description": "A clock using the bold Anton font, optionally showing seconds and date in ISO-8601 format.", "description": "A clock using the bold Anton font, optionally showing seconds and date in ISO-8601 format.",
"readme":"README.md", "readme":"README.md",
"icon": "app.png", "icon": "app.png",

View File

@ -1,11 +1,12 @@
{ {
"id": "assistedgps", "id": "assistedgps",
"name": "Assisted GPS Update (AGPS)", "name": "Assisted GPS Updater (AGPS)",
"version": "0.03", "version": "0.03",
"description": "Downloads assisted GPS (AGPS) data to Bangle.js 1 or 2 for faster GPS startup and more accurate fixes. **No app will be installed**, this just uploads new data to the GPS chip.", "description": "Downloads assisted GPS (AGPS) data to Bangle.js for faster GPS startup and more accurate fixes. **No app will be installed**, this just uploads new data to the GPS chip.",
"sortorder": -1,
"icon": "app.png", "icon": "app.png",
"type": "RAM", "type": "RAM",
"tags": "tool,outdoors,agps", "tags": "tool,outdoors,agps,gps,a-gps",
"supports": ["BANGLEJS","BANGLEJS2"], "supports": ["BANGLEJS","BANGLEJS2"],
"custom": "custom.html", "custom": "custom.html",
"customConnect": true, "customConnect": true,

View File

@ -1,3 +1,4 @@
0.01: Create astral clock app 0.01: Create astral clock app
0.02: Fixed Whirlpool galaxy RA/DA, larger compass display, fixed moonphase overlapping battery widget 0.02: Fixed Whirlpool galaxy RA/DA, larger compass display, fixed moonphase overlapping battery widget
0.03: Update to use Bangle.setUI instead of setWatch 0.03: Update to use Bangle.setUI instead of setWatch
0.04: Tell clock widgets to hide.

View File

@ -767,6 +767,24 @@ function draw() {
g.clear(); g.clear();
current_moonphase = getMoonPhase(); current_moonphase = getMoonPhase();
Bangle.setUI("clockupdown", btn => {
if (btn==0) {
if (!processing) {
if (!modeswitch) {
modeswitch = true;
if (mode == "planetary") mode = "extras";
else mode = "planetary";
}
else
modeswitch = false;
}
} else {
if (!processing)
ready_to_compute = true;
}
});
// Load widgets // Load widgets
Bangle.loadWidgets(); Bangle.loadWidgets();
Bangle.drawWidgets(); Bangle.drawWidgets();
@ -799,23 +817,6 @@ Bangle.setGPSPower(1);
// Show launcher when button pressed // Show launcher when button pressed
Bangle.setClockMode(); Bangle.setClockMode();
Bangle.setUI("clockupdown", btn => {
if (btn==0) {
if (!processing) {
if (!modeswitch) {
modeswitch = true;
if (mode == "planetary") mode = "extras";
else mode = "planetary";
}
else
modeswitch = false;
}
} else {
if (!processing)
ready_to_compute = true;
}
});
setWatch(function () { setWatch(function () {
if (!astral_settings.astral_default) { if (!astral_settings.astral_default) {
colours_switched = true; colours_switched = true;

View File

@ -1,7 +1,7 @@
{ {
"id": "astral", "id": "astral",
"name": "Astral Clock", "name": "Astral Clock",
"version": "0.03", "version": "0.04",
"description": "Clock that calculates and displays Alt Az positions of all planets, Sun as well as several other astronomy targets (customizable) and current Moon phase. Coordinates are calculated by GPS & time and onscreen compass assists orienting. See Readme before using.", "description": "Clock that calculates and displays Alt Az positions of all planets, Sun as well as several other astronomy targets (customizable) and current Moon phase. Coordinates are calculated by GPS & time and onscreen compass assists orienting. See Readme before using.",
"icon": "app-icon.png", "icon": "app-icon.png",
"type": "clock", "type": "clock",

View File

@ -2,3 +2,4 @@
0.02: Add sit ups 0.02: Add sit ups
Add more feedback to the user about the exercises Add more feedback to the user about the exercises
Clean up code Clean up code
0.03: Add software back button on main menu

View File

@ -71,7 +71,8 @@ function showMainMenu() {
let menu; let menu;
menu = { menu = {
"": { "": {
title: "BanglExercise" title: "BanglExercise",
back: load
} }
}; };
@ -381,4 +382,5 @@ Bangle.on('HRM', function(hrm) {
}); });
g.clear(1); g.clear(1);
Bangle.loadWidgets();
showMainMenu(); showMainMenu();

View File

@ -1,7 +1,7 @@
{ "id": "banglexercise", { "id": "banglexercise",
"name": "BanglExercise", "name": "BanglExercise",
"shortName":"BanglExercise", "shortName":"BanglExercise",
"version":"0.02", "version":"0.03",
"description": "Can automatically track exercises while wearing the Bangle.js watch.", "description": "Can automatically track exercises while wearing the Bangle.js watch.",
"icon": "app.png", "icon": "app.png",
"screenshots": [{"url":"screenshot.png"}], "screenshots": [{"url":"screenshot.png"}],

View File

@ -7,3 +7,4 @@
0.07: Step count resets at midnight 0.07: Step count resets at midnight
0.08: Step count stored in memory to survive reloads. Now shows step count daily and since last reboot. 0.08: Step count stored in memory to survive reloads. Now shows step count daily and since last reboot.
0.09: NOW it really should reset daily (instead of every other day...) 0.09: NOW it really should reset daily (instead of every other day...)
0.10: Tell clock widgets to hide.

View File

@ -416,9 +416,9 @@ var layout = new Layout( {
// Clear the screen once, at startup // Clear the screen once, at startup
g.clear(); g.clear();
Bangle.setUI("clock");
Bangle.loadWidgets(); Bangle.loadWidgets();
Bangle.drawWidgets(); Bangle.drawWidgets();
Bangle.setUI("clock");
layout.render(); layout.render();
Bangle.on('lock', function(locked) { Bangle.on('lock', function(locked) {

View File

@ -2,7 +2,7 @@
"name": "Barcode clock", "name": "Barcode clock",
"shortName":"Barcode clock", "shortName":"Barcode clock",
"icon": "barcode.icon.png", "icon": "barcode.icon.png",
"version":"0.09", "version":"0.10",
"description": "EAN-8 compatible barcode clock.", "description": "EAN-8 compatible barcode clock.",
"tags": "barcode,ean,ean-8,watchface,clock,clockface", "tags": "barcode,ean,ean-8,watchface,clock,clockface",
"type": "clock", "type": "clock",

View File

@ -1,2 +1,3 @@
0.01: App Created! 0.01: App Created!
0.02: Update to use Bangle.setUI instead of setWatch 0.02: Update to use Bangle.setUI instead of setWatch
0.03: Tell clock widgets to hide.

View File

@ -249,6 +249,9 @@ g.clear();
g.setColor(0, 0.5, 0).drawImage(bg_crack); g.setColor(0, 0.5, 0).drawImage(bg_crack);
g.setColor(1, 1, 1).drawImage(batman); g.setColor(1, 1, 1).drawImage(batman);
// Show launcher when button pressed
Bangle.setUI("clock");
Bangle.loadWidgets(); Bangle.loadWidgets();
Bangle.drawWidgets(); Bangle.drawWidgets();
@ -256,5 +259,3 @@ Bangle.drawWidgets();
timeInterval = setInterval(showTime, 1000); timeInterval = setInterval(showTime, 1000);
showTime(); showTime();
// Show launcher when button pressed
Bangle.setUI("clock");

View File

@ -2,7 +2,7 @@
"id": "batclock", "id": "batclock",
"name": "Bat Clock", "name": "Bat Clock",
"shortName": "Bat Clock", "shortName": "Bat Clock",
"version": "0.02", "version": "0.03",
"description": "Morphing Clock, with an awesome \"The Dark Knight\" themed logo.", "description": "Morphing Clock, with an awesome \"The Dark Knight\" themed logo.",
"icon": "bat-clock.png", "icon": "bat-clock.png",
"screenshots": [{"url":"screenshot.png"}], "screenshots": [{"url":"screenshot.png"}],

View File

@ -1,2 +1,3 @@
0.02: Modified for use with new bootloader and firmware 0.02: Modified for use with new bootloader and firmware
0.03: Update to use Bangle.setUI instead of setWatch 0.03: Update to use Bangle.setUI instead of setWatch
0.04: Tell clock widgets to hide.

View File

@ -100,10 +100,12 @@ Bangle.on('lcdPower', on => {
if (on) drawClock(); if (on) drawClock();
}); });
// Show launcher when button pressed
Bangle.setUI("clock");
g.clear(); g.clear();
Bangle.loadWidgets(); Bangle.loadWidgets();
Bangle.drawWidgets(); Bangle.drawWidgets();
setInterval(() => { drawClock(); }, 1000); setInterval(() => { drawClock(); }, 1000);
drawClock(); drawClock();
// Show launcher when button pressed
Bangle.setUI("clock");

View File

@ -1,7 +1,7 @@
{ {
"id": "bclock", "id": "bclock",
"name": "Binary Clock", "name": "Binary Clock",
"version": "0.03", "version": "0.04",
"description": "A simple binary clock watch face", "description": "A simple binary clock watch face",
"icon": "clock-binary.png", "icon": "clock-binary.png",
"type": "clock", "type": "clock",

View File

@ -3,3 +3,5 @@
0.03: Internationalisation; bug fix - battery icon responds promptly to charging state 0.03: Internationalisation; bug fix - battery icon responds promptly to charging state
0.04: bug fix 0.04: bug fix
0.05: proper fix for the race condition in queueDraw() 0.05: proper fix for the race condition in queueDraw()
0.06: Tell clock widgets to hide.
0.07: Better battery graphic - now has green, yellow and red sections; battery status reflected in the bar across the middle of the screen; current battery state checked only once every 15 minutes, leading to longer-lasting battery charge

View File

@ -11,6 +11,8 @@ Graphics.prototype.setFontOpenSans = function(scale) {
}; };
var drawTimeout; var drawTimeout;
var lastBattCheck = 0;
var width = 0;
function queueDraw(millis_now) { function queueDraw(millis_now) {
if (drawTimeout) clearTimeout(drawTimeout); if (drawTimeout) clearTimeout(drawTimeout);
@ -24,12 +26,15 @@ function draw() {
var date = new Date(); var date = new Date();
var h = date.getHours(), var h = date.getHours(),
m = date.getMinutes(); m = date.getMinutes();
var d = date.getDate(), var d = date.getDate();
w = date.getDay(); // d=1..31; w=0..6
const level = E.getBattery();
const width = level + (level/2);
var is12Hour = (require("Storage").readJSON("setting.json", 1) || {})["12hour"]; var is12Hour = (require("Storage").readJSON("setting.json", 1) || {})["12hour"];
var dows = require("date_utils").dows(0,1); var dow = require("date_utils").dows(0,1)[date.getDay()];
if ((date.getTime() >= lastBattCheck + 15*60000) || Bangle.isCharging()) {
lastBattcheck = date.getTime();
width = E.getBattery();
width += width/2;
}
g.reset(); g.reset();
g.clear(); g.clear();
@ -47,24 +52,35 @@ function draw() {
g.drawString(d, g.getWidth() -6, 98); g.drawString(d, g.getWidth() -6, 98);
g.setFont('Vector', 52); g.setFont('Vector', 52);
g.setFontAlign(-1, -1); g.setFontAlign(-1, -1);
g.drawString(dows[w].slice(0,2).toUpperCase(), 6, 103); g.drawString(dow.slice(0,2).toUpperCase(), 6, 103);
g.fillRect(9,159,166,171); g.fillRect(9,159,166,171);
g.fillRect(167,163,170,167); g.fillRect(167,163,170,167);
if (Bangle.isCharging()) { if (Bangle.isCharging()) {
g.setColor(1,1,0); g.setColor(1,1,0);
} else if (level > 40) { g.fillRect(12,162,12+width,168);
g.setColor(0,1,0);
} else { } else {
g.setColor(1,0,0); g.setColor(1,0,0);
g.fillRect(12,162,57,168);
g.setColor(1,1,0);
g.fillRect(58,162,72,168);
g.setColor(0,1,0);
g.fillRect(73,162,162,168);
} }
g.fillRect(12,162,12+width,168); if (width < 150) {
if (level < 100) {
g.setColor(g.theme.bg); g.setColor(g.theme.bg);
g.fillRect(12+width+1,162,162,168); g.fillRect(12+width+1,162,162,168);
} }
if (Bangle.isCharging()) {
g.setColor(1,1,0);
} else if (width <= 45) {
g.setColor(1,0,0);
} else if (width <= 60) {
g.setColor(1,1,0);
} else {
g.setColor(0, 1, 0); g.setColor(0, 1, 0);
}
g.fillRect(0, 90, g.getWidth(), 94); g.fillRect(0, 90, g.getWidth(), 94);
// widget redraw // widget redraw
@ -85,7 +101,8 @@ Bangle.on('charging', (charging) => {
draw(); draw();
}); });
Bangle.setUI("clock");
Bangle.loadWidgets(); Bangle.loadWidgets();
draw(); draw();
Bangle.setUI("clock");

View File

@ -1,7 +1,7 @@
{ "id": "bigdclock", { "id": "bigdclock",
"name": "Big digit clock containing just the essentials", "name": "Big digit clock containing just the essentials",
"shortName":"Big digit clk", "shortName":"Big digit clk",
"version":"0.05", "version":"0.07",
"description": "A clock containing just the essentials, made as easy to read as possible for those of us that need glasses. It contains the time, the day-of-week, the day-of-month, and the current battery state-of-charge.", "description": "A clock containing just the essentials, made as easy to read as possible for those of us that need glasses. It contains the time, the day-of-week, the day-of-month, and the current battery state-of-charge.",
"icon": "bigdclock.png", "icon": "bigdclock.png",
"type": "clock", "type": "clock",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -1,3 +1,4 @@
0.01: New App! 0.01: New App!
0.02: Fixed bug where screen didn't clear so incorrect time displayed. 0.02: Fixed bug where screen didn't clear so incorrect time displayed.
0.03: Update to use Bangle.setUI instead of setWatch 0.03: Update to use Bangle.setUI instead of setWatch
0.04: Tell clock widgets to hide.

View File

@ -164,9 +164,6 @@ Bangle.on('lcdPower',on=>{
draw(); // draw immediately draw(); // draw immediately
} }
}); });
// Load widgets
Bangle.loadWidgets();
Bangle.drawWidgets();
// Show launcher when button pressed // Show launcher when button pressed
Bangle.setUI("clockupdown", btn=>{ Bangle.setUI("clockupdown", btn=>{
if (btn!=1) return; if (btn!=1) return;
@ -176,3 +173,6 @@ Bangle.setUI("clockupdown", btn=>{
displayTime = 0; displayTime = 0;
} }
}); });
// Load widgets
Bangle.loadWidgets();
Bangle.drawWidgets();

View File

@ -2,7 +2,7 @@
"id": "binclock", "id": "binclock",
"name": "Binary Clock", "name": "Binary Clock",
"shortName": "Binary Clock", "shortName": "Binary Clock",
"version": "0.03", "version": "0.04",
"description": "A binary clock with hours and minutes. BTN1 toggles a digital clock.", "description": "A binary clock with hours and minutes. BTN1 toggles a digital clock.",
"icon": "app.png", "icon": "app.png",
"type": "clock", "type": "clock",

View File

@ -2,3 +2,5 @@
0.02: first running version for BangleJs2 0.02: first running version for BangleJs2
0.03: corrected icon, added screen shot, extended description 0.03: corrected icon, added screen shot, extended description
0.04: corrected format of background image (raw binary) 0.04: corrected format of background image (raw binary)
0.05: move setUI() up before draw() as to not have a false positive 'sanity
check' when building on github.

View File

@ -334,6 +334,7 @@ function setRuntimeValues(resolution) {
var hour = 0, minute = 1, second = 50; var hour = 0, minute = 1, second = 50;
var batVLevel = 20; var batVLevel = 20;
Bangle.setUI("clock");
function draw() { function draw() {
var d = new Date(); var d = new Date();
@ -371,7 +372,6 @@ function draw() {
} }
// Show launcher when button pressed // Show launcher when button pressed
Bangle.setUI("clock");
setRuntimeValues(g.getWidth()); setRuntimeValues(g.getWidth());
g.reset().clear(); g.reset().clear();
Bangle.loadWidgets(); Bangle.loadWidgets();

View File

@ -3,7 +3,7 @@
"shortName":"BinWatch", "shortName":"BinWatch",
"icon": "app.png", "icon": "app.png",
"screenshots": [{"url":"screenshot.png"}], "screenshots": [{"url":"screenshot.png"}],
"version":"0.04", "version":"0.05",
"supports": ["BANGLEJS2"], "supports": ["BANGLEJS2"],
"readme": "README.md", "readme": "README.md",
"allow_emulator":true, "allow_emulator":true,

View File

@ -5,3 +5,4 @@
0.04: Modified to account for changes in the behavior of Graphics.fillPoly 0.04: Modified to account for changes in the behavior of Graphics.fillPoly
0.05: Slight increase to draw speed after LCD on 0.05: Slight increase to draw speed after LCD on
0.06: Update to use Bangle.setUI instead of setWatch, allow themes and different size screens 0.06: Update to use Bangle.setUI instead of setWatch, allow themes and different size screens
0.07: Tell clock widgets to hide.

View File

@ -99,6 +99,10 @@ function startTimers() {
Bangle.drawWidgets(); Bangle.drawWidgets();
intervalRef = setInterval(redraw,1000); intervalRef = setInterval(redraw,1000);
} }
// Show launcher when button pressed
Bangle.setUI("clock");
Bangle.loadWidgets(); Bangle.loadWidgets();
startTimers(); startTimers();
Bangle.on('lcdPower',function(on) { Bangle.on('lcdPower',function(on) {
@ -108,5 +112,3 @@ Bangle.on('lcdPower',function(on) {
clearTimers(); clearTimers();
} }
}); });
// Show launcher when button pressed
Bangle.setUI("clock");

View File

@ -2,7 +2,7 @@
"id": "blobclk", "id": "blobclk",
"name": "Large Digit Blob Clock", "name": "Large Digit Blob Clock",
"shortName": "Blob Clock", "shortName": "Blob Clock",
"version": "0.06", "version": "0.07",
"description": "A clock with big digits", "description": "A clock with big digits",
"icon": "clock-blob.png", "icon": "clock-blob.png",
"type": "clock", "type": "clock",

View File

@ -3,3 +3,4 @@
0.04: Work with themes, smaller screens 0.04: Work with themes, smaller screens
0.05: Adjust hand lengths to be within 'tick' points 0.05: Adjust hand lengths to be within 'tick' points
0.06: Removed "wake LCD on face-up"-feature: A watch-face should not set things like "wake LCD on face-up". 0.06: Removed "wake LCD on face-up"-feature: A watch-face should not set things like "wake LCD on face-up".
0.07: Tell clock widgets to hide.

View File

@ -130,9 +130,10 @@ Bangle.on('lcdPower', (on) => {
} }
}); });
// Show launcher when button pressed
Bangle.setUI("clock");
g.clear(); g.clear();
Bangle.loadWidgets(); Bangle.loadWidgets();
Bangle.drawWidgets(); Bangle.drawWidgets();
startTimers(); startTimers();
// Show launcher when button pressed
Bangle.setUI("clock");

View File

@ -1,7 +1,7 @@
{ {
"id": "boldclk", "id": "boldclk",
"name": "Bold Clock", "name": "Bold Clock",
"version": "0.06", "version": "0.07",
"description": "Simple, readable and practical clock", "description": "Simple, readable and practical clock",
"icon": "bold_clock.png", "icon": "bold_clock.png",
"screenshots": [{"url":"screenshot_bold.png"}], "screenshots": [{"url":"screenshot_bold.png"}],

View File

@ -11,3 +11,13 @@
0.11: Performance improvements. 0.11: Performance improvements.
0.12: Implements a 2D menu. 0.12: Implements a 2D menu.
0.13: Clicks < 24px are for widgets, if fullscreen mode is disabled. 0.13: Clicks < 24px are for widgets, if fullscreen mode is disabled.
0.14: Adds humidity to weather data.
0.15: Added option for a dynamic mode to show widgets only if unlocked.
0.16: You can now show your agenda if your calendar is synced with Gadgetbridge.
0.17: Fix - Step count was no more shown in the menu.
0.18: Set timer for an agenda entry by simply clicking in the middle of the screen. Only one timer can be set.
0.19: Fix - Compatibility with "Digital clock widget"
0.20: Better handling of async data such as getPressure.
0.21: On the default menu the week of year can be shown.
0.22: Use the new clkinfo module for the menu.
0.23: Feedback of apps after run is now optional and decided by the corresponding clkinfo.

View File

@ -1,46 +1,49 @@
# BW Clock # BW Clock
A very minimalistic clock with date and time in focus. A very minimalistic clock.
![](screenshot.png) ![](screenshot.png)
## Features ## Features
The BW clock provides many features as well as 3rd party integrations: The BW clock implements features that are exposed by other apps through the `clkinfo` module.
For example, if you install the HomeAssistant app, this menu item will be shown if you click right
and additionally allows you to send triggers directly from the clock (select triggers via up/down and
send via click center). Here are examples of other apps that are integrated:
- Bangle data such as steps, heart rate, battery or charging state. - Bangle data such as steps, heart rate, battery or charging state.
- A timer can be set directly. *Requirement: Scheduler library* - Show agenda entries. A timer for an agenda entry can also be set by simply clicking in the middle of the screen. This can be used to not forget a meeting etc. Note that only one agenda-timer can be set at a time. *Requirement: Gadgetbridge calendar sync enabled*
- Weather temperature as well as the wind speed can be shown. *Requirement: Weather app* - Weather temperature as well as the wind speed can be shown. *Requirement: Weather app*
- HomeAssistant triggers can be executed directly. *Requirement: HomeAssistant app* - HomeAssistant triggers can be executed directly. *Requirement: HomeAssistant app*
Note: If some apps are not installed (e.gt. weather app), then this menu item is hidden. Note: If some apps are not installed (e.gt. weather app), then this menu item is hidden.
## Menu
2D menu allows you to display lots of different data including data from 3rd party apps and it's also possible to control things e.g. to set a timer or send a HomeAssistant trigger.
Simply click left / right to go through the menu entries such as Bangle, Timer etc.
and click up/down to move into this sub-menu. You can then click in the middle of the screen
to e.g. send a trigger via HomeAssistant once you selected it.
```
+5min
|
Bangle -- Timer[Optional] -- Weather[Optional] -- HomeAssistant [Optional]
| | | |
Bpm -5min Temperature Trigger1
| | |
Steps ... ...
|
Battery
```
## Settings ## Settings
- Fullscreen on/off (widgets are still loaded). - Screen: Normal (widgets shown), Dynamic (widgets shown if unlocked) or Full (widgets are hidden).
- Enable/disable lock icon in the settings. Useful if fullscreen is on. - Enable/disable lock icon in the settings. Useful if fullscreen mode is on.
- The colon (e.g. 7:35 = 735) can be hidden in the settings for an even larger time font to improve readability further. - The colon (e.g. 7:35 = 735) can be hidden in the settings for an even larger time font to improve readability further.
- There are no design settings, as your bangle sys settings are used. - Your bangle uses the sys color settings so you can change the color too.
## Menu structure
2D menu allows you to display lots of different data including data from 3rd party apps and it's also possible to control things e.g. to trigger HomeAssistant.
Simply click left / right to go through the menu entries such as Bangle, Weather etc.
and click up/down to move into this sub-menu. You can then click in the middle of the screen
to e.g. send a trigger via HomeAssistant once you selected it. The actions really depend
on the app that provide this sub-menu through the `clkinfo` module.
```
Bangle -- Agenda -- Weather -- HomeAssistant
| | | |
Battery Entry 1 Temperature Trigger1
| | | |
Steps ... ... ...
|
...
```
## Thanks to ## Thanks to
<a href="https://www.flaticon.com/free-icons/" title="Icons">Icons created by Flaticon</a> - Thanks to Gordon Williams not only for the great BangleJs, but specifically also for the implementation of `clkinfo` which simplified the BWClock a lot and moved complexety to the apps where it should be located.
- <a href="https://www.flaticon.com/free-icons/" title="Icons">Icons created by Flaticon</a>
## Creator ## Creator
[David Peer](https://github.com/peerdavid) [David Peer](https://github.com/peerdavid)

View File

@ -1,22 +1,25 @@
/************ /************************************************
* Includes * Includes
*/ */
const locale = require('locale'); const locale = require('locale');
const storage = require('Storage'); const storage = require('Storage');
const clock_info = require("clock_info");
/************
* Statics /************************************************
* Globals
*/ */
const SETTINGS_FILE = "bwclk.setting.json"; const SETTINGS_FILE = "bwclk.setting.json";
const TIMER_IDX = "bwclk";
const W = g.getWidth(); const W = g.getWidth();
const H = g.getHeight(); const H = g.getHeight();
var lock_input = false;
/************
/************************************************
* Settings * Settings
*/ */
let settings = { let settings = {
fullscreen: false, screen: "Normal",
showLock: true, showLock: true,
hideColon: false, hideColon: false,
menuPosX: 0, menuPosX: 0,
@ -28,22 +31,10 @@ for (const key in saved_settings) {
settings[key] = saved_settings[key] settings[key] = saved_settings[key]
} }
/************************************************
/************
* Assets * Assets
*/ */
// Manrope font // Manrope font
Graphics.prototype.setXLargeFont = function(scale) {
// Actual height 53 (55 - 3)
this.setFontCustom(
E.toString(require('heatshrink').decompress(atob('AHM/8AIG/+AA4sD/wQGh/4EWQA/AC8YA40HNA0BRY8/RY0P/6LFgf//4iFA4IiFj4HBEQkHCAQiDHIIZGv4HCFQY5BDAo5CAAIpDDAfACA3wLYv//hsFKYxcCMgoiBOooiBQwwiBS40AHIgA/ACS/DLYjYCBAjQEBAYQDBAgHDUAbyDZQi3CegoHEVQQZFagUfW4Y0DaAgECaIJSEFYMPbIYNDv5ACGAIrBCgJ1EFYILCAAQWCj4zDGgILCegcDEQRNDHIIiCHgZ2BEQShFIqUDFYidCh5ODg4NCn40DAgd/AYR5BDILZEAAIMDAAYVCh7aHdYhKDbQg4Dv7rGBAihFCAwIDCAgA/AB3/eoa7GAAk/dgbVGDJrvCDK67DDIjaGdYpbCdYonCcQjjDEVUBEQ4A/AEMcAYV/NAUHcYUDawd/cYUPRYSmBBgaLBToP8BgYiBSgIiCj4iCg//EQSuDW4IMDVwYiCBgIiBBgrRDCATeBaIYqCv70DCgT4CEQMfIgQZBBoRnDv/3EQIvBDIffEQMHFwReBRYUfOgX/+IiDKIeHEQRRECwUHKwIuB8AiDIoJEBCwZFCv/4HIZaBIgPAEQS2CUYQiCD4SABEQcfOwIZBEQaHBO4RcEAAI/BEQQgBSIQiDTIRZBEQZuBVYQiDHoKWCEQQICFQIiDBAQeCEQQA/AANwA40BLIJ5BO4JWCBAUPAYR5En7RBUIQECN4SYCQQIiEh6CCEQk/BoQiBgYeCBoTrCAgT0CCgIfCFYQiBg4IBGgIiDj6rBg4rCBYLRDFYIiBbYIfBLgQiBIQYiD4JCCLgf/bQIWDBYV/EQV/BYXz/5FBgIiD5//IowZBD4M/NAX/BIPgDIJoC//5GgKUDn//4f/8KLE/wTBAAI8BEQPwj4HBVwYmBDgIZDN4QZCGYKJCHQP/JoSgCBATrCh5dBKITVDG4gICAAbvDAH5SCL4QADK4J5CCAiTCCAp1BCAqCDCAgiGCAIiFCAQiFeoIiFg6/FCAgiECAXnEQgQB/kfEQYQC4F/EQYQCgIiDfoIQBg4iDCAUAEQZUCcgIiDDIIQBEQhuBBoIiENoYiFDwQiECAQiFwEBPQQNCAQKDDEYMDDoMfRh4iGUwqvEESBiBaQ5oEbgr0FNAo+EEIwA+oAHGgJoFRAMHe4L0CAALNBBAT0BfwScDCAXweAL0DWgUPQYQiDwF/QYQiC/zTB+C0FBAL0CEQYIBGgMPCgIxBg4rCJIKsCh5IBBwTPCj4WBgYLBZ4V/MAIiBBQQrBEQYtCBYQiCO4QLFCwgiDIQIiGIoMHEQpFBn5FFD4JoENwRoGDgSUCAoKfBw//DgIiCT4auCFwN/T4RRET4TaCEQKoCDIQiCGgK/DAAQICdYQACHoIqCBAoQFEwIhFAH4AFQIROEj4IGXwIIGNwIACbgIhEBAiRCVwoqDTogHEW4QZFXgIZB/z9Cv49CF4MPBwI0Ca4LlB8ATCJoP4AoINDfQPAg7PBg4cBBwUfD4MfFYILCCwgOCf4QLEwEPCwILCgJaBn4WBBYQxCIQQiD+EDCYI5CBYRQBIo4fBMQIuBC4N/NAv8AoIcBSgU/FYIIBZIYrCW4hOCXIQZCgYUBv7jEh4uBZAscewZ8CgEgUYT0EEoQIBA4gICFQQIEHYQA+KQzdDAArdCAArpCEScHaIQiEvwiGe4QiFUwQiEbgIiFYIL0DEQTkBEQrJEEQc/cYYiCg4HBDIQiCfoRoEHQLaDEQQHBbQYiBCAT8Dn/BCAoXBJYP/OgZKC/6OEEARLCEQZLEEQZLEEQjKFEQI6EEQZLDEQbsGEQLjGYYYA/JIxzEg/AfgJSDAoPgfgiDC8COFAoPnaQj6CAAR+CW4TCFA4i6CDIqhCDIfwHoYHCYIN/GgKuBJ4JDBFYUf/C5CBYIZBv/Ag4ZBg4rBBYQTBAQIcBg4FBn5UBAQUfFwIfCEQeAgYfBAQUBFAKbCAQQiCGwIiE+A2BwBFNwE/AoM/EQJoIWwKCCh4cBFYKUERYV/W46uHFYIZGaJA0B/glBGYT0JIITiEMIJvCFQQAEHYQA/ABBlEOIhdGQAIRFSgQIBgQICn4IB8EAjiBCUYglCbQYeBEoQZCTwM/CYIZD/gEBUwIzBJ4UHYAU/EwIrBh4rCAoIXCn4rBCgUDAQN/FYMfBYIXBCYJnCBYXggf8HgQLCwEPEQQuBgJOECwILDCwgiLHIUHBYJFGD4IxBgYWCn4rBBwJoFDIYNBCgPADgKHBRYfDBQN/GAIrBToTLDVwYACDILiCWAb8DAAYzBYAjTCAAI9BAARNCBAoqCBAgQDFgbYCAH4AufgQACf4T8CAAT/CfgQACBwITCAAYOBCYQioh4iEAHQA=='))),
46,
atob("FR4uHyopKyksJSssGA=="),
70+(scale<<8)+(1<<16)
);
};
Graphics.prototype.setLargeFont = function(scale) { Graphics.prototype.setLargeFont = function(scale) {
// Actual height 47 (48 - 2) // Actual height 47 (48 - 2)
this.setFontCustom( this.setFontCustom(
@ -55,14 +46,12 @@ Graphics.prototype.setLargeFont = function(scale) {
return this; return this;
}; };
Graphics.prototype.setMediumFont = function(scale) { Graphics.prototype.setMediumFont = function(scale) {
// Actual height 41 (42 - 2) // Actual height 41 (42 - 2)
this.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/AAAAAAAA/AAAAAAAA/AAAAAAAA/AAAAAAAA/AAAAAAAA/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHAAAAAAAB/AAAAAAAP/AAAAAAD//AAAAAA///AAAAAP///AAAAB///8AAAAf///AAAAH///wAAAB///+AAAAH///gAAAAH//4AAAAAH/+AAAAAAH/wAAAAAAH8AAAAAAAHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA///8AAAAH////AAAAP////wAAAf////4AAA/////8AAB/////+AAD/gAAH+AAD+AAAD/AAH8AAAB/AAH4AAAA/gAH4AAAAfgAH4AAAAfgAPwAAAAfgAPwAAAAfgAPwAAAAfgAHwAAAAfgAH4AAAAfgAH4AAAA/gAH8AAAA/AAD+AAAD/AAD/gAAH/AAB/////+AAB/////8AAA/////4AAAf////wAAAH////gAAAB///+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPgAAAAAAAfwAAAAAAA/gAAAAAAA/AAAAAAAB/AAAAAAAD+AAAAAAAD8AAAAAAAH8AAAAAAAH//////AAH//////AAH//////AAH//////AAH//////AAH//////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD4AAA/AAAP4AAB/AAAf4AAD/AAA/4AAD/AAB/4AAH/AAD/4AAP/AAH/AAAf/AAH8AAA//AAH4AAB//AAP4AAD//AAPwAAH+/AAPwAAP8/AAPwAAf4/AAPwAA/4/AAPwAA/w/AAPwAB/g/AAPwAD/A/AAP4AH+A/AAH8AP8A/AAH/A/4A/AAD///wA/AAD///gA/AAB///AA/AAA//+AA/AAAP/8AA/AAAD/wAA/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgAAH4AAAHwAAH4AAAH4AAH4AAAH8AAH4AAAP+AAH4AAAH+AAH4A4AB/AAH4A+AA/AAH4B/AA/gAH4D/AAfgAH4H+AAfgAH4P+AAfgAH4f+AAfgAH4/+AAfgAH5/+AAfgAH5//AAfgAH7+/AA/gAH/8/gB/AAH/4f4H/AAH/wf//+AAH/gP//8AAH/AH//8AAH+AD//wAAH8AB//gAAD4AAf+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+AAAAAAAD/AAAAAAAP/AAAAAAB//AAAAAAH//AAAAAAf//AAAAAB///AAAAAH///AAAAAf/8/AAAAB//w/AAAAH/+A/AAAA//4A/AAAD//gA/AAAH/+AA/AAAH/4AA/AAAH/gAA/AAAH+AAA/AAAHwAAA/AAAHAAf///AAEAAf///AAAAAf///AAAAAf///AAAAAf///AAAAAf///AAAAAAA/AAAAAAAA/AAAAAAAA/AAAAAAAA/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAAAAAP/AHgAAH///AP4AAH///gP8AAH///gP8AAH///gP+AAH///gD/AAH/A/AB/AAH4A/AA/gAH4A+AAfgAH4B+AAfgAH4B+AAfgAH4B8AAfgAH4B8AAfgAH4B+AAfgAH4B+AAfgAH4B+AA/gAH4B/AA/AAH4A/gD/AAH4A/4H+AAH4Af//+AAH4AP//8AAH4AP//4AAHwAD//wAAAAAB//AAAAAAAf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA///8AAAAD////AAAAP////wAAAf////4AAA/////8AAB/////+AAD/gP4H+AAD/AfgD/AAH8A/AB/AAH8A/AA/gAH4B+AAfgAH4B+AAfgAPwB8AAfgAPwB8AAfgAPwB+AAfgAPwB+AAfgAH4B+AAfgAH4B/AA/gAH8B/AB/AAH+A/wD/AAD+A/8P+AAB8Af//+AAB4AP//8AAAwAH//4AAAAAD//gAAAAAA//AAAAAAAP4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPwAAAAAAAPwAAAAAAAPwAAAAAAAPwAAAAAAAPwAAAAHAAPwAAAA/AAPwAAAD/AAPwAAAf/AAPwAAB//AAPwAAP//AAPwAA//8AAPwAH//wAAPwAf/+AAAPwB//4AAAPwP//AAAAPw//8AAAAP3//gAAAAP//+AAAAAP//wAAAAAP//AAAAAAP/4AAAAAAP/gAAAAAAP+AAAAAAAHwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP+AAAAH+A//gAAAf/h//4AAA//z//8AAB/////+AAD/////+AAD///+H/AAH+H/4B/AAH8B/wA/gAH4A/gAfgAH4A/gAfgAPwA/AAfgAPwA/AAfgAPwA/AAfgAPwA/AAfgAH4A/gAfgAH4A/gAfgAH8B/wA/gAH/H/4B/AAD///+H/AAD/////+AAB/////+AAA//z//8AAAf/h//4AAAH+A//gAAAAAAH+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/gAAAAAAD/8AAAAAAP/+AAAAAAf//AAcAAA///gA8AAB///wB+AAD/x/4B/AAD+AP4B/AAH8AH8A/gAH4AH8A/gAH4AD8AfgAP4AD8AfgAPwAB8AfgAPwAB8AfgAPwAB8AfgAPwAB8AfgAH4AD8AfgAH4AD4A/gAH8AH4B/AAD+APwD/AAD/g/wP+AAB/////+AAA/////8AAAf////4AAAP////wAAAH////AAAAA///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD8APwAAAAD8APwAAAAD8APwAAAAD8APwAAAAD8APwAAAAD8APwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="), 46, atob("DxcjFyAfISAiHCAiEg=="), 54+(scale<<8)+(1<<16)); this.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/AAAAAAAA/AAAAAAAA/AAAAAAAA/AAAAAAAA/AAAAAAAA/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHAAAAAAAB/AAAAAAAP/AAAAAAD//AAAAAA///AAAAAP///AAAAB///8AAAAf///AAAAH///wAAAB///+AAAAH///gAAAAH//4AAAAAH/+AAAAAAH/wAAAAAAH8AAAAAAAHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA///8AAAAH////AAAAP////wAAAf////4AAA/////8AAB/////+AAD/gAAH+AAD+AAAD/AAH8AAAB/AAH4AAAA/gAH4AAAAfgAH4AAAAfgAPwAAAAfgAPwAAAAfgAPwAAAAfgAHwAAAAfgAH4AAAAfgAH4AAAA/gAH8AAAA/AAD+AAAD/AAD/gAAH/AAB/////+AAB/////8AAA/////4AAAf////wAAAH////gAAAB///+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPgAAAAAAAfwAAAAAAA/gAAAAAAA/AAAAAAAB/AAAAAAAD+AAAAAAAD8AAAAAAAH8AAAAAAAH//////AAH//////AAH//////AAH//////AAH//////AAH//////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD4AAA/AAAP4AAB/AAAf4AAD/AAA/4AAD/AAB/4AAH/AAD/4AAP/AAH/AAAf/AAH8AAA//AAH4AAB//AAP4AAD//AAPwAAH+/AAPwAAP8/AAPwAAf4/AAPwAA/4/AAPwAA/w/AAPwAB/g/AAPwAD/A/AAP4AH+A/AAH8AP8A/AAH/A/4A/AAD///wA/AAD///gA/AAB///AA/AAA//+AA/AAAP/8AA/AAAD/wAA/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgAAH4AAAHwAAH4AAAH4AAH4AAAH8AAH4AAAP+AAH4AAAH+AAH4A4AB/AAH4A+AA/AAH4B/AA/gAH4D/AAfgAH4H+AAfgAH4P+AAfgAH4f+AAfgAH4/+AAfgAH5/+AAfgAH5//AAfgAH7+/AA/gAH/8/gB/AAH/4f4H/AAH/wf//+AAH/gP//8AAH/AH//8AAH+AD//wAAH8AB//gAAD4AAf+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+AAAAAAAD/AAAAAAAP/AAAAAAB//AAAAAAH//AAAAAAf//AAAAAB///AAAAAH///AAAAAf/8/AAAAB//w/AAAAH/+A/AAAA//4A/AAAD//gA/AAAH/+AA/AAAH/4AA/AAAH/gAA/AAAH+AAA/AAAHwAAA/AAAHAAf///AAEAAf///AAAAAf///AAAAAf///AAAAAf///AAAAAf///AAAAAAA/AAAAAAAA/AAAAAAAA/AAAAAAAA/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAAAAAP/AHgAAH///AP4AAH///gP8AAH///gP8AAH///gP+AAH///gD/AAH/A/AB/AAH4A/AA/gAH4A+AAfgAH4B+AAfgAH4B+AAfgAH4B8AAfgAH4B8AAfgAH4B+AAfgAH4B+AAfgAH4B+AA/gAH4B/AA/AAH4A/gD/AAH4A/4H+AAH4Af//+AAH4AP//8AAH4AP//4AAHwAD//wAAAAAB//AAAAAAAf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA///8AAAAD////AAAAP////wAAAf////4AAA/////8AAB/////+AAD/gP4H+AAD/AfgD/AAH8A/AB/AAH8A/AA/gAH4B+AAfgAH4B+AAfgAPwB8AAfgAPwB8AAfgAPwB+AAfgAPwB+AAfgAH4B+AAfgAH4B/AA/gAH8B/AB/AAH+A/wD/AAD+A/8P+AAB8Af//+AAB4AP//8AAAwAH//4AAAAAD//gAAAAAA//AAAAAAAP4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPwAAAAAAAPwAAAAAAAPwAAAAAAAPwAAAAAAAPwAAAAHAAPwAAAA/AAPwAAAD/AAPwAAAf/AAPwAAB//AAPwAAP//AAPwAA//8AAPwAH//wAAPwAf/+AAAPwB//4AAAPwP//AAAAPw//8AAAAP3//gAAAAP//+AAAAAP//wAAAAAP//AAAAAAP/4AAAAAAP/gAAAAAAP+AAAAAAAHwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP+AAAAH+A//gAAAf/h//4AAA//z//8AAB/////+AAD/////+AAD///+H/AAH+H/4B/AAH8B/wA/gAH4A/gAfgAH4A/gAfgAPwA/AAfgAPwA/AAfgAPwA/AAfgAPwA/AAfgAH4A/gAfgAH4A/gAfgAH8B/wA/gAH/H/4B/AAD///+H/AAD/////+AAB/////+AAA//z//8AAAf/h//4AAAH+A//gAAAAAAH+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/gAAAAAAD/8AAAAAAP/+AAAAAAf//AAcAAA///gA8AAB///wB+AAD/x/4B/AAD+AP4B/AAH8AH8A/gAH4AH8A/gAH4AD8AfgAP4AD8AfgAPwAB8AfgAPwAB8AfgAPwAB8AfgAPwAB8AfgAH4AD8AfgAH4AD4A/gAH8AH4B/AAD+APwD/AAD/g/wP+AAB/////+AAA/////8AAAf////4AAAP////wAAAH////AAAAA///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD8APwAAAAD8APwAAAAD8APwAAAAD8APwAAAAD8APwAAAAD8APwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="), 46, atob("DxcjFyAfISAiHCAiEg=="), 54+(scale<<8)+(1<<16));
return this; return this;
}; };
Graphics.prototype.setSmallFont = function(scale) { Graphics.prototype.setSmallFont = function(scale) {
// Actual height 28 (27 - 0) // Actual height 28 (27 - 0)
this.setFontCustom( this.setFontCustom(
@ -74,6 +63,16 @@ Graphics.prototype.setSmallFont = function(scale) {
return this; return this;
}; };
Graphics.prototype.setMiniFont = function(scale) {
// Actual height 16 (15 - 0)
this.setFontCustom(
atob('AAAAAAAAAAAAAP+w/5AAAAAA4ADgAOAA4AAAAAAAAAABgBmAGbAb8D+A+YDZ8B/wf4D5gJmAGQAQAAAAAAAeOD8cMwzxj/GPMYwc/Az4AAAAAHAA+DDIYMjA+YBzAAYADeA7MHMw4zDD4ADAAAAz4H/wzjDHMMMwwbBj4APgADAAAAAA4ADgAAAAAAAAAAfwH/54B+ABAAAAAOABeAcf/gfwAAAAACAAaAD4APgAOABgAAAAAAACAAIAAgA/wAMAAgACAAAAAAAAPAA4AAAAAAIAAgACAAIAAgAAAAAAADAAMAAAAAAAcAfwf4D4AIAAAAA/wH/gwDDAMMAwwDB/4D/AAAAAAGAAwAD/8P/wAAAAAHAw8HDA8MHww7DnMH4wGBAAAMBgyHDcMPww/DDv4MfAAAAAAAHgD+A+YPhgwGAH8AfwAEAAAAAA/GD8cMwwzDDMMM5wx+ABgAAAP8B/4MwwzDDMMMwwx+ADwAAAgADAAMBwwfDPgP4A8ADAAAAAe+D/8M4wxjDGMP5wf+ABwAAAfAB+cMYwwjDCMMYwf+A/wAAAAAAAAAxgBCAAAAAAAAAYPBA4AAAAAAAAAgAHAA+AHMAYYAAAAAAAAAAAAAAJAAkACQAJAAkACQAJAAkAAAAAAAAAAAAAABhgHMAPgAcAAgAAAAAAAABgAOAAwbDDsMYA/AA4AAAAAAAD4A/wGBgxzDPsMyQjJDPkM+wYIBxgD+AAAAAAABAA8A/gf8DwwODA/sAfwAHwADAAAP/w//DGMMYwxjDOMP9we+ABwA8AP8Bw4MAwwDDAMMAwwDDgcHDgMMAAAAAA//D/8MAwwDDAMMAw4HB/4D/AAAAAAP/w//DGMMYwxjDGMMQwgBAAAP/w//DDAMMAwwDDAMAADwA/wHDgwDDAMMAwwDDCMOJwc+ADwAAA//D/8AMAAwADAAMAAwD/8P/wAAAAAP/w//AAAABgAHAAMAAwAHD/4P+AAAAAAP/w//AOAB+AOcBw4MBwgDAAEAAA//D/8AAwADAAMAAwADAAAP/w//A8AA8AA+AA8AHwB8AeAHgA//D/8AAAAAD/8P/wcAAcAA8AA4AB4P/w//AAAA8AP8Bw4MAwwDDAMMAwwDDgcH/gP8AAAAAA//D/8MMAwwDDAMYA7gB8ABgADwA/wHDgwDDAMMAwwDDA8ODwf/A/8AAAAAD/8P/wwwDDAMMAx4Dv4HxwEBAAAHjg/HDMMMYwxjDGMONwc+ABwMAAwADAAMAA//D/8MAAwADAAIAAAAD/wP/gAHAAMAAwADAAMAHg/8AAAMAA+AA/AAfgAPAA8AfgPwD4AMAAwAD4AD+AA/AA8A/g/gDwAP4AH8AB8APwH8D8AMAAgBDAMPDgO8APAB8AOcDw8MAwgBCAAOAAeAAeAAfwH/B4AOAAwAAAAMAwwPDB8Mew3jD4MPAwwDAAAAAAAAB//3//QABAAAAAAADgAP4AH+AB8AAQAABAAEAAf/9//wAAAAAAAAAAGAAwAGAAwABgADAAGAAAAAAAAAQABAAEAAQABAAEAAQABAAEAAQABAAAAAAAAAAAAAAAAAAAAAAAQA3wHbAZMBswGzAf4A/wAAAAAP/w//AYMBgwGDAYMA/gB8AAAAEAD+Ae8BgwGDAYMBgwDGAAAAMAD+Ae8BgwGDAYMBhw//D/8AAAAYAP4B/wGTAZMBkwGTAP4AcAEAAYAP/w//CQAJAAAwAP4hz3GDMQMxAzGHcf/h/8AAAAAP/w//AYABgAGAAYAA/wB/AAAAAA3/Df8AAAAAOf/9//AAAAAP/w//ADgAfADGAYMBAQAAD/8P/wAAAAAB/wH/AYABgAGAAf8A/wGAAYABgAH/AP8AAAAAAf8B/wGAAYABgAGAAP8AfwAAADAA/gHvAYMBgwGDAYMA/gB8AAAAAAH/8f/xgwGDAYMBgwD+AHwAAAAwAP4B7wGDAYMBgwGHAf/x//AAAAAB/wH/AYABgAEAAAAA5gHzAbMBkwGbAd8AzgEAAYAP/wf/AQMBAwAAAAAB/gH/AAMAAwADAAcB/wH/AAABAAHgAPwAHwAPAH4B8AGAAQAB8AB+AA8APwHwAeAA/AAPAD8B+AHAAQEBgwHOAHwAOAD+AccBAwAAAQAB4AD4EB/wB8A/APgBwAAAAAEBgwGPAZ8B8wHjAcMBAQAAAAAABgf/9/n2AAAAAAAP/w//AAAEAAYAB/nz//AGAAAAAAAAAAAAcABgAGAAcAAwAHAAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'),
32,
atob("AwUHDwoOCwQHBwcJBAcEBgoGCQkKCQoICQoFBQoMCgkPCgoMCwkICwsECAoIDgsMCgwKCgoLCg8KCQoHBgcLCwgJCgkKCQYKCgQECAQOCgoKCgYIBwoIDAkJCAcEBwsQ"),
16+(scale<<8)+(1<<16)
);
return this;
};
function imgLock(){ function imgLock(){
return { return {
@ -83,279 +82,100 @@ function imgLock(){
} }
} }
function imgSteps(){
return {
width : 24, height : 24, bpp : 1,
transparent : 1,
buffer : require("heatshrink").decompress(atob("/H///wv4CBn4CD8ACCj4IBj8f+Eeh/wjgCBngCCg/4nEH//4h/+jEP/gRBAQX+jkf/wgB//8GwP4FoICDHgICCBwIA=="))
}
}
function imgBattery(){ /************************************************
return { * Menu
width : 24, height : 24, bpp : 1,
transparent : 1,
buffer : require("heatshrink").decompress(atob("/4AN4EAg4TBgd///9oEAAQv8ARQRDDQQgCEwQ4OA"))
}
}
function imgCharging() {
return {
width : 24, height : 24, bpp : 1,
transparent : 1,
buffer : require("heatshrink").decompress(atob("//+v///k///4AQPwBANgBoMxBoMb/P+h/w/kH8H4gfB+EBwfggHH4EAt4CBn4CBj4CBh4FCCIO/8EB//Agf/wEH/8Gh//x////fAQIA="))
}
}
function imgBpm() {
return {
width : 24, height : 24, bpp : 1,
transparent : 1,
buffer : require("heatshrink").decompress(atob("/4AOn4CD/wCCjgCCv/8jF/wGYgOA5MB//BC4PDAQnjAQPnAQgANA"))
}
}
function imgTemperature() {
return {
width : 24, height : 24, bpp : 1,
transparent : 1,
buffer : require("heatshrink").decompress(atob("//D///wICBjACBngCNkgCP/0kv/+s1//nDn/8wICEBAIOC/08v//IYJECA=="))
}
}
function imgWeather(){
return {
width : 24, height : 24, bpp : 1,
transparent : 0,
buffer : require("heatshrink").decompress(atob("AAcYAQ0MgEwAQUAngLB/8AgP/wACCgf/4Fz//OAQQICCIoaCEAQpGHA4ACA="))
}
}
function imgWind () {
return {
width : 24, height : 24, bpp : 1,
transparent : 1,
buffer : require("heatshrink").decompress(atob("/0f//8h///Pn//zAQXzwf/88B//mvGAh18gEevn/DIICB/PwgEBAQMHBAIADFwM/wEAGAP/54CD84CE+eP//wIQU/A=="))
}
}
function imgTimer() {
return {
width : 24, height : 24, bpp : 1,
transparent : 1,
buffer : require("heatshrink").decompress(atob("/+B/4CD84CEBAPygFP+F+h/x/+P+fz5/n+HnAQNn5/wuYCBmYCC5kAAQfOgFz80As/ngHn+fD54mC/F+j/+gF/HAQA=="))
}
}
function imgWatch() {
return {
width : 24, height : 24, bpp : 1,
transparent : 1,
buffer : require("heatshrink").decompress(atob("/8B//+ARANB/l4//5/1/+f/n/n5+fAQnf9/P44CC8/n7/n+YOB/+fDQQgCEwQsCHBBEC"))
}
}
function imgHomeAssistant() {
return {
width : 48, height : 48, bpp : 1,
transparent : 0,
buffer : require("heatshrink").decompress(atob("AD8BwAFDg/gAocP+AFDj4FEn/8Aod//wFD/1+FAf4j+8AoMD+EPDAUH+OPAoUP+fPAoUfBYk/C4l/EYIwC//8n//FwIFEgYFD4EH+E8nkP8BdBAonjjk44/wj/nzk58/4gAFDF4PgCIMHAoPwhkwh4FB/EEkEfIIWAHwIFC4A+BAoXgg4FDL4IFDL4IFDLIYFkAEQA=="))
}
}
/************
* 2D MENU with entries of:
* [name, icon, opt[customDownFun], opt[customUpFun], opt[customCenterFun]]
*
*/ */
var menu = [ // Custom bwItems menu - therefore, its added here and not in a clkinfo.js file.
[ var bwItems = {
function(){ return [ null, null ] }, name: null,
], img: null,
[ items: [
function(){ return [ "Bangle", imgWatch() ] }, { name: "WeekOfYear",
function(){ return [ E.getBattery() + "%", Bangle.isCharging() ? imgCharging() : imgBattery() ] }, get: () => ({ text: "Week " + weekOfYear(), img: null}),
function(){ return [ getSteps(), imgSteps() ] }, show: function() { bwItems.items[0].emit("redraw"); },
function(){ return [ Math.round(Bangle.getHealthStatus("last").bpm) + " bpm", imgBpm()] }, hide: function () {}
]
]
/*
* Timer Menu
*/
try{
require('sched');
menu.push([
function(){
var text = isAlarmEnabled() ? getAlarmMinutes() + " min." : "Timer";
return [text, imgTimer(), () => decreaseAlarm(), () => increaseAlarm(), null ]
}, },
]); ]
} catch(ex) { };
// If sched is not installed, we hide this menu item
}
/* function weekOfYear() {
* WEATHER MENU var date = new Date();
*/ date.setHours(0, 0, 0, 0);
if(storage.readJSON('weather.json') !== undefined){ // Thursday in current week decides the year.
menu.push([ date.setDate(date.getDate() + 3 - (date.getDay() + 6) % 7);
function(){ return [ "Weather", imgWeather() ] }, // January 4 is always in week 1.
function(){ return [ getWeather().temp, imgTemperature() ] }, var week1 = new Date(date.getFullYear(), 0, 4);
function(){ return [ getWeather().wind, imgWind() ] }, // Adjust to Thursday in week 1 and count number of weeks from date to week1.
]); return 1 + Math.round(((date.getTime() - week1.getTime()) / 86400000
- 3 + (week1.getDay() + 6) % 7) / 7);
} }
/* // Load menu
* HOME ASSISTANT MENU var menu = clock_info.load();
*/ menu = menu.concat(bwItems);
try{
var triggers = require("ha.lib.js").getTriggers();
var haMenu = [
function(){ return [ "Home", imgHomeAssistant() ] },
];
triggers.forEach(trigger => {
haMenu.push(function(){ // Ensure that our settings are still in range (e.g. app uninstall). Otherwise reset the position it.
return [trigger.display, trigger.getIcon(), () => {}, () => {}, function(){ if(settings.menuPosX >= menu.length || settings.menuPosY > menu[settings.menuPosX].items.length ){
var ha = require("ha.lib.js"); settings.menuPosX = 0;
ha.sendTrigger("TRIGGER_BW"); settings.menuPosY = 0;
ha.sendTrigger(trigger.trigger); }
}]
}); // Set draw functions for each item
menu.forEach((menuItm, x) => {
menuItm.items.forEach((item, y) => {
function drawItem() {
// For the clock, we have a special case, as we don't wanna redraw
// immediately when something changes. Instead, we update data each minute
// to save some battery etc. Therefore, we hide (and disable the listener)
// immedeately after redraw...
item.hide();
// After drawing the item, we enable inputs again...
lock_input = false;
var info = item.get();
drawMenuItem(info.text, info.img);
}
item.on('redraw', drawItem);
}) })
menu.push(haMenu); });
} catch(ex){
// If HomeAssistant is not installed, we hide this item
}
function getMenuEntry(){ function canRunMenuItem(){
// In case the user removes HomeAssistant entries, showInfo if(settings.menuPosY == 0){
// could be larger than infoArray.length...
settings.menuPosX = settings.menuPosX % menu.length;
settings.menuPosY = settings.menuPosY % menu[settings.menuPosX].length;
return menu[settings.menuPosX][settings.menuPosY]();
}
/************
* Helper
*/
function getSteps() {
var steps = 0;
try{
if (WIDGETS.wpedom !== undefined) {
steps = WIDGETS.wpedom.getSteps();
} else if (WIDGETS.activepedom !== undefined) {
steps = WIDGETS.activepedom.getSteps();
} else {
steps = Bangle.getHealthStatus("day").steps;
}
} catch(ex) {
// In case we failed, we can only show 0 steps.
}
steps = Math.round(steps/100) / 10; // This ensures that we do not show e.g. 15.0k and 15k instead
return steps + "k";
}
function getWeather(){
var weatherJson;
try {
weatherJson = storage.readJSON('weather.json');
var weather = weatherJson.weather;
// Temperature
weather.temp = locale.temp(weather.temp-273.15);
// Humidity
weather.hum = weather.hum + "%";
// Wind
const wind = locale.speed(weather.wind).match(/^(\D*\d*)(.*)$/);
weather.wind = Math.round(wind[1]) + "kph";
return weather
} catch(ex) {
// Return default
}
return {
temp: " ? ",
hum: " ? ",
txt: " ? ",
wind: " ? ",
wdir: " ? ",
wrose: " ? "
};
}
function isAlarmEnabled(){
try{
var alarm = require('sched');
var alarmObj = alarm.getAlarm(TIMER_IDX);
if(alarmObj===undefined || !alarmObj.on){
return false; return false;
} }
return true; var menuEntry = menu[settings.menuPosX];
var item = menuEntry.items[settings.menuPosY-1];
} catch(ex){ } return item.run !== undefined;
return false;
} }
function getAlarmMinutes(){ function runMenuItem(){
if(!isAlarmEnabled()){ if(settings.menuPosY == 0){
return -1; return;
} }
var alarm = require('sched'); var menuEntry = menu[settings.menuPosX];
var alarmObj = alarm.getAlarm(TIMER_IDX); var item = menuEntry.items[settings.menuPosY-1];
return Math.round(alarm.getTimeToAlarm(alarmObj)/(60*1000));
}
function increaseAlarm(){
try{ try{
var minutes = isAlarmEnabled() ? getAlarmMinutes() : 0; var ret = item.run();
var alarm = require('sched') if(ret){
alarm.setAlarm(TIMER_IDX, { Bangle.buzz(300, 0.6);
timer : (minutes+5)*60*1000, }
}); } catch (ex) {
alarm.reload(); // Simply ignore it...
} catch(ex){ }
}
function decreaseAlarm(){
try{
var minutes = getAlarmMinutes();
minutes -= 5;
var alarm = require('sched')
alarm.setAlarm(TIMER_IDX, undefined);
if(minutes > 0){
alarm.setAlarm(TIMER_IDX, {
timer : minutes*60*1000,
});
} }
alarm.reload();
} catch(ex){ }
} }
/************ /************************************************
* DRAW * Draw
*/ */
function draw() { function draw() {
// Queue draw again // Queue draw again
@ -363,7 +183,7 @@ function draw() {
// Draw clock // Draw clock
drawDate(); drawDate();
drawTime(); drawMenuAndTime();
drawLock(); drawLock();
drawWidgets(); drawWidgets();
} }
@ -371,12 +191,12 @@ function draw() {
function drawDate(){ function drawDate(){
// Draw background // Draw background
var y = H/5*2; var y = H/5*2 + (isFullscreen() ? 0 : 8);
g.reset().clearRect(0,0,W,W); g.reset().clearRect(0,0,W,y);
// Draw date // Draw date
y = parseInt(y/2)+4; y = parseInt(y/2)+4;
y += settings.fullscreen ? 0 : 13; y += isFullscreen() ? 0 : 8;
var date = new Date(); var date = new Date();
var dateStr = date.getDate(); var dateStr = date.getDate();
dateStr = ("0" + dateStr).substr(-2); dateStr = ("0" + dateStr).substr(-2);
@ -395,15 +215,12 @@ function drawDate(){
g.setMediumFont(); g.setMediumFont();
g.setColor(g.theme.fg); g.setColor(g.theme.fg);
g.drawString(dateStr, W/2 - fullDateW / 2, y+1); g.drawString(dateStr, W/2 - fullDateW / 2, y+2);
} }
function drawTime(){ function drawTime(y, smallText){
// Draw background // Draw background
var y = H/5*2 + (settings.fullscreen ? 0 : 8);
g.setColor(g.theme.fg);
g.fillRect(0,y,W,H);
var date = new Date(); var date = new Date();
// Draw time // Draw time
@ -419,45 +236,65 @@ function drawTime(){
// Set y coordinates correctly // Set y coordinates correctly
y += parseInt((H - y)/2) + 5; y += parseInt((H - y)/2) + 5;
var menuEntry = getMenuEntry();
var menuName = menuEntry[0];
var menuImg = menuEntry[1];
var printImgLeft = settings.menuPosY != 0;
// Show large or small time depending on info entry // Show large or small time depending on info entry
if(menuName == null){ if(smallText){
if(settings.hideColon){ y -= 15;
g.setXLargeFont(); g.setMediumFont();
} else { } else {
g.setLargeFont(); g.setLargeFont();
} }
} else {
y -= 15;
g.setMediumFont();
}
g.drawString(timeStr, W/2, y); g.drawString(timeStr, W/2, y);
}
// Draw menu if set function drawMenuItem(text, image){
if(menuName == null){ // First clear the time region
var y = H/5*2 + (isFullscreen() ? 0 : 8);
g.setColor(g.theme.fg);
g.fillRect(0,y,W,H);
// Draw menu text
var hasText = (text != null && text != "");
if(hasText){
g.setFontAlign(0,0);
// For multiline text we show an even smaller font...
text = String(text);
if(text.split('\n').length > 1){
g.setMiniFont();
} else {
g.setSmallFont();
}
var imgWidth = image == null ? 0 : 24;
var strWidth = g.stringWidth(text);
g.setColor(g.theme.fg).fillRect(0, 149-14, W, H);
g.setColor(g.theme.bg).drawString(text, W/2 + imgWidth/2 + 2, 149+3);
if(image != null){
var scale = imgWidth / image.width;
g.drawImage(image, W/2 + -strWidth/2-4 - parseInt(imgWidth/2), 149 - parseInt(imgWidth/2), {scale: scale});
}
}
// Draw time
drawTime(y, hasText);
}
function drawMenuAndTime(){
var menuEntry = menu[settings.menuPosX];
// The first entry is the overview...
if(settings.menuPosY == 0){
drawMenuItem(menuEntry.name, menuEntry.img);
return; return;
} }
y += 35; // Draw item if needed
g.setFontAlign(0,0); lock_input = true;
g.setSmallFont(); var item = menuEntry.items[settings.menuPosY-1];
var imgWidth = 0; item.show();
if(menuImg !== undefined){
imgWidth = 24.0;
var strWidth = g.stringWidth(menuName);
var scale = imgWidth / menuImg.width;
g.drawImage(
menuImg,
W/2 + (printImgLeft ? -strWidth/2-2 : strWidth/2+2) - parseInt(imgWidth/2),
y - parseInt(imgWidth/2),
{ scale: scale }
);
}
g.drawString(menuName, printImgLeft ? W/2 + imgWidth/2 + 2 : W/2 - imgWidth/2 - 2, y+3);
} }
@ -470,7 +307,7 @@ function drawLock(){
function drawWidgets(){ function drawWidgets(){
if(settings.fullscreen){ if(isFullscreen()){
for (let wd of WIDGETS) {wd.draw=()=>{};wd.area="";} for (let wd of WIDGETS) {wd.draw=()=>{};wd.area="";}
} else { } else {
Bangle.drawWidgets(); Bangle.drawWidgets();
@ -478,9 +315,19 @@ function drawWidgets(){
} }
function isFullscreen(){
var s = settings.screen.toLowerCase();
if(s == "dynamic"){
return Bangle.isLocked()
} else {
return s == "full"
}
}
/*
* Draw timeout
/************************************************
* Listener
*/ */
// timeout used to update every minute // timeout used to update every minute
var drawTimeout; var drawTimeout;
@ -508,6 +355,13 @@ Bangle.on('lcdPower',on=>{
Bangle.on('lock', function(isLocked) { Bangle.on('lock', function(isLocked) {
if (drawTimeout) clearTimeout(drawTimeout); if (drawTimeout) clearTimeout(drawTimeout);
drawTimeout = undefined; drawTimeout = undefined;
if(!isLocked && settings.screen.toLowerCase() == "dynamic"){
// If we have to show the widgets again, we load it from our
// cache and not through Bangle.loadWidgets as its much faster!
for (let wd of WIDGETS) {wd.draw=wd._draw;wd.area=wd._area;}
}
draw(); draw();
}); });
@ -516,13 +370,13 @@ Bangle.on('charging',function(charging) {
drawTimeout = undefined; drawTimeout = undefined;
// Jump to battery // Jump to battery
settings.menuPosX = 1; settings.menuPosX = 0;
settings.menuPosY = 1; settings.menuPosY = 1;
draw(); draw();
}); });
Bangle.on('touch', function(btn, e){ Bangle.on('touch', function(btn, e){
var widget_size = settings.fullscreen ? 0 : 20; // Its not exactly 24px -- empirically it seems that 20 worked better... var widget_size = isFullscreen() ? 0 : 20; // Its not exactly 24px -- empirically it seems that 20 worked better...
var left = parseInt(g.getWidth() * 0.22); var left = parseInt(g.getWidth() * 0.22);
var right = g.getWidth() - left; var right = g.getWidth() - left;
var upper = parseInt(g.getHeight() * 0.22) + widget_size; var upper = parseInt(g.getHeight() * 0.22) + widget_size;
@ -534,17 +388,15 @@ Bangle.on('touch', function(btn, e){
var is_right = e.x > right && !is_upper && !is_lower; var is_right = e.x > right && !is_upper && !is_lower;
var is_center = !is_upper && !is_lower && !is_left && !is_right; var is_center = !is_upper && !is_lower && !is_left && !is_right;
if(is_lower){ if(lock_input){
Bangle.buzz(40, 0.6); return;
settings.menuPosY = (settings.menuPosY+1) % menu[settings.menuPosX].length;
// Handle custom menu entry function
var menuEntry = getMenuEntry();
if(menuEntry.length > 2){
menuEntry[2]();
} }
drawTime(); if(is_lower){
Bangle.buzz(40, 0.6);
settings.menuPosY = (settings.menuPosY+1) % (menu[settings.menuPosX].items.length+1);
drawMenuAndTime();
} }
if(is_upper){ if(is_upper){
@ -554,22 +406,16 @@ Bangle.on('touch', function(btn, e){
Bangle.buzz(40, 0.6); Bangle.buzz(40, 0.6);
settings.menuPosY = settings.menuPosY-1; settings.menuPosY = settings.menuPosY-1;
settings.menuPosY = settings.menuPosY < 0 ? menu[settings.menuPosX].length-1 : settings.menuPosY; settings.menuPosY = settings.menuPosY < 0 ? menu[settings.menuPosX].items.length : settings.menuPosY;
// Handle custom menu entry function drawMenuAndTime();
var menuEntry = getMenuEntry();
if(menuEntry.length > 3){
menuEntry[3]();
}
drawTime();
} }
if(is_right){ if(is_right){
Bangle.buzz(40, 0.6); Bangle.buzz(40, 0.6);
settings.menuPosX = (settings.menuPosX+1) % menu.length; settings.menuPosX = (settings.menuPosX+1) % menu.length;
settings.menuPosY = 0; settings.menuPosY = 0;
drawTime(); drawMenuAndTime();
} }
if(is_left){ if(is_left){
@ -577,23 +423,12 @@ Bangle.on('touch', function(btn, e){
settings.menuPosY = 0; settings.menuPosY = 0;
settings.menuPosX = settings.menuPosX-1; settings.menuPosX = settings.menuPosX-1;
settings.menuPosX = settings.menuPosX < 0 ? menu.length-1 : settings.menuPosX; settings.menuPosX = settings.menuPosX < 0 ? menu.length-1 : settings.menuPosX;
drawTime(); drawMenuAndTime();
} }
if(is_center){ if(is_center){
var menuEntry = getMenuEntry(); if(canRunMenuItem()){
if(menuEntry.length > 4){ runMenuItem();
Bangle.buzz(80, 0.6).then(()=>{
try{
menuEntry[4]();
setTimeout(()=>{
Bangle.buzz(80, 0.6);
}, 250);
} catch(ex){
// In case it fails, we simply ignore it.
}
}
);
} }
} }
}); });
@ -608,17 +443,24 @@ E.on("kill", function(){
}); });
/* /************************************************
* Draw clock the first time * Startup Clock
*/ */
// The upper part is inverse i.e. light if dark and dark if light theme // The upper part is inverse i.e. light if dark and dark if light theme
// is enabled. In order to draw the widgets correctly, we invert the // is enabled. In order to draw the widgets correctly, we invert the
// dark/light theme as well as the colors. // dark/light theme as well as the colors.
g.setTheme({bg:g.theme.fg,fg:g.theme.bg, dark:!g.theme.dark}).clear(); g.setTheme({bg:g.theme.fg,fg:g.theme.bg, dark:!g.theme.dark}).clear();
// Load widgets and draw clock the first time
Bangle.loadWidgets();
draw();
// Show launcher when middle button pressed // Show launcher when middle button pressed
Bangle.setUI("clock"); Bangle.setUI("clock");
// Load widgets and draw clock the first time
Bangle.loadWidgets();
// Cache draw function for dynamic screen to hide / show widgets
// Bangle.loadWidgets() could also be called later on but its much slower!
for (let wd of WIDGETS) {wd._draw=wd.draw; wd._area=wd.area;}
// Draw first time
draw();

View File

@ -1,8 +1,8 @@
{ {
"id": "bwclk", "id": "bwclk",
"name": "BW Clock", "name": "BW Clock",
"version": "0.13", "version": "0.23",
"description": "A very minimalistic clock with date and time in focus.", "description": "A very minimalistic clock to mainly show date and time.",
"readme": "README.md", "readme": "README.md",
"icon": "app.png", "icon": "app.png",
"screenshots": [{"url":"screenshot.png"}, {"url":"screenshot_2.png"}, {"url":"screenshot_3.png"}, {"url":"screenshot_4.png"}], "screenshots": [{"url":"screenshot.png"}, {"url":"screenshot_2.png"}, {"url":"screenshot_3.png"}, {"url":"screenshot_4.png"}],

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -4,7 +4,7 @@
// initialize with default settings... // initialize with default settings...
const storage = require('Storage') const storage = require('Storage')
let settings = { let settings = {
fullscreen: false, screen: "Normal",
showLock: true, showLock: true,
hideColon: false, hideColon: false,
}; };
@ -17,15 +17,16 @@
storage.write(SETTINGS_FILE, settings) storage.write(SETTINGS_FILE, settings)
} }
var screenOptions = ["Normal", "Dynamic", "Full"];
E.showMenu({ E.showMenu({
'': { 'title': 'BW Clock' }, '': { 'title': 'BW Clock' },
'< Back': back, '< Back': back,
'Fullscreen': { 'Screen': {
value: settings.fullscreen, value: 0 | screenOptions.indexOf(settings.screen),
format: () => (settings.fullscreen ? 'Yes' : 'No'), min: 0, max: 2,
onchange: () => { format: v => screenOptions[v],
settings.fullscreen = !settings.fullscreen; onchange: v => {
settings.screen = screenOptions[v];
save(); save();
}, },
}, },

3
apps/calclock/ChangeLog Normal file
View File

@ -0,0 +1,3 @@
0.01: Initial version
0.02: More compact rendering & app icon
0.03: Tell clock widgets to hide.

9
apps/calclock/README.md Normal file
View File

@ -0,0 +1,9 @@
# Calendar Clock - Your day at a glance
This clock shows a chronological view of your current and future events.
It uses events synced from Gadgetbridge to achieve this.
The current time and date is highlighted in cyan.
## Screenshot
![](screenshot.png)

View File

@ -0,0 +1 @@
require("heatshrink").decompress(atob("mEwwgpm5gAB4AVRhgWCAAQWWDCARC/4ACJR4uB54WDAAP8DBotFGIgXLFwv4GAouQC4gwMLooXF/gXJOowXGJBIXBCIgXQxgXLMAIXXMAmIC5OIx4XJhH/wAXIxnIC78IxGIHoIABI44MBC4wQBEQIDB5gXGPAJgEC6IxBC5oABC4wwDa4YTCxAWD5nPDAzvGFYgAB5AXWJBK+GcAq5CGBIuBC5X4GBIJBdoQXB/GIx4CDPJAuEC5JoCDAgWBFwYXJxCBIFwYXKYwoACCwZ3IPQoWIC5YABGYIABCwpHKAQYMBCwwX/C5QAMC8R3/R/4XNhAXNwAXHgGIABgWIAFwA=="))

119
apps/calclock/calclock.js Normal file
View File

@ -0,0 +1,119 @@
var calendar = [];
var current = [];
var next = [];
function updateCalendar() {
calendar = require("Storage").readJSON("android.calendar.json",true)||[];
calendar = calendar.filter(e => isActive(e) || getTime() <= e.timestamp);
calendar.sort((a,b) => a.timestamp - b.timestamp);
current = calendar.filter(isActive);
next = calendar.filter(e=>!isActive(e));
}
function isActive(event) {
var timeActive = getTime() - event.timestamp;
return timeActive >= 0 && timeActive <= event.durationInSeconds;
}
function zp(str) {
return ("0"+str).substr(-2);
}
function drawEventHeader(event, y) {
g.setFont("Vector", 24);
var time = isActive(event) ? new Date() : new Date(event.timestamp * 1000);
var timeStr = zp(time.getHours()) + ":" + zp(time.getMinutes());
g.drawString(timeStr, 5, y);
y += 24;
g.setFont("12x20", 1);
if (isActive(event)) {
g.drawString(zp(time.getDate())+". " + require("locale").month(time,1),15*timeStr.length,y-21);
} else {
var offset = 0-time.getTimezoneOffset()/1440;
var days = Math.floor((time.getTime()/1000)/86400+offset)-Math.floor(getTime()/86400+offset);
if(days > 0) {
var daysStr = days===1?/*LANG*/"tomorrow":/*LANG*/"in "+days+/*LANG*/" days";
g.drawString(daysStr,15*timeStr.length,y-21);
}
}
return y;
}
function drawEventBody(event, y) {
g.setFont("12x20", 1);
var lines = g.wrapString(event.title, g.getWidth()-10);
if (lines.length > 2) {
lines = lines.slice(0,2);
lines[1] = lines[1].slice(0,-3)+"...";
}
g.drawString(lines.join('\n'), 5, y);
y+=20 * lines.length;
if(event.location) {
g.drawImage(atob("DBSBAA8D/H/nDuB+B+B+B3Dn/j/B+A8A8AYAYAYAAAAAAA=="),5,y);
g.drawString(event.location, 20, y);
y+=20;
}
y+=5;
return y;
}
function drawEvent(event, y) {
y = drawEventHeader(event, y);
y = drawEventBody(event, y);
return y;
}
var curEventHeight = 0;
function drawCurrentEvents(y) {
g.setColor("#0ff");
g.clearRect(5, y, g.getWidth() - 5, y + curEventHeight);
curEventHeight = y;
if(current.length === 0) {
y = drawEvent({timestamp: getTime(), durationInSeconds: 100}, y);
} else {
y = drawEventHeader(current[0], y);
for (var e of current) {
y = drawEventBody(e, y);
}
}
curEventHeight = y - curEventHeight;
return y;
}
function drawFutureEvents(y) {
g.setColor(g.theme.fg);
for (var e of next) {
y = drawEvent(e, y);
if(y>g.getHeight())break;
}
return y;
}
function fullRedraw() {
g.clearRect(5,24,g.getWidth()-5,g.getHeight());
updateCalendar();
var y = 30;
y = drawCurrentEvents(y);
drawFutureEvents(y);
}
function redraw() {
g.reset();
if (current.find(e=>!isActive(e)) || next.find(isActive)) {
fullRedraw();
} else {
drawCurrentEvents(30);
}
}
g.clear();
fullRedraw();
var minuteInterval = setInterval(redraw, 60 * 1000);
Bangle.setUI("clock");
Bangle.loadWidgets();
Bangle.drawWidgets();

BIN
apps/calclock/calclock.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
apps/calclock/location.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 692 B

View File

@ -0,0 +1,17 @@
{
"id": "calclock",
"name": "Calendar Clock",
"shortName": "CalClock",
"version": "0.03",
"description": "Show the current and upcoming events synchronized from Gadgetbridge",
"icon": "calclock.png",
"type": "clock",
"tags": "clock agenda",
"supports": ["BANGLEJS2"],
"readme": "README.md",
"storage": [
{"name":"calclock.app.js","url":"calclock.js"},
{"name":"calclock.img","url":"calclock-icon.js","evaluate":true}
],
"screenshots": [{"url":"screenshot.png"}]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@ -9,3 +9,4 @@
0.8: Update Some Variable Scopes to not use memory until need 0.8: Update Some Variable Scopes to not use memory until need
0.9: Remove ESLint spaces 0.9: Remove ESLint spaces
0.10: Show daily steps, heartrate and the temperature if weather information is available. 0.10: Show daily steps, heartrate and the temperature if weather information is available.
0.11: Tell clock widgets to hide.

View File

@ -165,10 +165,10 @@ Bangle.on("lock", (locked) => {
} }
}); });
Bangle.setUI("clock");
// Load widgets, but don't show them // Load widgets, but don't show them
Bangle.loadWidgets(); Bangle.loadWidgets();
Bangle.setUI("clock");
g.reset(); g.reset();
g.clear(); g.clear();

View File

@ -4,7 +4,7 @@
"description": "Animated Clock with Space Cassio Watch Style", "description": "Animated Clock with Space Cassio Watch Style",
"screenshots": [{ "url": "screens/screen_night.png" },{ "url": "screens/screen_day.png" }], "screenshots": [{ "url": "screens/screen_night.png" },{ "url": "screens/screen_day.png" }],
"icon": "app.png", "icon": "app.png",
"version": "0.10", "version": "0.11",
"type": "clock", "type": "clock",
"tags": "clock, weather, cassio, retro", "tags": "clock, weather, cassio, retro",
"supports": ["BANGLEJS2"], "supports": ["BANGLEJS2"],

2
apps/chimer/ChangeLog Normal file
View File

@ -0,0 +1,2 @@
0.01: Initial Creation
0.02: Fixed some sleep bugs. Added a sleep mode toggle

11
apps/chimer/README.MD Normal file
View File

@ -0,0 +1,11 @@
# Chimer - For the BangleJS
A fork of [Hour Chime](https://github.com/espruino/BangleApps/tree/master/apps/widchime) that adds extra features such as:
- Buzz or beep on every 60, 30 or 15 minutes.
- Repeat Chime up to 3 times
- Set hours to disable chime
Setting the hours you don't want your watch to chime for is done by setting the hour you want it to stop, and the hour you want it to start.
Hours range from 0 - 23.

2
apps/chimer/icon.txt Normal file
View File

@ -0,0 +1,2 @@
widget.png: "https://icons8.com/icon/114436/alarm"

16
apps/chimer/metadata.json Normal file
View File

@ -0,0 +1,16 @@
{
"id": "chimer",
"name": "Chimer",
"version": "0.02",
"description": "A fork of Hour Chime that adds extra features such as: \n - Buzz or beep on every 60, 30 or 15 minutes. \n - Reapeat Chime up to 3 times \n - Set hours to disable chime",
"icon": "widget.png",
"type": "widget",
"tags": "widget",
"supports": ["BANGLEJS", "BANGLEJS2"],
"readme": "README.MD",
"storage": [
{ "name": "chimer.wid.js", "url": "widget.js" },
{ "name": "chimer.settings.js", "url": "settings.js" }
],
"data": [{ "name": "chimer.json" }]
}

94
apps/chimer/settings.js Normal file
View File

@ -0,0 +1,94 @@
/**
* @param {function} back Use back() to return to settings menu
*/
(function (back) {
// default to buzzing
var FILE = "chimer.json";
var settings = {};
const chimes = ["Off", "Buzz", "Beep", "Both"];
const frequency = ["60 min", "30 min", "15 min", "1 min"];
var showMainMenu = () => {
E.showMenu({
"": { title: "Chimer" },
"< Back": () => back(),
"Chime Type": {
value: settings.type,
min: 0,
max: 2, // both is just silly
format: (v) => chimes[v],
onchange: (v) => {
settings.type = v;
writeSettings(settings);
},
},
Frequency: {
value: settings.freq,
min: 0,
max: 2,
format: (v) => frequency[v],
onchange: (v) => {
settings.freq = v;
writeSettings(settings);
},
},
Repetition: {
value: settings.repeat,
min: 1,
max: 5,
format: (v) => v,
onchange: (v) => {
settings.repeat = v;
writeSettings(settings);
},
},
"Sleep Mode": {
value: !!settings.sleep,
onchange: (v) => {
settings.sleep = v;
writeSettings(settings);
},
},
"Sleep Start": {
value: settings.start,
min: 0,
max: 23,
format: (v) => v,
onchange: (v) => {
settings.start = v;
writeSettings(settings);
},
},
"Sleep End": {
value: settings.end,
min: 0,
max: 23,
format: (v) => v,
onchange: (v) => {
settings.end = v;
writeSettings(settings);
},
},
});
};
var readSettings = () => {
var settings = require("Storage").readJSON(FILE, 1) || {
type: 1,
freq: 0,
repeat: 1,
sleep: true,
start: 6,
end: 22,
};
return settings;
};
var writeSettings = (settings) => {
require("Storage").writeJSON(FILE, settings);
};
settings = readSettings();
showMainMenu();
});

134
apps/chimer/widget.js Normal file
View File

@ -0,0 +1,134 @@
(function () {
// 0: off, 1: buzz, 2: beep, 3: both
var FILE = "chimer.json";
var readSettings = () => {
var settings = require("Storage").readJSON(FILE, 1) || {
type: 1,
freq: 0,
repeat: 1,
sleep: true,
start: 6,
end: 22,
};
return settings;
};
var settings = readSettings();
function sleep(milliseconds) {
const date = Date.now();
let currentDate = null;
do {
currentDate = Date.now();
} while (currentDate - date < milliseconds);
}
function chime() {
for (var i = 0; i < settings.repeat; i++) {
if (settings.type === 1) {
Bangle.buzz(100);
} else if (settings.type === 2) {
Bangle.beep();
} else {
return;
}
sleep(150);
}
}
let lastHour = new Date().getHours();
let lastMinute = new Date().getMinutes(); // don't chime when (re)loaded at a whole hour
function check() {
const now = new Date(),
h = now.getHours(),
m = now.getMinutes(),
s = now.getSeconds(),
ms = now.getMilliseconds();
if (
(settings.sleep && h > settings.end) ||
(settings.sleep && h >= settings.end && m !== 0) ||
(settings.sleep && h < settings.start)
) {
var mLeft = 60 - m,
sLeft = mLeft * 60 - s,
msLeft = sLeft * 1000 - ms;
setTimeout(check, msLeft);
return;
}
if (settings.freq === 1) {
if ((m !== lastMinute && m === 0) || (m !== lastMinute && m === 30))
chime();
lastHour = h;
lastMinute = m;
// check again in 30 minutes
switch (true) {
case m / 30 >= 1:
var mLeft = 30 - (m - 30),
sLeft = mLeft * 60 - s,
msLeft = sLeft * 1000 - ms;
break;
case m / 30 < 1:
var mLeft = 30 - m,
sLeft = mLeft * 60 - s,
msLeft = sLeft * 1000 - ms;
break;
}
setTimeout(check, msLeft);
} else if (settings.freq === 2) {
if (
(m !== lastMinute && m === 0) ||
(m !== lastMinute && m === 15) ||
(m !== lastMinute && m === 30) ||
(m !== lastMinute && m === 45)
)
chime();
lastHour = h;
lastMinute = m;
// check again in 15 minutes
switch (true) {
case m / 15 >= 3:
var mLeft = 15 - (m - 45),
sLeft = mLeft * 60 - s,
msLeft = sLeft * 1000 - ms;
break;
case m / 15 >= 2:
var mLeft = 15 - (m - 30),
sLeft = mLeft * 60 - s,
msLeft = sLeft * 1000 - ms;
break;
case m / 15 >= 1:
var mLeft = 15 - (m - 15),
sLeft = mLeft * 60 - s,
msLeft = sLeft * 1000 - ms;
break;
case m / 15 < 1:
var mLeft = 15 - m,
sLeft = mLeft * 60 - s,
msLeft = sLeft * 1000 - ms;
break;
}
setTimeout(check, msLeft);
} else if (settings.freq === 3) {
if (m !== lastMinute) chime();
lastHour = h;
lastMinute = m;
// check again in 1 minute
var mLeft = 1,
sLeft = mLeft * 60 - s,
msLeft = sLeft * 1000 - ms;
setTimeout(check, msLeft);
} else {
if (h !== lastHour && m === 0) chime();
lastHour = h;
// check again in 60 minutes
var mLeft = 60 - m,
sLeft = mLeft * 60 - s,
msLeft = sLeft * 1000 - ms;
setTimeout(check, msLeft);
}
}
check();
})();

BIN
apps/chimer/widget.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -2,3 +2,5 @@
0.02: Added scrollable calendar and swipe gestures 0.02: Added scrollable calendar and swipe gestures
0.03: Configurable drag gestures 0.03: Configurable drag gestures
0.04: Use default Bangle formatter for booleans 0.04: Use default Bangle formatter for booleans
0.05: Improved colors (connected vs disconnected)
0.06: Tell clock widgets to hide.

View File

@ -1,3 +1,4 @@
Bangle.setUI("clock");
Bangle.loadWidgets(); Bangle.loadWidgets();
var s = Object.assign({ var s = Object.assign({
@ -123,7 +124,7 @@ function drawMinutes() {
var d = new Date(); var d = new Date();
var hours = s.MODE24 ? d.getHours().toString().padStart(2, ' ') : ((d.getHours() + 24) % 12 || 12).toString().padStart(2, ' '); var hours = s.MODE24 ? d.getHours().toString().padStart(2, ' ') : ((d.getHours() + 24) % 12 || 12).toString().padStart(2, ' ');
var minutes = d.getMinutes().toString().padStart(2, '0'); var minutes = d.getMinutes().toString().padStart(2, '0');
var textColor = NRF.getSecurityStatus().connected ? '#fff' : '#f00'; var textColor = NRF.getSecurityStatus().connected ? '#99f' : '#fff';
var size = 50; var size = 50;
var clock_x = (w - 20) / 2; var clock_x = (w - 20) / 2;
if (dimSeconds) { if (dimSeconds) {
@ -307,4 +308,4 @@ NRF.on('disconnect', BTevent);
dimSeconds = Bangle.isLocked(); dimSeconds = Bangle.isLocked();
drawWatch(); drawWatch();
Bangle.setUI("clock");

Some files were not shown because too many files have changed in this diff Show More