Merge branch 'espruino:master' into master
263
apps.json
|
@ -1,14 +1,15 @@
|
|||
[
|
||||
{ "id": "boot",
|
||||
"name": "Bootloader",
|
||||
"tags": "tool,system",
|
||||
"tags": "tool,system,b2",
|
||||
"type":"bootloader",
|
||||
"icon": "bootloader.png",
|
||||
"version":"0.22",
|
||||
"version":"0.27",
|
||||
"description": "This is needed by Bangle.js to automatically load the clock, menu, widgets and settings",
|
||||
"storage": [
|
||||
{"name":".boot0","url":"boot0.js"},
|
||||
{"name":".bootcde","url":"bootloader.js"}
|
||||
{"name":".bootcde","url":"bootloader.js"},
|
||||
{"name":"bootupdate.js","url":"bootupdate.js"}
|
||||
],
|
||||
"sortorder" : -10
|
||||
},
|
||||
|
@ -41,21 +42,34 @@
|
|||
"name": "Launcher (Default)",
|
||||
"shortName":"Launcher",
|
||||
"icon": "app.png",
|
||||
"version":"0.04",
|
||||
"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.07",
|
||||
"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"},
|
||||
|
@ -67,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",
|
||||
|
@ -104,7 +118,7 @@
|
|||
{ "id": "welcome",
|
||||
"name": "Welcome",
|
||||
"icon": "app.png",
|
||||
"version":"0.09",
|
||||
"version":"0.10",
|
||||
"description": "Appears at first boot and explains how to use Bangle.js",
|
||||
"tags": "start,welcome",
|
||||
"allow_emulator":true,
|
||||
|
@ -171,13 +185,12 @@
|
|||
{ "id": "setting",
|
||||
"name": "Settings",
|
||||
"icon": "settings.png",
|
||||
"version":"0.24",
|
||||
"version":"0.27",
|
||||
"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"},
|
||||
{"name":"setting.boot.js","url":"boot.js"},
|
||||
{"name":"setting.img","url":"settings-icon.js","evaluate":true}
|
||||
],
|
||||
"data": [
|
||||
|
@ -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": [
|
||||
|
@ -337,9 +350,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": [
|
||||
|
@ -350,9 +363,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": [
|
||||
|
@ -363,9 +376,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"},
|
||||
|
@ -387,13 +400,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",
|
||||
|
@ -478,10 +495,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},
|
||||
|
@ -551,7 +569,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",
|
||||
|
@ -596,14 +614,25 @@
|
|||
{ "id": "widbat",
|
||||
"name": "Battery Level Widget",
|
||||
"icon": "widget.png",
|
||||
"version":"0.05",
|
||||
"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"}
|
||||
]
|
||||
},
|
||||
{ "id": "widlock",
|
||||
"name": "Lock Widget",
|
||||
"icon": "widget.png",
|
||||
"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,b2",
|
||||
"type":"widget",
|
||||
"storage": [
|
||||
{"name":"widlock.wid.js","url":"widget.js"}
|
||||
]
|
||||
},
|
||||
{ "id": "widbatpc",
|
||||
"name": "Battery Level Widget (with percentage)",
|
||||
"shortName": "Battery Widget",
|
||||
|
@ -641,9 +670,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"}
|
||||
|
@ -679,7 +708,7 @@
|
|||
{ "id": "hrm",
|
||||
"name": "Heart Rate Monitor",
|
||||
"icon": "heartrate.png",
|
||||
"version":"0.03",
|
||||
"version":"0.04",
|
||||
"description": "Measure your heart rate and see live sensor data",
|
||||
"tags": "health",
|
||||
"storage": [
|
||||
|
@ -861,9 +890,9 @@
|
|||
{ "id": "sclock",
|
||||
"name": "Simple Clock",
|
||||
"icon": "clock-simple.png",
|
||||
"version":"0.04",
|
||||
"version":"0.05",
|
||||
"description": "A Simple Digital Clock",
|
||||
"tags": "clock",
|
||||
"tags": "clock,b2",
|
||||
"type":"clock",
|
||||
"allow_emulator":true,
|
||||
"storage": [
|
||||
|
@ -871,10 +900,23 @@
|
|||
{"name":"sclock.img","url":"clock-simple-icon.js","evaluate":true}
|
||||
]
|
||||
},
|
||||
{ "id": "s7clk",
|
||||
"name": "Simple 7 segment Clock",
|
||||
"icon": "icon.png",
|
||||
"version":"0.03",
|
||||
"description": "A simple 7 segment Clock with date",
|
||||
"tags": "clock,b2",
|
||||
"type":"clock",
|
||||
"allow_emulator":true,
|
||||
"storage": [
|
||||
{"name":"s7clk.app.js","url":"app.js"},
|
||||
{"name":"s7clk.img","url":"icon.js","evaluate":true}
|
||||
]
|
||||
},
|
||||
{ "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",
|
||||
|
@ -900,9 +942,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": [
|
||||
|
@ -1026,7 +1068,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",
|
||||
|
@ -1102,9 +1144,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": [
|
||||
|
@ -1115,9 +1157,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": [
|
||||
|
@ -1128,7 +1170,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",
|
||||
|
@ -1139,9 +1181,9 @@
|
|||
{ "id": "widpedom",
|
||||
"name": "Pedometer widget",
|
||||
"icon": "widget.png",
|
||||
"version":"0.12",
|
||||
"version":"0.14",
|
||||
"description": "Daily pedometer widget",
|
||||
"tags": "widget",
|
||||
"tags": "widget,b2",
|
||||
"type":"widget",
|
||||
"storage": [
|
||||
{"name":"widpedom.wid.js","url":"widget.js"},
|
||||
|
@ -1151,7 +1193,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",
|
||||
|
@ -1164,9 +1206,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": [
|
||||
|
@ -1204,9 +1246,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": [
|
||||
|
@ -1285,9 +1327,9 @@
|
|||
"name": "Commandline-Clock",
|
||||
"shortName":"CLI-Clock",
|
||||
"icon": "app.png",
|
||||
"version":"0.11",
|
||||
"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": [
|
||||
|
@ -1309,10 +1351,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"},
|
||||
|
@ -1322,9 +1365,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": [
|
||||
|
@ -1459,9 +1502,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"},
|
||||
|
@ -1526,9 +1569,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"},
|
||||
|
@ -1567,7 +1610,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",
|
||||
|
@ -1853,9 +1896,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": [
|
||||
|
@ -1981,7 +2024,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",
|
||||
|
@ -2025,9 +2068,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,
|
||||
|
@ -2109,7 +2152,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",
|
||||
|
@ -2136,9 +2179,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"},
|
||||
|
@ -2152,9 +2195,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"},
|
||||
|
@ -2167,7 +2210,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",
|
||||
|
@ -2285,7 +2328,7 @@
|
|||
{ "id": "multiclock",
|
||||
"name": "Multi Clock",
|
||||
"icon": "multiclock.png",
|
||||
"version":"0.12",
|
||||
"version":"0.13",
|
||||
"description": "Clock with multiple faces - Big, Analogue, Digital, Text, Time-Date.\n Switch between faces with BTN1 & BTN3",
|
||||
"readme": "README.md",
|
||||
"tags": "clock",
|
||||
|
@ -2472,7 +2515,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",
|
||||
|
@ -2490,9 +2533,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"},
|
||||
|
@ -2750,7 +2793,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",
|
||||
|
@ -2809,7 +2852,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"},
|
||||
|
@ -3046,7 +3089,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}
|
||||
|
@ -3136,7 +3179,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",
|
||||
|
@ -3144,11 +3187,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}
|
||||
],
|
||||
|
@ -3210,7 +3251,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}
|
||||
|
@ -3220,7 +3260,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",
|
||||
|
@ -3244,5 +3284,62 @@
|
|||
{"name":"doztime.app.js","url":"app.js"},
|
||||
{"name":"doztime.img","url":"app-icon.js","evaluate":true}
|
||||
]
|
||||
},
|
||||
{ "id":"gbtwist",
|
||||
"name":"Gadgetbridge Twist Control",
|
||||
"shortName":"Twist Control",
|
||||
"icon":"app.png",
|
||||
"version":"0.01",
|
||||
"description":"Shake your wrist to control your music app via Gadgetbridge",
|
||||
"tags":"tools,bluetooth,gadgetbridge,music",
|
||||
"type":"app",
|
||||
"allow_emulator":false,
|
||||
"readme": "README.md",
|
||||
"storage": [
|
||||
{"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.00",
|
||||
"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}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
|
@ -5,3 +5,4 @@
|
|||
0.05: Actual pixels as of 27 Apr 2020
|
||||
0.06: Actual pixels as of 12 Jun 2020
|
||||
0.07: Pressing a button now exits immediately (fix #618)
|
||||
0.08: Make about (mostly) work on non-240px screens
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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" });
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
0.01: New App!
|
||||
0.02: Add BTN2 -> launcher
|
||||
0.03: Update to use setUI
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
0.01: New App!
|
||||
0.02: Fix bug if image clock wasn't installed
|
||||
0.03: Update to use setUI
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -3,3 +3,5 @@
|
|||
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
|
||||
0.06: Improve accuracy
|
||||
0.07: Update to use Bangle.setUI instead of setWatch
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
# Bar Clock
|
||||
A simple digital clock showing seconds as a horizontal bar.
|
||||
|
||||
| 24hr style | 12hr style |
|
||||
| --- | --- |
|
||||
|  |  |
|
|
@ -2,11 +2,10 @@
|
|||
/**
|
||||
* 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
|
||||
// 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
|
||||
|
@ -18,16 +17,16 @@
|
|||
locale.hasMeridian = (locale.meridian(date) !== '')
|
||||
}
|
||||
|
||||
}
|
||||
const screen = {
|
||||
}
|
||||
const screen = {
|
||||
width: g.getWidth(),
|
||||
height: g.getWidth(),
|
||||
middle: g.getWidth() / 2,
|
||||
center: g.getHeight() / 2,
|
||||
}
|
||||
}
|
||||
|
||||
// hardcoded "settings"
|
||||
const settings = {
|
||||
// hardcoded "settings"
|
||||
const settings = {
|
||||
time: {
|
||||
color: -1,
|
||||
font: '6x8',
|
||||
|
@ -52,11 +51,11 @@
|
|||
top: 155, // just below time
|
||||
thickness: 6, // matches 24h time "pixel" size
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const SECONDS_PER_MINUTE = 60
|
||||
const SECONDS_PER_MINUTE = 60
|
||||
|
||||
const timeText = function (date) {
|
||||
const timeText = function (date) {
|
||||
if (!is12Hour) {
|
||||
return locale.time(date, true)
|
||||
}
|
||||
|
@ -68,20 +67,20 @@
|
|||
date12.setHours(hours - 12)
|
||||
}
|
||||
return locale.time(date12, true)
|
||||
}
|
||||
const ampmText = function (date) {
|
||||
}
|
||||
const ampmText = function (date) {
|
||||
return is12Hour ? locale.meridian(date) : ''
|
||||
}
|
||||
}
|
||||
|
||||
const dateText = function (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 drawDateTime = function (date) {
|
||||
const t = settings.time
|
||||
g.setColor(t.color)
|
||||
g.setFont(t.font, t.size)
|
||||
|
@ -103,9 +102,9 @@
|
|||
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 drawBar = function (date) {
|
||||
const b = settings.bar
|
||||
const seconds = date.getSeconds()
|
||||
if (seconds === 0) {
|
||||
|
@ -116,16 +115,16 @@
|
|||
width = fraction * screen.width
|
||||
g.setColor(b.color)
|
||||
g.fillRect(0, b.top, width, b.top + b.thickness)
|
||||
}
|
||||
}
|
||||
|
||||
const clearScreen = function () {
|
||||
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 () {
|
||||
let lastSeconds, tTick
|
||||
const tick = function () {
|
||||
g.reset()
|
||||
const date = new Date()
|
||||
const seconds = date.getSeconds()
|
||||
|
@ -136,36 +135,35 @@
|
|||
}
|
||||
// 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)
|
||||
}
|
||||
|
||||
let iTick
|
||||
const start = function () {
|
||||
const start = function () {
|
||||
lastSeconds = 99 // force redraw
|
||||
tick()
|
||||
iTick = setInterval(tick, 1000)
|
||||
}
|
||||
const stop = function () {
|
||||
if (iTick) {
|
||||
clearInterval(iTick)
|
||||
iTick = undefined
|
||||
}
|
||||
}
|
||||
const stop = function () {
|
||||
if (tTick) {
|
||||
clearTimeout(tTick)
|
||||
tTick = undefined
|
||||
}
|
||||
}
|
||||
|
||||
// clean app screen
|
||||
g.clear()
|
||||
Bangle.loadWidgets()
|
||||
Bangle.drawWidgets()
|
||||
// Show launcher when middle button pressed
|
||||
setWatch(Bangle.showLauncher, BTN2, {repeat: false, edge: 'falling'})
|
||||
// clean app screen
|
||||
g.clear()
|
||||
Bangle.loadWidgets()
|
||||
Bangle.drawWidgets()
|
||||
// Show launcher when button pressed
|
||||
Bangle.setUI("clock");
|
||||
|
||||
Bangle.on('lcdPower', function (on) {
|
||||
Bangle.on('lcdPower', function (on) {
|
||||
if (on) {
|
||||
start()
|
||||
} else {
|
||||
stop()
|
||||
}
|
||||
})
|
||||
start()
|
||||
}
|
||||
})
|
||||
start()
|
||||
|
|
After Width: | Height: | Size: 2.7 KiB |
After Width: | Height: | Size: 2.5 KiB |
|
@ -1 +1,2 @@
|
|||
0.01: App Created!
|
||||
0.02: Update to use Bangle.setUI instead of setWatch
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
0.02: Modified for use with new bootloader and firmware
|
||||
0.03: Update to use Bangle.setUI instead of setWatch
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -51,64 +51,62 @@ 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<h<13)
|
||||
let R1, R2, RC1, RC2, CX, CY, HW2, MW2, HR, MR, M, HSCALE;
|
||||
|
||||
// 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<h<13)
|
||||
let R1, R2, RC1, RC2, CX, CY, HW2, MW2, HR, MR, M, HSCALE;
|
||||
// Screen size
|
||||
const GW = g.getWidth();
|
||||
const GH = g.getHeight();
|
||||
|
||||
// Screen size
|
||||
const GW = g.getWidth();
|
||||
const GH = g.getHeight();
|
||||
// Top margin: the gap taken from the top of the buffer, except when
|
||||
// in mode 0 (full screen)
|
||||
let TM;
|
||||
|
||||
// Top margin: the gap taken from the top of the buffer, except when
|
||||
// in mode 0 (full screen)
|
||||
let TM;
|
||||
// Buffer image. undefined means it needs regenerating
|
||||
let faceImg;
|
||||
|
||||
// Buffer image. undefined means it needs regenerating
|
||||
let faceImg;
|
||||
// with_seconds flag determines whether the face is updated every
|
||||
// second or every minute, and to draw the hand or not.
|
||||
let with_seconds = true;
|
||||
|
||||
// with_seconds flag determines whether the face is updated every
|
||||
// second or every minute, and to draw the hand or not.
|
||||
let with_seconds = true;
|
||||
// Display flags, determined from `mode` by setMode()
|
||||
let with_widgets = false;
|
||||
let with_digital_time = true;
|
||||
let with_digital_date = true;
|
||||
|
||||
// Display flags, determined from `mode` by setMode()
|
||||
let with_widgets = false;
|
||||
let with_digital_time = true;
|
||||
let with_digital_date = true;
|
||||
// Create offscreen buffer for the once-per-minute face draw
|
||||
const G1 = Graphics.createArrayBuffer(g.getWidth(), g.getHeight(), 1, {msb:true});
|
||||
|
||||
// Create offscreen buffer for the once-per-minute face draw
|
||||
const G1 = Graphics.createArrayBuffer(g.getWidth(), g.getHeight(), 1, {msb:true});
|
||||
|
||||
// Precalculate sin/cos for the hour marks. Might be premature
|
||||
// optimisation, but might as well.
|
||||
let ss = [], cs = [];
|
||||
for (let h=1; h<=12; h++) {
|
||||
// Precalculate sin/cos for the hour marks. Might be premature
|
||||
// optimisation, but might as well.
|
||||
let ss = [], cs = [];
|
||||
for (let h=1; h<=12; h++) {
|
||||
const a = Math.PI * h / 6;
|
||||
ss[h] = Math.sin(a);
|
||||
cs[h] = Math.cos(a);
|
||||
}
|
||||
}
|
||||
|
||||
// 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) => {
|
||||
// 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;
|
||||
|
@ -148,30 +146,30 @@ Graphics.prototype.drawRotLine = function (sina, cosa, cx, cy, r1, r2) {
|
|||
// widgets.
|
||||
const img = {width:GW,height:GH-TM,buffer:G.buffer};
|
||||
return img;
|
||||
};
|
||||
};
|
||||
|
||||
let hours, minutes, seconds, date;
|
||||
let hours, minutes, seconds, date;
|
||||
|
||||
// Schedule event for calling at the start of the next second
|
||||
const inOneSecond = (cb) => {
|
||||
// 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) => {
|
||||
// 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) =>
|
||||
// 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) => {
|
||||
// Redraw function
|
||||
const drawAll = (force) => {
|
||||
let now = new Date();
|
||||
|
||||
if (!faceImg) force = true;
|
||||
|
@ -274,23 +272,18 @@ Graphics.prototype.drawRotLine = function (sina, cosa, cx, cy, r1, r2) {
|
|||
inOneSecond(drawAll);
|
||||
else
|
||||
inOneMinute(drawAll);
|
||||
};
|
||||
};
|
||||
|
||||
const setButtons = () => {
|
||||
const opts = { repeat: true, edge:'rising', debounce:30};
|
||||
const setButtons = () => {
|
||||
// Show launcher when button pressed
|
||||
Bangle.setUI("clockupdown", btn=> {
|
||||
if (btn==0) changeSeconds();
|
||||
if (btn==1) { ++mode; setMode(); drawAll(true); }
|
||||
});
|
||||
};
|
||||
|
||||
// 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 = () => {
|
||||
// Load display parameters based on `mode`
|
||||
const setMode = () => {
|
||||
// Normalize mode to 0 <= mode <= 5
|
||||
mode = (6+mode) % 6;
|
||||
|
||||
|
@ -355,30 +348,30 @@ Graphics.prototype.drawRotLine = function (sina, cosa, cx, cy, r1, r2) {
|
|||
|
||||
// Clear the screen: we need to make sure all parts are cleaned off.
|
||||
g.clear();
|
||||
};
|
||||
};
|
||||
|
||||
const changeSeconds = () => {
|
||||
const changeSeconds = () => {
|
||||
with_seconds = !with_seconds;
|
||||
drawAll(true);
|
||||
};
|
||||
};
|
||||
|
||||
Bangle.loadWidgets();
|
||||
Bangle.loadWidgets();
|
||||
|
||||
// Restore mode
|
||||
try {
|
||||
// Restore mode
|
||||
try {
|
||||
conf = storage.readJSON(filename);
|
||||
mode = conf[0];
|
||||
with_seconds = conf[1];
|
||||
} catch (e) {
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
mode = 1;
|
||||
}
|
||||
}
|
||||
|
||||
setButtons();
|
||||
setMode();
|
||||
drawAll();
|
||||
setButtons();
|
||||
setMode();
|
||||
drawAll();
|
||||
|
||||
Bangle.on('lcdPower', (on) => {
|
||||
Bangle.on('lcdPower', (on) => {
|
||||
if (on) {
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
|
@ -386,6 +379,4 @@ Graphics.prototype.drawRotLine = function (sina, cosa, cx, cy, r1, r2) {
|
|||
} else {
|
||||
clearTimeout();
|
||||
}
|
||||
});
|
||||
|
||||
})(g);
|
||||
});
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -167,12 +167,12 @@ Bangle.on('lcdPower',on=>{
|
|||
// 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;
|
||||
}
|
||||
}, BTN, {edge:"rising", debounce:50, repeat:true});
|
||||
});
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -21,3 +21,8 @@
|
|||
0.20: Allow Gadgetbridge to work even with programmable:off
|
||||
0.21: Handle echo off char from Gadgetbridge app when programmable:off (fix #558)
|
||||
0.22: Stop LCD timeout being disabled on first run (when there is no settings.json)
|
||||
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
|
||||
|
|
|
@ -1,68 +1,2 @@
|
|||
// This ALWAYS runs at boot
|
||||
E.setFlags({pretokenise:1});
|
||||
// Load settings...
|
||||
var s = require('Storage').readJSON('setting.json',1)||{};
|
||||
if (s.ble!==false) {
|
||||
if (s.HID) { // Human interface device
|
||||
if (s.HID=="joy") Bangle.HID = E.toUint8Array(atob("BQEJBKEBCQGhAAUJGQEpBRUAJQGVBXUBgQKVA3UBgQMFAQkwCTEVgSV/dQiVAoECwMA="));
|
||||
else if (s.HID=="kb") Bangle.HID = E.toUint8Array(atob("BQEJBqEBBQcZ4CnnFQAlAXUBlQiBApUBdQiBAZUFdQEFCBkBKQWRApUBdQORAZUGdQgVACVzBQcZAClzgQAJBRUAJv8AdQiVArECwA=="));
|
||||
else /*kbmedia*/Bangle.HID = E.toUint8Array(atob("BQEJBqEBhQIFBxngKecVACUBdQGVCIEClQF1CIEBlQV1AQUIGQEpBZEClQF1A5EBlQZ1CBUAJXMFBxkAKXOBAAkFFQAm/wB1CJUCsQLABQwJAaEBhQEVACUBdQGVAQm1gQIJtoECCbeBAgm4gQIJzYECCeKBAgnpgQIJ6oECwA=="));
|
||||
NRF.setServices({}, {uart:true, hid:Bangle.HID});
|
||||
}
|
||||
}
|
||||
if (s.blerepl===false) { // If not programmable, force terminal off Bluetooth
|
||||
if (s.log) Terminal.setConsole(true); // if showing debug, force REPL onto terminal
|
||||
else E.setConsole(null,{force:true}); // on new (2v05+) firmware we have E.setConsole which allows a 'null' console
|
||||
/* If not programmable add our own handler for Bluetooth data
|
||||
to allow Gadgetbridge commands to be received*/
|
||||
Bluetooth.line="";
|
||||
Bluetooth.on('data',function(d) {
|
||||
var l = (Bluetooth.line + d).split("\n");
|
||||
Bluetooth.line = l.pop();
|
||||
l.forEach(n=>Bluetooth.emit("line",n));
|
||||
});
|
||||
Bluetooth.on('line',function(l) {
|
||||
if (l.startsWith('\x10')) l=l.slice(1);
|
||||
if (l.startsWith('GB({') && l.endsWith('})') && global.GB)
|
||||
try { global.GB(JSON.parse(l.slice(3,-1))); } catch(e) {}
|
||||
});
|
||||
} else {
|
||||
if (s.log && !NRF.getSecurityStatus().connected) Terminal.setConsole(); // if showing debug, put REPL on terminal (until connection)
|
||||
else Bluetooth.setConsole(true); // else if no debug, force REPL to Bluetooth
|
||||
}
|
||||
// we just reset, so BLE should be on.
|
||||
// Don't disconnect if something is already connected to us
|
||||
if (s.ble===false && !NRF.getSecurityStatus().connected) NRF.sleep();
|
||||
// Set time, vibrate, beep, etc
|
||||
if (!Bangle.F_BEEPSET) {
|
||||
if (!s.vibrate) Bangle.buzz=Promise.resolve;
|
||||
if (s.beep===false) Bangle.beep=Promise.resolve;
|
||||
else if (s.beep=="vib") Bangle.beep = function (time, freq) {
|
||||
return new Promise(function(resolve) {
|
||||
if ((0|freq)<=0) freq=4000;
|
||||
if ((0|time)<=0) time=200;
|
||||
if (time>5000) time=5000;
|
||||
analogWrite(D13,0.1,{freq:freq});
|
||||
setTimeout(function() {
|
||||
digitalWrite(D13,0);
|
||||
resolve();
|
||||
}, time);
|
||||
});
|
||||
};
|
||||
}
|
||||
if (s.timeout!==undefined) Bangle.setLCDTimeout(s.timeout);
|
||||
if (!s.timeout) Bangle.setLCDPower(1);
|
||||
E.setTimeZone(s.timezone);
|
||||
delete s;
|
||||
// Draw out of memory errors onto the screen
|
||||
E.on('errorFlag', function(errorFlags) {
|
||||
g.reset(1).setColor("#ff0000").setFont("6x8").setFontAlign(0,1).drawString(errorFlags,g.getWidth()/2,g.getHeight()-1).flip();
|
||||
print("Interpreter error:", errorFlags);
|
||||
E.getErrorFlags(); // clear flags so we get called next time
|
||||
});
|
||||
// stop users doing bad things!
|
||||
global.save = function() { throw new Error("You can't use save() on Bangle.js without overwriting the bootloader!"); }
|
||||
// Load *.boot.js files
|
||||
require('Storage').list(/\.boot\.js/).forEach(bootFile=>{
|
||||
eval(require('Storage').read(bootFile));
|
||||
});
|
||||
// Initially this runs and rewrites itself
|
||||
eval(require('Storage').read('bootupdate.js'));
|
||||
|
|
|
@ -14,11 +14,7 @@ if (!clockApp) {
|
|||
if (clockApp)
|
||||
clockApp = require("Storage").read(clockApp.src);
|
||||
}
|
||||
if (!clockApp) clockApp=`E.showMessage("No Clock Found");
|
||||
setWatch(() => {
|
||||
Bangle.showLauncher();
|
||||
}, BTN2, {repeat:false,edge:"falling"});)
|
||||
`;
|
||||
if (!clockApp) clockApp=`E.showMessage("No Clock Found");setWatch(()=>{Bangle.showLauncher();}, BTN2, {repeat:false,edge:"falling"});`;
|
||||
// check to see if our clock is wrong - if it is use GPS time
|
||||
if ((new Date()).getFullYear()<2000) {
|
||||
E.showMessage("Searching for\nGPS time");
|
||||
|
|
|
@ -0,0 +1,143 @@
|
|||
/* This rewrites boot0.js based on current settings. If settings changed then it
|
||||
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`;
|
||||
boot += `E.setFlags({pretokenise:1});\n`;
|
||||
if (s.ble!==false) {
|
||||
if (s.HID) { // Human interface device
|
||||
if (s.HID=="joy") boot += `Bangle.HID = E.toUint8Array(atob("BQEJBKEBCQGhAAUJGQEpBRUAJQGVBXUBgQKVA3UBgQMFAQkwCTEVgSV/dQiVAoECwMA="));`;
|
||||
else if (s.HID=="kb") boot += `Bangle.HID = E.toUint8Array(atob("BQEJBqEBBQcZ4CnnFQAlAXUBlQiBApUBdQiBAZUFdQEFCBkBKQWRApUBdQORAZUGdQgVACVzBQcZAClzgQAJBRUAJv8AdQiVArECwA=="));`
|
||||
else /*kbmedia*/boot += `Bangle.HID = E.toUint8Array(atob("BQEJBqEBhQIFBxngKecVACUBdQGVCIEClQF1CIEBlQV1AQUIGQEpBZEClQF1A5EBlQZ1CBUAJXMFBxkAKXOBAAkFFQAm/wB1CJUCsQLABQwJAaEBhQEVACUBdQGVAQm1gQIJtoECCbeBAgm4gQIJzYECCeKBAgnpgQIJ6oECwA=="));`;
|
||||
boot += `NRF.setServices({}, {uart:true, hid:Bangle.HID});\n`;
|
||||
}
|
||||
}
|
||||
if (s.blerepl===false) { // If not programmable, force terminal off Bluetooth
|
||||
if (s.log) boot += `Terminal.setConsole(true);\n`; // if showing debug, force REPL onto terminal
|
||||
else boot += `E.setConsole(null,{force:true});\n`; // on new (2v05+) firmware we have E.setConsole which allows a 'null' console
|
||||
/* If not programmable add our own handler for Bluetooth data
|
||||
to allow Gadgetbridge commands to be received*/
|
||||
boot += `
|
||||
Bluetooth.line="";
|
||||
Bluetooth.on('data',function(d) {
|
||||
var l = (Bluetooth.line + d).split("\n");
|
||||
Bluetooth.line = l.pop();
|
||||
l.forEach(n=>Bluetooth.emit("line",n));
|
||||
});
|
||||
Bluetooth.on('line',function(l) {
|
||||
if (l.startsWith('\x10')) l=l.slice(1);
|
||||
if (l.startsWith('GB({') && l.endsWith('})') && global.GB)
|
||||
try { global.GB(JSON.parse(l.slice(3,-1))); } catch(e) {}
|
||||
});\n`;
|
||||
} else {
|
||||
if (s.log) boot += `if (!NRF.getSecurityStatus().connected) Terminal.setConsole();\n`; // if showing debug, put REPL on terminal (until connection)
|
||||
else boot += `Bluetooth.setConsole(true);\n`; // else if no debug, force REPL to Bluetooth
|
||||
}
|
||||
// we just reset, so BLE should be on.
|
||||
// Don't disconnect if something is already connected to us
|
||||
if (s.ble===false) boot += `if (!NRF.getSecurityStatus().connected) NRF.sleep();\n`;
|
||||
// Set time
|
||||
if (s.timeout!==undefined) boot += `Bangle.setLCDTimeout(${s.timeout});\n`;
|
||||
if (!s.timeout) boot += `Bangle.setLCDPower(1);\n`;
|
||||
boot += `E.setTimeZone(${s.timezone});`;
|
||||
// Set vibrate, beep, etc IF on older firmwares
|
||||
if (!Bangle.F_BEEPSET) {
|
||||
if (!s.vibrate) boot += `Bangle.buzz=Promise.resolve;\n`
|
||||
if (s.beep===false) boot += `Bangle.beep=Promise.resolve;\n`
|
||||
else if (s.beep=="vib") boot += `Bangle.beep = function (time, freq) {
|
||||
return new Promise(function(resolve) {
|
||||
if ((0|freq)<=0) freq=4000;
|
||||
if ((0|time)<=0) time=200;
|
||||
if (time>5000) time=5000;
|
||||
analogWrite(D13,0.1,{freq:freq});
|
||||
setTimeout(function() {
|
||||
digitalWrite(D13,0);
|
||||
resolve();
|
||||
}, time);
|
||||
});
|
||||
};\n`;
|
||||
}
|
||||
// Draw out of memory errors onto the screen
|
||||
boot += `E.on('errorFlag', function(errorFlags) {
|
||||
g.reset(1).setColor("#ff0000").setFont("6x8").setFontAlign(0,1).drawString(errorFlags,g.getWidth()/2,g.getHeight()-1).flip();
|
||||
print("Interpreter error:", errorFlags);
|
||||
E.getErrorFlags(); // clear flags so we get called next time
|
||||
});\n`;
|
||||
// stop users doing bad things!
|
||||
if (global.save) boot += `global.save = function() { throw new Error("You can't use save() on Bangle.js without overwriting the bootloader!"); }\n`;
|
||||
// Apply any settings-specific stuff
|
||||
if (s.options) boot+=`Bangle.setOptions(${E.toJS(s.options)});\n`;
|
||||
if (s.quiet && s.qmOptions) boot+=`Bangle.setOptions(${E.toJS(s.qmOptions)});\n`;
|
||||
if (s.quiet && s.qmBrightness) {
|
||||
if (s.qmBrightness!=1) boot+=`Bangle.setLCDBrightness(${s.qmBrightness});\n`;
|
||||
} else {
|
||||
if (s.brightness && s.brightness!=1) boot+=`Bangle.setLCDBrightness(${s.brightness});\n`;
|
||||
}
|
||||
if (s.quiet && s.qmTimeout) boot+=`Bangle.setLCDTimeout(${s.qmTimeout});\n`;
|
||||
if (s.passkey!==undefined && s.passkey.length==6) boot+=`NRF.setSecurity({passkey:${s.passkey}, mitm:1, display:1});\n`;
|
||||
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,dark:true};\n`;
|
||||
}
|
||||
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);
|
||||
delete Bangle.btnWatches;
|
||||
}
|
||||
if (Bangle.swipeHandler) {
|
||||
Bangle.removeListener("swipe", Bangle.swipeHandler);
|
||||
delete Bangle.swipeHandler;
|
||||
}
|
||||
if (Bangle.touchandler) {
|
||||
Bangle.removeListener("touch", Bangle.touchHandler);
|
||||
delete Bangle.touchHandler;
|
||||
}
|
||||
if (!mode) return;
|
||||
else if (mode=="updown") {
|
||||
Bangle.btnWatches = [
|
||||
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() { cb(-1); }, BTN1, {repeat:1}),
|
||||
setWatch(function() { cb(1); }, BTN3, {repeat:1}),
|
||||
setWatch(function() { cb(); }, BTN2, {repeat:1})
|
||||
];
|
||||
Bangle.swipeHandler = d => {cb(d);};
|
||||
Bangle.on("swipe", Bangle.swipeHandler);
|
||||
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`;
|
||||
}
|
||||
// Append *.boot.js files
|
||||
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);
|
||||
delete boot;
|
||||
E.showMessage("Reloading...");
|
||||
eval(require('Storage').read('.boot0'));
|
||||
eval(require('Storage').read('.bootcde'));
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 4.0 KiB |
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 7.4 KiB |
|
@ -1 +1,2 @@
|
|||
0.01: Basic calendar
|
||||
0.02: Make Bangle 2 compatible
|
||||
|
|
|
@ -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(
|
||||
() => {
|
||||
Bangle.on("touch",area=>{
|
||||
const month = date.getMonth();
|
||||
const prevMonth = month > 0 ? month - 1 : 11;
|
||||
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" });
|
||||
});
|
||||
|
||||
// Show launcher when button pressed
|
||||
Bangle.setUI("clock"); // TODO: ideally don't set 'clock' mode
|
||||
// No space for widgets!
|
||||
|
|
|
@ -3,3 +3,5 @@
|
|||
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
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
var fontsize = 3;
|
||||
var fontsize = g.getWidth()>200 ? 3 : 2;
|
||||
var fontheight = 10*fontsize;
|
||||
var locale = require("locale");
|
||||
var marginTop = 40;
|
||||
var flag = false;
|
||||
var WeekDays = ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];
|
||||
|
||||
var hrtOn = false;
|
||||
var hrtStr = "Hrt: ??? bpm";
|
||||
|
@ -26,41 +26,37 @@ function drawAll(){
|
|||
}
|
||||
|
||||
function updateRest(now){
|
||||
let date = locale.date(now,false);
|
||||
writeLine(WeekDays[now.getDay()],1);
|
||||
writeLine(date,2);
|
||||
writeLine(locale.dow(now),1);
|
||||
writeLine(locale.date(now,1),2);
|
||||
drawInfo(5);
|
||||
}
|
||||
function updateTime(){
|
||||
if (!Bangle.isLCDOn()) return;
|
||||
let now = new Date();
|
||||
let h = now.getHours();
|
||||
let m = now.getMinutes();
|
||||
h = h>=10?h:"0"+h;
|
||||
m = m>=10?m:"0"+m;
|
||||
writeLine(h+":"+m,0);
|
||||
writeLine(locale.time(now,1),0);
|
||||
writeLine(flag?" ":"_",3);
|
||||
flag = !flag;
|
||||
if(now.getMinutes() == 0)
|
||||
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);
|
||||
|
||||
|
@ -68,7 +64,7 @@ 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;
|
||||
|
@ -76,7 +72,7 @@ function drawInfo(line) {
|
|||
|
||||
switch(infoMode) {
|
||||
case NONE_MODE:
|
||||
col = 0x0000;
|
||||
col = "#fff";
|
||||
str = "";
|
||||
break;
|
||||
case HRT_MODE:
|
||||
|
@ -106,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() {
|
||||
|
@ -191,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();
|
||||
});
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"});
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
0.02: Modified for use with new bootloader and firmware
|
||||
0.03: Changed setWatch to Bangle.setUI
|
||||
|
|
|
@ -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"});
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"});
|
|
@ -0,0 +1,2 @@
|
|||
0.01: New App!
|
||||
0.02: Adjust for different screen types and themes
|
|
@ -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(()=>{
|
||||
Bangle.buzz(100,0.1).then(()=>{
|
||||
g.clear();
|
||||
return new Promise(resolve=>setTimeout(resolve,250)); // wait 250ms
|
||||
}).then(()=>{
|
||||
}).then(()=>{
|
||||
return Bangle.buzz(150);
|
||||
}).then(()=>{
|
||||
g.drawImage(img, 25, 40, {scale:2});
|
||||
});
|
||||
|
||||
}).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");
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,9 +25,9 @@ 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) {
|
||||
|
@ -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);
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
0.01: App Made!
|
||||
0.02: Changed setWatch to Bangle.setUI, code tidy
|
||||
|
|
|
@ -10,104 +10,13 @@ function draw() {
|
|||
var date = new Date();
|
||||
var h = date.getHours();
|
||||
var m = date.getMinutes();
|
||||
var day = date.getDay();
|
||||
var month = date.getMonth();
|
||||
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);
|
||||
|
||||
//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;
|
||||
|
||||
}
|
||||
|
||||
if (h > 12) {
|
||||
half = "PM";
|
||||
h = h - 12;
|
||||
|
@ -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"});
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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" });
|
||||
|
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 9.8 KiB After Width: | Height: | Size: 9.8 KiB |
|
@ -1 +1,2 @@
|
|||
0.01: First released version
|
||||
0.02: Changed setWatch to Bangle.setUI
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
(() => {
|
||||
// Current shown notification, saved for dismissing.
|
||||
var currentNot = null;
|
||||
|
||||
// Music handling
|
||||
const state = {
|
||||
music: "stop",
|
||||
|
@ -151,15 +154,18 @@
|
|||
global.GB = (event) => {
|
||||
switch (event.t) {
|
||||
case "notify":
|
||||
case "notify-":
|
||||
if (event.t === "notify") {
|
||||
require("notify").show(prettifyNotificationEvent(event));
|
||||
currentNot = prettifyNotificationEvent(event);
|
||||
require("notify").show(currentNot);
|
||||
if (!(require('Storage').readJSON('setting.json',1)||{}).quiet) {
|
||||
Bangle.buzz();
|
||||
}
|
||||
} else { // notify-
|
||||
break;
|
||||
case "notify-":
|
||||
currentNot.t = "notify";
|
||||
currentNot.n = "DISMISS";
|
||||
gbSend(currentNot);
|
||||
currentNot = null;
|
||||
require("notify").hide(event);
|
||||
}
|
||||
break;
|
||||
case "musicinfo":
|
||||
state.musicInfo = event;
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
0.01: Initial version
|
|
@ -0,0 +1,15 @@
|
|||
# Gadgetbridge Twist Control
|
||||
|
||||
Control your music app (e.g. MortPlayer Music [a folder based, not tag based player] ) that handles multiple play-commands (same as using a single-button-headset's button to change songs) on your Gadgetbridge-connected phone.
|
||||
- Activate counting for 4 seconds with a twist (beeps at start and end of counting)
|
||||
- twist multiple times for:
|
||||
play/pause (1),
|
||||
next song (2),
|
||||
prev. song (3),
|
||||
next folder (4),
|
||||
prev. folder (5),
|
||||
reset counter (6)
|
||||
- the command to be sent is shown in green
|
||||
- Volume up/down is controlled by BTN1/BTN3 presses
|
||||
|
||||

|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("mEwwIYVhAFEjgFEh4FEg+AAocD4AME8ADCgPAvAFCj/8nkQAoN//8enAQB///44FBgYFB8f4FoIFB+IFBh/+n/4AocH/AXBj/+gP8FIIFDFwM//0x/wFDAIIFNv4FB/4FNEaIFFj/gn5HCj+AAoUEh4FBMgUP4AFDw/gv/wAoPDPoKhBjnxAoKtBjl4TYLICninBagUPWYLJPFoIADZIYABnj6KABIA="))
|
|
@ -0,0 +1,97 @@
|
|||
// just a watch, to fill an empty screen
|
||||
|
||||
function drwClock() {
|
||||
var d = new Date();
|
||||
var h = d.getHours(), m = d.getMinutes();
|
||||
var time = ("0"+h).substr(-2) + ":" + ("0"+m).substr(-2);
|
||||
g.reset();
|
||||
g.setFont('6x8',7);
|
||||
g.setFontAlign(-1,-1);
|
||||
g.drawString(time,20,80);
|
||||
}
|
||||
|
||||
g.clear();
|
||||
drwClock();
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
|
||||
/////////////////////////////////////////////////////////////
|
||||
// control music by twist/buttons
|
||||
|
||||
var counter = 0; //stores your counted your twists
|
||||
var tstate = false; //are you ready to count the twists?
|
||||
|
||||
function playx() {
|
||||
Bluetooth.println(JSON.stringify({t:"music", n:"play"}));
|
||||
}
|
||||
|
||||
function volup() {
|
||||
Bluetooth.println(JSON.stringify({t:"music", n:"volumeup"}));
|
||||
}
|
||||
|
||||
function voldn() {
|
||||
Bluetooth.println(JSON.stringify({t:"music", n:"volumedown"}));
|
||||
}
|
||||
|
||||
function sendCmd() {
|
||||
print (counter);
|
||||
Bangle.beep(200,3000);
|
||||
if (tstate==false && counter>0){
|
||||
do {playx(); counter--;}
|
||||
while (counter >= 1);
|
||||
}
|
||||
}
|
||||
|
||||
function twistctrl() {
|
||||
if (tstate==false){
|
||||
tstate=true;
|
||||
setTimeout('tstate=false',4000);
|
||||
setTimeout(sendCmd,4100);
|
||||
Bangle.beep(200,3000);
|
||||
}
|
||||
else{
|
||||
g.clearRect(10,140,230,200);
|
||||
if (tstate==true){
|
||||
if (counter < 5){
|
||||
counter++;
|
||||
drwCmd();
|
||||
Bangle.buzz(100,2);
|
||||
}
|
||||
else {
|
||||
counter = 0;
|
||||
Bangle.buzz(400);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function drwCmd() {
|
||||
g.setFont('6x8',6);
|
||||
g.setColor(0.3,1,0.3);
|
||||
g.clearRect(10,140,230,200);
|
||||
switch (counter){
|
||||
case 1:
|
||||
g.drawString('play',50,150);
|
||||
break;
|
||||
case 2:
|
||||
g.drawString('next',50,150);
|
||||
break;
|
||||
case 3:
|
||||
g.drawString('prev',50,150);
|
||||
break;
|
||||
case 4:
|
||||
g.drawString('nx f',50,150);
|
||||
break;
|
||||
case 5:
|
||||
g.drawString('pr f',50,150);
|
||||
break;
|
||||
case 0:
|
||||
g.clearRect(10,140,230,200);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
setWatch(volup,BTN1,{repeat:true});
|
||||
setWatch(voldn,BTN3,{repeat:true});
|
||||
Bangle.on('twist',twistctrl);
|
||||
setWatch(Bangle.showLauncher, BTN2, {repeat:false,edge:"falling"});
|
After Width: | Height: | Size: 906 B |
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
# GPS Recorder
|
||||
|
||||

|
||||
|
||||
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.
|
||||
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
0.01: New App!
|
||||
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
|
||||
|
|
|
@ -4,18 +4,25 @@ Bangle.setHRMPower(1);
|
|||
var hrmInfo, hrmOffset = 0;
|
||||
var hrmInterval;
|
||||
function onHRM(h) {
|
||||
// this is the first time we're called
|
||||
if (counter!==undefined) {
|
||||
// the first time we're called remove
|
||||
// the countdown
|
||||
counter = undefined;
|
||||
g.clear();
|
||||
}
|
||||
hrmInfo = h;
|
||||
hrmOffset = 0;
|
||||
/* On 2v09 and earlier firmwares the only solution for realtime
|
||||
HRM was to look at the 'raw' array that got reported. If you timed
|
||||
it right you could grab the data pretty much as soon as it was written.
|
||||
In new firmwares, '.raw' is not available. */
|
||||
if (hrmInterval) clearInterval(hrmInterval);
|
||||
hrmInterval = undefined;
|
||||
if (hrmInfo.raw) {
|
||||
hrmOffset = 0;
|
||||
setTimeout(function() {
|
||||
hrmInterval = setInterval(readHRM,41);
|
||||
}, 40);
|
||||
}
|
||||
|
||||
var px = g.getWidth()/2;
|
||||
g.setFontAlign(0,0);
|
||||
|
@ -28,13 +35,32 @@ function onHRM(h) {
|
|||
g.drawString("BPM",px+15,45);
|
||||
}
|
||||
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.moveTo(-100,0);
|
||||
}
|
||||
|
||||
y = E.clip(170 - (v.raw*2),100,230);
|
||||
g.setColor(1,1,1);
|
||||
g.lineTo(hrmOffset, y);
|
||||
});
|
||||
|
||||
// It takes 5 secs for us to get the first HRM event
|
||||
var counter = 5;
|
||||
function countDown() {
|
||||
E.showMessage("Please wait...\n"+counter--);
|
||||
if (counter) setTimeout(countDown, 1000);
|
||||
if (counter) {
|
||||
g.drawString(counter--,g.getWidth()/2,g.getHeight()/2, true);
|
||||
setTimeout(countDown, 1000);
|
||||
}
|
||||
}
|
||||
g.clear().setFont("6x8",2).setFontAlign(0,0);
|
||||
g.drawString("Please wait...",g.getWidth()/2,g.getHeight()/2 - 16);
|
||||
countDown();
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -41,9 +41,25 @@ The following buttons depend on which face is currently in use
|
|||
- Waypointer : select next waypoint
|
||||
|
||||
|
||||
## Stepo2
|
||||

|
||||
|
||||
- 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
|
||||

|
||||
|
||||
- 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
|
||||

|
||||
- 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
|
||||

|
||||
- A simple stopwatch
|
||||
|
@ -76,6 +94,9 @@ The following buttons depend on which face is currently in use
|
|||
## Heart
|
||||

|
||||
- 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
|
||||
|
|
|
@ -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();
|
||||
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
After Width: | Height: | Size: 30 KiB |
|
@ -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;
|
||||
})();
|
|
@ -2,3 +2,5 @@
|
|||
0.02: Only store relevant app data (saves RAM when many apps)
|
||||
0.03: Allow scrolling to wrap around (fix #382)
|
||||
0.04: Now displays widgets
|
||||
0.05: Use g.theme for colours
|
||||
0.06: Use Bangle.setUI for buttons
|
||||
|
|
|
@ -12,47 +12,44 @@ var menuScroll = 0;
|
|||
var menuShowing = false;
|
||||
|
||||
function drawMenu() {
|
||||
g.setFont("6x8",2);
|
||||
g.setFontAlign(-1,0);
|
||||
var n = 3;
|
||||
g.reset().setFont("6x8",2).setFontAlign(-1,0);
|
||||
var w = g.getWidth();
|
||||
var h = g.getHeight();
|
||||
var m = w/2;
|
||||
var n = (h-48)/64;
|
||||
if (selected>=n+menuScroll) menuScroll = 1+selected-n;
|
||||
if (selected<menuScroll) menuScroll = selected;
|
||||
// arrows
|
||||
g.setColor(menuScroll ? -1 : 0);
|
||||
g.fillPoly([120,6,106,20,134,20]);
|
||||
g.setColor((apps.length>n+menuScroll) ? -1 : 0);
|
||||
g.fillPoly([120,233,106,219,134,219]);
|
||||
g.setColor(menuScroll ? g.theme.fg : g.theme.bg);
|
||||
g.fillPoly([m,6,m-14,20,m+14,20]);
|
||||
g.setColor((apps.length>n+menuScroll) ? g.theme.fg : g.theme.bg);
|
||||
g.fillPoly([m,h-7,m-14,h-21,m+14,h-21]);
|
||||
// draw
|
||||
g.setColor(-1);
|
||||
g.setColor(g.theme.fg);
|
||||
for (var i=0;i<n;i++) {
|
||||
var app = apps[i+menuScroll];
|
||||
if (!app) break;
|
||||
var y = 24+i*64;
|
||||
if (i+menuScroll==selected) {
|
||||
g.setColor(0.3,0.3,0.3);
|
||||
g.fillRect(0,y,239,y+63);
|
||||
g.setColor(1,1,1);
|
||||
g.drawRect(0,y,239,y+63);
|
||||
g.setColor(g.theme.bgH).fillRect(0,y,w-1,y+63);
|
||||
g.setColor(g.theme.fgH).drawRect(0,y,w-1,y+63);
|
||||
} else
|
||||
g.clearRect(0,y,239,y+63);
|
||||
g.clearRect(0,y,w-1,y+63);
|
||||
g.drawString(app.name,64,y+32);
|
||||
var icon=undefined;
|
||||
if (app.icon) icon = s.read(app.icon);
|
||||
if (icon) try {g.drawImage(icon,8,y+8);} catch(e){}
|
||||
}
|
||||
}
|
||||
g.clear();
|
||||
drawMenu();
|
||||
setWatch(function() {
|
||||
selected--;
|
||||
Bangle.setUI("updown",dir=>{
|
||||
if (dir) {
|
||||
selected += dir;
|
||||
if (selected<0) selected = apps.length-1;
|
||||
drawMenu();
|
||||
}, BTN1, {repeat:true});
|
||||
setWatch(function() {
|
||||
selected++;
|
||||
if (selected>=apps.length) selected = 0;
|
||||
drawMenu();
|
||||
}, BTN3, {repeat:true});
|
||||
setWatch(function() { // run
|
||||
} else {
|
||||
if (!apps[selected].src) return;
|
||||
if (require("Storage").read(apps[selected].src)===undefined) {
|
||||
E.showMessage("App Source\nNot found");
|
||||
|
@ -61,6 +58,7 @@ setWatch(function() { // run
|
|||
E.showMessage("Loading...");
|
||||
load(apps[selected].src);
|
||||
}
|
||||
}, BTN2, {repeat:true,edge:"falling"});
|
||||
}
|
||||
});
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
0.01: New App!
|
|
@ -0,0 +1,67 @@
|
|||
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.name<b.name) return -1;
|
||||
if (a.name>b.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<n;i++) drawApp(i);
|
||||
g.setClipRect(0,0,g.getWidth()-1,g.getHeight()-1);
|
||||
}
|
||||
g.clear();
|
||||
drawMenu();
|
||||
Bangle.on('drag',e=>{
|
||||
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();
|
After Width: | Height: | Size: 899 B |
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 707 B After Width: | Height: | Size: 707 B |
Before Width: | Height: | Size: 707 B After Width: | Height: | Size: 707 B |