mirror of https://github.com/espruino/BangleApps
commit
e975bad1ad
|
@ -3,3 +3,4 @@ node_modules
|
||||||
package-lock.json
|
package-lock.json
|
||||||
.DS_Store
|
.DS_Store
|
||||||
*.js.bak
|
*.js.bak
|
||||||
|
appdates.csv
|
||||||
|
|
|
@ -14,3 +14,7 @@ Changed for individual apps are listed in `apps/appname/ChangeLog`
|
||||||
* Added espruinotools.js for pretokenisation
|
* Added espruinotools.js for pretokenisation
|
||||||
* Included image and compression tools in repo
|
* Included image and compression tools in repo
|
||||||
* Added better upload of large files (incl. compression)
|
* Added better upload of large files (incl. compression)
|
||||||
|
* URL fetch is now async
|
||||||
|
* Adding '#search' after the URL (when not the name of a 'filter' chip) will set up search for that term
|
||||||
|
* If `bin/pre-publish.sh` has been run and recent.csv created, add 'Sort By' chip
|
||||||
|
* New 'espruinotools' which fixes pretokenise issue when ID follows ID (fix #416)
|
||||||
|
|
|
@ -344,6 +344,9 @@ that handles configuring the app.
|
||||||
When the app settings are opened, this function is called with one
|
When the app settings are opened, this function is called with one
|
||||||
argument, `back`: a callback to return to the settings menu.
|
argument, `back`: a callback to return to the settings menu.
|
||||||
|
|
||||||
|
Usually it will save any information in `app.json` where `app` is the name
|
||||||
|
of your app - so you should change the example accordingly.
|
||||||
|
|
||||||
Example `settings.js`
|
Example `settings.js`
|
||||||
```js
|
```js
|
||||||
// make sure to enclose the function in parentheses
|
// make sure to enclose the function in parentheses
|
||||||
|
|
82
apps.json
82
apps.json
|
@ -2,7 +2,7 @@
|
||||||
{ "id": "boot",
|
{ "id": "boot",
|
||||||
"name": "Bootloader",
|
"name": "Bootloader",
|
||||||
"icon": "bootloader.png",
|
"icon": "bootloader.png",
|
||||||
"version":"0.16",
|
"version":"0.17",
|
||||||
"description": "This is needed by Bangle.js to automatically load the clock, menu, widgets and settings",
|
"description": "This is needed by Bangle.js to automatically load the clock, menu, widgets and settings",
|
||||||
"tags": "tool,system",
|
"tags": "tool,system",
|
||||||
"type":"bootloader",
|
"type":"bootloader",
|
||||||
|
@ -78,7 +78,7 @@
|
||||||
{ "id": "welcome",
|
{ "id": "welcome",
|
||||||
"name": "Welcome",
|
"name": "Welcome",
|
||||||
"icon": "app.png",
|
"icon": "app.png",
|
||||||
"version":"0.08",
|
"version":"0.09",
|
||||||
"description": "Appears at first boot and explains how to use Bangle.js",
|
"description": "Appears at first boot and explains how to use Bangle.js",
|
||||||
"tags": "start,welcome",
|
"tags": "start,welcome",
|
||||||
"allow_emulator":true,
|
"allow_emulator":true,
|
||||||
|
@ -108,7 +108,7 @@
|
||||||
{ "id": "mclock",
|
{ "id": "mclock",
|
||||||
"name": "Morphing Clock",
|
"name": "Morphing Clock",
|
||||||
"icon": "clock-morphing.png",
|
"icon": "clock-morphing.png",
|
||||||
"version":"0.05",
|
"version":"0.06",
|
||||||
"description": "7 segment clock that morphs between minutes and hours",
|
"description": "7 segment clock that morphs between minutes and hours",
|
||||||
"tags": "clock",
|
"tags": "clock",
|
||||||
"type":"clock",
|
"type":"clock",
|
||||||
|
@ -168,7 +168,7 @@
|
||||||
"name": "Image background clock",
|
"name": "Image background clock",
|
||||||
"shortName":"Image Clock",
|
"shortName":"Image Clock",
|
||||||
"icon": "app.png",
|
"icon": "app.png",
|
||||||
"version":"0.05",
|
"version":"0.06",
|
||||||
"description": "A clock with an image as a background",
|
"description": "A clock with an image as a background",
|
||||||
"tags": "clock",
|
"tags": "clock",
|
||||||
"type" : "clock",
|
"type" : "clock",
|
||||||
|
@ -589,7 +589,7 @@
|
||||||
"id": "ncstart",
|
"id": "ncstart",
|
||||||
"name": "NCEU Startup",
|
"name": "NCEU Startup",
|
||||||
"icon": "start.png",
|
"icon": "start.png",
|
||||||
"version":"0.05",
|
"version":"0.06",
|
||||||
"description": "NodeConfEU 2019 'First Start' Sequence",
|
"description": "NodeConfEU 2019 'First Start' Sequence",
|
||||||
"tags": "start,welcome",
|
"tags": "start,welcome",
|
||||||
"storage": [
|
"storage": [
|
||||||
|
@ -1272,7 +1272,7 @@
|
||||||
"name": "Battery Chart",
|
"name": "Battery Chart",
|
||||||
"shortName":"Battery Chart",
|
"shortName":"Battery Chart",
|
||||||
"icon": "app.png",
|
"icon": "app.png",
|
||||||
"version":"0.09",
|
"version":"0.10",
|
||||||
"readme": "README.md",
|
"readme": "README.md",
|
||||||
"description": "A widget and an app for recording and visualizing battery percentage over time.",
|
"description": "A widget and an app for recording and visualizing battery percentage over time.",
|
||||||
"tags": "app,widget,battery,time,record,chart,tool",
|
"tags": "app,widget,battery,time,record,chart,tool",
|
||||||
|
@ -1421,7 +1421,7 @@
|
||||||
"id": "metronome",
|
"id": "metronome",
|
||||||
"name": "Metronome",
|
"name": "Metronome",
|
||||||
"icon": "metronome_icon.png",
|
"icon": "metronome_icon.png",
|
||||||
"version": "0.04",
|
"version": "0.05",
|
||||||
"readme": "README.md",
|
"readme": "README.md",
|
||||||
"description": "Makes the watch blinking and vibrating with a given rate",
|
"description": "Makes the watch blinking and vibrating with a given rate",
|
||||||
"tags": "tool",
|
"tags": "tool",
|
||||||
|
@ -1435,7 +1435,8 @@
|
||||||
"name": "metronome.img",
|
"name": "metronome.img",
|
||||||
"url": "metronome-icon.js",
|
"url": "metronome-icon.js",
|
||||||
"evaluate": true
|
"evaluate": true
|
||||||
}
|
},
|
||||||
|
{"name":"metronome.settings.js","url":"settings.js"}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{ "id": "blackjack",
|
{ "id": "blackjack",
|
||||||
|
@ -1469,7 +1470,7 @@
|
||||||
"name": "Round clock with seconds, minutes and date",
|
"name": "Round clock with seconds, minutes and date",
|
||||||
"shortName":"Round Clock",
|
"shortName":"Round Clock",
|
||||||
"icon": "app.png",
|
"icon": "app.png",
|
||||||
"version":"0.02",
|
"version":"0.03",
|
||||||
"description": "Designed round clock with ticks for minutes and seconds and heart rate indication",
|
"description": "Designed round clock with ticks for minutes and seconds and heart rate indication",
|
||||||
"tags": "clock",
|
"tags": "clock",
|
||||||
"type": "clock",
|
"type": "clock",
|
||||||
|
@ -1572,7 +1573,7 @@
|
||||||
"id": "largeclock",
|
"id": "largeclock",
|
||||||
"name": "Large Clock",
|
"name": "Large Clock",
|
||||||
"icon": "largeclock.png",
|
"icon": "largeclock.png",
|
||||||
"version": "0.02",
|
"version": "0.03",
|
||||||
"description": "A readable and informational digital watch, with date, seconds and moon phase",
|
"description": "A readable and informational digital watch, with date, seconds and moon phase",
|
||||||
"readme": "README.md",
|
"readme": "README.md",
|
||||||
"tags": "clock",
|
"tags": "clock",
|
||||||
|
@ -1591,12 +1592,10 @@
|
||||||
{
|
{
|
||||||
"name": "largeclock.settings.js",
|
"name": "largeclock.settings.js",
|
||||||
"url": "settings.js"
|
"url": "settings.js"
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "largeclock.json",
|
|
||||||
"url": "largeclock.json",
|
|
||||||
"evaluate": true
|
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
"data": [
|
||||||
|
{"name":"largeclock.json"}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{ "id": "smtswch",
|
{ "id": "smtswch",
|
||||||
|
@ -1617,6 +1616,18 @@
|
||||||
{"name":"switch-off.img","url":"switch-off.js","evaluate":true}
|
{"name":"switch-off.img","url":"switch-off.js","evaluate":true}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{ "id": "miplant",
|
||||||
|
"name": "Xiaomi Plant Sensor",
|
||||||
|
"shortName":"Mi Plant",
|
||||||
|
"icon": "app.png",
|
||||||
|
"version":"0.01",
|
||||||
|
"description": "Reads and displays data from Xiaomi bluetooth plant moisture sensors",
|
||||||
|
"tags": "xiaomi,mi,plant,ble,bluetooth",
|
||||||
|
"storage": [
|
||||||
|
{"name":"miplant.app.js","url":"app.js"},
|
||||||
|
{"name":"miplant.img","url":"app-icon.js","evaluate":true}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "simpletimer",
|
"id": "simpletimer",
|
||||||
"name": "Timer",
|
"name": "Timer",
|
||||||
|
@ -1708,7 +1719,46 @@
|
||||||
{ "name": "gallifr.settings.js", "url": "settings.js" }
|
{ "name": "gallifr.settings.js", "url": "settings.js" }
|
||||||
],
|
],
|
||||||
"data": [
|
"data": [
|
||||||
{"name":"app.json"}
|
{"name":"gallifr.json"}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{ "id": "rndmclk",
|
||||||
|
"name": "Random Clock Loader",
|
||||||
|
"icon": "rndmclk.png",
|
||||||
|
"version":"0.02",
|
||||||
|
"description": "Load a different clock whenever the LCD is switched on.",
|
||||||
|
"readme": "README.md",
|
||||||
|
"tags": "widget,clock",
|
||||||
|
"type":"widget",
|
||||||
|
"storage": [
|
||||||
|
{"name":"rndmclk.wid.js","url":"widget.js"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{ "id": "dotmatrixclock",
|
||||||
|
"name": "Dotmatrix Clock",
|
||||||
|
"icon": "dotmatrixclock.png",
|
||||||
|
"version":"0.01",
|
||||||
|
"description": "A clear white-on-blue dotmatrix simulated clock",
|
||||||
|
"tags": "clock,dotmatrix,retro",
|
||||||
|
"type": "clock",
|
||||||
|
"allow_emulator":true,
|
||||||
|
"readme": "README.md",
|
||||||
|
"storage": [
|
||||||
|
{"name":"dotmatrixclock.app.js","url":"app.js"},
|
||||||
|
{"name":"dotmatrixclock.img","url":"dotmatrixclock-icon.js","evaluate":true}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "jbm8b",
|
||||||
|
"name": "Magic 8 Ball",
|
||||||
|
"shortName": "Magic 8 Ball",
|
||||||
|
"icon": "app.png",
|
||||||
|
"description": "A simple fortune telling app",
|
||||||
|
"tags": "game",
|
||||||
|
"storage": [
|
||||||
|
{ "name": "jbm8b.app.js", "url": "app.js" },
|
||||||
|
{ "name": "jbm8b.img", "url": "app-icon.js", "evaluate": true }
|
||||||
|
],
|
||||||
|
"version": "0.03"
|
||||||
}
|
}
|
||||||
]
|
]
|
|
@ -7,3 +7,4 @@
|
||||||
0.07: Improve logging and charting of component states and add widget icon
|
0.07: Improve logging and charting of component states and add widget icon
|
||||||
0.08: Fix for Home button in the app and README added.
|
0.08: Fix for Home button in the app and README added.
|
||||||
0.09: Fix failing dismissal of Gadgetbridge notifications, record (coarse) bluetooth state
|
0.09: Fix failing dismissal of Gadgetbridge notifications, record (coarse) bluetooth state
|
||||||
|
0.10: Remove widget icon and improve listener and setInterval handling for widget (might help with https://github.com/espruino/BangleApps/issues/381)
|
|
@ -1,4 +1,5 @@
|
||||||
(() => {
|
(() => {
|
||||||
|
let recordingInterval = null;
|
||||||
const Storage = require("Storage");
|
const Storage = require("Storage");
|
||||||
|
|
||||||
const switchableConsumers = {
|
const switchableConsumers = {
|
||||||
|
@ -14,53 +15,44 @@
|
||||||
const recordingInterval10Min = 60 * 10 * 1000;
|
const recordingInterval10Min = 60 * 10 * 1000;
|
||||||
const recordingInterval1Min = 60 * 1000; //For testing
|
const recordingInterval1Min = 60 * 1000; //For testing
|
||||||
const recordingInterval10S = 10 * 1000; //For testing
|
const recordingInterval10S = 10 * 1000; //For testing
|
||||||
var recordingInterval = null;
|
|
||||||
|
|
||||||
var compassEventReceived = false;
|
var compassEventReceived = false;
|
||||||
var gpsEventReceived = false;
|
var gpsEventReceived = false;
|
||||||
var hrmEventReceived = false;
|
var hrmEventReceived = false;
|
||||||
|
|
||||||
// draw your widget
|
|
||||||
function draw() {
|
function draw() {
|
||||||
let x = this.x;
|
// void
|
||||||
let y = this.y;
|
|
||||||
|
|
||||||
g.setColor(0, 1, 0);
|
|
||||||
g.fillPoly([x + 5, y, x + 5, y + 4, x + 1, y + 4, x + 1, y + 20, x + 18, y + 20, x + 18, y + 4, x + 13, y + 4, x + 13, y], true);
|
|
||||||
|
|
||||||
g.setColor(0, 0, 0);
|
|
||||||
g.drawPoly([x + 5, y + 6, x + 8, y + 12, x + 13, y + 12, x + 16, y + 18], false);
|
|
||||||
|
|
||||||
g.reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function onMag() {
|
function batteryChartOnMag() {
|
||||||
compassEventReceived = true;
|
compassEventReceived = true;
|
||||||
// Stop handling events when no longer necessarry
|
// Stop handling events when no longer necessarry
|
||||||
Bangle.removeListener("mag", onMag);
|
Bangle.removeListener("mag", batteryChartOnMag);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onGps() {
|
function batterChartOnGps() {
|
||||||
gpsEventReceived = true;
|
gpsEventReceived = true;
|
||||||
Bangle.removeListener("GPS", onGps);
|
Bangle.removeListener("GPS", batterChartOnGps);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onHrm() {
|
function batteryChartOnHrm() {
|
||||||
hrmEventReceived = true;
|
hrmEventReceived = true;
|
||||||
Bangle.removeListener("HRM", onHrm);
|
Bangle.removeListener("HRM", batteryChartOnHrm);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getEnabledConsumersValue() {
|
function getEnabledConsumersValue() {
|
||||||
// Wait for an event from each of the devices to see if they are switched on
|
// Wait for an event from each of the devices to see if they are switched on
|
||||||
var enabledConsumers = switchableConsumers.none;
|
var enabledConsumers = switchableConsumers.none;
|
||||||
|
|
||||||
Bangle.on('mag', onMag);
|
Bangle.on('mag', batteryChartOnMag);
|
||||||
Bangle.on('GPS', onGps);
|
Bangle.on('GPS', batterChartOnGps);
|
||||||
Bangle.on('HRM', onHrm);
|
Bangle.on('HRM', batteryChartOnHrm);
|
||||||
|
|
||||||
// Wait two seconds, that should be enough for each of the events to get raised once
|
// Wait two seconds, that should be enough for each of the events to get raised once
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
Bangle.removeAllListeners();
|
Bangle.removeListener('mag', batteryChartOnMag);
|
||||||
|
Bangle.removeListener('GPS', batterChartOnGps);
|
||||||
|
Bangle.removeListener('HRM', batteryChartOnHrm);
|
||||||
}, 2000);
|
}, 2000);
|
||||||
|
|
||||||
if (Bangle.isLCDOn())
|
if (Bangle.isLCDOn())
|
||||||
|
@ -112,14 +104,20 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function reload() {
|
function reload() {
|
||||||
WIDGETS["batchart"].width = 24;
|
console.log("Reloading BatteryChart widget");
|
||||||
|
WIDGETS["batchart"].width = 0;
|
||||||
|
|
||||||
|
if (recordingInterval) {
|
||||||
|
clearInterval(recordingInterval);
|
||||||
|
recordingInterval = null;
|
||||||
|
}
|
||||||
|
|
||||||
recordingInterval = setInterval(logBatteryData, recordingInterval10Min);
|
recordingInterval = setInterval(logBatteryData, recordingInterval10Min);
|
||||||
}
|
}
|
||||||
|
|
||||||
// add the widget
|
// add the widget
|
||||||
WIDGETS["batchart"] = {
|
WIDGETS["batchart"] = {
|
||||||
area: "tl", width: 24, draw: draw, reload: reload
|
area: "tl", width: 0, draw: draw, reload: reload
|
||||||
};
|
};
|
||||||
|
|
||||||
reload();
|
reload();
|
||||||
|
|
|
@ -15,3 +15,4 @@
|
||||||
0.14: Move welcome loaders to *.boot.js
|
0.14: Move welcome loaders to *.boot.js
|
||||||
0.15: Added BLE HID option for Joystick and bare Keyboard
|
0.15: Added BLE HID option for Joystick and bare Keyboard
|
||||||
0.16: Detect out of memory errors and draw them onto the bottom of the screen in red
|
0.16: Detect out of memory errors and draw them onto the bottom of the screen in red
|
||||||
|
0.17: Don't modify beep/buzz behaviour if firmware does it automatically
|
||||||
|
|
|
@ -21,6 +21,7 @@ if (s.blerepl===false) { // If not programmable, force terminal off Bluetooth
|
||||||
// Don't disconnect if something is already connected to us
|
// Don't disconnect if something is already connected to us
|
||||||
if (s.ble===false && !NRF.getSecurityStatus().connected) NRF.sleep();
|
if (s.ble===false && !NRF.getSecurityStatus().connected) NRF.sleep();
|
||||||
// Set time, vibrate, beep, etc
|
// Set time, vibrate, beep, etc
|
||||||
|
if (!Bangle.F_BEEPSET) {
|
||||||
if (!s.vibrate) Bangle.buzz=Promise.resolve;
|
if (!s.vibrate) Bangle.buzz=Promise.resolve;
|
||||||
if (s.beep===false) Bangle.beep=Promise.resolve;
|
if (s.beep===false) Bangle.beep=Promise.resolve;
|
||||||
else if (s.beep=="vib") Bangle.beep = function (time, freq) {
|
else if (s.beep=="vib") Bangle.beep = function (time, freq) {
|
||||||
|
@ -35,6 +36,7 @@ else if (s.beep=="vib") Bangle.beep = function (time, freq) {
|
||||||
}, time);
|
}, time);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
}
|
||||||
Bangle.setLCDTimeout(s.timeout);
|
Bangle.setLCDTimeout(s.timeout);
|
||||||
if (!s.timeout) Bangle.setLCDPower(1);
|
if (!s.timeout) Bangle.setLCDPower(1);
|
||||||
E.setTimeZone(s.timezone);
|
E.setTimeZone(s.timezone);
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
0.01: Create dotmatrix clock app
|
|
@ -0,0 +1,28 @@
|
||||||
|
# Dotmatrix clock
|
||||||
|
|
||||||
|
A clock face simulating the classic dotmatrix displays. Shows time, date, compass, and heart rate.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
* Easy to read digits
|
||||||
|
* Simulated white-on-blue dotmatrix display
|
||||||
|
* Compass
|
||||||
|
* Heart rate monitor
|
||||||
|
* Multiple colour palletes, swipe to change
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### Sensor readings
|
||||||
|
|
||||||
|
When the display is activated by 'flipping' the watch up, the compass and heart sensors will be activated automatically, but if
|
||||||
|
you activate the LCD through a button press, then the sensors will remain off until you press button-1.
|
||||||
|
|
||||||
|
### Colours
|
||||||
|
|
||||||
|
The display defaults to blue, but you can change this to orange by swiping the screen
|
||||||
|
|
||||||
|
## Requests
|
||||||
|
|
||||||
|
If you have any feature requests, please send an email to the author paulcockrell@gmail.com`
|
|
@ -0,0 +1,354 @@
|
||||||
|
/**
|
||||||
|
* BangleJS DotMatrixCLOCK
|
||||||
|
*
|
||||||
|
* + Original Author: Paul Cockrell https://github.com/paulcockrell
|
||||||
|
* + Created: May 2020
|
||||||
|
*/
|
||||||
|
const storage = require('Storage');
|
||||||
|
const settings = (storage.readJSON('setting.json', 1) || {});
|
||||||
|
const is12Hour = settings["12hour"] || false;
|
||||||
|
const timeout = settings.timeout || 20;
|
||||||
|
|
||||||
|
const font7x7 = {
|
||||||
|
"empty": "00000000",
|
||||||
|
"0": "3E61514945433E",
|
||||||
|
"1": "1808080808081C",
|
||||||
|
"2": "7E01013E40407F",
|
||||||
|
"3": "7E01013E01017E",
|
||||||
|
"4": "4141417F010101",
|
||||||
|
"5": "7F40407E01017E",
|
||||||
|
"6": "3E40407E41413E",
|
||||||
|
"7": "3F010202040408",
|
||||||
|
"8": "3E41413E41413E",
|
||||||
|
"9": "3E41413F01013E",
|
||||||
|
};
|
||||||
|
|
||||||
|
const font5x5 = {
|
||||||
|
"empty": "00000000",
|
||||||
|
"-": "0000FF0000",
|
||||||
|
"0": "0E1915130E",
|
||||||
|
"1": "0C0404040E",
|
||||||
|
"2": "1E010E101F",
|
||||||
|
"3": "1E010E011E",
|
||||||
|
"4": "11111F0101",
|
||||||
|
"5": "1F101E011E",
|
||||||
|
"6": "0E101E110E",
|
||||||
|
"7": "1F01020408",
|
||||||
|
"8": "0E110E110E",
|
||||||
|
"9": "0E110F010E",
|
||||||
|
"A": "040A0E1111",
|
||||||
|
"B": "1E111E111E",
|
||||||
|
"C": "0F1010100F",
|
||||||
|
"D": "1E1111111E",
|
||||||
|
"E": "1F101E101F",
|
||||||
|
"F": "1F101E1010",
|
||||||
|
"G": "0F1013110E",
|
||||||
|
"H": "11111F1111",
|
||||||
|
"I": "0E0404040E",
|
||||||
|
"J": "1F0404140C",
|
||||||
|
"L": "101010101F",
|
||||||
|
"M": "111B151111",
|
||||||
|
"N": "1119151311",
|
||||||
|
"O": "0E1111110E",
|
||||||
|
"P": "1E111E1010",
|
||||||
|
"R": "1E111E1111",
|
||||||
|
"S": "0F100E011E",
|
||||||
|
"T": "1F04040404",
|
||||||
|
"U": "111111110E",
|
||||||
|
"V": "1111110A04",
|
||||||
|
"W": "111115150A",
|
||||||
|
"Y": "110A040404",
|
||||||
|
};
|
||||||
|
|
||||||
|
// Char renderer
|
||||||
|
const COLORS = {
|
||||||
|
blue: {
|
||||||
|
BG: "#0297fe",
|
||||||
|
DARK: "#3b3ce8",
|
||||||
|
LIGHT: "#E9ffff",
|
||||||
|
},
|
||||||
|
orange: {
|
||||||
|
BG: "#f7b336",
|
||||||
|
DARK: "#ac721e",
|
||||||
|
LIGHT: "#f6fc0f",
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let selectedColor = "blue";
|
||||||
|
let displayTimeoutRef, sensorTimeoutRef;
|
||||||
|
|
||||||
|
// Example
|
||||||
|
// binToHex(["0111110", "1000000", "1000000", "1111110", "1000001", "1000001", "0111110"])
|
||||||
|
function binToHex(bins) {
|
||||||
|
return bins.map(bin => ("00" + (parseInt(bin, 2).toString(16))).substr(-2).toUpperCase()).join("");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Example
|
||||||
|
// hexToBin("3E40407E41413E")
|
||||||
|
function hexToBin(hexStr) {
|
||||||
|
const regEx = new RegExp("..", "g");
|
||||||
|
const bin = hexStr
|
||||||
|
.replace(regEx, el => el + '_')
|
||||||
|
.slice(0, -1)
|
||||||
|
.split('_')
|
||||||
|
.map(hex => ("00000000" + (parseInt(hex, 16)).toString(2)).substr(-8));
|
||||||
|
|
||||||
|
return bin;
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawPixel(opts) {
|
||||||
|
g.setColor(opts.color);
|
||||||
|
g.fillRect(opts.x, opts.y, opts.x + opts.w, opts.y + opts.h);
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawGrid(pos, dims, charAsBin, opts) {
|
||||||
|
const defaultOpts = {
|
||||||
|
pxlW: 5,
|
||||||
|
pxlH: 5,
|
||||||
|
gap: 1,
|
||||||
|
offColor: COLORS[selectedColor].DARK,
|
||||||
|
onColor: COLORS[selectedColor].LIGHT
|
||||||
|
};
|
||||||
|
const pxl = Object.assign({}, defaultOpts, opts);
|
||||||
|
|
||||||
|
for (let rowY = 0; rowY < dims.rows; rowY++) {
|
||||||
|
const y = pos.y + ((pxl.pxlH + pxl.gap) * rowY);
|
||||||
|
|
||||||
|
for (let colX = 7; colX > (7 - dims.cols); colX--) {
|
||||||
|
const x = pos.x + ((pxl.pxlW + pxl.gap) * colX);
|
||||||
|
const color = (charAsBin && parseInt(charAsBin[rowY][colX])) ? pxl.onColor : pxl.offColor;
|
||||||
|
|
||||||
|
drawPixel({
|
||||||
|
x: x,
|
||||||
|
y: y,
|
||||||
|
w: pxl.pxlW,
|
||||||
|
h: pxl.pxlH,
|
||||||
|
color: color,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawFont(str, font, x, y) {
|
||||||
|
let fontMap, rows, cols;
|
||||||
|
|
||||||
|
switch(font) {
|
||||||
|
case "7x7":
|
||||||
|
fontMap = font7x7;
|
||||||
|
rows = cols = 7;
|
||||||
|
break;
|
||||||
|
case "5x5":
|
||||||
|
fontMap = font5x5;
|
||||||
|
rows = cols = 5;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw "Unknown font type: " + font;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pxlW = 2;
|
||||||
|
const pxlH = 2;
|
||||||
|
const gap = 2;
|
||||||
|
const gutter = 3;
|
||||||
|
const charArr = str.split("");
|
||||||
|
const gridWidthTotal = (rows * (pxlW + gap)) + gutter;
|
||||||
|
for (let i = 0; i < charArr.length; i++) {
|
||||||
|
const charAsBin = fontMap.hasOwnProperty(charArr[i])?
|
||||||
|
hexToBin(fontMap[charArr[i]]):
|
||||||
|
fontMap.empty;
|
||||||
|
|
||||||
|
drawGrid(
|
||||||
|
{x: x + (i * gridWidthTotal), y: y},
|
||||||
|
{rows: rows, cols: cols},
|
||||||
|
charAsBin,
|
||||||
|
{pxlW: pxlW, pxlH: pxlH, gap: gap}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawTitles() {
|
||||||
|
g.setColor("#ffffff");
|
||||||
|
g.setFont("6x8");
|
||||||
|
g.drawString("COMPASS", 52, 49);
|
||||||
|
g.drawString("HEART", 122, 49);
|
||||||
|
g.drawString("TIME", 52, 94);
|
||||||
|
g.drawString("DATE", 52, 144);
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawCompass(lastHeading) {
|
||||||
|
const directions = [
|
||||||
|
'N',
|
||||||
|
'NE',
|
||||||
|
'E',
|
||||||
|
'SE',
|
||||||
|
'S',
|
||||||
|
'SW',
|
||||||
|
'W',
|
||||||
|
'NW'
|
||||||
|
];
|
||||||
|
const cps = Bangle.getCompass();
|
||||||
|
let angle = cps.heading;
|
||||||
|
let heading = angle?
|
||||||
|
directions[Math.round(((angle %= 360) < 0 ? angle + 360 : angle) / 45) % 8]:
|
||||||
|
"-- ";
|
||||||
|
|
||||||
|
heading = (heading + " ").slice(0, 3);
|
||||||
|
if (lastHeading != heading) drawFont(heading, "5x5", 40, 67);
|
||||||
|
setTimeout(drawCompass.bind(null, heading), 1000 * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawHeart(hrm) {
|
||||||
|
drawFont((" " + (hrm ? hrm.bpm : "---")).slice(-3), "5x5", 109, 67);
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawTime(lastHrs, lastMns, toggle) {
|
||||||
|
const date = new Date();
|
||||||
|
const h = date.getHours();
|
||||||
|
const hrs = ("00" + ((is12Hour && h > 12) ? h - 12 : h)).substr(-2);
|
||||||
|
const mns = ("00" + date.getMinutes()).substr(-2);
|
||||||
|
|
||||||
|
if (lastHrs != hrs) {
|
||||||
|
drawFont(hrs, "7x7", 48, 109);
|
||||||
|
}
|
||||||
|
if (lastMns != mns) {
|
||||||
|
drawFont(mns, "7x7", 124, 109);
|
||||||
|
}
|
||||||
|
|
||||||
|
const color = toggle? COLORS[selectedColor].LIGHT : COLORS[selectedColor].DARK;
|
||||||
|
|
||||||
|
// This should toggle on/off per second
|
||||||
|
drawPixel({
|
||||||
|
color: color,
|
||||||
|
x: 118, y: 118,
|
||||||
|
w: 2, h: 2,
|
||||||
|
});
|
||||||
|
drawPixel({
|
||||||
|
color: color,
|
||||||
|
x: 118, y: 125,
|
||||||
|
w: 2, h: 2,
|
||||||
|
});
|
||||||
|
|
||||||
|
setTimeout(drawTime.bind(null, hrs, mns, !toggle), 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawDate(lastDate) {
|
||||||
|
const locale = require('locale');
|
||||||
|
const date = new Date();
|
||||||
|
|
||||||
|
if (lastDate != date.toISOString().split('T')[0]) {
|
||||||
|
const dow = locale.dow(date, 1).toUpperCase();
|
||||||
|
const dayNum = ("00" + date.getDate()).slice(-2);
|
||||||
|
const mon = locale.month(date).toUpperCase().slice(0, 3);
|
||||||
|
const yr = date.getFullYear().toString().slice(-2);
|
||||||
|
drawFont(dow + " " + dayNum, "5x5", 40, 159);
|
||||||
|
drawFont(mon + " " + yr, "5x5", 40, 189);
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(drawDate.bind(null, date.toISOString().split('T')), 1000 * 60);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setSensors(state) {
|
||||||
|
// Already reading sensors and trying to activate sensors, do nothing
|
||||||
|
if (sensorTimeoutRef && state === 1) return;
|
||||||
|
|
||||||
|
// If we are activating the sensors, turn them off again in one minute
|
||||||
|
if (state === 1) {
|
||||||
|
sensorTimeoutRef = setTimeout(() => { setSensors(0); }, 1000 * 60);
|
||||||
|
} else {
|
||||||
|
if (sensorTimeoutRef) {
|
||||||
|
clearInterval(sensorTimeoutRef);
|
||||||
|
sensorTimeoutRef = null;
|
||||||
|
}
|
||||||
|
// Bit nasty, but we only redraw the heart value on sensor callback
|
||||||
|
// but we want to blank out when sensor is off, but no callback for
|
||||||
|
// that so force redraw here
|
||||||
|
drawHeart();
|
||||||
|
}
|
||||||
|
|
||||||
|
Bangle.setHRMPower(state);
|
||||||
|
Bangle.setCompassPower(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawScreen() {
|
||||||
|
g.setBgColor(COLORS[selectedColor].BG);
|
||||||
|
g.clearRect(0, 24, g.getWidth(), g.getHeight());
|
||||||
|
|
||||||
|
// Draw components
|
||||||
|
drawTitles();
|
||||||
|
drawCompass();
|
||||||
|
drawHeart();
|
||||||
|
drawTime();
|
||||||
|
drawDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearTimers(){
|
||||||
|
if (displayTimeoutRef) {
|
||||||
|
clearInterval(displayTimeoutRef);
|
||||||
|
displayTimeoutRef = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sensorTimeoutRef) {
|
||||||
|
clearInterval(sensorTimeoutRef);
|
||||||
|
sensorTimeoutRef = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetDisplayTimeout() {
|
||||||
|
if (displayTimeoutRef) clearInterval(displayTimeoutRef);
|
||||||
|
Bangle.setLCDPower(true);
|
||||||
|
|
||||||
|
displayTimeoutRef = setTimeout(() => {
|
||||||
|
if (Bangle.isLCDOn()) Bangle.setLCDPower(false);
|
||||||
|
clearTimers();
|
||||||
|
}, 1000 * timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Turn sensors on
|
||||||
|
setSensors(1);
|
||||||
|
|
||||||
|
// Reset screen
|
||||||
|
g.clear();
|
||||||
|
|
||||||
|
// Load and draw widgets
|
||||||
|
Bangle.loadWidgets();
|
||||||
|
Bangle.drawWidgets();
|
||||||
|
|
||||||
|
// Draw screen
|
||||||
|
drawScreen();
|
||||||
|
resetDisplayTimeout();
|
||||||
|
|
||||||
|
// Setup callbacks
|
||||||
|
Bangle.on('swipe', (sDir) => {
|
||||||
|
selectedColor = selectedColor === "blue" ? "orange" : "blue";
|
||||||
|
resetDisplayTimeout();
|
||||||
|
drawScreen();
|
||||||
|
});
|
||||||
|
|
||||||
|
Bangle.on('HRM', drawHeart);
|
||||||
|
|
||||||
|
setWatch(() => {
|
||||||
|
setSensors(1);
|
||||||
|
resetDisplayTimeout();
|
||||||
|
}, BTN1, {repeat: true, edge: "falling"});
|
||||||
|
|
||||||
|
setWatch(() => {
|
||||||
|
setSensors(0);
|
||||||
|
clearTimers();
|
||||||
|
Bangle.setLCDMode();
|
||||||
|
Bangle.showLauncher();
|
||||||
|
}, BTN2, {repeat: false, edge: "falling"});
|
||||||
|
|
||||||
|
Bangle.on('lcdPower', (on) => {
|
||||||
|
if(on) {
|
||||||
|
resetDisplayTimeout();
|
||||||
|
} else {
|
||||||
|
clearTimers();
|
||||||
|
setSensors(0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Bangle.on('faceUp', (up) => {
|
||||||
|
if (up && !Bangle.isLCDOn()) {
|
||||||
|
setSensors(1);
|
||||||
|
resetDisplayTimeout();
|
||||||
|
}
|
||||||
|
});
|
Binary file not shown.
After Width: | Height: | Size: 1.8 KiB |
|
@ -0,0 +1 @@
|
||||||
|
require("heatshrink").decompress(atob("mEwxH+AAmBAEgrFAAZelFo+s1krAEcAE4IuFHIIJBAEXXE4KSEF84nCF4WBgErBYoAfEoaTBF42zF8PXF5QNBi4AgMIYv/F9nX64CDAw4ACl8vBIgGGF/4AOEgKPfI4xfoF96P/R/6PdACAv/F/4v/F/4v/F8HX68Xl8vAwIDCBIQADBIQQDBoQQDF/4AOGQqPbLAxmGL5gGDF/4AfF/6PRBIQQDSwwv/ABwoCR7xYGMwxfhF94AeF/4vr1nXBoIAf64mCF4gJEF8IkCF4YABFYQLDAEItBwIuCF9InBF4iSBwMrAEgnBFwgACXsIADFo4ABqwAkFQg="))
|
Binary file not shown.
After Width: | Height: | Size: 9.8 KiB |
|
@ -201,7 +201,7 @@ function showSortAppsManually() {
|
||||||
function setSortorder(app, val) {
|
function setSortorder(app, val) {
|
||||||
app = store.readJSON(app.id + '.info', 1);
|
app = store.readJSON(app.id + '.info', 1);
|
||||||
app.sortorder = val;
|
app.sortorder = val;
|
||||||
store.writeJSON(app.id + '.info', app);
|
store.write(app.id + '.info', JSON.stringify(app));
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAppsList() {
|
function getAppsList() {
|
||||||
|
|
|
@ -10,7 +10,7 @@ const cirRad = 2*Math.PI;
|
||||||
const proportion = 0.3; // relative size of hour hand
|
const proportion = 0.3; // relative size of hour hand
|
||||||
const thickness = 4; // thickness of decorative lines
|
const thickness = 4; // thickness of decorative lines
|
||||||
// retrieve settings from menu
|
// retrieve settings from menu
|
||||||
let settings = require('Storage').readJSON('app.json',1)||{};
|
let settings = require('Storage').readJSON('gallifr.json',1)||{};
|
||||||
const decoration = !settings.decoration;
|
const decoration = !settings.decoration;
|
||||||
const widgets = !settings.widgets;
|
const widgets = !settings.widgets;
|
||||||
if (widgets) {
|
if (widgets) {
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
// make sure to enclose the function in parentheses
|
// make sure to enclose the function in parentheses
|
||||||
(function (back) {
|
(function (back) {
|
||||||
let settings = require('Storage').readJSON('app.json',1)||{};
|
let settings = require('Storage').readJSON('gallifr.json',1)||{};
|
||||||
let colours = ["green","red","blue","80s"];
|
let colours = ["green","red","blue","80s"];
|
||||||
let onoff = ["on","off"];
|
let onoff = ["on","off"];
|
||||||
function save(key, value) {
|
function save(key, value) {
|
||||||
settings[key] = value;
|
settings[key] = value;
|
||||||
require('Storage').write('app.json',settings);
|
require('Storage').writeJSON('gallifr.json',settings);
|
||||||
}
|
}
|
||||||
const appMenu = {
|
const appMenu = {
|
||||||
'': {'title': 'Clock Settings'},
|
'': {'title': 'Clock Settings'},
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
0.01: First working version
|
||||||
|
0.02: Added delay in replying for dramatic effect
|
||||||
|
0.03: Fixed apps.json entry
|
|
@ -0,0 +1 @@
|
||||||
|
require("heatshrink").decompress(atob("mEwhBC/AGMrq2B1gAEwNWlYthq2s64AKGYIydFpoAEGLUrFqIADqxcXFqhiDFymBFy7GCF1owTRjCSVlYudeiGsF7/XlaNqSKBeP1mBwJxQMBReO1gaEleBMDBLN1hAC1hhBAoIwNCwQAGlZINqxvFGAIXOSBAXQN4hPBC5yQIVBxfBCAgvQSBC+NFAYRDMwJHOF654DqxkBYooALF6+sbIhkEF8Z3CRIWBR6AvXFAzvQF6wnIYQJgNd5AWNdoLoGBBAvPO5pfYH4IvUUwS/GVBzXBYCpHCq2s1mBDwKOWDwRgNPAwVVMCRLCwIABCZ6OJJSAATLxZgRACJeLAAMrFz9WFxiRgRpoADwIub1guQGDmsXhqSfRiL0G1jqkMRYxRwKLUGK2sFryVEq2B1gAEwNWFkIA/AH4A/AH4AQ"))
|
|
@ -0,0 +1,80 @@
|
||||||
|
const affirmative = [
|
||||||
|
'It is\ncertain.',
|
||||||
|
'It is\ndicededly\nso.',
|
||||||
|
'Without\na doubt.',
|
||||||
|
'Yes\ndefinitely.',
|
||||||
|
'You may\nrely\non it.',
|
||||||
|
'As I see,\nit yes.',
|
||||||
|
'Most\nlikely.',
|
||||||
|
'Outlook\ngood.',
|
||||||
|
'Yes.',
|
||||||
|
'Signs point\nto yes.'
|
||||||
|
];
|
||||||
|
const nonCommittal = [
|
||||||
|
'Reply hazy,\ntry again.',
|
||||||
|
'Ask again\nlater.',
|
||||||
|
'Better not\ntell you\nnow.',
|
||||||
|
'Cannot\npredict\nnow.',
|
||||||
|
'Concentrate\nand\nask again.'
|
||||||
|
];
|
||||||
|
const negative = [
|
||||||
|
'Don\'t\ncount on it.',
|
||||||
|
'My reply\nis no.',
|
||||||
|
'My sources\nsay no.',
|
||||||
|
'Outlook\nis not\nso\ngood.',
|
||||||
|
'Very\ndoubtful.'
|
||||||
|
];
|
||||||
|
|
||||||
|
const title = 'Magic 8 Ball';
|
||||||
|
|
||||||
|
const answers = [affirmative, nonCommittal, negative];
|
||||||
|
|
||||||
|
function getRandomArbitrary(min, max) {
|
||||||
|
return Math.random() * (max - min) + min;
|
||||||
|
}
|
||||||
|
|
||||||
|
function predict() {
|
||||||
|
// affirmative, negative or non-committal
|
||||||
|
let max = answers.length;
|
||||||
|
const a = Math.floor(getRandomArbitrary(0, max));
|
||||||
|
// sets max compared to answer category
|
||||||
|
max = answers[a].length;
|
||||||
|
const b = Math.floor(getRandomArbitrary(0, max));
|
||||||
|
// get the answer
|
||||||
|
const response = answers[a][b];
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
function draw(msg) {
|
||||||
|
// console.log(msg);
|
||||||
|
g.clear();
|
||||||
|
E.showMessage(msg, title);
|
||||||
|
}
|
||||||
|
|
||||||
|
function reply(button) {
|
||||||
|
const theButton = (typeof button === 'undefined' || isNaN(button)) ? 1 : button;
|
||||||
|
const timer = Math.floor(getRandomArbitrary(0, theButton) * 1000);
|
||||||
|
// Thinking...
|
||||||
|
draw('...');
|
||||||
|
setTimeout('draw(predict());', timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ask() {
|
||||||
|
draw('Ask me a\nYes or No\nquestion\nand\ntouch the\nscreen');
|
||||||
|
}
|
||||||
|
|
||||||
|
g.clear();
|
||||||
|
|
||||||
|
Bangle.loadWidgets();
|
||||||
|
Bangle.drawWidgets();
|
||||||
|
ask();
|
||||||
|
|
||||||
|
// Event Handlers
|
||||||
|
|
||||||
|
Bangle.on('touch', (button) => reply(button));
|
||||||
|
|
||||||
|
setWatch(ask, BTN1, { repeat: true, edge: "falling" });
|
||||||
|
setWatch(reply, BTN3, { repeat: true, edge: "falling" });
|
||||||
|
|
||||||
|
// Back to launcher
|
||||||
|
setWatch(Bangle.showLauncher, BTN2, { repeat: false, edge: "falling" });
|
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
|
@ -1,2 +1,3 @@
|
||||||
0.01: Init
|
0.01: Init
|
||||||
0.02: fix 3/4 moon orientation
|
0.02: fix 3/4 moon orientation
|
||||||
|
0.03: Change `largeclock.json` to 'data' file to allow settings to be preserved
|
||||||
|
|
|
@ -9,10 +9,8 @@ const moonX = 215;
|
||||||
const moonY = 50;
|
const moonY = 50;
|
||||||
|
|
||||||
const settings = require("Storage").readJSON("largeclock.json", 1);
|
const settings = require("Storage").readJSON("largeclock.json", 1);
|
||||||
const BTN1app = settings.BTN1;
|
const BTN1app = settings.BTN1 || "";
|
||||||
const BTN3app = settings.BTN3;
|
const BTN3app = settings.BTN3 || "";
|
||||||
console.log("BTN1app", BTN1app);
|
|
||||||
console.log("BTN3app", BTN3app);
|
|
||||||
|
|
||||||
function drawMoon(d) {
|
function drawMoon(d) {
|
||||||
const BLACK = 0,
|
const BLACK = 0,
|
||||||
|
@ -174,14 +172,14 @@ Bangle.setLCDMode();
|
||||||
// Show launcher when middle button pressed
|
// Show launcher when middle button pressed
|
||||||
clearWatch();
|
clearWatch();
|
||||||
setWatch(Bangle.showLauncher, BTN2, { repeat: false, edge: "falling" });
|
setWatch(Bangle.showLauncher, BTN2, { repeat: false, edge: "falling" });
|
||||||
setWatch(
|
if (BTN1app) setWatch(
|
||||||
function() {
|
function() {
|
||||||
load(BTN1app);
|
load(BTN1app);
|
||||||
},
|
},
|
||||||
BTN1,
|
BTN1,
|
||||||
{ repeat: false, edge: "rising" }
|
{ repeat: false, edge: "rising" }
|
||||||
);
|
);
|
||||||
setWatch(
|
if (BTN3app) setWatch(
|
||||||
function() {
|
function() {
|
||||||
load(BTN3app);
|
load(BTN3app);
|
||||||
},
|
},
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
|
|
||||||
function onchange(v) {
|
function onchange(v) {
|
||||||
settings[btn] = v;
|
settings[btn] = v;
|
||||||
s.write("largeclock.json", settings);
|
s.writeJSON("largeclock.json", settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
const btnMenu = {
|
const btnMenu = {
|
||||||
|
|
|
@ -3,3 +3,4 @@
|
||||||
0.04: Improve performance, attempt to remove occasional glitch when LCD on (fix #279)
|
0.04: Improve performance, attempt to remove occasional glitch when LCD on (fix #279)
|
||||||
0.05: Add "ram" keyword to allow 2v06 Espruino builds to cache function that needs to be fast
|
0.05: Add "ram" keyword to allow 2v06 Espruino builds to cache function that needs to be fast
|
||||||
Fix issue where first digit could get stuck going from "2x:xx" to " x:xx" (fix #365)
|
Fix issue where first digit could get stuck going from "2x:xx" to " x:xx" (fix #365)
|
||||||
|
0.06: Support 12 hour time
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
var is12Hour = (require("Storage").readJSON("setting.json",1)||{})["12hour"];
|
||||||
var locale = require("locale");
|
var locale = require("locale");
|
||||||
var CHARW = 34; // how tall are digits?
|
var CHARW = 34; // how tall are digits?
|
||||||
var CHARP = 2; // how chunky are digits?
|
var CHARP = 2; // how chunky are digits?
|
||||||
|
@ -146,7 +147,7 @@ function drawDigits(lastText,thisText,n) {
|
||||||
x+=s+p+7;
|
x+=s+p+7;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function drawSeconds() {
|
function drawEverythingElse() {
|
||||||
var x = (CHARW + CHARP + 6)*5;
|
var x = (CHARW + CHARP + 6)*5;
|
||||||
var y = Y + 2*CHARW + CHARP;
|
var y = Y + 2*CHARW + CHARP;
|
||||||
var d = new Date();
|
var d = new Date();
|
||||||
|
@ -154,6 +155,8 @@ function drawSeconds() {
|
||||||
g.setFont("6x8");
|
g.setFont("6x8");
|
||||||
g.setFontAlign(-1,-1);
|
g.setFontAlign(-1,-1);
|
||||||
g.drawString(("0"+d.getSeconds()).substr(-2), x, y-8, true);
|
g.drawString(("0"+d.getSeconds()).substr(-2), x, y-8, true);
|
||||||
|
// meridian
|
||||||
|
if (is12Hour) g.drawString((d.getHours() < 12) ? "AM" : "PM", x, Y + 4, true);
|
||||||
// date
|
// date
|
||||||
g.setFontAlign(0,-1);
|
g.setFontAlign(0,-1);
|
||||||
var date = locale.date(d,false);
|
var date = locale.date(d,false);
|
||||||
|
@ -164,13 +167,15 @@ function drawSeconds() {
|
||||||
function showTime() {
|
function showTime() {
|
||||||
if (animInterval) return; // in animation - quit
|
if (animInterval) return; // in animation - quit
|
||||||
var d = new Date();
|
var d = new Date();
|
||||||
var t = (" "+d.getHours()).substr(-2)+":"+
|
var hours = d.getHours();
|
||||||
|
if (is12Hour) hours = ((hours + 11) % 12) + 1;
|
||||||
|
var t = (" "+hours).substr(-2)+":"+
|
||||||
("0"+d.getMinutes()).substr(-2);
|
("0"+d.getMinutes()).substr(-2);
|
||||||
var l = lastTime;
|
var l = lastTime;
|
||||||
// same - don't animate
|
// same - don't animate
|
||||||
if (t==l || l=="-----") {
|
if (t==l || l=="-----") {
|
||||||
drawDigits(l,t,0);
|
drawDigits(l,t,0);
|
||||||
drawSeconds();
|
drawEverythingElse();
|
||||||
lastTime = t;
|
lastTime = t;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,3 +2,4 @@
|
||||||
0.02: Watch vibrates with every beat
|
0.02: Watch vibrates with every beat
|
||||||
0.03: Uses mean of three time intervalls to calculate bmp
|
0.03: Uses mean of three time intervalls to calculate bmp
|
||||||
0.04: App shows instructions, Widgets remain visible, color changed
|
0.04: App shows instructions, Widgets remain visible, color changed
|
||||||
|
0.05: Buzz intensity and beats per bar can be changed via settings-app
|
||||||
|
|
|
@ -8,6 +8,7 @@ This metronome makes your watch blink and vibrate with a given rate.
|
||||||
* Use `BTN1` to increase the bmp value by one.
|
* Use `BTN1` to increase the bmp value by one.
|
||||||
* Use `BTN3` to decrease the bmp value by one.
|
* Use `BTN3` to decrease the bmp value by one.
|
||||||
* You can change the bpm value any time by tapping the screen or using `BTN1` and `BTN3`.
|
* You can change the bpm value any time by tapping the screen or using `BTN1` and `BTN3`.
|
||||||
|
* Intensity of buzzing and the beats per bar (default 4) can be changed with the settings-app. The first beat per bar will be marked in red.
|
||||||
|
|
||||||
## Attributions
|
## Attributions
|
||||||
|
|
||||||
|
|
|
@ -6,31 +6,40 @@ var tindex=0; //index to iterate through time_diffs
|
||||||
|
|
||||||
Bangle.setLCDTimeout(undefined); //do not deaktivate display while running this app
|
Bangle.setLCDTimeout(undefined); //do not deaktivate display while running this app
|
||||||
|
|
||||||
|
const storage = require("Storage");
|
||||||
|
const SETTINGS_FILE = 'metronome.settings.json';
|
||||||
|
|
||||||
|
//return setting
|
||||||
|
function setting(key) {
|
||||||
|
//define default settings
|
||||||
|
const DEFAULTS = {
|
||||||
|
'beatsperbar': 4,
|
||||||
|
'buzzintens': 0.75,
|
||||||
|
};
|
||||||
|
if (!settings) { loadSettings(); }
|
||||||
|
return (key in settings) ? settings[key] : DEFAULTS[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
//load settings
|
||||||
|
let settings;
|
||||||
|
|
||||||
|
function loadSettings() {
|
||||||
|
settings = storage.readJSON(SETTINGS_FILE, 1) || {};
|
||||||
|
}
|
||||||
|
|
||||||
function changecolor() {
|
function changecolor() {
|
||||||
const maxColors = 2;
|
|
||||||
const colors = {
|
const colors = {
|
||||||
0: { value: 0xFFFF, name: "White" },
|
0: { value: 0xF800, name: "Red" },
|
||||||
// 1: { value: 0x000F, name: "Navy" },
|
1: { value: 0xFFFF, name: "White" },
|
||||||
// 2: { value: 0x03E0, name: "DarkGreen" },
|
2: { value: 0x9492, name: "gray" },
|
||||||
// 3: { value: 0x03EF, name: "DarkCyan" },
|
3: { value: 0xFFFF, name: "White" },
|
||||||
// 4: { value: 0x7800, name: "Maroon" },
|
4: { value: 0x9492, name: "gray" },
|
||||||
// 5: { value: 0x780F, name: "Purple" },
|
5: { value: 0xFFFF, name: "White" },
|
||||||
// 6: { value: 0x7BE0, name: "Olive" },
|
6: { value: 0x9492, name: "gray" },
|
||||||
// 7: { value: 0xC618, name: "LightGray" },
|
7: { value: 0xFFFF, name: "White" },
|
||||||
// 8: { value: 0x7BEF, name: "DarkGrey" },
|
|
||||||
// 9: { value: 0x001F, name: "Blue" },
|
|
||||||
// 10: { value: 0x07E0, name: "Green" },
|
|
||||||
// 11: { value: 0x07FF, name: "Cyan" },
|
|
||||||
1: { value: 0xF800, name: "Red" },
|
|
||||||
// 13: { value: 0xF81F, name: "Magenta" },
|
|
||||||
// 14: { value: 0xFFE0, name: "Yellow" },
|
|
||||||
// 15: { value: 0xFFFF, name: "White" },
|
|
||||||
// 16: { value: 0xFD20, name: "Orange" },
|
|
||||||
// 17: { value: 0xAFE5, name: "GreenYellow" },
|
|
||||||
// 18: { value: 0xF81F, name: "Pink" },
|
|
||||||
};
|
};
|
||||||
g.setColor(colors[cindex].value);
|
g.setColor(colors[cindex].value);
|
||||||
if (cindex == maxColors-1) {
|
if (cindex == setting('beatsperbar')-1) {
|
||||||
cindex = 0;
|
cindex = 0;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -42,11 +51,16 @@ function changecolor() {
|
||||||
function updateScreen() {
|
function updateScreen() {
|
||||||
g.clearRect(0, 50, 250, 150);
|
g.clearRect(0, 50, 250, 150);
|
||||||
changecolor();
|
changecolor();
|
||||||
Bangle.buzz(50, 0.75);
|
try {
|
||||||
|
Bangle.buzz(50, setting('buzzintens'));
|
||||||
|
}
|
||||||
|
catch(err) {
|
||||||
|
}
|
||||||
g.setFont("Vector",48);
|
g.setFont("Vector",48);
|
||||||
g.drawString(Math.floor(bpm)+"bpm", 5, 60);
|
g.drawString(Math.floor(bpm)+"bpm", 5, 60);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Bangle.on('touch', function(button) {
|
Bangle.on('touch', function(button) {
|
||||||
// setting bpm by tapping the screen. Uses the mean time difference between several tappings.
|
// setting bpm by tapping the screen. Uses the mean time difference between several tappings.
|
||||||
if (tindex < time_diffs.length) {
|
if (tindex < time_diffs.length) {
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
// This file should contain exactly one function, which shows the app's settings
|
||||||
|
/**
|
||||||
|
* @param {function} back Use back() to return to settings menu
|
||||||
|
*/
|
||||||
|
(function(back) {
|
||||||
|
const SETTINGS_FILE = 'metronome.settings.json';
|
||||||
|
|
||||||
|
// initialize with default settings...
|
||||||
|
let s = {
|
||||||
|
'beatsperbar': 4,
|
||||||
|
'buzzintens': 0.75,
|
||||||
|
};
|
||||||
|
// ...and overwrite them with any saved values
|
||||||
|
// This way saved values are preserved if a new version adds more settings
|
||||||
|
const storage = require('Storage');
|
||||||
|
const saved = storage.readJSON(SETTINGS_FILE, 1) || {};
|
||||||
|
for (const key in saved) {
|
||||||
|
s[key] = saved[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
// creates a function to safe a specific setting, e.g. save('color')(1)
|
||||||
|
function save(key) {
|
||||||
|
return function(value) {
|
||||||
|
s[key] = value;
|
||||||
|
storage.write(SETTINGS_FILE, s);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const menu = {
|
||||||
|
'': { 'title': 'Metronome' },
|
||||||
|
'< Back': back,
|
||||||
|
'beats per bar': {
|
||||||
|
value: s.beatsperbar,
|
||||||
|
min: 1,
|
||||||
|
max: 8,
|
||||||
|
step: 1,
|
||||||
|
onchange: save('beatsperbar'),
|
||||||
|
},
|
||||||
|
'buzz intensity': {
|
||||||
|
value: s.buzzintens,
|
||||||
|
min: 0.0,
|
||||||
|
max: 1.0,
|
||||||
|
step: 0.25,
|
||||||
|
onchange: save('buzzintens'),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
E.showMenu(menu);
|
||||||
|
});
|
|
@ -0,0 +1 @@
|
||||||
|
0.01: New App!
|
|
@ -0,0 +1 @@
|
||||||
|
require("heatshrink").decompress(atob("mEwxH+4AA/AH4A/AAPQ64AQ44ZKBYwvc6/QF9wwFF9XXF73I4IAH44/F54vdCpYQESAYvm5Avm44ADA4Yvmc44v/F/4v/F/4v/F/4v+zmjv4ABF9GrwoACrYvn2WGFwgABSh4AV0QtDFwYvmFwlhF9wuDF9QuEF82jFw4vmMIQuFv4vuEDOi0d/WgV/0YNGBIN/LrSvCABAkECAI4GAChKBF5QABCIYEDADKpCsIvJLQQ0EGoShJMBwACSJYvEB5GiMCYxJF4LuCLorTLF6IxGQILuBMYgAGC4QwP0YwHYwQbCF4K1CL4lhCohfQMBBiCFQQvEAgIsFAATxWSQyPDAYYSIHgRgZE4IsBF4QGCCI6NRMBboFXgTTIFyYwIPYWcGAb2CCI2iF6qwBD4aqERYQABIQ+cFywALLwgAqXoYvrSAQROA=="))
|
|
@ -0,0 +1,74 @@
|
||||||
|
|
||||||
|
function getImgHum() {
|
||||||
|
return require("heatshrink").decompress(atob("jUoxH+AEtlsoYYDS4ZYDAYaVDLAYFDSQYHDSIZYDBIaPDLAYLDRoZYDBoaLDLAYPDRIZYDCIaHDLAYTDQoZYDCoaDDOQYXAA+JxIYX1utDSwYBAAIzYGiwZUTgpODQpzPGGgY3OdI4aRDIIaMDJIYCDIztDGRwaJP5oaWDAwaRDBAbOC5YcKB5I="));
|
||||||
|
}
|
||||||
|
function getImgTemp() {
|
||||||
|
return require("heatshrink").decompress(atob("iUqxH+AA2sAAQLHCBASMCAoSLCPOBAAQRfI/5Hn3YACy4ACCL4ADCL5H/I/AQHCRAQJCQwQLCQgQNCQYRQCB4A/ADaPjYqTpSCRYQGCZALFA"));
|
||||||
|
}
|
||||||
|
function getImgFert() {
|
||||||
|
return require("heatshrink").decompress(atob("kklxH+AC+FwtbDbAfFAAVbEbgiGEbYiHEbQiEsIjiEQYjeEQiPdEQrXdEdKnTAAJsMD6QlJFZAAIGAIkPEaIkCrdhEaR9MT4gkLFAyjMYoojNUZ4jFEoxrGEBCJDEZSWEEZdhCwpsKJQiJFAgYgGEQwjLD4QjFCRD+KCAylGQ4gjXVhAiPEhAKDJIwiQEowIEEQo2GERgAKEYwAcEUQkDEL9VAAgHFETgAIDJwePEZwdTE5ggdMJt6AAQEEqwRMABYQDAAwkBF5AkKEBQAPEUR6ESAQicJIX+A=="));
|
||||||
|
}
|
||||||
|
|
||||||
|
var deviceInfo = {};
|
||||||
|
|
||||||
|
function parseDevice(device) {
|
||||||
|
var d = new DataView(device.serviceData["fe95"]);
|
||||||
|
var frame = d.getUint16(0,true);
|
||||||
|
var offset = 5;
|
||||||
|
if (frame&16) offset+=6; // mac address
|
||||||
|
if (frame&32) offset+=1; // capabilitities
|
||||||
|
if (frame&64) { // event
|
||||||
|
var l = d.getUint8(offset+2);
|
||||||
|
var code = d.getUint16(offset,true);
|
||||||
|
if (!deviceInfo[device.id]) deviceInfo[device.id]={id:device.id};
|
||||||
|
event = deviceInfo[device.id];
|
||||||
|
switch (code) {
|
||||||
|
case 0x1004: event.temperature = d.getInt16(offset+3,true)/10; break;
|
||||||
|
case 0x1006: event.humidity = d.getInt16(offset+3)/10; break;
|
||||||
|
case 0x100D:
|
||||||
|
event.temperature = d.getInt16(offset+3,true)/10;
|
||||||
|
event.humidity = d.getInt16(offset+5)/10; break;
|
||||||
|
case 0x1008: event.moisture = d.getUint8(offset+3); break;
|
||||||
|
case 0x1009: event.fertility = d.getUint16(offset+3,true)/10; break;
|
||||||
|
// case 0x1007: break; // 3 bytes? got 84,0,0 or 68,0,0
|
||||||
|
default: event.code = code;
|
||||||
|
event.raw = new Uint8Array(d.buffer, offset+3, l);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
//print(event);
|
||||||
|
show(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
eg. {
|
||||||
|
"id": "c4:7c:8d:6a:ac:79 public",
|
||||||
|
"temperature": 16.6, "code": 4103,
|
||||||
|
"raw": new Uint8Array([246, 0, 0]),
|
||||||
|
"moisture": 46, "fertility": 20.8 }
|
||||||
|
*/
|
||||||
|
function show(event) {
|
||||||
|
g.reset().setFont("6x8");
|
||||||
|
var y = 45 + 50*Object.keys(deviceInfo).indexOf(event.id);
|
||||||
|
|
||||||
|
g.drawString(event.id.substr(0,17),0,y);
|
||||||
|
g.drawImage(getImgHum(),0,y+15);
|
||||||
|
g.setFont("6x8",2);
|
||||||
|
var t = (event.moisture===undefined) ? "?" : event.moisture;
|
||||||
|
g.drawString((t+" ").substr(0,3),35,y+25,true);
|
||||||
|
g.drawImage(getImgFert(),80,y+15);
|
||||||
|
t = Math.round(event.fertility) || "?";
|
||||||
|
g.drawString((t+" ").substr(0,3), 120, y+25, true);
|
||||||
|
g.drawImage(getImgTemp(),160,y+15);
|
||||||
|
t = Math.round(event.temperature) || "?";
|
||||||
|
g.drawString((t+" ").substr(0,3), 180, y+25, true);
|
||||||
|
g.flip();
|
||||||
|
}
|
||||||
|
|
||||||
|
g.clear();
|
||||||
|
g.setFont("6x8",2).setFontAlign(0,-1).drawString("Scanning...",120,24);
|
||||||
|
|
||||||
|
Bangle.loadWidgets()
|
||||||
|
Bangle.drawWidgets()
|
||||||
|
|
||||||
|
NRF.setScan(parseDevice, { filters: [{serviceData:{"fe95":{}}}], timeout: 2000 });
|
Binary file not shown.
After Width: | Height: | Size: 1.6 KiB |
|
@ -6,3 +6,4 @@
|
||||||
Don't run again when settings app is updated (or absent)
|
Don't run again when settings app is updated (or absent)
|
||||||
Add "Run Now" option to settings
|
Add "Run Now" option to settings
|
||||||
0.05: Don't overwrite existing settings on app update
|
0.05: Don't overwrite existing settings on app update
|
||||||
|
0.06: Allow welcome to run after a fresh install
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
(function() {
|
(function() {
|
||||||
let s = require('Storage').readJSON('ncstart.json', 1)
|
let s = require('Storage').readJSON('ncstart.json', 1) || {};
|
||||||
|| require('Storage').readJSON('setting.json', 1)
|
if (!s.welcomed) {
|
||||||
|| {welcomed: true} // do NOT run if global settings are also absent
|
|
||||||
if (!s.welcomed && require('Storage').read('ncstart.app.js')) {
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
s.welcomed = true
|
require('Storage').write('ncstart.json', {welcomed: true})
|
||||||
require('Storage').write('ncstart.json', s)
|
|
||||||
load('ncstart.app.js')
|
load('ncstart.app.js')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
0.01: New widget
|
||||||
|
0.02: Less invasive, change default clock setting instead of directly loading the new clock (no longer breaks Gadgetbridge notifications)
|
|
@ -0,0 +1,6 @@
|
||||||
|
# Summary
|
||||||
|
Random Clock is a widget that will randomly show one of the installed watch faces each time the LCD is turned on.
|
||||||
|
|
||||||
|
# How it works
|
||||||
|
Everytime the LCD is turned off, the widget randomly changes the clock. When you long press BTN 3 the next time,
|
||||||
|
you might (or might not, it's random after all) see another watch face.
|
Binary file not shown.
After Width: | Height: | Size: 1.9 KiB |
|
@ -0,0 +1,35 @@
|
||||||
|
(() => {
|
||||||
|
let currentClock = "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Random value between zero (inclusive) and max (exclusive)
|
||||||
|
* @param {int} max
|
||||||
|
*/
|
||||||
|
function getRandomInt(max) {
|
||||||
|
return Math.floor(Math.random() * Math.floor(max));
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadRandomClock() {
|
||||||
|
// Find available clock apps (same way as in the bootloader)
|
||||||
|
var clockApps = require("Storage").list(/\.info$/).map(app => require("Storage").readJSON(app, 1) || {}).filter(app => app.type == "clock").sort((a, b) => a.sortorder - b.sortorder);
|
||||||
|
|
||||||
|
if (clockApps && clockApps.length > 0) {
|
||||||
|
var clockIndex = getRandomInt(clockApps.length);
|
||||||
|
|
||||||
|
// Only update the file if the clock really change to be nice to the FLASH mem
|
||||||
|
if (clockApps[clockIndex].src != currentClock) {
|
||||||
|
currentClock = clockApps[clockIndex].src;
|
||||||
|
settings = require("Storage").readJSON('setting.json', 1);
|
||||||
|
settings.clock = clockApps[clockIndex].src;
|
||||||
|
require("Storage").write('setting.json', settings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Bangle.on('lcdPower', (on) => {
|
||||||
|
if (!on) {
|
||||||
|
loadRandomClock();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
})();
|
|
@ -8,3 +8,6 @@
|
||||||
Don't run again when settings app is updated (or absent)
|
Don't run again when settings app is updated (or absent)
|
||||||
Add "Run Now" option to settings
|
Add "Run Now" option to settings
|
||||||
0.08: Don't overwrite existing settings on app update
|
0.08: Don't overwrite existing settings on app update
|
||||||
|
0.09: Allow welcome to run after a fresh install
|
||||||
|
More useful app menu
|
||||||
|
BTN2 now goes to menu on release
|
||||||
|
|
|
@ -285,7 +285,7 @@ setWatch(()=>{
|
||||||
if (sceneNumber == scenes.length-1) {
|
if (sceneNumber == scenes.length-1) {
|
||||||
load();
|
load();
|
||||||
}
|
}
|
||||||
}, BTN2, {repeat:true,edge:"rising"});
|
}, BTN2, {repeat:true,edge:"falling"});
|
||||||
setWatch(()=>move(-1), BTN1, {repeat:true});
|
setWatch(()=>move(-1), BTN1, {repeat:true});
|
||||||
|
|
||||||
(function migrateSettings(){
|
(function migrateSettings(){
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
(function() {
|
(function() {
|
||||||
let s = require('Storage').readJSON('welcome.json', 1)
|
let s = require('Storage').readJSON('welcome.json', 1) || {};
|
||||||
|| require('Storage').readJSON('setting.json', 1)
|
if (!s.welcomed) {
|
||||||
|| {welcomed: true} // do NOT run if global settings are also absent
|
|
||||||
if (!s.welcomed && require('Storage').read('welcome.app.js')) {
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
s.welcomed = true
|
require('Storage').write('welcome.json', {welcomed: true})
|
||||||
require('Storage').write('welcome.json', {welcomed: "yes"})
|
|
||||||
load('welcome.app.js')
|
load('welcome.app.js')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,12 +3,16 @@
|
||||||
|| require('Storage').readJSON('setting.json', 1) || {}
|
|| require('Storage').readJSON('setting.json', 1) || {}
|
||||||
E.showMenu({
|
E.showMenu({
|
||||||
'': { 'title': 'Welcome App' },
|
'': { 'title': 'Welcome App' },
|
||||||
'Run on Next Boot': {
|
'Run next boot': {
|
||||||
value: !settings.welcomed,
|
value: !settings.welcomed,
|
||||||
format: v => v ? 'OK' : 'No',
|
format: v => v ? 'Yes' : 'No',
|
||||||
onchange: v => require('Storage').write('welcome.json', {welcomed: !v}),
|
onchange: v => require('Storage').write('welcome.json', {welcomed: !v}),
|
||||||
},
|
},
|
||||||
'Run Now': () => load('welcome.app.js'),
|
'Run Now': () => load('welcome.app.js'),
|
||||||
|
'Turn off & run next': () => {
|
||||||
|
require('Storage').write('welcome.json', {welcomed: false});
|
||||||
|
Bangle.off();
|
||||||
|
},
|
||||||
'< Back': back,
|
'< Back': back,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
cd `dirname $0`/..
|
||||||
|
nodejs bin/sanitycheck.js || exit 1
|
||||||
|
|
||||||
|
echo "Sanity check passed."
|
||||||
|
|
||||||
|
echo "Finding app dates..."
|
||||||
|
|
||||||
|
# Create list of:
|
||||||
|
# appid,created_time,modified_time
|
||||||
|
cd apps
|
||||||
|
for appfolder in *; do
|
||||||
|
echo "$appfolder,$(git log --follow --format=%ai -- $appfolder | tail -n 1),$(git log --follow --format=%ai -- $appfolder | head -n 1)" ;
|
||||||
|
done | grep -v _example_ | grep -v unknown.png > ../appdates.csv
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
echo "Ready to publish"
|
19
index.html
19
index.html
|
@ -40,6 +40,12 @@
|
||||||
.chip {
|
.chip {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
.filter-nav {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
.sort-nav {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
.tile-content { position: relative; }
|
.tile-content { position: relative; }
|
||||||
.link-github {
|
.link-github {
|
||||||
position:absolute;
|
position:absolute;
|
||||||
|
@ -88,8 +94,9 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="container bangle-tab" id="librarycontainer">
|
<div class="container bangle-tab" id="librarycontainer">
|
||||||
|
<div>
|
||||||
<div class="filter-nav">
|
<div class="filter-nav">
|
||||||
<label class="chip active" filterid="">All</label>
|
<label class="chip active" filterid="">Default</label>
|
||||||
<label class="chip" filterid="clock">Clocks</label>
|
<label class="chip" filterid="clock">Clocks</label>
|
||||||
<label class="chip" filterid="game">Games</label>
|
<label class="chip" filterid="game">Games</label>
|
||||||
<label class="chip" filterid="tool">Tools</label>
|
<label class="chip" filterid="tool">Tools</label>
|
||||||
|
@ -98,7 +105,15 @@
|
||||||
<label class="chip" filterid="outdoors">Outdoors</label>
|
<label class="chip" filterid="outdoors">Outdoors</label>
|
||||||
<label class="chip" filterid="favourites">Favourites</label>
|
<label class="chip" filterid="favourites">Favourites</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel">
|
<div class="sort-nav hidden">
|
||||||
|
<span>Sort by:</span>
|
||||||
|
<label class="chip active" sortid="">None</label>
|
||||||
|
<label class="chip" sortid="created">New</label>
|
||||||
|
<label class="chip" sortid="modified">Updated</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="panel" style="clear:both">
|
||||||
<div class="panel-header">
|
<div class="panel-header">
|
||||||
<div class="input-group" id="searchform">
|
<div class="input-group" id="searchform">
|
||||||
<input class="form-input" type="text" placeholder="Keywords...">
|
<input class="form-input" type="text" placeholder="Keywords...">
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
|
if (typeof btoa==="undefined")
|
||||||
|
function btoa(d) { return Buffer.from(d).toString('base64'); }
|
||||||
|
|
||||||
// Converts a string into most efficient way to send to Espruino (either json, base64, or compressed base64)
|
// Converts a string into most efficient way to send to Espruino (either json, base64, or compressed base64)
|
||||||
function toJS(txt) {
|
function toJS(txt) {
|
||||||
var json = JSON.stringify(txt);
|
var json = JSON.stringify(txt);
|
||||||
var b64 = "atob("+JSON.stringify(btoa(json))+")";
|
var b64 = "atob("+JSON.stringify(btoa(json))+")";
|
||||||
var js = b64.length < json.length ? b64 : json;
|
var js = b64.length < json.length ? b64 : json;
|
||||||
|
|
||||||
if (heatshrink) {
|
if (typeof heatshrink !== "undefined") {
|
||||||
var ua = new Uint8Array(txt.length);
|
var ua = new Uint8Array(txt.length);
|
||||||
for (var i=0;i<txt.length;i++) ua[i] = txt.charCodeAt(i);
|
for (var i=0;i<txt.length;i++) ua[i] = txt.charCodeAt(i);
|
||||||
var c = heatshrink.compress(ua);
|
var c = heatshrink.compress(ua);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// EspruinoTools bundle (https://github.com/espruino/EspruinoTools)
|
// EspruinoTools bundle (https://github.com/espruino/EspruinoTools)
|
||||||
// Created with https://github.com/espruino/EspruinoWebIDE/blob/gh-pages/extras/create_espruinotools_js.sh
|
// Created with https://github.com/espruino/EspruinoWebIDE/blob/gh-pages/extras/create_espruinotools_js.sh
|
||||||
// Based on EspruinoWebIDE 0.73.4
|
// Based on EspruinoWebIDE 0.73.7
|
||||||
/**
|
/**
|
||||||
Copyright 2014 Gordon Williams (gw@pur3.co.uk)
|
Copyright 2014 Gordon Williams (gw@pur3.co.uk)
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@ var Espruino;
|
||||||
*
|
*
|
||||||
* Common processors are:
|
* Common processors are:
|
||||||
*
|
*
|
||||||
|
* jsCodeChanged - called when the code in the editor changes with {code}
|
||||||
* sending - sending code to Espruino (no data)
|
* sending - sending code to Espruino (no data)
|
||||||
* transformForEspruino - transform code ready to be sent to Espruino
|
* transformForEspruino - transform code ready to be sent to Espruino
|
||||||
* transformModuleForEspruino({code,name})
|
* transformModuleForEspruino({code,name})
|
||||||
|
@ -123,6 +124,7 @@ Espruino.Core.Status = {
|
||||||
hasProgress : function() { return false; },
|
hasProgress : function() { return false; },
|
||||||
incrementProgress : function(amt) {}
|
incrementProgress : function(amt) {}
|
||||||
};
|
};
|
||||||
|
var acorn = (function(){ var exports={};var module={};
|
||||||
(function (global, factory) {
|
(function (global, factory) {
|
||||||
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
|
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
|
||||||
typeof define === 'function' && define.amd ? define(['exports'], factory) :
|
typeof define === 'function' && define.amd ? define(['exports'], factory) :
|
||||||
|
@ -3988,6 +3990,7 @@ exports.nonASCIIwhitespace = nonASCIIwhitespace;
|
||||||
Object.defineProperty(exports, '__esModule', { value: true });
|
Object.defineProperty(exports, '__esModule', { value: true });
|
||||||
|
|
||||||
})));
|
})));
|
||||||
|
return exports;})();
|
||||||
/**
|
/**
|
||||||
Copyright 2014 Gordon Williams (gw@pur3.co.uk)
|
Copyright 2014 Gordon Williams (gw@pur3.co.uk)
|
||||||
|
|
||||||
|
@ -4507,8 +4510,8 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
||||||
fileLoader.click();
|
fileLoader.click();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Save a file with a save file dialog. callback(savedFileName) only called in chrome app case when we knopw the filename*/
|
// Save a file with a save file dialog
|
||||||
function fileSaveDialog(data, filename, callback) {
|
function fileSaveDialog(data, filename) {
|
||||||
function errorHandler() {
|
function errorHandler() {
|
||||||
Espruino.Core.Notifications.error("Error Saving", true);
|
Espruino.Core.Notifications.error("Error Saving", true);
|
||||||
}
|
}
|
||||||
|
@ -4524,7 +4527,6 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
||||||
writer.onwriteend = function(e) {
|
writer.onwriteend = function(e) {
|
||||||
writer.onwriteend = function(e) {
|
writer.onwriteend = function(e) {
|
||||||
console.log('FileWriter: complete');
|
console.log('FileWriter: complete');
|
||||||
if (callback) callback(writableFileEntry.name);
|
|
||||||
};
|
};
|
||||||
console.log('FileWriter: writing');
|
console.log('FileWriter: writing');
|
||||||
writer.write(blob);
|
writer.write(blob);
|
||||||
|
@ -4535,8 +4537,10 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
||||||
}, errorHandler);
|
}, errorHandler);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
var rawdata = new Uint8Array(data.length);
|
||||||
|
for (var i=0;i<data.length;i++) rawdata[i]=data.charCodeAt(i);
|
||||||
var a = document.createElement("a"),
|
var a = document.createElement("a"),
|
||||||
file = new Blob([data], {type: "text/plain"});
|
file = new Blob([rawdata.buffer], {type: "text/plain"});
|
||||||
var url = URL.createObjectURL(file);
|
var url = URL.createObjectURL(file);
|
||||||
a.href = url;
|
a.href = url;
|
||||||
a.download = filename;
|
a.download = filename;
|
||||||
|
@ -4765,6 +4769,16 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
||||||
console.log("GET chrome.storage.sync = "+JSON.stringify(value));
|
console.log("GET chrome.storage.sync = "+JSON.stringify(value));
|
||||||
callback(value);
|
callback(value);
|
||||||
});
|
});
|
||||||
|
} else if (typeof window !== 'undefined' && window.localStorage) {
|
||||||
|
var data = {};
|
||||||
|
var value = window.localStorage.getItem("CONFIG");
|
||||||
|
console.log("GET window.localStorage = "+JSON.stringify(value));
|
||||||
|
try {
|
||||||
|
data = JSON.parse(value);
|
||||||
|
} catch (e) {
|
||||||
|
console.log("Invalid config data");
|
||||||
|
}
|
||||||
|
callback(data);
|
||||||
} else if (typeof document != "undefined") {
|
} else if (typeof document != "undefined") {
|
||||||
var data = {};
|
var data = {};
|
||||||
var cookie = document.cookie;
|
var cookie = document.cookie;
|
||||||
|
@ -4786,8 +4800,11 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
||||||
|
|
||||||
function _set(data) {
|
function _set(data) {
|
||||||
if (typeof chrome !== 'undefined' && chrome.storage) {
|
if (typeof chrome !== 'undefined' && chrome.storage) {
|
||||||
console.log("SET chrome.storage.sync = "+JSON.stringify(data));
|
console.log("SET chrome.storage.sync = "+JSON.stringify(data,null,2));
|
||||||
chrome.storage.sync.set({ CONFIGS : data });
|
chrome.storage.sync.set({ CONFIGS : data });
|
||||||
|
} else if (typeof window !== 'undefined' && window.localStorage) {
|
||||||
|
console.log("SET window.localStorage = "+JSON.stringify(data,null,2));
|
||||||
|
window.localStorage.setItem("CONFIG",JSON.stringify(data));
|
||||||
} else if (typeof document != "undefined") {
|
} else if (typeof document != "undefined") {
|
||||||
document.cookie = "CONFIG="+btoa(JSON.stringify(data));
|
document.cookie = "CONFIG="+btoa(JSON.stringify(data));
|
||||||
}
|
}
|
||||||
|
@ -4811,7 +4828,6 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
||||||
addSection("General", { sortOrder:100, description: "General Web IDE Settings" });
|
addSection("General", { sortOrder:100, description: "General Web IDE Settings" });
|
||||||
addSection("Communications", { sortOrder:200, description: "Settings for communicating with the Espruino Board" });
|
addSection("Communications", { sortOrder:200, description: "Settings for communicating with the Espruino Board" });
|
||||||
addSection("Board", { sortOrder:300, description: "Settings for the Espruino Board itself" });
|
addSection("Board", { sortOrder:300, description: "Settings for the Espruino Board itself" });
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function add(name, options) {
|
function add(name, options) {
|
||||||
|
@ -5076,6 +5092,7 @@ To add a new serial device, you must add an object to
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var portInfo = { port:serialPort };
|
||||||
connectionInfo = undefined;
|
connectionInfo = undefined;
|
||||||
flowControlXOFF = false;
|
flowControlXOFF = false;
|
||||||
currentDevice = portToDevice[serialPort];
|
currentDevice = portToDevice[serialPort];
|
||||||
|
@ -5088,7 +5105,6 @@ To add a new serial device, you must add an object to
|
||||||
connectionInfo = cInfo;
|
connectionInfo = cInfo;
|
||||||
connectedPort = serialPort;
|
connectedPort = serialPort;
|
||||||
console.log("Connected", cInfo);
|
console.log("Connected", cInfo);
|
||||||
var portInfo = { port:serialPort };
|
|
||||||
if (connectionInfo.portName)
|
if (connectionInfo.portName)
|
||||||
portInfo.portName = connectionInfo.portName;
|
portInfo.portName = connectionInfo.portName;
|
||||||
Espruino.callProcessor("connected", portInfo, function() {
|
Espruino.callProcessor("connected", portInfo, function() {
|
||||||
|
@ -5127,8 +5143,8 @@ To add a new serial device, you must add an object to
|
||||||
sendingBinary = false;
|
sendingBinary = false;
|
||||||
flowControlXOFF = false;
|
flowControlXOFF = false;
|
||||||
|
|
||||||
Espruino.callProcessor("disconnected", undefined, function() {
|
Espruino.callProcessor("disconnected", portInfo, function() {
|
||||||
disconnectCallback();
|
disconnectCallback(portInfo);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -5608,9 +5624,6 @@ To add a new serial device, you must add an object to
|
||||||
|
|
||||||
// When code is sent to Espruino, search it for modules and add extra code required to load them
|
// When code is sent to Espruino, search it for modules and add extra code required to load them
|
||||||
Espruino.addProcessor("transformForEspruino", function(code, callback) {
|
Espruino.addProcessor("transformForEspruino", function(code, callback) {
|
||||||
if (Espruino.Config.ROLLUP) {
|
|
||||||
return loadModulesRollup(code, callback);
|
|
||||||
}
|
|
||||||
loadModules(code, callback);
|
loadModules(code, callback);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -5787,24 +5800,8 @@ To add a new serial device, you must add an object to
|
||||||
callback(loadedModuleData.join("\n") + "\n" + code);
|
callback(loadedModuleData.join("\n") + "\n" + code);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
function loadModulesRollup(code, callback) {
|
|
||||||
rollupTools.loadModulesRollup(code)
|
|
||||||
.then(generated => {
|
|
||||||
const minified = generated.code;
|
|
||||||
console.log('rollup: '+minified.length+' bytes');
|
|
||||||
|
|
||||||
// FIXME: needs warnings?
|
|
||||||
Espruino.Core.Notifications.info('Rollup no errors. Bundling ' + code.length + ' bytes to ' + minified.length + ' bytes');
|
|
||||||
callback(minified);
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
console.log('rollup:error', err);
|
|
||||||
Espruino.Core.Notifications.error("Rollup errors - Bundling failed: " + String(err).trim());
|
|
||||||
callback(code);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Espruino.Core.Modules = {
|
Espruino.Core.Modules = {
|
||||||
init : init
|
init : init
|
||||||
|
@ -6484,6 +6481,7 @@ To add a new serial device, you must add an object to
|
||||||
(function(){
|
(function(){
|
||||||
if (typeof acorn == "undefined") {
|
if (typeof acorn == "undefined") {
|
||||||
console.log("pretokenise: needs acorn, disabling.");
|
console.log("pretokenise: needs acorn, disabling.");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
|
@ -6587,11 +6585,12 @@ To add a new serial device, you must add an object to
|
||||||
var tp = "?";
|
var tp = "?";
|
||||||
if (tk.type.label=="template" || tk.type.label=="string") tp="STRING";
|
if (tk.type.label=="template" || tk.type.label=="string") tp="STRING";
|
||||||
if (tk.type.label=="num") tp="NUMBER";
|
if (tk.type.label=="num") tp="NUMBER";
|
||||||
if (tk.type.keyword) tp="ID";
|
if (tk.type.keyword || tk.type.label=="name") tp="ID";
|
||||||
|
if (tp=="?" && tk.start+1==tk.end) tp="CHAR";
|
||||||
return {
|
return {
|
||||||
startIdx : tk.start,
|
startIdx : tk.start,
|
||||||
endIdx : tk.end,
|
endIdx : tk.end,
|
||||||
str : code.substr(tk.start, tk.end),
|
str : code.substring(tk.start, tk.end),
|
||||||
type : tp
|
type : tp
|
||||||
};
|
};
|
||||||
}};
|
}};
|
||||||
|
@ -6802,5 +6801,7 @@ Espruino.transform = function(code, options) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if ("undefined"==typeof document) Espruino.init();
|
||||||
if ("undefined"!=typeof module)
|
if ("undefined"!=typeof module)
|
||||||
module.exports = Espruino;
|
module.exports = Espruino;
|
||||||
|
|
||||||
|
|
44
js/index.js
44
js/index.js
|
@ -1,5 +1,6 @@
|
||||||
var appJSON = []; // List of apps and info from apps.json
|
var appJSON = []; // List of apps and info from apps.json
|
||||||
var appsInstalled = []; // list of app JSON
|
var appsInstalled = []; // list of app JSON
|
||||||
|
var appSortInfo = {}; // list of data to sort by, from appdates.csv { created, modified }
|
||||||
var files = []; // list of files on Bangle
|
var files = []; // list of files on Bangle
|
||||||
var DEFAULTSETTINGS = {
|
var DEFAULTSETTINGS = {
|
||||||
pretokenise : true,
|
pretokenise : true,
|
||||||
|
@ -19,6 +20,19 @@ httpGet("apps.json").then(apps=>{
|
||||||
refreshFilter();
|
refreshFilter();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
httpGet("appdates.csv").then(csv=>{
|
||||||
|
document.querySelector(".sort-nav").classList.remove("hidden");
|
||||||
|
csv.split("\n").forEach(line=>{
|
||||||
|
var l = line.split(",");
|
||||||
|
appSortInfo[l[0]] = {
|
||||||
|
created : Date.parse(l[1]),
|
||||||
|
modified : Date.parse(l[2])
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}).catch(err=>{
|
||||||
|
console.log("No recent.csv - app sort disabled");
|
||||||
|
});
|
||||||
|
|
||||||
// =========================================== Top Navigation
|
// =========================================== Top Navigation
|
||||||
function showChangeLog(appid) {
|
function showChangeLog(appid) {
|
||||||
var app = appNameToApp(appid);
|
var app = appNameToApp(appid);
|
||||||
|
@ -182,11 +196,12 @@ function showTab(tabname) {
|
||||||
|
|
||||||
// =========================================== Library
|
// =========================================== Library
|
||||||
|
|
||||||
var chips = Array.from(document.querySelectorAll('.chip')).map(chip => chip.attributes.filterid.value);
|
var chips = Array.from(document.querySelectorAll('.filter-nav .chip')).map(chip => chip.attributes.filterid.value);
|
||||||
var hash = window.location.hash ? window.location.hash.slice(1) : '';
|
var hash = window.location.hash ? window.location.hash.slice(1) : '';
|
||||||
|
|
||||||
var activeFilter = !!~chips.indexOf(hash) ? hash : '';
|
var activeFilter = !!~chips.indexOf(hash) ? hash : '';
|
||||||
var currentSearch = '';
|
var activeSort = '';
|
||||||
|
var currentSearch = activeFilter ? '' : hash;
|
||||||
|
|
||||||
function refreshFilter(){
|
function refreshFilter(){
|
||||||
var filtersContainer = document.querySelector("#librarycontainer .filter-nav");
|
var filtersContainer = document.querySelector("#librarycontainer .filter-nav");
|
||||||
|
@ -194,6 +209,12 @@ function refreshFilter(){
|
||||||
if(activeFilter) filtersContainer.querySelector('.chip[filterid="'+activeFilter+'"]').classList.add('active');
|
if(activeFilter) filtersContainer.querySelector('.chip[filterid="'+activeFilter+'"]').classList.add('active');
|
||||||
else filtersContainer.querySelector('.chip[filterid]').classList.add('active');
|
else filtersContainer.querySelector('.chip[filterid]').classList.add('active');
|
||||||
}
|
}
|
||||||
|
function refreshSort(){
|
||||||
|
var sortContainer = document.querySelector("#librarycontainer .sort-nav");
|
||||||
|
sortContainer.querySelector('.active').classList.remove('active');
|
||||||
|
if(activeSort) sortContainer.querySelector('.chip[sortid="'+activeSort+'"]').classList.add('active');
|
||||||
|
else sortContainer.querySelector('.chip[sortid]').classList.add('active');
|
||||||
|
}
|
||||||
function refreshLibrary() {
|
function refreshLibrary() {
|
||||||
var panelbody = document.querySelector("#librarycontainer .panel-body");
|
var panelbody = document.querySelector("#librarycontainer .panel-body");
|
||||||
var visibleApps = appJSON;
|
var visibleApps = appJSON;
|
||||||
|
@ -211,6 +232,13 @@ function refreshLibrary() {
|
||||||
visibleApps = visibleApps.filter(app => app.name.toLowerCase().includes(currentSearch) || app.tags.includes(currentSearch));
|
visibleApps = visibleApps.filter(app => app.name.toLowerCase().includes(currentSearch) || app.tags.includes(currentSearch));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (activeSort) {
|
||||||
|
visibleApps = visibleApps.slice(); // clone the array so sort doesn't mess with original
|
||||||
|
if (activeSort=="created" || activeSort=="modified") {
|
||||||
|
visibleApps = visibleApps.sort((a,b) => appSortInfo[b.id][activeSort] - appSortInfo[a.id][activeSort]);
|
||||||
|
} else throw new Error("Unknown sort type "+activeSort);
|
||||||
|
}
|
||||||
|
|
||||||
panelbody.innerHTML = visibleApps.map((app,idx) => {
|
panelbody.innerHTML = visibleApps.map((app,idx) => {
|
||||||
var appInstalled = appsInstalled.find(a=>a.id==app.id);
|
var appInstalled = appsInstalled.find(a=>a.id==app.id);
|
||||||
var version = getVersionInfo(app, appInstalled);
|
var version = getVersionInfo(app, appInstalled);
|
||||||
|
@ -580,12 +608,22 @@ filtersContainer.addEventListener('click', ({ target }) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
var librarySearchInput = document.querySelector("#searchform input");
|
var librarySearchInput = document.querySelector("#searchform input");
|
||||||
|
librarySearchInput.value = currentSearch;
|
||||||
librarySearchInput.addEventListener('input', evt => {
|
librarySearchInput.addEventListener('input', evt => {
|
||||||
currentSearch = evt.target.value.toLowerCase();
|
currentSearch = evt.target.value.toLowerCase();
|
||||||
refreshLibrary();
|
refreshLibrary();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var sortContainer = document.querySelector("#librarycontainer .sort-nav");
|
||||||
|
sortContainer.addEventListener('click', ({ target }) => {
|
||||||
|
if (target.classList.contains('active')) return;
|
||||||
|
|
||||||
|
activeSort = target.getAttribute('sortid') || '';
|
||||||
|
refreshSort();
|
||||||
|
refreshLibrary();
|
||||||
|
window.location.hash = activeFilter;
|
||||||
|
});
|
||||||
|
|
||||||
// =========================================== About
|
// =========================================== About
|
||||||
|
|
||||||
if (window.location.host=="banglejs.com") {
|
if (window.location.host=="banglejs.com") {
|
||||||
|
|
|
@ -37,7 +37,10 @@ function httpGet(url) {
|
||||||
});
|
});
|
||||||
oReq.addEventListener("error", () => reject());
|
oReq.addEventListener("error", () => reject());
|
||||||
oReq.addEventListener("abort", () => reject());
|
oReq.addEventListener("abort", () => reject());
|
||||||
oReq.open("GET", url);
|
oReq.open("GET", url, true);
|
||||||
|
oReq.onerror = function () {
|
||||||
|
reject("HTTP Request failed");
|
||||||
|
};
|
||||||
oReq.send();
|
oReq.send();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue