mirror of https://github.com/espruino/BangleApps
Merge branch 'espruino:master' into master
commit
ecf73cd843
|
@ -9,3 +9,4 @@
|
|||
0.09: New app screen (instead of showing settings or the alert) and some optimisations
|
||||
0.10: Add software back button via setUI
|
||||
0.11: Add setting to unlock screen
|
||||
0.12: Fix handling that dates can be given as ms since epoch.
|
||||
|
|
|
@ -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.11",
|
||||
"version":"0.12",
|
||||
"icon": "app.png",
|
||||
"type": "app",
|
||||
"tags": "tool,activity",
|
||||
|
|
|
@ -5,4 +5,5 @@
|
|||
0.05: Improved colors (connected vs disconnected)
|
||||
0.06: Tell clock widgets to hide.
|
||||
0.07: Convert Yes/No On/Off in settings to checkboxes
|
||||
0.08: Fixed typo in settings.js for DRAGDOWN to make option work
|
||||
0.08: Fixed typo in settings.js for DRAGDOWN to make option work
|
||||
0.09: You can now back out of the calendar using the button
|
|
@ -7,23 +7,24 @@ I know that it seems redundant because there already **is** a *time&cal*-app, bu
|
|||
|:--:|:-|
|
||||
||locked: triggers only one minimal update/min|
|
||||
||unlocked: smaller clock, but with seconds|
|
||||
||swipe up for big calendar, (up down to scroll, left/right to exit)|
|
||||
||swipe up for big calendar<br>⬆️/⬇️ to scroll<br> ⬅️/➡️ to exit|
|
||||
|
||||
## Configurable Features
|
||||
- Number of calendar rows (weeks)
|
||||
- Buzz on connect/disconnect (I know, this should be an extra widget, but for now, it is included)
|
||||
- Buzz on connect/disconnect (feel free to disable and use a widget)
|
||||
- Clock Mode (24h/12h). (No am/pm indicator)
|
||||
- First day of the week
|
||||
- Red Saturday/Sunday
|
||||
- Swipe/Drag gestures to launch features or apps.
|
||||
|
||||
## Auto detects your message/music apps:
|
||||
- swiping down will search your files for an app with the string "message" in its filename and launch it. (configurable)
|
||||
- swiping right will search your files for an app with the string "music" in its filename and launch it. (configurable)
|
||||
## Integrated swipe launcher: (Configure in Settings)
|
||||
- ⬇️ (down) will search your files for an app with the string "**message**"
|
||||
- ➡️ (right) will search your files for an app with the string "**music**"
|
||||
- ⬅️ (left) will search your files for an app with the string "**agenda**"
|
||||
- ⬆️ (up) will show the **internal full calendar**
|
||||
|
||||
## Feedback
|
||||
The clock works for me in a 24h/MondayFirst/WeekendFree environment but is not well-tested with other settings.
|
||||
So if something isn't working, please tell me: https://github.com/foostuff/BangleApps/issues
|
||||
If something isn't working, please tell me: https://github.com/Stuff-etc/BangleApps/issues (I moved my github repo)
|
||||
|
||||
## Planned features:
|
||||
- Internal lightweight music control, because switching apps has a loading time.
|
||||
|
|
|
@ -28,11 +28,11 @@ var monthOffset = 0;
|
|||
* Calendar features
|
||||
*/
|
||||
function drawFullCalendar(monthOffset) {
|
||||
addMonths = function (_d, _am) {
|
||||
var ay = 0, m = _d.getMonth(), y = _d.getFullYear();
|
||||
const addMonths = function (_d, _am) {
|
||||
let ay = 0, m = _d.getMonth(), y = _d.getFullYear();
|
||||
while ((m + _am) > 11) { ay++; _am -= 12; }
|
||||
while ((m + _am) < 0) { ay--; _am += 12; }
|
||||
n = new Date(_d.getTime());
|
||||
let n = new Date(_d.getTime());
|
||||
n.setMonth(m + _am);
|
||||
n.setFullYear(y + ay);
|
||||
return n;
|
||||
|
@ -45,7 +45,7 @@ function drawFullCalendar(monthOffset) {
|
|||
if (typeof dayInterval !== "undefined") clearTimeout(dayInterval);
|
||||
if (typeof secondInterval !== "undefined") clearTimeout(secondInterval);
|
||||
if (typeof minuteInterval !== "undefined") clearTimeout(minuteInterval);
|
||||
d = addMonths(Date(), monthOffset);
|
||||
var d = addMonths(Date(), monthOffset);
|
||||
tdy = Date().getDate() + "." + Date().getMonth();
|
||||
newmonth = false;
|
||||
c_y = 0;
|
||||
|
@ -124,7 +124,7 @@ function drawMinutes() {
|
|||
var d = new Date();
|
||||
var hours = s.MODE24 ? d.getHours().toString().padStart(2, ' ') : ((d.getHours() + 24) % 12 || 12).toString().padStart(2, ' ');
|
||||
var minutes = d.getMinutes().toString().padStart(2, '0');
|
||||
var textColor = NRF.getSecurityStatus().connected ? '#99f' : '#fff';
|
||||
var textColor = NRF.getSecurityStatus().connected ? '#fff' : '#f00';
|
||||
var size = 50;
|
||||
var clock_x = (w - 20) / 2;
|
||||
if (dimSeconds) {
|
||||
|
@ -156,7 +156,7 @@ function drawSeconds() {
|
|||
}
|
||||
|
||||
function drawWatch() {
|
||||
if (DEBUG) console.log("CALENDAR");
|
||||
if (DEBUG) console.log("DRAWWATCH");
|
||||
monthOffset = 0;
|
||||
state = "watch";
|
||||
var d = new Date();
|
||||
|
@ -197,6 +197,7 @@ function drawWatch() {
|
|||
if (DEBUG) console.log("Next Day:" + (nextday / 3600));
|
||||
if (typeof dayInterval !== "undefined") clearTimeout(dayInterval);
|
||||
dayInterval = setTimeout(drawWatch, nextday * 1000);
|
||||
if (DEBUG) console.log("ended DRAWWATCH. next refresh in " + nextday + "s");
|
||||
}
|
||||
|
||||
function BTevent() {
|
||||
|
@ -211,8 +212,11 @@ function action(a) {
|
|||
g.reset();
|
||||
if (typeof secondInterval !== "undefined") clearTimeout(secondInterval);
|
||||
if (DEBUG) console.log("action:" + a);
|
||||
state = "unknown";
|
||||
console.log("state -> unknown");
|
||||
switch (a) {
|
||||
case "[ignore]":
|
||||
drawWatch();
|
||||
break;
|
||||
case "[calend.]":
|
||||
drawFullCalendar();
|
||||
|
@ -229,6 +233,12 @@ function action(a) {
|
|||
load(l[0]);
|
||||
} else E.showAlert("Message app not found", "Not found").then(drawWatch);
|
||||
break;
|
||||
case "[AI:agenda]":
|
||||
l = require("Storage").list(RegExp("agenda.*app.js"));
|
||||
if (l.length > 0) {
|
||||
load(l[0]);
|
||||
} else E.showAlert("Agenda app not found", "Not found").then(drawWatch);
|
||||
break;
|
||||
default:
|
||||
l = require("Storage").list(RegExp(a + ".app.js"));
|
||||
if (l.length > 0) {
|
||||
|
@ -276,7 +286,6 @@ function input(dir) {
|
|||
drawWatch();
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -309,3 +318,10 @@ NRF.on('disconnect', BTevent);
|
|||
dimSeconds = Bangle.isLocked();
|
||||
drawWatch();
|
||||
|
||||
setWatch(function() {
|
||||
if (state == "watch") {
|
||||
Bangle.showLauncher()
|
||||
} else if (state == "calendar") {
|
||||
drawWatch();
|
||||
}
|
||||
}, BTN1, {repeat:true, edge:"falling"});
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "clockcal",
|
||||
"name": "Clock & Calendar",
|
||||
"version": "0.08",
|
||||
"version": "0.09",
|
||||
"description": "Clock with Calendar",
|
||||
"readme":"README.md",
|
||||
"icon": "app.png",
|
||||
|
|
|
@ -9,12 +9,12 @@
|
|||
REDSAT: true, // Use red color for saturday?
|
||||
DRAGDOWN: "[AI:messg]",
|
||||
DRAGRIGHT: "[AI:music]",
|
||||
DRAGLEFT: "[ignore]",
|
||||
DRAGLEFT: "[AI:agenda]",
|
||||
DRAGUP: "[calend.]"
|
||||
};
|
||||
settings = Object.assign(defaults, require('Storage').readJSON(FILE, true) || {});
|
||||
|
||||
actions = ["[ignore]","[calend.]","[AI:music]","[AI:messg]"];
|
||||
actions = ["[ignore]","[calend.]","[AI:music]","[AI:messg]","[AI:agenda]"];
|
||||
require("Storage").list(RegExp(".app.js")).forEach(element => actions.push(element.replace(".app.js","")));
|
||||
|
||||
function writeSettings() {
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
0.01: New App!
|
||||
0.02: Added Settings & readme
|
|
@ -0,0 +1,24 @@
|
|||
# Counter2 by Michael
|
||||
|
||||
I needed an HP/XP-Tracker for a game, so i made one.
|
||||
The counter state gets saved. Best to use this with pattern launcher or ClockCal
|
||||
|
||||
- Colored Background Mode
|
||||
- 
|
||||
- Colored Text Mode
|
||||
- 
|
||||
|
||||
## Howto
|
||||
- Tap top side or swipe up to increase counter
|
||||
- Tap bottom side or swipe down to decrease counter
|
||||
- Hold (600ms) to reset to default value (configurable)
|
||||
- Press button to exit
|
||||
|
||||
## Configurable Features
|
||||
- Default value Counter 1
|
||||
- Default value Counter 2
|
||||
- Buzz on interact
|
||||
- Colored Text/Background
|
||||
|
||||
## Feedback
|
||||
If something isn't working, please tell me: https://github.com/Stuff-etc/BangleApps/issues
|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("mEwwcAyVJkgCFAwwCBAgd5CI+eCI2T/IRH/wR7n//AAPyCIdPBAX8CKpr/CLTpSCOipB8gRFXoPJCIknCJAIBOoYRCagLNCa4f8Q4gREI4tP8mT/41HCKJHFGoQRG+QKBLI4RHLIx9CCJ7zBGpxZCPoyhQYpIIBYor7kCP4R8YoX/WY69DAIM/BAT+BdIYICeYQRTGqKP/CNIA=="))
|
|
@ -0,0 +1,96 @@
|
|||
Bangle.loadWidgets();
|
||||
|
||||
var s = Object.assign({
|
||||
counter0:10,
|
||||
counter1:20,
|
||||
max0:15,
|
||||
max1:25,
|
||||
buzz: true,
|
||||
colortext: true,
|
||||
}, require('Storage').readJSON("counter2.json", true) || {});
|
||||
|
||||
f1 = (s.colortext) ? "#f00" : "#fff";
|
||||
f2 = (s.colortext) ? "#00f" : "#fff";
|
||||
b1 = (s.colortext) ? g.theme.bg : "#f00";
|
||||
b2 = (s.colortext) ? g.theme.bg : "#00f";
|
||||
|
||||
var counter = 0;
|
||||
var drag;
|
||||
|
||||
screenwidth = g.getWidth();
|
||||
screenheight = g.getHeight();
|
||||
halfwidth = screenwidth / 2;
|
||||
halfheight = screenheight / 2;
|
||||
|
||||
counter = [];
|
||||
counter[0] = s.counter0;
|
||||
counter[1] = s.counter1;
|
||||
defaults = [];
|
||||
defaults[0] = s.max0;
|
||||
defaults[1] = s.max1;
|
||||
|
||||
function saveSettings() {
|
||||
s.counter0 = counter[0];
|
||||
s.counter1 = counter[1];
|
||||
s.max0 = defaults[0];
|
||||
s.max1 = defaults[1];
|
||||
require('Storage').writeJSON("counter2.json", s);
|
||||
}
|
||||
|
||||
ignoreonce = false;
|
||||
var dragtimeout;
|
||||
|
||||
function updateScreen() {
|
||||
g.setBgColor(b1);
|
||||
g.clearRect(0, 0, halfwidth, screenheight);
|
||||
g.setBgColor(b2);
|
||||
g.clearRect(halfwidth, 0, screenwidth, screenheight);
|
||||
g.setFont("Vector", 60).setFontAlign(0, 0);
|
||||
g.setColor(f1);
|
||||
g.drawString(Math.floor(counter[0]), halfwidth * 0.5, halfheight);
|
||||
g.setColor(f2);
|
||||
g.drawString(Math.floor(counter[1]), halfwidth * 1.5, halfheight);
|
||||
saveSettings();
|
||||
if (s.buzz) Bangle.buzz(50,.5);
|
||||
Bangle.drawWidgets();
|
||||
}
|
||||
|
||||
Bangle.on("drag", e => {
|
||||
c = (e.x < halfwidth) ? 0 : 1;
|
||||
if (!drag) {
|
||||
if (ignoreonce) {
|
||||
ignoreonce = false;
|
||||
return;
|
||||
}
|
||||
drag = { x: e.x, y: e.y };
|
||||
dragtimeout = setTimeout(function () { resetcounter(c); }, 600); //if dragging for 500ms, reset counter
|
||||
}
|
||||
else if (drag && !e.b) { // released
|
||||
adjust = 0;
|
||||
const dx = e.x - drag.x, dy = e.y - drag.y;
|
||||
if (Math.abs(dy) > Math.abs(dx) + 30) {
|
||||
adjust = (dy > 0) ? -1 : 1;
|
||||
} else {
|
||||
adjust = (e.y > halfwidth) ? -1 : 1;
|
||||
}
|
||||
counter[c] += adjust;
|
||||
updateScreen();
|
||||
drag = undefined;
|
||||
clearTimeout(dragtimeout);
|
||||
}
|
||||
});
|
||||
|
||||
function resetcounter(which) {
|
||||
counter[which] = defaults[which];
|
||||
console.log("resetting counter ", which);
|
||||
updateScreen();
|
||||
drag = undefined;
|
||||
ignoreonce = true;
|
||||
}
|
||||
|
||||
|
||||
updateScreen();
|
||||
|
||||
setWatch(function() {
|
||||
load();
|
||||
}, BTN1, {repeat:true, edge:"falling"});
|
Binary file not shown.
After Width: | Height: | Size: 2.4 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.8 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.7 KiB |
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"id": "counter2",
|
||||
"name": "Counter2",
|
||||
"version": "0.02",
|
||||
"description": "Dual Counter",
|
||||
"readme":"README.md",
|
||||
"icon": "counter2-icon.png",
|
||||
"tags": "tool",
|
||||
"supports": ["BANGLEJS2"],
|
||||
"screenshots": [{"url":"counter2-screenshot.png"},{"url":"counter2dark-screenshot.png"}],
|
||||
"allow_emulator": true,
|
||||
"storage": [
|
||||
{"name":"counter2.app.js","url":"app.js"},
|
||||
{"name":"counter2.settings.js","url":"settings.js"},
|
||||
{"name":"counter2.img","url":"app-icon.js","evaluate":true}
|
||||
],
|
||||
"data": [{"name":"counter2.json"}]
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
(function (back) {
|
||||
var FILE = "counter2.json";
|
||||
defaults={
|
||||
counter0:12,
|
||||
counter1:0,
|
||||
max0:12,
|
||||
max1:0,
|
||||
buzz: true,
|
||||
colortext: true,
|
||||
};
|
||||
settings = Object.assign(defaults, require('Storage').readJSON(FILE, true) || {});
|
||||
|
||||
function writeSettings() {
|
||||
require('Storage').writeJSON(FILE, settings);
|
||||
}
|
||||
|
||||
menu = {
|
||||
"": { "title": "Counter2" },
|
||||
"< Back": () => back(),
|
||||
'Default C1': {
|
||||
value: settings[0],
|
||||
min: -99, max: 99,
|
||||
onchange: v => {
|
||||
settings.max0 = v;
|
||||
writeSettings();
|
||||
}
|
||||
},
|
||||
'Default C2': {
|
||||
value: settings[2],
|
||||
min: -99, max: 99,
|
||||
onchange: v => {
|
||||
settings.max1 = v;
|
||||
writeSettings();
|
||||
}
|
||||
},
|
||||
'Color': {
|
||||
value: settings.colortext,
|
||||
format: v => v?"Text":"Backg",
|
||||
onchange: v => {
|
||||
settings.colortext = v;
|
||||
console.log("Color",v);
|
||||
writeSettings();
|
||||
}
|
||||
},
|
||||
'Vibrate': {
|
||||
value: settings.buzz,
|
||||
onchange: v => {
|
||||
settings.buzz = v;
|
||||
writeSettings();
|
||||
}
|
||||
}
|
||||
};
|
||||
// Show the menu
|
||||
E.showMenu(menu);
|
||||
});
|
|
@ -1,11 +1,17 @@
|
|||
#### ⚠️EXPERIMENTAL⚠️
|
||||
|
||||
# Fastload Utils
|
||||
|
||||
*EXPERIMENTAL* Use this with caution. When you find something misbehaving please check if the problem actually persists when removing this app.
|
||||
Use this with caution. When you find something misbehaving please check if the problem actually persists when removing this app.
|
||||
|
||||
This allows fast loading of all apps with two conditions:
|
||||
* Loaded app contains `Bangle.loadWidgets`. This is needed to prevent problems with apps not expecting widgets to be already loaded.
|
||||
* Current app can be removed completely from RAM.
|
||||
|
||||
#### ⚠️ KNOWN ISSUES ⚠️
|
||||
|
||||
* Fastload currently does not play nice with the automatic reload option of the apploader. App installs and upgrades are unreliable since the fastload causes code to run after reset and interfere with the upload process.
|
||||
|
||||
## Settings
|
||||
|
||||
* Activate app history and navigate back through recent apps instead of immediately loading the clock face
|
||||
|
|
|
@ -59,13 +59,6 @@ module.exports = {
|
|||
"no-unused-vars"
|
||||
]
|
||||
},
|
||||
"sleeplog/settings.js": {
|
||||
"hash": "bd5e3e1382321df6682ef1cb718b0e15ab355422bef77278eb086f213f643021",
|
||||
"rules": [
|
||||
"no-unused-vars",
|
||||
"no-undef"
|
||||
]
|
||||
},
|
||||
"showimg/app.js": {
|
||||
"hash": "71cbbaa488e2d08c5bf28f7d56178d5e7694eb9761cd4752bbc9733e825d4bcf",
|
||||
"rules": [
|
||||
|
@ -276,13 +269,6 @@ module.exports = {
|
|||
"no-undef"
|
||||
]
|
||||
},
|
||||
"sleeplog/app.js": {
|
||||
"hash": "336da552e4b04677447cf76a253b40bc259a597ea11d455121933f93afe99794",
|
||||
"rules": [
|
||||
"no-unused-vars",
|
||||
"no-undef"
|
||||
]
|
||||
},
|
||||
"qmsched/app.js": {
|
||||
"hash": "4b7dbabed6c252021531d6b0449c16a3adc2e405f2ddda33ca0a65f5fa42c663",
|
||||
"rules": [
|
||||
|
@ -562,13 +548,6 @@ module.exports = {
|
|||
"no-undef"
|
||||
]
|
||||
},
|
||||
"sleeplog/lib.js": {
|
||||
"hash": "755e0d4c02b92181281fd6990df39c9446c73ff896b50b64d7e14cb1c0188556",
|
||||
"rules": [
|
||||
"no-unused-vars",
|
||||
"no-undef"
|
||||
]
|
||||
},
|
||||
"doztime/app-bangle1.js": {
|
||||
"hash": "1e9598c201175180ae77d1c3bc47e8138b339b72eb58782b5057fb7aefdc88a1",
|
||||
"rules": [
|
||||
|
@ -666,12 +645,6 @@ module.exports = {
|
|||
"no-undef"
|
||||
]
|
||||
},
|
||||
"taglaunch/app.js": {
|
||||
"hash": "944689f0600e59bbe4d9e5e2684baeefabe4457a6edd938aae451dc4cd659ad3",
|
||||
"rules": [
|
||||
"no-undef"
|
||||
]
|
||||
},
|
||||
"tabanchi/app.js": {
|
||||
"hash": "6ad6dc1d6b0f539f9f659d5773b5a26d19eb6dacafe7b4682469e6f3c412647e",
|
||||
"rules": [
|
||||
|
@ -762,12 +735,6 @@ module.exports = {
|
|||
"no-undef"
|
||||
]
|
||||
},
|
||||
"sleeplog/boot.js": {
|
||||
"hash": "b4c9d8e3c3e7cdf44ea10e29a9e3b53f958b86c21ca91d88e4efb85901c3bde9",
|
||||
"rules": [
|
||||
"no-undef"
|
||||
]
|
||||
},
|
||||
"scicalc/app.js": {
|
||||
"hash": "416c7b2eb12a5d10bcc3a99d89d8f6f54ecd2b47cce2d1f4d55c3e3bc602b31a",
|
||||
"rules": [
|
||||
|
@ -798,12 +765,6 @@ module.exports = {
|
|||
"no-undef"
|
||||
]
|
||||
},
|
||||
"ratchet_launch/app.js": {
|
||||
"hash": "592d432301d7836aa54e288d465ae8952ecb891d628f824ea9f62479a2a01631",
|
||||
"rules": [
|
||||
"no-undef"
|
||||
]
|
||||
},
|
||||
"rclock/rclock.app.js": {
|
||||
"hash": "8e698787730601a1bba71aff03204c2adfaf7eeb77b35dc706534755f63f613b",
|
||||
"rules": [
|
||||
|
|
|
@ -104,3 +104,4 @@
|
|||
0.75: Handle text with images in messages list by just displaying the first line
|
||||
0.76: Swipe up/down on a shown message to show the next newer/older message.
|
||||
0.77: Messages can now use international fonts if they are installed
|
||||
0.78: Fix: When user taps on a new message, clear the unread timeout
|
||||
|
|
|
@ -233,6 +233,7 @@ function showMusicMessage(msg) {
|
|||
}
|
||||
|
||||
function showMessageScroller(msg) {
|
||||
cancelReloadTimeout();
|
||||
active = "scroller";
|
||||
var bodyFont = fontBig;
|
||||
g.setFont(bodyFont);
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"id": "messagegui",
|
||||
"name": "Message UI",
|
||||
"shortName": "Messages",
|
||||
"version": "0.77",
|
||||
"version": "0.78",
|
||||
"description": "Default app to display notifications from iOS and Gadgetbridge/Android",
|
||||
"icon": "app.png",
|
||||
"type": "app",
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
0.01: Initial release
|
||||
0.02: Cache the app-launch info
|
||||
0.03: Fix bugs that would make the launcher unusable on most watches
|
||||
|
|
|
@ -5,13 +5,13 @@ var font = g.getFonts().includes("6x15") ? "6x15" : "6x8:2";
|
|||
var largeFont = g.getFonts().includes("12x20") ? "12x20" : "6x8:3";
|
||||
var currentApp = 0;
|
||||
var overscroll = 0;
|
||||
var blankImage = Graphics.createImage(` `);
|
||||
var blankImage = Graphics.createImage(`\n \n`);
|
||||
var rowHeight = g.getHeight()/3;
|
||||
|
||||
// Load apps list
|
||||
var apps;
|
||||
|
||||
var launchCache = s.readJSON("launch.cache.json", true)||{};
|
||||
var launchCache = Storage.readJSON("launch.cache.json", true)||{};
|
||||
var launchHash = require("Storage").hash(/\.info/);
|
||||
if (launchCache.hash==launchHash) {
|
||||
apps = launchCache.apps;
|
||||
|
@ -39,7 +39,7 @@ if (launchCache.hash==launchHash) {
|
|||
});
|
||||
|
||||
launchCache = { apps, hash: launchHash };
|
||||
s.writeJSON("launch.cache.json", launchCache);
|
||||
Storage.writeJSON("launch.cache.json", launchCache);
|
||||
}
|
||||
|
||||
// Uncomment for testing in the emulator without apps:
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"id": "ratchet_launch",
|
||||
"name": "Ratchet Launcher",
|
||||
"shortName": "Ratchet",
|
||||
"version": "0.02",
|
||||
"version": "0.03",
|
||||
"description": "Launcher with discrete scrolling for quicker app selection",
|
||||
"icon": "app.png",
|
||||
"type": "launch",
|
||||
|
|
|
@ -12,3 +12,4 @@
|
|||
0.14: Add "Delete all logfiles before" to interface.html, display all logfiles in the interface
|
||||
0.15: Issue newline before GB commands (solves issue with console.log and ignored commands)
|
||||
0.16: Only write logs if we have a non-empty log to write
|
||||
0.17: Minor code improvements
|
||||
|
|
|
@ -245,13 +245,13 @@ function draw() {
|
|||
g.reset();
|
||||
var imgStr = "";
|
||||
// check which icon to set
|
||||
if (!global.sleeplog || sleeplog.conf.enabled !== true) {
|
||||
if (!global.sleeplog || global.sleeplog.conf.enabled !== true) {
|
||||
// set color and disabled service icon
|
||||
g.setColor(1, 0, 0);
|
||||
imgStr = "FBSBAOAAfwAP+AH3wD4+B8Hw+A+fAH/gA/wAH4AB+AA/wAf+APnwHw+D4Hx8A++AH/AA/gAH";
|
||||
} else if (sleeplog.debug) {
|
||||
} else if (global.sleeplog.debug) {
|
||||
// set debugging icon
|
||||
imgStr = typeof sleeplog.debug === "object" ?
|
||||
imgStr = typeof global.sleeplog.debug === "object" ?
|
||||
"FBSBAB/4AQDAF+4BfvAX74F+CBf+gX/oFJKBf+gUkoF/6BSSgX/oFJ6Bf+gX/oF/6BAAgf/4" : // file
|
||||
"FBSBAP//+f/V///4AAGAABkAAZgAGcABjgAYcAGDgBhwAY4AGcABmH+ZB/mAABgAAYAAH///"; // console
|
||||
}
|
||||
|
@ -297,7 +297,7 @@ var ATID; // analysis timeout ID
|
|||
var drawingID = 0; // drawing ID for ongoing process
|
||||
// get screen width and center (zero based)
|
||||
var width = g.getWidth() - 1;
|
||||
var center = width / 2 - 1;
|
||||
//var center = width / 2 - 1;
|
||||
|
||||
// set areas and actions array
|
||||
var aaa = [
|
||||
|
|
|
@ -18,14 +18,14 @@ global.sleeplog = {
|
|||
};
|
||||
|
||||
// check if service is enabled
|
||||
if (sleeplog.conf.enabled) {
|
||||
if (global.sleeplog.conf.enabled) {
|
||||
// assign functions to global object
|
||||
global.sleeplog = Object.assign({
|
||||
// define function to initialy start or restart the service
|
||||
start: function() {
|
||||
// add kill and health listener
|
||||
E.on('kill', sleeplog.saveStatus);
|
||||
Bangle.on('health', sleeplog.health);
|
||||
E.on('kill', global.sleeplog.saveStatus);
|
||||
Bangle.on('health', global.sleeplog.health);
|
||||
|
||||
// restore saved status
|
||||
this.restoreStatus();
|
||||
|
@ -34,8 +34,8 @@ if (sleeplog.conf.enabled) {
|
|||
// define function to stop the service, it will be restarted on reload if enabled
|
||||
stop: function() {
|
||||
// remove all listeners
|
||||
Bangle.removeListener('health', sleeplog.health);
|
||||
E.removeListener('kill', sleeplog.saveStatus);
|
||||
Bangle.removeListener('health', global.sleeplog.health);
|
||||
E.removeListener('kill', global.sleeplog.saveStatus);
|
||||
|
||||
// save active values
|
||||
this.saveStatus();
|
||||
|
@ -122,11 +122,11 @@ if (sleeplog.conf.enabled) {
|
|||
if (!global.sleeplog) return new Error("sleeplog: Can't save status, global object missing!");
|
||||
|
||||
// check saveUpToDate is not set or forced
|
||||
if (!sleeplog.info.saveUpToDate || force) {
|
||||
if (!global.sleeplog.info.saveUpToDate || force) {
|
||||
// save status, consecutive status and info timestamps to restore on reload
|
||||
var save = [sleeplog.info.lastCheck, sleeplog.info.awakeSince, sleeplog.info.asleepSince];
|
||||
var save = [global.sleeplog.info.lastCheck, global.sleeplog.info.awakeSince, global.sleeplog.info.asleepSince];
|
||||
// add debuging status if active
|
||||
if (sleeplog.debug) save.push(sleeplog.debug.writeUntil, sleeplog.debug.fileid);
|
||||
if (global.sleeplog.debug) save.push(global.sleeplog.debug.writeUntil, global.sleeplog.debug.fileid);
|
||||
|
||||
// stringify entries
|
||||
save = "," + save.map((entry, index) => {
|
||||
|
@ -135,8 +135,8 @@ if (sleeplog.conf.enabled) {
|
|||
}).join(",") + "\n";
|
||||
|
||||
// add present status if forced
|
||||
if (force) save = (sleeplog.info.lastChange / 6E5) + "," +
|
||||
sleeplog.status + "," + sleeplog.consecutive + "\n" + save;
|
||||
if (force) save = (global.sleeplog.info.lastChange / 6E5) + "," +
|
||||
global.sleeplog.status + "," + global.sleeplog.consecutive + "\n" + save;
|
||||
|
||||
// append saved data to StorageFile
|
||||
require("Storage").open("sleeplog.log", "a").write(save);
|
||||
|
@ -161,20 +161,20 @@ if (sleeplog.conf.enabled) {
|
|||
// add preliminary status depending on charging and movement thresholds
|
||||
// 1 = not worn, 2 = awake, 3 = light sleep, 4 = deep sleep
|
||||
data.status = Bangle.isCharging() ? 1 :
|
||||
data.movement <= sleeplog.conf.deepTh ? 4 :
|
||||
data.movement <= sleeplog.conf.lightTh ? 3 : 2;
|
||||
data.movement <= global.sleeplog.conf.deepTh ? 4 :
|
||||
data.movement <= global.sleeplog.conf.lightTh ? 3 : 2;
|
||||
|
||||
// check if changing to deep sleep from non sleeping
|
||||
if (data.status === 4 && sleeplog.status <= 2) {
|
||||
sleeplog.checkIsWearing((isWearing, data) => {
|
||||
if (data.status === 4 && global.sleeplog.status <= 2) {
|
||||
global.sleeplog.checkIsWearing((isWearing, data) => {
|
||||
// correct status
|
||||
if (!isWearing) data.status = 1;
|
||||
// set status
|
||||
sleeplog.setStatus(data);
|
||||
global.sleeplog.setStatus(data);
|
||||
}, data);
|
||||
} else {
|
||||
// set status
|
||||
sleeplog.setStatus(data);
|
||||
global.sleeplog.setStatus(data);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -185,7 +185,7 @@ if (sleeplog.conf.enabled) {
|
|||
}
|
||||
|
||||
// create a temporary object to store data and functions
|
||||
global.tmpWearingCheck = {
|
||||
const tmpWearingCheck = {
|
||||
// define temporary hrm listener function to read the wearing status
|
||||
hrmListener: hrm => tmpWearingCheck.isWearing = hrm.isWearing,
|
||||
// set default wearing status
|
||||
|
@ -195,22 +195,18 @@ if (sleeplog.conf.enabled) {
|
|||
// enable HRM
|
||||
Bangle.setHRMPower(true, "wearingCheck");
|
||||
// wait until HRM is initialised
|
||||
setTimeout((returnFn, data) => {
|
||||
setTimeout((returnFn, data, tmpWearingCheck) => {
|
||||
// add HRM listener
|
||||
Bangle.on('HRM-raw', tmpWearingCheck.hrmListener);
|
||||
// wait for two cycles (HRM working on 60Hz)
|
||||
setTimeout((returnFn, data) => {
|
||||
setTimeout((returnFn, data, tmpWearingCheck) => {
|
||||
// remove listener and disable HRM
|
||||
Bangle.removeListener('HRM-raw', tmpWearingCheck.hrmListener);
|
||||
Bangle.setHRMPower(false, "wearingCheck");
|
||||
// cache wearing status
|
||||
var isWearing = tmpWearingCheck.isWearing;
|
||||
// clear temporary object
|
||||
delete global.tmpWearingCheck;
|
||||
// call return function with status
|
||||
returnFn(isWearing, data);
|
||||
}, 34, returnFn, data);
|
||||
}, 2500, returnFn, data);
|
||||
returnFn(tmpWearingCheck.isWearing, data);
|
||||
}, 34, returnFn, data, tmpWearingCheck);
|
||||
}, 2500, returnFn, data, tmpWearingCheck);
|
||||
},
|
||||
|
||||
// define function to set the status
|
||||
|
@ -361,7 +357,7 @@ if (sleeplog.conf.enabled) {
|
|||
|
||||
// define trigger object
|
||||
trigger: {}
|
||||
}, sleeplog);
|
||||
}, global.sleeplog);
|
||||
|
||||
// initial starting
|
||||
global.sleeplog.start();
|
||||
|
|
|
@ -3,7 +3,7 @@ exports = {
|
|||
// define en-/disable function, restarts the service to make changes take effect
|
||||
setEnabled: function(enable) {
|
||||
// stop if enabled
|
||||
if (global.sleeplog && sleeplog.enabled) sleeplog.stop();
|
||||
if (global.sleeplog && global.sleeplog.enabled) global.sleeplog.stop();
|
||||
|
||||
// define settings filename
|
||||
var settings = "sleeplog.json";
|
||||
|
@ -138,7 +138,7 @@ exports = {
|
|||
}
|
||||
|
||||
// define last index
|
||||
var lastIndex = log.length - 1;
|
||||
//var lastIndex = log.length - 1;
|
||||
// set timestamp of first entry to since if first entry before since
|
||||
if (log[0] && log[0][0] < since) log[0][0] = since;
|
||||
// add timestamp at now with unknown status if until after now
|
||||
|
@ -251,7 +251,7 @@ exports = {
|
|||
// set default date or correct date type if needed
|
||||
if (!date || !date.getDay) date = date ? new Date(date) : new Date();
|
||||
// set default ToD as set in sleeplog.conf or settings if available
|
||||
if (ToD === undefined) ToD = (global.sleeplog && sleeplog.conf ? sleeplog.conf.breakToD :
|
||||
if (ToD === undefined) ToD = (global.sleeplog && global.sleeplog.conf ? global.sleeplog.conf.breakToD :
|
||||
(require("Storage").readJSON("sleeplog.json", true) || {}).breakToD) || 12;
|
||||
// calculate last break time and return
|
||||
return new Date(date.getFullYear(), date.getMonth(), date.getDate(), ToD);
|
||||
|
@ -274,24 +274,24 @@ exports = {
|
|||
|
||||
// check if nothing has to be changed
|
||||
if (!duration &&
|
||||
(enable && sleeplog.debug === true) ||
|
||||
(!enable && !sleeplog.debug)) return;
|
||||
(enable && global.sleeplog.debug === true) ||
|
||||
(!enable && !global.sleeplog.debug)) return;
|
||||
|
||||
// check if en- or disable debugging
|
||||
if (enable) {
|
||||
// define debug object
|
||||
sleeplog.debug = {};
|
||||
global.sleeplog.debug = {};
|
||||
|
||||
// check if a file should be generated
|
||||
if (typeof duration === "number") {
|
||||
// check duration boundaries, 0 => 8
|
||||
duration = duration > 96 ? 96 : duration || 12;
|
||||
// calculate and set writeUntil in 10min steps
|
||||
sleeplog.debug.writeUntil = ((Date.now() / 6E5 | 0) + duration * 6) * 6E5;
|
||||
global.sleeplog.debug.writeUntil = ((Date.now() / 6E5 | 0) + duration * 6) * 6E5;
|
||||
// set fileid to "{hours since 1970}"
|
||||
sleeplog.debug.fileid = Date.now() / 36E5 | 0;
|
||||
global.sleeplog.debug.fileid = Date.now() / 36E5 | 0;
|
||||
// write csv header on empty file
|
||||
var file = require("Storage").open("sleeplog_" + sleeplog.debug.fileid + ".csv", "a");
|
||||
var file = require("Storage").open("sleeplog_" + global.sleeplog.debug.fileid + ".csv", "a");
|
||||
if (!file.getLength()) file.write(
|
||||
"timestamp,movement,status,consecutive,asleepSince,awakeSince,bpm,bpmConfidence\n"
|
||||
);
|
||||
|
@ -299,21 +299,21 @@ exports = {
|
|||
file = undefined;
|
||||
} else {
|
||||
// set debug as active
|
||||
sleeplog.debug = true;
|
||||
global.sleeplog.debug = true;
|
||||
}
|
||||
} else {
|
||||
// disable debugging
|
||||
delete sleeplog.debug;
|
||||
delete global.sleeplog.debug;
|
||||
}
|
||||
|
||||
// save status forced
|
||||
sleeplog.saveStatus(true);
|
||||
global.sleeplog.saveStatus(true);
|
||||
},
|
||||
|
||||
// define debugging function, called after logging if debug is set
|
||||
debug: function(data) {
|
||||
// check if global variable accessable and debug active
|
||||
if (!global.sleeplog || !sleeplog.debug) return;
|
||||
if (!global.sleeplog || !global.sleeplog.debug) return;
|
||||
|
||||
// set functions to convert timestamps
|
||||
function localTime(timestamp) {
|
||||
|
@ -328,10 +328,10 @@ exports = {
|
|||
var console = "sleeplog: " +
|
||||
localTime(data.timestamp) + " > " +
|
||||
"movement: " + ("" + data.movement).padStart(4) + ", " +
|
||||
"unknown ,non consec.,consecutive".split(",")[sleeplog.consecutive] + " " +
|
||||
"unknown ,non consec.,consecutive".split(",")[global.sleeplog.consecutive] + " " +
|
||||
"unknown,not worn,awake,light sleep,deep sleep".split(",")[data.status].padEnd(12) + ", " +
|
||||
"asleep since: " + localTime(sleeplog.info.asleepSince) + ", " +
|
||||
"awake since: " + localTime(sleeplog.info.awakeSince);
|
||||
"asleep since: " + localTime(global.sleeplog.info.asleepSince) + ", " +
|
||||
"awake since: " + localTime(global.sleeplog.info.awakeSince);
|
||||
// add bpm if set
|
||||
if (data.bpm) console += ", " +
|
||||
"bpm: " + ("" + data.bpm).padStart(3) + ", " +
|
||||
|
@ -340,24 +340,24 @@ exports = {
|
|||
print(console);
|
||||
|
||||
// check if debug is set as object with a file id and it is not past writeUntil
|
||||
if (typeof sleeplog.debug === "object" && sleeplog.debug.fileid &&
|
||||
Date.now() < sleeplog.debug.writeUntil) {
|
||||
if (typeof global.sleeplog.debug === "object" && global.sleeplog.debug.fileid &&
|
||||
Date.now() < global.sleeplog.debug.writeUntil) {
|
||||
// generate next csv line
|
||||
var csv = [
|
||||
officeTime(data.timestamp),
|
||||
data.movement,
|
||||
data.status,
|
||||
sleeplog.consecutive,
|
||||
sleeplog.info.asleepSince ? officeTime(sleeplog.info.asleepSince) : "",
|
||||
sleeplog.info.awakeSince ? officeTime(sleeplog.info.awakeSince) : "",
|
||||
global.sleeplog.consecutive,
|
||||
global.sleeplog.info.asleepSince ? officeTime(global.sleeplog.info.asleepSince) : "",
|
||||
global.sleeplog.info.awakeSince ? officeTime(global.sleeplog.info.awakeSince) : "",
|
||||
data.bpm || "",
|
||||
data.bpmConfidence || ""
|
||||
].join(",");
|
||||
// write next line to log if set
|
||||
require("Storage").open("sleeplog_" + sleeplog.debug.fileid + ".csv", "a").write(csv + "\n");
|
||||
require("Storage").open("sleeplog_" + global.sleeplog.debug.fileid + ".csv", "a").write(csv + "\n");
|
||||
} else {
|
||||
// clear file setting in debug
|
||||
sleeplog.debug = true;
|
||||
global.sleeplog.debug = true;
|
||||
}
|
||||
|
||||
},
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"id":"sleeplog",
|
||||
"name":"Sleep Log",
|
||||
"shortName": "SleepLog",
|
||||
"version": "0.16",
|
||||
"version": "0.17",
|
||||
"description": "Log and view your sleeping habits. This app is using the built in movement calculation.",
|
||||
"icon": "app.png",
|
||||
"type": "app",
|
||||
|
|
|
@ -174,8 +174,8 @@
|
|||
}
|
||||
|
||||
// get thresholds
|
||||
var deepTh = global.sleeplog ? sleeplog.conf.deepTh : defaults.deepTh;
|
||||
var lightTh = global.sleeplog ? sleeplog.conf.lightTh : defaults.lightTh;
|
||||
var deepTh = global.sleeplog ? global.sleeplog.conf.deepTh : defaults.deepTh;
|
||||
var lightTh = global.sleeplog ? global.sleeplog.conf.lightTh : defaults.lightTh;
|
||||
// set lowest movement displayed
|
||||
var minMove = deepTh - 20;
|
||||
// set start point
|
||||
|
@ -240,8 +240,8 @@
|
|||
// check if sleeplog is available
|
||||
if (global.sleeplog) {
|
||||
// get debug status, file and duration
|
||||
var enabled = !!sleeplog.debug;
|
||||
var file = typeof sleeplog.debug === "object";
|
||||
var enabled = !!global.sleeplog.debug;
|
||||
var file = typeof global.sleeplog.debug === "object";
|
||||
var duration = 0;
|
||||
// setup debugging menu
|
||||
var debugMenu = {
|
||||
|
@ -250,7 +250,7 @@
|
|||
},
|
||||
/*LANG*/"< Back": () => {
|
||||
// check if some value has changed
|
||||
if (enabled !== !!sleeplog.debug || file !== (typeof sleeplog.debug === "object") || duration)
|
||||
if (enabled !== !!global.sleeplog.debug || file !== (typeof global.sleeplog.debug === "object") || duration)
|
||||
require("sleeplog").setDebug(enabled, file ? duration || 12 : undefined);
|
||||
// redraw main menu
|
||||
showMain(7);
|
||||
|
@ -265,7 +265,7 @@
|
|||
onchange: v => file = v
|
||||
},
|
||||
/*LANG*/"Duration": {
|
||||
value: file ? (sleeplog.debug.writeUntil - Date.now()) / 36E5 | 0 : 12,
|
||||
value: file ? (global.sleeplog.debug.writeUntil - Date.now()) / 36E5 | 0 : 12,
|
||||
min: 1,
|
||||
max: 96,
|
||||
wrap: true,
|
||||
|
@ -275,7 +275,7 @@
|
|||
/*LANG*/"Cancel": () => showMain(7),
|
||||
};
|
||||
// show menu
|
||||
var menu = E.showMenu(debugMenu);
|
||||
/*var menu =*/ E.showMenu(debugMenu);
|
||||
} else {
|
||||
// show error prompt
|
||||
E.showPrompt("Sleeplog" + /*LANG*/"not enabled!", {
|
||||
|
@ -290,7 +290,7 @@
|
|||
// show menu to change thresholds
|
||||
function showThresholds() {
|
||||
// setup logging menu
|
||||
var menu;
|
||||
//var menu;
|
||||
var thresholdsMenu = {
|
||||
"": {
|
||||
title: /*LANG*/"Thresholds"
|
||||
|
@ -377,9 +377,9 @@
|
|||
buttons: {
|
||||
/*LANG*/"Ok": 0
|
||||
}
|
||||
}).then(() => menu = E.showMenu(thresholdsMenu));
|
||||
}).then(() => /*menu =*/ E.showMenu(thresholdsMenu));
|
||||
} else {
|
||||
menu = E.showMenu(thresholdsMenu);
|
||||
/*menu =*/ E.showMenu(thresholdsMenu);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -388,9 +388,9 @@
|
|||
// set debug image
|
||||
var debugImg = !global.sleeplog ?
|
||||
"FBSBAOAAfwAP+AH3wD4+B8Hw+A+fAH/gA/wAH4AB+AA/wAf+APnwHw+D4Hx8A++AH/AA/gAH" : // X
|
||||
typeof sleeplog.debug === "object" ?
|
||||
typeof global.sleeplog.debug === "object" ?
|
||||
"FBSBAB/4AQDAF+4BfvAX74F+CBf+gX/oFJKBf+gUkoF/6BSSgX/oFJ6Bf+gX/oF/6BAAgf/4" : // file
|
||||
sleeplog.debug ?
|
||||
global.sleeplog.debug ?
|
||||
"FBSBAP//+f/V///4AAGAABkAAZgAGcABjgAYcAGDgBhwAY4AGcABmH+ZB/mAABgAAYAAH///" : // console
|
||||
0; // off
|
||||
debugImg = debugImg ? "\0" + atob(debugImg) : false;
|
||||
|
@ -440,7 +440,7 @@
|
|||
onchange: () => setTimeout(showDebug, 10)
|
||||
}
|
||||
};
|
||||
var menu = E.showMenu(mainMenu);
|
||||
/*var menu =*/ E.showMenu(mainMenu);
|
||||
}
|
||||
|
||||
// draw main menu
|
||||
|
|
|
@ -3,3 +3,4 @@
|
|||
0.03: Remove app from 'tool' when it has at least one other known tag
|
||||
Add tag 'health' for apps like Heart Rate Monitor
|
||||
0.04: Fix remove handler
|
||||
0.05: Make the "App source not found" warning less buggy
|
||||
|
|
|
@ -106,8 +106,9 @@ let showTagMenu = (tag) => {
|
|||
let app = appsByTag[tag][i];
|
||||
if (!app) return;
|
||||
if (!app.src || require("Storage").read(app.src)===undefined) {
|
||||
Bangle.setUI();
|
||||
E.showMessage(/*LANG*/"App Source\nNot found");
|
||||
setTimeout(drawMenu, 2000);
|
||||
setTimeout(showMainMenu, 2000);
|
||||
} else {
|
||||
load(app.src);
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"id": "taglaunch",
|
||||
"name": "Tag Launcher",
|
||||
"shortName": "Taglauncher",
|
||||
"version": "0.04",
|
||||
"version": "0.05",
|
||||
"description": "Launcher that puts all applications into submenus based on their tag. With many applications installed this can result in a faster application selection than the linear access of the default launcher.",
|
||||
"readme": "README.md",
|
||||
"icon": "app.png",
|
||||
|
|
Loading…
Reference in New Issue