Add Q Alarm app

pull/865/head
qucchia 2021-10-27 18:54:06 +02:00
parent 375cbf3166
commit 6d72c4480d
9 changed files with 521 additions and 0 deletions

View File

@ -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" }]
}
]

1
apps/qalarm/ChangeLog Normal file
View File

@ -0,0 +1 @@
0.01: First version!

1
apps/qalarm/app-icon.js Normal file
View File

@ -0,0 +1 @@
require("heatshrink").decompress(atob("/wA/AH4A/AH4AF0WiF1wwtF73GB53MAAgkY4wABFqIxPEhQuXGB4vUFxYwMEpBpGBwouNGAwfFF5I1KF6ZQHGAwNLFx4wHF/4v/F/4v/AoYGDF6gaFF5AwHL7QuMBJQvWEpwvxBQ4uRGBAkJT4wuWGBIuIRjKRNF8wwXFy4wWFzIwU53NFzPN5wuR5/PGK4tBDYSNQ5wVCCwIzBAAQoIAAQWGSJ5HFDYYAQIYTCRKRIeBAAYmDAAZsJMCQAbeCAybFiQ0XFTQAIzgAGFcYvz0QAGF84wGF1AwFF1QA/AH4A/ADQ="))

278
apps/qalarm/app.js Normal file
View File

@ -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();

BIN
apps/qalarm/app.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

1
apps/qalarm/boot.js Normal file
View File

@ -0,0 +1 @@
eval(require("Storage").read("qalarmcheck.js"));

157
apps/qalarm/qalarm.js Normal file
View File

@ -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]);
}

View File

@ -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);
}

22
apps/qalarm/widget.js Normal file
View File

@ -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();