Merge branch 'master' of github.com:espruino/BangleApps
After Width: | Height: | Size: 983 B |
|
@ -0,0 +1 @@
|
|||
0.01: New App!
|
|
@ -0,0 +1 @@
|
|||
atob("MDCBAAAAAAAAAAAAAAAAAAAAH/AAAAAAf/4AAAAB4AeAAAAHgAHgAAAOAABwAAAcAAA4AAA4AMAcAABwAMAOAABgA/AGAADAAeADAAHAAMADgAGAAAABgAGAAAABgAMAAAAAwAMBAAAAwAMDAAAAwAMHwAAAwAMHwAAAwAMDAACAwAMBAADAwAMAAAPgwAMAAAPgwAMAAADAwAGAAACBgAGAAAABgAHAAAADgADAAAADAADgAAAHAAB////+AAB////+AABgAAAGAABgAAAGAABgAAAGAADAAAADAADAAAADAADAAAADAAGAAAABgAGAAAABgAH/////gAP/////wAYAAAAAYAYAAAAAYAf/////4AP/////wAAAAAAAAAAAAAAAAA==")
|
|
@ -0,0 +1,92 @@
|
|||
var keyboard = "textinput";
|
||||
var Name = "";
|
||||
Bangle.setLCDTimeout(0);
|
||||
var menuOpen = 1;
|
||||
var answers = new Array("no", "yes","WHAT????","What do you think", "That was a bad question", "YES!!!", "NOOOOO!!", "nope","100%","yup","why should I answer that?","think for yourself","ask again later, I'm busy", "what Was that horrible question","how dare you?","you wanted to hear yes? okay, yes", "Don't get angry when I say no","you are 100% wrong","totally, for sure","hmmm... I'll ponder it and get back to you later","wow, you really have a lot of questions", "NOPE","is the sky blue, hmmm...","I don't have time to answer","How many more questions before you change my name?","theres this thing called wikipedia","hmm... I don't seem to be able to reach the internet right now","if you phrase it like that, yes","Huh, never thought so hard in my life","The winds of time say no");
|
||||
var consonants = new Array("b","c","d","f","g","h","j","k","l","m","n","p","q","r","s","t","v","w","x","y","z");
|
||||
var vowels = new Array("a","e","i","o","u");
|
||||
try {keyboard = require(keyboard);} catch(e) {keyboard = null;}
|
||||
function generateName()
|
||||
{
|
||||
Name = "";
|
||||
var nameLength = Math.round(Math.random()*5);
|
||||
for(var i = 0; i < nameLength; i++){
|
||||
var cosonant = consonants[Math.round(Math.random()*consonants.length/2)];
|
||||
var vowel = vowels[Math.round(Math.random()*vowels.length/2)];
|
||||
Name = Name + cosonant + vowel;
|
||||
if(Name == "")
|
||||
{
|
||||
generateName();
|
||||
}
|
||||
}
|
||||
}
|
||||
generateName();
|
||||
function menu()
|
||||
{
|
||||
g.clear();
|
||||
E.showMenu();
|
||||
menuOpen = 1;
|
||||
E.showMenu({
|
||||
"" : { title : Name },
|
||||
"< Back" : () => menu(),
|
||||
"Start" : () => {
|
||||
E.showMenu();
|
||||
g.clear();
|
||||
menuOpen = 0;
|
||||
Drawtext("ask " + Name + " a yes or no question");
|
||||
},
|
||||
"regenerate name" : () => {
|
||||
menu();
|
||||
generateName();
|
||||
},
|
||||
"show answers" : () => {
|
||||
var menu = new Array([]);
|
||||
for(var i = 0; i < answers.length; i++){
|
||||
menu.push({title : answers[i]});
|
||||
}
|
||||
E.showMenu(menu);
|
||||
|
||||
|
||||
},
|
||||
|
||||
"Add answer" : () => {
|
||||
E.showMenu();
|
||||
keyboard.input({}).then(result => {if(result != ""){answers.push(result);} menu();});
|
||||
},
|
||||
"Edit name" : () => {
|
||||
E.showMenu();
|
||||
keyboard.input({}).then(result => {if(result != ""){Name = result;} menu();});
|
||||
|
||||
},
|
||||
"Exit" : () => load(),
|
||||
});
|
||||
}
|
||||
menu();
|
||||
|
||||
var answer;
|
||||
function Drawtext(text)
|
||||
{
|
||||
g.clear();
|
||||
g.setFont("Vector", 20);
|
||||
g.drawString(g.wrapString(text, g.getWidth(), -20).join("\n"));
|
||||
}
|
||||
function WriteAnswer()
|
||||
{
|
||||
if (menuOpen == 0)
|
||||
{
|
||||
var randomnumber = Math.round(Math.random()*answers.length);
|
||||
answer = answers[randomnumber];
|
||||
Drawtext(answer);
|
||||
setTimeout(function() {
|
||||
Drawtext("ask " + Name + " a yes or no question");
|
||||
}, 3000);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
setWatch(function() {
|
||||
menu();
|
||||
|
||||
}, (process.env.HWVERSION==2) ? BTN1 : BTN2, {repeat:true, edge:"falling"});
|
||||
|
||||
Bangle.on('touch', function(button, xy) { WriteAnswer(); });
|
|
@ -0,0 +1,19 @@
|
|||
{ "id": "8ball",
|
||||
"name": "Magic 8 ball",
|
||||
"shortName":"8ball",
|
||||
"icon": "8ball.png",
|
||||
"version":"0.01",
|
||||
"screenshots": [
|
||||
{"url":"screenshot.png"},
|
||||
{"url":"screenshot-1.png"},
|
||||
{"url":"screenshot-2.png"}
|
||||
],
|
||||
"allow_emulator": true,
|
||||
"description": "A very sarcastic magic 8ball",
|
||||
"tags": "game",
|
||||
"supports": ["BANGLEJS2"],
|
||||
"storage": [
|
||||
{"name":"8ball.app.js","url":"app.js"},
|
||||
{"name":"8ball.img","url":"app-icon.js","evaluate":true}
|
||||
]
|
||||
}
|
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 2.7 KiB |
|
@ -0,0 +1 @@
|
|||
0.10: New app introduced to the app loader!
|
|
@ -0,0 +1,13 @@
|
|||
# Binary LED Clock
|
||||
|
||||
A binary watch with LEDs, showing time and date.
|
||||
|
||||
From top to bottom the watch face shows four rows of leds:
|
||||
|
||||
* hours (red leds)
|
||||
* minutes (green leds)
|
||||
* day (yellow leds, top row)
|
||||
* month (yellow leds, bottom row)
|
||||
|
||||
As usual, luminous leds represent a logical one, dark leds a logcal '0'.
|
||||
Widgets aren't affected and are shown as normal.
|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("mEw4n/AAIHBqut8FPgH4sspk1T885/feoMI74TB1Fc51Dmfg28gKmMCrNSAgMlyo5BgV7uQIKgEhiMRkECAYMSgErolLBBIXBqIKBqEFAYMVgF0olEuAIIC4ORBQOQhIDBjMA2gOB2AIIF7JfXR67X0lvdHwQII7vSa4/TmYKBBBEtmc9a40NmYKBBBIbBmfQa4oOEBBAXFF65fXR64A/AG8IvN4AgOG62ABAuHy4IGgEHiMXAgNu91gBAtxiNwBAsAhMRjIEB73ucIIIEyMRyAIFF7BfXAH6/IttoKxRoIgEG93mQxSYIgEN93tWxTIIF7BfXAH4AGw93u/A44IDhl8vQRFBogXB0ECuGoBAcKxRxBC53Hhlyk8ggVyuQGBvlwhgNBk98BAN6I4UgC4N4BwWgAwWsC4fAk4IB0AvBAgIQBBwUIkQOBAwQXCJIIEBI4UAkQXE48sAwgXJF40mgAvDvRtCC4pfEC4WCPYJdBDYNyC4wAX"))
|
After Width: | Height: | Size: 1.4 KiB |
|
@ -0,0 +1,136 @@
|
|||
//Binary LED Clock (BLC) by aeMKai
|
||||
|
||||
{ // must be inside our own scope here so that when we are unloaded everything disappears
|
||||
// we also define functions using 'let fn = function() {..}' for the same reason. function decls are global
|
||||
let drawTimeout;
|
||||
|
||||
// Actually draw the watch face
|
||||
let draw = function()
|
||||
{
|
||||
// Bangle.js2 -> 176x176
|
||||
var x_rgt = g.getWidth();
|
||||
var y_bot = g.getHeight();
|
||||
//var x_cntr = x_rgt / 2;
|
||||
var y_cntr = y_bot / 18*7; // not to high because of widget-field (1/3 is to high)
|
||||
g.reset().clearRect(Bangle.appRect); // clear whole background (w/o widgets)
|
||||
|
||||
let white = [1,1,1];
|
||||
let red = [1,0,0];
|
||||
let green = [0,1,0];
|
||||
//let blue = [0,0,1];
|
||||
let yellow = [1,1,0];
|
||||
//let magenta = [1,0,1];
|
||||
//let cyan = [0,1,1];
|
||||
let black = [0,0,0];
|
||||
let bord_col = white;
|
||||
let col_off = black;
|
||||
|
||||
var col = new Array(red, green, yellow, yellow); // [R,G,B]
|
||||
|
||||
let pot_2 = [1, 2, 4, 8, 16, 32]; // array with powers of two, because power-op (**)
|
||||
// doesn't work -> maybe also faster
|
||||
|
||||
|
||||
var nr_lines = 4; // 4 rows: hour (hr), minute (min), day (day), month (mon)
|
||||
|
||||
// Arrays: [hr, min, day, mon]
|
||||
//No of Bits: 5 6 5 4
|
||||
let msbits = [4, 5, 4, 3]; // MSB = No bits - 1
|
||||
let rad = [12, 12, 8, 8]; // radiuses for each row
|
||||
var x_dist = 28;
|
||||
let y_dist = [0, 30, 60, 85]; // y-position from y_centr for each row from top
|
||||
// don't calc. automatic as for x, because of different spaces
|
||||
var x_offs_rgt = 16; // distance from right border (layout)
|
||||
|
||||
// Date-Time-Array: 4x6 Bit
|
||||
//var idx_hr = 0;
|
||||
//var idx_min = 1;
|
||||
//var idx_day = 2;
|
||||
//var idx_mon = 3;
|
||||
var dt_bit_arr = [[0, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0]];
|
||||
|
||||
var date_time = new Date();
|
||||
var hr = date_time.getHours(); // 0..23
|
||||
var min = date_time.getMinutes(); // 0..59
|
||||
var day = date_time.getDate(); // 1..31
|
||||
var mon = date_time.getMonth() + 1; // GetMonth() -> 0..11
|
||||
|
||||
let dt_array = [hr, min, day, mon];
|
||||
|
||||
|
||||
////////////////////////////////////////
|
||||
// compute bit-pattern from time/date and draw leds
|
||||
////////////////////////////////////////
|
||||
var line_cnt = 0;
|
||||
var cnt = 0;
|
||||
var bit_cnt = 0;
|
||||
|
||||
while (line_cnt < nr_lines)
|
||||
{
|
||||
|
||||
////////////////////////////////////////
|
||||
// compute bit-pattern
|
||||
bit_cnt = msbits[line_cnt];
|
||||
|
||||
while (bit_cnt >= 0)
|
||||
{
|
||||
if (dt_array[line_cnt] >= pot_2[bit_cnt])
|
||||
{
|
||||
dt_array[line_cnt] -= pot_2[bit_cnt];
|
||||
dt_bit_arr[line_cnt][bit_cnt] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
dt_bit_arr[line_cnt][bit_cnt] = 0;
|
||||
}
|
||||
bit_cnt--;
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
// draw leds (first white border for black screen, then led itself)
|
||||
cnt = 0;
|
||||
|
||||
while (cnt <= msbits[line_cnt])
|
||||
{
|
||||
g.setColor(bord_col[0], bord_col[1], bord_col[2]);
|
||||
g.drawCircle(x_rgt-x_offs_rgt-cnt*x_dist, y_cntr-20+y_dist[line_cnt], rad[line_cnt]);
|
||||
|
||||
if (dt_bit_arr[line_cnt][cnt] == 1)
|
||||
{
|
||||
g.setColor(col[line_cnt][0], col[line_cnt][1], col[line_cnt][2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
g.setColor(col_off[0], col_off[1], col_off[2]);
|
||||
}
|
||||
g.fillCircle(x_rgt-x_offs_rgt-cnt*x_dist, y_cntr-20+y_dist[line_cnt], rad[line_cnt]-1);
|
||||
cnt++;
|
||||
}
|
||||
line_cnt++;
|
||||
}
|
||||
|
||||
// queue next draw
|
||||
if (drawTimeout) clearTimeout(drawTimeout);
|
||||
drawTimeout = setTimeout(function()
|
||||
{
|
||||
drawTimeout = undefined;
|
||||
draw();
|
||||
}, 60000 - (Date.now() % 60000));
|
||||
};
|
||||
|
||||
// Show launcher when middle button pressed
|
||||
Bangle.setUI(
|
||||
{
|
||||
mode : "clock",
|
||||
remove : function()
|
||||
{
|
||||
// Called to unload all of the clock app
|
||||
if (drawTimeout) clearTimeout(drawTimeout);
|
||||
drawTimeout = undefined;
|
||||
}
|
||||
});
|
||||
// Load widgets
|
||||
Bangle.loadWidgets();
|
||||
draw();
|
||||
setTimeout(Bangle.drawWidgets,0);
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"id":"blc",
|
||||
"name":"Binary LED Clock",
|
||||
"version": "0.10",
|
||||
"description": "Binary LED Clock with date",
|
||||
"icon":"blc-icon.png",
|
||||
"screenshots": [{"url":"screenshot_blc.bmp"}],
|
||||
"type": "clock",
|
||||
"tags": "clock",
|
||||
"supports": ["BANGLEJS2"],
|
||||
"allow_emulator": true,
|
||||
"readme": "README.md",
|
||||
"storage": [
|
||||
{"name":"blc.app.js","url":"blc.js"},
|
||||
{"name":"blc.img","url":"blc-icon.js","evaluate":true}
|
||||
]
|
||||
}
|
After Width: | Height: | Size: 15 KiB |
|
@ -3,3 +3,4 @@
|
|||
0.03: Allows showing the month in short or long format by setting `"shortMonth"` to true or false
|
||||
0.04: Improves touchscreen drag handling for background apps such as Pattern Launcher
|
||||
0.05: Fixes step count not resetting after a new day starts
|
||||
0.06 Added clockbackground app functionality
|
||||
|
|
|
@ -5,11 +5,11 @@
|
|||
* ---------------------------------------------------------------
|
||||
*/
|
||||
|
||||
let background = require("clockbg");
|
||||
let storage = require("Storage");
|
||||
let locale = require("locale");
|
||||
let widgets = require("widget_utils");
|
||||
let date = new Date();
|
||||
let bgImage;
|
||||
let configNumber = (storage.readJSON("boxclk.json", 1) || {}).selectedConfig || 0;
|
||||
let fileName = 'boxclk' + (configNumber > 0 ? `-${configNumber}` : '') + '.json';
|
||||
// Add a condition to check if the file exists, if it does not, default to 'boxclk.json'
|
||||
|
@ -71,14 +71,6 @@
|
|||
* ---------------------------------------------------------------
|
||||
*/
|
||||
|
||||
for (let key in boxesConfig) {
|
||||
if (key === 'bg' && boxesConfig[key].img) {
|
||||
bgImage = storage.read(boxesConfig[key].img);
|
||||
} else if (key !== 'selectedConfig') {
|
||||
boxes[key] = Object.assign({}, boxesConfig[key]);
|
||||
}
|
||||
}
|
||||
|
||||
let boxKeys = Object.keys(boxes);
|
||||
|
||||
boxKeys.forEach((key) => {
|
||||
|
@ -224,9 +216,7 @@
|
|||
return function(boxes) {
|
||||
date = new Date();
|
||||
g.clear();
|
||||
if (bgImage) {
|
||||
g.drawImage(bgImage, 0, 0);
|
||||
}
|
||||
background.fillRect(Bangle.appRect);
|
||||
if (boxes.time) {
|
||||
boxes.time.string = modString(boxes.time, locale.time(date, isBool(boxes.time.short, true) ? 1 : 0));
|
||||
updatePerMinute = isBool(boxes.time.short, true);
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
"version": "0.05",
|
||||
"description": "A customizable clock with configurable text boxes that can be positioned to show your favorite background",
|
||||
"icon": "app.png",
|
||||
"dependencies" : { "clockbg":"module" },
|
||||
"screenshots": [
|
||||
{"url":"screenshot.png"},
|
||||
{"url":"screenshot-1.png"},
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
0.01: attempt to import
|
|
@ -0,0 +1,20 @@
|
|||
# Ded Reckon
|
||||
|
||||
Dead Reckoning using compass and step counter.
|
||||
|
||||
This allows logging track using "dead reckoning" -- that's logging
|
||||
angles from compass and distances from step counter. You need to mark
|
||||
turns, and point watch to direction of the turn. Simultaneously, it
|
||||
tries to log positions using GPS. You can use it to calibrate your
|
||||
step length by comparing GPS and step counter data. It can also get
|
||||
pretty accurate recording of track walked in right circumstances.
|
||||
|
||||
Tap bottom part of the screen to select display (text or map for
|
||||
now). Point watch to new direction, then tap top left part of screen
|
||||
to indicate a turn.
|
||||
|
||||
Map shows blue line for track from dead reckonging, and green line for
|
||||
track from GPS.
|
||||
|
||||
You probably want magnav installed (and calibrated) for useful
|
||||
results, as it provides library with better compass.
|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("mEwhHXAH4A/AH4A/AFsAFtoADF1wwqF4wwhEI5goGGIjFYN4wFF1KbHGUolIMc4lGSdIwJd9DstAH7FrBywwgad4veDwojJBIIvcFwIACGBYICGDYvEGBYvdFwqyLL8i+LF7oxFRxgveGAQ0EF5IwfMY4vpL5AFLAEYv/F8owoE44vrAY4vmAQIEEF85dGGE0AE4gvoFwpmHd0oINAH4A/AH4AvA"))
|
After Width: | Height: | Size: 1.8 KiB |
|
@ -0,0 +1,442 @@
|
|||
/* Ded Reckon */
|
||||
/* eslint-disable no-unused-vars */
|
||||
|
||||
/* fmt library v0.1.3 */
|
||||
let fmt = {
|
||||
icon_alt : "\0\x08\x1a\1\x00\x00\x00\x20\x30\x78\x7C\xFE\xFF\x00\xC3\xE7\xFF\xDB\xC3\xC3\xC3\xC3\x00\x00\x00\x00\x00\x00\x00\x00",
|
||||
icon_m : "\0\x08\x1a\1\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xC3\xE7\xFF\xDB\xC3\xC3\xC3\xC3\x00\x00\x00\x00\x00\x00\x00\x00",
|
||||
icon_km : "\0\x08\x1a\1\xC3\xC6\xCC\xD8\xF0\xD8\xCC\xC6\xC3\x00\xC3\xE7\xFF\xDB\xC3\xC3\xC3\xC3\x00\x00\x00\x00\x00\x00\x00\x00",
|
||||
icon_kph : "\0\x08\x1a\1\xC3\xC6\xCC\xD8\xF0\xD8\xCC\xC6\xC3\x00\xC3\xE7\xFF\xDB\xC3\xC3\xC3\xC3\x00\xFF\x00\xC3\xC3\xFF\xC3\xC3",
|
||||
icon_c : "\0\x08\x1a\1\x00\x00\x60\x90\x90\x60\x00\x7F\xFF\xC0\xC0\xC0\xC0\xC0\xFF\x7F\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
|
||||
|
||||
/* 0 .. DD.ddddd
|
||||
1 .. DD MM.mmm'
|
||||
2 .. DD MM'ss"
|
||||
*/
|
||||
geo_mode : 1,
|
||||
|
||||
init: function() {},
|
||||
fmtDist: function(km) {
|
||||
if (km >= 1.0) return km.toFixed(1) + this.icon_km;
|
||||
return (km*1000).toFixed(0) + this.icon_m;
|
||||
},
|
||||
fmtSteps: function(n) { return this.fmtDist(0.001 * 0.719 * n); },
|
||||
fmtAlt: function(m) { return m.toFixed(0) + this.icon_alt; },
|
||||
draw_dot : 1,
|
||||
add0: function(i) {
|
||||
if (i > 9) {
|
||||
return ""+i;
|
||||
} else {
|
||||
return "0"+i;
|
||||
}
|
||||
},
|
||||
fmtTOD: function(now) {
|
||||
this.draw_dot = !this.draw_dot;
|
||||
let dot = ":";
|
||||
if (!this.draw_dot)
|
||||
dot = ".";
|
||||
return now.getHours() + dot + this.add0(now.getMinutes());
|
||||
},
|
||||
fmtNow: function() { return this.fmtTOD(new Date()); },
|
||||
fmtTimeDiff: function(d) {
|
||||
if (d < 180)
|
||||
return ""+d.toFixed(0);
|
||||
d = d/60;
|
||||
return ""+d.toFixed(0)+"m";
|
||||
},
|
||||
fmtAngle: function(x) {
|
||||
switch (this.geo_mode) {
|
||||
case 0:
|
||||
return "" + x;
|
||||
case 1: {
|
||||
let d = Math.floor(x);
|
||||
let m = x - d;
|
||||
m = m*60;
|
||||
return "" + d + " " + m.toFixed(3) + "'";
|
||||
}
|
||||
case 2: {
|
||||
let d = Math.floor(x);
|
||||
let m = x - d;
|
||||
m = m*60;
|
||||
let mf = Math.floor(m);
|
||||
let s = m - mf;
|
||||
s = s*60;
|
||||
return "" + d + " " + mf + "'" + s.toFixed(0) + '"';
|
||||
}
|
||||
}
|
||||
return "bad mode?";
|
||||
},
|
||||
fmtPos: function(pos) {
|
||||
let x = pos.lat;
|
||||
let c = "N";
|
||||
if (x<0) {
|
||||
c = "S";
|
||||
x = -x;
|
||||
}
|
||||
let s = c+this.fmtAngle(x) + "\n";
|
||||
c = "E";
|
||||
if (x<0) {
|
||||
c = "W";
|
||||
x = -x;
|
||||
}
|
||||
return s + c + this.fmtAngle(x);
|
||||
},
|
||||
fmtFix: function(fix, t) {
|
||||
if (fix && fix.fix && fix.lat) {
|
||||
return this.fmtSpeed(fix.speed) + " " +
|
||||
this.fmtAlt(fix.alt);
|
||||
} else {
|
||||
return "N/FIX " + this.fmtTimeDiff(t);
|
||||
}
|
||||
},
|
||||
fmtSpeed: function(kph) {
|
||||
return kph.toFixed(1) + this.icon_kph;
|
||||
},
|
||||
};
|
||||
|
||||
/* gps library v0.1.1 */
|
||||
let gps = {
|
||||
emulator: -1,
|
||||
init: function(x) {
|
||||
this.emulator = (process.env.BOARD=="EMSCRIPTEN"
|
||||
|| process.env.BOARD=="EMSCRIPTEN2")?1:0;
|
||||
},
|
||||
state: {},
|
||||
on_gps: function(f) {
|
||||
let fix = this.getGPSFix();
|
||||
f(fix);
|
||||
|
||||
/*
|
||||
"lat": number, // Latitude in degrees
|
||||
"lon": number, // Longitude in degrees
|
||||
"alt": number, // altitude in M
|
||||
"speed": number, // Speed in kph
|
||||
"course": number, // Course in degrees
|
||||
"time": Date, // Current Time (or undefined if not known)
|
||||
"satellites": 7, // Number of satellites
|
||||
"fix": 1 // NMEA Fix state - 0 is no fix
|
||||
"hdop": number, // Horizontal Dilution of Precision
|
||||
*/
|
||||
this.state.timeout = setTimeout(this.on_gps, 1000, f);
|
||||
},
|
||||
off_gps: function() {
|
||||
clearTimeout(this.state.timeout);
|
||||
},
|
||||
getGPSFix: function() {
|
||||
if (!this.emulator)
|
||||
return Bangle.getGPSFix();
|
||||
let fix = {};
|
||||
fix.fix = 1;
|
||||
fix.lat = 50;
|
||||
fix.lon = 14-(getTime()-this.gps_start) / 1000; /* Go West! */
|
||||
fix.alt = 200;
|
||||
fix.speed = 5;
|
||||
fix.course = 30;
|
||||
fix.time = Date();
|
||||
fix.satellites = 5;
|
||||
fix.hdop = 12;
|
||||
return fix;
|
||||
},
|
||||
gps_start : -1,
|
||||
start_gps: function() {
|
||||
Bangle.setGPSPower(1, "libgps");
|
||||
this.gps_start = getTime();
|
||||
},
|
||||
stop_gps: function() {
|
||||
Bangle.setGPSPower(0, "libgps");
|
||||
},
|
||||
};
|
||||
|
||||
/* ui library 0.1 */
|
||||
let ui = {
|
||||
display: 0,
|
||||
numScreens: 2,
|
||||
drawMsg: function(msg) {
|
||||
g.reset().setFont("Vector", 35)
|
||||
.setColor(1,1,1)
|
||||
.fillRect(0, this.wi, 176, 176)
|
||||
.setColor(0,0,0)
|
||||
.drawString(msg, 5, 30);
|
||||
},
|
||||
drawBusy: function() {
|
||||
this.drawMsg("\n.oO busy");
|
||||
},
|
||||
nextScreen: function() {
|
||||
print("nextS");
|
||||
this.display = this.display + 1;
|
||||
if (this.display == this.numScreens)
|
||||
this.display = 0;
|
||||
this.drawBusy();
|
||||
},
|
||||
prevScreen: function() {
|
||||
print("prevS");
|
||||
this.display = this.display - 1;
|
||||
if (this.display < 0)
|
||||
this.display = this.numScreens - 1;
|
||||
this.drawBusy();
|
||||
},
|
||||
onSwipe: function(dir) {
|
||||
this.nextScreen();
|
||||
},
|
||||
h: 176,
|
||||
w: 176,
|
||||
wi: 32,
|
||||
last_b: 0,
|
||||
touchHandler: function(d) {
|
||||
let x = Math.floor(d.x);
|
||||
let y = Math.floor(d.y);
|
||||
|
||||
if (d.b != 1 || this.last_b != 0) {
|
||||
this.last_b = d.b;
|
||||
return;
|
||||
}
|
||||
|
||||
print("touch", x, y, this.h, this.w);
|
||||
|
||||
/*
|
||||
if ((x<this.h/2) && (y<this.w/2)) {
|
||||
}
|
||||
if ((x>this.h/2) && (y<this.w/2)) {
|
||||
}
|
||||
*/
|
||||
|
||||
if ((x<this.h/2) && (y>this.w/2)) {
|
||||
print("prev");
|
||||
this.prevScreen();
|
||||
}
|
||||
if ((x>this.h/2) && (y>this.w/2)) {
|
||||
print("next");
|
||||
this.nextScreen();
|
||||
}
|
||||
},
|
||||
init: function() {
|
||||
}
|
||||
};
|
||||
|
||||
var last_steps = Bangle.getStepCount(), last_time = getTime(), speed = 0, step_phase = 0;
|
||||
|
||||
var mpstep = 0.719 * 1.15;
|
||||
|
||||
function updateSteps() {
|
||||
if (step_phase ++ > 9) {
|
||||
step_phase =0;
|
||||
let steps = Bangle.getStepCount();
|
||||
let time = getTime();
|
||||
|
||||
speed = 3.6 * mpstep * ((steps-last_steps) / (time-last_time));
|
||||
last_steps = steps;
|
||||
last_time = time;
|
||||
}
|
||||
return "" + fmt.fmtSpeed(speed) + " " + step_phase + "\n" + fmt.fmtDist(log_dist/1000) + " " + fmt.fmtDist(log_last/1000);
|
||||
}
|
||||
|
||||
/* compensated compass */
|
||||
var CALIBDATA = require("Storage").readJSON("magnav.json",1)||null;
|
||||
const tiltfixread = require("magnav").tiltfixread;
|
||||
var heading;
|
||||
|
||||
|
||||
var cancel_gps = false;
|
||||
|
||||
function drawStats() {
|
||||
let fix = gps.getGPSFix();
|
||||
|
||||
let msg = fmt.fmtFix(fix, getTime() - gps.gps_start);
|
||||
|
||||
msg += "\n" + fmt.fmtDist(gps_dist/1000) + " " + fmt.fmtDist(gps_last/1000) + "\n" + updateSteps();
|
||||
let c = Bangle.getCompass();
|
||||
if (c) msg += "\n" + c.heading.toFixed(0) + "/" + heading.toFixed(0) + "deg " + log.length + "\n";
|
||||
|
||||
g.reset().clear().setFont("Vector", 31)
|
||||
.setColor(1,1,1)
|
||||
.fillRect(0, 24, 176, 100)
|
||||
.setColor(0,0,0)
|
||||
.drawString(msg, 3, 25);
|
||||
}
|
||||
|
||||
function updateGps() {
|
||||
if (cancel_gps)
|
||||
return;
|
||||
heading = tiltfixread(CALIBDATA.offset,CALIBDATA.scale);
|
||||
if (ui.display == 0) {
|
||||
setTimeout(updateGps, 1000);
|
||||
drawLog();
|
||||
drawStats();
|
||||
}
|
||||
if (ui.display == 1) {
|
||||
setTimeout(updateGps, 1000);
|
||||
drawLog();
|
||||
}
|
||||
}
|
||||
|
||||
function stopGps() {
|
||||
cancel_gps=true;
|
||||
gps.stop_gps();
|
||||
}
|
||||
|
||||
var log = [], log_dist = 0, gps_dist = 0;
|
||||
var log_last = 0, gps_last = 0;
|
||||
|
||||
function logEntry() {
|
||||
let e = {};
|
||||
e.time = getTime();
|
||||
e.fix = gps.getGPSFix();
|
||||
e.steps = Bangle.getStepCount();
|
||||
if (0) {
|
||||
let c = Bangle.getCompass();
|
||||
if (c)
|
||||
e.dir = c.heading;
|
||||
else
|
||||
e.dir = -1;
|
||||
} else {
|
||||
e.dir = heading;
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
function onTurn() {
|
||||
let e = logEntry();
|
||||
log.push(e);
|
||||
}
|
||||
|
||||
function radians(a) { return a*Math.PI/180; }
|
||||
function degrees(a) { return a*180/Math.PI; }
|
||||
// distance between 2 lat and lons, in meters, Mean Earth Radius = 6371km
|
||||
// https://www.movable-type.co.uk/scripts/latlong.html
|
||||
// (Equirectangular approximation)
|
||||
function calcDistance(a,b) {
|
||||
var x = radians(b.lon-a.lon) * Math.cos(radians((a.lat+b.lat)/2));
|
||||
var y = radians(b.lat-a.lat);
|
||||
return Math.sqrt(x*x + y*y) * 6371000;
|
||||
}
|
||||
|
||||
var dn, de;
|
||||
function initConv(fix) {
|
||||
let n = { lat: fix.lat+1, lon: fix.lon };
|
||||
let e = { lat: fix.lat, lon: fix.lon+1 };
|
||||
|
||||
dn = calcDistance(fix, n);
|
||||
de = calcDistance(fix, e);
|
||||
print("conversion is ", dn, 108000, de, 50000);
|
||||
}
|
||||
function toM(start, fix) {
|
||||
return { x: (fix.lon - start.lon) * de, y: (fix.lat - start.lat) * dn };
|
||||
}
|
||||
var mpp = 4;
|
||||
function toPix(q) {
|
||||
let p = { x: q.x, y: q.y };
|
||||
p.x /= mpp; /* 10 m / pix */
|
||||
p.y /= -mpp;
|
||||
p.x += 85;
|
||||
p.y += 85;
|
||||
return p;
|
||||
}
|
||||
|
||||
function drawLog() {
|
||||
let here = logEntry();
|
||||
if (!here.fix.lat) {
|
||||
here.fix.lat = 50;
|
||||
here.fix.lon = 14;
|
||||
}
|
||||
initConv(here.fix);
|
||||
log.push(here);
|
||||
let l = log;
|
||||
log_dist = 0;
|
||||
log_last = -1;
|
||||
gps_last = -1;
|
||||
|
||||
g.reset().clear();
|
||||
g.setColor(0, 0, 1);
|
||||
let last = { x: 0, y: 0 };
|
||||
for (let i = l.length - 2; i >= 0; i--) {
|
||||
let next = {};
|
||||
let m = (l[i+1].steps - l[i].steps) * mpstep;
|
||||
let dir = radians(180 + l[i].dir);
|
||||
next.x = last.x + m * Math.sin(dir);
|
||||
next.y = last.y + m * Math.cos(dir);
|
||||
print(dir, m, last, next);
|
||||
let lp = toPix(last);
|
||||
let np = toPix(next);
|
||||
g.drawLine(lp.x, lp.y, np.x, np.y);
|
||||
g.drawCircle(np.x, np.y, 3);
|
||||
last = next;
|
||||
if (log_last == -1)
|
||||
log_last = m;
|
||||
log_dist += m;
|
||||
}
|
||||
g.setColor(0, 1, 0);
|
||||
last = { x: 0, y: 0 };
|
||||
gps_dist = 0;
|
||||
for (let i = l.length - 2; i >= 0; i--) {
|
||||
let fix = l[i].fix;
|
||||
if (fix.fix && fix.lat) {
|
||||
let next = toM(here.fix, fix);
|
||||
let lp = toPix(last);
|
||||
let np = toPix(next);
|
||||
let d = Math.sqrt((next.x-last.x)*(next.x-last.x)+(next.y-last.y)*(next.y-last.y));
|
||||
if (gps_last == -1)
|
||||
gps_last = d;
|
||||
gps_dist += d;
|
||||
g.drawLine(lp.x, lp.y, np.x, np.y);
|
||||
g.drawCircle(np.x, np.y, 3);
|
||||
last = next;
|
||||
}
|
||||
}
|
||||
log.pop();
|
||||
}
|
||||
|
||||
function testPaint() {
|
||||
let pos = gps.getGPSFix();
|
||||
log = [];
|
||||
let e = { fix: pos, steps: 100, dir: 0 };
|
||||
log.push(e);
|
||||
e = { fix: pos, steps: 200, dir: 90 };
|
||||
log.push(e);
|
||||
e = { fix: pos, steps: 300, dir: 0 };
|
||||
log.push(e);
|
||||
print(log, log.length, log[0], log[1]);
|
||||
drawLog();
|
||||
}
|
||||
|
||||
function touchHandler(d) {
|
||||
let x = Math.floor(d.x);
|
||||
let y = Math.floor(d.y);
|
||||
|
||||
if (d.b != 1 || ui.last_b != 0) {
|
||||
ui.last_b = d.b;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if ((x<ui.h/2) && (y<ui.w/2)) {
|
||||
ui.drawMsg("Turn");
|
||||
onTurn();
|
||||
}
|
||||
if ((x>ui.h/2) && (y<ui.w/2)) {
|
||||
ui.drawMsg("Writing");
|
||||
require('Storage').writeJSON("speedstep."+getTime()+".json", log);
|
||||
ui.drawMsg("Wrote");
|
||||
}
|
||||
ui.touchHandler(d);
|
||||
}
|
||||
|
||||
|
||||
fmt.init();
|
||||
gps.init();
|
||||
ui.init();
|
||||
ui.drawBusy();
|
||||
gps.start_gps();
|
||||
Bangle.setCompassPower(1, "speedstep");
|
||||
Bangle.on("drag", touchHandler);
|
||||
Bangle.setUI({
|
||||
mode : "custom",
|
||||
swipe : (s) => ui.onSwipe(s),
|
||||
clock : 0
|
||||
});
|
||||
|
||||
if (0)
|
||||
testPaint();
|
||||
if (1) {
|
||||
g.reset();
|
||||
updateGps();
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
{ "id": "dedreckon",
|
||||
"name": "Ded Reckon",
|
||||
"version": "0.01",
|
||||
"description": "Dead Reckoning using compass and step counter",
|
||||
"icon": "app.png",
|
||||
"readme": "README.md",
|
||||
"supports" : ["BANGLEJS2"],
|
||||
"tags": "outdoors",
|
||||
"storage": [
|
||||
{"name":"dedreckon.app.js","url":"dedreckon.app.js"},
|
||||
{"name":"dedreckon.img","url":"app-icon.js","evaluate":true}
|
||||
]
|
||||
}
|
|
@ -4,3 +4,4 @@
|
|||
Also avoid polluting global scope.
|
||||
0.04: Enhance menu: enable bluetooth, visit settings & visit recovery
|
||||
0.05: Enhance menu: permit toggling bluetooth
|
||||
0.06: Display clock in green when charging, with "charging" text
|
||||
|
|
|
@ -37,14 +37,19 @@ var draw = function () {
|
|||
require("locale").dow(date, 0).toUpperCase();
|
||||
var x2 = x + 6;
|
||||
var y2 = y + 66;
|
||||
var charging = Bangle.isCharging();
|
||||
g.reset()
|
||||
.clearRect(Bangle.appRect)
|
||||
.setFont("Vector", 55)
|
||||
.setFontAlign(0, 0)
|
||||
.setColor(charging ? "#0f0" : g.theme.fg)
|
||||
.drawString(timeStr, x, y)
|
||||
.setFont("Vector", 24)
|
||||
.drawString(dateStr, x2, y2)
|
||||
.drawString("".concat(E.getBattery(), "%"), x2, y2 + 48);
|
||||
.drawString(dateStr, x2, y2);
|
||||
if (charging)
|
||||
g.drawString("charging: ".concat(E.getBattery(), "%"), x2, y2 + 48);
|
||||
else
|
||||
g.drawString("".concat(E.getBattery(), "%"), x2, y2 + 48);
|
||||
if (nextDraw)
|
||||
clearTimeout(nextDraw);
|
||||
nextDraw = setTimeout(function () {
|
||||
|
@ -96,8 +101,10 @@ function drainedRestore() {
|
|||
load();
|
||||
}
|
||||
var checkCharge = function () {
|
||||
if (E.getBattery() < restore)
|
||||
if (E.getBattery() < restore) {
|
||||
draw();
|
||||
return;
|
||||
}
|
||||
drainedRestore();
|
||||
};
|
||||
if (Bangle.isCharging())
|
||||
|
|
|
@ -54,15 +54,21 @@ const draw = () => {
|
|||
require("locale").dow(date, 0).toUpperCase();
|
||||
const x2 = x + 6;
|
||||
const y2 = y + 66;
|
||||
const charging = Bangle.isCharging();
|
||||
|
||||
g.reset()
|
||||
.clearRect(Bangle.appRect)
|
||||
.setFont("Vector", 55)
|
||||
.setFontAlign(0, 0)
|
||||
.setColor(charging ? "#0f0" : g.theme.fg)
|
||||
.drawString(timeStr, x, y)
|
||||
.setFont("Vector", 24)
|
||||
.drawString(dateStr, x2, y2)
|
||||
.drawString(`${E.getBattery()}%`, x2, y2 + 48);
|
||||
.drawString(dateStr, x2, y2);
|
||||
|
||||
if(charging)
|
||||
g.drawString(`charging: ${E.getBattery()}%`, x2, y2 + 48);
|
||||
else
|
||||
g.drawString(`${E.getBattery()}%`, x2, y2 + 48);
|
||||
|
||||
if(nextDraw) clearTimeout(nextDraw);
|
||||
nextDraw = setTimeout(() => {
|
||||
|
@ -125,7 +131,10 @@ function drainedRestore() { // "public", to allow users to call
|
|||
}
|
||||
|
||||
const checkCharge = () => {
|
||||
if(E.getBattery() < restore) return;
|
||||
if(E.getBattery() < restore) {
|
||||
draw();
|
||||
return;
|
||||
}
|
||||
drainedRestore();
|
||||
};
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "drained",
|
||||
"name": "Drained",
|
||||
"version": "0.05",
|
||||
"version": "0.06",
|
||||
"description": "Switches to displaying a simple clock when the battery percentage is low, and disables some peripherals",
|
||||
"readme": "README.md",
|
||||
"icon": "icon.png",
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
0.01: New Clock Nifty A ++ >> adding more information on the right side of the clock
|
||||
0.02: Fix weather icon for languages other than English
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
const w = require("weather");
|
||||
//const locale = require("locale");
|
||||
const locale = require("locale");
|
||||
|
||||
// Weather icons from https://icons8.com/icon/set/weather/color
|
||||
function getSun() {
|
||||
|
@ -67,6 +67,33 @@ function chooseIcon(condition) {
|
|||
return getPartSun;
|
||||
} else return getErr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Choose weather icon to display based on weather conditition code
|
||||
* https://openweathermap.org/weather-conditions#Weather-Condition-Codes-2
|
||||
*/
|
||||
function chooseIconByCode(code) {
|
||||
const codeGroup = Math.round(code / 100);
|
||||
switch (codeGroup) {
|
||||
case 2: return getStorm;
|
||||
case 3: return getRain;
|
||||
case 5:
|
||||
switch (code) {
|
||||
case 511: return getSnow;
|
||||
default: return getRain;
|
||||
}
|
||||
case 6: return getSnow;
|
||||
case 7: return getPartSun;
|
||||
case 8:
|
||||
switch (code) {
|
||||
case 800: return getSun;
|
||||
case 804: return getCloud;
|
||||
default: return getPartSun;
|
||||
}
|
||||
default: return getCloud;
|
||||
}
|
||||
}
|
||||
|
||||
/*function condenseWeather(condition) {
|
||||
condition = condition.toLowerCase();
|
||||
if (condition.includes("thunderstorm") ||
|
||||
|
@ -143,8 +170,17 @@ const clock = new ClockFace({
|
|||
//let cWea =(curr === "no data" ? "no data" : curr.txt);
|
||||
let cTemp= (curr === "no data" ? 273 : curr.temp);
|
||||
// const temp = locale.temp(curr.temp - 273.15).match(/^(\D*\d*)(.*)$/);
|
||||
let w_icon = chooseIcon(curr.txt === undefined ? "no data" : curr.txt );
|
||||
//let w_icon = chooseIcon(curr.txt);
|
||||
|
||||
let w_icon = getErr;
|
||||
if (locale.name === "en" || locale.name === "en_GB" || locale.name === "en_US") {
|
||||
w_icon = chooseIcon(curr.txt === undefined ? "no data" : curr.txt);
|
||||
} else {
|
||||
// cannot use condition string to determine icon if language is not English; use weather code instead
|
||||
const code = curr.code || -1;
|
||||
if (code > 0) {
|
||||
w_icon = chooseIconByCode(curr.code);
|
||||
}
|
||||
}
|
||||
|
||||
g.setFontAlign(1, 0).setFont("Vector", 90 * this.scale);
|
||||
g.drawString(format(hour), this.centerTimeScaleX, this.center.y - 31 * this.scale);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "ffcniftyapp",
|
||||
"name": "Nifty-A Clock ++",
|
||||
"version": "0.01",
|
||||
"version": "0.02",
|
||||
"description": "A nifty clock with time and date and more",
|
||||
"dependencies": {"weather":"app"},
|
||||
"icon": "app.png",
|
||||
|
|
|
@ -106,6 +106,7 @@ function onInit(device) {
|
|||
else if (crcs[0] == 3816337552) version = "2v21";
|
||||
else if (crcs[0] == 3329616485) version = "2v22";
|
||||
else if (crcs[0] == 1569433504) version = "2v23";
|
||||
else if (crcs[0] == 680675961) version = "2v24";
|
||||
else { // for other versions all 7 pages are used, check those
|
||||
var crc = crcs[1];
|
||||
if (crc==1339551013) { version = "2v10.219"; ok = false; }
|
||||
|
|
|
@ -138,4 +138,6 @@
|
|||
|
||||
0.25: Minor code improvements
|
||||
|
||||
0.26: Support for large paths (grid sizes > 65k)
|
||||
0.26: Add option to plot openstmap if installed
|
||||
|
||||
0.27: Support for large paths (grid sizes > 65k)
|
||||
|
|
|
@ -666,11 +666,11 @@ class Status {
|
|||
towards = next_point;
|
||||
}
|
||||
let diff = towards.minus(this.projected_point);
|
||||
direction = Math.atan2(diff.lat, diff.lon);
|
||||
const direction = Math.atan2(diff.lat, diff.lon);
|
||||
|
||||
let full_angle = direction - this.angle;
|
||||
|
||||
c = this.projected_point.coordinates(
|
||||
const c = this.projected_point.coordinates(
|
||||
this.displayed_position,
|
||||
this.adjusted_cos_direction,
|
||||
this.adjusted_sin_direction,
|
||||
|
@ -1400,7 +1400,7 @@ function ask_options(fn) {
|
|||
g.flip();
|
||||
|
||||
function options_select(b, xy) {
|
||||
end = false;
|
||||
let end = false;
|
||||
if (xy.y < height / 2 - 10) {
|
||||
g.setColor(0, 0, 0).fillRect(10, 10, width - 10, height / 2 - 10);
|
||||
g.setColor(1, 1, 1).setFont("Vector:30").setFontAlign(0,0).drawString("Forward", width/2, height/4);
|
||||
|
@ -1480,6 +1480,98 @@ function start_gipy(path, maps, interests, heights) {
|
|||
}
|
||||
},
|
||||
};
|
||||
try {
|
||||
// plot openstmap option if installed
|
||||
const osm = require("openstmap");
|
||||
menu[/*LANG*/"Plot OpenStMap"] = function() {
|
||||
E.showMenu(); // remove menu
|
||||
|
||||
// compute min/max coordinates
|
||||
const fix = Bangle.getGPSFix();
|
||||
let minLat = fix.lat ? fix.lat : 90;
|
||||
let maxLat = fix.lat ? fix.lat : -90;
|
||||
let minLong = fix.lon ? fix.lon : 180;
|
||||
let maxLong = fix.lon ? fix.lon : -180;
|
||||
for(let i=0; i<path.len; i++) {
|
||||
const point = path.point(i);
|
||||
if(point.lat>maxLat) maxLat=point.lat; if(point.lat<minLat) minLat=point.lat;
|
||||
if(point.lon>maxLong) maxLong=point.lon; if(point.lon<minLong) minLong=point.lon;
|
||||
}
|
||||
const max = Bangle.project({lat: maxLat, lon: maxLong});
|
||||
const min = Bangle.project({lat: minLat, lon: minLong});
|
||||
const scaleX = (max.x-min.x)/Bangle.appRect.w;
|
||||
const scaleY = (max.y-min.y)/Bangle.appRect.h;
|
||||
|
||||
// openstmap initialization
|
||||
osm.scale = Math.ceil((scaleX > scaleY ? scaleX : scaleY)*1.1); // add 10% margin
|
||||
osm.lat = (minLat+maxLat)/2.0;
|
||||
osm.lon = (minLong+maxLong)/2.0;
|
||||
|
||||
const drawOpenStmap = () => {
|
||||
g.clearRect(Bangle.appRect);
|
||||
osm.draw();
|
||||
|
||||
// draw track
|
||||
g.setColor("#f09");
|
||||
for(let i=0; i<path.len; i++) {
|
||||
const point = path.point(i);
|
||||
const mp = osm.latLonToXY(point.lat, point.lon);
|
||||
if (i == 0) {
|
||||
g.moveTo(mp.x,mp.y);
|
||||
} else {
|
||||
g.lineTo(mp.x,mp.y);
|
||||
}
|
||||
g.fillCircle(mp.x,mp.y,2); // make the track more visible
|
||||
}
|
||||
|
||||
// draw current position
|
||||
g.setColor("#000");
|
||||
if (fix.lat && fix.lon) {
|
||||
const icon = require("heatshrink").decompress(atob("jEYwYPMyVJkgHEkgICyAHCgIIDyQIChIIEoAIDC4IIEBwOAgEEyVIBAY4DBD4sGHxBQIMRAIIPpAyCHAYILUJEAiVJkAIFgVJXo5fCABQA==")); // 24x24px
|
||||
const mp = osm.latLonToXY(fix.lat, fix.lon);
|
||||
g.drawImage(icon, mp.x, mp.y);
|
||||
}
|
||||
|
||||
// labels
|
||||
g.setFont("6x8",2);
|
||||
g.setFontAlign(0,0,3);
|
||||
g.drawString(/*LANG*/"Back", g.getWidth() - 10, g.getHeight()/2);
|
||||
g.drawString("+", g.getWidth() - 10, g.getHeight()/4);
|
||||
g.drawString("-", g.getWidth() - 10, g.getHeight()/4*3);
|
||||
};
|
||||
drawOpenStmap();
|
||||
|
||||
let startDrag = 0;
|
||||
Bangle.setUI({
|
||||
mode: "custom",
|
||||
btn: (n) => { // back handling
|
||||
g.clearRect(0, 0, g.getWidth(), g.getHeight());
|
||||
E.showMenu(menu);
|
||||
},
|
||||
drag: (ev) => { // zoom, move
|
||||
if (ev.b) {
|
||||
osm.scroll(ev.dx, ev.dy);
|
||||
if (!startDrag) {
|
||||
startDrag = getTime();
|
||||
}
|
||||
} else {
|
||||
if (getTime() - startDrag < 0.2) {
|
||||
// tap
|
||||
if (ev.y > g.getHeight() / 2) {
|
||||
osm.scale *= 2;
|
||||
} else {
|
||||
osm.scale /= 2;
|
||||
}
|
||||
}
|
||||
startDrag = 0;
|
||||
drawOpenStmap();
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
} catch (ex) {
|
||||
// openstmap not available.
|
||||
}
|
||||
E.showMenu(menu);
|
||||
},
|
||||
BTN1,
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
0.01: attempt to import
|
||||
0.02: implement colors and lines
|
||||
|
|
|
@ -3,5 +3,18 @@
|
|||
Bitmap editor suitable for creating icons and fonts for BangleJS2.
|
||||
|
||||
You'll want to run a copy of this in simulator, and another one on
|
||||
watch to view the results. Draw using the provided tools, then press
|
||||
the button, and you'll get result on the console.
|
||||
watch to view the results.
|
||||
|
||||
Draw using the provided tools, then press the button, and you'll get
|
||||
result on the console; you can also use "dump();" on command
|
||||
line. show_icon() takes same parameter as is used in app-icon.js
|
||||
files, you can just copy&paste it to get an icon. By using
|
||||
"for_screen();" command, then taking a screenshot, you can easily
|
||||
generate app.png file.
|
||||
|
||||
It is also possible to load existing icon into editor, using
|
||||
"load_icon("");" command. At the end of iconbits.app.js file there are
|
||||
more utility functions.
|
||||
|
||||
|
||||
|
||||
|
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.0 KiB |
|
@ -10,14 +10,16 @@
|
|||
let kule = [0, 0, 0]; // R, G, B
|
||||
var font_height = 22, font_width = 8;
|
||||
var zoom_x = 64, zoom_y = 24, zoom_f = 6;
|
||||
var color = true;
|
||||
let oldLock = false;
|
||||
let sg = null;
|
||||
const top_bar = 20;
|
||||
|
||||
function clear(m) {
|
||||
sg.setColor(1,1,1).fillRect(0,0, font_width, font_height);
|
||||
}
|
||||
|
||||
function setup(m) {
|
||||
function __setup(m) {
|
||||
mode = m;
|
||||
switch (m) {
|
||||
case 'font':
|
||||
|
@ -37,19 +39,32 @@
|
|||
zoom_f = 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
function setup(m) {
|
||||
__setup(m);
|
||||
sg = Graphics.createArrayBuffer(font_width, font_height, 8, {});
|
||||
clear();
|
||||
}
|
||||
|
||||
function icon_big() {
|
||||
zoom_x = 16;
|
||||
zoom_y = 25;
|
||||
zoom_f = 3;
|
||||
}
|
||||
|
||||
function icon_small() {
|
||||
__setup("icon");
|
||||
}
|
||||
|
||||
function updateLock() {
|
||||
if (oldLock) {
|
||||
return;
|
||||
}
|
||||
g.setColor('#fff');
|
||||
g.fillRect(0, 0, g.getWidth(), 20);
|
||||
g.setFont('6x8', 2);
|
||||
g.setFont('Vector', 22);
|
||||
g.setColor('#000');
|
||||
g.drawString('PLEASE UNLOCK', 10, 2);
|
||||
g.drawString('PLEASE\nUNLOCK', 10, 2);
|
||||
oldLock = true;
|
||||
}
|
||||
Bangle.on("lock", function() {
|
||||
|
@ -60,17 +75,20 @@ Bangle.on("lock", function() {
|
|||
drawUtil();
|
||||
}
|
||||
});
|
||||
function nextColor () {
|
||||
function nextColor() {
|
||||
kule[0] = Math.random();
|
||||
kule[1] = Math.random();
|
||||
kule[2] = Math.random();
|
||||
}
|
||||
function selectColor (x) {
|
||||
let c;
|
||||
function selectColor(x) {
|
||||
if (color) {
|
||||
let i = Math.floor((x - 32) / 4);
|
||||
kule = toColor(i);
|
||||
return;
|
||||
}
|
||||
let c = 255;
|
||||
if (x < g.getWidth()/2) {
|
||||
c = 0;
|
||||
} else {
|
||||
c = 255;
|
||||
}
|
||||
kule[0] = c;
|
||||
kule[1] = c;
|
||||
|
@ -79,8 +97,8 @@ Bangle.on("lock", function() {
|
|||
function nextPen () {
|
||||
switch (pen) {
|
||||
case 'circle': pen = 'pixel'; break;
|
||||
case 'pixel': pen = 'crayon'; break;
|
||||
case 'crayon': pen = 'square'; break;
|
||||
case 'pixel': pen = 'line'; break;
|
||||
case 'line': pen = 'square'; break;
|
||||
case 'square': pen = 'circle'; break;
|
||||
default: pen = 'pixel'; break;
|
||||
}
|
||||
|
@ -89,8 +107,8 @@ Bangle.on("lock", function() {
|
|||
discard = setTimeout(function () { oldX = -1; oldY = -1; console.log('timeout'); discard = null; }, 500);
|
||||
}
|
||||
|
||||
var oldX = -1;
|
||||
var oldY = -1;
|
||||
var oldX = -1, oldY = -1;
|
||||
var line_from = null;
|
||||
|
||||
function drawBrushIcon () {
|
||||
const w = g.getWidth();
|
||||
|
@ -110,13 +128,17 @@ Bangle.on("lock", function() {
|
|||
g.drawLine(w - 14, 6, w - 10, 12);
|
||||
g.drawLine(w - 6, 6, w - 10, 12);
|
||||
break;
|
||||
case 'line':
|
||||
g.drawLine(w - 5, 5, w - 15, 15);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function drawArea () {
|
||||
function drawArea() {
|
||||
g.clear();
|
||||
if (mode == "draw")
|
||||
return;
|
||||
const w = g.getWidth;
|
||||
g.setColor(0, 0, 0.5);
|
||||
g.fillRect(0, 0, g.getWidth(), g.getHeight());
|
||||
g.setColor(1, 1, 1);
|
||||
|
@ -129,13 +151,28 @@ Bangle.on("lock", function() {
|
|||
update();
|
||||
}
|
||||
|
||||
function drawUtil () {
|
||||
function toColor(i) {
|
||||
let r = [0, 0, 0];
|
||||
r[0] = (i % 3) / 2;
|
||||
i = Math.floor(i / 3);
|
||||
r[1] = (i % 3) / 2;
|
||||
i = Math.floor(i / 3);
|
||||
r[2] = (i % 3) / 2;
|
||||
return r;
|
||||
}
|
||||
|
||||
function drawUtil() {
|
||||
if (Bangle.isLocked()) {
|
||||
updateLock();
|
||||
}
|
||||
// titlebar
|
||||
g.setColor(kule[0], kule[1], kule[2]);
|
||||
g.fillRect(0, 0, g.getWidth(), 20);
|
||||
g.fillRect(0, 0, g.getWidth(), top_bar);
|
||||
for (let i = 0; i < 3*3*3; i++) {
|
||||
let r = toColor(i);
|
||||
g.setColor(r[0], r[1], r[2]);
|
||||
g.fillRect(32+4*i, 12, 32+4*i+3, top_bar);
|
||||
}
|
||||
// clear button
|
||||
g.setColor('#000'); // black
|
||||
g.fillCircle(10, 10, 8, 8);
|
||||
|
@ -149,7 +186,7 @@ Bangle.on("lock", function() {
|
|||
drawBrushIcon();
|
||||
}
|
||||
|
||||
function transform (p) {
|
||||
function transform(p) {
|
||||
if (p.x < zoom_x || p.y < zoom_y)
|
||||
return p;
|
||||
p.x = ((p.x - zoom_x) / zoom_f);
|
||||
|
@ -159,8 +196,12 @@ Bangle.on("lock", function() {
|
|||
return p;
|
||||
}
|
||||
|
||||
function __draw (g, from, to) {
|
||||
function __draw(g, from, to) {
|
||||
let XS = (to.x - from.x) / 32;
|
||||
let YS = (to.y - from.y) / 32;
|
||||
|
||||
switch (pen) {
|
||||
case 'line':
|
||||
case 'pixel':
|
||||
g.drawLine(from.x, from.y, to.x, to.y);
|
||||
break;
|
||||
|
@ -170,27 +211,25 @@ Bangle.on("lock", function() {
|
|||
g.drawLine(from.x + 2, from.y + 2, to.x, to.y + 2);
|
||||
break;
|
||||
case 'circle':
|
||||
var XS = (to.x - from.x) / 32;
|
||||
var YS = (to.y - from.y) / 32;
|
||||
for (let i = 0; i < 32; i++) {
|
||||
g.fillCircle(from.x + (i * XS), from.y + (i * YS), 4, 4);
|
||||
g.fillCircle(from.x + (i * XS), from.y + (i * YS), 2, 2);
|
||||
}
|
||||
break;
|
||||
case 'square':
|
||||
var XS = (to.x - from.x) / 32;
|
||||
var YS = (to.y - from.y) / 32;
|
||||
for (let i = 0; i < 32; i++) {
|
||||
const posX = from.x + (i * XS);
|
||||
const posY = from.y + (i * YS);
|
||||
g.fillRect(posX - 10, posY - 10, posX + 10, posY + 10);
|
||||
g.fillRect(posX - 4, posY - 4, posX + 4, posY + 4);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
print("Unkown pen ", pen);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function update() {
|
||||
g.drawImage(sg, 0, 64, {});
|
||||
if (zoom_f < 3)
|
||||
g.drawImage(sg, 4, 64, {});
|
||||
g.drawImage(sg, zoom_x, zoom_y, { scale: zoom_f });
|
||||
}
|
||||
|
||||
|
@ -227,7 +266,7 @@ Bangle.on("lock", function() {
|
|||
}, 100);
|
||||
|
||||
// tap and hold the clear button
|
||||
if (tap.x < 32 && tap.y < 32) {
|
||||
if (tap.x < 32 && tap.y < top_bar) {
|
||||
if (tap.b === 1) {
|
||||
if (tapTimer === null) {
|
||||
tapTimer = setTimeout(function () {
|
||||
|
@ -244,7 +283,7 @@ Bangle.on("lock", function() {
|
|||
}
|
||||
return;
|
||||
}
|
||||
if (tap.x > g.getWidth() - 32 && tap.y < 32) {
|
||||
if (tap.x > g.getWidth() - 32 && tap.y < top_bar) {
|
||||
if (tap.b === 1) {
|
||||
if (tapTimer === null) {
|
||||
tapTimer = setTimeout(function () {
|
||||
|
@ -264,7 +303,7 @@ Bangle.on("lock", function() {
|
|||
}
|
||||
drawUtil();
|
||||
return;
|
||||
} else if (tap.y < 32) {
|
||||
} else if (tap.y < top_bar) {
|
||||
if (mode == "draw")
|
||||
nextColor();
|
||||
else
|
||||
|
@ -272,20 +311,31 @@ Bangle.on("lock", function() {
|
|||
drawUtil();
|
||||
return;
|
||||
}
|
||||
oldX = to.x;
|
||||
oldY = to.y;
|
||||
sg.setColor(kule[0], kule[1], kule[2]);
|
||||
g.setColor(kule[0], kule[1], kule[2]);
|
||||
oldX = to.x;
|
||||
oldY = to.y;
|
||||
|
||||
if (pen != "line") {
|
||||
do_draw(from, to);
|
||||
} else {
|
||||
if (tap.b == 1) {
|
||||
print(line_from);
|
||||
if (!line_from) {
|
||||
line_from = to;
|
||||
} else {
|
||||
do_draw(line_from, to);
|
||||
line_from = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
drawUtil();
|
||||
}
|
||||
function on_btn(n) {
|
||||
|
||||
function dump(n) {
|
||||
function f(i) {
|
||||
return "\\x" + i.toString(16).padStart(2, '0');
|
||||
}
|
||||
print("on_btn", n);
|
||||
print(g.getPixel(0, 0));
|
||||
let s = f(0) + f(font_width) + f(font_height) + f(1);
|
||||
// 0..black, 65535..white
|
||||
for (let y = 0; y < font_height; y++) {
|
||||
|
@ -296,41 +346,55 @@ Bangle.on("lock", function() {
|
|||
}
|
||||
s += f(v);
|
||||
}
|
||||
print("Manual bitmap\n");
|
||||
print('ft("' + s + '");');
|
||||
if (1) {
|
||||
s = "";
|
||||
if (mode == "font")
|
||||
print('show_font("' + s + '");');
|
||||
var im = sg.asImage("string");
|
||||
for (var v of im) {
|
||||
//print("val", v, typeof v);
|
||||
s += f(v);
|
||||
}
|
||||
//print("wh", im, typeof im, im[0], typeof im[0]);
|
||||
//print("Image:", im.length, s);
|
||||
print('fi("'+btoa(im)+'");');
|
||||
//print('show_unc_icon("'+btoa(im)+'");');
|
||||
print('show_icon("'+btoa(require('heatshrink').compress(im))+'");');
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
setup("icon");
|
||||
drawArea();
|
||||
Bangle.setUI({
|
||||
setup("icon");
|
||||
drawArea();
|
||||
Bangle.setUI({
|
||||
"mode": "custom",
|
||||
"drag": on_drag,
|
||||
"btn": on_btn,
|
||||
});
|
||||
drawUtil();
|
||||
"btn": dump,
|
||||
});
|
||||
drawUtil();
|
||||
|
||||
|
||||
function ft(icon) {
|
||||
function show_font(icon) {
|
||||
g.reset().clear();
|
||||
g.setFont("Vector", 26).drawString("Hellord" + icon, 0, 0);
|
||||
}
|
||||
|
||||
function fi(icon) {
|
||||
function show_bin_icon(icon) {
|
||||
g.reset().clear();
|
||||
g.drawImage(atob(icon), 40, 40);
|
||||
g.drawImage(icon, 40, 40);
|
||||
}
|
||||
|
||||
function show_unc_icon(icon) {
|
||||
show_bin_icon(atob(icon));
|
||||
}
|
||||
|
||||
function show_icon(icon) {
|
||||
let unc = require("heatshrink").decompress(atob(icon));
|
||||
show_bin_icon(unc);
|
||||
}
|
||||
|
||||
function load_bin_icon(i) {
|
||||
sg.reset().clear();
|
||||
sg.drawImage(i, 0, 0);
|
||||
drawArea();
|
||||
}
|
||||
|
||||
function load_icon(icon) {
|
||||
let unc = require("heatshrink").decompress(atob(icon));
|
||||
load_bin_icon(unc);
|
||||
}
|
||||
|
||||
function for_screen() {
|
||||
g.reset().clear();
|
||||
icon_big();
|
||||
update();
|
||||
}
|
||||
|
||||
//ft(icon_10 + "23.1" + icon_hpa);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{ "id": "iconbits",
|
||||
"name": "Icon bits",
|
||||
"version": "0.01",
|
||||
"version": "0.02",
|
||||
"description": "Bitmap editor suitable for creating icons",
|
||||
"icon": "app.png",
|
||||
"readme": "README.md",
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
0.01: first release
|
||||
0.02: Use clock_info module as an app
|
||||
0.03: clock_info now uses app name to maintain settings specifically for this clock face
|
||||
0.04: add optional date display, and a settings page to configure it
|
|
@ -5,6 +5,7 @@ A simple clock with the Lato font, with fast load and clock_info
|
|||

|
||||

|
||||

|
||||

|
||||
|
||||
This clock is a Lato version of Simplest++. Simplest++ provided the
|
||||
smallest example of a clock that supports 'fast load' and 'clock
|
||||
|
@ -25,6 +26,8 @@ Pastel Clock.
|
|||
|
||||
* Settings are saved automatically and reloaded along with the clock.
|
||||
|
||||
* Date display can be enabled and disabled, along with format choice in the app settings
|
||||
|
||||
## About Clock Info's
|
||||
|
||||
* The clock info modules enable all clocks to add the display of information to the clock face.
|
||||
|
@ -52,3 +55,5 @@ Pastel Clock.
|
|||
Written by: [Hugh Barney](https://github.com/hughbarney) For support
|
||||
and discussion please post in the [Bangle JS
|
||||
Forum](http://forum.espruino.com/microcosms/1424/)
|
||||
|
||||
Date functionality added by [Septolum](https://github.com/Septolum)
|
||||
|
|
|
@ -38,6 +38,11 @@ Graphics.prototype.setFontLatoSmall = function(scale) {
|
|||
// must be inside our own scope here so that when we are unloaded everything disappears
|
||||
// we also define functions using 'let fn = function() {..}' for the same reason. function decls are global
|
||||
|
||||
let settings = Object.assign({
|
||||
dateDisplay: false,
|
||||
dateFormat: 0,
|
||||
}, require("Storage").readJSON("lato.json", true) || {});
|
||||
|
||||
let draw = function() {
|
||||
var date = new Date();
|
||||
var timeStr = require("locale").time(date,1);
|
||||
|
@ -53,6 +58,25 @@ Graphics.prototype.setFontLatoSmall = function(scale) {
|
|||
g.setFontAlign(0, 0);
|
||||
g.setColor(g.theme.fg);
|
||||
g.drawString(timeStr, w/2, h/2);
|
||||
|
||||
if (settings.dateDisplay) {
|
||||
switch (settings.dateFormat) {
|
||||
case 1:
|
||||
var dateStr = require("locale").date(date,1);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
var dateStr = require("locale").date(date);
|
||||
break;
|
||||
|
||||
default:
|
||||
var dateStr = require("locale").dow(date,1) + ', ' + date.getDate() + ' ' + require("locale").month(date,1);
|
||||
break;
|
||||
}
|
||||
g.setFontVector(16);
|
||||
g.drawString(dateStr, w/2, h/4 -4);
|
||||
}
|
||||
|
||||
clockInfoMenu.redraw(); // clock_info_support
|
||||
|
||||
// schedule a draw for the next minute
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "lato",
|
||||
"name": "Lato",
|
||||
"version": "0.03",
|
||||
"version": "0.04",
|
||||
"description": "A Lato Font clock with fast load and clock_info",
|
||||
"readme": "README.md",
|
||||
"icon": "app.png",
|
||||
|
@ -12,6 +12,10 @@
|
|||
"dependencies" : { "clock_info":"module" },
|
||||
"storage": [
|
||||
{"name":"lato.app.js","url":"app.js"},
|
||||
{"name":"lato.img","url":"icon.js","evaluate":true}
|
||||
{"name":"lato.img","url":"icon.js","evaluate":true},
|
||||
{"name":"lato.settings.js","url":"settings.js"}
|
||||
],
|
||||
"data": [
|
||||
{"name":"lato.json"}
|
||||
]
|
||||
}
|
||||
|
|
After Width: | Height: | Size: 1.5 KiB |
|
@ -0,0 +1,24 @@
|
|||
(function(back) {
|
||||
let settings = require('Storage').readJSON('lato.json',1)||{};
|
||||
if (typeof settings.dateDisplay !== "boolean") settings.dateDisplay = false; // default value
|
||||
if (typeof settings.dateFormat !== "number") settings.dateFormat = 0; // default value
|
||||
function save(key, value) {
|
||||
settings[key] = value;
|
||||
require('Storage').write('lato.json', settings);
|
||||
}
|
||||
const appMenu = {
|
||||
'': {'title': 'Lato'},
|
||||
'< Back': back,
|
||||
'Display Date?': {
|
||||
value: settings.dateDisplay,
|
||||
onchange: (v) => {save('dateDisplay', v)}
|
||||
},
|
||||
"Date Format": {
|
||||
value: settings.dateFormat,
|
||||
min: 0, max: 2,
|
||||
format: v => ["DoW, dd MMM","Locale Short","Locale Long"][v],
|
||||
onchange: (v) => {save('dateFormat', v)}
|
||||
}
|
||||
};
|
||||
E.showMenu(appMenu)
|
||||
})
|
|
@ -196,12 +196,6 @@ module.exports = {
|
|||
"no-undef"
|
||||
]
|
||||
},
|
||||
"apps/sixths/sixths.app.js": {
|
||||
"hash": "2a4676828bdf78df052df402de34e6f1abd1c847ebe0d193fc789cd6e9dd0e5c",
|
||||
"rules": [
|
||||
"no-undef"
|
||||
]
|
||||
},
|
||||
"apps/scribble/app.js": {
|
||||
"hash": "6d13abd27bab8009a6bdabe1df2df394bc14aac20c68f67e8f8b085fa6b427cd",
|
||||
"rules": [
|
||||
|
@ -1021,12 +1015,6 @@ module.exports = {
|
|||
"no-undef"
|
||||
]
|
||||
},
|
||||
"apps/gipy/app.js": {
|
||||
"hash": "41f342e8ef6f2a87b3aea19b75ee45cfdfeff723b94281049e3ae0ec89cddba5",
|
||||
"rules": [
|
||||
"no-undef"
|
||||
]
|
||||
},
|
||||
"apps/geissclk/precompute.js": {
|
||||
"hash": "2317812a9e348e7883e93a4be9e294ad7accd4dc3f0e31ee00343e2412030f98",
|
||||
"rules": [
|
||||
|
@ -1249,12 +1237,6 @@ module.exports = {
|
|||
"no-undef"
|
||||
]
|
||||
},
|
||||
"apps/accelrec/app.js": {
|
||||
"hash": "b5369a60afc8f360f0b33f71080eb3f5d09a1bf3703acfcf07cd80dd19f1997d",
|
||||
"rules": [
|
||||
"no-undef"
|
||||
]
|
||||
},
|
||||
"apps/BLEcontroller/app-joy.js": {
|
||||
"hash": "e4f34bb1bc11b52c3d7a1c537a140b0e23ccef82694dcd602cb517a8ba342898",
|
||||
"rules": [
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
<html>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<link rel="stylesheet" href="../../css/spectre.min.css">
|
||||
<style>
|
||||
table { width:100%;}
|
||||
.table_t {font-weight:bold;width:40%;};
|
||||
table {width:100%;margin-top:3%;}
|
||||
.table_t {font-weight:bold;width:40%;}
|
||||
.form-group > * {display:block;}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
@ -15,18 +17,20 @@
|
|||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input id="translations" type="checkbox" /> <label for="translations">Add common language translations like "Yes", "No", "On", "Off"<br/><i>(Not recommended. For translations use the option under <code>More...</code> in the app loader.</i></label>
|
||||
<label><input id="translations" type="checkbox" /> Add common language translations like "Yes", "No", "On", "Off"<br/><i>(Not recommended. For translations use the option under <code>More...</code> in the app loader.</i></label>
|
||||
<label><input id="customize" type="checkbox" /> Advanced: Customize the date and time formats.</label>
|
||||
</div>
|
||||
<p>
|
||||
<table id="examples">
|
||||
<span id="customize-warning"></span>
|
||||
<table id="examples-short-long"></table>
|
||||
<table id="examples"></table>
|
||||
</p>
|
||||
|
||||
</table>
|
||||
<p>Then click <button id="upload" class="btn btn-primary">Upload</button></p>
|
||||
|
||||
<script src="../../core/lib/customize.js"></script>
|
||||
<script src="../../core/js/utils.js"></script>
|
||||
<script src="locales.js" charset="utf-8"></script>
|
||||
<script src="locales.js"></script>
|
||||
|
||||
<script>
|
||||
/*
|
||||
|
@ -125,15 +129,14 @@ exports = { name : "system", currencySym:"£",
|
|||
});
|
||||
|
||||
|
||||
function createLocaleModule(lang) {
|
||||
function createLocaleModule() {
|
||||
console.log(`Language ${lang}`);
|
||||
|
||||
const translations = document.getElementById('translations').checked;
|
||||
console.log(`Translations: ${translations}`);
|
||||
|
||||
const locale = locales[lang];
|
||||
if (!locale) {
|
||||
alert(`Language ${lang} not found!`);
|
||||
alert(`Locale not set for language ${lang}!`);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -185,16 +188,10 @@ exports = { name : "system", currencySym:"£",
|
|||
"%P": `d.getHours()<12?${js(locale.ampm[0].toLowerCase())}:${js(locale.ampm[1].toLowerCase())}`
|
||||
};
|
||||
|
||||
var timeN = locale.timePattern[0];
|
||||
var timeS = locale.timePattern[1];
|
||||
var dateN = locale.datePattern[0];
|
||||
var dateS = locale.datePattern[1];
|
||||
Object.keys(replaceList).forEach(e => {
|
||||
timeN = timeN.replace(e,"${"+replaceList[e]+"}");
|
||||
timeS = timeS.replace(e,"${"+replaceList[e]+"}");
|
||||
dateN = dateN.replace(e,"${"+replaceList[e]+"}");
|
||||
dateS = dateS.replace(e,"${"+replaceList[e]+"}");
|
||||
});
|
||||
var timeN = patternToCode(locale.timePattern[0]);
|
||||
var timeS = patternToCode(locale.timePattern[1]);
|
||||
var dateN = patternToCode(locale.datePattern[0]);
|
||||
var dateS = patternToCode(locale.datePattern[1]);
|
||||
var temperature = locale.temperature=='°F' ? '(t*9/5)+32' : 't';
|
||||
|
||||
function getLocaleModule(isLocal) {
|
||||
|
@ -246,46 +243,200 @@ exports = {
|
|||
eval(getLocaleModule(true));
|
||||
console.log("exports:",exports);
|
||||
|
||||
function patternToCode(pattern){
|
||||
for(const symbol of Object.keys(replaceList)){
|
||||
pattern = pattern.replaceAll(symbol,"${"+replaceList[symbol]+"}");
|
||||
}
|
||||
return pattern;
|
||||
}
|
||||
function patternToOutput(pattern){
|
||||
const code = patternToCode(pattern);
|
||||
const result = eval(`let d = new Date();\`${code}\``);
|
||||
return result;
|
||||
}
|
||||
function dataList(id, options, formatter){
|
||||
let output = `<datalist id="${id}">`;
|
||||
for(const option of options){
|
||||
const formatted = formatter?.(option) || option;
|
||||
output+=`\n<option value="${option}">${formatted}</option>`
|
||||
}
|
||||
output += "\n</datalist>";
|
||||
return output;
|
||||
}
|
||||
|
||||
var date = new Date();
|
||||
document.getElementById("examples").innerHTML = `
|
||||
// TODO: This warning should have a link to an article explaining how the formats work, and how long they are allowed to be
|
||||
document.getElementById("customize-warning").innerText = customizeLocale ? "⚠️ If you make the formats too long, some apps will not work!" : "";
|
||||
document.getElementById("examples-short-long").innerHTML = `
|
||||
<tr><td class="table_t"></td><td style="font-weight:bold">Short</td><td style="font-weight:bold">Long</td></tr>
|
||||
<tr><td class="table_t">Day</td><td>${exports.dow(date,1)}</td><td>${exports.dow(date,0)}</td></tr>
|
||||
<tr><td class="table_t">Month</td><td>${exports.month(date,1)}</td><td>${exports.month(date,0)}</td></tr>
|
||||
<tr><td class="table_t">Date</td><td>${exports.date(date,1)}</td><td>${exports.date(date,0)}</td></tr>
|
||||
<tr><td class="table_t">Time</td><td>${exports.time(date,1)}</td><td>${exports.time(date,0)}</td></tr>
|
||||
<tr><td class="table_t">Number</td><td>${exports.number(12.3456789)}</td><td>${exports.number(12.3456789,4)}</td></tr>
|
||||
<tr><td class="table_t">Distance</td><td>${exports.distance(12.34,0)}</td><td>${exports.distance(12345.6,1)}</td></tr>
|
||||
<tr><td class="table_t">Speed</td><td></td><td>${exports.speed(123)}</td></tr>
|
||||
<tr><td class="table_t">Temperature</td><td></td><td>${exports.temp(12,0)}</td></tr>
|
||||
<tr><td class="table_t">Date</td>
|
||||
<td id="short-date-pattern-output">${exports.date(date,1)}</td>
|
||||
<td id="long-date-pattern-output">${exports.date(date,0)}</td>
|
||||
</tr>
|
||||
${customizeLocale ? `<tr><td class="table_t">Date format</td>
|
||||
<td>
|
||||
<input type=text id="short-date-pattern" list="short-date-patterns" value="${locale?.datePattern["1"]}"/>
|
||||
${dataList("short-date-patterns", [locale?.datePattern["1"], "%-d.%-m.%y", "%-d/%-m/%y", "%d/%m/%Y"], patternToOutput)}
|
||||
</td>
|
||||
<td>
|
||||
<input type=text id="long-date-pattern" list="long-date-patterns" value="${locale?.datePattern["0"]}"/>
|
||||
${dataList("long-date-patterns", [locale?.datePattern["0"], "%-d. %b %Y", "%b %d, %Y"], patternToOutput)}
|
||||
</td>
|
||||
</td>`
|
||||
: ""}
|
||||
<tr><td class="table_t">Time</td>
|
||||
<td id="short-time-pattern-output">${exports.time(date,1)}</td>
|
||||
<td id="long-time-pattern-output">${exports.time(date,0)}</td>
|
||||
</tr>
|
||||
${customizeLocale ? `<tr><td class="table_t">Time format</td>
|
||||
<td>
|
||||
<input type=text id="short-time-pattern" list="short-time-patterns" value="${locale?.timePattern["1"]}"/>
|
||||
${dataList("short-time-patterns", [ "%HH.%MM", "%HH:%MM"], patternToOutput)}
|
||||
</td>
|
||||
<td>
|
||||
<input type=text id="long-time-pattern" list="long-time-patterns" value="${locale?.timePattern["0"]}"/>
|
||||
${dataList("long-time-patterns", [locale?.timePattern["0"], "%HH.%MM.%SS", "%HH:%MM:%SS"], patternToOutput)}
|
||||
</td>
|
||||
</td>`
|
||||
: ""}
|
||||
<tr><td class="table_t">Number</td><td>${exports.number(12.3456789)}</td><td>${exports.number(12.3456789,4)}</td></tr>
|
||||
<tr><td class="table_t">Distance</td><td>${exports.distance(12.34,0)}</td><td>${exports.distance(12345.6,1)}</td></tr>
|
||||
`;
|
||||
document.getElementById("examples").innerHTML = `
|
||||
<tr><td class="table_t">Meridian</td><td>
|
||||
<span id="meridian-am-output">${exports.meridian(new Date(0))}</span> /
|
||||
<span id="meridian-pm-output">${exports.meridian(new Date(43200000))}</span>
|
||||
</td></tr>
|
||||
${customizeLocale ? `<tr><td class="table_t">Meridian names</td>
|
||||
<td>
|
||||
<input type=text id="meridian-am" list="meridian-ams" value="${locale?.ampm["0"]}"/>
|
||||
${dataList("meridian-ams", [locale?.ampm["0"], "AM"])}
|
||||
</td>
|
||||
<td>
|
||||
<input type=text id="meridian-pm" list="meridian-pms" value="${locale?.ampm["1"]}"/>
|
||||
${dataList("meridian-pms", [locale?.ampm["1"], "PM"])}
|
||||
</td>
|
||||
</tr>`
|
||||
: ""}
|
||||
<tr><td class="table_t">Speed</td><td>${exports.speed(123)}</td></tr>
|
||||
<tr><td class="table_t">Temperature</td><td>${exports.temp(12,0)}</td></tr>
|
||||
`;
|
||||
|
||||
if(customizeLocale){
|
||||
document.querySelector("input#short-date-pattern").addEventListener("input", event => {
|
||||
locale.datePattern["1"] = event.target.value;
|
||||
document.querySelector("td#short-date-pattern-output").innerText = patternToOutput(event.target.value);
|
||||
});
|
||||
document.querySelector("input#long-date-pattern").addEventListener("input", event => {
|
||||
locale.datePattern["0"] = event.target.value;
|
||||
document.querySelector("td#long-date-pattern-output").innerText = patternToOutput(event.target.value);
|
||||
});
|
||||
document.querySelector("input#short-time-pattern").addEventListener("input", event => {
|
||||
locale.timePattern["1"] = event.target.value;
|
||||
document.querySelector("td#short-time-pattern-output").innerText = patternToOutput(event.target.value);
|
||||
});
|
||||
document.querySelector("input#long-time-pattern").addEventListener("input", event => {
|
||||
locale.timePattern["0"] = event.target.value;
|
||||
document.querySelector("td#long-time-pattern-output").innerText = patternToOutput(event.target.value);
|
||||
});
|
||||
document.querySelector("input#meridian-am").addEventListener("input", event => {
|
||||
locale.ampm["0"] = event.target.value;
|
||||
document.querySelector("span#meridian-am-output").innerText = event.target.value;
|
||||
});
|
||||
document.querySelector("input#meridian-pm").addEventListener("input", event => {
|
||||
locale.ampm["1"] = event.target.value;
|
||||
document.querySelector("span#meridian-pm-output").innerText = event.target.value;
|
||||
});
|
||||
}
|
||||
return getLocaleModule(false);
|
||||
}
|
||||
|
||||
const lastUploadedLocaleID = "last-uploaded-locale";
|
||||
let lastUploadedLocale;
|
||||
try{
|
||||
lastUploadedLocale = JSON.parse(localStorage?.getItem(lastUploadedLocaleID));
|
||||
}catch(error){
|
||||
console.warn("Unable to load last uploaded locale", error);
|
||||
}
|
||||
if(lastUploadedLocale){
|
||||
if(!lastUploadedLocale.lang){
|
||||
lastUploadedLocale = undefined;
|
||||
console.warn("Unable to load last uploaded locale, it is missing the lang entry");
|
||||
}else if(lastUploadedLocale.custom){
|
||||
// Make sure to add any missing data from the original lang
|
||||
// We don't know if fx a new entry has been added after the locale was last saved
|
||||
const originalLocale = structuredClone(locales[lastUploadedLocale.lang]);
|
||||
lastUploadedLocale = {...originalLocale, ...lastUploadedLocale};
|
||||
|
||||
// Add a special entry for the custom locale, put it first in the list
|
||||
locales = {[lastUploadedLocaleID]: lastUploadedLocale, ...locales};
|
||||
}
|
||||
}
|
||||
|
||||
var lang;
|
||||
var locale;
|
||||
var customizeLocale = false;
|
||||
var languageSelector = document.getElementById("languages");
|
||||
var customizeSelector = document.getElementById('customize');
|
||||
languageSelector.innerHTML = Object.keys(locales).map(l=>{
|
||||
var locale = locales[l];
|
||||
var localeParts = l.split("_"); // en_GB -> ["en","GB"]
|
||||
var name = l === lastUploadedLocaleID ? `Custom locale based on ${locale.lang}` : locale.lang;
|
||||
var localeParts = locale.lang.split("_"); // en_GB -> ["en","GB"]
|
||||
var icon = "";
|
||||
// If we have a 2 char ISO country code, use it to get the unicode flag
|
||||
if (locale.icon)
|
||||
icon = locale.icon+" ";
|
||||
else if (localeParts[1] && localeParts[1].length==2)
|
||||
icon = localeParts[1].toUpperCase().replace(/./g, char => String.fromCodePoint(char.charCodeAt(0)+127397) )+" ";
|
||||
return `<option value="${l}">${icon}${l}${locale.notes?" - "+locale.notes:""}</option>`
|
||||
return `<option value="${l}">${icon}${name}${locale.notes?" - "+locale.notes:""}</option>`
|
||||
}).join("\n");
|
||||
languageSelector.addEventListener('change', function() {
|
||||
const lang = languageSelector.options[languageSelector.selectedIndex].value;
|
||||
createLocaleModule(lang);
|
||||
});
|
||||
// initial value
|
||||
createLocaleModule(languageSelector.options[languageSelector.selectedIndex].value);
|
||||
if(lastUploadedLocale){
|
||||
if(lastUploadedLocale.custom){
|
||||
// If the last uploaded locale was customized, choose the custom locale as default value
|
||||
languageSelector.value = lastUploadedLocaleID;
|
||||
}else{
|
||||
// If the last uploaded locale was not customized, choose the existing locale in the list as the default value
|
||||
languageSelector.value = lastUploadedLocale.lang;
|
||||
}
|
||||
}
|
||||
languageSelector.addEventListener('change', handleLanguageChange);
|
||||
function handleLanguageChange(){
|
||||
lang = languageSelector.value;
|
||||
locale = structuredClone(locales[lang]);
|
||||
// If the locale is customized, make sure the customization option is activated. If not, disable it.
|
||||
if(Boolean(customizeSelector.checked) !== Boolean(locale.custom)){
|
||||
customizeSelector.checked = Boolean(locale.custom);
|
||||
handleCustomizeChange();
|
||||
}else{
|
||||
createLocaleModule();
|
||||
}
|
||||
}
|
||||
customizeSelector.addEventListener('change', handleCustomizeChange);
|
||||
function handleCustomizeChange(){
|
||||
customizeLocale = customizeSelector.checked;
|
||||
// If the user no longer wants to customize, make sure to return to the default lang entry
|
||||
if(!customizeLocale){
|
||||
languageSelector.value = locales[lang].lang;
|
||||
handleLanguageChange();
|
||||
}else{
|
||||
createLocaleModule();
|
||||
}
|
||||
}
|
||||
// set initial values
|
||||
handleLanguageChange();
|
||||
|
||||
|
||||
|
||||
document.getElementById("upload").addEventListener("click", function() {
|
||||
|
||||
const lang = languageSelector.options[languageSelector.selectedIndex].value;
|
||||
var localeModule = createLocaleModule(lang);
|
||||
var localeModule = createLocaleModule();
|
||||
|
||||
// Save the locale data to make it easier to upload the same locale next time.
|
||||
// If the locale is not customized, only save the lang. The rest of the data will be added when the page loads next time.
|
||||
const savedLocaleData = customizeLocale ? {...locale, custom: true} : {lang: locale.lang};
|
||||
localStorage?.setItem(lastUploadedLocaleID, JSON.stringify(savedLocaleData));
|
||||
|
||||
console.log("Locale Module is:",localeModule);
|
||||
sendCustomizedApp({
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
0.1: Initial release
|
||||
0.2: Draw line for 3d effect, fix number alignment
|
||||
0.3: Fix day-end overflowing hour calculation
|
||||
|
|
|
@ -78,6 +78,19 @@
|
|||
return lineEndFull - 5;
|
||||
};
|
||||
|
||||
let drawHourString = function(hour, yLines) {
|
||||
var hourForDrawing = 0;
|
||||
if (hour < 0) {
|
||||
// a negative hour => (+ and - = -)
|
||||
hourForDrawing = 24 + hour;
|
||||
} else if (hour >= 24) {
|
||||
hourForDrawing = hour - 24;
|
||||
} else {
|
||||
hourForDrawing = hour;
|
||||
}
|
||||
g.drawString(hourForDrawing, hourStringXOffset(hourForDrawing), yLines, true);
|
||||
};
|
||||
|
||||
let drawTime = function () {
|
||||
g.clear();
|
||||
var d = new Date();
|
||||
|
@ -101,12 +114,12 @@
|
|||
switch (yTopLines - 88 + mins) {
|
||||
case -60:
|
||||
lineEnd = lineEndFull;
|
||||
g.drawString(d.getHours()-1, hourStringXOffset(d.getHours()-1), yTopLines, true);
|
||||
drawHourString(d.getHours() - 1, yTopLines);
|
||||
break;
|
||||
case 0:
|
||||
case 60:
|
||||
lineEnd = lineEndFull;
|
||||
g.drawString(d.getHours(), hourStringXOffset(d.getHours()), yTopLines, true);
|
||||
drawHourString(d.getHours(), yTopLines);
|
||||
break;
|
||||
case 45:
|
||||
case -45:
|
||||
|
@ -136,11 +149,11 @@
|
|||
case 0:
|
||||
case 60:
|
||||
lineEnd = lineEndFull;
|
||||
g.drawString(d.getHours() + 1, hourStringXOffset(d.getHours()+1), yBottomLines, true);
|
||||
drawHourString(d.getHours() + 1, yBottomLines);
|
||||
break;
|
||||
case 120:
|
||||
lineEnd = lineEndFull;
|
||||
g.drawString(d.getHours() + 2, hourStringXOffset(d.getHours()+2), yBottomLines, true);
|
||||
drawHourString(d.getHours() + 2, yBottomLines);
|
||||
break;
|
||||
case 15:
|
||||
case 75:
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "measuretime",
|
||||
"name": "Measure Time",
|
||||
"version": "0.2",
|
||||
"version": "0.3",
|
||||
"description": "Measure Time in a fancy way.",
|
||||
"icon": "measuretime_icon.png",
|
||||
"screenshots": [
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
# Pomodoro
|
||||
|
||||
> The Pomodoro Technique is a time management method developed by Francesco Cirillo in the late 1980s. It uses a kitchen timer to break work into intervals, typically 25 minutes in length, separated by short breaks. Each interval is known as a pomodoro, from the Italian word for tomato, after the tomato-shaped kitchen timer Cirillo used as a university student.
|
||||
>
|
||||
> The original technique has six steps:
|
||||
>
|
||||
> Decide on the task to be done.
|
||||
> Set the Pomodoro timer (typically for 25 minutes).
|
||||
> Work on the task.
|
||||
> End work when the timer rings and take a short break (typically 5–10 minutes).
|
||||
> Go back to Step 2 and repeat until you complete four pomodori.
|
||||
> After four pomodori are done, take a long break (typically 20 to 30 minutes) instead of a short break. Once the long break is finished, return to step 2.
|
||||
|
||||
*Description gathered from https://en.wikipedia.org/wiki/Pomodoro_Technique*
|
|
@ -7,6 +7,7 @@
|
|||
"type": "app",
|
||||
"tags": "pomodoro,cooking,tools",
|
||||
"supports": ["BANGLEJS", "BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
"allow_emulator": true,
|
||||
"screenshots": [{"url":"bangle2-pomodoro-screenshot.png"}],
|
||||
"storage": [
|
||||
|
|
|
@ -8,3 +8,4 @@
|
|||
0.05: Fix display of final menu item when no options are given and
|
||||
handling of E.showMenu() with no arguments
|
||||
0.06: Fix lower bounding of numeric values
|
||||
0.07: Fix bug with alarms app (scroller) and correctly show images
|
||||
|
|
|
@ -28,6 +28,9 @@ E.showMenu = function (items) {
|
|||
y += 22;
|
||||
var lastIdx = 0;
|
||||
var selectEdit = undefined;
|
||||
var scroller = {
|
||||
scroll: selected,
|
||||
};
|
||||
var l = {
|
||||
draw: function (rowmin, rowmax) {
|
||||
var rows = 0 | Math.min((y2 - y) / fontHeight, menuItems.length);
|
||||
|
@ -76,10 +79,11 @@ E.showMenu = function (items) {
|
|||
v = "";
|
||||
}
|
||||
{
|
||||
if (name.length >= 17 - v.length && typeof item === "object") {
|
||||
var vplain = v.indexOf("\0") < 0;
|
||||
if (vplain && name.length >= 17 - v.length && typeof item === "object") {
|
||||
g.drawString(name.substring(0, 12 - v.length) + "...", x + 3.7, iy + 2.7);
|
||||
}
|
||||
else if (name.length >= 15) {
|
||||
else if (vplain && name.length >= 15) {
|
||||
g.drawString(name.substring(0, 15) + "...", x + 3.7, iy + 2.7);
|
||||
}
|
||||
else {
|
||||
|
@ -138,9 +142,11 @@ E.showMenu = function (items) {
|
|||
else {
|
||||
var lastSelected = selected;
|
||||
selected = (selected + dir + menuItems.length) % menuItems.length;
|
||||
scroller.scroll = selected;
|
||||
l.draw(Math.min(lastSelected, selected), Math.max(lastSelected, selected));
|
||||
}
|
||||
},
|
||||
scroller: scroller,
|
||||
};
|
||||
l.draw();
|
||||
var back = options.back;
|
||||
|
|
|
@ -35,6 +35,10 @@ E.showMenu = (items?: Menu): MenuInstance => {
|
|||
let lastIdx = 0;
|
||||
let selectEdit: undefined | ActualMenuItem = undefined;
|
||||
|
||||
const scroller = {
|
||||
scroll: selected,
|
||||
};
|
||||
|
||||
const l = {
|
||||
draw: (rowmin?: number, rowmax?: number) => {
|
||||
let rows = 0|Math.min((y2 - y) / fontHeight, menuItems.length);
|
||||
|
@ -83,9 +87,10 @@ E.showMenu = (items?: Menu): MenuInstance => {
|
|||
}
|
||||
|
||||
/*???*/{
|
||||
if(name.length >= 17 - v.length && typeof item === "object"){
|
||||
const vplain = v.indexOf("\0") < 0;
|
||||
if(vplain && name.length >= 17 - v.length && typeof item === "object"){
|
||||
g.drawString(name.substring(0, 12 - v.length) + "...", x + 3.7, iy + 2.7);
|
||||
}else if(name.length >= 15){
|
||||
}else if(vplain && name.length >= 15){
|
||||
g.drawString(name.substring(0, 15) + "...", x + 3.7, iy + 2.7);
|
||||
}else{
|
||||
g.drawString(name, x + 3.7, iy + 2.7);
|
||||
|
@ -156,9 +161,11 @@ E.showMenu = (items?: Menu): MenuInstance => {
|
|||
} else {
|
||||
const lastSelected = selected;
|
||||
selected = (selected + dir + /*keep +ve*/menuItems.length) % menuItems.length;
|
||||
scroller.scroll = selected;
|
||||
l.draw(Math.min(lastSelected, selected), Math.max(lastSelected, selected));
|
||||
}
|
||||
},
|
||||
scroller,
|
||||
};
|
||||
|
||||
l.draw();
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "promenu",
|
||||
"name": "Pro Menu",
|
||||
"version": "0.06",
|
||||
"version": "0.07",
|
||||
"description": "Replace the built in menu function. Supports Bangle.js 1 and Bangle.js 2.",
|
||||
"icon": "icon.png",
|
||||
"type": "bootloader",
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("mEw4X/AwX48AFCqoAEC4oL/Bf4L/Bf4LTAH4A/ADGqAAIL/Bf4LD"))
|
|
@ -0,0 +1,142 @@
|
|||
{
|
||||
const minute_boxes = [
|
||||
{x:0.5, y:0},
|
||||
{x:0.5, y:0.5},
|
||||
{x:0, y:0.5},
|
||||
{x:0, y:0},
|
||||
];
|
||||
|
||||
const hour_boxes = [
|
||||
{x:0.5, y:0},
|
||||
{x:0.75, y:0},
|
||||
{x:0.75, y:0.25},
|
||||
{x:0.75, y:0.5},
|
||||
{x:0.75, y:0.75},
|
||||
{x:0.5, y:0.75},
|
||||
{x:0.25, y:0.75},
|
||||
{x:0, y:0.75},
|
||||
{x:0, y:0.5},
|
||||
{x:0, y:0.25},
|
||||
{x:0, y:0},
|
||||
{x:0.25, y:0},
|
||||
];
|
||||
|
||||
let drawTimeout;
|
||||
|
||||
// schedule a draw for the next 15 minute period
|
||||
let queueDraw = function queueDraw() {
|
||||
if (drawTimeout) clearTimeout(drawTimeout);
|
||||
drawTimeout = setTimeout(function() {
|
||||
drawTimeout = undefined;
|
||||
draw();
|
||||
}, (60000 * 15) - (Date.now() % (60000 * 15)));
|
||||
};
|
||||
|
||||
// Main draw function
|
||||
let draw = function draw() {
|
||||
var d = new Date();
|
||||
var h = d.getHours(), m = d.getMinutes();
|
||||
|
||||
g.setBgColor(settings.backgroundColour);
|
||||
g.clearRect(Bangle.appRect);
|
||||
|
||||
if (settings.showBattery) {
|
||||
drawBattery();
|
||||
}
|
||||
|
||||
// Draw minute box
|
||||
drawBox(Math.floor(m/15), minute_boxes, Bangle.appRect.h/2, settings.minuteColour);
|
||||
|
||||
// Draw an hour box or write the number
|
||||
if (settings.digital) {
|
||||
g.setColor(settings.hourColour);
|
||||
g.setFont("Vector:60");
|
||||
g.setFontAlign(0,0);
|
||||
g.drawString(h, Bangle.appRect.x + Bangle.appRect.w/2, Bangle.appRect.y + Bangle.appRect.h/2);
|
||||
} else {
|
||||
drawBox(h % 12, hour_boxes, Bangle.appRect.h/4, settings.hourColour);
|
||||
}
|
||||
|
||||
queueDraw();
|
||||
};
|
||||
|
||||
// Draw battery box
|
||||
let drawBattery = function drawBattery() {
|
||||
// Round battery up to 10% interval
|
||||
let battery = Math.min((Math.floor(E.getBattery()/10)+1)/10, 1);
|
||||
|
||||
// Maximum battery box
|
||||
let batterySize = 30;
|
||||
|
||||
// Draw outer box at full brightness
|
||||
g.setColor(settings.batteryColour);
|
||||
g.drawRect(
|
||||
(Bangle.appRect.w / 2) - batterySize,
|
||||
(Bangle.appRect.h / 2) - batterySize + Bangle.appRect.y,
|
||||
(Bangle.appRect.w / 2) + batterySize,
|
||||
(Bangle.appRect.h / 2) + batterySize + Bangle.appRect.y
|
||||
);
|
||||
|
||||
// Fade battery colour and draw inner box
|
||||
g.setColor(settings.batteryColour.split('').map((c) => {
|
||||
return c=='f' ? Math.ceil(15 * battery).toString(16) : c;
|
||||
}).join(''));
|
||||
g.fillRect(
|
||||
(Bangle.appRect.w / 2) - (batterySize * battery),
|
||||
(Bangle.appRect.h / 2) - (batterySize * battery) + Bangle.appRect.y,
|
||||
(Bangle.appRect.w / 2) + (batterySize * battery),
|
||||
(Bangle.appRect.h / 2) + (batterySize * battery) + Bangle.appRect.y
|
||||
);
|
||||
};
|
||||
|
||||
// Draw hour or minute boxes
|
||||
let drawBox = function drawBox(current, boxes, size, colour) {
|
||||
let x1 = (boxes[current].x * Bangle.appRect.h) + (Bangle.appRect.y/2);
|
||||
let y1 = (boxes[current].y * Bangle.appRect.h) + Bangle.appRect.y;
|
||||
let x2 = x1 + size;
|
||||
let y2 = y1 + size;
|
||||
g.setColor(colour);
|
||||
g.fillRect(x1, y1, x2, y2);
|
||||
};
|
||||
|
||||
let settings = Object.assign({
|
||||
// Default values
|
||||
minuteColour: '#f00',
|
||||
hourColour: '#ff0',
|
||||
backgroundColour: 'theme',
|
||||
showWidgets: true,
|
||||
showBattery: true,
|
||||
digital: false,
|
||||
batteryColour: '#0f0'
|
||||
}, require('Storage').readJSON('quarterclock.json', true) || {});
|
||||
|
||||
if (settings.backgroundColour == 'theme') {
|
||||
settings.backgroundColour = g.theme.bg;
|
||||
}
|
||||
|
||||
// Set minuteColour to a darker shade if same as hourColour
|
||||
if (settings.minuteColour == settings.hourColour) {
|
||||
settings.minuteColour = settings.minuteColour.split('').map((c) => {
|
||||
return c=='f' ? '7' : c;
|
||||
}).join('');
|
||||
}
|
||||
|
||||
// Show launcher when middle button pressed
|
||||
// Remove handler to allow fast loading
|
||||
Bangle.setUI({mode:"clock", remove:function() {
|
||||
if (drawTimeout) clearTimeout(drawTimeout);
|
||||
require("widget_utils").show();
|
||||
}});
|
||||
|
||||
// Load and display widgets
|
||||
Bangle.loadWidgets();
|
||||
if (settings.showWidgets) {
|
||||
require("widget_utils").show();
|
||||
} else {
|
||||
require("widget_utils").hide();
|
||||
}
|
||||
|
||||
// draw initial boxes and queue subsequent redraws
|
||||
draw();
|
||||
}
|
||||
|
After Width: | Height: | Size: 252 B |
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"id": "quarterclock",
|
||||
"name": "Quarter Clock",
|
||||
"shortName":"Quarter Clock",
|
||||
"icon": "app.png",
|
||||
"screenshots" : [ { "url":"screenshot.png" } ],
|
||||
"version":"0.01",
|
||||
"description": "For those lazy days when the exact time doesn't matter. Small square shows the hour, large square shows the fifteen minute period, and centre square shows the battery level.",
|
||||
"type": "clock",
|
||||
"tags": "clock",
|
||||
"supports": ["BANGLEJS2"],
|
||||
"storage": [
|
||||
{"name":"quarterclock.app.js","url":"app.js"},
|
||||
{"name":"quarterclock.settings.js","url":"settings.js"},
|
||||
{"name":"quarterclock.img","url":"app-icon.js","evaluate":true}
|
||||
],
|
||||
"data": [
|
||||
{"name":"quarterclock.json"}
|
||||
]
|
||||
}
|
After Width: | Height: | Size: 1.4 KiB |
|
@ -0,0 +1,66 @@
|
|||
(function(back) {
|
||||
var FILE = 'quarterclock.json';
|
||||
// Load settings
|
||||
var settings = Object.assign({
|
||||
minuteColour: '#f00',
|
||||
hourColour: '#ff0',
|
||||
backgroundColour: 'theme',
|
||||
showWidgets: true,
|
||||
showBattery: true,
|
||||
digital: false,
|
||||
batteryColour: '#0f0',
|
||||
}, require('Storage').readJSON(FILE, true) || {});
|
||||
|
||||
function setSetting(key,value) {
|
||||
settings[key] = value;
|
||||
require('Storage').writeJSON(FILE, settings);
|
||||
}
|
||||
|
||||
// Helper method which uses int-based menu item for set of string values and their labels
|
||||
function stringItems(key, startvalue, values, labels) {
|
||||
return {
|
||||
value: (startvalue === undefined ? 0 : values.indexOf(startvalue)),
|
||||
format: v => labels[v],
|
||||
min: 0,
|
||||
max: values.length - 1,
|
||||
wrap: true,
|
||||
step: 1,
|
||||
onchange: v => {
|
||||
setSetting(key,values[v]);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Helper method which breaks string set settings down to local settings object
|
||||
function stringInSettings(name, values, labels) {
|
||||
return stringItems(name,settings[name], values, labels);
|
||||
}
|
||||
|
||||
// Show the menu
|
||||
E.showMenu({
|
||||
'' : { 'title' : 'Quarter Clock' },
|
||||
'< Back' : () => back(),
|
||||
'Hour Colour': stringInSettings('hourColour', ['#f00', '#0f0', '#00f', '#ff0', '#0ff', '#f0f'], ['Red', 'Green', 'Blue', 'Yellow', 'Cyan', 'Magenta']),
|
||||
'Minute Colour': stringInSettings('minuteColour', ['#f00', '#0f0', '#00f', '#ff0', '#0ff', '#f0f'], ['Red', 'Green', 'Blue', 'Yellow', 'Cyan', 'Magenta']),
|
||||
'Background Colour': stringInSettings('backgroundColour', ['theme', '#000', '#fff'],['theme', 'Black', 'White']),
|
||||
'Digital': {
|
||||
value: !!settings.digital, // !! converts undefined to false
|
||||
onchange: v => {
|
||||
setSetting('digital', v);
|
||||
},
|
||||
},
|
||||
'Show Widgets': {
|
||||
value: !!settings.showWidgets,
|
||||
onchange: v => {
|
||||
setSetting('showWidgets', v);
|
||||
},
|
||||
},
|
||||
'Show Battery': {
|
||||
value: !!settings.showBattery,
|
||||
onchange: v => {
|
||||
setSetting('showBattery', v);
|
||||
},
|
||||
},
|
||||
'Battery Colour': stringInSettings('batteryColour', ['#f00', '#0f0', '#00f', '#ff0', '#0ff', '#f0f'], ['Red', 'Green', 'Blue', 'Yellow', 'Cyan', 'Magenta']),
|
||||
});
|
||||
})
|
|
@ -651,11 +651,11 @@ function showUtilMenu() {
|
|||
E.showMessage(/*LANG*/'Flattening battery - this can take hours.\nLong-press button to cancel.');
|
||||
Bangle.setLCDTimeout(0);
|
||||
Bangle.setLCDPower(1);
|
||||
Bangle.setLCDBrightness(1);
|
||||
if (Bangle.setGPSPower) Bangle.setGPSPower(1,"flat");
|
||||
if (Bangle.setHRMPower) Bangle.setHRMPower(1,"flat");
|
||||
if (Bangle.setCompassPower) Bangle.setCompassPower(1,"flat");
|
||||
if (Bangle.setBarometerPower) Bangle.setBarometerPower(1,"flat");
|
||||
if (Bangle.setHRMPower) Bangle.setGPSPower(1,"flat");
|
||||
setInterval(function() {
|
||||
var i=1000;while (i--);
|
||||
}, 1);
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
0.01: attempt to import
|
||||
0.02: Minor code improvements
|
||||
0.03: big rewrite, adding time-adjust and altitude-adjust functionality
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{ "id": "skyspy",
|
||||
"name": "Sky Spy",
|
||||
"version": "0.02",
|
||||
"version": "0.03",
|
||||
"description": "Application for debugging GPS problems",
|
||||
"icon": "app.png",
|
||||
"readme": "README.md",
|
||||
|
|
|
@ -1,20 +1,121 @@
|
|||
/* Sky spy */
|
||||
/* 0 .. DD.ddddd
|
||||
|
||||
/* fmt library v0.1 */
|
||||
let fmt = {
|
||||
icon_alt : "\0\x08\x1a\1\x00\x00\x00\x20\x30\x78\x7C\xFE\xFF\x00\xC3\xE7\xFF\xDB\xC3\xC3\xC3\xC3\x00\x00\x00\x00\x00\x00\x00\x00",
|
||||
icon_m : "\0\x08\x1a\1\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xC3\xE7\xFF\xDB\xC3\xC3\xC3\xC3\x00\x00\x00\x00\x00\x00\x00\x00",
|
||||
icon_km : "\0\x08\x1a\1\xC3\xC6\xCC\xD8\xF0\xD8\xCC\xC6\xC3\x00\xC3\xE7\xFF\xDB\xC3\xC3\xC3\xC3\x00\x00\x00\x00\x00\x00\x00\x00",
|
||||
icon_kph : "\0\x08\x1a\1\xC3\xC6\xCC\xD8\xF0\xD8\xCC\xC6\xC3\x00\xC3\xE7\xFF\xDB\xC3\xC3\xC3\xC3\x00\xFF\x00\xC3\xC3\xFF\xC3\xC3",
|
||||
icon_c : "\0\x08\x1a\1\x00\x00\x60\x90\x90\x60\x00\x7F\xFF\xC0\xC0\xC0\xC0\xC0\xFF\x7F\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
|
||||
|
||||
/* 0 .. DD.ddddd
|
||||
1 .. DD MM.mmm'
|
||||
2 .. DD MM'ss"
|
||||
*/
|
||||
var mode = 1;
|
||||
*/
|
||||
geo_mode : 1,
|
||||
|
||||
init: function() {},
|
||||
fmtDist: function(km) { return km.toFixed(1) + this.icon_km; },
|
||||
fmtSteps: function(n) { return this.fmtDist(0.001 * 0.719 * n); },
|
||||
fmtAlt: function(m) { return m.toFixed(0) + this.icon_alt; },
|
||||
fmtTimeDiff: function(d) {
|
||||
if (d < 180)
|
||||
return ""+d.toFixed(0);
|
||||
d = d/60;
|
||||
return ""+d.toFixed(0)+"m";
|
||||
},
|
||||
fmtAngle: function(x) {
|
||||
switch (this.geo_mode) {
|
||||
case 0:
|
||||
return "" + x;
|
||||
case 1: {
|
||||
let d = Math.floor(x);
|
||||
let m = x - d;
|
||||
m = m*60;
|
||||
return "" + d + " " + m.toFixed(3) + "'";
|
||||
}
|
||||
case 2: {
|
||||
let d = Math.floor(x);
|
||||
let m = x - d;
|
||||
m = m*60;
|
||||
let mf = Math.floor(m);
|
||||
let s = m - mf;
|
||||
s = s*60;
|
||||
return "" + d + " " + mf + "'" + s.toFixed(0) + '"';
|
||||
}
|
||||
}
|
||||
return "bad mode?";
|
||||
},
|
||||
fmtPos: function(pos) {
|
||||
let x = pos.lat;
|
||||
let c = "N";
|
||||
if (x<0) {
|
||||
c = "S";
|
||||
x = -x;
|
||||
}
|
||||
let s = c+this.fmtAngle(pos.lat) + "\n";
|
||||
c = "E";
|
||||
if (x<0) {
|
||||
c = "W";
|
||||
x = -x;
|
||||
}
|
||||
return s + c + this.fmtAngle(pos.lon);
|
||||
},
|
||||
};
|
||||
|
||||
/* gps library v0.1 */
|
||||
let gps = {
|
||||
emulator: -1,
|
||||
init: function(x) {
|
||||
this.emulator = (process.env.BOARD=="EMSCRIPTEN"
|
||||
|| process.env.BOARD=="EMSCRIPTEN2")?1:0;
|
||||
},
|
||||
state: {},
|
||||
on_gps: function(f) {
|
||||
let fix = this.getGPSFix();
|
||||
f(fix);
|
||||
|
||||
/*
|
||||
"lat": number, // Latitude in degrees
|
||||
"lon": number, // Longitude in degrees
|
||||
"alt": number, // altitude in M
|
||||
"speed": number, // Speed in kph
|
||||
"course": number, // Course in degrees
|
||||
"time": Date, // Current Time (or undefined if not known)
|
||||
"satellites": 7, // Number of satellites
|
||||
"fix": 1 // NMEA Fix state - 0 is no fix
|
||||
"hdop": number, // Horizontal Dilution of Precision
|
||||
*/
|
||||
this.state.timeout = setTimeout(this.on_gps, 1000, f);
|
||||
},
|
||||
off_gps: function() {
|
||||
clearTimeout(this.state.timeout);
|
||||
},
|
||||
getGPSFix: function() {
|
||||
if (!this.emulator)
|
||||
return Bangle.getGPSFix();
|
||||
let fix = {};
|
||||
fix.fix = 1;
|
||||
fix.lat = 50;
|
||||
fix.lon = 14;
|
||||
fix.alt = 200;
|
||||
fix.speed = 5;
|
||||
fix.course = 30;
|
||||
fix.time = Date();
|
||||
fix.satellites = 5;
|
||||
fix.hdop = 12;
|
||||
return fix;
|
||||
}
|
||||
};
|
||||
|
||||
var display = 0;
|
||||
|
||||
var debug = 0;
|
||||
|
||||
var cancel_gps, gps_start;
|
||||
var gps_start;
|
||||
var cur_altitude;
|
||||
|
||||
var wi = 24;
|
||||
var h = 176-wi, w = 176;
|
||||
|
||||
var fix;
|
||||
var adj_time = 0, adj_alt = 0;
|
||||
|
||||
function radA(p) { return p*(Math.PI*2); }
|
||||
function radD(d) { return d*(h/2); }
|
||||
|
@ -27,26 +128,7 @@ function radY(p, d) {
|
|||
return h/2 - Math.cos(a)*radD(d) + wi;
|
||||
}
|
||||
|
||||
function format(x) {
|
||||
switch (mode) {
|
||||
case 0:
|
||||
return "" + x;
|
||||
case 1:
|
||||
d = Math.floor(x);
|
||||
m = x - d;
|
||||
m = m*60;
|
||||
return "" + d + " " + m.toFixed(3) + "'";
|
||||
case 2:
|
||||
d = Math.floor(x);
|
||||
m = x - d;
|
||||
m = m*60;
|
||||
mf = Math.floor(m);
|
||||
s = m - mf;
|
||||
s = s*60;
|
||||
return "" + d + " " + mf + "'" + s.toFixed(0) + '"';
|
||||
}
|
||||
}
|
||||
var qalt = -1;
|
||||
var qalt = -1, min_dalt, max_dalt, step;
|
||||
function resetAlt() {
|
||||
min_dalt = 9999; max_dalt = -9999; step = 0;
|
||||
}
|
||||
|
@ -64,65 +146,96 @@ function calcAlt(alt, cur_altitude) {
|
|||
return ddalt;
|
||||
}
|
||||
function updateGps() {
|
||||
let /*have = false,*/ lat = "lat", lon = "lon", alt = "alt",
|
||||
speed = "speed", hdop = "hdop"; // balt = "balt";
|
||||
let lat = "lat ", alt = "?",
|
||||
speed = "speed ", hdop = "?", adelta = "adelta ",
|
||||
tdelta = "tdelta ";
|
||||
|
||||
if (cancel_gps)
|
||||
return;
|
||||
fix = Bangle.getGPSFix();
|
||||
fix = gps.getGPSFix();
|
||||
if (adj_time) {
|
||||
print("Adjusting time");
|
||||
setTime(fix.time.getTime()/1000);
|
||||
adj_time = 0;
|
||||
}
|
||||
if (adj_alt) {
|
||||
print("Adjust altitude");
|
||||
if (qalt < 5) {
|
||||
let rest_altitude = fix.alt;
|
||||
let alt_adjust = cur_altitude - rest_altitude;
|
||||
let abs = Math.abs(alt_adjust);
|
||||
print("adj", alt_adjust);
|
||||
let o = Bangle.getOptions();
|
||||
if (abs > 10 && abs < 150) {
|
||||
let a = 0.01;
|
||||
// FIXME: draw is called often compared to alt reading
|
||||
if (cur_altitude > rest_altitude)
|
||||
a = -a;
|
||||
o.seaLevelPressure = o.seaLevelPressure + a;
|
||||
Bangle.setOptions(o);
|
||||
}
|
||||
msg = o.seaLevelPressure.toFixed(1) + "hPa";
|
||||
print(msg);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
Bangle.getPressure().then((x) => {
|
||||
cur_altitude = x.altitude;
|
||||
}, print);
|
||||
} catch (e) {
|
||||
print("Altimeter error", e);
|
||||
//print("Altimeter error", e);
|
||||
}
|
||||
|
||||
speed = getTime() - gps_start;
|
||||
|
||||
//print(fix);
|
||||
if (fix && fix.time) {
|
||||
tdelta = "" + (getTime() - fix.time.getTime()/1000).toFixed(0);
|
||||
}
|
||||
if (fix && fix.fix && fix.lat) {
|
||||
lat = "" + format(fix.lat);
|
||||
lon = "" + format(fix.lon);
|
||||
alt = "" + fix.alt.toFixed(1);
|
||||
lat = "" + fmt.fmtPos(fix);
|
||||
alt = "" + fix.alt.toFixed(0);
|
||||
adelta = "" + (cur_altitude - fix.alt).toFixed(0);
|
||||
speed = "" + fix.speed.toFixed(1);
|
||||
hdop = "" + fix.hdop.toFixed(1);
|
||||
//have = true;
|
||||
hdop = "" + fix.hdop.toFixed(0);
|
||||
} else {
|
||||
lat = "NO FIX\n"
|
||||
+ "" + (getTime() - gps_start).toFixed(0) + "s "
|
||||
+ sats_used + "/" + snum;
|
||||
if (cur_altitude)
|
||||
adelta = "" + cur_altitude.toFixed(0);
|
||||
}
|
||||
|
||||
let ddalt = calcAlt(alt, cur_altitude);
|
||||
if (display == 1)
|
||||
g.reset().setFont("Vector", 20)
|
||||
.setColor(1,1,1)
|
||||
.fillRect(0, wi, 176, 176)
|
||||
.setColor(0,0,0)
|
||||
.drawString("Acquiring GPS", 0, 30)
|
||||
.drawString(lat, 0, 50)
|
||||
.drawString(lon, 0, 70)
|
||||
.drawString("alt "+alt, 0, 90)
|
||||
.drawString("speed "+speed, 0, 110)
|
||||
.drawString("hdop "+hdop, 0, 130)
|
||||
.drawString("balt" + cur_altitude, 0, 150);
|
||||
|
||||
let msg = "";
|
||||
if (display == 1) {
|
||||
msg = lat +
|
||||
"\ne" + hdop + "m "+tdelta+"s\n" +
|
||||
speed + "km/h\n"+ alt + "m+" + adelta + "\nmsghere";
|
||||
}
|
||||
if (display == 2) {
|
||||
g.reset().setFont("Vector", 20)
|
||||
.setColor(1,1,1)
|
||||
.fillRect(0, wi, 176, 176)
|
||||
.setColor(0,0,0)
|
||||
.drawString("GPS status", 0, 30)
|
||||
.drawString("speed "+speed, 0, 50)
|
||||
.drawString("hdop "+hdop, 0, 70)
|
||||
.drawString("dd "+qalt.toFixed(0) + " (" + ddalt.toFixed(0) + ")", 0, 90)
|
||||
.drawString("alt "+alt, 0, 110)
|
||||
.drawString("balt " + cur_altitude, 0, 130)
|
||||
.drawString(step, 0, 150);
|
||||
/* qalt is altitude quality estimate -- over ten seconds,
|
||||
computes differences between GPS and barometric altitude.
|
||||
The lower the better.
|
||||
|
||||
ddalt is just a debugging -- same estimate, but without
|
||||
waiting 10 seconds, so will be always optimistic at start
|
||||
of the cycle */
|
||||
msg = speed + "km/h\n" +
|
||||
"e"+hdop + "m"
|
||||
+"\ndd "+qalt.toFixed(0) + "\n(" + step + "/" + ddalt.toFixed(0) + ")" +
|
||||
"\n"+alt + "m+" + adelta;
|
||||
}
|
||||
step++;
|
||||
if (step == 10) {
|
||||
qalt = max_dalt - min_dalt;
|
||||
resetAlt();
|
||||
}
|
||||
if (display > 0) {
|
||||
g.reset().setFont("Vector", 31)
|
||||
.setColor(1,1,1)
|
||||
.fillRect(0, wi, 176, 176)
|
||||
.setColor(0,0,0)
|
||||
.drawString(msg, 3, 25);
|
||||
}
|
||||
|
||||
if (debug > 0)
|
||||
print(fix);
|
||||
setTimeout(updateGps, 1000);
|
||||
|
@ -184,7 +297,7 @@ function drawSats(sats) {
|
|||
|
||||
var sats = [];
|
||||
var snum = 0;
|
||||
//var sats_receiving = 0;
|
||||
var sats_used = 0;
|
||||
|
||||
function parseRaw(msg, lost) {
|
||||
if (lost)
|
||||
|
@ -199,6 +312,7 @@ function parseRaw(msg, lost) {
|
|||
if (s[2] == "1") {
|
||||
snum = 0;
|
||||
sats = [];
|
||||
sats_used = 0;
|
||||
}
|
||||
|
||||
let view = 1 * s[3];
|
||||
|
@ -217,6 +331,8 @@ function parseRaw(msg, lost) {
|
|||
sat.ele = 1*s[i++];
|
||||
sat.azi = 1*s[i++];
|
||||
sat.snr = s[i++];
|
||||
if (sat.snr != "")
|
||||
sats_used++;
|
||||
if (debug > 0)
|
||||
print(" ", sat);
|
||||
sats[snum++] = sat;
|
||||
|
@ -231,30 +347,80 @@ function parseRaw(msg, lost) {
|
|||
}
|
||||
}
|
||||
|
||||
function stopGps() {
|
||||
cancel_gps=true;
|
||||
Bangle.setGPSPower(0, "skyspy");
|
||||
}
|
||||
|
||||
function markGps() {
|
||||
cancel_gps = false;
|
||||
Bangle.setGPSPower(1, "skyspy");
|
||||
Bangle.on('GPS-raw', parseRaw);
|
||||
gps_start = getTime();
|
||||
updateGps();
|
||||
}
|
||||
|
||||
function onSwipe(dir) {
|
||||
display = display + 1;
|
||||
if (display == 3)
|
||||
display = 0;
|
||||
function drawMsg(msg) {
|
||||
g.reset().setFont("Vector", 35)
|
||||
.setColor(1,1,1)
|
||||
.fillRect(0, wi, 176, 176)
|
||||
.setColor(0,0,0)
|
||||
.drawString(msg, 5, 30);
|
||||
}
|
||||
function drawBusy() {
|
||||
drawMsg("\n.oO busy");
|
||||
}
|
||||
|
||||
var numScreens = 3;
|
||||
|
||||
function nextScreen() {
|
||||
display = display + 1;
|
||||
if (display == numScreens)
|
||||
display = 0;
|
||||
drawBusy();
|
||||
}
|
||||
|
||||
function prevScreen() {
|
||||
display = display - 1;
|
||||
if (display < 0)
|
||||
display = numScreens - 1;
|
||||
drawBusy();
|
||||
}
|
||||
|
||||
function onSwipe(dir) {
|
||||
nextScreen();
|
||||
}
|
||||
|
||||
var last_b = 0;
|
||||
function touchHandler(d) {
|
||||
let x = Math.floor(d.x);
|
||||
let y = Math.floor(d.y);
|
||||
|
||||
if (d.b != 1 || last_b != 0) {
|
||||
last_b = d.b;
|
||||
return;
|
||||
}
|
||||
last_b = d.b;
|
||||
|
||||
if ((x<h/2) && (y<w/2)) {
|
||||
drawMsg("Clock\nadjust");
|
||||
adj_time = 1;
|
||||
}
|
||||
if ((x>h/2) && (y<w/2)) {
|
||||
drawMsg("Alt\nadjust");
|
||||
adj_alt = 1;
|
||||
}
|
||||
|
||||
if ((x<h/2) && (y>w/2))
|
||||
prevScreen();
|
||||
if ((x>h/2) && (y>w/2))
|
||||
nextScreen();
|
||||
}
|
||||
|
||||
gps.init();
|
||||
fmt.init();
|
||||
|
||||
Bangle.on("drag", touchHandler);
|
||||
Bangle.setUI({
|
||||
mode : "custom",
|
||||
swipe : onSwipe,
|
||||
clock : 0
|
||||
});
|
||||
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
drawBusy();
|
||||
markGps();
|
||||
|
|
|
@ -11,3 +11,4 @@
|
|||
Stop ClockInfo text drawing outside the allocated area
|
||||
0.09: Use clock_info module as an app
|
||||
0.10: Option to hide widgets, tweak top widget width to avoid overlap with hour text at 9am
|
||||
0.11: Avoid rendering clkinfo in the same colour as the background
|
||||
|
|
|
@ -86,6 +86,7 @@ let draw = function() {
|
|||
|
||||
let isAnimIn = true;
|
||||
let animInterval;
|
||||
let minuteX;
|
||||
// Draw *just* the minute image
|
||||
let drawMinute = function() {
|
||||
var yo = slopeBorder + offsy + y - 2*slope*minuteX/R.w;
|
||||
|
@ -128,9 +129,9 @@ let clockInfoDraw = (itm, info, options) => {
|
|||
let texty = options.y+41;
|
||||
// set a cliprect to stop us drawing outside our box
|
||||
g.reset().setClipRect(options.x, options.y, options.x+options.w-1, options.y+options.h-1);
|
||||
g.setFont("6x15").setBgColor(options.bg).setColor(options.fg).clearRect(options.x, texty-15, options.x+options.w-2, texty);
|
||||
g.setFont("6x15").setBgColor(options.bg).clearRect(options.x, texty-15, options.x+options.w-2, texty);
|
||||
|
||||
if (options.focus) g.setColor(options.hl);
|
||||
g.setColor(options.focus ? options.hl : options.fg);
|
||||
if (options.x < g.getWidth()/2) { // left align
|
||||
let x = options.x+2;
|
||||
if (info.img) g.clearRect(x, options.y, x+23, options.y+23).drawImage(info.img, x, options.y);
|
||||
|
@ -150,7 +151,7 @@ let clockInfoMenu = require("clock_info").addInteractive(clockInfoItems, { // t
|
|||
});
|
||||
let clockInfoMenu2 = require("clock_info").addInteractive(clockInfoItems, { // bottom left
|
||||
app:"slopeclockpp",x:0, y:115, w:50, h:40,
|
||||
draw : clockInfoDraw, bg : bgColor, fg : g.theme.bg, hl : (bgColor=="#000")?"#f00"/*red*/:g.theme.fg
|
||||
draw : clockInfoDraw, bg : bgColor, fg : g.theme.bg, hl : (g.theme.fg===g.toColor(bgColor))?"#f00"/*red*/:g.theme.fg
|
||||
});
|
||||
|
||||
// Show launcher when middle button pressed
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{ "id": "slopeclockpp",
|
||||
"name": "Slope Clock ++",
|
||||
"version":"0.10",
|
||||
"version":"0.11",
|
||||
"description": "A clock where hours and minutes are divided by a sloping line. When the minute changes, the numbers slide off the screen. This is a clone of the original Slope Clock which shows extra information and allows the colors to be selected.",
|
||||
"icon": "app.png",
|
||||
"screenshots": [{"url":"screenshot.png"}],
|
||||
|
|
|
@ -7,3 +7,4 @@
|
|||
0.07: Update clock_info to avoid a redraw
|
||||
0.08: Timer ClockInfo now updates once a minute
|
||||
0.09: Timer ClockInfo resets to timer menu when blurred
|
||||
0.10: Timer ClockInfo now uses +- icons, and changes timer from 'T-5 min' to just '5 min' to aid readability
|
|
@ -28,7 +28,7 @@
|
|||
var min = getAlarmMinutes();
|
||||
if(min < 0)
|
||||
return "OFF";
|
||||
return "T-" + String(min)+ " min";
|
||||
return min + " min";
|
||||
}
|
||||
|
||||
function increaseAlarm(t){
|
||||
|
@ -80,7 +80,7 @@
|
|||
offsets.forEach((o, i) => {
|
||||
smpltmrItems.items = smpltmrItems.items.concat({
|
||||
name: null,
|
||||
get: () => ({ text: (o > 0 ? "+" : "") + o + " min.", img: smpltmrItems.img }),
|
||||
get: () => ({ text: (o > 0 ? "+" : "") + o + " min", img: (o>0)?atob("GBiBAAB+AAB+AAAYAAAYAAB+AA3/sA+B8A4AcAwAMBgYGBgYGDAYDDAYDDH/jDH/jDAYDDAYDBgYGBgYGAwAMA4AcAeB4AH/gAB+AA=="):atob("GBiBAAB+AAB+AAAYAAAYAAB+AA3/sA+B8A4AcAwAMBgAGBgAGDAADDAADDH/jDH/jDAADDAADBgAGBgAGAwAMA4AcAeB4AH/gAB+AA==") }),
|
||||
show: function() { },
|
||||
hide: function() { },
|
||||
blur: restoreMainItem,
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"id": "smpltmr",
|
||||
"name": "Simple Timer",
|
||||
"shortName": "Simple Timer",
|
||||
"version": "0.09",
|
||||
"version": "0.10",
|
||||
"description": "A very simple app to start a timer.",
|
||||
"icon": "app.png",
|
||||
"tags": "tool,alarm,timer,clkinfo",
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
0.01: New App!
|
||||
0.02: Adjusted main font size to fit nicely even at 8pm, minor tweaks
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{ // must be inside our own scope here so that when we are unloaded everything disappears
|
||||
// we also define functions using 'let fn = function() {..}' for the same reason. function decls are globalj
|
||||
// we also define functions using 'let fn = function() {..}' for the same reason. function decls are global
|
||||
let removeHasNotRun = true;
|
||||
let drawTimeout;
|
||||
|
||||
|
@ -37,19 +37,19 @@ let drawSplashScreen = function (frame, total) {
|
|||
|
||||
// for fast startup-feeling, draw the splash screen once directly once
|
||||
g.clear()
|
||||
drawSplashScreen(0, 20);
|
||||
drawSplashScreen(0, 15);
|
||||
|
||||
let splashScreen = function () {
|
||||
g.clearRect(R.x,R.y, R.x2, R.y2);
|
||||
return new Promise((resolve, reject) => {
|
||||
let frame = 0;
|
||||
function tick() {
|
||||
if (removeHasNotRun) drawSplashScreen(frame, 20);
|
||||
if (removeHasNotRun) drawSplashScreen(frame, 15);
|
||||
frame += 1;
|
||||
if (!removeHasNotRun) {
|
||||
reject();
|
||||
} else if (frame < 20) {
|
||||
setTimeout(tick, 50);
|
||||
} else if (frame < 15) {
|
||||
setTimeout(tick, 30);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
|
@ -62,13 +62,13 @@ let splashScreen = function () {
|
|||
Graphics.prototype.setFontPlayfairDisplay = function() {
|
||||
// https://www.espruino.com/Font+Converter
|
||||
// <link href="https://fonts.googleapis.com/css2?family=Playfair+Display:ital@0;1&display=swap" rel="stylesheet">
|
||||
// 60pt, 2bpp, Numeric
|
||||
// Actual height 62 (67 - 6)
|
||||
// Actual height 58 (61 - 4)
|
||||
// 1 BPP
|
||||
return this.setFontCustom(
|
||||
E.toString(require('heatshrink').decompress(atob('AD8/A40B/4IGh/8DI/4BA3/8AHFg//wAIFj/+ES8DEQ5FIj4ZGBAKdzhwIHNA8f4BoGUpBwGg/wRQ7HHPA0BFJA6HJY9/FI46GgLWHMiF/Mi8Dbo8MbuYALv6VGg//BA1/BAwQB/51Fn4IBNokBA4P/UAkPBASYEFQIABDI7DEDIY9EDIY9DDIY0EJoICDJoYNCFYgnDAYcDJQUBMAbKDBgcAuADCgw8DBgcYBg0AkAMGgAVDsADCgQiDLYYVDg4ZDCocOBgYiDnwDGNocHNAh/CRYy3Gj6uLcYgZHW4f8BAYrDDIjaDA4Y0DGYjJBbIoIDFQhGDCAoRBCAwAqcYcEBAbNDiDNHoCLDZoUDEQ8MBAccAYVwOAigCOQbaBToylDPYicC//waI4iVegYiDdYYiEdYYiEHgYiECAZFEDobbGRYoADRYgADVwgADVwYAjcYUDaoQAB8ACBjxcEAYX4BAc4DIQUCSgJtCj4iDhwDC/wZGg4iDgIeCn4iDGYS6BEQc8agQiEVQV/EQcDHgMDv4iDh4CBnIiEnwqB84iDgIeBj8fEQcH+AKBEQkf+E/8IiEv7qBg4iEfYQiFBAPgEQoIBNAs/DIIiEgAZCEQkDBAI3BRYn//AiFFYPAEQs/AoIiED4KVBEQg0BwAiFdASuFCYYiEJAYiEPwYHGAFsDAYUOBAcIAYVwBAdgCgRtDgIECjgQDgwDCMgkYVwSHEEQQZBCwQnDUgM4IIkD4AkDvACBh4WDgINBgE8gEMBoYLBEQMwBoY8B4AWCBoTfBwEPEQICCb4MAZ4V+EQX/h/cGwLSCg///98gE/HgUf//9/gMBNYU///nCYLsDAoOfAQJiCeIP8v4IBCAUP//wA4P8BAQrBwYZEJwIyC/6hDDIITBDIZXBwA/BDIZbCGYgRBCYRNDCYYqEDgoAXgYIHd4IAGXwQAEZgIIGYYIqGOAYADj4iH/4iGVAIQGuYiGgePEQ0cdQaVD4AiGhxFHuEPEQsDYAIiFjBOBFQwiGhxXBEQtwgAiFZ4IACCQbyBAAQSCdIIADQAgACGod/EQ0HDIgiCFQgiCFQoiCDIp7GaI5oGH4TRGFwIZHEQ9/EQwZBEQwAcggIHiAIHoA7EwBzBVwn+AgMMaAfAmAFBAQRlCDIMAVwfwgyiCEQQZBjAEBjgiDgHgAoNwEQcDHgQlCEQMOAgMeEQk4AgN4EQ0DEoQiCIQMfDIQiBh5rBXAYiBn7bEEQX/PgYiDfgJ8CEQYIBaQYiCBAJ5CEQYZEEQIpB//4EQkHDIjxCWAhaBEQIrBGYd/LYN/JoYAD/5nDbYiBCAAgQGAFReBHYp4CLwZ6CBAysCDQp6BRQghDAAJ5DXoQABDIaIBWwoqDRYgqDbIoADGgTFCGgoZBD4MHFYYeBKgMBcQQMBgZSCMAUf4EYBAQiCDoNgCwRNC8AZCgEMDIQEDgEgAQN4gE4EQkDKIIwChwCDEgIFBIoQXBh5uBj5RCDIK3CNAQ/CRYpUBSoaLCDgKEDHgSeEQQRUCcYpZCaIzbDTgbKEfog0DA4gICM4QIFFQgAih4pHn6ICAAn/VwReFEQ4ZHn5uFEQTCBESIMEEQd/TwYiCQgIVGYQIVCEQSwCLYQiCaYR1CEQLKFEQSFBEQzkCLYQiBaQRFFfwoiBAIPwgxoEj7iFEQJ7G//HV4ogBnzRHYA0/IIbRMCA8PZA8/A40ACA4AUvDlKAAl/BAcHAgKlBRgYNCcIiBBX4a+Cj4WBX4ThCv4WBDILhEQQICBGgQZBVwLQEDIP/z/gv6XBgLwCBwMfFYK1BAAIWBjySCFAk4AQPgIwQFBsA8BCQQoCEQMMBARdBgQTBkA+CBwMIBAINBGgYOBEQJHBMwQiDQgcGH4aBBBAMYBAJCBGgIDBH4MD/h7C/EPEQKZCMQQtCLwSFCRYnhPgS3CAgKoCVwi/DPgQFB8CXCDIQFBXQbrCj4VBSwiyDRoYAEv4zCBApnBAAp4CAExZCAApeECAgIGSwJWFSYTJBAAbADDIyXBMQYZCQQVgDIg0BgKRBDIY0BhwHBgIQCFYMwJogrBgKnCn4DBv+Ag48CIQU+gE8HgQuCnEAWAUcCgXgg4NCJARDBDIRIDg0B+D+CDIUwh48CEQfARod8DIUPQgaRCnL+DQQJrCDIZoDTwk/BAYZCRYYZERYf/JoSuE/5bCFYjSEW4aBCGgraHcZAqDBAYQFEYQHFAHh2Cj5XDg5UBS4JVETIMHUocARAU/NIcHO4SUEj4WBWILIECwKxBZAgiCW4YiIh4iDJwZFIv4NBh7rDNAiRkA=='))),
|
||||
E.toString(require('heatshrink').decompress(atob('ADv8AwsB/4PG/+AA43gA4t/+AHFn/4A4sfGA0P/wHFg44GIBF/IA0fPL8OA40/PI5IGMA0HPA0f4BXNO40DR40PU40/Ew5FWEw5FNgJFGgAmGAEbpBJYr5BMYoHB/5UEh4HBDAgHCKogHCMogHCEAgnCEAgHDNwYHDIIcDA4QoDA4OALQK6GeggkCgYwDuADGmADCjAHGhgLGgQLGgIDCgxtDNIUDA4ZACgJEDsBAKngDCTQZdCfAkPOwMfQJZ+BWQ1/BAQHDn4HGYQYHDFAbKDFAbzEEAQGDEAYHEDAI/EDARXDADKiDhAvDIoUEVwzKDVwa+EnAbFgEeB4TGDj5xC8CJG+AHCg4HCYQaRDNQa6IA4SKEA4ZADZQZADZQZADA4ZADKAZADAAccA40GA40BUw7jEAC8gAQMMA4cwAQMOA40PA444DYQUPPIYHDPIc8A4R5DNoUPPIY0Ch66DGgUPXQcHGgLdBaQY0Bhy6DgI0Bj1/IAUBFgM+n5ADEgM/j5ADv/B/5AEZQUHIAbKCwZADHoP/wJAEfIRAEA4RADgAHB4BAEv4HBIAgwB4BAEGAPAIAgwB4EDIAYgB4AzBA4aSBA4L7FDQQHEB4JADACkCeYoiBdYoHBHIQPDgA5CB4cAsAHGCgQHEjACBjkAhgEDcALqBAgICCOAMHAgYFBwEDHoIKCgaIBA4QCBgfggJFBg4CBgPwAIIMCDAP8gK4BA4d/wfuC4LLCn//++Ag7LCaQP7/EfA4UH//5doLTCW4P8A4i3B/giBbYYEBEQIHDn/+eoIHDj/+EQLrDg/+EQIHDgIUBv77EnhLCbApLBA4oaCABqjCA4rhCA4iQCA4iQCHAiICA4iACA4hAGgxQGh1/IAsOn5AFh0fIAsMh5AFjhAGjkDIAscQI0YYoIHEnCqBIAgHBIArhBdYgHEFIbIBAAQHHFIQHEFIQGD/5qCA4hqCC4hqFQI0AQIzCIQIzCIg7CGgJXDACsBBA4hDgZXCoAGCMwdgPIX8YYMAmB5C4EIZwaxB8EMewR+C+EGAgMOPwX4g5jCAQX8gY9BA4UD/0BW4MHBQJuBgBIBgbCDwFwKYhABngXBA4RABj4HBWYRABh/gXYZACaQhACA4K7CIAQHEIAQHEIAU//7LDIAMfA4vgGAIHD//wGAIPEHgIHEAAU/eY43DAAcgeS4AMJ4KHCAARfFIwR4BXARZCTAhpCAAIYEA4SMBA4zJCU4QABHIQHEVIgoGA4YoDIwQbBJIX/+IEBfQbBBBgQwCv8AA4UYM4UAoAEBhgCBn0AsAEBgQCBj0AmD/CA4ccKoRABh0Ah4PCFYIFBHoQCDBgJxEEQJyDA4QiBA4SiBFQSyCVQQqBYQKJDJwLSBA4b+BFATTFA44oBA4ogBWIYYDcQj8CUAQARH4IWGdAYADv4PGn4HGj4XGh5GGg5WGgZmDBYRABBYX/UAJABAYMPJgd/Z4RzDIASsBEARACSYhACYgRAEA4QsBIAV/A4ZACA4Q0BIATsCJARABRYpABBoZADaIpABQQsH/qSFOoKiFIAI8CYQguEIATbGn4HGjz4TACsPdo0fOQYMCYIJTCBgQHBNYQEB4ACBQYQEB+DZFAgLpBaIQECAQT+D//PZIcHAgP38EHHgKgBCod4A4glBjioBaAIdCgwKBIwQdCA4NgDIJOCEQMgXQJvCoEAjCyBGAQNBhhKCN4MQFQQgBM4IVBgYUBIIQVBgPwdYIYBhzpC//vDALeCFwPzLYhPCNYg2B+ASBMYRXCRgQHBFAP4PgS6Cv5nBA4kPA4IgBA4UDP4JiDAAZSBA4ojBF4QASg6iCAAZjBL4IADH4I7BA4qaBA4qACA4pAEA4RQBmAvDbgS7BA4YoBXYJvCFAS7CA4eAg5XC/+DGAIHCgYtBg/gcIUBHoXwgYEBA4c4A4UAAQUMgKbCsACBgwkCKYcCW4UAjgzCA4cPGYMDZ4TLDge/A4TICKYKTDMAQHEv4HGQIQHEPIYHDgYHC/yqDB4yyDA4ggCA4ggCegpBBdYpXBbQgAon50CToIHCGwMfIIc/AgMfKIYECh55Dj5mBKQJwDBgJrBFAQMCXoJiCBgbFBTIYMBv44Dv4MBIAkfA4MPA4cHA4MBSQoAE'))),
|
||||
46,
|
||||
atob("ExouGyYjJiEoISgoFQ=="),
|
||||
70|65536
|
||||
atob("EBYpGCEfIh4lHyQjEQ=="),
|
||||
65|65536
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -95,11 +95,10 @@ let draw = function() {
|
|||
g.setColor(g.theme.fg)
|
||||
// Time
|
||||
const yt = R.y + 92 - 20 - 30 + 6 + 10;
|
||||
const xt = R.w/2 - 5;
|
||||
const xt = R.w/2;
|
||||
let hours = date.getHours()+'';
|
||||
g.setFontAlign(1, 0).setFontPlayfairDisplay().drawString(hours, xt - 8, yt);
|
||||
g.setFontAlign(0, 0).setFontPlayfairDisplay().drawString(':', xt, yt);
|
||||
g.setFontAlign(-1, 0).setFontPlayfairDisplay().drawString(minutes, xt + 8, yt);
|
||||
|
||||
g.setFontAlign(0, 0).setFontPlayfairDisplay().drawString(hours + ':' + minutes, xt, yt);
|
||||
// logo
|
||||
g.drawImage(supaClockImg, R.x2 - supaClockImg.width - 2, R.y + 2);
|
||||
// dow + date
|
||||
|
@ -174,16 +173,15 @@ splashScreen().then(() => {
|
|||
draw();
|
||||
Bangle.drawWidgets();
|
||||
// Allocate and draw clockinfos
|
||||
g.setFontAlign(1, 1).setFont('6x8').drawString('Loading Clock Info Modules...', R.x + 10, upperCI);
|
||||
setTimeout(() => {
|
||||
// delay loading of clock info, so that the clock face appears quicker
|
||||
g.clearRect(R.x, upperCI, R.x2, upperCI+10); // clear loading text
|
||||
try {
|
||||
clockInfoItems = require("clock_info").load();
|
||||
clockInfoMenu1 = require("clock_info").addInteractive(clockInfoItems, { app:"lcdclock", x:R.x+1, y:upperCI, w:midX-2, h:28, draw : clockInfoDraw});
|
||||
clockInfoMenu2 = require("clock_info").addInteractive(clockInfoItems, { app:"lcdclock", x:midX+1, y:upperCI, w:midX-2, h:28, draw : clockInfoDrawR});
|
||||
clockInfoMenu3 = require("clock_info").addInteractive(clockInfoItems, { app:"lcdclock", x:R.x+1, y:lowerCI, w:midX-2, h:28, draw : clockInfoDraw});
|
||||
clockInfoMenu4 = require("clock_info").addInteractive(clockInfoItems, { app:"lcdclock", x:midX+1, y:lowerCI, w:midX-2, h:28, draw : clockInfoDrawR});
|
||||
clockInfoMenu1 = require("clock_info").addInteractive(clockInfoItems, { app:"supaclk", x:R.x+1, y:upperCI, w:midX-2, h:28, draw : clockInfoDraw});
|
||||
clockInfoMenu2 = require("clock_info").addInteractive(clockInfoItems, { app:"supaclk", x:midX+1, y:upperCI, w:midX-2, h:28, draw : clockInfoDrawR});
|
||||
clockInfoMenu3 = require("clock_info").addInteractive(clockInfoItems, { app:"supaclk", x:R.x+1, y:lowerCI, w:midX-2, h:28, draw : clockInfoDraw});
|
||||
clockInfoMenu4 = require("clock_info").addInteractive(clockInfoItems, { app:"supaclk", x:midX+1, y:lowerCI, w:midX-2, h:28, draw : clockInfoDrawR});
|
||||
} catch(err) {
|
||||
if ((err + '').includes('Module "clock_info" not found' )) {
|
||||
g.setFont('6x8').drawString('Please install\nclockinfo module!', R.x + 10, upperCI);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{ "id": "supaclk",
|
||||
"name": "SUPACLOCK Pro ULTRA",
|
||||
"version": "0.01",
|
||||
"version": "0.02",
|
||||
"description": "SUPACLOCK Pro ULTRA, with four ClockInfo areas at the bottom. Tap them and swipe up/down and left/right to toggle between different information.",
|
||||
"icon": "app.png",
|
||||
"screenshots": [{"url":"screenshot.png"},{"url":"screenshot2.png"}],
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
0.01: New Clock!
|
||||
0.02: Clockinfos now save under correct name, and wrap correctly to >1 line
|
|
@ -134,8 +134,8 @@ for (var i=0;i<10;i++)
|
|||
if (g.stringWidth(txt) > options.w) // if too big, smaller font
|
||||
g.setFont("LECO1976Regular14");
|
||||
if (g.stringWidth(txt) > options.w) {// if still too big, split to 2 lines
|
||||
var l = g.wrapString(txt, options.w);
|
||||
txt = l.slice(0,2).join("\n") + (l.length>2)?"...":"";
|
||||
var l = g.wrapString(txt, options.w-4);
|
||||
txt = l.slice(0,2).join("\n") + ((l.length>2)?"...":"");
|
||||
}
|
||||
var x = options.x+options.w/2, y = options.y+54;
|
||||
g.setColor(g.theme.bg).drawString(txt, x-2, y). // draw the text background
|
||||
|
@ -147,12 +147,12 @@ for (var i=0;i<10;i++)
|
|||
};
|
||||
|
||||
clockInfoMenuA = require("clock_info").addInteractive(clockInfoItems, {
|
||||
app:"pebblepp",
|
||||
app:"twotwoclock",
|
||||
x : g.getWidth()-clockInfoW, y: 0, w: clockInfoW, h:clockInfoH,
|
||||
draw : clockInfoDraw
|
||||
});
|
||||
clockInfoMenuB = require("clock_info").addInteractive(clockInfoItems, {
|
||||
app:"pebblepp",
|
||||
app:"twotwoclock",
|
||||
x : g.getWidth()-clockInfoW, y: clockInfoH, w: clockInfoW, h:clockInfoH,
|
||||
draw : clockInfoDraw
|
||||
});
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{ "id": "twotwoclock",
|
||||
"name": "TwoTwo Clock",
|
||||
"shortName":"22 Clock",
|
||||
"version":"0.01",
|
||||
"version":"0.02",
|
||||
"description": "A clock with the time split over two lines, with custom backgrounds and two ClockInfos",
|
||||
"icon": "icon.png",
|
||||
"type": "clock",
|
||||
|
|
2
core
|
@ -1 +1 @@
|
|||
Subproject commit 1cdcb3405f78ef35f231b9c3df501721bda75525
|
||||
Subproject commit 4f07b72ce2bdac4a8da6bfa3da3e2152370446fc
|
|
@ -16,7 +16,7 @@ if (window.location.host=="banglejs.com") {
|
|||
'This is not the official Bangle.js App Loader - you can try the <a href="https://banglejs.com/apps/">Official Version</a> here.';
|
||||
}
|
||||
|
||||
var RECOMMENDED_VERSION = "2v23";
|
||||
var RECOMMENDED_VERSION = "2v24";
|
||||
// could check http://www.espruino.com/json/BANGLEJS.json for this
|
||||
|
||||
// We're only interested in Bangles
|
||||
|
|
|
@ -90,7 +90,6 @@ exports.swipeOn = function(autohide) {
|
|||
|
||||
function queueDraw() {
|
||||
const o = exports.offset;
|
||||
if (o>-24) {
|
||||
Bangle.appRect.y = o+24;
|
||||
Bangle.appRect.h = 1 + Bangle.appRect.y2 - Bangle.appRect.y;
|
||||
if (o>-24) {
|
||||
|
@ -104,7 +103,6 @@ exports.swipeOn = function(autohide) {
|
|||
Bangle.setLCDOverlay(undefined, {id: "widget_utils"});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (var w of global.WIDGETS) if (!w._draw) { // already hidden
|
||||
w._draw = w.draw;
|
||||
|
|