Merge branch 'espruino:master' into master
|
@ -14,5 +14,6 @@
|
|||
{"name":"90sclk.app.js","url":"app.js"},
|
||||
{"name":"90sclk.img","url":"app-icon.js","evaluate":true},
|
||||
{"name":"90sclk.settings.js","url":"settings.js"}
|
||||
]
|
||||
],
|
||||
"data": [{"name":"90sclk.setting.json"}]
|
||||
}
|
||||
|
|
|
@ -14,5 +14,6 @@
|
|||
{"name":"activepedom.settings.js","url":"settings.js"},
|
||||
{"name":"activepedom.img","url":"app-icon.js","evaluate":true},
|
||||
{"name":"activepedom.app.js","url":"app.js"}
|
||||
]
|
||||
],
|
||||
"data":[{"name":"activepedom.settings.json"}]
|
||||
}
|
||||
|
|
|
@ -13,3 +13,4 @@
|
|||
Added dynamic, short and range fields to clkinfo
|
||||
0.12: Added color field and updating clkinfo periodically (running events)
|
||||
0.13: Show day of the week in date
|
||||
0.14: Fixed "Today" and "Yesterday" wrongly displayed for allDay events on some time zones
|
||||
|
|
|
@ -38,13 +38,12 @@ function formatDay(date) {
|
|||
if (!settings.useToday) {
|
||||
return formattedDate;
|
||||
}
|
||||
const dateformatted = date.toISOString().split('T')[0]; // yyyy-mm-dd
|
||||
const today = new Date(Date.now()).toISOString().split('T')[0]; // yyyy-mm-dd
|
||||
if (dateformatted == today) {
|
||||
const today = new Date(Date.now());
|
||||
if (date.getDay() == today.getDay() && date.getMonth() == today.getMonth())
|
||||
return /*LANG*/"Today ";
|
||||
} else {
|
||||
const tomorrow = new Date(Date.now() + 86400 * 1000).toISOString().split('T')[0]; // yyyy-mm-dd
|
||||
if (dateformatted == tomorrow) {
|
||||
else {
|
||||
const tomorrow = new Date(Date.now() + 86400 * 1000);
|
||||
if (date.getDay() == tomorrow.getDay() && date.getMonth() == tomorrow.getMonth()) {
|
||||
return /*LANG*/"Tomorrow ";
|
||||
}
|
||||
return formattedDate;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "agenda",
|
||||
"name": "Agenda",
|
||||
"version": "0.13",
|
||||
"version": "0.14",
|
||||
"description": "Simple agenda",
|
||||
"icon": "agenda.png",
|
||||
"screenshots": [{"url":"screenshot_agenda_overview.png"}, {"url":"screenshot_agenda_event1.png"}, {"url":"screenshot_agenda_event2.png"}],
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
0.01: first release
|
|
@ -0,0 +1,4 @@
|
|||
# Half-Life Alyx Style clock
|
||||
|
||||

|
||||
|
|
@ -0,0 +1,174 @@
|
|||
const icoH = [
|
||||
[0,1,1,0,0,1,1,0],
|
||||
[1,1,1,1,1,1,1,1],
|
||||
[1,1,1,1,1,1,1,1],
|
||||
[1,1,1,1,1,1,1,1],
|
||||
[0,1,1,1,1,1,1,0],
|
||||
[0,0,1,1,1,1,0,0],
|
||||
[0,0,0,1,1,0,0,0],
|
||||
[0,0,0,0,0,0,0,0],
|
||||
]
|
||||
|
||||
const icoR = [
|
||||
[0,0,0,0,1,1,1,1,0,0,0,0],
|
||||
[0,0,1,1,0,0,0,0,1,1,0,0],
|
||||
[0,1,1,1,1,0,0,1,1,0,1,0],
|
||||
[0,1,1,0,0,0,0,0,0,0,1,0],
|
||||
[1,1,1,1,1,1,1,1,0,0,0,1],
|
||||
[1,1,0,0,1,0,0,0,0,0,0,1],
|
||||
[1,1,1,1,1,1,1,0,1,1,0,1],
|
||||
[1,1,1,1,1,1,0,0,0,0,1,1],
|
||||
[0,1,1,1,1,1,1,1,1,1,1,0],
|
||||
[0,1,1,1,1,1,1,1,1,1,1,0],
|
||||
[0,0,1,1,1,1,1,1,1,1,0,0],
|
||||
[0,0,0,0,1,1,1,1,0,0,0,0],
|
||||
]
|
||||
|
||||
let idTimeout = null;
|
||||
|
||||
function icon (icon, x, y, size, gap) {
|
||||
const color = g.getColor();
|
||||
for (let r=0; r<icon.length; r++) {
|
||||
for (let c=0; c<icon[r].length; c++) {
|
||||
if (icon[r][c]===1){
|
||||
g.setColor(color);
|
||||
g.fillRect(c * size + x, r * size + y, (c+1) * size - gap + x, (r+1)*size - gap + y);
|
||||
g.setColor('#fff');
|
||||
g.drawLine(c * size + x + size/2 - 1, r * size + y + size/2 - 1, c * size + x + size/2 - 1, r * size + y + size/2 - 1, )
|
||||
}
|
||||
}
|
||||
}
|
||||
g.setColor(color);
|
||||
}
|
||||
|
||||
function ohmA(x, y) {
|
||||
g.setColor('#666');
|
||||
g.fillRect(x, y, x+8, y+15);
|
||||
g.setColor('#00f');
|
||||
g.drawLine(x, y + 4, x + 8, y + 4);
|
||||
g.setColor('#f00');
|
||||
g.drawLine(x, y + 6, x + 8, y + 6);
|
||||
g.setColor('#0f0');
|
||||
g.drawLine(x, y + 8, x + 8, y + 8);
|
||||
}
|
||||
|
||||
function ohmB(x, y) {
|
||||
g.setColor('#666');
|
||||
g.fillRect(x, y, x+15, y+8);
|
||||
g.setColor('#00f');
|
||||
g.drawLine(x + 4, y + 8, x + 4, y);
|
||||
g.setColor('#f00');
|
||||
g.drawLine(x + 6, y + 8, x + 6, y);
|
||||
g.setColor('#0f0');
|
||||
g.drawLine(x + 8, y + 8, x + 8, y);
|
||||
}
|
||||
|
||||
function heart (x, y) {
|
||||
g.setColor('#000');
|
||||
g.fillRect(x-2, y-2, x + 32, y + 32)
|
||||
g.setColor('#666');
|
||||
g.drawRect(x-2, y-2, x + 32, y + 32)
|
||||
g.setColor('#f00');
|
||||
icon(icoH, x, y, 4, 2);
|
||||
}
|
||||
|
||||
function resin() {
|
||||
let d = Date();
|
||||
let h = d.getHours();
|
||||
let m = d.getMinutes();
|
||||
|
||||
const resinPosX = 25;
|
||||
const resinPosY = 130;
|
||||
g.setColor('#000');
|
||||
g.fillRect(resinPosX - 3, resinPosY - 3, Bangle.appRect.w - resinPosX + 2, resinPosY + 40);
|
||||
g.setColor('#666');
|
||||
g.drawRect(resinPosX - 3, resinPosY - 3, Bangle.appRect.w - resinPosX + 2, resinPosY + 40);
|
||||
g.setColor('#6ff');
|
||||
icon(icoR, resinPosX, resinPosY, 3, 1);
|
||||
g.setFont('6x8', 5);
|
||||
g.setFontAlign(-1, -1);
|
||||
g.drawString('_' + (m<10?'0':'')+m, resinPosX + 40, resinPosY - 5);
|
||||
|
||||
g.setFontAlign(1, -1);
|
||||
g.setFont('6x8', 2);
|
||||
g.drawString(h, resinPosX + 66, resinPosY);
|
||||
}
|
||||
|
||||
function screw(x, y) {
|
||||
g.setColor('#666').fillCircle(x, y, 4).setColor('#000').drawLine(x - 4, y, x + 4, y)
|
||||
}
|
||||
|
||||
function led(x,y) {
|
||||
g.setColor('#0f0').fillCircle(x, y, 8).setColor('#fff').fillCircle(x-3, y-3, 3);
|
||||
}
|
||||
|
||||
|
||||
function drawTime() {
|
||||
const R = Bangle.appRect;
|
||||
g.setBgColor('#000');
|
||||
g.clear();
|
||||
Bangle.drawWidgets();
|
||||
g.reset();
|
||||
|
||||
// pcb
|
||||
g.setColor('#030').fillRect(R.x, R.y, R.x2, R.y2);
|
||||
screw(R.x + 8, R.y + 8)
|
||||
screw(R.x2 - 8, R.y + 8)
|
||||
screw(R.x + 8, R.y2 - 8)
|
||||
screw(R.x2 - 8, R.y2 - 8)
|
||||
for(let i=0; i<6; i++) {
|
||||
g.setColor('#fff');
|
||||
g.drawLine(24 + i * 9, 70, 24 + i * 9, 110);
|
||||
g.drawLine(24 + i * 9, 110, 54 + i * 9, 140);
|
||||
}
|
||||
ohmA(29, 90);
|
||||
ohmA(56, 90);
|
||||
ohmB(80, 90);
|
||||
screw(90, 110)
|
||||
// led
|
||||
led(50, R.y+10);
|
||||
led(70, R.y+10);
|
||||
ohmB(20, R.y + 10);
|
||||
ohmB(90, R.y + 2);
|
||||
ohmB(90, R.y + 14);
|
||||
|
||||
heart(10, 52);
|
||||
heart(50, 52);
|
||||
heart(90, 52);
|
||||
|
||||
|
||||
|
||||
g.setColor('#666');
|
||||
for (let i=0; i<6; i++) {
|
||||
g.fillCircle(110 + i*10, 80+10, 3);
|
||||
g.fillCircle(110 + i*10, 110+10, 3);
|
||||
}
|
||||
g.setColor('#000');
|
||||
g.fillRect(110, 80+10, 170, 110+10);
|
||||
g.setColor('#666');
|
||||
g.drawRect(110, 80+10, 170, 110+10);
|
||||
g.setFont('6x8').setColor('#666').drawString('AH-118080\n0WT 18-001', 112, 85+10);
|
||||
|
||||
|
||||
resin();
|
||||
|
||||
let d = Date();
|
||||
let t = d.getSeconds()*1000 + d.getMilliseconds();
|
||||
idTimeout = setTimeout(drawTime, 60000 - t); // time till next minute
|
||||
}
|
||||
|
||||
// special function to handle display switch on
|
||||
Bangle.on('lcdPower', function(on){
|
||||
if (on) {
|
||||
drawTime();
|
||||
} else {
|
||||
if(idTimeout) {
|
||||
clearTimeout(idTimeout);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Show launcher when button pressed
|
||||
Bangle.setUI("clock");
|
||||
Bangle.loadWidgets();
|
||||
drawTime();
|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("mEwwkAqoA/AHlUmYADC69FC601C600C60yC6x4SAANTPCgyFkowTSCgACkZ4TAAVDPCwvCPCaqEPCSnDPCZeDmc0Uyh4TqQXFPCBGEPCQWFPCClEPCSlDmjZDdiUlMYZ4NIwg0EPBpGEDoh4NIIYpCPCDqGMoUydh4oDPB5GGPCBGGG4h4CGQ6HDN4gIEqkjSY4+DBYreDSZINDHYpoDKYw9FTww5DC5BGJPAg8MQQw6DBpBGJWIsyCwtUkQABZhA7CkjYKfJIsGAB9UCqgA/ACQ"))
|
After Width: | Height: | Size: 854 B |
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"id": "alyxclock",
|
||||
"name": "Alyx Clock",
|
||||
"version": "0.01",
|
||||
"description": "A clock in the style of half-life alyx gravity gloves",
|
||||
"icon": "alyxclock.png",
|
||||
"screenshots": [{"url":"screenshot_alyxclock.png"}],
|
||||
"type": "clock",
|
||||
"tags": "clock",
|
||||
"supports": ["BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
"allow_emulator": true,
|
||||
"storage": [
|
||||
{"name":"alyxclock.app.js","url":"alyxclock.app.js"},
|
||||
{"name":"alyxclock.img","url":"alyxclock.icon.js","evaluate":true}
|
||||
]
|
||||
}
|
After Width: | Height: | Size: 3.5 KiB |
|
@ -26,3 +26,5 @@
|
|||
0.25: Added option to 'ignore' an app from the message
|
||||
0.26: Change handling of GPS status to depend on GPS events instead of connection events
|
||||
0.27: Issue newline before GB commands (solves issue with console.log and ignored commands)
|
||||
0.28: Navigation messages no longer launch the Maps view unless they're new
|
||||
0.29: Support for http request xpath return format
|
|
@ -203,6 +203,8 @@
|
|||
event.t="add";
|
||||
event.src="maps"; // for the icon
|
||||
event.title="Navigation";
|
||||
if (require("messages").getMessages().find(m=>m.id=="nav"))
|
||||
event.t = "modify";
|
||||
} else {
|
||||
event.t="remove";
|
||||
}
|
||||
|
@ -229,6 +231,7 @@
|
|||
//send the request
|
||||
var req = {t: "http", url:url, id:options.id};
|
||||
if (options.xpath) req.xpath = options.xpath;
|
||||
if (options.return) req.return = options.return; // for xpath
|
||||
if (options.method) req.method = options.method;
|
||||
if (options.body) req.body = options.body;
|
||||
if (options.headers) req.headers = options.headers;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"id": "android",
|
||||
"name": "Android Integration",
|
||||
"shortName": "Android",
|
||||
"version": "0.27",
|
||||
"version": "0.29",
|
||||
"description": "Display notifications/music/etc sent from the Gadgetbridge app on Android. This replaces the old 'Gadgetbridge' Bangle.js widget.",
|
||||
"icon": "app.png",
|
||||
"tags": "tool,system,messages,notifications,gadgetbridge",
|
||||
|
|
|
@ -1,2 +1,5 @@
|
|||
0.01: New App!
|
||||
0.02: New config options such as step, meridian, short/long formats, custom prefix/suffix
|
||||
0.03: Allows showing the month in short or long format by setting `"shortMonth"` to true or false
|
||||
0.04: Improves touchscreen drag handling for background apps such as Pattern Launcher
|
||||
0.05: Fixes step count not resetting after a new day starts
|
||||
|
|
|
@ -18,7 +18,7 @@ Each box can be customized extensively via a simple JSON configuration. You can
|
|||
|
||||
## Config File Structure
|
||||
|
||||
Here's what an example configuration might look like:
|
||||
Here's an example of what a configuration might contain:
|
||||
|
||||
```
|
||||
{
|
||||
|
@ -37,8 +37,9 @@ Here's what an example configuration might look like:
|
|||
"boxPos": { "x": 0.5, "y": 0.5 },
|
||||
"prefix": "", // Adds a string to the beginning of the main string
|
||||
"suffix": "", // Adds a string to the end of the main string
|
||||
"disableSuffix": true, // Only used to remove the DayOfMonth suffix
|
||||
"short": false // Gets long format value of time, meridian, date, or DoW
|
||||
"disableSuffix": true, // Use to remove DayOfMonth suffix only
|
||||
"short": false, // Use long format of time, meridian, date, or DoW
|
||||
"shortMonth": false // Use long format of month within date
|
||||
|
||||
},
|
||||
"bg": { // Can also be removed for no background
|
||||
|
@ -51,9 +52,9 @@ __Breakdown of Parameters:__
|
|||
|
||||
* **Box Name:** The name of your text box. Box Clock includes functional support for "time", "date", "meridian" (AM/PM), "dow" (Day of Week), "batt" (Battery), and "step" (Step count). You can add additional custom boxes with unique titles.
|
||||
|
||||
* **string:** The text string to be displayed inside the box.
|
||||
* **string:** The text string to be displayed inside the box. This is only required for custom Box Names.
|
||||
|
||||
* **font:** The font name given to g.setFont()
|
||||
* **font:** The font name given to g.setFont().
|
||||
|
||||
* **fontSize:** The size of the font.
|
||||
|
||||
|
@ -75,17 +76,34 @@ __Breakdown of Parameters:__
|
|||
|
||||
* **suffix:** Adds a string to the end of the main string. For example, you can set "suffix": "%" to display "80%" for the battery percentage.
|
||||
|
||||
* **disableSuffix:** Applies only to the "date" box. Set to true to disable the DayOfMonth suffix. This is used to remove the "st","nd","rd", or "th" from the DayOfMonth number
|
||||
* **disableSuffix:** Applies only to the "date" box. Set to true to disable the DayOfMonth suffix. This is used to remove the "st","nd","rd", or "th" from the DayOfMonth number.
|
||||
|
||||
* **short:** Set to false to get the long format value of time, meridian, date, or DayOfWeek. Short formats are used by default,
|
||||
* **short:** Set to false to get the long format value of time, meridian, date, or DayOfWeek. Short formats are used by default if not specified.
|
||||
|
||||
* **shortMonth:** Applies only to the "date" box. Set to false to get the long format value of the month. Short format is used by default if not specified.
|
||||
|
||||
* **bg:** This specifies a custom background image, with the img property defining the name of the image file on the Bangle.js storage.
|
||||
|
||||
## Multiple Configurations
|
||||
|
||||
The app includes a settings menu that allows you to switch between different configurations. The selected configuration is stored in the default JSON file alongside the other configuration data using the selectedConfig property.
|
||||
__Settings Menu:__
|
||||
|
||||
If the selectedConfig property is not present or is set to 0, the app will use the default configuration. To create additional configurations, create separate JSON files with the naming convention boxclk-N.json, where N is the configuration number. The settings menu will list all available configurations.
|
||||
The app includes a settings menu that allows you to switch between different configurations. The selected configuration is stored as a number in the default `boxclk.json` file using the selectedConfig property.
|
||||
|
||||
If the selectedConfig property is not present or is set to 0, the app will use the default configuration. To create additional configurations, create separate JSON files with the naming convention `boxclk-N.json`, where `N` is the configuration number. The settings menu will list all available configurations.
|
||||
|
||||
## Example Configs:
|
||||
|
||||
To easily try out other configs, download and place the JSON configs and/or background images from below onto your Bangle.js storage. Then go to the Box Clock settings menu to select the new config number. You can also modify them to suit your personal preferences.
|
||||
|
||||
__Space Theme:__
|
||||
|
||||
- **Config:** [boxclk-1.json](https://github.com/espruino/BangleApps/tree/master/apps/boxclk/boxclk-1.json)
|
||||
- **Background:** [boxclk.space.img](https://github.com/espruino/BangleApps/tree/master/apps/boxclk/boxclk.space.img) ([Original Source](https://www.pixilart.com/art/fallin-from-outer-space-sr2e0c1a705749a))
|
||||
|
||||
__System Color Theme:__
|
||||
|
||||
- **Config:** [boxclk-2.json](https://github.com/espruino/BangleApps/tree/master/apps/boxclk/boxclk-2.json)
|
||||
|
||||
## Compatibility
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* 1. Module dependencies and initial configurations
|
||||
* ---------------------------------------------------------------
|
||||
*/
|
||||
|
||||
let storage = require("Storage");
|
||||
let locale = require("locale");
|
||||
let widgets = require("widget_utils");
|
||||
|
@ -30,6 +31,7 @@
|
|||
* 2. Graphical and visual configurations
|
||||
* ---------------------------------------------------------------
|
||||
*/
|
||||
|
||||
let w = g.getWidth();
|
||||
let h = g.getHeight();
|
||||
let totalWidth, totalHeight;
|
||||
|
@ -40,6 +42,7 @@
|
|||
* 3. Touchscreen Handlers
|
||||
* ---------------------------------------------------------------
|
||||
*/
|
||||
|
||||
let touchHandler;
|
||||
let dragHandler;
|
||||
let movementDistance = 0;
|
||||
|
@ -49,6 +52,7 @@
|
|||
* 4. Font loading function
|
||||
* ---------------------------------------------------------------
|
||||
*/
|
||||
|
||||
let loadCustomFont = function() {
|
||||
Graphics.prototype.setFontBrunoAce = function() {
|
||||
// Actual height 23 (24 - 2)
|
||||
|
@ -66,6 +70,7 @@
|
|||
* 5. Initial settings of boxes and their positions
|
||||
* ---------------------------------------------------------------
|
||||
*/
|
||||
|
||||
for (let key in boxesConfig) {
|
||||
if (key === 'bg' && boxesConfig[key].img) {
|
||||
bgImage = storage.read(boxesConfig[key].img);
|
||||
|
@ -167,14 +172,15 @@
|
|||
* 7. String forming helper functions
|
||||
* ---------------------------------------------------------------
|
||||
*/
|
||||
|
||||
let isBool = function(val, defaultVal) {
|
||||
return typeof val !== 'undefined' ? Boolean(val) : defaultVal;
|
||||
};
|
||||
|
||||
let getDate = function(short, disableSuffix) {
|
||||
let getDate = function(short, shortMonth, disableSuffix) {
|
||||
const date = new Date();
|
||||
const dayOfMonth = date.getDate();
|
||||
const month = short ? locale.month(date, 0) : locale.month(date, 1);
|
||||
const month = shortMonth ? locale.month(date, 1) : locale.month(date, 0);
|
||||
const year = date.getFullYear();
|
||||
let suffix;
|
||||
if ([1, 21, 31].includes(dayOfMonth)) {
|
||||
|
@ -211,6 +217,7 @@
|
|||
* 8. Main draw function
|
||||
* ---------------------------------------------------------------
|
||||
*/
|
||||
|
||||
let draw = (function() {
|
||||
let updatePerMinute = true; // variable to track the state of time display
|
||||
|
||||
|
@ -228,7 +235,12 @@
|
|||
boxes.meridian.string = modString(boxes.meridian, locale.meridian(date, isBool(boxes.meridian.short, true)));
|
||||
}
|
||||
if (boxes.date) {
|
||||
boxes.date.string = modString(boxes.date, getDate(isBool(boxes.date.short, true), isBool(boxes.date.disableSuffix, false)));
|
||||
boxes.date.string = (
|
||||
modString(boxes.date,
|
||||
getDate(isBool(boxes.date.short, true),
|
||||
isBool(boxes.date.shortMonth, true),
|
||||
isBool(boxes.date.disableSuffix, false)
|
||||
)));
|
||||
}
|
||||
if (boxes.dow) {
|
||||
boxes.dow.string = modString(boxes.dow, getDayOfWeek(date, isBool(boxes.dow.short, true)));
|
||||
|
@ -237,7 +249,7 @@
|
|||
boxes.batt.string = modString(boxes.batt, E.getBattery());
|
||||
}
|
||||
if (boxes.step) {
|
||||
boxes.step.string = modString(boxes.step, Bangle.getStepCount());
|
||||
boxes.step.string = modString(boxes.step, Bangle.getHealthStatus("day").steps);
|
||||
}
|
||||
boxKeys.forEach((boxKey) => {
|
||||
let boxItem = boxes[boxKey];
|
||||
|
@ -267,6 +279,7 @@
|
|||
* 9. Helper function for touch event
|
||||
* ---------------------------------------------------------------
|
||||
*/
|
||||
|
||||
let touchInText = function(e, boxItem, boxKey) {
|
||||
calcBoxSize(boxItem);
|
||||
const pos = calcBoxPos(boxKey);
|
||||
|
@ -291,6 +304,7 @@
|
|||
* 10. Setup function to configure event handlers
|
||||
* ---------------------------------------------------------------
|
||||
*/
|
||||
|
||||
let setup = function() {
|
||||
// ------------------------------------
|
||||
// Define the touchHandler function
|
||||
|
@ -338,6 +352,8 @@
|
|||
// Define the dragHandler function
|
||||
// ------------------------------------
|
||||
dragHandler = function(e) {
|
||||
// Check if any box is being dragged
|
||||
if (!Object.values(isDragging).some(Boolean)) return;
|
||||
// Calculate the movement distance
|
||||
movementDistance += Math.abs(e.dx) + Math.abs(e.dy);
|
||||
// Check if the movement distance exceeds a threshold
|
||||
|
@ -391,8 +407,9 @@
|
|||
* 11. Main execution part
|
||||
* ---------------------------------------------------------------
|
||||
*/
|
||||
|
||||
Bangle.loadWidgets();
|
||||
widgets.swipeOn();
|
||||
modSetColor();
|
||||
setup();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
{
|
||||
"time": {
|
||||
"font": "6x8",
|
||||
"fontSize": 3,
|
||||
"outline": 2,
|
||||
"color": "#0ff",
|
||||
"outlineColor": "#00f",
|
||||
"border": "#0f0",
|
||||
"xPadding": -1,
|
||||
"yPadding": -2.5,
|
||||
"xOffset": 2,
|
||||
"yOffset": 0,
|
||||
"boxPos": {
|
||||
"x": "0.33",
|
||||
"y": "0.29"
|
||||
}
|
||||
},
|
||||
"meridian": {
|
||||
"font": "6x8",
|
||||
"fontSize": 2,
|
||||
"outline": 1,
|
||||
"color": "#FF9900",
|
||||
"outlineColor": "fg",
|
||||
"border": "#0ff",
|
||||
"xPadding": -0.5,
|
||||
"yPadding": -1.5,
|
||||
"xOffset": 2,
|
||||
"yOffset": 1,
|
||||
"boxPos": {
|
||||
"x": "0.34",
|
||||
"y": "0.46"
|
||||
},
|
||||
"short": false
|
||||
},
|
||||
"dow": {
|
||||
"font": "6x8",
|
||||
"fontSize": 2,
|
||||
"outline": 1,
|
||||
"color": "#000",
|
||||
"outlineColor": "#fff",
|
||||
"border": "#0f0",
|
||||
"xPadding": -0.5,
|
||||
"yPadding": -0.5,
|
||||
"xOffset": 1,
|
||||
"yOffset": 1,
|
||||
"boxPos": {
|
||||
"x": "0.5",
|
||||
"y": "0.82"
|
||||
}
|
||||
},
|
||||
"step": {
|
||||
"font": "6x8",
|
||||
"fontSize": 2,
|
||||
"outline": 1,
|
||||
"color": "#000",
|
||||
"outlineColor": "#fff",
|
||||
"border": "#0f0",
|
||||
"xPadding": -0.5,
|
||||
"yPadding": 0.5,
|
||||
"xOffset": 1,
|
||||
"yOffset": 1,
|
||||
"boxPos": {
|
||||
"x": "0.5",
|
||||
"y": "0.71"
|
||||
},
|
||||
"prefix": "Steps: "
|
||||
},
|
||||
"batt": {
|
||||
"font": "4x6",
|
||||
"fontSize": 2,
|
||||
"outline": 1,
|
||||
"color": "#0ff",
|
||||
"outlineColor": "#00f",
|
||||
"border": "#0f0",
|
||||
"xPadding": -0.5,
|
||||
"yPadding": -0.5,
|
||||
"xOffset": 1,
|
||||
"yOffset": 1,
|
||||
"boxPos": {
|
||||
"x": "0.87",
|
||||
"y": "0.87"
|
||||
},
|
||||
"suffix": "%"
|
||||
},
|
||||
"bg": {
|
||||
"img": "boxclk.space.img"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
{
|
||||
"time": {
|
||||
"font": "6x8",
|
||||
"fontSize": 5,
|
||||
"outline": 3,
|
||||
"color": "bgH",
|
||||
"outlineColor": "fg",
|
||||
"border": "#f0f",
|
||||
"xPadding": -2,
|
||||
"yPadding": -4.5,
|
||||
"xOffset": 3,
|
||||
"yOffset": 0,
|
||||
"boxPos": {
|
||||
"x": "0.5",
|
||||
"y": "0.33"
|
||||
}
|
||||
},
|
||||
"dow": {
|
||||
"font": "6x8",
|
||||
"fontSize": 3,
|
||||
"outline": 1,
|
||||
"color": "#5ccd73",
|
||||
"outlineColor": "fg",
|
||||
"border": "#f0f",
|
||||
"xPadding": -1,
|
||||
"yPadding": 0.5,
|
||||
"xOffset": 2,
|
||||
"yOffset": 0,
|
||||
"boxPos": {
|
||||
"x": "0.5",
|
||||
"y": "0.57"
|
||||
},
|
||||
"short": false
|
||||
},
|
||||
"date": {
|
||||
"font": "6x8",
|
||||
"fontSize": 2,
|
||||
"outline": 1,
|
||||
"color": "#5ccd73",
|
||||
"outlineColor": "fg",
|
||||
"border": "#f0f",
|
||||
"xPadding": -0.5,
|
||||
"yPadding": 0.5,
|
||||
"xOffset": 1,
|
||||
"yOffset": 0,
|
||||
"boxPos": {
|
||||
"x": "0.5",
|
||||
"y": "0.75"
|
||||
},
|
||||
"shortMonth": false,
|
||||
"disableSuffix": true
|
||||
},
|
||||
"step": {
|
||||
"font": "4x6",
|
||||
"fontSize": 3,
|
||||
"outline": 2,
|
||||
"color": "bgH",
|
||||
"outlineColor": "fg",
|
||||
"border": "#f0f",
|
||||
"xPadding": -1,
|
||||
"yPadding": 0.5,
|
||||
"xOffset": 2,
|
||||
"yOffset": 1,
|
||||
"boxPos": {
|
||||
"x": "0.5",
|
||||
"y": "0.92"
|
||||
},
|
||||
"prefix": "Steps: "
|
||||
},
|
||||
"batt": {
|
||||
"font": "4x6",
|
||||
"fontSize": 3,
|
||||
"outline": 2,
|
||||
"color": "bgH",
|
||||
"outlineColor": "fg",
|
||||
"border": "#f0f",
|
||||
"xPadding": -1,
|
||||
"yPadding": -1,
|
||||
"xOffset": 2,
|
||||
"yOffset": 2,
|
||||
"boxPos": {
|
||||
"x": "0.85",
|
||||
"y": "0.08"
|
||||
},
|
||||
"suffix": "%"
|
||||
}
|
||||
}
|
|
@ -1,12 +1,13 @@
|
|||
{
|
||||
"id": "boxclk",
|
||||
"name": "Box Clock",
|
||||
"version": "0.02",
|
||||
"version": "0.05",
|
||||
"description": "A customizable clock with configurable text boxes that can be positioned to show your favorite background",
|
||||
"icon": "app.png",
|
||||
"screenshots": [
|
||||
{"url":"screenshot.png"},
|
||||
{"url":"screenshot-1.png"}
|
||||
{"url":"screenshot-1.png"},
|
||||
{"url":"screenshot-2.png"}
|
||||
],
|
||||
"type": "clock",
|
||||
"tags": "clock",
|
||||
|
|
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 5.9 KiB |
After Width: | Height: | Size: 3.4 KiB |
|
@ -1,411 +1,413 @@
|
|||
var __assign = Object.assign;
|
||||
var Layout = require("Layout");
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
var HRM_MIN_CONFIDENCE = 75;
|
||||
var services = ["0x180d", "0x181a", "0x1819"];
|
||||
var acc;
|
||||
var bar;
|
||||
var gps;
|
||||
var hrm;
|
||||
var hrmAny;
|
||||
var mag;
|
||||
var btnsShown = false;
|
||||
var prevBtnsShown = undefined;
|
||||
var hrmAnyClear;
|
||||
var settings = {
|
||||
bar: false,
|
||||
gps: false,
|
||||
hrm: false,
|
||||
mag: false,
|
||||
};
|
||||
var idToName = {
|
||||
acc: "Acceleration",
|
||||
bar: "Barometer",
|
||||
gps: "GPS",
|
||||
hrm: "HRM",
|
||||
mag: "Magnetometer",
|
||||
};
|
||||
var infoFont = "6x8:2";
|
||||
var colour = {
|
||||
on: "#0f0",
|
||||
off: "#fff",
|
||||
};
|
||||
var makeToggle = function (id) { return function () {
|
||||
settings[id] = !settings[id];
|
||||
var entry = btnLayout[id];
|
||||
var col = settings[id] ? colour.on : colour.off;
|
||||
entry.btnBorder = entry.col = col;
|
||||
btnLayout.update();
|
||||
btnLayout.render();
|
||||
enableSensors();
|
||||
}; };
|
||||
var btnStyle = {
|
||||
font: "Vector:14",
|
||||
fillx: 1,
|
||||
filly: 1,
|
||||
col: g.theme.fg,
|
||||
bgCol: g.theme.bg,
|
||||
btnBorder: "#fff",
|
||||
};
|
||||
var btnLayout = new Layout({
|
||||
type: "v",
|
||||
c: [
|
||||
{
|
||||
type: "h",
|
||||
c: [
|
||||
__assign({ type: "btn", label: idToName.bar, id: "bar", cb: makeToggle('bar') }, btnStyle),
|
||||
__assign({ type: "btn", label: idToName.gps, id: "gps", cb: makeToggle('gps') }, btnStyle),
|
||||
]
|
||||
},
|
||||
{
|
||||
type: "h",
|
||||
c: [
|
||||
__assign({ type: "btn", label: idToName.hrm, id: "hrm", cb: makeToggle('hrm') }, btnStyle),
|
||||
__assign({ type: "btn", label: idToName.mag, id: "mag", cb: makeToggle('mag') }, btnStyle),
|
||||
]
|
||||
},
|
||||
{
|
||||
type: "h",
|
||||
c: [
|
||||
__assign(__assign({ type: "btn", label: idToName.acc, id: "acc", cb: function () { } }, btnStyle), { col: colour.on, btnBorder: colour.on }),
|
||||
__assign({ type: "btn", label: "Back", cb: function () {
|
||||
setBtnsShown(false);
|
||||
} }, btnStyle),
|
||||
]
|
||||
}
|
||||
]
|
||||
}, {
|
||||
lazy: true,
|
||||
back: function () {
|
||||
setBtnsShown(false);
|
||||
},
|
||||
});
|
||||
var setBtnsShown = function (b) {
|
||||
btnsShown = b;
|
||||
hook(!btnsShown);
|
||||
setIntervals();
|
||||
redraw();
|
||||
};
|
||||
var drawInfo = function (force) {
|
||||
var _a = Bangle.appRect, y = _a.y, x = _a.x, w = _a.w;
|
||||
var mid = x + w / 2;
|
||||
var drawn = false;
|
||||
if (!force && !bar && !gps && !hrm && !mag)
|
||||
return;
|
||||
g.reset()
|
||||
.clearRect(Bangle.appRect)
|
||||
.setFont(infoFont)
|
||||
.setFontAlign(0, -1);
|
||||
if (bar) {
|
||||
g.drawString("".concat(bar.altitude.toFixed(1), "m"), mid, y);
|
||||
y += g.getFontHeight();
|
||||
g.drawString("".concat(bar.pressure.toFixed(1), " hPa"), mid, y);
|
||||
y += g.getFontHeight();
|
||||
g.drawString("".concat(bar.temperature.toFixed(1), "C"), mid, y);
|
||||
y += g.getFontHeight();
|
||||
drawn = true;
|
||||
}
|
||||
if (gps) {
|
||||
g.drawString("".concat(gps.lat.toFixed(4), " lat, ").concat(gps.lon.toFixed(4), " lon"), mid, y);
|
||||
y += g.getFontHeight();
|
||||
g.drawString("".concat(gps.alt, "m (").concat(gps.satellites, " sat)"), mid, y);
|
||||
y += g.getFontHeight();
|
||||
drawn = true;
|
||||
}
|
||||
if (hrm) {
|
||||
g.drawString("".concat(hrm.bpm, " BPM (").concat(hrm.confidence, "%)"), mid, y);
|
||||
y += g.getFontHeight();
|
||||
drawn = true;
|
||||
}
|
||||
else if (hrmAny) {
|
||||
g.drawString("~".concat(hrmAny.bpm, " BPM (").concat(hrmAny.confidence, "%)"), mid, y);
|
||||
y += g.getFontHeight();
|
||||
drawn = true;
|
||||
if (!settings.hrm && !hrmAnyClear) {
|
||||
hrmAnyClear = setTimeout(function () {
|
||||
hrmAny = undefined;
|
||||
hrmAnyClear = undefined;
|
||||
}, 10000);
|
||||
}
|
||||
}
|
||||
if (mag) {
|
||||
g.drawString("".concat(mag.x, " ").concat(mag.y, " ").concat(mag.z), mid, y);
|
||||
y += g.getFontHeight();
|
||||
g.drawString("heading: ".concat(mag.heading.toFixed(1)), mid, y);
|
||||
y += g.getFontHeight();
|
||||
drawn = true;
|
||||
}
|
||||
if (!drawn) {
|
||||
if (!force || Object.values(settings).every(function (x) { return !x; })) {
|
||||
g.drawString("swipe to enable", mid, y);
|
||||
}
|
||||
else {
|
||||
g.drawString("events pending", mid, y);
|
||||
}
|
||||
y += g.getFontHeight();
|
||||
}
|
||||
};
|
||||
var onTap = function () {
|
||||
setBtnsShown(true);
|
||||
};
|
||||
var redraw = function () {
|
||||
if (btnsShown) {
|
||||
if (!prevBtnsShown) {
|
||||
prevBtnsShown = btnsShown;
|
||||
Bangle.removeListener("swipe", onTap);
|
||||
btnLayout.setUI();
|
||||
btnLayout.forgetLazyState();
|
||||
g.clearRect(Bangle.appRect);
|
||||
}
|
||||
btnLayout.render();
|
||||
}
|
||||
else {
|
||||
if (prevBtnsShown) {
|
||||
prevBtnsShown = btnsShown;
|
||||
Bangle.setUI();
|
||||
Bangle.on("swipe", onTap);
|
||||
drawInfo(true);
|
||||
}
|
||||
else {
|
||||
drawInfo();
|
||||
}
|
||||
}
|
||||
};
|
||||
var encodeHrm = function (hrm) {
|
||||
return [0, hrm.bpm];
|
||||
};
|
||||
encodeHrm.maxLen = 2;
|
||||
var encodePressure = function (data) {
|
||||
return toByteArray(Math.round(data.pressure * 10), 4, false);
|
||||
};
|
||||
encodePressure.maxLen = 4;
|
||||
var encodeElevation = function (data) {
|
||||
return toByteArray(Math.round(data.altitude * 100), 3, true);
|
||||
};
|
||||
encodeElevation.maxLen = 3;
|
||||
var encodeTemp = function (data) {
|
||||
return toByteArray(Math.round(data.temperature * 10), 2, true);
|
||||
};
|
||||
encodeTemp.maxLen = 2;
|
||||
var encodeGps = function (data) {
|
||||
var speed = toByteArray(Math.round(1000 * data.speed / 36), 2, false);
|
||||
var lat = toByteArray(Math.round(data.lat * 10000000), 4, true);
|
||||
var lon = toByteArray(Math.round(data.lon * 10000000), 4, true);
|
||||
var elevation = toByteArray(Math.round(data.alt * 100), 3, true);
|
||||
var heading = toByteArray(Math.round(data.course * 100), 2, false);
|
||||
return [
|
||||
157,
|
||||
2,
|
||||
speed[0], speed[1],
|
||||
lat[0], lat[1], lat[2], lat[3],
|
||||
lon[0], lon[1], lon[2], lon[3],
|
||||
elevation[0], elevation[1], elevation[2],
|
||||
heading[0], heading[1]
|
||||
];
|
||||
};
|
||||
encodeGps.maxLen = 17;
|
||||
var encodeGpsHeadingOnly = function (data) {
|
||||
var heading = toByteArray(Math.round(data.heading * 100), 2, false);
|
||||
return [
|
||||
16,
|
||||
16,
|
||||
heading[0], heading[1]
|
||||
];
|
||||
};
|
||||
encodeGpsHeadingOnly.maxLen = 17;
|
||||
var encodeMag = function (data) {
|
||||
var x = toByteArray(data.x, 2, true);
|
||||
var y = toByteArray(data.y, 2, true);
|
||||
var z = toByteArray(data.z, 2, true);
|
||||
return [x[0], x[1], y[0], y[1], z[0], z[1]];
|
||||
};
|
||||
encodeMag.maxLen = 6;
|
||||
var toByteArray = function (value, numberOfBytes, isSigned) {
|
||||
var byteArray = new Array(numberOfBytes);
|
||||
if (isSigned && (value < 0)) {
|
||||
value += 1 << (numberOfBytes * 8);
|
||||
}
|
||||
for (var index = 0; index < numberOfBytes; index++) {
|
||||
byteArray[index] = (value >> (index * 8)) & 0xff;
|
||||
}
|
||||
return byteArray;
|
||||
};
|
||||
var enableSensors = function () {
|
||||
Bangle.setBarometerPower(settings.bar, "btadv");
|
||||
if (!settings.bar)
|
||||
bar = undefined;
|
||||
Bangle.setGPSPower(settings.gps, "btadv");
|
||||
if (!settings.gps)
|
||||
gps = undefined;
|
||||
Bangle.setHRMPower(settings.hrm, "btadv");
|
||||
if (!settings.hrm)
|
||||
hrm = hrmAny = undefined;
|
||||
Bangle.setCompassPower(settings.mag, "btadv");
|
||||
if (!settings.mag)
|
||||
mag = undefined;
|
||||
};
|
||||
var haveServiceData = function (serv) {
|
||||
switch (serv) {
|
||||
case "0x180d": return !!hrm;
|
||||
case "0x181a": return !!(bar || mag);
|
||||
case "0x1819": return !!(gps && gps.lat && gps.lon || mag);
|
||||
}
|
||||
};
|
||||
var serviceToAdvert = function (serv, initial) {
|
||||
var _a, _b, _c;
|
||||
if (initial === void 0) { initial = false; }
|
||||
switch (serv) {
|
||||
case "0x180d":
|
||||
if (hrm || initial) {
|
||||
var o = {
|
||||
maxLen: encodeHrm.maxLen,
|
||||
readable: true,
|
||||
notify: true,
|
||||
};
|
||||
if (hrm) {
|
||||
o.value = encodeHrm(hrm);
|
||||
hrm = undefined;
|
||||
}
|
||||
return _a = {}, _a["0x2a37"] = o, _a;
|
||||
}
|
||||
return {};
|
||||
case "0x1819":
|
||||
if (gps || initial) {
|
||||
var o = {
|
||||
maxLen: encodeGps.maxLen,
|
||||
readable: true,
|
||||
notify: true,
|
||||
};
|
||||
if (gps) {
|
||||
o.value = encodeGps(gps);
|
||||
gps = undefined;
|
||||
}
|
||||
return _b = {}, _b["0x2a67"] = o, _b;
|
||||
}
|
||||
else if (mag) {
|
||||
var o = {
|
||||
maxLen: encodeGpsHeadingOnly.maxLen,
|
||||
readable: true,
|
||||
notify: true,
|
||||
value: encodeGpsHeadingOnly(mag),
|
||||
};
|
||||
return _c = {}, _c["0x2a67"] = o, _c;
|
||||
}
|
||||
return {};
|
||||
case "0x181a": {
|
||||
var o = {};
|
||||
if (bar || initial) {
|
||||
o["0x2a6c"] = {
|
||||
maxLen: encodeElevation.maxLen,
|
||||
readable: true,
|
||||
notify: true,
|
||||
};
|
||||
o["0x2A1F"] = {
|
||||
maxLen: encodeTemp.maxLen,
|
||||
readable: true,
|
||||
notify: true,
|
||||
};
|
||||
o["0x2a6d"] = {
|
||||
maxLen: encodePressure.maxLen,
|
||||
readable: true,
|
||||
notify: true,
|
||||
};
|
||||
if (bar) {
|
||||
o["0x2a6c"].value = encodeElevation(bar);
|
||||
o["0x2A1F"].value = encodeTemp(bar);
|
||||
o["0x2a6d"].value = encodePressure(bar);
|
||||
bar = undefined;
|
||||
}
|
||||
}
|
||||
if (mag || initial) {
|
||||
o["0x2aa1"] = {
|
||||
maxLen: encodeMag.maxLen,
|
||||
readable: true,
|
||||
notify: true,
|
||||
};
|
||||
if (mag) {
|
||||
o["0x2aa1"].value = encodeMag(mag);
|
||||
}
|
||||
}
|
||||
return o;
|
||||
}
|
||||
}
|
||||
};
|
||||
var getBleAdvert = function (map, all) {
|
||||
if (all === void 0) { all = false; }
|
||||
var advert = {};
|
||||
for (var _i = 0, services_1 = services; _i < services_1.length; _i++) {
|
||||
var serv = services_1[_i];
|
||||
if (all || haveServiceData(serv)) {
|
||||
advert[serv] = map(serv);
|
||||
}
|
||||
}
|
||||
mag = undefined;
|
||||
return advert;
|
||||
};
|
||||
var updateServices = function () {
|
||||
var newAdvert = getBleAdvert(serviceToAdvert);
|
||||
NRF.updateServices(newAdvert);
|
||||
};
|
||||
var onAccel = function (newAcc) { return acc = newAcc; };
|
||||
var onPressure = function (newBar) { return bar = newBar; };
|
||||
var onGPS = function (newGps) { return gps = newGps; };
|
||||
var onHRM = function (newHrm) {
|
||||
if (newHrm.confidence >= HRM_MIN_CONFIDENCE)
|
||||
hrm = newHrm;
|
||||
hrmAny = newHrm;
|
||||
};
|
||||
var onMag = function (newMag) { return mag = newMag; };
|
||||
var hook = function (enable) {
|
||||
if (enable) {
|
||||
Bangle.on("accel", onAccel);
|
||||
Bangle.on("pressure", onPressure);
|
||||
Bangle.on("GPS", onGPS);
|
||||
Bangle.on("HRM", onHRM);
|
||||
Bangle.on("mag", onMag);
|
||||
}
|
||||
else {
|
||||
Bangle.removeListener("accel", onAccel);
|
||||
Bangle.removeListener("pressure", onPressure);
|
||||
Bangle.removeListener("GPS", onGPS);
|
||||
Bangle.removeListener("HRM", onHRM);
|
||||
Bangle.removeListener("mag", onMag);
|
||||
}
|
||||
};
|
||||
var setIntervals = function (locked, connected) {
|
||||
if (locked === void 0) { locked = Bangle.isLocked(); }
|
||||
if (connected === void 0) { connected = NRF.getSecurityStatus().connected; }
|
||||
changeInterval(redrawInterval, locked ? 15000 : 5000);
|
||||
if (connected) {
|
||||
var interval = btnsShown ? 5000 : 1000;
|
||||
if (bleInterval) {
|
||||
changeInterval(bleInterval, interval);
|
||||
}
|
||||
else {
|
||||
bleInterval = setInterval(updateServices, interval);
|
||||
}
|
||||
}
|
||||
else if (bleInterval) {
|
||||
clearInterval(bleInterval);
|
||||
bleInterval = undefined;
|
||||
}
|
||||
};
|
||||
var redrawInterval = setInterval(redraw, 1000);
|
||||
Bangle.on("lock", function (locked) { return setIntervals(locked); });
|
||||
var bleInterval;
|
||||
NRF.on("connect", function () { return setIntervals(undefined, true); });
|
||||
NRF.on("disconnect", function () { return setIntervals(undefined, false); });
|
||||
setIntervals();
|
||||
setBtnsShown(true);
|
||||
enableSensors();
|
||||
{
|
||||
var ad = getBleAdvert(function (serv) { return serviceToAdvert(serv, true); }, true);
|
||||
var adServices = Object
|
||||
.keys(ad)
|
||||
.map(function (k) { return k.replace("0x", ""); });
|
||||
NRF.setServices(ad, {
|
||||
advertise: adServices,
|
||||
uart: false,
|
||||
var __assign = Object.assign;
|
||||
var Layout_1 = require("Layout");
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
var HRM_MIN_CONFIDENCE_1 = 75;
|
||||
var services_1 = ["0x180d", "0x181a", "0x1819"];
|
||||
var acc_1;
|
||||
var bar_1;
|
||||
var gps_1;
|
||||
var hrm_1;
|
||||
var hrmAny_1;
|
||||
var mag_1;
|
||||
var btnsShown_1 = false;
|
||||
var prevBtnsShown_1 = undefined;
|
||||
var hrmAnyClear_1;
|
||||
var settings_1 = {
|
||||
bar: false,
|
||||
gps: false,
|
||||
hrm: false,
|
||||
mag: false,
|
||||
};
|
||||
var idToName = {
|
||||
acc: "Acceleration",
|
||||
bar: "Barometer",
|
||||
gps: "GPS",
|
||||
hrm: "HRM",
|
||||
mag: "Magnetometer",
|
||||
};
|
||||
var infoFont_1 = "6x8:2";
|
||||
var colour_1 = {
|
||||
on: "#0f0",
|
||||
off: "#fff",
|
||||
};
|
||||
var makeToggle = function (id) { return function () {
|
||||
settings_1[id] = !settings_1[id];
|
||||
var entry = btnLayout_1[id];
|
||||
var col = settings_1[id] ? colour_1.on : colour_1.off;
|
||||
entry.btnBorder = entry.col = col;
|
||||
btnLayout_1.update();
|
||||
btnLayout_1.render();
|
||||
enableSensors_1();
|
||||
}; };
|
||||
var btnStyle = {
|
||||
font: "Vector:14",
|
||||
fillx: 1,
|
||||
filly: 1,
|
||||
col: g.theme.fg,
|
||||
bgCol: g.theme.bg,
|
||||
btnBorder: "#fff",
|
||||
};
|
||||
var btnLayout_1 = new Layout_1({
|
||||
type: "v",
|
||||
c: [
|
||||
{
|
||||
type: "h",
|
||||
c: [
|
||||
__assign({ type: "btn", label: idToName.bar, id: "bar", cb: makeToggle('bar') }, btnStyle),
|
||||
__assign({ type: "btn", label: idToName.gps, id: "gps", cb: makeToggle('gps') }, btnStyle),
|
||||
]
|
||||
},
|
||||
{
|
||||
type: "h",
|
||||
c: [
|
||||
__assign({ type: "btn", label: idToName.hrm, id: "hrm", cb: makeToggle('hrm') }, btnStyle),
|
||||
__assign({ type: "btn", label: idToName.mag, id: "mag", cb: makeToggle('mag') }, btnStyle),
|
||||
]
|
||||
},
|
||||
{
|
||||
type: "h",
|
||||
c: [
|
||||
__assign(__assign({ type: "btn", label: idToName.acc, id: "acc", cb: function () { } }, btnStyle), { col: colour_1.on, btnBorder: colour_1.on }),
|
||||
__assign({ type: "btn", label: "Back", cb: function () {
|
||||
setBtnsShown_1(false);
|
||||
} }, btnStyle),
|
||||
]
|
||||
}
|
||||
]
|
||||
}, {
|
||||
lazy: true,
|
||||
back: function () {
|
||||
setBtnsShown_1(false);
|
||||
},
|
||||
});
|
||||
var setBtnsShown_1 = function (b) {
|
||||
btnsShown_1 = b;
|
||||
hook_1(!btnsShown_1);
|
||||
setIntervals_1();
|
||||
redraw_1();
|
||||
};
|
||||
var drawInfo_1 = function (force) {
|
||||
var _a = Bangle.appRect, y = _a.y, x = _a.x, w = _a.w;
|
||||
var mid = x + w / 2;
|
||||
var drawn = false;
|
||||
if (!force && !bar_1 && !gps_1 && !hrm_1 && !mag_1)
|
||||
return;
|
||||
g.reset()
|
||||
.clearRect(Bangle.appRect)
|
||||
.setFont(infoFont_1)
|
||||
.setFontAlign(0, -1);
|
||||
if (bar_1) {
|
||||
g.drawString("".concat(bar_1.altitude.toFixed(1), "m"), mid, y);
|
||||
y += g.getFontHeight();
|
||||
g.drawString("".concat(bar_1.pressure.toFixed(1), " hPa"), mid, y);
|
||||
y += g.getFontHeight();
|
||||
g.drawString("".concat(bar_1.temperature.toFixed(1), "C"), mid, y);
|
||||
y += g.getFontHeight();
|
||||
drawn = true;
|
||||
}
|
||||
if (gps_1) {
|
||||
g.drawString("".concat(gps_1.lat.toFixed(4), " lat, ").concat(gps_1.lon.toFixed(4), " lon"), mid, y);
|
||||
y += g.getFontHeight();
|
||||
g.drawString("".concat(gps_1.alt, "m (").concat(gps_1.satellites, " sat)"), mid, y);
|
||||
y += g.getFontHeight();
|
||||
drawn = true;
|
||||
}
|
||||
if (hrm_1) {
|
||||
g.drawString("".concat(hrm_1.bpm, " BPM (").concat(hrm_1.confidence, "%)"), mid, y);
|
||||
y += g.getFontHeight();
|
||||
drawn = true;
|
||||
}
|
||||
else if (hrmAny_1) {
|
||||
g.drawString("~".concat(hrmAny_1.bpm, " BPM (").concat(hrmAny_1.confidence, "%)"), mid, y);
|
||||
y += g.getFontHeight();
|
||||
drawn = true;
|
||||
if (!settings_1.hrm && !hrmAnyClear_1) {
|
||||
hrmAnyClear_1 = setTimeout(function () {
|
||||
hrmAny_1 = undefined;
|
||||
hrmAnyClear_1 = undefined;
|
||||
}, 10000);
|
||||
}
|
||||
}
|
||||
if (mag_1) {
|
||||
g.drawString("".concat(mag_1.x, " ").concat(mag_1.y, " ").concat(mag_1.z), mid, y);
|
||||
y += g.getFontHeight();
|
||||
g.drawString("heading: ".concat(mag_1.heading.toFixed(1)), mid, y);
|
||||
y += g.getFontHeight();
|
||||
drawn = true;
|
||||
}
|
||||
if (!drawn) {
|
||||
if (!force || Object.values(settings_1).every(function (x) { return !x; })) {
|
||||
g.drawString("swipe to enable", mid, y);
|
||||
}
|
||||
else {
|
||||
g.drawString("events pending", mid, y);
|
||||
}
|
||||
y += g.getFontHeight();
|
||||
}
|
||||
};
|
||||
var onTap_1 = function () {
|
||||
setBtnsShown_1(true);
|
||||
};
|
||||
var redraw_1 = function () {
|
||||
if (btnsShown_1) {
|
||||
if (!prevBtnsShown_1) {
|
||||
prevBtnsShown_1 = btnsShown_1;
|
||||
Bangle.removeListener("swipe", onTap_1);
|
||||
btnLayout_1.setUI();
|
||||
btnLayout_1.forgetLazyState();
|
||||
g.clearRect(Bangle.appRect);
|
||||
}
|
||||
btnLayout_1.render();
|
||||
}
|
||||
else {
|
||||
if (prevBtnsShown_1) {
|
||||
prevBtnsShown_1 = btnsShown_1;
|
||||
Bangle.setUI();
|
||||
Bangle.on("swipe", onTap_1);
|
||||
drawInfo_1(true);
|
||||
}
|
||||
else {
|
||||
drawInfo_1();
|
||||
}
|
||||
}
|
||||
};
|
||||
var encodeHrm_1 = function (hrm) {
|
||||
return [0, hrm.bpm];
|
||||
};
|
||||
encodeHrm_1.maxLen = 2;
|
||||
var encodePressure_1 = function (data) {
|
||||
return toByteArray_1(Math.round(data.pressure * 10), 4, false);
|
||||
};
|
||||
encodePressure_1.maxLen = 4;
|
||||
var encodeElevation_1 = function (data) {
|
||||
return toByteArray_1(Math.round(data.altitude * 100), 3, true);
|
||||
};
|
||||
encodeElevation_1.maxLen = 3;
|
||||
var encodeTemp_1 = function (data) {
|
||||
return toByteArray_1(Math.round(data.temperature * 10), 2, true);
|
||||
};
|
||||
encodeTemp_1.maxLen = 2;
|
||||
var encodeGps_1 = function (data) {
|
||||
var speed = toByteArray_1(Math.round(1000 * data.speed / 36), 2, false);
|
||||
var lat = toByteArray_1(Math.round(data.lat * 10000000), 4, true);
|
||||
var lon = toByteArray_1(Math.round(data.lon * 10000000), 4, true);
|
||||
var elevation = toByteArray_1(Math.round(data.alt * 100), 3, true);
|
||||
var heading = toByteArray_1(Math.round(data.course * 100), 2, false);
|
||||
return [
|
||||
157,
|
||||
2,
|
||||
speed[0], speed[1],
|
||||
lat[0], lat[1], lat[2], lat[3],
|
||||
lon[0], lon[1], lon[2], lon[3],
|
||||
elevation[0], elevation[1], elevation[2],
|
||||
heading[0], heading[1]
|
||||
];
|
||||
};
|
||||
encodeGps_1.maxLen = 17;
|
||||
var encodeGpsHeadingOnly_1 = function (data) {
|
||||
var heading = toByteArray_1(Math.round(data.heading * 100), 2, false);
|
||||
return [
|
||||
16,
|
||||
16,
|
||||
heading[0], heading[1]
|
||||
];
|
||||
};
|
||||
encodeGpsHeadingOnly_1.maxLen = 17;
|
||||
var encodeMag_1 = function (data) {
|
||||
var x = toByteArray_1(data.x, 2, true);
|
||||
var y = toByteArray_1(data.y, 2, true);
|
||||
var z = toByteArray_1(data.z, 2, true);
|
||||
return [x[0], x[1], y[0], y[1], z[0], z[1]];
|
||||
};
|
||||
encodeMag_1.maxLen = 6;
|
||||
var toByteArray_1 = function (value, numberOfBytes, isSigned) {
|
||||
var byteArray = new Array(numberOfBytes);
|
||||
if (isSigned && (value < 0)) {
|
||||
value += 1 << (numberOfBytes * 8);
|
||||
}
|
||||
for (var index = 0; index < numberOfBytes; index++) {
|
||||
byteArray[index] = (value >> (index * 8)) & 0xff;
|
||||
}
|
||||
return byteArray;
|
||||
};
|
||||
var enableSensors_1 = function () {
|
||||
Bangle.setBarometerPower(settings_1.bar, "btadv");
|
||||
if (!settings_1.bar)
|
||||
bar_1 = undefined;
|
||||
Bangle.setGPSPower(settings_1.gps, "btadv");
|
||||
if (!settings_1.gps)
|
||||
gps_1 = undefined;
|
||||
Bangle.setHRMPower(settings_1.hrm, "btadv");
|
||||
if (!settings_1.hrm)
|
||||
hrm_1 = hrmAny_1 = undefined;
|
||||
Bangle.setCompassPower(settings_1.mag, "btadv");
|
||||
if (!settings_1.mag)
|
||||
mag_1 = undefined;
|
||||
};
|
||||
var haveServiceData_1 = function (serv) {
|
||||
switch (serv) {
|
||||
case "0x180d": return !!hrm_1;
|
||||
case "0x181a": return !!(bar_1 || mag_1);
|
||||
case "0x1819": return !!(gps_1 && gps_1.lat && gps_1.lon || mag_1);
|
||||
}
|
||||
};
|
||||
var serviceToAdvert_1 = function (serv, initial) {
|
||||
var _a, _b, _c;
|
||||
if (initial === void 0) { initial = false; }
|
||||
switch (serv) {
|
||||
case "0x180d":
|
||||
if (hrm_1 || initial) {
|
||||
var o = {
|
||||
maxLen: encodeHrm_1.maxLen,
|
||||
readable: true,
|
||||
notify: true,
|
||||
};
|
||||
if (hrm_1) {
|
||||
o.value = encodeHrm_1(hrm_1);
|
||||
hrm_1 = undefined;
|
||||
}
|
||||
return _a = {}, _a["0x2a37"] = o, _a;
|
||||
}
|
||||
return {};
|
||||
case "0x1819":
|
||||
if (gps_1 || initial) {
|
||||
var o = {
|
||||
maxLen: encodeGps_1.maxLen,
|
||||
readable: true,
|
||||
notify: true,
|
||||
};
|
||||
if (gps_1) {
|
||||
o.value = encodeGps_1(gps_1);
|
||||
gps_1 = undefined;
|
||||
}
|
||||
return _b = {}, _b["0x2a67"] = o, _b;
|
||||
}
|
||||
else if (mag_1) {
|
||||
var o = {
|
||||
maxLen: encodeGpsHeadingOnly_1.maxLen,
|
||||
readable: true,
|
||||
notify: true,
|
||||
value: encodeGpsHeadingOnly_1(mag_1),
|
||||
};
|
||||
return _c = {}, _c["0x2a67"] = o, _c;
|
||||
}
|
||||
return {};
|
||||
case "0x181a": {
|
||||
var o = {};
|
||||
if (bar_1 || initial) {
|
||||
o["0x2a6c"] = {
|
||||
maxLen: encodeElevation_1.maxLen,
|
||||
readable: true,
|
||||
notify: true,
|
||||
};
|
||||
o["0x2A1F"] = {
|
||||
maxLen: encodeTemp_1.maxLen,
|
||||
readable: true,
|
||||
notify: true,
|
||||
};
|
||||
o["0x2a6d"] = {
|
||||
maxLen: encodePressure_1.maxLen,
|
||||
readable: true,
|
||||
notify: true,
|
||||
};
|
||||
if (bar_1) {
|
||||
o["0x2a6c"].value = encodeElevation_1(bar_1);
|
||||
o["0x2A1F"].value = encodeTemp_1(bar_1);
|
||||
o["0x2a6d"].value = encodePressure_1(bar_1);
|
||||
bar_1 = undefined;
|
||||
}
|
||||
}
|
||||
if (mag_1 || initial) {
|
||||
o["0x2aa1"] = {
|
||||
maxLen: encodeMag_1.maxLen,
|
||||
readable: true,
|
||||
notify: true,
|
||||
};
|
||||
if (mag_1) {
|
||||
o["0x2aa1"].value = encodeMag_1(mag_1);
|
||||
}
|
||||
}
|
||||
return o;
|
||||
}
|
||||
}
|
||||
};
|
||||
var getBleAdvert_1 = function (map, all) {
|
||||
if (all === void 0) { all = false; }
|
||||
var advert = {};
|
||||
for (var _i = 0, services_2 = services_1; _i < services_2.length; _i++) {
|
||||
var serv = services_2[_i];
|
||||
if (all || haveServiceData_1(serv)) {
|
||||
advert[serv] = map(serv);
|
||||
}
|
||||
}
|
||||
mag_1 = undefined;
|
||||
return advert;
|
||||
};
|
||||
var updateServices_1 = function () {
|
||||
var newAdvert = getBleAdvert_1(serviceToAdvert_1);
|
||||
NRF.updateServices(newAdvert);
|
||||
};
|
||||
var onAccel_1 = function (newAcc) { return acc_1 = newAcc; };
|
||||
var onPressure_1 = function (newBar) { return bar_1 = newBar; };
|
||||
var onGPS_1 = function (newGps) { return gps_1 = newGps; };
|
||||
var onHRM_1 = function (newHrm) {
|
||||
if (newHrm.confidence >= HRM_MIN_CONFIDENCE_1)
|
||||
hrm_1 = newHrm;
|
||||
hrmAny_1 = newHrm;
|
||||
};
|
||||
var onMag_1 = function (newMag) { return mag_1 = newMag; };
|
||||
var hook_1 = function (enable) {
|
||||
if (enable) {
|
||||
Bangle.on("accel", onAccel_1);
|
||||
Bangle.on("pressure", onPressure_1);
|
||||
Bangle.on("GPS", onGPS_1);
|
||||
Bangle.on("HRM", onHRM_1);
|
||||
Bangle.on("mag", onMag_1);
|
||||
}
|
||||
else {
|
||||
Bangle.removeListener("accel", onAccel_1);
|
||||
Bangle.removeListener("pressure", onPressure_1);
|
||||
Bangle.removeListener("GPS", onGPS_1);
|
||||
Bangle.removeListener("HRM", onHRM_1);
|
||||
Bangle.removeListener("mag", onMag_1);
|
||||
}
|
||||
};
|
||||
var setIntervals_1 = function (locked, connected) {
|
||||
if (locked === void 0) { locked = Bangle.isLocked(); }
|
||||
if (connected === void 0) { connected = NRF.getSecurityStatus().connected; }
|
||||
changeInterval(redrawInterval_1, locked ? 15000 : 5000);
|
||||
if (connected) {
|
||||
var interval = btnsShown_1 ? 5000 : 1000;
|
||||
if (bleInterval_1) {
|
||||
changeInterval(bleInterval_1, interval);
|
||||
}
|
||||
else {
|
||||
bleInterval_1 = setInterval(updateServices_1, interval);
|
||||
}
|
||||
}
|
||||
else if (bleInterval_1) {
|
||||
clearInterval(bleInterval_1);
|
||||
bleInterval_1 = undefined;
|
||||
}
|
||||
};
|
||||
var redrawInterval_1 = setInterval(redraw_1, 1000);
|
||||
Bangle.on("lock", function (locked) { return setIntervals_1(locked); });
|
||||
var bleInterval_1;
|
||||
NRF.on("connect", function () { return setIntervals_1(undefined, true); });
|
||||
NRF.on("disconnect", function () { return setIntervals_1(undefined, false); });
|
||||
setIntervals_1();
|
||||
setBtnsShown_1(true);
|
||||
enableSensors_1();
|
||||
{
|
||||
var ad = getBleAdvert_1(function (serv) { return serviceToAdvert_1(serv, true); }, true);
|
||||
var adServices = Object
|
||||
.keys(ad)
|
||||
.map(function (k) { return k.replace("0x", ""); });
|
||||
NRF.setServices(ad, {
|
||||
advertise: adServices,
|
||||
uart: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// ts helpers:
|
||||
{
|
||||
// @ts-ignore helper
|
||||
const __assign = Object.assign;
|
||||
|
||||
const Layout = require("Layout");
|
||||
|
@ -713,3 +714,4 @@ enableSensors();
|
|||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,5 +18,6 @@
|
|||
{"name":"bthrm.settings.js","url":"settings.js"},
|
||||
{"name":"bthrm","url":"lib.js"},
|
||||
{"name":"bthrm.default.json","url":"default.json"}
|
||||
]
|
||||
],
|
||||
"data": [{"name":"bthrm.json"}]
|
||||
}
|
||||
|
|
|
@ -15,5 +15,6 @@
|
|||
{"name":"bwclk.app.js","url":"app.js"},
|
||||
{"name":"bwclk.img","url":"app-icon.js","evaluate":true},
|
||||
{"name":"bwclk.settings.js","url":"settings.js"}
|
||||
]
|
||||
],
|
||||
"data":[{"name":"bwclk.setting.json"}]
|
||||
}
|
||||
|
|
|
@ -39,5 +39,10 @@
|
|||
"name": "bwclklite.settings.js",
|
||||
"url": "settings.js"
|
||||
}
|
||||
],
|
||||
"data": [
|
||||
{
|
||||
"name": "bwclklite.setting.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -12,7 +12,10 @@
|
|||
"readme": "README.md",
|
||||
"storage": [
|
||||
{ "name": "cassioWatch.app.js", "url": "app.js" },
|
||||
{"name":"cassioWatch.settings.js","url":"settings.js"},
|
||||
{ "name": "cassioWatch.settings.js","url": "settings.js" },
|
||||
{ "name": "cassioWatch.img", "url": "icon.js", "evaluate": true }
|
||||
],
|
||||
"data": [
|
||||
{ "name": "cassioWatch.settings.json" }
|
||||
]
|
||||
}
|
||||
|
|
|
@ -2,3 +2,4 @@
|
|||
0.02: Support BangleJS2
|
||||
0.03: Added threshold
|
||||
0.04: Added notification
|
||||
0.05: Fixed boot
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
const pin = process.env.HWVERSION === 2 ? D3 : D30;
|
||||
|
||||
var id;
|
||||
Bangle.on('charging', (charging) => {
|
||||
function gent(charging) {
|
||||
if (charging) {
|
||||
if (!id) {
|
||||
var max = 0;
|
||||
|
@ -37,5 +37,8 @@
|
|||
require('notify').hide({id: 'chargent'});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Bangle.on('charging', gent);
|
||||
if (Bangle.isCharging()) gent(true);
|
||||
})();
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{ "id": "chargent",
|
||||
"name": "Charge Gently",
|
||||
"version": "0.04",
|
||||
"version": "0.05",
|
||||
"description": "When charging, reminds you to disconnect the watch to prolong battery life.",
|
||||
"icon": "icon.png",
|
||||
"type": "bootloader",
|
||||
|
|
|
@ -11,5 +11,6 @@
|
|||
"storage": [
|
||||
{"name":"chargerot.boot.js","url":"boot.js"},
|
||||
{"name":"chargerot.settings.js","url":"settings.js"}
|
||||
]
|
||||
],
|
||||
"data":[{"name":"chargerot.settings.json"}]
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("mEwxH+AH4A/AH4A/AEnPAEAv/wAAcF6XWAAYdFBQgLLF/4v/F/4vTFKoLGF/4v/F/4v/F4QpWBQov/F7UslgKBAYIABEgIDDF/4v/F4es1gvTdKoLBFYYAHF/4vTmQvuvQwJFxAvbAAOIxIAFFxIvzFKYLG6CMNF8GsF92BdpwvfqwvtRwgvQAC+IxIAJF5QAYF93OwEyRwqSPACwsJGEov/AH4A/AH4AwA="))
|
|
@ -0,0 +1,283 @@
|
|||
// Using p4wn chess engine: https://p4wn.sourceforge.net/ | https://github.com/douglasbagnall/p4wn
|
||||
const engine = require("chessengine");
|
||||
|
||||
Bangle.loadWidgets(); // load before first appRect call
|
||||
|
||||
const FIELD_WIDTH = Bangle.appRect.w/8;
|
||||
const FIELD_HEIGHT = Bangle.appRect.h/8;
|
||||
const SETTINGS_FILE = "chess.json";
|
||||
const DEFAULT_TIMEOUT = Bangle.getOptions().lockTimeout;
|
||||
const ICON_SIZE=45;
|
||||
const ICON_BISHOP = require("heatshrink").decompress(atob("lstwMB/4Ac/wFE4IED/kPAofgn4FDGon8j4QEBQgQE4EHBQcACwfAgF/BQYWD8EAHAX+NgI4C+AQEwAQDDYIhDDYMDCAQKBGQQsHHogKDCAJODCAI3CHoQKCHoIQDHoIQCFgoQBFgfgIQYmBEIQECKgIrCBYQKDC4OBg/8iCvEAC+AA="));
|
||||
const ICON_PAWN = require("heatshrink").decompress(atob("lstwMB/4At/AFEGon4h4FDwE/AgX8CAngCAkAv4bDgYbECAf4gAhD4AhD/kAg4mDCAkACAYbBEIYQBG4gbDEII9DFhXAgEfBQYWDEwJUC/wKBGQXwCAgEBE4RCBCAYmBCAQmCCAQmBCAbdCCAIbCQ4gAYwA="));
|
||||
const ICON_KING = require("heatshrink").decompress(atob("lstwMB/4Ac/wFE+4KEh4FD+F/AofvCwgKE+IKEg4bEj4FDwADC/k8g+HAoJhCC4PwAoQXBNod//AECgYfBAoUP/gQE8AQEBQcfCAaLBCAZmBEIZuBBQgyDJAIWCPgXAEAQWDBQRUCPgQnBHgJqBLwYhDOwRvDGQc/EIaSDCwLedwAA=="));
|
||||
const ICON_QUEEN = require("heatshrink").decompress(atob("lstwMB/4Ac/l/AgXn4PzAgP+j0Ph4FB8FwuE///PgeDwPn/k8n0+j0f4Hz+Px8F+g/Px+fgf4vgACn/jAAf/x8Pj0en/8vAsB+P/+PBwcHj//w0MjEwJgMwsHBw5CBwMEhBDBPoR6B/gFCDYPgAoRZBAgUH//4AoQbB4AbDCAYbBCAZ1CAgJ7CwAKDGQQmBCAYmBEIQmC+AQEDYQQBDYQQCFgo3CXQIsFBYIEDACmAA="));
|
||||
const ICON_ROOK = require("heatshrink").decompress(atob("lstwMB/4Ax/0HgPAAoPwnEOg4FBwBFBn///gEBI4XgAoMPAoJWCv4QDDYXwBQf/4AKD/wmDCARuDGQImCEIQbCGQMDCAQKBj4EB/AFBBQQsgDYQQCNQQhCOog3CCAQ3BEIRvCAoSRCE4IxCKgQmCKgYAZwA="));
|
||||
const ICON_KNIGHT = require("heatshrink").decompress(atob("lstwMB/4Ann1/AgX48IKD4UPAgX+gEHAoXwgALDJQMfDYQFBEQWAgBSCBQQcC4AFBn///hnCBQPgAgMDGIQnDGIIQDAgQQBEwQQCGIIQCEwMECAQxBsAQBEwMPCAQmBAIJDB4EPDoM/CAIoBKgP4BQQQB/AzCKgJlIPgQ+COwJlCHoJlDJwJlDS4aBDDYQsCADOA"));
|
||||
|
||||
const settings = Object.assign({
|
||||
state: engine.P4_INITIAL_BOARD,
|
||||
computer_level: 0, // default to "stupid" which is the fastest
|
||||
}, require("Storage").readJSON(SETTINGS_FILE,1) || {});
|
||||
|
||||
var ovr = Graphics.createArrayBuffer(Bangle.appRect.w,Bangle.appRect.h,2,{msb:true});
|
||||
const curfield = [4*FIELD_WIDTH, 6*FIELD_HEIGHT]; // e2
|
||||
const startfield = Array(2);
|
||||
let piece_sel = 0;
|
||||
let showmenu = false;
|
||||
|
||||
const writeSettings = () => {
|
||||
settings.state = engine.p4_state2fen(state);
|
||||
require('Storage').writeJSON(SETTINGS_FILE, settings);
|
||||
};
|
||||
|
||||
const generateBgImage = () => {
|
||||
var buf = Graphics.createArrayBuffer(Bangle.appRect.w,Bangle.appRect.h,1,{msb:true});
|
||||
for(let idxrow=0; idxrow<8; idxrow++) {
|
||||
for(let idxcol=0; idxcol<8; idxcol++) {
|
||||
const bgCol = idxrow % 2 != idxcol % 2 ? 0 : 1;
|
||||
const x = idxcol*FIELD_WIDTH;
|
||||
const y = idxrow*FIELD_HEIGHT;
|
||||
buf.setColor(bgCol).fillRect({x:x, y:y, w:FIELD_WIDTH, h:FIELD_HEIGHT});
|
||||
}
|
||||
}
|
||||
return {width:buf.getWidth(), height:buf.getHeight(),
|
||||
buffer:buf.buffer
|
||||
};
|
||||
};
|
||||
|
||||
const idx2Pos = (idxcol, idxrow) => {
|
||||
"ram"
|
||||
return 2*(1+8+1) + (7-idxrow)*(1+8+1) + idxcol + 1;
|
||||
};
|
||||
|
||||
const drawPiece = (buf, x, y, piece) => {
|
||||
let icon;
|
||||
|
||||
switch(piece & ~0x1) {
|
||||
case engine.P4_PAWN:
|
||||
icon = ICON_PAWN;
|
||||
break;
|
||||
case engine.P4_BISHOP:
|
||||
icon = ICON_BISHOP;
|
||||
break;
|
||||
case engine.P4_KING:
|
||||
icon = ICON_KING;
|
||||
break;
|
||||
case engine.P4_QUEEN:
|
||||
icon = ICON_QUEEN;
|
||||
break;
|
||||
case engine.P4_ROOK:
|
||||
icon = ICON_ROOK;
|
||||
break;
|
||||
case engine.P4_KNIGHT:
|
||||
icon = ICON_KNIGHT;
|
||||
break;
|
||||
}
|
||||
|
||||
if (icon) {
|
||||
const scale = FIELD_HEIGHT/ICON_SIZE;
|
||||
buf.drawImage(icon, x+(FIELD_WIDTH-(ICON_SIZE*scale))/2, y, {scale: scale});
|
||||
}
|
||||
return buf;
|
||||
};
|
||||
|
||||
const drawBoard = () => {
|
||||
//console.log("Free: " + process.memory().free);
|
||||
|
||||
g.setBgColor("#555").setColor("#aaa").drawImage(bgImage, Bangle.appRect.x, Bangle.appRect.y);
|
||||
for(let idxrow=0; idxrow<8; idxrow++) {
|
||||
for(let idxcol=0; idxcol<8; idxcol++) {
|
||||
const x = idxcol*FIELD_WIDTH+Bangle.appRect.x;
|
||||
const y = idxrow*FIELD_HEIGHT+Bangle.appRect.y;
|
||||
|
||||
const pos = idx2Pos(idxcol, idxrow);
|
||||
const field = state.board[pos];
|
||||
|
||||
if (field) {
|
||||
const fgCol = field & 0x1 ? "#000" : "#fff";
|
||||
drawPiece(g.setBgColor(fgCol), x, y, field);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const roundX = (x) => {
|
||||
return Math.round(x/FIELD_WIDTH)*FIELD_WIDTH;
|
||||
};
|
||||
|
||||
const roundY = (y) => {
|
||||
return Math.round(y/FIELD_HEIGHT)*FIELD_HEIGHT;
|
||||
};
|
||||
|
||||
const drawSelectedField = () => {
|
||||
ovr.clear();
|
||||
if (!showmenu) {
|
||||
if (startfield[0] !== undefined && startfield[1] !== undefined) {
|
||||
// remove piece from startfield
|
||||
const x = startfield[0];
|
||||
const y = startfield[1];
|
||||
ovr.setColor(2).fillRect({x:x, y:y, w:FIELD_WIDTH, h:FIELD_HEIGHT});
|
||||
}
|
||||
|
||||
const x = roundX(curfield[0]);
|
||||
const y = roundY(curfield[1]);
|
||||
ovr.setColor(piece_sel ? 1 : 2)
|
||||
.drawRect({x:x+1, y:y, w:FIELD_WIDTH-2, h:FIELD_HEIGHT})
|
||||
.drawRect({x:x+2, y:y+1, w:FIELD_WIDTH-4, h:FIELD_HEIGHT-2})
|
||||
.drawRect({x:x+3, y:y+2, w:FIELD_WIDTH-6, h:FIELD_HEIGHT-4});
|
||||
if (piece_sel) {
|
||||
drawPiece(ovr.setBgColor(1), x, y, piece_sel);
|
||||
ovr.setBgColor(0); // back to transparent
|
||||
}
|
||||
}
|
||||
Bangle.setLCDOverlay({width:ovr.getWidth(), height:ovr.getHeight(),
|
||||
bpp:2, transparent:0,
|
||||
palette:new Uint16Array([0, g.toColor("#F00"), g.toColor("#0F0"), 0]),
|
||||
buffer:ovr.buffer
|
||||
},Bangle.appRect.x,Bangle.appRect.y);
|
||||
};
|
||||
|
||||
const isInside = (rect, e) => {
|
||||
return e.x>=rect.x && e.x<rect.x+rect.w
|
||||
&& e.y>=rect.y && e.y<=rect.y+rect.h;
|
||||
};
|
||||
|
||||
const showAlert = (msg) => {
|
||||
showmenu = true;
|
||||
drawSelectedField();
|
||||
E.showAlert(msg).then(function() {
|
||||
showmenu = false;
|
||||
drawBoard();
|
||||
drawSelectedField();
|
||||
});
|
||||
};
|
||||
|
||||
const move = (from,to) => {
|
||||
const res = state.move(from, to);
|
||||
//console.log(res);
|
||||
if (!res.ok) {
|
||||
showAlert("Illegal move");
|
||||
} else {
|
||||
if (res.flags & engine.P4_MOVE_FLAG_MATE) {
|
||||
showAlert("Checkmate or stalemate");
|
||||
} else if (res.flags & engine.P4_MOVE_FLAG_CHECK) {
|
||||
showAlert("A king is in check");
|
||||
} else if (res.flags & engine.P4_MOVE_FLAG_DRAW) {
|
||||
showAlert("A draw is available");
|
||||
}
|
||||
}
|
||||
return res;
|
||||
};
|
||||
|
||||
const showMessage = (msg) => {
|
||||
g.setColor("#f00").setFont("4x6:2").setFontAlign(-1,1).drawString(msg, 10, Bangle.appRect.y2-10);
|
||||
};
|
||||
|
||||
// Run
|
||||
|
||||
g.reset();
|
||||
const bgImage = generateBgImage();
|
||||
let state = engine.p4_fen2state(settings.state);
|
||||
drawBoard();
|
||||
drawSelectedField();
|
||||
Bangle.drawWidgets();
|
||||
|
||||
// drag selected field
|
||||
Bangle.on('drag', (ev) => {
|
||||
const newx = curfield[0]+ev.dx;
|
||||
const newy = curfield[1]+ev.dy;
|
||||
if (newx >= 0 && newx <= 7*FIELD_WIDTH) {
|
||||
curfield[0] = newx;
|
||||
}
|
||||
if (newy >= 0 && newy <= 7*FIELD_HEIGHT) {
|
||||
curfield[1] = newy;
|
||||
}
|
||||
drawSelectedField();
|
||||
});
|
||||
|
||||
// touch to start/stop moving a piece
|
||||
Bangle.on('touch', (button, xy) => {
|
||||
if (isInside(Bangle.appRect, xy) && !showmenu) {
|
||||
if (piece_sel === 0) {
|
||||
startfield[0] = roundX(curfield[0]);
|
||||
startfield[1] = roundY(curfield[1]);
|
||||
const startpos = idx2Pos(startfield[0]/FIELD_WIDTH, startfield[1]/FIELD_HEIGHT);
|
||||
piece_sel = state.board[startpos];
|
||||
if (piece_sel === 0) {
|
||||
startfield[0] = startfield[1] = undefined;
|
||||
// nothing here, do nothing
|
||||
return;
|
||||
}
|
||||
} else { // piece_sel === 0
|
||||
const colTo = roundX(curfield[0]);
|
||||
const rowTo = roundY(curfield[1]);
|
||||
if (startfield[0] !== colTo || startfield[1] !== rowTo) {
|
||||
showMessage(/*LANG*/"Moving..");
|
||||
const posFrom = idx2Pos(startfield[0]/FIELD_WIDTH, startfield[1]/FIELD_HEIGHT);
|
||||
const posTo = idx2Pos(colTo/FIELD_WIDTH, rowTo/FIELD_HEIGHT);
|
||||
setTimeout(() => {
|
||||
if (move(posFrom, posTo).ok) {
|
||||
// human move ok, update
|
||||
drawBoard();
|
||||
drawSelectedField();
|
||||
// do computer move
|
||||
Bangle.setLCDTimeout(0.1); // this can take some time, turn off to save power
|
||||
showMessage(/*LANG*/"Calculating..");
|
||||
setTimeout(() => {
|
||||
const compMove = state.findmove(settings.computer_level+1);
|
||||
const result = move(compMove[0], compMove[1]);
|
||||
writeSettings();
|
||||
Bangle.setLCDPower(true);
|
||||
Bangle.setLocked(false);
|
||||
Bangle.setLCDTimeout(DEFAULT_TIMEOUT/1000); // restore
|
||||
if (!showmenu) {
|
||||
showAlert(result.string);
|
||||
}
|
||||
}, 200); // execute after display update
|
||||
}
|
||||
}, 100); // execute after display update
|
||||
} // piece_sel === 0
|
||||
startfield[0] = startfield[1] = undefined;
|
||||
piece_sel = 0;
|
||||
}
|
||||
drawSelectedField();
|
||||
}
|
||||
});
|
||||
|
||||
// show menu on button
|
||||
setWatch(() => {
|
||||
showmenu = true;
|
||||
drawSelectedField();
|
||||
|
||||
const closeMenu = () => {
|
||||
showmenu = false;
|
||||
E.showMenu();
|
||||
drawBoard();
|
||||
drawSelectedField();
|
||||
};
|
||||
|
||||
E.showMenu({
|
||||
"" : { title : /*LANG*/"Chess settings" },
|
||||
"< Back" : () => closeMenu(),
|
||||
/*LANG*/"New Game" : () => {
|
||||
state = engine.p4_fen2state(engine.P4_INITIAL_BOARD);
|
||||
writeSettings();
|
||||
closeMenu();
|
||||
},
|
||||
/*LANG*/"Undo Move" : () => {
|
||||
state.jump_to_moveno(-2);
|
||||
closeMenu();
|
||||
},
|
||||
/*LANG*/'Level': {
|
||||
value: settings.computer_level,
|
||||
min: 0, max: 4,
|
||||
format: v => [/*LANG*/'stupid', /*LANG*/'middling', /*LANG*/'default', /*LANG*/'slow', /*LANG*/'slowest'][v],
|
||||
onchange: v => {
|
||||
settings.computer_level = v;
|
||||
writeSettings();
|
||||
}
|
||||
},
|
||||
/*LANG*/"Exit" : () => load(),
|
||||
});
|
||||
}, BTN, { repeat: true, edge: "falling" });
|
After Width: | Height: | Size: 445 B |
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"id": "chess",
|
||||
"name": "Chess",
|
||||
"shortName": "Chess",
|
||||
"version": "0.01",
|
||||
"description": "Chess game based on the [p4wn engine](https://p4wn.sourceforge.net/). Drag on the touchscreen to move the green cursor onto a piece, select it with a single touch and drag the now red cursor around. Release the piece with another touch to finish the move. The button opens a menu.",
|
||||
"icon": "app.png",
|
||||
"tags": "game",
|
||||
"supports": ["BANGLEJS2"],
|
||||
"storage": [
|
||||
{"name":"chess.app.js","url":"app.js"},
|
||||
{"name":"chessengine","url":"engine.js"},
|
||||
{"name":"chess.img","url":"app-icon.js","evaluate":true}
|
||||
],
|
||||
"data": [{"name":"chess.json"}],
|
||||
"screenshots": [ {"url":"screenshot.png"} ]
|
||||
}
|
After Width: | Height: | Size: 3.5 KiB |
|
@ -1,3 +1,4 @@
|
|||
0.01: Initial Creation
|
||||
0.02: Fixed some sleep bugs. Added a sleep mode toggle
|
||||
0.03: Reduce busy-loop and code
|
||||
0.04: Separate buzz-time and sleep-time
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "chimer",
|
||||
"name": "Chimer",
|
||||
"version": "0.03",
|
||||
"version": "0.04",
|
||||
"description": "A fork of Hour Chime that adds extra features such as: \n - Buzz or beep on every 60, 30 or 15 minutes. \n - Repeat Chime up to 3 times \n - Set hours to disable chime",
|
||||
"icon": "widget.png",
|
||||
"type": "widget",
|
||||
|
|
|
@ -20,15 +20,16 @@
|
|||
let count = settings.repeat;
|
||||
|
||||
const chime1 = () => {
|
||||
let p;
|
||||
if (settings.type === 1) {
|
||||
Bangle.buzz(100);
|
||||
p = Bangle.buzz(100);
|
||||
} else if (settings.type === 2) {
|
||||
Bangle.beep();
|
||||
p = Bangle.beep();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
if (--count > 0)
|
||||
setTimeout(chime1, 150);
|
||||
p.then(() => setTimeout(chime1, 150));
|
||||
};
|
||||
|
||||
chime1();
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
const enum StopWatchFormat {
|
||||
HMS,
|
||||
Colon,
|
||||
}
|
||||
type StopWatchSettings = {
|
||||
format: StopWatchFormat,
|
||||
};
|
||||
|
||||
(back => {
|
||||
const SETTINGS_FILE = "clkinfostopw.setting.json";
|
||||
|
||||
const storage = require("Storage");
|
||||
const settings: StopWatchSettings = Object.assign(
|
||||
{ format: StopWatchFormat.HMS },
|
||||
storage.readJSON(SETTINGS_FILE, true),
|
||||
);
|
||||
|
||||
const save = () => {
|
||||
storage.writeJSON(SETTINGS_FILE, settings)
|
||||
};
|
||||
|
||||
E.showMenu({
|
||||
"": { "title": "stopwatch" },
|
||||
"< Back": back,
|
||||
"Format": {
|
||||
value: settings.format,
|
||||
min: StopWatchFormat.HMS,
|
||||
max: StopWatchFormat.Colon,
|
||||
format: v => v === StopWatchFormat.HMS ? "12m34s" : "12:34",
|
||||
onchange: v => {
|
||||
settings.format = v;
|
||||
save();
|
||||
},
|
||||
},
|
||||
});
|
||||
}) satisfies SettingsFunc
|
|
@ -5,6 +5,7 @@
|
|||
"icon": "app.png",
|
||||
"type": "clkinfo",
|
||||
"tags": "clkinfo,sunrise",
|
||||
"dependencies": {"mylocation":"app"},
|
||||
"supports" : ["BANGLEJS2"],
|
||||
"storage": [
|
||||
{"name":"sunrise.clkinfo.js","url":"clkinfo.js"}
|
||||
|
|
|
@ -3,4 +3,5 @@
|
|||
0.03: Reported image for battery now reflects charge level
|
||||
0.04: On 2v18+ firmware, we can now stop swipe events from being handled by other apps
|
||||
eg. when a clockinfo is selected, swipes won't affect swipe-down widgets
|
||||
0.05: Reported image for battery is now transparent (2v18+)
|
||||
0.05: Reported image for battery is now transparent (2v18+)
|
||||
0.06: When >1 clockinfo, swiping one back tries to ensure they don't display the same thing
|
|
@ -10,7 +10,12 @@ if (stepGoal == undefined) {
|
|||
stepGoal = d != undefined && d.settings != undefined ? d.settings.goal : 10000;
|
||||
}
|
||||
|
||||
// Load the settings, with defaults
|
||||
/// How many times has addInteractive been called?
|
||||
exports.loadCount = 0;
|
||||
/// A list of all the instances returned by addInteractive
|
||||
exports.clockInfos = [];
|
||||
|
||||
/// Load the settings, with defaults
|
||||
exports.loadSettings = function() {
|
||||
return Object.assign({
|
||||
hrmOn : 0, // 0(Always), 1(Tap)
|
||||
|
@ -22,6 +27,7 @@ exports.loadSettings = function() {
|
|||
);
|
||||
};
|
||||
|
||||
/// Load a list of ClockInfos - this does not cache and reloads each time
|
||||
exports.load = function() {
|
||||
var settings = exports.loadSettings();
|
||||
delete settings.apps; // keep just the basic settings in memory
|
||||
|
@ -63,7 +69,7 @@ exports.load = function() {
|
|||
} else img=atob("GBiBAAABgAADwAAHwAAPgACfAAHOAAPkBgHwDwP4Hwf8Pg/+fB//OD//kD//wD//4D//8D//4B//QB/+AD/8AH/4APnwAHAAACAAAA==");
|
||||
return {
|
||||
text : v + "%", v : v, min:0, max:100, img : img
|
||||
}
|
||||
};
|
||||
},
|
||||
show : function() { this.interval = setInterval(()=>this.emit('redraw'), 60000); Bangle.on("charging", batteryUpdateHandler); batteryUpdateHandler(); },
|
||||
hide : function() { clearInterval(this.interval); delete this.interval; Bangle.removeListener("charging", batteryUpdateHandler); },
|
||||
|
@ -73,7 +79,7 @@ exports.load = function() {
|
|||
get : () => { let v = Bangle.getHealthStatus("day").steps; return {
|
||||
text : v, v : v, min : 0, max : stepGoal,
|
||||
img : atob("GBiBAAcAAA+AAA/AAA/AAB/AAB/gAA/g4A/h8A/j8A/D8A/D+AfH+AAH8AHn8APj8APj8AHj4AHg4AADAAAHwAAHwAAHgAAHgAADAA==")
|
||||
}},
|
||||
};},
|
||||
show : function() { Bangle.on("step", stepUpdateHandler); stepUpdateHandler(); },
|
||||
hide : function() { Bangle.removeListener("step", stepUpdateHandler); },
|
||||
},
|
||||
|
@ -82,7 +88,7 @@ exports.load = function() {
|
|||
get : () => { return {
|
||||
text : (hrm||"--") + " bpm", v : hrm, min : 40, max : 200,
|
||||
img : atob("GBiBAAAAAAAAAAAAAAAAAAAAAADAAADAAAHAAAHjAAHjgAPngH9n/n82/gA+AAA8AAA8AAAcAAAYAAAYAAAAAAAAAAAAAAAAAAAAAA==")
|
||||
}},
|
||||
};},
|
||||
run : function() {
|
||||
Bangle.setHRMPower(1,"clkinfo");
|
||||
if (settings.hrmOn==1/*Tap*/) {
|
||||
|
@ -131,11 +137,11 @@ exports.load = function() {
|
|||
require("Storage").list(/clkinfo.js$/).forEach(fn => {
|
||||
try{
|
||||
var a = eval(require("Storage").read(fn))();
|
||||
var b = menu.find(x => x.name === a.name)
|
||||
var b = menu.find(x => x.name === a.name);
|
||||
if(b) b.items = b.items.concat(a.items);
|
||||
else menu = menu.concat(a);
|
||||
} catch(e){
|
||||
console.log("Could not load clock info "+E.toJS(fn))
|
||||
console.log("Could not load clock info "+E.toJS(fn));
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -204,11 +210,12 @@ exports.addInteractive = function(menu, options) {
|
|||
if ("function" == typeof options) options = {draw:options}; // backwards compatibility
|
||||
options.index = 0|exports.loadCount;
|
||||
exports.loadCount = options.index+1;
|
||||
exports.clockInfos[options.index] = options;
|
||||
options.focus = options.index==0 && options.x===undefined; // focus if we're the first one loaded and no position has been defined
|
||||
const appName = (options.app||"default")+":"+options.index;
|
||||
|
||||
// load the currently showing clock_infos
|
||||
let settings = exports.loadSettings()
|
||||
let settings = exports.loadSettings();
|
||||
if (settings.apps[appName]) {
|
||||
let a = settings.apps[appName].a|0;
|
||||
let b = settings.apps[appName].b|0;
|
||||
|
@ -259,6 +266,10 @@ exports.addInteractive = function(menu, options) {
|
|||
//can happen for dynamic ones (alarms, events)
|
||||
//in the worst case we come back to 0
|
||||
} while(menu[options.menuA].items.length==0);
|
||||
// When we change, ensure we don't display the same thing as another clockinfo if we can avoid it
|
||||
while ((options.menuB < menu[options.menuA].items.length) &&
|
||||
exports.clockInfos.some(m => (m!=options) && m.menuA==options.menuA && m.menuB==options.menuB))
|
||||
options.menuB++;
|
||||
}
|
||||
if (oldMenuItem) {
|
||||
menuHideItem(oldMenuItem);
|
||||
|
@ -319,6 +330,7 @@ exports.addInteractive = function(menu, options) {
|
|||
delete Bangle.CLKINFO_FOCUS;
|
||||
menuHideItem(menu[options.menuA].items[options.menuB]);
|
||||
exports.loadCount--;
|
||||
delete exports.clockInfos[options.index];
|
||||
};
|
||||
options.redraw = function() {
|
||||
drawItem(menu[options.menuA].items[options.menuB]);
|
||||
|
@ -339,8 +351,7 @@ exports.addInteractive = function(menu, options) {
|
|||
menuShowItem(menu[options.menuA].items[options.menuB]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
delete settings; // don't keep settings in RAM - save space
|
||||
return options;
|
||||
};
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{ "id": "clock_info",
|
||||
"name": "Clock Info Module",
|
||||
"shortName": "Clock Info",
|
||||
"version":"0.05",
|
||||
"version":"0.06",
|
||||
"description": "A library used by clocks to provide extra information on the clock face (Altitude, BPM, etc)",
|
||||
"icon": "app.png",
|
||||
"type": "module",
|
||||
|
|
|
@ -6,3 +6,4 @@
|
|||
0.06: Add button for force compass calibration
|
||||
0.07: Use 360-heading to output the correct heading value (fix #1866)
|
||||
0.08: Added adjustment for Bangle.js magnetometer heading fix
|
||||
0.09: use falling edge of button to reset compass (allows exit without compass reset)
|
|
@ -68,7 +68,7 @@ g.clear(1);
|
|||
g.setFont("6x8").setFontAlign(0,0,3).drawString(/*LANG*/"RESET", g.getWidth()-5, g.getHeight()/2);
|
||||
setWatch(function() {
|
||||
Bangle.resetCompass();
|
||||
}, (process.env.HWVERSION==2) ? BTN1 : BTN2, {repeat:true});
|
||||
}, (process.env.HWVERSION==2) ? BTN1 : BTN2, {repeat:true, edge:"falling"});
|
||||
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "compass",
|
||||
"name": "Compass",
|
||||
"version": "0.08",
|
||||
"version": "0.09",
|
||||
"description": "Simple compass that points North",
|
||||
"icon": "compass.png",
|
||||
"screenshots": [{"url":"screenshot_compass.png"}],
|
||||
|
|
|
@ -15,5 +15,6 @@
|
|||
{"name":"contourclock.settings.js","url":"contourclock.settings.js"},
|
||||
{"name":"contourclock","url":"lib.js"},
|
||||
{"name":"contourclock.img","url":"app-icon.js","evaluate":true}
|
||||
]
|
||||
],
|
||||
"data": [{"name":"contourclock.json"}]
|
||||
}
|
||||
|
|
|
@ -13,5 +13,6 @@
|
|||
{"name":"cprassist.app.js","url":"cprassist.js"},
|
||||
{"name":"cprassist.img","url":"cprassist-icon.js","evaluate":true},
|
||||
{"name":"cprassist.settings.js","url":"settings.js"}
|
||||
]
|
||||
],
|
||||
"data":[{"name":"cprassist.settings.json"}]
|
||||
}
|
||||
|
|
|
@ -12,5 +12,8 @@
|
|||
{"name":"cscsensor.app.js","url":"cscsensor.app.js"},
|
||||
{"name":"cscsensor.settings.js","url":"settings.js"},
|
||||
{"name":"cscsensor.img","url":"cscsensor-icon.js","evaluate":true}
|
||||
],
|
||||
"data": [
|
||||
{"name":"cscsensor.json"}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -13,5 +13,8 @@
|
|||
{"name":"cycling.settings.js","url":"settings.js"},
|
||||
{"name":"blecsc","url":"blecsc.js"},
|
||||
{"name":"cycling.img","url":"cycling.icon.js","evaluate": true}
|
||||
],
|
||||
"data": [
|
||||
{"name":"cycling.json"}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -6,10 +6,13 @@
|
|||
"type":"textinput",
|
||||
"tags": "keyboard",
|
||||
"supports" : ["BANGLEJS2"],
|
||||
"screenshots": [{"url":"screenshot.png"}],
|
||||
"screenshots": [{"url":"screenshot.png"}],
|
||||
"readme": "README.md",
|
||||
"storage": [
|
||||
{"name":"textinput","url":"lib.js"},
|
||||
{"name":"dragboard.settings.js","url":"settings.js"}
|
||||
],
|
||||
"data": [
|
||||
{"name":"dragboard.json"}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -6,10 +6,13 @@
|
|||
"type":"textinput",
|
||||
"tags": "keyboard",
|
||||
"supports" : ["BANGLEJS2"],
|
||||
"screenshots": [{"url":"screenshot.png"}],
|
||||
"screenshots": [{"url":"screenshot.png"}],
|
||||
"readme": "README.md",
|
||||
"storage": [
|
||||
{"name":"textinput","url":"lib.js"},
|
||||
{"name":"draguboard.settings.js","url":"settings.js"}
|
||||
],
|
||||
"data": [
|
||||
{"name":"draguboard.json"}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -12,5 +12,6 @@
|
|||
{"name":"f9lander.app.js","url":"app.js"},
|
||||
{"name":"f9lander.img","url":"app-icon.js","evaluate":true},
|
||||
{"name":"f9lander.settings.js", "url":"settings.js"}
|
||||
]
|
||||
],
|
||||
"data":[{"name":"f9settings.json"}]
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
0.01: New App!
|
||||
0.02: Allow redirection of loads to the launcher
|
||||
0.03: Allow hiding the fastloading info screen
|
||||
0.04: (WIP) Allow use of app history when going back (`load()` or `Bangle.load()` calls without specified app).
|
||||
|
|
|
@ -8,9 +8,16 @@ This allows fast loading of all apps with two conditions:
|
|||
|
||||
## Settings
|
||||
|
||||
* Activate app history and navigate back through recent apps instead of immediately loading the clock face
|
||||
* If Quick Launch is installed it can be excluded from app history
|
||||
* Allows to redirect all loads usually loading the clock to the launcher instead
|
||||
* The "Fastloading..." screen can be switched off
|
||||
|
||||
## App history
|
||||
|
||||
* Long press of hardware button clears the app history and loads the clock face
|
||||
* Installing the 'Fast Reset' app allows doing fastloads directly to the clock face by pressing the hardware button for one second. Useful if there are many apps in the history and the user want to access the clock quickly.
|
||||
|
||||
## Technical infos
|
||||
|
||||
This is still experimental but it uses the same mechanism as `.bootcde` does.
|
||||
|
@ -19,3 +26,6 @@ It checks the app to be loaded for widget use and stores the result of that and
|
|||
# Creator
|
||||
|
||||
[halemmerich](https://github.com/halemmerich)
|
||||
|
||||
# Contributors
|
||||
[thyttan](https://github.com/thyttan)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
{
|
||||
const SETTINGS = require("Storage").readJSON("fastload.json") || {};
|
||||
const s = require("Storage");
|
||||
const SETTINGS = s.readJSON("fastload.json") || {};
|
||||
|
||||
let loadingScreen = function(){
|
||||
g.reset();
|
||||
|
@ -16,26 +17,26 @@ let loadingScreen = function(){
|
|||
g.flip(true);
|
||||
};
|
||||
|
||||
let cache = require("Storage").readJSON("fastload.cache") || {};
|
||||
let cache = s.readJSON("fastload.cache") || {};
|
||||
|
||||
let checkApp = function(n){
|
||||
// no widgets, no problem
|
||||
if (!global.WIDGETS) return true;
|
||||
let app = require("Storage").read(n);
|
||||
let app = s.read(n);
|
||||
if (cache[n] && E.CRC32(app) == cache[n].crc)
|
||||
return cache[n].fast
|
||||
return cache[n].fast;
|
||||
cache[n] = {};
|
||||
cache[n].fast = app.includes("Bangle.loadWidgets");
|
||||
cache[n].crc = E.CRC32(app);
|
||||
require("Storage").writeJSON("fastload.cache", cache);
|
||||
s.writeJSON("fastload.cache", cache);
|
||||
return cache[n].fast;
|
||||
}
|
||||
};
|
||||
|
||||
global._load = load;
|
||||
|
||||
let slowload = function(n){
|
||||
global._load(n);
|
||||
}
|
||||
};
|
||||
|
||||
let fastload = function(n){
|
||||
if (!n || checkApp(n)){
|
||||
|
@ -50,17 +51,40 @@ let fastload = function(n){
|
|||
};
|
||||
global.load = fastload;
|
||||
|
||||
let appHistory, resetHistory, recordHistory;
|
||||
if (SETTINGS.useAppHistory){
|
||||
appHistory = s.readJSON("fastload.history.json",true)||[];
|
||||
resetHistory = ()=>{appHistory=[];s.writeJSON("fastload.history.json",appHistory);};
|
||||
recordHistory = ()=>{s.writeJSON("fastload.history.json",appHistory);};
|
||||
}
|
||||
|
||||
Bangle.load = (o => (name) => {
|
||||
if (Bangle.uiRemove && !SETTINGS.hideLoading) loadingScreen();
|
||||
if (SETTINGS.useAppHistory){
|
||||
if (name && name!=".bootcde" && !(name=="quicklaunch.app.js" && SETTINGS.disregardQuicklaunch)) {
|
||||
// store the name of the app to launch
|
||||
appHistory.push(name);
|
||||
} else if (name==".bootcde") { // when Bangle.showClock is called
|
||||
resetHistory();
|
||||
} else if (name=="quicklaunch.app.js" && SETTINGS.disregardQuicklaunch) {
|
||||
// do nothing with history
|
||||
} else {
|
||||
// go back in history
|
||||
appHistory.pop();
|
||||
name = appHistory[appHistory.length-1];
|
||||
}
|
||||
}
|
||||
if (SETTINGS.autoloadLauncher && !name){
|
||||
let orig = Bangle.load;
|
||||
Bangle.load = (n)=>{
|
||||
Bangle.load = orig;
|
||||
fastload(n);
|
||||
}
|
||||
};
|
||||
Bangle.showLauncher();
|
||||
Bangle.load = orig;
|
||||
} else
|
||||
} else
|
||||
o(name);
|
||||
})(Bangle.load);
|
||||
|
||||
if (SETTINGS.useAppHistory) E.on('kill', ()=>{if (!BTN.read()) recordHistory(); else resetHistory();}); // Usually record history, but reset it if long press of HW button was used.
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{ "id": "fastload",
|
||||
"name": "Fastload Utils",
|
||||
"shortName" : "Fastload Utils",
|
||||
"version": "0.03",
|
||||
"version": "0.04",
|
||||
"icon": "icon.png",
|
||||
"description": "Enable experimental fastloading for more apps",
|
||||
"type":"bootloader",
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
(function(back) {
|
||||
var FILE="fastload.json";
|
||||
var settings;
|
||||
|
||||
var isQuicklaunchPresent = !!require('Storage').read("quicklaunch.app.js", 0, 1);
|
||||
|
||||
function writeSettings(key, value) {
|
||||
var s = require('Storage').readJSON(FILE, true) || {};
|
||||
s[key] = value;
|
||||
|
@ -12,25 +13,52 @@
|
|||
function readSettings(){
|
||||
settings = require('Storage').readJSON(FILE, true) || {};
|
||||
}
|
||||
|
||||
|
||||
readSettings();
|
||||
|
||||
function buildMainMenu(){
|
||||
var mainmenu = {
|
||||
'': { 'title': 'Fastload', back: back },
|
||||
'Force load to launcher': {
|
||||
var mainmenu = {};
|
||||
|
||||
mainmenu[''] = { 'title': 'Fastload', back: back };
|
||||
|
||||
mainmenu['Activate app history'] = {
|
||||
value: !!settings.useAppHistory,
|
||||
onchange: v => {
|
||||
writeSettings("useAppHistory",v);
|
||||
if (v && settings.autoloadLauncher) {
|
||||
writeSettings("autoloadLauncher",!v); // Don't use app history and load to launcher together.
|
||||
setTimeout(()=>E.showMenu(buildMainMenu()), 0); // Update the menu so it can be seen if a value was automatically set to false (app history vs load launcher).
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (isQuicklaunchPresent) {
|
||||
mainmenu['Exclude Quick Launch from history'] = {
|
||||
value: !!settings.disregardQuicklaunch,
|
||||
onchange: v => {
|
||||
writeSettings("disregardQuicklaunch",v);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
mainmenu['Force load to launcher'] = {
|
||||
value: !!settings.autoloadLauncher,
|
||||
onchange: v => {
|
||||
writeSettings("autoloadLauncher",v);
|
||||
if (v && settings.useAppHistory) {
|
||||
writeSettings("useAppHistory",!v);
|
||||
setTimeout(()=>E.showMenu(buildMainMenu()), 0); // Update the menu so it can be seen if a value was automatically set to false (app history vs load launcher).
|
||||
} // Don't use app history and load to launcher together.
|
||||
}
|
||||
},
|
||||
'Hide "Fastloading..."': {
|
||||
};
|
||||
|
||||
mainmenu['Hide "Fastloading..."'] = {
|
||||
value: !!settings.hideLoading,
|
||||
onchange: v => {
|
||||
writeSettings("hideLoading",v);
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
return mainmenu;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
0.01: New App!
|
|
@ -0,0 +1,32 @@
|
|||
# Fast Reset
|
||||
|
||||
Reset the watch by holding the hardware button for half a second. If 'Fastload Utils' is installed this will typically be done with fastloading. A buzz acts as indicator.
|
||||
|
||||
Fast Reset was developed with the app history feature of 'Fastload Utils' in mind. If many apps are in the history stack, the user may want a fast way to exit directly to the clock face without using the firmwares reset function.
|
||||
|
||||
## Usage
|
||||
|
||||
Just install and it will run as boot code.
|
||||
|
||||
## Features
|
||||
|
||||
If 'Fastload Utils' is installed fastloading will be used when possible. Otherwise a standard `load(.bootcde)` is used.
|
||||
|
||||
If the hardware button is held for longer the standard reset functionality of the firmware is executed as well (total 1.5 seconds). And eventually the watchdog will be kicked.
|
||||
|
||||
## Controls
|
||||
|
||||
Hold the hardware button for half a second to feel the buzz, loading the clock face.
|
||||
|
||||
## Requests
|
||||
|
||||
Mention @[thyttan](https://github.com/thyttan) in an issue to the official [BangleApps repository](https://github.com/espruino/BangleApps/issues) for feature requests and bug reports.
|
||||
|
||||
## Acknowledgements
|
||||
|
||||
<a target="_blank" href="https://icons8.com/icon/15165/rewind">Rewind</a> icon by <a target="_blank" href="https://icons8.com">Icons8</a>
|
||||
|
||||
## Creator
|
||||
|
||||
[thyttan](https://github.com/thyttan)
|
||||
|
After Width: | Height: | Size: 343 B |
|
@ -0,0 +1,5 @@
|
|||
{let buzzTimeout;
|
||||
setWatch((e)=>{
|
||||
if (e.state) buzzTimeout = setTimeout(()=>{Bangle.buzz(80,0.40);Bangle.showClock();}, 500);
|
||||
if (!e.state && buzzTimeout) clearTimeout(buzzTimeout);},
|
||||
BTN,{repeat:true, edge:'both' });}
|
|
@ -0,0 +1,14 @@
|
|||
{ "id": "fastreset",
|
||||
"name": "Fast Reset",
|
||||
"shortName":"Fast Reset",
|
||||
"version":"0.01",
|
||||
"description": "Reset the watch by holding the hardware button for half a second. If 'Fastload Utils' is installed this will typically be done with fastloading. A buzz acts as indicator.",
|
||||
"icon": "app.png",
|
||||
"type": "bootloader",
|
||||
"tags": "system",
|
||||
"supports" : ["BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
"storage": [
|
||||
{"name":"fastreset.boot.js","url":"boot.js"}
|
||||
]
|
||||
}
|
|
@ -14,5 +14,6 @@
|
|||
{"name":"game1024.app.js","url":"app.js"},
|
||||
{"name":"game1024.settings.js","url":"settings.js"},
|
||||
{"name":"game1024.img","url":"app-icon.js","evaluate":true}
|
||||
]
|
||||
],
|
||||
"data":[{"name":"game1024.settings.json"}]
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
0.01: New App!
|
|
@ -0,0 +1,11 @@
|
|||
Bluetooth.println("");
|
||||
Bluetooth.println(JSON.stringify({
|
||||
t:"intent",
|
||||
target:"activity",
|
||||
action:"android.intent.action.VOICE_COMMAND",
|
||||
flags:["FLAG_ACTIVITY_NEW_TASK"]
|
||||
}));
|
||||
|
||||
setTimeout(function() {
|
||||
Bangle.showClock();
|
||||
}, 0);
|
After Width: | Height: | Size: 799 B |
|
@ -0,0 +1,21 @@
|
|||
// load settings
|
||||
var settings = Object.assign({
|
||||
enableTap: true
|
||||
}, require("Storage").readJSON("gassist.json", true) || {});
|
||||
|
||||
if (settings.enableTap) {
|
||||
Bangle.on("tap", function(e) {
|
||||
if (e.dir=="front" && e.double) {
|
||||
Bluetooth.println("");
|
||||
Bluetooth.println(JSON.stringify({
|
||||
t:"intent",
|
||||
target:"activity",
|
||||
action:"android.intent.action.VOICE_COMMAND",
|
||||
flags:["FLAG_ACTIVITY_NEW_TASK"]
|
||||
}));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// clear variable
|
||||
settings = undefined;
|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("mEwxH+AH4A/AH4ALiAAFFtoxmFpQxjFxwwfFyAwdFyQwcF9wuUGDQvuFywwYF/4vUnAABF9YuCGBAv/F/6/PGC4bE3QACG5YvdFoYxSLzAvuFw4wjLxbCidhAvVGB4UFF7QxMCZAuaGJIRKF7oATFtoA/AEPMAAQttGNQuHGE4vuFxIwlF/4v/d/4vwGBAumGIwtpAH4A/AEIA=="))
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"id": "gassist",
|
||||
"name": "Google Assist",
|
||||
"version": "0.01",
|
||||
"description": "A simple way to initiate Google Assistant on Android. Intents must be enabled in Gadgetbridge.",
|
||||
"icon": "app.png",
|
||||
"type": "app",
|
||||
"tags": "tool, voice, tasker",
|
||||
"supports": ["BANGLEJS","BANGLEJS2"],
|
||||
"allow_emulator": false,
|
||||
"storage": [
|
||||
{"name":"gassist.boot.js","url":"boot.js"},
|
||||
{"name":"gassist.app.js","url":"app.js"},
|
||||
{"name":"gassist.settings.js","url":"settings.js"},
|
||||
{"name":"gassist.img","url":"icon.js","evaluate":true}
|
||||
],
|
||||
"data": [{"name":"gassist.json"}]
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
(function (back) {
|
||||
let storage = require('Storage');
|
||||
let file = "gassist.json";
|
||||
|
||||
// Load and set default settings
|
||||
let appSettings = Object.assign({
|
||||
enableTap : true
|
||||
}, storage.readJSON(file, true) || {});
|
||||
|
||||
// Save settings to storage
|
||||
function writeSettings() {
|
||||
storage.writeJSON(file, appSettings);
|
||||
}
|
||||
|
||||
function showMenu() {
|
||||
E.showMenu({
|
||||
"": {
|
||||
"title": "Google Assist"
|
||||
},
|
||||
"< Back": () => back(),
|
||||
'Front Tap:': {
|
||||
value: (appSettings.enableTap === true),
|
||||
format: v => v ? "On" : "Off",
|
||||
onchange: v => {
|
||||
appSettings.enableTap = v;
|
||||
writeSettings();
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
// Initially show the menu
|
||||
showMenu();
|
||||
});
|
|
@ -2,3 +2,4 @@
|
|||
0.02: BTN2->launcher, use smaller text to allow "20:00" to fit on screen
|
||||
0.03: Changed setWatch to Bangle.setUI
|
||||
0.04: Tell clock widgets to hide.
|
||||
0.05: Making geissclock work on Bangle.js 2 (but only animate when unlocked!)
|
|
@ -1,4 +1,7 @@
|
|||
var W = 79, H = 64;
|
||||
// if screen is always on, only animate when unlocked
|
||||
var isScreenAlwaysOn = process.env.BOARD=="BANGLEJS2";
|
||||
|
||||
/*var compiled = E.compiledC(`
|
||||
// void transl(int, int, int )
|
||||
int transl(unsigned char *map, unsigned char *imgfrom, unsigned char *imgto) {
|
||||
|
@ -46,6 +49,7 @@ var map = new Uint8Array(W*H);
|
|||
var pal = new Uint16Array(256);
|
||||
var PALETTES = 3;
|
||||
var MAPS = 6;
|
||||
var animInterval;
|
||||
|
||||
// If we're missing any maps, compute them!
|
||||
(function() {
|
||||
|
@ -65,6 +69,8 @@ function randomPalette() {
|
|||
var n = (0|Math.random()*200000) % PALETTES;
|
||||
var p = new Uint8Array(pal.buffer);
|
||||
p.set(require("Storage").readArrayBuffer("geissclk."+n+".pal"));
|
||||
if (!g.theme.dark) // if not dark, invert colors
|
||||
E.mapInPlace(pal,pal,x=>x^0xFFFF);
|
||||
}
|
||||
|
||||
function randomMap() {
|
||||
|
@ -93,7 +99,7 @@ var im = {
|
|||
};
|
||||
var lastSeconds = -1;
|
||||
|
||||
function iterate() { "ram"
|
||||
function iterate(clearBuf) { "ram"
|
||||
var d = new Date();
|
||||
var time = require("locale").time(d,1);
|
||||
var seconds = d.getSeconds().toString().padStart(2,0);
|
||||
|
@ -108,27 +114,59 @@ function iterate() { "ram"
|
|||
gfx.buffer = dataa.buffer;
|
||||
}
|
||||
var x,y,n,t = getTime()/10;
|
||||
var amt = 100*Bangle.getAccel().diff;
|
||||
for (var i=0;i<amt;i++) {
|
||||
//x = Math.round((W/2) + 20*Math.sin(t));
|
||||
//y = Math.round((H/2) + 20*Math.cos(t));
|
||||
//t += 0.628;
|
||||
x = 1+(Math.random()*(W-2))|0;
|
||||
y = 1+(Math.random()*(H-2))|0;
|
||||
dataa[x + y*W] = 240;
|
||||
if (clearBuf) {
|
||||
gfx.clear();
|
||||
} else { // do geiss animation
|
||||
var amt = 100*Bangle.getAccel().diff;
|
||||
for (var i=0;i<amt;i++) {
|
||||
//x = Math.round((W/2) + 20*Math.sin(t));
|
||||
//y = Math.round((H/2) + 20*Math.cos(t));
|
||||
//t += 0.628;
|
||||
x = 1+(Math.random()*(W-2))|0;
|
||||
y = 1+(Math.random()*(H-2))|0;
|
||||
dataa[x + y*W] = 240;
|
||||
}
|
||||
compiled.transl(addrmap, addra, addrb);
|
||||
}
|
||||
compiled.transl(addrmap, addra, addrb);
|
||||
|
||||
|
||||
x = 8;
|
||||
|
||||
gfx.setFont("5x9Numeric7Seg",2);
|
||||
gfx.drawString(time, x, 20);
|
||||
gfx.setFont("5x9Numeric7Seg");
|
||||
gfx.drawString(seconds, x+55, 30);
|
||||
if (!clearBuf) { // don't draw seconds if not animating
|
||||
gfx.setFont("5x9Numeric7Seg");
|
||||
gfx.drawString(seconds, x+55, 30);
|
||||
}
|
||||
// firmwares pre-2v09 wouldn't accelerate a 3x blit if it went right to the RHS - hence we're 79px not 80
|
||||
g.drawImage(im,1,24,{scale:3});
|
||||
if (g.getWidth()==176) // Bangle.js 2
|
||||
g.drawImage(im,8,24,{scale:2});
|
||||
else
|
||||
g.drawImage(im,3,24,{scale:3});
|
||||
}
|
||||
|
||||
if (isScreenAlwaysOn) {
|
||||
Bangle.on('lock',function(on) {
|
||||
if (animInterval) {
|
||||
clearInterval(animInterval);
|
||||
animInterval = undefined;
|
||||
}
|
||||
if (!on) { // not locked - animate!
|
||||
randomMap();
|
||||
randomPalette();
|
||||
iterate();
|
||||
animInterval = setInterval(iterate, 50);
|
||||
} else {
|
||||
iterate(true); // just clear
|
||||
animInterval = setTimeout(function() {
|
||||
iterate(true);
|
||||
animInterval = setInterval(function() {
|
||||
iterate(true);
|
||||
}, 60000);
|
||||
}, 60000 - (Date.now() % 60000));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Bangle.on('lcdPower',function(on) {
|
||||
if (animInterval) {
|
||||
|
@ -144,11 +182,15 @@ Bangle.on('lcdPower',function(on) {
|
|||
});
|
||||
|
||||
// Show launcher when button pressed
|
||||
Bangle.setUI("clock");g.clear();
|
||||
Bangle.setUI("clock");
|
||||
g.clear(1);
|
||||
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
iterate();
|
||||
animInterval = setInterval(iterate, 50);
|
||||
iterate(true);
|
||||
if (Bangle.isLCDOn() && (!isScreenAlwaysOn || !Bangle.isLocked())) {
|
||||
console.log("Starting");
|
||||
animInterval = setInterval(iterate, 50);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"id": "geissclk",
|
||||
"name": "Geiss Clock",
|
||||
"version": "0.04",
|
||||
"version": "0.05",
|
||||
"description": "7 segment clock with animated background in the style of Ryan Geiss' music visualisation. NOTE: The first run will take ~1 minute to do some precalculation",
|
||||
"icon": "clock.png",
|
||||
"type": "clock",
|
||||
"tags": "clock",
|
||||
"supports": ["BANGLEJS"],
|
||||
"supports": ["BANGLEJS","BANGLEJS2"],
|
||||
"storage": [
|
||||
{"name":"geissclk.app.js","url":"clock.js"},
|
||||
{"name":"geissclk.precompute.js","url":"precompute.js"},
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// PALETTES ---------------------------
|
||||
E.showMessage("Precomputing\npalettes\n\nPlease wait...\n0 / 3");
|
||||
(function() { // fire
|
||||
(function() { "jit" // fire
|
||||
for (var i=0;i<256;i++) {
|
||||
var r = Math.min(i*6,240);
|
||||
var g = Math.min(i*3,240);
|
||||
|
@ -10,7 +10,7 @@ E.showMessage("Precomputing\npalettes\n\nPlease wait...\n0 / 3");
|
|||
})()
|
||||
require("Storage").write("geissclk.0.pal",pal.buffer);
|
||||
E.showMessage("Precomputing\npalettes\n\nPlease wait...\n1 / 3");
|
||||
(function() { // gunge
|
||||
(function() { "jit" // gunge
|
||||
for (var i=0;i<256;i++) {
|
||||
var r = 0;
|
||||
var g = Math.min(i*3,255);
|
||||
|
@ -20,7 +20,7 @@ E.showMessage("Precomputing\npalettes\n\nPlease wait...\n1 / 3");
|
|||
})()
|
||||
require("Storage").write("geissclk.1.pal",pal.buffer);
|
||||
E.showMessage("Precomputing\npalettes\n\nPlease wait...\n2 / 3");
|
||||
(function() { // rainbow
|
||||
(function() { "jit" // rainbow
|
||||
for (var i=0;i<256;i++) {
|
||||
var cl = E.HSBtoRGB((48+i)/128,1,Math.min(i/16,0.9),true);
|
||||
var r = cl[0];
|
||||
|
@ -35,7 +35,7 @@ require("Storage").write("geissclk.2.pal",pal.buffer);
|
|||
// MAPS ----------------------------------------------
|
||||
E.showMessage("Precomputing\nmaps\n\nPlease wait...\n0 / 5");
|
||||
// straight out
|
||||
(function() { "ram"; var n = 0; for (var y=0;y<H;y++) {
|
||||
(function() { "jit"; var n = 0; for (var y=0;y<H;y++) {
|
||||
for (var x=0;x<W;x++) {
|
||||
var dx = x-(W/2);
|
||||
var dy = y-(H/2);
|
||||
|
@ -49,7 +49,7 @@ E.showMessage("Precomputing\nmaps\n\nPlease wait...\n0 / 5");
|
|||
require("Storage").write("geissclk.0.map",map);
|
||||
E.showMessage("Precomputing\nmaps\n\nPlease wait...\n1 / 5");
|
||||
// ripple out
|
||||
(function() { "ram"; var n = 0; for (var y=0;y<H;y++) {
|
||||
(function() { "jit"; var n = 0; for (var y=0;y<H;y++) {
|
||||
for (var x=0;x<W;x++) {
|
||||
var dx = x-(W/2);
|
||||
var dy = y-(H/2);
|
||||
|
@ -63,7 +63,7 @@ E.showMessage("Precomputing\nmaps\n\nPlease wait...\n1 / 5");
|
|||
require("Storage").write("geissclk.1.map",map);
|
||||
E.showMessage("Precomputing\nmaps\n\nPlease wait...\n2 / 5");
|
||||
// twisty outwards
|
||||
(function() { "ram"; var n = 0; for (var y=0;y<H;y++) {
|
||||
(function() { "jit"; var n = 0; for (var y=0;y<H;y++) {
|
||||
for (var x=0;x<W;x++) {
|
||||
var dx = x-(W/2);
|
||||
var dy = y-(H/2);
|
||||
|
@ -76,7 +76,7 @@ E.showMessage("Precomputing\nmaps\n\nPlease wait...\n2 / 5");
|
|||
require("Storage").write("geissclk.2.map",map);
|
||||
E.showMessage("Precomputing\nmaps\n\nPlease wait...\n3 / 5");
|
||||
// spiral
|
||||
(function() { "ram"; var n = 0; for (var y=0;y<H;y++) {
|
||||
(function() { "jit"; var n = 0; for (var y=0;y<H;y++) {
|
||||
for (var x=0;x<W;x++) {
|
||||
var dx = x-(W/2);
|
||||
var dy = y-(H/2);
|
||||
|
@ -89,7 +89,7 @@ E.showMessage("Precomputing\nmaps\n\nPlease wait...\n3 / 5");
|
|||
require("Storage").write("geissclk.3.map",map);
|
||||
E.showMessage("Precomputing\nmaps\n\nPlease wait...\n4 / 5");
|
||||
// blur down
|
||||
(function() { "ram"; var n=0; for (var y=0;y<H;y++) {
|
||||
(function() { "jit"; var n=0; for (var y=0;y<H;y++) {
|
||||
for (var x=0;x<W;x++) {
|
||||
map[n++] = 136 - 6*16 + (y&1)*8-4;
|
||||
}
|
||||
|
@ -97,7 +97,7 @@ E.showMessage("Precomputing\nmaps\n\nPlease wait...\n4 / 5");
|
|||
require("Storage").write("geissclk.4.map",map);
|
||||
E.showMessage("Precomputing\nmaps\n\nPlease wait...\n5 / 5");
|
||||
// twisty
|
||||
(function() { "ram"; var n=0; for (var y=0;y<H;y++) {
|
||||
(function() { "jit"; var n=0; for (var y=0;y<H;y++) {
|
||||
for (var x=0;x<W;x++) {
|
||||
dx = Math.sin(y*0.2);
|
||||
dy = Math.cos(x*0.2);
|
||||
|
|
|
@ -14,5 +14,6 @@
|
|||
{"name":"getup.app.js","url":"app.js"},
|
||||
{"name":"getup.settings.js","url":"settings.js"},
|
||||
{"name":"getup.img","url":"app-icon.js","evaluate":true}
|
||||
]
|
||||
],
|
||||
"data":[{"name":"getup.settings.json"}]
|
||||
}
|
||||
|
|
|
@ -20,5 +20,6 @@
|
|||
{"name":"happyclk.app.js","url":"happyclk.app.js"},
|
||||
{"name":"happyclk.img","url":"happyclk.icon.js","evaluate":true},
|
||||
{"name":"happyclk.settings.js","url":"happyclk.settings.js"}
|
||||
]
|
||||
],
|
||||
"data":[{"name":"happyclk.setting.json"}]
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"shortName":"HR Alarm",
|
||||
"version":"0.02",
|
||||
"description": "This invisible widget vibrates whenever the heart rate gets close to the upper limit or goes over or under the configured limits",
|
||||
"icon": "widget.png",
|
||||
"icon": "widget.png",
|
||||
"type": "widget",
|
||||
"tags": "widget",
|
||||
"supports" : ["BANGLEJS2"],
|
||||
|
@ -12,5 +12,8 @@
|
|||
"storage": [
|
||||
{"name":"hralarm.wid.js","url":"widget.js"},
|
||||
{"name":"hralarm.settings.js","url":"settings.js"}
|
||||
],
|
||||
"data": [
|
||||
{"name":"hralarm.json"}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -15,5 +15,8 @@
|
|||
{"name":"imageclock.app.js","url":"app.js"},
|
||||
{"name":"imageclock.settings.js","url":"settings.js"},
|
||||
{"name":"imageclock.img","url":"app-icon.js","evaluate":true}
|
||||
],
|
||||
"data": [
|
||||
{"name":"imageclock.json"}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -12,5 +12,6 @@
|
|||
{"name":"textinput","url":"lib.js"},
|
||||
{"name":"kbtouch.settings.js","url":"settings.js"}
|
||||
],
|
||||
"sortorder":-1
|
||||
"sortorder":-1,
|
||||
"data":[{"name":"kbtouch.settings.json"}]
|
||||
}
|
||||
|
|
|
@ -24,4 +24,6 @@
|
|||
0.24: Add ability to disable alarm functionality.
|
||||
0.25: Add more colors to the settings and add the ability to disable the data charts+Markup.
|
||||
0.26: Use widget_utils.
|
||||
0.27: Report latest HRM rather than HRM 10 minutes ago (fix #2395)
|
||||
0.27: Report latest HRM rather than HRM 10 minutes ago (fix #2395)
|
||||
0.28: Battery Vref implemented correctly.
|
||||
0.29: Support fastload.
|
|
@ -25,7 +25,8 @@ the "sched" app must be installed on your device.
|
|||
## Data that can be configured
|
||||
* Steps - Steps loaded via the wpedom app.
|
||||
* Battery - Current battery level in %
|
||||
* VREF - Voltage of battery
|
||||
* BattVolt - Voltage of battery
|
||||
* VREF - Internal Voltage Reference
|
||||
* HRM - Last measured HRM
|
||||
* Temp - Weather temperature loaded via the weather module + gadgetbridge
|
||||
* Humidity - Humidity loaded via the weather module + gadgetbridge
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
{
|
||||
const TIMER_IDX = "lcars";
|
||||
const SETTINGS_FILE = "lcars.setting.json";
|
||||
const locale = require('locale');
|
||||
const storage = require('Storage')
|
||||
const storage = require('Storage');
|
||||
const widget_utils = require('widget_utils');
|
||||
let settings = {
|
||||
alarm: -1,
|
||||
|
@ -18,7 +19,7 @@ let settings = {
|
|||
};
|
||||
let saved_settings = storage.readJSON(SETTINGS_FILE, 1) || settings;
|
||||
for (const key in saved_settings) {
|
||||
settings[key] = saved_settings[key]
|
||||
settings[key] = saved_settings[key];
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -36,10 +37,10 @@ let cGrey = "#424242";
|
|||
*/
|
||||
let lcarsViewPos = 0;
|
||||
// let hrmValue = 0;
|
||||
var plotMonth = false;
|
||||
let plotMonth = false;
|
||||
|
||||
|
||||
function convert24to16(input)
|
||||
let convert24to16 = function(input)
|
||||
{
|
||||
let RGB888 = parseInt(input.replace(/^#/, ''), 16);
|
||||
let r = (RGB888 & 0xFF0000) >> 16;
|
||||
|
@ -55,17 +56,17 @@ function convert24to16(input)
|
|||
RGB565 = RGB565 | b;
|
||||
|
||||
return "0x"+RGB565.toString(16);
|
||||
}
|
||||
};
|
||||
|
||||
var color1C = convert24to16(color1);//Converting colors to the correct format.
|
||||
var color2C = convert24to16(color2);
|
||||
var color3C = convert24to16(color3);
|
||||
let color1C = convert24to16(color1);//Converting colors to the correct format.
|
||||
let color2C = convert24to16(color2);
|
||||
let color3C = convert24to16(color3);
|
||||
|
||||
/*
|
||||
* Requirements and globals
|
||||
*/
|
||||
|
||||
var colorPalette = new Uint16Array([//Used to change the color of the image if the user selects a color that is diffrent than the default.
|
||||
let colorPalette = new Uint16Array([//Used to change the color of the image if the user selects a color that is diffrent than the default.
|
||||
0x0000, // not used
|
||||
color2C, // second
|
||||
color3C, // third
|
||||
|
@ -84,73 +85,73 @@ var colorPalette = new Uint16Array([//Used to change the color of the image if t
|
|||
0x0000 // not used
|
||||
],0,1);
|
||||
|
||||
var bgLeftFullscreen = {
|
||||
let bgLeftFullscreen = {
|
||||
width : 27, height : 176, bpp : 3,
|
||||
transparent : 0,
|
||||
buffer : require("heatshrink").decompress((atob("/4AB+VJkmSAQV///+BAtJn//5IIFkmf/4IGyVP/gIGpMnF41PHIImGF4ImHJoQmGJoIdK8hNHNY47C/JNGBIJZGyYJBQA5GCKH5Q/KAQAoUP7y/KH5QGDoQAy0hGF34JB6RGFr4JB9JkFl4JB+gdFy4JB/QdFpYJB/odFkqrCS4xGCWoyDCKH5Q1GShlJChQLCCg5TCHw5TMAD35FAoIIkgJB8hGGv/8Mg8/+QIFp4cB5IRGBIIvI/4IFybyCF4wTCDp5NBHZZiGz4JBLJKAGk4JBO4xQ/KGQA8UP7y/KH5QnAHih/eX5Q/GQ4JCGRJlKCgxTDBAwgCCg5TCHwxTCNA4"))),
|
||||
palette: colorPalette
|
||||
};
|
||||
|
||||
var bgLeftNotFullscreen = {
|
||||
let bgLeftNotFullscreen = {
|
||||
width : 27, height : 152, bpp : 3,
|
||||
transparent : 0,
|
||||
buffer : require("heatshrink").decompress((atob("/4AB+VJkmSAQV///+BAtJn//5IIFkmf/4IGyVP/gIGpMnF41PHIImGF4ImHJoQmGJoIdK8hNHNY47C/JNGBIJZGyYJBQA5GCKH5Q/KAQAy0hGF34JB6RGFr4JB9JkFl4JB+gdFy4JB/QdFpYJB/odFkqrCS4xGCWoyhCKH5Q1GShlJChQLCCg5TCHw5TMAD35FAoIIkgJB8hGGv/8Mg8/+QIFp4cB5IRGBIIvI/4IFybyCF4wTCDp5NBHZZiGz4JBLJKAGk4JBO4xQ/KGQA8UP7y/KH5QnAHih/eX5Q/GQ4JCGRJlKCgxTDBAwgCCg5TCHwxTCNA4A=="))),
|
||||
palette: colorPalette
|
||||
};
|
||||
|
||||
var bgRightFullscreen = {
|
||||
let bgRightFullscreen = {
|
||||
width : 27, height : 176, bpp : 3,
|
||||
transparent : 0,
|
||||
buffer : require("heatshrink").decompress((atob("yVJkgCCyf/AAPJBAYCBk4JB8gUFyVP//yBAoCB//5BAwUCAAIUHAAIgGChopGv5TIn5TIz4yLKYxxC/iGI/xxGKH5Q/agwAnUP7y/KH4yGeVYAJ0hGF34JB6RGFr4JB9JkFl4JB+gdFy4JB/QdFpYJB/odFkp4CS4xGCWoyhCKH5QuDoxQCDpI7GDoJZGHYIRGLIQvGO4QvGMQRNJADv+GIqTC/5PGz4JBJ41JBIPJCg2TD4QLGn4JB/gUaHwRTGHwRTHBIRTGNAQyJ8gyI+QdFp4JB/IdFk5lLKH5QvAHih/eX5Q/KE4A8UP7y/KH5QGDpg7HJoxZCCIx3CJowmCF4yACJoyJC/4A=="))),
|
||||
palette: colorPalette
|
||||
};
|
||||
|
||||
var bgRightNotFullscreen = {
|
||||
let bgRightNotFullscreen = {
|
||||
width : 27, height : 152, bpp : 3,
|
||||
transparent : 0,
|
||||
buffer : require("heatshrink").decompress((atob("yVJkgCCyf/AAPJBAYCBk4JB8gUFyVP//yBAoCB//5BAwUCAAIUHAAIgGChopGv5TIn5TIz4yLKYxxC/iGI/xxGKH5Q/agwAx0hGF34JB6RGFr4JB9JkFl4JB+gdFy4JB/QdFpYJB/odFkqrCS4xGCWoyhCKH5QuDoxQCDpI7GDoJZGHYIRGLIQvGO4QvGMQRNJADv+GIqTC/5PGz4JBJ41JBIPJCg2TD4QLGn4JB/gUaHwRTGHwRTHBIRTGNAQyJ8gyI+QdFp4JB/IdFk5lLKH5QvAHih/eX5Q/KE4A8UP7y/KH5QGDpg7HJoxZCCIx3CJowmCF4yACJoyJC/4A="))),
|
||||
palette: colorPalette
|
||||
};
|
||||
|
||||
var bgLeft = settings.fullscreen ? bgLeftFullscreen : bgLeftNotFullscreen;
|
||||
var bgRight= settings.fullscreen ? bgRightFullscreen : bgRightNotFullscreen;
|
||||
let bgLeft = settings.fullscreen ? bgLeftFullscreen : bgLeftNotFullscreen;
|
||||
let bgRight= settings.fullscreen ? bgRightFullscreen : bgRightNotFullscreen;
|
||||
|
||||
var iconEarth = {
|
||||
let iconEarth = {
|
||||
width : 50, height : 50, bpp : 3,
|
||||
buffer : require("heatshrink").decompress(atob("AFtx48ECBsDwU5k/yhARLjgjBjlzAQMQEZcIkOP/fn31IEZgCBnlz58cEpM4geugEgwU/8+WNZJHDuHHvgmBCQ8goEOnVgJoMnyV58mACItHI4X8uAFBuVHnnz4BuGxk4////Egz3IkmWvPgNw8f/prB//BghTC+AjE7848eMjNnzySBwUJkmf/BuGuPDAQIjBiPHhhTCSQnjMo0ITANJn44Dg8MuFBggCCiFBcAJ0Bv5xEh+ITo2OhHkyf/OIQdBWwVHhgjBNwUE+fP/5EEgePMoYLBhMgyVJk/+BQQdC688I4XxOIc8v//NAvr+QEBj/5NwKVBy1/QYUciPBhk1EAJrC+KeC489QYaMBgU/8BNB9+ChEjz1Jkn/QYMBDQIgCcYTCCiP/nlzJQmenMAgV4//uy/9wRaB/1J8iVCcAfHjt9TYYICnhKCgRKBw159/v//r927OIeeoASBDQccvv3791KYVDBYPLJQeCnPnz//AAP6ocEjEkXgMgJQtz79fLAP8KYkccAcJ8Gf/f/xu/cAMQ4eP5MlyQRCMolx40YsOGBAPfnnzU4KVDpKMBvz8Dh0/8me7IICgkxJQXPIgZTD58sEgcJk+eNoONnFBhk4/5uB/pcDg5KD+4mEv4CBXISVDhEn31/8/+mH7x//JQK5CAAMB4JBCnnxJQf/+fJEgkAa4L+CAQOOjMn/1bXIRxDJQXx58f//Hhlz/88EgsChMgz/Zs/+nfkyV/8huDOI6SD498NwoACi1Z8+S/Plz17/+QCI7jC+ZxBmfPnojIAAMDcYWSp//2wRJEwq2GABECjMgNYwAmA="))
|
||||
};
|
||||
|
||||
var iconSaturn = {
|
||||
let iconSaturn = {
|
||||
width : 50, height : 50, bpp : 3,
|
||||
transparent : 1,
|
||||
buffer : require("heatshrink").decompress(atob("AH4A/AEkQuPHCJ0ChEAwARNjAjBjgjOhs06Q2OEYVx4ARMhEggUMkANIDoIgBoEEgEBNxJEC6ZrBAAMwNxAjDNYcHNxIjB7dtEwIHBwRoKj158+cuPEjlwCRAjC23bpu0wRNDAAsHEYWeEwaSJ6YjCAQUNSRQjEzxQBWZMNEYlsmg2JWAIjCz95SoJuJggjDtuw6dMG5JKCz998wFBJRVNEYW0yaVBJRNhJQN9+4pCzhKJmBKC4YpB/fINxIgCzFxSoQ3J4ENm3CAQPb98wbpEcAQMYWwKYBNxMDXgc2/fv3g2IEAOAgAjBjy5CEhEMfYICBgfPnjdLjj+CgMHiC3JknDhhoINw4jCAB0IJQIANR4QjPAH4A/AFA"))
|
||||
};
|
||||
|
||||
var iconMoon = {
|
||||
let iconMoon = {
|
||||
width : 50, height : 50, bpp : 3,
|
||||
transparent : 1,
|
||||
buffer : require("heatshrink").decompress(atob("AH4AQjlx44CCCZsg8eOkHDwAQKEYgmPhEgEQM48AOIgMHEYoCB4ATI8UAmH/x04JoRuJsImHuBKLn37EwZuIgEQOI8cEpXj/yYBhE8+YNGgkYoJxITBUPnAaC///nC+FjBuIOJZEB8YeCh/8AoYACoMEEAnEjhQDPQJKJ/DCDAoi5DoLdHAoMQgLjFWYPOnngh02IwXzwDjEgPGEYS8BI4MBYoSVG4fP/nghkAgZrDkngJQqSG4gvBg4sBQgkImHihEAWwP8ZBMBEYl5/+cSoVAGQIUFh04weJn///0gj/OEw5KEz45BzhuCTYQAEgePB4IACAoJuBnAQEa4XHjxKB//xFgWHJQsCRgMDEonipwjENwUBDQNx8+evvn/hTDLw3igE+EgZxB8UOXIvEJQUfEYOfv53DEQkgga5BJQvzx84cAj+CDoNh8/eEYJKDuCSEcocnEon+/7xEgFBIIcfB4Mf/IICXI2DgDdBAAn758gCIq5Dv4zBvJuIOIfjEgvP/ARHgwdCB4P3AoTdFAAk4EYk8SQgAFTALaDSQwAGh08//vnDmBABYmEEZYAzA=="))
|
||||
};
|
||||
|
||||
var iconMars = {
|
||||
let iconMars = {
|
||||
width : 50, height : 50, bpp : 3,
|
||||
transparent : 1,
|
||||
buffer : require("heatshrink").decompress(atob("AH4ATjlwCJ+Dh0wwAQMg0cuPHjFhCZkDps0yVJkmQCBMEjFx42atOmzQmLhMkEYQCCCREQoOGEYmmzB0IEY4CBkARGoJKBEYQCEzgSGkGSpAjDyYCCphuGiFhJQgCD8ASFgRHGAQKbB6BuHJRGeOIsINxEk6dNmARDgMEjQjHAQPnVQojIyZKB6YSDNwK5FAQt54BuDXJIjBEwK5EgxKKXgq5BJRdgXIojJAQJKMcAM0EwM2JUApDoCVFExa7FkGCgAmIkAREEwUEjAmHCIgABhEggQmFpACBCIojBEwRQCzVhwkQU4YADgQmBwQCCI4IFBCAojFAQojGJQQjDAQgRGEZICBEo4gFyUIkilFJQUYEAZrBAQMYNw5KDSQSbCNwwABgOGEwgCBsPACQ5xGwdNnARJcAVh48evvnCJK8Chs+/fv33gCRcB48cuPHCBYA/ADAA=="))
|
||||
};
|
||||
|
||||
var iconSatellite = {
|
||||
let iconSatellite = {
|
||||
width : 50, height : 50, bpp : 3,
|
||||
transparent : 2,
|
||||
buffer : require("heatshrink").decompress(atob("pMkyQC/ATGXhIRPyNl0gmPjlwCJ9ly1aCJ1c+fHJR1Hy1ZJR1I+fPnlx6QRLpe+/JKBr5KMuYjBJQMdCJce/fvJQW0CJUlEYQCBSpvvJQbXJjl0NwnzNxGQwEOnHhgF78+WqQyIrFx48cAQXz4ShJgAABh0+8cP//9LJEhg4jDuP3//0LhGQgYlBgeAn///5cIy8MuAmDCIP/9I4HkmCEYMOgHfCQWkCI0cuBuDgF/CIP+CI1Ny1IkeAgHANwIAB/QRFrj7BhkxEwQRC/4RFpbXDgSVBg4RCSorXDI4MJAQMfCIP8cwImDn37fwN58+kwHgLgSVFub7CI4NyBAJKDLgkuEYX78+evKtCLg0jEYRKC58JMoRcFkwjDJQTFDl65EkojEAQMdcwn/+gFC3YjEJQLXEpYRDWwQmEdI6SHAQO0CJUkx4jDF4gCIJQgRMXIjCEARIjCCJ2XEYPKCJqJBJQIROcAUpCJ0kybaDARtdCKAC2kAA="))
|
||||
};
|
||||
|
||||
var iconCharging = {
|
||||
let iconCharging = {
|
||||
width : 50, height : 50, bpp : 3,
|
||||
transparent : 5,
|
||||
buffer : require("heatshrink").decompress(atob("23btugAwUBtoICARG0h048eODQYCJ6P/AAUCCJfbo4SDxYRLtEcuPHjlwgoRJ7RnIloUHoYjDAQfAExEAwUIkACEkSAIEYwCBhZKH6EIJI0CJRFHEY0BJRWBSgf//0AJRYSE4BKLj4SE8BKLv4RD/hK/JS2AXY0gXwRKG4cMmACCJQMAg8csEFJQsBAwfasEAm379u0gFbcBfHzgFBz1xMQZKBjY/D0E2+BOChu26yVEEYdww+cgAFCg+cgIfB6RKF4HbgEIkGChEAthfCJQ0eEAIjBBAMxk6GCJQtgtyVBwRKBAQMbHAJKGXIIFCgACBhl54qVG2E+EAJKBJoWAm0WJQ6SCXgdxFgMLJQvYjeAEAUwFIUitEtJQ14NwUHgEwKYZKGwOwNYX7XgWCg3CJQ5rB4MevPnAoPDJRJrCgEG/ECAoNsJRUwoEesIIBiJKI3CVDti/CJRKVDiJHBSo0YsOGjED8AjBcAcIgdhcAXAPIUAcAYIBcA4dBAQUG8BrBgBuCgOwcBEeXIK2BBAIFBgRqBGoYAChq8CcYUE4FbUYOACQsHzgjDgwFBCIImBAQsDtwYD7cAloRI22B86YBw5QBgoRJ7dAgYEDCJaeBJoMcsARMAQNoJIIRE6A"))
|
||||
};
|
||||
|
||||
var iconWarning = {
|
||||
let iconWarning = {
|
||||
width : 50, height : 50, bpp : 3,
|
||||
transparent : 1,
|
||||
buffer : require("heatshrink").decompress(atob("kmSpIC/AWMyoQIFsmECJFJhMmA4QXByVICIwODAQ4RRFIQGD5JVLkIGDzJqMyAGDph8MiRKGyApEAoZKFyYIDQwMkSQNkQZABBhIIOOJRuEL5gRIAUKACVQMhmUSNYNDQYJTBBwYFByGTkOE5FJWYNMknCAQKYCiaSCpmGochDoSYBhMwTAZrChILBhmEzKPBF4ImBTAREBDoMmEwJVDoYjBycJFgWEJQRuLJQ1kmQCCjJlCBYbjCagaDBwyDBmBuBF4TjJAUQKINBChCDQxZBcZIIQF4NIgEAgKSDiQmEVQKMBoARBAAMCSQLLBVoxqKL4gaCChVCNwoRKOIo4CJIgABBoSMHpIRFgDdJOIJUBCAUJRgJuEAQb+DIIgRIAX4C/ASOQA"))
|
||||
|
@ -172,26 +173,26 @@ Graphics.prototype.setFontAntonioLarge = function(scale) {
|
|||
/*
|
||||
* Draw watch face
|
||||
*/
|
||||
var drawTimeout;
|
||||
function queueDraw() {
|
||||
let drawTimeout;
|
||||
let queueDraw = function() {
|
||||
|
||||
// Faster updates during alarm to ensure that it is
|
||||
// shown correctly...
|
||||
var timeout = isAlarmEnabled() ? 10000 : 60000;
|
||||
let timeout = isAlarmEnabled() ? 10000 : 60000;
|
||||
|
||||
if (drawTimeout) clearTimeout(drawTimeout);
|
||||
drawTimeout = setTimeout(function() {
|
||||
drawTimeout = undefined;
|
||||
draw();
|
||||
}, timeout - (Date.now() % timeout));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* This function plots a data row in LCARS style.
|
||||
* Note: It can be called async and therefore, the text alignment and
|
||||
* font is set each time the function is called.
|
||||
*/
|
||||
function printRow(text, value, y, c){
|
||||
let printRow = function(text, value, y, c){
|
||||
g.setFontAntonioMedium();
|
||||
g.setFontAlign(-1,-1,0);
|
||||
|
||||
|
@ -210,23 +211,23 @@ function printRow(text, value, y, c){
|
|||
g.setColor(c);
|
||||
g.setFontAlign(1,-1,0);
|
||||
g.drawString(value, 126, y);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
function drawData(key, y, c){
|
||||
let drawData = function(key, y, c){
|
||||
try{
|
||||
_drawData(key, y, c);
|
||||
} catch(ex){
|
||||
// Show last error - next try hopefully works.
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
function _drawData(key, y, c){
|
||||
let _drawData = function(key, y, c){
|
||||
key = key.toUpperCase()
|
||||
var text = key;
|
||||
var value = "ERR";
|
||||
var should_print= true;
|
||||
let text = key;
|
||||
let value = "ERR";
|
||||
let should_print= true;
|
||||
|
||||
if(key == "STEPS"){
|
||||
text = "STEP";
|
||||
|
@ -239,21 +240,24 @@ function _drawData(key, y, c){
|
|||
} else if (key == "VREF"){
|
||||
value = E.getAnalogVRef().toFixed(2) + "V";
|
||||
|
||||
} else if (key =="BATTVOLT" ) {
|
||||
text = "BATV";
|
||||
value = (E.getAnalogVRef()*analogRead(3)*4).toFixed(2) + "V";
|
||||
} else if(key == "HRM"){
|
||||
value = Math.round(Bangle.getHealthStatus().bpm||Bangle.getHealthStatus("last").bpm);
|
||||
|
||||
} else if (key == "TEMP"){
|
||||
var weather = getWeather();
|
||||
let weather = getWeather();
|
||||
value = weather.temp;
|
||||
|
||||
} else if (key == "HUMIDITY"){
|
||||
text = "HUM";
|
||||
var weather = getWeather();
|
||||
let weather = getWeather();
|
||||
value = weather.hum;
|
||||
|
||||
} else if (key == "WIND"){
|
||||
text = "WND";
|
||||
var weather = getWeather();
|
||||
let weather = getWeather();
|
||||
value = weather.wind;
|
||||
|
||||
} else if (key == "ALTITUDE"){
|
||||
|
@ -277,18 +281,18 @@ function _drawData(key, y, c){
|
|||
if(should_print){
|
||||
printRow(text, value, y, c);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function drawHorizontalBgLine(color, x1, x2, y, h){
|
||||
let drawHorizontalBgLine = function(color, x1, x2, y, h){
|
||||
g.setColor(color);
|
||||
|
||||
for(var i=0; i<h; i++){
|
||||
for(let i=0; i<h; i++){
|
||||
g.drawLine(x1, y+i, x2,y+i);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
function drawInfo(){
|
||||
let drawInfo = function(){
|
||||
if(lcarsViewPos != 0 || !settings.fullscreen){
|
||||
return;
|
||||
}
|
||||
|
@ -310,9 +314,9 @@ function drawInfo(){
|
|||
g.setColor(color3);
|
||||
g.drawString("LOCK", 128, 53);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function drawState(){
|
||||
let drawState = function(){
|
||||
if(lcarsViewPos != 0){
|
||||
return;
|
||||
}
|
||||
|
@ -322,11 +326,11 @@ function drawState(){
|
|||
g.setFontAntonioMedium();
|
||||
|
||||
if(!isAlarmEnabled()){
|
||||
var bat = E.getBattery();
|
||||
var flash = storage.getFree() / process.env.STORAGE;
|
||||
var current = new Date();
|
||||
var hours = current.getHours();
|
||||
var iconMsg =
|
||||
let bat = E.getBattery();
|
||||
let flash = storage.getFree() / process.env.STORAGE;
|
||||
let current = new Date();
|
||||
let hours = current.getHours();
|
||||
let iconMsg =
|
||||
Bangle.isCharging() ? { icon: iconCharging, text: "STATUS" } :
|
||||
bat < 30 ? { icon: iconWarning, text: "BAT" } :
|
||||
flash < 0.1 ? { icon: iconWarning, text: "DISK" } :
|
||||
|
@ -348,12 +352,12 @@ function drawState(){
|
|||
}
|
||||
|
||||
g.setFontAlign(-1, -1, 0);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
function drawPosition0(){
|
||||
let drawPosition0 = function(){
|
||||
// Draw background image
|
||||
var offset = settings.fullscreen ? 0 : 24;
|
||||
let offset = settings.fullscreen ? 0 : 24;
|
||||
g.drawImage(bgLeft, 0, offset);
|
||||
drawHorizontalBgLine(color1, 25, 120, offset, 4);
|
||||
drawHorizontalBgLine(color1, 130, 176, offset, 4);
|
||||
|
@ -363,13 +367,13 @@ function drawPosition0(){
|
|||
drawHorizontalBgLine(color2, 120, 176, 87, 4);
|
||||
|
||||
// The last line is a battery indicator too
|
||||
var bat = E.getBattery() / 100.0;
|
||||
var batStart = 19;
|
||||
var batWidth = 172 - batStart;
|
||||
var batX2 = parseInt(batWidth * bat + batStart);
|
||||
let bat = E.getBattery() / 100.0;
|
||||
let batStart = 19;
|
||||
let batWidth = 172 - batStart;
|
||||
let batX2 = parseInt(batWidth * bat + batStart);
|
||||
drawHorizontalBgLine(color2, batStart, batX2, 171, 5);
|
||||
drawHorizontalBgLine(cGrey, batX2, 172, 171, 5);
|
||||
for(var i=0; i+batStart<=172; i+=parseInt(batWidth/4)){
|
||||
for(let i=0; i+batStart<=172; i+=parseInt(batWidth/4)){
|
||||
drawHorizontalBgLine(cBlack, batStart+i, batStart+i+3, 168, 8)
|
||||
}
|
||||
|
||||
|
@ -379,8 +383,8 @@ function drawPosition0(){
|
|||
// Write time
|
||||
g.setFontAlign(-1, -1, 0);
|
||||
g.setColor(cWhite);
|
||||
var currentDate = new Date();
|
||||
var timeStr = locale.time(currentDate,1);
|
||||
let currentDate = new Date();
|
||||
let timeStr = locale.time(currentDate,1);
|
||||
g.setFontAntonioLarge();
|
||||
if(settings.fullscreen){
|
||||
g.drawString(timeStr, 27, 10);
|
||||
|
@ -392,13 +396,13 @@ function drawPosition0(){
|
|||
g.setColor(cWhite);
|
||||
g.setFontAntonioMedium();
|
||||
if(settings.fullscreen){
|
||||
var dayStr = locale.dow(currentDate, true).toUpperCase();
|
||||
let dayStr = locale.dow(currentDate, true).toUpperCase();
|
||||
dayStr += " " + currentDate.getDate();
|
||||
dayStr += " " + locale.month(currentDate, 1).toUpperCase();
|
||||
g.drawString(dayStr, 30, 56);
|
||||
} else {
|
||||
var dayStr = locale.dow(currentDate, true).toUpperCase();
|
||||
var date = currentDate.getDate();
|
||||
let dayStr = locale.dow(currentDate, true).toUpperCase();
|
||||
let date = currentDate.getDate();
|
||||
g.drawString(dayStr, 128, 35);
|
||||
g.drawString(date, 128, 55);
|
||||
}
|
||||
|
@ -412,11 +416,11 @@ function drawPosition0(){
|
|||
|
||||
// Draw state
|
||||
drawState();
|
||||
}
|
||||
};
|
||||
|
||||
function drawPosition1(){
|
||||
let drawPosition1 = function(){
|
||||
// Draw background image
|
||||
var offset = settings.fullscreen ? 0 : 24;
|
||||
let offset = settings.fullscreen ? 0 : 24;
|
||||
g.drawImage(bgRight, 149, offset);
|
||||
if(settings.fullscreen){
|
||||
drawHorizontalBgLine(color1, 0, 140, offset, 4);
|
||||
|
@ -444,8 +448,8 @@ function drawPosition1(){
|
|||
|
||||
// Plot HRM graph
|
||||
if(plotMonth){
|
||||
var data = new Uint16Array(32);
|
||||
var cnt = new Uint8Array(32);
|
||||
let data = new Uint16Array(32);
|
||||
let cnt = new Uint8Array(32);
|
||||
health.readDailySummaries(new Date(), h=>{
|
||||
data[h.day]+=h.bpm;
|
||||
if (h.bpm) cnt[h.day]++;
|
||||
|
@ -462,9 +466,9 @@ function drawPosition1(){
|
|||
});
|
||||
|
||||
// Plot step graph
|
||||
var data = new Uint16Array(32);
|
||||
data = new Uint16Array(32);
|
||||
health.readDailySummaries(new Date(), h=>data[h.day]+=h.steps/1000);
|
||||
var gridY = parseInt(Math.max.apply(Math, data)/2);
|
||||
let gridY = parseInt(Math.max.apply(Math, data)/2);
|
||||
gridY = gridY <= 0 ? 1 : gridY;
|
||||
require("graph").drawBar(g, data, {
|
||||
axes : true,
|
||||
|
@ -490,8 +494,8 @@ function drawPosition1(){
|
|||
|
||||
// Plot day
|
||||
} else {
|
||||
var data = new Uint16Array(24);
|
||||
var cnt = new Uint8Array(24);
|
||||
let data = new Uint16Array(24);
|
||||
let cnt = new Uint8Array(24);
|
||||
health.readDay(new Date(), h=>{
|
||||
data[h.hr]+=h.bpm;
|
||||
if (h.bpm) cnt[h.hr]++;
|
||||
|
@ -508,9 +512,9 @@ function drawPosition1(){
|
|||
});
|
||||
|
||||
// Plot step graph
|
||||
var data = new Uint16Array(24);
|
||||
data = new Uint16Array(24);
|
||||
health.readDay(new Date(), h=>data[h.hr]+=h.steps);
|
||||
var gridY = parseInt(Math.max.apply(Math, data)/1000)*1000;
|
||||
let gridY = parseInt(Math.max.apply(Math, data)/1000)*1000;
|
||||
gridY = gridY <= 0 ? 1000 : gridY;
|
||||
require("graph").drawBar(g, data, {
|
||||
axes : true,
|
||||
|
@ -534,9 +538,9 @@ function drawPosition1(){
|
|||
g.drawString("DAY", 154, 115);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function draw(){
|
||||
let draw = function(){
|
||||
// Queue draw first to ensure that its called in one minute again.
|
||||
queueDraw();
|
||||
|
||||
|
@ -557,14 +561,14 @@ function draw(){
|
|||
} else {
|
||||
Bangle.drawWidgets();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Step counter via widget
|
||||
*/
|
||||
function getSteps() {
|
||||
var steps = 0;
|
||||
let getSteps = function() {
|
||||
let steps = 0;
|
||||
try{
|
||||
if (WIDGETS.wpedom !== undefined) {
|
||||
steps = WIDGETS.wpedom.getSteps();
|
||||
|
@ -578,15 +582,15 @@ function getSteps() {
|
|||
}
|
||||
|
||||
return steps;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
function getWeather(){
|
||||
var weatherJson;
|
||||
let getWeather = function(){
|
||||
let weatherJson;
|
||||
|
||||
try {
|
||||
weatherJson = storage.readJSON('weather.json');
|
||||
var weather = weatherJson.weather;
|
||||
let weather = weatherJson.weather;
|
||||
|
||||
// Temperature
|
||||
weather.temp = locale.temp(weather.temp-273.15);
|
||||
|
@ -596,7 +600,7 @@ function getWeather(){
|
|||
|
||||
// Wind
|
||||
const wind = locale.speed(weather.wind).match(/^(\D*\d*)(.*)$/);
|
||||
var speedFactor = settings.speed == "kph" ? 1.0 : 1.0 / 1.60934;
|
||||
let speedFactor = settings.speed == "kph" ? 1.0 : 1.0 / 1.60934;
|
||||
weather.wind = Math.round(wind[1] * speedFactor);
|
||||
|
||||
return weather
|
||||
|
@ -613,15 +617,15 @@ function getWeather(){
|
|||
wdir: " ? ",
|
||||
wrose: " ? "
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Handle alarm
|
||||
*/
|
||||
function isAlarmEnabled(){
|
||||
let isAlarmEnabled = function(){
|
||||
try{
|
||||
var alarm = require('sched');
|
||||
var alarmObj = alarm.getAlarm(TIMER_IDX);
|
||||
let alarm = require('sched');
|
||||
let alarmObj = alarm.getAlarm(TIMER_IDX);
|
||||
if(alarmObj===undefined || !alarmObj.on){
|
||||
return false;
|
||||
}
|
||||
|
@ -630,35 +634,35 @@ function isAlarmEnabled(){
|
|||
|
||||
} catch(ex){ }
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
function getAlarmMinutes(){
|
||||
let getAlarmMinutes = function(){
|
||||
if(!isAlarmEnabled()){
|
||||
return -1;
|
||||
}
|
||||
|
||||
var alarm = require('sched');
|
||||
var alarmObj = alarm.getAlarm(TIMER_IDX);
|
||||
let alarm = require('sched');
|
||||
let alarmObj = alarm.getAlarm(TIMER_IDX);
|
||||
return Math.round(alarm.getTimeToAlarm(alarmObj)/(60*1000));
|
||||
}
|
||||
};
|
||||
|
||||
function increaseAlarm(){
|
||||
let increaseAlarm = function(){
|
||||
try{
|
||||
var minutes = isAlarmEnabled() ? getAlarmMinutes() : 0;
|
||||
var alarm = require('sched')
|
||||
let minutes = isAlarmEnabled() ? getAlarmMinutes() : 0;
|
||||
let alarm = require('sched')
|
||||
alarm.setAlarm(TIMER_IDX, {
|
||||
timer : (minutes+5)*60*1000,
|
||||
});
|
||||
alarm.reload();
|
||||
} catch(ex){ }
|
||||
}
|
||||
};
|
||||
|
||||
function decreaseAlarm(){
|
||||
let decreaseAlarm = function(){
|
||||
try{
|
||||
var minutes = getAlarmMinutes();
|
||||
let minutes = getAlarmMinutes();
|
||||
minutes -= 5;
|
||||
|
||||
var alarm = require('sched')
|
||||
let alarm = require('sched')
|
||||
alarm.setAlarm(TIMER_IDX, undefined);
|
||||
|
||||
if(minutes > 0){
|
||||
|
@ -669,13 +673,13 @@ function decreaseAlarm(){
|
|||
|
||||
alarm.reload();
|
||||
} catch(ex){ }
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Listeners
|
||||
*/
|
||||
Bangle.on('lcdPower',on=>{
|
||||
let onLcdPower = on=>{
|
||||
if (on) {
|
||||
// Whenever we connect to Gadgetbridge, reading data from
|
||||
// health failed. Therefore, we update only partially...
|
||||
|
@ -685,31 +689,34 @@ Bangle.on('lcdPower',on=>{
|
|||
if (drawTimeout) clearTimeout(drawTimeout);
|
||||
drawTimeout = undefined;
|
||||
}
|
||||
});
|
||||
};
|
||||
Bangle.on('lcdPower', onLcdPower);
|
||||
|
||||
Bangle.on('lock', function(isLocked) {
|
||||
let onLock = function(isLocked) {
|
||||
drawInfo();
|
||||
});
|
||||
};
|
||||
Bangle.on('lock', onLock);
|
||||
|
||||
Bangle.on('charging',function(charging) {
|
||||
|
||||
let onCharge = function(charging) {
|
||||
drawState();
|
||||
});
|
||||
};
|
||||
Bangle.on('charging', onCharge);
|
||||
|
||||
function feedback(){
|
||||
let feedback = function(){
|
||||
Bangle.buzz(40, 0.3);
|
||||
}
|
||||
};
|
||||
|
||||
// Touch gestures to control clock. We don't use swipe to be compatible with the bangle ecosystem
|
||||
Bangle.on('touch', function(btn, e){
|
||||
var left = parseInt(g.getWidth() * 0.2);
|
||||
var right = g.getWidth() - left;
|
||||
var upper = parseInt(g.getHeight() * 0.2);
|
||||
var lower = g.getHeight() - upper;
|
||||
let onTouch = function(btn, e){
|
||||
let left = parseInt(g.getWidth() * 0.2);
|
||||
let right = g.getWidth() - left;
|
||||
let upper = parseInt(g.getHeight() * 0.2);
|
||||
let lower = g.getHeight() - upper;
|
||||
|
||||
var is_left = e.x < left;
|
||||
var is_right = e.x > right;
|
||||
var is_upper = e.y < upper;
|
||||
var is_lower = e.y > lower;
|
||||
let is_left = e.x < left;
|
||||
let is_right = e.x > right;
|
||||
let is_upper = e.y < upper;
|
||||
let is_lower = e.y > lower;
|
||||
|
||||
if(!settings.disableData){
|
||||
if(is_left && lcarsViewPos == 1){
|
||||
|
@ -744,16 +751,30 @@ Bangle.on('touch', function(btn, e){
|
|||
draw();
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
};
|
||||
// Touch gestures to control clock. We don't use swipe to be compatible with the bangle ecosystem
|
||||
Bangle.on('touch', onTouch);
|
||||
|
||||
let themeBefore = g.theme;
|
||||
/*
|
||||
* Lets start widgets, listen for btn etc.
|
||||
*/
|
||||
// Show launcher when middle button pressed
|
||||
Bangle.setUI("clock");
|
||||
Bangle.setUI({mode:"clock",remove:function() {
|
||||
if (drawTimeout) clearTimeout(drawTimeout);
|
||||
delete Graphics.prototype.setFontAntonioMedium;
|
||||
delete Graphics.prototype.setFontAntonioLarge;
|
||||
Bangle.removeListener("lcdPower",onLcdPower);
|
||||
Bangle.removeListener("lock",onLock);
|
||||
Bangle.removeListener("charging",onCharge);
|
||||
Bangle.removeListener("touch",onTouch);
|
||||
require('sched').setAlarm(TIMER_IDX, undefined);
|
||||
g.setTheme(themeBefore);
|
||||
widget_utils.cleanup();
|
||||
}});
|
||||
Bangle.loadWidgets();
|
||||
|
||||
// Clear the screen once, at startup and draw clock
|
||||
g.setTheme({bg:"#000",fg:"#fff",dark:true}).clear();
|
||||
draw();
|
||||
}
|
|
@ -26,7 +26,7 @@
|
|||
}
|
||||
|
||||
|
||||
var dataOptions = ["Steps", "Battery", "VREF", "HRM", "Temp", "Humidity", "Wind", "Altitude", "CoreT"];
|
||||
var dataOptions = ["Steps", "Battery", "BattVolt", "VREF", "HRM", "Temp", "Humidity", "Wind", "Altitude", "CoreT"];
|
||||
var speedOptions = ["kph", "mph"];
|
||||
var color_options = ['Green','Orange','Cyan','Purple','Red','Blue','Yellow','White','Purple','Pink','Light Green','Dark Green'];
|
||||
var bg_code = ['#00ff00','#FF9900','#0094FF','#FF00DC','#ff0000','#0000ff','#ffef00','#FFFFFF','#FF00FF','#6C00FF','#99FF00','#556B2F'];
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"name": "LCARS Clock",
|
||||
"shortName":"LCARS",
|
||||
"icon": "lcars.png",
|
||||
"version":"0.27",
|
||||
"version":"0.29",
|
||||
"readme": "README.md",
|
||||
"supports": ["BANGLEJS2"],
|
||||
"description": "Library Computer Access Retrieval System (LCARS) clock.",
|
||||
|
@ -16,5 +16,6 @@
|
|||
{"name":"lcars.app.js","url":"lcars.app.js"},
|
||||
{"name":"lcars.img","url":"lcars.icon.js","evaluate":true},
|
||||
{"name":"lcars.settings.js","url":"lcars.settings.js"}
|
||||
]
|
||||
],
|
||||
"data":[{"name":"lcars.setting.json"}]
|
||||
}
|
||||
|
|
|
@ -13,5 +13,8 @@
|
|||
{"name":"limelight.app.js","url":"limelight.app.js"},
|
||||
{"name":"limelight.settings.js","url":"limelight.settings.js"},
|
||||
{"name":"limelight.img","url":"limelight.icon.js","evaluate":true}
|
||||
],
|
||||
"data": [
|
||||
{"name":"limelight.json"}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -14,5 +14,6 @@
|
|||
{"name":"linuxclock.app.js","url":"app.js"},
|
||||
{"name":"linuxclock.img","url":"app-icon.js","evaluate":true},
|
||||
{"name":"linuxclock.settings.js","url":"settings.js"}
|
||||
]
|
||||
],
|
||||
"data":[{"name":"linuxclock.setting.json"}]
|
||||
}
|
||||
|
|
|
@ -10,5 +10,6 @@
|
|||
"readme": "README.md",
|
||||
"storage": [
|
||||
{"name":"loadingscreen.settings.js","url":"settings.js"}
|
||||
]
|
||||
],
|
||||
"data":[{"name":".loading"}]
|
||||
}
|
||||
|
|
|
@ -96,4 +96,7 @@
|
|||
Nav messages with '/' now get split on newlines
|
||||
0.70: Handle nav messages from newer Gadgetbridge builds that output distance as a String
|
||||
If we receive a 'music' message and we're in the messages app (but not showing a message) show music (#2814)
|
||||
0.71: Cancel buzzing when watch unlocked, or when different messages viewed
|
||||
0.71: Cancel buzzing when watch unlocked, or when different messages viewed
|
||||
On 2v18.64+ firmware, 'No Messages' now has a 'back' button
|
||||
0.72: Nav message updastes don't automatically launch navigation menu unless they're new
|
||||
0.73: Add sharp left+right nav icons
|
|
@ -70,6 +70,8 @@ var onMessagesModified = function(type,msg) {
|
|||
if (msg.state && msg.state!="play") openMusic = false; // no longer playing music to go back to
|
||||
if ((active!=undefined) && (active!="list") && (active!="music")) return; // don't open music over other screens (but do if we're in the main menu)
|
||||
}
|
||||
if (msg && msg.id=="nav" && msg.t=="modify" && active!="map")
|
||||
return; // don't show an updated nav message if we're just in the menu
|
||||
showMessage(msg&&msg.id);
|
||||
};
|
||||
Bangle.on("message", onMessagesModified);
|
||||
|
@ -102,6 +104,8 @@ function showMapMessage(msg) {
|
|||
case "right": img = "GhcBAABgAAA8AAAPgAAB8AAAPgAAB8D///j///9///+/AAPPAAHjgAD44AB8OAA+DgAPA4ABAOAAADgAAA4AAAOAAADgAAA4AAAOAAAA";break;
|
||||
case "left_slight": img = "ERgB//B/+D/8H4AP4Af4A74Bz4Dj4HD4OD4cD4AD4ADwADwADgAHgAPAAOAAcAA4ABwADgAH";break;
|
||||
case "right_slight": img = "ERgBB/+D/8H/4APwA/gD/APuA+cD44Phw+Dj4HPgAeAB4ADgAPAAeAA4ABwADgAHAAOAAcAA";break;
|
||||
case "left_sharp": img = "GBaBAAAA+AAB/AAH/gAPjgAeBwA8BwB4B+DwB+HgB+PAB+eAB+8AB+4AB/wAB/gAB//gB//gB//gBwAABwAABwAABwAABw=="; break;
|
||||
case "right_sharp": img = "GBaBAB8AAD+AAH/gAHHwAOB4AOA8AOAeAOAPB+AHh+ADx+AB5+AA9+AAd+AAP+AAH+AH/+AH/+AH/+AAAOAAAOAAAOAAAA==";break;
|
||||
case "keep_left": img = "ERmBAACAAOAB+AD+AP+B/+H3+PO+8c8w4wBwADgAHgAPAAfAAfAAfAAfAAeAAeAAcAA8AA4ABwADgA==";break;
|
||||
case "keep_right": img = "ERmBAACAAOAA/AD+AP+A//D/fPueeceY4YBwADgAPAAeAB8AHwAfAB8ADwAPAAcAB4ADgAHAAOAAAA==";break;
|
||||
case "uturn_left": img = "GRiBAAAH4AAP/AAP/wAPj8APAfAPAHgHgB4DgA8BwAOA4AHAcADsOMB/HPA7zvgd9/gOf/gHH/gDh/gBwfgA4DgAcBgAOAAAHAAADgAABw==";break;
|
||||
|
@ -414,8 +418,9 @@ function checkMessages(options) {
|
|||
if (!options.clockIfNoMsg) return E.showPrompt(/*LANG*/"No Messages",{
|
||||
title:/*LANG*/"Messages",
|
||||
img:require("heatshrink").decompress(atob("kkk4UBrkc/4AC/tEqtACQkBqtUDg0VqAIGgoZFDYQIIM1sD1QAD4AIBhnqA4WrmAIBhc6BAWs8AIBhXOBAWz0AIC2YIC5wID1gkB1c6BAYFBEQPqBAYXBEQOqBAnDAIQaEnkAngaEEAPDFgo+IKA5iIOhCGIAFb7RqAIGgtUBA0VqobFgNVA")),
|
||||
buttons : {/*LANG*/"Ok":1}
|
||||
}).then(() => { load() });
|
||||
buttons : {/*LANG*/"Ok":1},
|
||||
back: () => load()
|
||||
}).then(() => load());
|
||||
return load();
|
||||
}
|
||||
// we have >0 messages
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"id": "messagegui",
|
||||
"name": "Message UI",
|
||||
"shortName": "Messages",
|
||||
"version": "0.71",
|
||||
"version": "0.73",
|
||||
"description": "Default app to display notifications from iOS and Gadgetbridge/Android",
|
||||
"icon": "app.png",
|
||||
"type": "app",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Messages library
|
||||
|
||||
This library handles the passing of messages. It can storess a list of messages
|
||||
This library handles the passing of messages. It can stores a list of messages
|
||||
and allows them to be retrieved by other apps.
|
||||
|
||||
## Example
|
||||
|
@ -37,18 +37,10 @@ myMessageListener = Bangle.on("message", (type, message)=>{
|
|||
});
|
||||
```
|
||||
|
||||
Apps can launch the full GUI by calling `require("messages").openGUI()`, if you
|
||||
want to write your own GUI, it should include boot code that listens for
|
||||
`"messageGUI"` events:
|
||||
|
||||
```js
|
||||
Bangle.on("messageGUI", message=>{
|
||||
if (message.handled) return; // another app already opened it's GUI
|
||||
message.handled = true; // prevent other apps form launching
|
||||
Bangle.load("my_message_gui.app.js");
|
||||
})
|
||||
|
||||
```
|
||||
Apps can launch the currently installed Message GUI by calling `require("messages").openGUI()`.
|
||||
If you want to write your own GUI, it should include a library called `messagegui`
|
||||
with a method called `open` that will cause it to be opened, with the
|
||||
optionally supplied message. See `apps/messagegui/lib.js` for an example.
|
||||
|
||||
|
||||
## Requests
|
||||
|
|
|
@ -107,7 +107,7 @@ exports.dismiss = function(msg) {
|
|||
};
|
||||
|
||||
/**
|
||||
* Emit a "type=openGUI" event, to open GUI app
|
||||
* Open the Messages GUI app
|
||||
*
|
||||
* @param {object} [msg={}] Message the app should show
|
||||
*/
|
||||
|
@ -215,7 +215,7 @@ exports.buzz = function(msgSrc) {
|
|||
|
||||
let repeat = msgSettings.repeat;
|
||||
if (repeat===undefined) repeat = 4; // repeat may be zero
|
||||
if (repeat)
|
||||
if (repeat)
|
||||
{
|
||||
exports.buzzInterval = setInterval(() => require("buzz").pattern(pattern), repeat*1000);
|
||||
let vibrateTimeout = msgSettings.vibrateTimeout;
|
||||
|
|
|
@ -13,5 +13,6 @@
|
|||
{"name":"metronome.app.js","url":"metronome.js"},
|
||||
{"name":"metronome.img","url":"metronome-icon.js","evaluate":true},
|
||||
{"name":"metronome.settings.js","url":"settings.js"}
|
||||
]
|
||||
],
|
||||
"data":[{"name":"metronome.settings.json"}]
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
0.01: Initial version
|
||||
0.02: Update for time_utils module
|
||||
0.03: Use default Bangle formatter for booleans
|
||||
0.04: Remove copied sched alarm.js & import newer features (oneshot alarms)
|
||||
|
|