Merge branch 'master' into messages-load-function

master
Gordon Williams 2022-09-07 09:16:46 +01:00 committed by GitHub
commit 5e49dcedf2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
262 changed files with 3778 additions and 1417 deletions

3
.gitignore vendored
View File

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

View File

@ -1,2 +1,3 @@
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();
// 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",
"name": "90s Clock",
"version": "0.02",
"version": "0.03",
"description": "A 90s style watch-face",
"readme": "README.md",
"icon": "app.png",

View File

@ -6,3 +6,4 @@
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.08: Use default Bangle formatter for booleans
0.09: New app screen (instead of showing settings or the alert) and some optimisations

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,54 @@
(function () {
// load variable before defining functions cause it can trigger a ReferenceError
const activityreminder = require("activityreminder");
const storage = require("Storage");
const activityreminder_settings = activityreminder.loadSettings();
let activityreminder_data = activityreminder.loadData();
// load variable before defining functions cause it can trigger a ReferenceError
const activityreminder = require("activityreminder");
let activityreminder_data = activityreminder.loadData();
let W = g.getWidth();
// let H = g.getHeight();
function drawAlert() {
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);
}
function run() {
if (activityreminder.mustAlert(activityreminder_data, activityreminder_settings)) {
drawAlert();
} else {
eval(storage.read("activityreminder.settings.js"))(() => load());
}
}
function getHoursMins(date){
var h = date.getHours();
var m = date.getMinutes();
return (""+h).substr(-2) + ":" + ("0"+m).substr(-2);
}
function drawData(name, value, y){
g.drawString(name, 10, y);
g.drawString(value, 100, y);
}
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() {
g.clear();
Bangle.loadWidgets();
Bangle.drawWidgets();
run();
drawInfo();
}
run();
})();

View File

@ -1,70 +1,81 @@
(function () {
// load variable before defining functions cause it can trigger a ReferenceError
const activityreminder = require("activityreminder");
const activityreminder_settings = activityreminder.loadSettings();
let activityreminder_data = activityreminder.loadData();
if (activityreminder_data.firstLoad) {
activityreminder_data.firstLoad = false;
// load variable before defining functions cause it can trigger a ReferenceError
const activityreminder = require("activityreminder");
const activityreminder_settings = activityreminder.loadSettings();
let activityreminder_data = activityreminder.loadData();
if (activityreminder_data.firstLoad) {
activityreminder_data.firstLoad = false;
activityreminder.saveData(activityreminder_data);
}
function run() {
if (isNotWorn()) return;
let now = new Date();
let h = now.getHours();
if (isDuringAlertHours(h)) {
let health = Bangle.getHealthStatus("day");
if (health.steps - activityreminder_data.stepsOnDate >= activityreminder_settings.minSteps // more steps made than needed
|| health.steps < activityreminder_data.stepsOnDate) { // new day or reboot of the watch
activityreminder_data.stepsOnDate = health.steps;
activityreminder_data.stepsDate = now;
activityreminder.saveData(activityreminder_data);
}
function run() {
if (isNotWorn()) return;
let now = new Date();
let h = now.getHours();
if (isDuringAlertHours(h)) {
let health = Bangle.getHealthStatus("day");
if (health.steps - activityreminder_data.stepsOnDate >= activityreminder_settings.minSteps // more steps made than needed
|| health.steps < activityreminder_data.stepsOnDate) { // new day or reboot of the watch
activityreminder_data.stepsOnDate = health.steps;
activityreminder_data.stepsDate = now;
activityreminder.saveData(activityreminder_data);
/* todo in a futur release
Add settimer to trigger like 30 secs after going in this part cause the person have been walking
(pass some argument to run() to handle long walks and not triggering so often)
*/
}
if (activityreminder.mustAlert(activityreminder_data, activityreminder_settings)) {
load('activityreminder.app.js');
}
}
}
function isNotWorn() {
return (Bangle.isCharging() || activityreminder_settings.tempThreshold >= E.getTemperature());
}
function isDuringAlertHours(h) {
if (activityreminder_settings.startHour < activityreminder_settings.endHour) { // not passing through midnight
return (h >= activityreminder_settings.startHour && h < activityreminder_settings.endHour);
} else { // passing through midnight
return (h >= activityreminder_settings.startHour || h < activityreminder_settings.endHour);
}
}
Bangle.on('midnight', function () {
/*
Usefull trick to have the app working smothly for people using it at night
*/
let now = new Date();
let h = now.getHours();
if (activityreminder_settings.enabled && isDuringAlertHours(h)) {
// updating only the steps and keeping the original stepsDate on purpose
activityreminder_data.stepsOnDate = 0;
activityreminder.saveData(activityreminder_data);
}
});
if (activityreminder_settings.enabled) {
setInterval(run, 60000);
/* todo in a futur release
increase setInterval time to something that is still sensible (5 mins ?)
when we added a settimer
Add settimer to trigger like 30 secs after going in this part cause the person have been walking
(pass some argument to run() to handle long walks and not triggering so often)
*/
}
if (mustAlert(now)) {
load('activityreminder.alert.js');
}
}
}
function isNotWorn() {
return (Bangle.isCharging() || activityreminder_settings.tempThreshold >= E.getTemperature());
}
function isDuringAlertHours(h) {
if (activityreminder_settings.startHour < activityreminder_settings.endHour) { // not passing through midnight
return (h >= activityreminder_settings.startHour && h < activityreminder_settings.endHour);
} else { // passing through midnight
return (h >= activityreminder_settings.startHour || h < activityreminder_settings.endHour);
}
}
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 () {
/*
Usefull trick to have the app working smothly for people using it at night
*/
let now = new Date();
let h = now.getHours();
if (activityreminder_settings.enabled && isDuringAlertHours(h)) {
// updating only the steps and keeping the original stepsDate on purpose
activityreminder_data.stepsOnDate = 0;
activityreminder.saveData(activityreminder_data);
}
});
if (activityreminder_settings.enabled) {
setInterval(run, 60000);
/* todo in a futur release
increase setInterval time to something that is still sensible (5 mins ?)
when we added a settimer
*/
}
})();

View File

@ -1,56 +1,44 @@
exports.loadSettings = function () {
return Object.assign({
enabled: true,
startHour: 9,
endHour: 20,
maxInnactivityMin: 30,
dismissDelayMin: 15,
pauseDelayMin: 120,
minSteps: 50,
tempThreshold: 27
}, require("Storage").readJSON("activityreminder.s.json", true) || {});
return Object.assign({
enabled: true,
startHour: 9,
endHour: 20,
maxInnactivityMin: 30,
dismissDelayMin: 15,
pauseDelayMin: 120,
minSteps: 50,
tempThreshold: 27
}, require("Storage").readJSON("activityreminder.s.json", true) || {});
};
exports.writeSettings = function (settings) {
require("Storage").writeJSON("activityreminder.s.json", settings);
require("Storage").writeJSON("activityreminder.s.json", settings);
};
exports.saveData = function (data) {
require("Storage").writeJSON("activityreminder.data.json", data);
require("Storage").writeJSON("activityreminder.data.json", data);
};
exports.loadData = function () {
let health = Bangle.getHealthStatus("day");
let data = Object.assign({
firstLoad: true,
stepsDate: new Date(),
stepsOnDate: health.steps,
okDate: new Date(1970),
dismissDate: new Date(1970),
pauseDate: new Date(1970),
},
let health = Bangle.getHealthStatus("day");
let data = Object.assign({
firstLoad: true,
stepsDate: new Date(),
stepsOnDate: health.steps,
okDate: new Date(1970),
dismissDate: new Date(1970),
pauseDate: new Date(1970),
},
require("Storage").readJSON("activityreminder.data.json") || {});
if(typeof(data.stepsDate) == "string")
data.stepsDate = new Date(data.stepsDate);
if(typeof(data.okDate) == "string")
data.okDate = new Date(data.okDate);
if(typeof(data.dismissDate) == "string")
data.dismissDate = new Date(data.dismissDate);
if(typeof(data.pauseDate) == "string")
data.pauseDate = new Date(data.pauseDate);
if (typeof (data.stepsDate) == "string")
data.stepsDate = new Date(data.stepsDate);
if (typeof (data.okDate) == "string")
data.okDate = new Date(data.okDate);
if (typeof (data.dismissDate) == "string")
data.dismissDate = new Date(data.dismissDate);
if (typeof (data.pauseDate) == "string")
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",
"shortName":"Activity Reminder",
"description": "A reminder to take short walks for the ones with a sedentary lifestyle",
"version":"0.08",
"version":"0.09",
"icon": "app.png",
"type": "app",
"tags": "tool,activity",
@ -13,11 +13,12 @@
{"name": "activityreminder.app.js", "url":"app.js"},
{"name": "activityreminder.boot.js", "url": "boot.js"},
{"name": "activityreminder.settings.js", "url": "settings.js"},
{"name": "activityreminder.alert.js", "url": "alert.js"},
{"name": "activityreminder", "url": "lib.js"},
{"name": "activityreminder.img", "url": "app-icon.js", "evaluate": true}
],
"data": [
{"name": "activityreminder.s.json"},
{"name": "activityreminder.data.json"}
{"name": "activityreminder.data.json", "storageFile": true}
]
}

View File

@ -1,80 +1,86 @@
(function (back) {
// Load settings
const activityreminder = require("activityreminder");
let settings = activityreminder.loadSettings();
// Load settings
const activityreminder = require("activityreminder");
let settings = activityreminder.loadSettings();
// Show the menu
E.showMenu({
"": { "title": "Activity Reminder" },
"< Back": () => back(),
'Enable': {
value: settings.enabled,
onchange: v => {
settings.enabled = v;
activityreminder.writeSettings(settings);
}
},
'Start hour': {
value: settings.startHour,
min: 0, max: 24,
onchange: v => {
settings.startHour = v;
activityreminder.writeSettings(settings);
}
},
'End hour': {
value: settings.endHour,
min: 0, max: 24,
onchange: v => {
settings.endHour = v;
activityreminder.writeSettings(settings);
}
},
'Max inactivity': {
value: settings.maxInnactivityMin,
min: 15, max: 120,
onchange: v => {
settings.maxInnactivityMin = v;
activityreminder.writeSettings(settings);
},
format: x => x + "m"
},
'Dismiss delay': {
value: settings.dismissDelayMin,
min: 5, max: 60,
onchange: v => {
settings.dismissDelayMin = v;
activityreminder.writeSettings(settings);
},
format: x => x + "m"
},
'Pause delay': {
value: settings.pauseDelayMin,
min: 30, max: 240, step: 5,
onchange: v => {
settings.pauseDelayMin = v;
activityreminder.writeSettings(settings);
},
format: x => {
return x + "m";
}
},
'Min steps': {
value: settings.minSteps,
min: 10, max: 500, step: 10,
onchange: v => {
settings.minSteps = v;
activityreminder.writeSettings(settings);
}
},
'Temp Threshold': {
value: settings.tempThreshold,
min: 20, max: 40, step: 0.5,
format: v => v + "°C",
onchange: v => {
settings.tempThreshold = v;
activityreminder.writeSettings(settings);
}
function getMainMenu(){
var mainMenu = {
"": { "title": "Activity Reminder" },
"< Back": () => back(),
'Enable': {
value: settings.enabled,
onchange: v => {
settings.enabled = v;
activityreminder.writeSettings(settings);
}
});
},
'Start hour': {
value: settings.startHour,
min: 0, max: 24,
onchange: v => {
settings.startHour = v;
activityreminder.writeSettings(settings);
}
},
'End hour': {
value: settings.endHour,
min: 0, max: 24,
onchange: v => {
settings.endHour = v;
activityreminder.writeSettings(settings);
}
},
'Max inactivity': {
value: settings.maxInnactivityMin,
min: 15, max: 120,
onchange: v => {
settings.maxInnactivityMin = v;
activityreminder.writeSettings(settings);
},
format: x => x + "m"
},
'Dismiss delay': {
value: settings.dismissDelayMin,
min: 5, max: 60,
onchange: v => {
settings.dismissDelayMin = v;
activityreminder.writeSettings(settings);
},
format: x => x + "m"
},
'Pause delay': {
value: settings.pauseDelayMin,
min: 30, max: 240, step: 5,
onchange: v => {
settings.pauseDelayMin = v;
activityreminder.writeSettings(settings);
},
format: x => {
return x + "m";
}
},
'Min steps': {
value: settings.minSteps,
min: 10, max: 500, step: 10,
onchange: v => {
settings.minSteps = v;
activityreminder.writeSettings(settings);
}
},
'Temp Threshold': {
value: settings.tempThreshold,
min: 20, max: 40, step: 0.5,
format: v => v + "°C",
onchange: v => {
settings.tempThreshold = v;
activityreminder.writeSettings(settings);
}
}
};
return mainMenu;
}
// Show the menu
E.showMenu(getMainMenu());
})

View File

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

View File

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

View File

@ -1,7 +1,7 @@
{ "id": "advcasio",
"name": "Advanced Casio Clock",
"shortName":"advcasio",
"version":"0.02",
"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.",
"icon": "app.png",
"tags": "clock",

View File

@ -1,3 +1,4 @@
0.01: Basic agenda with events from GB
0.02: Added settings page to force calendar sync
0.03: Disable past events display from settings
0.04: Added awareness of allDay field

View File

@ -26,18 +26,21 @@ var fontLarge = g.getFonts().includes("6x15")?"6x15:2":"6x8:4";
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) {
return new Date(timestamp*1000);
}
function formatDateLong(date, includeDay) {
if(includeDay)
return Locale.date(date)+" "+Locale.time(date,1);
return Locale.time(date,1);
function formatDateLong(date, includeDay, allDay) {
let shortTime = Locale.time(date,1)+Locale.meridian(date);
if(allDay) shortTime = "";
if(includeDay || allDay)
return Locale.date(date)+" "+shortTime;
return shortTime;
}
function formatDateShort(date) {
return Locale.date(date).replace(/\d\d\d\d/,"")+Locale.time(date,1);
function formatDateShort(date, allDay) {
return Locale.date(date).replace(/\d\d\d\d/,"")+(allDay?
"" : Locale.time(date,1)+Locale.meridian(date));
}
var lines = [];
@ -46,7 +49,7 @@ function showEvent(ev) {
if(!ev) return;
g.setFont(bodyFont);
//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 start = getDate(ev.timestamp);
var end = getDate((+ev.timestamp) + (+ev.durationInSeconds));
@ -54,17 +57,17 @@ function showEvent(ev) {
if (titleCnt) lines.push(""); // add blank line after title
if(start.getDay() == end.getDay() && start.getMonth() == end.getMonth())
includeDay = false;
if(includeDay) {
if(includeDay || ev.allDay) {
lines = lines.concat(
/*LANG*/"Start:",
g.wrapString(formatDateLong(start, includeDay), g.getWidth()-10),
g.wrapString(formatDateLong(start, includeDay, ev.allDay), g.getWidth()-10),
/*LANG*/"End:",
g.wrapString(formatDateLong(end, includeDay), g.getWidth()-10));
g.wrapString(formatDateLong(end, includeDay, ev.allDay), g.getWidth()-10));
} else {
lines = lines.concat(
g.wrapString(Locale.date(start), g.getWidth()-10),
g.wrapString(/*LANG*/"Start"+": "+formatDateLong(start, includeDay), g.getWidth()-10),
g.wrapString(/*LANG*/"End"+": "+formatDateLong(end, includeDay), g.getWidth()-10));
g.wrapString(/*LANG*/"Start"+": "+formatDateLong(start, includeDay, ev.allDay), g.getWidth()-10),
g.wrapString(/*LANG*/"End"+": "+formatDateLong(end, includeDay, ev.allDay), g.getWidth()-10));
}
if(ev.location)
lines = lines.concat(/*LANG*/"Location"+": ", g.wrapString(ev.location, g.getWidth()-10));
@ -110,7 +113,7 @@ function showList() {
if (!ev) return;
var isPast = false;
var x = r.x+2, title = ev.title;
var body = formatDateShort(getDate(ev.timestamp))+"\n"+(ev.location?ev.location:/*LANG*/"No location");
var body = formatDateShort(getDate(ev.timestamp),ev.allDay)+"\n"+(ev.location?ev.location:/*LANG*/"No location");
if(settings.pastEvents) isPast = ev.timestamp + ev.durationInSeconds < (new Date())/1000;
if (title) g.setFontAlign(-1,-1).setFont(fontBig)
.setColor(isPast ? "#888" : g.theme.fg).drawString(title, x,r.y+2);

View File

@ -1,7 +1,7 @@
{
"id": "agenda",
"name": "Agenda",
"version": "0.03",
"version": "0.04",
"description": "Simple agenda",
"icon": "agenda.png",
"screenshots": [{"url":"screenshot_agenda_overview.png"}, {"url":"screenshot_agenda_event1.png"}, {"url":"screenshot_agenda_event2.png"}],

View File

@ -1,3 +1,5 @@
0.01: New App!
0.02: Fix bug if image clock wasn't installed
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();
var secondInterval = setInterval(draw,100);
// load widgets
Bangle.loadWidgets();
Bangle.drawWidgets();
// Stop when LCD goes off
Bangle.on('lcdPower',on=>{
@ -104,3 +103,5 @@ if (g.drawImages) {
}
// Show launcher when button pressed
Bangle.setUI("clock");
Bangle.loadWidgets();

View File

@ -2,7 +2,7 @@
"id": "animclk",
"name": "Animated 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",
"icon": "app.png",
"type": "clock",

View File

@ -1,3 +1,4 @@
0.01: Create astral clock app
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.04: Tell clock widgets to hide.

View File

@ -767,6 +767,24 @@ function draw() {
g.clear();
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
Bangle.loadWidgets();
Bangle.drawWidgets();
@ -799,23 +817,6 @@ Bangle.setGPSPower(1);
// Show launcher when button pressed
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 () {
if (!astral_settings.astral_default) {
colours_switched = true;

View File

@ -1,7 +1,7 @@
{
"id": "astral",
"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.",
"icon": "app-icon.png",
"type": "clock",

View File

@ -7,3 +7,4 @@
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.09: NOW it really should reset daily (instead of every other day...)
0.10: Tell clock widgets to hide.

View File

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

View File

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

View File

@ -1,2 +1,3 @@
0.01: App Created!
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(1, 1, 1).drawImage(batman);
// Show launcher when button pressed
Bangle.setUI("clock");
Bangle.loadWidgets();
Bangle.drawWidgets();
@ -256,5 +259,3 @@ Bangle.drawWidgets();
timeInterval = setInterval(showTime, 1000);
showTime();
// Show launcher when button pressed
Bangle.setUI("clock");

View File

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

View File

@ -1,2 +1,3 @@
0.02: Modified for use with new bootloader and firmware
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();
});
// Show launcher when button pressed
Bangle.setUI("clock");
g.clear();
Bangle.loadWidgets();
Bangle.drawWidgets();
setInterval(() => { drawClock(); }, 1000);
drawClock();
// Show launcher when button pressed
Bangle.setUI("clock");

View File

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

View File

@ -3,3 +3,4 @@
0.03: Internationalisation; bug fix - battery icon responds promptly to charging state
0.04: bug fix
0.05: proper fix for the race condition in queueDraw()
0.06: Tell clock widgets to hide.

View File

@ -85,7 +85,8 @@ Bangle.on('charging', (charging) => {
draw();
});
Bangle.setUI("clock");
Bangle.loadWidgets();
draw();
Bangle.setUI("clock");

View File

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

View File

@ -1,3 +1,4 @@
0.01: New App!
0.02: Fixed bug where screen didn't clear so incorrect time displayed.
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
}
});
// Load widgets
Bangle.loadWidgets();
Bangle.drawWidgets();
// Show launcher when button pressed
Bangle.setUI("clockupdown", btn=>{
if (btn!=1) return;
@ -176,3 +173,6 @@ Bangle.setUI("clockupdown", btn=>{
displayTime = 0;
}
});
// Load widgets
Bangle.loadWidgets();
Bangle.drawWidgets();

View File

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

View File

@ -2,3 +2,5 @@
0.02: first running version for BangleJs2
0.03: corrected icon, added screen shot, extended description
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 batVLevel = 20;
Bangle.setUI("clock");
function draw() {
var d = new Date();
@ -371,7 +372,6 @@ function draw() {
}
// Show launcher when button pressed
Bangle.setUI("clock");
setRuntimeValues(g.getWidth());
g.reset().clear();
Bangle.loadWidgets();

View File

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

View File

@ -5,3 +5,4 @@
0.04: Modified to account for changes in the behavior of Graphics.fillPoly
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.07: Tell clock widgets to hide.

View File

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

View File

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

View File

@ -3,3 +3,4 @@
0.04: Work with themes, smaller screens
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.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();
Bangle.loadWidgets();
Bangle.drawWidgets();
startTimers();
// Show launcher when button pressed
Bangle.setUI("clock");

View File

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

View File

@ -11,4 +11,10 @@
0.11: Performance improvements.
0.12: Implements a 2D menu.
0.13: Clicks < 24px are for widgets, if fullscreen mode is disabled.
0.14: Adds humidity to weather data.
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.

View File

@ -4,15 +4,22 @@ A very minimalistic clock to mainly show date and time.
![](screenshot.png)
## Features
The BW clock provides many features as well as 3rd party integrations:
The BW clock provides many features and also 3rd party integrations:
- 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*
- 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.
## Menu
## Settings
- Screen: Normal (widgets shown), Dynamic (widgets shown if unlocked) or Full (widgets are hidden).
- 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.
- 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 set a timer or send a HomeAssistant trigger.
Simply click left / right to go through the menu entries such as Bangle, Timer etc.
@ -22,25 +29,18 @@ 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 ... ...
Bangle -- Timer[Optional] -- Agenda 1[Optional] -- Weather[Optional] -- HomeAssistant [Optional]
| | | | |
Bpm -5min Agenda 2 Temperature Trigger1
| | | |
Steps ... ... ...
|
Battery
```
## Settings
- Fullscreen on/off (widgets are still loaded).
- Enable/disable lock icon in the settings. Useful if fullscreen 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.
- There are no design settings, as your bangle sys settings are used.
## Thanks to
<a href="https://www.flaticon.com/free-icons/" title="Icons">Icons created by Flaticon</a>
## Creator
[David Peer](https://github.com/peerdavid)

View File

@ -8,7 +8,8 @@ const storage = require('Storage');
* Statics
*/
const SETTINGS_FILE = "bwclk.setting.json";
const TIMER_IDX = "bwclk";
const TIMER_IDX = "bwclk_timer";
const TIMER_AGENDA_IDX = "bwclk_agenda";
const W = g.getWidth();
const H = g.getHeight();
@ -16,7 +17,7 @@ const H = g.getHeight();
* Settings
*/
let settings = {
fullscreen: false,
screen: "Normal",
showLock: true,
hideColon: false,
menuPosX: 0,
@ -33,17 +34,6 @@ for (const key in saved_settings) {
* Assets
*/
// 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) {
// Actual height 47 (48 - 2)
this.setFontCustom(
@ -75,6 +65,19 @@ Graphics.prototype.setSmallFont = function(scale) {
};
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(){
return {
width : 16, height : 16, bpp : 1,
@ -165,12 +168,27 @@ function imgWatch() {
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=="))
width : 24, height : 24, bpp : 1,
transparent : 1,
buffer : require("heatshrink").decompress(atob("/4AF84CB4YCBwICBCAP+jFH/k8g/4kkH+AFB8ACB4cY4eHzPhgmZkHnzPn8fb4/gvwUD8EYARhAC"))
}
}
function imgAgenda() {
return {
width : 24, height : 24, bpp : 1,
transparent : 1,
buffer : require("heatshrink").decompress(atob("/4AFnPP+ALBAQX4CIgLFAQvggEBAQvAgEDAQMCwEAgwTBhgiB/AlCGQ8BGQQ"))
}
}
function imgMountain() {
return {
width : 24, height : 24, bpp : 1,
transparent : 1,
buffer : atob("//////////////////////3///n///D//uZ//E8//A+/+Z+f8//P5//n7//3z//zn//5AAAAAAAA////////////////////")
}
}
/************
* 2D MENU with entries of:
@ -186,6 +204,7 @@ var menu = [
function(){ return [ E.getBattery() + "%", Bangle.isCharging() ? imgCharging() : imgBattery() ] },
function(){ return [ getSteps(), imgSteps() ] },
function(){ return [ Math.round(Bangle.getHealthStatus("last").bpm) + " bpm", imgBpm()] },
function(){ return [ measureAltitude, imgMountain() ]},
]
]
@ -196,14 +215,90 @@ try{
require('sched');
menu.push([
function(){
var text = isAlarmEnabled() ? getAlarmMinutes() + " min." : "Timer";
return [text, imgTimer(), () => decreaseAlarm(), () => increaseAlarm(), null ]
var text = isAlarmEnabled(TIMER_IDX) ? getAlarmMinutes(TIMER_IDX) + " min." : "Timer";
return [text, imgTimer(), () => decreaseAlarm(TIMER_IDX), () => increaseAlarm(TIMER_IDX), null ]
},
]);
} catch(ex) {
// If sched is not installed, we hide this menu item
}
/*
* AGENDA MENU
* Note that we handle the agenda differently in order to hide old entries...
*/
var agendaIdx = 0;
var agendaTimerIdx = 0;
if(storage.readJSON("android.calendar.json") !== undefined){
function nextAgendaEntry(){
agendaIdx += 1;
}
function previousAgendaEntry(){
agendaIdx -= 1;
}
menu.push([
function(){
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);
if(agenda.length <= 0){
return ["All done", imgAgenda()]
}
agendaIdx = agendaIdx < 0 ? 0 : agendaIdx;
agendaIdx = agendaIdx >= agenda.length ? agendaIdx -1 : agendaIdx;
var entry = agenda[agendaIdx];
var title = entry.title.slice(0,14);
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) : "";
function dynImgAgenda(){
if(isAlarmEnabled(TIMER_AGENDA_IDX) && agendaTimerIdx == agendaIdx){
return imgTimer();
} else {
return imgAgenda();
}
}
return [title + "\n" + dateStr, dynImgAgenda(), () => nextAgendaEntry(), () => previousAgendaEntry(), function(){
try{
var alarm = require('sched')
// If other time, we disable the old one and enable this one.
if(agendaIdx != agendaTimerIdx){
agendaTimerIdx = -1;
alarm.setAlarm(TIMER_AGENDA_IDX, undefined);
}
// Disable alarm if enabled
if(isAlarmEnabled(TIMER_AGENDA_IDX)){
agendaTimerIdx = -1;
alarm.setAlarm(TIMER_AGENDA_IDX, undefined);
alarm.reload();
return
}
// Otherwise, set alarm for given event
agendaTimerIdx = agendaIdx;
alarm.setAlarm(TIMER_AGENDA_IDX, {
msg: title,
timer : parseInt((date - now)),
});
alarm.reload();
} catch(ex){ }
}]
},
]);
}
/*
* WEATHER MENU
*/
@ -246,13 +341,37 @@ function getMenuEntry(){
// 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]();
var menuEntry = menu[settings.menuPosX][settings.menuPosY]();
if(menuEntry[0] == null){
return menuEntry;
}
// For the first entry we always convert it into a callback function
// such that the menu is compatible with async functions such as
// measuring the pressure, altitude or sending http requests...
if(typeof menuEntry[0] !== 'function'){
var value = menuEntry[0];
menuEntry[0] = function(callbackFun){
callbackFun(String(value), settings.menuPosX, settings.menuPosY);
}
}
return menuEntry;
}
/************
* Helper
*/
function isFullscreen(){
var s = settings.screen.toLowerCase();
if(s == "dynamic"){
return Bangle.isLocked()
} else {
return s == "full"
}
}
function getSteps() {
var steps = 0;
try{
@ -267,8 +386,7 @@ function getSteps() {
// 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";
return steps;
}
@ -306,10 +424,10 @@ function getWeather(){
}
function isAlarmEnabled(){
function isAlarmEnabled(idx){
try{
var alarm = require('sched');
var alarmObj = alarm.getAlarm(TIMER_IDX);
var alarmObj = alarm.getAlarm(idx);
if(alarmObj===undefined || !alarmObj.on){
return false;
}
@ -321,22 +439,22 @@ function isAlarmEnabled(){
}
function getAlarmMinutes(){
if(!isAlarmEnabled()){
function getAlarmMinutes(idx){
if(!isAlarmEnabled(idx)){
return -1;
}
var alarm = require('sched');
var alarmObj = alarm.getAlarm(TIMER_IDX);
var alarmObj = alarm.getAlarm(idx);
return Math.round(alarm.getTimeToAlarm(alarmObj)/(60*1000));
}
function increaseAlarm(){
function increaseAlarm(idx){
try{
var minutes = isAlarmEnabled() ? getAlarmMinutes() : 0;
var alarm = require('sched')
alarm.setAlarm(TIMER_IDX, {
var minutes = isAlarmEnabled(idx) ? getAlarmMinutes(idx) : 0;
var alarm = require('sched');
alarm.setAlarm(idx, {
timer : (minutes+5)*60*1000,
});
alarm.reload();
@ -344,16 +462,16 @@ function increaseAlarm(){
}
function decreaseAlarm(){
function decreaseAlarm(idx){
try{
var minutes = getAlarmMinutes();
var minutes = getAlarmMinutes(idx);
minutes -= 5;
var alarm = require('sched')
alarm.setAlarm(TIMER_IDX, undefined);
alarm.setAlarm(idx, undefined);
if(minutes > 0){
alarm.setAlarm(TIMER_IDX, {
alarm.setAlarm(idx, {
timer : minutes*60*1000,
});
}
@ -363,6 +481,23 @@ function decreaseAlarm(){
}
function measureAltitude(callbackFun){
var oldX = settings.menuPosX;
var oldY = settings.menuPosY;
try{
Bangle.getPressure().then(data=>{
if(data && data.altitude && data.altitude > -100){
callbackFun(Math.round(data.altitude) + "m", oldX, oldY);
} else {
callbackFun("???", oldX, oldY);
}
});
}catch(ex){
callbackFun("err", oldX, oldY);
}
}
/************
* DRAW
*/
@ -385,7 +520,7 @@ function drawDate(){
// Draw date
y = parseInt(y/2)+4;
y += settings.fullscreen ? 0 : 13;
y += isFullscreen() ? 0 : 13;
var date = new Date();
var dateStr = date.getDate();
dateStr = ("0" + dateStr).substr(-2);
@ -410,7 +545,7 @@ function drawDate(){
function drawTime(){
// Draw background
var y = H/5*2 + (settings.fullscreen ? 0 : 8);
var y = H/5*2 + (isFullscreen() ? 0 : 8);
g.setColor(g.theme.fg);
g.fillRect(0,y,W,H);
var date = new Date();
@ -429,44 +564,55 @@ function drawTime(){
y += parseInt((H - y)/2) + 5;
var menuEntry = getMenuEntry();
var menuName = menuEntry[0];
var menuTextFun = menuEntry[0];
var menuImg = menuEntry[1];
var printImgLeft = settings.menuPosY != 0;
// Show large or small time depending on info entry
if(menuName == null){
if(settings.hideColon){
g.setXLargeFont();
} else {
g.setLargeFont();
}
if(menuTextFun == null){
g.setLargeFont();
g.drawString(timeStr, W/2, y);
return;
} else {
y -= 15;
g.setMediumFont();
}
g.drawString(timeStr, W/2, y);
// Draw menu if set
if(menuName == null){
return;
g.drawString(timeStr, W/2, y);
}
y += 35;
g.setFontAlign(0,0);
g.setSmallFont();
var imgWidth = 0;
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);
// Async set the menu (could be that some data is async fetched)
menuTextFun((menuText, oldX, oldY) => {
// We display the text IFF the user did not change the menu
if(settings.menuPosX != oldX || settings.menuPosY != oldY){
return;
}
// As its a callback, we have to ensure that the color
// font etc. is still correct...
g.setColor(g.theme.bg);
g.setFontAlign(0,0);
y += 35;
if(menuText.split('\n').length > 1){
g.setMiniFont();
} else {
g.setSmallFont();
}
var imgWidth = 0;
if(menuImg !== undefined){
imgWidth = 24.0;
var strWidth = g.stringWidth(menuText);
var scale = imgWidth / menuImg.width;
g.drawImage(
menuImg,
W/2 + (printImgLeft ? -strWidth/2-4 : strWidth/2+4) - parseInt(imgWidth/2),
y - parseInt(imgWidth/2),
{ scale: scale }
);
}
g.drawString(menuText, printImgLeft ? W/2 + imgWidth/2 + 2 : W/2 - imgWidth/2 - 2, y+3);
});
}
@ -479,7 +625,7 @@ function drawLock(){
function drawWidgets(){
if(settings.fullscreen){
if(isFullscreen()){
for (let wd of WIDGETS) {wd.draw=()=>{};wd.area="";}
} else {
Bangle.drawWidgets();
@ -517,6 +663,13 @@ Bangle.on('lcdPower',on=>{
Bangle.on('lock', function(isLocked) {
if (drawTimeout) clearTimeout(drawTimeout);
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();
});
@ -531,7 +684,7 @@ Bangle.on('charging',function(charging) {
});
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 right = g.getWidth() - left;
var upper = parseInt(g.getHeight() * 0.22) + widget_size;
@ -575,6 +728,9 @@ Bangle.on('touch', function(btn, e){
}
if(is_right){
// A bit hacky but we ensure that always the first agenda entry is shown...
agendaIdx = 0;
Bangle.buzz(40, 0.6);
settings.menuPosX = (settings.menuPosX+1) % menu.length;
settings.menuPosY = 0;
@ -582,6 +738,9 @@ Bangle.on('touch', function(btn, e){
}
if(is_left){
// A bit hacky but we ensure that always the first agenda entry is shown...
agendaIdx = 0;
Bangle.buzz(40, 0.6);
settings.menuPosY = 0;
settings.menuPosX = settings.menuPosX-1;
@ -591,12 +750,13 @@ Bangle.on('touch', function(btn, e){
if(is_center){
var menuEntry = getMenuEntry();
if(menuEntry.length > 4){
if(menuEntry.length > 4 && menuEntry[4] != null){
Bangle.buzz(80, 0.6).then(()=>{
try{
menuEntry[4]();
setTimeout(()=>{
Bangle.buzz(80, 0.6);
drawTime();
}, 250);
} catch(ex){
// In case it fails, we simply ignore it.
@ -625,9 +785,15 @@ E.on("kill", function(){
// dark/light theme as well as the colors.
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
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,7 +1,7 @@
{
"id": "bwclk",
"name": "BW Clock",
"version": "0.14",
"version": "0.20",
"description": "A very minimalistic clock to mainly show date and time.",
"readme": "README.md",
"icon": "app.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...
const storage = require('Storage')
let settings = {
fullscreen: false,
screen: "Normal",
showLock: true,
hideColon: false,
};
@ -17,15 +17,16 @@
storage.write(SETTINGS_FILE, settings)
}
var screenOptions = ["Normal", "Dynamic", "Full"];
E.showMenu({
'': { 'title': 'BW Clock' },
'< Back': back,
'Fullscreen': {
value: settings.fullscreen,
format: () => (settings.fullscreen ? 'Yes' : 'No'),
onchange: () => {
settings.fullscreen = !settings.fullscreen;
'Screen': {
value: 0 | screenOptions.indexOf(settings.screen),
min: 0, max: 2,
format: v => screenOptions[v],
onchange: v => {
settings.screen = screenOptions[v];
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

@ -8,4 +8,5 @@
0.7: Update Rocket Sequences Scope to not use memory all time
0.8: Update Some Variable Scopes to not use memory until need
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,11 +165,11 @@ Bangle.on("lock", (locked) => {
}
});
Bangle.setUI("clock");
// Load widgets, but don't show them
Bangle.loadWidgets();
Bangle.setUI("clock");
g.reset();
g.clear();
draw();
draw();

View File

@ -4,7 +4,7 @@
"description": "Animated Clock with Space Cassio Watch Style",
"screenshots": [{ "url": "screens/screen_night.png" },{ "url": "screens/screen_day.png" }],
"icon": "app.png",
"version": "0.10",
"version": "0.11",
"type": "clock",
"tags": "clock, weather, cassio, retro",
"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.03: Configurable drag gestures
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();
var s = Object.assign({
@ -123,7 +124,7 @@ function drawMinutes() {
var d = new Date();
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 textColor = NRF.getSecurityStatus().connected ? '#fff' : '#f00';
var textColor = NRF.getSecurityStatus().connected ? '#99f' : '#fff';
var size = 50;
var clock_x = (w - 20) / 2;
if (dimSeconds) {
@ -307,4 +308,4 @@ NRF.on('disconnect', BTevent);
dimSeconds = Bangle.isLocked();
drawWatch();
Bangle.setUI("clock");

View File

@ -1,7 +1,7 @@
{
"id": "clockcal",
"name": "Clock & Calendar",
"version": "0.04",
"version": "0.06",
"description": "Clock with Calendar",
"readme":"README.md",
"icon": "app.png",

View File

@ -1,2 +1,3 @@
...
0.03: First update with ChangeLog Added
0.04: Tell clock widgets to hide.

View File

@ -3,6 +3,8 @@
let outerRadius = Math.min(CenterX,CenterY) * 0.9;
Bangle.setUI('clock');
Bangle.loadWidgets();
/**** updateClockFaceSize ****/
@ -241,7 +243,3 @@
refreshDisplay();
}
});
Bangle.loadWidgets();
Bangle.setUI('clock');

View File

@ -1,7 +1,7 @@
{ "id": "colorful_clock",
"name": "Colorful Analog Clock",
"shortName":"Colorful Clock",
"version":"0.03",
"version":"0.04",
"description": "a colorful analog clock",
"icon": "app-icon.png",
"type": "clock",

View File

@ -1,2 +1,3 @@
...
0.02: First update with ChangeLog Added
0.03: Tell clock widgets to hide.

View File

@ -5,6 +5,7 @@
let ScreenWidth = g.getWidth(), CenterX;
let ScreenHeight = g.getHeight(), CenterY, outerRadius;
Bangle.setUI('clock');
Bangle.loadWidgets();
/**** updateClockFaceSize ****/
@ -1377,4 +1378,3 @@
}
});
Bangle.setUI('clock');

View File

@ -1,7 +1,7 @@
{ "id": "configurable_clock",
"name": "Configurable Analog Clock",
"shortName":"Configurable Clock",
"version":"0.02",
"version":"0.03",
"description": "an analog clock with several kinds of faces, hands and colors to choose from",
"icon": "app-icon.png",
"type": "clock",

View File

@ -1,3 +1,4 @@
0.01: New App!
0.02: Removed "wake LCD on face-up"-feature: A watch-face should not set things like "wake LCD on face-up".
0.03: Fix the clock for dark mode.
0.04: Tell clock widgets to hide.

View File

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

View File

@ -1,7 +1,7 @@
{
"id": "crowclk",
"name": "Crow Clock",
"version": "0.03",
"version": "0.04",
"description": "A simple clock based on Bold Clock that has MST3K's Crow T. Robot for a face",
"icon": "crow_clock.png",
"screenshots": [{"url":"screenshot_crow.png"}],

View File

@ -0,0 +1 @@
0.01: New face!

17
apps/distortclk/README.md Normal file
View File

@ -0,0 +1,17 @@
# Distort Watchface
Was playing around with custom fonts and made something with it
Made for Bangle.js 2
![screenshot (3)](https://user-images.githubusercontent.com/44651387/157507228-100452bf-94a6-476f-aec6-d13d5dad86d5.png)
## Features
Has a dark mode
## Requests
If you have any issues or would like to suggest a feature, click here to send a message -> [here](https://github.com/elykittytee/BangleApps/issues/new?title=Poketch%20Clock%20Bug).
## Creator
Eleanor Tayam

View File

@ -0,0 +1 @@
require("heatshrink").decompress(atob("j0ewkBiIAxHIQMJiBJEIxAaCAIQfHDgIUFDwwNCHYgVFiAVBHYgIDEghKCCIQGCFYoaDAYgORGIJ2DBwYIBHgQOPgAOIPIYOGAgQOFFgh7DHZQeDBwhoFQgh3JEAgOFFoqkHYRzgOfx4bCJ4gNGSIaJEABA7EAGA"))

115
apps/distortclk/app.js Normal file

File diff suppressed because one or more lines are too long

BIN
apps/distortclk/app.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 660 B

View File

@ -0,0 +1,17 @@
{
"id": "distortclk",
"name": "Distort Clock",
"shortName":"Distort Clock",
"version": "0.01",
"description": "A clockface",
"icon": "app.png",
"type": "clock",
"tags": "clock",
"supports": ["BANGLEJS2"],
"allow_emulator": true,
"readme":"README.md",
"storage": [
{"name":"distortclk.app.js","url":"app.js"},
{"name":"distortclk.img","url":"app-icon.js","evaluate":true}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@ -1,2 +1,3 @@
0.01: First published version of app
0.02: Move to Bangle.setUI to launcher support
0.03: Tell clock widgets to hide.

View File

@ -173,6 +173,9 @@ const drawHR = function () {
}
};
// Show launcher when button pressed
Bangle.setUI("clock");
// clean app screen
g.clear();
Bangle.loadWidgets();
@ -198,6 +201,3 @@ Bangle.on('HRM', function (d) {
// draw now
drawClock();
// Show launcher when button pressed
Bangle.setUI("clock");

View File

@ -2,7 +2,7 @@
"id": "fclock",
"name": "fclock",
"shortName": "F Clock",
"version": "0.02",
"version": "0.03",
"description": "Simple design of a digital clock",
"icon": "app.png",
"type": "clock",

View File

@ -1,3 +1,4 @@
0.01: first release
0.02: RAM efficient version of `fourTwentyTz.js` (as suggested by @gfwilliams).
0.03: `mkFourTwentyTz.js` now handles new timezonedb.com CSV format
0.04: Tell clock widgets to hide.

View File

@ -33,6 +33,8 @@ function draw() {
// Clear the screen once, at startup
g.clear();
// Show launcher when middle button pressed
Bangle.setUI("clock");
// Load widgets
Bangle.loadWidgets();
Bangle.drawWidgets();
@ -47,5 +49,4 @@ Bangle.on('lcdPower',on=>{
drawTimeout = undefined;
}
});
// Show launcher when middle button pressed
Bangle.setUI("clock");

View File

@ -1,7 +1,7 @@
{
"id": "ftclock",
"name": "Four Twenty Clock",
"version": "0.03",
"version": "0.04",
"description": "A clock that tells when and where it's going to be 4:20 next",
"icon": "app.png",
"screenshots": [{"url":"screenshot.png"}, {"url":"screenshot1.png"}],

View File

@ -83,6 +83,7 @@ function onInit(device) {
if (crc==3508163280 || crc==1418074094) version = "2v12";
if (crc==4056371285) version = "2v13";
if (crc==1038322422) version = "2v14";
if (crc==2560806221) version = "2v15";
if (!ok) {
version += `(&#9888; update required)`;
}

View File

@ -1,2 +1,3 @@
0.01: First released version
0.02: Changed setWatch to Bangle.setUI
0.03: Tell clock widgets to hide.

View File

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

View File

@ -2,7 +2,7 @@
"id": "gallifr",
"name": "Time Traveller's Chronometer",
"shortName": "Time Travel Clock",
"version": "0.02",
"version": "0.03",
"description": "A clock for time travellers. The light pie segment shows the minutes, the black circle, the hour. The dial itself reads 'time' just in case you forget.",
"icon": "gallifr.png",
"screenshots": [{"url":"screenshot_time.png"}],

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