From 01d3615663bb9d74d2c601de7820ae7012b1604a Mon Sep 17 00:00:00 2001 From: Adam Schmalhofer Date: Tue, 4 Jan 2022 22:57:00 +0100 Subject: [PATCH 001/174] Let apps.json be generated by jekyll Reading https://github.com/espruino/BangleApps/issues/1020 https://github.com/espruino/BangleApps/issues/46 My understanding is that the requirement for a splitt apps.json solution is: - work seemlessly with github pages (no manually calling a script) - single (or at most a few) apps.json for the browser to load for the store so the store page is fast As the github pages already use jekyll to build the store page this can be solved by a minimal jekyll plugin. This is a proof of concept of that. If the concept is accepted in a next step, I will create the splitt files for mmore that just the two here. --- .gitignore | 1 + _plugins/AppsJsonGenerator.rb | 26 + apps.json | 5431 --------------------------------- apps/gbridge/metadata.json | 18 + apps/lcars/metadata.json | 18 + 5 files changed, 63 insertions(+), 5431 deletions(-) create mode 100644 _plugins/AppsJsonGenerator.rb delete mode 100644 apps.json create mode 100644 apps/gbridge/metadata.json create mode 100644 apps/lcars/metadata.json diff --git a/.gitignore b/.gitignore index 47233d1f5..6542325c5 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ appdates.csv _config.yml tests/Layout/bin/tmp.* tests/Layout/testresult.bmp +/apps.json diff --git a/_plugins/AppsJsonGenerator.rb b/_plugins/AppsJsonGenerator.rb new file mode 100644 index 000000000..1a6525cca --- /dev/null +++ b/_plugins/AppsJsonGenerator.rb @@ -0,0 +1,26 @@ +class AppsJsonPage < Jekyll::Page + def initialize(site) + @site = site + @base = site.source + @basename = 'apps' + @ext = '.json' + @name = 'apps.json' + @data = {} + end +end + +# Generates the apps.json +# out of all the /apps/*/metadata.json files +class Generator < Jekyll::Generator + safe true + + def generate(site) + metadatas = site.static_files.select { |file| file.name == 'metadata.json' } + json = metadatas.map { |file| JSON.load(open(file.path)) } + appsjson = AppsJsonPage.new(site) + open(appsjson.path, 'wb') do |file| + file << JSON.generate(json) + end + site.pages << appsjson + end +end diff --git a/apps.json b/apps.json deleted file mode 100644 index ebafa9c97..000000000 --- a/apps.json +++ /dev/null @@ -1,5431 +0,0 @@ -[ - { - "id": "fwupdate", - "name": "Firmware Update", - "version": "0.02", - "description": "[BETA] Uploads new Espruino firmwares to Bangle.js 2. For now, please use the instructions under https://www.espruino.com/Bangle.js2#firmware-updates", - "icon": "app.png", - "type": "RAM", - "tags": "tools,system", - "supports": ["BANGLEJS2"], - "custom": "custom.html", - "customConnect": true, - "storage": [], - "sortorder": 20 - }, - { - "id": "boot", - "name": "Bootloader", - "version": "0.40", - "description": "This is needed by Bangle.js to automatically load the clock, menu, widgets and settings", - "icon": "bootloader.png", - "type": "bootloader", - "tags": "tool,system", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":".boot0","url":"boot0.js"}, - {"name":".bootcde","url":"bootloader.js"}, - {"name":"bootupdate.js","url":"bootupdate.js"} - ], - "sortorder": -10 - }, - { - "id": "hebrew_calendar", - "name": "Hebrew Calendar", - "shortName": "HebCal", - "version": "0.04", - "description": "lists the date according to the hebrew calendar", - "icon": "app.png", - "allow_emulator": false, - "tags": "tool,locale", - "supports": [ - "BANGLEJS", - "BANGLEJS2" - ], - "readme": "README.md", - "storage": [ - { - "name": "hebrew_calendar.app.js", - "url": "app.js" - }, - { - "name": "hebrewDate", - "url": "hebrewDate.js" - }, - { - "name": "hebrew_calendar.img", - "url": "app-icon.js", - "evaluate": true - } - ] - }, - { "id": "golfscore", - "name": "Golf Score", - "shortName":"golfscore", - "version":"0.02", - "description": "keeps track of strokes during a golf game", - "icon": "app.png", - "tags": "outdoors", - "allow_emulator": true, - "supports" : ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "storage": [ - {"name":"golfscore.app.js","url":"app.js"}, - {"name":"golfscore.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "messages", - "name": "Messages", - "version": "0.17", - "description": "App to display notifications from iOS and Gadgetbridge", - "icon": "app.png", - "type": "app", - "tags": "tool,system", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "storage": [ - {"name":"messages.app.js","url":"app.js"}, - {"name":"messages.settings.js","url":"settings.js"}, - {"name":"messages.img","url":"app-icon.js","evaluate":true}, - {"name":"messages.wid.js","url":"widget.js"}, - {"name":"messages","url":"lib.js"} - ], - "data": [{"name":"messages.json"},{"name":"messages.settings.json"}], - "screenshots": [{"url":"screenshot.png"},{"url":"screenshot-notify.gif"}], - "sortorder": -9 - }, - { - "id": "android", - "name": "Android Integration", - "shortName": "Android", - "version": "0.05", - "description": "Display notifications/music/etc sent from the Gadgetbridge app on Android. This replaces the old 'Gadgetbridge' Bangle.js widget.", - "icon": "app.png", - "tags": "tool,system,messages,notifications", - "dependencies": {"messages":"app"}, - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"android.app.js","url":"app.js"}, - {"name":"android.settings.js","url":"settings.js"}, - {"name":"android.img","url":"app-icon.js","evaluate":true}, - {"name":"android.boot.js","url":"boot.js"} - ], - "sortorder": -8 - }, - { - "id": "ios", - "name": "iOS Integration", - "version": "0.08", - "description": "Display notifications/music/etc from iOS devices", - "icon": "app.png", - "tags": "tool,system,ios,apple,messages,notifications", - "dependencies": {"messages":"app"}, - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"ios.app.js","url":"app.js"}, - {"name":"ios.img","url":"app-icon.js","evaluate":true}, - {"name":"ios.boot.js","url":"boot.js"} - ], - "sortorder": -8 - }, - { - "id": "health", - "name": "Health Tracking", - "version": "0.09", - "description": "Logs health data and provides an app to view it (requires firmware 2v10.100 or later)", - "icon": "app.png", - "tags": "tool,system,health", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "interface": "interface.html", - "storage": [ - {"name":"health.app.js","url":"app.js"}, - {"name":"health.img","url":"app-icon.js","evaluate":true}, - {"name":"health.boot.js","url":"boot.js"}, - {"name":"health","url":"lib.js"} - ] - }, - { - "id": "launch", - "name": "Launcher", - "shortName": "Launcher", - "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", - "tags": "tool,system,launcher", - "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.settings.js","url":"settings.js","supports":["BANGLEJS2"]} - ], - "data": [{"name":"launch.json"}], - "sortorder": -10 - }, - { - "id": "setting", - "name": "Settings", - "version": "0.40", - "description": "A menu for setting up Bangle.js", - "icon": "settings.png", - "tags": "tool,system", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "storage": [ - {"name":"setting.app.js","url":"settings.js"}, - {"name":"setting.img","url":"settings-icon.js","evaluate":true} - ], - "data": [{"name":"setting.json","url":"settings.min.json","evaluate":true}], - "sortorder": -5 - }, - { - "id": "about", - "name": "About", - "version": "0.12", - "description": "Bangle.js About page - showing software version, stats, and a collaborative mural from the Bangle.js KickStarter backers", - "icon": "app.png", - "tags": "tool,system", - "supports": ["BANGLEJS","BANGLEJS2"], - "screenshots": [{"url":"bangle1-about-screenshot.png"}], - "allow_emulator": true, - "storage": [ - {"name":"about.app.js","url":"app-bangle1.js","supports": ["BANGLEJS"]}, - {"name":"about.app.js","url":"app-bangle2.js","supports": ["BANGLEJS2"]}, - {"name":"about.img","url":"app-icon.js","evaluate":true} - ], - "sortorder": -4 - }, - { - "id": "alarm", - "name": "Default Alarm & Timer", - "shortName": "Alarms", - "version": "0.14", - "description": "Set and respond to alarms and timers", - "icon": "app.png", - "tags": "tool,alarm,widget", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"alarm.app.js","url":"app.js"}, - {"name":"alarm.boot.js","url":"boot.js"}, - {"name":"alarm.js","url":"alarm.js"}, - {"name":"alarm.img","url":"app-icon.js","evaluate":true}, - {"name":"alarm.wid.js","url":"widget.js"} - ], - "data": [{"name":"alarm.json"}] - }, - { - "id": "locale", - "name": "Languages", - "version": "0.14", - "description": "Translations for different countries", - "icon": "locale.png", - "type": "locale", - "tags": "tool,system,locale,translate", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "custom": "locale.html", - "storage": [ - {"name":"locale"} - ], - "sortorder": -10 - }, - { - "id": "notify", - "name": "Notifications (default)", - "shortName": "Notifications", - "version": "0.11", - "description": "Provides the default `notify` module used by applications to display notifications in a bar at the top of the screen. This module is installed by default by client applications such as the Gadgetbridge app. Installing `Fullscreen Notifications` replaces this module with a version that displays the notifications using the full screen", - "icon": "notify.png", - "type": "notify", - "tags": "widget", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"notify","url":"notify.js"} - ] - }, - { - "id": "notifyfs", - "name": "Fullscreen Notifications", - "shortName": "Notifications", - "version": "0.12", - "description": "Provides a replacement for the `Notifications (default)` `notify` module. This version is used by applications to display notifications fullscreen. This may not fully restore the screen after on some apps. See `Notifications (default)` for more information about the notify module.", - "icon": "notify.png", - "type": "notify", - "tags": "widget", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"notify","url":"notify.js"} - ] - }, - { - "id": "welcome", - "name": "Welcome", - "shortName": "Welcome", - "version": "0.14", - "description": "Appears at first boot and explains how to use Bangle.js", - "icon": "app.png", - "screenshots": [{"url":"screenshot_welcome.png"}], - "tags": "start,welcome", - "supports": ["BANGLEJS","BANGLEJS2"], - "allow_emulator": true, - "storage": [ - {"name":"welcome.boot.js","url":"boot.js"}, - {"name":"welcome.app.js","url":"app-bangle1.js","supports": ["BANGLEJS"]}, - {"name":"welcome.app.js","url":"app-bangle2.js","supports": ["BANGLEJS2"]}, - {"name":"welcome.settings.js","url":"settings.js"}, - {"name":"welcome.img","url":"app-icon.js","evaluate":true} - ], - "data": [{"name":"welcome.json"}] - }, - { - "id": "mywelcome", - "name": "Customised Welcome", - "shortName": "My Welcome", - "version": "0.13", - "description": "Appears at first boot and explains how to use Bangle.js. Like 'Welcome', but can be customised with a greeting", - "icon": "app.png", - "tags": "start,welcome", - "supports": ["BANGLEJS","BANGLEJS2"], - "custom": "custom.html", - "screenshots": [{"url":"bangle1-customized-welcome-screenshot.png"}], - "storage": [ - {"name":"mywelcome.boot.js","url":"boot.js"}, - {"name":"mywelcome.app.js","url":"app-bangle1.js","supports": ["BANGLEJS"]}, - {"name":"mywelcome.app.js","url":"app-bangle2.js","supports": ["BANGLEJS2"]}, - {"name":"mywelcome.settings.js","url":"settings.js"}, - {"name":"mywelcome.img","url":"app-icon.js","evaluate":true} - ], - "data": [{"name":"mywelcome.json"}] - }, - { - "id": "gbridge", - "name": "Gadgetbridge", - "version": "0.25", - "description": "(NOT RECOMMENDED) Displays Gadgetbridge notifications from Android. Please use the 'Android' Bangle.js app instead.", - "icon": "app.png", - "type": "widget", - "tags": "tool,system,android,widget", - "supports": ["BANGLEJS","BANGLEJS2"], - "dependencies": {"notify":"type"}, - "readme": "README.md", - "storage": [ - {"name":"gbridge.settings.js","url":"settings.js"}, - {"name":"gbridge.img","url":"app-icon.js","evaluate":true}, - {"name":"gbridge.wid.js","url":"widget.js"} - ], - "data": [{"name":"gbridge.json"}] - }, - { "id": "gbdebug", - "name": "Gadgetbridge Debug", - "shortName":"GB Debug", - "version":"0.01", - "description": "Debug info for Gadgetbridge. Run this app and when Gadgetbridge messages arrive they are displayed on-screen.", - "icon": "app.png", - "tags": "", - "supports" : ["BANGLEJS2"], - "readme": "README.md", - "storage": [ - {"name":"gbdebug.app.js","url":"app.js"}, - {"name":"gbdebug.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "mclock", - "name": "Morphing Clock", - "version": "0.07", - "description": "7 segment clock that morphs between minutes and hours", - "icon": "clock-morphing.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "allow_emulator": true, - "screenshots": [{"url":"bangle1-morphing-clock-screenshot.png"}], - "storage": [ - {"name":"mclock.app.js","url":"clock-morphing.js"}, - {"name":"mclock.img","url":"clock-morphing-icon.js","evaluate":true} - ], - "sortorder": -9 - }, - { - "id": "moonphase", - "name": "Moonphase", - "version": "0.02", - "description": "Shows current moon phase. Now with GPS function.", - "icon": "app.png", - "tags": "", - "supports": ["BANGLEJS"], - "screenshots": [{"url":"bangle1-moon-phase-screenshot.png"}], - "allow_emulator": true, - "storage": [ - {"name":"moonphase.app.js","url":"app.js"}, - {"name":"moonphase.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "daysl", - "name": "Days left", - "version": "0.03", - "description": "Shows you the days left until a certain date. Date can be set with a settings app and is written to a file.", - "icon": "app.png", - "tags": "", - "supports": ["BANGLEJS"], - "allow_emulator": false, - "storage": [ - {"name":"daysl.app.js","url":"app.js"}, - {"name":"daysl.img","url":"app-icon.js","evaluate":true}, - {"name":"daysl.wid.js","url":"widget.js"} - ] - }, - { - "id": "wclock", - "name": "Word Clock", - "version": "0.03", - "description": "Display Time as Text", - "icon": "clock-word.png", - "screenshots": [{"url":"screenshot_word.png"}], - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "allow_emulator": true, - "storage": [ - {"name":"wclock.app.js","url":"clock-word.js"}, - {"name":"wclock.img","url":"clock-word-icon.js","evaluate":true} - ] - }, - { - "id": "fontclock", - "name": "Font Clock", - "version": "0.01", - "description": "Choose the font and design of clock face from a library of available designs", - "icon": "fontclock.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "readme": "README.md", - "custom": "custom.html", - "allow_emulator": false, - "storage": [ - {"name":"fontclock.app.js","url":"fontclock.js"}, - {"name":"fontclock.img","url":"fontclock-icon.js","evaluate":true}, - {"name":"fontclock.hand.js","url":"fontclock.hand.js"}, - {"name":"fontclock.thinhand.js","url":"fontclock.thinhand.js"}, - {"name":"fontclock.thickhand.js","url":"fontclock.thickhand.js"}, - {"name":"fontclock.hourscriber.js","url":"fontclock.hourscriber.js"}, - {"name":"fontclock.font.js","url":"fontclock.font.js"}, - {"name":"fontclock.font.abril_ff50.js","url":"fontclock.font.abril_ff50.js"}, - {"name":"fontclock.font.cpstc58.js","url":"fontclock.font.cpstc58.js"}, - {"name":"fontclock.font.mntn25.js","url":"fontclock.font.mntn25.js"}, - {"name":"fontclock.font.mntn50.js","url":"fontclock.font.mntn50.js"}, - {"name":"fontclock.font.vector25.js","url":"fontclock.font.vector25.js"}, - {"name":"fontclock.font.vector50.js","url":"fontclock.font.vector50.js"} - ] - }, - { - "id": "slidingtext", - "name": "Sliding Clock", - "version": "0.07", - "description": "Inspired by the Pebble sliding clock, old times are scrolled off the screen and new times on. You are also able to change language on the fly so you can see the time written in other languages using button 1. Currently English, French, Japanese, Spanish and German are supported", - "icon": "slidingtext.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "custom": "custom.html", - "allow_emulator": false, - "storage": [ - {"name":"slidingtext.app.js","url":"slidingtext.js"}, - {"name":"slidingtext.img","url":"slidingtext-icon.js","evaluate":true}, - {"name":"slidingtext.locale.en.js","url":"slidingtext.locale.en.js"}, - {"name":"slidingtext.locale.en2.js","url":"slidingtext.locale.en2.js"}, - {"name":"slidingtext.utils.en.js","url":"slidingtext.utils.en.js"}, - {"name":"slidingtext.locale.es.js","url":"slidingtext.locale.es.js"}, - {"name":"slidingtext.locale.fr.js","url":"slidingtext.locale.fr.js"}, - {"name":"slidingtext.locale.jp.js","url":"slidingtext.locale.jp.js"}, - {"name":"slidingtext.locale.de.js","url":"slidingtext.locale.de.js"}, - {"name":"slidingtext.dtfmt.js","url":"slidingtext.dtfmt.js"} - ] - }, - { - "id": "solarclock", - "name": "Solar Clock", - "version": "0.02", - "description": "Using your current or chosen location the solar watch face shows the Sun's sky position, time and date. Also allows you to wind backwards and forwards in time to see the sun's position", - "icon": "solar_clock.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "readme": "README.md", - "custom": "custom.html", - "allow_emulator": false, - "storage": [ - {"name":"solarclock.app.js","url":"solar_clock.js"}, - {"name":"solarclock.img","url":"solar_clock-icon.js","evaluate":true}, - {"name":"solar_colors.js","url":"solar_colors.js"}, - {"name":"solar_controller.js","url":"solar_controller.js"}, - {"name":"solar_date_utils.js","url":"solar_date_utils.js"}, - {"name":"solar_graphic_utils.js","url":"solar_graphic_utils.js"}, - {"name":"solar_location.js","url":"solar_location.js"}, - {"name":"solar_math_utils.js","url":"solar_math_utils.js"}, - {"name":"solar_loc.Reykjavik.json","url":"solar_loc.Reykjavik.json"}, - {"name":"solar_loc.Hong_Kong.json","url":"solar_loc.Hong_Kong.json"}, - {"name":"solar_loc.Honolulu.json","url":"solar_loc.Honolulu.json"}, - {"name":"solar_loc.Rio.json","url":"solar_loc.Rio.json"}, - {"name":"solar_loc.Tokyo.json","url":"solar_loc.Tokyo.json"}, - {"name":"solar_loc.Seoul.json","url":"solar_loc.Seoul.json"} - ] - }, - { - "id": "sweepclock", - "name": "Sweep Clock", - "version": "0.04", - "description": "Smooth sweep secondhand with single hour numeral. Use button 1 to toggle the numeral font, button 3 to change the colour theme and button 4 to change the date placement", - "icon": "sweepclock.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "readme": "README.md", - "allow_emulator": true, - "screenshots": [{"url":"bangle1-sweep-clock-screenshot.png"}], - "storage": [ - {"name":"sweepclock.app.js","url":"sweepclock.js"}, - {"name":"sweepclock.img","url":"sweepclock-icon.js","evaluate":true} - ] - }, - { - "id": "matrixclock", - "name": "Matrix Clock", - "version": "0.02", - "description": "inspired by The Matrix, a clock of the same style", - "icon": "matrixclock.png", - "screenshots": [{"url":"screenshot_matrix.png"}], - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "allow_emulator": true, - "storage": [ - {"name":"matrixclock.app.js","url":"matrixclock.js"}, - {"name":"matrixclock.img","url":"matrixclock-icon.js","evaluate":true} - ] - }, - { - "id": "mandelbrotclock", - "name": "Mandelbrot Clock", - "version": "0.01", - "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": "mandelbrotclock.app.js", "url": "mandelbrotclock.js" }, - { - "name": "mandelbrotclock.img", - "url": "mandelbrotclock-icon.js", - "evaluate": true - } - ] - }, - { - "id": "imgclock", - "name": "Image background clock", - "shortName": "Image Clock", - "version": "0.08", - "description": "A clock with an image as a background", - "icon": "app.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "custom": "custom.html", - "storage": [ - {"name":"imgclock.app.js","url":"app.js"}, - {"name":"imgclock.img","url":"app-icon.js","evaluate":true}, - {"name":"imgclock.face.img"}, - {"name":"imgclock.face.json"}, - {"name":"imgclock.face.bg","content":""} - ] - }, - { - "id": "impwclock", - "name": "Imprecise Word Clock", - "version": "0.04", - "description": "Imprecise word clock for vacations, weekends, and those who never need accurate time.", - "icon": "clock-impword.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "screenshots": [{"url":"bangle1-impercise-word-clock-screenshot.png"}], - "allow_emulator": true, - "storage": [ - {"name":"impwclock.app.js","url":"clock-impword.js"}, - {"name":"impwclock.img","url":"clock-impword-icon.js","evaluate":true} - ] - }, - { - "id": "aclock", - "name": "Analog Clock", - "version": "0.15", - "description": "An Analog Clock", - "icon": "clock-analog.png", - "screenshots": [{"url":"screenshot_analog.png"}], - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "allow_emulator": true, - "storage": [ - {"name":"aclock.app.js","url":"clock-analog.js"}, - {"name":"aclock.img","url":"clock-analog-icon.js","evaluate":true} - ] - }, - { - "id": "clock2x3", - "name": "2x3 Pixel Clock", - "version": "0.05", - "description": "This is a simple clock using minimalist 2x3 pixel numerical digits", - "icon": "clock2x3.png", - "screenshots": [{"url":"screenshot_pixel.png"}], - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "allow_emulator": true, - "storage": [ - {"name":"clock2x3.app.js","url":"clock2x3-app.js"}, - {"name":"clock2x3.img","url":"clock2x3-icon.js","evaluate":true} - ] - }, - { - "id": "geissclk", - "name": "Geiss Clock", - "version": "0.03", - "description": "7 segment clock with animated background in the style of Ryan Geiss' music visualisation. NOTE: The first run will take ~1 minute to do some precalculation", - "icon": "clock.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"geissclk.app.js","url":"clock.js"}, - {"name":"geissclk.precompute.js","url":"precompute.js"}, - {"name":"geissclk.img","url":"clock-icon.js","evaluate":true} - ], - "data": [{"name":"geissclk.0.map"},{"name":"geissclk.1.map"},{"name":"geissclk.2.map"},{"name":"geissclk.3.map"},{"name":"geissclk.4.map"},{"name":"geissclk.5.map"},{"name":"geissclk.0.pal"},{"name":"geissclk.1.pal"},{"name":"geissclk.2.pal"}] - }, - { - "id": "trex", - "name": "T-Rex", - "version": "0.04", - "description": "T-Rex game in the style of Chrome's offline game", - "icon": "trex.png", - "screenshots": [{"url":"screenshot_trex.png"}], - "tags": "game", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "allow_emulator": true, - "storage": [ - {"name":"trex.app.js","url":"trex.js"}, - {"name":"trex.img","url":"trex-icon.js","evaluate":true}, - {"name":"trex.settings.js","url":"settings.js"} - ], - "data": [{"name":"trex.score","storageFile":true}] - }, - { - "id": "cubescramble", - "name": "Cube Scramble", - "version":"0.04", - "description": "A random scramble generator for the 3x3 Rubik's cube with a basic timer", - "icon": "cube-scramble.png", - "tags": "", - "supports" : ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "allow_emulator": true, - "screenshots": [{"url":"bangle2-cube-scramble-screenshot.png"},{"url":"bangle1-cube-scramble-screenshot.png"}], - "storage": [ - {"name":"cubescramble.app.js","url":"cube-scramble.js"}, - {"name":"cubescramble.img","url":"cube-scramble-icon.js","evaluate":true} - ] - }, - { - "id": "astroid", - "name": "Asteroids!", - "version": "0.03", - "description": "Retro asteroids game", - "icon": "asteroids.png", - "screenshots": [{"url":"screenshot_asteroids.png"}], - "tags": "game", - "supports": ["BANGLEJS","BANGLEJS2"], - "allow_emulator": true, - "storage": [ - {"name":"astroid.app.js","url":"asteroids.js"}, - {"name":"astroid.img","url":"asteroids-icon.js","evaluate":true} - ] - }, - { - "id": "clickms", - "name": "Click Master", - "version": "0.01", - "description": "Get several friends to start the game, then compete to see who can press BTN1 the most!", - "icon": "click-master.png", - "tags": "game", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"clickms.app.js","url":"click-master.js"}, - {"name":"clickms.img","url":"click-master-icon.js","evaluate":true} - ] - }, - { - "id": "horsey", - "name": "Horse Race!", - "version": "0.01", - "description": "Get several friends to start the game, then compete to see who can press BTN1 the most!", - "icon": "horse-race.png", - "tags": "game", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"horsey.app.js","url":"horse-race.js"}, - {"name":"horsey.img","url":"horse-race-icon.js","evaluate":true} - ] - }, - { - "id": "compass", - "name": "Compass", - "version": "0.05", - "description": "Simple compass that points North", - "icon": "compass.png", - "screenshots": [{"url":"screenshot_compass.png"}], - "tags": "tool,outdoors", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"compass.app.js","url":"compass.js"}, - {"name":"compass.img","url":"compass-icon.js","evaluate":true} - ] - }, - { - "id": "gpstime", - "name": "GPS Time", - "version": "0.05", - "description": "Update the Bangle.js's clock based on the time from the GPS receiver", - "icon": "gpstime.png", - "tags": "tool,gps", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"gpstime.app.js","url":"gpstime.js"}, - {"name":"gpstime.img","url":"gpstime-icon.js","evaluate":true} - ] - }, - { - "id": "openloc", - "name": "Open Location / Plus Codes", - "shortName": "Open Location", - "version": "0.01", - "description": "Convert your current GPS location to a series of characters", - "icon": "app.png", - "tags": "tool,outdoors,gps", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"openloc.app.js","url":"app.js"}, - {"name":"openloc.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "speedo", - "name": "Speedo", - "version": "0.05", - "description": "Show the current speed according to the GPS", - "icon": "speedo.png", - "tags": "tool,outdoors,gps", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"speedo.app.js","url":"speedo.js"}, - {"name":"speedo.img","url":"speedo-icon.js","evaluate":true} - ] - }, - { - "id": "gpsrec", - "name": "GPS Recorder", - "version": "0.27", - "description": "Application that allows you to record a GPS track. Can run in background", - "icon": "app.png", - "tags": "tool,outdoors,gps,widget", - "screenshots": [{"url":"screenshot.png"}], - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "interface": "interface.html", - "storage": [ - {"name":"gpsrec.app.js","url":"app.js"}, - {"name":"gpsrec.img","url":"app-icon.js","evaluate":true}, - {"name":"gpsrec.wid.js","url":"widget.js"}, - {"name":"gpsrec.settings.js","url":"settings.js"} - ], - "data": [{"name":"gpsrec.json"},{"wildcard":".gpsrc?","storageFile":true}] - }, - { - "id": "recorder", - "name": "Recorder (BETA)", - "shortName": "Recorder", - "version": "0.05", - "description": "Record GPS position, heart rate and more in the background, then download to your PC.", - "icon": "app.png", - "tags": "tool,outdoors,gps,widget", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "interface": "interface.html", - "storage": [ - {"name":"recorder.app.js","url":"app.js"}, - {"name":"recorder.img","url":"app-icon.js","evaluate":true}, - {"name":"recorder.wid.js","url":"widget.js"}, - {"name":"recorder.settings.js","url":"settings.js"} - ], - "data": [{"name":"recorder.json"},{"wildcard":"recorder.log?.csv","storageFile":true}] - }, - { - "id": "gpsnav", - "name": "GPS Navigation", - "version": "0.05", - "description": "Displays GPS Course and Speed, + Directions to waypoint and waypoint recording, now with waypoint editor", - "icon": "icon.png", - "tags": "tool,outdoors,gps", - "supports": ["BANGLEJS"], - "readme": "README.md", - "interface": "waypoints.html", - "storage": [ - {"name":"gpsnav.app.js","url":"app.min.js"}, - {"name":"gpsnav.img","url":"app-icon.js","evaluate":true} - ], - "data": [{"name":"waypoints.json","url":"waypoints.json"}] - }, - { - "id": "heart", - "name": "Heart Rate Recorder", - "shortName": "HRM Record", - "version": "0.07", - "description": "Application that allows you to record your heart rate. Can run in background", - "icon": "app.png", - "tags": "tool,health,widget", - "supports": ["BANGLEJS","BANGLEJS2"], - "interface": "interface.html", - "storage": [ - {"name":"heart.app.js","url":"app.js"}, - {"name":"heart.img","url":"app-icon.js","evaluate":true}, - {"name":"heart.wid.js","url":"widget.js"} - ], - "data": [{"name":"heart.json"},{"wildcard":".heart?","storageFile":true}] - }, - { - "id": "slevel", - "name": "Spirit Level", - "version": "0.02", - "description": "Show the current angle of the watch, so you can use it to make sure something is absolutely flat", - "icon": "spiritlevel.png", - "tags": "tool", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"slevel.app.js","url":"spiritlevel.js"}, - {"name":"slevel.img","url":"spiritlevel-icon.js","evaluate":true} - ] - }, - { - "id": "files", - "name": "App Manager", - "version": "0.07", - "description": "Show currently installed apps, free space, and allow their deletion from the watch", - "icon": "files.png", - "tags": "tool,system,files", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"files.app.js","url":"files.js"}, - {"name":"files.img","url":"files-icon.js","evaluate":true} - ] - }, - { - "id": "weather", - "name": "Weather", - "version": "0.15", - "description": "Show Gadgetbridge weather report", - "icon": "icon.png", - "screenshots": [{"url":"screenshot.png"}], - "tags": "widget,outdoors", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "readme.md", - "storage": [ - {"name":"weather.app.js","url":"app.js"}, - {"name":"weather.wid.js","url":"widget.js"}, - {"name":"weather","url":"lib.js"}, - {"name":"weather.img","url":"icon.js","evaluate":true}, - {"name":"weather.settings.js","url":"settings.js"} - ], - "data": [{"name":"weather.json"}] - }, - { - "id": "chargeanim", - "name": "Charge Animation", - "version": "0.02", - "description": "When charging, show a sideways charging animation and keep the screen on. When removed from the charger load the clock again.", - "icon": "icon.png", - "tags": "battery", - "supports": ["BANGLEJS", "BANGLEJS2"], - "allow_emulator": true, - "screenshots": [{"url":"bangle2-charge-animation-screenshot.png"},{"url":"bangle-charge-animation-screenshot.png"}], - "storage": [ - {"name":"chargeanim.app.js","url":"app.js"}, - {"name":"chargeanim.boot.js","url":"boot.js"}, - {"name":"chargeanim.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "bluetoothdock", - "name": "Bluetooth Dock", - "shortName": "Dock", - "version": "0.01", - "description": "When charging shows the time, scans Bluetooth for known devices (eg temperature) and shows them on the screen", - "icon": "app.png", - "tags": "bluetooth", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"bluetoothdock.app.js","url":"app.js"}, - {"name":"bluetoothdock.boot.js","url":"boot.js"}, - {"name":"bluetoothdock.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "widbat", - "name": "Battery Level Widget", - "version": "0.09", - "description": "Show the current battery level and charging status in the top right of the clock", - "icon": "widget.png", - "type": "widget", - "tags": "widget,battery", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"widbat.wid.js","url":"widget.js"} - ] - }, - { - "id": "widbatv", - "name": "Battery Level Widget (Vertical)", - "version": "0.01", - "description": "Slim, vertical battery widget that only takes up 14px", - "icon": "widget.png", - "type": "widget", - "tags": "widget,battery", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"widbatv.wid.js","url":"widget.js"} - ] - }, - { - "id": "widlock", - "name": "Lock Widget", - "version": "0.03", - "description": "On devices with always-on display (Bangle.js 2) this displays lock icon whenever the display is locked", - "icon": "widget.png", - "type": "widget", - "tags": "widget,lock", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"widlock.wid.js","url":"widget.js"} - ] - }, - { - "id": "widbatpc", - "name": "Battery Level Widget (with percentage)", - "shortName": "Battery Widget", - "version": "0.15", - "description": "Show the current battery level and charging status in the top right of the clock, with charge percentage", - "icon": "widget.png", - "type": "widget", - "tags": "widget,battery", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "storage": [ - {"name":"widbatpc.wid.js","url":"widget.js"}, - {"name":"widbatpc.settings.js","url":"settings.js"} - ], - "data": [{"name":"widbatpc.json"}] - }, - { - "id": "widbatwarn", - "name": "Battery Warning", - "shortName": "Battery Warning", - "version": "0.02", - "description": "Show a warning when the battery runs low.", - "icon": "widget.png", - "screenshots": [{"url":"screenshot.png"}], - "type": "widget", - "tags": "tool,battery", - "supports": ["BANGLEJS"], - "dependencies": {"notify":"type"}, - "readme": "README.md", - "storage": [ - {"name":"widbatwarn.wid.js","url":"widget.js"}, - {"name":"widbatwarn.settings.js","url":"settings.js"} - ], - "data": [{"name":"widbatwarn.json"}] - }, - { - "id": "widbt", - "name": "Bluetooth Widget", - "version": "0.08", - "description": "Show the current Bluetooth connection status in the top right of the clock", - "icon": "widget.png", - "type": "widget", - "tags": "widget,bluetooth", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"widbt.wid.js","url":"widget.js"} - ] - }, - { - "id": "widchime", - "name": "Hour Chime", - "version": "0.02", - "description": "Buzz or beep on every whole hour.", - "icon": "widget.png", - "type": "widget", - "tags": "widget", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"widchime.wid.js","url":"widget.js"}, - {"name":"widchime.settings.js","url":"settings.js"} - ], - "data": [{"name":"widchime.json"}] - }, - { - "id": "widram", - "name": "RAM Widget", - "shortName": "RAM Widget", - "version": "0.01", - "description": "Display your Bangle's available RAM percentage in a widget", - "icon": "widget.png", - "type": "widget", - "tags": "widget", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"widram.wid.js","url":"widget.js"} - ] - }, - { - "id": "hrm", - "name": "Heart Rate Monitor", - "version": "0.06", - "description": "Measure your heart rate and see live sensor data", - "icon": "heartrate.png", - "tags": "health", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"hrm.app.js","url":"heartrate.js"}, - {"name":"hrm.img","url":"heartrate-icon.js","evaluate":true} - ] - }, - { - "id": "widhrm", - "name": "Simple Heart Rate widget", - "version": "0.05", - "description": "When the screen is on, the widget turns on the heart rate monitor and displays the current heart rate (or last known in grey). For this to work well you'll need at least a 15 second LCD Timeout.", - "icon": "widget.png", - "type": "widget", - "tags": "health,widget", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"widhrm.wid.js","url":"widget.js"} - ] - }, - { - "id": "bthrm", - "name": "Bluetooth Heart Rate Monitor", - "shortName": "BT HRM", - "version": "0.01", - "description": "Overrides Bangle.js's build in heart rate monitor with an external Bluetooth one.", - "icon": "app.png", - "type": "boot", - "tags": "health,bluetooth", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "storage": [ - {"name":"bthrm.boot.js","url":"boot.js"}, - {"name":"bthrm.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "stetho", - "name": "Stethoscope", - "version": "0.01", - "description": "Hear your heart rate", - "icon": "stetho.png", - "tags": "health", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"stetho.app.js","url":"stetho.js"}, - {"name":"stetho.img","url":"stetho-icon.js","evaluate":true} - ] - }, - { - "id": "swatch", - "name": "Stopwatch", - "version": "0.07", - "description": "Simple stopwatch with Lap Time logging to a JSON file", - "icon": "stopwatch.png", - "tags": "health", - "supports": ["BANGLEJS"], - "readme": "README.md", - "interface": "interface.html", - "allow_emulator": true, - "screenshots": [{"url":"bangle1-stopwatch-screenshot.png"}], - "storage": [ - {"name":"swatch.app.js","url":"stopwatch.js"}, - {"name":"swatch.img","url":"stopwatch-icon.js","evaluate":true} - ] - }, - { - "id": "hidmsic", - "name": "Bluetooth Music Controls", - "shortName": "Music Control", - "version": "0.02", - "description": "Enable HID in settings, pair with your phone, then use this app to control music from your watch!", - "icon": "hid-music.png", - "tags": "bluetooth", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"hidmsic.app.js","url":"hid-music.js"}, - {"name":"hidmsic.img","url":"hid-music-icon.js","evaluate":true} - ] - }, - { - "id": "hidkbd", - "name": "Bluetooth Keyboard", - "shortName": "Bluetooth Kbd", - "version": "0.02", - "description": "Enable HID in settings, pair with your phone/PC, then use this app to control other apps", - "icon": "hid-keyboard.png", - "tags": "bluetooth", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"hidkbd.app.js","url":"hid-keyboard.js"}, - {"name":"hidkbd.img","url":"hid-keyboard-icon.js","evaluate":true} - ] - }, - { - "id": "hidbkbd", - "name": "Binary Bluetooth Keyboard", - "shortName": "Binary BT Kbd", - "version": "0.02", - "description": "Enable HID in settings, pair with your phone/PC, then type messages using the onscreen keyboard by tapping repeatedly on the key you want", - "icon": "hid-binary-keyboard.png", - "tags": "bluetooth", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"hidbkbd.app.js","url":"hid-binary-keyboard.js"}, - {"name":"hidbkbd.img","url":"hid-binary-keyboard-icon.js","evaluate":true} - ] - }, - { - "id": "animals", - "name": "Animals Game", - "version": "0.01", - "description": "Simple toddler's game - displays a different number of animals each time the screen is pressed", - "icon": "animals.png", - "tags": "game", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"animals.app.js","url":"animals.js"}, - {"name":"animals.img","url":"animals-icon.js","evaluate":true}, - {"name":"animals-snake.img","url":"animals-snake.js","evaluate":true}, - {"name":"animals-duck.img","url":"animals-duck.js","evaluate":true}, - {"name":"animals-swan.img","url":"animals-swan.js","evaluate":true}, - {"name":"animals-fox.img","url":"animals-fox.js","evaluate":true}, - {"name":"animals-camel.img","url":"animals-camel.js","evaluate":true}, - {"name":"animals-pig.img","url":"animals-pig.js","evaluate":true}, - {"name":"animals-sheep.img","url":"animals-sheep.js","evaluate":true}, - {"name":"animals-mouse.img","url":"animals-mouse.js","evaluate":true} - ] - }, - { - "id": "qrcode", - "name": "Custom QR Code", - "version": "0.05", - "description": "Use this to upload a customised QR code to Bangle.js", - "icon": "app.png", - "tags": "qrcode", - "supports": ["BANGLEJS","BANGLEJS2"], - "custom": "custom.html", - "customConnect": true, - "storage": [ - {"name":"qrcode.app.js"}, - {"name":"qrcode.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "beer", - "name": "Beer Compass", - "version": "0.01", - "description": "Uploads all the pubs in an area onto your watch, so it can always point you at the nearest one", - "icon": "app.png", - "tags": "", - "supports": ["BANGLEJS"], - "custom": "custom.html", - "storage": [ - {"name":"beer.app.js"}, - {"name":"beer.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "route", - "name": "Route Viewer", - "version": "0.02", - "description": "Upload a KML file of a route, and have your watch display a map with how far around it you are", - "icon": "app.png", - "tags": "", - "supports": ["BANGLEJS"], - "custom": "custom.html", - "storage": [ - {"name":"route.app.js"}, - {"name":"route.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "ncstart", - "name": "NCEU Startup", - "version": "0.06", - "description": "NodeConfEU 2019 'First Start' Sequence", - "icon": "start.png", - "tags": "start,welcome", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"ncstart.app.js","url":"start.js"}, - {"name":"ncstart.boot.js","url":"boot.js"}, - {"name":"ncstart.settings.js","url":"settings.js"}, - {"name":"ncstart.img","url":"start-icon.js","evaluate":true}, - {"name":"nc-bangle.img","url":"start-bangle.js","evaluate":true}, - {"name":"nc-nceu.img","url":"start-nceu.js","evaluate":true}, - {"name":"nc-nfr.img","url":"start-nfr.js","evaluate":true}, - {"name":"nc-nodew.img","url":"start-nodew.js","evaluate":true}, - {"name":"nc-tf.img","url":"start-tf.js","evaluate":true} - ], - "data": [{"name":"ncstart.json"}] - }, - { - "id": "ncfrun", - "name": "NCEU 5K Fun Run", - "version": "0.01", - "description": "Display a map of the NodeConf EU 2019 5K Fun Run route and your location on it", - "icon": "nceu-funrun.png", - "tags": "health", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"ncfrun.app.js","url":"nceu-funrun.js"}, - {"name":"ncfrun.img","url":"nceu-funrun-icon.js","evaluate":true} - ] - }, - { - "id": "widnceu", - "name": "NCEU Logo Widget", - "version": "0.02", - "description": "Show the NodeConf EU logo in the top left", - "icon": "widget.png", - "type": "widget", - "tags": "widget", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"widnceu.wid.js","url":"widget.js"} - ] - }, - { - "id": "sclock", - "name": "Simple Clock", - "version": "0.07", - "description": "A Simple Digital Clock", - "icon": "clock-simple.png", - "screenshots": [{"url":"screenshot_simplec.png"}], - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "allow_emulator": true, - "storage": [ - {"name":"sclock.app.js","url":"clock-simple.js"}, - {"name":"sclock.img","url":"clock-simple-icon.js","evaluate":true} - ] - }, - { - "id": "s7clk", - "name": "Simple 7 segment Clock", - "version": "0.03", - "description": "A simple 7 segment Clock with date", - "icon": "icon.png", - "screenshots": [{"url":"screenshot_s7segment.png"}], - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "allow_emulator": true, - "storage": [ - {"name":"s7clk.app.js","url":"app.js"}, - {"name":"s7clk.img","url":"icon.js","evaluate":true} - ] - }, - { - "id": "vibrclock", - "name": "Vibrate Clock", - "version": "0.03", - "description": "When BTN1 is pressed, vibrate out the time as a series of buzzes, one digit at a time. Hours, then Minutes. Zero is signified by one long buzz. Otherwise a simple digital clock.", - "icon": "app.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "allow_emulator": true, - "screenshots": [{"url":"bangle1-vibrate-clock-screenshot.png"}], - "storage": [ - {"name":"vibrclock.app.js","url":"app.js"}, - {"name":"vibrclock.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "svclock", - "name": "Simple V-Clock", - "version": "0.04", - "description": "Modification of Simple Clock 0.04 to use Vectorfont", - "icon": "vclock-simple.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "allow_emulator": true, - "screenshots": [{"url":"bangle2-simple-v-clock-screenshot.png"}], - "storage": [ - {"name":"svclock.app.js","url":"vclock-simple.js"}, - {"name":"svclock.img","url":"vclock-simple-icon.js","evaluate":true} - ] - }, - { - "id": "dclock", - "name": "Dev Clock", - "version": "0.10", - "description": "A Digital Clock including timestamp (tst), beats(@), days in current month (dm) and days since new moon (l)", - "icon": "clock-dev.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "allow_emulator": true, - "screenshots": [{"url":"bangle2-dev-clock-screenshot.png"},{"url":"bangle1-dev-clock-screenshot.png"}], - "storage": [ - {"name":"dclock.app.js","url":"clock-dev.js"}, - {"name":"dclock.img","url":"clock-dev-icon.js","evaluate":true} - ] - }, - { - "id": "gesture", - "name": "Gesture Test", - "version": "0.01", - "description": "BETA! Uploads a basic Tensorflow Gesture model, and then outputs each gesture as a message", - "icon": "gesture.png", - "type": "app", - "tags": "gesture,ai", - "supports": ["BANGLEJS", "BANGLEJS2"], - "storage": [ - {"name":"gesture.app.js","url":"gesture.js"}, - {"name":".tfnames","url":"gesture-tfnames.js","evaluate":true}, - {"name":".tfmodel","url":"gesture-tfmodel.js","evaluate":true}, - {"name":"gesture.img","url":"gesture-icon.js","evaluate":true} - ] - }, - { - "id": "pparrot", - "name": "Party Parrot", - "version": "0.01", - "description": "Party with a parrot on your wrist", - "icon": "party-parrot.png", - "type": "app", - "tags": "party,parrot,lol", - "supports": ["BANGLEJS"], - "allow_emulator": true, - "screenshots": [{"url":"bangle1-party-parrot-screenshot.png"}], - "storage": [ - {"name":"pparrot.app.js","url":"party-parrot.js"}, - {"name":"pparrot.img","url":"party-parrot-icon.js","evaluate":true} - ] - }, - { - "id": "hrings", - "name": "Hypno Rings", - "version": "0.01", - "description": "Experiment with trippy rings, press buttons for change", - "icon": "hypno-rings.png", - "type": "app", - "tags": "rings,hypnosis,psychadelic", - "supports": ["BANGLEJS"], - "allow_emulator": true, - "screenshots": [{"url":"bangle1-hypno-rings-screenshot.png"}], - "storage": [ - {"name":"hrings.app.js","url":"hypno-rings.js"}, - {"name":"hrings.img","url":"hypno-rings-icon.js","evaluate":true} - ] - }, - { - "id": "morse", - "name": "Morse Code", - "version": "0.01", - "description": "Learn morse code by hearing/seeing/feeling the code. Tap to toggle buzz!", - "icon": "morse-code.png", - "type": "app", - "tags": "morse,sound,visual,input", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"morse.app.js","url":"morse-code.js"}, - {"name":"morse.img","url":"morse-code-icon.js","evaluate":true} - ] - }, - { - "id": "blescan", - "name": "BLE Scanner", - "version": "0.01", - "description": "Scan for advertising BLE devices", - "icon": "blescan.png", - "tags": "bluetooth", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"blescan.app.js","url":"blescan.js"}, - {"name":"blescan.img","url":"blescan-icon.js","evaluate":true} - ] - }, - { - "id": "mmonday", - "name": "Manic Monday Tone", - "version": "0.02", - "description": "The Bangles make a comeback", - "icon": "manic-monday-icon.png", - "tags": "sound", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"mmonday.app.js","url":"manic-monday.js"}, - {"name":"mmonday.img","url":"manic-monday-icon.js","evaluate":true} - ] - }, - { - "id": "jbells", - "name": "Jingle Bells", - "version": "0.01", - "description": "Play Jingle Bells", - "icon": "jbells.png", - "type": "app", - "tags": "sound", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"jbells.app.js","url":"jbells.js"}, - {"name":"jbells.img","url":"jbells-icon.js","evaluate":true} - ] - }, - { - "id": "scolor", - "name": "Show Color", - "version": "0.01", - "description": "Display all available Colors and Names", - "icon": "show-color.png", - "type": "app", - "tags": "tool", - "screenshots": [{"url":"bangle1-view-color-screenshot.png"}], - "supports": ["BANGLEJS"], - "allow_emulator": true, - "storage": [ - {"name":"scolor.app.js","url":"show-color.js"}, - {"name":"scolor.img","url":"show-color-icon.js","evaluate":true} - ] - }, - { - "id": "miclock", - "name": "Mixed Clock", - "version": "0.05", - "description": "A mix of analog and digital Clock", - "icon": "clock-mixed.png", - "type": "clock", - "tags": "clock", - "screenshots": [{"url":"bangle1-mixed-clock-screenshot.png"}], - "supports": ["BANGLEJS"], - "allow_emulator": true, - "storage": [ - {"name":"miclock.app.js","url":"clock-mixed.js"}, - {"name":"miclock.img","url":"clock-mixed-icon.js","evaluate":true} - ] - }, - { - "id": "bclock", - "name": "Binary Clock", - "version": "0.03", - "description": "A simple binary clock watch face", - "icon": "clock-binary.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "allow_emulator": true, - "screenshots": [{"url":"bangle1-binary-clock-screenshot.png"}], - "storage": [ - {"name":"bclock.app.js","url":"clock-binary.js"}, - {"name":"bclock.img","url":"clock-binary-icon.js","evaluate":true} - ] - }, - { - "id": "clotris", - "name": "Clock-Tris", - "version": "0.01", - "description": "A fully functional clone of a classic game of falling blocks", - "icon": "clock-tris.png", - "tags": "game", - "supports": ["BANGLEJS"], - "screenshots": [{"url":"bangle1-clock-tris-screenshot.png"}], - "allow_emulator": true, - "storage": [ - {"name":"clotris.app.js","url":"clock-tris.js"}, - {"name":"clotris.img","url":"clock-tris-icon.js","evaluate":true}, - {"name":".trishig","url":"clock-tris-high"} - ] - }, - { - "id": "flappy", - "name": "Flappy Bird", - "version": "0.05", - "description": "A Flappy Bird game clone", - "icon": "app.png", - "screenshots": [{"url":"screenshot1_flappy.png"},{"url":"screenshot2_flappy.png"}], - "tags": "game", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "allow_emulator": true, - "storage": [ - {"name":"flappy.app.js","url":"app.js"}, - {"name":"flappy.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "gpsinfo", - "name": "GPS Info", - "version": "0.06", - "description": "An application that displays information about altitude, lat/lon, satellites and time", - "icon": "gps-info.png", - "type": "app", - "tags": "gps", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"gpsinfo.app.js","url":"gps-info.js"}, - {"name":"gpsinfo.img","url":"gps-info-icon.js","evaluate":true} - ] - }, - { - "id": "assistedgps", - "name": "Assisted GPS Update (AGPS)", - "version": "0.01", - "description": "Downloads assisted GPS (AGPS) data to Bangle.js 1 for faster GPS startup and more accurate fixes. **No app will be installed**, this just uploads new data to the GPS chip.", - "icon": "app.png", - "type": "RAM", - "tags": "tool,outdoors,agps", - "supports": ["BANGLEJS"], - "custom": "custom.html", - "storage": [] - }, - { - "id": "pomodo", - "name": "Pomodoro", - "version": "0.02", - "description": "A simple pomodoro timer.", - "icon": "pomodoro.png", - "type": "app", - "tags": "pomodoro,cooking,tools", - "supports": ["BANGLEJS", "BANGLEJS2"], - "allow_emulator": true, - "screenshots": [{"url":"bangle2-pomodoro-screenshot.png"}], - "storage": [ - {"name":"pomodo.app.js","url":"pomodoro.js"}, - {"name":"pomodo.img","url":"pomodoro-icon.js","evaluate":true} - ] - }, - { - "id": "blobclk", - "name": "Large Digit Blob Clock", - "shortName": "Blob Clock", - "version": "0.06", - "description": "A clock with big digits", - "icon": "clock-blob.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "allow_emulator": true, - "screenshots": [{"url":"bangle2-large-digit-blob-clock-screenshot.png"},{"url":"bangle1-large-digit-blob-clock-screenshot.png"}], - "storage": [ - {"name":"blobclk.app.js","url":"clock-blob.js"}, - {"name":"blobclk.img","url":"clock-blob-icon.js","evaluate":true} - ] - }, - { - "id": "boldclk", - "name": "Bold Clock", - "version": "0.05", - "description": "Simple, readable and practical clock", - "icon": "bold_clock.png", - "screenshots": [{"url":"screenshot_bold.png"}], - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "allow_emulator": true, - "storage": [ - {"name":"boldclk.app.js","url":"bold_clock.js"}, - {"name":"boldclk.img","url":"bold_clock-icon.js","evaluate":true} - ] - }, - { - "id": "widclk", - "name": "Digital clock widget", - "version": "0.06", - "description": "A simple digital clock widget", - "icon": "widget.png", - "type": "widget", - "tags": "widget,clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"widclk.wid.js","url":"widget.js"} - ] - }, - { - "id": "widpedom", - "name": "Pedometer widget", - "version": "0.20", - "description": "Daily pedometer widget", - "icon": "widget.png", - "type": "widget", - "tags": "widget", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"widpedom.wid.js","url":"widget.js"}, - {"name":"widpedom.settings.js","url":"settings.js"} - ] - }, - { - "id": "berlinc", - "name": "Berlin Clock", - "version": "0.05", - "description": "Berlin Clock (see https://en.wikipedia.org/wiki/Mengenlehreuhr)", - "icon": "berlin-clock.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "allow_emulator": true, - "screenshots": [{"url":"berlin-clock-screenshot.png"}], - "storage": [ - {"name":"berlinc.app.js","url":"berlin-clock.js"}, - {"name":"berlinc.img","url":"berlin-clock-icon.js","evaluate":true} - ] - }, - { - "id": "ctrclk", - "name": "Centerclock", - "version": "0.03", - "description": "Watch-centered digital 24h clock with date in dd.mm.yyyy format.", - "icon": "app.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "screenshots": [{"url":"bangle1-center-clock-screenshot.png"}], - "allow_emulator": true, - "storage": [ - {"name":"ctrclk.app.js","url":"app.js"}, - {"name":"ctrclk.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "demoapp", - "name": "Demo Loop", - "version": "0.02", - "description": "Simple demo app - displays Bangle.js, JS logo, graphics, and Bangle.js information", - "icon": "app.png", - "type": "app", - "tags": "", - "screenshots": [{"url":"bangle1-demo-loop-screenshot1.png"},{"url":"bangle1-demo-loop-screenshot2.png"},{"url":"bangle1-demo-loop-screenshot3.png"},{"url":"bangle1-demo-loop-screenshot4.png"}], - "supports": ["BANGLEJS"], - "allow_emulator": true, - "storage": [ - {"name":"demoapp.app.js","url":"app.js"}, - {"name":"demoapp.img","url":"app-icon.js","evaluate":true} - ], - "sortorder": -9 - }, - { - "id": "flagrse", - "name": "Espruino Flag Raiser", - "version": "0.01", - "description": "App to send a command to another Espruino to cause it to raise a flag", - "icon": "app.png", - "tags": "", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"flagrse.app.js","url":"app.js"}, - {"name":"flagrse.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "pipboy", - "name": "Pipboy", - "version": "0.04", - "description": "Pipboy themed clock", - "icon": "app.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "allow_emulator": true, - "screenshots": [{"url":"bangle1-pipboy-themed-clock-screenshot.png"}], - "storage": [ - {"name":"pipboy.app.js","url":"app.js"}, - {"name":"pipboy.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "torch", - "name": "Torch", - "shortName": "Torch", - "version": "0.02", - "description": "Turns screen white to help you see in the dark. Select from the launcher or press BTN1,BTN3,BTN1,BTN3 quickly to start when in any app that shows widgets", - "icon": "app.png", - "tags": "tool,torch", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"torch.app.js","url":"app.js"}, - {"name":"torch.wid.js","url":"widget.js"}, - {"name":"torch.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "rtorch", - "name": "Red Torch", - "shortName": "RedTorch", - "version": "0.02", - "description": "Turns screen RED to help you see in the dark without breaking your night vision. Select from the launcher or on Bangle 1 press BTN3,BTN1,BTN3,BTN1 quickly to start when in any app that shows widgets", - "icon": "app.png", - "tags": "tool,torch", - "supports": ["BANGLEJS","BANGLEJS2"], - "allow_emulator": true, - "storage": [ - {"name":"rtorch.app.js","url":"app.js"}, - {"name":"rtorch.wid.js","url":"widget.js", "supports": ["BANGLEJS"]}, - {"name":"rtorch.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "wohrm", - "name": "Workout HRM", - "version": "0.08", - "description": "Workout heart rate monitor notifies you with a buzz if your heart rate goes above or below the set limits.", - "icon": "app.png", - "type": "app", - "tags": "hrm,workout", - "supports": ["BANGLEJS"], - "readme": "README.md", - "allow_emulator": true, - "screenshots": [{"url":"bangle1-workout-HRM-screenshot.png"}], - "storage": [ - {"name":"wohrm.app.js","url":"app.js"}, - {"name":"wohrm.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "widid", - "name": "Bluetooth ID Widget", - "version": "0.03", - "description": "Display the last two tuple of your Bangle.js MAC address in the widget section. This is useful for figuring out which Bangle.js to connect to if you have more than one Bangle.js!", - "icon": "widget.png", - "type": "widget", - "tags": "widget,address,mac", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"widid.wid.js","url":"widget.js"} - ] - }, - { - "id": "grocery", - "name": "Grocery", - "version": "0.02", - "description": "Simple grocery (shopping) list - Display a list of product and track if you already put them in your cart.", - "icon": "grocery.png", - "type": "app", - "tags": "tool,outdoors,shopping,list", - "supports": ["BANGLEJS", "BANGLEJS2"], - "custom": "grocery.html", - "allow_emulator": true, - "storage": [ - {"name":"grocery.app.js","url":"app.js"}, - {"name":"grocery.img","url":"grocery-icon.js","evaluate":true} - ] - }, - { - "id": "marioclock", - "name": "Mario Clock", - "version": "0.15", - "description": "Animated retro Mario clock, with Gameboy style 8-bit grey-scale graphics.", - "icon": "marioclock.png", - "type": "clock", - "tags": "clock,mario,retro", - "supports": ["BANGLEJS"], - "readme": "README.md", - "allow_emulator": false, - "screenshots": [{"url":"bangle1-mario-clock-screenshot.png"}], - "storage": [ - {"name":"marioclock.app.js","url":"marioclock-app.js"}, - {"name":"marioclock.img","url":"marioclock-icon.js","evaluate":true} - ] - }, - { - "id": "cliock", - "name": "Commandline-Clock", - "shortName": "CLI-Clock", - "version": "0.15", - "description": "Simple CLI-Styled Clock", - "icon": "app.png", - "screenshots": [{"url":"screenshot_cli.png"}], - "type": "clock", - "tags": "clock,cli,command,bash,shell", - "supports": ["BANGLEJS","BANGLEJS2"], - "allow_emulator": true, - "storage": [ - {"name":"cliock.app.js","url":"app.js"}, - {"name":"cliock.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "widver", - "name": "Firmware Version Widget", - "version": "0.03", - "description": "Display the version of the installed firmware in the top widget section.", - "icon": "widget.png", - "type": "widget", - "tags": "widget,tool,system", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"widver.wid.js","url":"widget.js"} - ] - }, - { - "id": "barclock", - "name": "Bar Clock", - "version": "0.09", - "description": "A simple digital clock showing seconds as a bar", - "icon": "clock-bar.png", - "screenshots": [{"url":"screenshot.png"},{"url":"screenshot_pm.png"}], - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "allow_emulator": true, - "storage": [ - {"name":"barclock.app.js","url":"clock-bar.js"}, - {"name":"barclock.img","url":"clock-bar-icon.js","evaluate":true} - ] - }, - { - "id": "dotclock", - "name": "Dot Clock", - "version": "0.03", - "description": "A Minimal Dot Analog Clock", - "icon": "clock-dot.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "allow_emulator": true, - "screenshots": [{"url":"bangle2-dot-clcok-screenshot.png"},{"url":"bangle1-dot-clock-screenshot.png"}], - "storage": [ - {"name":"dotclock.app.js","url":"clock-dot.js"}, - {"name":"dotclock.img","url":"clock-dot-icon.js","evaluate":true} - ] - }, - { - "id": "widtbat", - "name": "Tiny Battery Widget", - "version": "0.02", - "description": "Tiny blueish battery widget, vibs and changes level color when charging", - "icon": "widget.png", - "type": "widget", - "tags": "widget,tool,system", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"widtbat.wid.js","url":"widget.js"} - ] - }, - { - "id": "chrono", - "name": "Chrono", - "shortName": "Chrono", - "version": "0.01", - "description": "Single click BTN1 to add 5 minutes. Single click BTN2 to add 30 seconds. Single click BTN3 to add 5 seconds. Tap to pause or play to timer. Double click BTN1 to reset. When timer finishes the watch vibrates.", - "icon": "chrono.png", - "tags": "tool", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"chrono.app.js","url":"chrono.js"}, - {"name":"chrono.img","url":"chrono-icon.js","evaluate":true} - ] - }, - { - "id": "astrocalc", - "name": "Astrocalc", - "version": "0.02", - "description": "Calculates interesting information on the sun and moon cycles for the current day based on your location.", - "icon": "astrocalc.png", - "tags": "app,sun,moon,cycles,tool,outdoors", - "supports": ["BANGLEJS"], - "allow_emulator": true, - "storage": [ - {"name":"astrocalc.app.js","url":"astrocalc-app.js"}, - {"name":"suncalc.js","url":"suncalc.js"}, - {"name":"astrocalc.img","url":"astrocalc-icon.js","evaluate":true}, - {"name":"first-quarter.img","url":"first-quarter-icon.js","evaluate":true}, - {"name":"last-quarter.img","url":"last-quarter-icon.js","evaluate":true}, - {"name":"waning-crescent.img","url":"waning-crescent-icon.js","evaluate":true}, - {"name":"waning-gibbous.img","url":"waning-gibbous-icon.js","evaluate":true}, - {"name":"full.img","url":"full-icon.js","evaluate":true}, - {"name":"new.img","url":"new-icon.js","evaluate":true}, - {"name":"waxing-gibbous.img","url":"waxing-gibbous-icon.js","evaluate":true}, - {"name":"waxing-crescent.img","url":"waxing-crescent-icon.js","evaluate":true} - ] - }, - { - "id": "widhwt", - "name": "Hand Wash Timer", - "version": "0.01", - "description": "Swipe your wrist over the watch face to start your personal Bangle.js hand wash timer for 35 sec. Start washing after the short buzz and stop after the long buzz.", - "icon": "widget.png", - "type": "widget", - "tags": "widget,tool", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"widhwt.wid.js","url":"widget.js"} - ] - }, - { - "id": "toucher", - "name": "Touch Launcher", - "shortName": "Toucher", - "version": "0.07", - "description": "Touch enable left to right launcher.", - "icon": "app.png", - "type": "launch", - "tags": "tool,system,launcher", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "storage": [ - {"name":"toucher.app.js","url":"app.js"}, - {"name":"toucher.settings.js","url":"settings.js"} - ], - "data": [{"name":"toucher.json"}] - }, - { - "id": "balltastic", - "name": "Balltastic", - "version": "0.02", - "description": "Simple but fun ball eats dots game.", - "icon": "app.png", - "type": "app", - "tags": "game,fun", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"balltastic.app.js","url":"app.js"}, - {"name":"balltastic.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "rpgdice", - "name": "RPG dice", - "version": "0.02", - "description": "Simple RPG dice rolling app.", - "icon": "rpgdice.png", - "type": "app", - "tags": "game,fun", - "supports": ["BANGLEJS"], - "allow_emulator": true, - "screenshots": [{"url":"bangle1-rpg-dice-screenshot.png"}], - "storage": [ - {"name":"rpgdice.app.js","url":"app.js"}, - {"name":"rpgdice.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "widmp", - "name": "Moon Phase Widget", - "version": "0.02", - "description": "Display the current moon phase in blueish for the northern hemisphere in eight phases", - "icon": "widget.png", - "type": "widget", - "tags": "widget,tools", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"widmp.wid.js","url":"widget.js"} - ] - }, - { - "id": "widmpsh", - "name": "Moon Phase Widget Southern Hemisphere", - "version": "0.01", - "description": "Display the current moon phase in blueish for the southern hemisphere in eight phases", - "icon": "widget.png", - "type": "widget", - "tags": "widget,tools", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"widmpsh.wid.js","url":"widget.js"} - ] - }, - { - "id": "minionclk", - "name": "Minion clock", - "version": "0.05", - "description": "Minion themed clock.", - "icon": "minionclk.png", - "type": "clock", - "tags": "clock,minion", - "supports": ["BANGLEJS"], - "allow_emulator": true, - "screenshots": [{"url":"bangle1-minion-clock-screenshot.png"}], - "storage": [ - {"name":"minionclk.app.js","url":"app.js"}, - {"name":"minionclk.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "openstmap", - "name": "OpenStreetMap", - "shortName": "OpenStMap", - "version": "0.11", - "description": "Loads map tiles from OpenStreetMap onto your Bangle.js and displays a map of where you are. Once installed this also adds map functionality to `GPS Recorder` and `Recorder` apps", - "icon": "app.png", - "tags": "outdoors,gps,osm", - "supports": ["BANGLEJS","BANGLEJS2"], - "screenshots": [{"url":"screenshot.png"}], - "custom": "custom.html", - "customConnect": true, - "storage": [ - {"name":"openstmap","url":"openstmap.js"}, - {"name":"openstmap.app.js","url":"app.js"}, - {"name":"openstmap.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "activepedom", - "name": "Active Pedometer", - "shortName": "Active Pedometer", - "version": "0.09", - "description": "Pedometer that filters out arm movement and displays a step goal progress. Steps are saved to a daily file and can be viewed as graph.", - "icon": "app.png", - "tags": "outdoors,widget", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"activepedom.wid.js","url":"widget.js"}, - {"name":"activepedom.settings.js","url":"settings.js"}, - {"name":"activepedom.img","url":"app-icon.js","evaluate":true}, - {"name":"activepedom.app.js","url":"app.js"} - ] - }, - { - "id": "chronowid", - "name": "Chrono Widget", - "shortName": "Chrono Widget", - "version": "0.05", - "description": "Chronometer (timer) which runs as widget.", - "icon": "app.png", - "tags": "tool,widget", - "supports": ["BANGLEJS","BANGLEJS2"], - "screenshots": [{"url":"screenshot.png"}], - "readme": "README.md", - "storage": [ - {"name":"chronowid.wid.js","url":"widget.js"}, - {"name":"chronowid.app.js","url":"app.js"}, - {"name":"chronowid.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "tabata", - "name": "Tabata", - "shortName": "Tabata - Control High-Intensity Interval Training", - "version": "0.01", - "description": "Control high-intensity interval training (according to tabata: https://en.wikipedia.org/wiki/Tabata_method).", - "icon": "tabata.png", - "tags": "workout,health", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"tabata.app.js","url":"tabata.js"}, - {"name":"tabata.img","url":"tabata-icon.js","evaluate":true} - ] - }, - { - "id": "custom", - "name": "Custom Boot Code ", - "version": "0.01", - "description": "Add code you want to run at boot time", - "icon": "custom.png", - "type": "bootloader", - "tags": "tool,system", - "supports": ["BANGLEJS","BANGLEJS2"], - "custom": "custom.html", - "storage": [ - {"name":"custom"} - ] - }, - { - "id": "devstopwatch", - "name": "Dev Stopwatch", - "shortName": "Dev Stopwatch", - "version": "0.03", - "description": "Stopwatch with 5 laps supported (cyclically replaced)", - "icon": "app.png", - "tags": "stopwatch,chrono,timer,chronometer", - "supports": ["BANGLEJS","BANGLEJS2"], - "screenshots": [{"url":"bangle1-dev-stopwatch-screenshot.png"}], - "allow_emulator": true, - "storage": [ - {"name":"devstopwatch.app.js","url":"app.js"}, - {"name":"devstopwatch.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "batchart", - "name": "Battery Chart", - "shortName": "Battery Chart", - "version": "0.10", - "description": "A widget and an app for recording and visualizing battery percentage over time.", - "icon": "app.png", - "tags": "app,widget,battery,time,record,chart,tool", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"batchart.wid.js","url":"widget.js"}, - {"name":"batchart.app.js","url":"app.js"}, - {"name":"batchart.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "nato", - "name": "NATO Alphabet", - "shortName": "NATOAlphabet", - "version": "0.01", - "description": "Learn the NATO Phonetic alphabet plus some numbers.", - "icon": "nato.png", - "type": "app", - "tags": "app,learn,visual", - "supports": ["BANGLEJS"], - "allow_emulator": true, - "screenshots": [{"url":"bangle1-NATO-alphabet-screenshot.png"},{"url":"bangle1-NATO-alphabet-screenshot2.png"}], - "storage": [ - {"name":"nato.app.js","url":"nato.js"}, - {"name":"nato.img","url":"nato-icon.js","evaluate":true} - ] - }, - { - "id": "numerals", - "name": "Numerals Clock", - "shortName": "Numerals Clock", - "version": "0.10", - "description": "A simple big numerals clock", - "icon": "numerals.png", - "type": "clock", - "tags": "numerals,clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "allow_emulator": true, - "screenshots": [{"url":"bangle1-numerals-screenshot.png"}], - "storage": [ - {"name":"numerals.app.js","url":"numerals.app.js"}, - {"name":"numerals.img","url":"numerals-icon.js","evaluate":true}, - {"name":"numerals.settings.js","url":"numerals.settings.js"} - ], - "data": [{"name":"numerals.json"}] - }, - { - "id": "bledetect", - "name": "BLE Detector", - "shortName": "BLE Detector", - "version": "0.03", - "description": "Detect BLE devices and show some informations.", - "icon": "bledetect.png", - "tags": "app,bluetooth,tool", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"bledetect.app.js","url":"bledetect.js"}, - {"name":"bledetect.img","url":"bledetect-icon.js","evaluate":true} - ] - }, - { - "id": "snake", - "name": "Snake", - "shortName": "Snake", - "version": "0.02", - "description": "The classic snake game. Eat apples and don't bite your tail.", - "icon": "snake.png", - "tags": "game,fun", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"snake.app.js","url":"snake.js"}, - {"name":"snake.img","url":"snake-icon.js","evaluate":true} - ] - }, - { "id": "snek", - "name": "The snek game", - "shortName":"Snek", - "version": "0.02", - "description": "A snek game where you control a snek to eat all the apples!", - "screenshots": [{"url":"screenshot_snek.png"}], - "icon": "snek.png", - "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", - "shortName": "Calculator", - "version": "0.05", - "description": "Basic calculator reminiscent of MacOs's one. Handy for small calculus.", - "icon": "calculator.png", - "screenshots": [{"url":"screenshot_calculator.png"}], - "tags": "app,tool", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"calculator.app.js","url":"app.js"}, - {"name":"calculator.img","url":"calculator-icon.js","evaluate":true} - ] - }, - { - "id": "dane", - "name": "Digital Assistant, not EDITH", - "shortName": "DANE", - "version": "0.16", - "description": "A Watchface inspired by Tony Stark's EDITH and based on https://arwes.dev/", - "icon": "app.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "allow_emulator": true, - "storage": [ - {"name":"dane.app.js","url":"app.js"}, - {"name":"dane.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "dane_tcr", - "name": "DANE Touch Launcher", - "shortName": "DANE Toucher", - "version": "0.07", - "description": "Touch enable left to right launcher in the style of the DANE Watchface", - "icon": "app.png", - "type": "launch", - "tags": "tool,system,launcher", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"dane_tcr.app.js","url":"app.js"}, - {"name":"dane_tcr.settings.js","url":"settings.js"} - ], - "data": [{"name":"dane_tcr.json"}] - }, - { - "id": "buffgym", - "name": "BuffGym", - "version": "0.02", - "description": "BuffGym is the famous 5x5 workout program for the BangleJS", - "icon": "buffgym.png", - "type": "app", - "tags": "tool,outdoors,gym,exercise", - "supports": ["BANGLEJS"], - "readme": "README.md", - "interface": "buffgym.html", - "allow_emulator": false, - "storage": [ - {"name":"buffgym.app.js","url":"buffgym.app.js"}, - {"name":"buffgym-set.js","url":"buffgym-set.js"}, - {"name":"buffgym-exercise.js","url":"buffgym-exercise.js"}, - {"name":"buffgym-workout.js","url":"buffgym-workout.js"}, - {"name":"buffgym-workout-a.json","url":"buffgym-workout-a.json"}, - {"name":"buffgym-workout-b.json","url":"buffgym-workout-b.json"}, - {"name":"buffgym-workout-index.json","url":"buffgym-workout-index.json"}, - {"name":"buffgym.img","url":"buffgym-icon.js","evaluate":true} - ] - }, - { - "id": "banglerun", - "name": "BangleRun", - "shortName": "BangleRun", - "version": "0.10", - "description": "An app for running sessions. Displays info and logs your run for later viewing.", - "icon": "banglerun.png", - "tags": "run,running,fitness,outdoors", - "supports": ["BANGLEJS"], - "interface": "interface.html", - "allow_emulator": false, - "storage": [ - {"name":"banglerun.app.js","url":"app.js"}, - {"name":"banglerun.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "metronome", - "name": "Metronome", - "version": "0.07", - "readme": "README.md", - "description": "Makes the watch blinking and vibrating with a given rate", - "icon": "metronome_icon.png", - "tags": "tool", - "supports": ["BANGLEJS","BANGLEJS2"], - "allow_emulator": true, - "screenshots": [{"url":"bangle1-metronome-screenshot.png"}], - "storage": [ - {"name":"metronome.app.js","url":"metronome.js"}, - {"name":"metronome.img","url":"metronome-icon.js","evaluate":true}, - {"name":"metronome.settings.js","url":"settings.js"} - ] - }, - { - "id": "blackjack", - "name": "Black Jack game", - "shortName": "Black Jack game", - "version": "0.02", - "description": "Simple implementation of card game Black Jack", - "icon": "blackjack.png", - "tags": "game", - "supports": ["BANGLEJS"], - "screenshots": [{"url":"bangle1-black-jack-game-screenshot.png"}], - "allow_emulator": true, - "storage": [ - {"name":"blackjack.app.js","url":"blackjack.app.js"}, - {"name":"blackjack.img","url":"blackjack-icon.js","evaluate":true} - ] - }, - { - "id": "hidcam", - "name": "Camera shutter", - "shortName": "Cam shutter", - "version": "0.03", - "description": "Enable HID, connect to your phone, start your camera and trigger the shot on your Bangle", - "icon": "app.png", - "tags": "bluetooth,tool", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"hidcam.app.js","url":"app.js"}, - {"name":"hidcam.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "swlclk", - "name": "SWL Clock / Short Wave Listner Clock", - "shortName": "SWL Clock", - "version": "0.02", - "description": "Display Local, UTC time and some programs on the shorts waves along the day, with the frequencies", - "icon": "swlclk.png", - "type": "clock", - "tags": "tool,clock", - "supports": ["BANGLEJS"], - "readme": "README.md", - "allow_emulator": true, - "screenshots": [{"url":"bangle1-SWL-clock-screenshot.png"}], - "storage": [ - {"name":"swlclk.app.js","url":"app.js"}, - {"name":"swlclk.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "rclock", - "name": "Round clock with seconds, minutes and date", - "shortName": "Round Clock", - "version": "0.06", - "description": "Designed round clock with ticks for minutes and seconds and heart rate indication", - "icon": "app.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"rclock.app.js","url":"rclock.app.js"}, - {"name":"rclock.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "fclock", - "name": "fclock", - "shortName": "F Clock", - "version": "0.02", - "description": "Simple design of a digital clock", - "icon": "app.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"fclock.app.js","url":"fclock.app.js"}, - {"name":"fclock.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "hamloc", - "name": "QTH Locator / Maidenhead Locator System", - "shortName": "QTH Locator", - "version": "0.01", - "description": "Convert your current GPS location to the Maidenhead locator system used by HAM amateur radio operators", - "icon": "app.png", - "tags": "tool,outdoors,gps", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"hamloc.app.js","url":"app.js"}, - {"name":"hamloc.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "osmpoi", - "name": "POI Compass", - "version": "0.03", - "description": "Uploads all the points of interest in an area onto your watch, same as Beer Compass with more p.o.i.", - "icon": "app.png", - "tags": "tool,outdoors,gps", - "supports": ["BANGLEJS"], - "readme": "README.md", - "custom": "custom.html", - "storage": [ - {"name":"osmpoi.app.js"}, - {"name":"osmpoi.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "pong", - "name": "Pong", - "shortName": "Pong", - "version": "0.03", - "description": "A clone of the Atari game Pong", - "icon": "pong.png", - "type": "app", - "tags": "game", - "supports": ["BANGLEJS"], - "readme": "README.md", - "allow_emulator": true, - "screenshots": [{"url":"bangle1-pong-screenshot.png"}], - "storage": [ - {"name":"pong.app.js","url":"app.js"}, - {"name":"pong.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "ballmaze", - "name": "Ball Maze", - "version": "0.02", - "description": "Navigate a ball through a maze by tilting your watch.", - "icon": "icon.png", - "type": "app", - "tags": "game", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"ballmaze.app.js","url":"app.js"}, - {"name":"ballmaze.img","url":"icon.js","evaluate":true} - ], - "data": [{"name":"ballmaze.json"}] - }, - { - "id": "calendar", - "name": "Calendar", - "version": "0.06", - "description": "Simple calendar", - "icon": "calendar.png", - "screenshots": [{"url":"screenshot_calendar.png"}], - "tags": "calendar", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "allow_emulator": true, - "storage": [ - {"name":"calendar.app.js","url":"calendar.js"}, - {"name":"calendar.settings.js","url":"settings.js"}, - {"name":"calendar.img","url":"calendar-icon.js","evaluate":true} - ], - "data": [{"name":"calendar.json"}] - }, - { - "id": "hidjoystick", - "name": "Bluetooth Joystick", - "shortName": "Joystick", - "version": "0.01", - "description": "Emulates a 2 axis/5 button Joystick using the accelerometer as stick input and buttons 1-3, touch left as button 4 and touch right as button 5.", - "icon": "app.png", - "tags": "bluetooth", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"hidjoystick.app.js","url":"app.js"}, - {"name":"hidjoystick.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "largeclock", - "name": "Large Clock", - "version": "0.10", - "description": "A readable and informational digital watch, with date, seconds and moon phase", - "icon": "largeclock.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "readme": "README.md", - "allow_emulator": true, - "screenshots": [{"url":"bangle1-large-clock-screenshot.png"}], - "storage": [ - {"name":"largeclock.app.js","url":"largeclock.js"}, - {"name":"largeclock.img","url":"largeclock-icon.js","evaluate":true}, - {"name":"largeclock.settings.js","url":"settings.js"} - ], - "data": [{"name":"largeclock.json"}] - }, - { - "id": "smtswch", - "name": "Smart Switch", - "shortName": "Smart Switch", - "version": "0.01", - "description": "Using EspruinoHub, control your smart devices on and off via Bluetooth Low Energy!", - "icon": "app.png", - "type": "app", - "tags": "bluetooth,btle,smart,switch", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"smtswch.app.js","url":"app.js"}, - {"name":"smtswch.img","url":"app-icon.js","evaluate":true}, - {"name":"light-on.img","url":"light-on.js","evaluate":true}, - {"name":"light-off.img","url":"light-off.js","evaluate":true}, - {"name":"switch-on.img","url":"switch-on.js","evaluate":true}, - {"name":"switch-off.img","url":"switch-off.js","evaluate":true} - ] - }, - { - "id": "miplant", - "name": "Xiaomi Plant Sensor", - "shortName": "Mi Plant", - "version": "0.02", - "description": "Reads and displays data from Xiaomi bluetooth plant moisture sensors", - "icon": "app.png", - "tags": "xiaomi,mi,plant,ble,bluetooth", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"miplant.app.js","url":"app.js"}, - {"name":"miplant.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "simpletimer", - "name": "Timer", - "version": "0.07", - "description": "Simple timer, useful when playing board games or cooking", - "icon": "app.png", - "tags": "timer", - "supports": ["BANGLEJS"], - "readme": "README.md", - "allow_emulator": true, - "screenshots": [{"url":"bangle1-timer-screenshot.png"}], - "storage": [ - {"name":"simpletimer.app.js","url":"app.js"}, - {"name":".tfnames","url":"gesture-tfnames.js","evaluate":true}, - {"name":".tfmodel","url":"gesture-tfmodel.js","evaluate":true}, - {"name":"simpletimer.img","url":"app-icon.js","evaluate":true} - ], - "data": [{"name":"simpletimer.json"}] - }, - { - "id": "beebclock", - "name": "Beeb Clock", - "version": "0.05", - "description": "Clock face that may be coincidentally familiar to BBC viewers", - "icon": "beebclock.png", - "type": "clock", - "tags": "clock", - "screenshots": [{"url":"bangle1-beeb-clock-screenshot.png"}], - "supports": ["BANGLEJS"], - "allow_emulator": true, - "storage": [ - {"name":"beebclock.app.js","url":"beebclock.js"}, - {"name":"beebclock.img","url":"beebclock-icon.js","evaluate":true} - ] - }, - { - "id": "findphone", - "name": "Find Phone", - "shortName": "Find Phone", - "version": "0.03", - "description": "Find your phone via Gadgetbridge. Click any button to let your phone ring. 📳 Note: The functionality is available even without this app, just go to Settings, App Settings, Gadgetbridge, Find Phone.", - "icon": "app.png", - "tags": "tool,android", - "supports": ["BANGLEJS"], - "readme": "README.md", - "allow_emulator": true, - "storage": [ - {"name":"findphone.app.js","url":"app.js"}, - {"name":"findphone.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "getup", - "name": "Get Up", - "shortName": "Get Up", - "version": "0.01", - "description": "Reminds you to getup every x minutes. Sitting to long is dangerous!", - "icon": "app.png", - "tags": "tools,health", - "supports": ["BANGLEJS"], - "readme": "README.md", - "screenshots": [{"url":"bangle1-get-up-screenshot.png"}], - "allow_emulator": true, - "storage": [ - {"name":"getup.app.js","url":"app.js"}, - {"name":"getup.settings.js","url":"settings.js"}, - {"name":"getup.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "gallifr", - "name": "Time Traveller's Chronometer", - "shortName": "Time Travel Clock", - "version": "0.02", - "description": "A clock for time travellers. The light pie segment shows the minutes, the black circle, the hour. The dial itself reads 'time' just in case you forget.", - "icon": "gallifr.png", - "screenshots": [{"url":"screenshot_time.png"}], - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "allow_emulator": true, - "storage": [ - {"name":"gallifr.app.js","url":"app.js"}, - {"name":"gallifr.img","url":"app-icon.js","evaluate":true}, - {"name":"gallifr.settings.js","url":"settings.js"} - ], - "data": [{"name":"gallifr.json"}] - }, - { - "id": "rndmclk", - "name": "Random Clock Loader", - "version": "0.03", - "description": "Load a different clock whenever the LCD is switched on.", - "icon": "rndmclk.png", - "type": "widget", - "tags": "widget,clock", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"rndmclk.wid.js","url":"widget.js"} - ] - }, - { - "id": "dotmatrixclock", - "name": "Dotmatrix Clock", - "version": "0.01", - "description": "A clear white-on-blue dotmatrix simulated clock", - "icon": "dotmatrixclock.png", - "type": "clock", - "tags": "clock,dotmatrix,retro", - "supports": ["BANGLEJS"], - "readme": "README.md", - "allow_emulator": true, - "storage": [ - {"name":"dotmatrixclock.app.js","url":"app.js"}, - {"name":"dotmatrixclock.img","url":"dotmatrixclock-icon.js","evaluate":true} - ] - }, - { - "id": "jbm8b", - "name": "Magic 8 Ball", - "shortName": "Magic 8 Ball", - "version": "0.03", - "description": "A simple fortune telling app", - "icon": "app.png", - "tags": "game", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"jbm8b.app.js","url":"app.js"}, - {"name":"jbm8b.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "jbm8b_IT", - "name": "Magic 8 Ball Italiano", - "shortName": "Magic 8 Ball IT", - "version": "0.01", - "description": "La palla predice il futuro", - "icon": "app.png", - "screenshots": [{"url":"bangle1-magic-8-ball-italiano-screenshot.png"}], - "tags": "game", - "supports": ["BANGLEJS"], - "allow_emulator": true, - "storage": [ - {"name":"jbm8b_IT.app.js","url":"app.js"}, - {"name":"jbm8b_IT.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "BLEcontroller", - "name": "BLE Customisable Controller with Joystick", - "shortName": "BLE Controller", - "version": "0.01", - "description": "A configurable controller for BLE devices and robots, with a basic four direction joystick. Designed to be easy to customise so you can add your own menus.", - "icon": "BLEcontroller.png", - "tags": "tool,bluetooth", - "supports": ["BANGLEJS"], - "readme": "README.md", - "allow_emulator": false, - "storage": [ - {"name":"BLEcontroller.app.js","url":"app.js"}, - {"name":"BLEcontroller.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "widviz", - "name": "Widget Visibility Widget", - "shortName": "Viz Widget", - "version": "0.03", - "description": "Swipe left to hide top bar widgets, swipe right to redisplay.", - "icon": "eye.png", - "type": "widget", - "tags": "widget", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"widviz.wid.js","url":"widget.js"} - ] - }, - { - "id": "binclock", - "name": "Binary Clock", - "shortName": "Binary Clock", - "version": "0.03", - "description": "A binary clock with hours and minutes. BTN1 toggles a digital clock.", - "icon": "app.png", - "type": "clock", - "tags": "clock,binary", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"binclock.app.js","url":"app.js"}, - {"name":"binclock.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "pizzatimer", - "name": "Pizza Timer", - "shortName": "Pizza Timer", - "version": "0.01", - "description": "A timer app for when you cook Pizza. Some say it can also time other things", - "icon": "pizza.png", - "tags": "timer,tool,pizza", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"pizzatimer.app.js","url":"app.js"}, - {"name":"pizzatimer.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "animclk", - "name": "Animated Clock", - "shortName": "Anim Clock", - "version": "0.03", - "description": "An animated clock face using Mark Ferrari's amazing 8 bit game art and palette cycling: http://www.markferrari.com/art/8bit-game-art", - "icon": "app.png", - "type": "clock", - "tags": "clock,animated", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"animclk.app.js","url":"app.js"}, - {"name":"animclk.pixels1","url":"animclk.pixels1"}, - {"name":"animclk.pixels2","url":"animclk.pixels2"}, - {"name":"animclk.pal","url":"animclk.pal"}, - {"name":"animclk.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "analogimgclk", - "name": "Analog Clock (Image background)", - "shortName": "Analog Clock", - "version": "0.03", - "description": "An analog clock with an image background", - "icon": "app.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"analogimgclk.app.js","url":"app.js"}, - {"name":"analogimgclk.bg.img","url":"bg.img"}, - {"name":"analogimgclk.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "verticalface", - "name": "Vertical watch face", - "shortName": "Vertical Face", - "version": "0.09", - "description": "A simple vertical watch face with the date. Heart rate monitor is toggled with BTN1", - "icon": "app.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "allow_emulator": true, - "screenshots": [{"url":"bangle1-vertical-watch-face-screenshot.png"}], - "storage": [ - {"name":"verticalface.app.js","url":"app.js"}, - {"name":"verticalface.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "sleepphasealarm", - "name": "SleepPhaseAlarm", - "shortName": "SleepPhaseAlarm", - "version": "0.02", - "description": "Uses the accelerometer to estimate sleep and wake states with the principle of Estimation of Stationary Sleep-segments (ESS, see https://ubicomp.eti.uni-siegen.de/home/datasets/ichi14/index.html.en). This app will read the next alarm from the alarm application and will wake you up to 30 minutes early at the best guessed time when you are almost already awake.", - "icon": "app.png", - "tags": "alarm", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"sleepphasealarm.app.js","url":"app.js"}, - {"name":"sleepphasealarm.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "life", - "name": "Game of Life", - "version": "0.04", - "description": "Conway's Game of Life - 16x16 board", - "icon": "life.png", - "tags": "game", - "supports": ["BANGLEJS"], - "screenshots": [{"url":"bangle1-game-of-life-screenshot.png"}], - "allow_emulator": true, - "storage": [ - {"name":"life.app.js","url":"life.min.js"}, - {"name":"life.img","url":"life-icon.js","evaluate":true} - ] - }, - { - "id": "magnav", - "name": "Navigation Compass", - "version": "0.05", - "description": "Compass with linear display as for GPSNAV. Has Tilt compensation and remembers calibration.", - "screenshots": [{"url":"screenshot-b2.png"},{"url":"screenshot-light-b2.png"}], - "icon": "magnav.png", - "tags": "tool,outdoors", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "storage": [ - {"name":"magnav.app.js","url":"magnav_b1.js","supports":["BANGLEJS"]}, - {"name":"magnav.app.js","url":"magnav_b2.js","supports":["BANGLEJS2"]}, - {"name":"magnav.img","url":"magnav-icon.js","evaluate":true} - ], - "data": [{"name":"magnav.json"}] - }, - { - "id": "gpspoilog", - "name": "GPS POI Logger", - "shortName": "GPS POI Log", - "version": "0.01", - "description": "A simple app to log points of interest with their GPS coordinates and read them back onto your PC. Based on the https://www.espruino.com/Bangle.js+Storage tutorial", - "icon": "app.png", - "tags": "outdoors", - "supports": ["BANGLEJS"], - "interface": "interface.html", - "storage": [ - {"name":"gpspoilog.app.js","url":"app.js"}, - {"name":"gpspoilog.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "miclock2", - "name": "Mixed Clock 2", - "version": "0.01", - "description": "White color variant of the Mixed Clock with thicker clock hands for better readability in the bright sunlight, extra space under the clock for widgets and seconds in the digital clock.", - "icon": "clock-mixed.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "screenshots": [{"url":"bangle1-mixed-clock-2-screenshot.png"}], - "allow_emulator": true, - "storage": [ - {"name":"miclock2.app.js","url":"clock-mixed.js"}, - {"name":"miclock2.img","url":"clock-mixed-icon.js","evaluate":true} - ] - }, - { - "id": "1button", - "name": "One-Button-Tracker", - "version": "0.01", - "description": "A widget that turns BTN1 into a tracker, records time of button press/release.", - "icon": "widget.png", - "type": "widget", - "tags": "tool,quantifiedself,widget", - "supports": ["BANGLEJS"], - "readme": "README.md", - "interface": "interface.html", - "storage": [ - {"name":"1button.wid.js","url":"widget.js"} - ], - "data": [{"name":"one_button_presses.csv","storageFile":true}] - }, - { - "id": "gpsautotime", - "name": "GPS auto time", - "shortName": "GPS auto time", - "version": "0.01", - "description": "A widget that automatically updates the Bangle.js time to the GPS time whenever there is a valid GPS fix.", - "icon": "widget.png", - "type": "widget", - "tags": "widget,gps", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"gpsautotime.wid.js","url":"widget.js"} - ] - }, - { - "id": "espruinoctrl", - "name": "Espruino Control", - "shortName": "Espruino Ctrl", - "version": "0.01", - "description": "Send commands to other Espruino devices via the Bluetooth UART interface. Customisable commands!", - "icon": "app.png", - "tags": "", - "supports": ["BANGLEJS"], - "readme": "README.md", - "custom": "custom.html", - "storage": [ - {"name":"espruinoctrl.app.js"}, - {"name":"espruinoctrl.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "multiclock", - "name": "Multi Clock", - "version": "0.09", - "description": "Clock with multiple faces. Switch between faces with BTN1 & BTN3 (Bangle 2 touch top-right, bottom right). For best display set theme Background 2 to cyan or some other bright colour in settings.", - "screenshots": [{"url":"screen-ana.png"},{"url":"screen-big.png"},{"url":"screen-td.png"},{"url":"screen-nifty.png"},{"url":"screen-word.png"},{"url":"screen-sec.png"}], - "icon": "multiclock.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "allow_emulator": true, - "storage": [ - {"name":"multiclock.app.js","url":"multiclock.app.js"}, - {"name":"big.face.js","url":"big.face.js"}, - {"name":"ana.face.js","url":"ana.face.js"}, - {"name":"digi.face.js","url":"digi.face.js"}, - {"name":"txt.face.js","url":"txt.face.js"}, - {"name":"dk.face.js","url":"dk.face.js"}, - {"name":"nifty.face.js","url":"nifty.face.js"}, - {"name":"multiclock.img","url":"multiclock-icon.js","evaluate":true} - ] - }, - { - "id": "widancs", - "name": "Apple Notification Widget", - "shortName": "ANCS Widget", - "version": "0.07", - "description": "Displays call, message etc notifications from a paired iPhone. Read README before installation as it only works with compatible apps", - "icon": "widget.png", - "type": "widget", - "tags": "widget", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"widancs.wid.js","url":"ancs.min.js"}, - {"name":"widancs.settings.js","url":"settings.js"} - ] - }, - { - "id": "accelrec", - "name": "Acceleration Recorder", - "shortName": "Accel Rec", - "version": "0.02", - "description": "This app puts the Bangle's accelerometer into 100Hz mode and reads 2 seconds worth of data after movement starts. The data can then be exported back to the PC.", - "icon": "app.png", - "tags": "", - "supports": ["BANGLEJS"], - "readme": "README.md", - "interface": "interface.html", - "storage": [ - {"name":"accelrec.app.js","url":"app.js"}, - {"name":"accelrec.img","url":"app-icon.js","evaluate":true} - ], - "data": [{"wildcard":"accelrec.?.csv"}] - }, - { - "id": "accellog", - "name": "Acceleration Logger", - "shortName": "Accel Log", - "version": "0.03", - "description": "Logs XYZ acceleration data to a CSV file that can be downloaded to your PC", - "icon": "app.png", - "tags": "outdoor", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "interface": "interface.html", - "storage": [ - {"name":"accellog.app.js","url":"app.js"}, - {"name":"accellog.img","url":"app-icon.js","evaluate":true} - ], - "data": [{"wildcard":"accellog.?.csv"}] - }, - { - "id": "cprassist", - "name": "CPR Assist", - "version": "0.02", - "description": "Provides assistance while performing a CPR", - "icon": "cprassist-icon.png", - "tags": "tool,firstaid", - "supports": ["BANGLEJS", "BANGLEJS2"], - "readme": "README.md", - "allow_emulator": true, - "screenshots": [{"url":"bangle1-CPR-assist-screenshot.png"}], - "storage": [ - {"name":"cprassist.app.js","url":"cprassist.js"}, - {"name":"cprassist.img","url":"cprassist-icon.js","evaluate":true}, - {"name":"cprassist.settings.js","url":"settings.js"} - ] - }, - { - "id": "osgridref", - "name": "Ordnance Survey Grid Reference", - "shortName": "OS Grid ref", - "version": "0.01", - "description": "Displays the UK Ordnance Survey grid reference of your current GPS location. Useful when in the United Kingdom with an Ordnance Survey map", - "icon": "app.png", - "tags": "outdoors,gps", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"osgridref.app.js","url":"app.js"}, - {"name":"osgridref.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "openseizure", - "name": "OpenSeizureDetector Widget", - "shortName": "Short Name", - "version": "0.01", - "description": "[BETA!] A widget to work alongside [OpenSeizureDetector](https://www.openseizuredetector.org.uk/)", - "icon": "widget.png", - "type": "widget", - "tags": "widget", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"openseizure.wid.js","url":"widget.js"} - ] - }, - { - "id": "counter", - "name": "Counter", - "version": "0.03", - "description": "Simple counter", - "icon": "counter_icon.png", - "tags": "tool", - "supports": ["BANGLEJS"], - "screenshots": [{"url":"bangle1-counter-screenshot.png"}], - "allow_emulator": true, - "storage": [ - {"name":"counter.app.js","url":"counter.js"}, - {"name":"counter.img","url":"counter-icon.js","evaluate":true} - ] - }, - { - "id": "bootgattbat", - "name": "BLE GATT Battery Service", - "shortName": "BLE Battery Service", - "version": "0.01", - "description": "Adds the GATT Battery Service to advertise the percentage of battery currently remaining over Bluetooth.\n", - "icon": "bluetooth.png", - "type": "bootloader", - "tags": "battery,ble,bluetooth,gatt", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "storage": [ - {"name":"gattbat.boot.js","url":"boot.js"} - ] - }, - { - "id": "viewstl", - "name": "STL file viewer", - "shortName": "ViewSTL", - "version": "0.02", - "description": "This app allows you to view STL 3D models on your watch", - "icon": "icons8-octahedron-48.png", - "tags": "tool", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"viewstl.app.js","url":"viewstl.min.js"}, - {"name":"viewstl.img","url":"viewstl-icon.js","evaluate":true}, - {"name":"tetra.stl","url":"tetra.stl"}, - {"name":"cube.stl","url":"cube.stl"}, - {"name":"icosa.stl","url":"icosa.stl"} - ] - }, - { - "id": "cscsensor", - "name": "Cycling speed sensor", - "shortName": "CSCSensor", - "version": "0.06", - "description": "Read BLE enabled cycling speed and cadence sensor and display readings on watch", - "icon": "icons8-cycling-48.png", - "tags": "outdoors,exercise,ble,bluetooth", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"cscsensor.app.js","url":"cscsensor.app.js"}, - {"name":"cscsensor.settings.js","url":"settings.js"}, - {"name":"cscsensor.img","url":"cscsensor-icon.js","evaluate":true} - ] - }, - { - "id": "fileman", - "name": "File manager", - "shortName": "FileManager", - "version": "0.03", - "description": "Simple file manager, allows user to examine watch storage and display, load or delete individual files", - "icon": "icons8-filing-cabinet-48.png", - "tags": "tools", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"fileman.app.js","url":"fileman.app.js"}, - {"name":"fileman.img","url":"fileman-icon.js","evaluate":true} - ] - }, - { - "id": "worldclock", - "name": "World Clock - 4 time zones", - "shortName": "World Clock", - "version": "0.05", - "description": "Current time zone plus up to four others", - "icon": "app.png", - "screenshots": [{"url":"screenshot_world.png"}], - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "custom": "custom.html", - "storage": [ - {"name":"worldclock.app.js","url":"app.js"}, - {"name":"worldclock.img","url":"worldclock-icon.js","evaluate":true} - ], - "data": [{"name":"worldclock.settings.json"}] - }, - { - "id": "digiclock", - "name": "Digital Clock Face", - "shortName": "Digi Clock", - "version": "0.02", - "description": "A simple digital clock with the time, day, month, and year", - "icon": "digiclock.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"digiclock.app.js","url":"digiclock.js"}, - {"name":"digiclock.img","url":"digiclock-icon.js","evaluate":true} - ] - }, - { - "id": "dsdrelay", - "name": "DSD BLE Relay controller", - "shortName": "DSDRelay", - "version": "0.01", - "description": "Control BLE relay board from the watch", - "icon": "icons8-relay-48.png", - "tags": "ble,bluetooth", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"dsdrelay.app.js","url":"dsdrelay.app.js"}, - {"name":"dsdrelay.img","url":"dsdrelay-icon.js","evaluate":true} - ] - }, - { - "id": "mandel", - "name": "Mandelbrot", - "shortName": "Mandel", - "version": "0.01", - "description": "Draw a zoomable Mandelbrot set", - "icon": "mandel.png", - "tags": "game", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"mandel.app.js","url":"mandel.min.js"}, - {"name":"mandel.img","url":"mandel-icon.js","evaluate":true} - ] - }, - { - "id": "petrock", - "name": "Pet rock", - "version": "0.02", - "description": "A virtual pet rock with wobbly eyes", - "icon": "petrock.png", - "type": "app", - "tags": "game", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"petrock.app.js","url":"app.js"}, - {"name":"petrock.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "smartibot", - "name": "Smartibot controller", - "shortName": "Smartibot", - "version": "0.01", - "description": "Control a [Smartibot Robot](https://thecraftyrobot.net/) straight from your Bangle.js", - "icon": "app.png", - "tags": "", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"smartibot.app.js","url":"app.js"}, - {"name":"smartibot.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "widncr", - "name": "NCR Logo Widget", - "version": "0.01", - "description": "Show the NodeConf Remote logo in the top left", - "icon": "widget.png", - "type": "widget", - "tags": "widget", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"widncr.wid.js","url":"widget.js"} - ] - }, - { - "id": "ncrclk", - "name": "NCR Clock", - "shortName": "NCR Clock", - "version": "0.02", - "description": "NodeConf Remote clock", - "icon": "app.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"ncrclk.app.js","url":"app.js"}, - {"name":"ncrclk.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "isoclock", - "name": "ISO Compliant Clock Face", - "shortName": "ISO Clock", - "version": "0.02", - "description": "Tweaked fork of digiclock for ISO date and time", - "icon": "isoclock.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"isoclock.app.js","url":"isoclock.js"}, - {"name":"isoclock.img","url":"isoclock-icon.js","evaluate":true} - ] - }, - { - "id": "gpstimeserver", - "name": "GPS Time Server", - "version": "0.01", - "description": "A widget which automatically starts the GPS and turns Bangle.js into a Bluetooth time server.", - "icon": "widget.png", - "type": "widget", - "tags": "widget", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"gpstimeserver.wid.js","url":"widget.js"} - ] - }, - { - "id": "tilthydro", - "name": "Tilt Hydrometer Display", - "shortName": "Tilt Hydro", - "version": "0.01", - "description": "A display for the [Tilt Hydrometer](https://tilthydrometer.com/) - [more info here](http://www.espruino.com/Tilt+Hydrometer+Display)", - "icon": "app.png", - "tags": "tools,bluetooth", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"tilthydro.app.js","url":"app.js"}, - {"name":"tilthydro.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "supmariodark", - "name": "Super mario clock night mode", - "shortName": "supmariodark", - "version": "0.01", - "description": "Super mario clock in night mode", - "icon": "supmariodark.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"supmariodark.app.js","url":"supmariodark.js"}, - {"name":"supmariodark.img","url":"supmariodark-icon.js","evaluate":true}, - {"name":"supmario30x24.bin","url":"supmario30x24.bin.js"}, - {"name":"supmario30x24.wdt","url":"supmario30x24.wdt.js"}, - {"name":"banner-up.img","url":"banner-up.js","evaluate":true}, - {"name":"banner-down.img","url":"banner-down.js","evaluate":true}, - {"name":"brick2.img","url":"brick2.js","evaluate":true}, - {"name":"enemy.img","url":"enemy.js","evaluate":true}, - {"name":"flower.img","url":"flower.js","evaluate":true}, - {"name":"flower_b.img","url":"flower_b.js","evaluate":true}, - {"name":"mario_wh.img","url":"mario_wh.js","evaluate":true}, - {"name":"pipe.img","url":"pipe.js","evaluate":true} - ] - }, - { - "id": "gmeter", - "name": "G-Meter", - "shortName": "G-Meter", - "version": "0.01", - "description": "Simple G-Meter", - "icon": "app.png", - "tags": "", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"gmeter.app.js","url":"app.js"}, - {"name":"gmeter.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "dtlaunch", - "name": "Desktop Launcher", - "version": "0.07", - "description": "Desktop style App Launcher with six (four for Bangle 2) apps per page - fast access if you have lots of apps installed.", - "screenshots": [{"url":"shot1.png"},{"url":"shot2.png"},{"url":"shot3.png"}], - "icon": "icon.png", - "type": "launch", - "tags": "tool,system,launcher", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "storage": [ - {"name":"dtlaunch.app.js","url":"app-b1.js", "supports": ["BANGLEJS"]}, - {"name":"dtlaunch.app.js","url":"app-b2.js", "supports": ["BANGLEJS2"]}, - {"name":"dtlaunch.settings.js","url":"settings-b1.js", "supports": ["BANGLEJS"]}, - {"name":"dtlaunch.settings.js","url":"settings-b2.js", "supports": ["BANGLEJS2"]}, - {"name":"dtlaunch.img","url":"app-icon.js","evaluate":true} - ], - "data": [{"name":"dtlaunch.json"}] - }, - { - "id": "HRV", - "name": "Heart Rate Variability monitor", - "shortName": "HRV monitor", - "version": "0.04", - "description": "Heart Rate Variability monitor, see Readme for more info", - "icon": "hrv.png", - "tags": "", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"HRV.app.js","url":"app.js"}, - {"name":"HRV.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "hardalarm", - "name": "Hard Alarm", - "shortName": "HardAlarm", - "version": "0.02", - "description": "Make sure you wake up! Count to the right number to turn off the alarm", - "icon": "app.png", - "tags": "tool,alarm,widget", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"hardalarm.app.js","url":"app.js"}, - {"name":"hardalarm.boot.js","url":"boot.js"}, - {"name":"hardalarm.js","url":"hardalarm.js"}, - {"name":"hardalarm.img","url":"app-icon.js","evaluate":true}, - {"name":"hardalarm.wid.js","url":"widget.js"} - ], - "data": [{"name":"hardalarm.json"}] - }, - { - "id": "edisonsball", - "name": "Edison's Ball", - "shortName": "Edison's Ball", - "version": "0.01", - "description": "Hypnagogia/Micro-Sleep alarm for experimental use in exploring sleep transition and combating drowsiness", - "icon": "app-icon.png", - "tags": "", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"edisonsball.app.js","url":"app.js"}, - {"name":"edisonsball.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "hrrawexp", - "name": "HRM Data Exporter", - "shortName": "HRM Data Exporter", - "version": "0.01", - "description": "export raw hrm signal data to a csv file", - "icon": "app-icon.png", - "tags": "", - "supports": ["BANGLEJS"], - "readme": "README.md", - "interface": "interface.html", - "storage": [ - {"name":"hrrawexp.app.js","url":"app.js"}, - {"name":"hrrawexp.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "breath", - "name": "Breathing App", - "shortName": "Breathing App", - "version": "0.01", - "description": "app to aid relaxation and train breath syncronicity using haptics and visualisation, also displays HR", - "icon": "app-icon.png", - "tags": "tools,health", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"breath.app.js","url":"app.js"}, - {"name":"breath.img","url":"app-icon.js","evaluate":true} - ], - "data": [{"name":"breath.settings.json","url":"settings.json"}] - }, - { - "id": "lazyclock", - "name": "Lazy Clock", - "version": "0.03", - "description": "Tells the time, roughly", - "icon": "lazyclock.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "readme": "README.md", - "screenshots": [{"url":"bangle1-lazy-clock-screenshot.png"}], - "allow_emulator": true, - "storage": [ - {"name":"lazyclock.app.js","url":"lazyclock-app.js"}, - {"name":"lazyclock.img","url":"lazyclock-icon.js","evaluate":true} - ] - }, - { - "id": "astral", - "name": "Astral Clock", - "version": "0.03", - "description": "Clock that calculates and displays Alt Az positions of all planets, Sun as well as several other astronomy targets (customizable) and current Moon phase. Coordinates are calculated by GPS & time and onscreen compass assists orienting. See Readme before using.", - "icon": "app-icon.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"astral.app.js","url":"app.js"}, - {"name":"astral.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "alpinenav", - "name": "Alpine Nav", - "version": "0.01", - "description": "App that performs GPS monitoring to track and display position relative to a given origin in realtime", - "icon": "app-icon.png", - "tags": "outdoors,gps", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"alpinenav.app.js","url":"app.js"}, - {"name":"alpinenav.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "lifeclk", - "name": "Game of Life Clock", - "shortName": "Conway's Clock", - "version": "0.06", - "description": "Modification and clockification of Conway's Game of Life", - "icon": "app.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"lifeclk.app.js","url":"app.min.js"}, - {"name":"lifeclk.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "speedalt", - "name": "GPS Adventure Sports", - "shortName": "GPS Adv Sport", - "version": "1.02", - "description": "GPS speed, altitude and distance to waypoint display. Designed for easy viewing and use during outdoor activities such as para-gliding, hang-gliding, sailing, cycling etc.", - "icon": "app.png", - "type": "app", - "tags": "tool,outdoors", - "supports": ["BANGLEJS"], - "readme": "README.md", - "allow_emulator": true, - "storage": [ - {"name":"speedalt.app.js","url":"app.js"}, - {"name":"speedalt.img","url":"app-icon.js","evaluate":true}, - {"name":"speedalt.settings.js","url":"settings.js"} - ], - "data": [{"name":"speedalt.json"}] - }, - { - "id": "speedalt2", - "name": "GPS Adventure Sports II", - "shortName":"GPS Adv Sport II", - "version":"1.10", - "description": "GPS speed, altitude and distance to waypoint display. Designed for easy viewing and use during outdoor activities such as para-gliding, hang-gliding, sailing, cycling etc.", - "icon": "app.png", - "type": "app", - "tags": "tool,outdoors", - "supports": ["BANGLEJS"], - "readme": "README.md", - "allow_emulator": true, - "storage": [ - {"name":"speedalt2.app.js","url":"app.js"}, - {"name":"speedalt2.img","url":"app-icon.js","evaluate":true}, - {"name":"speedalt2.settings.js","url":"settings.js"} - ], - "data": [{"name":"speedalt2.json"}] - }, - { - "id": "slomoclock", - "name": "SloMo Clock", - "shortName": "SloMo Clock", - "version": "0.10", - "description": "Simple 24h clock face with large digits, hour above minute. Uses Layout library.", - "icon": "watch.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "readme": "README.md", - "allow_emulator": true, - "screenshots": [{"url":"bangle1-slow-mo-clock-screenshot.png"}], - "storage": [ - {"name":"slomoclock.app.js","url":"app.js"}, - {"name":"slomoclock.img","url":"app-icon.js","evaluate":true}, - {"name":"slomoclock.settings.js","url":"settings.js"} - ], - "data": [{"name":"slomoclock.json"}] - }, - { - "id": "de-stress", - "name": "De-Stress", - "shortName": "De-Stress", - "version": "0.02", - "description": "Simple haptic heartbeat", - "icon": "app.png", - "tags": "", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"de-stress.app.js","url":"app.js"}, - {"name":"de-stress.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "mclockplus", - "name": "Morph Clock+", - "shortName": "Morph Clock+", - "version": "0.03", - "description": "Morphing Clock with more readable seconds and date and additional stopwatch", - "icon": "mclockplus.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"mclockplus.app.js","url":"mclockplus.app.js"}, - {"name":"mclockplus.img","url":"mclockplus-icon.js","evaluate":true} - ] - }, - { - "id": "intervals", - "name": "Intervals App", - "shortName": "Intervals", - "version": "0.01", - "description": "Intervals for training. It is possible to configure work time and rest time and number of sets.", - "icon": "intervals.png", - "tags": "", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"intervals.app.js","url":"intervals.app.js"}, - {"name":"intervals.img","url":"intervals-icon.js","evaluate":true} - ] - }, - { - "id": "planetarium", - "name": "Planetarium", - "shortName": "Planetarium", - "version": "0.03", - "description": "Planetarium showing up to 500 stars using the watch location and time", - "icon": "planetarium.png", - "tags": "", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"planetarium.app.js","url":"planetarium.app.js"}, - {"name":"planetarium.data.csv","url":"planetarium.data.csv"}, - {"name":"planetarium.const.csv","url":"planetarium.const.csv"}, - {"name":"planetarium.extra.csv","url":"planetarium.extra.csv"}, - {"name":"planetarium.settings.js","url":"settings.js"}, - {"name":"planetarium.img","url":"planetarium-icon.js","evaluate":true} - ], - "data": [{"name":"planetarium.json"}] - }, - { - "id": "tapelauncher", - "name": "Tape Launcher", - "version": "0.02", - "description": "An App launcher, icons displayed in a horizontal tape, swipe or use buttons", - "icon": "icon.png", - "type": "launch", - "tags": "tool,system,launcher", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"tapelauncher.app.js","url":"app.js"}, - {"name":"tapelauncher.img","url":"icon.js","evaluate":true} - ] - }, - { - "id": "oblique", - "name": "Oblique Strategies", - "version": "0.01", - "description": "Oblique Strategies for creativity. Copied from Brian Eno.", - "icon": "eno.png", - "tags": "tool", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"oblique.app.js","url":"app.js"}, - {"name":"oblique.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "testuserinput", - "name": "Test User Input", - "shortName": "Test User Input", - "version": "0.06", - "description": "App to test the bangle.js input interface. It displays the user action in text, circle buttons or on/off switch UI elements.", - "icon": "app.png", - "tags": "input,interface,buttons,touch,UI", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"testuserinput.app.js","url":"app.js"}, - {"name":"testuserinput.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "gpssetup", - "name": "GPS Setup", - "shortName": "GPS Setup", - "version": "0.02", - "description": "Configure the GPS power options and store them in the GPS nvram", - "icon": "gpssetup.png", - "tags": "gps,tools,outdoors", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"gpssetup","url":"gpssetup.js"}, - {"name":"gpssetup.settings.js","url":"settings.js"}, - {"name":"gpssetup.app.js","url":"app.js"}, - {"name":"gpssetup.img","url":"icon.js","evaluate":true} - ], - "data": [{"name":"gpssetup.settings.json","url":"settings.json"}] - }, - { - "id": "walkersclock", - "name": "Walkers Clock", - "shortName": "Walkers Clock", - "version": "0.04", - "description": "A large font watch, displays steps, can switch GPS on/off, displays grid reference", - "icon": "walkersclock48.png", - "type": "clock", - "tags": "clock,gps,tools,outdoors", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"walkersclock.app.js","url":"app.js"}, - {"name":"walkersclock.img","url":"icon.js","evaluate":true} - ] - }, - { - "id": "widgps", - "name": "GPS Widget", - "version": "0.03", - "description": "Tiny widget to show the power on/off status of the GPS", - "icon": "widget.png", - "type": "widget", - "tags": "widget,gps", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "storage": [ - {"name":"widgps.wid.js","url":"widget.js"} - ] - }, - { - "id": "widhrt", - "name": "HRM Widget", - "version": "0.03", - "description": "Tiny widget to show the power on/off status of the Heart Rate Monitor", - "icon": "widget.png", - "type": "widget", - "tags": "widget,hrm", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "storage": [ - {"name":"widhrt.wid.js","url":"widget.js"} - ] - }, - { - "id": "countdowntimer", - "name": "Countdown Timer", - "version": "0.01", - "description": "A simple countdown timer with a focus on usability", - "icon": "countdowntimer.png", - "tags": "timer,tool", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"countdowntimer.app.js","url":"countdowntimer.js"}, - {"name":"countdowntimer.img","url":"countdowntimer-icon.js","evaluate":true} - ] - }, - { - "id": "helloworld", - "name": "hello, world!", - "shortName": "hello world", - "version": "0.02", - "description": "A cross cultural hello world!/hola mundo! app with colors and languages", - "icon": "app.png", - "tags": "input,interface,buttons,touch", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"helloworld.app.js","url":"app.js"}, - {"name":"helloworld.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "widcom", - "name": "Compass Widget", - "version": "0.02", - "description": "Tiny widget to show the power on/off status of the Compass", - "icon": "widget.png", - "type": "widget", - "tags": "widget,compass", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "storage": [ - {"name":"widcom.wid.js","url":"widget.js"} - ] - }, - { - "id": "arrow", - "name": "Arrow Compass", - "version": "0.05", - "description": "Moving arrow compass that points North, shows heading, with tilt correction. Based on jeffmer's Navigation Compass", - "icon": "arrow.png", - "type": "app", - "tags": "tool,outdoors", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"arrow.app.js","url":"app.js"}, - {"name":"arrow.img","url":"icon.js","evaluate":true} - ] - }, - { - "id": "waypointer", - "name": "Way Pointer", - "version": "0.01", - "description": "Navigate to a waypoint using the GPS for bearing and compass to point way, uses the same waypoint interface as GPS Navigation", - "icon": "waypointer.png", - "tags": "tool,outdoors,gps", - "supports": ["BANGLEJS"], - "readme": "README.md", - "interface": "waypoints.html", - "storage": [ - {"name":"waypointer.app.js","url":"app.js"}, - {"name":"waypointer.img","url":"icon.js","evaluate":true} - ], - "data": [{"name":"waypoints.json","url":"waypoints.json"}] - }, - { - "id": "color_catalog", - "name": "Colors Catalog", - "shortName": "Colors Catalog", - "version": "0.01", - "description": "Displays RGB565 and RGB888 colors, its name and code in screen.", - "icon": "app.png", - "tags": "Color,input,buttons,touch,UI", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"color_catalog.app.js","url":"app.js"}, - {"name":"color_catalog.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "UI4swatch", - "name": "UI 4 swatch", - "shortName": "UI 4 swatch", - "version": "0.01", - "description": "A UI/UX for espruino smartwatches, displays dinamically calc. x,y coordinates.", - "icon": "app.png", - "tags": "Color,input,buttons,touch,UI", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"UI4swatch.app.js","url":"app.js"}, - {"name":"UI4swatch.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "simplest", - "name": "Simplest Clock", - "version": "0.03", - "description": "The simplest working clock, acts as a tutorial piece", - "icon": "simplest.png", - "screenshots": [{"url":"screenshot_simplest.png"}], - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"simplest.app.js","url":"app.js"}, - {"name":"simplest.img","url":"icon.js","evaluate":true} - ] - }, - { - "id": "stepo", - "name": "Stepometer Clock", - "version": "0.03", - "description": "A large font watch, displays step count in a doughnut guage and warns of low battery, requires one of the steps widgets to be installed", - "icon": "stepo.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"stepo.app.js","url":"app.js"}, - {"name":"stepo.img","url":"icon.js","evaluate":true} - ] - }, - { - "id": "gbmusic", - "name": "Gadgetbridge Music Controls", - "shortName": "Music Controls", - "version": "0.08", - "description": "Control the music on your Gadgetbridge-connected phone", - "icon": "icon.png", - "screenshots": [{"url":"screenshot_v1.png"},{"url":"screenshot_v2.png"}], - "type": "app", - "tags": "tools,bluetooth,gadgetbridge,music", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "allow_emulator": true, - "storage": [ - {"name":"gbmusic.app.js","url":"app.js"}, - {"name":"gbmusic.settings.js","url":"settings.js"}, - {"name":"gbmusic.wid.js","url":"widget.js"}, - {"name":"gbmusic.img","url":"icon.js","evaluate":true} - ], - "data": [{"name":"gbmusic.json"},{"name":"gbmusic.load.json"}] - }, - { - "id": "battleship", - "name": "Battleship", - "version": "0.01", - "description": "The classic game of battleship", - "icon": "battleship-icon.png", - "tags": "game", - "supports": ["BANGLEJS"], - "screenshots": [{"url":"bangle1-battle-ship-screenshot.png"}], - "readme": "README.md", - "allow_emulator": true, - "storage": [ - {"name":"battleship.app.js","url":"battleship.js"}, - {"name":"battleship.img","url":"battleship-icon.js","evaluate":true} - ] - }, - { - "id": "kitchen", - "name": "Kitchen Combo", - "version": "0.13", - "description": "Combination of the Stepo, Walkersclock, Arrow and Waypointer apps into a multiclock format. 'Everything but the kitchen sink'", - "icon": "kitchen.png", - "type": "clock", - "tags": "tool,outdoors,gps", - "supports": ["BANGLEJS"], - "readme": "README.md", - "interface": "waypoints.html", - "storage": [ - {"name":"kitchen.app.js","url":"kitchen.app.js"}, - {"name":"stepo2.kit.js","url":"stepo2.kit.js"}, - {"name":"swatch.kit.js","url":"swatch.kit.js"}, - {"name":"gps.kit.js","url":"gps.kit.js"}, - {"name":"compass.kit.js","url":"compass.kit.js"}, - {"name":"kitchen.img","url":"kitchen.icon.js","evaluate":true} - ], - "data": [{"name":"waypoints.json","url":"waypoints.json"}] - }, - { - "id": "banglebridge", - "name": "BangleBridge", - "shortName": "BangleBridge", - "version": "0.01", - "description": "Widget that allows Bangle Js to record pair and end data using Bluetooth Low Energy in combination with the BangleBridge Android App", - "icon": "widget.png", - "type": "widget", - "tags": "widget", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"banglebridge.wid.js","url":"widget.js"}, - {"name":"banglebridge.watch.img","url":"watch.img"}, - {"name":"banglebridge.heart.img","url":"heart.img"} - ] - }, - { - "id": "qmsched", - "name": "Quiet Mode Schedule and Widget", - "shortName": "Quiet Mode", - "version": "0.06", - "description": "Automatically turn Quiet Mode on or off at set times, and change LCD options while Quiet Mode is active.", - "icon": "app.png", - "screenshots": [{"url":"screenshot_b1_main.png"},{"url":"screenshot_b1_edit.png"},{"url":"screenshot_b1_lcd.png"}, - {"url":"screenshot_b2_main.png"},{"url":"screenshot_b2_edit.png"},{"url":"screenshot_b2_lcd.png"}], - "tags": "tool,widget", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "storage": [ - {"name":"qmsched","url":"lib.js"}, - {"name":"qmsched.app.js","url":"app.js"}, - {"name":"qmsched.boot.js","url":"boot.js"}, - {"name":"qmsched.img","url":"icon.js","evaluate":true}, - {"name":"qmsched.wid.js","url":"widget.js"} - ], - "data": [{"name":"qmsched.json"}] - }, - { - "id": "hourstrike", - "name": "Hour Strike", - "shortName": "Hour Strike", - "version": "0.08", - "description": "Strike the clock on the hour. A great tool to remind you an hour has passed!", - "icon": "app-icon.png", - "tags": "tool,alarm", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"hourstrike.app.js","url":"app.js"}, - {"name":"hourstrike.boot.js","url":"boot.js"}, - {"name":"hourstrike.img","url":"app-icon.js","evaluate":true}, - {"name":"hourstrike.json","url":"hourstrike.json"} - ] - }, - { - "id": "whereworld", - "name": "Where in the World?", - "shortName": "Where World", - "version": "0.01", - "description": "Shows your current location on the world map", - "icon": "app.png", - "tags": "gps", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"whereworld.app.js","url":"app.js"}, - {"name":"whereworld.img","url":"app-icon.js","evaluate":true}, - {"name":"whereworld.worldmap","url":"worldmap"} - ] - }, - { - "id": "omnitrix", - "name": "Omnitrix", - "version": "0.01", - "description": "An Omnitrix Showpiece", - "icon": "omnitrix.png", - "screenshots": [{"url":"screenshot.png"}], - "tags": "game", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"omnitrix.app.js","url":"omnitrix.app.js"}, - {"name":"omnitrix.img","url":"omnitrix.icon.js","evaluate":true} - ] - }, - { - "id": "batclock", - "name": "Bat Clock", - "shortName": "Bat Clock", - "version": "0.02", - "description": "Morphing Clock, with an awesome \"The Dark Knight\" themed logo.", - "icon": "bat-clock.png", - "screenshots": [{"url":"screenshot.png"}], - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"batclock.app.js","url":"bat-clock.app.js"}, - {"name":"batclock.img","url":"bat-clock.icon.js","evaluate":true} - ] - }, - { - "id": "doztime", - "name": "Dozenal Time", - "shortName": "Dozenal Time", - "version": "0.04", - "description": "A dozenal Holocene calendar and dozenal diurnal clock", - "icon": "app.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS", "BANGLEJS2"], - "readme": "README.md", - "allow_emulator": true, - "storage": [ - {"name":"doztime.app.js","url":"app-bangle1.js","supports":["BANGLEJS"]}, - {"name":"doztime.app.js","url":"app-bangle2.js","supports":["BANGLEJS2"]}, - {"name":"doztime.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "gbtwist", - "name": "Gadgetbridge Twist Control", - "shortName": "Twist Control", - "version": "0.01", - "description": "Shake your wrist to control your music app via Gadgetbridge", - "icon": "app.png", - "type": "app", - "tags": "tools,bluetooth,gadgetbridge,music", - "supports": ["BANGLEJS"], - "readme": "README.md", - "allow_emulator": false, - "storage": [ - {"name":"gbtwist.app.js","url":"app.js"}, - {"name":"gbtwist.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "thermom", - "name": "Thermometer", - "version": "0.05", - "description": "Displays the current temperature in degree Celsius/Fahrenheit (depending on locale), updates every 10 seconds with average of last 5 readings.", - "icon": "app.png", - "tags": "tool", - "supports": ["BANGLEJS", "BANGLEJS2"], - "screenshots": [{"url":"screenshot.png"}], - "allow_emulator": true, - "storage": [ - {"name":"thermom.app.js","url":"app.js"}, - {"name":"thermom.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "mysticdock", - "name": "Mystic Dock", - "version": "1.00", - "description": "A retro-inspired dockface that displays the current time and battery charge while plugged in, and which features an interactive mode that shows the time, date, and a rotating data display line.", - "icon": "mystic-dock.png", - "type": "dock", - "tags": "dock", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"mysticdock.app.js","url":"mystic-dock-app.js"}, - {"name":"mysticdock.boot.js","url":"mystic-dock-boot.js"}, - {"name":"mysticdock.settings.js","url":"mystic-dock-settings.js"}, - {"name":"mysticdock.img","url":"mystic-dock-icon.js","evaluate":true} - ] - }, - { - "id": "mysticclock", - "name": "Mystic Clock", - "version": "1.01", - "description": "A retro-inspired watchface featuring time, date, and an interactive data display line.", - "icon": "mystic-clock.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "screenshots": [{"url":"bangle1-mystic-clock-screenshot.png"}], - "readme": "README.md", - "allow_emulator": true, - "storage": [ - {"name":"mysticclock.app.js","url":"mystic-clock-app.js"}, - {"name":"mysticclock.settings.js","url":"mystic-clock-settings.js"}, - {"name":"mysticclock.img","url":"mystic-clock-icon.js","evaluate":true} - ] - }, - { - "id": "hcclock", - "name": "Hi-Contrast Clock", - "version": "0.03", - "description": "Hi-Contrast Clock : A simple yet very bold clock that aims to be readable in high luninosity environments. Uses big 10x5 pixel digits. Use BTN 1 to switch background and foreground colors.", - "icon": "hcclock-icon.png", - "type": "clock", - "tags": "clock", - "screenshots": [{"url":"bangle1-high-contrast-clock-screenshot.png"}], - "supports": ["BANGLEJS"], - "allow_emulator": true, - "storage": [ - {"name":"hcclock.app.js","url":"hcclock.app.js"}, - {"name":"hcclock.img","url":"hcclock-icon.js","evaluate":true} - ] - }, - { - "id": "thermomF", - "name": "Fahrenheit Temp", - "version": "0.01", - "description": "[NOT RECOMMENDED] A modification of the Thermometer App to display temprature in Fahrenheit. Please use the 'Thermometer App' and install 'Languages' to get the temperature in the correct format for your locale.", - "icon": "thermf.png", - "tags": "tool", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"thermomF.app.js","url":"app.js"}, - {"name":"thermomF.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "nixie", - "name": "Nixie Clock", - "shortName": "Nixie", - "version": "0.01", - "description": "A nixie tube clock for both Bangle 1 and 2.", - "icon": "nixie.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"nixie.app.js","url":"app.js"}, - {"name":"nixie.img","url":"app-icon.js","evaluate":true}, - {"name":"m_vatch.js","url":"m_vatch.js"} - ] - }, - { - "id": "carcrazy", - "name": "Car Crazy", - "shortName": "Car Crazy", - "version": "0.03", - "description": "A simple car game where you try to avoid the other cars by tilting your wrist left and right. Hold down button 2 to start.", - "icon": "carcrash.png", - "tags": "game", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"carcrazy.app.js","url":"app.js"}, - {"name":"carcrazy.img","url":"app-icon.js","evaluate":true}, - {"name":"carcrazy.settings.js","url":"settings.js"} - ], - "data": [{"name":"CarCrazy.csv"}] - }, - { - "id": "shortcuts", - "name": "Shortcuts", - "shortName": "Shortcuts", - "version": "0.01", - "description": "Quickly load your favourite apps from (almost) any watch face.", - "icon": "app.png", - "type": "bootloader", - "tags": "tool", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"shortcuts.boot.js","url":"boot.js"}, - {"name":"shortcuts.settings.js","url":"settings.js"} - ], - "data": [{"name":"shortcuts.json"}] - }, - { - "id": "vectorclock", - "name": "Vector Clock", - "version": "0.03", - "description": "A digital clock that uses the built-in vector font.", - "icon": "app.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS", "BANGLEJS2"], - "allow_emulator": true, - "screenshots": [ - {"url":"bangle2-vector-clock-screenshot.png"}, - {"url":"bangle1-vector-clock-screenshot.png"} - ], - "storage": [ - {"name":"vectorclock.app.js","url":"app.js"}, - {"name":"vectorclock.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "fd6fdetect", - "name": "fd6fdetect", - "shortName": "fd6fdetect", - "version": "0.2", - "description": "Allows you to see 0xFD6F beacons near you.", - "icon": "app.png", - "tags": "tool", - "readme": "README.md", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"fd6fdetect.app.js","url":"app.js"}, - {"name":"fd6fdetect.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "choozi", - "name": "Choozi", - "version": "0.01", - "description": "Choose people or things at random using Bangle.js.", - "icon": "app.png", - "tags": "tool", - "supports": ["BANGLEJS"], - "readme": "README.md", - "allow_emulator": true, - "screenshots": [{"url":"bangle1-choozi-screenshot1.png"},{"url":"bangle1-choozi-screenshot2.png"}], - "storage": [ - {"name":"choozi.app.js","url":"app.js"}, - {"name":"choozi.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "widclkbttm", - "name": "Digital clock (Bottom) widget", - "shortName": "Digital clock Bottom Widget", - "version": "0.03", - "description": "Displays time in the bottom area.", - "icon": "widclkbttm.png", - "type": "widget", - "tags": "widget", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "storage": [ - {"name":"widclkbttm.wid.js","url":"widclkbttm.wid.js"} - ] - }, - { - "id": "pastel", - "name": "Pastel Clock", - "shortName": "Pastel", - "version": "0.10", - "description": "A Configurable clock with custom fonts, background and weather display. Has a cyclic information line that includes, day, date, battery, sunrise and sunset times", - "icon": "pastel.png", - "dependencies": {"mylocation":"app", "widpedom":"app","weather":"app"}, - "screenshots": [{"url":"screenshot_pastel.png"}, {"url":"weather_icons.png"}], - "type": "clock", - "tags": "clock, weather, tool", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "storage": [ - {"name":"f_architect","url":"f_architect.js"}, - {"name":"f_gochihand","url":"f_gochihand.js"}, - {"name":"f_cabin","url":"f_cabin.js"}, - {"name":"f_orbitron","url":"f_orbitron.js"}, - {"name":"f_monoton","url":"f_monoton.js"}, - {"name":"f_elite","url":"f_elite.js"}, - {"name":"f_lato","url":"f_lato.js"}, - {"name":"f_latosmall","url":"f_latosmall.js"}, - {"name":"pastel.app.js","url":"pastel.app.js"}, - {"name":"pastel.img","url":"pastel.icon.js","evaluate":true}, - {"name":"pastel.settings.js","url":"pastel.settings.js"} - ], - "data": [{"name":"pastel.json"}] - }, - { - "id": "antonclk", - "name": "Anton Clock", - "version": "0.03", - "description": "A simple clock using the bold Anton font.", - "icon": "app.png", - "screenshots": [{"url":"screenshot.png"}], - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "allow_emulator": true, - "storage": [ - {"name":"antonclk.app.js","url":"app.js"}, - {"name":"antonclk.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "waveclk", - "name": "Wave Clock", - "version": "0.02", - "description": "A clock using a wave image by [Lillith May](https://www.instagram.com/_lilustrations_/). **Note: Works on any Bangle.js 2, but requires firmware 2v11 or later on Bangle.js 1**", - "icon": "app.png", - "screenshots": [{"url":"screenshot.png"}], - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "allow_emulator": true, - "storage": [ - {"name":"waveclk.app.js","url":"app.js"}, - {"name":"waveclk.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "floralclk", - "name": "Floral Clock", - "version": "0.01", - "description": "A clock with a flower background by [Lillith May](https://www.instagram.com/_lilustrations_/). **Note: Works on any Bangle.js 2 but requires firmware 2v11 or later on Bangle.js 1**", - "icon": "app.png", - "screenshots": [{"url":"screenshot_floral.png"}], - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "allow_emulator": true, - "storage": [ - {"name":"floralclk.app.js","url":"app.js"}, - {"name":"floralclk.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "score", - "name": "Score Tracker", - "version": "0.01", - "description": "Score Tracker for sports that use plain numbers (e.g. Badminton, Volleyball, Soccer, Table Tennis, ...). Also supports tennis scoring.", - "icon": "score.app.png", - "screenshots": [{"url":"screenshot_score.png"}], - "type": "app", - "tags": "", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"score.app.js","url":"score.app.js"}, - {"name":"score.settings.js","url":"score.settings.js"}, - {"name":"score.presets.json","url":"score.presets.json"}, - {"name":"score.img","url":"score.app-icon.js","evaluate":true} - ], - "data": [{"name":"score.json"}] - }, - { - "id": "menusmall", - "name": "Small Menus", - "version": "0.02", - "description": "Replace Bangle.js 2's menus with a version that contains smaller text", - "icon": "app.png", - "type": "boot", - "tags": "system", - "supports": ["BANGLEJS2"], - "storage": [ - {"name":"menusmall.boot.js","url":"boot.js"} - ] - }, - { - "id": "ffcniftya", - "name": "Nifty-A Clock", - "version": "0.01", - "description": "A nifty clock with time and date", - "icon": "app.png", - "screenshots": [{"url":"screenshot_nifty.png"}], - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "allow_emulator": true, - "storage": [ - {"name":"ffcniftya.app.js","url":"app.js"}, - {"name":"ffcniftya.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "ffcniftyb", - "name": "Nifty-B Clock", - "version": "0.02", - "description": "A nifty clock (series B) with time, date and color configuration", - "icon": "app.png", - "screenshots": [{"url":"screenshot.png"}], - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "allow_emulator": true, - "storage": [ - {"name":"ffcniftyb.app.js","url":"app.js"}, - {"name":"ffcniftyb.img","url":"app-icon.js","evaluate":true}, - {"name":"ffcniftyb.settings.js","url":"settings.js"} - ], - "data": [{"name":"ffcniftyb.json"}] - }, - { - "id": "stopwatch", - "name": "Stopwatch Touch", - "version": "0.01", - "description": "A touch based stop watch for Bangle JS 2", - "icon": "stopwatch.png", - "screenshots": [{"url":"screenshot1.png"},{"url":"screenshot2.png"},{"url":"screenshot3.png"}], - "tags": "tools,app", - "supports": ["BANGLEJS2"], - "readme": "README.md", - "storage": [ - {"name":"stopwatch.app.js","url":"stopwatch.app.js"}, - {"name":"stopwatch.img","url":"stopwatch.icon.js","evaluate":true} - ] - }, - { - "id": "vernierrespirate", - "name": "Vernier Go Direct Respiration Belt", - "shortName": "Respiration Belt", - "version": "0.01", - "description": "Connects to a Go Direct Respiration Belt and shows respiration rate", - "icon": "app.png", - "tags": "health,bluetooth", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "storage": [ - {"name":"vernierrespirate.app.js","url":"app.js"}, - {"name":"vernierrespirate.img","url":"app-icon.js","evaluate":true} - ], - "data": [{"name":"vernierrespirate.json"}] - }, - { - "id": "gpstouch", - "name": "GPS Touch", - "version": "0.02", - "description": "A touch based GPS watch, shows OS map reference", - "icon": "gpstouch.png", - "screenshots": [{"url":"screenshot4.png"},{"url":"screenshot2.png"},{"url":"screenshot3.png"},{"url":"screenshot1.png"}], - "tags": "tools,app", - "supports": ["BANGLEJS2"], - "readme": "README.md", - "storage": [ - {"name":"geotools","url":"geotools.js"}, - {"name":"gpstouch.app.js","url":"gpstouch.app.js"}, - {"name":"gpstouch.img","url":"gpstouch.icon.js","evaluate":true} - ] - }, - { - "id": "swiperclocklaunch", - "name": "Swiper Clock Launch", - "version": "0.02", - "description": "Navigate between clock and launcher with Swipe action", - "icon": "swiperclocklaunch.png", - "type": "bootloader", - "tags": "tools, system", - "supports": ["BANGLEJS", "BANGLEJS2"], - "storage": [ - {"name":"swiperclocklaunch.boot.js","url":"boot.js"}, - {"name":"swiperclocklaunch.img","url":"icon.js","evaluate":true} - ] - }, - { - "id": "qalarm", - "name": "Q Alarm and Timer", - "shortName": "Q Alarm", - "icon": "app.png", - "version": "0.03", - "description": "Alarm and timer app with days of week and 'hard' option.", - "tags": "tool,alarm,widget", - "supports": ["BANGLEJS", "BANGLEJS2"], - "storage": [ - { "name": "qalarm.app.js", "url": "app.js" }, - { "name": "qalarm.boot.js", "url": "boot.js" }, - { "name": "qalarm.js", "url": "qalarm.js" }, - { "name": "qalarmcheck.js", "url": "qalarmcheck.js" }, - { "name": "qalarm.img", "url": "app-icon.js", "evaluate": true }, - { "name": "qalarm.wid.js", "url": "widget.js" } - ], - "data": [{ "name": "qalarm.json" }] - }, - { - "id": "emojuino", - "name": "Emojuino", - "shortName": "Emojuino", - "version": "0.03", - "description": "Emojis & Espruino: broadcast Unicode emojis via Bluetooth Low Energy.", - "icon": "emojuino.png", - "screenshots": [ - { "url": "screenshot-tx.png" }, - { "url": "screenshot-swipe.png" }, - { "url": "screenshot-welcome.png" } - ], - "type": "app", - "tags": "emoji", - "supports" : [ "BANGLEJS2" ], - "allow_emulator": true, - "readme": "README.md", - "storage": [ - { "name": "emojuino.app.js", "url": "emojuino.js" }, - { "name": "emojuino.img", "url": "emojuino-icon.js", "evaluate": true } - ] - }, - { - "id": "cliclockJS2Enhanced", - "name": "Commandline-Clock JS2 Enhanced", - "shortName": "CLI-Clock JS2", - "version": "0.03", - "description": "Simple CLI-Styled Clock with enhancements. Modes that are hard to use and unneded are removed (BPM, battery info, memory ect) credit to hughbarney for the original code and design. Also added HID media controlls, just swipe on the clock face to controll the media! Gadgetbride support coming soon(hopefully) Thanks to t0m1o1 for media controls!", - "icon": "app.png", - "screenshots": [{"url":"screengrab.png"}], - "type": "clock", - "tags": "clock,cli,command,bash,shell", - "supports": ["BANGLEJS","BANGLEJS2"], - "allow_emulator": true, - "storage": [ - {"name":"cliclockJS2Enhanced.app.js","url":"app.js"}, - {"name":"cliclockJS2Enhanced.img","url":"app.icon.js","evaluate":true} - ] - }, - { - "id": "wid_a_battery_widget", - "name": "A Battery Widget (with percentage)", - "shortName":"A Battery Widget", - "icon": "widget.png", - "version":"1.02", - "type": "widget", - "supports": ["BANGLEJS", "BANGLEJS2"], - "readme": "README.md", - "description": "Simple and slim battery widget with charge status and percentage", - "tags": "widget,battery", - "storage": [ - {"name":"wid_a_battery_widget.wid.js","url":"widget.js"} - ] - }, - { - "id": "lcars", - "name": "LCARS Clock", - "shortName":"LCARS", - "icon": "lcars.png", - "version":"0.09", - "readme": "README.md", - "supports": ["BANGLEJS2"], - "description": "Library Computer Access Retrieval System (LCARS) clock.", - "type": "clock", - "tags": "clock", - "screenshots": [{"url":"screenshot.png"}], - "storage": [ - {"name":"lcars.app.js","url":"lcars.app.js"}, - {"name":"lcars.img","url":"lcars.icon.js","evaluate":true}, - {"name":"lcars.settings.js","url":"lcars.settings.js"} - ] - }, - { "id": "binwatch", - "name": "Binary Watch", - "shortName":"BinWatch", - "icon": "app.png", - "screenshots": [{"url":"screenshot.png"}], - "version":"0.04", - "supports": ["BANGLEJS2"], - "readme": "README.md", - "allow_emulator":true, - "description": "Famous binary watch", - "tags": "clock", - "type": "clock", - "storage": [ - {"name":"binwatch.app.js","url":"app.js"}, - {"name":"binwatch.bg176.img","url":"Background176_center.img"}, - {"name":"binwatch.bg240.img","url":"Background240_center.img"}, - {"name":"binwatch.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "hidmsicswipe", - "name": "Bluetooth Music Swipe Controls", - "shortName": "Swipe Control", - "version": "0.01", - "description": "Based on the original Bluetooth Music Controls. Swipe up/down for volume, left/right for previous and next, tap for play/pause and btn1 to lock and unlock the controls. Enable HID in settings, pair with your phone, then use this app to control music from your watch!", - "icon": "hidmsicswipe.png", - "tags": "bluetooth", - "supports": ["BANGLEJS2"], - "storage": [ - {"name":"hidmsicswipe.app.js","url":"hidmsicswipe.js"}, - {"name":"hidmsicswipe.img","url":"hidmsicswipe-icon.js","evaluate":true} - ] - }, - { - "id": "authentiwatch", - "name": "2FA Authenticator", - "shortName": "AuthWatch", - "icon": "app.png", - "screenshots": [{"url":"screenshot.png"}], - "version": "0.04", - "description": "Google Authenticator compatible tool.", - "tags": "tool", - "interface": "interface.html", - "supports": ["BANGLEJS", "BANGLEJS2"], - "readme": "README.md", - "allow_emulator": true, - "storage": [ - {"name":"authentiwatch.app.js","url":"app.js"}, - {"name":"authentiwatch.img","url":"app-icon.js","evaluate":true} - ], - "data": [{"name":"authentiwatch.json"}] - }, - { "id": "schoolCalendar", - "name": "School Calendar", - "shortName":"SCalendar", - "icon": "CalenderLogo.png", - "version": "0.01", - "description": "A simple calendar that you can see your upcoming events that you create in the customizer. Keep in note that your events reapeat weekly.(Beta)", - "tags": "tool", - "readme":"README.md", - "custom":"custom.html", - "supports": ["BANGLEJS"], - "screenshots": [{"url":"screenshot_basic.png"},{"url":"screenshot_info.png"}], - "storage": [ - {"name":"schoolCalendar.app.js"}, - {"name":"schoolCalendar.img","url":"app-icon.js","evaluate":true} - ], - "data": [ - {"name":"calendarItems.csv"} - ] - }, - { "id": "timecal", - "name": "TimeCal", - "shortName":"TimeCal", - "icon": "icon.png", - "version":"0.01", - "description": "TimeCal shows the Time along with a 3 week calendar", - "tags": "clock", - "type": "clock", - "supports":["BANGLEJS2"], - "storage": [ - {"name":"timecal.app.js","url":"timecal.app.js"} - ] - }, - { - "id": "a_clock_timer", - "name": "A Clock with Timer", - "version": "0.01", - "description": "A Clock with Timer, Map and Time Zones", - "icon": "app.png", - "screenshots": [{"url":"screenshot.png"}], - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS2"], - "allow_emulator": true, - "readme": "README.md", - "storage": [ - {"name":"a_clock_timer.app.js","url":"app.js"}, - {"name":"a_clock_timer.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id":"intervalTimer", - "name":"Interval Timer", - "shortName":"Interval Timer", - "icon": "app.png", - "version":"0.01", - "description": "Interval Timer for workouts, HIIT, or whatever else.", - "tags": "timer, interval, hiit, workout", - "readme":"README.md", - "supports":["BANGLEJS2"], - "storage": [ - {"name":"intervalTimer.app.js","url":"app.js"}, - {"name":"intervalTimer.img","url":"app-icon.js","evaluate":true} - ] - }, - { "id": "93dub", - "name": "93 Dub", - "shortName":"93 Dub", - "icon": "93dub.png", - "screenshots": [{"url":"screenshot.png"}], - "version":"0.06", - "description": "Fan recreation of orviwan's 91 Dub app for the Pebble smartwatch. Uses assets from his 91-Dub-v2.0 repo", - "tags": "clock", - "type": "clock", - "supports":["BANGLEJS2"], - "readme": "README.md", - "allow_emulator": true, - "storage": [ - {"name":"93dub.app.js","url":"app.js"}, - {"name":"93dub.img","url":"app-icon.js","evaluate":true} - ] - }, - { "id": "poweroff", - "name": "Poweroff", - "shortName":"Poweroff", - "version":"0.01", - "description": "Simple app to power off your Bangle.js", - "icon": "app.png", - "tags": "tool, poweroff, shutdown", - "supports" : ["BANGLEJS", "BANGLEJS2"], - "readme": "README.md", - "allow_emulator": true, - "storage": [ - {"name":"poweroff.app.js","url":"app.js"}, - {"name":"poweroff.img","url":"app-icon.js","evaluate":true} - ] -}, -{ - "id": "sensible", - "name": "SensiBLE", - "shortName": "SensiBLE", - "version": "0.05", - "description": "Collect, display and advertise real-time sensor data.", - "icon": "sensible.png", - "screenshots": [ - { "url": "screenshot-top.png" }, - { "url": "screenshot-acc.png" }, - { "url": "screenshot-bar.png" }, - { "url": "screenshot-gps.png" }, - { "url": "screenshot-hrm.png" }, - { "url": "screenshot-mag.png" } - ], - "type": "app", - "tags": "tool,sensors", - "supports" : [ "BANGLEJS2" ], - "allow_emulator": true, - "readme": "README.md", - "storage": [ - { "name": "sensible.app.js", "url": "sensible.js" }, - { "name": "sensible.img", "url": "sensible-icon.js", "evaluate": true } - ] -}, - { - "id": "widbars", - "name": "Bars Widget", - "version": "0.01", - "description": "Display several measurements as vertical bars.", - "icon": "icon.png", - "screenshots": [{"url":"screenshot.png"}], - "readme": "README.md", - "type": "widget", - "tags": "widget", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"widbars.wid.js","url":"widget.js"} - ] -}, -{ - "id":"a_speech_timer", - "name":"Speech Timer", - "icon": "app.png", - "version":"1.01", - "description": "A timer designed to help keeping your speeches and presentations to time.", - "tags": "tool,timer", - "readme":"README.md", - "supports":["BANGLEJS2"], - "screenshots": [{"url":"screenshot1.png"},{"url":"screenshot2.png"},{"url":"screenshot3.png"}], - "allow_emulator": true, - "storage": [ - {"name":"a_speech_timer.app.js","url":"app.js"}, - {"name":"a_speech_timer.img","url":"app-icon.js","evaluate":true} - ] -}, - { "id": "mylocation", - "name": "My Location", - "shortName":"My Location", - "icon": "mylocation.png", - "type": "app", - "screenshots": [{"url":"screenshot_1.png"}], - "version":"0.02", - "description": "Sets and stores the lat and long of your preferred City or it can be set from the GPS. mylocation.json can be used by other apps that need your main location lat and lon. See README", - "readme": "README.md", - "tags": "tool,utility", - "supports": ["BANGLEJS", "BANGLEJS2"], - "storage": [ - {"name":"mylocation.app.js","url":"mylocation.app.js"}, - {"name":"mylocation.img","url":"mylocation.icon.js","evaluate": true } - ], - "data": [ - {"name":"mylocation.json"} - ] - }, - { - "id": "pebble", - "name": "Pebble Clock", - "shortName": "Pebble", - "version": "0.07", - "description": "A pebble style clock to keep the rebellion going", - "dependencies": {"widpedom":"app"}, - "readme": "README.md", - "icon": "pebble.png", - "screenshots": [{"url":"pebble_screenshot.png"}], - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS", "BANGLEJS2"], - "storage": [ - {"name":"pebble.app.js","url":"pebble.app.js"}, - {"name":"pebble.settings.js","url":"pebble.settings.js"}, - {"name":"pebble.img","url":"pebble.icon.js","evaluate":true} - ] - }, - { "id": "pooqroman", - "name": "pooq Roman watch face", - "shortName":"pooq Roman", - "version":"0.03", - "description": "A classic watch face with a certain dynamicity. Most amusing in 24h mode. Slide up to show more hands, down for less(!). By design does not support standard widgets, sorry!", - "icon": "app.png", - "type": "clock", - "tags": "clock", - "supports" : ["BANGLEJS2"], - "allow_emulator":true, - "readme": "README.md", - "storage": [ - {"name":"pooqroman.app.js","url":"app.js"}, - {"name":"pooqroman.img","url":"app-icon.js","evaluate":true} - ], - "data": [ - {"name":"pooqroman.json"} - ] - }, - { - "id": "widbata", - "name": "Battery Level Widget (Themed)", - "shortName":"Battery Theme", - "icon": "widbata.png", - "screenshots": [{"url":"screenshot_widbata_1.png"}], - "version":"0.01", - "type": "widget", - "supports": ["BANGLEJS", "BANGLEJS2"], - "readme": "README.md", - "description": "Shows the current battery level status in the top right using the clocks colour theme", - "tags": "widget,battery", - "storage": [ - {"name":"widbata.wid.js","url":"widbata.wid.js"} - ] - }, - { - "id": "weatherClock", - "name": "Weather Clock", - "version": "0.05", - "description": "A clock which displays current weather conditions (requires Gadgetbridge and Weather apps).", - "icon": "app.png", - "screenshots": [{"url":"screens/screen1.png"}], - "type": "clock", - "tags": "clock, weather", - "supports": ["BANGLEJS","BANGLEJS2"], - "allow_emulator": true, - "readme": "README.md", - "storage": [ - {"name":"weatherClock.app.js","url":"app.js"}, - {"name":"weatherClock.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "menuwheel", - "name": "Wheel Menus", - "version": "0.01", - "description": "Replace Bangle.js 2's menus with a version that contains variable-size text and a back button", - "readme": "README.md", - "icon": "icon.png", - "screenshots": [ - {"url":"screenshot_b1_dark.png"},{"url":"screenshot_b1_edit.png"},{"url":"screenshot_b1_light.png"}, - {"url":"screenshot_b2_dark.png"},{"url":"screenshot_b2_edit.png"},{"url":"screenshot_b2_light.png"} - ], - "type": "boot", - "tags": "system", - "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 } - ] - }, - { "id": "tinydraw", - "name": "TinyDraw", - "shortName":"TinyDraw", - "version":"0.01", - "type": "app", - "description": "Draw stuff in your wrist", - "icon": "app.png", - "allow_emulator": true, - "tags": "tools, keyboard, text, scribble", - "supports" : ["BANGLEJS2"], - "readme": "README.md", - "storage": [ - {"name":"tinydraw.app.js","url":"app.js"}, - {"name":"tinydraw.img","url":"app-icon.js","evaluate":true} - ], - "screenshots":[ - { "url":"screenshot.png" } - ] - }, - { "id": "scribble", - "name": "Scribble", - "shortName":"Scribble", - "version":"0.01", - "type": "app", - "description": "A keyboard on your wrist! Swipe right for space, left for delete.", - "icon": "app.png", - "allow_emulator": true, - "tags": "tools, keyboard, text, scribble", - "supports" : ["BANGLEJS2"], - "readme": "README.md", - "storage": [ - {"name":"scribble.app.js","url":"app.js"}, - {"name":"scribble.img","url":"app-icon.js","evaluate":true} - ], - "screenshots":[ - { "url":"screenshot.png" } - ] - }, - { - "id": "ptlaunch", - "name": "Pattern Launcher", - "shortName": "Pattern Launcher", - "version": "0.13", - "description": "Directly launch apps from the clock screen with custom patterns.", - "icon": "app.png", - "screenshots": [{"url":"manage_patterns_light.png"}], - "tags": "tools", - "supports": ["BANGLEJS2"], - "readme": "README.md", - "storage": [ - { "name": "ptlaunch.app.js", "url": "app.js" }, - { "name": "ptlaunch.boot.js", "url": "boot.js" }, - { "name": "ptlaunch.img", "url": "app-icon.js", "evaluate": true } - ], - "data": [{"name":"ptlaunch.patterns.json"}] - }, - { "id": "slimehunt", - "name": "Slime Hunt", - "shortName":"SlimeHunt", - "icon": "app.png", - "version":"0.02", - "description": "Fight against slimes in turn based combat, try to get the highscore!", - "tags": "rpg,slime", - "supports" : ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"slimehunt.app.js","url":"app.js"}, - {"name":"slimehunt.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "rebble", - "name": "Rebble Clock", - "shortName": "Rebble", - "version": "0.04", - "description": "A Pebble style clock, with configurable background, three sidebars including steps, day, date, sunrise, sunset, long live the rebellion", - "readme": "README.md", - "icon": "rebble.png", - "dependencies": {"mylocation":"app", "widpedom":"app"}, - "screenshots": [{"url":"screenshot_rebble.png"}], - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS2"], - "storage": [ - {"name":"rebble.app.js","url":"rebble.app.js"}, - {"name":"rebble.settings.js","url":"rebble.settings.js"}, - {"name":"rebble.img","url":"rebble.icon.js","evaluate":true} - ] - }, - { "id": "snaky", - "name": "Snaky", - "shortName":"Snaky", - "version":"0.01", - "description": "The classic snake game. Eat apples and don't bite your tail. Control the snake with the touch screen.", - "tags": "game,fun", - "icon": "snaky.png", - "supports" : ["BANGLEJS2"], - "readme": "README.md", - "storage": [ - {"name":"snaky.app.js","url":"snaky.js"}, - {"name":"snaky.img","url":"snaky-icon.js","evaluate":true} - ] - }, - { - "id": "clicompleteclk", - "name": "CLI complete clock", - "shortName":"CLI cmplt clock", - "version":"0.03", - "description": "Command line styled clock with lots of information", - "icon": "app.png", - "allow_emulator": true, - "type": "clock", - "tags": "clock,cli,command,bash,shell,weather,hrt", - "supports" : ["BANGLEJS", "BANGLEJS2"], - "readme": "README.md", - "storage": [ - {"name":"clicompleteclk.app.js","url":"app.js"}, - {"name":"clicompleteclk.img","url":"app-icon.js","evaluate":true}, - {"name":"clicompleteclk.settings.js","url":"settings.js"} - ], - "data": [{"name":"clicompleteclk.json"}] - }, - { - "id":"awairmonitor", - "name":"Awair Monitor", - "icon": "app.png", - "screenshots": [{"url":"screenshot.png"}], - "allow_emulator": true, - "version":"0.03", - "description": "Displays the level of CO2, VOC, PM 2.5, Humidity and Temperature, from your Awair device.", - "type": "clock", - "tags": "clock,tool,health", - "readme":"README.md", - "supports":["BANGLEJS2"], - "storage": [ - {"name":"awairmonitor.app.js","url":"app.js"}, - {"name":"awairmonitor.img","url":"app-icon.js","evaluate":true} - ] - }, - { "id": "pooqround", - "name": "pooq Round watch face", - "shortName":"pooq Round", - "version":"0.01", - "description": "A 24 hour analogue watchface with high legibility and a novel style.", - "icon": "app.png", - "type": "clock", - "tags": "clock", - "supports" : ["BANGLEJS2"], - "allow_emulator":true, - "readme": "README.md", - "storage": [ - {"name":"pooqround.app.js","url":"app.js"}, - {"name":"pooqround.img","url":"app-icon.js","evaluate":true} - ], - "data": [ - {"name":"pooqround.json"} - ] - }, - { - "id": "coretemp", - "name": "CoreTemp", - "version": "0.02", - "description": "Display CoreTemp device sensor data", - "icon": "coretemp.png", - "type": "app", - "tags": "health", - "readme": "README.md", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"coretemp.wid.js","url":"widget.js"}, - {"name":"coretemp.app.js","url":"coretemp.js"}, - {"name":"coretemp.settings.js","url":"settings.js"}, - {"name":"coretemp.img","url":"coretemp-icon.js","evaluate":true}, - {"name":"coretemp.boot.js","url":"boot.js"} - ], - "data": [{"name":"coretemp.json","url":"app-settings.json"}], - "screenshots": [{"url":"screenshot.png"}] - }, - { - "id": "showimg", - "name": "simple image viewer", - "shortName":"showImage", - "version":"0.2", - "description": "Displays the image in \"showimg.user.img\". The file has to be uploaded via the espruino IDE. Returns to watch face after 60s or button push. I use it to display my vaccination certificate.", - "icon": "app.png", - "tags": "tool", - "supports" : ["BANGLEJS2"], - "storage": [ - {"name":"showimg.app.js","url":"app.js"}, - {"name":"showimg.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "lapcounter", - "name": "Lap Counter", - "version": "0.01", - "description": "Click button to count laps. Shows count and total time snapshot (like a stopwatch, but laid back).", - "icon": "app.png", - "screenshots": [{"url":"screenshot.png"}], - "type": "app", - "tags": "tool,outdoors", - "readme":"README.md", - "supports": ["BANGLEJS", "BANGLEJS2"], - "allow_emulator": true, - "storage": [ - {"name":"lapcounter.app.js","url":"app.js"}, - {"name":"lapcounter.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "pebbled", - "name": "Pebble Clock with distance", - "shortName": "Pebble + distance", - "version": "0.1", - "description": "Fork of Pebble Clock with distance in KM. Both step count and the distance are on the main screen. Default step length = 0.75m (can be changed in settings).", - "readme": "README.md", - "icon": "pebbled.png", - "screenshots": [{"url":"pebble_screenshot.png"}], - "type": "clock", - "tags": "clock,distance", - "supports": ["BANGLEJS2"], - "storage": [ - {"name":"pebbled.app.js","url":"pebbled.app.js"}, - {"name":"pebbled.settings.js","url":"pebbled.settings.js"}, - {"name":"pebbled.img","url":"pebbled.icon.js","evaluate":true} - ] - }, - { "id": "circlesclock", - "name": "Circles clock", - "shortName":"Circles clock", - "version":"0.03", - "description": "A clock with circles for different data at the bottom in a probably familiar style", - "icon": "app.png", - "screenshots": [{"url":"screenshot.png"}], - "dependencies": {"widpedom":"app"}, - "type": "clock", - "tags": "clock", - "supports" : ["BANGLEJS2"], - "allow_emulator":true, - "readme": "README.md", - "storage": [ - {"name":"circlesclock.app.js","url":"app.js"}, - {"name":"circlesclock.img","url":"app-icon.js","evaluate":true}, - {"name":"circlesclock.settings.js","url":"settings.js"} - ], - "data": [ - {"name":"circlesclock.json"} - ] - }, - { "id": "contourclock", - "name": "Contour Clock", - "shortName" : "Contour Clock", - "version":"0.01", - "icon": "app.png", - "description": "A Minimalist clockface with large Digits. Looks best with the dark theme", - "screenshots" : [{"url":"screenshot.png"}], - "tags": "clock", - "allow_emulator":true, - "supports" : ["BANGLEJS2"], - "type": "clock", - "storage": [ - {"name":"contourclock.app.js","url":"app.js"}, - {"name":"contourclock.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "ltherm", - "name": "Localized Thermometer", - "shortName": "Thermometer", - "version": "0.01", - "description": "Displays the current temperature in localized units.", - "icon": "thermf.png", - "tags": "tool", - "supports": ["BANGLEJS2"], - "allow_emulator": true, - "readme": "README.md", - "storage": [ - {"name":"ltherm.app.js","url":"app.js"}, - {"name":"ltherm.img","url":"icon.js","evaluate":true} - ] - }, - { - "id": "presentor", - "name": "Presentor", - "version": "3.0", - "description": "Use your Bangle to present!", - "icon": "app.png", - "type": "app", - "tags": "tool,bluetooth", - "interface": "interface.html", - "readme":"README.md", - "supports": ["BANGLEJS", "BANGLEJS2"], - "allow_emulator": true, - "storage": [ - {"name":"presentor.app.js","url":"app.js"}, - {"name":"presentor.img","url":"app-icon.js","evaluate":true}, - {"name":"presentor.json","url":"settings.json"} - ] - }, - { - "id": "slash", - "name": "Slash Watch", - "shortName":"Slash", - "icon": "slash.png", - "screenshots": [{"url":"screenshot.png"}], - "version":"0.01", - "description": "Slash Watch based on Pebble watch face by Nikki.", - "tags": "clock", - "type": "clock", - "supports":["BANGLEJS2"], - "readme": "README.md", - "allow_emulator": true, - "storage": [ - {"name":"slash.app.js","url":"app.js"}, - {"name":"slash.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "promenu", - "name": "Pro Menu", - "version": "0.01", - "description": "Replace Bangle.js 1's built in menu function.", - "icon": "icon.png", - "type": "boot", - "tags": "system", - "supports": ["BANGLEJS"], - "screenshots": [{"url":"pro-menu-screenshot.png"}], - "storage": [ - {"name":"promenu.boot.js","url":"boot.js"}, - {"name":"promenu.img","url":"promenuIcon.js","evaluate":true} - ] - }, - { - "id": "touchtimer", - "name": "Touch Timer", - "shortName": "Touch Timer", - "version": "0.02", - "description": "Quickly and easily create a timer with touch-only input. The time can be easily set with a number pad.", - "icon": "app.png", - "tags": "tools", - "supports": ["BANGLEJS2"], - "readme": "README.md", - "screenshots": [{"url":"0_light_timer_edit.png"},{"url":"1_light_timer_ready.png"},{"url":"2_light_timer_running.png"},{"url":"3_light_timer_finished.png"}], - "storage": [ - { "name": "touchtimer.app.js", "url": "app.js" }, - { "name":"touchtimer.settings.js", "url":"settings.js"}, - { "name": "touchtimer.img", "url": "app-icon.js", "evaluate": true } - ], - "data": [{"name":"touchtimer.data.json"}] - }, - { - "id": "teatimer", - "name": "Tea Timer", - "version": "1.00", - "description": "A simple timer. You can easyly set up the time.", - "icon": "teatimer.png", - "type": "app", - "tags": "tool", - "supports": ["BANGLEJS2"], - "readme": "README.md", - "storage": [ - {"name":"teatimer.app.js","url":"app.js"}, - {"name":"teatimer.img","url":"app-icon.js","evaluate":true} - ], - "screenshots": [ - {"url":"TeatimerStart.jpg"}, - {"url":"TeatimerHelp.jpg"}, - {"url":"TeatimerRun.jpg"}, - {"url":"TeatimerUp.jpg"} - ] - }, - { - "id": "swp2clk", - "name": "Swipe back to the Clock", - "shortName": "Swipe to Clock", - "version": "0.01", - "description": "Let's you swipe from left to right on any app to return back to the clock face. Please configure in the settings app after installing to activate, since its disabled by default.", - "icon": "app.png", - "type": "boot", - "tags": "tools", - "supports": ["BANGLEJS2"], - "readme": "README.md", - "storage": [ - { "name": "swp2clk.boot.js", "url": "boot.js" }, - {"name":"swp2clk.settings.js","url":"settings.js"} - ], - "data": [{"name":"swp2clk.data.json"}] - }, - { - "id":"colorwheel", - "name":"Color Wheel", - "tags":"app,tool", - "version":"0.01", - "description":"a tappable wheel of good-looking colors", - "readme":"README.md", - "supports":["BANGLEJS2"], - "allow_emulator":true, - "icon":"colorwheel.png", - "storage": [ - {"name":"colorwheel.app.js","url":"app.js"}, - {"name":"colorwheel.img","url":"app-icon.js","evaluate":true} - ] - }, - { "id": "minimal_clock", - "name": "Minimal Analog Clock", - "shortName":"Minimal Clock", - "version":"0.03", - "description": "a minimal analog clock - just with some hands and no clock face", - "icon": "app-icon.png", - "type": "clock", - "tags": "clock", - "supports" : ["BANGLEJS2"], - "allow_emulator": true, - "screenshots": [{"url":"app-screenshot.png"}], - "readme": "README.md", - "storage": [ - {"name":"minimal_clock.app.js","url":"app.js"}, - {"name":"minimal_clock.img","url":"app-icon.js","evaluate":true} - ] - }, - { "id": "simple_clock", - "name": "Simple Analog Clock", - "shortName":"Simple Clock", - "version":"0.02", - "description": "a simple, yet stylish, analog clock", - "icon": "app-icon.png", - "type": "clock", - "tags": "clock", - "supports" : ["BANGLEJS2"], - "allow_emulator": true, - "screenshots": [{"url":"app-screenshot.png"}], - "readme": "README.md", - "storage": [ - {"name":"simple_clock.app.js","url":"app.js"}, - {"name":"simple_clock.img","url":"app-icon.js","evaluate":true} - ] - }, - { "id": "colorful_clock", - "name": "Colorful Analog Clock", - "shortName":"Colorful Clock", - "version":"0.02", - "description": "a colorful analog clock", - "icon": "app-icon.png", - "type": "clock", - "tags": "clock", - "supports" : ["BANGLEJS2"], - "allow_emulator": true, - "screenshots": [{"url":"app-screenshot.png"}], - "readme": "README.md", - "storage": [ - {"name":"colorful_clock.app.js","url":"app.js"}, - {"name":"colorful_clock.img","url":"app-icon.js","evaluate":true} - ] - }, - { "id": "themesetter", - "name": "Theme Setter", - "shortName":"Theme Setter", - "version":"0.04", - "description": "a comfortable way to configure theme colors", - "icon": "app-icon.png", - "type": "app", - "tags": "tool", - "supports" : ["BANGLEJS2"], - "allow_emulator": true, - "screenshots": [{"url":"app-screenshot.png"}], - "readme": "README.md", - "storage": [ - {"name":"themesetter.app.js","url":"app.js"}, - {"name":"themesetter.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "widviztime", - "name": "Widget Autohide Widget", - "shortName": "Viz Time Widget", - "version": "0.01", - "description": "The widgets will be shown for four seconds after the device is unlocked.", - "icon": "eye.png", - "type": "widget", - "tags": "widget", - "readme":"README.md", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"widviztime.wid.js","url":"widget.js"} - ] - }, - { - "id": "supf", - "name": "Simple Clock with Date", - "shortName": "supf Clock", - "version": "0.01", - "description": "Simple Clock with seconds and date in custom language. Install 'Languages' to get localized names.", - "icon": "icon.png", - "screenshots": [{"url":"screenshot_supf.png"}], - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS2"], - "allow_emulator": true, - "readme": "README.md", - "storage": [ - {"name":"supf.app.js","url":"app.js"}, - {"name":"supf.img","url":"icon.js","evaluate":true} - ] - }, - { "id": "andark", - "name": "Analog Dark", - "shortName":"AnDark", - "version":"0.04", - "description": "analog clock face without disturbing widgets", - "icon": "andark_icon.png", - "type": "clock", - "tags": "clock", - "supports" : ["BANGLEJS2"], - "readme": "README.md", - "storage": [ - {"name":"andark.app.js","url":"app.js"}, - {"name":"andark.img","url":"app_icon.js","evaluate":true} - ] - }, - { - "id": "diract", - "name": "DirAct", - "shortName": "DirAct", - "version": "0.01", - "description": "Proximity interaction detection.", - "icon": "diract.png", - "type": "app", - "tags": "tool,sensors", - "supports" : [ "BANGLEJS2" ], - "allow_emulator": false, - "readme": "README.md", - "storage": [ - { "name": "diract.app.js", "url": "diract.js" }, - { "name": "diract.img", "url": "diract-icon.js", "evaluate": true } - ] - }, - { - "id": "sonicclk", - "name": "Sonic Clock", - "version": "1.01", - "description": "A classic sonic clock featuring run, stop and wait animations.", - "icon": "app.png", - "screenshots": [{"url":"screenshot.png"}], - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS2"], - "allow_emulator": true, - "readme": "README.md", - "storage": [ - {"name":"sonicclk.app.js","url":"app.js"}, - {"name":"sonicclk.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "touchmenu", - "name": "TouchMenu", - "version": "0.01", - "description": "Redesigned menu that uses the full touchscreen on the Bangle.js 2", - "screenshots": [{"url":"touchmenu.gif"}], - "icon": "touchmenu.png", - "type": "bootloader", - "tags": "tool", - "supports": ["BANGLEJS2"], - "storage": [ - {"name":"touchmenu.boot.js","url":"touchmenu.boot.js"} - ] - }, - { - "id": "puzzle15", - "name": "15 puzzle", - "version": "0.05", - "description": "A 15 puzzle game with drag gesture interface", - "readme":"README.md", - "icon": "puzzle15.app.png", - "screenshots": [{"url":"screenshot.png"}], - "type": "app", - "tags": "game", - "supports": ["BANGLEJS2"], - "allow_emulator": true, - "storage": [ - {"name":"puzzle15.app.js","url":"puzzle15.app.js"}, - {"name":"puzzle15.settings.js","url":"puzzle15.settings.js"}, - {"name":"puzzle15.img","url":"puzzle15.app-icon.js","evaluate":true} - ], - "data": [{"name":"puzzle15.json"}] - } -] diff --git a/apps/gbridge/metadata.json b/apps/gbridge/metadata.json new file mode 100644 index 000000000..cdbc95c11 --- /dev/null +++ b/apps/gbridge/metadata.json @@ -0,0 +1,18 @@ +{ + "id": "gbridge", + "name": "Gadgetbridge", + "version": "0.25", + "description": "(NOT RECOMMENDED) Displays Gadgetbridge notifications from Android. Please use the 'Android' Bangle.js app instead.", + "icon": "app.png", + "type": "widget", + "tags": "tool,system,android,widget", + "supports": ["BANGLEJS","BANGLEJS2"], + "dependencies": {"notify":"type"}, + "readme": "README.md", + "storage": [ + {"name":"gbridge.settings.js","url":"settings.js"}, + {"name":"gbridge.img","url":"app-icon.js","evaluate":true}, + {"name":"gbridge.wid.js","url":"widget.js"} + ], + "data": [{"name":"gbridge.json"}] +} diff --git a/apps/lcars/metadata.json b/apps/lcars/metadata.json new file mode 100644 index 000000000..5f4e1ffe3 --- /dev/null +++ b/apps/lcars/metadata.json @@ -0,0 +1,18 @@ +{ + "id": "lcars", + "name": "LCARS Clock", + "shortName":"LCARS", + "icon": "lcars.png", + "version":"0.07", + "readme": "README.md", + "supports": ["BANGLEJS2"], + "description": "Library Computer Access Retrieval System (LCARS) clock.", + "type": "clock", + "tags": "clock", + "screenshots": [{"url":"screenshot.png"}], + "storage": [ + {"name":"lcars.app.js","url":"lcars.app.js"}, + {"name":"lcars.img","url":"lcars.icon.js","evaluate":true}, + {"name":"lcars.settings.js","url":"lcars.settings.js"} + ] +} From 03d6a5058048351b9326bc03f2a6279b9d1031ce Mon Sep 17 00:00:00 2001 From: Adam Schmalhofer Date: Wed, 5 Jan 2022 14:13:02 +0100 Subject: [PATCH 002/174] Let apps.json be generated by Liquid template Instead of plugin as tried first. Turns out github doesn't allow own plugins (unlike gitlab). It is the simpler and more elegant solution any how. --- .gitignore | 1 - _plugins/AppsJsonGenerator.rb | 26 -------------------------- apps.json | 14 ++++++++++++++ 3 files changed, 14 insertions(+), 27 deletions(-) delete mode 100644 _plugins/AppsJsonGenerator.rb create mode 100644 apps.json diff --git a/.gitignore b/.gitignore index 6542325c5..47233d1f5 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,3 @@ appdates.csv _config.yml tests/Layout/bin/tmp.* tests/Layout/testresult.bmp -/apps.json diff --git a/_plugins/AppsJsonGenerator.rb b/_plugins/AppsJsonGenerator.rb deleted file mode 100644 index 1a6525cca..000000000 --- a/_plugins/AppsJsonGenerator.rb +++ /dev/null @@ -1,26 +0,0 @@ -class AppsJsonPage < Jekyll::Page - def initialize(site) - @site = site - @base = site.source - @basename = 'apps' - @ext = '.json' - @name = 'apps.json' - @data = {} - end -end - -# Generates the apps.json -# out of all the /apps/*/metadata.json files -class Generator < Jekyll::Generator - safe true - - def generate(site) - metadatas = site.static_files.select { |file| file.name == 'metadata.json' } - json = metadatas.map { |file| JSON.load(open(file.path)) } - appsjson = AppsJsonPage.new(site) - open(appsjson.path, 'wb') do |file| - file << JSON.generate(json) - end - site.pages << appsjson - end -end diff --git a/apps.json b/apps.json new file mode 100644 index 000000000..c62663ee0 --- /dev/null +++ b/apps.json @@ -0,0 +1,14 @@ +--- +layout: none +--- +{%- assign apps = site.static_files | where: "name", "metadata.json" -%} + +[ + +{%- include_relative {{ apps.first.path }} -%} + +{%- for app in apps offset:1 -%} +,{%- include_relative {{ app.path }} -%} +{%- endfor -%} + +] From 7c833a21cb13901a1885152291248f34ee1070b1 Mon Sep 17 00:00:00 2001 From: Adam Schmalhofer Date: Wed, 5 Jan 2022 14:17:51 +0100 Subject: [PATCH 003/174] Cleanup remove unneeded layout definition in apps.json --- apps.json | 1 - 1 file changed, 1 deletion(-) diff --git a/apps.json b/apps.json index c62663ee0..4783d84cd 100644 --- a/apps.json +++ b/apps.json @@ -1,5 +1,4 @@ --- -layout: none --- {%- assign apps = site.static_files | where: "name", "metadata.json" -%} From d8d0dae4b5ad6bf004563c3a00a878148f03a58c Mon Sep 17 00:00:00 2001 From: Adam Schmalhofer Date: Thu, 6 Jan 2022 23:37:38 +0100 Subject: [PATCH 004/174] metadata for _example_app, _widget as the folder starts with "_" jekyll ignores that. So no additional logic needed in apps.json --- apps/_example_app/{add_to_apps.json => metadata.json} | 1 - apps/_example_widget/{add_to_apps.json => metadata.json} | 1 - 2 files changed, 2 deletions(-) rename apps/_example_app/{add_to_apps.json => metadata.json} (89%) rename apps/_example_widget/{add_to_apps.json => metadata.json} (89%) diff --git a/apps/_example_app/add_to_apps.json b/apps/_example_app/metadata.json similarity index 89% rename from apps/_example_app/add_to_apps.json rename to apps/_example_app/metadata.json index cc28e1e93..e0d664338 100644 --- a/apps/_example_app/add_to_apps.json +++ b/apps/_example_app/metadata.json @@ -1,4 +1,3 @@ -// Create an entry in apps.json as follows: { "id": "7chname", "name": "My app's human readable name", "shortName":"Short Name", diff --git a/apps/_example_widget/add_to_apps.json b/apps/_example_widget/metadata.json similarity index 89% rename from apps/_example_widget/add_to_apps.json rename to apps/_example_widget/metadata.json index b55adce9d..ad4b7537d 100644 --- a/apps/_example_widget/add_to_apps.json +++ b/apps/_example_widget/metadata.json @@ -1,4 +1,3 @@ -// Create an entry in apps.json as follows: { "id": "7chname", "name": "My widget's human readable name", "shortName":"Short Name", From 6f9cd734254dd76ef9cada7819b4b2b2bd41e8c7 Mon Sep 17 00:00:00 2001 From: Adam Schmalhofer Date: Fri, 7 Jan 2022 01:14:18 +0100 Subject: [PATCH 005/174] Port sanitychess.js to metadata.json --- bin/sanitycheck.js | 49 +++++++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/bin/sanitycheck.js b/bin/sanitycheck.js index e50256fb6..b5577d3f2 100755 --- a/bin/sanitycheck.js +++ b/bin/sanitycheck.js @@ -26,29 +26,34 @@ function WARN(s) { console.log("Warning: "+s); } -var appsFile, apps; -try { - appsFile = fs.readFileSync(BASEDIR+"apps.json").toString(); -} catch (e) { - ERROR("apps.json not found"); -} -try{ - apps = JSON.parse(appsFile); -} catch (e) { - console.log(e); - var m = e.toString().match(/in JSON at position (\d+)/); - if (m) { - var char = parseInt(m[1]); - console.log("==============================================="); - console.log("LINE "+appsFile.substr(0,char).split("\n").length); - console.log("==============================================="); - console.log(appsFile.substr(char-10, 20)); - console.log("==============================================="); +var apps = []; +var dirs = fs.readdirSync(APPSDIR, {withFileTypes: true}); +dirs.forEach(dir => { + var appsFile; + if (dir.name.startsWith("_example")) + return; + try { + appsFile = fs.readFileSync(APPSDIR+dir.name+"/metadata.json").toString(); + } catch (e) { + return; } - console.log(m); - ERROR("apps.json not valid JSON"); - -} + try{ + apps.push(JSON.parse(appsFile)); + } catch (e) { + console.log(e); + var m = e.toString().match(/in JSON at position (\d+)/); + if (m) { + var char = parseInt(m[1]); + console.log("==============================================="); + console.log("LINE "+appsFile.substr(0,char).split("\n").length); + console.log("==============================================="); + console.log(appsFile.substr(char-10, 20)); + console.log("==============================================="); + } + console.log(m); + ERROR(dir.name+"/metadata.json not valid JSON"); + } +}); const APP_KEYS = [ 'id', 'name', 'shortName', 'version', 'icon', 'screenshots', 'description', 'tags', 'type', From bddd130c3f82d5c78637d5adf61efba2e0148443 Mon Sep 17 00:00:00 2001 From: Francisco Pina Martins Date: Thu, 13 Jan 2022 15:48:05 +0000 Subject: [PATCH 006/174] Allows colour customization. Adds settings --- apps/vectorclock/app.js | 19 +++++++++------ apps/vectorclock/settings.js | 45 ++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 7 deletions(-) create mode 100644 apps/vectorclock/settings.js diff --git a/apps/vectorclock/app.js b/apps/vectorclock/app.js index 78c17b3d4..fe1f6e64c 100644 --- a/apps/vectorclock/app.js +++ b/apps/vectorclock/app.js @@ -1,5 +1,10 @@ const is12Hour = (require("Storage").readJSON("setting.json",1)||{})["12hour"]; const locale = require("locale"); +var settings = require('Storage').readJSON("vectorclock.json", true) || {}; +var dowcol = settings.dowcol || 0xFFE0; +var timecol = settings.timecol || 0xFFFF; +var datecol = settings.datecol || 0xFFFF; + function padNum(n, l) { return ("0".repeat(l)+n).substr(-l); @@ -26,8 +31,8 @@ function executeCommands() { commands = []; } -function drawVectorText(text, size, x, y, alignX, alignY) { - g.setFont("Vector", size).setFontAlign(alignX, alignY).drawString(text, x, y); +function drawVectorText(text, size, x, y, alignX, alignY, color) { + g.setFont("Vector", size).setColor(color).setFontAlign(alignX, alignY).drawString(text, x, y); var m = g.stringMetrics(text); return { x1: x - m.width * (alignX / 2 + 0.5), @@ -64,15 +69,15 @@ function draw() { let x = 2; let y = 24 + spacer; - pushCommand(drawVectorText, timeText, timeFontSize, x, y, -1, -1); - pushCommand(drawVectorText, meridian, timeFontSize*9/20, x + width, y, 1, -1); - if (showSeconds) pushCommand(drawVectorText, secondsText, timeFontSize*9/20, x + width, y + timeHeight, 1, 1); + pushCommand(drawVectorText, timeText, timeFontSize, x, y, -1, -1, timecol); + pushCommand(drawVectorText, meridian, timeFontSize*9/20, x + width, y, 1, -1, timecol); + if (showSeconds) pushCommand(drawVectorText, secondsText, timeFontSize*9/20, x + width, y + timeHeight, 1, 1, timecol); y += timeHeight + spacer; - pushCommand(drawVectorText, dowText, dowFontSize, x + width/2, y, 0, -1); + pushCommand(drawVectorText, dowText, dowFontSize, x + width/2, y, 0, -1, dowcol); y += dowHeight + spacer; - pushCommand(drawVectorText, dateText, dateFontSize, x + width/2, y, 0, -1); + pushCommand(drawVectorText, dateText, dateFontSize, x + width/2, y, 0, -1, datecol); executeCommands(); } diff --git a/apps/vectorclock/settings.js b/apps/vectorclock/settings.js new file mode 100644 index 000000000..3331b4c16 --- /dev/null +++ b/apps/vectorclock/settings.js @@ -0,0 +1,45 @@ +(function(back) { + var FILE = "vectorclock.json"; + // Load settings + var settings = Object.assign({ + }, require('Storage').readJSON(FILE, true) || {}); + + function writeSettings() { + require('Storage').writeJSON(FILE, settings); + } + + var colnames = ["white", "yellow", "green", "cyan", "red", "orange"]; + var colvalues = [0xFFFF, 0xFFE0, 0x07E0, 0x07FF, 0xF800, 0xFD20]; + // Show the menu + E.showMenu({ + "" : { "title" : "VectorClock colours" }, + "< Back" : () => back(), + 'Time': { + value: Math.max(0 | colvalues.indexOf(settings.timecol),0), + min: 0, max: colvalues.length-1, + format: v => colnames[v], + onchange: v => { + settings.timecol = v; + writeSettings(); + } + }, + 'Weekday': { + value: Math.max(0 | colvalues.indexOf(settings.dowcol),0), + min: 0, max: colvalues.length-1, + format: v => colnames[v], + onchange: v => { + settings.dowcol = v; + writeSettings(); + } + }, + 'Date': { + value: Math.max(0 | colvalues.indexOf(settings.datecol),0), + min: 0, max: colvalues.length-1, + format: v => colnames[v], + onchange: v => { + settings.datecol = v; + writeSettings(); + } + }, + }); +}) From d84ceccf6d1d6d63a99873a5c9963f6e6843824f Mon Sep 17 00:00:00 2001 From: Francisco Pina Martins Date: Thu, 13 Jan 2022 15:48:40 +0000 Subject: [PATCH 007/174] Adds settings files for vector clock --- apps.json | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/apps.json b/apps.json index 167e1b87a..08ee80653 100644 --- a/apps.json +++ b/apps.json @@ -4200,7 +4200,7 @@ { "id": "vectorclock", "name": "Vector Clock", - "version": "0.03", + "version": "0.04", "description": "A digital clock that uses the built-in vector font.", "icon": "app.png", "type": "clock", @@ -4213,8 +4213,10 @@ ], "storage": [ {"name":"vectorclock.app.js","url":"app.js"}, - {"name":"vectorclock.img","url":"app-icon.js","evaluate":true} - ] + {"name":"vectorclock.img","url":"app-icon.js","evaluate":true}, + {"name":"vectorclock.settings.js","url":"settings.js"} + ], + "data": [{"name":"vectorclock.json"}] }, { "id": "fd6fdetect", From 2e3a94c8df5d2eff407a7f7055053c9c78d077c5 Mon Sep 17 00:00:00 2001 From: Francisco Pina Martins Date: Thu, 13 Jan 2022 15:49:39 +0000 Subject: [PATCH 008/174] Adds version information --- apps/vectorclock/ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/vectorclock/ChangeLog b/apps/vectorclock/ChangeLog index 8addc7170..6ba096f88 100644 --- a/apps/vectorclock/ChangeLog +++ b/apps/vectorclock/ChangeLog @@ -1,3 +1,4 @@ 0.01: New watch face 0.02: Use Bangle.setUI for button/launcher handling 0.03: Bangle.js 2 support +0.04: Adds costumizable colours and the respective settings menu From 7e8df5593e450e0742c182a844d7313cbc9f0173 Mon Sep 17 00:00:00 2001 From: The Dod Date: Thu, 13 Jan 2022 17:53:42 +0200 Subject: [PATCH 009/174] Add AccelaMaze game app --- apps.json | 15 ++ apps/acmaze/ChangeLog | 1 + apps/acmaze/README.md | 17 +++ apps/acmaze/app-icon.js | 1 + apps/acmaze/app.js | 276 +++++++++++++++++++++++++++++++++++++ apps/acmaze/app.png | Bin 0 -> 8863 bytes apps/acmaze/screenshot.png | Bin 0 -> 10082 bytes 7 files changed, 310 insertions(+) create mode 100644 apps/acmaze/ChangeLog create mode 100644 apps/acmaze/README.md create mode 100644 apps/acmaze/app-icon.js create mode 100644 apps/acmaze/app.js create mode 100644 apps/acmaze/app.png create mode 100644 apps/acmaze/screenshot.png diff --git a/apps.json b/apps.json index f28766ab5..bf887cabc 100644 --- a/apps.json +++ b/apps.json @@ -5660,5 +5660,20 @@ {"name":"timeandlife.app.js","url":"app.js"}, {"name":"timeandlife.img","url":"app-icon.js","evaluate":true} ] + }, + { "id": "acmaze", + "name": "AccelaMaze", + "shortName":"AccelaMaze", + "version":"0.01", + "description": "Tilt the watch to roll a ball through a maze", + "icon": "app.png", + "tags": "game", + "supports" : ["BANGLEJS2"], + "readme": "README.md", + "screenshots": [{"url":"screenshot.png"}], + "storage": [ + {"name":"acmaze.app.js","url":"app.js"}, + {"name":"acmaze.img","url":"app-icon.js","evaluate":true} + ] } ] diff --git a/apps/acmaze/ChangeLog b/apps/acmaze/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/acmaze/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/acmaze/README.md b/apps/acmaze/README.md new file mode 100644 index 000000000..4724eea3e --- /dev/null +++ b/apps/acmaze/README.md @@ -0,0 +1,17 @@ +# AccelaMaze + +Tilt the watch to roll a ball through a maze. + +![Screenshot](screenshot.png) + +## Usage + +* Use the menu to select difficulty level (or exit). +* Wait until the maze gets generated and a red ball appears. +* Tilt the watch to get the ball into the green cell. + +At any time you can click the button to return to the menu. + +## Creator + +[Nimrod Kerrett](https://zzzen.com) diff --git a/apps/acmaze/app-icon.js b/apps/acmaze/app-icon.js new file mode 100644 index 000000000..8bd043b8b --- /dev/null +++ b/apps/acmaze/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwggaXh3M53/AA3yl4IHn//+EM5nMAoIX/C4RfCC4szmcxC4QFBAAUxC4UPAwIOB+YCCiMRkAFCkIGBAAQfBC4IUEAQhHIAAQX/C5EDmcyCgUTAoYXDR4kzC4UBPoKVB+YFFAQSPBiAKBiCnDGoZECABDUCa4YX/C5qPBQwoXGkczmC/FQYSSCVQSSCEwQOCC4hKFX4QXCd5YX/C4qMEmQXITAinDPoIADTwSPFkKMBX47RGI47XIC/4XCgZ9DQYYABmKYBmIXFkczmEBRIK/CQYQIBkECSoiSCA4MQa5pEFd6IX/RgMyC6H/QASVCRIS/EAQrXFJQoX/C6kDRQIXCiYFD+QFBmIUCkYFD+CJBiSPCRwIFFSoQFCiF3u9wI4gAO+wXW+IXygAAW")) diff --git a/apps/acmaze/app.js b/apps/acmaze/app.js new file mode 100644 index 000000000..53a851b5e --- /dev/null +++ b/apps/acmaze/app.js @@ -0,0 +1,276 @@ +const MARGIN = 25; +const WALL_RIGHT = 1, WALL_DOWN = 2; +const STATUS_GENERATING = 0, STATUS_PLAYING = 1, + STATUS_SOLVED = 2, STATUS_ABORTED = -1; + +function Maze(n) { + this.n = n; + this.status = STATUS_GENERATING; + this.wall_length = Math.floor((g.getHeight()-2*MARGIN)/n); + this.total_length = this.wall_length*n; + this.margin = Math.floor((g.getHeight()-this.total_length)/2); + this.ball_x = 0; + this.ball_y = 0; + this.clearScreen = function() { + g.clearRect( + 0, this.margin, + g.getWidth(), this.margin+this.total_length + ); + }; + this.clearScreen(); + g.setColor(g.theme.fg); + for (let i=0; i<=n; i++) { + g.drawRect( + this.margin, this.margin+i*this.wall_length, + g.getWidth()-this.margin, this.margin+i*this.wall_length + ); + g.drawRect( + this.margin+i*this.wall_length, this.margin, + this.margin+i*this.wall_length, g.getHeight() - this.margin + ); + } + this.walls = new Uint8Array(n*n); + this.groups = new Uint8Array(n*n); + for (let cell = 0; cell0 && !(this.walls[n*(ball_r-1)+ball_c]&WALL_DOWN)) { + next_y--; + } else if (dy>0 && ball_r<(this.n-1) && !(this.walls[n*ball_r+ball_c]&WALL_DOWN)) { + next_y++; + } else if (dx<0 && ball_c>0 && !(this.walls[n*ball_r+ball_c-1]&WALL_RIGHT)) { + next_x--; + } else if (dx>0 && ball_c<(this.n-1) && !(this.walls[n*ball_r+ball_c]&WALL_RIGHT)) { + next_x++; + } else { + return false; + } + } + this.clearCell(ball_r, ball_c); + if (this.ball_x%this.wall_length) { + this.clearCell(ball_r, ball_c+1); + } + if (this.ball_y%this.wall_length) { + this.clearCell(ball_r+1, ball_c); + } + this.ball_x = next_x; + this.ball_y = next_y; + this.drawBall(this.ball_x, this.ball_y); + if (this.ball_x==(n-1)*this.wall_length && this.ball_y==(n-1)*this.wall_length) { + this.status = STATUS_SOLVED; + } + return true; + }; + this.try_move_horizontally = function(accel_x) { + if (accel_x>0.15) { + return this.move(-1, 0); + } else if (accel_x<-0.15) { + return this.move(1, 0); + } + return false; + }; + this.try_move_vertically = function(accel_y) { + if (accel_y<-0.15) { + return this.move(0,1); + } else if (accel_y>0.15) { + return this.move(0,-1); + } + return false; + }; + this.tick = function() { + accel = Bangle.getAccel(); + if (this.ball_x%this.wall_length) { + this.try_move_horizontally(accel.x); + } else if (this.ball_y%this.wall_length) { + this.try_move_vertically(accel.y); + } else { + if (Math.abs(accel.x)>Math.abs(accel.y)) { // prefer horizontally + if (!this.try_move_horizontally(accel.x)) { + this.try_move_vertically(accel.y); + } + } else { // prefer vertically + if (!this.try_move_vertically(accel.y)) { + this.try_move_horizontally(accel.x); + } + } + } + }; + this.clearCell(0,0); + this.clearCell(n-1,n-1); + this.drawBall(0,0); + this.status = STATUS_PLAYING; +} + +function timeToText(t) { // Courtesy of stopwatch app + let hrs = Math.floor(t/3600000); + let mins = Math.floor(t/60000)%60; + let secs = Math.floor(t/1000)%60; + let tnth = Math.floor(t/100)%10; + let text; + + if (hrs === 0) + text = ("0"+mins).substr(-2) + ":" + ("0"+secs).substr(-2) + "." + tnth; + else + text = ("0"+hrs) + ":" + ("0"+mins).substr(-2) + ":" + ("0"+secs).substr(-2); + return text; +} + +let aborting = false; +let start_time = 0; +let duration = 0; +let maze=null; +let mazeMenu = { + "": { "title": "Maze size", "selected": 1 }, + "Easy (8x8)": function() { E.showMenu(); maze = new Maze(8); }, + "Medium (10x10)": function() { E.showMenu(); maze = new Maze(10); }, + "Hard (14x14)": function() { E.showMenu(); maze = new Maze(14); }, + "< Exit": function() { setTimeout(load, 100); } // timeout voodoo prevents deadlock +}; + +g.clear(true); +Bangle.loadWidgets(); +Bangle.drawWidgets(); +Bangle.setLocked(false); +Bangle.setLCDTimeout(0); +E.showMenu(mazeMenu); +let maze_interval = setInterval( + function() { + if (maze) { + if (digitalRead(BTN1) || maze.status==STATUS_ABORTED) { + console.log(`aborting ${start_time}`); + maze = null; + start_time = duration = 0; + aborting = false; + setTimeout(function() {E.showMenu(mazeMenu); }, 100); + return; + } + if (!start_time) { + start_time = Date.now(); + } + if (maze.status==STATUS_PLAYING) { + maze.tick(); + } + if (maze.status==STATUS_SOLVED && !duration) { + duration = Date.now()-start_time; + g.setFontAlign(0,0).setColor(g.theme.fg); + g.setFont("Vector",18); + g.drawString(`Solved in\n ${timeToText(duration)} \nClick to play again`, g.getWidth()/2, g.getHeight()/2, true); + } + } + }, 25); diff --git a/apps/acmaze/app.png b/apps/acmaze/app.png new file mode 100644 index 0000000000000000000000000000000000000000..0d96448b11888295d626c0eb3a81c031b105f177 GIT binary patch literal 8863 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 Date: Thu, 13 Jan 2022 16:54:40 +0000 Subject: [PATCH 010/174] Changes a default value from it's debug state --- apps/vectorclock/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/vectorclock/app.js b/apps/vectorclock/app.js index fe1f6e64c..894400f07 100644 --- a/apps/vectorclock/app.js +++ b/apps/vectorclock/app.js @@ -1,7 +1,7 @@ const is12Hour = (require("Storage").readJSON("setting.json",1)||{})["12hour"]; const locale = require("locale"); var settings = require('Storage').readJSON("vectorclock.json", true) || {}; -var dowcol = settings.dowcol || 0xFFE0; +var dowcol = settings.dowcol || 0xFFFF; var timecol = settings.timecol || 0xFFFF; var datecol = settings.datecol || 0xFFFF; From 298c709a6aa18fe8aaaededdd536bdeafa67fa8f Mon Sep 17 00:00:00 2001 From: Francisco Pina Martins Date: Thu, 13 Jan 2022 16:55:21 +0000 Subject: [PATCH 011/174] Fixes the settings reading values --- apps/vectorclock/settings.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/vectorclock/settings.js b/apps/vectorclock/settings.js index 3331b4c16..ea6ece9e9 100644 --- a/apps/vectorclock/settings.js +++ b/apps/vectorclock/settings.js @@ -19,7 +19,7 @@ min: 0, max: colvalues.length-1, format: v => colnames[v], onchange: v => { - settings.timecol = v; + settings.timecol = colvalues[v]; writeSettings(); } }, @@ -28,7 +28,7 @@ min: 0, max: colvalues.length-1, format: v => colnames[v], onchange: v => { - settings.dowcol = v; + settings.dowcol = colvalues[v]; writeSettings(); } }, @@ -37,7 +37,7 @@ min: 0, max: colvalues.length-1, format: v => colnames[v], onchange: v => { - settings.datecol = v; + settings.datecol = colvalues[v]; writeSettings(); } }, From 5dbca35e2a3a3b2275a517b752c922bdc2d80685 Mon Sep 17 00:00:00 2001 From: David Peer Date: Thu, 13 Jan 2022 18:22:13 +0100 Subject: [PATCH 012/174] Improved battery visualization --- apps/lcars/lcars.app.js | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/apps/lcars/lcars.app.js b/apps/lcars/lcars.app.js index 2674d323f..3b9745a7a 100644 --- a/apps/lcars/lcars.app.js +++ b/apps/lcars/lcars.app.js @@ -20,7 +20,7 @@ let cOrange = "#FF9900"; let cPurple = "#FF00DC"; let cWhite = "#FFFFFF"; let cBlack = "#000000"; -let cGrey = "#9E9E9E"; +let cGrey = "#424242"; /* * Global lcars variables @@ -143,7 +143,7 @@ function printData(key, y, c){ } else if (key == "HUMIDITY"){ text = "HUM"; var weather = getWeather(); - value = parseInt(weather.hum) + "%"; + value = weather.hum + "%"; } else if(key == "CORET"){ value = locale.temp(parseInt(E.getTemperature())); @@ -242,9 +242,14 @@ function drawPosition0(){ // The last line is a battery indicator too var bat = E.getBattery() / 100.0; - var batX2 = parseInt((172 - 35) * bat + 35); - drawHorizontalBgLine(cOrange, 35, batX2-5, 171, 5); - drawHorizontalBgLine(cGrey, batX2+5, 172, 171, 5); + var batStart = 19; + var batWidth = 172 - batStart; + var batX2 = parseInt(batWidth * bat + batStart); + drawHorizontalBgLine(cOrange, batStart, batX2, 171, 5); + drawHorizontalBgLine(cGrey, batX2, 172, 171, 5); + for(var i=0; i+batStart<=172; i+=parseInt(batWidth/4)){ + drawHorizontalBgLine(cBlack, batStart+i, batStart+i+3, 168, 8) + } // Draw Infos drawInfo(); From fbbb0bb36738c0ff69ccad9db2c1d8b70a49178c Mon Sep 17 00:00:00 2001 From: David Peer Date: Thu, 13 Jan 2022 18:24:30 +0100 Subject: [PATCH 013/174] New version. --- apps.json | 2 +- apps/lcars/ChangeLog | 3 ++- apps/lcars/screenshot.png | Bin 5721 -> 5787 bytes 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps.json b/apps.json index 93b1cf44e..bf8151743 100644 --- a/apps.json +++ b/apps.json @@ -4518,7 +4518,7 @@ "name": "LCARS Clock", "shortName":"LCARS", "icon": "lcars.png", - "version":"0.12", + "version":"0.13", "readme": "README.md", "supports": ["BANGLEJS2"], "description": "Library Computer Access Retrieval System (LCARS) clock.", diff --git a/apps/lcars/ChangeLog b/apps/lcars/ChangeLog index 702ef58b9..dba05915b 100644 --- a/apps/lcars/ChangeLog +++ b/apps/lcars/ChangeLog @@ -9,4 +9,5 @@ 0.09: Tab anywhere to open the launcher. 0.10: Removed swipes to be compatible with the Pattern Launcher. Stability improvements. 0.11: Show the gadgetbridge weather temperature (settings). -0.12: Added humidity to data. \ No newline at end of file +0.12: Added humidity to data. +0.13: Improved battery visualization. \ No newline at end of file diff --git a/apps/lcars/screenshot.png b/apps/lcars/screenshot.png index 319062dcce36640c38e24378d97b7724ab3a9f74..120229fba29717e0501a63ac1f805467b1edc5fc 100644 GIT binary patch literal 5787 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 Z@PEl{>&?){aSZ?f002ovPDHLkV1j3-{UHDV literal 5721 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 Date: Thu, 13 Jan 2022 18:58:22 +0000 Subject: [PATCH 014/174] Simple Pedometer and Lato Pedometer widgets, fix size after step count reset --- apps.json | 4 ++-- apps/widpa/ChangeLog | 1 + apps/widpa/widpa.wid.js | 2 +- apps/widpb/ChangeLog | 1 + apps/widpb/widpb.wid.js | 6 +++--- 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/apps.json b/apps.json index f28766ab5..b837b8f2b 100644 --- a/apps.json +++ b/apps.json @@ -5618,7 +5618,7 @@ "shortName":"Simple Pedometer", "icon": "screenshot_widpa.png", "screenshots": [{"url":"screenshot_widpa.png"}], - "version":"0.01", + "version":"0.02", "type": "widget", "supports": ["BANGLEJS", "BANGLEJS2"], "readme": "README.md", @@ -5634,7 +5634,7 @@ "shortName":"Lato Pedometer", "icon": "screenshot_widpb.png", "screenshots": [{"url":"screenshot_widpb.png"}], - "version":"0.01", + "version":"0.02", "type": "widget", "supports": ["BANGLEJS", "BANGLEJS2"], "readme": "README.md", diff --git a/apps/widpa/ChangeLog b/apps/widpa/ChangeLog index 7b83706bf..5197bb4bd 100644 --- a/apps/widpa/ChangeLog +++ b/apps/widpa/ChangeLog @@ -1 +1,2 @@ 0.01: First release +0.02: Size widget after step count is reset diff --git a/apps/widpa/widpa.wid.js b/apps/widpa/widpa.wid.js index b8c439d2b..1c0f27394 100644 --- a/apps/widpa/widpa.wid.js +++ b/apps/widpa/widpa.wid.js @@ -6,7 +6,7 @@ WIDGETS["widpa"]={area:"tl",width:13,draw:function() { if (!Bangle.isLCDOn()) return; // dont redraw if LCD is off var steps = Bangle.getHealthStatus("day").steps; var w = 1 + (steps.toString().length)*12; - if (w > this.width) {this.width = w; setTimeout(() => Bangle.drawWidgets(),10); return;} + if (w != this.width) {this.width = w; setTimeout(() => Bangle.drawWidgets(),10); return;} g.reset(); g.setColor(g.theme.bg); g.fillRect(this.x, this.y, this.x + this.width, this.y + 23); diff --git a/apps/widpb/ChangeLog b/apps/widpb/ChangeLog index 7b83706bf..1409a81ff 100644 --- a/apps/widpb/ChangeLog +++ b/apps/widpb/ChangeLog @@ -1 +1,2 @@ 0.01: First release +0.02: Fixed widget id to wibpb, Size widget after step count is reset diff --git a/apps/widpb/widpb.wid.js b/apps/widpb/widpb.wid.js index d65d7fe43..6129fac51 100644 --- a/apps/widpb/widpb.wid.js +++ b/apps/widpb/widpb.wid.js @@ -1,13 +1,13 @@ // on.step version Bangle.on('step', function(s) { WIDGETS["bata"].draw(); }); Bangle.on('lcdPower', function(on) { - if (on) WIDGETS["bata"].draw(); + if (on) WIDGETS["widpb"].draw(); }); -WIDGETS["bata"]={area:"tl",width:13,draw:function() { +WIDGETS["widpb"]={area:"tl",width:13,draw:function() { if (!Bangle.isLCDOn()) return; // dont redraw if LCD is off var steps = Bangle.getHealthStatus("day").steps; var w = 1 + (steps.toString().length)*12; - if (w > this.width) {this.width = w; setTimeout(() => Bangle.drawWidgets(),10); return;} + if (w != this.width) {this.width = w; setTimeout(() => Bangle.drawWidgets(),10); return;} g.reset(); g.setColor(g.theme.bg); g.fillRect(this.x, this.y, this.x + this.width, this.y + 23); // erase background From b80909be9b6b9dc5ef039fd46512acfd5e3c44e7 Mon Sep 17 00:00:00 2001 From: hughbarney Date: Thu, 13 Jan 2022 19:24:57 +0000 Subject: [PATCH 015/174] Widlock: set sortorder -1 --- apps.json | 3 ++- apps/widlock/ChangeLog | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/apps.json b/apps.json index b837b8f2b..65fe64ed3 100644 --- a/apps.json +++ b/apps.json @@ -942,12 +942,13 @@ { "id": "widlock", "name": "Lock Widget", - "version": "0.03", + "version": "0.04", "description": "On devices with always-on display (Bangle.js 2) this displays lock icon whenever the display is locked", "icon": "widget.png", "type": "widget", "tags": "widget,lock", "supports": ["BANGLEJS","BANGLEJS2"], + "sortorder": -1, "storage": [ {"name":"widlock.wid.js","url":"widget.js"} ] diff --git a/apps/widlock/ChangeLog b/apps/widlock/ChangeLog index 3b1436feb..8aeb75429 100644 --- a/apps/widlock/ChangeLog +++ b/apps/widlock/ChangeLog @@ -1,3 +1,4 @@ 0.01: First commit 0.02: Handle new firmwares with 'lock' event 0.03: Don't try to be fancy - just bail out on firmwares without a lock event +0.04: Set sortorder to -1 so that widget always takes up the furthest left position From db0e55b18e9ca0805d8dfd0e7c7b53babf9ea456 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Fri, 14 Jan 2022 09:47:26 +0100 Subject: [PATCH 016/174] Add sit ups Add more feedback to the user about the exercises Clean up code --- apps/banglexercise/ChangeLog | 3 + apps/banglexercise/README.md | 4 +- apps/banglexercise/app.js | 128 ++++++++++++++++++++--------------- 3 files changed, 80 insertions(+), 55 deletions(-) diff --git a/apps/banglexercise/ChangeLog b/apps/banglexercise/ChangeLog index 5560f00bc..5f1d3bd7d 100644 --- a/apps/banglexercise/ChangeLog +++ b/apps/banglexercise/ChangeLog @@ -1 +1,4 @@ 0.01: New App! +0.02: Add sit ups + Add more feedback to the user about the exercises + Clean up code diff --git a/apps/banglexercise/README.md b/apps/banglexercise/README.md index 28b276a59..c9f9ec38a 100644 --- a/apps/banglexercise/README.md +++ b/apps/banglexercise/README.md @@ -2,7 +2,7 @@ Can automatically track exercises while wearing the Bangle.js watch. -Currently only push ups and curls are supported. +Currently only push ups, curls and sit ups are supported. ## Disclaimer @@ -23,7 +23,7 @@ Press stop to end your exercise. ## TODO * Add other exercise types: * Rope jumps - * Sit ups + * Star jumps * ... * Save exercise summaries to file system * Configure daily goal for exercises diff --git a/apps/banglexercise/app.js b/apps/banglexercise/app.js index 0d5c814bf..bc6e35f07 100644 --- a/apps/banglexercise/app.js +++ b/apps/banglexercise/app.js @@ -25,22 +25,32 @@ let exerciseType = { const exerciseTypes = [{ "id": "pushup", "name": "push ups", - "useYaxe": true, - "useZaxe": false, - "thresholdY": 2500, - "thresholdMinTime": 1400, // mininmal time between two push ups in ms + "useYaxis": true, + "useZaxis": false, + "threshold": 2500, + "thresholdMinTime": 800, // mininmal time between two push ups in ms "thresholdMaxTime": 5000, // maximal time between two push ups in ms - "thresholdMinDurationTime": 700, // mininmal duration of half a push ups in ms + "thresholdMinDurationTime": 600, // mininmal duration of half a push up in ms }, { "id": "curl", "name": "curls", - "useYaxe": true, - "useZaxe": false, - "thresholdY": 2500, - "thresholdMinTime": 1000, // mininmal time between two curls in ms + "useYaxis": true, + "useZaxis": false, + "threshold": 2500, + "thresholdMinTime": 800, // mininmal time between two curls in ms "thresholdMaxTime": 5000, // maximal time between two curls in ms - "thresholdMinDurationTime": 500, // mininmal duration of half a push ups in ms + "thresholdMinDurationTime": 500, // mininmal duration of half a curl in ms + }, + { + "id": "situp", + "name": "sit ups", + "useYaxis": false, + "useZaxis": true, + "threshold": 3500, + "thresholdMinTime": 800, // mininmal time between two sit ups in ms + "thresholdMaxTime": 5000, // maximal time between two sit ups in ms + "thresholdMinDurationTime": 500, // mininmal duration of half a sit up in ms } ]; let exerciseCounter = 0; @@ -66,7 +76,7 @@ function showMainMenu() { }; exerciseTypes.forEach(function(et) { - menu["Do " + et.name] = function() { + menu[et.name] = function() { exerciseType = et; E.showMenu(); startTraining(); @@ -81,8 +91,8 @@ function showMainMenu() { value: exerciseCounter + " " + exerciseType.name }; } - menu.Exit = function() { - load(); + menu.exit = function() { + load(); }; E.showMenu(menu); @@ -91,11 +101,11 @@ function showMainMenu() { function accelHandler(accel) { if (!exerciseType) return; const t = Math.round(new Date().getTime()); // time in ms - const y = exerciseType.useYaxe ? accel.y * 8192 : 0; - const z = exerciseType.useZaxe ? accel.z * 8192 : 0; + const y = exerciseType.useYaxis ? accel.y * 8192 : 0; + const z = exerciseType.useZaxis ? accel.z * 8192 : 0; //console.log(t, y, z); - if (exerciseType.useYaxe) { + if (exerciseType.useYaxis) { while (historyY.length > avgSize) historyY.shift(); @@ -109,7 +119,7 @@ function accelHandler(accel) { } } - if (exerciseType.useYaxe) { + if (exerciseType.useZaxis) { while (historyZ.length > avgSize) historyZ.shift(); @@ -124,72 +134,64 @@ function accelHandler(accel) { } // slope for Y - if (exerciseType.useYaxe) { + if (exerciseType.useYaxis) { let l = historyAvgY.length; if (l > 1) { const p1 = historyAvgY[l - 2]; const p2 = historyAvgY[l - 1]; const slopeY = (p2[1] - p1[1]) / (p2[0] / 1000 - p1[0] / 1000); // we use this data for exercises which can be detected by using Y axis data - switch (exerciseType.id) { - case "pushup": - isValidYAxisExercise(slopeY, t); - break; - case "curl": - isValidYAxisExercise(slopeY, t); - break; - } - + isValidExercise(slopeY, t); } } // slope for Z - if (exerciseType.useZaxe) { + if (exerciseType.useZaxis) { l = historyAvgZ.length; if (l > 1) { const p1 = historyAvgZ[l - 2]; const p2 = historyAvgZ[l - 1]; - const slopeZ = (p2[1] - p1[1]) / (p2[0] - p1[0]); - historyAvgZ.shift(); - historySlopeZ.push([p2[0] - p1[0], slopeZ]); - - // TODO: we can use this data for some exercises which can be detected by using Z axis data + const slopeZ = (p2[1] - p1[1]) / (p2[0] / 1000 - p1[0] / 1000); + // we use this data for some exercises which can be detected by using Z axis data + isValidExercise(slopeZ, t); } } } /* - * Check if slope value of Y-axis data looks like an exercise + * Check if slope value of Y-axis or Z-axis data (depending on exercise type) looks like an exercise * - * In detail we look for slop values which are bigger than the configured Y threshold for the current exercise + * In detail we look for slop values which are bigger than the configured threshold for the current exercise type * Then we look for two consecutive slope values of which one is above 0 and the other is below zero. * If we find one pair of these values this could be part of one exercise. * Then we look for a pair of values which cross the zero from the otherwise direction */ -function isValidYAxisExercise(slopeY, t) { +function isValidExercise(slope, t) { if (!exerciseType) return; - const thresholdY = exerciseType.thresholdY; + const threshold = exerciseType.threshold; + const historySlopeValues = exerciseType.useYaxis ? historySlopeY : historySlopeZ; const thresholdMinTime = exerciseType.thresholdMinTime; const thresholdMaxTime = exerciseType.thresholdMaxTime; const thresholdMinDurationTime = exerciseType.thresholdMinDurationTime; const exerciseName = exerciseType.name; - if (Math.abs(slopeY) >= thresholdY) { - historyAvgY.shift(); - historySlopeY.push([t, slopeY]); - //console.log(t, Math.abs(slopeY)); - const lSlopeY = historySlopeY.length; - if (lSlopeY > 1) { - const p1 = historySlopeY[lSlopeY - 1][1]; - const p2 = historySlopeY[lSlopeY - 2][1]; + if (Math.abs(slope) >= threshold) { + historySlopeValues.push([t, slope]); + //console.log(t, Math.abs(slope)); + + const lSlopeHistory = historySlopeValues.length; + if (lSlopeHistory > 1) { + const p1 = historySlopeValues[lSlopeHistory - 1][1]; + const p2 = historySlopeValues[lSlopeHistory - 2][1]; if (p1 > 0 && p2 < 0) { if (lastZeroPassCameFromPositive == false) { lastExerciseHalfCompletionTime = t; - //console.log(t, exerciseName + " half complete..."); + console.log(t, exerciseName + " half complete..."); layout.progress.label = "½"; + layout.recording.label = "TRAINING"; g.clear(); layout.render(); } @@ -201,7 +203,7 @@ function isValidYAxisExercise(slopeY, t) { if (lastZeroPassCameFromPositive == true) { const tDiffLastExercise = t - lastExerciseCompletionTime; const tDiffStart = t - tStart; - //console.log(t, exerciseName + " maybe complete?", Math.round(tDiffLastExercise), Math.round(tDiffStart)); + console.log(t, exerciseName + " maybe complete?", Math.round(tDiffLastExercise), Math.round(tDiffStart)); // check minimal time between exercises: if ((lastExerciseCompletionTime <= 0 && tDiffStart >= thresholdMinTime) || tDiffLastExercise >= thresholdMinTime) { @@ -219,22 +221,36 @@ function isValidYAxisExercise(slopeY, t) { layout.count.label = exerciseCounter; layout.progress.label = ""; + layout.recording.label = "Good!"; + g.clear(); layout.render(); if (settings.buzz) - Bangle.buzz(100, 0.4); + Bangle.buzz(200, 0.5); } else { - //console.log(t, exerciseName + " to quick for duration time threshold!"); + console.log(t, exerciseName + " too quick for duration time threshold!"); // thresholdMinDurationTime lastExerciseCompletionTime = t; + + layout.recording.label = "Go slower!"; + g.clear(); + layout.render(); } } else { - //console.log(t, exerciseName + " to slow for time threshold!"); + console.log(t, exerciseName + " top slow for time threshold!"); // thresholdMaxTime lastExerciseCompletionTime = t; + + layout.recording.label = "Go faster!"; + g.clear(); + layout.render(); } } else { - //console.log(t, exerciseName + " to quick for time threshold!"); + console.log(t, exerciseName + " too quick for time threshold!"); // thresholdMinTime lastExerciseCompletionTime = t; + + layout.recording.label = "Go slower!"; + g.clear(); + layout.render(); } } @@ -267,6 +283,7 @@ function startTraining() { if (recordActive) return; g.clear(1); reset(); + Bangle.setLCDTimeout(0); // force LCD on Bangle.setHRMPower(1, "banglexercise"); if (!hrtValue) hrtValue = "..."; @@ -285,7 +302,7 @@ function startTraining() { type: "txt", id: "count", font: exerciseCounter < 100 ? "6x8:9" : "6x8:8", - label: 10, + label: exerciseCounter, pad: 5 }, { @@ -337,11 +354,16 @@ function startTraining() { layout.render(); Bangle.setPollInterval(80); // 12.5 Hz - Bangle.on('accel', accelHandler); + tStart = new Date().getTime(); recordActive = true; if (settings.buzz) Bangle.buzz(200, 1); + + // delay start a little bit + setTimeout(() => { + Bangle.on('accel', accelHandler); + }, 1000); } function stopTraining() { From ef1292322ba772bb3753da4086cdd0d6db331da5 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Fri, 14 Jan 2022 09:49:35 +0100 Subject: [PATCH 017/174] Update apps.json --- apps.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps.json b/apps.json index f28766ab5..28e2b73ef 100644 --- a/apps.json +++ b/apps.json @@ -5594,7 +5594,7 @@ { "id": "banglexercise", "name": "BanglExercise", "shortName":"BanglExercise", - "version":"0.01", + "version":"0.02", "description": "Can automatically track exercises while wearing the Bangle.js watch.", "icon": "app.png", "screenshots": [{"url":"screenshot.png"}], From a746510f0bf1bd4b12fba8fe2239c45f1c684f82 Mon Sep 17 00:00:00 2001 From: David Peer Date: Fri, 14 Jan 2022 13:05:17 +0100 Subject: [PATCH 018/174] Included altitude. --- apps/lcars/lcars.app.js | 40 +++++++++++++++++++++++++----------- apps/lcars/lcars.settings.js | 8 ++++---- 2 files changed, 32 insertions(+), 16 deletions(-) diff --git a/apps/lcars/lcars.app.js b/apps/lcars/lcars.app.js index 3b9745a7a..e3a9d143b 100644 --- a/apps/lcars/lcars.app.js +++ b/apps/lcars/lcars.app.js @@ -116,11 +116,27 @@ function queueDraw() { } +function printRow(text, value, y, c){ + g.setColor(c); + g.fillRect(79, y-2, 85 ,y+18); + + g.setFontAlign(0,-1,0); + g.drawString(value, 110, y); + + g.setColor(c); + g.setFontAlign(-1,-1,0); + g.fillRect(133, y-2, 165 ,y+18); + g.fillCircle(161, y+8, 10); + g.setColor(cBlack); + g.drawString(text, 135, y); +} + function printData(key, y, c){ g.setFontAlign(-1,-1,0); key = key.toUpperCase() var text = key; var value = "ERR"; + var should_print= true; if(key == "STEPS"){ text = "STEP"; @@ -145,22 +161,22 @@ function printData(key, y, c){ var weather = getWeather(); value = weather.hum + "%"; + } else if (key == "ALTITUDE"){ + should_print= false; + text = "ALT"; + Bangle.getPressure().then(function(data){ + value = data.altitude.toFixed(0); + printRow(text, value, y, c); + }) + } else if(key == "CORET"){ value = locale.temp(parseInt(E.getTemperature())); } - g.setColor(c); - g.fillRect(79, y-2, 85 ,y+18); - - g.setFontAlign(0,-1,0); - g.drawString(value, 110, y); - - g.setColor(c); - g.setFontAlign(-1,-1,0); - g.fillRect(133, y-2, 165 ,y+18); - g.fillCircle(161, y+8, 10); - g.setColor(cBlack); - g.drawString(text, 135, y); + // Print for all datapoints that are not async + if(should_print){ + printRow(text, value, y, c); + } } function drawHorizontalBgLine(color, x1, x2, y, h){ diff --git a/apps/lcars/lcars.settings.js b/apps/lcars/lcars.settings.js index ba630799a..076dea4d1 100644 --- a/apps/lcars/lcars.settings.js +++ b/apps/lcars/lcars.settings.js @@ -18,14 +18,14 @@ storage.write(SETTINGS_FILE, settings) } - var data_options = ["Steps", "Battery", "VREF", "HRM", "Temp", "Humidity", "CoreT"]; + var data_options = ["Steps", "Battery", "VREF", "HRM", "Temp", "Humidity", "Altitude", "CoreT"]; E.showMenu({ '': { 'title': 'LCARS Clock' }, '< Back': back, 'Row 1': { value: 0 | data_options.indexOf(settings.dataRow1), - min: 0, max: 6, + min: 0, max: 7, format: v => data_options[v], onchange: v => { settings.dataRow1 = data_options[v]; @@ -34,7 +34,7 @@ }, 'Row 2': { value: 0 | data_options.indexOf(settings.dataRow2), - min: 0, max: 6, + min: 0, max: 7, format: v => data_options[v], onchange: v => { settings.dataRow2 = data_options[v]; @@ -43,7 +43,7 @@ }, 'Row 3': { value: 0 | data_options.indexOf(settings.dataRow3), - min: 0, max: 6, + min: 0, max: 7, format: v => data_options[v], onchange: v => { settings.dataRow3 = data_options[v]; From ebb35f75aa4fe759096338bab6735509d58860f1 Mon Sep 17 00:00:00 2001 From: David Peer Date: Fri, 14 Jan 2022 13:13:49 +0100 Subject: [PATCH 019/174] Stability improvement for alt. --- apps/lcars/lcars.app.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/lcars/lcars.app.js b/apps/lcars/lcars.app.js index e3a9d143b..771a3e08a 100644 --- a/apps/lcars/lcars.app.js +++ b/apps/lcars/lcars.app.js @@ -165,8 +165,12 @@ function printData(key, y, c){ should_print= false; text = "ALT"; Bangle.getPressure().then(function(data){ - value = data.altitude.toFixed(0); - printRow(text, value, y, c); + if(data && data.altitude){ + value = data.altitude.toFixed(0); + printRow(text, value, y, c); + } else { + printRow(text, "-", y, c); + } }) } else if(key == "CORET"){ From ae68361bd49e9eeb092401f646bc1248b8a14258 Mon Sep 17 00:00:00 2001 From: David Peer Date: Fri, 14 Jan 2022 14:29:31 +0100 Subject: [PATCH 020/174] Stability improvements for data --- apps/lcars/lcars.app.js | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/apps/lcars/lcars.app.js b/apps/lcars/lcars.app.js index 771a3e08a..6e2768998 100644 --- a/apps/lcars/lcars.app.js +++ b/apps/lcars/lcars.app.js @@ -131,11 +131,23 @@ function printRow(text, value, y, c){ g.drawString(text, 135, y); } + function printData(key, y, c){ + try{ + _printData(key, y, c); + } catch(ex){ + var text = key.toUpperCase(); + var value = "ERR-2"; + printRow(text, value, y, c); + } +} + + +function _printData(key, y, c){ g.setFontAlign(-1,-1,0); key = key.toUpperCase() var text = key; - var value = "ERR"; + var value = "ERR-1"; var should_print= true; if(key == "STEPS"){ @@ -164,12 +176,13 @@ function printData(key, y, c){ } else if (key == "ALTITUDE"){ should_print= false; text = "ALT"; + + // Immediately print something - avoid that its empty + printRow(text, "", y, c); Bangle.getPressure().then(function(data){ if(data && data.altitude){ value = data.altitude.toFixed(0); printRow(text, value, y, c); - } else { - printRow(text, "-", y, c); } }) From eb4279d2cee43c1d3261458a64882e4c23260480 Mon Sep 17 00:00:00 2001 From: David Peer Date: Fri, 14 Jan 2022 14:34:46 +0100 Subject: [PATCH 021/174] Better error handling --- apps/lcars/lcars.app.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/lcars/lcars.app.js b/apps/lcars/lcars.app.js index 6e2768998..0bd6ced11 100644 --- a/apps/lcars/lcars.app.js +++ b/apps/lcars/lcars.app.js @@ -136,9 +136,7 @@ function printData(key, y, c){ try{ _printData(key, y, c); } catch(ex){ - var text = key.toUpperCase(); - var value = "ERR-2"; - printRow(text, value, y, c); + // Show last error - next try hopefully works. } } @@ -147,7 +145,7 @@ function _printData(key, y, c){ g.setFontAlign(-1,-1,0); key = key.toUpperCase() var text = key; - var value = "ERR-1"; + var value = "ERR"; var should_print= true; if(key == "STEPS"){ From 3e6fb2755caa82b85b9f765806435043b8560c7b Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Fri, 14 Jan 2022 14:46:59 +0100 Subject: [PATCH 022/174] Allow setting empty circles --- apps/circlesclock/ChangeLog | 1 + apps/circlesclock/app.js | 5 ++++- apps/circlesclock/settings.js | 11 ++++++----- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/apps/circlesclock/ChangeLog b/apps/circlesclock/ChangeLog index 5464a8103..d22ef7737 100644 --- a/apps/circlesclock/ChangeLog +++ b/apps/circlesclock/ChangeLog @@ -7,3 +7,4 @@ Make circles and text slightly bigger 0.05: Show correct percentage values in circles Show humidity as weather circle data +0.06: Allow settings empty circles diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 88a04d4b9..581e167d1 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -127,6 +127,9 @@ function drawCircle(index) { case "weather": drawWeather(w); break; + case "empty": + // we do nothing here + return; } } @@ -221,7 +224,7 @@ function drawHeartRate(w) { g.setColor(colorGrey); g.fillCircle(w, h3, radiusOuter); - if (hrtValue != undefined && hrtValue > 0) { + if (hrtValue != undefined) { const minHR = settings.minHR || 40; const percent = (hrtValue - minHR) / (settings.maxHR - minHR); drawGauge(w, h3, percent, colorRed); diff --git a/apps/circlesclock/settings.js b/apps/circlesclock/settings.js index ac4215a8a..8dab5fccf 100644 --- a/apps/circlesclock/settings.js +++ b/apps/circlesclock/settings.js @@ -6,8 +6,9 @@ settings[key] = value; storage.write(SETTINGS_FILE, settings); } - var valuesCircleTypes = ["steps", "stepsDist", "hr", "battery", "weather"]; - var namesCircleTypes = ["steps", "distance", "heart", "battery", "weather"]; + + var valuesCircleTypes = ["steps", "stepsDist", "hr", "battery", "weather", "empty"]; + var namesCircleTypes = ["steps", "distance", "heart", "battery", "weather", "empty"]; E.showMenu({ '': { 'title': 'circlesclock' }, '< Back': back, @@ -78,19 +79,19 @@ }, 'left': { value: settings.circle1 ? valuesCircleTypes.indexOf(settings.circle1) : 0, - min: 0, max: 4, + min: 0, max: 5, format: v => namesCircleTypes[v], onchange: x => save('circle1', valuesCircleTypes[x]), }, 'middle': { value: settings.circle2 ? valuesCircleTypes.indexOf(settings.circle2) : 2, - min: 0, max: 4, + min: 0, max: 5, format: v => namesCircleTypes[v], onchange: x => save('circle2', valuesCircleTypes[x]), }, 'right': { value: settings.circle3 ? valuesCircleTypes.indexOf(settings.circle3) : 3, - min: 0, max: 4, + min: 0, max: 5, format: v => namesCircleTypes[v], onchange: x => save('circle3', valuesCircleTypes[x]), } From a5fd98756beb9781f4d5b8bbadfbc855d0aba4fd Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Fri, 14 Jan 2022 15:19:00 +0100 Subject: [PATCH 023/174] Quicker lookup of circle positions --- apps/circlesclock/app.js | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 581e167d1..9a217541f 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -133,16 +133,33 @@ function drawCircle(index) { } } +// serves as cache for quicker lookup of circle positions +let circlePositionsCache = []; +/* + * Looks in the following order if a circle with the given type is somewhere visible/configured + * 1. circlePositionsCache + * 2. settings + * 3. defaultCircleTypes + * + * In case 2 and 3 the circlePositionsCache will be updated + */ function getCirclePosition(type) { + if (circlePositionsCache[type] >= 0) { + return circlePosX[circlePositionsCache[type]]; + } for (let i = 1; i <= 3; i++) { const setting = settings['circle' + i]; - if (setting == type) return circlePosX[i - 1]; + if (setting == type) { + circlePositionsCache[type] = i - 1; + return circlePosX[i - 1]; + } } for (let i = 0; i < defaultCircleTypes.length; i++) { - if (type == defaultCircleTypes[i] && (!settings || settings['circle' + (i + 1)] == undefined)) { - return circlePosX[i]; - } - } + if (type == defaultCircleTypes[i] && (!settings || settings['circle' + (i + 1)] == undefined)) { + circlePositionsCache[type] = i; + return circlePosX[i]; + } + } return undefined; } From 107c299b184b2685059b0732402fe31134aaa0b8 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Fri, 14 Jan 2022 15:43:17 +0100 Subject: [PATCH 024/174] Support to choose between humidity and wind speed for weather circle progress --- apps/circlesclock/ChangeLog | 1 + apps/circlesclock/README.md | 2 +- apps/circlesclock/app.js | 21 ++++++++++++++++++--- apps/circlesclock/settings.js | 13 +++++++++++-- 4 files changed, 31 insertions(+), 6 deletions(-) diff --git a/apps/circlesclock/ChangeLog b/apps/circlesclock/ChangeLog index d22ef7737..d34e59db3 100644 --- a/apps/circlesclock/ChangeLog +++ b/apps/circlesclock/ChangeLog @@ -8,3 +8,4 @@ 0.05: Show correct percentage values in circles Show humidity as weather circle data 0.06: Allow settings empty circles + Support to choose between humidity and wind speed for weather circle progress diff --git a/apps/circlesclock/README.md b/apps/circlesclock/README.md index c3704e3d7..b5a15bab0 100644 --- a/apps/circlesclock/README.md +++ b/apps/circlesclock/README.md @@ -10,7 +10,7 @@ It can show the following information (this can be configured): * Heart rate (automatically updates when screen is on and unlocked) * Battery (including charging status and battery low warning) * Weather (requires [weather app](https://banglejs.com/apps/#weather)) - * Humidity as circle progress + * Humidity or wind speed as circle progress * Temperature inside circle * Condition as icon below circle diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 9a217541f..11e8ccfd6 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -29,6 +29,7 @@ function loadSettings() { 'stepLength': 0.8, 'batteryWarn': 30, 'showWidgets': false, + 'weatherCircleData': 'humidity', 'circle1': 'hr', 'circle2': 'steps', 'circle3': 'battery' @@ -305,7 +306,6 @@ function drawWeather(w) { if (!w) w = getCirclePosition("weather"); const weather = getWeather(); const tempString = weather ? locale.temp(weather.temp - 273.15) : undefined; - const humidity = weather ? weather.hum : undefined; const code = weather ? weather.code : -1; // Draw rectangle background: @@ -315,8 +315,23 @@ function drawWeather(w) { g.setColor(colorGrey); g.fillCircle(w, h3, radiusOuter); - if (humidity >= 0) { - drawGauge(w, h3, humidity / 100, colorYellow); + const data = settings.weatherCircleData || "humidity"; + switch (data) { + case "humidity": + const humidity = weather ? weather.hum : undefined; + if (humidity >= 0) { + drawGauge(w, h3, humidity / 100, colorYellow); + } + break; + case "wind": + const wind = weather ? weather.wind : undefined; + if (wind >= 0) { + // wind goes from 0 to 12 (see https://en.wikipedia.org/wiki/Beaufort_scale) + drawGauge(w, h3, wind / 12, colorYellow); + } + break; + case "empty": + break; } g.setColor(colorBg); diff --git a/apps/circlesclock/settings.js b/apps/circlesclock/settings.js index 8dab5fccf..c03f02847 100644 --- a/apps/circlesclock/settings.js +++ b/apps/circlesclock/settings.js @@ -7,8 +7,11 @@ storage.write(SETTINGS_FILE, settings); } - var valuesCircleTypes = ["steps", "stepsDist", "hr", "battery", "weather", "empty"]; - var namesCircleTypes = ["steps", "distance", "heart", "battery", "weather", "empty"]; + const valuesCircleTypes = ["steps", "stepsDist", "hr", "battery", "weather", "empty"]; + const namesCircleTypes = ["steps", "distance", "heart", "battery", "weather", "empty"]; + + const weatherData = ["humidity", "wind", "empty"]; + E.showMenu({ '': { 'title': 'circlesclock' }, '< Back': back, @@ -77,6 +80,12 @@ format: () => (settings.showWidgets ? 'Yes' : 'No'), onchange: x => save('showWidgets', x), }, + 'weather circle': { + value: settings.weatherCircleData ? weatherData.indexOf(settings.weatherCircleData) : 0, + min: 0, max: 2, + format: v => weatherData[v], + onchange: x => save('weatherCircleData', weatherData[x]), + }, 'left': { value: settings.circle1 ? valuesCircleTypes.indexOf(settings.circle1) : 0, min: 0, max: 5, From a96aba5f728a896ef8226af862fd781dbe017d6d Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Fri, 14 Jan 2022 15:44:56 +0100 Subject: [PATCH 025/174] Increase version --- apps.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps.json b/apps.json index 14e12c164..bef9f9bb1 100644 --- a/apps.json +++ b/apps.json @@ -5151,7 +5151,7 @@ { "id": "circlesclock", "name": "Circles clock", "shortName":"Circles clock", - "version":"0.05", + "version":"0.06", "description": "A clock with circles for different data at the bottom in a probably familiar style", "icon": "app.png", "screenshots": [{"url":"screenshot-dark.png"}, {"url":"screenshot-light.png"}], From e633bf00a0e7c9e60746affffb6b8ac6c9c91d05 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Fri, 14 Jan 2022 16:14:42 +0100 Subject: [PATCH 026/174] Code cleanup & moved common code to functions --- apps/circlesclock/app.js | 136 ++++++++++++++++----------------------- 1 file changed, 55 insertions(+), 81 deletions(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 11e8ccfd6..40cf16ad6 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -65,7 +65,6 @@ const radiusOuter = 25; const radiusInner = 20; const circleFont = "Vector:15"; const circleFontBig = "Vector:16"; -const circleFontSmall = "Vector:13"; function draw() { g.clear(true); @@ -168,16 +167,12 @@ function isCircleEnabled(type) { return getCirclePosition(type) != undefined; } + function drawSteps(w) { if (!w) w = getCirclePosition("steps"); const steps = getSteps(); - // Draw rectangle background: - g.setColor(colorBg); - g.fillRect(w - radiusOuter - 3, h3 - radiusOuter - 3, w + radiusOuter + 3, h3 + radiusOuter + 3); - - g.setColor(colorGrey); - g.fillCircle(w, h3, radiusOuter); + drawCircleBackground(w); const stepGoal = settings.stepGoal || 10000; if (stepGoal > 0) { @@ -186,15 +181,9 @@ function drawSteps(w) { drawGauge(w, h3, percent, colorBlue); } - g.setColor(colorBg); - g.fillCircle(w, h3, radiusInner); + drawInnerCircleAndTriangle(w); - g.fillPoly([w, h3, w - 15, h3 + radiusOuter + 5, w + 15, h3 + radiusOuter + 5]); - - g.setFont(circleFont); - g.setFontAlign(0, 0); - g.setColor(colorFg); - g.drawString(shortValue(steps), w + 2, h3); + writeCircleText(w, shortValue(steps)); g.drawImage(shoesIcon, w - 6, h3 + radiusOuter - 6); } @@ -205,12 +194,7 @@ function drawStepsDistance(w) { const stepDistance = settings.stepLength || 0.8; const stepsDistance = Math.round(steps * stepDistance); - // Draw rectangle background: - g.setColor(colorBg); - g.fillRect(w - radiusOuter - 3, h3 - radiusOuter - 3, w + radiusOuter + 3, h3 + radiusOuter + 3); - - g.setColor(colorGrey); - g.fillCircle(w, h3, radiusOuter); + drawCircleBackground(w); const stepDistanceGoal = settings.stepDistanceGoal || 8000; if (stepDistanceGoal > 0) { @@ -219,15 +203,9 @@ function drawStepsDistance(w) { drawGauge(w, h3, percent, colorGreen); } - g.setColor(colorBg); - g.fillCircle(w, h3, radiusInner); + drawInnerCircleAndTriangle(w); - g.fillPoly([w, h3, w - 15, h3 + radiusOuter + 5, w + 15, h3 + radiusOuter + 5]); - - g.setFont(circleFont); - g.setFontAlign(0, 0); - g.setColor(colorFg); - g.drawString(shortValue(stepsDistance), w + 2, h3); + writeCircleText(w, shortValue(stepsDistance)); g.drawImage(shoesIconGreen, w - 6, h3 + radiusOuter - 6); } @@ -235,12 +213,7 @@ function drawStepsDistance(w) { function drawHeartRate(w) { if (!w) w = getCirclePosition("hr"); - // Draw rectangle background: - g.setColor(colorBg); - g.fillRect(w - radiusOuter - 3, h3 - radiusOuter - 3, w + radiusOuter + 3, h3 + radiusOuter + 3); - - g.setColor(colorGrey); - g.fillCircle(w, h3, radiusOuter); + drawCircleBackground(w); if (hrtValue != undefined) { const minHR = settings.minHR || 40; @@ -248,15 +221,9 @@ function drawHeartRate(w) { drawGauge(w, h3, percent, colorRed); } - g.setColor(colorBg); - g.fillCircle(w, h3, radiusInner); + drawInnerCircleAndTriangle(w); - g.fillPoly([w, h3, w - 15, h3 + radiusOuter + 5, w + 15, h3 + radiusOuter + 5]); - - g.setFont(circleFontBig); - g.setFontAlign(0, 0); - g.setColor(colorFg); - g.drawString(hrtValue != undefined ? hrtValue : "-", w, h3); + writeCircleText(w, hrtValue != undefined ? hrtValue : "-"); g.drawImage(heartIcon, w - 6, h3 + radiusOuter - 6); } @@ -265,25 +232,14 @@ function drawBattery(w) { if (!w) w = getCirclePosition("battery"); const battery = E.getBattery(); - // Draw rectangle background: - g.setColor(colorBg); - g.fillRect(w - radiusOuter - 3, h3 - radiusOuter - 3, w + radiusOuter + 3, h3 + radiusOuter + 3); - - g.setColor(colorGrey); - g.fillCircle(w, h3, radiusOuter); + drawCircleBackground(w); if (battery > 0) { const percent = battery / 100; drawGauge(w, h3, percent, colorYellow); } - g.setColor(colorBg); - g.fillCircle(w, h3, radiusInner); - - g.fillPoly([w, h3, w - 15, h3 + radiusOuter + 5, w + 15, h3 + radiusOuter + 5]); - - g.setFont(circleFont); - g.setFontAlign(0, 0); + drawInnerCircleAndTriangle(w); let icon = powerIcon; let color = colorFg; @@ -296,8 +252,7 @@ function drawBattery(w) { icon = powerIconRed; } } - g.setColor(color); - g.drawString(battery + '%', w, h3); + writeCircleText(w, battery + '%'); g.drawImage(icon, w - 6, h3 + radiusOuter - 6); } @@ -308,12 +263,7 @@ function drawWeather(w) { const tempString = weather ? locale.temp(weather.temp - 273.15) : undefined; const code = weather ? weather.code : -1; - // Draw rectangle background: - g.setColor(colorBg); - g.fillRect(w - radiusOuter - 3, h3 - radiusOuter - 3, w + radiusOuter + 3, h3 + radiusOuter + 3); - - g.setColor(colorGrey); - g.fillCircle(w, h3, radiusOuter); + drawCircleBackground(w); const data = settings.weatherCircleData || "humidity"; switch (data) { @@ -334,16 +284,9 @@ function drawWeather(w) { break; } - g.setColor(colorBg); - g.fillCircle(w, h3, radiusInner); + drawInnerCircleAndTriangle(w); - g.fillPoly([w, h3, w - 25, h3 + radiusOuter + 5, w + 25, h3 + radiusOuter + 5]); - - const content = tempString ? tempString : "?"; - g.setFont(content.length < 4 ? circleFont : circleFontSmall); - g.setFontAlign(0, 0); - g.setColor(colorFg); - g.drawString(content, w, h3); + writeCircleText(w, tempString ? tempString : "?"); if (code > 0) { const icon = getWeatherIconByCode(code); @@ -400,32 +343,63 @@ function getWeatherIconByCode(code) { return undefined; } +/* + * Draws the background and the grey circle + */ +function drawCircleBackground(w) { + // Draw rectangle background: + g.setColor(colorBg); + g.fillRect(w - radiusOuter - 3, h3 - radiusOuter - 3, w + radiusOuter + 3, h3 + radiusOuter + 3); + // Draw grey background circle: + g.setColor(colorGrey); + g.fillCircle(w, h3, radiusOuter); +} + +function drawInnerCircleAndTriangle(w) { + // Draw inner circle + g.setColor(colorBg); + g.fillCircle(w, h3, radiusInner); + // Draw triangle which covers the bottom of the circle + g.fillPoly([w, h3, w - 15, h3 + radiusOuter + 5, w + 15, h3 + radiusOuter + 5]); +} + function radians(a) { return a * Math.PI / 180; } +/* + * This draws the actual gauge consisting out of lots of little filled circles + */ function drawGauge(cx, cy, percent, color) { const offset = 15; const end = 345; - const r = radiusInner + 3; + const radius = radiusInner + 3; + const size = radiusOuter - radiusInner - 2; if (percent <= 0) return; if (percent > 1) percent = 1; - const startrot = -offset; - const endrot = startrot - ((end - offset) * percent); + const startRotation = -offset; + const endRotation = startRotation - ((end - offset) * percent); g.setColor(color); - const size = radiusOuter - radiusInner - 2; - // draw gauge - for (let i = startrot; i > endrot - size; i -= size) { - x = cx + r * Math.sin(radians(i)); - y = cy + r * Math.cos(radians(i)); + for (let i = startRotation; i > endRotation - size; i -= size) { + x = cx + radius * Math.sin(radians(i)); + y = cy + radius * Math.cos(radians(i)); g.fillCircle(x, y, size); } } +function writeCircleText(w, content) { + if (content == undefined) return; + g.setFont(content.length < 4 ? circleFontBig : circleFont); + + g.setFontAlign(0, 0); + g.setColor(colorFg); + g.drawString(content, w, h3); +} + function shortValue(v) { if (isNaN(v)) return '-'; if (v <= 999) return v; From cd9520272b29c5cedff9a0bf2347c9d045216cc0 Mon Sep 17 00:00:00 2001 From: Hilmar Strauch <56518493+HilmarSt@users.noreply.github.com> Date: Fri, 14 Jan 2022 16:31:05 +0100 Subject: [PATCH 027/174] Don't start drawing with white colour on white canvas --- apps/tinydraw/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/tinydraw/app.js b/apps/tinydraw/app.js index e4c612219..4c8cdc5a6 100644 --- a/apps/tinydraw/app.js +++ b/apps/tinydraw/app.js @@ -1,7 +1,7 @@ (function () { var pen = 'circle'; var discard = null; - var kule = [255, 255, 255]; + var kule = [0, 255, 255]; // cyan, magenta, yellow var oldLock = false; setInterval(() => { From 746b7c28711b728230f1e5e68fd83f25a739c68a Mon Sep 17 00:00:00 2001 From: Hilmar Strauch <56518493+HilmarSt@users.noreply.github.com> Date: Fri, 14 Jan 2022 16:42:25 +0100 Subject: [PATCH 028/174] Update ChangeLog --- apps/tinydraw/ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/tinydraw/ChangeLog b/apps/tinydraw/ChangeLog index af7f83942..2ee16e6b5 100644 --- a/apps/tinydraw/ChangeLog +++ b/apps/tinydraw/ChangeLog @@ -1 +1,2 @@ 0.01: Initial release +0.02: Don't start drawing with white colour on white canvas From 1029d76614d7b70ea491c45b7f40ede4e96002e1 Mon Sep 17 00:00:00 2001 From: Hilmar Strauch <56518493+HilmarSt@users.noreply.github.com> Date: Fri, 14 Jan 2022 16:43:27 +0100 Subject: [PATCH 029/174] Update apps.json --- apps.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps.json b/apps.json index 14e12c164..6e9852253 100644 --- a/apps.json +++ b/apps.json @@ -4923,7 +4923,7 @@ { "id": "tinydraw", "name": "TinyDraw", "shortName":"TinyDraw", - "version":"0.01", + "version":"0.02", "type": "app", "description": "Draw stuff in your wrist", "icon": "app.png", From f4fd7e1d41af928373df5a0d11fc32974935c9ba Mon Sep 17 00:00:00 2001 From: Andreas Rozek Date: Fri, 14 Jan 2022 17:22:49 +0100 Subject: [PATCH 030/174] Update Customizer.html --- apps/ac_ac/Customizer.html | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/apps/ac_ac/Customizer.html b/apps/ac_ac/Customizer.html index cc8e21d1f..f675db265 100644 --- a/apps/ac_ac/Customizer.html +++ b/apps/ac_ac/Customizer.html @@ -101,8 +101,8 @@