mirror of https://github.com/espruino/BangleApps
Add Q Alarm app
parent
375cbf3166
commit
6d72c4480d
19
apps.json
19
apps.json
|
@ -4166,5 +4166,24 @@
|
|||
"storage": [
|
||||
{"name":"swiperclocklaunch.boot.js","url":"boot.js"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "qalarm",
|
||||
"name": "Q Alarm and Timer",
|
||||
"shortName": "Q Alarm",
|
||||
"icon": "app.png",
|
||||
"version": "0.01",
|
||||
"description": "Alarm and timer app with days of week and 'hard' option.",
|
||||
"tags": "tool,alarm,widget",
|
||||
"supports": ["BANGLEJS", "BANGLEJS2"],
|
||||
"storage": [
|
||||
{ "name": "qalarm.app.js", "url": "app.js" },
|
||||
{ "name": "qalarm.boot.js", "url": "boot.js" },
|
||||
{ "name": "qalarm.js", "url": "qalarm.js" },
|
||||
{ "name": "qalarmcheck.js", "url": "qalarmcheck.js" },
|
||||
{ "name": "qalarm.img", "url": "app-icon.js", "evaluate": true },
|
||||
{ "name": "qalarm.wid.js", "url": "widget.js" }
|
||||
],
|
||||
"data": [{ "name": "qalarm.json" }]
|
||||
}
|
||||
]
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
0.01: First version!
|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("/wA/AH4A/AH4AF0WiF1wwtF73GB53MAAgkY4wABFqIxPEhQuXGB4vUFxYwMEpBpGBwouNGAwfFF5I1KF6ZQHGAwNLFx4wHF/4v/F/4v/AoYGDF6gaFF5AwHL7QuMBJQvWEpwvxBQ4uRGBAkJT4wuWGBIuIRjKRNF8wwXFy4wWFzIwU53NFzPN5wuR5/PGK4tBDYSNQ5wVCCwIzBAAQoIAAQWGSJ5HFDYYAQIYTCRKRIeBAAYmDAAZsJMCQAbeCAybFiQ0XFTQAIzgAGFcYvz0QAGF84wGF1AwFF1QA/AH4A/ADQ="))
|
|
@ -0,0 +1,278 @@
|
|||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
|
||||
let alarms = require("Storage").readJSON("qalarm.json", 1) || [];
|
||||
/*
|
||||
Alarm format:
|
||||
{
|
||||
on : true,
|
||||
t : 23400000, // Time of day since midnight in ms
|
||||
msg : "Eat chocolate", // (optional) Must be set manually from the IDE
|
||||
last : 0, // Last day of the month we alarmed on - so we don't alarm twice in one day!
|
||||
rp : true, // Repeat
|
||||
as : false, // Auto snooze
|
||||
hard: true, // Whether the alarm will be like HardAlarm or not
|
||||
timer : 300, // (optional) If set, this is a timer and it's the time in seconds
|
||||
daysOfWeek: [true,true,true,true,true,true,true] // What days of the week the alarm is on. First item is Sunday, 2nd is Monday, etc.
|
||||
}
|
||||
*/
|
||||
|
||||
function formatTime(t) {
|
||||
mins = 0 | (t / 60000) % 60;
|
||||
hrs = 0 | (t / 3600000);
|
||||
return hrs + ":" + ("0" + mins).substr(-2);
|
||||
}
|
||||
|
||||
function formatTimer(t) {
|
||||
mins = 0 | (t / 60) % 60;
|
||||
hrs = 0 | (t / 3600);
|
||||
return hrs + ":" + ("0" + mins).substr(-2);
|
||||
}
|
||||
|
||||
function getCurrentTime() {
|
||||
let time = new Date();
|
||||
return (
|
||||
time.getHours() * 3600000 +
|
||||
time.getMinutes() * 60000 +
|
||||
time.getSeconds() * 1000
|
||||
);
|
||||
}
|
||||
|
||||
function showMainMenu() {
|
||||
const menu = {
|
||||
"": { title: "Alarms" },
|
||||
"New Alarm": () => showEditAlarmMenu(-1),
|
||||
"New Timer": () => showEditTimerMenu(-1),
|
||||
};
|
||||
alarms.forEach((alarm, idx) => {
|
||||
let txt =
|
||||
(alarm.timer ? "TIMER " : "ALARM ") +
|
||||
(alarm.on ? "on " : "off ") +
|
||||
(alarm.timer ? formatTimer(alarm.timer) : formatTime(alarm.t));
|
||||
menu[txt] = function () {
|
||||
if (alarm.timer) showEditTimerMenu(idx);
|
||||
else showEditAlarmMenu(idx);
|
||||
};
|
||||
});
|
||||
menu["< Back"] = () => {
|
||||
load();
|
||||
};
|
||||
|
||||
if (WIDGETS["qalarm"]) WIDGETS["qalarm"].reload();
|
||||
return E.showMenu(menu);
|
||||
}
|
||||
|
||||
function showEditAlarmMenu(alarmIndex, alarm) {
|
||||
const newAlarm = alarmIndex < 0;
|
||||
|
||||
if (!alarm) {
|
||||
if (newAlarm) {
|
||||
alarm = {
|
||||
t: 43200000,
|
||||
on: true,
|
||||
rp: true,
|
||||
as: false,
|
||||
hard: false,
|
||||
daysOfWeek: new Array(7).fill(true),
|
||||
};
|
||||
} else {
|
||||
alarm = Object.assign({}, alarms[alarmIndex]); // Copy object in case we don't save it
|
||||
}
|
||||
}
|
||||
|
||||
let hrs = 0 | (alarm.t / 3600000);
|
||||
let mins = 0 | (alarm.t / 60000) % 60;
|
||||
let secs = 0 | (alarm.t / 1000) % 60;
|
||||
|
||||
const menu = {
|
||||
"": { title: alarm.msg ? alarm.msg : "Alarms" },
|
||||
Hours: {
|
||||
value: hrs,
|
||||
onchange: function (v) {
|
||||
if (v < 0) v = 23;
|
||||
if (v > 23) v = 0;
|
||||
hrs = v;
|
||||
this.value = v;
|
||||
}, // no arrow fn -> preserve 'this'
|
||||
},
|
||||
Minutes: {
|
||||
value: mins,
|
||||
onchange: function (v) {
|
||||
if (v < 0) v = 59;
|
||||
if (v > 59) v = 0;
|
||||
mins = v;
|
||||
this.value = v;
|
||||
}, // no arrow fn -> preserve 'this'
|
||||
},
|
||||
Seconds: {
|
||||
value: secs,
|
||||
onchange: function (v) {
|
||||
if (v < 0) v = 59;
|
||||
if (v > 59) v = 0;
|
||||
secs = v;
|
||||
this.value = v;
|
||||
}, // no arrow fn -> preserve 'this'
|
||||
},
|
||||
Enabled: {
|
||||
value: alarm.on,
|
||||
format: (v) => (v ? "On" : "Off"),
|
||||
onchange: (v) => (alarm.on = v),
|
||||
},
|
||||
Repeat: {
|
||||
value: alarm.rp,
|
||||
format: (v) => (v ? "Yes" : "No"),
|
||||
onchange: (v) => (alarm.rp = v),
|
||||
},
|
||||
"Auto snooze": {
|
||||
value: alarm.as,
|
||||
format: (v) => (v ? "Yes" : "No"),
|
||||
onchange: (v) => (alarm.as = v),
|
||||
},
|
||||
Hard: {
|
||||
value: alarm.hard,
|
||||
format: (v) => (v ? "Yes" : "No"),
|
||||
onchange: (v) => (alarm.hard = v),
|
||||
},
|
||||
"Days of week": () => showDaysMenu(alarmIndex, getAlarm()),
|
||||
};
|
||||
|
||||
function getAlarm() {
|
||||
alarm.t = hrs * 3600000 + mins * 60000 + secs * 1000;
|
||||
|
||||
alarm.last = 0;
|
||||
// If alarm is for tomorrow not today (eg, in the past), set day
|
||||
if (alarm.t < getCurrentTime()) alarm.last = new Date().getDate();
|
||||
|
||||
return alarm;
|
||||
}
|
||||
|
||||
menu["> Save"] = function () {
|
||||
if (newAlarm) alarms.push(getAlarm());
|
||||
else alarms[alarmIndex] = getAlarm();
|
||||
require("Storage").write("qalarm.json", JSON.stringify(alarms));
|
||||
eval(require("Storage").read("qalarmcheck.js"));
|
||||
showMainMenu();
|
||||
};
|
||||
|
||||
if (!newAlarm) {
|
||||
menu["> Delete"] = function () {
|
||||
alarms.splice(alarmIndex, 1);
|
||||
require("Storage").write("qalarm.json", JSON.stringify(alarms));
|
||||
eval(require("Storage").read("qalarmcheck.js"));
|
||||
showMainMenu();
|
||||
};
|
||||
}
|
||||
menu["< Back"] = showMainMenu;
|
||||
return E.showMenu(menu);
|
||||
}
|
||||
|
||||
function showDaysMenu(alarmIndex, alarm) {
|
||||
const menu = {
|
||||
"": { title: alarm.msg ? alarm.msg : "Alarms" },
|
||||
"< Back": () => showEditAlarmMenu(alarmIndex, alarm),
|
||||
};
|
||||
|
||||
[
|
||||
"Sunday",
|
||||
"Monday",
|
||||
"Tuesday",
|
||||
"Wednesday",
|
||||
"Thursday",
|
||||
"Friday",
|
||||
"Saturday",
|
||||
].forEach((dayOfWeek, i) => {
|
||||
menu[dayOfWeek] = {
|
||||
value: alarm.daysOfWeek[i],
|
||||
format: (v) => (v ? "Yes" : "No"),
|
||||
onchange: (v) => (alarm.daysOfWeek[i] = v),
|
||||
};
|
||||
});
|
||||
|
||||
return E.showMenu(menu);
|
||||
}
|
||||
|
||||
function showEditTimerMenu(timerIndex) {
|
||||
var newAlarm = timerIndex < 0;
|
||||
|
||||
let alarm;
|
||||
if (newAlarm) {
|
||||
alarm = {
|
||||
timer: 300,
|
||||
on: true,
|
||||
rp: false,
|
||||
as: false,
|
||||
hard: false,
|
||||
};
|
||||
} else {
|
||||
alarm = alarms[timerIndex];
|
||||
}
|
||||
|
||||
let hrs = 0 | (alarm.timer / 3600);
|
||||
let mins = 0 | (alarm.timer / 60) % 60;
|
||||
let secs = (0 | alarm.timer) % 60;
|
||||
|
||||
const menu = {
|
||||
"": { title: "Timer" },
|
||||
Hours: {
|
||||
value: hrs,
|
||||
onchange: function (v) {
|
||||
if (v < 0) v = 23;
|
||||
if (v > 23) v = 0;
|
||||
hrs = v;
|
||||
this.value = v;
|
||||
}, // no arrow fn -> preserve 'this'
|
||||
},
|
||||
Minutes: {
|
||||
value: mins,
|
||||
onchange: function (v) {
|
||||
if (v < 0) v = 59;
|
||||
if (v > 59) v = 0;
|
||||
mins = v;
|
||||
this.value = v;
|
||||
}, // no arrow fn -> preserve 'this'
|
||||
},
|
||||
Seconds: {
|
||||
value: secs,
|
||||
onchange: function (v) {
|
||||
if (v < 0) v = 59;
|
||||
if (v > 59) v = 0;
|
||||
secs = v;
|
||||
this.value = v;
|
||||
}, // no arrow fn -> preserve 'this'
|
||||
},
|
||||
Enabled: {
|
||||
value: alarm.on,
|
||||
format: (v) => (v ? "On" : "Off"),
|
||||
onchange: (v) => (alarm.on = v),
|
||||
},
|
||||
Hard: {
|
||||
value: alarm.hard,
|
||||
format: (v) => (v ? "On" : "Off"),
|
||||
onchange: (v) => (alarm.hard = v),
|
||||
},
|
||||
};
|
||||
function getTimer() {
|
||||
alarm.timer = hrs * 3600 + mins * 60 + secs;
|
||||
alarm.t = (getCurrentTime() + alarm.timer * 1000) % 86400000;
|
||||
return alarm;
|
||||
}
|
||||
menu["> Save"] = function () {
|
||||
if (newAlarm) alarms.push(getTimer());
|
||||
else alarms[timerIndex] = getTimer();
|
||||
require("Storage").write("qalarm.json", JSON.stringify(alarms));
|
||||
eval(require("Storage").read("qalarmcheck.js"));
|
||||
showMainMenu();
|
||||
};
|
||||
if (!newAlarm) {
|
||||
menu["> Delete"] = function () {
|
||||
alarms.splice(timerIndex, 1);
|
||||
require("Storage").write("qalarm.json", JSON.stringify(alarms));
|
||||
eval(require("Storage").read("qalarmcheck.js"));
|
||||
showMainMenu();
|
||||
};
|
||||
}
|
||||
menu["< Back"] = showMainMenu;
|
||||
return E.showMenu(menu);
|
||||
}
|
||||
|
||||
showMainMenu();
|
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
|
@ -0,0 +1 @@
|
|||
eval(require("Storage").read("qalarmcheck.js"));
|
|
@ -0,0 +1,157 @@
|
|||
// This file shows the alarm
|
||||
|
||||
print("Starting alarm");
|
||||
|
||||
function formatTime(t) {
|
||||
let hrs = Math.floor(t / 3600000);
|
||||
let mins = Math.round((t / 60000) % 60);
|
||||
return hrs + ":" + ("0" + mins).substr(-2);
|
||||
}
|
||||
|
||||
function getCurrentTime() {
|
||||
let time = new Date();
|
||||
return (
|
||||
time.getHours() * 3600000 +
|
||||
time.getMinutes() * 60000 +
|
||||
time.getSeconds() * 1000
|
||||
);
|
||||
}
|
||||
|
||||
function getRandomInt(max) {
|
||||
return Math.floor(Math.random() * Math.floor(max));
|
||||
}
|
||||
|
||||
function getRandomFromRange(
|
||||
lowerRangeMin,
|
||||
lowerRangeMax,
|
||||
higherRangeMin,
|
||||
higherRangeMax
|
||||
) {
|
||||
let lowerRange = lowerRangeMax - lowerRangeMin;
|
||||
let higherRange = higherRangeMax - higherRangeMin;
|
||||
let fullRange = lowerRange + higherRange;
|
||||
let randomNum = getRandomInt(fullRange);
|
||||
if (randomNum <= lowerRangeMax - lowerRangeMin) {
|
||||
return randomNum + lowerRangeMin;
|
||||
} else {
|
||||
return randomNum + (higherRangeMin - lowerRangeMax);
|
||||
}
|
||||
}
|
||||
|
||||
function showNumberPicker(currentGuess, randomNum) {
|
||||
if (currentGuess == randomNum) {
|
||||
E.showMessage("" + currentGuess + "\n PRESS ENTER", "Get to " + randomNum);
|
||||
} else {
|
||||
E.showMessage("" + currentGuess, "Get to " + randomNum);
|
||||
}
|
||||
}
|
||||
|
||||
function showPrompt(msg, buzzCount, alarm) {
|
||||
E.showPrompt(msg, {
|
||||
title: alarm.timer ? "TIMER!" : "ALARM!",
|
||||
buttons: { Sleep: true, Ok: false }, // default is sleep so it'll come back in 10 mins
|
||||
}).then(function (sleep) {
|
||||
buzzCount = 0;
|
||||
if (sleep) {
|
||||
if (alarm.ohr === undefined) alarm.ohr = alarm.t;
|
||||
alarm.t += 10 / 60; // 10 minutes
|
||||
require("Storage").write("qalarm.json", JSON.stringify(alarms));
|
||||
load();
|
||||
} else {
|
||||
alarm.last = new Date().getDate();
|
||||
if (alarm.ohr !== undefined) {
|
||||
alarm.t = alarm.ohr;
|
||||
delete alarm.ohr;
|
||||
}
|
||||
if (!alarm.rp) alarm.on = false;
|
||||
require("Storage").write("qalarm.json", JSON.stringify(alarms));
|
||||
load();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function showAlarm(alarm) {
|
||||
if ((require("Storage").readJSON("setting.json", 1) || {}).quiet > 1) return; // total silence
|
||||
let msg = formatTime(alarm.t);
|
||||
let buzzCount = 20;
|
||||
if (alarm.msg) msg += "\n" + alarm.msg + "!";
|
||||
|
||||
if (alarm.hard) {
|
||||
let okClicked = false;
|
||||
let currentGuess = 10;
|
||||
let randomNum = getRandomFromRange(0, 7, 13, 20);
|
||||
showNumberPicker(currentGuess, randomNum);
|
||||
setWatch(
|
||||
(o) => {
|
||||
if (!okClicked && currentGuess < 20) {
|
||||
currentGuess = currentGuess + 1;
|
||||
showNumberPicker(currentGuess, randomNum);
|
||||
}
|
||||
},
|
||||
BTN1,
|
||||
{ repeat: true, edge: "rising" }
|
||||
);
|
||||
|
||||
setWatch(
|
||||
(o) => {
|
||||
if (currentGuess == randomNum) {
|
||||
okClicked = true;
|
||||
showPrompt(msg, buzzCount, alarm);
|
||||
}
|
||||
},
|
||||
BTN2,
|
||||
{ repeat: true, edge: "rising" }
|
||||
);
|
||||
|
||||
setWatch(
|
||||
(o) => {
|
||||
if (!okClicked && currentGuess > 0) {
|
||||
currentGuess = currentGuess - 1;
|
||||
showNumberPicker(currentGuess, randomNum);
|
||||
}
|
||||
},
|
||||
BTN3,
|
||||
{ repeat: true, edge: "rising" }
|
||||
);
|
||||
} else {
|
||||
showPrompt(msg, buzzCount, alarm);
|
||||
}
|
||||
|
||||
function buzz() {
|
||||
Bangle.buzz(500).then(() => {
|
||||
setTimeout(() => {
|
||||
Bangle.buzz(500).then(function () {
|
||||
setTimeout(() => {
|
||||
Bangle.buzz(2000).then(function () {
|
||||
if (buzzCount--) setTimeout(buzz, 2000);
|
||||
else if (alarm.as) {
|
||||
// auto-snooze
|
||||
buzzCount = 20;
|
||||
setTimeout(buzz, 600000); // 10 minutes
|
||||
}
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
}
|
||||
buzz();
|
||||
}
|
||||
|
||||
let time = new Date();
|
||||
let t = getCurrentTime();
|
||||
let alarms = require("Storage").readJSON("qalarm.json", 1) || [];
|
||||
|
||||
let active = alarms.filter(
|
||||
(alarm) =>
|
||||
alarm.on &&
|
||||
alarm.t < t &&
|
||||
alarm.last != time.getDate() &&
|
||||
(alarm.timer || alarm.daysOfWeek[time.getDay()])
|
||||
);
|
||||
|
||||
print(active);
|
||||
|
||||
if (active.length) {
|
||||
showAlarm(active.sort((a, b) => a.t - b.t)[0]);
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/**
|
||||
* This file checks for upcoming alarms and schedules qalarm.js to deal with them and itself to continue doing these checks.
|
||||
*/
|
||||
|
||||
print("Checking for alarms...");
|
||||
|
||||
clearInterval();
|
||||
|
||||
function getCurrentTime() {
|
||||
let time = new Date();
|
||||
return (
|
||||
time.getHours() * 3600000 +
|
||||
time.getMinutes() * 60000 +
|
||||
time.getSeconds() * 1000
|
||||
);
|
||||
}
|
||||
|
||||
let time = new Date();
|
||||
let t = getCurrentTime();
|
||||
|
||||
let nextAlarms = (require("Storage").readJSON("qalarm.json", 1) || [])
|
||||
.filter(
|
||||
(alarm) =>
|
||||
alarm.on &&
|
||||
alarm.t > t &&
|
||||
alarm.last != time.getDate() &&
|
||||
(alarm.timer || alarm.daysOfWeek[time.getDay()])
|
||||
)
|
||||
.sort((a, b) => a.t - b.t);
|
||||
|
||||
if (nextAlarms[0]) {
|
||||
print("Found alarm, scheduling...", nextAlarms[0].t - t);
|
||||
setTimeout(() => {
|
||||
load("qalarm.js");
|
||||
eval(require("Storage").read("qalarmcheck.js"));
|
||||
}, 3600000 * (nextAlarms[0].t - t));
|
||||
} else {
|
||||
print("No alarms found. Will re-check at midnight.");
|
||||
setTimeout(() => {
|
||||
eval(require("Storage").read("qalarmcheck.js"));
|
||||
}, 86400000 - t);
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
WIDGETS["qalarm"] = {
|
||||
area: "tl",
|
||||
width: 0,
|
||||
draw: function () {
|
||||
if (this.width)
|
||||
g.reset().drawImage(
|
||||
atob(
|
||||
"GBgBAAAAAAAAABgADhhwDDwwGP8YGf+YMf+MM//MM//MA//AA//AA//AA//AA//AA//AB//gD//wD//wAAAAADwAABgAAAAAAAAA"
|
||||
),
|
||||
this.x,
|
||||
this.y
|
||||
);
|
||||
},
|
||||
reload: function () {
|
||||
WIDGETS["qalarm"].width = (
|
||||
require("Storage").readJSON("qalarm.json", 1) || []
|
||||
).some((alarm) => alarm.on)
|
||||
? 24
|
||||
: 0;
|
||||
},
|
||||
};
|
||||
WIDGETS["qalarm"].reload();
|
Loading…
Reference in New Issue