mirror of https://github.com/espruino/BangleApps
Merge branch 'master' into localization
commit
e1dd6d2368
|
@ -3,3 +3,4 @@
|
|||
0.03: Do not alarm while charging
|
||||
0.04: Obey system quiet mode
|
||||
0.05: Battery optimisation, add the pause option, bug fixes
|
||||
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
|
||||
|
|
|
@ -11,4 +11,5 @@ Different settings can be personalized:
|
|||
- Dismiss delay: Delay added before the next alert if the alert is dismissed. From 5 to 60 min
|
||||
- Pause delay: Same as Dismiss delay but longer (usefull for meetings and such). From 30 to 240 min
|
||||
- Min steps: Minimal amount of steps to count as an activity
|
||||
- Temp Threshold: Temperature threshold to determine if the watch is worn
|
||||
|
||||
|
|
|
@ -2,17 +2,17 @@ function run() {
|
|||
if (isNotWorn()) return;
|
||||
let now = new Date();
|
||||
let h = now.getHours();
|
||||
let health = Bangle.getHealthStatus("day");
|
||||
|
||||
if (h >= activityreminder_settings.startHour && h < activityreminder_settings.endHour) {
|
||||
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 10 secs after the stepsDate + minSteps
|
||||
cancel all other timers of this app
|
||||
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)
|
||||
*/
|
||||
}
|
||||
|
||||
|
@ -24,22 +24,42 @@ function run() {
|
|||
}
|
||||
|
||||
function isNotWorn() {
|
||||
// todo in a futur release check temperature and mouvement in a futur release
|
||||
return Bangle.isCharging();
|
||||
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);
|
||||
}
|
||||
});
|
||||
|
||||
const activityreminder = require("activityreminder");
|
||||
const activityreminder_settings = activityreminder.loadSettings();
|
||||
if (activityreminder_settings.enabled) {
|
||||
const activityreminder_data = activityreminder.loadData();
|
||||
if(activityreminder_data.firstLoad){
|
||||
activityreminder_data.firstLoad =false;
|
||||
activityreminder_data.firstLoad = false;
|
||||
activityreminder.saveData(activityreminder_data);
|
||||
}
|
||||
setInterval(run, 60000);
|
||||
/* todo in a futur release
|
||||
increase setInterval time to something that is still sensible (5 mins ?)
|
||||
add settimer to trigger like 10 secs after the stepsDate + minSteps
|
||||
cancel all other timers of this app
|
||||
when we added a settimer
|
||||
*/
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,8 @@ exports.loadSettings = function () {
|
|||
maxInnactivityMin: 30,
|
||||
dismissDelayMin: 15,
|
||||
pauseDelayMin: 120,
|
||||
minSteps: 50
|
||||
minSteps: 50,
|
||||
tempThreshold: 27
|
||||
}, storage.readJSON("activityreminder.s.json", true) || {});
|
||||
};
|
||||
|
||||
|
|
|
@ -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.05",
|
||||
"version":"0.06",
|
||||
"icon": "app.png",
|
||||
"type": "app",
|
||||
"tags": "tool,activity",
|
||||
|
|
|
@ -55,7 +55,7 @@
|
|||
},
|
||||
'Pause delay': {
|
||||
value: settings.pauseDelayMin,
|
||||
min: 30, max: 240,
|
||||
min: 30, max: 240, step: 5,
|
||||
onchange: v => {
|
||||
settings.pauseDelayMin = v;
|
||||
activityreminder.writeSettings(settings);
|
||||
|
@ -66,11 +66,20 @@
|
|||
},
|
||||
'Min steps': {
|
||||
value: settings.minSteps,
|
||||
min: 10, max: 500,
|
||||
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);
|
||||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
|
|
|
@ -29,3 +29,4 @@
|
|||
0.27: New UI!
|
||||
0.28: Fix bug with alarms not firing when configured to fire only once
|
||||
0.29: Fix wrong 'dow' handling in new timer if first day of week is Monday
|
||||
0.30: Fix "Enable All"
|
||||
|
|
|
@ -86,7 +86,8 @@ function showEditAlarmMenu(selectedAlarm, alarmIndex) {
|
|||
const menu = {
|
||||
"": { "title": isNew ? /*LANG*/"New Alarm" : /*LANG*/"Edit Alarm" },
|
||||
"< Back": () => {
|
||||
saveAlarm(alarm, alarmIndex, time);
|
||||
prepareAlarmForSave(alarm, alarmIndex, time);
|
||||
saveAndReload();
|
||||
showMainMenu();
|
||||
},
|
||||
/*LANG*/"Hour": {
|
||||
|
@ -144,7 +145,7 @@ function showEditAlarmMenu(selectedAlarm, alarmIndex) {
|
|||
E.showMenu(menu);
|
||||
}
|
||||
|
||||
function saveAlarm(alarm, alarmIndex, time) {
|
||||
function prepareAlarmForSave(alarm, alarmIndex, time) {
|
||||
alarm.t = require("time_utils").encodeTime(time);
|
||||
alarm.last = alarm.t < require("time_utils").getCurrentTimeMillis() ? new Date().getDate() : 0;
|
||||
|
||||
|
@ -153,8 +154,6 @@ function saveAlarm(alarm, alarmIndex, time) {
|
|||
} else {
|
||||
alarms[alarmIndex] = alarm;
|
||||
}
|
||||
|
||||
saveAndReload();
|
||||
}
|
||||
|
||||
function saveAndReload() {
|
||||
|
@ -251,7 +250,8 @@ function showEditTimerMenu(selectedTimer, timerIndex) {
|
|||
const menu = {
|
||||
"": { "title": isNew ? /*LANG*/"New Timer" : /*LANG*/"Edit Timer" },
|
||||
"< Back": () => {
|
||||
saveTimer(timer, timerIndex, time);
|
||||
prepareTimerForSave(timer, timerIndex, time);
|
||||
saveAndReload();
|
||||
showMainMenu();
|
||||
},
|
||||
/*LANG*/"Hours": {
|
||||
|
@ -293,7 +293,7 @@ function showEditTimerMenu(selectedTimer, timerIndex) {
|
|||
E.showMenu(menu);
|
||||
}
|
||||
|
||||
function saveTimer(timer, timerIndex, time) {
|
||||
function prepareTimerForSave(timer, timerIndex, time) {
|
||||
timer.timer = require("time_utils").encodeTime(time);
|
||||
timer.t = require("time_utils").getCurrentTimeMillis() + timer.timer;
|
||||
timer.last = 0;
|
||||
|
@ -303,8 +303,6 @@ function saveTimer(timer, timerIndex, time) {
|
|||
} else {
|
||||
alarms[timerIndex] = timer;
|
||||
}
|
||||
|
||||
saveAndReload();
|
||||
}
|
||||
|
||||
function showAdvancedMenu() {
|
||||
|
@ -327,7 +325,16 @@ function enableAll(on) {
|
|||
} else {
|
||||
E.showPrompt(/*LANG*/"Are you sure?", { title: on ? /*LANG*/"Enable All" : /*LANG*/"Disable All" }).then((confirm) => {
|
||||
if (confirm) {
|
||||
alarms.forEach(alarm => alarm.on = on);
|
||||
alarms.forEach((alarm, i) => {
|
||||
alarm.on = on;
|
||||
if (on) {
|
||||
if (alarm.timer) {
|
||||
prepareTimerForSave(alarm, i, require("time_utils").decodeTime(alarm.timer))
|
||||
} else {
|
||||
prepareAlarmForSave(alarm, i, require("time_utils").decodeTime(alarm.t))
|
||||
}
|
||||
}
|
||||
});
|
||||
saveAndReload();
|
||||
showMainMenu();
|
||||
} else {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"id": "alarm",
|
||||
"name": "Alarms & Timers",
|
||||
"shortName": "Alarms",
|
||||
"version": "0.29",
|
||||
"version": "0.30",
|
||||
"description": "Set alarms and timers on your Bangle",
|
||||
"icon": "app.png",
|
||||
"tags": "tool,alarm,widget",
|
||||
|
|
|
@ -9,3 +9,5 @@
|
|||
0.09: Fix time/date disappearing after fullscreen notification
|
||||
0.10: Use ClockFace library
|
||||
0.11: Use ClockFace.is12Hour
|
||||
0.12: Add settings to hide date,widgets
|
||||
0.13: Add font setting
|
||||
|
|
|
@ -4,3 +4,7 @@ A simple digital clock showing seconds as a horizontal bar.
|
|||
| 24hr style | 12hr style |
|
||||
| --- | --- |
|
||||
|  |  |
|
||||
|
||||
## Settings
|
||||
* `Show date`: display date at the bottom of screen
|
||||
* `Font`: choose between bitmap or vector fonts
|
|
@ -51,24 +51,25 @@ function dateText(date) {
|
|||
const ClockFace = require("ClockFace"),
|
||||
clock = new ClockFace({
|
||||
precision:1,
|
||||
settingsFile:'barclock.settings.json',
|
||||
init: function() {
|
||||
const Layout = require("Layout");
|
||||
this.layout = new Layout({
|
||||
type: "v", c: [
|
||||
{
|
||||
type: "h", c: [
|
||||
{id: "time", label: "88:88", type: "txt", font: "6x8:5", col:g.theme.fg, bgCol: g.theme.bg}, // size updated below
|
||||
{id: "time", label: "88:88", type: "txt", font: "6x8:5", col:g.theme.fg, bgCol: g.theme.bg}, // updated below
|
||||
{id: "ampm", label: " ", type: "txt", font: "6x8:2", col:g.theme.fg, bgCol: g.theme.bg},
|
||||
],
|
||||
},
|
||||
{id: "bar", type: "custom", fraction: 0, fillx: 1, height: 6, col: g.theme.fg2, render: renderBar},
|
||||
{height: 40},
|
||||
{id: "date", type: "txt", font: "10%", valign: 1},
|
||||
this.showDate ? {height: 40} : {},
|
||||
this.showDate ? {id: "date", type: "txt", font: "10%", valign: 1} : {},
|
||||
],
|
||||
}, {lazy: true});
|
||||
// adjustments based on screen size and whether we display am/pm
|
||||
let thickness; // bar thickness, same as time font "pixel block" size
|
||||
if (this.is12Hour) {
|
||||
if (this.is12Hour && locale.hasMeridian) {
|
||||
// Maximum font size = (<screen width> - <ampm: 2chars * (2*6)px>) / (5chars * 6px)
|
||||
thickness = Math.floor((Bangle.appRect.w-24)/(5*6));
|
||||
} else {
|
||||
|
@ -76,13 +77,23 @@ const ClockFace = require("ClockFace"),
|
|||
thickness = Math.floor(Bangle.appRect.w/(5*6));
|
||||
}
|
||||
this.layout.bar.height = thickness+1;
|
||||
this.layout.time.font = "6x8:"+thickness;
|
||||
if (this.font===1) { // vector
|
||||
const B2 = process.env.HWVERSION>1;
|
||||
if (this.is12Hour && locale.hasMeridian) {
|
||||
this.layout.time.font = "Vector:"+(B2 ? 50 : 60);
|
||||
this.layout.ampm.font = "Vector:"+(B2 ? 20 : 40);
|
||||
} else {
|
||||
this.layout.time.font = "Vector:"+(B2 ? 60 : 80);
|
||||
}
|
||||
} else {
|
||||
this.layout.time.font = "6x8:"+thickness;
|
||||
}
|
||||
this.layout.update();
|
||||
},
|
||||
update: function(date, c) {
|
||||
if (c.m) this.layout.time.label = timeText(date);
|
||||
if (c.h) this.layout.ampm.label = ampmText(date);
|
||||
if (c.d) this.layout.date.label = dateText(date);
|
||||
if (c.d && this.showDate) this.layout.date.label = dateText(date);
|
||||
const SECONDS_PER_MINUTE = 60;
|
||||
if (c.s) this.layout.bar.fraction = date.getSeconds()/SECONDS_PER_MINUTE;
|
||||
this.layout.render();
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "barclock",
|
||||
"name": "Bar Clock",
|
||||
"version": "0.11",
|
||||
"version": "0.13",
|
||||
"description": "A simple digital clock showing seconds as a bar",
|
||||
"icon": "clock-bar.png",
|
||||
"screenshots": [{"url":"screenshot.png"},{"url":"screenshot_pm.png"}],
|
||||
|
@ -12,6 +12,10 @@
|
|||
"allow_emulator": true,
|
||||
"storage": [
|
||||
{"name":"barclock.app.js","url":"clock-bar.js"},
|
||||
{"name":"barclock.settings.js","url":"settings.js"},
|
||||
{"name":"barclock.img","url":"clock-bar-icon.js","evaluate":true}
|
||||
],
|
||||
"data": [
|
||||
{"name":"barclock.settings.json"}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
(function(back) {
|
||||
let s = require('Storage').readJSON("barclock.settings.json", true) || {};
|
||||
|
||||
function saver(key) {
|
||||
return value => {
|
||||
s[key] = value;
|
||||
require('Storage').writeJSON("barclock.settings.json", s);
|
||||
}
|
||||
}
|
||||
|
||||
const fonts = [/*LANG*/"Bitmap",/*LANG*/"Vector"];
|
||||
const menu = {
|
||||
"": {"title": /*LANG*/"Bar Clock"},
|
||||
/*LANG*/"< Back": back,
|
||||
/*LANG*/"Show date": require("ClockFace_menu").showDate(s.showDate, saver('showDate')),
|
||||
/*LANG*/"Load widgets": require("ClockFace_menu").loadWidgets(s.loadWidgets, saver('loadWidgets')),
|
||||
/*LANG*/"Font": {
|
||||
value: s.font|0,
|
||||
min:0,max:1,wrap:true,
|
||||
format:v=>fonts[v],
|
||||
onchange:saver('font'),
|
||||
},
|
||||
};
|
||||
|
||||
E.showMenu(menu);
|
||||
});
|
|
@ -0,0 +1,9 @@
|
|||
0.01: Please forgive me
|
||||
0.02: Now tells time!
|
||||
0.03: Interaction
|
||||
0.04: Shows day of week
|
||||
0.05: Shows day of month
|
||||
0.06: Updates every 5 minutes when locked, or when unlock occurs. Also shows nr of steps.
|
||||
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,0 +1,23 @@
|
|||
# Barcode clockwatchface
|
||||
|
||||
A scannable EAN-8 compatible clockwatchface for your Bangle 2
|
||||
|
||||
The format of the bars are
|
||||
|
||||
`||HHmm||MMwc||`
|
||||
|
||||
* Left section: HHmm
|
||||
* H: Hours
|
||||
* m: Minutes
|
||||
* Right section: MM9c
|
||||
* M: Day of month
|
||||
* w: Day of week
|
||||
* c: Calculated EAN-8 digit checksum
|
||||
|
||||
Apart from that
|
||||
|
||||
* The upper left section displays total number of steps per day
|
||||
* The upper right section displays total number of steps from last boot ("stepuptime")
|
||||
* The face updates every 5 minutes or on demant by pressing the hardware button
|
||||
|
||||
This clockwathface is aware of theme choice, so it will adapt to Light/Dark themes.
|
|
@ -0,0 +1,428 @@
|
|||
/* Sizes */
|
||||
let checkBarWidth = 10;
|
||||
let checkBarHeight = 140;
|
||||
|
||||
let digitBarWidth = 14;
|
||||
let digitBarHeight = 100;
|
||||
|
||||
let textBarWidth = 56;
|
||||
let textBarHeight = 20;
|
||||
|
||||
let textWidth = 14;
|
||||
let textHeight = 20;
|
||||
|
||||
/* Offsets */
|
||||
var startOffsetX = 17;
|
||||
var startOffsetY = 30;
|
||||
|
||||
let startBarOffsetX = startOffsetX;
|
||||
let startBarOffsetY = startOffsetY;
|
||||
|
||||
let upperTextBarLeftOffsetX = startBarOffsetX + checkBarWidth;
|
||||
let upperTextBarLeftOffsetY = startOffsetY;
|
||||
|
||||
let midBarOffsetX = upperTextBarLeftOffsetX + textBarWidth;
|
||||
let midBarOffsetY = startOffsetY;
|
||||
|
||||
let upperTextBarRightOffsetX = midBarOffsetX + checkBarWidth;
|
||||
let upperTextBarRightOffsetY = startOffsetY;
|
||||
|
||||
let endBarOffsetX = upperTextBarRightOffsetX + textBarWidth;
|
||||
let endBarOffsetY = startOffsetY;
|
||||
|
||||
let leftBarsStartX = startBarOffsetX + checkBarWidth;
|
||||
let leftBarsStartY = upperTextBarLeftOffsetY + textBarHeight;
|
||||
|
||||
let rightBarsStartX = midBarOffsetX + checkBarWidth;
|
||||
let rightBarsStartY = upperTextBarRightOffsetY + textBarHeight;
|
||||
|
||||
/* Utilities */
|
||||
let stepCount = require("Storage").readJSON("stepCount",1);
|
||||
if(stepCount === undefined) stepCount = 0;
|
||||
let intCaster = num => Number(num);
|
||||
|
||||
var drawTimeout;
|
||||
|
||||
function renderWatch(l) {
|
||||
g.setFont("4x6",2);
|
||||
|
||||
// work out how to display the current time
|
||||
|
||||
var d = new Date();
|
||||
var h = d.getHours(), m = d.getMinutes();
|
||||
var time = h + ":" + ("0"+m).substr(-2);
|
||||
//var month = ("0" + (d.getMonth()+1)).slice(-2);
|
||||
var dayOfMonth = ('0' + d.getDate()).slice(-2);
|
||||
var dayOfWeek = d.getDay() || 7;
|
||||
var concatTime = ("0"+h).substr(-2) + ("0"+m).substr(-2) + dayOfMonth + dayOfWeek;
|
||||
|
||||
const chars = String(concatTime).split("").map((concatTime) => {
|
||||
return Number(concatTime);
|
||||
});
|
||||
const checkSum = calculateChecksum(chars);
|
||||
concatTime += checkSum;
|
||||
|
||||
drawCheckBar(startBarOffsetX, startBarOffsetY);
|
||||
|
||||
drawLDigit(chars[0], 0, leftBarsStartY);
|
||||
drawLDigit(chars[1], 1, leftBarsStartY);
|
||||
drawLDigit(chars[2], 2, leftBarsStartY);
|
||||
drawLDigit(chars[3], 3, leftBarsStartY);
|
||||
|
||||
g.drawString(getStepCount(), startOffsetX + checkBarWidth + 3, startOffsetY + 4);
|
||||
g.drawString(concatTime.substring(0,4), startOffsetX + checkBarWidth + 3, startOffsetY + textBarHeight + digitBarHeight + 6);
|
||||
|
||||
drawCheckBar(midBarOffsetX, midBarOffsetY);
|
||||
|
||||
drawRDigit(chars[4], 0, rightBarsStartY);
|
||||
drawRDigit(chars[5], 1, rightBarsStartY);
|
||||
drawRDigit(chars[6], 2, rightBarsStartY);
|
||||
drawRDigit(checkSum, 3, rightBarsStartY);
|
||||
|
||||
g.drawString(Bangle.getStepCount(), midBarOffsetX + checkBarWidth + 3, startOffsetY + 4);
|
||||
g.drawString(concatTime.substring(4), midBarOffsetX + checkBarWidth + 3, startOffsetY + textBarHeight + digitBarHeight + 6);
|
||||
|
||||
drawCheckBar(endBarOffsetX, endBarOffsetY);
|
||||
|
||||
// schedule a draw for the next minute
|
||||
if (drawTimeout) {
|
||||
clearTimeout(drawTimeout);
|
||||
}
|
||||
drawTimeout = setTimeout(function() {
|
||||
drawTimeout = undefined;
|
||||
layout.render(layout.watch);
|
||||
}, (1000 * 60 * 5) - (Date.now() % (1000 * 60 * 5)));
|
||||
}
|
||||
|
||||
function drawLDigit(digit, index, offsetY) {
|
||||
switch(digit) {
|
||||
case 0:
|
||||
drawLZeroWithOffset(leftBarsStartX+(digitBarWidth*index), offsetY);
|
||||
break;
|
||||
case 1:
|
||||
drawLOneWithOffset(leftBarsStartX+(digitBarWidth*index), offsetY);
|
||||
break;
|
||||
case 2:
|
||||
drawLTwoWithOffset(leftBarsStartX+(digitBarWidth*index), offsetY);
|
||||
break;
|
||||
case 3:
|
||||
drawLThreeWithOffset(leftBarsStartX+(digitBarWidth*index), offsetY);
|
||||
break;
|
||||
case 4:
|
||||
drawLFourWithOffset(leftBarsStartX+(digitBarWidth*index), offsetY);
|
||||
break;
|
||||
case 5:
|
||||
drawLFiveWithOffset(leftBarsStartX+(digitBarWidth*index), offsetY);
|
||||
break;
|
||||
case 6:
|
||||
drawLSixWithOffset(leftBarsStartX+(digitBarWidth*index), offsetY);
|
||||
break;
|
||||
case 7:
|
||||
drawLSevenWithOffset(leftBarsStartX+(digitBarWidth*index), offsetY);
|
||||
break;
|
||||
case 8:
|
||||
drawLEightWithOffset(leftBarsStartX+(digitBarWidth*index), offsetY);
|
||||
break;
|
||||
case 9:
|
||||
drawLNineWithOffset(leftBarsStartX+(digitBarWidth*index), offsetY);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function drawRDigit(digit, index, offsetY) {
|
||||
switch(digit) {
|
||||
case 0:
|
||||
drawRZeroWithOffset(rightBarsStartX+(digitBarWidth*index), offsetY);
|
||||
break;
|
||||
case 1:
|
||||
drawROneWithOffset(rightBarsStartX+(digitBarWidth*index), offsetY);
|
||||
break;
|
||||
case 2:
|
||||
drawRTwoWithOffset(rightBarsStartX+(digitBarWidth*index), offsetY);
|
||||
break;
|
||||
case 3:
|
||||
drawRThreeWithOffset(rightBarsStartX+(digitBarWidth*index), offsetY);
|
||||
break;
|
||||
case 4:
|
||||
drawRFourWithOffset(rightBarsStartX+(digitBarWidth*index), offsetY);
|
||||
break;
|
||||
case 5:
|
||||
drawRFiveWithOffset(rightBarsStartX+(digitBarWidth*index), offsetY);
|
||||
break;
|
||||
case 6:
|
||||
drawRSixWithOffset(rightBarsStartX+(digitBarWidth*index), offsetY);
|
||||
break;
|
||||
case 7:
|
||||
drawRSevenWithOffset(rightBarsStartX+(digitBarWidth*index), offsetY);
|
||||
break;
|
||||
case 8:
|
||||
drawREightWithOffset(rightBarsStartX+(digitBarWidth*index), offsetY);
|
||||
break;
|
||||
case 9:
|
||||
drawRNineWithOffset(rightBarsStartX+(digitBarWidth*index), offsetY);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
LEAN
|
||||
|
||||
01234567890123
|
||||
xxxx xx
|
||||
xx xxxx
|
||||
xxxxxxxx xx
|
||||
xx xxxx
|
||||
xxxx xx
|
||||
xx xxxxxxxx
|
||||
xxxxxx xxxx
|
||||
xxxx xxxxxx
|
||||
xx xxxx
|
||||
xxxx xx
|
||||
*/
|
||||
function drawLOneWithOffset(offset, offsetY) {
|
||||
let barOneX = 4;
|
||||
let barTwoX = 12;
|
||||
g.fillRect(barOneX+offset,offsetY+0,barOneX+3+offset,offsetY+digitBarHeight);
|
||||
g.fillRect(barTwoX+offset,offsetY+0,barTwoX+1+offset,offsetY+digitBarHeight);
|
||||
//g.drawString("1",offset+3,offsetY+digitHeight+5);
|
||||
}
|
||||
|
||||
function drawLTwoWithOffset(offset, offsetY) {
|
||||
let barOneX = 4;
|
||||
let barTwoX = 10;
|
||||
g.fillRect(barOneX+offset,offsetY+0,barOneX+1+offset,offsetY+digitBarHeight);
|
||||
g.fillRect(barTwoX+offset,offsetY+0,barTwoX+3+offset,offsetY+digitBarHeight);
|
||||
//g.drawString("2",offset+3,offsetY+digitHeight+5);
|
||||
}
|
||||
|
||||
function drawLThreeWithOffset(offset, offsetY) {
|
||||
let barOneX = 2;
|
||||
let barTwoX = 12;
|
||||
g.fillRect(barOneX+offset,offsetY+0,barOneX+7+offset,offsetY+digitBarHeight);
|
||||
g.fillRect(barTwoX+offset,offsetY+0,barTwoX+1+offset,offsetY+digitBarHeight);
|
||||
//g.drawString("3",offset+3,offsetY+digitHeight+5);
|
||||
}
|
||||
|
||||
function drawLFourWithOffset(offset, offsetY) {
|
||||
let barOneX = 2;
|
||||
let barTwoX = 10;
|
||||
g.fillRect(barOneX+offset,offsetY+0,barOneX+1+offset,offsetY+digitBarHeight);
|
||||
g.fillRect(barTwoX+offset,offsetY+0,barTwoX+3+offset,offsetY+digitBarHeight);
|
||||
//g.drawString("4",offset+3,offsetY+digitHeight+5);
|
||||
}
|
||||
|
||||
function drawLFiveWithOffset(offset, offsetY) {
|
||||
let barOneX = 2;
|
||||
let barTwoX = 12;
|
||||
g.fillRect(barOneX+offset,offsetY+0,barOneX+3+offset,offsetY+digitBarHeight);
|
||||
g.fillRect(barTwoX+offset,offsetY+0,barTwoX+1+offset,offsetY+digitBarHeight);
|
||||
//g.drawString("5",offset+3,offsetY+digitHeight+5);
|
||||
}
|
||||
|
||||
function drawLSixWithOffset(offset, offsetY) {
|
||||
let barOneX = 2;
|
||||
let barTwoX = 6;
|
||||
g.fillRect(barOneX+offset,offsetY+0,barOneX+1+offset,offsetY+digitBarHeight);
|
||||
g.fillRect(barTwoX+offset,offsetY+0,barTwoX+7+offset,offsetY+digitBarHeight);
|
||||
//g.drawString("6",offset+3,offsetY+digitHeight+5);
|
||||
}
|
||||
|
||||
function drawLSevenWithOffset(offset, offsetY) {
|
||||
let barOneX = 2;
|
||||
let barTwoX = 10;
|
||||
g.fillRect(barOneX+offset,offsetY+0,barOneX+5+offset,offsetY+digitBarHeight);
|
||||
g.fillRect(barTwoX+offset,offsetY+0,barTwoX+3+offset,offsetY+digitBarHeight);
|
||||
//g.drawString("7",offset+3,offsetY+digitHeight+5);
|
||||
}
|
||||
|
||||
function drawLEightWithOffset(offset, offsetY) {
|
||||
let barOneX = 2;
|
||||
let barTwoX = 8;
|
||||
g.fillRect(barOneX+offset,offsetY+0,barOneX+3+offset,offsetY+digitBarHeight);
|
||||
g.fillRect(barTwoX+offset,offsetY+0,barTwoX+5+offset,offsetY+digitBarHeight);
|
||||
//g.drawString("8",offset+3,offsetY+digitHeight+5);
|
||||
}
|
||||
|
||||
function drawLNineWithOffset(offset, offsetY) {
|
||||
let barOneX = 6;
|
||||
let barTwoX = 10;
|
||||
g.fillRect(barOneX+offset,offsetY+0,barOneX+1+offset,offsetY+digitBarHeight);
|
||||
g.fillRect(barTwoX+offset,offsetY+0,barTwoX+3+offset,offsetY+digitBarHeight);
|
||||
//g.drawString("9",offset+3,offsetY+digitHeight+5);
|
||||
}
|
||||
|
||||
function drawLZeroWithOffset(offset, offsetY) {
|
||||
let barOneX = 6;
|
||||
let barTwoX = 12;
|
||||
g.fillRect(barOneX+offset,offsetY+0,barOneX+3+offset,offsetY+digitBarHeight);
|
||||
g.fillRect(barTwoX+offset,offsetY+0,barTwoX+1+offset,offsetY+digitBarHeight);
|
||||
//g.drawString("0",offset+3,offsetY+digitHeight+5);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
REAN
|
||||
|
||||
01234567890123
|
||||
xxxx xxxx
|
||||
xxxx xxxx
|
||||
xx xx
|
||||
xx xxxxxx
|
||||
xx xxxxxx
|
||||
xx xx
|
||||
xx xx
|
||||
xx xx
|
||||
xxxxxx xx
|
||||
xxxxxx xx
|
||||
|
||||
*/
|
||||
function drawROneWithOffset(offset, offsetY) {
|
||||
let barOneX = 0;
|
||||
let barTwoX = 8;
|
||||
g.fillRect(offset+barOneX,offsetY+0,offset+barOneX+3,offsetY+digitBarHeight);
|
||||
g.fillRect(offset+barTwoX,offsetY+0,offset+barTwoX+3,offsetY+digitBarHeight);
|
||||
//g.drawString("1",offset+2,offsetY+textHeight+5);
|
||||
}
|
||||
|
||||
function drawRTwoWithOffset(offset, offsetY) {
|
||||
let barOneX = 0;
|
||||
let barTwoX = 6;
|
||||
g.fillRect(offset+barOneX,offsetY+0,offset+barOneX+3,offsetY+digitBarHeight);
|
||||
g.fillRect(offset+barTwoX,offsetY+0,offset+barTwoX+3,offsetY+digitBarHeight);
|
||||
//g.drawString("2",offset+2,offsetY+textHeight+5);
|
||||
}
|
||||
|
||||
function drawRThreeWithOffset(offset, offsetY) {
|
||||
let barOneX = 0;
|
||||
let barTwoX = 10;
|
||||
g.fillRect(barOneX+offset,offsetY+0,barOneX+1+offset,offsetY+digitBarHeight);
|
||||
g.fillRect(barTwoX+offset,offsetY+0,barTwoX+1+offset,offsetY+digitBarHeight);
|
||||
//g.drawString("3",offset+2,offsetY+textHeight+5);
|
||||
}
|
||||
|
||||
function drawRFourWithOffset(offset, offsetY) {
|
||||
let barOneX = 0;
|
||||
let barTwoX = 4;
|
||||
g.fillRect(barOneX+offset,offsetY+0,barOneX+1+offset,offsetY+digitBarHeight);
|
||||
g.fillRect(barTwoX+offset,offsetY+0,barTwoX+5+offset,offsetY+digitBarHeight);
|
||||
//g.drawString("4",offset+2,offsetY+textHeight+5);
|
||||
}
|
||||
|
||||
function drawRFiveWithOffset(offset, offsetY) {
|
||||
let barOneX = 0;
|
||||
let barTwoX = 6;
|
||||
g.fillRect(barOneX+offset,offsetY+0,barOneX+1+offset,offsetY+digitBarHeight);
|
||||
g.fillRect(barTwoX+offset,offsetY+0,barTwoX+5+offset,offsetY+digitBarHeight);
|
||||
//g.drawString("5",offset+2,offsetY+textHeight+5);
|
||||
}
|
||||
|
||||
function drawRSixWithOffset(offset, offsetY) {
|
||||
let barOneX = 0;
|
||||
let barTwoX = 4;
|
||||
g.fillRect(barOneX+offset,offsetY+0,barOneX+1+offset,offsetY+digitBarHeight);
|
||||
g.fillRect(barTwoX+offset,offsetY+0,barTwoX+1+offset,offsetY+digitBarHeight);
|
||||
//g.drawString("6",offset+2,offsetY+textHeight+5);
|
||||
}
|
||||
|
||||
function drawRSevenWithOffset(offset, offsetY) {
|
||||
let barOneX = 0;
|
||||
let barTwoX = 8;
|
||||
g.fillRect(barOneX+offset,offsetY+0,barOneX+1+offset,offsetY+digitBarHeight);
|
||||
g.fillRect(barTwoX+offset,offsetY+0,barTwoX+1+offset,offsetY+digitBarHeight);
|
||||
//g.drawString("7",offset+2,offsetY+textHeight+5);
|
||||
}
|
||||
|
||||
function drawREightWithOffset(offset, offsetY) {
|
||||
let barOneX = 0;
|
||||
let barTwoX = 6;
|
||||
g.fillRect(offset+barOneX,offsetY+0,offset+barOneX+1,offsetY+digitBarHeight);
|
||||
g.fillRect(offset+barTwoX,offsetY+0,offset+barTwoX+1,offsetY+digitBarHeight);
|
||||
//g.drawString("8",offset+2,offsetY+textHeight+5);
|
||||
}
|
||||
|
||||
function drawRNineWithOffset(offset, offsetY) {
|
||||
let barOneX = 0;
|
||||
let barTwoX = 8;
|
||||
g.fillRect(barOneX+offset,offsetY+0,barOneX+5+offset,offsetY+digitBarHeight);
|
||||
g.fillRect(barTwoX+offset,offsetY+0,barTwoX+1+offset,offsetY+digitBarHeight);
|
||||
//g.drawString("9",offset+2,offsetY+textHeight+5);
|
||||
}
|
||||
|
||||
function drawRZeroWithOffset(offset, offsetY) {
|
||||
let barOneX = 0;
|
||||
let barTwoX = 10;
|
||||
g.fillRect(barOneX+offset,offsetY+0,barOneX+5+offset,offsetY+digitBarHeight);
|
||||
g.fillRect(barTwoX+offset,offsetY+0,barTwoX+1+offset,offsetY+digitBarHeight);
|
||||
//g.drawString("0",offset+2,offsetY+textHeight+5);
|
||||
}
|
||||
|
||||
function drawCheckBar(offsetX, offsetY) {
|
||||
const barOneX = offsetX+2;
|
||||
const barOneWidth = 1;
|
||||
const barTwoX = offsetX+6;
|
||||
const barTwoWidth = 1;
|
||||
g.fillRect(barOneX,offsetY,barOneX+barOneWidth,offsetY+checkBarHeight);
|
||||
g.fillRect(barTwoX,offsetY,barTwoX+barTwoWidth,offsetY+checkBarHeight);
|
||||
}
|
||||
|
||||
function calculateChecksum(digits) {
|
||||
let oddSum = digits[6] + digits[4] + digits[2] + digits[0];
|
||||
let evenSum = digits[5] + digits[3] + digits[1];
|
||||
|
||||
let checkSum = (10 - ((3 * oddSum + evenSum) % 10)) % 10;
|
||||
|
||||
return checkSum;
|
||||
}
|
||||
|
||||
function storeStepCount() {
|
||||
stepCount = Bangle.getStepCount();
|
||||
require("Storage").writeJSON("stepCount",stepCount);
|
||||
}
|
||||
|
||||
function getStepCount() {
|
||||
let accumulatedSteps = Bangle.getStepCount();
|
||||
if(accumulatedSteps <= stepCount) {
|
||||
return 0;
|
||||
}
|
||||
return accumulatedSteps - stepCount;
|
||||
}
|
||||
|
||||
function resetAtMidnight() {
|
||||
let now = new Date();
|
||||
let night = new Date(
|
||||
now.getFullYear(),
|
||||
now.getMonth(),
|
||||
now.getDate(), // the next day, ...
|
||||
23, 58, 0 // ...at 00:00:00 hours
|
||||
);
|
||||
let msToMidnight = night.getTime() - now.getTime();
|
||||
|
||||
setTimeout(function() {
|
||||
storeStepCount(); // <-- This is the function being called at midnight.
|
||||
resetAtMidnight(); // Then, reset again next midnight.
|
||||
}, msToMidnight);
|
||||
}
|
||||
|
||||
resetAtMidnight();
|
||||
|
||||
// The layout, referencing the custom renderer
|
||||
var Layout = require("Layout");
|
||||
var layout = new Layout( {
|
||||
type:"v", c: [
|
||||
{type:"custom", render:renderWatch, id:"watch", bgCol:g.theme.bg, fillx:1, filly:1 }
|
||||
]
|
||||
});
|
||||
|
||||
// Clear the screen once, at startup
|
||||
g.clear();
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
Bangle.setUI("clock");
|
||||
layout.render();
|
||||
|
||||
Bangle.on('lock', function(locked) {
|
||||
if(!locked) {
|
||||
layout.render();
|
||||
}
|
||||
});
|
Binary file not shown.
After Width: | Height: | Size: 2.7 KiB |
|
@ -0,0 +1 @@
|
|||
E.toArrayBuffer(atob("MDAE///+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifrV6mlp+rXYiFXZr8k4q8r+if/////+if7+///u//79ie7/7//u///+if/////+ifnP6t+378r+ienvyf/K/7v+if/////+ifrfx6/I78j+ibe/+e/W75n+if/////+iee/+t/Z77f+iervyv/r/7v+if//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////"))
|
Binary file not shown.
After Width: | Height: | Size: 2.3 KiB |
|
@ -0,0 +1,16 @@
|
|||
{ "id": "barcode",
|
||||
"name": "Barcode clock",
|
||||
"shortName":"Barcode clock",
|
||||
"icon": "barcode.icon.png",
|
||||
"version":"0.09",
|
||||
"description": "EAN-8 compatible barcode clock.",
|
||||
"tags": "barcode,ean,ean-8,watchface,clock,clockface",
|
||||
"type": "clock",
|
||||
"supports" : ["BANGLEJS2"],
|
||||
"storage": [
|
||||
{"name":"barcode.app.js","url":"barcode.app.js"},
|
||||
{"name":"barcode.img","url":"barcode.icon.js","evaluate":true}
|
||||
],
|
||||
"readme":"README.md",
|
||||
"screenshots": [{"url":"barcode.clock.png"}]
|
||||
}
|
|
@ -7,3 +7,4 @@
|
|||
0.07: Fix off-by-one-error on previous month
|
||||
0.08: Do not register as watch, manually start clock on button
|
||||
read start of week from system settings
|
||||
0.09: Fix scope of let variables
|
||||
|
|
|
@ -16,6 +16,12 @@ const white = "#ffffff";
|
|||
const red = "#d41706";
|
||||
const blue = "#0000ff";
|
||||
const yellow = "#ffff00";
|
||||
let bgColor = color4;
|
||||
let bgColorMonth = color1;
|
||||
let bgColorDow = color2;
|
||||
let bgColorWeekend = color3;
|
||||
let fgOtherMonth = gray1;
|
||||
let fgSameMonth = white;
|
||||
|
||||
let settings = require('Storage').readJSON("calendar.json", true) || {};
|
||||
let startOnSun = ((require("Storage").readJSON("setting.json", true) || {}).firstDayOfWeek || 0) === 0;
|
||||
|
@ -27,19 +33,12 @@ if (settings.ndColors === undefined)
|
|||
}
|
||||
|
||||
if (settings.ndColors === true) {
|
||||
let bgColor = white;
|
||||
let bgColorMonth = blue;
|
||||
let bgColorDow = black;
|
||||
let bgColorWeekend = yellow;
|
||||
let fgOtherMonth = blue;
|
||||
let fgSameMonth = black;
|
||||
} else {
|
||||
let bgColor = color4;
|
||||
let bgColorMonth = color1;
|
||||
let bgColorDow = color2;
|
||||
let bgColorWeekend = color3;
|
||||
let fgOtherMonth = gray1;
|
||||
let fgSameMonth = white;
|
||||
bgColor = white;
|
||||
bgColorMonth = blue;
|
||||
bgColorDow = black;
|
||||
bgColorWeekend = yellow;
|
||||
fgOtherMonth = blue;
|
||||
fgSameMonth = black;
|
||||
}
|
||||
|
||||
function getDowLbls(locale) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "calendar",
|
||||
"name": "Calendar",
|
||||
"version": "0.08",
|
||||
"version": "0.09",
|
||||
"description": "Simple calendar",
|
||||
"icon": "calendar.png",
|
||||
"screenshots": [{"url":"screenshot_calendar.png"}],
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
1.00: New App!
|
||||
1.01: Use fractional numbers and scale the points to keep working consistently on whole screen
|
|
@ -6,6 +6,7 @@ A simple calibration app for the touchscreen
|
|||
Once lauched touch the cross that appear on the screen to make
|
||||
another spawn elsewhere.
|
||||
|
||||
each new touch on the screen will help to calibrate the offset
|
||||
of your finger on the screen. After five or more input, press
|
||||
the button to save the calibration and close the application.
|
||||
Each new touch on the screen will help to calibrate the offset
|
||||
of your finger on the screen. After four or more inputs, press
|
||||
the button to save the calibration and close the application. Quality
|
||||
of the calibration gets better with every touch on a cross.
|
||||
|
|
|
@ -1,40 +1,60 @@
|
|||
class BanglejsApp {
|
||||
constructor() {
|
||||
this.maxSamples = 16;
|
||||
this.target = {
|
||||
xMin: Math.floor(0.1 * g.getWidth()),
|
||||
xMax: Math.floor(0.9 * g.getWidth()),
|
||||
yMin: Math.floor(0.1 * g.getHeight()),
|
||||
yMax: Math.floor(0.9 * g.getHeight()),
|
||||
};
|
||||
this.x = 0;
|
||||
this.y = 0;
|
||||
this.step = 0;
|
||||
this.settings = {
|
||||
xoffset: 0,
|
||||
yoffset: 0,
|
||||
xoffset: [0],
|
||||
yoffset: [0],
|
||||
xMaxActual: [this.target.xMax],
|
||||
yMaxActual: [this.target.yMax],
|
||||
};
|
||||
}
|
||||
|
||||
load_settings() {
|
||||
let settings = require('Storage').readJSON('calibration.json', true) || {active: false};
|
||||
|
||||
// do nothing if the calibration is deactivated
|
||||
if (settings.active === true) {
|
||||
// cancel the calibration offset
|
||||
Bangle.on('touch', function(button, xy) {
|
||||
xy.x += settings.xoffset;
|
||||
xy.y += settings.yoffset;
|
||||
});
|
||||
}
|
||||
if (!settings.xoffset) settings.xoffset = 0;
|
||||
if (!settings.yoffset) settings.yoffset = 0;
|
||||
|
||||
console.log('loaded settings:');
|
||||
console.log(settings);
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
save_settings() {
|
||||
this.settings.active = true;
|
||||
this.settings.reload = false;
|
||||
require('Storage').writeJSON('calibration.json', this.settings);
|
||||
getMedian(array){
|
||||
array.sort();
|
||||
let i = Math.floor(array.length/2);
|
||||
if ( array.length % 2 && array.length > 1 ){
|
||||
return (array[i]+array[i+1])/2;
|
||||
} else {
|
||||
return array[i];
|
||||
}
|
||||
}
|
||||
|
||||
console.log('saved settings:');
|
||||
console.log(this.settings);
|
||||
getMedianSettings(){
|
||||
let medianSettings = {
|
||||
xoffset: this.getMedian(this.settings.xoffset),
|
||||
yoffset: this.getMedian(this.settings.yoffset)
|
||||
};
|
||||
|
||||
medianSettings.xscale = this.target.xMax / (medianSettings.xoffset + this.getMedian(this.settings.xMaxActual));
|
||||
medianSettings.yscale = this.target.yMax / (medianSettings.yoffset + this.getMedian(this.settings.yMaxActual));
|
||||
return medianSettings;
|
||||
}
|
||||
|
||||
save_settings() {
|
||||
let settingsToSave = this.getMedianSettings();
|
||||
settingsToSave.active = true;
|
||||
settingsToSave.reload = false;
|
||||
require('Storage').writeJSON('calibration.json', settingsToSave);
|
||||
|
||||
console.log('saved settings:', settingsToSave);
|
||||
}
|
||||
|
||||
explain() {
|
||||
|
@ -46,29 +66,78 @@ class BanglejsApp {
|
|||
}
|
||||
|
||||
drawTarget() {
|
||||
this.x = 16 + Math.floor(Math.random() * (g.getWidth() - 32));
|
||||
this.y = 40 + Math.floor(Math.random() * (g.getHeight() - 80));
|
||||
switch (this.step){
|
||||
case 0:
|
||||
this.x = this.target.xMin;
|
||||
this.y = this.target.yMin;
|
||||
break;
|
||||
case 1:
|
||||
this.x = this.target.xMax;
|
||||
this.y = this.target.yMin;
|
||||
break;
|
||||
case 2:
|
||||
this.x = this.target.xMin;
|
||||
this.y = this.target.yMax;
|
||||
break;
|
||||
case 3:
|
||||
this.x = this.target.xMax;
|
||||
this.y = this.target.yMax;
|
||||
break;
|
||||
}
|
||||
|
||||
g.clearRect(0, 24, g.getWidth(), g.getHeight() - 24);
|
||||
g.clearRect(0, 0, g.getWidth(), g.getHeight());
|
||||
g.setColor(g.theme.fg);
|
||||
g.drawLine(this.x, this.y - 5, this.x, this.y + 5);
|
||||
g.drawLine(this.x - 5, this.y, this.x + 5, this.y);
|
||||
g.setFont('Vector', 10);
|
||||
g.drawString('current offset: ' + this.settings.xoffset + ', ' + this.settings.yoffset, 0, 24);
|
||||
let medianSettings = this.getMedianSettings();
|
||||
g.drawString('current offset: ' + medianSettings.xoffset.toFixed(3) + ', ' + medianSettings.yoffset.toFixed(3), 2, (g.getHeight()/2)-6);
|
||||
g.drawString('current scale: ' + medianSettings.xscale.toFixed(3) + ', ' + medianSettings.yscale.toFixed(3), 2, (g.getHeight()/2)+6);
|
||||
}
|
||||
|
||||
setOffset(xy) {
|
||||
this.settings.xoffset = Math.round((this.settings.xoffset + (this.x - Math.floor((this.x + xy.x)/2)))/2);
|
||||
this.settings.yoffset = Math.round((this.settings.yoffset + (this.y - Math.floor((this.y + xy.y)/2)))/2);
|
||||
switch (this.step){
|
||||
case 0:
|
||||
this.settings.xoffset.push(this.x - xy.x);
|
||||
this.settings.yoffset.push(this.y - xy.y);
|
||||
break;
|
||||
case 1:
|
||||
this.settings.xMaxActual.push(xy.x);
|
||||
this.settings.yoffset.push(this.y - xy.y);
|
||||
break;
|
||||
case 2:
|
||||
this.settings.xoffset.push(this.x - xy.x);
|
||||
this.settings.yMaxActual.push(xy.y);
|
||||
break;
|
||||
case 3:
|
||||
this.settings.xMaxActual.push(xy.x);
|
||||
this.settings.yMaxActual.push(xy.y);
|
||||
break;
|
||||
}
|
||||
|
||||
for (let c in this.settings){
|
||||
if (this.settings[c].length > this.maxSamples) this.settings[c] = this.settings[c].slice(1, this.maxSamples);
|
||||
}
|
||||
}
|
||||
|
||||
nextStep() {
|
||||
this.step++;
|
||||
if ( this.step == 4 ) this.step = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
E.srand(Date.now());
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
|
||||
calibration = new BanglejsApp();
|
||||
calibration.load_settings();
|
||||
Bangle.disableCalibration = true;
|
||||
|
||||
function touchHandler (btn, xy){
|
||||
if (xy) calibration.setOffset(xy);
|
||||
calibration.nextStep();
|
||||
calibration.drawTarget();
|
||||
}
|
||||
|
||||
let modes = {
|
||||
mode : 'custom',
|
||||
|
@ -76,10 +145,7 @@ let modes = {
|
|||
calibration.save_settings(this.settings);
|
||||
load();
|
||||
},
|
||||
touch : function(btn, xy) {
|
||||
calibration.setOffset(xy);
|
||||
calibration.drawTarget();
|
||||
},
|
||||
touch : touchHandler,
|
||||
};
|
||||
Bangle.setUI(modes);
|
||||
calibration.drawTarget();
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
let cal_settings = require('Storage').readJSON("calibration.json", true) || {active: false};
|
||||
Bangle.on('touch', function(button, xy) {
|
||||
// do nothing if the calibration is deactivated
|
||||
if (cal_settings.active === false) return;
|
||||
if (cal_settings.active === false || Bangle.disableCalibration) return;
|
||||
|
||||
// reload the calibration offset at each touch event /!\ bad for the flash memory
|
||||
if (cal_settings.reload === true) {
|
||||
|
@ -9,6 +9,6 @@ Bangle.on('touch', function(button, xy) {
|
|||
}
|
||||
|
||||
// apply the calibration offset
|
||||
xy.x += cal_settings.xoffset;
|
||||
xy.y += cal_settings.yoffset;
|
||||
xy.x = E.clip(Math.round((xy.x + (cal_settings.xoffset || 0)) * (cal_settings.xscale || 1)),0,g.getWidth());
|
||||
xy.y = E.clip(Math.round((xy.y + (cal_settings.yoffset || 0)) * (cal_settings.yscale || 1)),0,g.getHeight());
|
||||
});
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"name": "Touchscreen Calibration",
|
||||
"shortName":"Calibration",
|
||||
"icon": "calibration.png",
|
||||
"version":"1.00",
|
||||
"version":"1.01",
|
||||
"description": "A simple calibration app for the touchscreen",
|
||||
"supports": ["BANGLEJS","BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 6.1 KiB |
|
@ -0,0 +1,2 @@
|
|||
0.01: New clock
|
||||
0.02: Use ClockFace library, add settings
|
|
@ -0,0 +1,111 @@
|
|||
Graphics.prototype.setFont15x32N = function() {
|
||||
this.setFontCustom(atob(
|
||||
// 15x32.png, converted using http://ebfc.mattbrailsford.com/
|
||||
"/////oAAAAKAAAACgAAAAoAAAAKAAAACgf//AoEAAQKB//8CgAAAAoAAAAKAAAACgAAAAoAAAAL////+/wAB/oEAAQKBAAECgf//AoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAAC////AgAAAQIAAAH+/w///oEIAAKBCAACgQgAAoEIAAKBCAACgQg/AoEIIQKB+CECgAAhAoAAIQKAACECgAAhAoAAIQL//+H+/w/h/oEIIQKBCCECgQghAoEIIQKBCCECgQghAoEIIQKB+D8CgAAAAoAAAAKAAAACgAAAAoAAAAL////+///gAIAAIACAACAAgAAgAIAAIAD/+CAAAAggAAAIIAAACD/+//gAAoAAAAKAAAACgAAAAoAAAAL////+///h/oAAIQKAACECgAAhAoAAIQKAACECgfghAoEIIQKBCD8CgQgAAoEIAAKBCAACgQgAAoEIAAL/D//+/////oAAAAKAAAACgAAAAoAAAAKAAAACgfg/AoEIIQKBCD8CgQgAAoEIAAKBCAACgQgAAoEIAAL/D//+/wAAAIEAAACBAAAAgQAAAIEAAACBAAAAgQAAAIH///6AAAACgAAAAoAAAAKAAAACgAAAAoAAAAL////+/////oAAAAKAAAACgAAAAoAAAAKAAAACgfg/AoEIIQKB+D8CgAAAAoAAAAKAAAACgAAAAoAAAAL////+///h/oAAIQKAACECgAAhAoAAIQKAACECgfghAoEIIQKB+D8CgAAAAoAAAAKAAAACgAAAAoAAAAL////+"
|
||||
), "0".charCodeAt(0), 15, 32);
|
||||
};
|
||||
|
||||
/**
|
||||
* Add coordinates for nth tooth to vertices
|
||||
* @param {array} poly Array to add points to
|
||||
* @param {number} n Tooth number
|
||||
*/
|
||||
function addTooth(poly, n) {
|
||||
const
|
||||
tau = Math.PI*2, arc = tau/clock.teeth,
|
||||
e = arc*clock.edge, p = arc*clock.point, s = (arc-(e+p))/2; // edge,point,slopes
|
||||
const sin = Math.sin, cos = Math.cos,
|
||||
x = clock.x, y = clock.y,
|
||||
r2 = clock.r2, r3 = clock.r3;
|
||||
let r = (n-1)*arc+e/2; // rads
|
||||
poly.push(x+r2*sin(r), y-r2*cos(r));
|
||||
r += s;
|
||||
poly.push(x+r3*sin(r), y-r3*cos(r));
|
||||
r += p;
|
||||
poly.push(x+r3*sin(r), y-r3*cos(r));
|
||||
r += s;
|
||||
poly.push(x+r2*sin(r), y-r2*cos(r));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} n Tooth number to fill (1-based)
|
||||
* @param col Fill color
|
||||
*/
|
||||
function fillTooth(n, col) {
|
||||
if (!n) return; // easiest to check here
|
||||
let poly = [];
|
||||
addTooth(poly, n);
|
||||
g.setColor(col).fillPoly(poly)
|
||||
.setColor(g.theme.fg2).drawPoly(poly); // fillPoly colored over the outline
|
||||
}
|
||||
|
||||
const ClockFace = require("ClockFace");
|
||||
const clock = new ClockFace({
|
||||
precision: 1,
|
||||
settingsFile: "cogclock.settings.json",
|
||||
init: function() {
|
||||
this.r1 = 84; // inner radius
|
||||
this.r3 = Math.min(Bangle.appRect.w/2, Bangle.appRect.h/2); // outer radius
|
||||
this.r2 = (this.r1*3+this.r3*2)/5;
|
||||
this.teeth = 12;
|
||||
this.edge = 0.45;
|
||||
this.point = 0.35; // as fraction of arc
|
||||
this.x = Bangle.appRect.x+Bangle.appRect.w/2;
|
||||
this.y = Bangle.appRect.y+Bangle.appRect.h/2;
|
||||
},
|
||||
draw: function(d) {
|
||||
const x = this.x, y = this.y;
|
||||
g.setColor(g.theme.bg2).fillCircle(x, y, this.r2) // fill cog
|
||||
.setColor(g.theme.bg).fillCircle(x, y, this.r1) // clear center
|
||||
.setColor(g.theme.fg2).drawCircle(x, y, this.r1); // draw inner border
|
||||
let poly = []; // complete teeth outline
|
||||
for(let t = 1; t<=this.teeth; t++) {
|
||||
fillTooth(t, g.theme.bg2);
|
||||
addTooth(poly, t);
|
||||
}
|
||||
g.drawPoly(poly, true); // draw outer border
|
||||
if (!this.showDate) {
|
||||
// draw top/bottom rectangles (instead of year/date)
|
||||
g.reset()
|
||||
.fillRect(x-30, y-60, x+29, y-33).clearRect(x-28, y-58, x+27, y-33)
|
||||
.fillRect(x-30, y+60, x+29, y+30).clearRect(x-28, y+58, x+27, y+30);
|
||||
}
|
||||
this.tooth = 0;
|
||||
this.update(d, {s: 1, m: 1, h: 1, d: 1});
|
||||
},
|
||||
update: function(d, c) {
|
||||
g.reset();
|
||||
const pad2 = num => (num<10 ? "0" : "")+num,
|
||||
year = d.getFullYear(),
|
||||
date = pad2(d.getDate())+pad2(d.getMonth()),
|
||||
time = pad2(d.getHours())+pad2(d.getMinutes()),
|
||||
tooth = Math.round(d.getSeconds()/60*this.teeth);
|
||||
const x = this.x, y = this.y;
|
||||
if (c.m) {
|
||||
g.setFont("15x32N:2").setFontAlign(0, 0) // center middle
|
||||
.drawString(time, x, y, true);
|
||||
}
|
||||
if (this.showDate) {
|
||||
if (c.d) {
|
||||
g.setFont("15x32N").setFontAlign(0, -1) // center top
|
||||
.drawString(year, x, y+32, true)
|
||||
.setFont("15x32N").setFontAlign(0, 1) // center bottom
|
||||
.drawString(date, x, y-32, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (tooth!==this.tooth) {
|
||||
if (tooth>this.tooth) {
|
||||
for(let t = this.tooth; t<=tooth; t++) { // fill missing teeth
|
||||
fillTooth(t, g.theme.fg2);
|
||||
}
|
||||
} else {
|
||||
for(let t = this.tooth; t>tooth; t--) { // erase extraneous teeth
|
||||
fillTooth(t, g.theme.bg2);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.tooth = tooth;
|
||||
}
|
||||
});
|
||||
clock.start();
|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("mEwwhC/ACcikQXpCQUCC4MgBAgqMCQIXEAgQXNBwIDCAggXOABAXLHwQAHMYQXmmczI5oiCBwUjCwIABmQXDEgJ0KCwMwCwMDDAgyGLYoWBgAXBgAYBMZIXEkYWBC4YYBGAh7FFwgHCC4YEBPRIwCFwYXFGAaqHC56oIIwgXFJAbUJLwpgHI4qPDIwpIFR4wWDLwa6BAAQHDVIYYCC/gYCC453MPIR3HU5gADd5bXHC4rvJMAYAECwJeCd5MjGAjVDC4ZHGNARIFGAgNDFw5IJUogwFC4gwBDAhGBBghIFBQhhBbYguEPAweCDAgACCwZACNg5LFXQYsIC5QAFdg4XcCxJHNBwYTEC6A+BJYQEEC5YYBMYhbCCxo0GCaIXbAHgA="))
|
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"id": "cogclock",
|
||||
"name": "Cog Clock",
|
||||
"version": "0.02",
|
||||
"description": "A cross-shaped clock inside a cog",
|
||||
"icon": "icon.png",
|
||||
"screenshots": [{"url":"screenshot.png"}],
|
||||
"type": "clock",
|
||||
"tags": "clock",
|
||||
"supports": ["BANGLEJS"],
|
||||
"allow_emulator": true,
|
||||
"storage": [
|
||||
{"name":"cogclock.app.js","url":"app.js"},
|
||||
{"name":"cogclock.settings.js","url":"settings.js"},
|
||||
{"name":"cogclock.img","url":"icon.js","evaluate":true}
|
||||
],
|
||||
"data": [
|
||||
{"name": "cogclock.settings.json"}
|
||||
]
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 5.7 KiB |
|
@ -0,0 +1,19 @@
|
|||
(function(back) {
|
||||
let s = require('Storage').readJSON("cogclock.settings.json", true) || {};
|
||||
|
||||
function saver(key) {
|
||||
return value => {
|
||||
s[key] = value;
|
||||
require('Storage').writeJSON("cogclock.settings.json", s);
|
||||
}
|
||||
}
|
||||
|
||||
const menu = {
|
||||
"": {"title": /*LANG*/"Cog Clock"},
|
||||
/*LANG*/"< Back": back,
|
||||
/*LANG*/"Show date": require("ClockFace_menu").showDate(s.showDate, saver('showDate')),
|
||||
/*LANG*/"Load widgets": require("ClockFace_menu").loadWidgets(s.loadWidgets, saver('loadWidgets')),
|
||||
};
|
||||
|
||||
E.showMenu(menu);
|
||||
});
|
|
@ -14,7 +14,7 @@ var nhwmn = { // New homework Menu
|
|||
|
||||
function newHomeworkMenu() {
|
||||
E.showMessage("Getting subjects...");
|
||||
var rawsubjects = require("Storage").read("subjects.txt"); // This code reads out the subjects list and removes the newline character at the end
|
||||
var rawsubjects = require("Storage").read("homework.subjects.txt"); // This code reads out the subjects list and removes the newline character at the end
|
||||
var splitsubjects = rawsubjects.split(",");
|
||||
var lastItem = splitsubjects[splitsubjects.length - 1];
|
||||
var thiscurrentsubject;
|
||||
|
|
|
@ -9,6 +9,10 @@
|
|||
"supports" : ["BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
"custom": "subjects.html",
|
||||
"data": [
|
||||
{"name":"homework.txt" },
|
||||
{"name":"homework.subjects.txt" }
|
||||
],
|
||||
"storage": [
|
||||
{"name":"homework.app.js","url":"app.js"},
|
||||
{"name":"homework.img","url":"app-icon.js","evaluate":true}
|
||||
|
|
|
@ -20,9 +20,10 @@
|
|||
// send finished app (in addition to contents of app.json)
|
||||
sendCustomizedApp({
|
||||
storage:[
|
||||
{name:"subjects.txt"},
|
||||
{name:"homework.subjects.txt", url:"subjects.txt", content:app},
|
||||
]
|
||||
});
|
||||
console.log("Sent homework.subjects.txt!");
|
||||
});
|
||||
|
||||
</script>
|
||||
|
|
|
@ -51,3 +51,4 @@
|
|||
0.36: Ensure a new message plus an almost immediate deletion of that message doesn't load the messages app (fix #1362)
|
||||
0.37: Now use the setUI 'back' icon in the top left rather than specific buttons/menu items
|
||||
0.38: Add telegram foss handling
|
||||
0.39: Don't turn on the screen after unread timeout expires (#1873)
|
||||
|
|
|
@ -411,19 +411,17 @@ function cancelReloadTimeout() {
|
|||
unreadTimeout = undefined;
|
||||
}
|
||||
|
||||
|
||||
g.clear();
|
||||
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
|
||||
setTimeout(() => {
|
||||
var unreadTimeoutSecs = settings.unreadTimeout;
|
||||
if (unreadTimeoutSecs===undefined) unreadTimeoutSecs=60;
|
||||
if (unreadTimeoutSecs)
|
||||
unreadTimeout = setTimeout(function() {
|
||||
print("Message not seen - reloading");
|
||||
load();
|
||||
}, unreadTimeoutSecs*1000);
|
||||
var unreadTimeoutMillis = (settings.unreadTimeout || 60) * 1000;
|
||||
if (unreadTimeoutMillis) {
|
||||
unreadTimeout = setTimeout(load, unreadTimeoutMillis);
|
||||
}
|
||||
// only openMusic on launch if music is new
|
||||
var newMusic = MESSAGES.some(m=>m.id==="music"&&m.new);
|
||||
checkMessages({clockIfNoMsg:0,clockIfAllRead:0,showMsgIfUnread:1,openMusic:newMusic&&settings.openMusic});
|
||||
},10); // if checkMessages wants to 'load', do that
|
||||
var newMusic = MESSAGES.some(m => m.id === "music" && m.new);
|
||||
checkMessages({ clockIfNoMsg: 0, clockIfAllRead: 0, showMsgIfUnread: 1, openMusic: newMusic && settings.openMusic });
|
||||
}, 10); // if checkMessages wants to 'load', do that
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "messages",
|
||||
"name": "Messages",
|
||||
"version": "0.38",
|
||||
"version": "0.39",
|
||||
"description": "App to display notifications from iOS and Gadgetbridge/Android",
|
||||
"icon": "app.png",
|
||||
"type": "app",
|
||||
|
|
|
@ -27,7 +27,6 @@ draw:function(recall) {
|
|||
if (quiet) WIDGETS["messages"].t -= 500000; // if quiet, set last time in the past so there is no buzzing
|
||||
WIDGETS["messages"].width=this.iconwidth;
|
||||
Bangle.drawWidgets();
|
||||
Bangle.setLCDPower(1);// turns screen on
|
||||
},hide:function() {
|
||||
delete WIDGETS["messages"].t;
|
||||
delete WIDGETS["messages"].l;
|
||||
|
|
|
@ -10,3 +10,6 @@
|
|||
0.09: Move some functions to new time_utils module
|
||||
0.10: Default to sched.js if custom js not found
|
||||
0.11: Fix default dow
|
||||
0.12: Update default buzz patterns to new values
|
||||
Improve timer message using formatDuration
|
||||
Fix wrong fallback for buzz pattern
|
||||
|
|
|
@ -106,8 +106,8 @@ exports.getSettings = function () {
|
|||
defaultRepeat: false,
|
||||
buzzCount: 10,
|
||||
buzzIntervalMillis: 3000, // 3 seconds
|
||||
defaultAlarmPattern: "..",
|
||||
defaultTimerPattern: ".."
|
||||
defaultAlarmPattern: "::",
|
||||
defaultTimerPattern: "::"
|
||||
},
|
||||
require("Storage").readJSON("sched.settings.json", true) || {}
|
||||
);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "sched",
|
||||
"name": "Scheduler",
|
||||
"version": "0.11",
|
||||
"version": "0.12",
|
||||
"description": "Scheduling library for alarms and timers",
|
||||
"icon": "app.png",
|
||||
"type": "scheduler",
|
||||
|
|
|
@ -9,7 +9,7 @@ function showAlarm(alarm) {
|
|||
const settings = require("sched").getSettings();
|
||||
|
||||
let msg = "";
|
||||
msg += require("time_utils").formatTime(alarm.timer ? alarm.timer : alarm.t);
|
||||
msg += alarm.timer ? require("time_utils").formatDuration(alarm.timer) : require("time_utils").formatTime(alarm.t);
|
||||
if (alarm.msg) {
|
||||
msg += "\n"+alarm.msg;
|
||||
} else {
|
||||
|
@ -50,7 +50,8 @@ function showAlarm(alarm) {
|
|||
Bangle.setLocked(false);
|
||||
}
|
||||
|
||||
require("buzz").pattern(alarm.vibrate === undefined ? ".." : alarm.vibrate).then(() => {
|
||||
const pattern = alarm.vibrate || (alarm.timer ? settings.defaultTimerPattern : settings.defaultAlarmPattern);
|
||||
require("buzz").pattern(pattern).then(() => {
|
||||
if (buzzCount--) {
|
||||
setTimeout(buzz, settings.buzzIntervalMillis);
|
||||
} else if (alarm.as) { // auto-snooze
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
min: 5,
|
||||
max: 30,
|
||||
step: 5,
|
||||
format: v => v + /*LANG*/" min",
|
||||
format: v => v + /*LANG*/"m",
|
||||
onchange: v => {
|
||||
settings.defaultSnoozeMillis = v * 60000;
|
||||
require("sched").setSettings(settings);
|
||||
|
|
|
@ -51,3 +51,4 @@
|
|||
0.45: Add calibrate battery option
|
||||
0.46: Fix regression after making 'calibrate battery' only for Bangle.js 2
|
||||
0.47: Allow colors to be translated
|
||||
Improve "Turn Off" user experience
|
||||
|
|
|
@ -575,7 +575,25 @@ function showUtilMenu() {
|
|||
} else showUtilMenu();
|
||||
});
|
||||
};
|
||||
menu[/*LANG*/'Turn Off'] = ()=>{ if (Bangle.softOff) Bangle.softOff(); else Bangle.off() };
|
||||
menu[/*LANG*/"Turn Off"] = () => {
|
||||
E.showPrompt(/*LANG*/"Are you sure? Alarms and timers won't fire", {
|
||||
title:/*LANG*/"Turn Off"
|
||||
}).then((confirmed) => {
|
||||
if (confirmed) {
|
||||
E.showMessage(/*LANG*/"See you\nlater!", /*LANG*/"Goodbye");
|
||||
setTimeout(() => {
|
||||
// clear the screen so when the user will turn on the watch they'll see
|
||||
// an empty screen instead of the latest displayed screen
|
||||
E.showMessage();
|
||||
g.clear(true);
|
||||
|
||||
Bangle.softOff ? Bangle.softOff() : Bangle.off();
|
||||
}, 2500);
|
||||
} else {
|
||||
showUtilMenu();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
if (Bangle.factoryReset) {
|
||||
menu[/*LANG*/'Factory Reset'] = ()=>{
|
||||
|
|
|
@ -37,7 +37,7 @@ When the GPS obtains a fix the number of satellites is displayed as 'Sats:nn'. W
|
|||
|
||||
## Power Saving
|
||||
|
||||
The The GPS Adv Sport app obeys the watch screen off timeouts as a power saving measure. Restore the screen as per any of the colck/watch apps. Use BTN2 to lock the screen on but doing this will use more battery.
|
||||
The The GPS Adv Sport app obeys the watch screen off timeouts as a power saving measure. Restore the screen as per any of the clock/watch apps. Use BTN2 to lock the screen on but doing this will use more battery.
|
||||
|
||||
This app will work quite happily on its own but will use the [GPS Setup App](https://banglejs.com/apps/#gps%20setup) if it is installed. You may choose to use the GPS Setup App to gain significantly longer battery life while the GPS is on. Please read the Low Power GPS Setup App Readme to understand what this does.
|
||||
|
||||
|
@ -65,7 +65,7 @@ The Droidscript script file is called : **GPS Adv Sports II.js**
|
|||
|
||||
Start/Stop buttons tell the Bangle.js to start or stop sending BLE data packets to the Android device. While stopped the Bangle.js reverts to full power saving mode when the screen is asleep.
|
||||
|
||||
When runnig a blue 'led' will flash each time a data packet is recieved to refresh the android display.
|
||||
When running a blue 'led' will flash each time a data packet is recieved to refresh the android display.
|
||||
|
||||
An orange 'led' will flash for each reconnection attempt if no data is received for 30 seconds. It will keep trying to reconnect so you can restart the Bangle, run another Bangle app or temprarily turn off bluetooth. The android mirror display will automatically reconnect when the GPS Adv Sports II app is running on the Bangle again. ( Designed to leave the Android device running as the display mirror in a sealed case all day while retaining the ability to do other functions on the Bangle.js and returning to the GPS Speed Alt II app. )
|
||||
|
||||
|
|
|
@ -10,7 +10,8 @@ function ClockFace(options) {
|
|||
"precision",
|
||||
"init", "draw", "update",
|
||||
"pause", "resume",
|
||||
"up", "down", "upDown"
|
||||
"up", "down", "upDown",
|
||||
"settingsFile",
|
||||
].includes(k)) throw `Invalid ClockFace option: ${k}`;
|
||||
});
|
||||
if (!options.draw && !options.update) throw "ClockFace needs at least one of draw() or update() functions";
|
||||
|
@ -33,7 +34,18 @@ function ClockFace(options) {
|
|||
};
|
||||
if (options.upDown) this._upDown = options.upDown;
|
||||
|
||||
this.is12Hour = !!(require("Storage").readJSON("setting.json", 1) || {})["12hour"];
|
||||
if (options.settingsFile) {
|
||||
const settings = (require("Storage").readJSON(options.settingsFile, true) || {});
|
||||
Object.keys(settings).forEach(k => {
|
||||
this[k] = settings[k];
|
||||
});
|
||||
}
|
||||
// these default to true
|
||||
["showDate", "loadWidgets"].forEach(k => {
|
||||
if (this[k]===undefined) this[k] = true;
|
||||
});
|
||||
// use global 24/12-hour setting if not set by clock-settings
|
||||
if (!('is12Hour' in this)) this.is12Hour = !!(require("Storage").readJSON("setting.json", true) || {})["12hour"];
|
||||
}
|
||||
|
||||
ClockFace.prototype.tick = function() {
|
||||
|
@ -46,7 +58,7 @@ ClockFace.prototype.tick = function() {
|
|||
};
|
||||
if (!this._last) {
|
||||
g.clear(true);
|
||||
Bangle.drawWidgets();
|
||||
if (global.WIDGETS) Bangle.drawWidgets();
|
||||
g.reset();
|
||||
this.draw.apply(this, [time, {d: true, h: true, m: true, s: true}]);
|
||||
} else {
|
||||
|
@ -70,7 +82,7 @@ ClockFace.prototype.start = function() {
|
|||
.CLOCK is set by Bangle.setUI('clock') but we want to load widgets so we can check appRect and *then*
|
||||
call setUI. see #1864 */
|
||||
Bangle.CLOCK = 1;
|
||||
Bangle.loadWidgets();
|
||||
if (this.loadWidgets) Bangle.loadWidgets();
|
||||
if (this.init) this.init.apply(this);
|
||||
if (this._upDown) Bangle.setUI("clockupdown", d=>this._upDown.apply(this,[d]));
|
||||
else Bangle.setUI("clock");
|
||||
|
|
|
@ -85,6 +85,7 @@ var clock = new ClockFace({
|
|||
if (dir === -1) // Up
|
||||
else // (dir === 1): Down
|
||||
},
|
||||
settingsFile: 'appid.settings.json', // optional, values from file will be applied to `this`
|
||||
});
|
||||
clock.start();
|
||||
|
||||
|
@ -110,11 +111,51 @@ clock.start();
|
|||
|
||||
```
|
||||
|
||||
|
||||
SettingsFile
|
||||
------------
|
||||
If you use the `settingsFile` option, values from that file are loaded and set
|
||||
directly on the clock.
|
||||
|
||||
For example:
|
||||
|
||||
```json
|
||||
// example.settings.json:
|
||||
{
|
||||
"showDate": false,
|
||||
"foo": 123
|
||||
}
|
||||
```
|
||||
```js
|
||||
var ClockFace = require("ClockFace");
|
||||
var clock = new ClockFace({
|
||||
draw: function(){/*...*/},
|
||||
settingsFile: "example.settings.json",
|
||||
});
|
||||
// now
|
||||
clock.showDate === false;
|
||||
clock.foo === 123;
|
||||
clock.loadWidgets === true; // default when not in settings file
|
||||
clock.is12Hour === ??; // not in settings file: uses global setting
|
||||
clock.start();
|
||||
|
||||
```
|
||||
|
||||
Properties
|
||||
----------
|
||||
The following properties are automatically set on the clock:
|
||||
* `is12Hour`: `true` if the "Time Format" setting is set to "12h", `false` for "24h".
|
||||
* `paused`: `true` while the clock is paused. (You don't need to check this inside your `draw()` code)
|
||||
* `showDate`: `true` (if not overridden through the settings file.)
|
||||
* `loadWidgets`: `true` (if not overridden through the settings file.)
|
||||
If set to `false` before calling `start()`, the clock won't call `Bangle.loadWidgets();` for you.
|
||||
Best is to add a setting for this, but if you never want to load widgets, you could do this:
|
||||
```js
|
||||
var ClockFace = require("ClockFace");
|
||||
var clock = new ClockFace({draw: function(){/*...*/}});
|
||||
clock.loadWidgets = false; // prevent loading of widgets
|
||||
clock.start();
|
||||
```
|
||||
|
||||
Inside the `draw()`/`update()` function you can access these using `this`:
|
||||
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
// boolean options, which default to true
|
||||
exports.showDate =
|
||||
exports.loadWidgets =
|
||||
function(value, callback) {
|
||||
if (value === undefined) value = true;
|
||||
return {
|
||||
value: !!value,
|
||||
onchange: v=>callback(v),
|
||||
};
|
||||
};
|
|
@ -1,14 +1,33 @@
|
|||
/* Call this with a pattern like '.-.', '.. .' or '..' to buzz that pattern
|
||||
out on the internal vibration motor. use buzz_menu to display a menu
|
||||
where the patterns can be chosen. */
|
||||
/**
|
||||
* Buzz the passed `pattern` out on the internal vibration motor.
|
||||
*
|
||||
* A pattern is a sequence of `.`, `,`, `-`, `:`, `;` and `=` where
|
||||
* - `.` is one short and weak vibration
|
||||
* - `,` is one medium and weak vibration
|
||||
* - `-` is one long and weak vibration
|
||||
* - `:` is one short and strong vibration
|
||||
* - `;` is one medium and strong vibration
|
||||
* - `=` is one long and strong vibration
|
||||
*
|
||||
* You can use the `buzz_menu` module to display a menu where some common patterns can be chosen.
|
||||
*
|
||||
* @param {string} pattern A string like `.-.`, `..=`, `:.:`, `..`, etc.
|
||||
* @returns a Promise
|
||||
*/
|
||||
exports.pattern = pattern => new Promise(resolve => {
|
||||
function b() {
|
||||
if (pattern=="") resolve();
|
||||
function doBuzz() {
|
||||
if (pattern == "") resolve();
|
||||
var c = pattern[0];
|
||||
pattern = pattern.substr(1);
|
||||
if (c==".") Bangle.buzz().then(()=>setTimeout(b,100));
|
||||
else if (c=="-") Bangle.buzz(500).then(()=>setTimeout(b,100));
|
||||
else setTimeout(b,100);
|
||||
const BUZZ_WEAK = 0.25, BUZZ_STRONG = 1;
|
||||
const SHORT_MS = 100, MEDIUM_MS = 200, LONG_MS = 500;
|
||||
if (c == ".") Bangle.buzz(SHORT_MS, BUZZ_WEAK).then(() => setTimeout(doBuzz, 100));
|
||||
else if (c == ",") Bangle.buzz(MEDIUM_MS, BUZZ_WEAK).then(() => setTimeout(doBuzz, 100));
|
||||
else if (c == "-") Bangle.buzz(LONG_MS, BUZZ_WEAK).then(() => setTimeout(doBuzz, 100));
|
||||
else if (c == ":") Bangle.buzz(SHORT_MS, BUZZ_STRONG).then(() => setTimeout(doBuzz, 100));
|
||||
else if (c == ";") Bangle.buzz(MEDIUM_MS, BUZZ_STRONG).then(() => setTimeout(doBuzz, 100));
|
||||
else if (c == "=") Bangle.buzz(LONG_MS, BUZZ_STRONG).then(() => setTimeout(doBuzz, 100));
|
||||
else setTimeout(doBuzz, 100);
|
||||
}
|
||||
b();
|
||||
doBuzz();
|
||||
});
|
||||
|
|
|
@ -1,14 +1,19 @@
|
|||
/* Display a menu to select from various vibration patterns for use with buzz.js */
|
||||
|
||||
exports.pattern = function(value, callback) {
|
||||
var vibPatterns = ["", ".", "..", "-", "--", "-.-", "---"];
|
||||
/**
|
||||
* Display a menu to select from various common vibration patterns for use with buzz.js.
|
||||
*
|
||||
* @param {string} value The pre-selected pattern
|
||||
* @param {*} callback A function called with the user selected pattern
|
||||
*/
|
||||
exports.pattern = function (value, callback) {
|
||||
var patterns = ["", ".", ":", "..", "::", ",", ";", ",,", ";;", "-", "=", "--", "==", "...", ":::", "---", ";;;", "==="];
|
||||
return {
|
||||
value: Math.max(0,vibPatterns.indexOf(value)),
|
||||
min: 0, max: vibPatterns.length-1,
|
||||
format: v => vibPatterns[v]||/*LANG*/"Off",
|
||||
value: Math.max(0, patterns.indexOf(value)),
|
||||
min: 0,
|
||||
max: patterns.length - 1,
|
||||
format: v => patterns[v] || /*LANG*/"Off",
|
||||
onchange: v => {
|
||||
require("buzz").pattern(vibPatterns[v]);
|
||||
callback(vibPatterns[v]);
|
||||
require("buzz").pattern(patterns[v]);
|
||||
callback(patterns[v]);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@ exports.decodeTime = (millis) => {
|
|||
*/
|
||||
exports.formatTime = (value) => {
|
||||
var time = safeTime(typeof value === "object" ? value : exports.decodeTime(value));
|
||||
if (time.d != 0) throw "(d)ays not supported here";
|
||||
if (time.d != 0) throw "days not supported here";
|
||||
if (time.h < 0 || time.h > 23) throw "Invalid value: must be 0 <= h <= 23";
|
||||
if (time.m < 0 || time.m > 59) throw "Invalid value: must be 0 <= m <= 59";
|
||||
return time.h + ":" + ("0" + time.m).substr(-2);
|
||||
|
@ -63,16 +63,19 @@ exports.formatTime = (value) => {
|
|||
|
||||
/**
|
||||
* @param {object|int} value {d, h, m, s} object or milliseconds
|
||||
* @returns an human-readable duration string like "3d 1h 10m 45s"
|
||||
* @param {boolean} compact `true` to remove all whitespaces between the values
|
||||
* @returns an human-readable duration string like "3d 1h 10m 45s" (or "3d1h10m45s" if `compact` is `true`)
|
||||
*/
|
||||
exports.formatDuration = (value) => {
|
||||
exports.formatDuration = (value, compact) => {
|
||||
compact = compact || false;
|
||||
var duration = "";
|
||||
var time = safeTime(typeof value === "object" ? value : exports.decodeTime(value));
|
||||
if (time.d > 0) duration += time.d + "d ";
|
||||
if (time.h > 0) duration += time.h + "h ";
|
||||
if (time.m > 0) duration += time.m + "m ";
|
||||
if (time.s > 0) duration += time.s + "s"
|
||||
return duration.trim();
|
||||
duration = duration.trim()
|
||||
return compact ? duration.replace(" ", "") : duration;
|
||||
}
|
||||
|
||||
exports.getCurrentTimeMillis = () => {
|
||||
|
|
Loading…
Reference in New Issue