diff --git a/apps/8ball/8ball.png b/apps/8ball/8ball.png new file mode 100644 index 000000000..72344261a Binary files /dev/null and b/apps/8ball/8ball.png differ diff --git a/apps/8ball/ChangeLog b/apps/8ball/ChangeLog new file mode 100644 index 000000000..3bcffb19b --- /dev/null +++ b/apps/8ball/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/8ball/app-icon.js b/apps/8ball/app-icon.js new file mode 100644 index 000000000..399dbef21 --- /dev/null +++ b/apps/8ball/app-icon.js @@ -0,0 +1 @@ +atob("MDCBAAAAAAAAAAAAAAAAAAAAH/AAAAAAf/4AAAAB4AeAAAAHgAHgAAAOAABwAAAcAAA4AAA4AMAcAABwAMAOAABgA/AGAADAAeADAAHAAMADgAGAAAABgAGAAAABgAMAAAAAwAMBAAAAwAMDAAAAwAMHwAAAwAMHwAAAwAMDAACAwAMBAADAwAMAAAPgwAMAAAPgwAMAAADAwAGAAACBgAGAAAABgAHAAAADgADAAAADAADgAAAHAAB////+AAB////+AABgAAAGAABgAAAGAABgAAAGAADAAAADAADAAAADAADAAAADAAGAAAABgAGAAAABgAH/////gAP/////wAYAAAAAYAYAAAAAYAf/////4AP/////wAAAAAAAAAAAAAAAAA==") diff --git a/apps/8ball/app.js b/apps/8ball/app.js new file mode 100644 index 000000000..8a3ee427e --- /dev/null +++ b/apps/8ball/app.js @@ -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(); }); diff --git a/apps/8ball/metadata.json b/apps/8ball/metadata.json new file mode 100644 index 000000000..da387d3d6 --- /dev/null +++ b/apps/8ball/metadata.json @@ -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} + ] +} diff --git a/apps/8ball/screenshot-1.png b/apps/8ball/screenshot-1.png new file mode 100644 index 000000000..edf1a4695 Binary files /dev/null and b/apps/8ball/screenshot-1.png differ diff --git a/apps/8ball/screenshot-2.png b/apps/8ball/screenshot-2.png new file mode 100644 index 000000000..c5c607089 Binary files /dev/null and b/apps/8ball/screenshot-2.png differ diff --git a/apps/8ball/screenshot.png b/apps/8ball/screenshot.png new file mode 100644 index 000000000..f1f888cf3 Binary files /dev/null and b/apps/8ball/screenshot.png differ diff --git a/apps/boxclk/ChangeLog b/apps/boxclk/ChangeLog index cc73fbc08..b78eba44c 100644 --- a/apps/boxclk/ChangeLog +++ b/apps/boxclk/ChangeLog @@ -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 diff --git a/apps/boxclk/app.js b/apps/boxclk/app.js index 12c69e789..548062349 100644 --- a/apps/boxclk/app.js +++ b/apps/boxclk/app.js @@ -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); @@ -412,4 +402,4 @@ widgets.swipeOn(); modSetColor(); setup(); -} \ No newline at end of file +} diff --git a/apps/boxclk/boxclk.space.img b/apps/boxclk/boxclk.space.img deleted file mode 100644 index 1708b5c24..000000000 Binary files a/apps/boxclk/boxclk.space.img and /dev/null differ diff --git a/apps/boxclk/metadata.json b/apps/boxclk/metadata.json index dd81ac436..79b4c3019 100644 --- a/apps/boxclk/metadata.json +++ b/apps/boxclk/metadata.json @@ -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"}, diff --git a/apps/dedreckon/ChangeLog b/apps/dedreckon/ChangeLog new file mode 100644 index 000000000..263d4078d --- /dev/null +++ b/apps/dedreckon/ChangeLog @@ -0,0 +1 @@ +0.01: attempt to import diff --git a/apps/dedreckon/README.md b/apps/dedreckon/README.md new file mode 100644 index 000000000..706c7f191 --- /dev/null +++ b/apps/dedreckon/README.md @@ -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. \ No newline at end of file diff --git a/apps/dedreckon/app-icon.js b/apps/dedreckon/app-icon.js new file mode 100644 index 000000000..39b72f00b --- /dev/null +++ b/apps/dedreckon/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwhHXAH4A/AH4A/AFsAFtoADF1wwqF4wwhEI5goGGIjFYN4wFF1KbHGUolIMc4lGSdIwJd9DstAH7FrBywwgad4veDwojJBIIvcFwIACGBYICGDYvEGBYvdFwqyLL8i+LF7oxFRxgveGAQ0EF5IwfMY4vpL5AFLAEYv/F8owoE44vrAY4vmAQIEEF85dGGE0AE4gvoFwpmHd0oINAH4A/AH4AvA")) diff --git a/apps/dedreckon/app.png b/apps/dedreckon/app.png new file mode 100644 index 000000000..db3fcfb88 Binary files /dev/null and b/apps/dedreckon/app.png differ diff --git a/apps/dedreckon/dedreckon.app.js b/apps/dedreckon/dedreckon.app.js new file mode 100644 index 000000000..449bf9c1b --- /dev/null +++ b/apps/dedreckon/dedreckon.app.js @@ -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 ((xthis.h/2) && (ythis.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 ((xui.h/2) && (y ui.onSwipe(s), + clock : 0 +}); + +if (0) + testPaint(); +if (1) { + g.reset(); + updateGps(); +} diff --git a/apps/dedreckon/metadata.json b/apps/dedreckon/metadata.json new file mode 100644 index 000000000..79bf8868e --- /dev/null +++ b/apps/dedreckon/metadata.json @@ -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} + ] +} diff --git a/apps/ffcniftyapp/ChangeLog b/apps/ffcniftyapp/ChangeLog index 30dcec467..ef797827e 100644 --- a/apps/ffcniftyapp/ChangeLog +++ b/apps/ffcniftyapp/ChangeLog @@ -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 diff --git a/apps/ffcniftyapp/app.js b/apps/ffcniftyapp/app.js index 840dd72ff..5ca48c2f1 100644 --- a/apps/ffcniftyapp/app.js +++ b/apps/ffcniftyapp/app.js @@ -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); diff --git a/apps/ffcniftyapp/metadata.json b/apps/ffcniftyapp/metadata.json index bbe8e7e69..6f368160b 100644 --- a/apps/ffcniftyapp/metadata.json +++ b/apps/ffcniftyapp/metadata.json @@ -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", diff --git a/apps/fwupdate/custom.html b/apps/fwupdate/custom.html index 6c47cf3f2..606e59d89 100644 --- a/apps/fwupdate/custom.html +++ b/apps/fwupdate/custom.html @@ -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; } diff --git a/apps/gipy/app.js b/apps/gipy/app.js index 0559a4bd1..4d0838282 100644 --- a/apps/gipy/app.js +++ b/apps/gipy/app.js @@ -660,11 +660,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, @@ -1394,7 +1394,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); diff --git a/apps/iconbits/ChangeLog b/apps/iconbits/ChangeLog index 263d4078d..10f5d311c 100644 --- a/apps/iconbits/ChangeLog +++ b/apps/iconbits/ChangeLog @@ -1 +1,2 @@ 0.01: attempt to import +0.02: implement colors and lines diff --git a/apps/iconbits/README.md b/apps/iconbits/README.md index c5c524ab0..90bc0f5a3 100644 --- a/apps/iconbits/README.md +++ b/apps/iconbits/README.md @@ -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. + + + diff --git a/apps/iconbits/app.png b/apps/iconbits/app.png index 7a3ee2e90..d4e822ac7 100644 Binary files a/apps/iconbits/app.png and b/apps/iconbits/app.png differ diff --git a/apps/iconbits/iconbits.app.js b/apps/iconbits/iconbits.app.js index 625070dd5..5fc10423c 100644 --- a/apps/iconbits/iconbits.app.js +++ b/apps/iconbits/iconbits.app.js @@ -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; - do_draw(from, to); + 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 = ""; - 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)+'");'); - } - - + if (mode == "font") + print('show_font("' + s + '");'); + var im = sg.asImage("string"); + //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); diff --git a/apps/iconbits/metadata.json b/apps/iconbits/metadata.json index b98a43953..edb4b4d6a 100644 --- a/apps/iconbits/metadata.json +++ b/apps/iconbits/metadata.json @@ -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", diff --git a/apps/lato/ChangeLog b/apps/lato/ChangeLog index 686f3b707..814b06b31 100644 --- a/apps/lato/ChangeLog +++ b/apps/lato/ChangeLog @@ -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 \ No newline at end of file +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 \ No newline at end of file diff --git a/apps/lato/README.md b/apps/lato/README.md index 556ee6fbc..1dc571509 100644 --- a/apps/lato/README.md +++ b/apps/lato/README.md @@ -5,6 +5,7 @@ A simple clock with the Lato font, with fast load and clock_info ![](screenshot1.png) ![](screenshot2.png) ![](screenshot3.png) +![](screenshot4.png) 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) diff --git a/apps/lato/app.js b/apps/lato/app.js index 88e723a78..369cba17f 100644 --- a/apps/lato/app.js +++ b/apps/lato/app.js @@ -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 diff --git a/apps/lato/metadata.json b/apps/lato/metadata.json index 406413790..baeb5d3ea 100644 --- a/apps/lato/metadata.json +++ b/apps/lato/metadata.json @@ -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"} ] } diff --git a/apps/lato/screenshot4.png b/apps/lato/screenshot4.png new file mode 100644 index 000000000..5fc70fb18 Binary files /dev/null and b/apps/lato/screenshot4.png differ diff --git a/apps/lato/settings.js b/apps/lato/settings.js new file mode 100644 index 000000000..ff74ed47c --- /dev/null +++ b/apps/lato/settings.js @@ -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) + }) \ No newline at end of file diff --git a/apps/lint_exemptions.js b/apps/lint_exemptions.js index e5a2170bd..b3503de72 100644 --- a/apps/lint_exemptions.js +++ b/apps/lint_exemptions.js @@ -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": [ diff --git a/apps/measuretime/ChangeLog b/apps/measuretime/ChangeLog index d0ac21aac..886e92f22 100644 --- a/apps/measuretime/ChangeLog +++ b/apps/measuretime/ChangeLog @@ -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 diff --git a/apps/measuretime/measuretime.app.js b/apps/measuretime/measuretime.app.js index 97b56c710..419916416 100644 --- a/apps/measuretime/measuretime.app.js +++ b/apps/measuretime/measuretime.app.js @@ -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: diff --git a/apps/measuretime/metadata.json b/apps/measuretime/metadata.json index 6ba022dc0..e25fe1ef6 100644 --- a/apps/measuretime/metadata.json +++ b/apps/measuretime/metadata.json @@ -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": [ diff --git a/apps/promenu/bootb2.js b/apps/promenu/bootb2.js index 9909d2af3..434f0c07f 100644 --- a/apps/promenu/bootb2.js +++ b/apps/promenu/bootb2.js @@ -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; diff --git a/apps/promenu/bootb2.ts b/apps/promenu/bootb2.ts index 9342d2ec9..11ae56e1b 100644 --- a/apps/promenu/bootb2.ts +++ b/apps/promenu/bootb2.ts @@ -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(); diff --git a/apps/quarterclock/app-icon.js b/apps/quarterclock/app-icon.js new file mode 100644 index 000000000..d6ed783ec --- /dev/null +++ b/apps/quarterclock/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEw4X/AwX48AFCqoAEC4oL/Bf4L/Bf4LTAH4A/ADGqAAIL/Bf4LD")) diff --git a/apps/quarterclock/app.js b/apps/quarterclock/app.js new file mode 100644 index 000000000..a668860cd --- /dev/null +++ b/apps/quarterclock/app.js @@ -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(); +} + diff --git a/apps/quarterclock/app.png b/apps/quarterclock/app.png new file mode 100644 index 000000000..e2a1c7fc0 Binary files /dev/null and b/apps/quarterclock/app.png differ diff --git a/apps/quarterclock/metadata.json b/apps/quarterclock/metadata.json new file mode 100644 index 000000000..9ce2bce18 --- /dev/null +++ b/apps/quarterclock/metadata.json @@ -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"} + ] +} diff --git a/apps/quarterclock/screenshot.png b/apps/quarterclock/screenshot.png new file mode 100644 index 000000000..f1741f4ca Binary files /dev/null and b/apps/quarterclock/screenshot.png differ diff --git a/apps/quarterclock/settings.js b/apps/quarterclock/settings.js new file mode 100644 index 000000000..892e82cfd --- /dev/null +++ b/apps/quarterclock/settings.js @@ -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']), + }); +}) diff --git a/apps/setting/settings.js b/apps/setting/settings.js index c5149ab5a..d9d77d052 100644 --- a/apps/setting/settings.js +++ b/apps/setting/settings.js @@ -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); diff --git a/apps/skyspy/ChangeLog b/apps/skyspy/ChangeLog index 79da4daf2..15a83ceeb 100644 --- a/apps/skyspy/ChangeLog +++ b/apps/skyspy/ChangeLog @@ -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 diff --git a/apps/skyspy/metadata.json b/apps/skyspy/metadata.json index 07bc9280a..d8e9d1356 100644 --- a/apps/skyspy/metadata.json +++ b/apps/skyspy/metadata.json @@ -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", diff --git a/apps/skyspy/skyspy.app.js b/apps/skyspy/skyspy.app.js index ff6e29712..a3a0d8776 100644 --- a/apps/skyspy/skyspy.app.js +++ b/apps/skyspy/skyspy.app.js @@ -1,20 +1,121 @@ /* Sky spy */ -/* 0 .. DD.ddddd - 1 .. DD MM.mmm' - 2 .. DD MM'ss" -*/ -var mode = 1; + +/* 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" + */ + 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 ((xh/2) && (yw/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(); diff --git a/apps/slopeclockpp/ChangeLog b/apps/slopeclockpp/ChangeLog index 39f837386..43b457d4e 100644 --- a/apps/slopeclockpp/ChangeLog +++ b/apps/slopeclockpp/ChangeLog @@ -10,4 +10,5 @@ 0.08: Stability improvements - ensure we continue even if a flat string can't be allocated 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 \ No newline at end of file +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 diff --git a/apps/slopeclockpp/app.js b/apps/slopeclockpp/app.js index 5b1d898d1..df732c1db 100644 --- a/apps/slopeclockpp/app.js +++ b/apps/slopeclockpp/app.js @@ -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 @@ -175,4 +176,4 @@ Bangle.loadWidgets(); if (settings.hideWidgets) require("widget_utils").swipeOn(); else setTimeout(Bangle.drawWidgets,0); draw(); -} \ No newline at end of file +} diff --git a/apps/slopeclockpp/metadata.json b/apps/slopeclockpp/metadata.json index 086b8148f..00e0b0a77 100644 --- a/apps/slopeclockpp/metadata.json +++ b/apps/slopeclockpp/metadata.json @@ -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"}], diff --git a/apps/smpltmr/ChangeLog b/apps/smpltmr/ChangeLog index 2c073ff43..c3f069428 100644 --- a/apps/smpltmr/ChangeLog +++ b/apps/smpltmr/ChangeLog @@ -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 \ No newline at end of file diff --git a/apps/smpltmr/clkinfo.js b/apps/smpltmr/clkinfo.js index a7a6bf71b..6fc2cd265 100644 --- a/apps/smpltmr/clkinfo.js +++ b/apps/smpltmr/clkinfo.js @@ -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, diff --git a/apps/smpltmr/metadata.json b/apps/smpltmr/metadata.json index 98affcfe6..2f33f07b9 100644 --- a/apps/smpltmr/metadata.json +++ b/apps/smpltmr/metadata.json @@ -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", diff --git a/apps/twotwoclock/ChangeLog b/apps/twotwoclock/ChangeLog index 09953593e..d3275c0e8 100644 --- a/apps/twotwoclock/ChangeLog +++ b/apps/twotwoclock/ChangeLog @@ -1 +1,2 @@ 0.01: New Clock! +0.02: Clockinfos now save under correct name, and wrap correctly to >1 line \ No newline at end of file diff --git a/apps/twotwoclock/app.js b/apps/twotwoclock/app.js index 57be691e1..b2d5ea9fb 100644 --- a/apps/twotwoclock/app.js +++ b/apps/twotwoclock/app.js @@ -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 }); diff --git a/apps/twotwoclock/metadata.json b/apps/twotwoclock/metadata.json index ebcba539c..ae3b958ef 100644 --- a/apps/twotwoclock/metadata.json +++ b/apps/twotwoclock/metadata.json @@ -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", diff --git a/core b/core index 1cdcb3405..294690a4f 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 1cdcb3405f78ef35f231b9c3df501721bda75525 +Subproject commit 294690a4f0257cfb2221770b2e48eb20404e6a68 diff --git a/loader.js b/loader.js index d63610ade..1f3350656 100644 --- a/loader.js +++ b/loader.js @@ -16,7 +16,7 @@ if (window.location.host=="banglejs.com") { 'This is not the official Bangle.js App Loader - you can try the Official Version 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 diff --git a/modules/widget_utils.js b/modules/widget_utils.js index 4e2acd296..4f9b85835 100644 --- a/modules/widget_utils.js +++ b/modules/widget_utils.js @@ -90,19 +90,17 @@ exports.swipeOn = function(autohide) { function queueDraw() { const o = exports.offset; + Bangle.appRect.y = o+24; + Bangle.appRect.h = 1 + Bangle.appRect.y2 - Bangle.appRect.y; if (o>-24) { - Bangle.appRect.y = o+24; - Bangle.appRect.h = 1 + Bangle.appRect.y2 - Bangle.appRect.y; - if (o>-24) { - Bangle.setLCDOverlay(og, 0, o, { - id:"widget_utils", - remove:()=>{ - require("widget_utils").cleanupOverlay(); - } - }); - } else { - Bangle.setLCDOverlay(undefined, {id: "widget_utils"}); - } + Bangle.setLCDOverlay(og, 0, o, { + id:"widget_utils", + remove:()=>{ + require("widget_utils").cleanupOverlay(); + } + }); + } else { + Bangle.setLCDOverlay(undefined, {id: "widget_utils"}); } }