pull/1663/head
storm64 2022-04-06 23:40:54 +02:00
commit 2d291b4d70
55 changed files with 1395 additions and 119 deletions

2
apps/90sclk/ChangeLog Normal file
View File

@ -0,0 +1,2 @@
0.01: New App!
0.02: Fullscreen settings.

13
apps/90sclk/README.md Normal file
View File

@ -0,0 +1,13 @@
# 90s Clock
A watch face in 90s style:
![](screenshot_2.png)
Fullscreen mode can be enabled in the settings:
![](screenshot.png)
## Creator
- [David Peer](https://github.com/peerdavid)

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

@ -0,0 +1 @@
require("heatshrink").decompress(atob("mEwgc8+fAgEgwAMDvPnz99BYdl2weHtu27ft2AGBiEcuEAhAPDg4jGgECIRMN23fthUNgP374vBAB3gAgc/gAXNjlx4EDxwJEpAjG/6IBjkBL4UAjVgBAJuCgPHBQMFEIkkyQjFhwEClgXBEYNBwkQJoibCBwNFBAUCEAVAQZAjC/8euPHDon//hKB//xEYMP//jBYP/+ARDNYM///+EYIgBj1B/8fCIUhEYQRB//FUIM/EZU4EYMkEYP/8VhEYUH/gRBWAUfI4MD+AjBoAsBwEH8EB/EDwE4HwYjCuEHWAOHgExEYKbBCIZNB8fAEYQHByE/EwPABAY+BgRHDBANyJQXHNwIjD8CSBj/+BwMSTwOOBYK2D/4CCNYZQB/iJBQwYjCCIcAgeBSoOAWYQjEVoIRCNAIjKAQKJBgAFC8ZoCWwJbDABMHGQPAAoMQB5EDx/4A4gqBZwIGCWwIABuBWC4EBZwPgv/AcwS/EAAcIU4IRBVQIRKEwIjBv0ARIUDCJIjD//x/ARK/5HC/+BCJkcI45uDgECUgQjCWAM4WwUBWYanEAA8cTARWBEYUC5RAHw1YgEOFQXADQPHIIkAhgICuARBh0A23blhHBagIKBsOGjNswhHDEYUUAoTUBhkxEYMwKwU503bvuwXILmCEYMYsumWYYjB85lDEYovBEYXm7fs25EBI4kYtOWNwIjD4+8NYsw4YjGz9/2hrEoOGjVBwE4NYdzNYSwBuEDEYcxaIUA8+atugGogjBiVgWAI"))

144
apps/90sclk/app.js Normal file

File diff suppressed because one or more lines are too long

BIN
apps/90sclk/app.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

BIN
apps/90sclk/bg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

18
apps/90sclk/metadata.json Normal file
View File

@ -0,0 +1,18 @@
{
"id": "90sclk",
"name": "90s Clock",
"version": "0.02",
"description": "A 90s style watch-face",
"readme": "README.md",
"icon": "app.png",
"screenshots": [{"url":"screenshot.png"},{"url":"screenshot_2.png"}],
"type": "clock",
"tags": "clock",
"supports": ["BANGLEJS2"],
"allow_emulator": true,
"storage": [
{"name":"90sclk.app.js","url":"app.js"},
{"name":"90sclk.img","url":"app-icon.js","evaluate":true},
{"name":"90sclk.settings.js","url":"settings.js"}
]
}

BIN
apps/90sclk/screenshot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

31
apps/90sclk/settings.js Normal file
View File

@ -0,0 +1,31 @@
(function(back) {
const SETTINGS_FILE = "90sclk.setting.json";
// initialize with default settings...
const storage = require('Storage')
let settings = {
fullscreen: false,
};
let saved_settings = storage.readJSON(SETTINGS_FILE, 1) || settings;
for (const key in saved_settings) {
settings[key] = saved_settings[key]
}
function save() {
storage.write(SETTINGS_FILE, settings)
}
E.showMenu({
'': { 'title': '90s Clock' },
'< Back': back,
'Full Screen': {
value: settings.fullscreen,
format: () => (settings.fullscreen ? 'Yes' : 'No'),
onchange: () => {
settings.fullscreen = !settings.fullscreen;
save();
},
}
});
})

2
apps/altimeter/ChangeLog Normal file
View File

@ -0,0 +1,2 @@
0.01: New App!
0.02: Actually upload correct code

View File

@ -0,0 +1 @@
require("heatshrink").decompress(atob("mEw4UA///t9TmuV3+GJf4AN+ALVgf8BasP/4LVn//4ALUWgJUJBZUDBYJUIBZcP3/nKhEOt/WBZE5r+VKg0KgEVr9V3wLHqtaqt9sALElWAqoABt1QBZNeBYuq0ILCrVUBYulBYVWBYkCBYgABBZ8K1WVBYlABZegKQWqBQlVqALKqWoKQWpBYtWBZeqKRAAB1WABZZSHAANq0ALLKQ6qC1ALLKQ5UEAH4AG"))

30
apps/altimeter/app.js Normal file
View File

@ -0,0 +1,30 @@
Bangle.setBarometerPower(true, "app");
g.clear(1);
Bangle.loadWidgets();
Bangle.drawWidgets();
var zero = 0;
var R = Bangle.appRect;
var y = R.y + R.h/2;
var MEDIANLENGTH = 20;
var avr = [], median;
var value = 0;
Bangle.on('pressure', function(e) {
while (avr.length>MEDIANLENGTH) avr.pop();
avr.unshift(e.altitude);
median = avr.slice().sort();
g.reset().clearRect(0,y-30,g.getWidth()-10,y+30);
if (median.length>10) {
var mid = median.length>>1;
value = E.sum(median.slice(mid-4,mid+5)) / 9;
g.setFont("Vector",50).setFontAlign(0,0).drawString((value-zero).toFixed(1), g.getWidth()/2, y);
}
});
g.reset();
g.setFont("6x8").setFontAlign(0,0).drawString(/*LANG*/"ALTITUDE (m)", g.getWidth()/2, y-40);
g.setFont("6x8").setFontAlign(0,0,3).drawString(/*LANG*/"ZERO", g.getWidth()-5, g.getHeight()/2);
setWatch(function() {
zero = value;
}, (process.env.HWVERSION==2) ? BTN1 : BTN2, {repeat:true});

BIN
apps/altimeter/app.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1,12 @@
{ "id": "altimeter",
"name": "Altimeter",
"version":"0.02",
"description": "Simple altimeter that can display height changed using Bangle.js 2's built in pressure sensor.",
"icon": "app.png",
"tags": "tool,outdoors",
"supports" : ["BANGLEJS2"],
"storage": [
{"name":"altimeter.app.js","url":"app.js"},
{"name":"altimeter.img","url":"app-icon.js","evaluate":true}
]
}

5
apps/bwclk/ChangeLog Normal file
View File

@ -0,0 +1,5 @@
0.01: New App.
0.02: Use build in function for steps and other improvements.
0.03: Adapt colors based on the theme of the user.
0.04: Steps can be hidden now such that the time is even larger.
0.05: Included icons for information.

16
apps/bwclk/README.md Normal file
View File

@ -0,0 +1,16 @@
# Black & White clock
![](screenshot.png)
## Features
- Fullscreen on/off
- The design is adapted to the theme of your bangle.
- Tab left/right of screen to show steps, temperature etc.
- Enable / disable lock icon in the settings.
- If the "sched" app is installed tab top / bottom of the screen to set the timer.
## Thanks to
<a href="https://www.flaticon.com/free-icons/" title="Icons">Icons created by Flaticon</a>
## Creator
- [David Peer](https://github.com/peerdavid)

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

@ -0,0 +1 @@
require("heatshrink").decompress(atob("mEwgIcah0EgEB/H8iFsAoOY4kMBYMDhmGgXkAoUGiWkAoQQBoAFCjgnCAoM4hgFDuEI+wpC8EKyg1C/0eAoMAsEAiQvBAAeAApQAB/4Ao+P4v/wn0P8Pgn/wnkH4Pjv/j/nn9PH//n/nj/IFF4F88AXBAoM88EcAoPHj//jlDAoOf/+Y+YFHjnnjAjBEIIjD+BHDO9IALA=="))

412
apps/bwclk/app.js Normal file

File diff suppressed because one or more lines are too long

BIN
apps/bwclk/app.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

18
apps/bwclk/metadata.json Normal file
View File

@ -0,0 +1,18 @@
{
"id": "bwclk",
"name": "BlackWhite Clock",
"version": "0.05",
"description": "Black and white clock.",
"readme": "README.md",
"icon": "app.png",
"screenshots": [{"url":"screenshot.png"}, {"url":"screenshot_2.png"}],
"type": "clock",
"tags": "clock",
"supports": ["BANGLEJS2"],
"allow_emulator": true,
"storage": [
{"name":"bwclk.app.js","url":"app.js"},
{"name":"bwclk.img","url":"app-icon.js","evaluate":true},
{"name":"bwclk.settings.js","url":"settings.js"}
]
}

BIN
apps/bwclk/screenshot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
apps/bwclk/screenshot_2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

40
apps/bwclk/settings.js Normal file
View File

@ -0,0 +1,40 @@
(function(back) {
const SETTINGS_FILE = "bwclk.setting.json";
// initialize with default settings...
const storage = require('Storage')
let settings = {
fullscreen: false,
showLock: true,
};
let saved_settings = storage.readJSON(SETTINGS_FILE, 1) || settings;
for (const key in saved_settings) {
settings[key] = saved_settings[key]
}
function save() {
storage.write(SETTINGS_FILE, settings)
}
E.showMenu({
'': { 'title': 'BlackWhite Clock' },
'< Back': back,
'Fullscreen': {
value: settings.fullscreen,
format: () => (settings.fullscreen ? 'Yes' : 'No'),
onchange: () => {
settings.fullscreen = !settings.fullscreen;
save();
},
},
'Show Lock': {
value: settings.showLock,
format: () => (settings.showLock ? 'Yes' : 'No'),
onchange: () => {
settings.showLock = !settings.showLock;
save();
},
}
});
})

View File

@ -3,3 +3,4 @@
0.03: Eliminate flickering
0.04: Fix for Bangle.js 2 and themes
0.05: Fix bearing not clearing correctly (visible in single or double digit bearings)
0.06: Add button for force compass calibration

29
apps/compass/README.md Normal file
View File

@ -0,0 +1,29 @@
# Compass
This app uses Bangle.js's built-in magnetometer as a compass.
## Usage
Hold your Bangle.js **face up** (so the display is parallel to the ground),
and the red arrow will point north, with the heading in degrees printed at
the top of the screen.
This compass app does not include tilt compensation - so much like a real
compass you should always keep it face up when taking a reading.
The first time you run the compass after your Bangle has booted (or if
you move to an area with a substantially different magnetic field) you will
need to recalibrate your compass (even if a heading is shown).
## Calibration
Press the button next to the `RESET` label on the screen. The North/South marker
will disappear and a message will appear asking you to rotate the watch 360 degrees.
* Hold the watch face up, so the display is parallel to the ground
* Rotate it around slowly, all 360 degrees (with the display still parallel to the ground)
* The `Uncalibrated` message will disappear before you have finished rotating the full 360 degrees - but you should still complete the full rotation in order for the compass to work properly.
Once you've rotated the full 360 degrees your compass should now work fine,
and calibration is stored between runs of the app. However if you go near
to a strong magnet you may still need to recalibrate.

View File

@ -38,7 +38,7 @@ Bangle.on('mag', function(m) {
if (!wasUncalibrated) {
g.clearRect(0,24,W,48);
g.setFontAlign(0,-1).setFont("6x8");
g.drawString("Uncalibrated\nturn 360° around",M,24+4);
g.drawString(/*LANG*/"Uncalibrated\nturn 360° around",M,24+4);
wasUncalibrated = true;
}
} else {
@ -64,7 +64,12 @@ Bangle.on('mag', function(m) {
oldHeading = m.heading;
});
g.clear();
g.clear(1);
g.setFont("6x8").setFontAlign(0,0,3).drawString(/*LANG*/"RESET", g.getWidth()-5, g.getHeight()/2);
setWatch(function() {
Bangle.resetCompass();
}, (process.env.HWVERSION==2) ? BTN1 : BTN2, {repeat:true});
Bangle.loadWidgets();
Bangle.drawWidgets();
Bangle.setCompassPower(1);

View File

@ -1,12 +1,13 @@
{
"id": "compass",
"name": "Compass",
"version": "0.05",
"version": "0.06",
"description": "Simple compass that points North",
"icon": "compass.png",
"screenshots": [{"url":"screenshot_compass.png"}],
"tags": "tool,outdoors",
"supports": ["BANGLEJS","BANGLEJS2"],
"readme": "README.md",
"storage": [
{"name":"compass.app.js","url":"compass.js"},
{"name":"compass.img","url":"compass-icon.js","evaluate":true}

1
apps/fuzzyw/ChangeLog Normal file
View File

@ -0,0 +1 @@
0.01: First release

26
apps/fuzzyw/README.md Normal file
View File

@ -0,0 +1,26 @@
# Fuzzy Text Clock
An imprecise clock for when you're not in a rush.
This clock is a remake of one of my favourite Pebble watchfaces, Fuzzy Text International. I use this watch for weekends and holidays, when 'within 5 minutes of the actual time' is close enough!
By default it will use the language set on the watch, go to settings to pick:
* en_GB - English
* en_US - American
* es_ES - Spanish
* fr_FR - French
* no_NO - Norwegian
* sv_SE - Swedish
* de_DE - German
Most translations are taken from the original Fuzzy Text International code.
## TODO
* Bold hour word (as the pebble version has)
* Animation when changing time?
## References
Based on Pebble app Fuzzy Text International: https://github.com/hallettj/Fuzzy-Text-International
![](fuzzyw-light.png)
![](fuzzyw-dark.png)

View File

@ -0,0 +1,163 @@
{
"en_GB":{
"hours":[
"midnight", "one", "two", "three", "four", "five",
"six", "seven", "eight", "nine", "ten", "eleven",
"twelve", "one", "two", "three", "four", "five",
"six", "seven", "eight", "nine", "ten", "eleven"
],
"minutes":[
"*$1 o'clock",
"five past *$1",
"ten past *$1",
"quarter past *$1",
"twenty past *$1",
"twenty five past *$1",
"half past *$1",
"twenty five to *$2",
"twenty to *$2",
"quarter to *$2",
"ten to *$2",
"five to *$2"
],
"text_scale":3.5
},
"en_US":{
"hours":[
"midnight", "one", "two", "three", "four", "five",
"six", "seven", "eight", "nine", "ten", "eleven",
"twelve", "one", "two", "three", "four", "five",
"six", "seven", "eight", "nine", "ten", "eleven"
],
"minutes":[
"*$1 o'clock",
"five after *$1",
"ten after *$1",
"quarter after *$1",
"twenty after *$1",
"twenty five after *$1",
"half past *$1",
"twenty five to *$2",
"twenty to *$2",
"quarter to *$2",
"ten to *$2",
"five to *$2"
],
"text_scale":3.5
},
"es_ES":{
"hours":[
"doce", "una", "dos", "tres", "cuatro", "cinco",
"seis", "siete", "ocho", "nueve", "diez", "once",
"doce", "una", "dos", "tres", "cuatro", "cinco",
"seis", "siete", "ocho", "nueve", "diez", "once"
],
"minutes":[
"*$1 en punto",
"*$1 y cinco",
"*$1 y diez",
"*$1 y cuarto",
"*$1 y veinte",
"*$1 y veinti- cinco",
"*$1 y media",
"*$2 menos veinti- cinco",
"*$2 menos veinte",
"*$2 menos cuarto",
"*$2 menos diez",
"*$2 menos cinco"
],
"text_scale":3.5
},
"fr_FR":{
"hours":[
"douze", "une", "deux", "trois", "quatre", "cinq",
"six", "sept", "huit", "neuf", "dix", "onze",
"douze", "une", "deux", "trois", "quatre", "cinq",
"six", "sept", "huit", "neuf", "dix", "onze"
],
"minutes":[
"*$1 heures",
"*$1 heures cinq",
"*$1 heures dix",
"*$1 heures et quart",
"*$1 heures vingt",
"*$1 heures vingt- cinq",
"*$1 heures et demie",
"*$2 moins vingt- cinq",
"*$2 heures moins vingt",
"*$2 moins le quart",
"*$2 heures moins dix",
"*$2 heures moins cinq"
],
"text_scale":3.5
},
"no_NB":{
"hours":[
"tolv", "ett", "to", "tre", "fire", "fem",
"seks", "sju", "åtte", "ni", "ti", "elleve",
"tolv", "ett", "to", "tre", "fire", "fem",
"seks", "sju", "åtte", "ni", "ti", "elleve"
],
"minutes":[
"klokka er *$1",
"fem over *$1",
"ti over *$1",
"kvart over *$1",
"ti på halv *$2",
"fem på halv *$2",
"halv *$2",
"fem over halv *$2",
"ti over halv *$2",
"kvart på *$2",
"ti på *$2",
"fem på *$2"
],
"text_scale":3.5
},
"sv_SE":{
"hours":[
"tolv", "ett", "två", "tre", "fyra", "fem",
"sex", "sju", "åtta", "nio", "tio", "elva",
"tolv", "ett", "två", "tre", "fyra", "fem",
"sex", "sju", "åtta", "nio", "tio", "elva"
],
"minutes":[
"*$1",
"fem över *$1",
"tio över *$1",
"kvart över *$1",
"tjugo över *$1",
"fem i halv *$2",
"halv *$2",
"fem över halv *$2",
"tjugo i *$2",
"kvart i *$2",
"tio i *$2",
"fem i *$2"
],
"text_scale":3.5
},
"de_DE":{
"hours":[
"zwölf", "eins", "zwei", "drei", "vier", "fünf",
"sechs", "sieben", "acht", "neun", "zehn", "elf",
"zwölf", "eins", "zwei", "drei", "vier", "fünf",
"sechs", "sieben", "acht", "neun", "zehn", "elf"
],
"minutes":[
"*$1 uhr",
"fünf nach *$1",
"zehn nach *$1",
"viertel nach *$1",
"zwanzig nach *$1",
"fünf for halb *$2",
"halb *$2",
"fünf nach halb *$2",
"zwanzig vor *$2",
"viertel vor *$2",
"zehn vor *$2",
"fünf vor *$2"
],
"text_scale":3.5
}
}

BIN
apps/fuzzyw/fuzzyw-dark.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

75
apps/fuzzyw/fuzzyw.app.js Normal file
View File

@ -0,0 +1,75 @@
// adapted from https://github.com/hallettj/Fuzzy-Text-International/
const fuzzy_strings = require("Storage").readJSON("fuzzy_strings.json");
const SETTINGS_FILE = "fuzzyw.settings.json";
let settings = require("Storage").readJSON(SETTINGS_FILE,1)|| {'language': 'System', 'alignment':'Centre'};
if (settings.language == 'System') {
settings.language = require('locale').name;
}
let fuzzy_string = fuzzy_strings[settings.language];
let timeout = 2.5*60;
let drawTimeout;
function queueDraw(seconds) {
let millisecs = seconds * 1000;
if (drawTimeout) clearTimeout(drawTimeout);
drawTimeout = setTimeout(function() {
drawTimeout = undefined;
draw();
}, millisecs - (Date.now() % millisecs));
}
const h = g.getHeight();
const w = g.getWidth();
let align_mode = 0;
let align_pos = w/2;
if (settings.alignment =='Left') {
align_mode = -1;
align_pos = 0;
} else if (settings.alignment == 'Right') {
align_mode = 1;
align_pos = w;
}
function getTimeString(date) {
let segment = Math.round((date.getMinutes()*60 + date.getSeconds() + 1)/300);
let hour = date.getHours() + Math.floor(segment/12);
f_string = fuzzy_string.minutes[segment % 12];
if (f_string.includes('$1')) {
f_string = f_string.replace('$1', fuzzy_string.hours[(hour) % 24]);
} else {
f_string = f_string.replace('$2', fuzzy_string.hours[(hour + 1) % 24]);
}
return f_string;
}
function draw() {
let time_string = getTimeString(new Date()).replace('*', '');
// print(time_string);
g.setFont('Vector', (h-24*2)/fuzzy_string.text_scale);
g.setFontAlign(align_mode, 0);
g.clearRect(0, 24, w, h-24);
g.setColor(g.theme.fg);
g.drawString(g.wrapString(time_string, w).join("\n"), align_pos, h/2);
queueDraw(timeout);
}
g.clear();
draw();
// Stop updates when LCD is off, restart when on
Bangle.on('lcdPower',on=>{
if (on) {
draw(); // draw immediately, queue redraw
} else { // stop draw timer
if (drawTimeout) clearTimeout(drawTimeout);
drawTimeout = undefined;
}
});
Bangle.setUI('clock');
Bangle.loadWidgets();
Bangle.drawWidgets();

View File

@ -0,0 +1 @@
require("heatshrink").decompress(atob("mEwgP/ABX8oYFD+AFE8AFE8IXE8YFKwFCj08h4FBocenEHCIPDjk4CoIFBhlwAoeMuIFEuBSBAoOI+AFD4HxGoQFB+AFD4P4uYFC8P4gYFD/w7BAFEfApfEj+B/Ecg/Ah8A+EMg/Dw0YseHj/Dw/8sfHAoPH/lhDoIFBwFwj4FB40AvkPAoU8v4dCAoIdDw04FIMP4EOgFwh47Bj8EvEfw/DJwgFXABY"))

BIN
apps/fuzzyw/fuzzyw.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 893 B

View File

@ -0,0 +1,46 @@
(function(back) {
const SETTINGS_FILE = "fuzzyw.settings.json";
var align_options = ['Left','Centre','Right'];
var language_options = ['System', 'en_GB', 'en_US', 'es_ES', 'fr_FR', 'no_NO', 'sv_SE', 'de_DE'];
// initialize with default settings...
let s = {'language': 'System', 'alignment': 'Centre'};
// ...and overwrite them with any saved values
// This way saved values are preserved if a new version adds more settings
const storage = require('Storage')
let settings = storage.readJSON(SETTINGS_FILE, 1) || s;
const saved = settings || {}
for (const key in saved) {
s[key] = saved[key]
}
function save() {
settings = s
storage.write(SETTINGS_FILE, settings)
}
E.showMenu({
'': { 'title': 'Fuzzy Text Clock' },
'< Back': back,
'Language': {
value: 0 | language_options.indexOf(s.language),
min: 0, max: language_options.length - 1,
format: v => language_options[v],
onchange: v => {
s.language = language_options[v];
save();
}
},
'Alignment': {
value: 0 | align_options.indexOf(s.alignment),
min: 0, max: align_options.length - 1,
format: v => align_options[v],
onchange: v => {
s.alignment = align_options[v];
save();
}
},
});
})

20
apps/fuzzyw/metadata.json Normal file
View File

@ -0,0 +1,20 @@
{
"id":"fuzzyw",
"name":"Fuzzy Text Clock",
"shortName": "Fuzzy Text",
"version": "0.01",
"description": "An imprecise clock for when you're not in a rush",
"readme": "README.md",
"icon":"fuzzyw.png",
"screenshots": [{"url":"fuzzyw-light.png"},{"url":"fuzzyw-dark.png"}],
"type": "clock",
"tags": "clock",
"supports": ["BANGLEJS", "BANGLEJS2"],
"allow_emulator": true,
"storage": [
{"name":"fuzzyw.app.js","url":"fuzzyw.app.js"},
{"name":"fuzzyw.settings.js","url":"fuzzyw.settings.js"},
{"name":"fuzzyw.img","url":"fuzzyw.icon.js","evaluate":true},
{"name":"fuzzy_strings.json","url":"fuzzy_strings.json"}
]
}

View File

@ -17,3 +17,4 @@
0.17: Settings for mph/kph and other minor improvements.
0.18: Fullscreen mode can now be enabled or disabled in the settings.
0.19: Alarms can not go bigger than 100.
0.20: Use alarm for alarm functionality instead of own implementation.

View File

@ -3,7 +3,8 @@
A simple LCARS inspired clock.
Note: To display the steps, the wpedom app is required. To show weather data
such as temperature, humidity or window you BangleJS must be connected
with Gadgetbride and the weather app must be installed.
with Gadgetbride and the weather app must be installed. To use the timer
the "sched" app must be installed on your device.
## Control
* Tap left / right to change between screens.
@ -15,7 +16,7 @@ with Gadgetbride and the weather app must be installed.
* Tab on left/right to switch between different screens.
* Cusomizable data that is shown on screen 1 (steps, weather etc.)
* Shows random and real images of planets.
* Tap on top/bottom of screen 1 to activate an alarm.
* Tap on top/bottom of screen 1 to activate an alarm. Depends on widtmr.
* The lower orange line indicates the battery level.
* Display graphs (day or month) for steps + hrm on the second screen.
@ -36,8 +37,9 @@ Access different screens via tap on the left/ right side of the screen
![](screenshot_1.png)
![](screenshot_2.png)
## Creator
- [David Peer](https://github.com/peerdavid)
## Contributors
- [David Peer](https://github.com/peerdavid).
- [Adam Schmalhofer](https://github.com/adamschmalhofer).
- [Jon Warrington](https://github.com/BartokW).
- [Adam Schmalhofer](https://github.com/adamschmalhofer)
- [Jon Warrington](https://github.com/BartokW)

View File

@ -1,6 +1,7 @@
const TIMER_IDX = "lcars";
const SETTINGS_FILE = "lcars.setting.json";
const locale = require('locale');
const storage = require('Storage')
const storage = require('Storage');
let settings = {
alarm: -1,
dataRow1: "Steps",
@ -124,11 +125,16 @@ Graphics.prototype.setFontAntonioLarge = function(scale) {
*/
var drawTimeout;
function queueDraw() {
// Faster updates during alarm to ensure that it is
// shown correctly...
var timeout = isAlarmEnabled() ? 10000 : 60000;
if (drawTimeout) clearTimeout(drawTimeout);
drawTimeout = setTimeout(function() {
drawTimeout = undefined;
draw();
}, 60000 - (Date.now() % 60000));
}, timeout - (Date.now() % timeout));
}
/**
@ -238,6 +244,7 @@ function drawInfo(){
return;
}
g.setFontAlign(-1, -1, 0);
g.setFontAntonioMedium();
g.setColor(cOrange);
g.clearRect(120, 10, g.getWidth(), 75);
@ -480,9 +487,6 @@ function draw(){
// Queue draw first to ensure that its called in one minute again.
queueDraw();
// First handle alarm to show this correctly afterwards
handleAlarm();
// Next draw the watch face
g.reset();
g.clearRect(0, 0, g.getWidth(), g.getHeight());
@ -561,43 +565,57 @@ function getWeather(){
/*
* Handle alarm
*/
function getCurrentTimeInMinutes(){
return Math.floor(Date.now() / (1000*60));
}
function isAlarmEnabled(){
return settings.alarm >= 0;
try{
var alarm = require('sched');
var alarmObj = alarm.getAlarm(TIMER_IDX);
if(alarmObj===undefined || !alarmObj.on){
return false;
}
return true;
} catch(ex){ }
return false;
}
function getAlarmMinutes(){
var currentTime = getCurrentTimeInMinutes();
return settings.alarm - currentTime;
if(!isAlarmEnabled()){
return -1;
}
var alarm = require('sched');
var alarmObj = alarm.getAlarm(TIMER_IDX);
return Math.round(alarm.getTimeToAlarm(alarmObj)/(60*1000));
}
function handleAlarm(){
if(!isAlarmEnabled()){
return;
}
function increaseAlarm(){
try{
var minutes = isAlarmEnabled() ? getAlarmMinutes() : 0;
var alarm = require('sched')
alarm.setAlarm(TIMER_IDX, {
timer : (minutes+5)*60*1000,
});
alarm.reload();
} catch(ex){ }
}
if(getAlarmMinutes() > 0){
return;
}
function decreaseAlarm(){
try{
var minutes = getAlarmMinutes();
minutes -= 5;
// Alarm
var t = 300;
Bangle.buzz(t, 1)
.then(() => new Promise(resolve => setTimeout(resolve, t)))
.then(() => Bangle.buzz(t, 1))
.then(() => new Promise(resolve => setTimeout(resolve, t)))
.then(() => Bangle.buzz(t, 1))
.then(() => new Promise(resolve => setTimeout(resolve, t)))
.then(() => Bangle.buzz(t, 1))
.then(() => new Promise(resolve => setTimeout(resolve, 5E3)))
.then(() => {
// Update alarm state to disabled
settings.alarm = -1;
storage.writeJSON(SETTINGS_FILE, settings);
});
var alarm = require('sched')
alarm.setAlarm(TIMER_IDX, undefined);
if(minutes > 0){
alarm.setAlarm(TIMER_IDX, {
timer : minutes*60*1000,
});
}
alarm.reload();
} catch(ex){ }
}
@ -625,27 +643,6 @@ Bangle.on('charging',function(charging) {
});
function increaseAlarm(){
if(isAlarmEnabled() && getAlarmMinutes() < 95){
settings.alarm += 5;
} else {
settings.alarm = getCurrentTimeInMinutes() + 5;
}
storage.writeJSON(SETTINGS_FILE, settings);
}
function decreaseAlarm(){
if(isAlarmEnabled() && (settings.alarm-5 > getCurrentTimeInMinutes())){
settings.alarm -= 5;
} else {
settings.alarm = -1;
}
storage.writeJSON(SETTINGS_FILE, settings);
}
function feedback(){
Bangle.buzz(40, 0.3);
}

View File

@ -3,7 +3,7 @@
"name": "LCARS Clock",
"shortName":"LCARS",
"icon": "lcars.png",
"version":"0.19",
"version":"0.20",
"readme": "README.md",
"supports": ["BANGLEJS2"],
"description": "Library Computer Access Retrieval System (LCARS) clock.",

View File

@ -1,3 +1,4 @@
0.01: Launch app.
0.02: 12k steps are 360 degrees - improves readability of steps.
0.03: Battery improvements through sleep (no minute updates) and partial updates of drawing.
0.03: Battery improvements through sleep (no minute updates) and partial updates of drawing.
0.04: Use alarm for timer instead of own alarm implementation.

View File

@ -8,8 +8,8 @@ black one the battery level (100% = 360 degrees).
The selected theme is also respected. Note that this watch face is in fullscreen
mode, but widgets are still loaded in background.
## Other features
- Set a timer - simply touch top (+5min.) or bottom (-5 min.).
## Other Features
- Set a timer - simply touch top (+5min.) or bottom (-5 min.). This only works if "sched" is installed.
- If the weather is available through the weather app, the outside temp. will be shown.
- Sleep modus at midnight to save more battery (no minute updates).
- Icons for charging and GPS.
@ -29,5 +29,5 @@ which helped a lot for this development.
Icons from <a href="https://www.flaticon.com/free-icons" title="icons">by Freepik - Flaticon</a>
## Contributors
## Creator
- [David Peer](https://github.com/peerdavid).

View File

@ -3,7 +3,7 @@
"name": "Not Analog",
"shortName":"Not Analog",
"icon": "notanalog.png",
"version":"0.03",
"version":"0.04",
"readme": "README.md",
"supports": ["BANGLEJS2"],
"description": "An analog watch face for people that can not read analog watch faces.",

View File

@ -1,7 +1,7 @@
/**
* NOT ANALOG CLOCK
*/
const TIMER_IDX = "notanalog";
const locale = require('locale');
const storage = require('Storage')
const SETTINGS_FILE = "notanalog.setting.json";
@ -291,7 +291,6 @@ function drawSleep(){
function draw(fastUpdate){
// Execute handlers
handleState(fastUpdate);
handleAlarm();
if(state.sleep){
drawSleep();
@ -377,82 +376,80 @@ Bangle.on('touch', function(btn, e){
* Some helpers
*/
function queueDraw() {
// Faster updates during alarm to ensure that it is
// shown correctly...
var timeout = isAlarmEnabled() ? 10000 : 60000;
if (drawTimeout) clearTimeout(drawTimeout);
drawTimeout = setTimeout(function() {
drawTimeout = undefined;
draw(true);
}, 60000 - (Date.now() % 60000));
draw();
}, timeout - (Date.now() % timeout));
}
/*
* Handle alarm
*/
function getCurrentTimeInMinutes(){
return Math.floor(Date.now() / (1000*60));
}
function isAlarmEnabled(){
return settings.alarm >= 0;
}
try{
var alarm = require('sched');
var alarmObj = alarm.getAlarm(TIMER_IDX);
if(alarmObj===undefined || !alarmObj.on){
return false;
}
return true;
} catch(ex){ }
return false;
}
function getAlarmMinutes(){
var currentTime = getCurrentTimeInMinutes();
return settings.alarm - currentTime;
}
function handleAlarm(){
if(!isAlarmEnabled()){
return;
return -1;
}
if(getAlarmMinutes() > 0){
return;
}
// Alarm
var t = 300;
Bangle.buzz(t, 1)
.then(() => new Promise(resolve => setTimeout(resolve, t)))
.then(() => Bangle.buzz(t, 1))
.then(() => new Promise(resolve => setTimeout(resolve, t)))
.then(() => Bangle.buzz(t, 1))
.then(() => new Promise(resolve => setTimeout(resolve, t)))
.then(() => Bangle.buzz(t, 1))
.then(() => new Promise(resolve => setTimeout(resolve, 5E3)))
.then(() => {
// Update alarm state to disabled
settings.alarm = -1;
storage.writeJSON(SETTINGS_FILE, settings);
});
var alarm = require('sched');
var alarmObj = alarm.getAlarm(TIMER_IDX);
return Math.round(alarm.getTimeToAlarm(alarmObj)/(60*1000));
}
function increaseAlarm(){
if(isAlarmEnabled()){
settings.alarm += 5;
} else {
settings.alarm = getCurrentTimeInMinutes() + 5;
}
storage.writeJSON(SETTINGS_FILE, settings);
try{
var minutes = isAlarmEnabled() ? getAlarmMinutes() : 0;
var alarm = require('sched')
alarm.setAlarm(TIMER_IDX, {
timer : (minutes+5)*60*1000,
});
alarm.reload();
} catch(ex){ }
}
function decreaseAlarm(){
if(isAlarmEnabled() && (settings.alarm-5 > getCurrentTimeInMinutes())){
settings.alarm -= 5;
} else {
settings.alarm = -1;
}
try{
var minutes = getAlarmMinutes();
minutes -= 5;
storage.writeJSON(SETTINGS_FILE, settings);
var alarm = require('sched')
alarm.setAlarm(TIMER_IDX, undefined);
if(minutes > 0){
alarm.setAlarm(TIMER_IDX, {
timer : minutes*60*1000,
});
}
alarm.reload();
} catch(ex){ }
}
function feedback(){
Bangle.buzz(40, 0.6);
}
/*
* Lets start widgets, listen for btn etc.
*/

1
apps/smpltmr/ChangeLog Normal file
View File

@ -0,0 +1 @@
0.01: Release

21
apps/smpltmr/README.md Normal file
View File

@ -0,0 +1,21 @@
# Simple Timer
A simple app to set a timer quickly. Simply tab on top/bottom/left/right
to select the minutes and tab in the middle of the screen to start/stop
the timer. Note that this timer depends on qalarm.
# Overview
If you open the app, you can simply control the timer
by clicking on top, bottom, left or right of the screen.
If you tab at the middle of the screen, the timer is
started / stopped.
![](description.png)
# Creator
[David Peer](https://github.com/peerdavid)
# Thanks to...
Time icon created by <a href="https://www.flaticon.com/free-icons/time" title="time icons">CreativeCons - Flaticon</a>

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

@ -0,0 +1 @@
require("heatshrink").decompress(atob("mEwwMAg//AAXgApcAvAZBhwCBuAFuGoUeAQM4AQM8AQl8Bwn4AQMPgEB+AFBg+AgZYBgED4AHBAoIPBCYIAC/AfCGwQrCGAQ3CAAMcIYQFCJ4QABnoREvIdE/eeAgUB+fPAoUD8/nIIUHz/zJoUPn/5LIUev/8MoU8//+OIU5XwO8AoN7AoPeAoNzAoPOAsrFKg4QBAAPgApYA=="))

124
apps/smpltmr/app.js Normal file
View File

@ -0,0 +1,124 @@
/*
* SIMPLE TIMER
*
* Creator: David Peer
* Date: 02/2022
*/
Bangle.loadWidgets();
const alarm = require("sched");
const TIMER_IDX = "smpltmr";
const screenWidth = g.getWidth();
const screenHeight = g.getHeight();
const cx = parseInt(screenWidth/2);
const cy = parseInt(screenHeight/2)-12;
var minutes = 5;
var interval; //used for the 1 second interval timer
function isTimerEnabled(){
var alarmObj = alarm.getAlarm(TIMER_IDX);
if(alarmObj===undefined || !alarmObj.on){
return false;
}
return true;
}
function getTimerMin(){
var alarmObj = alarm.getAlarm(TIMER_IDX);
return Math.round(alarm.getTimeToAlarm(alarmObj)/(60*1000));
}
function setTimer(minutes){
alarm.setAlarm(TIMER_IDX, {
// msg : "Simple Timer",
timer : minutes*60*1000,
});
alarm.reload();
}
function deleteTimer(){
alarm.setAlarm(TIMER_IDX, undefined);
alarm.reload();
}
setWatch(_=>load(), BTN1);
function draw(){
g.clear(1);
Bangle.drawWidgets();
if (interval) {
clearInterval(interval);
}
interval = undefined;
// Write time
g.setFontAlign(0, 0, 0);
g.setFont("Vector", 32).setFontAlign(0,-1);
var started = isTimerEnabled();
var text = minutes + " min.";
if(started){
var min = getTimerMin();
text = min + " min.";
}
var rectWidth = parseInt(g.stringWidth(text) / 2);
if(started){
interval = setInterval(draw, 1000);
g.setColor("#ff0000");
} else {
g.setColor(g.theme.fg);
}
g.fillRect(cx-rectWidth-5, cy-5, cx+rectWidth, cy+30);
g.setColor(g.theme.bg);
g.drawString(text, cx, cy);
}
Bangle.on('touch', function(btn, e){
var left = parseInt(g.getWidth() * 0.25);
var right = g.getWidth() - left;
var upper = parseInt(g.getHeight() * 0.25);
var lower = g.getHeight() - upper;
var isLeft = e.x < left;
var isRight = e.x > right;
var isUpper = e.y < upper;
var isLower = e.y > lower;
var isMiddle = !isLeft && !isRight && !isUpper && !isLower;
var started = isTimerEnabled();
if(isRight && !started){
minutes += 1;
Bangle.buzz(40, 0.3);
} else if(isLeft && !started){
minutes -= 1;
Bangle.buzz(40, 0.3);
} else if(isUpper && !started){
minutes += 5;
Bangle.buzz(40, 0.3);
} else if(isLower && !started){
minutes -= 5;
Bangle.buzz(40, 0.3);
} else if(isMiddle) {
if(!started){
setTimer(minutes);
} else {
deleteTimer();
}
Bangle.buzz(80, 0.6);
}
minutes = Math.max(0, minutes);
draw();
});
g.reset();
draw();

BIN
apps/smpltmr/app.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

View File

@ -0,0 +1,17 @@
{
"id": "smpltmr",
"name": "Simple Timer",
"shortName": "Simple Timer",
"version": "0.01",
"description": "A very simple app to start a timer.",
"icon": "app.png",
"tags": "tool",
"dependencies": {"scheduler":"type"},
"supports": ["BANGLEJS2"],
"screenshots": [{"url":"screenshot.png"}, {"url": "screenshot_2.png"}],
"readme": "README.md",
"storage": [
{"name":"smpltmr.app.js","url":"app.js"},
{"name":"smpltmr.img","url":"app-icon.js","evaluate":true}
]
}

BIN
apps/smpltmr/screenshot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB