diff --git a/apps.json b/apps.json index f50a5370c..6476f6d47 100644 --- a/apps.json +++ b/apps.json @@ -1,10 +1,10 @@ [ { "id": "boot", "name": "Bootloader", - "tags": "tool,system", + "tags": "tool,system,b2", "type":"bootloader", "icon": "bootloader.png", - "version":"0.25", + "version":"0.28", "description": "This is needed by Bangle.js to automatically load the clock, menu, widgets and settings", "storage": [ {"name":".boot0","url":"boot0.js"}, @@ -44,19 +44,32 @@ "icon": "app.png", "version":"0.06", "description": "This is needed by Bangle.js to display a menu allowing you to choose your own applications. You can replace this with a customised launcher.", - "tags": "tool,system,launcher", + "tags": "tool,system,launcher,b2", "type":"launch", "storage": [ {"name":"launch.app.js","url":"app.js"} ], "sortorder" : -10 }, + { "id": "launchb2", + "name": "Launcher (Bangle.js 2)", + "shortName":"Launcher", + "icon": "app.png", + "version":"0.01", + "description": "This is needed by Bangle.js 2.0 to display a menu allowing you to choose your own applications. It will not work on Bangle.js 1.0.", + "tags": "tool,system,launcher,b2,bno1", + "type":"launch", + "storage": [ + {"name":"launchb2.app.js","url":"app.js"} + ], + "sortorder" : -10 + }, { "id": "about", "name": "About", "icon": "app.png", "version":"0.08", "description": "Bangle.js About page - showing software version, stats, and a collaborative mural from the Bangle.js KickStarter backers", - "tags": "tool,system", + "tags": "tool,system,b2", "allow_emulator":true, "storage": [ {"name":"about.app.js","url":"app.js"}, @@ -68,7 +81,7 @@ "icon": "locale.png", "version":"0.09", "description": "Translations for different countries", - "tags": "tool,system,locale,translate", + "tags": "tool,system,locale,translate,b2", "type": "locale", "custom":"locale.html", "readme": "README.md", @@ -81,7 +94,7 @@ "name": "Notifications (default)", "shortName":"Notifications", "icon": "notify.png", - "version":"0.08", + "version":"0.09", "description": "A handler for displaying notifications that displays them in a bar at the top of the screen", "tags": "widget", "type": "notify", @@ -94,7 +107,7 @@ "name": "Fullscreen Notifications", "shortName":"Notifications", "icon": "notify.png", - "version":"0.08", + "version":"0.09", "description": "A handler for displaying notifications that displays them fullscreen. This may not fully restore the screen after on some apps. See `Notifications (default)` for more information about the notifications library.", "tags": "widget", "type": "notify", @@ -140,7 +153,7 @@ { "id": "gbridge", "name": "Gadgetbridge", "icon": "app.png", - "version":"0.22", + "version":"0.23", "description": "The default notification handler for Gadgetbridge notifications from Android", "tags": "tool,system,android,widget", "readme": "README.md", @@ -158,7 +171,7 @@ { "id": "mclock", "name": "Morphing Clock", "icon": "clock-morphing.png", - "version":"0.06", + "version":"0.07", "description": "7 segment clock that morphs between minutes and hours", "tags": "clock", "type":"clock", @@ -172,9 +185,9 @@ { "id": "setting", "name": "Settings", "icon": "settings.png", - "version":"0.26", + "version":"0.28", "description": "A menu for setting up Bangle.js", - "tags": "tool,system", + "tags": "tool,system,b2", "readme": "README.md", "storage": [ {"name":"setting.app.js","url":"settings.js"}, @@ -191,7 +204,7 @@ "icon": "app.png", "version":"0.11", "description": "Set and respond to alarms", - "tags": "tool,alarm,widget", + "tags": "tool,alarm,widget,b2", "storage": [ {"name":"alarm.app.js","url":"app.js"}, {"name":"alarm.boot.js","url":"boot.js"}, @@ -206,9 +219,9 @@ { "id": "wclock", "name": "Word Clock", "icon": "clock-word.png", - "version":"0.02", + "version":"0.03", "description": "Display Time as Text", - "tags": "clock", + "tags": "clock,b2", "type":"clock", "allow_emulator":true, "storage": [ @@ -245,7 +258,7 @@ { "id": "slidingtext", "name": "Sliding Clock", "icon": "slidingtext.png", - "version":"0.05", + "version":"0.06", "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", "tags": "clock", "type":"clock", @@ -265,6 +278,33 @@ {"name":"slidingtext.dtfmt.js","url":"slidingtext.dtfmt.js"} ] }, + { "id": "solarclock", + "name": "Solar Clock", + "icon": "solar_clock.png", + "version":"0.01", + "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", + "tags": "clock", + "type":"clock", + "allow_emulator":false, + "readme": "README.md", + "custom":"custom.html", + "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", "icon": "sweepclock.png", @@ -283,7 +323,7 @@ "name": "Image background clock", "shortName":"Image Clock", "icon": "app.png", - "version":"0.07", + "version":"0.08", "description": "A clock with an image as a background", "tags": "clock", "type" : "clock", @@ -299,7 +339,7 @@ { "id": "impwclock", "name": "Imprecise Word Clock", "icon": "clock-impword.png", - "version":"0.02", + "version":"0.03", "description": "Imprecise word clock for vacations, weekends, and those who never need accurate time.", "tags": "clock", "type":"clock", @@ -312,9 +352,9 @@ { "id": "aclock", "name": "Analog Clock", "icon": "clock-analog.png", - "version": "0.14", + "version": "0.15", "description": "An Analog Clock", - "tags": "clock", + "tags": "clock,b2", "type":"clock", "allow_emulator":true, "storage": [ @@ -325,9 +365,9 @@ { "id": "clock2x3", "name": "2x3 Pixel Clock", "icon": "clock2x3.png", - "version":"0.04", + "version":"0.05", "description": "This is a simple clock using minimalist 2x3 pixel numerical digits", - "tags": "clock", + "tags": "clock,b2", "type": "clock", "allow_emulator":true, "storage": [ @@ -338,9 +378,9 @@ { "id": "geissclk", "name": "Geiss Clock", "icon": "clock.png", - "version":"0.02", + "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", - "tags": "clock", + "tags": "clock,bno2", "type":"clock", "storage": [ {"name":"geissclk.app.js","url":"clock.js"}, @@ -362,13 +402,17 @@ { "id": "trex", "name": "T-Rex", "icon": "trex.png", - "version":"0.02", + "version":"0.03", "description": "T-Rex game in the style of Chrome's offline game", "tags": "game", "allow_emulator":true, "storage": [ {"name":"trex.app.js","url":"trex.js"}, - {"name":"trex.img","url":"trex-icon.js","evaluate":true} + {"name":"trex.img","url":"trex-icon.js","evaluate":true}, + {"name":"trex.settings.js","url":"settings.js"} + ], + "data": [ + {"name":"trex.score", "storageFile": true} ] }, { "id": "astroid", @@ -453,10 +497,11 @@ { "id": "gpsrec", "name": "GPS Recorder", "icon": "app.png", - "version":"0.19", + "version":"0.22", "interface": "interface.html", "description": "Application that allows you to record a GPS track. Can run in background", "tags": "tool,outdoors,gps,widget", + "readme": "README.md", "storage": [ {"name":"gpsrec.app.js","url":"app.js"}, {"name":"gpsrec.img","url":"app-icon.js","evaluate":true}, @@ -515,7 +560,7 @@ { "id": "files", "name": "App Manager", "icon": "files.png", - "version":"0.06", + "version":"0.07", "description": "Show currently installed apps, free space, and allow their deletion from the watch", "tags": "tool,system,files", "storage": [ @@ -526,7 +571,7 @@ { "id": "weather", "name": "Weather", "icon": "icon.png", - "version":"0.03", + "version":"0.05", "description": "Show Gadgetbridge weather report", "readme": "readme.md", "tags": "widget,outdoors", @@ -571,9 +616,9 @@ { "id": "widbat", "name": "Battery Level Widget", "icon": "widget.png", - "version":"0.06", + "version":"0.07", "description": "Show the current battery level and charging status in the top right of the clock", - "tags": "widget,battery", + "tags": "widget,battery,b2", "type":"widget", "storage": [ {"name":"widbat.wid.js","url":"widget.js"} @@ -582,9 +627,9 @@ { "id": "widlock", "name": "Lock Widget", "icon": "widget.png", - "version":"0.01", + "version":"0.03", "description": "On devices with always-on display (Bangle.js 2) this displays lock icon whenever the display is locked", - "tags": "widget,lock", + "tags": "widget,lock,b2", "type":"widget", "storage": [ {"name":"widlock.wid.js","url":"widget.js"} @@ -627,9 +672,9 @@ { "id": "widbt", "name": "Bluetooth Widget", "icon": "widget.png", - "version":"0.04", + "version":"0.05", "description": "Show the current Bluetooth connection status in the top right of the clock", - "tags": "widget,bluetooth", + "tags": "widget,bluetooth,b2", "type":"widget", "storage": [ {"name":"widbt.wid.js","url":"widget.js"} @@ -665,7 +710,7 @@ { "id": "hrm", "name": "Heart Rate Monitor", "icon": "heartrate.png", - "version":"0.04", + "version":"0.05", "description": "Measure your heart rate and see live sensor data", "tags": "health", "storage": [ @@ -847,9 +892,9 @@ { "id": "sclock", "name": "Simple Clock", "icon": "clock-simple.png", - "version":"0.04", + "version":"0.06", "description": "A Simple Digital Clock", - "tags": "clock", + "tags": "clock,b2", "type":"clock", "allow_emulator":true, "storage": [ @@ -860,9 +905,9 @@ { "id": "s7clk", "name": "Simple 7 segment Clock", "icon": "icon.png", - "version":"0.02", + "version":"0.03", "description": "A simple 7 segment Clock with date", - "tags": "clock", + "tags": "clock,b2", "type":"clock", "allow_emulator":true, "storage": [ @@ -873,7 +918,7 @@ { "id": "vibrclock", "name": "Vibrate Clock", "icon": "app.png", - "version":"0.02", + "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.", "tags": "clock", "type":"clock", @@ -886,7 +931,7 @@ { "id": "svclock", "name": "Simple V-Clock", "icon": "vclock-simple.png", - "version":"0.01", + "version":"0.02", "description": "Modification of Simple Clock 0.04 to use Vectorfont", "tags": "clock", "type":"clock", @@ -899,9 +944,9 @@ { "id": "dclock", "name": "Dev Clock", "icon": "clock-dev.png", - "version":"0.09", + "version":"0.10", "description": "A Digital Clock including timestamp (tst), beats(@), days in current month (dm) and days since new moon (l)", - "tags": "clock", + "tags": "clock,b2", "type":"clock", "allow_emulator":true, "storage": [ @@ -1012,7 +1057,7 @@ { "id": "miclock", "name": "Mixed Clock", "icon": "clock-mixed.png", - "version":"0.04", + "version":"0.05", "description": "A mix of analog and digital Clock", "tags": "clock", "type":"clock", @@ -1025,7 +1070,7 @@ { "id": "bclock", "name": "Binary Clock", "icon": "clock-binary.png", - "version":"0.02", + "version":"0.03", "description": "A simple binary clock watch face", "tags": "clock", "type":"clock", @@ -1101,9 +1146,9 @@ "name": "Large Digit Blob Clock", "shortName" : "Blob Clock", "icon": "clock-blob.png", - "version":"0.05", + "version":"0.06", "description": "A clock with big digits", - "tags": "clock", + "tags": "clock,b2", "type":"clock", "allow_emulator":true, "storage": [ @@ -1114,9 +1159,9 @@ { "id": "boldclk", "name": "Bold Clock", "icon": "bold_clock.png", - "version":"0.03", + "version":"0.04", "description": "Simple, readable and practical clock", - "tags": "clock", + "tags": "clock,b2", "type":"clock", "allow_emulator":true, "storage": [ @@ -1127,7 +1172,7 @@ { "id": "widclk", "name": "Digital clock widget", "icon": "widget.png", - "version":"0.04", + "version":"0.05", "description": "A simple digital clock widget", "tags": "widget,clock", "type":"widget", @@ -1138,9 +1183,9 @@ { "id": "widpedom", "name": "Pedometer widget", "icon": "widget.png", - "version":"0.13", + "version":"0.14", "description": "Daily pedometer widget", - "tags": "widget", + "tags": "widget,b2", "type":"widget", "storage": [ {"name":"widpedom.wid.js","url":"widget.js"}, @@ -1150,7 +1195,7 @@ { "id": "berlinc", "name": "Berlin Clock", "icon": "berlin-clock.png", - "version":"0.03", + "version":"0.04", "description": "Berlin Clock (see https://en.wikipedia.org/wiki/Mengenlehreuhr)", "tags": "clock", "type":"clock", @@ -1163,9 +1208,9 @@ { "id": "ctrclk", "name": "Centerclock", "icon": "app.png", - "version":"0.02", + "version":"0.03", "description": "Watch-centered digital 24h clock with date in dd.mm.yyyy format.", - "tags": "clock", + "tags": "clock,bno2", "type":"clock", "allow_emulator":true, "storage": [ @@ -1203,9 +1248,9 @@ "id": "pipboy", "name": "Pipboy", "icon": "app.png", - "version": "0.03", + "version": "0.04", "description": "Pipboy themed clock", - "tags": "clock", + "tags": "clock,bno2", "type":"clock", "allow_emulator":true, "storage": [ @@ -1226,6 +1271,19 @@ {"name":"torch.img","url":"app-icon.js","evaluate":true} ] }, + { "id": "rtorch", + "name": "Red Torch", + "shortName":"RedTorch", + "icon": "app.png", + "version":"0.01", + "description": "Turns screen RED to help you see in the dark without breaking your night vision. Select from the launcher or press BTN3,BTN1,BTN3,BTN1 quickly to start when in any app that shows widgets", + "tags": "tool,torch", + "storage": [ + {"name":"rtorch.app.js","url":"app.js"}, + {"name":"rtorch.wid.js","url":"widget.js"}, + {"name":"rtorch.img","url":"app-icon.js","evaluate":true} + ] + }, { "id": "wohrm", "name": "Workout HRM", "icon": "app.png", @@ -1284,9 +1342,9 @@ "name": "Commandline-Clock", "shortName":"CLI-Clock", "icon": "app.png", - "version":"0.12", + "version":"0.13", "description": "Simple CLI-Styled Clock", - "tags": "clock,cli,command,bash,shell", + "tags": "clock,cli,command,bash,shell,b2", "type":"clock", "allow_emulator":true, "storage": [ @@ -1308,10 +1366,11 @@ { "id": "barclock", "name": "Bar Clock", "icon": "clock-bar.png", - "version":"0.05", + "version":"0.07", "description": "A simple digital clock showing seconds as a bar", "tags": "clock", "type":"clock", + "readme": "README.md", "allow_emulator":true, "storage": [ {"name":"barclock.app.js","url":"clock-bar.js"}, @@ -1321,9 +1380,9 @@ { "id": "dotclock", "name": "Dot Clock", "icon": "clock-dot.png", - "version":"0.02", + "version":"0.03", "description": "A Minimal Dot Analog Clock", - "tags": "clock", + "tags": "clock,b2", "type":"clock", "allow_emulator":true, "storage": [ @@ -1444,7 +1503,7 @@ { "id": "minionclk", "name": "Minion clock", "icon": "minionclk.png", - "version": "0.04", + "version": "0.05", "description": "Minion themed clock.", "tags": "clock,minion", "type": "clock", @@ -1458,9 +1517,9 @@ "name": "OpenStreetMap", "shortName":"OpenStMap", "icon": "app.png", - "version":"0.05", + "version":"0.08", "description": "[BETA] Loads map tiles from OpenStreetMap onto your Bangle.js and displays a map of where you are", - "tags": "outdoors,gps", + "tags": "outdoors,gps,b2", "custom": "custom.html", "storage": [ {"name":"openstmap","url":"openstmap.js"}, @@ -1525,9 +1584,9 @@ "name": "Dev Stopwatch", "shortName":"Dev Stopwatch", "icon": "app.png", - "version":"0.02", + "version":"0.03", "description": "Stopwatch with 5 laps supported (cyclically replaced)", - "tags": "stopwatch, chrono, timer, chronometer", + "tags": "stopwatch,chrono,timer,chronometer,b2", "allow_emulator":true, "storage": [ {"name":"devstopwatch.app.js","url":"app.js"}, @@ -1566,7 +1625,7 @@ "name": "Numerals Clock", "shortName": "Numerals Clock", "icon": "numerals.png", - "version":"0.08", + "version":"0.09", "description": "A simple big numerals clock", "tags": "numerals,clock", "type":"clock", @@ -1727,7 +1786,7 @@ "name": "Black Jack game", "shortName":"Black Jack game", "icon": "blackjack.png", - "version":"0.01", + "version":"0.02", "description": "Simple implementation of card game Black Jack", "tags": "game", "allow_emulator":true, @@ -1753,7 +1812,7 @@ "name": "SWL Clock / Short Wave Listner Clock", "shortName": "SWL Clock", "icon": "swlclk.png", - "version":"0.01", + "version":"0.02", "description": "Display Local, UTC time and some programs on the shorts waves along the day, with the frequencies", "tags": "tool,clock", "type":"clock", @@ -1769,7 +1828,7 @@ "name": "Round clock with seconds, minutes and date", "shortName": "Round Clock", "icon": "app.png", - "version": "0.05", + "version": "0.06", "description": "Designed round clock with ticks for minutes and seconds and heart rate indication", "tags": "clock", "type": "clock", @@ -1783,7 +1842,7 @@ "name": "fclock", "shortName": "F Clock", "icon": "app.png", - "version": "0.01", + "version": "0.02", "description": "Simple design of a digital clock", "tags": "clock", "type": "clock", @@ -1852,9 +1911,9 @@ { "id": "calendar", "name": "Calendar", "icon": "calendar.png", - "version": "0.01", + "version": "0.02", "description": "Simple calendar", - "tags": "calendar", + "tags": "calendar,b2", "readme": "README.md", "allow_emulator": true, "storage": [ @@ -1980,7 +2039,7 @@ "id": "beebclock", "name": "Beeb Clock", "icon": "beebclock.png", - "version":"0.03", + "version":"0.04", "description": "Clock face that may be coincidentally familiar to BBC viewers", "tags": "clock", "type": "clock", @@ -2024,9 +2083,9 @@ "name": "Time Traveller's Chronometer", "shortName": "Time Travel Clock", "icon": "gallifr.png", - "version": "0.01", + "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.", - "tags": "clock", + "tags": "clock,b2", "readme": "README.md", "type": "clock", "allow_emulator":true, @@ -2078,6 +2137,20 @@ { "name": "jbm8b.img", "url": "app-icon.js", "evaluate": true } ] }, + { + "id": "jbm8b_IT", + "name": "Magic 8 Ball Italiano", + "shortName": "Magic 8 Ball IT", + "icon": "app.png", + "description": "La palla predice il futuro", + "tags": "game", + "version": "0.01", + "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", @@ -2108,7 +2181,7 @@ "name": "Binary Clock", "shortName":"Binary Clock", "icon": "app.png", - "version":"0.02", + "version":"0.03", "description": "A binary clock with hours and minutes. BTN1 toggles a digital clock.", "tags": "clock,binary", "type": "clock", @@ -2135,9 +2208,9 @@ "name": "Animated Clock", "shortName":"Anim Clock", "icon": "app.png", - "version":"0.02", + "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", - "tags": "clock,animated", + "tags": "clock,animated,bno2", "type": "clock", "storage": [ {"name":"animclk.app.js","url":"app.js"}, @@ -2151,9 +2224,9 @@ "name": "Analog Clock (Image background)", "shortName":"Analog Clock", "icon": "app.png", - "version":"0.02", + "version":"0.03", "description": "An analog clock with an image background", - "tags": "clock", + "tags": "clock,bno2", "type": "clock", "storage": [ {"name":"analogimgclk.app.js","url":"app.js"}, @@ -2166,7 +2239,7 @@ "name": "Vertical watch face", "shortName":"Vertical Face", "icon": "app.png", - "version":"0.08", + "version":"0.09", "description": "A simple vertical watch face with the date. Heart rate monitor is toggled with BTN1", "tags": "clock", "type":"clock", @@ -2471,7 +2544,7 @@ "name": "World Clock - 4 time zones", "shortName":"World Clock", "icon": "app.png", - "version":"0.03", + "version":"0.04", "description": "Current time zone plus up to four others", "tags": "clock", "type" : "clock", @@ -2489,9 +2562,9 @@ "name": "Digital Clock Face", "shortName":"Digi Clock", "icon": "digiclock.png", - "version":"0.01", + "version":"0.02", "description": "A simple digital clock with the time, day, month, and year", - "tags": "clock", + "tags": "clock,bno2", "type" : "clock", "storage": [ {"name":"digiclock.app.js","url":"digiclock.js"}, @@ -2564,7 +2637,7 @@ "name": "NCR Clock", "shortName":"NCR Clock", "icon": "app.png", - "version":"0.01", + "version":"0.02", "description": "NodeConf Remote clock", "tags": "clock", "type": "clock", @@ -2577,7 +2650,7 @@ "name": "ISO Compliant Clock Face", "shortName":"ISO Clock", "icon": "isoclock.png", - "version":"0.01", + "version":"0.02", "description": "Tweaked fork of digiclock for ISO date and time", "tags": "clock", "type" : "clock", @@ -2648,7 +2721,7 @@ { "id": "dtlaunch", "name": "Desktop Launcher", "icon": "icon.png", - "version":"0.03", + "version":"0.04", "description": "Desktop style App Launcher with six apps per page - fast access if you have lots of apps installed.", "readme": "README.md", "tags": "tool,system,launcher", @@ -2735,7 +2808,7 @@ { "id": "lazyclock", "name": "Lazy Clock", "icon": "lazyclock.png", - "version":"0.02", + "version":"0.03", "readme": "README.md", "description": "Tells the time, roughly", "tags": "clock", @@ -2749,7 +2822,7 @@ { "id": "astral", "name": "Astral Clock", "icon": "app-icon.png", - "version":"0.02", + "version":"0.03", "readme": "README.md", "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.", "tags": "clock", @@ -2775,13 +2848,13 @@ "name": "Game of Life Clock", "shortName":"Conway's Clock", "icon": "app.png", - "version":"0.05", + "version":"0.06", "description": "Modification and clockification of Conway's Game of Life", "tags": "clock", "type" : "clock", "readme": "README.md", "storage": [ - {"name":"lifeclk.app.js","url":"app.js"}, + {"name":"lifeclk.app.js","url":"app.min.js"}, {"name":"lifeclk.img","url":"app-icon.js","evaluate":true} ] }, @@ -2808,7 +2881,7 @@ "name": "De-Stress", "shortName":"De-Stress", "icon": "app.png", - "version":"0.01", + "version":"0.02", "description": "Simple haptic heartbeat", "storage": [ {"name":"de-stress.app.js","url":"app.js"}, @@ -2837,7 +2910,7 @@ "name": "Morph Clock+", "shortName":"Morph Clock+", "icon": "mclockplus.png", - "version":"1.0", + "version":"0.02", "description": "Morphing Clock with more readable seconds and date and additional stopwatch", "tags": "clock", "type": "clock", @@ -3045,7 +3118,7 @@ "version":"0.01", "description": "Displays RGB565 and RGB888 colors, its name and code in screen.", "readme": "README.md", - "tags": "Color, input,buttons,touch,UI", + "tags": "Color,input,buttons,touch,UI,bno2", "storage": [ {"name":"color_catalog.app.js","url":"app.js"}, {"name":"color_catalog.img","url":"app-icon.js","evaluate":true} @@ -3067,7 +3140,7 @@ { "id": "simplest", "name": "Simplest Clock", "icon": "simplest.png", - "version":"0.01", + "version":"0.02", "description": "The simplest working clock, acts as a tutorial piece", "tags": "clock", "type":"clock", @@ -3135,7 +3208,7 @@ { "id": "kitchen", "name": "Kitchen Combo", "icon": "kitchen.png", - "version":"0.10", + "version":"0.12", "description": "Combination of the Stepo, Walkersclock, Arrow and Waypointer apps into a multiclock format. 'Everything but the kitchen sink'. Requires firmware v2.08.167 or later", "tags": "tool,outdoors,gps", "type":"clock", @@ -3143,11 +3216,9 @@ "interface":"waypoints.html", "storage": [ {"name":"kitchen.app.js","url":"kitchen.app.js"}, - {"name":"stepo.kit.js","url":"stepo.kit.js"}, - {"name":"gps.kit.js","url":"gps.kit.js"}, - {"name":"digi.kit.js","url":"digi.kit.js"}, - {"name":"heart.kit.js","url":"heart.kit.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} ], @@ -3155,19 +3226,35 @@ {"name":"waypoints.json","url":"waypoints.json"} ] }, +{ "id": "banglebridge", + "name": "BangleBridge", + "shortName":"BangleBridge", + "icon": "widget.png", + "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", + "tags": "widget", + "type": "widget", + "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", + "name": "Quiet Mode Schedule and Widget", "shortName":"Quiet Mode", "icon": "app.png", - "version":"0.01", + "version":"0.02", "description": "Automatically turn Quiet Mode on or off at set times", "readme": "README.md", - "tags": "tool", + "tags": "tool,widget", "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.img","url":"icon.js","evaluate":true}, + {"name":"qmsched.wid.js","url":"widget.js"} ], "data": [ {"name":"qmsched.json"} @@ -3209,7 +3296,6 @@ "readme": "README.md", "description": "An Omnitrix Showpiece", "tags": "game", - "readme": "README.md", "storage": [ {"name":"omnitrix.app.js","url":"omnitrix.app.js"}, {"name":"omnitrix.img","url":"omnitrix.icon.js","evaluate":true} @@ -3219,7 +3305,7 @@ "name": "Bat Clock", "shortName":"Bat Clock", "icon": "bat-clock.png", - "version":"0.01", + "version":"0.02", "description": "Morphing Clock, with an awesome \"The Dark Knight\" themed logo.", "tags": "clock", "type": "clock", @@ -3233,7 +3319,7 @@ "name":"Dozenal Time", "shortName":"Dozenal Time", "icon":"app.png", - "version":"0.01", + "version":"0.04", "description":"A dozenal Holocene calendar and dozenal diurnal clock", "tags":"clock", "type":"clock", @@ -3258,5 +3344,71 @@ {"name":"gbtwist.app.js","url":"app.js"}, {"name":"gbtwist.img","url":"app-icon.js","evaluate":true} ] +}, +{ "id": "thermom", + "name": "Thermometer", + "icon": "app.png", + "version":"0.02", + "description": "Displays the current temperature, updated every 20 seconds", + "tags": "tool", + "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", + "icon": "mystic-dock.png", + "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.", + "tags": "dock", + "type":"dock", + "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", + "icon": "mystic-clock.png", + "version":"1.01", + "description": "A retro-inspired watchface featuring time, date, and an interactive data display line.", + "tags": "clock", + "type":"clock", + "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", + "icon": "hcclock-icon.png", + "version":"0.01", + "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.", + "tags": "clock", + "type":"clock", + "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", + "icon": "thermf.png", + "version":"0.01", + "description": "A modification of the Thermometer App to display temprature in Fahrenheit", + "tags": "tool", + "storage": [ + {"name":"thermomF.app.js","url":"app.js"}, + {"name":"thermomF.img","url":"app-icon.js","evaluate":true} + ] } ] diff --git a/apps/about/app.js b/apps/about/app.js index 9edd0c94f..b95b8bbd0 100644 --- a/apps/about/app.js +++ b/apps/about/app.js @@ -37,5 +37,7 @@ g.drawString(NRF.getAddress(),g.getWidth()/2,g.getHeight()-8,true); g.flip(); setWatch(_=>load(), BTN1); -setWatch(_=>load(), BTN2); -setWatch(_=>load(), BTN3); +if (global.BTN2) { + setWatch(_=>load(), BTN2); + setWatch(_=>load(), BTN3); +} diff --git a/apps/aclock/ChangeLog b/apps/aclock/ChangeLog index 77d4ea646..aa910b6f6 100644 --- a/apps/aclock/ChangeLog +++ b/apps/aclock/ChangeLog @@ -9,3 +9,4 @@ 0.12: Fix regression after 0.11 0.13: Fix broken date padding (fix #376) 0.14: Remove hardcoded hour buzz (you can install widchime if you miss it) +0.15: Add color scheme support diff --git a/apps/aclock/clock-analog.js b/apps/aclock/clock-analog.js index 7516a0eb7..146f022fc 100644 --- a/apps/aclock/clock-analog.js +++ b/apps/aclock/clock-analog.js @@ -2,13 +2,16 @@ const locale = require('locale'); const p = Math.PI / 2; const pRad = Math.PI / 180; -const faceWidth = 100; // watch face radius (240/2 - 24px for widget area) +const faceWidth = g.getWidth()/2 - 20; // watch face radius (240/2 - 24px for widget area) const widgetHeight=24+1; let timer = null; let currentDate = new Date(); const centerX = g.getWidth() / 2; const centerY = (g.getWidth() / 2) + widgetHeight/2; - +g.theme.dark=false; +let colSecA = g.theme.dark ? "#00A" : "#58F"; // before the second +let colSecB = g.theme.dark ? "#58F" : "#00A"; // after the second +let colSec1 = g.theme.dark ? "#F83" : "#000"; // ON the second const seconds = (angle) => { const a = angle * pRad; @@ -46,40 +49,35 @@ const drawAll = () => { // draw all secs for (let i = 0; i < 60; i++) { - if (i > currentSec) { - g.setColor(0, 0, 0.6); - } else { - g.setColor(0.3, 0.3, 1); - } + g.setColor((i > currentSec) ? colSecA : colSecB); seconds((360 * i) / 60); } onSecond(); - }; const resetSeconds = () => { - g.setColor(0, 0, 0.6); + g.setColor(colSecA); for (let i = 0; i < 60; i++) { seconds((360 * i) / 60); } }; const onSecond = () => { - g.setColor(0.3, 0.3, 1); + g.setColor(colSecB); seconds((360 * currentDate.getSeconds()) / 60); if (currentDate.getSeconds() === 59) { resetSeconds(); onMinute(); } - g.setColor(1, 0.7, 0.2); + g.setColor(colSec1); currentDate = new Date(); seconds((360 * currentDate.getSeconds()) / 60); - g.setColor(1, 1, 1); + g.setColor(g.theme.fg); }; const drawDate = () => { g.reset(); - g.setColor(1, 0, 0); + g.setColor("#f00"); g.setFont('6x8', 2); const dayString = locale.dow(currentDate, true); @@ -89,7 +87,7 @@ const drawDate = () => { // console.log(`${dayString}|${dateString}`); // center date const l = (g.getWidth() - g.stringWidth(dateDisplay)) / 2; - const t = centerY + 37; + const t = centerY + faceWidth*0.37; g.drawString(dateDisplay, l, t, true); // console.log(l, t); }; @@ -99,7 +97,7 @@ const onMinute = () => { resetSeconds(); } // clear existing hands - g.setColor(0, 0, 0); + g.setColor(g.theme.bg); // Hour hand((360 * (currentDate.getHours() + currentDate.getMinutes() / 60)) / 12, -8, faceWidth - 35); // Minute @@ -107,10 +105,10 @@ const onMinute = () => { // get new date, then draw new hands currentDate = new Date(); - g.setColor(1, 0.9, 0.9); + g.setColor(g.theme.fg); // Hour hand((360 * (currentDate.getHours() + currentDate.getMinutes() / 60)) / 12, -8, faceWidth - 35); - g.setColor(1, 1, 0.9); + g.setColor(g.theme.fg); // Minute hand((360 * currentDate.getMinutes()) / 60, -8, faceWidth - 10); drawDate(); @@ -137,8 +135,9 @@ g.clear(); resetSeconds(); startTimers(); drawAll(); + +// Show launcher when button pressed +Bangle.setUI("clock"); + Bangle.loadWidgets(); Bangle.drawWidgets(); - -// Show launcher when middle button pressed -setWatch(Bangle.showLauncher, BTN2, { repeat: false, edge: "falling" }); diff --git a/apps/analogimgclk/ChangeLog b/apps/analogimgclk/ChangeLog index 864afc91e..877ecc04d 100644 --- a/apps/analogimgclk/ChangeLog +++ b/apps/analogimgclk/ChangeLog @@ -1,2 +1,3 @@ 0.01: New App! 0.02: Add BTN2 -> launcher +0.03: Update to use setUI diff --git a/apps/analogimgclk/app.js b/apps/analogimgclk/app.js index 99dace78e..1aea97961 100644 --- a/apps/analogimgclk/app.js +++ b/apps/analogimgclk/app.js @@ -114,5 +114,5 @@ if (g.drawImages) { E.showMessage("Please update\nBangle.js firmware\nto use this clock","analogimgclk"); } -// Show launcher when middle button pressed -setWatch(Bangle.showLauncher, BTN2, { repeat: false, edge: "falling" }); +// Show launcher when button pressed +Bangle.setUI("clock"); diff --git a/apps/animclk/ChangeLog b/apps/animclk/ChangeLog index 7852105a0..348448c34 100644 --- a/apps/animclk/ChangeLog +++ b/apps/animclk/ChangeLog @@ -1,2 +1,3 @@ 0.01: New App! 0.02: Fix bug if image clock wasn't installed +0.03: Update to use setUI diff --git a/apps/animclk/app.js b/apps/animclk/app.js index ced5372a0..4bf63daf6 100644 --- a/apps/animclk/app.js +++ b/apps/animclk/app.js @@ -102,5 +102,5 @@ if (g.drawImages) { } else { E.showMessage("Please update\nBangle.js firmware\nto use this clock","animclk"); } -// Show launcher when middle button pressed -setWatch(Bangle.showLauncher, BTN2, { repeat: false, edge: "falling" }); +// Show launcher when button pressed +Bangle.setUI("clock"); diff --git a/apps/arrow/README.md b/apps/arrow/README.md index 3b439711c..4b77dbc42 100644 --- a/apps/arrow/README.md +++ b/apps/arrow/README.md @@ -36,6 +36,10 @@ charge. *BTN3* - invokes calibration ( can be cancelled if pressed accidentally) +## Issues +* detect when calibration data is missing + ## Acknowledgement This app is based in the work done by [jeffmer](https://github.com/jeffmer/JeffsBangleAppsDev) + diff --git a/apps/astral/ChangeLog b/apps/astral/ChangeLog index 7a9d48bf1..a51c96760 100644 --- a/apps/astral/ChangeLog +++ b/apps/astral/ChangeLog @@ -1,2 +1,3 @@ 0.01: Create astral clock app 0.02: Fixed Whirlpool galaxy RA/DA, larger compass display, fixed moonphase overlapping battery widget +0.03: Update to use Bangle.setUI instead of setWatch diff --git a/apps/astral/app.js b/apps/astral/app.js index 5d2d16e8f..c445463f2 100644 --- a/apps/astral/app.js +++ b/apps/astral/app.js @@ -503,8 +503,8 @@ function coord_to_horizon(utc, ra, dec, lat, lon, h) { } // -// "mean_sidereal_time" returns the Mean Sidereal Time in units of degrees. -// Use lon = 0 to get the Greenwich MST. +// "mean_sidereal_time" returns the Mean Sidereal Time in units of degrees. +// Use lon = 0 to get the Greenwich MST. // East longitudes are positive; West longitudes are negative // // returns: time in degrees @@ -523,7 +523,7 @@ function mean_sidereal_time(lon) { var c = Math.floor(365.25 * year); var da = Math.floor(30.6001 * (month + 1)); - // days since J2000.0 + // days since J2000.0 var jd = b + c + da - 730550.5 + day + (hour + mins / 60.0 + secs / 3600.0) / 24.0; @@ -796,10 +796,11 @@ Bangle.on('lcdPower', on => { Bangle.setCompassPower(1); Bangle.setGPSPower(1); -// Buttons -setWatch(Bangle.showLauncher, BTN2, { repeat: false, edge: "falling" }); +// Show launcher when button pressed +Bangle.setClockMode(); -setWatch(function () { +Bangle.setUI("clockupdown", btn => { + if (btn==0) { if (!processing) { if (!modeswitch) { modeswitch = true; @@ -809,12 +810,11 @@ setWatch(function () { else modeswitch = false; } -}, BTN3, { repeat: true }); - -setWatch(function () { + } else { if (!processing) ready_to_compute = true; -}, BTN1, { repeat: true }); + } +}); setWatch(function () { if (!astral_settings.astral_default) { diff --git a/apps/banglebridge/README.md b/apps/banglebridge/README.md new file mode 100644 index 000000000..9897971f8 --- /dev/null +++ b/apps/banglebridge/README.md @@ -0,0 +1,10 @@ +Widget that allows Bangle Js to record pair and end data using Bluetooth Low Energy in combination with the BangleBridge Android App +Part of smartPPE project https://jorgepramos.github.io/Smart_PPE/index.html + +# BangleBridge + +Widget that allows Bangle Js to record pair and end data using Bluetooth Low Energy in combination with the BangleBridge Android App. + +## Full Project + +Part of smartPPE project [SmartPEE](https://jorgepramos.github.io/Smart_PPE/index.html). \ No newline at end of file diff --git a/apps/banglebridge/banglebridge.png b/apps/banglebridge/banglebridge.png new file mode 100644 index 000000000..3c1e693fc Binary files /dev/null and b/apps/banglebridge/banglebridge.png differ diff --git a/apps/banglebridge/heart.img b/apps/banglebridge/heart.img new file mode 100644 index 000000000..b8e339b30 --- /dev/null +++ b/apps/banglebridge/heart.img @@ -0,0 +1 @@ +00ˆþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ þþþþþþþþþþþþþþ þþþþþþþþþþþþþþþþþþ þþþþþþþþþþ þþþþþþþþþþþþþþþ þþþþþþ þþþþþþþþþþþþþ þþþþ þþþþþþþþþþþ þþ ?? þþþþþþþþþ ÿÿ þþþþþþþþ ÿÿ þþþþþþþ ÿÿ þþþþþþ ÿÿ þþþþþþ ?ÿÿÿÿÿÿÿÿÿÿ? þþþþþþ ?ÿÿÿÿÿÿÿÿÿÿ? þþþþþþ ÿÿ ''' 'þþþþþþ ÿÿ' '''þþþþþþ ÿÿ' ''''þþþþþþþ 'ÿÿ' '''''þþþþþþþþ '??'''''''þþþþþþþþþ ''''''''þþþþþþþþþþ ''''''''þþþþþþþþþþþ '''''''''þþþþþþþþþþþþ ''''''''''þþþþþþþþþþþþþ '''''''''''þþþþþþþþþþþþþþþ ''''''''''''þþþþþþþþþþþþþþþþþ ''''''''''''þþþþþþþþþþþþþþþþþþþ '''''''''''''þþþþþþþþþþþþþþþþþþþþþ '''''''''''''þþþþþþþþþþþþþþþþþþþþþþþ ''''''''''''''þþþþþþþþþþþþþþþþþþþþþþþþþ ''''''''''''''þþþþþþþþþþþþþþþþþþþþþþþþþþþ '''''''''''''''þþþþþþþþþþþþþþþþþþþþþþþþþþþþþ '''''''''''''''þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ''''''''''''''''þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ''''''''''''''þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ''''''''''þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ''''''''þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ''''''þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ''þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ \ No newline at end of file diff --git a/apps/banglebridge/watch.img b/apps/banglebridge/watch.img new file mode 100644 index 000000000..4a8434583 Binary files /dev/null and b/apps/banglebridge/watch.img differ diff --git a/apps/banglebridge/widget.js b/apps/banglebridge/widget.js new file mode 100644 index 000000000..48078de30 --- /dev/null +++ b/apps/banglebridge/widget.js @@ -0,0 +1,302 @@ +(() => { + /** + * Widget measurements + * Description: + * name: connection.wid.js + *icon: conectionIcon.icon + * + */ + + //Font + + g.setFont("Vector", 100); + //variabangle.Sensorss + let acclS, bttS, compssS, gpsS, hrmS, stepS; //Strings + let accelN, compssN, gpsN, hrmN, stepN; //Num + let prueba = 1; + let data = [0, 0, 0, 0, 0, 0]; + //Constants for redabangle.Sensors code + let storage = require('Storage'); + let deCom = require('heatshrink'); + + + + + //Sensors code + /** + * + * @author Jorge + */ + function accel() { + + Bangle.on('accel', function (acc) { + // acc = {x,y,z,diff,mag} + accelN = acc; + }); + + setInterval(function () { + + acclS = accelN.x + "##" + accelN.y + "##" + accelN.z + "\n" + accelN.diff + "##" + accelN.mag; + data[3] = accelN; + }, 2 * 1000); + + } + + function btt() { + + setInterval(function () { + + bttS = E.getBattery(); //return String + data[2] = E.getBattery(); + }, 15 * 1000); + + } + + + + function compss() { + + Bangle.setCompassPower(1); + Bangle.on('mag', function (mag) { + // mag = {x,y,z,dx,dy,dz,heading} + compssN = mag; + }); + + + setInterval(function () { + + compssS = "A: " + compssN.x + " ## " + compssN.y + " ## " + compssN.z + "\n" + + "B: " + compssN.dx + " ## " + compssN.dy + " ## " + compssN.dz + " ## " + "\n" + + "C: " + compssN.heading; //return String + data[4] = compssN; + }, 2 * 1000); + + } + + + + function gps() { + + Bangle.setGPSPower(1); + Bangle.on('GPS', function (gps) { + // gps = {lat,lon,alt,speed,etc} + gpsN = gps; + + }); + + setInterval(function () { + + gpsS = "A: " + gpsN.lat + " ## " + gpsN.lon + " ## " + gpsN.alt + "\n" + "B: " + gpsN.speed + " ## " + gpsN.course + " ## " + gpsN.time + "\n" + + "C: " + gpsN.satellites + " ## " + gpsN.fix; //return String + // work out how to display the current time + var d = new Date(); + var year = d.getFullYear(); + + var month = d.getMonth() + 1; + var finalMonth = 0; + if (month < 10) { + finalMonth = "0" + month; + } else { + finalMonth = month; + } + var day = d.getDate(); + var finalDay = 0; + if (day < 10) { + finalDay = "0" + day; + } else { + finalDay = day; + } + var h = d.getHours(), + m = d.getMinutes(); + var finalh = 0; + if (h < 10) { + finalh = "0" + h; + } else { + finalh = h; + } + var finalM = 0; + if (m < 10) { + finalM = "0" + m; + } else { + finalM = m; + } + + var s = d.getSeconds(); + var finalS = 0; + if (s < 10) { + finalS = "0" + s; + } else { + finalS = s; + } + var z = d.getMilliseconds(); + var zFinal = new String(z); + zFinal = zFinal.replace('.', ''); + var completeTime = year + "-" + finalMonth + "-" + finalDay + "T" + finalh + ":" + finalM + ":" + finalS + "." + z + "Z"; + var time = h + ":" + ("0" + m).substr(-2); + gpsN.time = completeTime; + data[5] = gpsN; + }, 2 * 1000); + } + + //2021-06-11T19:21:58.000Z + + function hrm() { + + let msr = [0, 0, 0, 0, 0]; + let lastInsert = -1; + + function roundInsert(nueva) { + let indexFinal = (lastInsert + 1) % (msr.length); + //console.log("Index ==> "+ index); + msr[indexFinal] = nueva; + + item = nueva; + lastInsert = indexFinal; + + } + + function normalize(nueva) { + + let normalize = 0; + roundInsert(nueva); + + + msr.forEach(function (number) { + normalize += number; + }); + normalize = normalize / msr.length; + + return normalize; + + } + + + + + setInterval(function () { + + if (!isNaN(hrmN)) { + + + hrmN = normalize(hrmN); + var roundedRate = parseFloat(hrmN).toFixed(2); + hrmS = String.valueOf(roundedRate); //return String + //console.log("array----->" + msr); + data[0] = roundedRate; + + } + + + + + + }, 2 * 1000); + + } + + + function steps() { + + Bangle.on('step', s => { + + stepN = s; + }); + + + setInterval(function () { + + stepS = String.valueOf(stepN); //return String + data[1] = stepN; + }, 2 * 1000); + + + } + + function initSensors() { + + //need power control + Bangle.setHRMPower(1); + + Bangle.on('HRM', function (hrm) { + hrmN = hrm.bpm; + + + }); + console.log("Sensors are being Init...."); + accel(); + btt(); + compss(); + gps(); + hrm(); + steps(); + + } + + var flip = 1; + Bangle.on('lcdPower', function (on) { + /* + prueba ++; + Bangle.drawWidgets(); + g.setFont("Vector", 45); + g.drawString(prueba,100,200);*/ + if (flip == 1) { //when off + + flip = 0; + //Bangle.buzz(1000); + g.clear(); + } else { //when on + + flip = 1; + g.setFont("Vector", 30); + g.drawString(data[0], 65, 180); + Bangle.drawWidgets(); + } + + }); + + + function draw() { + g.drawImage(storage.read("banglebridge.watch.img"),this.x + 1,this.y + 1); + g.drawImage(storage.read("banglebridge.heart.img"), 145, 167); + } + + + // Finally add widget + + + initSensors(); + // Bangle.drawWidgets(); + // Terminal.println("Running BangleBridge"); + data[0] = 80.5; + g.setFont("Vector", 30); + g.drawString(data[0], 65, 180); + // Bangle.drawWidgets(); + setInterval(function () { + //console.log("---------------------------------------------------------------"); + //console.log(data); + //Bluetooth.println(data[0]); + var measurement = { + hrm: data[0], + step: data[1], + batt: data[2], + acc: data[3], + com: data[4], + gps: data[5] + }; + /* g.clear(); + g.drawString(compssS,100,200); + */ + + + + Bluetooth.println(JSON.stringify(measurement) + "#"); + //draw(); + + }, 5 * 1000); + + WIDGETS["banglebridge"]={ + area: "tl", + width: 10, + draw: draw, + }; +})(); //End of Widget diff --git a/apps/banglebridge/widget.png b/apps/banglebridge/widget.png new file mode 100644 index 000000000..3c1e693fc Binary files /dev/null and b/apps/banglebridge/widget.png differ diff --git a/apps/banglerun/ChangeLog b/apps/banglerun/ChangeLog old mode 100755 new mode 100644 diff --git a/apps/barclock/ChangeLog b/apps/barclock/ChangeLog index 616ee66e9..9589a1902 100644 --- a/apps/barclock/ChangeLog +++ b/apps/barclock/ChangeLog @@ -2,4 +2,6 @@ 0.02: Apply locale, 12-hour setting 0.03: Fix dates drawing over each other at midnight 0.04: Small bugfix -0.05: Clock does not start if app Languages is not installed \ No newline at end of file +0.05: Clock does not start if app Languages is not installed +0.06: Improve accuracy +0.07: Update to use Bangle.setUI instead of setWatch diff --git a/apps/barclock/README.md b/apps/barclock/README.md new file mode 100644 index 000000000..4b92313c5 --- /dev/null +++ b/apps/barclock/README.md @@ -0,0 +1,6 @@ +# Bar Clock +A simple digital clock showing seconds as a horizontal bar. + +| 24hr style | 12hr style | +| --- | --- | +| ![24-hour bar clock](screenshot.png) | ![12-hour bar clock with meridian](screenshot_pm.png) | diff --git a/apps/barclock/clock-bar.js b/apps/barclock/clock-bar.js index 0f2609298..5069faa39 100644 --- a/apps/barclock/clock-bar.js +++ b/apps/barclock/clock-bar.js @@ -2,170 +2,168 @@ /** * A simple digital clock showing seconds as a bar **/ -{ - // Check settings for what type our clock should be - const is12Hour = (require('Storage').readJSON('setting.json', 1) || {})['12hour'] - let locale = require('locale') - { // add some more info to locale - let date = new Date() - date.setFullYear(1111) - date.setMonth(1, 3) // februari: months are zero-indexed - const localized = locale.date(date, true) - locale.dayFirst = /3.*2/.test(localized) - - locale.hasMeridian = false - if(typeof locale.meridian === 'function') { // function does not exists if languages app is not installed - locale.hasMeridian = (locale.meridian(date) !== '') - } - - } - const screen = { - width: g.getWidth(), - height: g.getWidth(), - middle: g.getWidth() / 2, - center: g.getHeight() / 2, +// Check settings for what type our clock should be +const is12Hour = (require('Storage').readJSON('setting.json', 1) || {})['12hour'] +let locale = require('locale') +{ // add some more info to locale + let date = new Date() + date.setFullYear(1111) + date.setMonth(1, 3) // februari: months are zero-indexed + const localized = locale.date(date, true) + locale.dayFirst = /3.*2/.test(localized) + + locale.hasMeridian = false + if(typeof locale.meridian === 'function') { // function does not exists if languages app is not installed + locale.hasMeridian = (locale.meridian(date) !== '') } - // hardcoded "settings" - const settings = { - time: { +} +const screen = { + width: g.getWidth(), + height: g.getWidth(), + middle: g.getWidth() / 2, + center: g.getHeight() / 2, +} + +// hardcoded "settings" +const settings = { + time: { + color: -1, + font: '6x8', + size: (is12Hour && locale.hasMeridian) ? 6 : 8, + middle: screen.middle, + center: screen.center, + ampm: { color: -1, font: '6x8', - size: (is12Hour && locale.hasMeridian) ? 6 : 8, - middle: screen.middle, - center: screen.center, - ampm: { - color: -1, - font: '6x8', - size: 2, - }, + size: 2, }, - date: { - color: -1, - font: 'Vector', - size: 20, - middle: screen.height - 20, // at bottom of screen - center: screen.center, - }, - bar: { - color: -1, - top: 155, // just below time - thickness: 6, // matches 24h time "pixel" size - }, - } - - const SECONDS_PER_MINUTE = 60 - - const timeText = function (date) { - if (!is12Hour) { - return locale.time(date, true) - } - const date12 = new Date(date.getTime()) - const hours = date12.getHours() - if (hours === 0) { - date12.setHours(12) - } else if (hours > 12) { - date12.setHours(hours - 12) - } - return locale.time(date12, true) - } - const ampmText = function (date) { - return is12Hour ? locale.meridian(date) : '' - } - - const dateText = function (date) { - const dayName = locale.dow(date, true), - month = locale.month(date, true), - day = date.getDate() - const dayMonth = locale.dayFirst ? `${day} ${month}` : `${month} ${day}` - return `${dayName} ${dayMonth}` - } - - const drawDateTime = function (date) { - const t = settings.time - g.setColor(t.color) - g.setFont(t.font, t.size) - g.setFontAlign(0, 0) // centered - g.drawString(timeText(date), t.center, t.middle, true) - if (is12Hour && locale.hasMeridian) { - const a = settings.time.ampm - g.setColor(a.color) - g.setFont(a.font, a.size) - g.setFontAlign(1, -1) // right top - // at right edge of screen, aligned with time bottom - const left = screen.width - a.size * 2, - top = t.middle + t.size - a.size - g.drawString(ampmText(date), left, top, true) - } - - const d = settings.date - g.setColor(d.color) - g.setFont(d.font, d.size) - g.setFontAlign(0, 0) // centered - g.drawString(dateText(date), d.center, d.middle, true) - } - - const drawBar = function (date) { - const b = settings.bar - const seconds = date.getSeconds() - if (seconds === 0) { - // zero-size rect stills draws one line of pixels, we don't want that - return - } - const fraction = seconds / SECONDS_PER_MINUTE, - width = fraction * screen.width - g.setColor(b.color) - g.fillRect(0, b.top, width, b.top + b.thickness) - } - - const clearScreen = function () { - g.setColor(0) - const timeTop = settings.time.middle - (settings.time.size * 4) - g.fillRect(0, timeTop, screen.width, screen.height) - } - - let lastSeconds - const tick = function () { - g.reset() - const date = new Date() - const seconds = date.getSeconds() - if (lastSeconds > seconds) { - // new minute - clearScreen() - drawDateTime(date) - } - // the bar only gets larger, so drawing on top of the previous one is fine - drawBar(date) - - lastSeconds = seconds - } - - let iTick - const start = function () { - lastSeconds = 99 // force redraw - tick() - iTick = setInterval(tick, 1000) - } - const stop = function () { - if (iTick) { - clearInterval(iTick) - iTick = undefined - } - } - - // clean app screen - g.clear() - Bangle.loadWidgets() - Bangle.drawWidgets() - // Show launcher when middle button pressed - setWatch(Bangle.showLauncher, BTN2, {repeat: false, edge: 'falling'}) - - Bangle.on('lcdPower', function (on) { - if (on) { - start() - } else { - stop() - } - }) - start() + }, + date: { + color: -1, + font: 'Vector', + size: 20, + middle: screen.height - 20, // at bottom of screen + center: screen.center, + }, + bar: { + color: -1, + top: 155, // just below time + thickness: 6, // matches 24h time "pixel" size + }, } + +const SECONDS_PER_MINUTE = 60 + +const timeText = function (date) { + if (!is12Hour) { + return locale.time(date, true) + } + const date12 = new Date(date.getTime()) + const hours = date12.getHours() + if (hours === 0) { + date12.setHours(12) + } else if (hours > 12) { + date12.setHours(hours - 12) + } + return locale.time(date12, true) +} +const ampmText = function (date) { + return is12Hour ? locale.meridian(date) : '' +} + +const dateText = function (date) { + const dayName = locale.dow(date, true), + month = locale.month(date, true), + day = date.getDate() + const dayMonth = locale.dayFirst ? `${day} ${month}` : `${month} ${day}` + return `${dayName} ${dayMonth}` +} + +const drawDateTime = function (date) { + const t = settings.time + g.setColor(t.color) + g.setFont(t.font, t.size) + g.setFontAlign(0, 0) // centered + g.drawString(timeText(date), t.center, t.middle, true) + if (is12Hour && locale.hasMeridian) { + const a = settings.time.ampm + g.setColor(a.color) + g.setFont(a.font, a.size) + g.setFontAlign(1, -1) // right top + // at right edge of screen, aligned with time bottom + const left = screen.width - a.size * 2, + top = t.middle + t.size - a.size + g.drawString(ampmText(date), left, top, true) + } + + const d = settings.date + g.setColor(d.color) + g.setFont(d.font, d.size) + g.setFontAlign(0, 0) // centered + g.drawString(dateText(date), d.center, d.middle, true) +} + +const drawBar = function (date) { + const b = settings.bar + const seconds = date.getSeconds() + if (seconds === 0) { + // zero-size rect stills draws one line of pixels, we don't want that + return + } + const fraction = seconds / SECONDS_PER_MINUTE, + width = fraction * screen.width + g.setColor(b.color) + g.fillRect(0, b.top, width, b.top + b.thickness) +} + +const clearScreen = function () { + g.setColor(0) + const timeTop = settings.time.middle - (settings.time.size * 4) + g.fillRect(0, timeTop, screen.width, screen.height) +} + +let lastSeconds, tTick +const tick = function () { + g.reset() + const date = new Date() + const seconds = date.getSeconds() + if (lastSeconds > seconds) { + // new minute + clearScreen() + drawDateTime(date) + } + // the bar only gets larger, so drawing on top of the previous one is fine + drawBar(date) + lastSeconds = seconds + // schedule next update + const millis = date.getMilliseconds() + tTick = setTimeout(tick, 1000-millis) +} + +const start = function () { + lastSeconds = 99 // force redraw + tick() +} +const stop = function () { + if (tTick) { + clearTimeout(tTick) + tTick = undefined + } +} + +// clean app screen +g.clear() +Bangle.loadWidgets() +Bangle.drawWidgets() +// Show launcher when button pressed +Bangle.setUI("clock"); + +Bangle.on('lcdPower', function (on) { + if (on) { + start() + } else { + stop() + } +}) +start() diff --git a/apps/barclock/screenshot.png b/apps/barclock/screenshot.png new file mode 100644 index 000000000..d37ee9cae Binary files /dev/null and b/apps/barclock/screenshot.png differ diff --git a/apps/barclock/screenshot_pm.png b/apps/barclock/screenshot_pm.png new file mode 100644 index 000000000..a2a3f63fb Binary files /dev/null and b/apps/barclock/screenshot_pm.png differ diff --git a/apps/batclock/ChangeLog b/apps/batclock/ChangeLog index 5d221b4c4..e6e21b146 100644 --- a/apps/batclock/ChangeLog +++ b/apps/batclock/ChangeLog @@ -1 +1,2 @@ 0.01: App Created! +0.02: Update to use Bangle.setUI instead of setWatch diff --git a/apps/batclock/bat-clock.app.js b/apps/batclock/bat-clock.app.js index abb5fbd3a..31b8f5b9b 100644 --- a/apps/batclock/bat-clock.app.js +++ b/apps/batclock/bat-clock.app.js @@ -256,8 +256,5 @@ Bangle.drawWidgets(); timeInterval = setInterval(showTime, 1000); showTime(); -// Show launcher when middle button pressed -setWatch(Bangle.showLauncher, BTN2, { - repeat: false, - edge: "falling" -}); +// Show launcher when button pressed +Bangle.setUI("clock"); diff --git a/apps/bclock/ChangeLog b/apps/bclock/ChangeLog index 7819dbe2a..5b2cf598c 100644 --- a/apps/bclock/ChangeLog +++ b/apps/bclock/ChangeLog @@ -1 +1,2 @@ 0.02: Modified for use with new bootloader and firmware +0.03: Update to use Bangle.setUI instead of setWatch diff --git a/apps/bclock/clock-binary.js b/apps/bclock/clock-binary.js index 833aa00f6..fdf945ee6 100644 --- a/apps/bclock/clock-binary.js +++ b/apps/bclock/clock-binary.js @@ -105,5 +105,5 @@ Bangle.loadWidgets(); Bangle.drawWidgets(); setInterval(() => { drawClock(); }, 1000); drawClock(); -// Show launcher when middle button pressed -setWatch(Bangle.showLauncher, BTN2, {repeat:false,edge:"falling"}); +// Show launcher when button pressed +Bangle.setUI("clock"); diff --git a/apps/beebclock/ChangeLog b/apps/beebclock/ChangeLog index ac1c58c29..b9a4dacec 100644 --- a/apps/beebclock/ChangeLog +++ b/apps/beebclock/ChangeLog @@ -1,3 +1,4 @@ 0.01: Initial commit. Not very efficient, and widgets not working for some reason. 0.02: Fixes; widget support 0.03: Remove hardcoded hour buzz (you can install widchime if you miss it) +0.04: Update to use Bangle.setUI instead of setWatch diff --git a/apps/beebclock/beebclock.js b/apps/beebclock/beebclock.js index bbf65697f..2f7c48c36 100644 --- a/apps/beebclock/beebclock.js +++ b/apps/beebclock/beebclock.js @@ -51,341 +51,332 @@ Graphics.prototype.drawRotLine = function (sina, cosa, cx, cy, r1, r2) { ); }; +// Display modes +// +// 0: full-screen +// 1: with widgets +// 2: centred on Bangle (v.1), no widgets or time/date +// 3: centred with time above +// 4: centred with date above +// 5: centred with time and date above +let mode; -(function(g) { - // Display modes - // - // 0: full-screen - // 1: with widgets - // 2: centred on Bangle (v.1), no widgets or time/date - // 3: centred with time above - // 4: centred with date above - // 5: centred with time and date above - let mode; +// R1, R2: Outer and inner radii of hour marks +// RC1, RC2: Outer and inner radii of hub +// CX, CY: Centre location, relative to buffer (not screen, necessarily) +// HW2, MW2: Half-width of hour and minute hand +// HR, MR: Length of hour and minute hand, relative to CX,CY +// M: Half-width of gap in hour marks +// HSCALE: Half-width of hour mark as function(0 { + const fw = R1 * 2; + const fh = R1 * 2; + const fw2 = R1; + const fh2 = R1; + let hs = []; + + // Wipe the image and start with white + G.clear(); + G.setColor(1,1,1); + + // Draw the hour marks. for (let h=1; h<=12; h++) { - const a = Math.PI * h / 6; - ss[h] = Math.sin(a); - cs[h] = Math.cos(a); + hs[h] = HSCALE(h); + G.fillRotRect(ss[h], cs[h], CX, CY, -hs[h], hs[h], R2, R1); + } - // Draw the face with hour and minute hand. Ideally, we'd separate - // the face from the hands and double-buffer, but memory is limited, - // so we buffer once and minute, and draw the second hand dynamically - // (with a bit of flicker) - const drawFace = (G) => { - const fw = R1 * 2; - const fh = R1 * 2; - const fw2 = R1; - const fh2 = R1; - let hs = []; + // Draw the hub + G.fillCircle(CX, CY, RC1); - // Wipe the image and start with white - G.clear(); - G.setColor(1,1,1); + // Black + G.setColor(0,0,0); - // Draw the hour marks. - for (let h=1; h<=12; h++) { - hs[h] = HSCALE(h); - G.fillRotRect(ss[h], cs[h], CX, CY, -hs[h], hs[h], R2, R1); + // Clear the centre of the hub + G.fillCircle(CX, CY, RC2); + // Draw the gap in the hour marks + for (let h=1; h<=12; h++) { + G.fillRotRect(ss[h], cs[h], CX, CY, -M, M, R2-1, R1+1); + } + + // Back to white for future draw operations + G.setColor(1,1,1); + + // While the buffer remains full-screen, we may trim out the + // bottom of the image so we can shift the whole thing down for + // widgets. + const img = {width:GW,height:GH-TM,buffer:G.buffer}; + return img; +}; + +let hours, minutes, seconds, date; + +// Schedule event for calling at the start of the next second +const inOneSecond = (cb) => { + let now = new Date(); + clearTimeout(); + setTimeout(cb, 1000 - now.getMilliseconds()); +}; + +// Schedule event for calling at the start of the next minute +const inOneMinute = (cb) => { + let now = new Date(); + clearTimeout(); + setTimeout(cb, 60000 - (now.getSeconds() * 1000 + now.getMilliseconds())); +}; + +// Draw a fat hour/minute hand +const drawHand = (G, a, w2, r1, r2) => + G.fillRotRect(Math.sin(a), Math.cos(a), CX, CY, -w2, w2, r1, r2); + +// Redraw function +const drawAll = (force) => { + let now = new Date(); + + if (!faceImg) force = true; + + let face_changed = force; + let date_changed = false; + + tmp = hours; + hours = now.getHours(); + if (tmp !== hours) + face_changed = true; + + tmp = minutes; + minutes = now.getMinutes(); + if (tmp !== minutes) + face_changed = true; + + // If the face has been updated and/or needs a redraw, + // face_changed is true. + + let time_changed = face_changed; + + // If the screen needs an update, regardless of whether the face + // needs a redraw, time_changed is true. + + if (with_seconds) { + // If we're going by second, we always need an update. + seconds = now.getSeconds(); + time_changed = true; + } + + if (with_digital_date) { + // See if the date has changed. If it has, then we need a + // full-blown redraw of the screen and the face, plus text. + tmp = date; + date = now.getDate(); + if (tmp !== date) { + date_changed = true; + face_changed = true; // Should have changed anyway with hour/minute rollover + } + } + + if (face_changed) { + // Redraw the face and hands onto the buffer G1. + faceImg = drawFace(G1); + drawHand(G1, Math.PI*hours/6, HW2, RC1, HR); + drawHand(G1, Math.PI*minutes/30, MW2, RC1, MR); + } + + // Has the time updated? If so, we'll need to draw something. + if (time_changed) { + + // Are we adding text? + if (with_digital_date || with_digital_time) { + + // Construct the date/time text to add above the face + let d = now.toString(); + let da = d.toString().split(" "); + let txt; + + if (with_digital_time) { + txt = da[4].substr(0, 5); + if (with_digital_date) + G1.drawStringDH(txt+',', 24, 0, 'L', GW); + else + G1.drawStringDH(txt, 0, 0, 'C', GW); + } + + if (with_digital_date) { + let txt = [da[0], da[1], da[2]].join(" "); + if (with_digital_time) + G1.drawStringDH(txt, -24, 0, 'R', GW); + else + G1.drawStringDH(txt, 0, 0, 'C', GW); + } } - // Draw the hub - G.fillCircle(CX, CY, RC1); - - // Black - G.setColor(0,0,0); - - // Clear the centre of the hub - G.fillCircle(CX, CY, RC2); - - // Draw the gap in the hour marks - for (let h=1; h<=12; h++) { - G.fillRotRect(ss[h], cs[h], CX, CY, -M, M, R2-1, R1+1); - } - - // Back to white for future draw operations - G.setColor(1,1,1); - - // While the buffer remains full-screen, we may trim out the - // bottom of the image so we can shift the whole thing down for - // widgets. - const img = {width:GW,height:GH-TM,buffer:G.buffer}; - return img; - }; - - let hours, minutes, seconds, date; - - // Schedule event for calling at the start of the next second - const inOneSecond = (cb) => { - let now = new Date(); - clearTimeout(); - setTimeout(cb, 1000 - now.getMilliseconds()); - }; - - // Schedule event for calling at the start of the next minute - const inOneMinute = (cb) => { - let now = new Date(); - clearTimeout(); - setTimeout(cb, 60000 - (now.getSeconds() * 1000 + now.getMilliseconds())); - }; - - // Draw a fat hour/minute hand - const drawHand = (G, a, w2, r1, r2) => - G.fillRotRect(Math.sin(a), Math.cos(a), CX, CY, -w2, w2, r1, r2); - - // Redraw function - const drawAll = (force) => { - let now = new Date(); - - if (!faceImg) force = true; - - let face_changed = force; - let date_changed = false; - - tmp = hours; - hours = now.getHours(); - if (tmp !== hours) - face_changed = true; - - tmp = minutes; - minutes = now.getMinutes(); - if (tmp !== minutes) - face_changed = true; - - // If the face has been updated and/or needs a redraw, - // face_changed is true. - - let time_changed = face_changed; - - // If the screen needs an update, regardless of whether the face - // needs a redraw, time_changed is true. + // If the time has updated, we need to _at least_ draw the + // image to the screen. + g.setColor(1,1,1); + g.drawImage({width:GW, + height:GH-TM, + buffer:G1.buffer}, 0, TM); + // and possibly add the second hand if (with_seconds) { - // If we're going by second, we always need an update. - seconds = now.getSeconds(); - time_changed = true; + let a = 2.0 * Math.PI * seconds / 60.0; + g.drawRotLine(Math.sin(a), Math.cos(a), CX, CY+TM, RC1, R1); } - if (with_digital_date) { - // See if the date has changed. If it has, then we need a - // full-blown redraw of the screen and the face, plus text. - tmp = date; - date = now.getDate(); - if (tmp !== date) { - date_changed = true; - face_changed = true; // Should have changed anyway with hour/minute rollover - } - } + // And draw widgets if we're in that mode + if (with_widgets) + Bangle.drawWidgets(); + } - if (face_changed) { - // Redraw the face and hands onto the buffer G1. - faceImg = drawFace(G1); - drawHand(G1, Math.PI*hours/6, HW2, RC1, HR); - drawHand(G1, Math.PI*minutes/30, MW2, RC1, MR); - } + // Schedule to repeat this. A `setTimeout(1000)` isn't good + // enough, as all the above might've taken some milliseconds and + // we don't want to drift. + if (with_seconds) + inOneSecond(drawAll); + else + inOneMinute(drawAll); +}; - // Has the time updated? If so, we'll need to draw something. - if (time_changed) { +const setButtons = () => { + // Show launcher when button pressed + Bangle.setUI("clockupdown", btn=> { + if (btn==0) changeSeconds(); + if (btn==1) { ++mode; setMode(); drawAll(true); } + }); +}; - // Are we adding text? - if (with_digital_date || with_digital_time) { +// Load display parameters based on `mode` +const setMode = () => { + // Normalize mode to 0 <= mode <= 5 + mode = (6+mode) % 6; - // Construct the date/time text to add above the face - let d = now.toString(); - let da = d.toString().split(" "); - let txt; + // [R1, R2, RC1, RC2, HW2, MW3, HR, MR, M, HSCALE] = + const scales = [ + [120, 84, 17, 12.4, 4.6, 2.2, 8, 2, 1, h => (3.0 + Math.ceil(h/1.5)) ], + [102, 70, 14.6, 10.7, 3.88, 1.8, 8, 2, 1, h => (2.4 + Math.ceil(h/1.6)) ], + ]; - if (with_digital_time) { - txt = da[4].substr(0, 5); - if (with_digital_date) - G1.drawStringDH(txt+',', 24, 0, 'L', GW); - else - G1.drawStringDH(txt, 0, 0, 'C', GW); - } + if (mode < 3) { + // Face without time/date text. Might have widgets though. + with_digital_time = with_digital_date = false; + with_widgets = (mode == 1); + } + else { + // Face with time/date text, but no widgets + with_digital_time = (mode-2)&1; + with_digital_date = (mode-2)&2; + with_widgets = false; + } - if (with_digital_date) { - let txt = [da[0], da[1], da[2]].join(" "); - if (with_digital_time) - G1.drawStringDH(txt, -24, 0, 'R', GW); - else - G1.drawStringDH(txt, 0, 0, 'C', GW); - } - } + // Destructure the array to the global display parameters + let arr = scales[mode > 0 ? 1 : 0]; + R1 = arr[0]; + R2 = arr[1]; + RC1 = arr[2]; + RC2 = arr[3]; + HW2 = arr[4]; + MW2 = arr[5]; + HR = R2 - arr[6]; + MR = R1 - arr[7]; + M = arr[8]; + HSCALE = arr[9]; + TM = with_widgets ? 36 : 0; - // If the time has updated, we need to _at least_ draw the - // image to the screen. - g.setColor(1,1,1); - g.drawImage({width:GW, - height:GH-TM, - buffer:G1.buffer}, 0, TM); + CX = GW/2; + CY = R1; - // and possibly add the second hand - if (with_seconds) { - let a = 2.0 * Math.PI * seconds / 60.0; - g.drawRotLine(Math.sin(a), Math.cos(a), CX, CY+TM, RC1, R1); - } + // If we're in the small-face + text regime, we're going to buffer + // the full screen but draw the clock face further down to give + // space for the text. + // + // Compare with modes 0 (full-screen) and 1 (with_widgets==true) + // where the face is drawn at the top of the buffer, but drawn + // lower down the screen (so CY doesn't move) + if (mode > 1) { + CY += 36; + } - // And draw widgets if we're in that mode - if (with_widgets) - Bangle.drawWidgets(); - } + // We only don't bother redrawing the face from modes 2 to 5, as + // they're the same. + if (!faceImg || mode<3) { + faceImg = undefined; + } - // Schedule to repeat this. A `setTimeout(1000)` isn't good - // enough, as all the above might've taken some milliseconds and - // we don't want to drift. - if (with_seconds) - inOneSecond(drawAll); - else - inOneMinute(drawAll); - }; - - const setButtons = () => { - const opts = { repeat: true, edge:'rising', debounce:30}; - - // BTN1: enable/disable second hand - setWatch(changeSeconds, BTN1, opts); - - // BTN2: return to launcher - setWatch(Bangle.showLauncher, BTN2, { repeat:false, edge:'falling' }); - - // BTN3: change display mode - setWatch(function () { ++mode; setMode(); drawAll(true); }, BTN3, opts); - }; - - // Load display parameters based on `mode` - const setMode = () => { - // Normalize mode to 0 <= mode <= 5 - mode = (6+mode) % 6; - - // [R1, R2, RC1, RC2, HW2, MW3, HR, MR, M, HSCALE] = - const scales = [ - [120, 84, 17, 12.4, 4.6, 2.2, 8, 2, 1, h => (3.0 + Math.ceil(h/1.5)) ], - [102, 70, 14.6, 10.7, 3.88, 1.8, 8, 2, 1, h => (2.4 + Math.ceil(h/1.6)) ], - ]; - - if (mode < 3) { - // Face without time/date text. Might have widgets though. - with_digital_time = with_digital_date = false; - with_widgets = (mode == 1); - } - else { - // Face with time/date text, but no widgets - with_digital_time = (mode-2)&1; - with_digital_date = (mode-2)&2; - with_widgets = false; - } - - // Destructure the array to the global display parameters - let arr = scales[mode > 0 ? 1 : 0]; - R1 = arr[0]; - R2 = arr[1]; - RC1 = arr[2]; - RC2 = arr[3]; - HW2 = arr[4]; - MW2 = arr[5]; - HR = R2 - arr[6]; - MR = R1 - arr[7]; - M = arr[8]; - HSCALE = arr[9]; - TM = with_widgets ? 36 : 0; - - CX = GW/2; - CY = R1; - - // If we're in the small-face + text regime, we're going to buffer - // the full screen but draw the clock face further down to give - // space for the text. - // - // Compare with modes 0 (full-screen) and 1 (with_widgets==true) - // where the face is drawn at the top of the buffer, but drawn - // lower down the screen (so CY doesn't move) - if (mode > 1) { - CY += 36; - } - - // We only don't bother redrawing the face from modes 2 to 5, as - // they're the same. - if (!faceImg || mode<3) { - faceImg = undefined; - } - - // Store the settings for next time - try { - storage.writeJSON(filename, [mode,with_seconds]); - } catch (e) { - console.log(e); - } - - // Clear the screen: we need to make sure all parts are cleaned off. - g.clear(); - }; - - const changeSeconds = () => { - with_seconds = !with_seconds; - drawAll(true); - }; - - Bangle.loadWidgets(); - - // Restore mode + // Store the settings for next time try { - conf = storage.readJSON(filename); - mode = conf[0]; - with_seconds = conf[1]; + storage.writeJSON(filename, [mode,with_seconds]); } catch (e) { console.log(e); - mode = 1; } - setButtons(); - setMode(); - drawAll(); + // Clear the screen: we need to make sure all parts are cleaned off. + g.clear(); +}; - Bangle.on('lcdPower', (on) => { - if (on) { - Bangle.loadWidgets(); - Bangle.drawWidgets(); - drawAll(); - } else { - clearTimeout(); - } - }); +const changeSeconds = () => { + with_seconds = !with_seconds; + drawAll(true); +}; -})(g); +Bangle.loadWidgets(); + +// Restore mode +try { + conf = storage.readJSON(filename); + mode = conf[0]; + with_seconds = conf[1]; +} catch (e) { + console.log(e); + mode = 1; +} + +setButtons(); +setMode(); +drawAll(); + +Bangle.on('lcdPower', (on) => { + if (on) { + Bangle.loadWidgets(); + Bangle.drawWidgets(); + drawAll(); + } else { + clearTimeout(); + } +}); diff --git a/apps/berlinc/ChangeLog b/apps/berlinc/ChangeLog index a33332bc4..65ed0505f 100644 --- a/apps/berlinc/ChangeLog +++ b/apps/berlinc/ChangeLog @@ -1,2 +1,3 @@ 0.02: Modified for use with new bootloader and firmware 0.03: Shrinked size to avoid cut-off edges on the physical device. BTN3: show date. BTN1: show time in decimal. +0.04: Update to use Bangle.setUI instead of setWatch diff --git a/apps/berlinc/berlin-clock.js b/apps/berlinc/berlin-clock.js index 3950147b8..144fa5ba7 100644 --- a/apps/berlinc/berlin-clock.js +++ b/apps/berlinc/berlin-clock.js @@ -16,7 +16,7 @@ time_digit = []; function drawBerlinClock() { g.clear(); var now = new Date(); - + // show date below the clock if (show_date) { var yr = now.getFullYear(); @@ -28,7 +28,7 @@ function drawBerlinClock() { g.setFontAlign(-1,-1); g.drawString(dateString, ( g.getWidth() - strWidth ) / 2, height + offset + 4); } - + rowlights[0] = Math.floor(now.getHours() / 5); rowlights[1] = now.getHours() % 5; rowlights[2] = Math.floor(now.getMinutes() / 5); @@ -62,7 +62,7 @@ function drawBerlinClock() { } else { g.setColor(1, 0, 0); } - g.fillRect(x1 + 2, y1 + 2, x2 - 2, y2 - 2); + g.fillRect(x1 + 2, y1 + 2, x2 - 2, y2 - 2); } if (row == 3 && show_time) { g.setColor(1,1,1); @@ -100,9 +100,11 @@ g.clear(); Bangle.loadWidgets(); Bangle.drawWidgets(); drawBerlinClock(); -// Toggle date display, when BTN3 is pressed -setWatch(toggleTime,BTN1, { repeat : true, edge: "falling"}); -// Toggle date display, when BTN3 is pressed -setWatch(toggleDate,BTN3, { repeat : true, edge: "falling"}); -// Show launcher when middle button pressed -setWatch(Bangle.showLauncher, BTN2, { repeat: false, edge: "falling" }); +if (BTN3) { + // Toggle date display, when BTN3 is pressed + setWatch(toggleTime,BTN1, { repeat : true, edge: "falling"}); + // Toggle date display, when BTN3 is pressed + setWatch(toggleDate,BTN3, { repeat : true, edge: "falling"}); +} +// Show launcher when button pressed +Bangle.setUI("clock"); diff --git a/apps/binclock/ChangeLog b/apps/binclock/ChangeLog index 2378e52f8..dc4ed8308 100644 --- a/apps/binclock/ChangeLog +++ b/apps/binclock/ChangeLog @@ -1,2 +1,3 @@ 0.01: New App! 0.02: Fixed bug where screen didn't clear so incorrect time displayed. +0.03: Update to use Bangle.setUI instead of setWatch diff --git a/apps/binclock/app.js b/apps/binclock/app.js index 7808dfe45..f8cbe8dd5 100644 --- a/apps/binclock/app.js +++ b/apps/binclock/app.js @@ -23,17 +23,17 @@ function drawTime(d) { } function updateHourArray(hours){ - + var j; for(j=0;j 15){ hourLED[0] = 1; hours = hours - 16; @@ -53,9 +53,9 @@ function updateHourArray(hours){ if(hours > 0){ hourLED[4] = 1; } - + return hourLED; - + } function updateMinuteArray(minutes){ @@ -63,12 +63,12 @@ function updateMinuteArray(minutes){ for(j=0;j 31){ minuteLED[0] = 1; minutes = minutes - 32; @@ -92,20 +92,20 @@ function updateMinuteArray(minutes){ if(minutes > 0){ minuteLED[5] = 1; } - + return minuteLED; - + } function draw(){ - + // work out how to display the current time var d = new Date(); var h = d.getHours(), m = d.getMinutes(); - + updateHourArray(h); updateMinuteArray(m); - + var i; //Draw hour circles for(i=0; i{ // Load widgets Bangle.loadWidgets(); Bangle.drawWidgets(); -// Show launcher when middle button pressed -setWatch(Bangle.showLauncher, BTN2, { repeat: false, edge: "falling" }); -setWatch(function() { +// Show launcher when button pressed +Bangle.setUI("clockupdown", btn=>{ + if (btn!=1) return; if(displayTime == 0){ displayTime = 1; } else{ - displayTime = 0; + displayTime = 0; } -}, BTN, {edge:"rising", debounce:50, repeat:true}); +}); diff --git a/apps/blackjack/ChangeLog b/apps/blackjack/ChangeLog index c941d90e5..25b5f9195 100644 --- a/apps/blackjack/ChangeLog +++ b/apps/blackjack/ChangeLog @@ -1 +1,2 @@ -0.01: New game! BTN4- Hit card, BTN5- Stand \ No newline at end of file +0.01: New game! BTN4- Hit card, BTN5- Stand +0.02: ignore buttons on pauses \ No newline at end of file diff --git a/apps/blackjack/blackjack.app.js b/apps/blackjack/blackjack.app.js index bbee8137b..b88432fd9 100644 --- a/apps/blackjack/blackjack.app.js +++ b/apps/blackjack/blackjack.app.js @@ -18,6 +18,7 @@ const Diamonds = { width : 48, height : 48, bpp : 4, var deck = []; var player = {Hand:[]}; var computer = {Hand:[]}; +var ctx = {ready:true}; function createDeck() { var suits = ["Spades", "Hearts", "Diamonds", "Clubs"]; @@ -44,6 +45,7 @@ function shuffle(a) { } function EndGameMessdage(msg){ + ctx.ready = false; g.drawString(msg, 155, 200); setTimeout(function(){ startGame(); @@ -52,6 +54,7 @@ function EndGameMessdage(msg){ } function hitMe() { + if (!ctx.ready) return; player.Hand.push(deck.pop()); renderOnScreen(1); var playerWeight = calcWeight(player.Hand, 0); @@ -97,6 +100,8 @@ function calcWeight(hand, hideCard) { } function stand(){ + if (!ctx.ready) return; + ctx.ready = false; function sleepFor( sleepDuration ){ console.log("Sleeping..."); var now = new Date().getTime(); @@ -156,6 +161,7 @@ function renderOnScreen(HideCard) { function dealHands() { player.Hand= []; computer.Hand= []; + ctx.ready = false; setTimeout(function(){ player.Hand.push(deck.pop()); @@ -175,6 +181,7 @@ function dealHands() { setTimeout(function(){ computer.Hand.push(deck.pop()); renderOnScreen(1); + ctx.ready = true; }, 2000); } diff --git a/apps/blobclk/ChangeLog b/apps/blobclk/ChangeLog index 10983d7e1..9c4ef5b7b 100644 --- a/apps/blobclk/ChangeLog +++ b/apps/blobclk/ChangeLog @@ -4,3 +4,4 @@ 0.03: Modified for use with new bootloader and firmware 0.04: Modified to account for changes in the behavior of Graphics.fillPoly 0.05: Slight increase to draw speed after LCD on +0.06: Update to use Bangle.setUI instead of setWatch, allow themes and different size screens diff --git a/apps/blobclk/clock-blob.js b/apps/blobclk/clock-blob.js index 9b68bd4bd..c84b8a1e6 100644 --- a/apps/blobclk/clock-blob.js +++ b/apps/blobclk/clock-blob.js @@ -1,4 +1,6 @@ -const buf = Graphics.createArrayBuffer(144,200,1,{msb:true}); +let big = g.getHeight() > 200; +const buf = Graphics.createArrayBuffer(big ? 144 : 120, big ? 180 : 150,1,{msb:true}); +// TODO: convert these to Polys -> much faster and cleaner! const NUMBERS = [ [1,1,1,1,3,1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1],//0 [0,1,1,1,3,0,0,1,1,1,0,0,1,1,1,0,0,1,1,1,0,0,1,1,1],//1 @@ -14,8 +16,10 @@ const NUMBERS = [ let intervalRef = null; let digits = [-1,-1,-1,-1,-1,-1]; function flip() { - g.setColor(1,1,1); - g.drawImage({width:buf.getWidth(),height:buf.getHeight(),buffer:buf.buffer},55,26); + g.reset(); + g.drawImage({width:buf.getWidth(),height:buf.getHeight(),buffer:buf.buffer}, + (g.getWidth() - buf.getWidth())/2, + 26 + (g.getHeight() - (buf.getHeight()+24))/2); } function drawPixel(ox,oy,x,y,r,p) { let x1 = ox+x*(r*2); @@ -53,26 +57,31 @@ function redraw() { let newDigits = [Math.floor(hours/10),hours%10,Math.floor(mins/10),mins%10,Math.floor(secs/10),secs%10]; + let s = big?6:5; // size of main digits + let y2 = big?72:55; + let y3 = big?144:110; + + for (var p = 0;p<25;p++) { var px = p%5; var py = Math.floor(p/5); if (digits[0] === -1 || NUMBERS[newDigits[0]][p] !== NUMBERS[digits[0]][p] ) { - drawPixel(0,20,px,py,6,NUMBERS[newDigits[0]][p]); + drawPixel(0,0,px,py,s,NUMBERS[newDigits[0]][p]); } if (digits[1] === -1 || NUMBERS[newDigits[1]][p] !== NUMBERS[digits[1]][p] ) { - drawPixel(78,20,px,py,6,NUMBERS[newDigits[1]][p]); + drawPixel(13*s,0,px,py,s,NUMBERS[newDigits[1]][p]); } if (digits[2] === -1 || NUMBERS[newDigits[2]][p] !== NUMBERS[digits[2]][p] ) { - drawPixel(0,92,px,py,6,NUMBERS[newDigits[2]][p]); + drawPixel(0,y2,px,py,s,NUMBERS[newDigits[2]][p]); } if (digits[3] === -1 || NUMBERS[newDigits[3]][p] !== NUMBERS[digits[3]][p] ) { - drawPixel(78,92,px,py,6,NUMBERS[newDigits[3]][p]); + drawPixel(13*s,y2,px,py,s,NUMBERS[newDigits[3]][p]); } if (digits[4] === -1 || NUMBERS[newDigits[4]][p] !== NUMBERS[digits[4]][p] ) { - drawPixel(69,164,px,py,3,NUMBERS[newDigits[4]][p]); + drawPixel(17*s - 3*12,y3,px,py,3,NUMBERS[newDigits[4]][p]); } if (digits[5] === -1 || NUMBERS[newDigits[5]][p] !== NUMBERS[digits[5]][p] ) { - drawPixel(108,164,px,py,3,NUMBERS[newDigits[5]][p]); + drawPixel(17*s,y3,px,py,3,NUMBERS[newDigits[5]][p]); } } digits = newDigits; @@ -99,5 +108,5 @@ Bangle.on('lcdPower',function(on) { clearTimers(); } }); -// Show launcher when middle button pressed -setWatch(Bangle.showLauncher, BTN2, {repeat:false,edge:"falling"}); +// Show launcher when button pressed +Bangle.setUI("clock"); diff --git a/apps/boldclk/ChangeLog b/apps/boldclk/ChangeLog index 0d02bf644..f5d1af878 100644 --- a/apps/boldclk/ChangeLog +++ b/apps/boldclk/ChangeLog @@ -1,2 +1,3 @@ 0.02: Modified for use with new bootloader and firmware 0.03: Tweak for more efficient rendering, and firmware 2v06 +0.04: Work with themes, smaller screens diff --git a/apps/boldclk/bold_clock.js b/apps/boldclk/bold_clock.js index b7eaa8968..191b6ec4f 100644 --- a/apps/boldclk/bold_clock.js +++ b/apps/boldclk/bold_clock.js @@ -12,9 +12,9 @@ var minute_hand = { //g.fillRect(0,24,239,239); // Apps area let intervalRef = null; const p180 = Math.PI/180; -const clock_center = {x:Math.floor((240-1)/2), y:24+Math.floor((239-24)/2)}; +const clock_center = {x:Math.floor((g.getWidth()-1)/2), y:24+Math.floor((g.getHeight()-25)/2)}; // ={ x: 119, y: 131 } -const radius = Math.floor((239-24+1)/2); // =108 +const radius = Math.floor((g.getWidth()-24+1)/2); // =108 let tick0 = Graphics.createArrayBuffer(30,8,1,{msb:true}); tick0.fillRect(0,0,tick0.getWidth()-1, tick0.getHeight()-1); @@ -60,18 +60,15 @@ function hour_angle(date){ function draw_clock(){ //console.log("draw_clock"); let date = new Date(); - //g.clear(); - g.setBgColor(0,0,0); - g.setColor(0,0,0); - g.fillRect(0,24,239,239); // clear app area - g.setColor(1,1,1); + g.reset(); + g.clearRect(0,24,239,239); // clear app area // draw cross lines for testing // g.setColor(1,0,0); // g.drawLine(clock_center.x - radius, clock_center.y, clock_center.x + radius, clock_center.y); // g.drawLine(clock_center.x, clock_center.y - radius, clock_center.x, clock_center.y + radius); - g.setColor(1,1,1); + g.setColor(g.theme.fg); let ticks = [0, 90, 180, 270]; ticks.forEach((item)=>{ let agl = item+180; @@ -87,13 +84,13 @@ function draw_clock(){ let minute_agl = minute_angle(date); g.drawImage(hour_hand, hour_pos_x(hour_agl), hour_pos_y(hour_agl), {rotate:hour_agl*p180}); // g.drawImage(minute_hand, minute_pos_x(minute_agl), minute_pos_y(minute_agl), {rotate:minute_agl*p180}); // - g.setColor(1,1,1); + g.setColor(g.theme.fg); g.fillCircle(clock_center.x, clock_center.y, 6); - g.setColor(0,0,0); + g.setColor(g.theme.bg); g.fillCircle(clock_center.x, clock_center.y, 3); // draw minute ticks. Takes long time to draw! - g.setColor(1,1,1); + g.setColor(g.theme.fg); for (var i=0; i<60; i++){ let agl = i*6+180; g.drawImage(tick1.asImage(), rotate_around_x(big_wheel_x(i*6), agl, tick1), rotate_around_y(big_wheel_y(i*6), agl, tick1), {rotate:agl*p180}); @@ -141,5 +138,5 @@ g.clear(); Bangle.loadWidgets(); Bangle.drawWidgets(); startTimers(); -// Show launcher when middle button pressed -setWatch(Bangle.showLauncher, BTN2, {repeat:false,edge:"falling"}); +// Show launcher when button pressed +Bangle.setUI("clock"); diff --git a/apps/boot/ChangeLog b/apps/boot/ChangeLog index 48e1baa48..4a8c62d59 100644 --- a/apps/boot/ChangeLog +++ b/apps/boot/ChangeLog @@ -24,3 +24,6 @@ 0.23: Move to a precalculated .boot0 file which should speed up load time 0.24: Add Bangle.setUI polyfill 0.25: Fix error in 'no clock app' message +0.26: Remove buzz in setUI polyfill (#750) +0.27: Update polyfill for most recent changes +0.28: Fix double clock load after settings are changed diff --git a/apps/boot/bootupdate.js b/apps/boot/bootupdate.js index 9dc90cc9a..4c4efed29 100644 --- a/apps/boot/bootupdate.js +++ b/apps/boot/bootupdate.js @@ -3,6 +3,7 @@ recalculates, but this avoids us doing a whole bunch of reconfiguration most of the time. */ E.showMessage("Updating boot0..."); var s = require('Storage').readJSON('setting.json',1)||{}; +var isB2 = process.env.HWVERSION; // Is Bangle.js 2 var boot = ""; var CRC = E.CRC32(require('Storage').read('setting.json'))+E.CRC32(require('Storage').list(/\.boot\.js/)); boot += `if (E.CRC32(require('Storage').read('setting.json'))+E.CRC32(require('Storage').list(/\.boot\.js/))!=${CRC}) { eval(require('Storage').read('bootupdate.js'));} else {\n`; @@ -81,9 +82,9 @@ if (s.passkey!==undefined && s.passkey.length==6) boot+=`NRF.setSecurity({passke if (s.whitelist) boot+=`NRF.on('connect', function(addr) { if (!(require('Storage').readJSON('setting.json',1)||{}).whitelist.includes(addr)) NRF.disconnect(); });\n`; // Pre-2v10 firmwares without a theme/setUI if (!g.theme) { - boot += `g.theme={fg:-1,bg:0,fg2:-1,bg2:7,fgH:-1,bgH:0x02F7};\n`; + boot += `g.theme={fg:-1,bg:0,fg2:-1,bg2:7,fgH:-1,bgH:0x02F7,dark:true};\n`; } -if (!Bangle.setUI) { +if (!Bangle.setUI) { // assume this is just for F18 - Q3 should already have it boot += `Bangle.setUI=function(mode, cb) { if (Bangle.btnWatches) { Bangle.btnWatches.forEach(clearWatch); @@ -97,26 +98,35 @@ if (Bangle.touchandler) { Bangle.removeListener("touch", Bangle.touchHandler); delete Bangle.touchHandler; } -function b() { - try{Bangle.buzz(20);}catch(e){} -} if (!mode) return; else if (mode=="updown") { Bangle.btnWatches = [ - setWatch(function() { b();cb(-1); }, BTN1, {repeat:1}), - setWatch(function() { b();cb(1); }, BTN3, {repeat:1}), - setWatch(function() { b();cb(); }, BTN2, {repeat:1}) + setWatch(function() { cb(-1); }, BTN1, {repeat:1}), + setWatch(function() { cb(1); }, BTN3, {repeat:1}), + setWatch(function() { cb(); }, BTN2, {repeat:1}) ]; } else if (mode=="leftright") { Bangle.btnWatches = [ - setWatch(function() { b();cb(-1); }, BTN1, {repeat:1}), - setWatch(function() { b();cb(1); }, BTN3, {repeat:1}), - setWatch(function() { b();cb(); }, BTN2, {repeat:1}) + setWatch(function() { cb(-1); }, BTN1, {repeat:1}), + setWatch(function() { cb(1); }, BTN3, {repeat:1}), + setWatch(function() { cb(); }, BTN2, {repeat:1}) ]; - Bangle.swipeHandler = d => {b();cb(d);}; + Bangle.swipeHandler = d => {cb(d);}; Bangle.on("swipe", Bangle.swipeHandler); - Bangle.touchHandler = d => {b();cb();}; + Bangle.touchHandler = d => {cb();}; Bangle.on("touch", Bangle.touchHandler); +} else if (mode=="clock") { + Bangle.CLOCK=1; + Bangle.btnWatches = [ + setWatch(Bangle.showLauncher, BTN2, {repeat:1,edge:"falling"}) + ]; +} else if (mode=="clockupdown") { + Bangle.CLOCK=1; + Bangle.btnWatches = [ + setWatch(function() { cb(-1); }, BTN1, {repeat:1}), + setWatch(function() { cb(1); }, BTN3, {repeat:1}), + setWatch(Bangle.showLauncher, BTN2, {repeat:1,edge:"falling"}) + ]; } else throw new Error("Unknown UI mode"); };\n`; @@ -126,8 +136,9 @@ require('Storage').list(/\.boot\.js/).forEach(bootFile=>{ boot += "//"+bootFile+"\n"+require('Storage').read(bootFile)+"\n"; }); boot += "}\n";// initial 'if' -var s = require('Storage').write('.boot0',boot); +require('Storage').write('.boot0',boot); delete boot; E.showMessage("Reloading..."); eval(require('Storage').read('.boot0')); -eval(require('Storage').read('.bootcde')); +// .bootcde should be run automatically after if required, since +// we normally get called automatically from '.boot0' diff --git a/apps/buffgym/buffgym-scrn1.png b/apps/buffgym/buffgym-scrn1.png old mode 100755 new mode 100644 diff --git a/apps/buffgym/buffgym-scrn2.png b/apps/buffgym/buffgym-scrn2.png old mode 100755 new mode 100644 diff --git a/apps/buffgym/buffgym-scrn3.png b/apps/buffgym/buffgym-scrn3.png old mode 100755 new mode 100644 diff --git a/apps/buffgym/buffgym-scrn4.png b/apps/buffgym/buffgym-scrn4.png old mode 100755 new mode 100644 diff --git a/apps/buffgym/buffgym-scrn5.png b/apps/buffgym/buffgym-scrn5.png old mode 100755 new mode 100644 diff --git a/apps/buffgym/buffgym-scrn6.png b/apps/buffgym/buffgym-scrn6.png old mode 100755 new mode 100644 diff --git a/apps/buffgym/buffgym.app.js b/apps/buffgym/buffgym.app.js old mode 100755 new mode 100644 diff --git a/apps/buffgym/buffgym.png b/apps/buffgym/buffgym.png old mode 100755 new mode 100644 diff --git a/apps/calendar/ChangeLog b/apps/calendar/ChangeLog index 3cf79ffe8..8bafff34a 100644 --- a/apps/calendar/ChangeLog +++ b/apps/calendar/ChangeLog @@ -1 +1,2 @@ 0.01: Basic calendar +0.02: Make Bangle 2 compatible diff --git a/apps/calendar/calendar.js b/apps/calendar/calendar.js index 720986162..6f3c33164 100644 --- a/apps/calendar/calendar.js +++ b/apps/calendar/calendar.js @@ -1,5 +1,6 @@ -const maxX = 240; -const maxY = 240; +const maxX = g.getWidth(); +const maxY = g.getHeight(); +const fontSize = g.getWidth()>200?2:1; const rowN = 7; const colN = 7; const headerH = maxY / 7; @@ -50,7 +51,7 @@ function drawCalendar(date) { 11: "December" }; g.setFontAlign(0, 0); - g.setFont("6x8", 2); + g.setFont("6x8", fontSize); g.setColor(white); g.drawString(`${monthMap[month]} ${year}`, maxX / 2, headerH / 2); g.drawPoly([10, headerH / 2, 20, 10, 20, headerH - 10], true); @@ -59,7 +60,7 @@ function drawCalendar(date) { true ); - g.setFont("6x8", 2); + g.setFont("6x8", fontSize); const dowLbls = ["Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"]; dowLbls.forEach((lbl, i) => { g.drawString(lbl, i * colW + colW / 2, headerH + rowH / 2); @@ -135,26 +136,21 @@ const today = { }; drawCalendar(date); clearWatch(); -setWatch( - () => { - const month = date.getMonth(); - const prevMonth = month > 0 ? month - 1 : 11; +Bangle.on("touch",area=>{ + const month = date.getMonth(); + let prevMonth; + if (area==1) { + let prevMonth = month > 0 ? month - 1 : 11; if (prevMonth === 11) date.setFullYear(date.getFullYear() - 1); date.setMonth(prevMonth); - drawCalendar(date); - }, - BTN4, - { repeat: true } -); -setWatch( - () => { - const month = date.getMonth(); - const prevMonth = month < 11 ? month + 1 : 0; + } else { + let prevMonth = month < 11 ? month + 1 : 0; if (prevMonth === 0) date.setFullYear(date.getFullYear() + 1); date.setMonth(month + 1); - drawCalendar(date); - }, - BTN5, - { repeat: true } -); -setWatch(Bangle.showLauncher, BTN2, { repeat: false, edge: "falling" }); + } + drawCalendar(date); +}); + +// Show launcher when button pressed +Bangle.setUI("clock"); // TODO: ideally don't set 'clock' mode +// No space for widgets! diff --git a/apps/cliock/ChangeLog b/apps/cliock/ChangeLog index 53616638b..66ef62eae 100644 --- a/apps/cliock/ChangeLog +++ b/apps/cliock/ChangeLog @@ -1,6 +1,7 @@ 0.07: Submitted to App Loader -0.08: Fixes issue where face would redraw on wake leading to all memory being used and watch crashing. +0.08: Fixes issue where face would redraw on wake leading to all memory being used and watch crashing. 0.09: Add BTN1 status line with ID,Fw ver, mem %, battery % 0.10: Icon fixed for transparency 0.11: added Heart Rate Monitor status and ability to turn on/off 0.12: added support for different locales +0.13: Use setUI, work with smaller screens and themes diff --git a/apps/cliock/app.js b/apps/cliock/app.js index d9541f545..6853aaf6f 100644 --- a/apps/cliock/app.js +++ b/apps/cliock/app.js @@ -1,4 +1,5 @@ -var fontsize = 3; +var fontsize = g.getWidth()>200 ? 3 : 2; +var fontheight = 10*fontsize; var locale = require("locale"); var marginTop = 40; var flag = false; @@ -39,22 +40,23 @@ function updateTime(){ updateRest(now); } function writeLineStart(line){ - g.drawString(">",4,marginTop+line*30); + g.drawString(">",4,marginTop+line*fontheight); } function writeLine(str,line){ + var y = marginTop+line*fontheight; g.setFont("6x8",fontsize); //g.setColor(0,1,0); - g.setColor(0,0x07E0,0); + g.setColor("#0f0"); g.setFontAlign(-1,-1); - g.clearRect(0,marginTop+line*30,((str.length+1)*20),marginTop+25+line*30); + g.clearRect(0,y,((str.length+1)*20),y+fontheight-1); writeLineStart(line); - g.drawString(str,25,marginTop+line*30); -} + g.drawString(str,25,y); +} function drawInfo(line) { let val; let str = ""; - let col = 0x07E0; // green + let col = "#0f0"; // green //console.log("drawInfo(), infoMode=" + infoMode + " funcMode=" + functionMode); @@ -62,15 +64,15 @@ function drawInfo(line) { case NONE_FN_MODE: break; case HRT_FN_MODE: - col = 0x07FF; // cyan + col = "#0ff"; // cyan str = "HRM: " + (hrtOn ? "ON" : "OFF"); drawModeLine(line,str,col); return; } - + switch(infoMode) { case NONE_MODE: - col = 0x0000; + col = "#fff"; str = ""; break; case HRT_MODE: @@ -100,10 +102,11 @@ function drawInfo(line) { function drawModeLine(line, str, col) { g.setColor(col); - g.fillRect(0, marginTop-3+line*30, 239, marginTop+25+line*30); - g.setColor(0,0,0); + var y = marginTop+line*fontheight; + g.fillRect(0, y, 239, y+fontheight-1); + g.setColor(0); g.setFontAlign(0, -1); - g.drawString(str, g.getWidth()/2, marginTop+line*30); + g.drawString(str, g.getWidth()/2, y); } function changeInfoMode() { @@ -160,7 +163,7 @@ function changeFunctionMode() { functionMode = NONE_FN_MODE; } //console.log(functionMode); - + } function stepsWidget() { @@ -185,10 +188,12 @@ Bangle.loadWidgets(); Bangle.drawWidgets(); drawAll(); Bangle.on('lcdPower',function(on) { - if (on) - drawAll(); + if (on) drawAll(); }); var click = setInterval(updateTime, 1000); -setWatch(Bangle.showLauncher, BTN2, {repeat:false,edge:"falling"}); -setWatch(() => { changeInfoMode(); drawAll(); }, BTN1, {repeat: true}); -setWatch(() => { changeFunctionMode(); drawAll(); }, BTN3, {repeat: true}); +// Show launcher when button pressed +Bangle.setUI("clockupdown", btn=>{ + if (btn==0) changeInfoMode(); + if (btn==1) changeFunctionMode(); + drawAll(); +}); diff --git a/apps/clock2x3/ChangeLog b/apps/clock2x3/ChangeLog index 88876affa..ef8057d6e 100644 --- a/apps/clock2x3/ChangeLog +++ b/apps/clock2x3/ChangeLog @@ -1,3 +1,4 @@ 0.02: Modified for use with new bootloader and firmware 0.03: Added 'reset' so we don't get the font color from widgets 0.04: Changed name from clck3x2 to clock2x3 +0.05: Use setUI, work with smaller screens and themes diff --git a/apps/clock2x3/clock2x3-app.js b/apps/clock2x3/clock2x3-app.js index 4caec28cb..bfe6a9ea8 100644 --- a/apps/clock2x3/clock2x3-app.js +++ b/apps/clock2x3/clock2x3-app.js @@ -1,8 +1,10 @@ + +const big = g.getWidth()>200; const ox=10; // x offset -const oy=80; -const pw=20; // pixel width -const ps=5; // pixel spacing -const ds=10; // digit spacing +const oy=big ? 80 : 70; +const pw=big ? 20 : 14; // pixel width +const ps=big ? 5 : 3; // pixel spacing +const ds=big ? 10 : 8; // digit spacing const ms=20; // middle space const x00=ox; // digit 0, pixel 0, x position @@ -90,7 +92,7 @@ Bangle.on('lcdPower', function(on){ } }); +// Show launcher when button pressed +Bangle.setUI("clock"); Bangle.loadWidgets(); drawTime(); -// Show launcher when middle button pressed -setWatch(Bangle.showLauncher, BTN2, {repeat:false,edge:"falling"}); diff --git a/apps/ctrclk/ChangeLog b/apps/ctrclk/ChangeLog index 7819dbe2a..e4659c1ae 100644 --- a/apps/ctrclk/ChangeLog +++ b/apps/ctrclk/ChangeLog @@ -1 +1,2 @@ 0.02: Modified for use with new bootloader and firmware +0.03: Changed setWatch to Bangle.setUI diff --git a/apps/ctrclk/app.js b/apps/ctrclk/app.js index 060aac2f9..7f6ab0570 100644 --- a/apps/ctrclk/app.js +++ b/apps/ctrclk/app.js @@ -46,26 +46,25 @@ function drawSegment (align, base, str) { point = base + (maxSegmentWidth / 2) - (g.stringWidth(str) / 2); } - g.setColor(1, 1, 1); + g.setColor(g.theme.fg); g.drawString(str, point, middleY - 4, false); } function drawDots (center) { - g.setColor(0xFD20); + g.setColor("#FA0"); g.fillCircle(center, middleY + 10, 2); g.fillCircle(center, middleY + 40, 2); } function drawLines () { - g.setColor(0.5, 0.5, 0.5); + g.setColor("#777"); g.drawLine(middleX - lineLength, lineY1, middleX + lineLength, lineY1); g.drawLine(middleX - lineLength, lineY2, middleX + lineLength, lineY2); } function drawDate (str) { let maxSegmentWidth = 236; - g.setColor(0.5, 0.5, 0.5); - g.setColor(0.5, 0.5, 0.5); + g.setColor("#777"); g.drawString(str, (maxSegmentWidth) - (g.stringWidth(str)), middleY - 22, false); } @@ -149,6 +148,9 @@ function start () { } start(); +// Show launcher when middle button pressed +Bangle.setUI("clock"); + Bangle.loadWidgets(); Bangle.drawWidgets(); Bangle.on('lcdPower', function (on) { @@ -158,6 +160,3 @@ Bangle.on('lcdPower', function (on) { stop(); } }); - -// Show launcher when middle button pressed -setWatch(Bangle.showLauncher, BTN2, {repeat:false,edge:"falling"}); diff --git a/apps/dclock/ChangeLog b/apps/dclock/ChangeLog index edf7da4c2..aa8ae23fe 100644 --- a/apps/dclock/ChangeLog +++ b/apps/dclock/ChangeLog @@ -7,3 +7,4 @@ 0.07: add days in current month (md) and days since new moon (l) 0.08: update icon 0.09: Use localised month and day of the week from locale +0.10: Changed setWatch to Bangle.setUI and allow small screen diff --git a/apps/dclock/clock-dev.js b/apps/dclock/clock-dev.js index d2c08726a..d2c3893d5 100644 --- a/apps/dclock/clock-dev.js +++ b/apps/dclock/clock-dev.js @@ -1,17 +1,18 @@ var locale = require("locale"); /* jshint esversion: 6 */ -const timeFontSize = 4; -const dateFontSize = 3; -const smallFontSize = 2; +const big = g.getWidth()>200; +const timeFontSize = big?4:3; +const dateFontSize = big?3:2; +const smallFontSize = big?2:1; const font = "6x8"; const xyCenter = g.getWidth() / 2; const yposTime = 50; -const yposDate = 85; -const yposTst = 115; -const yposDml = 170; -const yposDayMonth = 195; -const yposGMT = 220; +const yposDate = big?85:75; +const yposTst = big?115:95; +const yposDml = big?170:130; +const yposDayMonth = big?195:140; +const yposGMT = big?220:150; // Check settings for what type our clock should be var is12Hour = (require("Storage").readJSON("setting.json",1)||{})["12hour"]; @@ -99,6 +100,8 @@ Bangle.on('lcdPower', function(on) { // clean app screen g.clear(); +// Show launcher when button pressed +Bangle.setUI("clock"); Bangle.loadWidgets(); Bangle.drawWidgets(); @@ -107,6 +110,3 @@ setInterval(drawSimpleClock, 100); // draw now drawSimpleClock(); - -// Show launcher when middle button pressed -setWatch(Bangle.showLauncher, BTN2, {repeat:false,edge:"falling"}); \ No newline at end of file diff --git a/apps/de-stress/ChangeLog b/apps/de-stress/ChangeLog new file mode 100644 index 000000000..fcd7580b1 --- /dev/null +++ b/apps/de-stress/ChangeLog @@ -0,0 +1,2 @@ +0.01: New App! +0.02: Adjust for different screen types and themes diff --git a/apps/de-stress/app.js b/apps/de-stress/app.js index 445e853c5..b292fe601 100644 --- a/apps/de-stress/app.js +++ b/apps/de-stress/app.js @@ -1,29 +1,21 @@ +g.setBgColor(0).clear(); -//g.clear(); - -var img = { - width : 100, height : 100, bpp : 8, - transparent : 254, - buffer : require("heatshrink").decompress(atob("/wA/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4AglYAGE/44gHz4nnHKtPumez3C4WezFzp49ZLAgoCE4WeugnaHStPG4QAHzw9DE/Y6VHJQ9YMJwnEMk46CF4lzfglPug9WCAWYDQl0E4tzN4gLCMVC5Cp+YGoOezxBCubKHExxUEuiFCEoInECAhkjMQuYLArCFGwLLEHpjsGMIRpEfAsrMkwhBFAQ6BHJA9EKApDBHpAJBQYhPBE5iZBzAsDMb4gBEwg6MJhBkIYorgBPQiMMUAhkeHgkrug7ObI5qBHwhiGZYomOEojGeJQVzTx5kOMQ6JREAR3CDIJkcHobwEMiw+CAAYJEMSYWCAgRjcDgI4CYyiiDXopiFBooAWRwJkaHwjGVKwdzH4rADuhiXZAaICMbbtGHy2YBQ+YRDCiEMbidCULBkDLIwIIdqbmCp5jZPwIfDAYQAXXwNPzwACIQLQIACt0ZDIZBTwRFBHjWeHoSJCETlPc4ZjdAYYA7L4Jj/Mf5jCEYQDDAHhEEMbzH+McBfCMf4ADzxjep+YL/1PMb10MYQDCAHd0MYV0MbdzEYoA7UYdPMTBkCc4hj9leeAYRjbL4aIDAHN0UwRjeL4WYZHlPzBnCMbZkBQojtCAG6gEp5ibZARfCdwjG3ugDBzzGcMYTIEFAQA1ujGFMbjIFeAgA0HobGeZA9PAgYAyG4jGfZAyPBzBizf4LGjMggtCFAJpDAFw0FMURjCeAd0AgYAup90AgZjjMgWYFYZkwGImYMUhkDeYdPuZituZiDzximMYUrFwj6DAFF0TAg6CMcpkCSYpkqMQtPMVBkDuZktMQtzMVRkDLwZkoMQoFBMVZkJp5ijX4JizMhFPMkQjBMWpkHIAKjEADTrGMWZkDuY8DuZkdMQKKEMWpkDUIxFEACocGdoJi1MhCqBAwgATLYLkEMXJkDIY4GEAB+ep9PC4aDBMXRkJukruhiRCgxi+MglzJAtPMR7cGNIJi+MglPJYhSBzBhLzB0FzwWBMX5lGMghVGAAtzld0bwph/MhNzWYzKGNwR2Euhi/MhhTHA4ZrHA4Rh/Mp10YIlzA4JoCBQjE/ZTK8BA45i/MqtzX4jE/Mj0rYQjECBYZP/MrFPMoWep5h/ZT90ujE/MsZh/MsZB/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/ACg")) -}; +var img = require("heatshrink").decompress(atob("plB4X/ln7A4OGmMs5dVAANa1WlAoQADBI9W1QAByoJNtWv4f61ISEtWrBI2q4EAgeqCQgJHq2sLoU6IYdaBIg5CrWAn2q2EDF4dq4EO1W8gQcCtUD1fP9cA9QSC1cA9f/9XADgWohxBBh2whQvBq2gAwMAh+wlQSB1k7IIXogYvBrXAlYJC9k6DYOw9gIChXA9JBC0AJCncOytWwAtBAAMDF4RBDAAMOgWVrXDwDjD9kKy2gIIcAgXD0taDYgvCRIJBDF4OA0trhwIDJgK2B4BKDAAXptcLA4kC4HrD4IJE8HptE4BAhfBLAJBEgEslISGL4JOBBAoSB1ksBIs6/70DBIgSHh+q+AIFnASIABASU0EgCR0IhWgEp4SBHCBxJLzusXowAIaBISLhYSO8EptcOCR2w9NagXACJkDwGlrXDwASMgXDCQOA2ASMh0C0tW2HgCRkLh2Vq2glASMlEKytV1iFN9k6qtVtEOORcD2EpCQNqOwJwL4GpCQNa4GgCRUKgelCQJyBlgSKnBwBCQWgnZdLOAQAB1BfKLoMqCIVVtYHBXZPA9ISDL4PsCRE7LoZfDnRKJLoYAC1kOTI8CDoIREJgMA1gSGFwJKEJgaGH9hKFTIaGGPQKVEAAeogbTFhXASogADtXAlYSE9cDeYRMG2A5EG4MOJQxMC1g5EG4M6JQ4AB1Q5E9ED1QRIHIatBG5Y5EVoM6G5Y5DnXDCwJvIHIsD32AG5Y5C1aUBgHqG5atDLwI3MHIReCG5hgD4aUKHI2+G5xgC1RcNAAdpBJA")) function hr(){ - -Bangle.buzz(100,0.1).then(()=>{ - g.clear(); - return new Promise(resolve=>setTimeout(resolve,250)); // wait 250ms -}).then(()=>{ - return Bangle.buzz(150); -}).then(()=>{ - g.drawImage(img, 25, 40, {scale:2}); -}); - + Bangle.buzz(100,0.1).then(()=>{ + g.clear(); + return new Promise(resolve=>setTimeout(resolve,250)); // wait 250ms + }).then(()=>{ + return Bangle.buzz(150); + }).then(()=>{ + g.drawImage(img, g.getWidth()/2 - 76, g.getHeight()/2 - 65, {scale:2}); + }); } setInterval(hr, 2000); g.flip(); -setWatch(Bangle.showLauncher, BTN2, { repeat: false, edge: "falling" }); - - +// TODO - not clock but we still want a press to show launcher when button pressed +Bangle.setUI("clock"); diff --git a/apps/devstopwatch/ChangeLog b/apps/devstopwatch/ChangeLog index c6d24e9bc..e2b392fe9 100644 --- a/apps/devstopwatch/ChangeLog +++ b/apps/devstopwatch/ChangeLog @@ -1,2 +1,3 @@ 0.01: App created 0.02: Persist state to storage to enable stopwatch to continue in the background +0.03: Modified to use setUI, theme and different screens diff --git a/apps/devstopwatch/app.js b/apps/devstopwatch/app.js index 665ba084e..83bb693a9 100644 --- a/apps/devstopwatch/app.js +++ b/apps/devstopwatch/app.js @@ -2,13 +2,16 @@ const EMPTY_LAP = '--:--:---'; const EMPTY_H = '00:00:000'; const MAX_LAPS = 6; const XY_CENTER = g.getWidth() / 2; +const big = g.getWidth()>200; const Y_CHRONO = 40; -const Y_HEADER = 80; -const Y_LAPS = 125; -const Y_BTN3 = 225; +const Y_HEADER = big?80:60; +const Y_LAPS = big?125:90; +const H_LAPS = big?15:8; +const Y_BTN3 = big?225:165; const FONT = '6x8'; const CHRONO = '/* C H R O N O */'; + var reset = false; var currentLap = ''; var chronoInterval; @@ -22,11 +25,11 @@ var state = require("Storage").readJSON("devstopwatch.state.json",1) || { laps: [EMPTY_LAP, EMPTY_LAP, EMPTY_LAP, EMPTY_LAP, EMPTY_LAP, EMPTY_LAP, EMPTY_LAP], }; -// Set laps. -setWatch(() => { - +// Show launcher when button pressed +Bangle.setUI("clockupdown", btn=>{ + if (btn==0) { reset = false; - + if (state.started) { changeLap(); } else { @@ -34,13 +37,9 @@ setWatch(() => { chronoInterval = setInterval(chronometer, 10); } } -}, BTN1, { repeat: true, edge: 'rising' }); - -// Reset chronometre. -setWatch(() => { resetChrono(); }, BTN3, { repeat: true, edge: 'rising' }); - -// Show launcher when middle button pressed. -setWatch(Bangle.showLauncher, BTN2, { repeat: false, edge: 'falling' }); +} + if (btn==1) resetChrono(); +}); function resetChrono() { state.laps = [EMPTY_H, EMPTY_H, EMPTY_LAP, EMPTY_LAP, EMPTY_LAP, EMPTY_LAP, EMPTY_LAP]; @@ -106,33 +105,33 @@ function printChrono() { var print = ''; - g.setFont(FONT, 2); + g.setFont(FONT, big?2:1); print = CHRONO; g.drawString(print, XY_CENTER, Y_CHRONO, true); - g.setColor(0, 220, 0); - g.setFont(FONT, 3); + g.setColor("#0e0"); + g.setFont(FONT, big?3:2); print = ` T ${state.laps[0]}\n`; print += ` C ${state.laps[1]}\n`; g.drawString(print, XY_CENTER, Y_HEADER, true); - g.setColor(255, 255, 255); - g.setFont(FONT, 2); + g.setColor(g.theme.fg); + g.setFont(FONT, big?2:1); for (var i = 2; i < MAX_LAPS + 1; i++) { - g.setColor(255, 255, 255); + g.setColor(g.theme.fg); let suffix = ' '; if (state.currentLapIndex === i) { let suffix = '*'; - g.setColor(255, 200, 0); + g.setColor("#f70"); } const lapLine = `L${i - 1} ${state.laps[i]} ${suffix}\n`; - g.drawString(lapLine, XY_CENTER, Y_LAPS + (15 * (i - 1)), true); + g.drawString(lapLine, XY_CENTER, Y_LAPS + (H_LAPS * (i - 1)), true); } - g.setColor(255, 255, 255); + g.setColor(g.theme.fg); g.setFont(FONT, 1); print = 'Press 3 to reset'; g.drawString(print, XY_CENTER, Y_BTN3, true); @@ -166,7 +165,7 @@ E.on('kill', function(){ }); if(state.started){ - chronoInterval = setInterval(chronometer, 10); + chronoInterval = setInterval(chronometer, 10); } else { - resetChrono(); + resetChrono(); } diff --git a/apps/digiclock/ChangeLog b/apps/digiclock/ChangeLog index 0bb55854e..e41fae573 100644 --- a/apps/digiclock/ChangeLog +++ b/apps/digiclock/ChangeLog @@ -1 +1,2 @@ 0.01: App Made! +0.02: Changed setWatch to Bangle.setUI, code tidy diff --git a/apps/digiclock/digiclock.js b/apps/digiclock/digiclock.js index 7f74f2242..f404d30b2 100644 --- a/apps/digiclock/digiclock.js +++ b/apps/digiclock/digiclock.js @@ -1,141 +1,50 @@ //load fonts require("Font7x11Numeric7Seg").add(Graphics); -require("FontHaxorNarrow7x17").add(Graphics); +require("FontHaxorNarrow7x17").add(Graphics); //screen position -const X = 170; -const Y = 140; +const X = 170; +const Y = 140; function draw() { // Date Variables - var date = new Date(); - var h = date.getHours(); - var m = date.getMinutes(); - var day = date.getDay(); - var month = date.getMonth(); - var dateNum = date.getDate(); - var year = date.getFullYear(); - var half = "AM"; - var time = (" " + h).substr(-2) + ":" + ("0" + m).substr(-2); - - //convert day into string - switch (day) { - case 0: - day = "Sunday"; - break; - - case 1: - day = "Monday"; - break; - - case 2: - day = "Tuesday"; - break; - - case 3: - day = "Wednesday"; - break; - - case 4: - day = "Thursday"; - break; - - case 5: - day = "Friday"; - break; - - case 6: - day = "Saturday"; - break; - - default: - day = "ERROR"; - break; - } - - //convert month into String - switch(month) { - case 0: - month = "Jan"; - break; - - case 1: - month = "Feb"; - break; - - case 2: - month = "Mar"; - break; - - case 3: - month = "Apr"; - break; - - case 4: - month = "May"; - break; - - case 5: - month = "Jun"; - break; - - case 6: - month = "Jul"; - break; - - case 7: - month = "Aug"; - break; - - case 8: - month = "Sep"; - break; - - case 9: - month = "Oct"; - break; - - case 10: - month = "Nov"; - break; - - case 11: - month = "Dec"; - break; - - default: - month = "ERROR"; - break; - - } - + var date = new Date(); + var h = date.getHours(); + var m = date.getMinutes(); + var day = require("locale").dow(date); + var month = require("locale").month(date,1); + var dateNum = date.getDate(); + var year = date.getFullYear(); + var half = "AM"; + var time = (" " + h).substr(-2) + ":" + ("0" + m).substr(-2); + if (h > 12) { - half = "PM"; - h = h - 12; + half = "PM"; + h = h - 12; } //reset graphics - g.reset(); + g.reset(); //draw the time g.setFont("7x11Numeric7Seg", 5); g.setFontAlign(1,1); g.drawString(time, X, Y, true /*clear background*/); - g.setFont("7x11Numeric7Seg", 3); - g.drawString(("0"+date.getSeconds()).substr(-2), X+50, Y, true /*clear background*/); + g.setFont("7x11Numeric7Seg", 3); + g.drawString(("0"+date.getSeconds()).substr(-2), X+50, Y, true /*clear background*/); g.setFontAlign(0,1); g.setFont("HaxorNarrow7x17", 2); g.drawString(half, X+30, Y-35, true); g.setFont("HaxorNarrow7x17", 3); g.drawString(day, X-60, Y+53, true); - g.drawString(month, X-100, Y+95, true); - g.drawString(dateNum, X-40, Y+95, true); - g.drawString(year, X-90, Y-55, true); - - + g.drawString(month, X-100, Y+95, true); + g.drawString(dateNum, X-40, Y+95, true); + g.drawString(year, X-90, Y-55, true); + + } //clear screen at startup -g.clear(); +g.clear(); //draw immediatly -draw(); +draw(); var secondInterval = setInterval(draw, 1000); // Stop updates when LCD is off, restart when on @@ -148,7 +57,7 @@ Bangle.on('lcdPower',on=>{ } }); +// Show launcher when button pressed +Bangle.setUI("clock"); Bangle.loadWidgets(); Bangle.drawWidgets(); - -setWatch(Bangle.showLauncher, BTN2, {repeat : false, edge: "falling"}); diff --git a/apps/dotclock/ChangeLog b/apps/dotclock/ChangeLog index c9658afb8..563db87e7 100644 --- a/apps/dotclock/ChangeLog +++ b/apps/dotclock/ChangeLog @@ -1,2 +1,3 @@ 0.01: Based on the Analog Clock app, minimal dot 0.02: Remove hardcoded hour buzz (you can install widchime if you miss it) +0.03: Use setUI, adjust for themes and different size screens diff --git a/apps/dotclock/clock-dot.js b/apps/dotclock/clock-dot.js index c4a8be921..66255d1b4 100644 --- a/apps/dotclock/clock-dot.js +++ b/apps/dotclock/clock-dot.js @@ -1,20 +1,22 @@ -let g; -let Bangle; - +const big = g.getWidth()>200; const locale = require('locale'); const p = Math.PI / 2; const pRad = Math.PI / 180; -const faceWidth = 100; // watch face radius let timer = null; let currentDate = new Date(); -let hourRadius = 60; -let minRadius = 80; -const centerPx = g.getWidth() / 2; +const faceWidth = big?100:65; // watch face radius +let hourRadius = big?60:40; +let minRadius = big?80:55; +const centerX = g.getWidth() / 2; +const centerY = 24 + (g.getHeight()-24) / 2; +let colSecA = g.theme.dark ? "#00A" : "#58F"; // before the second +let colSecB = g.theme.dark ? "#58F" : "#00A"; // after the second +let colSec1 = g.theme.dark ? "#F83" : "#000"; // ON the second const seconds = (angle) => { const a = angle * pRad; - const x = centerPx + Math.sin(a) * faceWidth; - const y = centerPx - Math.cos(a) * faceWidth; + const x = centerX + Math.sin(a) * faceWidth; + const y = centerY - Math.cos(a) * faceWidth; // if 15 degrees, make hour marker larger const radius = (angle % 15) ? 2 : 4; @@ -23,15 +25,15 @@ const seconds = (angle) => { const hourDot = (angle,radius) => { const a = angle * pRad; - const x = centerPx + Math.sin(a) * hourRadius; - const y = centerPx - Math.cos(a) * hourRadius; + const x = centerX + Math.sin(a) * hourRadius; + const y = centerY - Math.cos(a) * hourRadius; g.fillCircle(x, y, radius); }; const minDot = (angle,radius) => { const a = angle * pRad; - const x = centerPx + Math.sin(a) * minRadius; - const y = centerPx - Math.cos(a) * minRadius; + const x = centerX + Math.sin(a) * minRadius; + const y = centerY - Math.cos(a) * minRadius; g.fillCircle(x, y, radius); }; @@ -45,54 +47,49 @@ const drawAll = () => { // draw all secs for (let i = 0; i < 60; i++) { - if (i > currentSec) { - g.setColor(0, 0, 0.6); - } else { - g.setColor(0.3, 0.3, 1); - } + g.setColor((i > currentSec) ? colSecA : colSecB); seconds((360 * i) / 60); } onSecond(); }; const resetSeconds = () => { - g.setColor(0, 0, 0.6); + g.setColor(colSecA); for (let i = 0; i < 60; i++) { seconds((360 * i) / 60); } }; const drawMin = () => { - g.setColor(0.5, 0.5, 0.5); + g.setColor("#777"); for (let i = 0; i < 60; i++) { minDot((360 * i) / 60,1); } }; const drawHour = () => { - g.setColor(0.5, 0.5, 0.5); + g.setColor("#777"); for (let i = 0; i < 12; i++) { hourDot((360 * 5 * i) / 60,1); } }; const onSecond = () => { - g.setColor(0.3, 0.3, 1); + g.setColor(colSecB); seconds((360 * currentDate.getSeconds()) / 60); if (currentDate.getSeconds() === 59) { resetSeconds(); onMinute(); } - g.setColor(1, 0.7, 0.2); + g.setColor(colSec1); currentDate = new Date(); seconds((360 * currentDate.getSeconds()) / 60); - g.setColor(1, 1, 1); + g.setColor(g.theme.fg); }; const drawDate = () => { g.reset(); - g.setColor(1, 1, 1); - g.setFont('6x8', 2); + g.setFont('6x8', big?2:1); const dayString = locale.dow(currentDate, true); // pad left date @@ -101,7 +98,7 @@ const drawDate = () => { // console.log(`${dayString}|${dateString}`); // center date const l = (g.getWidth() - g.stringWidth(dateDisplay)) / 2; - const t = centerPx - 6 ; + const t = centerY - 6 ; g.drawString(dateDisplay, l, t); // console.log(l, t); }; @@ -111,7 +108,7 @@ const onMinute = () => { resetSeconds(); } // clear existing hands - g.setColor(0, 0, 0); + g.setColor(g.theme.bg); hourDot((360 * currentDate.getHours()) / 12,4); minDot((360 * currentDate.getMinutes()) / 60,3); @@ -125,7 +122,7 @@ const onMinute = () => { g.setColor(1, 0, 0); // Hour hourDot((360 * currentDate.getHours()) / 12,4); - g.setColor(1, 0.9, 0.9); + g.setColor(g.theme.fg2); // Minute minDot((360 * currentDate.getMinutes()) / 60,3); drawDate(); @@ -152,8 +149,8 @@ g.clear(); resetSeconds(); startTimers(); drawAll(); +// Show launcher when button pressed +Bangle.setUI("clock"); + Bangle.loadWidgets(); Bangle.drawWidgets(); - -// Show launcher when middle button pressed -setWatch(Bangle.showLauncher, BTN2, { repeat: false, edge: "falling" }); diff --git a/apps/dotmatrixclock/app.js b/apps/dotmatrixclock/app.js old mode 100755 new mode 100644 diff --git a/apps/dotmatrixclock/dotmatrix-clock-screen-shot.png b/apps/dotmatrixclock/dotmatrix-clock-screen-shot.png old mode 100755 new mode 100644 diff --git a/apps/dotmatrixclock/dotmatrixclock.png b/apps/dotmatrixclock/dotmatrixclock.png old mode 100755 new mode 100644 diff --git a/apps/doztime/ChangeLog b/apps/doztime/ChangeLog index 5560f00bc..6c4a25b26 100644 --- a/apps/doztime/ChangeLog +++ b/apps/doztime/ChangeLog @@ -1 +1,4 @@ 0.01: New App! +0.02: added emulator capability and display of widgets +0.03: bug of advancing time fixed; doztime now correct within ca. 1 second +0.04: changed time colour from slightly off white to pure white diff --git a/apps/doztime/app.js b/apps/doztime/app.js index 83f536018..38c5acbac 100644 --- a/apps/doztime/app.js +++ b/apps/doztime/app.js @@ -13,11 +13,11 @@ const g_height_t = 48; // height of time region const A1 = [30,30,30,30,31,31,31,31,31,31,30,30]; const B1 = [30,30,30,30,30,31,31,31,31,31,30,30]; const B2 = [30,30,30,30,31,31,31,31,31,30,30,30]; -const timeColour = "#f2f2f2"; +const timeColour = "#ffffff"; const dateColours = ["#ff0000","#ffa500","#ffff00","#00b800","#0000ff","#ff00ff","#ff0080"]; const calen10 = {"size":32,"pt0":[32-g_x_off,16],"step":[20,0],"dx":-4.5,"dy":-4.5}; // positioning for usual calendar line const calen7 = {"size":32,"pt0":[62-g_x_off,16],"step":[20,0],"dx":-4.5,"dy":-4.5}; // positioning for S-day calendar line -const time5 = {"size":48,"pt0":[64-g_x_off,24],"step":[30,0],"dx":-6.5,"dy":-6.5}; // positioning for lull time line; was 64 +const time5 = {"size":48,"pt0":[64-g_x_off,24],"step":[30,0],"dx":-6.5,"dy":-6.5}; // positioning for lull time line const time6 = {"size":48,"pt0":[48-g_x_off,24],"step":[30,0],"dx":-6.5,"dy":-6.5}; // positioning for twinkling time line const baseYear = 11584; const baseDate = Date(2020,11,21); // month values run from 0 to 11 @@ -30,8 +30,11 @@ let lastX = 999999999; let res = {}; //var last_time_log = 0; +var drawtime_timeout; + // Date and time graphics buffers var dateColour = "#ffffff"; // override later +var timeColour2 = timeColour; var g_d = Graphics.createArrayBuffer(g_width,g_height_d,1,{'msb':true}); var g_t = Graphics.createArrayBuffer(g_width,g_height_t,1,{'msb':true}); // Set screen mode and function to write graphics buffers @@ -46,7 +49,7 @@ g.flip = function() height:g_height_d, buffer:g_d.buffer }, g_x_off, g_y_off + g_y_off_d); - g.setColor(timeColour); + g.setColor(timeColour2); g.drawImage( { width:g_width, @@ -118,7 +121,7 @@ function formatDate(res,dateFormat){ return(yyyy+"-"+m+"-"+w+"-"+d); } -function writeDozTime(text,def,colour){ +function writeDozTime(text,def){ let pts = def.pts; let x=def.pt0[0]; let y=def.pt0[1]; @@ -133,6 +136,7 @@ function writeDozTime(text,def,colour){ } } function writeDozDate(text,def,colour){ + dateColour = colour; let pts = def.pts; let x=def.pt0[0]; @@ -177,10 +181,10 @@ function drawTime() { // Write to background buffers, then display on screen writeDozDate(date,calenDef,res.colour); - writeDozTime(time,timeDef,timeColour); + writeDozTime(time,timeDef); g.flip(); // Ready next interval - setTimeout(drawTime,wait); + drawtime_timeout = setTimeout(drawTime,wait); } else { @@ -196,22 +200,14 @@ function modeTime() timeActiveUntil = new Date(); timeActiveUntil.setDate(timeActiveUntil.getDate()); timeActiveUntil.setSeconds(timeActiveUntil.getSeconds()+15); - //Bangle.setLCDPower(true); - clearTimeout(); + if (typeof drawtime_timeout !== 'undefined') + { + clearTimeout(drawtime_timeout); + } drawTime(); } - Bangle.loadWidgets(); - -// Time-logging function -/*function logTime(label) -{ - var d = new Date(); - var t = d.getTime(); - var diff_test = t - last_time_log; - last_time_log = t; - console.log(label + " at time: " + t + ", since last: " + diff_test); -}*/ +Bangle.drawWidgets(); // Functions for weather mode - TODO function drawWeather() {} @@ -222,4 +218,20 @@ Bangle.on('twist', function() { modeTime(); }); -Bangle.drawWidgets(); +// Time fix with GPS +function fixTime() { + Bangle.on("GPS",function cb(g) { + Bangle.setGPSPower(0,"time"); + Bangle.removeListener("GPS",cb); + if (!g.time || (g.time.getFullYear()<2000) || + (g.time.getFullYear()>2200)) { + } else { + // We have a GPS time. Set time + setTime(g.time.getTime()/1000); + } + }); + Bangle.setGPSPower(1,"time"); + setTimeout(fixTime, 10*60*1000); // every 10 minutes +} +// Start time fixing with GPS on next 10 minute interval +setTimeout(fixTime, ((60-(new Date()).getMinutes()) % 10) * 60 * 1000); diff --git a/apps/dtlaunch/ChangeLog b/apps/dtlaunch/ChangeLog index 3df4ab63b..985321e91 100644 --- a/apps/dtlaunch/ChangeLog +++ b/apps/dtlaunch/ChangeLog @@ -1,4 +1,4 @@ 0.01: Initial version 0.02: Multiple pages 0.03: cycle thru pages - +0.04: reset to clock after 2 mins of inactivity diff --git a/apps/dtlaunch/app.js b/apps/dtlaunch/app.js index 329a96958..9bbf3e219 100644 --- a/apps/dtlaunch/app.js +++ b/apps/dtlaunch/app.js @@ -2,6 +2,20 @@ * */ +function wdog(handle,timeout){ + if(handle !== undefined){ + wdog.handle = handle; + wdog.timeout = timeout; + } + if(wdog.timer){ + clearTimeout(wdog.timer) + } + wdog.timer = setTimeout(wdog.handle,wdog.timeout) +} + +// reset after two minutes of inactivity +wdog(load,120000) + var s = require("Storage"); var apps = s.list(/\.info$/).map(app=>{var a=s.readJSON(app,1);return a&&{name:a.name,type:a.type,icon:a.icon,sortorder:a.sortorder,src:a.src};}).filter(app=>app && (app.type=="app" || app.type=="clock" || !app.type)); apps.sort((a,b)=>{ @@ -42,6 +56,7 @@ function drawPage(p){ } Bangle.on("swipe",(dir)=>{ + wdog() selected = 0; oldselected=-1; if (dir<0){ @@ -54,6 +69,7 @@ Bangle.on("swipe",(dir)=>{ }); function nextapp(d){ + wdog(); oldselected = selected; selected+=d; selected = selected<0?5:selected>5?0:selected; diff --git a/apps/fclock/ChangeLog b/apps/fclock/ChangeLog index a8f708a0a..30e049f69 100644 --- a/apps/fclock/ChangeLog +++ b/apps/fclock/ChangeLog @@ -1 +1,2 @@ 0.01: First published version of app +0.02: Move to Bangle.setUI to launcher support diff --git a/apps/fclock/fclock.app.js b/apps/fclock/fclock.app.js index 044cde71f..afa0c5e2d 100644 --- a/apps/fclock/fclock.app.js +++ b/apps/fclock/fclock.app.js @@ -1,206 +1,203 @@ -{ - var minutes; - var seconds; - var hours; - var date; - var first = true; - var locale = require('locale'); - var _12hour = (require("Storage").readJSON("setting.json", 1) || {})["12hour"] || false; +var minutes; +var seconds; +var hours; +var date; +var first = true; +var locale = require('locale'); +var _12hour = (require("Storage").readJSON("setting.json", 1) || {})["12hour"] || false; - //HR variables - var id = 0; - var grow = true; - var size=10; +//HR variables +var id = 0; +var grow = true; +var size=10; - //Screen dimensions - const screen = { - width: g.getWidth(), - height: g.getWidth(), - middle: g.getWidth() / 2, - center: g.getHeight() / 2, - }; +//Screen dimensions +const screen = { + width: g.getWidth(), + height: g.getWidth(), + middle: g.getWidth() / 2, + center: g.getHeight() / 2, +}; - // Ssettings - const settings = { - time: { - color: '#dddddd', - font: 'Vector', - size: 100, - middle: screen.middle, - center: screen.center, - }, - date: { - color: '#dddddd', - font: 'Vector', - size: 15, - middle: screen.height-17, // at bottom of screen - center: screen.center, - }, - circle: { - colormin: '#ffffff', - colorsec: '#ffffff', - width: 10, - middle: screen.middle, - center: screen.center, - height: screen.height - }, - hr: { - color: '#333333', - size: 20, - x: screen.center, - y: screen.middle + 65 - } - }; +// Ssettings +const settings = { + time: { + color: '#dddddd', + font: 'Vector', + size: 100, + middle: screen.middle, + center: screen.center, + }, + date: { + color: '#dddddd', + font: 'Vector', + size: 15, + middle: screen.height-17, // at bottom of screen + center: screen.center, + }, + circle: { + colormin: '#ffffff', + colorsec: '#ffffff', + width: 10, + middle: screen.middle, + center: screen.center, + height: screen.height + }, + hr: { + color: '#333333', + size: 20, + x: screen.center, + y: screen.middle + 65 + } +}; - const dateStr = function (date) { - return locale.date(new Date(), 1); - }; +const dateStr = function (date) { + return locale.date(new Date(), 1); +}; - const getFormated = function(val) { - if (val<10) { - val='0'+val; - } +const getFormated = function(val) { + if (val<10) { + val='0'+val; + } - return val; - }; + return val; +}; - const drawMin = function (sections, color) { - - g.setFontAlign(0, 0, 0); - g.setColor('#000000'); - g.setFont(settings.time.font, settings.time.size/2); - g.drawString(getFormated(sections-1), settings.time.center+50, settings.time.middle); - g.setColor(settings.time.color); - g.setFont(settings.time.font, settings.time.size/2); - g.drawString(getFormated(sections), settings.time.center+50, settings.time.middle); - }; +const drawMin = function (sections, color) { - const drawSec = function (sections, color) { - g.setFontAlign(0, 0, 0); - g.setColor('#000000'); - g.setFont(settings.time.font, settings.time.size/4); - g.drawString(getFormated(sections-1), settings.time.center+100, settings.time.middle); - g.setColor(settings.time.color); - g.setFont(settings.time.font, settings.time.size/4); - g.drawString(getFormated(sections), settings.time.center+100, settings.time.middle); - }; + g.setFontAlign(0, 0, 0); + g.setColor('#000000'); + g.setFont(settings.time.font, settings.time.size/2); + g.drawString(getFormated(sections-1), settings.time.center+50, settings.time.middle); + g.setColor(settings.time.color); + g.setFont(settings.time.font, settings.time.size/2); + g.drawString(getFormated(sections), settings.time.center+50, settings.time.middle); +}; - const drawClock = function () { +const drawSec = function (sections, color) { + g.setFontAlign(0, 0, 0); + g.setColor('#000000'); + g.setFont(settings.time.font, settings.time.size/4); + g.drawString(getFormated(sections-1), settings.time.center+100, settings.time.middle); + g.setColor(settings.time.color); + g.setFont(settings.time.font, settings.time.size/4); + g.drawString(getFormated(sections), settings.time.center+100, settings.time.middle); +}; - currentTime = new Date(); +const drawClock = function () { - //Get date as a string - date = dateStr(currentTime); - - if(seconds==59) { - g.clear(); - } + currentTime = new Date(); - // Update minutes when needed - if (minutes != currentTime.getMinutes()) { - minutes = currentTime.getMinutes(); - drawMin(minutes, settings.circle.colormin); - } + //Get date as a string + date = dateStr(currentTime); - //Update seconds when needed - if (seconds != currentTime.getSeconds()) { - seconds = currentTime.getSeconds(); - drawSec(seconds, settings.circle.colorsec); - } + if(seconds==59) { + g.clear(); + } - //Write the time as configured in the settings - hours = currentTime.getHours(); - if (_12hour && hours > 13) { - hours = hours - 12; - } + // Update minutes when needed + if (minutes != currentTime.getMinutes()) { + minutes = currentTime.getMinutes(); + drawMin(minutes, settings.circle.colormin); + } - var meridian; + //Update seconds when needed + if (seconds != currentTime.getSeconds()) { + seconds = currentTime.getSeconds(); + drawSec(seconds, settings.circle.colorsec); + } - if (typeof locale.meridian === "function") { - meridian = locale.meridian(new Date()); - } else { - meridian = ""; - } + //Write the time as configured in the settings + hours = currentTime.getHours(); + if (_12hour && hours > 13) { + hours = hours - 12; + } - var timestr; + var meridian; - if (meridian.length > 0 && _12hour) { - timestr = hours + " " + meridian; - } else { - timestr = hours; - } - g.setFontAlign(0, 0, 0); - g.setColor(settings.time.color); - g.setFont(settings.time.font, settings.time.size); - g.drawString(timestr, settings.time.center-40, settings.time.middle); + if (typeof locale.meridian === "function") { + meridian = locale.meridian(new Date()); + } else { + meridian = ""; + } - //Write the date as configured in the settings - g.setColor(settings.date.color); - g.setFont(settings.date.font, settings.date.size); - g.drawString(date, settings.date.center, settings.date.middle); - }; + var timestr; - //setInterval for HR visualisation - const newBeats = function (hr) { - if (id != 0) { - changeInterval(id, 6e3 / hr.bpm); - } else { - id = setInterval(drawHR, 6e3 / hr.bpm); - } - }; + if (meridian.length > 0 && _12hour) { + timestr = hours + " " + meridian; + } else { + timestr = hours; + } + g.setFontAlign(0, 0, 0); + g.setColor(settings.time.color); + g.setFont(settings.time.font, settings.time.size); + g.drawString(timestr, settings.time.center-40, settings.time.middle); - //visualize HR with circles pulsating - const drawHR = function () { - if (grow && size < settings.hr.size) { - size++; - } + //Write the date as configured in the settings + g.setColor(settings.date.color); + g.setFont(settings.date.font, settings.date.size); + g.drawString(date, settings.date.center, settings.date.middle); +}; - if (!grow && size > 3) { - size--; - } +//setInterval for HR visualisation +const newBeats = function (hr) { + if (id != 0) { + changeInterval(id, 6e3 / hr.bpm); + } else { + id = setInterval(drawHR, 6e3 / hr.bpm); + } +}; - if (size == settings.hr.size || size == 3) { - grow = !grow; - } +//visualize HR with circles pulsating +const drawHR = function () { + if (grow && size < settings.hr.size) { + size++; + } - if (grow) { - color = settings.hr.color; - g.setColor(color); - g.fillCircle(settings.hr.x, settings.hr.y, size); - } else { - color = "#000000"; - g.setColor(color); - g.drawCircle(settings.hr.x, settings.hr.y, size); - } - }; + if (!grow && size > 3) { + size--; + } - // clean app screen - g.clear(); - Bangle.loadWidgets(); - Bangle.drawWidgets(); + if (size == settings.hr.size || size == 3) { + grow = !grow; + } - //manage when things should be enabled and not - Bangle.on('lcdPower', function (on) { - if (on) { - Bangle.setHRMPower(1); - } else { - Bangle.setHRMPower(0); - } - }); + if (grow) { + color = settings.hr.color; + g.setColor(color); + g.fillCircle(settings.hr.x, settings.hr.y, size); + } else { + color = "#000000"; + g.setColor(color); + g.drawCircle(settings.hr.x, settings.hr.y, size); + } +}; - // refesh every second - setInterval(drawClock, 1E3); +// clean app screen +g.clear(); +Bangle.loadWidgets(); +Bangle.drawWidgets(); - //start HR monitor and update frequency of update - Bangle.setHRMPower(1); - Bangle.on('HRM', function (d) { - newBeats(d); - }); +//manage when things should be enabled and not +Bangle.on('lcdPower', function (on) { + if (on) { + Bangle.setHRMPower(1); + } else { + Bangle.setHRMPower(0); + } +}); - // draw now - drawClock(); +// refesh every second +setInterval(drawClock, 1E3); - // Show launcher when middle button pressed - setWatch(Bangle.showLauncher, BTN2, { repeat: false, edge: "falling" }); +//start HR monitor and update frequency of update +Bangle.setHRMPower(1); +Bangle.on('HRM', function (d) { + newBeats(d); +}); -} \ No newline at end of file +// draw now +drawClock(); + +// Show launcher when button pressed +Bangle.setUI("clock"); diff --git a/apps/files/ChangeLog b/apps/files/ChangeLog index b4037a733..1908f7e5c 100644 --- a/apps/files/ChangeLog +++ b/apps/files/ChangeLog @@ -2,4 +2,5 @@ 0.03: Add support for data files 0.04: Add functionality to sort apps manually or alphabetically ascending/descending. 0.05: Tweaks to help with memory usage -0.06: Reduce memory usage \ No newline at end of file +0.06: Reduce memory usage +0.07: Allow negative numbers when manual-sorting \ No newline at end of file diff --git a/apps/files/files.js b/apps/files/files.js index 9e6c97702..9ac6ebb35 100644 --- a/apps/files/files.js +++ b/apps/files/files.js @@ -180,7 +180,7 @@ function showSortAppsManually() { appList.reduce((menu, app) => { menu[app.name] = { value: app.sortorder || 0, - min: 0, + min: -appList.length, max: appList.length, step: 1, onchange: val => setSortorder(app, val) diff --git a/apps/gallifr/ChangeLog b/apps/gallifr/ChangeLog index c785cbd67..0e1f45042 100644 --- a/apps/gallifr/ChangeLog +++ b/apps/gallifr/ChangeLog @@ -1 +1,2 @@ 0.01: First released version +0.02: Changed setWatch to Bangle.setUI diff --git a/apps/gallifr/app.js b/apps/gallifr/app.js index 281988ad7..d327bcdc1 100644 --- a/apps/gallifr/app.js +++ b/apps/gallifr/app.js @@ -243,5 +243,5 @@ startTimers(); Bangle.loadWidgets(); drawAll(); -// Show launcher when middle button pressed -setWatch(Bangle.showLauncher, BTN2, { repeat: false, edge: "falling" }); +// Show launcher when button pressed +Bangle.setUI("clock"); diff --git a/apps/gbridge/ChangeLog b/apps/gbridge/ChangeLog index f4837d60a..6e1c5b468 100644 --- a/apps/gbridge/ChangeLog +++ b/apps/gbridge/ChangeLog @@ -22,3 +22,4 @@ 0.20: Reduce memory usage 0.21: Fix HRM setting 0.22: Respect Quiet Mode +0.23: Allow notification dismiss to remove from phone too diff --git a/apps/gbridge/widget.js b/apps/gbridge/widget.js index b4ce71907..2c61e61fa 100644 --- a/apps/gbridge/widget.js +++ b/apps/gbridge/widget.js @@ -1,4 +1,7 @@ (() => { + // Current shown notification, saved for dismissing. + var currentNot = null; + // Music handling const state = { music: "stop", @@ -151,16 +154,23 @@ global.GB = (event) => { switch (event.t) { case "notify": - case "notify-": - if (event.t === "notify") { - require("notify").show(prettifyNotificationEvent(event)); - if (!(require('Storage').readJSON('setting.json',1)||{}).quiet) { - Bangle.buzz(); - } - } else { // notify- - require("notify").hide(event); + currentNot = prettifyNotificationEvent(event); + currentNot.onHide = function() { + // when notification hidden, remove from phone + gbSend({ t:"notify", n:"DISMISS", id:currentNot.id }); + }; + require("notify").show(currentNot); + if (!(require('Storage').readJSON('setting.json',1)||{}).quiet) { + Bangle.buzz(); } break; + case "notify-": + currentNot.t = "notify"; + currentNot.n = "DISMISS"; + gbSend(currentNot); + currentNot = null; + require("notify").hide(event); + break; case "musicinfo": state.musicInfo = event; updateMusic({on: false}); diff --git a/apps/geissclk/ChangeLog b/apps/geissclk/ChangeLog index bd718a5b1..7458fadee 100644 --- a/apps/geissclk/ChangeLog +++ b/apps/geissclk/ChangeLog @@ -1,2 +1,3 @@ 0.01: New App! 0.02: BTN2->launcher, use smaller text to allow "20:00" to fit on screen +0.03: Changed setWatch to Bangle.setUI diff --git a/apps/geissclk/clock.js b/apps/geissclk/clock.js index 7d63b815e..f14ea5f39 100644 --- a/apps/geissclk/clock.js +++ b/apps/geissclk/clock.js @@ -148,4 +148,5 @@ Bangle.drawWidgets(); iterate(); animInterval = setInterval(iterate, 50); -setWatch(Bangle.showLauncher, BTN2, {repeat:false,edge:"falling"}); +// Show launcher when button pressed +Bangle.setUI("clock"); diff --git a/apps/gpsrec/ChangeLog b/apps/gpsrec/ChangeLog index 412dbe9d3..289fb38d6 100644 --- a/apps/gpsrec/ChangeLog +++ b/apps/gpsrec/ChangeLog @@ -21,3 +21,6 @@ 0.17: Disable recording if storage is full (fix #574) 0.18: Period counter now uses GPS time rather than counting packets (allows use with GPS Setup) 0.19: Fix memory usage issues inside track viewer app +0.20: Add documentation to explain time needed for getting a time fix +0.21: Fix issue where a period of 1s recorded every 2s, 5s every 6s, and so on +0.22: Ensure Bangle.setGPSPower uses 'gpsrec' as a tag diff --git a/apps/gpsrec/README.md b/apps/gpsrec/README.md new file mode 100644 index 000000000..72f744452 --- /dev/null +++ b/apps/gpsrec/README.md @@ -0,0 +1,10 @@ +# GPS Recorder + +![icon](app.png) + +This app allows you to record a GPS track. It can run in background. The data can later be exported as KML or GPX files via the BangleJS app store. + +## Tips + +When you turn on recording, a widget badge that looks like a satellite will appear immediately at the top of the screen. However, the recording does not begin immediately. It usually takes several minutes for the watch to get a [GPS fix](https://en.wikipedia.org/wiki/Time_to_first_fix). You will notice a blinking question mark at the lower left of the badge indicating currently getting a fix. The badge will change when a GPS fix is achieved and that is when the app actually starts writing data to the log file. You can [upload assistant files](https://banglejs.com/apps/#assisted%20gps%20update) to speed up the time spent on getting a GPS fix. + diff --git a/apps/gpsrec/interface.html b/apps/gpsrec/interface.html index 11b53164f..4c7270f0a 100644 --- a/apps/gpsrec/interface.html +++ b/apps/gpsrec/interface.html @@ -95,6 +95,7 @@ function getTrackList() { Util.showModal("Loading Tracks..."); domTracks.innerHTML = ""; Puck.write(`\x10(function() { + Bluetooth.println(""); for (var n=0;n<36;n++) { var f = require("Storage").open(".gpsrc"+n.toString(36),"r"); var l = f.readLine(); diff --git a/apps/gpsrec/widget.js b/apps/gpsrec/widget.js index 8e4286db5..3d22373ec 100644 --- a/apps/gpsrec/widget.js +++ b/apps/gpsrec/widget.js @@ -29,7 +29,7 @@ var period = 1000000; if (lastFixTime!==undefined) period = fix.time.getTime() - lastFixTime; - if (period > settings.period*1000) { + if (period+500 > settings.period*1000) { // round up lastFixTime = fix.time.getTime(); try { if (gpsTrack) gpsTrack.write([ @@ -69,7 +69,7 @@ gpsTrack = undefined; } if (gOn != gpsOn) { - Bangle.setGPSPower(gOn); + Bangle.setGPSPower(gOn,"gpsrec"); gpsOn = gOn; } } diff --git a/apps/gpsservice/README.md b/apps/gpsservice/README.md index b1e3e60d4..061f3ba3b 100644 --- a/apps/gpsservice/README.md +++ b/apps/gpsservice/README.md @@ -2,6 +2,9 @@ A configurable, low power GPS widget that runs in the background. +NOTE: This app has been superceded by [gpssetup](https://github.com/espruino/BangleApps/blob/master/apps/gpssetup/README.md) + + ## Goals To develop a low power GPS widget that runs in the background and to diff --git a/apps/hcclock/ChangeLog b/apps/hcclock/ChangeLog new file mode 100644 index 000000000..0ca30d066 --- /dev/null +++ b/apps/hcclock/ChangeLog @@ -0,0 +1,2 @@ +0.01: base code + diff --git a/apps/hcclock/README.md b/apps/hcclock/README.md new file mode 100644 index 000000000..328f1fe03 --- /dev/null +++ b/apps/hcclock/README.md @@ -0,0 +1,13 @@ +# Hi-Contrast Clock + +A High-contrast, black-on-white or white-on-black clock displaying huge pixel digits. It is purposed for being both elegant and readable in high luminosity environments. The goal is to keep the clock as simple and efficient as possible. + +## Usage + +* BTN 1 switches between the two modes : black-on-white or white-on-black +* That's it! + +## Issues and Requests + +If you have issues, feel free to contact me at https://github.com/peeweek/ + diff --git a/apps/hcclock/hcclock-icon.js b/apps/hcclock/hcclock-icon.js new file mode 100644 index 000000000..2486c6500 --- /dev/null +++ b/apps/hcclock/hcclock-icon.js @@ -0,0 +1 @@ +E.toArrayBuffer(atob("MDAB////////////////////////////////////////////////////////////////////////////////4AABgAAH4AABgAAH///5n//n///5n//n4AABn//n4AABn//n5///n//n5///n//n4AABgAAH4AABgAAH/////////////////////////015urF//3d+vZt//1V5uNV/////////////////5//5gAAH5//5gAAH5//5n//n5//5n//n4AABgAAH4AABgAAH///5n//n///5n//n///5gAAH///5gAAH////////////////////////////////////////////////////////////////////////////////")) diff --git a/apps/hcclock/hcclock-icon.png b/apps/hcclock/hcclock-icon.png new file mode 100644 index 000000000..5d5506249 Binary files /dev/null and b/apps/hcclock/hcclock-icon.png differ diff --git a/apps/hcclock/hcclock.app.js b/apps/hcclock/hcclock.app.js new file mode 100644 index 000000000..98abbc6f3 --- /dev/null +++ b/apps/hcclock/hcclock.app.js @@ -0,0 +1,210 @@ + +////////////////////////////////////////////////////// +// Numbers Rect order (left, top, right, bottom) +// Each number defines a set of rects to draw + +const numbers = +[ + [// Zero + [0, 0, 1, 0.2], + [0, 0.8, 1, 1], + [0, 0, 0.1, 1], + [0.9, 0, 1, 1] + ], + [// One + [0.7, 0, 1, 0.2], + [0.9, 0, 1, 1] + ], + [// Two + [0, 0, 1, 0.2], + [0, 0.4, 1, 0.6], + [0, 0.8, 1, 1], + [0, 0.4, 0.1, 1], + [0.9, 0, 1, 0.6] + ], + [// Three + [0, 0, 1, 0.2], + [0.5, 0.4, 1, 0.6], + [0, 0.8, 1, 1], + [0.9, 0, 1, 1] + ], + [// Four + [0, 0.4, 1, 0.6], + [0, 0, 0.1, 0.6], + [0.9, 0, 1, 1] + ], + [// Five + [0, 0, 1, 0.2], + [0, 0.4, 1, 0.6], + [0, 0.8, 1, 1], + [0, 0, 0.1, 0.6], + [0.9, 0.4, 1, 1] + ], + [// Six + [0, 0, 1, 0.2], + [0, 0.4, 1, 0.6], + [0, 0.8, 1, 1], + [0, 0, 0.1, 1.0], + [0.9, 0.4, 1, 1] + ], + [// Seven + [0.0, 0, 1, 0.2], + [0.9, 0, 1, 1] + ], + [// Eight + [0, 0, 1, 0.2], + [0, 0.4, 1, 0.6], + [0, 0.8, 1, 1], + [0, 0, 0.1, 1], + [0.9, 0, 1, 1] + ], + [// Nine + [0, 0, 1, 0.2], + [0, 0.4, 1, 0.6], + [0, 0.8, 1, 1], + [0, 0, 0.1, 0.6], + [0.9, 0, 1, 1] + ] +]; + +const months = [ "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" ]; + +const interval = 1000; // in ms +const top = 32; + +let ampm = (require("Storage").readJSON("setting.json",1)||{})["12hour"]; + +let bg = 255; +let fg = 0; + +let mins = -1; +let hour = -1; +let day = -1; + +function redraw() { + mins = -1; + hour = -1; + day = -1; + refresh(); +} + +function refresh() { + g.setColor(bg,bg,bg); + g.fillRect(0,45,240,210); + Bangle.drawWidgets(); + updateTime(); +} + +function updateTime() +{ + let now = new Date(); + let m = now.getMinutes(); + let h = now.getHours(); + let mo = now.getMonth(); + let y = now.getFullYear(); + let d = now.getDate(); + + if(h != hour) + { + hour = h; + g.setColor(bg,bg,bg); + g.fillRect(0,60,240,110); + g.setColor(fg,fg,fg); + if(ampm) + h = h%12; + drawDigits(60, h); + } + if(m != mins) + { + mins = m; + g.setColor(bg,bg,bg); + g.fillRect(0,145,240,195); + g.setColor(fg,fg,fg); + drawDigits(145, mins); + } + if(d != day) + { + day = d; + g.setFont("6x8", 2); + g.setFontAlign(0, -1, 0); + g.drawString(fmtDate(d,mo,y,hour), 120, 120); + } +} + +function drawDigits(x, value) +{ + if(!Bangle.isLCDOn()) // No need to draw when LCD Off + return; + + drawChar(Math.floor(value/10), 15, x, 115, x+50); + if(value%10 == 1) + drawChar(value%10, 55, x, 155, x+50); + else + drawChar(value%10, 125, x, 225, x+50); +} + +function drawChar(i, xMin, yMin, xMax, yMax) +{ + numbers[i].forEach(rect => { + r = place(rect, xMin, yMin, xMax, yMax); + g.setColor(fg,fg,fg); + g.fillRect(r[0], r[1], r[2], r[3]); + }); +} + +function place(array, xMin, yMin, xMax, yMax) +{ + return [ + lerp(xMin,xMax,array[0]), + lerp(yMin,yMax,array[1]), + lerp(xMin,xMax,array[2]), + lerp(yMin,yMax,array[3]) + ]; +} + +function lerp(a,b,t) +{ + return a + t*(b-a); +} + +function fmtDate(day,month,year,hour) +{ + if(ampm) + { + let ap = "(AM)"; + if(hour == 0 || hour > 12) + ap = "(PM)"; + return months[month] + " " + day + " " + year + " "+ ap; + } + else + return months[month] + ". " + day + " " + year; +} + +// Handles Flipping colors, then refreshes the UI +function flipColors() +{ + let t = bg; + bg = fg; + fg = t; + redraw(); +} + +////////////////////////////////////////// +// +// MAIN FUNCTION() +// + +// Initialize +g.clear(); +Bangle.loadWidgets(); +redraw(); + +// Define Refresh Interval +setInterval(updateTime, interval); + +// Handle Button Press +setWatch(flipColors, BTN1, true); +setWatch(Bangle.showLauncher, BTN2, false); + +// Handle redraw on LCD on / fullscreen notifications dismissed +Bangle.on('lcdPower', (on) => { if(on) redraw(); }); diff --git a/apps/hrm/ChangeLog b/apps/hrm/ChangeLog index 6cedf8f1b..d27886b15 100644 --- a/apps/hrm/ChangeLog +++ b/apps/hrm/ChangeLog @@ -2,3 +2,4 @@ 0.02: Use HRM data and calculations from Bangle.js (don't access hardware directly) 0.03: Fix timing issues, and use 1/2 scale to keep graph on screen 0.04: Update for new firmwares that have a 'HRM-raw' event +0.05: Tweaks for 'HRM-raw' handling diff --git a/apps/hrm/heartrate.js b/apps/hrm/heartrate.js index 09e8a826e..a6b8e791a 100644 --- a/apps/hrm/heartrate.js +++ b/apps/hrm/heartrate.js @@ -3,6 +3,8 @@ Bangle.setLCDTimeout(0); Bangle.setHRMPower(1); var hrmInfo, hrmOffset = 0; var hrmInterval; +var btm = g.getHeight()-1; + function onHRM(h) { if (counter!==undefined) { // the first time we're called remove @@ -26,7 +28,7 @@ function onHRM(h) { var px = g.getWidth()/2; g.setFontAlign(0,0); - g.clearRect(0,24,239,90); + g.clearRect(0,24,239,80); g.setFont("6x8").drawString("Confidence "+hrmInfo.confidence+"%", px, 75); var str = hrmInfo.bpm; g.setFontVector(40).drawString(str,px,45); @@ -38,17 +40,21 @@ Bangle.on('HRM', onHRM); /* On newer (2v10) firmwares we can subscribe to get HRM events as they happen */ Bangle.on('HRM-raw', function(v) { - var a = v.raw; hrmOffset++; if (hrmOffset>g.getWidth()) { hrmOffset=0; - g.clearRect(0,90,239,239); + g.clearRect(0,80,239,239); g.moveTo(-100,0); } - y = E.clip(170 - (v.raw*2),100,230); - g.setColor(1,1,1); - g.lineTo(hrmOffset, y); + y = E.clip(btm-v.filt/4,btm-10,btm); + g.setColor(1,0,0).fillRect(hrmOffset,btm, hrmOffset, y); + y = E.clip(170 - (v.raw/2),80,btm); + g.setColor(g.theme.fg).lineTo(hrmOffset, y); + if (counter !==undefined) { + counter = undefined; + g.clear(); + } }); // It takes 5 secs for us to get the first HRM event @@ -80,7 +86,6 @@ function readHRM() { var a = hrmInfo.raw[hrmOffset]; hrmOffset++; y = E.clip(170 - (a*2),100,230); - g.setColor(1,1,1); - g.lineTo(hrmOffset, y); + g.setColor(g.theme.fg).lineTo(hrmOffset, y); } } diff --git a/apps/imgclock/ChangeLog b/apps/imgclock/ChangeLog index 20906fb87..01a6a4248 100644 --- a/apps/imgclock/ChangeLog +++ b/apps/imgclock/ChangeLog @@ -5,4 +5,5 @@ Scaling for background images <240px wide 0.05: Fix memory/interval leak when LCD turns on 0.06: Support 12 hour time -0.07: Don't cut off wide date formats \ No newline at end of file +0.07: Don't cut off wide date formats +0.08: Use Bangle.setUI for button/launcher handling diff --git a/apps/imgclock/app.js b/apps/imgclock/app.js index 751647a69..0e4435638 100644 --- a/apps/imgclock/app.js +++ b/apps/imgclock/app.js @@ -84,5 +84,5 @@ Bangle.on('lcdPower',on=>{ draw(); } }); -// Show launcher when middle button pressed -setWatch(Bangle.showLauncher, BTN2, { repeat: false, edge: "falling" }); +// Show launcher when button pressed +Bangle.setUI("clock"); diff --git a/apps/impwclock/ChangeLog b/apps/impwclock/ChangeLog index c6974d37c..0592d4d04 100644 --- a/apps/impwclock/ChangeLog +++ b/apps/impwclock/ChangeLog @@ -1,2 +1,3 @@ 0.01: New App! 0.02: Stopped watchface from flashing every interval +0.03: Move to Bangle.setUI to launcher support diff --git a/apps/impwclock/clock-impword.js b/apps/impwclock/clock-impword.js index 94b92b778..5492eac15 100644 --- a/apps/impwclock/clock-impword.js +++ b/apps/impwclock/clock-impword.js @@ -47,10 +47,9 @@ const activeColorNight = 0xF800 /*red*/ ; const activeColorDay = 0xFFFF /* white */; var hidxPrev; +var showDigitalTime = false; function drawWordClock() { - - // get time var t = new Date(); var h = t.getHours(); @@ -141,7 +140,7 @@ function drawWordClock() { // Display digital time while button 1 is pressed g.clearRect(0, 215, 240, 240); - if (BTN1.read()){ + if (showDigitalTime){ g.setColor(activeColor); g.drawString(time, 120, 215); } @@ -158,8 +157,20 @@ Bangle.drawWidgets(); setInterval(drawWordClock, 1E4); drawWordClock(); -// Show digital time while top button is pressed -setWatch(drawWordClock, BTN1, {repeat:true,edge:"both"}); +// Show digital time while top button is pressed (if we have physical buttons) +if (global.BTN3) setWatch(function() { + showDigitalTime = BTN1.read(); + drawWordClock(); +}, BTN1, {repeat:true,edge:"both"}); -// Show launcher when middle button pressed -setWatch(Bangle.showLauncher, BTN2, {repeat:false,edge:"falling"}); +// If LCD pressed (on Bangle.js 2) draw digital time +Bangle.on('drag',e=>{ + var pressed = e.b!=0; + if (pressed!=showDigitalTime) { + showDigitalTime = pressed; + drawWordClock(); + } +}); + +// Show launcher when button pressed +Bangle.setUI("clock"); diff --git a/apps/isoclock/ChangeLog b/apps/isoclock/ChangeLog index cd3ceea5c..809091ce4 100644 --- a/apps/isoclock/ChangeLog +++ b/apps/isoclock/ChangeLog @@ -1 +1,2 @@ 0.01: Created app based on digiclock with some small tweaks. +0.02: Swap to Bangle.setUI for launcher/buttons diff --git a/apps/isoclock/isoclock.js b/apps/isoclock/isoclock.js index 5f63a1248..59f28e66e 100644 --- a/apps/isoclock/isoclock.js +++ b/apps/isoclock/isoclock.js @@ -1,82 +1,82 @@ //load fonts require("Font7x11Numeric7Seg").add(Graphics); -require("FontHaxorNarrow7x17").add(Graphics); +require("FontHaxorNarrow7x17").add(Graphics); //screen position -const X = 170; -const Y = 140; +const X = 170; +const Y = 140; function draw() { // Date Variables - var date = new Date(); - var h = date.getHours(); - var m = date.getMinutes(); - var day = date.getDay(); + var date = new Date(); + var h = date.getHours(); + var m = date.getMinutes(); + var day = date.getDay(); var month = date.getMonth()+1; - var dateNum = date.getDate(); - var year = date.getFullYear(); - var half = "AM"; - var time = ("0" + h).substr(-2) + ":" + ("0" + m).substr(-2); - - //convert day into string + var dateNum = date.getDate(); + var year = date.getFullYear(); + var half = "AM"; + var time = ("0" + h).substr(-2) + ":" + ("0" + m).substr(-2); + + //convert day into string switch (day) { case 0: - day = "Sunday"; - break; - + day = "Sunday"; + break; + case 1: - day = "Monday"; - break; - + day = "Monday"; + break; + case 2: - day = "Tuesday"; - break; - + day = "Tuesday"; + break; + case 3: - day = "Wednesday"; - break; - + day = "Wednesday"; + break; + case 4: - day = "Thursday"; - break; - + day = "Thursday"; + break; + case 5: - day = "Friday"; - break; - + day = "Friday"; + break; + case 6: - day = "Saturday"; - break; - + day = "Saturday"; + break; + default: - day = "ERROR"; - break; + day = "ERROR"; + break; } - + if (h > 12) { - half = "PM"; - h = h - 12; + half = "PM"; + h = h - 12; } //reset graphics - g.reset(); + g.reset(); //draw the time g.setFont("7x11Numeric7Seg", 5); g.setFontAlign(1,1); g.drawString(time, X+10, Y, true /*clear background*/); - g.setFont("7x11Numeric7Seg", 3); - g.drawString(("0"+date.getSeconds()).substr(-2), X+55, Y, true /*clear background*/); + g.setFont("7x11Numeric7Seg", 3); + g.drawString(("0"+date.getSeconds()).substr(-2), X+55, Y, true /*clear background*/); g.setFontAlign(0,1); g.setFont("HaxorNarrow7x17", 3); g.drawString(day, X-60, Y+53, true); - g.drawString(year+"-"+month+"-"+dateNum, X-55, Y-55, true); - - + g.drawString(year+"-"+month+"-"+dateNum, X-55, Y-55, true); + + } //clear screen at startup -g.clear(); +g.clear(); //draw immediatly -draw(); +draw(); var secondInterval = setInterval(draw, 1000); // Stop updates when LCD is off, restart when on @@ -92,4 +92,5 @@ Bangle.on('lcdPower',on=>{ Bangle.loadWidgets(); Bangle.drawWidgets(); -setWatch(Bangle.showLauncher, BTN2, {repeat : false, edge: "falling"}); +// Show launcher when button pressed +Bangle.setUI("clock"); diff --git a/apps/jbm8b_IT/ChangeLog b/apps/jbm8b_IT/ChangeLog new file mode 100644 index 000000000..b7b783924 --- /dev/null +++ b/apps/jbm8b_IT/ChangeLog @@ -0,0 +1 @@ +0.01: Cloning Magic 8 Ball and make it speak italian \ No newline at end of file diff --git a/apps/jbm8b_IT/app-icon.js b/apps/jbm8b_IT/app-icon.js new file mode 100644 index 000000000..09bf032a6 --- /dev/null +++ b/apps/jbm8b_IT/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwhBC/AGMrq2B1gAEwNWlYthq2s64AKGYIydFpoAEGLUrFqIADqxcXFqhiDFymBFy7GCF1owTRjCSVlYudeiGsF7/XlaNqSKBeP1mBwJxQMBReO1gaEleBMDBLN1hAC1hhBAoIwNCwQAGlZINqxvFGAIXOSBAXQN4hPBC5yQIVBxfBCAgvQSBC+NFAYRDMwJHOF654DqxkBYooALF6+sbIhkEF8Z3CRIWBR6AvXFAzvQF6wnIYQJgNd5AWNdoLoGBBAvPO5pfYH4IvUUwS/GVBzXBYCpHCq2s1mBDwKOWDwRgNPAwVVMCRLCwIABCZ6OJJSAATLxZgRACJeLAAMrFz9WFxiRgRpoADwIub1guQGDmsXhqSfRiL0G1jqkMRYxRwKLUGK2sFryVEq2B1gAEwNWFkIA/AH4A/AH4AQ")) \ No newline at end of file diff --git a/apps/jbm8b_IT/app.js b/apps/jbm8b_IT/app.js new file mode 100644 index 000000000..13ab3d39d --- /dev/null +++ b/apps/jbm8b_IT/app.js @@ -0,0 +1,79 @@ +const affirmative = [ + 'È certo.', + 'È decisamente\ncosì.', + 'Senza alcun\ndubbio.', + 'Sì,\nsenza dubbio.', + 'Ci puoi\ncontare.', + 'Da quanto\nvedo,\nsì.', + 'Molto\nprobabilmente.', + 'Le prospettive\nsono buone.', + 'Sì.', + 'I segni\nindicano\ndi sì.' +]; +const nonCommittal = [ + 'È difficile\ndirlo,\nprova di nuovo.', + 'Rifai la domanda\npiù tardi.', + 'Meglio non\nrisponderti\nadesso.', + 'Non posso\npredirlo ora.', + 'Concentrati e\nrifai la\ndomanda.' +]; +const negative = [ + 'Non ci\ncontare.', + 'La mia\nrisposta\nè no.', + 'Le mie\nfonti dicono\ndi no.', + 'Le prospettive\nnon sono\nbuone.', + 'È molto\ndubbio.' +]; +const title = 'Magic 8 Ball'; + +const answers = [affirmative, nonCommittal, negative]; + +function getRandomArbitrary(min, max) { + return Math.random() * (max - min) + min; +} + +function predict() { + // affirmative, negative or non-committal + let max = answers.length; + const a = Math.floor(getRandomArbitrary(0, max)); + // sets max compared to answer category + max = answers[a].length; + const b = Math.floor(getRandomArbitrary(0, max)); + // get the answer + const response = answers[a][b]; + return response; +} + +function draw(msg) { + // console.log(msg); + g.clear(); + E.showMessage(msg, title); +} + +function reply(button) { + const theButton = (typeof button === 'undefined' || isNaN(button)) ? 1 : button; + const timer = Math.floor(getRandomArbitrary(0, theButton) * 1000); + // Thinking... + draw('...'); + setTimeout('draw(predict());', timer); +} + +function ask() { + draw('Ponimi una\ndomanda\nSì/No e\ntocca lo\nschermo'); +} + +g.clear(); + +Bangle.loadWidgets(); +Bangle.drawWidgets(); +ask(); + +// Event Handlers + +Bangle.on('touch', (button) => reply(button)); + +setWatch(ask, BTN1, { repeat: true, edge: "falling" }); +setWatch(reply, BTN3, { repeat: true, edge: "falling" }); + +// Back to launcher +setWatch(Bangle.showLauncher, BTN2, { repeat: false, edge: "falling" }); \ No newline at end of file diff --git a/apps/jbm8b_IT/app.png b/apps/jbm8b_IT/app.png new file mode 100644 index 000000000..24c3013de Binary files /dev/null and b/apps/jbm8b_IT/app.png differ diff --git a/apps/kitchen/ChangeLog b/apps/kitchen/ChangeLog index 71548ec30..1df5d867f 100644 --- a/apps/kitchen/ChangeLog +++ b/apps/kitchen/ChangeLog @@ -8,3 +8,5 @@ 0.08: Improved error handling for missing firmware features, added template app.kit.js 0.09: Added heart rate monitor app 0.10: Converted Stepo to use direct screen writes, added a Trip Counter feature to stepo +0.11: Detect when waypoints.json is not present, error E-WPT +0.12: Added stepo2 as a replacement for stepo and digi diff --git a/apps/kitchen/README.md b/apps/kitchen/README.md index a829a39b0..2a1b148fd 100644 --- a/apps/kitchen/README.md +++ b/apps/kitchen/README.md @@ -41,9 +41,25 @@ The following buttons depend on which face is currently in use - Waypointer : select next waypoint +## Stepo2 +![](screenshot_stepo2.jpg) + +- Requires one of the pedominter widgets to be installed +- Stepo2 is a combination of Stepo and Digi and now replaces them +- Displays the time in large font +- Display current step count in a doughnut gauge +- The gauge show percentage of steps out of a goal of 10000 steps +- When the battery is less than 25% the doughnut turns red +- Use BTN1 to switch to the Trip Counter, use long press to reset Trip Counter +- Use BTN1 to cycle through the displays of Day,Date, Trip Counter, Battery %, Mem % and Firmware +- Use BTN3 to switch to the next app + + + ## Stepo ![](screenshot_stepo.jpg) +- now replaced by Stepo2 but still available if you install manually - Requires one of the pedominter widgets to be installed - Displays the time in large font - Display current step count in a doughnut gauge @@ -62,11 +78,13 @@ The following buttons depend on which face is currently in use ## Digi ![](screenshot_digi.jpg) +- now replaced by Stepo2 but still available if you install manually - Displays the time in large font - Display day and date - Use BTN1 to switch between display of battery and memory %. - Use BTN3 to switch to the next app. + ## Swatch ![](screenshot_swatch.jpg) - A simple stopwatch @@ -76,6 +94,9 @@ The following buttons depend on which face is currently in use ## Heart ![](screenshot_heart.jpg) - A simple heart rate monitor, at present the app is just showing the raw value from HRM.bpm +- This is an experimental app and not installed by default. The + heart.kit.js file can be uploaded via the Espruino IDE if you want + to try it out. Then reload the App. - BTN1, long press, turn heart rate monitor on / off ## Waypointer @@ -226,12 +247,12 @@ I have settled on directly writing to the screen using the Graphics object (g.) for the compass App. This creates a bit of flicker when the arrow moves but is more reliable than using the ArrayBuffer. -v0.09: Since adding the heart rate monitor I have noticed that I can -sometimes can a memory error when switch through the Apps back to the -Stepo App. I think this can be cured by statically allocating the -ArrayBuffer for stepo rather than using new everytime you switch back -into the stepo watch face. The problem is that the bangle memory -management / defragmentation is quite slow to run. +v0.09: Since adding the heart rate monitor I have sometimes observed +a low memory error when switching through the Apps back to the Stepo +App. I think this can be cured by statically allocating the +ArrayBuffer for stepo rather than using 'new' everytime you switch +back into the stepo watch face. The problem is that the bangle +memory management / defragmentation is quite slow to run. v0.10: Revisited having a display buffer for the stepo part of the App. Now use direct screen writing as it means less memory allocation and @@ -241,16 +262,21 @@ reduces chance of getting a memory error on switching watch faces. The following error codes will be displayed if one of the dependancies is not met. -* E-STEPS - no pedomintor widget has been installed, please install the widpedom or the activepedom widgets -* E-CALIB - no compass calibration data was found, see 'Compass Calibration' -* E-FW - require firmware 2v08.187 or later to detect gps and compass power status +* E-STEPS - no pedomintor widget has been installed, please install + the widpedom or the activepedom widgets +* E-CALIB - no compass calibration data was found, see 'Compass + Calibration' +* E-FW - require firmware 2v08.187 or later to detect gps and compass + power status +* E-WPT - missing waypoints.json file ### Issues / Future enhancements +* Add a settings app so that 'Kitchen' based clocks can be enabled/disabled * GPS time display shows GMT and not BST, needs localising -* Occassional buzzing after 2-3 days of use, seems to disappear after - a reset to the launcher menu. Needs investigation * Automatically switch the GPS power setting from Super-E to PSMOO 10 seconds after the LCD goes off. At present I just rely on using the GPSSetup app and set the GPS power mode that I want. * Add a small graph to the heart rate monitor app +* Add a facility to call the Arrow calibration process +* Maybe create waypoints.json file if missing diff --git a/apps/kitchen/annex.js b/apps/kitchen/annex.js new file mode 100644 index 000000000..d789f5d0c --- /dev/null +++ b/apps/kitchen/annex.js @@ -0,0 +1,29 @@ +// annexed code that might be worth keeping + +/***************************************************************************** + +Screen Buffer Object that can be shared between faces + +Making into a Class like this means we allocate the memory once +and avoid fragmenting the memory when we switch in and out of faces + +******************************************************************************/ + +function BUF() { + this.pal4color = new Uint16Array([0x0000,0xFFFF,0x7BEF,0xAFE5],0,2); // b,w,grey,greenyellow + this.pal4red = new Uint16Array([0x0000,0xFFFF,0xF800,0xAFE5],0,2); // b,w,red,greenyellow + this.buf = Graphics.createArrayBuffer(120,120,2,{msb:true}); +} + +BUF.prototype.flip = function(x,y) { + g.drawImage({width:120,height:120,bpp:2, buffer:this.buf.buffer, palette:this.pal4color}, x, y); + this.buf.clear(); +} + +BUF.prototype.flip_red = function(x,y) { + g.drawImage({width:120,height:120,bpp:2, buffer:this.buf.buffer, palette:this.pal4red}, x, y); + this.buf.clear(); +} + +let bufObj = new BUF(); + diff --git a/apps/kitchen/compass.kit.js b/apps/kitchen/compass.kit.js index 530ba021c..b20cdce2c 100644 --- a/apps/kitchen/compass.kit.js +++ b/apps/kitchen/compass.kit.js @@ -17,13 +17,12 @@ } function init(gps,sw, hrm) { - showMem("compass init() START"); gpsObject = gps; intervalRefSec = undefined; bearing = 0; // always point north if GPS is off heading = 0; oldHeading = 0; - previous = {hding:"-", bs:"-", dst:"-", wp_name:"-", course:999}; + resetPrevious(); loc = require("locale"); CALIBDATA = require("Storage").readJSON("magnav.json",1)||null; getWaypoint(); @@ -34,12 +33,9 @@ */ if (!Bangle.isCompassOn()) Bangle.setCompassPower(1); gps.determineGPSState(); - - showMem("compass init() END"); } function freeResources() { - showMem("compass freeResources() START"); gpsObject = undefined; intervalRefSec = undefined; previous = undefined; @@ -50,7 +46,6 @@ CALIBDATA = undefined; wp = undefined; if (Bangle.isCompassOn !== undefined && Bangle.isCompassOn()) Bangle.setCompassPower(0); - showMem("compass freeResources() END"); } function startTimer() { @@ -67,12 +62,6 @@ if (Bangle.isCompassOn !== undefined && Bangle.isCompassOn()) Bangle.setCompassPower(0); } - function showMem(msg) { - var val = process.memory(); - var str = msg + " " + Math.round(val.usage*100/val.total) + "%"; - log_debug(str); - } - function onButtonShort(btn) { log_debug("onButtonShort()"); if (gpsObject.getState() !== gpsObject.GPS_RUNNING) return; @@ -206,12 +195,12 @@ drawCompass(dir, 0xFFC0); // yellow oldHeading = dir; } - + if (gpsObject.getState() === gpsObject.GPS_RUNNING) { drawGPSData(); } else { drawCompassHeading(); - } + } } // only used when acting as compass with GPS off diff --git a/apps/kitchen/kitchen.app.js b/apps/kitchen/kitchen.app.js index c3f7bd74d..a7196ba83 100644 --- a/apps/kitchen/kitchen.app.js +++ b/apps/kitchen/kitchen.app.js @@ -2,7 +2,7 @@ var FACES = []; var STOR = require("Storage"); STOR.list(/\.kit\.js$/).forEach(face=>FACES.push(eval(require("Storage").read(face)))); -var iface = STOR.list(/\.kit\.js$/).indexOf("stepo.kit.js"); +var iface = STOR.list(/\.kit\.js$/).indexOf("stepo2.kit.js"); var face = FACES[iface](); var firstPress var pressTimer; @@ -33,10 +33,10 @@ function nextFace(){ // when you feel the buzzer you know you have done a long press function longPressCheck() { Bangle.buzz(); - debug_log("long PressCheck() buzz"); + debug_log("BUZZ, long press"); if (pressTimer) { clearInterval(pressTimer); - debug_log("clear pressTimer 2"); + debug_log("CLEAR pressTimer 2"); pressTimer = undefined; } } @@ -48,10 +48,10 @@ function buttonPressed(btn) { } else { firstPress = getTime(); if (pressTimer) { - debug_log("clear pressTimer 1"); + debug_log("CLEAR pressTimer 1"); clearInterval(pressTimer); } - debug_log("set pressTimer 1"); + debug_log("SET pressTimer 1"); pressTimer = setInterval(longPressCheck, 1500); } } @@ -60,7 +60,7 @@ function buttonPressed(btn) { function buttonReleased(btn) { var dur = getTime() - firstPress; if (pressTimer) { - debug_log("clear pressTimer 3"); + debug_log("CLEAR pressTimer 3"); clearInterval(pressTimer); pressTimer = undefined; } @@ -256,7 +256,7 @@ GPS.prototype.processFix = function(fix) { this.gpsState = this.GPS_RUNNING; if (!this.last_fix.fix && !(require("Storage").readJSON("setting.json", 1) || {}).quiet) { Bangle.buzz(); // buzz on first position - debug_log("GPS fix buzz"); + debug_log("BUZZ - gps fix"); } this.last_fix = fix; } @@ -303,7 +303,7 @@ GPS.prototype.getWPdistance = function() { //log_debug(this.last_fix); //log_debug(this.wp_current); - if (this.wp_current.name === "NONE" || this.wp_current.lat === undefined || this.wp_current.lat === 0) + if (this.wp_current.name === "E-WPT" || this.wp_current.name === "NONE" || this.wp_current.lat === undefined || this.wp_current.lat === 0) return 0; else return this.calcDistance(this.last_fix, this.wp_current); @@ -313,14 +313,14 @@ GPS.prototype.getWPbearing = function() { //log_debug(this.last_fix); //log_debug(this.wp_current); - if (this.wp_current.name === "NONE" || this.wp_current.lat === undefined || this.wp_current.lat === 0) + if (this.wp_current.name === "E-WPT" || this.wp_current.name === "NONE" || this.wp_current.lat === undefined || this.wp_current.lat === 0) return 0; else return this.calcBearing(this.last_fix, this.wp_current); } GPS.prototype.loadFirstWaypoint = function() { - var waypoints = require("Storage").readJSON("waypoints.json")||[{name:"NONE"}]; + var waypoints = require("Storage").readJSON("waypoints.json")||[{name:"E-WPT"}]; this.wp_index = 0; this.wp_current = waypoints[this.wp_index]; log_debug(this.wp_current); @@ -332,7 +332,7 @@ GPS.prototype.getCurrentWaypoint = function() { } GPS.prototype.waypointHasLocation = function() { - if (this.wp_current.name === "NONE" || this.wp_current.lat === undefined || this.wp_current.lat === 0) + if (this.wp_current.name === "E-WPT" || this.wp_current.name === "NONE" || this.wp_current.lat === undefined || this.wp_current.lat === 0) return false; else return true; @@ -340,12 +340,12 @@ GPS.prototype.waypointHasLocation = function() { GPS.prototype.markWaypoint = function() { - if(this.wp_current.name === "NONE") + if(this.wp_current.name === "E-WPT" || this.wp_current.name === "NONE") return; log_debug("GPS::markWaypoint()"); - var waypoints = require("Storage").readJSON("waypoints.json")||[{name:"NONE"}]; + var waypoints = require("Storage").readJSON("waypoints.json")||[{name:"E-WPT"}]; this.wp_current = waypoints[this.wp_index]; if (this.waypointHasLocation()) { @@ -360,7 +360,7 @@ GPS.prototype.markWaypoint = function() { } GPS.prototype.nextWaypoint = function(inc) { - var waypoints = require("Storage").readJSON("waypoints.json")||[{name:"NONE"}]; + var waypoints = require("Storage").readJSON("waypoints.json")||[{name:"E-WPT"}]; this.wp_index+=inc; if (this.wp_index>=waypoints.length) this.wp_index=0; if (this.wp_index<0) this.wp_index = waypoints.length-1; @@ -731,14 +731,14 @@ function TRIP() { TRIP.prototype.resetTrip = function(steps) { this.tripStart = (0 + steps); - console.log("resetTrip starting=" + this.tripStart); + log_debug("resetTrip starting=" + this.tripStart); } TRIP.prototype.getTrip = function(steps) { let tripSteps = (0 + steps) - this.tripStart; - console.log("getTrip steps=" + steps); - console.log("getTrip tripStart=" + this.tripStart); - console.log("getTrip=" + tripSteps); + log_debug("getTrip steps=" + steps); + log_debug("getTrip tripStart=" + this.tripStart); + log_debug("getTrip=" + tripSteps); return tripSteps; } @@ -758,7 +758,6 @@ Debug Object ******************************************************************************/ -/* function DEBUG() { this.logfile = require("Storage").open("debug.log","a"); } @@ -770,7 +769,6 @@ DEBUG.prototype.log = function(msg) { } debugObj = new DEBUG(); -*/ function debug_log(m) { //debugObj.log(m); diff --git a/apps/kitchen/screenshot_stepo2.jpg b/apps/kitchen/screenshot_stepo2.jpg new file mode 100644 index 000000000..acff792b0 Binary files /dev/null and b/apps/kitchen/screenshot_stepo2.jpg differ diff --git a/apps/kitchen/stepo2.kit.js b/apps/kitchen/stepo2.kit.js new file mode 100644 index 000000000..1133314dd --- /dev/null +++ b/apps/kitchen/stepo2.kit.js @@ -0,0 +1,256 @@ +(() => { + function getFace(){ + var intervalRefSec; + var trip; + var prevSteps; + var prevTopText1; + var prevTopText2; + var prevBottomText; + var prevMins; + var infoMode; + + const INFO_DATE = 0; + const INFO_TRIP = 1; + const INFO_BATT = 2; + const INFO_MEM = 3; + const INFO_FW = 4; + + function init(g,sw,hrm,tr) { + trip = tr; + infoMode = INFO_DATE; + forceRedraw(); + } + + function freeResources() { + trip = undefined; + } + + function forceRedraw() { + prevStepsText = ''; + prevSteps = -1; + prevTopText1 = ''; + prevTopText2 = ''; + prevBottomText = ''; + prevMins = ''; + } + + function cycleInfoMode() { + switch(infoMode) { + case INFO_DATE: + infoMode = INFO_TRIP; + break; + case INFO_TRIP: + infoMode = INFO_BATT; + break; + case INFO_BATT: + infoMode = INFO_MEM + break; + case INFO_MEM: + infoMode = INFO_FW + break; + case INFO_FW: + default: + infoMode = INFO_DATE; + break; + } + } + + function onButtonShort(btn) { + cycleInfoMode(); + forceRedraw(); + draw(); + } + + function onButtonLong(btn) { + trip.resetTrip(getSteps()); + infoMode = INFO_TRIP; + forceRedraw(); + draw(); + } + + function radians(a) { + return a*Math.PI/180; + } + + function startTimer() { + draw(); + intervalRefSec = setInterval(draw, 5000); + } + + function stopTimer() { + if(intervalRefSec) {intervalRefSec=clearInterval(intervalRefSec);} + } + + function draw() { + var d = new Date(); + var da = d.toString().split(" "); + var hh = da[4].substr(0,2); + var mm = da[4].substr(3,2); + var day = da[0]; + var day_month = da[2] + " " + da[1]; + + g.setColor(1,1,1); // white + + if (prevMins != mm) { + prevMins = mm; + // hours and minutes + g.clearRect(0, 24, 149, 239); + g.setFontAlign(-1, -1); + g.setFont("Vector", 104); + g.drawString(hh, 20, 30, true); + g.drawString(mm, 20, 120, true); + } + + /* + * if our trip count is greater than todays steps then we have + * rolled over to the next day so we should reset the trip counter + */ + var steps = getSteps(); + if (trip.getTrip(steps) < 0) + trip.resetTrip(steps); + + drawTopText(day,day_month); + drawBottomText(); + drawSteps(); + } + + function drawTopText(dy, dm) { + var topText1 = ""; + var topText2 = ""; + + switch(infoMode) { + case INFO_DATE: + topText1 = dy.toUpperCase(); + topText2 = dm.toUpperCase(); + break; + case INFO_TRIP: + topText2 = "TRIP"; + break; + case INFO_BATT: + topText2 = "BATT"; + break; + case INFO_MEM: + topText2 = "MEM"; + break; + case INFO_FW: + topText2 = "F/W"; + break; + } + + if (prevTopText1 !== topText1 || prevTopText2 !== topText2) { + prevTopText1 = topText1; + prevTopText2 = topText2; + + // day, date + g.setFont("Vector", 24); + g.setFontAlign(0, -1); + g.clearRect(150, 30, 239, 75); + g.drawString(topText1, 195, 30, true); + g.drawString(topText2, 195, 55, true); + } + } + + function drawBottomText() { + var bottomText = ""; + var steps = getSteps(); + + switch(infoMode) { + case INFO_DATE: + bottomText = "" + steps; + break; + case INFO_TRIP: + bottomText = "" + trip.getTrip(steps); + break; + case INFO_BATT: + bottomText = "" + E.getBattery() + "%"; + break; + case INFO_MEM: + var val = process.memory(); + bottomText = "" + Math.round(val.usage*100/val.total) + "%"; + break; + case INFO_FW: + bottomText = process.env.VERSION; + break; + } + + if (prevBottomText !== bottomText) { + prevBottomText = bottomText; + g.clearRect(148, 190, 239, 239); + g.setColor(1,1,1); // white + g.setFont("Vector", 24); + g.setFontAlign(0, -1); + g.drawString(bottomText, 195, 190); + } + } + + function drawSteps() { + var i = 0; + var cx = 150 + 45; + var cy = 130; + var r = 34; + + var steps = getSteps(); + + if (trip.getTripState() == true) + steps = trip.getTrip(steps); + + if (prevSteps == steps) + return; + + prevSteps = steps; + + var percent = steps / 10000; + + if (percent > 1) percent = 1; + + var startrot = 0 - 180; + var midrot = -180 - (360 * percent); + var endrot = -360 - 180; + + g.setColor(0x07FF); // light cyan + + // draw guauge + for (i = startrot; i > midrot; i -= 3) { + x = cx + r * Math.sin(radians(i)); + y = cy + r * Math.cos(radians(i)); + g.fillCircle(x,y,3); + } + + // change the remaining color to RED if battery is below 25% + if (E.getBattery() > 25) { + //g.setColor(0x7BEF); // grey + g.setColor(0x000D); // dark navy + } else { + g.setColor(0xF800); // red + } + + // draw remainder of guage in grey or red + for (i = midrot - 12; i > endrot + 12; i -= 3) { + x = cx + r * Math.sin(radians(i)); + y = cy + r * Math.cos(radians(i)); + g.fillCircle(x,y,3); + } + } + + function getSteps() { + if (stepsWidget() === undefined) + return "E-STEPS"; + + return stepsWidget().getSteps(); + } + + function stepsWidget() { + if (WIDGETS.activepedom !== undefined) { + return WIDGETS.activepedom; + } else if (WIDGETS.wpedom !== undefined) { + return WIDGETS.wpedom; + } + return undefined; + } + + return {init:init, freeResources:freeResources, startTimer:startTimer, stopTimer:stopTimer, + onButtonShort:onButtonShort, onButtonLong:onButtonLong}; + } + + return getFace; +})(); diff --git a/apps/largeclock/ChangeLog b/apps/largeclock/ChangeLog index 851829fcc..6fa9297d8 100644 --- a/apps/largeclock/ChangeLog +++ b/apps/largeclock/ChangeLog @@ -5,4 +5,5 @@ 0.05: Add support for 12 hour time 0.06: Allow to disable BTN1 and BTN3 buttons 0.07: Don't clear all intervals during initialisation -0.08: fix font size +0.08: Use Bangle.setUI for button/launcher handling +0.09: fix font size for latest firmwares diff --git a/apps/largeclock/largeclock.js b/apps/largeclock/largeclock.js index 34409797c..6e1efeb4c 100644 --- a/apps/largeclock/largeclock.js +++ b/apps/largeclock/largeclock.js @@ -179,9 +179,9 @@ Bangle.on("lcdPower", function(on) { Bangle.setLCDMode(); -// Show launcher when middle button pressed -clearWatch(); -setWatch(Bangle.showLauncher, BTN2, { repeat: false, edge: "falling" }); +// Show launcher when button pressed +Bangle.setUI("clock"); + if (BTN1app) setWatch( function() { load(BTN1app); diff --git a/apps/launchb2/ChangeLog b/apps/launchb2/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/launchb2/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/launchb2/app.js b/apps/launchb2/app.js new file mode 100644 index 000000000..183c09745 --- /dev/null +++ b/apps/launchb2/app.js @@ -0,0 +1,68 @@ +var s = require("Storage"); +var apps = s.list(/\.info$/).map(app=>{var a=s.readJSON(app,1);return a&&{name:a.name,type:a.type,icon:a.icon,sortorder:a.sortorder,src:a.src};}).filter(app=>app && (app.type=="app" || app.type=="clock" || !app.type)); +apps.sort((a,b)=>{ + var n=(0|a.sortorder)-(0|b.sortorder); + if (n) return n; // do sortorder first + if (a.nameb.name) return 1; + return 0; +}); +var APPH = 64; +var menuScroll = 0; +var menuShowing = false; +var w = g.getWidth(); +var h = g.getHeight(); +var n = Math.ceil((h-24)/APPH); +var menuScrollMax = APPH*apps.length - (h-24); + +apps.forEach(app=>{ + if (app.icon) + app.icon = s.read(app.icon); // should just be a link to a memory area +}); + +function drawApp(i) { + var y = 24+i*APPH-menuScroll; + var app = apps[i]; + if (!app || y<-APPH || y>=g.getHeight()) return; + g.setFont("6x8",2).setFontAlign(-1,0).drawString(app.name,64,y+32); + if (app.icon) try {g.drawImage(app.icon,8,y+8);} catch(e){} +} + +function drawMenu() { + g.reset().clearRect(0,24,w-1,h-1); + g.setClipRect(0,24,g.getWidth()-1,g.getHeight()-1); + for (var i=0;i{ + var dy = e.dy; + if (menuScroll - dy < 0) + dy = menuScroll; + if (menuScroll - dy > menuScrollMax) + dy = menuScroll - menuScrollMax; + if (!dy) return; + g.reset().setClipRect(0,24,g.getWidth()-1,g.getHeight()-1); + g.scroll(0,dy); + menuScroll -= dy; + if (e.dy < 0) drawApp(Math.floor((menuScroll+24)/APPH)+n-1); + else drawApp(Math.floor((menuScroll+24)/APPH)); + g.setClipRect(0,0,g.getWidth()-1,g.getHeight()-1); +}); +Bangle.on("touch",(_,e)=>{ + if (e.y<20) return; + var i = Math.floor((e.y+menuScroll-24) / APPH); + var app = apps[i]; + if (!app) return; + if (!app.src || require("Storage").read(app.src)===undefined) { + E.showMessage("App Source\nNot found"); + setTimeout(drawMenu, 2000); + } else { + E.showMessage("Loading..."); + load(app.src); + } +}); +Bangle.loadWidgets(); +Bangle.drawWidgets(); diff --git a/apps/launchb2/app.png b/apps/launchb2/app.png new file mode 100644 index 000000000..8b4e6caa2 Binary files /dev/null and b/apps/launchb2/app.png differ diff --git a/apps/lazyclock/ChangeLog b/apps/lazyclock/ChangeLog index 984d29869..a3f125786 100644 --- a/apps/lazyclock/ChangeLog +++ b/apps/lazyclock/ChangeLog @@ -1,2 +1,3 @@ 0.01: Launch app -0.02: Fix bug with the elusive one o'clock monster; Only change template when going over boundaries; Re-jig wording options \ No newline at end of file +0.02: Fix bug with the elusive one o'clock monster; Only change template when going over boundaries; Re-jig wording options +0.03: Use Bangle.setUI for launcher/buttons diff --git a/apps/lazyclock/lazyclock-app.js b/apps/lazyclock/lazyclock-app.js index 400e26ede..604448ce6 100644 --- a/apps/lazyclock/lazyclock-app.js +++ b/apps/lazyclock/lazyclock-app.js @@ -221,22 +221,13 @@ function addEvents() { } }); - setWatch(switchMode, BTN1, { - repeat: true, - edge: "falling" - }); - - setWatch(Bangle.showLauncher, BTN2, { - repeat: false, - edge: "falling" - }); - - setWatch(() => { - currentFormatter = null; - refreshTime(); - }, BTN3, { - repeat: true, - edge: "falling" + // Show launcher when button pressed + Bangle.setUI("clockupdown", btn=>{ + if (btn<0) switchMode(); + if (btn>0) { + currentFormatter = null; + refreshTime(); + } }); } @@ -245,9 +236,9 @@ function init() { startClock(); Bangle.loadWidgets(); - Bangle.drawWidgets(); + Bangle.drawWidgets(); addEvents(); } -init(); \ No newline at end of file +init(); diff --git a/apps/lifeclk/ChangeLog b/apps/lifeclk/ChangeLog index dfd8b8775..cdde84463 100644 --- a/apps/lifeclk/ChangeLog +++ b/apps/lifeclk/ChangeLog @@ -2,4 +2,5 @@ 0.02: Faster algorithm, hours and minutes are now displayable whenever, using the upper button 2021-01-14 0.03: Ah yes. Some people prefer the 12 hour system 2021-01-14 0.04: Fixed a bug, doesn't run while display's on now 2021-01-18 -0.05: Fixed a bug, doesn't count the time it was asleep when calculating the update time 2021-01-19 \ No newline at end of file +0.05: Fixed a bug, doesn't count the time it was asleep when calculating the update time 2021-01-19 +0.06: Use Bangle.set UI, change to unminified upload to ensure this works ok on Bangle.js diff --git a/apps/lifeclk/app.js b/apps/lifeclk/app.min.js similarity index 98% rename from apps/lifeclk/app.js rename to apps/lifeclk/app.min.js index 6064aa162..51a8ff93c 100644 --- a/apps/lifeclk/app.js +++ b/apps/lifeclk/app.min.js @@ -1,4 +1,4 @@ -Bangle.setLCDTimeout(30); +// Name as .min.js so we don't try and pretokenise (which stops Bangle.js running this somehow) const is12Hour = (require("Storage").readJSON("setting.json",1)||{})["12hour"]; @@ -435,9 +435,11 @@ function showMinAgain(){ } function setButtons(){ - setWatch(showMinAgain, BTN1, {repeat:true,edge:"falling"}); - setWatch(Bangle.showLauncher, BTN2, {repeat:false,edge:"falling"}); - setWatch(regen, BTN3, {repeat:true,edge:"falling"}); + // Show launcher when button pressed + Bangle.setUI("clockupdown", btn=>{ + if (btn<0) showMinAgain(); + if (btn>0) regen(); + }); } let wentToSleepAt; diff --git a/apps/marioclock/mario-clock-screen-shot.png b/apps/marioclock/mario-clock-screen-shot.png old mode 100755 new mode 100644 diff --git a/apps/mclock/ChangeLog b/apps/mclock/ChangeLog index cca1b6e6b..05b422406 100644 --- a/apps/mclock/ChangeLog +++ b/apps/mclock/ChangeLog @@ -4,3 +4,4 @@ 0.05: Add "ram" keyword to allow 2v06 Espruino builds to cache function that needs to be fast Fix issue where first digit could get stuck going from "2x:xx" to " x:xx" (fix #365) 0.06: Support 12 hour time +0.07: Use Bangle.setUI for button/launcher handling diff --git a/apps/mclock/clock-morphing.js b/apps/mclock/clock-morphing.js index 15ab206b9..f1254860b 100644 --- a/apps/mclock/clock-morphing.js +++ b/apps/mclock/clock-morphing.js @@ -216,5 +216,5 @@ Bangle.drawWidgets(); timeInterval = setInterval(showTime, 1000); showTime(); -// Show launcher when middle button pressed -setWatch(Bangle.showLauncher, BTN2, {repeat:false,edge:"falling"}); +// Show launcher when button pressed +Bangle.setUI("clock"); diff --git a/apps/mclockplus/ChangeLog b/apps/mclockplus/ChangeLog index 835c33353..a1cecc698 100644 --- a/apps/mclockplus/ChangeLog +++ b/apps/mclockplus/ChangeLog @@ -1 +1,2 @@ -1.0: Created app +0.01: Created app +0.02: Use Bangle.setUI for button/launcher handling diff --git a/apps/mclockplus/mclockplus.app.js b/apps/mclockplus/mclockplus.app.js index 495e78f35..4c74ce1be 100644 --- a/apps/mclockplus/mclockplus.app.js +++ b/apps/mclockplus/mclockplus.app.js @@ -310,8 +310,8 @@ Bangle.drawWidgets(); timeInterval = setInterval(showTime, 1000); showTime(); -// Show launcher when middle button pressed -setWatch(Bangle.showLauncher, BTN2, {repeat:false,edge:"falling"}); +// Show launcher when button pressed +Bangle.setUI("clock"); // Start stopwatch when BTN3 is pressed setWatch(() => {swInterval=setInterval(stopWatch, 1000);stopWatch();}, BTN3, {repeat:false,edge:"falling"}); diff --git a/apps/miclock/ChangeLog b/apps/miclock/ChangeLog index f2e354bc1..e92bad2e3 100644 --- a/apps/miclock/ChangeLog +++ b/apps/miclock/ChangeLog @@ -1,3 +1,4 @@ 0.02: Modified for use with new bootloader and firmware 0.03: Localization 0.04: move jshint to the top +0.05: Use Bangle.setUI for button/launcher handling diff --git a/apps/miclock/clock-mixed.js b/apps/miclock/clock-mixed.js index 0bed137c6..b3d6bea8d 100644 --- a/apps/miclock/clock-mixed.js +++ b/apps/miclock/clock-mixed.js @@ -83,5 +83,5 @@ Bangle.drawWidgets(); setInterval(drawMixedClock, 5E3); drawMixedClock(); -// Show launcher when middle button pressed -setWatch(Bangle.showLauncher, BTN2, {repeat:false,edge:"falling"}); +// Show launcher when button pressed +Bangle.setUI("clock"); diff --git a/apps/miclock/clock-mixed.png b/apps/miclock/clock-mixed.png old mode 100755 new mode 100644 diff --git a/apps/miclock2/clock-mixed.png b/apps/miclock2/clock-mixed.png old mode 100755 new mode 100644 diff --git a/apps/minionclk/ChangeLog b/apps/minionclk/ChangeLog old mode 100755 new mode 100644 index 27dab7259..a8b6efc81 --- a/apps/minionclk/ChangeLog +++ b/apps/minionclk/ChangeLog @@ -2,3 +2,4 @@ 0.02: Improved date readability, fixed drawing of widgets 0.03: Fixed rendering for Espruino v2.06 0.04: Fixed overlapped rendering of dates +0.05: Use Bangle.setUI for button/launcher handling diff --git a/apps/minionclk/app-icon.js b/apps/minionclk/app-icon.js old mode 100755 new mode 100644 diff --git a/apps/minionclk/app.js b/apps/minionclk/app.js old mode 100755 new mode 100644 index f0afbc45c..9648e3d89 --- a/apps/minionclk/app.js +++ b/apps/minionclk/app.js @@ -81,4 +81,5 @@ Bangle.on('lcdPower', (on) => { Bangle.loadWidgets(); startDrawing(); -setWatch(Bangle.showLauncher, BTN2, { repeat: false, edge: 'falling' }); +// Show launcher when button pressed +Bangle.setUI("clock"); diff --git a/apps/minionclk/minionclk.png b/apps/minionclk/minionclk.png old mode 100755 new mode 100644 diff --git a/apps/mysticclock/ChangeLog b/apps/mysticclock/ChangeLog new file mode 100644 index 000000000..b486a29a1 --- /dev/null +++ b/apps/mysticclock/ChangeLog @@ -0,0 +1,2 @@ +1.00: First published version. +1.01: Use Bangle.setUI for Launcher/buttons diff --git a/apps/mysticclock/README.md b/apps/mysticclock/README.md new file mode 100644 index 000000000..fd5bbb431 --- /dev/null +++ b/apps/mysticclock/README.md @@ -0,0 +1,40 @@ +# Mystic Clock for Bangle.js + +A retro-inspired watchface featuring time, date, and an interactive data display line. + +## Features + +- 24 or 12-hour time (adjustable via the Settings menu) +- Variable colors (also in the Settings) +- Interactive data display line (use upper and lower watch-buttons to rotate between values) +- Cover watch screen with your hand to put it to sleep (the watch, not your hand) +- International localization of date (which can be disabled via the Settings if memory becomes an issue) + +The interactive line rotates between the following items: + +- Current time zone +- Battery charge level +- Device ID (derived from the last 4 of the MAC) +- Memory usage +- Firmware version + + +## Inspirations + +- [CLI Clock](https://github.com/espruino/BangleApps/tree/master/apps/cliock) +- [Dev Clock](https://github.com/espruino/BangleApps/tree/master/apps/dclock) +- [Digital Clock](https://github.com/espruino/BangleApps/tree/master/apps/digiclock) +- [Simple Clock](https://github.com/espruino/BangleApps/tree/master/apps/sclock) +- [Simplest Clock](https://github.com/espruino/BangleApps/tree/master/apps/simplest) + +Icon adapted from [Public Domain Vectors](https://publicdomainvectors.org/en/free-clipart/Digital-clock-display-vector-image/10845.html). + + +## Changelog + +- 1.00: First published version. (June 2021) + + +## Author + +Eric Wooodward https://itsericwoodward.com/ diff --git a/apps/mysticclock/mystic-clock-app.js b/apps/mysticclock/mystic-clock-app.js new file mode 100644 index 000000000..2d95633fe --- /dev/null +++ b/apps/mysticclock/mystic-clock-app.js @@ -0,0 +1,208 @@ +/** + * Mystic Clock for Bangle.js + * + * + Original Author: Eric Wooodward https://itsericwoodward.com/ + * + see README.md for details + */ + +/* jshint esversion: 6 */ + +const timeFontSize = 6; +const dataFontSize = 2; +const font = "6x8"; + +const xyCenter = g.getWidth() / 2; + +const yposTime = 75; +const yposDate = 125; +const yposSymbol = 160; +const yposInfo = 220; + +const settings = require('Storage').readJSON('mysticclock.json', 1) || {}; +const colors = ['white', 'blue', 'green', 'purple', 'red', 'teal', 'other']; +const color = settings.color ? colors[settings.color] : 0; + +const infoData = { + '*GMT_MODE': { + calc: () => (new Date()).toString().split(" ")[5], + }, + BATT_MODE: { + calc: () => `BATT: ${E.getBattery()}%`, + }, + ID_MODE: { + calc: () => { + const val = NRF.getAddress().split(":"); + return `ID: ${val[4]}${val[5]}`; + }, + }, + MEM_MODE: { + calc: () => { + const val = process.memory(); + return `MEM: ${Math.round(val.usage * 100 / val.total)}%`; + }, + }, + VER_MODE: { + calc: () => `FW: ${process.env.VERSION}`, + }, +}; +const infoList = Object.keys(infoData).sort(); +let infoMode = infoList[0]; + +function setColor() { + const colorCommands = { + white: () => g.setColor(1, 1, 1), + blue: () => g.setColor(0, 0, 1), + green: () => g.setColor(0, 1, 0), + purple: () => g.setColor(1, 0, 1), + red: () => g.setColor(1, 0, 0), + teal: () => g.setColor(0, 1, 1), + other: () => g.setColor(1, 1, 0) + }; + + // default if value unknown + if (!color || !colorCommands[color]) return colorCommands.white(); + return colorCommands[color](); +} + +function getLocale() { + return require('locale'); +} + +function drawClock() { + + // default draw styles + g.reset(); + + // drawSting centered + g.setFontAlign(0, 0); + + // setup color + setColor(); + + // get date + const d = new Date(); + const dLocal = d.toString().split(" "); + + const useLocale = !settings.useLocale; + + const minutes = (`0${d.getMinutes()}`).substr(-2); + const seconds = (`0${d.getSeconds()}`).substr(-2); + + let hours = (`0${d.getHours()}`).substr(-2); + let meridian = ""; + + if (settings.use12Hour) { + hours = parseInt(hours, 10); + meridian = 'AM'; + if (hours === 0) { + hours = 12; + } + else if (hours >= 12) { + meridian = 'PM'; + if (hours > 12) hours -= 12; + } + hours = (' ' + hours).substr(-2); + } + + g.setFont(font, timeFontSize); + g.drawString(`${hours}${(d.getSeconds() % 2) ? ' ' : ':'}${minutes}`, xyCenter - 15, yposTime, true); + g.setFont(font, dataFontSize); + + if (settings.use12Hour) { + g.drawString(seconds, xyCenter + 97, yposTime - 10, true); + g.drawString(meridian, xyCenter + 97, yposTime + 10, true); + } + else { + g.drawString(seconds, xyCenter + 97, yposTime + 10, true); + } + + // draw DoW, name of month, date, year + g.setFont(font, dataFontSize); + g.drawString([ + useLocale ? getLocale().dow(d, 1) : dLocal[0], + useLocale ? getLocale().month(d, 1) : dLocal[1], + d.getDate(), + d.getFullYear() + ].join(" "), xyCenter, yposDate, true); + +} + +function drawInfo() { + if (infoData[infoMode] && infoData[infoMode].calc) { + // clear info + g.setColor(0, 0, 0); + g.fillRect(0, yposInfo - 8, 239, yposInfo + 25); + + // draw info + g.setFont(font, dataFontSize); + setColor(); + g.drawString((infoData[infoMode].calc()), xyCenter, yposInfo, true); + } +} + +function drawImage() { + setColor(); + g.drawPoly([xyCenter - 100, yposSymbol, xyCenter + 100, yposSymbol, xyCenter, yposSymbol + 30], true); +} + +function drawAll() { + drawClock(); + drawInfo(); + drawImage(); +} + +function nextInfo() { + let idx = infoList.indexOf(infoMode); + if (idx > -1) { + if (idx === infoList.length - 1) infoMode = infoList[0]; + else infoMode = infoList[idx + 1]; + } +} + +function prevInfo() { + let idx = infoList.indexOf(infoMode); + if (idx > -1) { + if (idx === 0) infoMode = infoList[infoList.length - 1]; + else infoMode = infoList[idx - 1]; + } +} + + +let secondInterval; + +// handle LCD power state change +Bangle.on('lcdPower', on => { + + // stop running when screen turns off + if (secondInterval) clearInterval(secondInterval); + secondInterval = undefined; + + // start running + if (on) { + secondInterval = setInterval(drawAll, 1000); + drawAll(); // draw immediately + } +}); + +// cover screen to put it to sleep +Bangle.on('touch', (button) => { + if (button === 3 && Bangle.isLCDOn()) Bangle.setLCDPower(false); +}); + +// clean app screen +g.clear(); +Bangle.loadWidgets(); +Bangle.drawWidgets(); + +// if screen already active, draw now and start interval +if (Bangle.isLCDOn()) { + secondInterval = setInterval(drawAll, 1000); + drawAll(); // draw immediately +} + +// Show launcher when button pressed +Bangle.setUI("clockupdown", btn=>{ + if (btn<0) prevInfo(); + if (btn>0) nextInfo(); + drawAll(); +}); diff --git a/apps/mysticclock/mystic-clock-icon.js b/apps/mysticclock/mystic-clock-icon.js new file mode 100644 index 000000000..7415fccd5 --- /dev/null +++ b/apps/mysticclock/mystic-clock-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwkBIf4A/AH4A/AH4A/AH4ALs1msADCA4MGAgQDBBYIAGg93u92s4DBuEAAYN3swDCC5AhBuwMBg4XBuwEBs4dCC49nHgNwCQREBCYNnEYYXHHQQvBAAJZBAgRPEC5IOCu0GM4YLCuCGDAAREBHwtnJ41gDQIXEOAQvBDoZ7CuwjCWwimTJgLCFZojWEbwbWIAH4A/AH4A/AH4A/AH4AFA")) diff --git a/apps/mysticclock/mystic-clock-settings.js b/apps/mysticclock/mystic-clock-settings.js new file mode 100644 index 000000000..2fa0c49c5 --- /dev/null +++ b/apps/mysticclock/mystic-clock-settings.js @@ -0,0 +1,41 @@ +// make sure to enclose the function in parentheses +(function (back) { + + const settings = require('Storage').readJSON('mysticclock.json',1)||{}; + const colors = ['White', 'Blue', 'Green', 'Purple', 'Red', 'Teal', 'Yellow']; + const offon = ['Off','On']; + const onoff = ['On','Off']; + + function save(key, value) { + settings[key] = value; + require('Storage').writeJSON('mysticclock.json',settings); + } + + const appMenu = { + '': {'title': 'Clock Settings'}, + '< Back': back, + 'Color': { + value: 0|settings['color'], + min:0, + max:6, + format: m => colors[m], + onchange: m => {save('color', m)} + }, + '12 Hour Clock': { + value: 0|settings['use12Hour'], + min:0, + max:1, + format: m => offon[m], + onchange: m => {save('use12Hour', m)} + }, + 'Use Locale': { + value: 0|settings['useLocale'], + min:0, + max:1, + format: m => onoff[m], + onchange: m => {save('useLocale', m)} + } + }; + E.showMenu(appMenu) + +}) diff --git a/apps/mysticclock/mystic-clock.png b/apps/mysticclock/mystic-clock.png new file mode 100644 index 000000000..915e2ee32 Binary files /dev/null and b/apps/mysticclock/mystic-clock.png differ diff --git a/apps/mysticdock/ChangeLog b/apps/mysticdock/ChangeLog new file mode 100644 index 000000000..34fe53627 --- /dev/null +++ b/apps/mysticdock/ChangeLog @@ -0,0 +1 @@ +1.00: First published version. diff --git a/apps/mysticdock/README.md b/apps/mysticdock/README.md new file mode 100644 index 000000000..09e81ba09 --- /dev/null +++ b/apps/mysticdock/README.md @@ -0,0 +1,43 @@ +# Mystic Dock for Bangle.js + +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. + +## Features + +- Screensaver-like dock mode while charging (displays the current time for 8 seconds and a blank screen for 2, changing text placement with each draw) +- 24 or 12-hour time (adjustable via the Settings menu) +- Variable colors (also in the Settings) +- Interactive watchface display (use upper and lower watch-buttons to activate it and rotate between values at the bottom) +- International localization of watchface date (which can be disabled via the Settings if memory becomes an issue) +- Automatic watchface reload when unplugged (toggleable via the Settings menu) +- Rotates display 90 degrees if it detects it is sideways (for use in a charging dock) + +When in interactive display mode, the bottom line rotates between the following items: + +- Current time zone +- Battery charge level +- Device ID (derived from the last 4 of the MAC) +- Memory usage +- Firmware version + + +## Inspirations + +- [Bluetooth Dock](https://github.com/espruino/BangleApps/tree/master/apps/bluetoothdock) +- [CLI Clock](https://github.com/espruino/BangleApps/tree/master/apps/cliock) +- [Dev Clock](https://github.com/espruino/BangleApps/tree/master/apps/dclock) +- [Digital Clock](https://github.com/espruino/BangleApps/tree/master/apps/digiclock) +- [Simple Clock](https://github.com/espruino/BangleApps/tree/master/apps/sclock) +- [Simplest Clock](https://github.com/espruino/BangleApps/tree/master/apps/simplest) + +Icon adapted from [this one](https://publicdomainvectors.org/en/free-clipart/Digital-clock-display-vector-image/10845.html) and [this one](https://publicdomainvectors.org/en/free-clipart/Vector-image-of-power-manager-icon/20141.html) from [Public Domain Vectors](https://publicdomainvectors.org). + + +## Changelog + +- 1.00: First published version. (June 2021) + + +## Author + +Eric Wooodward https://itsericwoodward.com/ diff --git a/apps/mysticdock/mystic-dock-app.js b/apps/mysticdock/mystic-dock-app.js new file mode 100644 index 000000000..2e6fdafc5 --- /dev/null +++ b/apps/mysticdock/mystic-dock-app.js @@ -0,0 +1,247 @@ +/** + * Mystic Dock for Bangle.js + * + * + Original Author: Eric Wooodward https://itsericwoodward.com/ + * + see README.md for details + */ + +/* jshint esversion: 6 */ + +const timeFontSize = 6; +const dataFontSize = 2; +const font = "6x8"; + +const xyCenter = g.getWidth() / 2; + +const ypos = [ + 45, // Time + 105, // Date + 145, // Symbol + 210 // Info +]; + +const settings = require('Storage').readJSON('mysticdock.json', 1) || + require('Storage').readJSON('mysticclock.json', 1) || {}; +const colors = ['white', 'blue', 'green', 'purple', 'red', 'teal', 'other']; +const color = settings.color ? colors[settings.color] : 0; + +const yposMax = 190; +const yposMin = 60; +let y = yposMax; + +let lastButtonPressTime; +let wasInActiveMode = false; + + +const infoData = { + '*GMT_MODE': { + calc: () => (new Date()).toString().split(" ")[5], + }, + BATT_MODE: { + calc: () => `BATT: ${E.getBattery()}%`, + }, + ID_MODE: { + calc: () => { + const val = NRF.getAddress().split(":"); + return `ID: ${val[4]}${val[5]}`; + }, + }, + MEM_MODE: { + calc: () => { + const val = process.memory(); + return `MEM: ${Math.round(val.usage * 100 / val.total)}%`; + }, + }, + VER_MODE: { + calc: () => `FW: ${process.env.VERSION}`, + }, +}; +const infoList = Object.keys(infoData).sort(); +let infoMode = infoList[0]; + + +function setColor() { + const colorCommands = { + white: () => g.setColor(1, 1, 1), + blue: () => g.setColor(0, 0, 1), + green: () => g.setColor(0, 1, 0), + purple: () => g.setColor(1, 0, 1), + red: () => g.setColor(1, 0, 0), + teal: () => g.setColor(0, 1, 1), + other: () => g.setColor(1, 1, 0) + }; + + // default if value unknown + if (!color || !colorCommands[color]) return colorCommands.white(); + return colorCommands[color](); +} + + +function drawInfo() { + if (infoData[infoMode] && infoData[infoMode].calc) { + // clear info + g.setColor(0, 0, 0); + g.fillRect(0, ypos[3] - 8, 239, ypos[3] + 25); + + // draw info + g.setFont(font, dataFontSize); + setColor(); + g.drawString((infoData[infoMode].calc()), xyCenter, ypos[3], true); + } +} + +function drawImage() { + setColor(); + g.drawPoly([xyCenter - 100, ypos[2], xyCenter + 100, ypos[2], xyCenter, ypos[2] + 30], true); +} + +function drawClock() { + + // default draw styles + g.reset(); + + // get date + const d = new Date(); + const dLocal = d.toString().split(" "); + + const minutes = (`0${d.getMinutes()}`).substr(-2); + const seconds = (`0${d.getSeconds()}`).substr(-2); + + const useLocale = !settings.useLocale; + + let hours = (`0${d.getHours()}`).substr(-2); + let meridian = ""; + + if (d.getSeconds() % 10 === 0) { + y = Math.floor(Math.random() * (yposMax - yposMin)) + yposMin; + } + + // drawSting centered + g.setFontAlign(0, 0); + + // setup color + setColor(); + + if (settings.use12Hour) { + hours = parseInt(hours, 10); + meridian = 'AM'; + if (hours === 0) { + hours = 12; + } + else if (hours >= 12) { + meridian = 'PM'; + if (hours > 12) hours -= 12; + } + hours = (' ' + hours).substr(-2); + } + + g.setFont(font, timeFontSize); + + if (lastButtonPressTime && ((d.getTime() - lastButtonPressTime) / 1000) < 5) { + + // clear screen when switching modes + if (!wasInActiveMode) { + g.clear(); + wasInActiveMode = true; + } + + // draw clock in center w/ seconds + // show date (locale'd, based on settings) + // show info line below it + g.drawString(`${hours}${(d.getSeconds() % 2) ? ' ' : ':'}${minutes}`, xyCenter - 15, ypos[0], true); + g.setFont(font, dataFontSize); + + if (settings.use12Hour) { + g.drawString(seconds, xyCenter + 97, ypos[0] - 10, true); + g.drawString(meridian, xyCenter + 97, ypos[0] + 10, true); + } + else { + g.drawString(seconds, xyCenter + 97, ypos[0] + 10, true); + } + + // draw DoW, name of month, date, year + g.setFont(font, dataFontSize); + g.drawString([ + useLocale ? require('locale').dow(d, 1) : dLocal[0], + useLocale ? require('locale').month(d, 1) : dLocal[1], + d.getDate(), + d.getFullYear() + ].join(' '), xyCenter, ypos[1], true); + + drawInfo(); + drawImage(); + } + else if (d.getSeconds() % 10 === 8) { + g.clear(); + wasInActiveMode = false; + } + else if (d.getSeconds() % 10 !== 9) { + // clear screen when switching modes + if (wasInActiveMode) { + g.clear(); + wasInActiveMode = false; + } + g.drawString(`${hours}${(d.getSeconds() % 2) ? ' ' : ':'}${minutes}`, xyCenter - (settings.use12Hour ? 15 : 0), y, true); + g.setFont(font, dataFontSize); + if (settings.use12Hour) { + g.drawString(meridian, xyCenter + 97, y + 10, true); + } + g.drawString(`BATT: ${E.getBattery() === 100 ? '100' : ('0' + E.getBattery()).substr(-2)}%`, xyCenter, y + 35, true); + } + + g.flip(); +} + + +function nextInfo() { + lastButtonPressTime = Date.now(); + let idx = infoList.indexOf(infoMode); + + if (idx > -1) { + if (idx === infoList.length - 1) infoMode = infoList[0]; + else infoMode = infoList[idx + 1]; + } +} + + +function prevInfo() { + lastButtonPressTime = Date.now(); + let idx = infoList.indexOf(infoMode); + + if (idx > -1) { + if (idx === 0) infoMode = infoList[infoList.length - 1]; + else infoMode = infoList[idx - 1]; + } +} + + +if (Bangle.getAccel().x < -0.7) { + g.setRotation(3); // assume watch in charge cradle +} + +g.clear(); + +setInterval(drawClock, 1000); +drawClock(); + +if (Bangle.isCharging()) { + Bangle.on("charging", isCharging => { + const reloadOnUplug = !settings.reloadOnUplug; + + if (!isCharging && reloadOnUplug) load(); + }); +} + +// show launcher when middle button pressed +setWatch(Bangle.showLauncher, BTN2, { repeat: false, edge: "falling" }); + +// change to "active mode" and rotate through info when the buttons are pressed +setWatch(() => { + nextInfo(); + drawClock(); +}, BTN3, { repeat: true }); + +setWatch(() => { + prevInfo(); + drawClock(); +}, BTN1, { repeat: true }); diff --git a/apps/mysticdock/mystic-dock-boot.js b/apps/mysticdock/mystic-dock-boot.js new file mode 100644 index 000000000..7cb7fa8a4 --- /dev/null +++ b/apps/mysticdock/mystic-dock-boot.js @@ -0,0 +1 @@ +Bangle.on("charging", isCharging => { if (isCharging) load("mysticdock.app.js"); }); diff --git a/apps/mysticdock/mystic-dock-icon.js b/apps/mysticdock/mystic-dock-icon.js new file mode 100644 index 000000000..527825dd7 --- /dev/null +++ b/apps/mysticdock/mystic-dock-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwkBIf4A6g93u9gs4DCBBIAFu9ms9wAYYIJAAt2FAN2BYMHEwIIIAAkGBQV3AYNns1mBAwXGg4KCIgYTEBAZ2JCYQABBBIXJQoRcCBA0GDQpPCBAUGuwTBBAwfCUwgTDMoVmBA8GQIIXGWoJ9DBA4vHAAIOBcoYIHC4xqCCQR2BBBEGJAKSGAH4Adb4SIBDCYXCUwQwVDCjJCXYS/CDh4SCAAoxPDA72CPaQdCTB57CLgQYCGCIdFJJ4QFTIQXUGwpHQJAapQI4qQPCIqtDVCQECMCR5BJgN2bSArCuACCbSIRCIobZQOgZMCgx4OJIjvCCyAYCCYJMBYB4zHC6oA/AE4=")) diff --git a/apps/mysticdock/mystic-dock-settings.js b/apps/mysticdock/mystic-dock-settings.js new file mode 100644 index 000000000..7bfda1c0f --- /dev/null +++ b/apps/mysticdock/mystic-dock-settings.js @@ -0,0 +1,48 @@ +// make sure to enclose the function in parentheses +(function (back) { + + const settings = require('Storage').readJSON('mysticdock.json',1)||{}; + const colors = ['White', 'Blue', 'Green', 'Purple', 'Red', 'Teal', 'Yellow']; + const offon = ['Off','On']; + const onoff = ['On','Off']; + + function save(key, value) { + settings[key] = value; + require('Storage').writeJSON('mysticdock.json',settings); + } + + const appMenu = { + '': {'title': 'Dock Settings'}, + '< Back': back, + 'Color': { + value: 0|settings['color'], + min:0, + max:6, + format: m => colors[m], + onchange: m => {save('color', m)} + }, + '12 Hour Clock': { + value: 0|settings['use12Hour'], + min:0, + max:1, + format: m => offon[m], + onchange: m => {save('use12Hour', m)} + }, + 'Reload on Unplug': { + value: 0|settings['reloadOnUplug'], + min:0, + max:1, + format: m => onoff[m], + onchange: m => {save('reloadOnUplug', m)} + }, + 'Use Locale': { + value: 0|settings['useLocale'], + min:0, + max:1, + format: m => onoff[m], + onchange: m => {save('useLocale', m)} + }, + }; + E.showMenu(appMenu) + +}) diff --git a/apps/mysticdock/mystic-dock.png b/apps/mysticdock/mystic-dock.png new file mode 100644 index 000000000..4c0dce770 Binary files /dev/null and b/apps/mysticdock/mystic-dock.png differ diff --git a/apps/mywelcome/app.js b/apps/mywelcome/app.js index 23cdd0d49..9d4a54928 100644 --- a/apps/mywelcome/app.js +++ b/apps/mywelcome/app.js @@ -11,11 +11,9 @@ function animate(seq,period) { // Fade in to FG color with angled lines function fade(col, callback) { var n = 0; - function f() { + function f() {"ram" g.setColor(col); - for (var i=n;i<240;i+=10) { - g.drawLine(i,0,0,i).drawLine(i,240,240,i); - } + for (var i=n;i<240;i+=10) g.drawLine(i,0,0,i).drawLine(i,240,240,i); g.flip(); n++; if (n<10) setTimeout(f,0); @@ -25,19 +23,22 @@ function fade(col, callback) { } -var scenes = [ - function() { +var SCENE_COUNT=11; +function getScene(n) { + if (n==0) return function() { console.log("Start app"); g.clear(1); eval(require("Storage").read("mywelcome.custom.js")); - },function() { + } + if (n==1) return function() { g.clear(1); g.setFont("4x6",2); var n=0; + var l = Bangle.getLogo(); var i = setInterval(function() { n+=0.04; g.setColor(n,n,n); - g.drawImage(Bangle.getLogo(),(240-222)/2,(240-100)/2); + g.drawImage(l,(240-222)/2,(240-100)/2); if (n>=1) { clearInterval(i); setTimeout(()=>g.drawString("Open",34,144), 500); @@ -45,7 +46,8 @@ var scenes = [ setTimeout(()=>g.drawString("Smart Watch",34,168), 1500); } },50); - },function() { + }; + if (n==2) return function() { var img = require("heatshrink").decompress(atob("ptRxH+qYAfvl70mj5gAC0ekvd8FkAAdz3HJAYAH4+eJXWkJJYAF0hK2vfNJaIAB5t7S3fN5/V6wAD6vOTg9SumXy2W3QAB3eXul2JdnO63XAApPEVYvAJQIACJoRQDzBLoJQ3W5/NIwr4GJohMFAAROgJYvVJQiPGABZNN3bsdvYyESwnWJSIAC3RNM3V1JjZAES4nVJSYAB4xMNJrbkE56WD5xLVdB5NbFofNJbgABJh26qREPrFXrlbAAWjFgfWJgRLaTQhMLy5KNJINhsJLDrYrD5xLC6pLa5nGTR7oLq9bJQJMKTAXWJbbnR3RLJSoRMHv4pC5rkec6SaIrBLGw2r2XW1epcoqYeJiOXJYziEsOH2RBBw7lF56Yg5nGc6FScZOGJQPX2TmDFIfVTEBMSc4hLEw5KB6+rsJMH63X6pMf5hMQzBLCq5LD1ZLEJhTlfJiWXTA2GJYpMIcwPNc2O6TAuGRIPX1igDJg/PJmyYDcgXWwxMH1ApC53XcsHAJiVYcg2HJYZME0YpC5vWJkhLNJgLlDTAeFJhF/FQfVJkG6JiGXcomyJgOrJYhMErYqD53NJj7lRzBMDcoeGJhzoBJb3GJiN1qZBCJgWyJYpNF1LigAAXAJiNSJgzlGJgt/JkZLRy9TJgeHJhznFcuSZGw5MHJomjcuhLBqdcJiSaiTChMV1CYxy5LCqdXIAWy6+rJhCalTCN2JgdYH4WHJiGpTF7kDc43W2RMJTUZLQzBLFc4mr6+GJh2jTFmXJYyaEwuyc5Sag4xLZTQmG2WFJhxNaJYZMLJZSaEJoOHTR9/Ja+6JbdTqRNETRRNF1JLV4BLcAANYI5ToK1BLYJhWYJZwABq5NoJZ91JaAABdAZNS0ZLey9SJaRNYv5KM426JZmXuxKUJrKcL0lTzBLKzBKYJrVXvfGSol7EYWXJI27zF1JLQADq5NUrgYB4wAEEIV0comXI7wAFrCcPJgYWBTIIAETIN2JYmWuhMkdSdYCgOeJgueqRLFyzhfTi9bq4TC45MF49TuuXJlpONcogAC0hKB0gHDvZMEqRMpAANSq9crlbJAYADqwRDxGk0mIA4eCTQOeveXJdYAHqxNFdAeIAAQGCrOI0oHEAGVXTRJMGvgGCwRM7TAZMHwQGCvhM1rBMERIhMGAwdZJmtSqVTwNcwJEDJg19cvIADa4d9JhANDJnSLHJgrl6AAhFFAwpZDegjn7vhMGcvwABrJAFJgjl/TQpBBI4jl/AAN8TQhHDcv4ADcJBMDvpM+IYaeDAAhL+qd9SgycEJn7iEAA18Jf7nEcv4AIrJLIcv6aMcv4ADvhMHrJJ/AAbl/c6ZM/AAt9cv7nSIv7nLcv4AHrLl/TRpJBvgnjA==")); g.reset(); g.setBgColor("#6633ff"); @@ -76,7 +78,8 @@ var scenes = [ },20); },3500); - },function() { + }; + if (n==3) return function() { g.reset(); g.setBgColor("#ffa800");g.clear(); g.setFont("6x8",2); @@ -91,8 +94,8 @@ var scenes = [ ()=>g.drawString("2",200,120), ()=>g.drawString("3",200,200) ],200); - }, - function() { + }; + if (n==4) return function() { g.reset(); g.setBgColor("#00a8ff");g.clear(); g.setFontAlign(0,0); @@ -101,8 +104,8 @@ var scenes = [ g.setFontAlign(-1,-1); g.setFont("6x8",2); g.drawString("Move up\nin menus\n\nTurn Bangle.js on\nif it was off", 20,40); - }, - function() { + }; + if (n==5) return function() { g.reset(); g.setBgColor("#00a8ff");g.clear(); g.setFontAlign(0,0); @@ -111,8 +114,8 @@ var scenes = [ g.setFontAlign(-1,-1); g.setFont("6x8",2); g.drawString("Select menu\nitem\n\nLaunch app\nwhen watch\nis showing", 20,70); - }, - function() { + }; + if (n==6) return function() { g.reset(); g.setBgColor("#00a8ff");g.clear(); g.setFontAlign(0,0); @@ -121,8 +124,8 @@ var scenes = [ g.setFontAlign(-1,-1); g.setFont("6x8",2); g.drawString("Move down\nin menus\n\nLong press\nto exit app\nand go back\nto clock", 20,100); - }, - function() { + }; + if (n==7) return function() { g.reset(); g.setBgColor("#ff3300");g.clear(); g.setFontAlign(0,0); @@ -132,8 +135,8 @@ var scenes = [ g.setFontAlign(-1,-1); g.setFont("6x8",2); g.drawString("If Bangle.js\never stops,\nhold buttons\n1 and 2 for\naround six\nseconds.\n\n\n\nBangle.js will\nthen reboot.", 20,20); - }, - function() { + }; + if (n==8) return function() { g.reset(); g.setBgColor("#00a8ff");g.clear(); g.setFont("6x8",2); @@ -150,8 +153,8 @@ var scenes = [ g.drawString("work too. Try now",x,y+=h); g.drawString("to change page.",x,y+=h);} ],300); - }, - function() { + }; + if (n==9) return function() { g.reset(); g.setBgColor("#339900");g.clear(); g.setFont("6x8",2); @@ -168,8 +171,8 @@ var scenes = [ g.drawString("with a Bluetooth",x,y+=h); g.drawString("capable device",x,y+=h);}, ],400); - }, - function() { + }; + if (n==10) return function() { g.reset(); g.setBgColor("#990066");g.clear(); g.setFont("6x8",2); @@ -182,6 +185,7 @@ var scenes = [ g.drawString("banglejs.com",x,y+=h); var rx = 0, ry = 0; + E.defrag(); // rearrange memory to ensure we have space var h = Graphics.createArrayBuffer(96,96,1,{msb:true}); // draw a cube function draw() { @@ -230,8 +234,8 @@ var scenes = [ } setInterval(draw,50); - }, - function() { + }; + if (n==11) return function() { g.reset(); g.setBgColor("#660099");g.clear(); g.setFontAlign(0,0); @@ -248,20 +252,18 @@ var scenes = [ g.drawString("Bangle.js",x,y+=h);} ],400); } -]; +} var sceneNumber = 0; function move(dir) { - if (dir>0 && sceneNumber+1 == scenes.length) return; // at the end - sceneNumber = (sceneNumber+dir)%scenes.length; + if (dir>0 && sceneNumber+1 == SCENE_COUNT) return; // at the end + sceneNumber = (sceneNumber+dir)%SCENE_COUNT; if (sceneNumber<0) sceneNumber=0; clearInterval(); - Bangle.setLCDMode(); - g.clear(); - scenes[sceneNumber](); + getScene(sceneNumber)(); if (sceneNumber>2) { - var l = scenes.length; + var l = SCENE_COUNT; for (var i=0;i