diff --git a/apps.json b/apps.json index d5e84f9dd..edfc6b288 100644 --- a/apps.json +++ b/apps.json @@ -29,6 +29,31 @@ ], "sortorder": -10 }, + { + "id": "hebrew_calendar", + "name": "Hebrew Calendar", + "shortName": "HebCal", + "version": "0.03", + "description": "lists the date according to the hebrew calendar", + "icon": "app.png", + "tags": "", + "supports": [ + "BANGLEJS", + "BANGLEJS2" + ], + "readme": "README.md", + "storage": [ + { + "name": "hebrew_calendar.app.js", + "url": "app.js" + }, + { + "name": "hebrew_calendar.img", + "url": "app-icon.js", + "evaluate": true + } + ] + }, { "id": "messages", "name": "Messages", @@ -104,7 +129,7 @@ "id": "launch", "name": "Launcher", "shortName": "Launcher", - "version": "0.09", + "version": "0.10", "description": "This is needed to display a menu allowing you to choose your own applications. You can replace this with a customised launcher.", "icon": "app.png", "type": "launch", @@ -112,8 +137,10 @@ "supports": ["BANGLEJS","BANGLEJS2"], "storage": [ {"name":"launch.app.js","url":"app-bangle1.js","supports":["BANGLEJS"]}, - {"name":"launch.app.js","url":"app-bangle2.js","supports":["BANGLEJS2"]} + {"name":"launch.app.js","url":"app-bangle2.js","supports":["BANGLEJS2"]}, + {"name":"launch.settings.js","url":"settings.js","supports":["BANGLEJS2"]} ], + "data": [{"name":"launch.json"}], "sortorder": -10 }, { @@ -463,22 +490,22 @@ ] }, { - "id": "mandlebrotclock", - "name": "Mandlebrot Clock", + "id": "mandelbrotclock", + "name": "Mandelbrot Clock", "version": "0.01", - "description": "A mandlebrot set themed clock cool", - "icon": "mandlebrotclock.png", - "screenshots": [{ "url": "screenshot_mandlebrotclock.png" }], + "description": "A mandelbrot set themed clock cool", + "icon": "mandelbrotclock.png", + "screenshots": [{ "url": "screenshot_mandelbrotclock.png" }], "type": "clock", "tags": "clock", "supports": ["BANGLEJS2"], "readme": "README.md", "allow_emulator": true, "storage": [ - { "name": "mandlebrotclock.app.js", "url": "mandlebrotclock.js" }, + { "name": "mandelbrotclock.app.js", "url": "mandelbrotclock.js" }, { - "name": "mandlebrotclock.img", - "url": "mandlebrotclock-icon.js", + "name": "mandelbrotclock.img", + "url": "mandelbrotclock-icon.js", "evaluate": true } ] @@ -2100,6 +2127,19 @@ {"name":"snake.img","url":"snake-icon.js","evaluate":true} ] }, + { "id": "snek", + "name": "The snek game", + "shortName":"Snek", + "version": "0.01", + "description": "A snek game where you control a snek to eat all the apples!", + "icon": "snek-icon.js", + "supports": ["BANGLEJS2"], + "tags": "game,fun", + "storage": [ + {"name":"snek.app.js","url":"snek.js"}, + {"name":"snek.img","url":"snek-icon.js","evaluate":true} + ] + }, { "id": "calculator", "name": "Calculator", @@ -4449,7 +4489,7 @@ "shortName": "AuthWatch", "icon": "app.png", "screenshots": [{"url":"screenshot.png"}], - "version": "0.03", + "version": "0.04", "description": "Google Authenticator compatible tool.", "tags": "tool", "interface": "interface.html", @@ -4591,9 +4631,9 @@ }, { "id":"a_speech_timer", - "name":"A Speech Timer", + "name":"Speech Timer", "icon": "app.png", - "version":"1.00", + "version":"1.01", "description": "A timer designed to help keeping your speeches and presentations to time.", "tags": "tool,timer", "readme":"README.md", @@ -4692,6 +4732,34 @@ "supports": ["BANGLEJS","BANGLEJS2"], "storage": [ {"name":"menuwheel.boot.js","url":"boot.js"} + ] + }, + { "id": "widChargingStatus", + "name": "Charging Status", + "shortName":"ChargingStatus", + "icon": "widget.png", + "version":"0.1", + "type": "widget", + "description": "A simple widget that shows a yellow lightning icon to indicate whenever the watch is charging. This way one can see the charging status at a glance, no matter which battery widget is being used.", + "tags": "widget", + "supports": ["BANGLEJS","BANGLEJS2"], + "storage": [ + {"name":"widChargingStatus.wid.js","url":"widget.js"} + ] + }, + { + "id": "flow", + "name": "FLOW", + "shortName": "FLOW", + "version": "0.01", + "description": "A game where you have to help a flow avoid white obstacles thing by tapping! This is a demake of an app which I forgot the name of. Press BTN(1) to restart. See if you can get to 2500 score!", + "icon": "app.png", + "tags": "game", + "supports" : ["BANGLEJS", "BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name": "flow.app.js", "url": "app.js" }, + {"name": "flow.img", "url": "app-icon.js","evaluate": true } ] } ] diff --git a/apps/a_speech_timer/ChangeLog b/apps/a_speech_timer/ChangeLog index 4a8e3fbe7..b3aa9e0dd 100644 --- a/apps/a_speech_timer/ChangeLog +++ b/apps/a_speech_timer/ChangeLog @@ -1 +1,2 @@ 1.00: Release (2021/12/01) +1.01: Grey font when timer is frozen (2021/12/04) diff --git a/apps/a_speech_timer/app.js b/apps/a_speech_timer/app.js index dae2545b2..440cd92c6 100644 --- a/apps/a_speech_timer/app.js +++ b/apps/a_speech_timer/app.js @@ -63,7 +63,7 @@ function countDown() { Bangle.on('touch',(touchside, touchdata)=>{ if (!islocked && istimeron && touchdata.y > (100+10)) { - Bangle.buzz(40); + Bangle.buzz(40); istimeron = false; clearInterval(timerinterval); } else if (touchdata.y > 24 && touchdata.y < (100-10)) { @@ -134,20 +134,20 @@ function draw() { else if (current_value >= current_from) { g.setBgColor("#8F8"); } g.clearRect(0,24,176,176); - g.reset(); - g.setFontAlign(0, 0); - + g.reset().setFontAlign(0, 0).setColor(istimeron ? "#000" : "#444"); g.setFont("Michroma36").drawString(timeToString(current_value), 88, 62); + g.reset().setFontAlign(0, 0); + g.setFont("HaxorNarrow7x17"); g.drawString(timeToString(current_from), 44, 62+26); g.drawString(timeToString(current_mid), 88, 62+26); g.drawString(timeToString(current_to), 132, 62+26); - + if (current_value >= current_from) { g.drawRect(44-1,62+26+9,44+1,62+26+9+1); } if (current_value >= current_mid) { g.drawRect(88-1,62+26+9,88+1,62+26+9+1); } if (current_value >= current_to) { g.drawRect(132-1,62+26+9,132+1,62+26+9+1); } - + if (showInstructions) { g.setFont("6x8").drawString("Tapping timer locks buttons", 88, 100+5); g.setFont("6x8").drawString("<= Swipe to change time =>", 88, 168); @@ -159,7 +159,7 @@ function draw() { g.drawString(timeToString(newtimer_left_to), 44, 138+9); g.drawString(timeToString(newtimer_right_from), 132, 138-9); g.drawString(timeToString(newtimer_right_to), 132, 138+9); - + g.drawRect(0+8,138-24, 88-9+1, 138+22+1); g.drawRect(0+8,138-24, 88-9, 138+22); g.drawRect(88+8,138-24, 176-10+1, 138+22+1); diff --git a/apps/authentiwatch/ChangeLog b/apps/authentiwatch/ChangeLog index 50cf3fcea..e1b8ed5bc 100644 --- a/apps/authentiwatch/ChangeLog +++ b/apps/authentiwatch/ChangeLog @@ -1,3 +1,4 @@ +0.04: Fix tapping at very bottom of list, exit on inactivity 0.03: Add "Calculating" placeholder, update JSON save format 0.02: Fix JSON save format 0.01: First release diff --git a/apps/authentiwatch/app.js b/apps/authentiwatch/app.js index 85c76b5d1..c0cb608c0 100644 --- a/apps/authentiwatch/app.js +++ b/apps/authentiwatch/app.js @@ -10,6 +10,8 @@ const calculating = "Calculating"; const notokens = "No tokens"; const notsupported = "Not supported"; +// sample settings: +// {tokens:[{"algorithm":"SHA1","digits":6,"period":30,"issuer":"","account":"","secret":"Bbb","label":"Aaa"}],misc:{}} var settings = require("Storage").readJSON("authentiwatch.json", true) || {tokens:[],misc:{}}; if (settings.data ) tokens = settings.data ; /* v0.02 settings */ if (settings.tokens) tokens = settings.tokens; /* v0.03+ settings */ @@ -146,14 +148,14 @@ function drawToken(id, r) { // counter - draw triangle as swipe hint let yc = (y1 + y2) / 2; g.fillPoly([0, yc, 10, yc - 10, 10, yc + 10, 0, yc]); - adj = 5; + adj = 10; } // digits just below label sz = 30; do { g.setFont("Vector", sz--); } while (g.stringWidth(state.otp) > (r.w - adj)); - g.drawString(state.otp, (x1 + x2) / 2 + adj, y1 + 16, false); + g.drawString(state.otp, (x1 + adj + x2) / 2, y1 + 16, false); } // shaded lines top and bottom g.setColor(0.5, 0.5, 0.5); @@ -163,6 +165,8 @@ function drawToken(id, r) { } function draw() { + var timerfn = exitApp; + var timerdly = 10000; var d = new Date(); if (state.curtoken != -1) { var t = tokens[state.curtoken]; @@ -203,17 +207,13 @@ function draw() { y += tokenentryheight; } if (drewcur) { - // the current token has been drawn - draw it again in 1sec - if (state.drawtimer) { - clearTimeout(state.drawtimer); - } - var dly; + // the current token has been drawn - schedule a redraw if (tokens[state.curtoken].period > 0) { - dly = (state.otp == calculating) ? 1 : 1000; + timerdly = (state.otp == calculating) ? 1 : 1000; // timed } else { - dly = state.nexttime - d.getTime(); + timerdly = state.nexttime - d.getTime(); // counter } - state.drawtimer = setTimeout(draw, dly); + timerfn = draw; if (tokens[state.curtoken].period <= 0) { state.hide = 0; } @@ -230,12 +230,16 @@ function draw() { g.setFontAlign(0, 0, 0); g.drawString(notokens, Bangle.appRect.x + Bangle.appRect.w / 2, Bangle.appRect.y + Bangle.appRect.h / 2, false); } + if (state.drawtimer) { + clearTimeout(state.drawtimer); + } + state.drawtimer = setTimeout(timerfn, timerdly); } function onTouch(zone, e) { if (e) { var id = Math.floor((state.listy + (e.y - Bangle.appRect.y)) / tokenentryheight); - if (id == state.curtoken || tokens.length == 0) { + if (id == state.curtoken || tokens.length == 0 || id >= tokens.length) { id = -1; } if (state.curtoken != id) { @@ -254,26 +258,20 @@ function onTouch(zone, e) { state.nextTime = 0; state.curtoken = id; state.hide = 2; - draw(); } } + draw(); } function onDrag(e) { if (e.x > g.getWidth() || e.y > g.getHeight()) return; if (e.dx == 0 && e.dy == 0) return; var newy = Math.min(state.listy - e.dy, tokens.length * tokenentryheight - Bangle.appRect.h); - newy = Math.max(0, newy); - if (newy != state.listy) { - state.listy = newy; - draw(); - } + state.listy = Math.max(0, newy); + draw(); } function onSwipe(e) { - if (e == 1) { - Bangle.showLauncher(); - } if (e == -1 && state.curtoken != -1 && tokens[state.curtoken].period <= 0) { tokens[state.curtoken].period--; let newsettings={tokens:tokens,misc:settings.misc}; @@ -281,8 +279,8 @@ function onSwipe(e) { state.nextTime = 0; state.otp = ""; state.hide = 2; - draw(); } + draw(); } function bangle1Btn(e) { @@ -302,16 +300,22 @@ function bangle1Btn(e) { state.curtoken = -1; state.nextTime = 0; onTouch(0, fakee); + } else { + draw(); // resets idle timer } } +function exitApp() { + Bangle.showLauncher(); +} + Bangle.on('touch', onTouch); Bangle.on('drag' , onDrag ); Bangle.on('swipe', onSwipe); if (typeof BTN2 == 'number') { - setWatch(function(){bangle1Btn(-1); }, BTN1, {edge:"rising", debounce:50, repeat:true}); - setWatch(function(){Bangle.showLauncher();}, BTN2, {edge:"rising", debounce:50, repeat:true}); - setWatch(function(){bangle1Btn( 1); }, BTN3, {edge:"rising", debounce:50, repeat:true}); + setWatch(function(){bangle1Btn(-1);}, BTN1, {edge:"rising", debounce:50, repeat:true}); + setWatch(function(){exitApp(); }, BTN2, {edge:"rising", debounce:50, repeat:true}); + setWatch(function(){bangle1Btn( 1);}, BTN3, {edge:"rising", debounce:50, repeat:true}); } Bangle.loadWidgets(); diff --git a/apps/flow/README.md b/apps/flow/README.md new file mode 100644 index 000000000..caeaf92d9 --- /dev/null +++ b/apps/flow/README.md @@ -0,0 +1,12 @@ +# FLOW + +This is a game where you have to help a flow avoid white obstacles thing by tapping! +This is a demake of an app which I forgot the name of. +Press BTN(1) to restart. +See if you can get to 2500 score! + +## Screenshots + +![](screenshot1.png) +![](screenshot2.png) +![](screenshot3.png) diff --git a/apps/flow/app-icon.js b/apps/flow/app-icon.js new file mode 100644 index 000000000..969a608f4 --- /dev/null +++ b/apps/flow/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEw4X/AwX48EHgEC1WgCQkVqoDBBfuqBQcBqoLagEqGAguBqALaGAOoAoQuEBbEAKgIMBBQNUBbgMCyoKHBbBVBBYIKGBbEBtNVrQLfOgNaT4gLagp0CPQOABbcBFwNAgEKBgILbitVqAFClWq0ALZFwTDFGAQLZFwYwDBfg")) diff --git a/apps/flow/app.js b/apps/flow/app.js new file mode 100644 index 000000000..5f4da8f35 --- /dev/null +++ b/apps/flow/app.js @@ -0,0 +1,220 @@ +const isB2 = process.env.HWVERSION === 2; + +// Bangle.js 1 runs just too fast in direct mode??? (also no getPixel) +if (!isB2) Bangle.setLCDMode("120x120"); + +const options = Bangle.getOptions(); + +options.lockTimeout = 0; +options.lcdPowerTimeout = 0; + +Bangle.setOptions(options); + +g.reset(); +g.setBgColor(0, 0, 0); +g.setColor(255, 255, 255); +g.clear(); +const h = g.getHeight(); + +function trigToCoord(ret) { + return ((ret + 1) * h) / 2; +} + +function trigToLen(ret) { + return (ret * h) / 2; +} + +let i = 0.2; +let speedCoef = 0.014; + +let flowFile = require("Storage").readJSON("flow.json"); + +let highestI = (flowFile && flowFile.hiscore) || 0.1; + +let colorA = [255, 255, 0]; +let colorB = [0, 255, 255]; + +let x = 0; +let xt = 0; +let safeMode = false; +let lost = false; + +function offsetRect(g, x, y, w) { + g.fillRect(x, y, x + w, y + w); +} + +function getColor(num) { + return [ + [1, 0, 0], + [0, 1, 0], + [0, 0, 1], + [1, 1, 0], + [0, 1, 1], + [1, 0, 1], + [0.5, 0.5, 1], + [1, 0.5, 0], + [0, 1, 0.5], + [0.5, 0.5, 0.5], + ][num]; +} + +function calculateColor(num) { + colorA = getColor(Math.floor((num % 1) * 10)); + colorB = getColor(Math.floor((num % 10) - (num % 1))); +} + +calculateColor(highestI); + +Bangle.on("touch", () => (safeMode = !safeMode)); + +function resetGame() { + x = xt = 0; + safeMode = lost = false; + i = 0.2; + speedCoef = 0.014; + obstaclePeriod = 150; + obstacleMode = 1; + g.clear(); + shownScore = false; + intervalId = setInterval(draw); +} + +function checkCollision() { + lost = g.getPixel(trigToCoord(+x), (h * 2) / 3 - 4) !== 0; + if (lost) { + scoringI = i; + speedCoef = Math.min(speedCoef, 0.02); + g.setFont(isB2 ? "6x15" : "4x6", 3); + g.setColor(colorA[0], colorA[1], colorA[2]) + .drawString( + "Game over", + trigToCoord(0) - g.stringWidth("Game over") / 2, + trigToCoord(0) + ) + .setColor(1, 1, 1); + } +} + +function drawPlayer() { + if (!safeMode) xt = Math.cos(i * Math.PI * 4) / 7.5; + else xt = -Math.cos(i * Math.PI * 2) / 20 + 0.35; + x = x * 0.8 + xt * 0.2; + if (highestI > 250) calculateColor(i); + g.setColor(colorA[0], colorA[1], colorA[2]); + offsetRect(g, trigToCoord(+x), (h * 2) / 3, 3); + g.setColor(colorB[0], colorB[1], colorB[2]); + offsetRect(g, trigToCoord(-x), (h * 2) / 3, 3); +} + +let obstaclePeriod = 150; +let obstacleMode = 1; + +function drawObstracle() { + g.setColor(1, 1, 1); + switch (obstacleMode) { + case 0: + offsetRect(g, trigToCoord(-0.15), 0, trigToLen(0.3)); + break; + case 1: + offsetRect(g, trigToCoord(0.2), 0, trigToLen(0.2)); + offsetRect(g, trigToCoord(-0.4), 0, trigToLen(0.2)); + break; + case 2: + break; + } + obstaclePeriod--; + if (obstaclePeriod <= 0) { + // If we are off cooldown mode, pick a random actual mode + if (obstacleMode === 2) { + obstaclePeriod = Math.random() * 50 + 50; + obstacleMode = Math.round(Math.random()); + } else if (Math.random() > 0.5) { + // Give it a chance to repeat with no cooldown + obstaclePeriod = 25 + 2.5 * speedCoef; + obstacleMode = 2; + } + } +} + +let shownScore = false; +let scoringI = 0; + +function draw() { + if (!lost) { + drawPlayer(); + checkCollision(); + speedCoef *= 1.0005; + drawObstracle(); + } else { + speedCoef /= 1.05; + if (speedCoef <= 0.005) { + clearInterval(intervalId); + i -= speedCoef; + g.setFont(isB2 ? "6x15" : "4x6", 1); + const str = "Hiscore: " + Math.round(highestI * 10); + g.setColor( + scoringI > highestI ? 0 : 255, + 0, + scoringI > highestI ? 255 : 0 + ) + .drawString( + str, + trigToCoord(0) - g.stringWidth(str) / 2, + trigToCoord(0) + ) + .setColor(255, 255, 255); + if (scoringI > highestI) { + highestI = scoringI; + require("Storage").writeJSON("flow.json", { + hiscore: highestI, + }); + calculateColor(highestI); + } + setTimeout(resetGame, 3000); + } else if (speedCoef <= 0.01 && !shownScore) { + shownScore = true; + g.setFont(isB2 ? "6x15" : "4x6", 2); + const str = "Score: " + Math.round(scoringI * 10); + g.setColor(colorB[0], colorB[1], colorB[2]) + .drawString( + str, + trigToCoord(0) - g.stringWidth(str) / 2, + trigToCoord(0) + ) + .setColor(1, 1, 1); + } + } + i += speedCoef; + g.scroll(0, speedCoef * h); + g.flip(); +} + +let intervalId; + +if (BTN.read()) { + for (let i = 0; i < 10; i++) { + color = getColor(i); + g.setColor(color[0], color[1], color[2]); + g.fillRect((i / 10) * h, 0, ((i + 1) / 10) * h, h); + } + g.setColor(0); + g.setFont("Vector", 9); + let str = "Welcome to the debug screen!"; + g.drawString( + str, + trigToCoord(0) - g.stringWidth(str) / 2, + trigToCoord(0) - 9 + ); + str = "Don't hold BTN while opening to play!"; + g.drawString(str, trigToCoord(0) - g.stringWidth(str) / 2, trigToCoord(0)); + g.flip(); + setInterval(() => { + g.scroll(0, 0.014 * h); + i += 0.014; + calculateColor(i); + g.setColor(colorA[0], colorA[1], colorA[2]); + g.fillRect(0, 0, trigToCoord(0), 0.014 * h); + g.setColor(colorB[0], colorB[1], colorB[2]); + g.fillRect(trigToCoord(0), 0, trigToCoord(1), 0.014 * h); + }, 1000 / 30); +} else intervalId = setInterval(draw, 1000 / 30); diff --git a/apps/flow/app.png b/apps/flow/app.png new file mode 100644 index 000000000..b35c3ca77 Binary files /dev/null and b/apps/flow/app.png differ diff --git a/apps/flow/screenshot1.png b/apps/flow/screenshot1.png new file mode 100644 index 000000000..fd5dee427 Binary files /dev/null and b/apps/flow/screenshot1.png differ diff --git a/apps/flow/screenshot2.png b/apps/flow/screenshot2.png new file mode 100644 index 000000000..e29691b69 Binary files /dev/null and b/apps/flow/screenshot2.png differ diff --git a/apps/flow/screenshot3.png b/apps/flow/screenshot3.png new file mode 100644 index 000000000..3e1c80ba7 Binary files /dev/null and b/apps/flow/screenshot3.png differ diff --git a/apps/hebrew_calendar/ChangeLog b/apps/hebrew_calendar/ChangeLog new file mode 100644 index 000000000..d7dbc19e3 --- /dev/null +++ b/apps/hebrew_calendar/ChangeLog @@ -0,0 +1,3 @@ +0.01: New App! +0.02: using TS and rollup to bundle +0.03: bug fixes and support bangle 1 \ No newline at end of file diff --git a/apps/hebrew_calendar/LICENSE b/apps/hebrew_calendar/LICENSE new file mode 100644 index 000000000..cd6624ad4 --- /dev/null +++ b/apps/hebrew_calendar/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016-20 Ionică Bizău (https://ionicabizau.net) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/apps/hebrew_calendar/README.md b/apps/hebrew_calendar/README.md new file mode 100644 index 000000000..7a96a97db --- /dev/null +++ b/apps/hebrew_calendar/README.md @@ -0,0 +1,26 @@ +# Hebrew Calendar + +Displays the current hebrew calendar date +Add screen shots (if possible) to the app folder and link then into this file with ![](.png) + +## Usage + +Open the app, and it shows a menu with the date components + +## Features + +Shows the hebrew date, month, and year; alongside the gregorian date + +## Controls + +Name the buttons and what they are used for + +## Requests + +Michael Salaverry (github.com/barakplasma) + +## Creator + +Michael Salaverry +with help from https://github.com/IonicaBizau/hebrew-date (MIT license) +
Icons made by Smashicons from [www.flaticon.com](https://www.flaticon.com/premium-icon/calendar_3130060?term=jewish&page=1&position=10&page=1&position=10&related_id=3130060&origin=tag)
\ No newline at end of file diff --git a/apps/hebrew_calendar/app-icon.js b/apps/hebrew_calendar/app-icon.js new file mode 100644 index 000000000..b6b0a53ae --- /dev/null +++ b/apps/hebrew_calendar/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("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/4ABIn4C/AXWQX/4C/X/6/DghH/AX4C5wC/DgBH/AX4C5Xwi//AX6//gESI/4C/AW8gX4sCI/4C/AW6+FAAMJJX4C/AWtAX48BJX4C/AWq+HAAMEJX4C/AWeAX5MAgRN/AX4CxXpQADn//AH4A/AFn8Xxy//AH6//X/4A/X/6//AH6//X/4A/X/6//AH6//X/4A/X/6//AH6//X/4A/X/6//AH6//X/4A/X/6//AH6//X/4A/X/6//AH6//X/4A/X/6//AH6//X/4A/X/6//AH6//X/4A/X/6//AH6//X/4A/X/6//AH6//X/4A/X/6//AH6//X/4A/X/6//AH6//X7n7tu/CaH27YnRE3d/EyO3X/4AG/3btu2CZ/t23bt4mS74mRtom1/4mSX+32JQXbCZwRCtu/E34mvX+xcCAQN/CRn7OIe3E34muX+39JSQRDTH4mO2wmSt6//X5JKNX4hxNE34mhX/6Y/E36/29qY/E3NtX/6/W/yY/EyffX/6//X/6//X/6//X/6//X/6//X/6//X/6//X/6//X/6//X/6//X/6//X/6//X/6//X/6//X/6//X/6//X/6//X/6//X/6//X/6//X/6//X/6//X/6//X/6//X/6//X/6//X/6//X/6//X/6//X/6//X/6//X/6//X/6//X/6//X/6//X/6//X/6//X/6//X7hKMX4xxME34mgX+RZGARBiDLIwCIE34mkX+xcOAQISB/YROtu3EyV/E34mOX+39JSFv/4RPAQIm/E0S/29pKR/xxSE0vfTCNtX6QmUX/4CJTCYm/E0C/3LiACB+xxSE0vbTCW+E0u/X/4C/AXy//AX4C/X/4C/AX6//AX4C/X/4C/AX6//AX4C/X/4C/AX6//AX4C/X/4C/AX6//AX4C/X/4C/AX6//AX4C/X/4C/AX6//AX4C/X/4C/AX6//ARX2L6PfTHO+CiXtX/6/wOKX+E3C//ABaY/E34CHTSS//TH6//X+1vOKQmm7/9TCQmmX+xKRt5xSE34miX/6Y/E36/2/5KQv///ZxP24m/E0S//TH4m/X+/2JR4TCOJ+/E34mjX/4CG75xSE0yYC/yYS9omlX+xKPTAZxPE34mkX+3/JRwSD/pxNt4m/E0i/3/ZKM24TEOJt/E34mlX+3/JRm/CQn2OJgm/E0y/39pKLCQv+OJffE3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")) \ No newline at end of file diff --git a/apps/hebrew_calendar/app.js b/apps/hebrew_calendar/app.js new file mode 100644 index 000000000..9c21fa89b --- /dev/null +++ b/apps/hebrew_calendar/app.js @@ -0,0 +1,17 @@ +!function(){"use strict"; +/*! + * This script was taked from this page and ported to Node.js by Ionic Bizu + * http://www.shamash.org/help/javadate.shtml + * + * This script was adapted from C sources written by + * Scott E. Lee, which contain the following copyright notice: + * + * Copyright 1993-1995, Scott E. Lee, all rights reserved. + * Permission granted to use, copy, modify, distribute and sell so long as + * the above copyright and this permission statement are retained in all + * copies. THERE IS NO WARRANTY - USE AT YOUR OWN RISK. + * + * Bill Hastings + * RBI Software Systems + * bhastings@rbi.com + */var t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t};var i=new function(t,i,e,o,r,n,h,a,s,f,u,l,v,c){this[0]=t,this[1]=i,this[2]=e,this[3]=o,this[4]=r,this[5]=n,this[6]=h,this[7]=a,this[8]=s,this[9]=f,this[10]=u,this[11]=l,this[12]=v,this[13]=c}("Tishri","Heshvan","Kislev","Tevet","Shevat","AdarI","AdarII","Nisan","Iyyar","Sivan","Tammuz","Av","Elul"),e=new function(t,i,e,o,r,n,h,a,s,f,u,l,v,c,y,d,m,M,b){this[0]=t,this[1]=i,this[2]=e,this[3]=o,this[4]=r,this[5]=n,this[6]=h,this[7]=a,this[8]=s,this[9]=f,this[10]=u,this[11]=l,this[12]=v,this[13]=c,this[14]=y,this[15]=d,this[16]=m,this[17]=M,this[18]=b}(12,12,13,12,12,13,12,13,12,12,13,12,12,13,12,12,13,12,13);g.clear();let o=new Date,r=function(o){var r,n,h=0,a=0,s=0,f=0,u=0,l=0,v=0;function c(t){var i,o,r,n;for(f=Math.floor((t+310)/6940),r=void 0,n=void 0,r=31524,n=(r+=45971*f)>>16,n+=2744*f,o=Math.floor(n/25920),r=(n-=25920*o)<<16|65535&r,i=Math.floor(r/25920),l=o<<16|i,v=r-=25920*i;lt-74);u++)v+=765433*e[u],l+=Math.floor(v/25920),v%=25920}function y(t,i,e){var o=i,r=o%7;return(e>=19440||!(2==t||5==t||7==t||10==t||13==t||16==t||18==t)&&2==r&&e>=9924||(3==t||6==t||8==t||11==t||14==t||17==t||0==t)&&1==r&&e>=16789)&&(o++,7==++r&&(r=0)),3!=r&&5!=r&&0!=r||o++,o}var d=o;return"object"===(void 0===d?"undefined":t(d))&&(r=o.getMonth()+1,n=o.getDate(),d=o.getFullYear()),function(t){var i,o=0,r=0,n=t-347997;if(c(n),n>=(o=y(u,l,v))){if(s=19*f+u+1,n=o-177)return void(n>o-30?(h=13,a=n-o+30):n>o-60?(h=12,a=n-o+60):n>o-89?(h=11,a=n-o+89):n>o-119?(h=10,a=n-o+119):n>o-148?(h=9,a=n-o+148):(h=8,a=n-o+178));if(13==e[(s-1)%19]){if(h=7,(a=n-o+207)>0)return;if(h--,(a+=30)>0)return;h--,a+=30}else{if(h=6,(a=n-o+207)>0)return;h--,a+=30}if(a>0)return;if(h--,(a+=29)>0)return;r=o,c(l-365),o=y(u,l,v)}if(l=n-o-29,355==(i=r-o)||385==i){if(l<=30)return h=2,void(a=l);l-=30}else{if(l<=29)return h=2,void(a=l);l-=29}h=3,a=l}(function(t,i,e){var o=0,r=0,n=void 0;return o=t<0?t+4801:t+4800,i>2?r=i-3:(r=i+9,o--),n=Math.floor(146097*Math.floor(o/100)/4),n+=Math.floor(o%100*1461/4),n+=Math.floor((153*r+2)/5),n+=e-32045}(d,r,n)),{year:s,month:h,date:a,month_name:i[h-1]}}(o);var n={"":{title:"Hebrew Date"},cal:{value:require("locale").date(o,1),onchange:()=>{}},date:{value:r.date,onchange:()=>{}},month:{value:r.month_name,onchange:()=>{}},year:{value:r.year,onchange:()=>{}}};E.showMenu(n)}(); diff --git a/apps/hebrew_calendar/app.png b/apps/hebrew_calendar/app.png new file mode 100644 index 000000000..0dae731cd Binary files /dev/null and b/apps/hebrew_calendar/app.png differ diff --git a/apps/hebrew_calendar/package.json b/apps/hebrew_calendar/package.json new file mode 100644 index 000000000..85e9ebbf0 --- /dev/null +++ b/apps/hebrew_calendar/package.json @@ -0,0 +1,23 @@ +{ + "name": "hebrew_calendar", + "version": "0.0.3", + "description": "Bangle.js app for seeing hebrew calendar", + "main": "app.js", + "types": "app.d.ts", + "scripts": { + "build": "rollup -c" + }, + "author": { + "name": "Michael Salaverry", + "url": "https://github.com/barakplasma" + }, + "license": "MIT", + "devDependencies": { + "@rollup/plugin-typescript": "^4.1.1", + "rollup": "^2.10.2", + "rollup-plugin-terser": "^5.3.0", + "terser": "^4.7.0", + "tslib": "^2.0.0", + "typescript": "^3.9.2" + } +} diff --git a/apps/hebrew_calendar/rollup.config.mjs b/apps/hebrew_calendar/rollup.config.mjs new file mode 100644 index 000000000..5f7f0746f --- /dev/null +++ b/apps/hebrew_calendar/rollup.config.mjs @@ -0,0 +1,15 @@ +import typescript from '@rollup/plugin-typescript'; +import { terser } from 'rollup-plugin-terser'; + +export default { + input: './src/app.ts', + output: { + dir: '.', + format: 'iife', + name: 'hebrew_calendar' + }, + plugins: [ + typescript(), + terser(), + ] +}; diff --git a/apps/hebrew_calendar/src/app.ts b/apps/hebrew_calendar/src/app.ts new file mode 100644 index 000000000..51314e337 --- /dev/null +++ b/apps/hebrew_calendar/src/app.ts @@ -0,0 +1,34 @@ +declare var Bangle: any; +declare var g: any; +declare var E: any; +declare var require: any; + +g.clear(); + +let now = new Date(); +import { hebrewDate } from "./hebrewDate"; + +let today = hebrewDate(now); + +var mainmenu = { + "" : { + "title" : "Hebrew Date" + }, + cal: { + value: require('locale').date(now,1), + onchange : () => {} + }, + date: { + value : today.date, + onchange : () => {} + }, + month: { + value : today.month_name, + onchange : () => {} + }, + year: { + value : today.year, + onchange : () => {} + } +}; +E.showMenu(mainmenu); diff --git a/apps/hebrew_calendar/src/hebrewDate.ts b/apps/hebrew_calendar/src/hebrewDate.ts new file mode 100644 index 000000000..cc3a5ed78 --- /dev/null +++ b/apps/hebrew_calendar/src/hebrewDate.ts @@ -0,0 +1,358 @@ +/*! + * This script was taked from this page and ported to Node.js by Ionic Bizu + * http://www.shamash.org/help/javadate.shtml + * + * This script was adapted from C sources written by + * Scott E. Lee, which contain the following copyright notice: + * + * Copyright 1993-1995, Scott E. Lee, all rights reserved. + * Permission granted to use, copy, modify, distribute and sell so long as + * the above copyright and this permission statement are retained in all + * copies. THERE IS NO WARRANTY - USE AT YOUR OWN RISK. + * + * Bill Hastings + * RBI Software Systems + * bhastings@rbi.com + */ + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +var GREG_SDN_OFFSET = 32045, + DAYS_PER_5_MONTHS = 153, + DAYS_PER_4_YEARS = 1461, + DAYS_PER_400_YEARS = 146097; + +var HALAKIM_PER_HOUR = 1080, + HALAKIM_PER_DAY = 25920, + HALAKIM_PER_LUNAR_CYCLE = 29 * HALAKIM_PER_DAY + 13753, + HALAKIM_PER_METONIC_CYCLE = HALAKIM_PER_LUNAR_CYCLE * (12 * 19 + 7); + +var HEB_SDN_OFFSET = 347997, + NEW_MOON_OF_CREATION = 31524, + NOON = 18 * HALAKIM_PER_HOUR, + AM3_11_20 = 9 * HALAKIM_PER_HOUR + 204, + AM9_32_43 = 15 * HALAKIM_PER_HOUR + 589; + +var SUN = 0, + MON = 1, + TUES = 2, + WED = 3, + THUR = 4, + FRI = 5, + SAT = 6; + +function weekdayarr(d0, d1, d2, d3, d4, d5, d6) { + this[0] = d0; + this[1] = d1; + this[2] = d2; + this[3] = d3; + this[4] = d4; + this[5] = d5; + this[6] = d6; +} + +function gregmontharr(m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11) { + this[0] = m0; + this[1] = m1; + this[2] = m2; + this[3] = m3; + this[4] = m4; + this[5] = m5; + this[6] = m6; + this[7] = m7; + this[8] = m8; + this[9] = m9; + this[10] = m10; + this[11] = m11; +} + +function hebrewmontharr(m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13?: any) { + this[0] = m0; + this[1] = m1; + this[2] = m2; + this[3] = m3; + this[4] = m4; + this[5] = m5; + this[6] = m6; + this[7] = m7; + this[8] = m8; + this[9] = m9; + this[10] = m10; + this[11] = m11; + this[12] = m12; + this[13] = m13; +} + +function monthsperyeararr(m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14, m15, m16, m17, m18) { + this[0] = m0; + this[1] = m1; + this[2] = m2; + this[3] = m3; + this[4] = m4; + this[5] = m5; + this[6] = m6; + this[7] = m7; + this[8] = m8; + this[9] = m9; + this[10] = m10; + this[11] = m11; + this[12] = m12; + this[13] = m13; + this[14] = m14; + this[15] = m15; + this[16] = m16; + this[17] = m17; + this[18] = m18; +} + +var gWeekday = new weekdayarr("Sun", "Mon", "Tues", "Wednes", "Thurs", "Fri", "Satur"), + gMonth = new gregmontharr("January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"), + hMonth = new hebrewmontharr("Tishri", "Heshvan", "Kislev", "Tevet", "Shevat", "AdarI", "AdarII", "Nisan", "Iyyar", "Sivan", "Tammuz", "Av", "Elul"), + mpy = new monthsperyeararr(12, 12, 13, 12, 12, 13, 12, 13, 12, 12, 13, 12, 12, 13, 12, 12, 13, 12, 13); + +/** + * hebrewDate + * Convert the Gregorian dates into Hebrew calendar dates. + * + * @name hebrewDate + * @function + * @param {Date|Number} inputDate The date object (representing the Gregorian date) or the year. + * @return {Object} An object containing: + * + * - `year`: The Hebrew year. + * - `month`: The Hebrew month. + * - `month_name`: The Hebrew month name. + * - `date`: The Hebrew date. + */ +export const hebrewDate = function (inputDateOrYear: Date) { + var inputMonth, inputDate; + + var hebrewMonth = 0, + hebrewDate = 0, + hebrewYear = 0, + metonicCycle = 0, + metonicYear = 0, + moladDay = 0, + moladHalakim = 0; + + function GregorianToSdn(inputYear, inputMonth, inputDay) { + + var year = 0, + month = 0, + sdn = void 0; + + // Make year a positive number + if (inputYear < 0) { + year = inputYear + 4801; + } else { + year = inputYear + 4800; + } + + // Adjust the start of the year + if (inputMonth > 2) { + month = inputMonth - 3; + } else { + month = inputMonth + 9; + year--; + } + + sdn = Math.floor(Math.floor(year / 100) * DAYS_PER_400_YEARS / 4); + sdn += Math.floor(year % 100 * DAYS_PER_4_YEARS / 4); + sdn += Math.floor((month * DAYS_PER_5_MONTHS + 2) / 5); + sdn += inputDay - GREG_SDN_OFFSET; + + return sdn; + } + + function SdnToHebrew(sdn) { + var tishri1 = 0, + tishri1After = 0, + yearLength = 0, + inputDay = sdn - HEB_SDN_OFFSET; + + FindTishriMolad(inputDay); + tishri1 = Tishri1(metonicYear, moladDay, moladHalakim); + + if (inputDay >= tishri1) { + // It found Tishri 1 at the start of the year. + hebrewYear = metonicCycle * 19 + metonicYear + 1; + if (inputDay < tishri1 + 59) { + if (inputDay < tishri1 + 30) { + hebrewMonth = 1; + hebrewDate = inputDay - tishri1 + 1; + } else { + hebrewMonth = 2; + hebrewDate = inputDay - tishri1 - 29; + } + return; + } + // We need the length of the year to figure this out,so find Tishri 1 of the next year. + moladHalakim += HALAKIM_PER_LUNAR_CYCLE * mpy[metonicYear]; + moladDay += Math.floor(moladHalakim / HALAKIM_PER_DAY); + moladHalakim = moladHalakim % HALAKIM_PER_DAY; + tishri1After = Tishri1((metonicYear + 1) % 19, moladDay, moladHalakim); + } else { + // It found Tishri 1 at the end of the year. + hebrewYear = metonicCycle * 19 + metonicYear; + if (inputDay >= tishri1 - 177) { + // It is one of the last 6 months of the year. + if (inputDay > tishri1 - 30) { + hebrewMonth = 13; + hebrewDate = inputDay - tishri1 + 30; + } else if (inputDay > tishri1 - 60) { + hebrewMonth = 12; + hebrewDate = inputDay - tishri1 + 60; + } else if (inputDay > tishri1 - 89) { + hebrewMonth = 11; + hebrewDate = inputDay - tishri1 + 89; + } else if (inputDay > tishri1 - 119) { + hebrewMonth = 10; + hebrewDate = inputDay - tishri1 + 119; + } else if (inputDay > tishri1 - 148) { + hebrewMonth = 9; + hebrewDate = inputDay - tishri1 + 148; + } else { + hebrewMonth = 8; + hebrewDate = inputDay - tishri1 + 178; + } + return; + } else { + if (mpy[(hebrewYear - 1) % 19] == 13) { + hebrewMonth = 7; + hebrewDate = inputDay - tishri1 + 207; + if (hebrewDate > 0) return; + hebrewMonth--; + hebrewDate += 30; + if (hebrewDate > 0) return; + hebrewMonth--; + hebrewDate += 30; + } else { + hebrewMonth = 6; + hebrewDate = inputDay - tishri1 + 207; + if (hebrewDate > 0) return; + hebrewMonth--; + hebrewDate += 30; + } + if (hebrewDate > 0) return; + hebrewMonth--; + hebrewDate += 29; + if (hebrewDate > 0) return; + // We need the length of the year to figure this out,so find Tishri 1 of this year. + tishri1After = tishri1; + FindTishriMolad(moladDay - 365); + tishri1 = Tishri1(metonicYear, moladDay, moladHalakim); + } + } + yearLength = tishri1After - tishri1; + moladDay = inputDay - tishri1 - 29; + if (yearLength == 355 || yearLength == 385) { + // Heshvan has 30 days + if (moladDay <= 30) { + hebrewMonth = 2; + hebrewDate = moladDay; + return; + } + moladDay -= 30; + } else { + // Heshvan has 29 days + if (moladDay <= 29) { + hebrewMonth = 2; + hebrewDate = moladDay; + return; + } + moladDay -= 29; + } + // It has to be Kislev. + hebrewMonth = 3; + hebrewDate = moladDay; + } + + function FindTishriMolad(inputDay) { + // Estimate the metonic cycle number. Note that this may be an under + // estimate because there are 6939.6896 days in a metonic cycle not + // 6940,but it will never be an over estimate. The loop below will + // correct for any error in this estimate. + metonicCycle = Math.floor((inputDay + 310) / 6940); + // Calculate the time of the starting molad for this metonic cycle. + MoladOfMetonicCycle(); + // If the above was an under estimate,increment the cycle number until + // the correct one is found. For modern dates this loop is about 98.6% + // likely to not execute,even once,because the above estimate is + // really quite close. + while (moladDay < inputDay - 6940 + 310) { + metonicCycle++; + moladHalakim += HALAKIM_PER_METONIC_CYCLE; + moladDay += Math.floor(moladHalakim / HALAKIM_PER_DAY); + moladHalakim = moladHalakim % HALAKIM_PER_DAY; + } + // Find the molad of Tishri closest to this date. + for (metonicYear = 0; metonicYear < 18; metonicYear++) { + if (moladDay > inputDay - 74) break; + moladHalakim += HALAKIM_PER_LUNAR_CYCLE * mpy[metonicYear]; + moladDay += Math.floor(moladHalakim / HALAKIM_PER_DAY); + moladHalakim = moladHalakim % HALAKIM_PER_DAY; + } + } + + function MoladOfMetonicCycle() { + var r1 = void 0, + r2 = void 0, + d1 = void 0, + d2 = void 0; + // Start with the time of the first molad after creation. + r1 = NEW_MOON_OF_CREATION; + // Calculate gMetonicCycle * HALAKIM_PER_METONIC_CYCLE. The upper 32 + // bits of the result will be in r2 and the lower 16 bits will be in r1. + r1 += metonicCycle * (HALAKIM_PER_METONIC_CYCLE & 0xFFFF); + r2 = r1 >> 16; + r2 += metonicCycle * (HALAKIM_PER_METONIC_CYCLE >> 16 & 0xFFFF); + // Calculate r2r1 / HALAKIM_PER_DAY. The remainder will be in r1,the + // upper 16 bits of the quotient will be in d2 and the lower 16 bits + // will be in d1. + d2 = Math.floor(r2 / HALAKIM_PER_DAY); + r2 -= d2 * HALAKIM_PER_DAY; + r1 = r2 << 16 | r1 & 0xFFFF; + d1 = Math.floor(r1 / HALAKIM_PER_DAY); + r1 -= d1 * HALAKIM_PER_DAY; + moladDay = d2 << 16 | d1; + moladHalakim = r1; + } + + function Tishri1(metonicYear, moladDay, moladHalakim) { + var tishri1 = moladDay, + dow = tishri1 % 7, + leapYear = metonicYear == 2 || metonicYear == 5 || metonicYear == 7 || metonicYear == 10 || metonicYear == 13 || metonicYear == 16 || metonicYear == 18, + lastWasLeapYear = metonicYear == 3 || metonicYear == 6 || metonicYear == 8 || metonicYear == 11 || metonicYear == 14 || metonicYear == 17 || metonicYear == 0; + + // Apply rules 2,3 and 4 + if (moladHalakim >= NOON || !leapYear && dow == TUES && moladHalakim >= AM3_11_20 || lastWasLeapYear && dow == MON && moladHalakim >= AM9_32_43) { + tishri1++; + dow++; + if (dow == 7) dow = 0; + } + + // Apply rule 1 after the others because it can cause an additional delay of one day. + if (dow == WED || dow == FRI || dow == SUN) { + tishri1++; + } + + return tishri1; + } + + var inputYear: Date | number = inputDateOrYear; + + if ((typeof inputYear === "undefined" ? "undefined" : _typeof(inputYear)) === "object") { + inputMonth = inputDateOrYear.getMonth() + 1; + inputDate = inputDateOrYear.getDate(); + inputYear = inputDateOrYear.getFullYear(); + } + + SdnToHebrew(GregorianToSdn(inputYear, inputMonth, inputDate)); + + return { + year: hebrewYear, + month: hebrewMonth, + date: hebrewDate, + month_name: hMonth[hebrewMonth - 1] + }; +}; \ No newline at end of file diff --git a/apps/hebrew_calendar/tsconfig.json b/apps/hebrew_calendar/tsconfig.json new file mode 100644 index 000000000..30a9e35f4 --- /dev/null +++ b/apps/hebrew_calendar/tsconfig.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "module": "es2015", + "noImplicitAny": false, + "target": "es2015" + }, + "include": [ + "src" + ] +} diff --git a/apps/launch/ChangeLog b/apps/launch/ChangeLog index 3b9dbc30c..0b2f134ad 100644 --- a/apps/launch/ChangeLog +++ b/apps/launch/ChangeLog @@ -8,3 +8,4 @@ 0.08: Merge Bangle.js 1 and 2 launchers 0.09: Bangle.js 2 - pressing the button goes back to clock (fix #971) After 10s of being locked, the launcher goes back to the clock screen +0.10: added in selectable font in settings including scalable vector font diff --git a/apps/launch/app-bangle2.js b/apps/launch/app-bangle2.js index 9a7aa81ed..156eecdf4 100644 --- a/apps/launch/app-bangle2.js +++ b/apps/launch/app-bangle2.js @@ -1,4 +1,22 @@ var s = require("Storage"); +let fonts = g.getFonts(); +var scaleval = 1; +var vectorval = 20; +var font = g.getFonts().includes("12x20") ? "12x20" : "6x8:2"; +let settings = require('Storage').readJSON("launch.json", true) || {}; +if ("vectorsize" in settings) { + vectorval = parseInt(settings.vectorsize); +} +if ("font" in settings){ + if(settings.font == "Vector"){ + scaleval = vectorval/20; + font = "Vector"+(vectorval).toString(); + } + else{ + font = settings.font; + scaleval = (font.split('x')[1])/20; + } +} var apps = s.list(/\.info$/).map(app=>{var a=s.readJSON(app,1);return a&&{name:a.name,type:a.type,icon:a.icon,sortorder:a.sortorder,src:a.src};}).filter(app=>app && (app.type=="app" || app.type=="clock" || !app.type)); apps.sort((a,b)=>{ var n=(0|a.sortorder)-(0|b.sortorder); @@ -11,8 +29,6 @@ apps.forEach(app=>{ if (app.icon) app.icon = s.read(app.icon); // should just be a link to a memory area }); -// FIXME: not needed after 2v11 -var font = g.getFonts().includes("12x20") ? "12x20" : "6x8:2"; // FIXME: check not needed after 2v11 if (g.wrapString) { g.setFont(font); @@ -22,9 +38,9 @@ if (g.wrapString) { function drawApp(i, r) { var app = apps[i]; if (!app) return; - g.clearRect(r.x,r.y,r.x+r.w-1, r.y+r.h-1); - g.setFont(font).setFontAlign(-1,0).drawString(app.name,64,r.y+32); - if (app.icon) try {g.drawImage(app.icon,8,r.y+8);} catch(e){} + g.clearRect((r.x),(r.y),(r.x+r.w-1), (r.y+r.h-1)); + g.setFont(font).setFontAlign(-1,0).drawString(app.name,64*scaleval,r.y+(32*scaleval)); + if (app.icon) try {g.drawImage(app.icon,8*scaleval, r.y+(8*scaleval), {scale: scaleval});} catch(e){} } g.clear(); @@ -32,7 +48,7 @@ Bangle.loadWidgets(); Bangle.drawWidgets(); E.showScroller({ - h : 64, c : apps.length, + h : 64*scaleval, c : apps.length, draw : drawApp, select : i => { var app = apps[i]; diff --git a/apps/launch/settings.js b/apps/launch/settings.js new file mode 100644 index 000000000..8be1adb36 --- /dev/null +++ b/apps/launch/settings.js @@ -0,0 +1,25 @@ +// make sure to enclose the function in parentheses +(function(back) { + let settings = require('Storage').readJSON('launch.json',1)||{}; + let fonts = g.getFonts(); + function save(key, value) { + settings[key] = value; + require('Storage').write('launch.json',settings); + } + const appMenu = { + '': {'title': 'Launcher Settings'}, + '< Back': back, + 'Font': { + value: fonts.includes(settings.font)? fonts.indexOf(settings.font) : fonts.indexOf("12x20"), + min:0, max:fonts.length-1, step:1,wrap:true, + onchange: (m) => {save('font', fonts[m])}, + format: v => fonts[v] + }, + 'Vector font size': { + value: settings.vectorsize || 10, + min:10, max: 20,step:1,wrap:true, + onchange: (m) => {save('vectorsize', m)} + } + }; + E.showMenu(appMenu); +}); diff --git a/apps/mandlebrotclock/ChangeLog b/apps/mandelbrotclock/ChangeLog similarity index 100% rename from apps/mandlebrotclock/ChangeLog rename to apps/mandelbrotclock/ChangeLog diff --git a/apps/mandlebrotclock/README.md b/apps/mandelbrotclock/README.md similarity index 55% rename from apps/mandlebrotclock/README.md rename to apps/mandelbrotclock/README.md index 8628a61d0..387343a9e 100644 --- a/apps/mandlebrotclock/README.md +++ b/apps/mandelbrotclock/README.md @@ -1,6 +1,6 @@ -# Mandlebrot Clock +# Mandelbrot Clock -A simple clock themed on the mandlebrot set. +A simple clock themed on the mandelbrot set. Written by [James Milner](https://www.github.com/jameslmilner) diff --git a/apps/mandlebrotclock/app.png b/apps/mandelbrotclock/app.png similarity index 100% rename from apps/mandlebrotclock/app.png rename to apps/mandelbrotclock/app.png diff --git a/apps/mandlebrotclock/mandlebrotclock-icon.js b/apps/mandelbrotclock/mandelbrotclock-icon.js similarity index 100% rename from apps/mandlebrotclock/mandlebrotclock-icon.js rename to apps/mandelbrotclock/mandelbrotclock-icon.js diff --git a/apps/mandlebrotclock/mandlebrotclock.js b/apps/mandelbrotclock/mandelbrotclock.js similarity index 99% rename from apps/mandlebrotclock/mandlebrotclock.js rename to apps/mandelbrotclock/mandelbrotclock.js index 16cc8dfb8..94636056e 100644 --- a/apps/mandlebrotclock/mandlebrotclock.js +++ b/apps/mandelbrotclock/mandelbrotclock.js @@ -1,6 +1,6 @@ // MIT License - James Milner 2021 -const mandlebrotBmp = { +const mandelbrotBmp = { width: 176, height: 176, bpp: 8, @@ -13,7 +13,7 @@ const mandlebrotBmp = { }; function draw() { - g.drawImage(mandlebrotBmp); + g.drawImage(mandelbrotBmp); // work out how to display the current time const d = new Date(); const h = d.getHours(), diff --git a/apps/mandlebrotclock/mandlebrotclock.png b/apps/mandelbrotclock/mandelbrotclock.png similarity index 100% rename from apps/mandlebrotclock/mandlebrotclock.png rename to apps/mandelbrotclock/mandelbrotclock.png diff --git a/apps/mandlebrotclock/screenshot_mandlebrotclock.png b/apps/mandelbrotclock/screenshot_mandelbrotclock.png similarity index 100% rename from apps/mandlebrotclock/screenshot_mandlebrotclock.png rename to apps/mandelbrotclock/screenshot_mandelbrotclock.png diff --git a/apps/snek/snek-icon.js b/apps/snek/snek-icon.js new file mode 100644 index 000000000..c919c429e --- /dev/null +++ b/apps/snek/snek-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("pFIwkB+MRAEH/EUIA7i93u9xEUIABEf4AC+93/4CBETpDBv//gEHEf6MB9wkB/8HSDl3vwjCAAfnErIjiEQYdBAAXuAoSNXEYIdDAAoj4j/3DpN3v6NWAA3/fDYjgRgIjLu9xESj2BAAN/SQwLBEe4XDdwghDBQQjSCgN+C5D9FEebTDEZJEWEQSDVEdZpDZYPnETYhDAAhpeEbzREI0rTbEdXuETb4Bvz1BAYIj/EYxrg9yQDv/3JoS9WEcoaGAAQtBOwYABEaSMBWoYeFJKgjjiIUD9ySEEjwAJFogj0SQgAFBQ4jRABcfXoQj/TowjCOgIkeEf7lHvz+CEb93Ef4jHR8Rr/fY4jCuIifAAQj/EIojbeohGeEcQhHfLRFDeoIicEcQbDv3uEYiNXIgnu87SgEcf/DKnxBJEf/4ACESf/EcYA==")) \ No newline at end of file diff --git a/apps/snek/snek.js b/apps/snek/snek.js new file mode 100644 index 000000000..4c3aec73e --- /dev/null +++ b/apps/snek/snek.js @@ -0,0 +1,469 @@ +function init() { + this.titleScreen = true; + this.min = 0; + this.max = 160; + this.step = 20; + this.scoreMultiplier = 25; + this.totalGrid = this.max / this.step; + + if (g.theme.dark) { + this.textColor = 1; + } else { + this.textColor = 0; + } + + this.getNewPosistion = () => { + let newPos; + while (!newPos) { + // random bonus points for bad luck / lag + if (currentPosition.length > 10) { + this.score += 1; + } + const x = Math.floor(Math.random() * this.totalGrid + 1) * this.step; + const y = Math.floor(Math.random() * this.totalGrid + 1) * this.step; + const found = currentPosition.find(pos => { + return pos.x === x && pos.y === y; + }); + if (!found) { + newPos = {x: x, y: y}; + } + } + return newPos; + }; + + this.restart = () => { + g.clear(); + this.titleScreen = false; + this.score = 0; + this.paused = false; + this.currentPosition = [{x: 2 * step, y: 3 * step},{x: 1 * step, y: 3 * step}]; + this.death = false; + this.gameSpeed = 200; + this.directionSet = null; + this.direction = 1; + this.createApple(); + }; + + const game = () => { + if (this.death && !this.paused) { + g.clear(); + this.showDeathScreen(); + } else if (this.titleScreen && !this.paused) { + this.showTitleScreen(); + } else if (!this.paused) { + g.clear(); + this.drawApple(); + this.drawSnake(); + this.boundries(); + + } + + setTimeout(() => { + game(); + }, this.gameSpeed); + }; + + this.increaseDifficulity = () => { + if (gameSpeed > 59) { + gameSpeed -= 10; + } + }; + + this.createApple = () => { + this.applePosition = getNewPosistion(); + }; + + this.drawApple = () => { + g.setColor(0, 1, 0); + + g.drawImage(this.appleLeaf, this.applePosition.x - 15, this.applePosition.y - 10); + g.setColor(1, 0, 0); + + g.drawImage(this.apple, this.applePosition.x - 15, this.applePosition.y - 2); + }; + + this.checkmax = (x) => { + if (x > this.max) { + return this.min; + } else if (x < this.min) { + return this.max; + } + return x; + }; + + this.movement = (lastItem) => { + let newPosition; + switch(this.direction) { + case 3: + newPosition = { + x: checkmax(lastItem.x + this.step), + y: lastItem.y + }; + break; + case 1: + newPosition = { + x: checkmax(lastItem.x - this.step), + y: lastItem.y + }; + break; + case 2: + newPosition = { + x: lastItem.x, + y: checkmax(lastItem.y + this.step) + }; + break; + case 0: + newPosition = { + x: lastItem.x, + y: checkmax(lastItem.y - this.step) + }; + break; + } + this.directionSet = false; + this.checkDeath(newPosition); + this.currentPosition.push(newPosition); + + }; + + this.snakeHead = (props) => { + switch (this.direction) { + case 0: + return [this.snakeUp, props.x - 9, props.y - 12]; + case 1: + return [this.snakeLeft, props.x - 20, props.y - 10]; + case 3: + return [this.snakeRight, props.x - 12, props.y - 12]; + case 2: + return [this.snakeDown, props.x - 12, props.y - 7]; + default: + return [this.snakeDown, props.x - 12, props.y - 7]; + } + }; + + this.drawSnake = () => { + const totalItems = this.currentPosition.length - 1; + g.setColor(0, 1, 0); + this.movement(this.currentPosition[totalItems]); + this.currentPosition.forEach((props, index) => { + if (index-1 === totalItems) { + const head = this.snakeHead(props); + + g.drawImage(head[0], head[1], head[2]); + } else { + g.fillCircle(props.x, props.y, 10); + } + }); + if (this.currentPosition[totalItems].x === this.applePosition.x && this.currentPosition[totalItems].y === this.applePosition.y) { + this.createApple(); + this.increaseDifficulity(); + } else { + this.currentPosition.shift(); + } + }; + + this.checkDeath = (newPos) => { + + const found = this.currentPosition.find((oldPos) => { + return newPos.x === oldPos.x && newPos.y === oldPos.y; + }); + if (found) { + Bangle.buzz(); + g.clear(); + this.death = true; + } + }; + + this.boundries = () => { + if (this.currentPosition.x >= this.maxPx) { + this.currentPosition.x = this.maxPx; + } + else if (this.currentPosition.x < 10) { + this.currentPosition.x = 10; + } + + if ( this.currentPosition.y >= this.maxPy) { + this.currentPosition.y = this.maxPy; + } else if (this.currentPosition.y < 10) { + this.currentPosition.y = 10; + } + }; + + this.creatTopScrore = () => { + require("Storage").writeJSON("snek_jd", { + topScore: this.calculateScore() + }); + }; + + this.calculateScore = () => { + return currentPosition.length * this.scoreMultiplier + this.score; + }; + + this.showDeathScreen = () => { + this.paused = true; + g.setFont('Vector', 25); + g.setColor(1, 0, 0); + g.drawString("GAME OVER",15, 50, "solid"); + g.setFont('Vector', 15); + g.setColor(this.textColor, this.textColor, this.textColor); + g.drawString("Score : " + this.calculateScore(), 50, 78, "solid"); + + let storage = require("Storage").readJSON("snek_jd"); + if (storage && storage.topScore) { + if (storage.topScore < this.calculateScore()) { + g.setColor(0, 1, 1); + g.drawString("New top score!", 20, 95, "solid"); + g.setFont('Vector', 22); + g.drawString(this.calculateScore(), 20, 115, "solid"); + + this.creatTopScrore(); + } else { + g.setColor(this.textColor, this.textColor, this.textColor); + g.drawString("Top score : " + storage.topScore, 20, 95, "solid"); + } + } else { + this.creatTopScrore(); + } + g.setFont('Vector', 25); + }; + + /* Events */ + Bangle.on('tap', (data) => { + Bangle.setLCDPower(true); + if (this.death) { + this.showTitleScreen(); + } else if (this.titleScreen || this.paused) { + this.restart(); + } + }); + + Bangle.on('accel', (xyz) => { + if (Math.abs(xyz.x) > Math.abs(xyz.y)) { + if (xyz.x < 0) { + if (!this.directionSet && this.direction !== 1) { + Bangle.setLCDPower(true); + this.direction = 3; + } + } else { + if (!this.directionSet && this.direction !== 3) { + Bangle.setLCDPower(true); + this.direction = 1; + } + } + } else { + if (xyz.y < 0) { + if (!this.directionSet && this.direction !== 0) { + Bangle.setLCDPower(true); + this.direction = 2; + } + } else { + if (!this.directionSet && this.direction !== 2) { + Bangle.setLCDPower(true); + this.direction = 0; + } + } + } + this.directionSet = true; + }); + + this.showTitleScreen = () => { + this.death = false; + g.clear(); + g.setColor(0, 1, 0); + g.setFont('Vector', 50); + g.drawString("nek", 70, 15, "solid"); + g.drawImage(this.titleScreenImg, 20, 20); + g.fillPoly([ + 15, 66, + 152, 70, + 159, 79, + 21, 71 ]); + g.setColor(this.textColor, this.textColor, this.textColor); + g.setFont('Vector', 15); + g.drawString("Tilt to turn", 20, 100, "solid"); + g.drawString("Tap to start", 20, 120, "solid"); + + g.setColor(0, 1, 0); + + g.setFont('4x6', 3); + g.drawString("Jason de Belle", 5, 145, "solid"); + + + + }; + +/* Graphics */ + this.snakeUp = Graphics.createImage(` + XX XX + xx xx + xx xx + xx + xx + xx + xx + xx + xxxxxxxx + xxxx xxxx + xxxxxx xxxxxxx + xxxxxxxxxxxxxxxx + xxxxx xXXx xxxxx + xxxxx XX xxxxx + xxxxx XX xxxxx + xxxxxx xxxx xxxxx + xxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxx + xxxxxxxxxxxxx + xxxxxxxxxxx + `); + this.snakeDown = Graphics.createImage(` + xxxxxxxxxx + xxxxxxxxxx + xxxxxxxxxx + xxxxxxxxxxxxxx + xxxxxxxxxxxxxx + xxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxx + xxxxxx xxxx xxxxxx + xxxxxx xxxx xxxxxx + xxxx XX xxxxx + xxxx XX xxxxx + xxxx xXXx xxxx + xxxx xXXx xxxx + xXxxxxxxxxxxxx + xXxxxxxxxxxxxx + xxx xxx + xxxx xxxx + xxxx + xx + xx + xx + xx + x x + xx xx + xx xx + `); + + this.snakeRight = Graphics.createImage(` + xxxxxxxxxx + xxxxxxxxxx + xxxxxxxxxxxx + xxxxxxxxxxxx + xXxxxxxx xxxx + xXxxxxxx xxxx + xxxxxxxX xxx + xxxxxxxX xxx xxxx +xxxxxxxxxxXX xxxxxx xxxx +xxxxxxxxxxXX xxxxxx xx +xxxxxxxxxxXXxxxxx xxxxxxxx +xxxxxxxxxxXXxxxxx xxxxxxxx +xxxxxxxxxxxx xxxxx xx +xxxxxxxxxxxx xxxxx xxx + xxxxxxxx xx xxxx + xxxxxxxx xx + xxxxxxxx xxx + xxxxxxxx xxx + xxxxxxxxxxx + xxxxxxxxxxx + xxxxxxxxx + xxxxxxxxx + `); + this.snakeLeft = Graphics.createImage(` + xxxxxxxxxx + xxxxxxxxxx + xxxxxxxxxxxx + xxxxxxxxxxxx + xXxxxxxxxxxxxx + xX xxxxxxxxxx + x xx xXxxxxxxxx + xx xx xXxxxxxxxx + xx xx xxxx xxXXxxxxxxxx + xxxxxxx xxxxxXXxxxxxxxx + xxxxxxx xxxxxXXxxxxxxxx + xx xx xxxx xxXXxxxxxxxx + xx xxx xxxxxxxxxx + x xxx xxxxxxxxx + xxxx xxxxxxxxx + xxxx xxxxxxxxxx + xxxxxxxxxxxxx + xxxxxxxxxxxxx + xxxxxxxxxxx + xxxxxxxxxxx + xxxxxxxxx + xxxxxxxxx + `); + + this.apple = Graphics.createImage(` + xxxxxxxxxx + xxxxxxxxxxxx + xxxxxxxxxxxxxx + xxxxxxxxxxxxxx + xxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxx + xxxxxxxxxxxxxx + xxxxxxxxxxxxxx + xxxxxxxxxxxx + xxxxxxxxxx + `); + + this.appleLeaf = Graphics.createImage(` + xxxxxx + xxxxxx + xxxx + XXxxxxxxxx + xx + xx + xx + xx + xx + `); + + +this.titleScreenImg = Graphics.createImage(` + sxxxxxxxs + xxsxxx xxxxxs + xxxxxxxxsxx xxxxsx + xxxxxxxxxxxxxxxsxxs xxxxsxx + xxxxxxxxxxxxxxxxxxxxxsxxxsssxxxxxxsxxxx + xxxxxxxxxxxxxxxxxxxsxxxxsxxs xxsxxx + xxxxxxxxxxxxxxxxxxxxxxxxxsxx xxxsxx + xxxxxxxxxxxxxxxxxxxxx sxxx ssxxsx + xxxxxxxxxxxxxxx xxxxxxs + xxxxxxxxxxxx ssss + xxxxxxxxxxxxx +xxxxxxxxxxxx +xxxxxxxxxxx +xxxxxxxxxxx + xxxxxxxxxxxxx + xxxxxxxxxxxxx + xxxxxxxxxxxxx + xxxxxxxxxxxxx + xxxxxxxxxxxxx + xxxxxxxxxxxxx + xxxxxxxxxxxxx + xxxxxxxxxxxxx + xxxxxxxxxxxx + xxxxxxxxxxxxx + xxxxxxxxxxxxx + xxxxxxxxxxxxx + xxxxxxxxxxxxx + xxxxxxxxxxxxx + xxxxxxxxxxxxx + xxxxxxxxxxxxxx + xxxxxxxxxxxxx + xxxxxxxxxxxx + xxxxxxxxxxx + xxxxxxxxxxxx + xxxxxxxxxxxx + xxxxxxxxxxxx + xxxxxxxxxx +xxxxxxx +xxx +`); + + game(); +} +init(); \ No newline at end of file diff --git a/apps/snek/snek.png b/apps/snek/snek.png new file mode 100644 index 000000000..8cf8d05e3 Binary files /dev/null and b/apps/snek/snek.png differ diff --git a/apps/widChargingStatus/ChangeLog b/apps/widChargingStatus/ChangeLog new file mode 100644 index 000000000..d3175e1ab --- /dev/null +++ b/apps/widChargingStatus/ChangeLog @@ -0,0 +1 @@ +0.1: First release. \ No newline at end of file diff --git a/apps/widChargingStatus/widget.js b/apps/widChargingStatus/widget.js new file mode 100644 index 000000000..90f9199fa --- /dev/null +++ b/apps/widChargingStatus/widget.js @@ -0,0 +1,31 @@ +(() => { + const icon = require("heatshrink").decompress(atob("ikggMAiEAgYIBmEAg4EB+EAh0AgPggEeCAIEBnwQBAgP+gEP//x///j//8f//k///H//4BYOP/4lBv4bDvwEB4EAvAEBwEAuA7DCAI7BgAQBhEAA")); + const iconWidth = 18; + + function draw() { + g.reset(); + if (Bangle.isCharging()) { + g.setColor("#FD0"); + g.drawImage(icon, this.x + 1, this.y + 1, { + scale: 0.6875 + }); + } + } + + WIDGETS.chargingStatus = { + area: 'tr', + width: Bangle.isCharging() ? iconWidth : 0, + draw: draw, + }; + + Bangle.on('charging', (charging) => { + if (charging) { + Bangle.buzz(); + WIDGETS.chargingStatus.width = iconWidth; + } else { + WIDGETS.chargingStatus.width = 0; + } + Bangle.drawWidgets(); // re-layout widgets + g.flip(); + }); +})(); \ No newline at end of file diff --git a/apps/widChargingStatus/widget.png b/apps/widChargingStatus/widget.png new file mode 100644 index 000000000..0097d45ef Binary files /dev/null and b/apps/widChargingStatus/widget.png differ diff --git a/core b/core index 23854083e..59f80bb52 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 23854083e0c3f83c649073a2d85e8079efc471d3 +Subproject commit 59f80bb52a38da12cb272f9106cb3951b49dab2e