Merge branch 'master' into master
|
|
@ -9,4 +9,4 @@ appdates.csv
|
|||
_config.yml
|
||||
tests/Layout/bin/tmp.*
|
||||
tests/Layout/testresult.bmp
|
||||
apps.json
|
||||
apps.local.json
|
||||
43
apps.json
|
|
@ -1,25 +1,38 @@
|
|||
---
|
||||
# =================================================================
|
||||
# ALL THE INFORMATION INSIDE APPS.JSON HAS NOW BEEN MOVED
|
||||
#
|
||||
# You'll find it inside a file called apps/yourapp/metadata.json
|
||||
#
|
||||
# Otherwise nothing has changed. GitHub Pages will automatically
|
||||
# create apps.json as your site is hosted, or if you're hosting
|
||||
# yourself you can run bin/create_apps_json.sh
|
||||
#
|
||||
# If you serve the store from localhost for development/testing,
|
||||
# the loader looks for apps.local.json instead, you can run
|
||||
# `bin/create_apps_json.sh apps.local.json` to create that file.
|
||||
# =================================================================
|
||||
|
||||
# Uncomment the following line if you only want explicitly listed
|
||||
# apps to be available on your site
|
||||
|
||||
# restricted: ["boot", "launch", "antonclk", "health", "setting", "about", "widbat", "widbt", "widlock", "widid"]
|
||||
---
|
||||
{% comment %}
|
||||
=================================================================
|
||||
ALL THE INFORMATION INSIDE APPS.JSON HAS NOW BEEN MOVED
|
||||
|
||||
You'll find it inside a file called apps/yourapp/metadata.json
|
||||
|
||||
Otherwise nothing has changed. GitHub Pages will automatically
|
||||
create apps.json as your site is hosted, or if you're hosting
|
||||
yourself you can run bin/create_apps_json.sh
|
||||
|
||||
=================================================================
|
||||
{% endcomment %}
|
||||
{%- assign apps = site.static_files | where: "name", "metadata.json" -%}
|
||||
{%- if page.restricted == nil -%}
|
||||
{%- assign apps = site.static_files | where: "name", "metadata.json" | map: "path" -%}
|
||||
{%- else -%}
|
||||
{%- capture temp -%}
|
||||
{%- for app in page.restricted %} /apps/{{app}}/metadata.json {%- endfor -%}
|
||||
{%- endcapture -%}
|
||||
{%- assign apps = temp | strip | split: " " -%}
|
||||
{%- endif -%}
|
||||
|
||||
[
|
||||
|
||||
{%- include_relative {{ apps.first.path }} -%}
|
||||
{%- include_relative {{ apps.first }} -%}
|
||||
|
||||
{%- for app in apps offset:1 -%}
|
||||
,{%- include_relative {{ app.path }} -%}
|
||||
,{%- include_relative {{ app }} -%}
|
||||
{%- endfor -%}
|
||||
|
||||
]
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
"tags": "Color,input,buttons,touch,UI",
|
||||
"supports": ["BANGLEJS"],
|
||||
"readme": "README.md",
|
||||
"screenshots": [{"url":"UI4swatch_icon.png"},{"url":"UI4swatch_s1.png"}],
|
||||
"storage": [
|
||||
{"name":"UI4swatch.app.js","url":"app.js"},
|
||||
{"name":"UI4swatch.img","url":"app-icon.js","evaluate":true}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
"tags": "outdoors,widget",
|
||||
"supports": ["BANGLEJS"],
|
||||
"readme": "README.md",
|
||||
"screenshots": [{"url":"600.png"},{"url":"10600.png"},{"url":"1600.png"}],
|
||||
"storage": [
|
||||
{"name":"activepedom.wid.js","url":"widget.js"},
|
||||
{"name":"activepedom.settings.js","url":"settings.js"},
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
"description": "Shows you the days left until a certain date. Date can be set with a settings app and is written to a file.",
|
||||
"icon": "app.png",
|
||||
"tags": "",
|
||||
"supports": ["BANGLEJS"],
|
||||
"supports": ["BANGLEJS", "BANGLEJS2"],
|
||||
"allow_emulator": false,
|
||||
"storage": [
|
||||
{"name":"daysl.app.js","url":"app.js"},
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
0.1: Added source code
|
||||
0.2: Added a README file
|
||||
0.01: Added source code
|
||||
0.02: Added a README file
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"id": "fd6fdetect",
|
||||
"name": "fd6fdetect",
|
||||
"shortName": "fd6fdetect",
|
||||
"version": "0.2",
|
||||
"version": "0.02",
|
||||
"description": "Allows you to see 0xFD6F beacons near you.",
|
||||
"icon": "app.png",
|
||||
"tags": "tool",
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
1.00: First published version.
|
||||
0.01: First published version.
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "mysticdock",
|
||||
"name": "Mystic Dock",
|
||||
"version": "1.00",
|
||||
"version": "0.01",
|
||||
"description": "A retro-inspired dockface that displays the current time and battery charge while plugged in, and which features an interactive mode that shows the time, date, and a rotating data display line.",
|
||||
"icon": "mystic-dock.png",
|
||||
"type": "dock",
|
||||
|
|
|
|||
|
|
@ -9,3 +9,5 @@
|
|||
0.09: Added dependancy on Pedometer Widget
|
||||
0.10: Added Weather line, fixed issues on a Bangle 1, update every minute
|
||||
0.11: Changed cycle on minute to prevInfo to avoid the 2nd one being the blank line
|
||||
0.12: Removed dependancy on widpedom, now uses Bangle.getHealthStatus("day").steps
|
||||
which requires 2.11.27 firmware to reset at midnight
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@
|
|||
"id": "pastel",
|
||||
"name": "Pastel Clock",
|
||||
"shortName": "Pastel",
|
||||
"version": "0.11",
|
||||
"description": "A Configurable clock with custom fonts, background and weather display. Has a cyclic information line that includes, day, date, battery, sunrise and sunset times",
|
||||
"version": "0.12",
|
||||
"description": "A Configurable clock with custom fonts, background and weather display. Has a cyclic information line that includes, day, date, battery, sunrise and sunset times. Requires firmware 2.11.27",
|
||||
"icon": "pastel.png",
|
||||
"dependencies": {"mylocation":"app", "widpedom":"app","weather":"app"},
|
||||
"dependencies": {"mylocation":"app","weather":"app"},
|
||||
"screenshots": [{"url":"screenshot_pastel.png"}, {"url":"weather_icons.png"}],
|
||||
"type": "clock",
|
||||
"tags": "clock, weather, tool",
|
||||
|
|
|
|||
|
|
@ -64,13 +64,15 @@ function loadFonts() {
|
|||
require("f_lato").add(Graphics);
|
||||
}
|
||||
|
||||
function stepsWidget() {
|
||||
if (WIDGETS.activepedom !== undefined) {
|
||||
return WIDGETS.activepedom;
|
||||
} else if (WIDGETS.wpedom !== undefined) {
|
||||
return WIDGETS.wpedom;
|
||||
function getSteps() {
|
||||
try {
|
||||
return Bangle.getHealthStatus("day").steps;
|
||||
} catch (e) {
|
||||
if (WIDGETS.wpedom !== undefined)
|
||||
return WIDGETS.wpedom.getSteps();
|
||||
else
|
||||
return '???'
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const infoData = {
|
||||
|
|
@ -79,7 +81,7 @@ const infoData = {
|
|||
ID_DAY: { calc: () => {var d = require("locale").dow(new Date).toLowerCase(); return d[0].toUpperCase() + d.substring(1);} },
|
||||
ID_SR: { calc: () => 'Sunrise: ' + sunRise },
|
||||
ID_SS: { calc: () => 'Sunset: ' + sunSet },
|
||||
ID_STEP: { calc: () => 'Steps: ' + stepsWidget().getSteps() },
|
||||
ID_STEP: { calc: () => 'Steps: ' + getSteps() },
|
||||
ID_BATT: { calc: () => 'Battery: ' + E.getBattery() + '%' },
|
||||
ID_MEM: { calc: () => {var val = process.memory(); return 'Ram: ' + Math.round(val.usage*100/val.total) + '%';} },
|
||||
ID_ID: { calc: () => {var val = NRF.getAddress().split(':'); return 'Id: ' + val[4] + val[5];} },
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
0.1: first release
|
||||
0.01: first release
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"id": "pebbled",
|
||||
"name": "Pebble Clock with distance",
|
||||
"shortName": "Pebble + distance",
|
||||
"version": "0.1",
|
||||
"version": "0.01",
|
||||
"description": "Fork of Pebble Clock with distance in KM. Both step count and the distance are on the main screen. Default step length = 0.75m (can be changed in settings).",
|
||||
"readme": "README.md",
|
||||
"icon": "pebbled.png",
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
0.1: Start of app.
|
||||
0.5: BLE keyboard functionality.
|
||||
1.0: BLE mouse functionality to scroll back/forward.
|
||||
1.5: Added accelerator style mouse.
|
||||
2.0: Added touchpad style mouse.
|
||||
2.1: Initial internal git(hub) release. Added icon and such.
|
||||
2.2: Begin work on presentation parts.
|
||||
3.0: Presentation parts!
|
||||
0.01: Start of app.
|
||||
0.02: BLE keyboard functionality.
|
||||
0.03: BLE mouse functionality to scroll back/forward.
|
||||
0.04: Added accelerator style mouse.
|
||||
0.05: Added touchpad style mouse.
|
||||
0.06: Initial internal git(hub) release. Added icon and such.
|
||||
0.07: Begin work on presentation parts.
|
||||
0.08: Presentation parts!
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "presentor",
|
||||
"name": "Presentor",
|
||||
"version": "3.0",
|
||||
"version": "0.08",
|
||||
"description": "Use your Bangle to present!",
|
||||
"icon": "app.png",
|
||||
"type": "app",
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
1.00: Hello Ruuvi Watch!
|
||||
1.01: Clear gfx on startup.
|
||||
0.01: Hello Ruuvi Watch!
|
||||
0.02: Clear gfx on startup.
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"name": "Ruuvi Watch",
|
||||
"shortName":"Ruuvi Watch",
|
||||
"icon": "ruuviwatch.png",
|
||||
"version":"1.01",
|
||||
"version":"0.02",
|
||||
"description": "Keep an eye on RuuviTag devices (https://ruuvi.com). Only shows RuuviTags using the v5 format.",
|
||||
"readme":"README.md",
|
||||
"tags": "bluetooth",
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
0.1: Initial release
|
||||
0.2: Fixed launcher image
|
||||
0.01: Initial release
|
||||
0.02: Fixed launcher image
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"id": "showimg",
|
||||
"name": "simple image viewer",
|
||||
"shortName":"showImage",
|
||||
"version":"0.2",
|
||||
"version":"0.02",
|
||||
"description": "Displays the image in \"showimg.user.img\". The file has to be uploaded via the espruino IDE. Returns to watch face after 60s or button push. I use it to display my vaccination certificate.",
|
||||
"icon": "app.png",
|
||||
"tags": "tool",
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
1.00 Added sonic clock app
|
||||
1.01 Fixed text alignment issue; Increased acceleration required to activate twist;
|
||||
0.01 Added sonic clock app
|
||||
0.02 Fixed text alignment issue; Increased acceleration required to activate twist;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "sonicclk",
|
||||
"name": "Sonic Clock",
|
||||
"version": "1.01",
|
||||
"version": "0.02",
|
||||
"description": "A classic sonic clock featuring run, stop and wait animations.",
|
||||
"icon": "app.png",
|
||||
"screenshots": [{"url":"screenshot.png"}],
|
||||
|
|
|
|||
|
|
@ -5,6 +5,6 @@
|
|||
0.05: Add setting to turn vibrate on/off.
|
||||
0.06: Tweaks to vibration settings.
|
||||
0.07: Switch to BTN1 for Max toggle and reset function.
|
||||
1.00: New features. Added waypoints file and distance to selected waypoint display. Added integration with GPS Setup module to switch GPS to low power mode when screen off. Save display settings and restore when app restarted.
|
||||
1.01: Add third screen mode with large clock and waypoint selection display to ease visibility in bright daylight.
|
||||
1.02: Add Kalman filter to smooth the speed and altitude values. Can be disabled in settings.
|
||||
0.08: New features. Added waypoints file and distance to selected waypoint display. Added integration with GPS Setup module to switch GPS to low power mode when screen off. Save display settings and restore when app restarted.
|
||||
0.09: Add third screen mode with large clock and waypoint selection display to ease visibility in bright daylight.
|
||||
0.10: Add Kalman filter to smooth the speed and altitude values. Can be disabled in settings.
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"id": "speedalt",
|
||||
"name": "GPS Adventure Sports",
|
||||
"shortName": "GPS Adv Sport",
|
||||
"version": "1.02",
|
||||
"version": "0.10",
|
||||
"description": "GPS speed, altitude and distance to waypoint display. Designed for easy viewing and use during outdoor activities such as para-gliding, hang-gliding, sailing, cycling etc.",
|
||||
"icon": "app.png",
|
||||
"type": "app",
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
0.01: Initial import.
|
||||
0.07: Add swipe to change screens.
|
||||
1.06: Misc memory and screen optimisations.
|
||||
1.10: ...
|
||||
0.02: Add swipe to change screens.
|
||||
0.03: Misc memory and screen optimisations.
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"id": "speedalt2",
|
||||
"name": "GPS Adventure Sports II",
|
||||
"shortName":"GPS Adv Sport II",
|
||||
"version":"1.10",
|
||||
"version":"0.03",
|
||||
"description": "GPS speed, altitude and distance to waypoint display. Designed for easy viewing and use during outdoor activities such as para-gliding, hang-gliding, sailing, cycling etc.",
|
||||
"icon": "app.png",
|
||||
"type": "app",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "teatimer",
|
||||
"name": "Tea Timer",
|
||||
"version": "1.00",
|
||||
"version": "0.01",
|
||||
"description": "A simple timer. You can easyly set up the time.",
|
||||
"icon": "teatimer.png",
|
||||
"type": "app",
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
0.01: New App!
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
# Timer Clock
|
||||
|
||||
A clock based on the Anton Clock with stopwatches, timers and alarms based on the Stopwatch Touch style and an alarm widget based on the one from Default alarm & timer.
|
||||
|
||||
## Features
|
||||
|
||||
* two slots for stopwatches / timers on the clock screen
|
||||
* configurable font and size (Anton font has fixed size)
|
||||
* stopwatch with modifiable start value
|
||||
* timer that can be paused
|
||||
* alarms
|
||||
* multiple stopwatches, timers and alarms
|
||||
* stopwatches and timers keep running in the background
|
||||
|
||||
## Images
|
||||
|
||||

|
||||
|
||||
### Stopwatch
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
### Settings
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
## Controls
|
||||
|
||||
### Bangle.js 1
|
||||
|
||||
#### Clock
|
||||
|
||||
* Left: Stopwatch
|
||||
* Right: Timer
|
||||
* Button 1 / 2: Alarm
|
||||
|
||||
#### Stopwatch / Timer / Alarm
|
||||
|
||||
* Button 1:
|
||||
* edit mode: increase
|
||||
* control mode: play / pause
|
||||
* Button 2: switch between edit / control mode
|
||||
* Button 3:
|
||||
* edit mode: decrease
|
||||
* control mode: reset / remove
|
||||
* Left:
|
||||
* edit mode: previous index
|
||||
* control mode: previous stopwatch / timer / alarm
|
||||
* Right:
|
||||
* edit mode: next index
|
||||
* control mode: next stopwatch / timer / alarm
|
||||
|
||||
### Bangle.js 2
|
||||
|
||||
#### Clock
|
||||
|
||||
* Swipe left: Stopwatch
|
||||
* Swipe right: Timer
|
||||
* Swipe over date: Alarm
|
||||
|
||||
#### Stopwatch / Timer / Alarm
|
||||
|
||||
* Swipe left: previous stopwatch / timer / alarm
|
||||
* Swipe right: next stopwatch / timer / alarm
|
||||
* Swipe up: increase index swiped over
|
||||
* Swipe down: decrease index swiped over
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
if (timerclkAlarmTimeout) clearInterval(timerclkAlarmTimeout);
|
||||
var timerclk = require("timerclk.lib.js");
|
||||
var settings = require('Storage').readJSON("timerclk.json", true) || {};
|
||||
settings = Object.assign({
|
||||
"vibrate":10
|
||||
}, settings.alarm||{});
|
||||
|
||||
function showAlarm(alarm) {
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
Bangle.setLocked(false);
|
||||
E.showPrompt("Alarm!",{
|
||||
title:"ALARM!",
|
||||
buttons : {/*LANG*/"Ok":true}
|
||||
}).then(function(ok) {
|
||||
buzzCount = 0;
|
||||
if (ok) {
|
||||
alarm.last = new Date().getDate();
|
||||
}
|
||||
require("Storage").write("timerclk.alarm.json",JSON.stringify(alarms));
|
||||
load();
|
||||
});
|
||||
function vibrate(counter) {
|
||||
VIBRATE.write(1);
|
||||
setTimeout(() => VIBRATE.write(0), 100);
|
||||
if (--counter) setTimeout(() => vibrate(counter), 250);
|
||||
}
|
||||
function buzz() {
|
||||
if ((require('Storage').readJSON('setting.json',1)||{}).quiet>1) return; // total silence
|
||||
vibrate(4);
|
||||
if (buzzCount--)
|
||||
setTimeout(buzz, 3000);
|
||||
else { // auto-snooze
|
||||
buzzCount = settings.vibrate;
|
||||
setTimeout(buzz, 600000);
|
||||
}
|
||||
}
|
||||
var buzzCount = settings.vibrate;
|
||||
buzz();
|
||||
}
|
||||
|
||||
// Check for alarms
|
||||
console.log("checking for alarms...");
|
||||
var alarms = require("Storage").readJSON("timerclk.alarm.json",1)||[];
|
||||
var active = alarms.filter(e=>e.on);
|
||||
if (active.length) {
|
||||
// if there's an alarm, show it
|
||||
active = active.sort((a,b)=>(a.time-b.time)+(a.last-b.last)*86400000);
|
||||
if (active[0].last != new Date().getDate()) {
|
||||
showAlarm(active[0]);
|
||||
} else {
|
||||
setTimeout(load, 100);
|
||||
}
|
||||
} else {
|
||||
// otherwise just go back to default app
|
||||
setTimeout(load, 100);
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
{"id":"timerclk","name":"tclk Alarm","src":"timerclk.alarm.js","icon":"timerclk.img","version":"0.01","tags":"","files":"","sortorder":10}
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
var timerclk = require("timerclk.lib.js");
|
||||
const height = g.getHeight(), width = g.getWidth();
|
||||
|
||||
var all = require("Storage").readJSON("timerclk.alarm.json") || [];
|
||||
var settings = require('Storage').readJSON("timerclk.json", true) || {};
|
||||
settings = Object.assign({
|
||||
"font":"Vector",
|
||||
"fontSize":40,
|
||||
"indexFont":"6x8",
|
||||
"indexFontSize":3,
|
||||
"buttonHeight":40,
|
||||
"vibrate":4,
|
||||
}, settings = settings.alarm||{});
|
||||
var defaultElement = {time:43200000, on:true, last:null};
|
||||
|
||||
var current = 0;
|
||||
var editIndex = 0;
|
||||
var drawInterval;
|
||||
var drawIntervalTimeout;
|
||||
var buttons;
|
||||
var dragBorderHrsMins=0, dragBorderMinsSecs=0;
|
||||
|
||||
function update() {
|
||||
if (drawInterval) clearInterval(drawInterval);
|
||||
if (drawIntervalTimeout) clearTimeout(drawIntervalTimeout);
|
||||
if (all[current].start) {
|
||||
drawIntervalTimeout = setTimeout(() => {drawInterval = setInterval(draw, 1000); draw();}, 1000 - (timerclk.getTime(all[current]) % 1000));
|
||||
} else {
|
||||
drawInterval = null;
|
||||
drawIntervalTimeout = null;
|
||||
}
|
||||
draw();
|
||||
drawButtons();
|
||||
}
|
||||
function activate() {
|
||||
all[current].on = !all[current].on;
|
||||
all[current].last = null;
|
||||
update();
|
||||
require("Storage").write("timerclk.alarm.json",JSON.stringify(all));
|
||||
timerclkCheckAlarms();
|
||||
}
|
||||
function remove() {
|
||||
all.splice(current, 1);
|
||||
if (current == all.length) current--;
|
||||
if (all.length == 0) {
|
||||
all.push(defaultElement.clone());
|
||||
current++;
|
||||
}
|
||||
update();
|
||||
require("Storage").write("timerclk.alarm.json",JSON.stringify(all));
|
||||
timerclkCheckAlarms();
|
||||
}
|
||||
|
||||
function edit(position, change) {
|
||||
if (position == 1) all[current].time += change*1000;
|
||||
else if (position == 2) all[current].time += change*60000;
|
||||
else if (position == 3) all[current].time += change*3600000;
|
||||
require("Storage").write("timerclk.alarm.json",JSON.stringify(all));
|
||||
timerclkCheckAlarms();
|
||||
}
|
||||
|
||||
var buttons = {
|
||||
reset: {pos:[0, height-settings.buttonHeight, width/2, height], callback: remove, img: timerclk.remove_img, col:"#f50"}, // remove
|
||||
play: {pos:[width/2, height-settings.buttonHeight, width, height], callback: activate, img: timerclk.play_img, col:"#0ff"}, // active
|
||||
};
|
||||
|
||||
|
||||
function drawButtons() {
|
||||
if (all[current].on) {
|
||||
buttons.play.img = timerclk.pause_img;
|
||||
} else {
|
||||
buttons.play.img = timerclk.play_img;
|
||||
}
|
||||
for (var button of buttons) {
|
||||
g.setColor(button.col);
|
||||
g.fillRect(button.pos[0], button.pos[1], button.pos[2], button.pos[3]);
|
||||
g.setColor("#000");
|
||||
// scale 24px images
|
||||
let iw = settings.buttonHeight-10;
|
||||
var scale = iw/24;
|
||||
let ix = button.pos[0] + ((button.pos[2]-button.pos[0] - iw) /2);
|
||||
let iy = button.pos[1] + ((button.pos[3]-button.pos[1] - iw) /2);
|
||||
g.drawImage(button.img, ix, iy, {scale: scale});
|
||||
}
|
||||
}
|
||||
|
||||
function draw() {
|
||||
var x = g.getWidth()/2;
|
||||
var y = g.getHeight()/2;
|
||||
g.reset();
|
||||
|
||||
g.clearRect(Bangle.appRect.x, Bangle.appRect.y, Bangle.appRect.x2, Bangle.appRect.y2-settings.buttonHeight);
|
||||
g.setFontAlign(0,0).setFont(settings.indexFont, settings.indexFontSize);
|
||||
g.drawString(current+1, x, Bangle.appRect.y + (g.stringMetrics("0").height/2));
|
||||
g.setFontAlign(0,0).setFont(settings.font, settings.fontSize);
|
||||
var timeStr = timerclk.formatTime(all[current].time, false, false, true);
|
||||
g.drawString(timeStr,x,y);
|
||||
var start = (width-g.stringMetrics(timeStr).width)/2;
|
||||
timeStr = timeStr.split(":");
|
||||
var markerPosChange = g.stringMetrics("__").width/2;
|
||||
if (editIndex == 3) x = start + g.stringMetrics(timeStr[0]).width - markerPosChange;
|
||||
else if (editIndex == 2) x = start + g.stringMetrics(timeStr[0]+":"+timeStr[1]).width - markerPosChange;
|
||||
else if (editIndex == 1) x = start + g.stringMetrics(timeStr[0]+":"+timeStr[1]+":"+timeStr[2]).width - markerPosChange;
|
||||
else x = 0;
|
||||
if (x) g.drawString("__", x, y);
|
||||
dragBorderHrsMins = start+g.stringMetrics(timeStr[0]).width+g.stringMetrics(":").width/2;
|
||||
dragBorderMinsSecs = start+g.stringMetrics(timeStr[0]+":"+timeStr[1]).width+g.stringMetrics(":").width/2;
|
||||
}
|
||||
|
||||
if (all.length == 0) {
|
||||
all.push(defaultElement.clone());
|
||||
}
|
||||
timerclk.registerControls(this);
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
update();
|
||||
|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("mEwgP/AFHzvmf+f8z/8tnv/vs9/1t/v+kv94jR/H4n/wn4CBAYPwnEP8AFDg/AAoUwAoPgmABBwfQAonwAo0/4gFC4AFE4gFLmGEAoQDBxgFCwEQAIIFIj4FD/k//hNBAoZZBAoc8j6oS8/P+1NAoP63+7+wMCz/u/YEB/v/v4dI1+pAQIFBx/J/2/AoP5tFJr71eA=="))
|
||||
|
After Width: | Height: | Size: 8.8 KiB |
|
|
@ -0,0 +1,48 @@
|
|||
var timerclkTimerTimeout;
|
||||
var timerclkAlarmTimeout;
|
||||
function timerclkCheckTimers() {
|
||||
if (timerclkTimerTimeout) clearTimeout(timerclkTimerTimeout);
|
||||
var timers = require('Storage').readJSON('timerclk.timer.json',1)||[];
|
||||
timers = timers.filter(e=>e.start);
|
||||
if (timers.length) {
|
||||
timers = timers.sort((a,b)=>{
|
||||
var at = a.timeAdd;
|
||||
if (a.start) at += Date.now()-a.start;
|
||||
at = a.period-at;
|
||||
var bt = b.timeAdd;
|
||||
if (b.start) bt += Date.now()-b.start;
|
||||
bt = b.period-bt;
|
||||
return at-bt;
|
||||
});
|
||||
if (!require('Storage').read("timerclk.timer.alert.js")) {
|
||||
console.log("No timer app!");
|
||||
} else {
|
||||
var time = timers[0].timeAdd;
|
||||
if (timers[0].start) time += Date.now()-timers[0].start;
|
||||
time = timers[0].time - time;
|
||||
if (time<1000) t=1000;
|
||||
if (timerclkTimerTimeout) clearTimeout(timerclkTimerTimeout);
|
||||
timerclkTimerTimeout = setTimeout(() => load("timerclk.timer.alert.js"),time);
|
||||
}
|
||||
}
|
||||
}
|
||||
function timerclkCheckAlarms() {
|
||||
if (timerclkAlarmTimeout) clearTimeout(timerclkAlarmTimeout);
|
||||
var alarms = require('Storage').readJSON('timerclk.alarm.json',1)||[];
|
||||
var currentTime = require("timerclk.lib.js").getCurrentTime();
|
||||
alarms = alarms.filter(e=>e.on);
|
||||
if (alarms.length) {
|
||||
alarms = alarms.sort((a,b)=>(a.time-b.time)+(a.last-b.last)*86400000);
|
||||
if (!require('Storage').read("timerclk.alarm.alert.js")) {
|
||||
console.log("No alarm app!");
|
||||
} else {
|
||||
var time = alarms[0].time-currentTime;
|
||||
if (alarms[0].last == new Date().getDate() || time < 0) time += 86400000;
|
||||
if (time<1000) t=1000;
|
||||
if (timerclkAlarmTimeout) clearTimeout(timerclkAlarmTimeout);
|
||||
timerclkAlarmTimeout = setTimeout(() => load("timerclk.alarm.alert.js"),time);
|
||||
}
|
||||
}
|
||||
}
|
||||
timerclkCheckTimers();
|
||||
timerclkCheckAlarms();
|
||||
|
|
@ -0,0 +1,127 @@
|
|||
exports.pause_img = atob("GBiBAf///////////+D/B+D/B+D/B+D/B+D/B+D/B+D/B+D/B+D/B+D/B+D/B+D/B+D/B+D/B+D/B+D/B+D/B+D/B////////////w==");
|
||||
exports.play_img = atob("GBiBAf////////////P///D///A///Af//AH//AB//AAf/AAH/AAB/AAB/AAH/AAf/AB//AH//Af//A///D///P//////////////w==");
|
||||
exports.reset_img = atob("GBiBAf////////////AAD+AAB+f/5+f/5+f/5+cA5+cA5+cA5+cA5+cA5+cA5+cA5+cA5+f/5+f/5+f/5+AAB/AAD////////////w==");
|
||||
exports.remove_img = atob("GBiBAf///////////+P/x+H/h+D/B/B+D/g8H/wYP/4Af/8A//+B//+B//8A//4Af/wYP/g8H/B+D+D/B+H/h+P/x////////////w==");
|
||||
|
||||
exports.formatTime = function(t, short, tnthEnable, fullTime) {
|
||||
var negative = "";
|
||||
if (t < 0) {
|
||||
t = t*(-1);
|
||||
negative = "-";
|
||||
}
|
||||
let hrs = Math.floor(t/3600000);
|
||||
let mins = Math.floor(t/60000)%60;
|
||||
let secs = Math.floor(t/1000)%60;
|
||||
var tnth = "";
|
||||
if (tnthEnable) {
|
||||
tnth = Math.floor(t/100)%10;
|
||||
tnth = "."+tnth;
|
||||
}
|
||||
var hrsStr = hrs;
|
||||
if (hrs < 10 && !negative) hrsStr = "0"+hrs;
|
||||
var text;
|
||||
if (short) {
|
||||
if (hrs === 0) text = negative + ("0"+mins).substr(-2) + ":" + ("0"+secs).substr(-2);
|
||||
else text = negative + hrsStr + "/" + ("0"+mins).substr(-2);
|
||||
} else {
|
||||
if (hrs === 0 && !fullTime) text = negative + ("0"+mins).substr(-2) + ":" + ("0"+secs).substr(-2) + tnth;
|
||||
else text = negative + hrsStr + ":" + ("0"+mins).substr(-2) + ":" + ("0"+secs).substr(-2);
|
||||
}
|
||||
return text;
|
||||
};
|
||||
|
||||
exports.getTime = function(e) {
|
||||
var time = e.timeAdd;
|
||||
if (e.start) {
|
||||
time += Date.now() - e.start;
|
||||
}
|
||||
return time;
|
||||
};
|
||||
|
||||
exports.getCurrentTime = function() {
|
||||
var date = new Date();
|
||||
return date.getHours()*3600000+date.getMinutes()*60000+date.getSeconds()*1000+date.getMilliseconds();
|
||||
};
|
||||
|
||||
exports.registerControls = function(o) {
|
||||
if (process.env.HWVERSION==1) {
|
||||
setWatch(()=>{
|
||||
if (o.editIndex == 0) o.buttons.play.callback();
|
||||
else o.edit(o.editIndex, 1);
|
||||
o.draw();
|
||||
}, BTN1, {repeat:true});
|
||||
setWatch(()=>{
|
||||
o.editIndex = !o.editIndex;
|
||||
o.draw();
|
||||
}, BTN2, {repeat:true});
|
||||
setWatch(()=>{
|
||||
if (o.editIndex == 0) o.buttons.reset.callback();
|
||||
else o.edit(o.editIndex, -1);
|
||||
o.draw();
|
||||
}, BTN3, {repeat:true});
|
||||
setWatch(()=>{
|
||||
if (o.editIndex) {
|
||||
o.editIndex++;
|
||||
if (o.editIndex > 3) o.editIndex = 1;
|
||||
} else if (o.current > 0) o.current--;
|
||||
o.update();
|
||||
}, BTN4, {repeat:true});
|
||||
setWatch(()=>{
|
||||
if (o.editIndex) {
|
||||
o.editIndex--;
|
||||
if (o.editIndex < 1) o.editIndex = 3;
|
||||
} else {
|
||||
o.current++;
|
||||
if (o.current == o.all.length) o.all.push(o.defaultElement.clone());
|
||||
}
|
||||
o.update();
|
||||
}, BTN5, {repeat:true});
|
||||
} else {
|
||||
setWatch(()=>load(), BTN1);
|
||||
Bangle.on('touch',(n,e)=>{
|
||||
for (var button of o.buttons) {
|
||||
if (e.x>=button.pos[0] && e.y>=button.pos[1] &&
|
||||
e.x<button.pos[2] && e.y<button.pos[3]) {
|
||||
button.callback();
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
var absX, lastX, lastY;
|
||||
Bangle.on('drag', e=>{
|
||||
if (!e.b) {
|
||||
if (lastX > 40) { // right
|
||||
o.current++;
|
||||
if (o.current == o.all.length) o.all.push(o.defaultElement.clone());
|
||||
} else if (lastX < -40) { // left
|
||||
if (o.current > 0) {
|
||||
o.current--;
|
||||
}
|
||||
} else if (lastY > 30) { // down
|
||||
if (absX < o.dragBorderHrsMins) {
|
||||
o.edit(3, -1);
|
||||
} else if (absX > o.dragBorderHrsMins && absX < o.dragBorderMinsSecs) {
|
||||
o.edit(2, -1);
|
||||
} else {
|
||||
o.edit(1, -1);
|
||||
}
|
||||
} else if (lastY < -30) { // up
|
||||
if (absX < o.dragBorderHrsMins) {
|
||||
o.edit(3, 1);
|
||||
} else if (absX > o.dragBorderHrsMins && absX < o.dragBorderMinsSecs) {
|
||||
o.edit(2, 1);
|
||||
} else {
|
||||
o.edit(1, 1);
|
||||
}
|
||||
}
|
||||
lastX = 0;
|
||||
lastY = 0;
|
||||
o.update();
|
||||
} else {
|
||||
absX = e.x;
|
||||
lastX = lastX + e.dx;
|
||||
lastY = lastY + e.dy;
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
"id": "timerclk",
|
||||
"name": "Timer Clock",
|
||||
"shortName":"Timer Clock",
|
||||
"version":"0.01",
|
||||
"description": "A clock with stopwatches, timers and alarms build in.",
|
||||
"icon": "app-icon.png",
|
||||
"type": "clock",
|
||||
"tags": "clock",
|
||||
"supports" : ["BANGLEJS","BANGLEJS2"],
|
||||
"screenshots": [
|
||||
{"url":"screenshot.png"},
|
||||
{"url":"screenshot_stopwatch1.png"},
|
||||
{"url":"screenshot_stopwatch2.png"},
|
||||
{"url":"screenshot_settings1.png"},
|
||||
{"url":"screenshot_settings2.png"},
|
||||
{"url":"screenshot_settings3.png"}
|
||||
],
|
||||
"readme": "README.md",
|
||||
"storage": [
|
||||
{"name":"timerclk.app.js","url":"app.js"},
|
||||
{"name":"timerclk.img","url":"app-icon.js","evaluate":true},
|
||||
{"name":"timerclk.boot.js","url":"boot.js"},
|
||||
{"name":"timerclk.lib.js","url":"lib.js"},
|
||||
{"name":"timerclk.wid.js","url":"wid.js"},
|
||||
{"name":"timerclk.settings.js","url":"settings.js"},
|
||||
{"name":"timerclk.stopwatch.js","url":"stopwatch.js"},
|
||||
{"name":"timerclk.timer.js","url":"timer.js"},
|
||||
{"name":"timerclk.timer.alert.js","url":"timer.alert.js"},
|
||||
{"name":"timerclk.alarm.js","url":"alarm.js"},
|
||||
{"name":"timerclk.alarm.alert.js","url":"alarm.alert.js"},
|
||||
{"name":"timerclk.stopwatch.info","url":"stopwatch.info"},
|
||||
{"name":"timerclk.timer.info","url":"timer.info"},
|
||||
{"name":"timerclk.alarm.info","url":"alarm.info"}
|
||||
],
|
||||
"data": [{"name":"timerclk.json"},{"name":"timerclk.stopwatch.json"},{"name":"timerclk.timer.json"},{"name":"timerclk.alarm.json"}],
|
||||
"sortorder": 0
|
||||
}
|
||||
|
After Width: | Height: | Size: 4.6 KiB |
|
After Width: | Height: | Size: 4.6 KiB |
|
After Width: | Height: | Size: 4.6 KiB |
|
After Width: | Height: | Size: 4.6 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
|
@ -0,0 +1,292 @@
|
|||
(function(back) {
|
||||
const FILE = "timerclk.json";
|
||||
const BOOL_FORMAT = v=>v?/*LANG*/"On":/*LANG*/"Off";
|
||||
// Load settings
|
||||
var settings = require('Storage').readJSON(FILE, true) || {}
|
||||
settings.clock = Object.assign({
|
||||
"timeFont":"Anton",
|
||||
"timeFontSize":0,
|
||||
"dateFont":"6x8",
|
||||
"dateFontSize":2,
|
||||
"dowFont":"6x8",
|
||||
"dowFontSize":2,
|
||||
"specialFont":"6x8",
|
||||
"specialFontSize":2,
|
||||
"shortDate":true,
|
||||
"showStopwatches":true,
|
||||
"showTimers":true,
|
||||
}, settings.clock||{});
|
||||
settings.stopwatch = Object.assign({
|
||||
"font":"Vector",
|
||||
"fontSize":40,
|
||||
"indexFont":"6x8",
|
||||
"indexFontSize":3,
|
||||
"buttonHeight":40,
|
||||
}, settings.stopwatch||{});
|
||||
settings.timer = Object.assign({
|
||||
"font":"Vector",
|
||||
"fontSize":40,
|
||||
"indexFont":"6x8",
|
||||
"indexFontSize":3,
|
||||
"buttonHeight":40,
|
||||
"vibrate":10,
|
||||
}, settings.timer||{});
|
||||
settings.alarm = Object.assign({
|
||||
"font":"Vector",
|
||||
"fontSize":40,
|
||||
"indexFont":"6x8",
|
||||
"indexFontSize":3,
|
||||
"buttonHeight":40,
|
||||
"vibrate":10,
|
||||
}, settings.alarm||{});
|
||||
var timeFonts = ["Anton"].concat(g.getFonts());
|
||||
|
||||
function writeSettings() {
|
||||
require('Storage').writeJSON(FILE, settings);
|
||||
}
|
||||
|
||||
// Show the menu
|
||||
var mainMenu = {
|
||||
"" : { "title" : "Timer Clock" },
|
||||
"< Back" : () => back(),
|
||||
"Clock": ()=>{E.showMenu(clockMenu);},
|
||||
"Stopwatch": ()=>{E.showMenu(stopwatchMenu);},
|
||||
"Timer": ()=>{E.showMenu(timerMenu);},
|
||||
"Alarm": ()=>{E.showMenu(alarmMenu);},
|
||||
};
|
||||
var clockMenu = {
|
||||
"" : { "title" : "Clock" },
|
||||
"< Back" : () => E.showMenu(mainMenu),
|
||||
"time font":{
|
||||
value: 0|timeFonts.indexOf(settings.clock.timeFont),
|
||||
format: v => timeFonts[v],
|
||||
min: 0, max: timeFonts.length-1,
|
||||
onchange: v => {
|
||||
settings.clock.timeFont = timeFonts[v];
|
||||
writeSettings();
|
||||
}
|
||||
},
|
||||
"time size":{
|
||||
value: 0|settings.clock.timeFontSize,
|
||||
min: 0,
|
||||
onchange: v => {
|
||||
settings.clock.timeFontSize = v;
|
||||
writeSettings();
|
||||
}
|
||||
},
|
||||
"date font":{
|
||||
value: 0|g.getFonts().indexOf(settings.clock.dateFont),
|
||||
format: v => g.getFonts()[v],
|
||||
min: 0, max: g.getFonts().length-1,
|
||||
onchange: v => {
|
||||
settings.clock.dateFont = g.getFonts()[v];
|
||||
writeSettings();
|
||||
}
|
||||
},
|
||||
"date size":{
|
||||
value: 0|settings.clock.dateFontSize,
|
||||
min: 0,
|
||||
onchange: v => {
|
||||
settings.clock.dateFontSize = v;
|
||||
writeSettings();
|
||||
}
|
||||
},
|
||||
"dow font":{
|
||||
value: 0|g.getFonts().indexOf(settings.clock.dowFont),
|
||||
format: v => g.getFonts()[v],
|
||||
min: 0, max: g.getFonts().length-1,
|
||||
onchange: v => {
|
||||
settings.clock.dowFont = g.getFonts()[v];
|
||||
writeSettings();
|
||||
}
|
||||
},
|
||||
"dow size":{
|
||||
value: 0|settings.clock.dowFontSize,
|
||||
min: 0,
|
||||
onchange: v => {
|
||||
settings.clock.dowFontSize = v;
|
||||
writeSettings();
|
||||
}
|
||||
},
|
||||
"short date": {
|
||||
value: !!settings.clock.shortDate,
|
||||
format: BOOL_FORMAT,
|
||||
onchange: v => {
|
||||
settings.clock.shortDate = v;
|
||||
writeSettings();
|
||||
}
|
||||
},
|
||||
"stopwatches": {
|
||||
value: !!settings.clock.showStopwatches,
|
||||
format: v=>v?/*LANG*/"Show":/*LANG*/"Hide",
|
||||
onchange: v => {
|
||||
settings.clock.showStopwatches = v;
|
||||
writeSettings();
|
||||
}
|
||||
},
|
||||
"timers": {
|
||||
value: !!settings.clock.showTimers,
|
||||
format: v=>v?/*LANG*/"Show":/*LANG*/"Hide",
|
||||
onchange: v => {
|
||||
settings.clock.showTimers = v;
|
||||
writeSettings();
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
var stopwatchMenu = {
|
||||
"" : { "title" : "Stopwatch" },
|
||||
"< Back" : () => E.showMenu(mainMenu),
|
||||
"font":{
|
||||
value: 0|g.getFonts().indexOf(settings.stopwatch.font),
|
||||
format: v => g.getFonts()[v],
|
||||
min: 0, max: g.getFonts().length-1,
|
||||
onchange: v => {
|
||||
settings.settings.stopwatch.font = g.getFonts()[v];
|
||||
writeSettings();
|
||||
}
|
||||
},
|
||||
"fontsize":{
|
||||
value: 0|settings.stopwatch.fontSize,
|
||||
min: 0,
|
||||
onchange: v => {
|
||||
settings.stopwatch.fontSize = v;
|
||||
writeSettings();
|
||||
}
|
||||
},
|
||||
"index font":{
|
||||
value: 0|g.getFonts().indexOf(settings.stopwatch.indexFont),
|
||||
format: v => g.getFonts()[v],
|
||||
min: 0, max: g.getFonts().length-1,
|
||||
onchange: v => {
|
||||
settings.settings.stopwatch.indexFont = g.getFonts()[v];
|
||||
writeSettings();
|
||||
}
|
||||
},
|
||||
"index size":{
|
||||
value: 0|settings.stopwatch.indexFontSize,
|
||||
min: 0,
|
||||
onchange: v => {
|
||||
settings.stopwatch.indexFontSize = v;
|
||||
writeSettings();
|
||||
}
|
||||
},
|
||||
"button height":{
|
||||
value: 0|settings.stopwatch.buttonHeight,
|
||||
min: 0,
|
||||
onchange: v => {
|
||||
settings.stopwatch.buttonHeight = v;
|
||||
writeSettings();
|
||||
}
|
||||
},
|
||||
};
|
||||
var timerMenu = {
|
||||
"" : { "title" : "Timer" },
|
||||
"< Back" : () => E.showMenu(mainMenu),
|
||||
"font":{
|
||||
value: 0|g.getFonts().indexOf(settings.timer.font),
|
||||
format: v => g.getFonts()[v],
|
||||
min: 0, max: g.getFonts().length-1,
|
||||
onchange: v => {
|
||||
settings.settings.timer.font = g.getFonts()[v];
|
||||
writeSettings();
|
||||
}
|
||||
},
|
||||
"fontsize":{
|
||||
value: 0|settings.timer.fontSize,
|
||||
min: 0,
|
||||
onchange: v => {
|
||||
settings.timer.fontSize = v;
|
||||
writeSettings();
|
||||
}
|
||||
},
|
||||
"index font":{
|
||||
value: 0|g.getFonts().indexOf(settings.timer.indexFont),
|
||||
format: v => g.getFonts()[v],
|
||||
min: 0, max: g.getFonts().length-1,
|
||||
onchange: v => {
|
||||
settings.settings.timer.indexFont = g.getFonts()[v];
|
||||
writeSettings();
|
||||
}
|
||||
},
|
||||
"index size":{
|
||||
value: 0|settings.timer.indexFontSize,
|
||||
min: 0,
|
||||
onchange: v => {
|
||||
settings.timer.indexFontSize = v;
|
||||
writeSettings();
|
||||
}
|
||||
},
|
||||
"button height":{
|
||||
value: 0|settings.timer.buttonHeight,
|
||||
min: 0,
|
||||
onchange: v => {
|
||||
settings.timer.buttonHeight = v;
|
||||
writeSettings();
|
||||
}
|
||||
},
|
||||
"vibrate":{
|
||||
value: 0|settings.timer.vibrate,
|
||||
min: 0,
|
||||
onchange: v=>{
|
||||
settings.timer.vibrate = v;
|
||||
writeSettings();
|
||||
}
|
||||
}
|
||||
};
|
||||
var alarmMenu = {
|
||||
"" : { "title" : "Alarm" },
|
||||
"< Back" : () => E.showMenu(mainMenu),
|
||||
"font":{
|
||||
value: 0|g.getFonts().indexOf(settings.alarm.font),
|
||||
format: v => g.getFonts()[v],
|
||||
min: 0, max: g.getFonts().length-1,
|
||||
onchange: v => {
|
||||
settings.settings.alarm.font = g.getFonts()[v];
|
||||
writeSettings();
|
||||
}
|
||||
},
|
||||
"fontsize":{
|
||||
value: 0|settings.alarm.fontSize,
|
||||
min: 0,
|
||||
onchange: v => {
|
||||
settings.alarm.fontSize = v;
|
||||
writeSettings();
|
||||
}
|
||||
},
|
||||
"index font":{
|
||||
value: 0|g.getFonts().indexOf(settings.alarm.indexFont),
|
||||
format: v => g.getFonts()[v],
|
||||
min: 0, max: g.getFonts().length-1,
|
||||
onchange: v => {
|
||||
settings.settings.alarm.indexFont = g.getFonts()[v];
|
||||
writeSettings();
|
||||
}
|
||||
},
|
||||
"index size":{
|
||||
value: 0|settings.alarm.indexFontSize,
|
||||
min: 0,
|
||||
onchange: v => {
|
||||
settings.alarm.indexFontSize = v;
|
||||
writeSettings();
|
||||
}
|
||||
},
|
||||
"button height":{
|
||||
value: 0|settings.alarm.buttonHeight,
|
||||
min: 0,
|
||||
onchange: v => {
|
||||
settings.alarm.buttonHeight = v;
|
||||
writeSettings();
|
||||
}
|
||||
},
|
||||
"vibrate":{
|
||||
value: 0|settings.alarm.vibrate,
|
||||
min: 0,
|
||||
onchange: v=>{
|
||||
settings.alarm.vibrate = v;
|
||||
writeSettings();
|
||||
}
|
||||
}
|
||||
};
|
||||
E.showMenu(mainMenu);
|
||||
});
|
||||
|
|
@ -0,0 +1 @@
|
|||
{"id":"timerclk","name":"tclk Stopwatch","src":"timerclk.stopwatch.js","icon":"timerclk.img","version":"0.01","tags":"","files":"","sortorder":10}
|
||||
|
|
@ -0,0 +1,135 @@
|
|||
var timerclk = require("timerclk.lib.js");
|
||||
const height = g.getHeight(), width = g.getWidth();
|
||||
|
||||
var all = require("Storage").readJSON("timerclk.stopwatch.json") || [];
|
||||
|
||||
var settings = require('Storage').readJSON("timerclk.json", true) || {};
|
||||
settings = Object.assign({
|
||||
"font":"Vector",
|
||||
"fontSize":40,
|
||||
"indexFont":"6x8",
|
||||
"indexFontSize":3,
|
||||
"buttonHeight":40,
|
||||
}, settings.stopwatch||{});
|
||||
var defaultElement = {start:null, timeAdd:0};
|
||||
var current = 0;
|
||||
var editIndex = 0;
|
||||
var drawInterval;
|
||||
var drawIntervalTimeout;
|
||||
var buttons;
|
||||
|
||||
function update() {
|
||||
if (drawInterval) clearInterval(drawInterval);
|
||||
if (drawIntervalTimeout) clearTimeout(drawIntervalTimeout);
|
||||
var interval = Math.floor(timerclk.getTime(all[current])/3600000)?1000:100;
|
||||
if (all[current].start) {
|
||||
drawIntervalTimeout = setTimeout(() => {drawInterval = setInterval(draw, interval); draw();}, interval - (timerclk.getTime(all[current]) % interval));
|
||||
} else {
|
||||
drawInterval = null;
|
||||
drawIntervalTimeout = null;
|
||||
}
|
||||
draw();
|
||||
drawButtons();
|
||||
}
|
||||
function play() {
|
||||
if (all[current].start) { // running
|
||||
all[current].timeAdd += Date.now() - all[current].start;
|
||||
all[current].start = null;
|
||||
update();
|
||||
} else { // paused
|
||||
all[current].start = Date.now();
|
||||
update();
|
||||
}
|
||||
require("Storage").write("timerclk.stopwatch.json",JSON.stringify(all));
|
||||
}
|
||||
function reset() {
|
||||
all[current] = defaultElement.clone();
|
||||
update();
|
||||
require("Storage").write("timerclk.stopwatch.json",JSON.stringify(all));
|
||||
}
|
||||
function remove() {
|
||||
all.splice(current, 1);
|
||||
if (current == all.length) current--;
|
||||
if (all.length == 0) {
|
||||
all.push(defaultElement.clone());
|
||||
current++;
|
||||
}
|
||||
update();
|
||||
require("Storage").write("timerclk.stopwatch.json",JSON.stringify(all));
|
||||
}
|
||||
|
||||
function edit(position, change) {
|
||||
if (position == 1) all[current].timeAdd += change*1000;
|
||||
else if (position == 2) all[current].timeAdd += change*60000;
|
||||
else if (position == 3) all[current].timeAdd += change*3600000;
|
||||
require("Storage").write("timerclk.stopwatch.json",JSON.stringify(all));
|
||||
}
|
||||
|
||||
|
||||
var buttonsRunning = {
|
||||
reset: {pos:[0, height-settings.buttonHeight, width/2, height], callback: reset, img: timerclk.reset_img, col:"#f50"},
|
||||
play: {pos:[width/2, height-settings.buttonHeight, width, height], callback: play, img: timerclk.play_img, col:"#0ff"},
|
||||
};
|
||||
var buttonsNormal = {
|
||||
reset: {pos:[0, height-settings.buttonHeight, width/2, height], callback: remove, img: timerclk.remove_img, col:buttonsRunning.reset.col},
|
||||
play: {pos:[width/2, height-settings.buttonHeight, width, height], callback: play, img: timerclk.play_img, col:buttonsRunning.play.col},
|
||||
};
|
||||
buttons = buttonsNormal;
|
||||
|
||||
function drawButtons() {
|
||||
if (all[current].start || all[current].time) {
|
||||
buttons = buttonsRunning;
|
||||
if (all[current].start) {
|
||||
buttons.play.img = timerclk.pause_img;
|
||||
} else {
|
||||
buttons.play.img = timerclk.play_img;
|
||||
}
|
||||
} else {
|
||||
buttons = buttonsNormal;
|
||||
}
|
||||
for (var button of buttons) {
|
||||
g.setColor(button.col);
|
||||
g.fillRect(button.pos[0], button.pos[1], button.pos[2], button.pos[3]);
|
||||
g.setColor("#000");
|
||||
// scale 24px images
|
||||
let iw = settings.buttonHeight-10;
|
||||
var scale = iw/24;
|
||||
let ix = button.pos[0] + ((button.pos[2]-button.pos[0] - iw) /2);
|
||||
let iy = button.pos[1] + ((button.pos[3]-button.pos[1] - iw) /2);
|
||||
g.drawImage(button.img, ix, iy, {scale: scale});
|
||||
}
|
||||
}
|
||||
|
||||
function draw() {
|
||||
var x = g.getWidth()/2;
|
||||
var y = g.getHeight()/2;
|
||||
g.reset();
|
||||
|
||||
var timeStr = timerclk.formatTime(timerclk.getTime(all[current]), false, true);
|
||||
g.clearRect(Bangle.appRect.x, Bangle.appRect.y, Bangle.appRect.x2, Bangle.appRect.y2-settings.buttonHeight);
|
||||
g.setFontAlign(0,0).setFont(settings.indexFont, settings.indexFontSize);
|
||||
g.drawString(current+1, x, Bangle.appRect.y + (g.stringMetrics("0").height/2));
|
||||
g.setFontAlign(0,0).setFont(settings.font, settings.fontSize);
|
||||
g.drawString(timeStr,x,y);
|
||||
|
||||
var start = (width-g.stringMetrics(timeStr).width)/2;
|
||||
timeStr = timeStr.split(".")[0].split(":");
|
||||
if (timeStr.length < 3) timeStr = [""].concat(timeStr);
|
||||
var markerPosChange = g.stringMetrics("__").width/2;
|
||||
if (editIndex == 3) x = start + g.stringMetrics(timeStr[0]).width - markerPosChange;
|
||||
else if (editIndex == 2) x = start + g.stringMetrics(timeStr[0]+":"+timeStr[1]).width - markerPosChange;
|
||||
else if (editIndex == 1) x = start + g.stringMetrics(timeStr[0]+":"+timeStr[1]+":"+timeStr[2]).width - markerPosChange;
|
||||
else x = 0;
|
||||
if (x) g.drawString("__", x, y);
|
||||
dragBorderHrsMins = start+g.stringMetrics(timeStr[0]).width+g.stringMetrics(":").width/2;
|
||||
dragBorderMinsSecs = start+g.stringMetrics(timeStr[0]+":"+timeStr[1]).width+g.stringMetrics(":").width/2;
|
||||
}
|
||||
|
||||
if (all.length == 0) {
|
||||
all.push(defaultElement.clone());
|
||||
}
|
||||
timerclk.registerControls(this);
|
||||
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
update();
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
if (timerclkTimerTimeout) clearInterval(timerclkTimerTimeout);
|
||||
var timerclk = require("timerclk.lib.js");
|
||||
var settings = require('Storage').readJSON("timerclk.json", true) || {};
|
||||
settings = Object.assign({
|
||||
"vibrate":10
|
||||
}, settings.timer||{});
|
||||
|
||||
function showTimer(timer) {
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
Bangle.setLocked(false);
|
||||
E.showPrompt("Timer finished!",{
|
||||
title:"TIMER!",
|
||||
buttons : {/*LANG*/"Ok":true}
|
||||
}).then(function(ok) {
|
||||
buzzCount = 0;
|
||||
if (ok) {
|
||||
timer.time += Date.now() - timer.start;
|
||||
timer.start = null;
|
||||
}
|
||||
require("Storage").write("timerclk.timer.json",JSON.stringify(timers));
|
||||
load();
|
||||
});
|
||||
function vibrate(counter) {
|
||||
VIBRATE.write(1);
|
||||
setTimeout(() => VIBRATE.write(0), 100);
|
||||
if (--counter) setTimeout(() => vibrate(counter), 250);
|
||||
}
|
||||
function buzz() {
|
||||
if ((require('Storage').readJSON('setting.json',1)||{}).quiet>1) return; // total silence
|
||||
vibrate(4);
|
||||
if (buzzCount--)
|
||||
setTimeout(buzz, 3000);
|
||||
else { // auto-snooze
|
||||
buzzCount = settings.vibrate;
|
||||
setTimeout(buzz, 600000);
|
||||
}
|
||||
}
|
||||
var buzzCount = settings.vibrate;
|
||||
buzz();
|
||||
}
|
||||
|
||||
// Check for timers
|
||||
console.log("checking for timers...");
|
||||
var timers = require("Storage").readJSON("timerclk.timer.json",1)||[];
|
||||
var active = timers.filter(e=>e.start);
|
||||
if (active.length) {
|
||||
// if there's an timer, show it
|
||||
active = active.sort((a,b)=>{
|
||||
var at = a.time;
|
||||
if (a.start) at += Date.now()-a.start;
|
||||
at = a.period-at;
|
||||
var bt = b.time;
|
||||
if (b.start) bt += Date.now()-b.start;
|
||||
bt = b.period-bt;
|
||||
return at-bt;
|
||||
});
|
||||
showTimer(active[0]);
|
||||
} else {
|
||||
// otherwise just go back to default app
|
||||
setTimeout(load, 100);
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
{"id":"timerclk","name":"tclk Timer","src":"timerclk.timer.js","icon":"timerclk.img","version":"0.01","tags":"","files":"","sortorder":10}
|
||||
|
|
@ -0,0 +1,139 @@
|
|||
var timerclk = require("timerclk.lib.js");
|
||||
const height = g.getHeight(), width = g.getWidth();
|
||||
|
||||
var all = require("Storage").readJSON("timerclk.timer.json") || [];
|
||||
var settings = require('Storage').readJSON("timerclk.json", true) || {};
|
||||
settings = Object.assign({
|
||||
"font":"Vector",
|
||||
"fontSize":40,
|
||||
"indexFont":"6x8",
|
||||
"indexFontSize":3,
|
||||
"buttonHeight":40,
|
||||
"vibrate":4,
|
||||
}, settings = settings.timer||{});
|
||||
var defaultElement = {time:300000, start:null, timeAdd:0};
|
||||
|
||||
var current = 0;
|
||||
var editIndex = 0;
|
||||
var drawInterval;
|
||||
var drawIntervalTimeout;
|
||||
var buttons;
|
||||
var dragBorderHrsMins=0, dragBorderMinsSecs=0;
|
||||
|
||||
function update() {
|
||||
if (drawInterval) clearInterval(drawInterval);
|
||||
if (drawIntervalTimeout) clearTimeout(drawIntervalTimeout);
|
||||
if (all[current].start) {
|
||||
drawIntervalTimeout = setTimeout(() => {drawInterval = setInterval(draw, 1000); draw();}, 1000 - (timerclk.getTime(all[current]) % 1000));
|
||||
} else {
|
||||
drawInterval = null;
|
||||
drawIntervalTimeout = null;
|
||||
}
|
||||
draw();
|
||||
drawButtons();
|
||||
}
|
||||
function play() {
|
||||
if (all[current].start) { // running
|
||||
all[current].timeAdd += Date.now() - all[current].start;
|
||||
all[current].start = null;
|
||||
update();
|
||||
} else { // paused
|
||||
all[current].start = Date.now();
|
||||
update();
|
||||
}
|
||||
require("Storage").write("timerclk.timer.json",JSON.stringify(all));
|
||||
timerclkCheckTimers();
|
||||
}
|
||||
function reset() {
|
||||
all[current] = defaultElement.clone();
|
||||
update();
|
||||
require("Storage").write("timerclk.timer.json",JSON.stringify(all));
|
||||
timerclkCheckTimers();
|
||||
}
|
||||
function remove() {
|
||||
all.splice(current, 1);
|
||||
if (current == all.length) current--;
|
||||
if (all.length == 0) {
|
||||
all.push(defaultElement.clone());
|
||||
current++;
|
||||
}
|
||||
update();
|
||||
require("Storage").write("timerclk.timer.json",JSON.stringify(all));
|
||||
timerclkCheckTimers();
|
||||
}
|
||||
|
||||
function edit(position, change) {
|
||||
if (position == 1) all[current].time += change*1000;
|
||||
else if (position == 2) all[current].time += change*60000;
|
||||
else if (position == 3) all[current].time += change*3600000;
|
||||
require("Storage").write("timerclk.timer.json",JSON.stringify(all));
|
||||
timerclkCheckTimers();
|
||||
}
|
||||
|
||||
var buttonsRunning = {
|
||||
reset: {pos:[0, height-settings.buttonHeight, width/2, height], callback: reset, img: timerclk.reset_img, col:"#f50"},
|
||||
play: {pos:[width/2, height-settings.buttonHeight, width, height], callback: play, img: timerclk.play_img, col:"#0ff"},
|
||||
};
|
||||
var buttonsNormal = {
|
||||
reset: {pos:[0, height-settings.buttonHeight, width/2, height], callback: remove, img: timerclk.remove_img, col:buttonsRunning.reset.col},
|
||||
play: {pos:[width/2, height-settings.buttonHeight, width, height], callback: play, img: timerclk.play_img, col:buttonsRunning.play.col},
|
||||
};
|
||||
buttons = buttonsNormal;
|
||||
|
||||
|
||||
function drawButtons() {
|
||||
if (all[current].start || all[current].timeAdd) {
|
||||
buttons = buttonsRunning;
|
||||
if (all[current].start) {
|
||||
buttons.play.img = timerclk.pause_img;
|
||||
} else {
|
||||
buttons.play.img = timerclk.play_img;
|
||||
}
|
||||
} else {
|
||||
buttons = buttonsNormal;
|
||||
}
|
||||
for (var button of buttons) {
|
||||
g.setColor(button.col);
|
||||
g.fillRect(button.pos[0], button.pos[1], button.pos[2], button.pos[3]);
|
||||
g.setColor("#000");
|
||||
// scale 24px images
|
||||
let iw = settings.buttonHeight-10;
|
||||
var scale = iw/24;
|
||||
let ix = button.pos[0] + ((button.pos[2]-button.pos[0] - iw) /2);
|
||||
let iy = button.pos[1] + ((button.pos[3]-button.pos[1] - iw) /2);
|
||||
g.drawImage(button.img, ix, iy, {scale: scale});
|
||||
}
|
||||
}
|
||||
|
||||
function draw() {
|
||||
var x = g.getWidth()/2;
|
||||
var y = g.getHeight()/2;
|
||||
g.reset();
|
||||
|
||||
var time = all[current].time - timerclk.getTime(all[current]);
|
||||
g.clearRect(Bangle.appRect.x, Bangle.appRect.y, Bangle.appRect.x2, Bangle.appRect.y2-settings.buttonHeight);
|
||||
g.setFontAlign(0,0).setFont(settings.indexFont, settings.indexFontSize);
|
||||
g.drawString(current+1, x, Bangle.appRect.y + (g.stringMetrics("0").height/2));
|
||||
g.setFontAlign(0,0).setFont(settings.font, settings.fontSize);
|
||||
var timeStr = timerclk.formatTime(time, false, false, true);
|
||||
g.drawString(timeStr,x,y);
|
||||
|
||||
var start = (width-g.stringMetrics(timeStr).width)/2;
|
||||
timeStr = timeStr.split(":");
|
||||
var markerPosChange = g.stringMetrics("__").width/2;
|
||||
if (editIndex == 3) x = start + g.stringMetrics(timeStr[0]).width - markerPosChange;
|
||||
else if (editIndex == 2) x = start + g.stringMetrics(timeStr[0]+":"+timeStr[1]).width - markerPosChange;
|
||||
else if (editIndex == 1) x = start + g.stringMetrics(timeStr[0]+":"+timeStr[1]+":"+timeStr[2]).width - markerPosChange;
|
||||
else x = 0;
|
||||
if (x) g.drawString("__", x, y);
|
||||
dragBorderHrsMins = start+g.stringMetrics(timeStr[0]).width+g.stringMetrics(":").width/2;
|
||||
dragBorderMinsSecs = start+g.stringMetrics(timeStr[0]+":"+timeStr[1]).width+g.stringMetrics(":").width/2;
|
||||
}
|
||||
|
||||
if (all.length == 0) {
|
||||
all.push(defaultElement.clone());
|
||||
}
|
||||
timerclk.registerControls(this);
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
update();
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
WIDGETS["timerclk.alarm"]={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["timerclk.alarm"].width = (require('Storage').readJSON('timerclk.alarm.json',1)||[]).some(alarm=>alarm.on) ? 24 : 0;
|
||||
}
|
||||
};
|
||||
WIDGETS["timerclk.alarm"].reload();
|
||||
|
|
@ -7,6 +7,7 @@
|
|||
"icon": "app.png",
|
||||
"type": "launch",
|
||||
"tags": "tool,system,launcher",
|
||||
"screenshots": [{"url":"screenshot1.jpg"}],
|
||||
"supports": ["BANGLEJS","BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
"storage": [
|
||||
|
|
|
|||
|
After Width: | Height: | Size: 3.7 KiB |
|
|
@ -8,6 +8,7 @@
|
|||
"tags": "health,bluetooth",
|
||||
"supports": ["BANGLEJS","BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
"screenshots": [{"url":"Vernier-go-direct-respiration-belt-screenshot.png"}],
|
||||
"storage": [
|
||||
{"name":"vernierrespirate.app.js","url":"app.js"},
|
||||
{"name":"vernierrespirate.img","url":"app-icon.js","evaluate":true}
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
0.1: First release.
|
||||
0.01: First release.
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"name": "Charging Status",
|
||||
"shortName":"ChargingStatus",
|
||||
"icon": "widget.png",
|
||||
"version":"0.1",
|
||||
"version":"0.01",
|
||||
"type": "widget",
|
||||
"description": "A simple widget that shows a yellow lightning icon to indicate whenever the watch is charging. This way one can see the charging status at a glance, no matter which battery widget is being used.",
|
||||
"tags": "widget",
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
1.00: Release for Bangle 2 (2021/11/18)
|
||||
1.01: Internal id update to wid_* as per Gordon's request (2021/11/21)
|
||||
1.02: Support dark themes
|
||||
1.03: Increase screen update rate when charging
|
||||
0.01: Release for Bangle 2 (2021/11/18)
|
||||
0.02: Internal id update to wid_* as per Gordon's request (2021/11/21)
|
||||
0.03: Support dark themes
|
||||
0.04: Increase screen update rate when charging
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
"name": "A Battery Widget (with percentage)",
|
||||
"shortName":"A Battery Widget",
|
||||
"icon": "widget.png",
|
||||
"version":"1.03",
|
||||
"version":"0.04",
|
||||
"type": "widget",
|
||||
"supports": ["BANGLEJS", "BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
|
|
|
|||
|
|
@ -1,2 +1,3 @@
|
|||
0.01: Created
|
||||
0.02: Set sort order to -10 so always display in right hand corner
|
||||
0.03: Set sort order from the code
|
||||
|
|
|
|||
|
|
@ -4,13 +4,12 @@
|
|||
"shortName":"Battery Theme",
|
||||
"icon": "widbata.png",
|
||||
"screenshots": [{"url":"screenshot_widbata_1.png"}],
|
||||
"version":"0.02",
|
||||
"version":"0.03",
|
||||
"type": "widget",
|
||||
"supports": ["BANGLEJS", "BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
"description": "Shows the current battery level status in the top right using the clocks colour theme",
|
||||
"tags": "widget,battery",
|
||||
"sortorder": -10,
|
||||
"storage": [
|
||||
{"name":"widbata.wid.js","url":"widbata.wid.js"}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ setInterval(()=>WIDGETS["bata"].draw(), 60000);
|
|||
Bangle.on('lcdPower', function(on) {
|
||||
if (on) WIDGETS["bata"].draw();
|
||||
});
|
||||
WIDGETS["bata"]={area:"tr",width:27,draw:function() {
|
||||
WIDGETS["bata"]={area:"tr",sortorder:-10,width:27,draw:function() {
|
||||
var s = 26;
|
||||
var t = 13; // thickness
|
||||
var x = this.x, y = this.y;
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
"tags": "widget,battery",
|
||||
"supports": ["BANGLEJS","BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
"screenshots": [{"url":"widbatpc.full.jpg"},{"url":"widbatpc.part.jpg"}],
|
||||
"storage": [
|
||||
{"name":"widbatpc.wid.js","url":"widget.js"},
|
||||
{"name":"widbatpc.settings.js","url":"settings.js"}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
"type": "widget",
|
||||
"tags": "widget,tool",
|
||||
"allow_emulator": true,
|
||||
"screenshots": [{"url":"wash-hand-timer-screenshot.png"}],
|
||||
"supports": ["BANGLEJS", "BANGLEJS2"],
|
||||
"storage": [
|
||||
{"name":"widhwt.app.js","url":"app.js"},
|
||||
|
|
|
|||
|
After Width: | Height: | Size: 2.0 KiB |
|
|
@ -3,3 +3,4 @@
|
|||
0.03: Don't try to be fancy - just bail out on firmwares without a lock event
|
||||
0.04: Set sortorder to -1 so that widget always takes up the furthest left position
|
||||
0.05: Set sortorder to -10 so that others can take -1 etc
|
||||
0.06: Set sortorder to -10 in widget code
|
||||
|
|
|
|||
|
|
@ -1,13 +1,12 @@
|
|||
{
|
||||
"id": "widlock",
|
||||
"name": "Lock Widget",
|
||||
"version": "0.05",
|
||||
"version": "0.06",
|
||||
"description": "On devices with always-on display (Bangle.js 2) this displays lock icon whenever the display is locked",
|
||||
"icon": "widget.png",
|
||||
"type": "widget",
|
||||
"tags": "widget,lock",
|
||||
"supports": ["BANGLEJS","BANGLEJS2"],
|
||||
"sortorder": -10,
|
||||
"storage": [
|
||||
{"name":"widlock.wid.js","url":"widget.js"}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
WIDGETS["lock"].width = Bangle.isLocked()?16:0;
|
||||
Bangle.drawWidgets();
|
||||
});
|
||||
WIDGETS["lock"]={area:"tl",width:Bangle.isLocked()?16:0,draw:function(w) {
|
||||
WIDGETS["lock"]={area:"tl",sortorder:10,width:Bangle.isLocked()?16:0,draw:function(w) {
|
||||
if (Bangle.isLocked())
|
||||
g.reset().drawImage(atob("DhABH+D/wwMMDDAwwMf/v//4f+H/h/8//P/z///f/g=="), w.x+1, w.y+4);
|
||||
}};
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
0.01: First release
|
||||
0.02: Size widget after step count is reset
|
||||
0.03: set sortorder to -1
|
||||
0.04: set sortorder through code
|
||||
|
|
|
|||
|
|
@ -4,13 +4,12 @@
|
|||
"shortName":"Simple Pedometer",
|
||||
"icon": "screenshot_widpa.png",
|
||||
"screenshots": [{"url":"screenshot_widpa.png"}],
|
||||
"version":"0.03",
|
||||
"version":"0.04",
|
||||
"type": "widget",
|
||||
"supports": ["BANGLEJS", "BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
"description": "Displays the current step count from `Bangle.getHealthStatus(\"day\").steps` in 12x16 font, requires firmware v2.11.21 or later",
|
||||
"tags": "widget,battery",
|
||||
"sortorder": -1,
|
||||
"storage": [
|
||||
{"name":"widpa.wid.js","url":"widpa.wid.js"}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ Bangle.on('step', function(s) { WIDGETS["widpa"].draw(); });
|
|||
Bangle.on('lcdPower', function(on) {
|
||||
if (on) WIDGETS["widpa"].draw();
|
||||
});
|
||||
WIDGETS["widpa"]={area:"tl",width:13,draw:function() {
|
||||
WIDGETS["widpa"]={area:"tl",sortorder:-1,width:13,draw:function() {
|
||||
if (!Bangle.isLCDOn()) return; // dont redraw if LCD is off
|
||||
var steps = Bangle.getHealthStatus("day").steps;
|
||||
var w = 1 + (steps.toString().length)*12;
|
||||
|
|
|
|||
|
|
@ -2,3 +2,4 @@
|
|||
0.02: Fixed widget id to wibpb, Size widget after step count is reset
|
||||
0.03: Fixed widget id in onStep() come on get it right!
|
||||
0.04: set sortorder to -1
|
||||
0.05: set sortorder through code
|
||||
|
|
|
|||
|
|
@ -4,13 +4,12 @@
|
|||
"shortName":"Lato Pedometer",
|
||||
"icon": "screenshot_widpb.png",
|
||||
"screenshots": [{"url":"screenshot_widpb.png"}],
|
||||
"version":"0.04",
|
||||
"version":"0.05",
|
||||
"type": "widget",
|
||||
"supports": ["BANGLEJS", "BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
"description": "Displays the current step count from `Bangle.getHealthStatus(\"day\").steps` in the Lato font, requires firmware v2.11.21 or later",
|
||||
"tags": "widget,battery",
|
||||
"sortorder": -1,
|
||||
"storage": [
|
||||
{"name":"widpb.wid.js","url":"widpb.wid.js"}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ Bangle.on('step', function(s) { WIDGETS["widpb"].draw(); });
|
|||
Bangle.on('lcdPower', function(on) {
|
||||
if (on) WIDGETS["widpb"].draw();
|
||||
});
|
||||
WIDGETS["widpb"]={area:"tl",width:13,draw:function() {
|
||||
WIDGETS["widpb"]={area:"tl",sortorder:-1,width:13,draw:function() {
|
||||
if (!Bangle.isLCDOn()) return; // dont redraw if LCD is off
|
||||
var steps = Bangle.getHealthStatus("day").steps;
|
||||
var w = 1 + (steps.toString().length)*12;
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ for Noble.
|
|||
var SETTINGS = {
|
||||
pretokenise : true
|
||||
};
|
||||
var APPSDIR = __dirname+"/../apps/";
|
||||
var Utils = require("../core/js/utils.js");
|
||||
var AppInfo = require("../core/js/appinfo.js");
|
||||
var noble;
|
||||
|
|
@ -29,18 +30,27 @@ if (!noble) {
|
|||
console.log(" npm install noble")
|
||||
}
|
||||
|
||||
var apps;
|
||||
var apps = [];
|
||||
|
||||
function ERROR(msg) {
|
||||
console.error(msg);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
var apps = [];
|
||||
var dirs = require("fs").readdirSync(APPSDIR, {withFileTypes: true});
|
||||
dirs.forEach(dir => {
|
||||
var appsFile;
|
||||
if (dir.name.startsWith("_example") || !dir.isDirectory())
|
||||
return;
|
||||
try {
|
||||
apps = JSON.parse(require("fs").readFileSync(__dirname+"/../apps.json"));
|
||||
appsFile = require("fs").readFileSync(APPSDIR+dir.name+"/metadata.json").toString();
|
||||
} catch (e) {
|
||||
ERROR("'apps.json' could not be loaded");
|
||||
ERROR(dir.name+"/metadata.json does not exist");
|
||||
return;
|
||||
}
|
||||
apps.push(JSON.parse(appsFile));
|
||||
});
|
||||
|
||||
var args = process.argv;
|
||||
|
||||
|
|
|
|||
|
|
@ -13,17 +13,36 @@
|
|||
#
|
||||
# If you do this, please do not attempt to commit your modified
|
||||
# apps.json back into the main BangleApps repository!
|
||||
#
|
||||
# You can pass an optional filename to this script, and it will write
|
||||
# to that instead, apps.local.json is used when opening the loader on localhost
|
||||
outfile="${1:-apps.json}"
|
||||
|
||||
cd `dirname $0`/..
|
||||
echo "[" > apps.json
|
||||
echo "[" > "$outfile"
|
||||
first=1
|
||||
for app in apps/*/; do
|
||||
echo "Processing $app...";
|
||||
if [[ "$app" =~ ^apps/_example.* ]]; then
|
||||
echo "Ignoring $app"
|
||||
else
|
||||
cat ${app}metadata.json >> apps.json
|
||||
if [ $first -eq 1 ]; then
|
||||
first=0;
|
||||
else
|
||||
echo "," >> "$outfile"
|
||||
fi;
|
||||
cat ${app}metadata.json >> "$outfile"
|
||||
# echo ",\"$app\"," >> apps.json # DEBUG ONLY
|
||||
echo "," >> apps.json
|
||||
fi
|
||||
done
|
||||
echo "null]" >> apps.json
|
||||
echo "]" >> "$outfile"
|
||||
|
||||
if [ -z "$1"]; then
|
||||
# Running with no arguments: prevent accidental commit of modified apps.json.
|
||||
# You can use `create_apps.json.sh apps.json` if you really want to both
|
||||
# overwrite and still commit apps.json
|
||||
git update-index --skip-worktree apps.json
|
||||
echo "Told git to ignore modified apps.json."
|
||||
# If you want to unignore it, use
|
||||
# 'git update-index --no-skip-worktree apps.json'
|
||||
fi
|
||||
|
|
@ -10,7 +10,6 @@ var SETTINGS = {
|
|||
var path = require('path');
|
||||
var ROOTDIR = path.join(__dirname, '..');
|
||||
var APPDIR = ROOTDIR+'/apps';
|
||||
var APPJSON = ROOTDIR+'/apps.json';
|
||||
var OUTFILE = ROOTDIR+'/firmware.js';
|
||||
var DEVICE = "BANGLEJS";
|
||||
var APPS = [ // IDs of apps to install
|
||||
|
|
@ -28,7 +27,6 @@ global.Const = {
|
|||
};
|
||||
|
||||
var AppInfo = require(ROOTDIR+"/core/js/appinfo.js");
|
||||
var appjson = JSON.parse(fs.readFileSync(APPJSON).toString());
|
||||
var appfiles = [];
|
||||
|
||||
function fileGetter(url) {
|
||||
|
|
@ -58,8 +56,11 @@ function fileGetter(url) {
|
|||
}
|
||||
|
||||
Promise.all(APPS.map(appid => {
|
||||
var app = appjson.find(app=>app.id==appid);
|
||||
if (app===undefined) throw new Error(`App ${appid} not found`);
|
||||
try {
|
||||
var app = JSON.parse(fs.readFileSync(APPDIR + "/" + appid + "metadata.json").toString());
|
||||
} catch (e) {
|
||||
throw new Error(`App ${appid} not found`);
|
||||
}
|
||||
return AppInfo.getFiles(app, {
|
||||
fileGetter : fileGetter,
|
||||
settings : SETTINGS,
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ var DEVICE = process.argv[2];
|
|||
var path = require('path');
|
||||
var ROOTDIR = path.join(__dirname, '..');
|
||||
var APPDIR = ROOTDIR+'/apps';
|
||||
var APPJSON = ROOTDIR+'/apps.json';
|
||||
var MINIFY = true;
|
||||
var OUTFILE, APPS;
|
||||
|
||||
|
|
@ -86,7 +85,6 @@ function atob(input) {
|
|||
}
|
||||
|
||||
var AppInfo = require(ROOTDIR+"/core/js/appinfo.js");
|
||||
var appjson = JSON.parse(fs.readFileSync(APPJSON).toString());
|
||||
var appfiles = [];
|
||||
|
||||
function fileGetter(url) {
|
||||
|
|
@ -134,8 +132,11 @@ function evaluateFile(file) {
|
|||
}
|
||||
|
||||
Promise.all(APPS.map(appid => {
|
||||
var app = appjson.find(app=>app.id==appid);
|
||||
if (app===undefined) throw new Error(`App ${appid} not found`);
|
||||
try {
|
||||
var app = JSON.parse(fs.readFileSync(APPDIR + "/" + appid + "metadata.json").toString());
|
||||
} catch (e) {
|
||||
throw new Error(`App ${appid} not found`);
|
||||
}
|
||||
return AppInfo.getFiles(app, {
|
||||
fileGetter : fileGetter,
|
||||
settings : SETTINGS,
|
||||
|
|
|
|||
2
core
|
|
@ -1 +1 @@
|
|||
Subproject commit 5023ee1228030130ba9f026d5dbe920f7527ee7d
|
||||
Subproject commit 3093d78a5d752cbf03ea8f9a1a7c0b50b9c8123b
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
{
|
||||
"//":"Czech language translations",
|
||||
"GLOBAL": {
|
||||
"//":"Translations that apply for all apps",
|
||||
"Alarm" : "Budík",
|
||||
"Hour" : "Hodina",
|
||||
"Hours" : "Hodiny",
|
||||
"Minute" : "Minuta",
|
||||
"Minutes" : "Minuty",
|
||||
"Second" : "Sekunda",
|
||||
"Seconds" : "Sekundy",
|
||||
"Month" : "Měsíc",
|
||||
"Enabled" : "Povoleno",
|
||||
"Background" : "Pozadí",
|
||||
"Connected" : "Připojeno",
|
||||
"Settings" : "Nastavení",
|
||||
"Save" : "Uložit",
|
||||
"Back" : "Zpět",
|
||||
"Repeat" : "Opakovat",
|
||||
"Delete" : "Smazat",
|
||||
"Sleep" : "Uspat",
|
||||
"Alarms" : "Budíky",
|
||||
"ALARM!" : "BUDÍK!",
|
||||
|
||||
" (repeat)" : " (opakovat)",
|
||||
"< Back" : "< Zpět",
|
||||
"> Delete" : "> Smazat",
|
||||
"> Save" : " > Uložit",
|
||||
"ALARM " : "BUDÍK ",
|
||||
|
||||
"Add Device" : "Přidat zařízení",
|
||||
"App Settings" : "Nast. Aplikací",
|
||||
"Apps" : "Aplikace"
|
||||
|
||||
},
|
||||
"alarm": {
|
||||
"//":"App-specific overrides",
|
||||
"Alarm/Timer" : "Budik/Časovač",
|
||||
"rpt" : "Opk.",
|
||||
"New Alarm" : "Nový budík",
|
||||
"New Timer" : "Nový časovač",
|
||||
"Auto snooze" : "Auto odložit"
|
||||
},
|
||||
"setting" : {
|
||||
"Quiet Mode" : "Tichý režim"
|
||||
|
||||
},
|
||||
"messages": {
|
||||
"Are you sure?" : "Opravdu?"
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
[
|
||||
{"code":"en_GB","name":"British English","url":"en_GB.json"},
|
||||
{"code":"cs_CZ","name":"Czech","url":"cs_CZ.json"},
|
||||
{"code":"de_DE","name":"German","url":"de_DE.json"},
|
||||
{"code":"es_ES","name":"Spanish","url":"es_ES.json"},
|
||||
{"code":"fi_FI","name":"Finnish","url":"fi_FI.json"},
|
||||
|
|
|
|||
|
|
@ -5,6 +5,11 @@ if (window.location.host=="banglejs.com") {
|
|||
document.title += " [Development]";
|
||||
document.getElementById("apploaderlinks").innerHTML =
|
||||
'This is the development Bangle.js App Loader - you can also try the <a href="https://banglejs.com/apps/">Official Version</a> for stable apps.';
|
||||
} else if (window.location.hostname==='localhost') {
|
||||
document.title += " [Local]";
|
||||
Const.APPS_JSON_FILE = "apps.local.json";
|
||||
document.getElementById("apploaderlinks").innerHTML =
|
||||
'This is your local Bangle.js App Loader - you can try the <a href="https://banglejs.com/apps/">Official Version</a> here.';
|
||||
} else {
|
||||
document.title += " [Unofficial]";
|
||||
document.getElementById("apploaderlinks").innerHTML =
|
||||
|
|
|
|||
|
|
@ -9,9 +9,17 @@
|
|||
"scripts": {
|
||||
"lint-apps": "eslint ./apps --ext .js",
|
||||
"test": "node bin/sanitycheck.js && eslint ./apps --ext .js",
|
||||
"update-local-apps": "./bin/create_apps_json.sh apps.local.json",
|
||||
"local": "npm-watch & npx http-server -a localhost -c-1",
|
||||
"start": "npx http-server -c-1"
|
||||
},
|
||||
"watch": {
|
||||
"update-local-apps": "apps/*/metadata.json"
|
||||
},
|
||||
"dependencies": {
|
||||
"acorn": "^7.2.0"
|
||||
},
|
||||
"devDpendencies": {
|
||||
"npm-watch": "^0.11.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||