Merge branch 'master' of https://github.com/dapgo/BangleApps
commit
c945298531
53
apps.json
53
apps.json
|
|
@ -1944,26 +1944,16 @@
|
|||
"id": "largeclock",
|
||||
"name": "Large Clock",
|
||||
"icon": "largeclock.png",
|
||||
"version": "0.09",
|
||||
"version": "0.10",
|
||||
"description": "A readable and informational digital watch, with date, seconds and moon phase",
|
||||
"readme": "README.md",
|
||||
"tags": "clock",
|
||||
"type": "clock",
|
||||
"allow_emulator": true,
|
||||
"storage": [
|
||||
{
|
||||
"name": "largeclock.app.js",
|
||||
"url": "largeclock.js"
|
||||
},
|
||||
{
|
||||
"name": "largeclock.img",
|
||||
"url": "largeclock-icon.js",
|
||||
"evaluate": true
|
||||
},
|
||||
{
|
||||
"name": "largeclock.settings.js",
|
||||
"url": "settings.js"
|
||||
}
|
||||
{"name": "largeclock.app.js", "url": "largeclock.js"},
|
||||
{"name": "largeclock.img", "url": "largeclock-icon.js", "evaluate": true},
|
||||
{"name": "largeclock.settings.js", "url": "settings.js"}
|
||||
],
|
||||
"data": [
|
||||
{"name":"largeclock.json"}
|
||||
|
|
@ -3265,14 +3255,15 @@
|
|||
"name": "Hour Strike",
|
||||
"shortName": "Hour Strike",
|
||||
"icon": "app-icon.png",
|
||||
"version": "0.07",
|
||||
"version": "0.08",
|
||||
"description": "Strike the clock on the hour. A great tool to remind you an hour has passed!",
|
||||
"tags": "tool,alarm",
|
||||
"readme": "README.md",
|
||||
"storage": [
|
||||
{"name":"hourstrike.app.js","url":"app.js"},
|
||||
{"name":"hourstrike.boot.js","url":"boot.js"},
|
||||
{"name":"hourstrike.img","url":"app-icon.js","evaluate":true}
|
||||
{"name":"hourstrike.img","url":"app-icon.js","evaluate":true},
|
||||
{"name":"hourstrike.json","url":"hourstrike.json"}
|
||||
]
|
||||
},
|
||||
{ "id": "whereworld",
|
||||
|
|
@ -3442,6 +3433,36 @@
|
|||
"data": [
|
||||
{"name":"app.json"}
|
||||
]
|
||||
},
|
||||
{ "id": "shortcuts",
|
||||
"name": "Shortcuts",
|
||||
"shortName":"Shortcuts",
|
||||
"icon": "app.png",
|
||||
"version":"0.01",
|
||||
"description": "Quickly load your favourite apps from (almost) any watch face.",
|
||||
"tags": "tool",
|
||||
"type": "bootloader",
|
||||
"readme": "README.md",
|
||||
"storage": [
|
||||
{"name":"shortcuts.boot.js","url":"boot.js"},
|
||||
{"name":"shortcuts.settings.js","url":"settings.js"}
|
||||
],
|
||||
"data": [
|
||||
{"name":"shortcuts.json"}
|
||||
]
|
||||
},
|
||||
{ "id": "vectorclock",
|
||||
"name": "Vector Clock",
|
||||
"icon": "app.png",
|
||||
"version": "0.02",
|
||||
"description": "A digital clock that uses the built-in vector font.",
|
||||
"tags": "clock",
|
||||
"type": "clock",
|
||||
"allow_emulator": true,
|
||||
"storage": [
|
||||
{"name":"vectorclock.app.js","url":"app.js"},
|
||||
{"name":"vectorclock.img","url":"app-icon.js","evaluate":true}
|
||||
]
|
||||
}
|
||||
{ "id": "widclkbttm",
|
||||
"name": "Digital clock (Bottom) widget",
|
||||
|
|
|
|||
|
|
@ -5,3 +5,4 @@
|
|||
0.05: Add display for the next strike time
|
||||
0.06: Move the next strike time to the first row of display
|
||||
0.07: Change the boot function to avoid reloading the entire watch
|
||||
0.08: Default to no strikes. Fix file-not-found issue during the first boot. Add data file.
|
||||
|
|
|
|||
|
|
@ -1,25 +1,10 @@
|
|||
const storage = require('Storage');
|
||||
let settings;
|
||||
var settings = storage.readJSON('hourstrike.json', 1);
|
||||
|
||||
function updateSettings() {
|
||||
storage.write('hourstrike.json', settings);
|
||||
}
|
||||
|
||||
function resetSettings() {
|
||||
settings = {
|
||||
interval: 3600,
|
||||
start: 9,
|
||||
end: 21,
|
||||
vlevel: 0.5,
|
||||
next_hour: -1,
|
||||
next_minute: -1,
|
||||
};
|
||||
updateSettings();
|
||||
}
|
||||
|
||||
settings = storage.readJSON('hourstrike.json', 1);
|
||||
if (!settings) resetSettings();
|
||||
|
||||
function showMainMenu() {
|
||||
var mode_txt = ['Off','1 min','5 min','10 min','1/4 h','1/2 h','1 h'];
|
||||
var mode_interval = [-1,60,300,600,900,1800,3600];
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
(function() {
|
||||
function setup () {
|
||||
var settings = require('Storage').readJSON('hourstrike.json',1)||[];
|
||||
var settings = require('Storage').readJSON('hourstrike.json',1);
|
||||
var t = new Date();
|
||||
var t_min_sec = t.getMinutes()*60+t.getSeconds();
|
||||
var wait_msec = settings.interval>0?(settings.interval-t_min_sec%settings.interval)*1000:-1;
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
{"interval":-1,"start":9,"end":21,"vlevel":0.5,"next_hour":-1,"next_minute":-1}
|
||||
|
|
@ -7,3 +7,4 @@
|
|||
0.07: Don't clear all intervals during initialisation
|
||||
0.08: Use Bangle.setUI for button/launcher handling
|
||||
0.09: fix font size for latest firmwares
|
||||
0.10: Configure the side text direction based on the wrist on which you wear your watch
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ A readable and informational digital watch, with date, seconds and moon phase an
|
|||
- Readable
|
||||
- Informative: hours, minutes, secondsa, date, year and moon phase
|
||||
- Pairs nicely with any other apps: in setting > large clock any installed app can be assigned to BTN1 and BTN3 in order to open it easily directly from the watch, without the hassle of passing trough the launcher. For example BTN1 can be assigned to alarm and BTN3 to chronometer.
|
||||
- Configure the text direction on the side depending on the wrist on which you wear your watch.
|
||||
|
||||
## How to use it
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,9 @@ const settings = require("Storage").readJSON("largeclock.json", 1)||{};
|
|||
const BTN1app = settings.BTN1 || "";
|
||||
const BTN3app = settings.BTN3 || "";
|
||||
|
||||
const right_hand = !!settings.right_hand;
|
||||
const rotation = right_hand ? 3 : 1;
|
||||
|
||||
function drawMoon(d) {
|
||||
const BLACK = 0,
|
||||
MOON = 0x41f,
|
||||
|
|
@ -145,9 +148,9 @@ function drawTime(d) {
|
|||
g.setColor(1, 50, 1);
|
||||
g.drawString(minutes, 40, 130, true);
|
||||
g.setFont("Vector", 20);
|
||||
g.setRotation(3);
|
||||
g.drawString(`${dow} ${day} ${month}`, 60, 10, true);
|
||||
g.drawString(year, is12Hour ? 46 : 75, 205, true);
|
||||
g.setRotation(rotation);
|
||||
g.drawString(`${dow} ${day} ${month}`, 60, right_hand?10:205, true);
|
||||
g.drawString(year, is12Hour?(right_hand?56:120):(right_hand?85:115), right_hand?205:10, true);
|
||||
lastMinutes = minutes;
|
||||
}
|
||||
g.setRotation(0);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
{
|
||||
"BTN1": "",
|
||||
"BTN3": ""
|
||||
"BTN3": "",
|
||||
"right_hand": false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,8 @@
|
|||
|
||||
const settings = s.readJSON("largeclock.json", 1) || {
|
||||
BTN1: "",
|
||||
BTN3: ""
|
||||
BTN3: "",
|
||||
right_hand: false
|
||||
};
|
||||
|
||||
function showApps(btn) {
|
||||
|
|
@ -67,10 +68,19 @@
|
|||
}
|
||||
|
||||
const mainMenu = {
|
||||
"": { title: "Large Clock Settings" },
|
||||
"": { title: "Large Clock" },
|
||||
"< Back": back,
|
||||
"BTN1 app": () => showApps("BTN1"),
|
||||
"BTN3 app": () => showApps("BTN3")
|
||||
"BTN3 app": () => showApps("BTN3"),
|
||||
"On right hand": {
|
||||
value: !!settings.right_hand,
|
||||
format: v=>v?"Yes":"No",
|
||||
onchange: v=>{
|
||||
settings.right_hand = v;
|
||||
s.writeJSON("largeclock.json", settings);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
E.showMenu(mainMenu);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
0.01: New App!
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
# Shortcuts
|
||||
|
||||
Any installed app can be assigned to BTN1 and BTN3 and launched directly from compatible watch faces. This works with any watch face that uses `Bangle.setUI("clock")`.
|
||||
|
||||
## Credits
|
||||
|
||||
<a target="_blank" href="https://icons8.com/icon/i1z7pQ2orcJk/shortcut">Shortcut</a> icon by <a target="_blank" href="https://icons8.com">Icons8</a>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 767 B |
|
|
@ -0,0 +1,16 @@
|
|||
(function() {
|
||||
var sui = Bangle.setUI;
|
||||
Bangle.setUI = function(mode, cb) {
|
||||
if (mode!="clock") return sui(mode,cb);
|
||||
return sui("clockupdown", (dir) => {
|
||||
let settings = require("Storage").readJSON("shortcuts.json", 1)||{};
|
||||
console.log(settings);
|
||||
if (dir == -1) {
|
||||
if (settings.BTN1) load(settings.BTN1);
|
||||
} else if (dir == 1) {
|
||||
if (settings.BTN3) load(settings.BTN3);
|
||||
}
|
||||
});
|
||||
};
|
||||
})();
|
||||
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
(function(back) {
|
||||
const s = require("Storage");
|
||||
const apps = s
|
||||
.list(/\.info$/)
|
||||
.map(app => {
|
||||
var a = s.readJSON(app, 1);
|
||||
return a && (a.type=="app" || a.type=="clock" || !a.type) && {n: a.name, src: a.src};
|
||||
})
|
||||
.filter(Boolean);
|
||||
apps.sort((a, b) => {
|
||||
if (a.n < b.n) return -1;
|
||||
if (a.n > b.n) return 1;
|
||||
return 0;
|
||||
});
|
||||
apps.push({n: "NONE", src: null});
|
||||
|
||||
const settings = s.readJSON("shortcuts.json", 1) || {
|
||||
BTN1: null,
|
||||
BTN3: null
|
||||
};
|
||||
|
||||
function showApps(btn) {
|
||||
function format(v) {
|
||||
return v === settings[btn] ? "*" : "";
|
||||
}
|
||||
|
||||
function onchange(v) {
|
||||
settings[btn] = v;
|
||||
s.writeJSON("shortcuts.json", settings);
|
||||
}
|
||||
|
||||
const btnMenu = {
|
||||
"": {
|
||||
title: `Apps for ${btn}`
|
||||
},
|
||||
"< Back": () => E.showMenu(mainMenu)
|
||||
};
|
||||
|
||||
if (apps.length > 0) {
|
||||
for (let a of apps) {
|
||||
btnMenu[a.n] = {
|
||||
value: a.src,
|
||||
format: format,
|
||||
onchange: onchange
|
||||
};
|
||||
}
|
||||
} else {
|
||||
btnMenu["...No Apps..."] = {
|
||||
value: undefined,
|
||||
format: () => "",
|
||||
onchange: () => {}
|
||||
};
|
||||
}
|
||||
|
||||
E.showMenu(btnMenu);
|
||||
}
|
||||
|
||||
const mainMenu = {
|
||||
"": { title: "Shortcuts Settings" },
|
||||
"< Back": back,
|
||||
"BTN1 app": () => showApps("BTN1"),
|
||||
"BTN3 app": () => showApps("BTN3")
|
||||
};
|
||||
E.showMenu(mainMenu);
|
||||
});
|
||||
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
0.1: New watch face
|
||||
0.2: Use Bangle.setUI for button/launcher handling
|
||||
|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("mEwwkEIf4AxgMhgUAiIHCmYKCmcgBAUCmQDEgUzkcg+QJBl//AYfzDgX///wAYcCmMzmQXC+c/AYM/kU/iEAgfzkfyAYcCAYM/HIUwC4QxCkEhgcwEYIDDgUwgcSC4QsBLQf/iATEAYcBiB3FC4cvKAIvINAMxgSGDC4UT/4ICC5EDkcjI40/mIHCgaNBC4IDCBAMDmUiXwU/mcQ/8zAYMyQ4M/RYQDBC4yxBIgIDDE4M//5FBAYasBifxf5QA/AC0iAALFDA4ICBgMhC5SBB//wA4gCBUoIXLXYKaBAAUjC54KJC6Ejmcxe4MAiczC4IJBmEjNwILBL4b5Bl7vCD4IEB+cCNgUP+A3EL4MyC4IkBiE/BoMD+cP+MvCoPygfxI4wXBA4UD+QZBh8wgacB/4ODC5YvC+EfC4JVBiAXLgP/n5JBZgcPSwgXIRYPz+cBQoIXBLwgARgU/c4gAQJYJeDF6TXBAH5OMmUBmcQkcgicxBQMTkBbDBIMCSAcTl8jmcxmXymczBQIECCIQEBkbDBAAUfFgMwgPymUDiUg+EjiUwgUhBIMQC4cCfgIXBeAINBicwC4JBBgY7BgcAC4cfkEDkUx+UAmUjBQPxmZZDBIQXDl//kQBC+UvDQIKBmM//4FCBYP/bX4A/ACIA="))
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
const is12Hour = (require("Storage").readJSON("setting.json",1)||{})["12hour"];
|
||||
const locale = require("locale");
|
||||
|
||||
function padNum(n, l) {
|
||||
return ("0".repeat(l)+n).substr(-l);
|
||||
}
|
||||
|
||||
let rects = {};
|
||||
let rectsToClear = {};
|
||||
let commands = [];
|
||||
|
||||
function pushCommand(command) {
|
||||
let hash = E.CRC32(E.toJS(arguments));
|
||||
if (!delete rectsToClear[hash]) {
|
||||
commands.push({hash: hash, command: Function.apply.bind(command, null, arguments.slice(1))});
|
||||
}
|
||||
}
|
||||
|
||||
function executeCommands() {
|
||||
"ram";
|
||||
for (let hash in rectsToClear) delete rects[hash];
|
||||
for (let r of rectsToClear) if (r) g.clearRect(r.x1, r.y1, r.x2, r.y2);
|
||||
g.getModified(true);
|
||||
for (let c of commands) {
|
||||
c.command();
|
||||
rects[c.hash] = g.getModified(true);
|
||||
}
|
||||
rectsToClear = Object.assign({}, rects);
|
||||
commands = [];
|
||||
}
|
||||
|
||||
function drawVectorText(text, size, x, y, alignX, alignY) {
|
||||
g.setFont("Vector", size).setFontAlign(alignX, alignY).drawString(text, x, y);
|
||||
}
|
||||
|
||||
function draw() {
|
||||
g.reset();
|
||||
|
||||
let d = new Date();
|
||||
let hours = is12Hour ? ((d.getHours() + 11) % 12) + 1 : d.getHours();
|
||||
let timeText = `${hours}:${padNum(d.getMinutes(), 2)}`;
|
||||
let meridian = is12Hour ? ((d.getHours() < 12) ? "AM" : "PM") : "";
|
||||
let secondsText = padNum(d.getSeconds(), 2);
|
||||
let dowText = locale.dow(d);
|
||||
let dateText = locale.date(d, true);
|
||||
|
||||
g.setFont("Vector", 256);
|
||||
let timeFontSize = g.getWidth() / ((g.stringWidth(timeText) / 256) + (Math.max(g.stringWidth(meridian), g.stringWidth(secondsText)) / 512 * 9 / 10));
|
||||
let dowFontSize = g.getWidth() / (g.stringWidth(dowText) / 256);
|
||||
let dateFontSize = g.getWidth() / (g.stringWidth(dateText) / 256);
|
||||
|
||||
let timeHeight = g.setFont("Vector", timeFontSize).getFontHeight() * 9 / 10;
|
||||
let dowHeight = g.setFont("Vector", dowFontSize).getFontHeight();
|
||||
let dateHeight = g.setFont("Vector", dateFontSize).getFontHeight();
|
||||
|
||||
let remainingHeight = g.getHeight() - 24 - timeHeight - dowHeight - dateHeight;
|
||||
let spacer = remainingHeight / 4;
|
||||
|
||||
let y = 24 + spacer;
|
||||
|
||||
pushCommand(drawVectorText, timeText, timeFontSize, 0, y, -1, -1);
|
||||
pushCommand(drawVectorText, meridian, timeFontSize*9/20, g.getWidth(), y, 1, -1);
|
||||
pushCommand(drawVectorText, secondsText, timeFontSize*9/20, g.getWidth(), y + timeHeight, 1, 1);
|
||||
y += timeHeight + spacer;
|
||||
|
||||
pushCommand(drawVectorText, dowText, dowFontSize, g.getWidth()/2, y, 0, -1);
|
||||
y += dowHeight + spacer;
|
||||
|
||||
pushCommand(drawVectorText, dateText, dateFontSize, g.getWidth()/2, y, 0, -1);
|
||||
|
||||
executeCommands();
|
||||
}
|
||||
|
||||
let timeout;
|
||||
|
||||
function tick() {
|
||||
draw();
|
||||
timeout = setTimeout(tick, 1000 - getTime() % 1 * 1000);
|
||||
}
|
||||
|
||||
Bangle.on('lcdPower', function(on) {
|
||||
if (timeout) clearTimeout(timeout);
|
||||
timeout = null;
|
||||
if (on) tick();
|
||||
});
|
||||
|
||||
g.clear();
|
||||
tick();
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
|
||||
// Show launcher when middle button pressed
|
||||
Bangle.setUI("clock");
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
Loading…
Reference in New Issue