mirror of https://github.com/espruino/BangleApps
Merge branch 'espruino:master' into timerclk
commit
9c8f1d43e3
|
@ -1 +1,2 @@
|
|||
0.01: New App!
|
||||
0.02: Barometer altitude adjustment setting
|
||||
|
|
|
@ -6,6 +6,10 @@
|
|||
|
||||
#### If "CALIB!" is shown on the display or the compass heading differs too much from GPS heading, compass calibration should be done with the ["Navigation Compass" App](https://banglejs.com/apps/?id=magnav)
|
||||
|
||||
Permanently diverging Barometer Altitude values can be compensated in the settings menu.
|
||||
|
||||
Please report bugs to https://github.com/espruino/BangleApps/issues/new?assignees=&labels=bug&template=bangle-bug-report-custom-form.yaml&title=%5BBike+Speedometer%5D+Short+description+of+bug
|
||||
|
||||
**Credits:**<br>
|
||||
Bike Speedometer App by <i>github.com/HilmarSt</i><br>
|
||||
Big parts of the software are based on <i>github.com/espruino/BangleApps/tree/master/apps/speedalt</i><br>
|
||||
|
|
|
@ -1 +1 @@
|
|||
require("heatshrink").decompress(atob("mEwxH+64A/AC+sF1uBgAwsq1W1krGEmswIFDlcAFoMrqyGjlcrGAQDB1guBBQJghKYZZCMYhqBlYugFAesgAuFYgQIHAE2sYMZDfwIABbgIuowMAqwABb4wAjFVQAEqyMrF4cAlYABqwypR4RgBwIyplYnF1hnBGIo8BAAQvhGIj6C1hpBgChBGCqGBqwdCRQQnCB4gJBGAgtWc4WBPoi9JH4ILBGYQATPoRHJRYoACwLFBLi4tGLIyLEA5QuPCoYpEMhBBBGDIuFgArIYQIUHA4b+GABLUBAwoQIXorDGI5RNGCB9WRQ0AJwwHGDxChOH4oDCRI4/GXpAaB1gyLEwlWKgTrBT46ALCogQKZoryFCwzgGBgz/NZpaQHHBCdEF5hKBBxWBUwoGBgEAEoIyHHYesBg7aBJQ7SBBAIvEIIJCBD4IFBgBIGEAcAUA8rGAIWHS4QvDCAJAHG4JfRCgKCFeAovCdRIiBDYq/NABi0Cfo5IEBgjUGACZ6BqwcGwLxBFYRsEHIKBIJwLkBNoIHDF468GYgIBBXY4EDE4IHDYwSwCN4IGBCIp5CJYtWgBZBHAgFEMoRjEE4QDCLYJUEUoaCBPYoQCgA4FGozxFLYwfEQgqrGexIYFBoxbDS4YHCIAYVEEAZcCYwwvGfoQHEcwQHHIg9WIAS9BIoYYESoowIABQuBUgg1DVwwACEpIwBChDLFDQ5JLlZnHJAajBQwgLEO4LDBHKAhBFxQxFCIIACAwadLHgJJBAAUrQJxYFAAbKPCwRGCCqAAm"))
|
||||
require("heatshrink").decompress(atob("mEwgP/ABO/AokfAgf+r4FD3lPBQcZw4FC/nD+4FC/Pn+YFCBIP7GQ4aDEIMDAol/ApQRFuAFEv0/BoQXBx0HAoPgh/nn40C4fwEoP+n/4/BWC/weBBYP5BAM/C4Pz7/7z+f//n7/z5/f//vA4Pv5//AIPv8/n//d//Ou5yBDIOfu58Bz42B+Z8Bz/8AoPgv+/AoP7w0f3IFBnc/5+bL4Oyv/nEYP/+X/mYFC+n8mff8ln+v4vfd7tfsvzvfN7tPtv2vPn6H35vg/f36vX7vj/fz9vvznH+Z3B/0+5/3/l//iDBMwMf+KEBOAPBUoOCj///CNBUQQAEA="))
|
||||
|
|
|
@ -460,9 +460,11 @@ function updateClock() {
|
|||
}
|
||||
|
||||
|
||||
// =Main Prog
|
||||
|
||||
// Read settings.
|
||||
let cfg = require('Storage').readJSON('bikespeedo.json',1)||{};
|
||||
|
||||
//###
|
||||
let cfg = {};
|
||||
cfg.spd = 1; // Multiplier for speed unit conversions. 0 = use the locale values for speed
|
||||
cfg.spd_unit = 'km/h'; // Displayed speed unit
|
||||
cfg.alt = 1; // Multiplier for altitude unit conversions. (feet:'0.3048')
|
||||
|
@ -472,8 +474,12 @@ cfg.dist_unit = 'km'; // Displayed distnce units
|
|||
cfg.modeA = 1;
|
||||
cfg.primSpd = 1; // 1 = Spd in primary, 0 = Spd in secondary
|
||||
|
||||
cfg.spdFilt = false;
|
||||
cfg.altFilt = false;
|
||||
cfg.altDiff = cfg.altDiff==undefined?100:cfg.altDiff;
|
||||
cfg.spdFilt = cfg.spdFilt==undefined?true:cfg.spdFilt;
|
||||
cfg.altFilt = cfg.altFilt==undefined?false:cfg.altFilt;
|
||||
// console.log("cfg.altDiff: " + cfg.altDiff);
|
||||
// console.log("cfg.spdFilt: " + cfg.spdFilt);
|
||||
// console.log("cfg.altFilt: " + cfg.altFilt);
|
||||
|
||||
if ( cfg.spdFilt ) var spdFilter = new KalmanFilter({R: 0.1 , Q: 1 });
|
||||
if ( cfg.altFilt ) var altFilter = new KalmanFilter({R: 0.01, Q: 2 });
|
||||
|
@ -489,7 +495,9 @@ function onGPSraw(nmea) {
|
|||
} }
|
||||
if(BANGLEJS2) Bangle.on('GPS-raw', onGPSraw);
|
||||
|
||||
function onPressure(dat) { altiBaro = dat.altitude.toFixed(0); }
|
||||
function onPressure(dat) {
|
||||
altiBaro = Number(dat.altitude.toFixed(0)) + Number(cfg.altDiff);
|
||||
}
|
||||
|
||||
Bangle.setBarometerPower(1); // needs some time...
|
||||
g.clearRect(0,screenYstart,screenW,screenH);
|
||||
|
@ -520,10 +528,10 @@ function Compass_tiltfixread(O,S){
|
|||
return psi;
|
||||
}
|
||||
var Compass_heading = 0;
|
||||
function Compass_newHeading(m,h){
|
||||
function Compass_newHeading(m,h){
|
||||
var s = Math.abs(m - h);
|
||||
var delta = (m>h)?1:-1;
|
||||
if (s>=180){s=360-s; delta = -delta;}
|
||||
if (s>=180){s=360-s; delta = -delta;}
|
||||
if (s<2) return h;
|
||||
var hd = h + delta*(1 + Math.round(s/5));
|
||||
if (hd<0) hd+=360;
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"id": "bikespeedo",
|
||||
"name": "Bike Speedometer (beta)",
|
||||
"shortName": "Bike Speedomet.",
|
||||
"version": "0.01",
|
||||
"shortName": "Bike Speedometer",
|
||||
"version": "0.02",
|
||||
"description": "Shows GPS speed, GPS heading, Compass heading, GPS altitude and Barometer altitude from internal sources",
|
||||
"icon": "app.png",
|
||||
"screenshots": [{"url":"Screenshot.png"}],
|
||||
|
@ -13,6 +13,8 @@
|
|||
"allow_emulator": true,
|
||||
"storage": [
|
||||
{"name":"bikespeedo.app.js","url":"app.js"},
|
||||
{"name":"bikespeedo.img","url":"app-icon.js","evaluate":true}
|
||||
]
|
||||
{"name":"bikespeedo.img","url":"app-icon.js","evaluate":true},
|
||||
{"name":"bikespeedo.settings.js","url":"settings.js"}
|
||||
],
|
||||
"data": [{"name":"bikespeedo.json"}]
|
||||
}
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
(function(back) {
|
||||
|
||||
let settings = require('Storage').readJSON('bikespeedo.json',1)||{};
|
||||
|
||||
function writeSettings() {
|
||||
require('Storage').write('bikespeedo.json',settings);
|
||||
}
|
||||
|
||||
const appMenu = {
|
||||
'': {'title': 'Bike Speedometer'},
|
||||
'< Back': back,
|
||||
'< Load Bike Speedometer': ()=>{load('bikespeedo.app.js');},
|
||||
'Barometer Altitude adjustment' : function() { E.showMenu(altdiffMenu); },
|
||||
'Kalman Filters' : function() { E.showMenu(kalMenu); }
|
||||
};
|
||||
|
||||
const altdiffMenu = {
|
||||
'': { 'title': 'Altitude adjustment' },
|
||||
'< Back': function() { E.showMenu(appMenu); },
|
||||
'Altitude delta': {
|
||||
value: settings.altDiff || 100,
|
||||
min: -200,
|
||||
max: 200,
|
||||
step: 10,
|
||||
onchange: v => {
|
||||
settings.altDiff = v;
|
||||
writeSettings(); }
|
||||
}
|
||||
};
|
||||
|
||||
const kalMenu = {
|
||||
'': {'title': 'Kalman Filters'},
|
||||
'< Back': function() { E.showMenu(appMenu); },
|
||||
'Speed' : {
|
||||
value : settings.spdFilt,
|
||||
format : v => v?"On":"Off",
|
||||
onchange : () => { settings.spdFilt = !settings.spdFilt; writeSettings(); }
|
||||
},
|
||||
'Altitude' : {
|
||||
value : settings.altFilt,
|
||||
format : v => v?"On":"Off",
|
||||
onchange : () => { settings.altFilt = !settings.altFilt; writeSettings(); }
|
||||
}
|
||||
};
|
||||
|
||||
E.showMenu(appMenu);
|
||||
|
||||
});
|
|
@ -4,3 +4,4 @@
|
|||
0.04: Add setting to switch color schemes. On Bangle 2 non-dithering colors will be used by default. Use localized names for months and days of the week (Language app needed).
|
||||
0.05: Update calendar weekend colors for start on Sunday
|
||||
0.06: Use larger font for dates
|
||||
0.07: Fix off-by-one-error on previous month
|
||||
|
|
|
@ -171,7 +171,7 @@ function drawCalendar(date) {
|
|||
let days = [];
|
||||
let nextMonthDay = 1;
|
||||
let thisMonthDay = 51;
|
||||
let prevMonthDay = monthMaxDayMap[month > 0 ? month - 1 : 11] - dowNorm;
|
||||
let prevMonthDay = monthMaxDayMap[month > 0 ? month - 1 : 11] - dowNorm + 1;
|
||||
for (let i = 0; i < colN * (rowN - 1) + 1; i++) {
|
||||
if (i < dowNorm) {
|
||||
days.push(prevMonthDay);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "calendar",
|
||||
"name": "Calendar",
|
||||
"version": "0.06",
|
||||
"version": "0.07",
|
||||
"description": "Simple calendar",
|
||||
"icon": "calendar.png",
|
||||
"screenshots": [{"url":"screenshot_calendar.png"}],
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
timezonedb.csv.zip
|
||||
TimeZoneDB.csv.zip
|
||||
country.csv
|
||||
zone.csv
|
||||
timezone.csv
|
||||
time_zone.csv
|
||||
database.sql
|
||||
readme.txt
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
0.01: first release
|
||||
0.02: RAM efficient version of `fourTwentyTz.js` (as suggested by @gfwilliams).
|
||||
0.03: `mkFourTwentyTz.js` now handles new timezonedb.com CSV format
|
||||
|
|
|
@ -1,33 +1,33 @@
|
|||
// Generated by mkFourTwentyTz.js
|
||||
// Wed Jan 12 2022 19:35:36 GMT+0200 (Israel Standard Time)
|
||||
// Data source: https://timezonedb.com/files/timezonedb.csv.zip
|
||||
// Sun Mar 27 2022 14:10:08 GMT+0300 (Israel Daylight Time)
|
||||
// Data source: https://timezonedb.com/files/TimeZoneDB.csv.zip
|
||||
exports.offsets = [1380,1320,1260,1200,1140,1080,1020,960,900,840,780,720,660,600,540,480,420,360,300,240,180,120,60,0];
|
||||
exports.timezones = function(offs) {
|
||||
switch (offs) {
|
||||
case 1380: return ["Cape Verde, Cabo Verde","Scoresbysund, Greenland","Azores, Portugal"];
|
||||
case 1320: return ["Noronha, Brazil","South Georgia, South Georgia and the South Sandwich Islands"];
|
||||
case 1260: return ["Palmer, Antarctica","Rothera, Antarctica","Buenos Aires, Argentina","Cordoba, Argentina","Salta, Argentina","Jujuy, Argentina","Tucuman, Argentina","Catamarca, Argentina","La Rioja, Argentina","San Juan, Argentina","Mendoza, Argentina","San Luis, Argentina","Rio Gallegos, Argentina","Ushuaia, Argentina","Belem, Brazil","Fortaleza, Brazil","Recife, Brazil","Araguaina, Brazil","Maceio, Brazil","Bahia, Brazil","Sao Paulo, Brazil","Santarem, Brazil","Santiago, Chile","Punta Arenas, Chile","Stanley, Falkland Islands (Malvinas)","Cayenne, French Guiana","Nuuk, Greenland","Miquelon, Saint Pierre and Miquelon","Asuncion, Paraguay","Paramaribo, Suriname","Montevideo, Uruguay"];
|
||||
case 1200: return ["Antigua, Antigua and Barbuda","Anguilla, Anguilla","Aruba, Aruba","Barbados, Barbados","St Barthelemy, Saint Barthélemy","Bermuda, Bermuda","La Paz, Bolivia (Plurinational State of)","Kralendijk, Bonaire, Sint Eustatius and Saba","Campo Grande, Brazil","Cuiaba, Brazil","Porto Velho, Brazil","Boa Vista, Brazil","Manaus, Brazil","Halifax, Canada","Glace Bay, Canada","Moncton, Canada","Goose Bay, Canada","Blanc-Sablon, Canada","Curacao, Curaçao","Dominica, Dominica","Santo Domingo, Dominican Republic","Grenada, Grenada","Thule, Greenland","Guadeloupe, Guadeloupe","Guyana, Guyana","St Kitts, Saint Kitts and Nevis","St Lucia, Saint Lucia","Marigot, Saint Martin (French part)","Martinique, Martinique","Montserrat, Montserrat","Puerto Rico, Puerto Rico","Lower Princes, Sint Maarten (Dutch part)","Port of_Spain, Trinidad and Tobago","St Vincent, Saint Vincent and the Grenadines","Caracas, Venezuela (Bolivarian Republic of)","Tortola, Virgin Islands (British)","St Thomas, Virgin Islands (U.S.)"];
|
||||
case 1140: return ["Eirunepe, Brazil","Rio Branco, Brazil","Nassau, Bahamas","Toronto, Canada","Nipigon, Canada","Thunder Bay, Canada","Iqaluit, Canada","Pangnirtung, Canada","Atikokan, Canada","Easter, Chile","Bogota, Colombia","Havana, Cuba","Guayaquil, Ecuador","Port-au-Prince, Haiti","Jamaica, Jamaica","Cayman, Cayman Islands","Cancun, Mexico","Panama, Panama","Lima, Peru","Grand Turk, Turks and Caicos Islands","New York, United States of America","Detroit, United States of America","Louisville, Kentucky","Monticello, Kentucky","Indianapolis, Indiana","Vincennes, Indiana","Winamac, Indiana","Marengo, Indiana","Petersburg, Indiana","Vevay, Indiana"];
|
||||
case 1080: return ["Belize, Belize","Winnipeg, Canada","Rainy River, Canada","Resolute, Canada","Rankin Inlet, Canada","Regina, Canada","Swift Current, Canada","Costa Rica, Costa Rica","Galapagos, Ecuador","Guatemala, Guatemala","Tegucigalpa, Honduras","Mexico City, Mexico","Merida, Mexico","Monterrey, Mexico","Matamoros, Mexico","Bahia Banderas, Mexico","Managua, Nicaragua","El Salvador, El Salvador","Chicago, United States of America","Tell City, Indiana","Knox, Indiana","Menominee, United States of America","Center, North Dakota","New_Salem, North Dakota","Beulah, North Dakota"];
|
||||
case 1020: return ["Edmonton, Canada","Cambridge Bay, Canada","Yellowknife, Canada","Inuvik, Canada","Creston, Canada","Dawson Creek, Canada","Fort Nelson, Canada","Whitehorse, Canada","Dawson, Canada","Mazatlan, Mexico","Chihuahua, Mexico","Ojinaga, Mexico","Hermosillo, Mexico","Denver, United States of America","Boise, United States of America","Phoenix, United States of America"];
|
||||
case 960: return ["Vancouver, Canada","Tijuana, Mexico","Pitcairn, Pitcairn","Los Angeles, United States of America"];
|
||||
case 900: return ["Gambier, French Polynesia","Anchorage, United States of America","Juneau, United States of America","Sitka, United States of America","Metlakatla, United States of America","Yakutat, United States of America","Nome, United States of America"];
|
||||
case 840: return ["Rarotonga, Cook Islands","Kiritimati, Kiribati","Tahiti, French Polynesia","Adak, United States of America","Honolulu, United States of America"];
|
||||
case 780: return ["McMurdo, Antarctica","Pago Pago, American Samoa","Fiji, Fiji","Kanton, Kiribati","Niue, Niue","Auckland, New Zealand","Fakaofo, Tokelau","Tongatapu, Tonga","Midway, United States Minor Outlying Islands","Apia, Samoa"];
|
||||
case 720: return ["Tarawa, Kiribati","Majuro, Marshall Islands","Kwajalein, Marshall Islands","Norfolk, Norfolk Island","Nauru, Nauru","Kamchatka, Russian Federation","Anadyr, Russian Federation","Funafuti, Tuvalu","Wake, United States Minor Outlying Islands","Wallis, Wallis and Futuna"];
|
||||
case 660: return ["Casey, Antarctica","Lord Howe, Australia","Macquarie, Australia","Hobart, Australia","Melbourne, Australia","Sydney, Australia","Pohnpei, Micronesia (Federated States of)","Kosrae, Micronesia (Federated States of)","Noumea, New Caledonia","Bougainville, Papua New Guinea","Magadan, Russian Federation","Sakhalin, Russian Federation","Srednekolymsk, Russian Federation","Guadalcanal, Solomon Islands","Efate, Vanuatu"];
|
||||
case 600: return ["DumontDUrville, Antarctica","Brisbane, Australia","Lindeman, Australia","Chuuk, Micronesia (Federated States of)","Guam, Guam","Saipan, Northern Mariana Islands","Port Moresby, Papua New Guinea","Vladivostok, Russian Federation","Ust-Nera, Russian Federation"];
|
||||
case 540: return ["Jayapura, Indonesia","Tokyo, Japan","Pyongyang, Korea (Democratic People's Republic of)","Seoul, Korea, Republic of","Palau, Palau","Chita, Russian Federation","Yakutsk, Russian Federation","Khandyga, Russian Federation","Dili, Timor-Leste"];
|
||||
case 1380: return ["Cape Verde, Cape Verde"];
|
||||
case 1320: return ["Noronha, Brazil","Nuuk, Greenland","South Georgia, South Georgia and the South Sandwich Islands","Miquelon, Saint Pierre and Miquelon"];
|
||||
case 1260: return ["Palmer, Antarctica","Rothera, Antarctica","Buenos Aires, Argentina","Cordoba, Argentina","Salta, Argentina","Jujuy, Argentina","Tucuman, Argentina","Catamarca, Argentina","La Rioja, Argentina","San Juan, Argentina","Mendoza, Argentina","San Luis, Argentina","Rio Gallegos, Argentina","Ushuaia, Argentina","Bermuda, Bermuda","Belem, Brazil","Fortaleza, Brazil","Recife, Brazil","Araguaina, Brazil","Maceio, Brazil","Bahia, Brazil","Sao Paulo, Brazil","Santarem, Brazil","Halifax, Canada","Glace Bay, Canada","Moncton, Canada","Goose Bay, Canada","Santiago, Chile","Punta Arenas, Chile","Stanley, Falkland Islands (Malvinas)","Cayenne, French Guiana","Thule, Greenland","Paramaribo, Suriname","Montevideo, Uruguay"];
|
||||
case 1200: return ["Antigua, Antigua and Barbuda","Anguilla, Anguilla","Aruba, Aruba","Barbados, Barbados","St Barthelemy, Saint Barthélemy","La Paz, Bolivia, Plurinational State of","Kralendijk, Bonaire, Sint Eustatius and Saba","Campo Grande, Brazil","Cuiaba, Brazil","Porto Velho, Brazil","Boa Vista, Brazil","Manaus, Brazil","Nassau, Bahamas","Blanc-Sablon, Canada","Toronto, Canada","Nipigon, Canada","Thunder Bay, Canada","Iqaluit, Canada","Pangnirtung, Canada","Havana, Cuba","Curacao, Curaçao","Dominica, Dominica","Santo Domingo, Dominican Republic","Grenada, Grenada","Guadeloupe, Guadeloupe","Guyana, Guyana","Port-au-Prince, Haiti","St Kitts, Saint Kitts and Nevis","St Lucia, Saint Lucia","Marigot, Saint Martin (French part)","Martinique, Martinique","Montserrat, Montserrat","Puerto Rico, Puerto Rico","Asuncion, Paraguay","Lower Princes, Sint Maarten (Dutch part)","Grand Turk, Turks and Caicos Islands","Port of_Spain, Trinidad and Tobago","New York, United States","Detroit, United States","Louisville, Kentucky","Monticello, Kentucky","Indianapolis, Indiana","Vincennes, Indiana","Winamac, Indiana","Marengo, Indiana","Petersburg, Indiana","Vevay, Indiana","St Vincent, Saint Vincent and the Grenadines","Caracas, Venezuela, Bolivarian Republic of","Tortola, Virgin Islands, British","St Thomas, Virgin Islands, U.S."];
|
||||
case 1140: return ["Eirunepe, Brazil","Rio Branco, Brazil","Atikokan, Canada","Winnipeg, Canada","Rainy River, Canada","Resolute, Canada","Rankin Inlet, Canada","Easter, Chile","Bogota, Colombia","Guayaquil, Ecuador","Jamaica, Jamaica","Cayman, Cayman Islands","Cancun, Mexico","Matamoros, Mexico","Panama, Panama","Lima, Peru","Chicago, United States","Tell City, Indiana","Knox, Indiana","Menominee, United States","Center, North Dakota","New_Salem, North Dakota","Beulah, North Dakota"];
|
||||
case 1080: return ["Belize, Belize","Regina, Canada","Swift Current, Canada","Edmonton, Canada","Cambridge Bay, Canada","Yellowknife, Canada","Inuvik, Canada","Costa Rica, Costa Rica","Galapagos, Ecuador","Guatemala, Guatemala","Tegucigalpa, Honduras","Mexico City, Mexico","Merida, Mexico","Monterrey, Mexico","Ojinaga, Mexico","Bahia Banderas, Mexico","Managua, Nicaragua","El Salvador, El Salvador","Denver, United States","Boise, United States"];
|
||||
case 1020: return ["Creston, Canada","Dawson Creek, Canada","Fort Nelson, Canada","Whitehorse, Canada","Dawson, Canada","Vancouver, Canada","Mazatlan, Mexico","Chihuahua, Mexico","Hermosillo, Mexico","Tijuana, Mexico","Phoenix, United States","Los Angeles, United States"];
|
||||
case 960: return ["Pitcairn, Pitcairn","Anchorage, United States","Juneau, United States","Sitka, United States","Metlakatla, United States","Yakutat, United States","Nome, United States"];
|
||||
case 900: return ["Gambier, French Polynesia","Adak, United States"];
|
||||
case 840: return ["Rarotonga, Cook Islands","Kiritimati, Kiribati","Tahiti, French Polynesia","Honolulu, United States"];
|
||||
case 780: return ["McMurdo, Antarctica","Pago Pago, American Samoa","Kanton, Kiribati","Niue, Niue","Auckland, New Zealand","Fakaofo, Tokelau","Tongatapu, Tonga","Midway, United States Minor Outlying Islands","Apia, Samoa"];
|
||||
case 720: return ["Fiji, Fiji","Tarawa, Kiribati","Majuro, Marshall Islands","Kwajalein, Marshall Islands","Norfolk, Norfolk Island","Nauru, Nauru","Kamchatka, Russian Federation","Anadyr, Russian Federation","Funafuti, Tuvalu","Wake, United States Minor Outlying Islands","Wallis, Wallis and Futuna"];
|
||||
case 660: return ["Casey, Antarctica","Lord Howe, Australia","Macquarie, Australia","Hobart, Australia","Melbourne, Australia","Sydney, Australia","Pohnpei, Micronesia, Federated States of","Kosrae, Micronesia, Federated States of","Noumea, New Caledonia","Bougainville, Papua New Guinea","Magadan, Russian Federation","Sakhalin, Russian Federation","Srednekolymsk, Russian Federation","Guadalcanal, Solomon Islands","Efate, Vanuatu"];
|
||||
case 600: return ["DumontDUrville, Antarctica","Brisbane, Australia","Lindeman, Australia","Chuuk, Micronesia, Federated States of","Guam, Guam","Saipan, Northern Mariana Islands","Port Moresby, Papua New Guinea","Vladivostok, Russian Federation","Ust-Nera, Russian Federation"];
|
||||
case 540: return ["Jayapura, Indonesia","Tokyo, Japan","Pyongyang, Korea, Democratic People's Republic of","Seoul, Korea, Republic of","Palau, Palau","Chita, Russian Federation","Yakutsk, Russian Federation","Khandyga, Russian Federation","Dili, Timor-Leste"];
|
||||
case 480: return ["Perth, Australia","Brunei, Brunei Darussalam","Shanghai, China","Hong Kong, Hong Kong","Makassar, Indonesia","Ulaanbaatar, Mongolia","Choibalsan, Mongolia","Macau, Macao","Kuala Lumpur, Malaysia","Kuching, Malaysia","Manila, Philippines","Irkutsk, Russian Federation","Singapore, Singapore","Taipei, Taiwan, Province of China"];
|
||||
case 420: return ["Davis, Antarctica","Christmas, Christmas Island","Jakarta, Indonesia","Pontianak, Indonesia","Phnom Penh, Cambodia","Vientiane, Lao People's Democratic Republic","Hovd, Mongolia","Novosibirsk, Russian Federation","Barnaul, Russian Federation","Tomsk, Russian Federation","Novokuznetsk, Russian Federation","Krasnoyarsk, Russian Federation","Bangkok, Thailand","Ho Chi_Minh, Viet Nam"];
|
||||
case 360: return ["Vostok, Antarctica","Dhaka, Bangladesh","Thimphu, Bhutan","Urumqi, China","Chagos, British Indian Ocean Territory","Bishkek, Kyrgyzstan","Almaty, Kazakhstan","Qostanay, Kazakhstan","Omsk, Russian Federation"];
|
||||
case 300: return ["Mawson, Antarctica","Qyzylorda, Kazakhstan","Aqtobe, Kazakhstan","Aqtau, Kazakhstan","Atyrau, Kazakhstan","Oral, Kazakhstan","Maldives, Maldives","Karachi, Pakistan","Yekaterinburg, Russian Federation","Kerguelen, French Southern Territories","Dushanbe, Tajikistan","Ashgabat, Turkmenistan","Samarkand, Uzbekistan","Tashkent, Uzbekistan"];
|
||||
case 240: return ["Dubai, United Arab Emirates","Yerevan, Armenia","Baku, Azerbaijan","Tbilisi, Georgia","Mauritius, Mauritius","Muscat, Oman","Reunion, Réunion","Astrakhan, Russian Federation","Saratov, Russian Federation","Ulyanovsk, Russian Federation","Samara, Russian Federation","Mahe, Seychelles"];
|
||||
case 180: return ["Syowa, Antarctica","Bahrain, Bahrain","Minsk, Belarus","Djibouti, Djibouti","Asmara, Eritrea","Addis Ababa, Ethiopia","Baghdad, Iraq","Nairobi, Kenya","Comoro, Comoros","Kuwait, Kuwait","Antananarivo, Madagascar","Qatar, Qatar","Moscow, Russian Federation","Simferopol, Ukraine","Kirov, Russian Federation","Volgograd, Russian Federation","Riyadh, Saudi Arabia","Mogadishu, Somalia","Istanbul, Turkey","Dar es_Salaam, Tanzania, United Republic of","Kampala, Uganda","Aden, Yemen","Mayotte, Mayotte"];
|
||||
case 120: return ["Mariehamn, Åland Islands","Sofia, Bulgaria","Bujumbura, Burundi","Gaborone, Botswana","Lubumbashi, Congo, Democratic Republic of the","Nicosia, Cyprus","Famagusta, Cyprus","Tallinn, Estonia","Cairo, Egypt","Helsinki, Finland","Athens, Greece","Jerusalem, Israel","Amman, Jordan","Beirut, Lebanon","Maseru, Lesotho","Vilnius, Lithuania","Riga, Latvia","Tripoli, Libya","Chisinau, Moldova, Republic of","Blantyre, Malawi","Maputo, Mozambique","Windhoek, Namibia","Gaza, Palestine, State of","Hebron, Palestine, State of","Bucharest, Romania","Kaliningrad, Russian Federation","Kigali, Rwanda","Khartoum, Sudan","Juba, South Sudan","Damascus, Syrian Arab Republic","Mbabane, Eswatini","Kiev, Ukraine","Uzhgorod, Ukraine","Zaporozhye, Ukraine","Johannesburg, South Africa","Lusaka, Zambia","Harare, Zimbabwe"];
|
||||
case 60: return ["Andorra, Andorra","Tirane, Albania","Luanda, Angola","Vienna, Austria","Sarajevo, Bosnia and Herzegovina","Brussels, Belgium","Porto-Novo, Benin","Kinshasa, Congo, Democratic Republic of the","Bangui, Central African Republic","Brazzaville, Congo","Zurich, Switzerland","Douala, Cameroon","Prague, Czechia","Berlin, Germany","Busingen, Germany","Copenhagen, Denmark","Algiers, Algeria","El Aaiun, Western Sahara","Madrid, Spain","Ceuta, Spain","Paris, France","Libreville, Gabon","Gibraltar, Gibraltar","Malabo, Equatorial Guinea","Zagreb, Croatia","Budapest, Hungary","Rome, Italy","Vaduz, Liechtenstein","Luxembourg, Luxembourg","Casablanca, Morocco","Monaco, Monaco","Podgorica, Montenegro","Skopje, North Macedonia","Malta, Malta","Niamey, Niger","Lagos, Nigeria","Amsterdam, Netherlands","Oslo, Norway","Warsaw, Poland","Belgrade, Serbia","Stockholm, Sweden","Ljubljana, Slovenia","Longyearbyen, Svalbard and Jan Mayen","Bratislava, Slovakia","San Marino, San Marino","Ndjamena, Chad","Tunis, Tunisia","Vatican, Holy See"];
|
||||
case 0: return ["Troll, Antarctica","Ouagadougou, Burkina Faso","Abidjan, Côte d'Ivoire","Canary, Spain","Faroe, Faroe Islands","London, United Kingdom of Great Britain and Northern Ireland","Guernsey, Guernsey","Accra, Ghana","Danmarkshavn, Greenland","Banjul, Gambia","Conakry, Guinea","Bissau, Guinea-Bissau","Dublin, Ireland","Isle of_Man, Isle of Man","Reykjavik, Iceland","Jersey, Jersey","Monrovia, Liberia","Bamako, Mali","Nouakchott, Mauritania","Lisbon, Portugal","Madeira, Portugal","St Helena, Saint Helena, Ascension and Tristan da Cunha","Freetown, Sierra Leone","Dakar, Senegal","Sao Tome, Sao Tome and Principe","Lome, Togo"];
|
||||
case 180: return ["Syowa, Antarctica","Mariehamn, Åland Islands","Sofia, Bulgaria","Bahrain, Bahrain","Minsk, Belarus","Nicosia, Cyprus","Famagusta, Cyprus","Djibouti, Djibouti","Tallinn, Estonia","Asmara, Eritrea","Addis Ababa, Ethiopia","Helsinki, Finland","Athens, Greece","Jerusalem, Israel","Baghdad, Iraq","Amman, Jordan","Nairobi, Kenya","Comoro, Comoros","Kuwait, Kuwait","Beirut, Lebanon","Vilnius, Lithuania","Riga, Latvia","Chisinau, Moldova, Republic of","Antananarivo, Madagascar","Gaza, Palestine, State of","Hebron, Palestine, State of","Qatar, Qatar","Bucharest, Romania","Moscow, Russian Federation","Simferopol, Ukraine","Kirov, Russian Federation","Volgograd, Russian Federation","Riyadh, Saudi Arabia","Mogadishu, Somalia","Damascus, Syrian Arab Republic","Istanbul, Turkey","Dar es_Salaam, Tanzania, United Republic of","Kiev, Ukraine","Uzhgorod, Ukraine","Zaporozhye, Ukraine","Kampala, Uganda","Aden, Yemen","Mayotte, Mayotte"];
|
||||
case 120: return ["Andorra, Andorra","Tirane, Albania","Troll, Antarctica","Vienna, Austria","Sarajevo, Bosnia and Herzegovina","Brussels, Belgium","Bujumbura, Burundi","Gaborone, Botswana","Lubumbashi, Congo, the Democratic Republic of the","Zurich, Switzerland","Prague, Czech Republic","Berlin, Germany","Busingen, Germany","Copenhagen, Denmark","Cairo, Egypt","Madrid, Spain","Ceuta, Spain","Paris, France","Gibraltar, Gibraltar","Zagreb, Croatia","Budapest, Hungary","Rome, Italy","Vaduz, Liechtenstein","Maseru, Lesotho","Luxembourg, Luxembourg","Tripoli, Libya","Monaco, Monaco","Podgorica, Montenegro","Skopje, Macedonia, the Former Yugoslav Republic of","Malta, Malta","Blantyre, Malawi","Maputo, Mozambique","Windhoek, Namibia","Amsterdam, Netherlands","Oslo, Norway","Warsaw, Poland","Belgrade, Serbia","Kaliningrad, Russian Federation","Kigali, Rwanda","Khartoum, Sudan","Stockholm, Sweden","Ljubljana, Slovenia","Longyearbyen, Svalbard and Jan Mayen","Bratislava, Slovakia","San Marino, San Marino","Juba, South Sudan","Mbabane, Swaziland","Vatican, Holy See (Vatican City State)","Johannesburg, South Africa","Lusaka, Zambia","Harare, Zimbabwe"];
|
||||
case 60: return ["Luanda, Angola","Porto-Novo, Benin","Kinshasa, Congo, the Democratic Republic of the","Bangui, Central African Republic","Brazzaville, Congo","Douala, Cameroon","Algiers, Algeria","Canary, Spain","Faroe, Faroe Islands","Libreville, Gabon","London, United Kingdom","Guernsey, Guernsey","Malabo, Equatorial Guinea","Dublin, Ireland","Isle of_Man, Isle of Man","Jersey, Jersey","Niamey, Niger","Lagos, Nigeria","Lisbon, Portugal","Madeira, Portugal","Ndjamena, Chad","Tunis, Tunisia"];
|
||||
case 0: return ["Ouagadougou, Burkina Faso","Abidjan, Côte d'Ivoire","El Aaiun, Western Sahara","Accra, Ghana","Danmarkshavn, Greenland","Scoresbysund, Greenland","Banjul, Gambia","Conakry, Guinea","Bissau, Guinea-Bissau","Reykjavik, Iceland","Monrovia, Liberia","Casablanca, Morocco","Bamako, Mali","Nouakchott, Mauritania","Azores, Portugal","St Helena, Saint Helena, Ascension and Tristan da Cunha","Freetown, Sierra Leone","Dakar, Senegal","Sao Tome, Sao Tome and Principe","Lome, Togo"];
|
||||
default: return ["Houston, we have a bug."];
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "ftclock",
|
||||
"name": "Four Twenty Clock",
|
||||
"version": "0.02",
|
||||
"version": "0.03",
|
||||
"description": "A clock that tells when and where it's going to be 4:20 next",
|
||||
"icon": "app.png",
|
||||
"screenshots": [{"url":"screenshot.png"}, {"url":"screenshot1.png"}],
|
||||
|
|
|
@ -4,7 +4,7 @@ let csv = require('csv');
|
|||
let countries = {},
|
||||
zones = {},
|
||||
offsdict = {},
|
||||
now = Date.now(); // we need this to find zone's current DST state
|
||||
now = Date.now()/1000; // we need this to find zone's current DST state
|
||||
|
||||
function handleWrite(err,bytes) {
|
||||
if (err) {
|
||||
|
@ -19,10 +19,10 @@ fs.createReadStream(__dirname+'/country.csv')
|
|||
countries[r[0]] = r[1];
|
||||
})
|
||||
.on('end', () => {
|
||||
fs.createReadStream(__dirname+'/zone.csv')
|
||||
fs.createReadStream(__dirname+'/time_zone.csv')
|
||||
.pipe(csv.parse())
|
||||
.on('data', (r) => {
|
||||
let parts = r[2].replace('_',' ').split('/');
|
||||
let parts = r[0].replace('_',' ').split('/');
|
||||
let city = parts[parts.length-1];
|
||||
let country ='';
|
||||
if (parts.length>2) { // e.g. America/North_Dakota/New_Salem
|
||||
|
@ -30,59 +30,51 @@ fs.createReadStream(__dirname+'/country.csv')
|
|||
} else {
|
||||
country = countries[r[1]]; // e.g. United States
|
||||
}
|
||||
zones[parseInt(r[0])] = {"name": `${city}, ${country}`};
|
||||
zone = zones[r[0]] || { "name": `${city}, ${country}` };
|
||||
let starttime = parseInt(r[3] || "0"), // Bugger. They're feeding us blanks for UTC now
|
||||
offs = parseInt(r[4]);
|
||||
if (offs<0) {
|
||||
offs += 60*60*24;
|
||||
}
|
||||
if (starttime<now && (!("starttime" in zone) || zone.starttime<starttime)) {
|
||||
zone.starttime = starttime;
|
||||
zone.offs = Math.floor(offs/60);
|
||||
}
|
||||
zones[r[0]] = zone;
|
||||
})
|
||||
.on('end', () => {
|
||||
fs.createReadStream(__dirname+'/timezone.csv')
|
||||
.pipe(csv.parse())
|
||||
.on('data', (r) => {
|
||||
code = parseInt(r[0]);
|
||||
if (!(code in zones)) return;
|
||||
starttime = parseInt(r[2] || "0"); // Bugger. They're feeding us blanks for UTC now
|
||||
offs = parseInt(r[3]);
|
||||
if (offs<0) {
|
||||
offs += 60*60*24;
|
||||
}
|
||||
zone = zones[code];
|
||||
if (starttime<now && (!("starttime" in zone) || zone.starttime<starttime)) {
|
||||
zone.starttime = starttime;
|
||||
zone.offs = Math.floor(offs/60);
|
||||
}
|
||||
})
|
||||
.on('end', () => {
|
||||
for (z in zones) {
|
||||
zone = zones[z];
|
||||
if (zone.offs%60) continue; // One a dem funky timezones. Ignore.
|
||||
zonelist = offsdict[zone.offs] || [];
|
||||
zonelist.push(zone.name);
|
||||
offsdict[zone.offs] = zonelist;
|
||||
}
|
||||
offsets = [];
|
||||
for (o in offsdict) {
|
||||
offsets.unshift(parseInt(o));
|
||||
}
|
||||
fs.open("fourTwentyTz.js","w", (err, fd) => {
|
||||
if (err) {
|
||||
console.log("Can't open output file");
|
||||
return;
|
||||
}
|
||||
fs.write(fd, "// Generated by mkFourTwentyTz.js\n", handleWrite);
|
||||
fs.write(fd, `// ${Date()}\n`, handleWrite);
|
||||
fs.write(fd, "// Data source: https://timezonedb.com/files/timezonedb.csv.zip\n", handleWrite);
|
||||
fs.write(fd, "exports.offsets = ", handleWrite);
|
||||
fs.write(fd, JSON.stringify(offsets), handleWrite);
|
||||
fs.write(fd, ";\n", handleWrite);
|
||||
fs.write(fd, "exports.timezones = function(offs) {\n", handleWrite);
|
||||
fs.write(fd, " switch (offs) {\n", handleWrite);
|
||||
for (i=0; i<offsets.length; i++) {
|
||||
let o = offsets[i].toString();
|
||||
fs.write(fd, ` case ${o}: return ${JSON.stringify(offsdict[o])};\n`, handleWrite);
|
||||
}
|
||||
fs.write(fd, " default: return [\"Houston, we have a bug.\"];\n", handleWrite);
|
||||
fs.write(fd, " }\n", handleWrite);
|
||||
fs.write(fd, "};\n", handleWrite);
|
||||
console.log('Done.');
|
||||
});
|
||||
})
|
||||
})
|
||||
for (z in zones) {
|
||||
zone = zones[z];
|
||||
if (zone.offs%60) continue; // One a dem funky timezones. Ignore.
|
||||
zonelist = offsdict[zone.offs] || [];
|
||||
zonelist.push(zone.name);
|
||||
offsdict[zone.offs] = zonelist;
|
||||
}
|
||||
offsets = [];
|
||||
for (o in offsdict) {
|
||||
offsets.unshift(parseInt(o));
|
||||
}
|
||||
fs.open("fourTwentyTz.js","w", (err, fd) => {
|
||||
if (err) {
|
||||
console.log("Can't open output file");
|
||||
return;
|
||||
}
|
||||
fs.write(fd, "// Generated by mkFourTwentyTz.js\n", handleWrite);
|
||||
fs.write(fd, `// ${Date()}\n`, handleWrite);
|
||||
fs.write(fd, "// Data source: https://timezonedb.com/files/TimeZoneDB.csv.zip\n", handleWrite);
|
||||
fs.write(fd, "exports.offsets = ", handleWrite);
|
||||
fs.write(fd, JSON.stringify(offsets), handleWrite);
|
||||
fs.write(fd, ";\n", handleWrite);
|
||||
fs.write(fd, "exports.timezones = function(offs) {\n", handleWrite);
|
||||
fs.write(fd, " switch (offs) {\n", handleWrite);
|
||||
for (i=0; i<offsets.length; i++) {
|
||||
let o = offsets[i].toString();
|
||||
fs.write(fd, ` case ${o}: return ${JSON.stringify(offsdict[o])};\n`, handleWrite);
|
||||
}
|
||||
fs.write(fd, " default: return [\"Houston, we have a bug.\"];\n", handleWrite);
|
||||
fs.write(fd, " }\n", handleWrite);
|
||||
fs.write(fd, "};\n", handleWrite);
|
||||
console.log('Done.');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -39,3 +39,4 @@
|
|||
0.24: Remove left-over debug statement
|
||||
0.25: Fix widget memory usage issues if message received and watch repeatedly calls Bangle.drawWidgets (fix #1550)
|
||||
0.26: Setting to auto-open music
|
||||
0.27: Add 'mark all read' option to popup menu (fix #1624)
|
||||
|
|
|
@ -302,6 +302,11 @@ function showMessageSettings(msg) {
|
|||
saveMessages();
|
||||
checkMessages({clockIfNoMsg:0,clockIfAllRead:0,showMsgIfUnread:0,openMusic:0});
|
||||
},
|
||||
/*LANG*/"Mark all read" : () => {
|
||||
MESSAGES.forEach(msg => msg.new = false);
|
||||
saveMessages();
|
||||
checkMessages({clockIfNoMsg:0,clockIfAllRead:0,showMsgIfUnread:0,openMusic:0});
|
||||
},
|
||||
/*LANG*/"Delete all messages" : () => {
|
||||
E.showPrompt(/*LANG*/"Are you sure?", {title:/*LANG*/"Delete All Messages"}).then(isYes => {
|
||||
if (isYes) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "messages",
|
||||
"name": "Messages",
|
||||
"version": "0.26",
|
||||
"version": "0.27",
|
||||
"description": "App to display notifications from iOS and Gadgetbridge/Android",
|
||||
"icon": "app.png",
|
||||
"type": "app",
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
## Magic the Gathering Watch Face
|
||||
Magic the Gathering themed watch face. Embrace the inner wizzard. Dispay any of the different types of mana on your watch. Which color are you devoted to today?
|
||||
|
||||
### Touch Enabled
|
||||
Simply touch the screen on the sides to switch the mana colors
|
|
@ -0,0 +1 @@
|
|||
E.toArrayBuffer(atob("MDCDAf/////////////////////////////////+AAAP/////////////////wAAAAAAAB+v////x//////+AAAAAAAAAAAv///////////wAAAAAAAAAAAhxxxxx/////+OAAAAAAAAAAAP//////////wAAAAAAAAAABxx/////////wAOAAAAAAAAAAAAB////////wABwAAAAAAAAAAAAB//////wAAAOAAAAAAAAAAAAB//////wAAAAAAAAAAAAAAAAB/////+AAAAAAAAAAAAAAAAAAP////wAAAAAAAAAAAAAAAAAAB////+AAAAAAAAAAAAAAAAAAAP///wAAAAAAAAAAAAAAAAAAAP///wAAAOOAAAAAAAAAP+AAAP///wABx///wAAAAAB////wAB//+AAB////+AAAAAP////wAP///wAB/////wAAAB/////wAB//+AAP/////wAAAB/////+AB///wAP/////wAAAB/////wAB//+AAP/////wAAAB/////+AB///wABxx//wAAAABx///xwAB///wAAAAAAAAAAAAAAAAAAAP////wAAAAAAAABwAAAAAAAB/////+AAAAAAAOBwAAAAAAAP///////wAAAABwBwAAAAABx////wAAAAAAAAAOB+AAAAAAAAAP/x///////wBwBwAB///////x/////////wB+P+AP///////x/x/x//x//wBxxwAB/x/xx//x///+Px+P/wAAAAAP/wOPwP/x/x/wPx/x/wAAAAAB/x//x//x///+OB+P/wAAAAAP/+P+B//x/x/wPwAB/wAAAAAB/x/+B//x///+P/wP/wAAOAAP/+P+P//x/x/wP/x//xwAAAAB/x/xxx/x///+P+P//xwAOAOP/+OOAP/x/x///x///xwAP/+B///////x////+P///x+B//+P///////x/xxxxxxxxx/////xxxxxxxxx//////////////////////////xx///xx/x/x///////x/////wP+P+B+P/wPx+P+OP+OP////xwAPxwB//x/xxx+B//xx////+OOPwP///+OBwAOOP+Px/////x///////x////x///x///////////////////////////w=="))
|
File diff suppressed because one or more lines are too long
Binary file not shown.
After Width: | Height: | Size: 3.3 KiB |
Binary file not shown.
After Width: | Height: | Size: 2.2 KiB |
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"id": "mtgwatchface",
|
||||
"name": "MTG Watchface",
|
||||
"shortName": "Magic the Gathering Watch Face",
|
||||
"version": "1v03",
|
||||
"description": "Magic the Gathering themed watch face. Embrace the inner wizzard. Dispay any of the different types of mana on your watch. Which color are you devoted to today? ",
|
||||
"icon": "icon.png",
|
||||
"screenshots": [
|
||||
{"url": "black.png"}
|
||||
],
|
||||
"tags": "clock",
|
||||
"type": "clock",
|
||||
"supports": [
|
||||
"BANGLEJS2"
|
||||
],
|
||||
"readme": "README.md",
|
||||
"allow_emulator": true,
|
||||
"storage": [
|
||||
{
|
||||
"name": "mtgwatchface.app.js",
|
||||
"url": "app.js"
|
||||
},
|
||||
{
|
||||
"name": "mtgwatchface.img",
|
||||
"url": "app-icon.js",
|
||||
"evaluate":true
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
0.01: Initial version
|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("kMigILIgPAAYMD/ADBwcGhkAwM5wcA/+2//Av/Rn/giFoyFggkUrFggEKlAkCiApCx+AAYNGoADBkU4AYMQj4DBvEICANkAoIPBgE2B4MAiMAH4MAwECAYNALYUgBIISCHYMYAoQWBAIMEgAYBAIMBwEDDQNgDwUf/4eBg4DCAA4"))
|
|
@ -0,0 +1,120 @@
|
|||
var settings = Object.assign(require("Storage").readJSON("quicklaunch.json", true) || {});
|
||||
|
||||
var apps = require("Storage").list(/\.info$/).map(app=>{var a=require("Storage").readJSON(app,1);return a&&{name:a.name,type:a.type,sortorder:a.sortorder,src:a.src};}).filter(app=>app && (app.type=="app" || app.type=="launch" || app.type=="clock" || !app.type));
|
||||
|
||||
apps.sort((a,b)=>{
|
||||
var n=(0|a.sortorder)-(0|b.sortorder);
|
||||
if (n) return n; // do sortorder first
|
||||
if (a.name<b.name) return -1;
|
||||
if (a.name>b.name) return 1;
|
||||
return 0;
|
||||
});
|
||||
|
||||
function save(key, value) {
|
||||
settings[key] = value;
|
||||
require("Storage").write("quicklaunch.json",settings);
|
||||
}
|
||||
|
||||
// Quick Launch menu
|
||||
function showMainMenu() {
|
||||
var mainmenu = {
|
||||
"" : { "title" : "Quick Launch" },
|
||||
"< Back" : ()=>{load();}
|
||||
};
|
||||
|
||||
//List all selected apps
|
||||
mainmenu["Left: "+settings.leftapp.name] = function() { E.showMenu(leftmenu); };
|
||||
mainmenu["Right: "+settings.rightapp.name] = function() { E.showMenu(rightmenu); };
|
||||
mainmenu["Up: "+settings.upapp.name] = function() { E.showMenu(upmenu); };
|
||||
mainmenu["Down: "+settings.downapp.name] = function() { E.showMenu(downmenu); };
|
||||
mainmenu["Tap: "+settings.tapapp.name] = function() { E.showMenu(tapmenu); };
|
||||
|
||||
return E.showMenu(mainmenu);
|
||||
}
|
||||
|
||||
//Left swipe menu
|
||||
var leftmenu = {
|
||||
"" : { "title" : "Left Swipe" },
|
||||
"< Back" : showMainMenu
|
||||
};
|
||||
|
||||
leftmenu["(none)"] = function() {
|
||||
save("leftapp", {"name":"(none)"});
|
||||
showMainMenu();
|
||||
};
|
||||
apps.forEach((a)=>{
|
||||
leftmenu[a.name] = function() {
|
||||
save("leftapp", a);
|
||||
showMainMenu();
|
||||
};
|
||||
});
|
||||
|
||||
//Right swipe menu
|
||||
var rightmenu = {
|
||||
"" : { "title" : "Right Swipe" },
|
||||
"< Back" : showMainMenu
|
||||
};
|
||||
|
||||
rightmenu["(none)"] = function() {
|
||||
save("rightapp", {"name":"(none)"});
|
||||
showMainMenu();
|
||||
};
|
||||
apps.forEach((a)=>{
|
||||
rightmenu[a.name] = function() {
|
||||
save("rightapp", a);
|
||||
showMainMenu();
|
||||
};
|
||||
});
|
||||
|
||||
//Up swipe menu
|
||||
var upmenu = {
|
||||
"" : { "title" : "Up Swipe" },
|
||||
"< Back" : showMainMenu
|
||||
};
|
||||
|
||||
upmenu["(none)"] = function() {
|
||||
save("upapp", {"name":"(none)"});
|
||||
showMainMenu();
|
||||
};
|
||||
apps.forEach((a)=>{
|
||||
upmenu[a.name] = function() {
|
||||
save("upapp", a);
|
||||
showMainMenu();
|
||||
};
|
||||
});
|
||||
|
||||
//Down swipe menu
|
||||
var downmenu = {
|
||||
"" : { "title" : "Down Swipe" },
|
||||
"< Back" : showMainMenu
|
||||
};
|
||||
|
||||
downmenu["(none)"] = function() {
|
||||
save("downapp", {"name":"(none)"});
|
||||
showMainMenu();
|
||||
};
|
||||
apps.forEach((a)=>{
|
||||
downmenu[a.name] = function() {
|
||||
save("downapp", a);
|
||||
showMainMenu();
|
||||
};
|
||||
});
|
||||
|
||||
//Tap menu
|
||||
var tapmenu = {
|
||||
"" : { "title" : "Tap" },
|
||||
"< Back" : showMainMenu
|
||||
};
|
||||
|
||||
tapmenu["(none)"] = function() {
|
||||
save("tapapp", {"name":"(none)"});
|
||||
showMainMenu();
|
||||
};
|
||||
apps.forEach((a)=>{
|
||||
tapmenu[a.name] = function() {
|
||||
save("tapapp", a);
|
||||
showMainMenu();
|
||||
};
|
||||
});
|
||||
|
||||
showMainMenu();
|
Binary file not shown.
After Width: | Height: | Size: 321 B |
|
@ -0,0 +1,67 @@
|
|||
(function() {
|
||||
var settings = Object.assign(require("Storage").readJSON("quicklaunch.json", true) || {});
|
||||
|
||||
//list all sources
|
||||
var apps = require("Storage").list(/\.info$/).map(app=>{var a=require("Storage").readJSON(app,1);return a&&{src:a.src};});
|
||||
|
||||
//populate empty app list
|
||||
|
||||
if (!settings.leftapp) {
|
||||
settings["leftapp"] = {"name":"(none)"};
|
||||
require("Storage").write("quicklaunch.json",settings);
|
||||
}
|
||||
if (!settings.rightapp) {
|
||||
settings["rightapp"] = {"name":"(none)"};
|
||||
require("Storage").write("quicklaunch.json",settings);
|
||||
}
|
||||
if (!settings.upapp) {
|
||||
settings["upapp"] = {"name":"(none)"};
|
||||
require("Storage").write("quicklaunch.json",settings);
|
||||
}
|
||||
if (!settings.downapp) {
|
||||
settings["downapp"] = {"name":"(none)"};
|
||||
require("Storage").write("quicklaunch.json",settings);
|
||||
}
|
||||
if (!settings.tapapp) {
|
||||
settings["tapapp"] = {"name":"(none)"};
|
||||
require("Storage").write("quicklaunch.json",settings);
|
||||
}
|
||||
|
||||
//activate on clock faces
|
||||
var sui = Bangle.setUI;
|
||||
Bangle.setUI = function(mode, cb) {
|
||||
sui(mode,cb);
|
||||
if(!mode) return;
|
||||
if ("object"==typeof mode) mode = mode.mode;
|
||||
if (!mode.startsWith("clock")) return;
|
||||
|
||||
function tap() {
|
||||
//tap, check if source exists, launch
|
||||
if ((settings.tapapp.src) && apps.some(e => e.src === settings.tapapp.src)) load (settings.tapapp.src);
|
||||
}
|
||||
|
||||
let drag;
|
||||
let e;
|
||||
|
||||
Bangle.on("touch",tap);
|
||||
Bangle.on("drag", e => {
|
||||
if (!drag) { // start dragging
|
||||
drag = {x: e.x, y: e.y};
|
||||
} else if (!e.b) { // released
|
||||
const dx = e.x-drag.x, dy = e.y-drag.y;
|
||||
drag = null;
|
||||
//horizontal swipes, check if source exists, launch
|
||||
if (Math.abs(dx)>Math.abs(dy)+10) {
|
||||
if ((settings.leftapp.src) && apps.some(e => e.src === settings.leftapp.src) && dx<0) load(settings.leftapp.src);
|
||||
if ((settings.rightapp.src) && apps.some(e => e.src === settings.rightapp.src) && dx>0) load(settings.rightapp.src);
|
||||
}
|
||||
//vertical swipes, check if source exists, launch
|
||||
else if (Math.abs(dy)>Math.abs(dx)+10) {
|
||||
if ((settings.upapp.src) && apps.some(e => e.src === settings.upapp.src) && dy<0) load(settings.upapp.src);
|
||||
if ((settings.downapp.src) && apps.some(e => e.src === settings.downapp.src) && dy>0) load(settings.downapp.src);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
};
|
||||
})();
|
|
@ -0,0 +1,14 @@
|
|||
{ "id": "quicklaunch",
|
||||
"name": "Quick Launch",
|
||||
"icon": "app.png",
|
||||
"version":"0.01",
|
||||
"description": "Tap or swipe left/right/up/down on your clock face to launch up to five apps of your choice.",
|
||||
"tags": "tools, system",
|
||||
"supports": ["BANGLEJS2"],
|
||||
"storage": [
|
||||
{"name":"quicklaunch.app.js","url":"app.js"},
|
||||
{"name":"quicklaunch.boot.js","url":"boot.js"},
|
||||
{"name":"quicklaunch.img","url":"app-icon.js","evaluate":true}
|
||||
],
|
||||
"data": [{"name":"quicklaunch.json"}]
|
||||
}
|
|
@ -9,4 +9,5 @@
|
|||
0.08: Added support for notifications from exstats. Support all stats from exstats
|
||||
0.09: Fix broken start/stop if recording not enabled (fix #1561)
|
||||
0.10: Don't allow the same setting to be chosen for 2 boxes (fix #1578)
|
||||
0.11: Notifications fixes
|
||||
0.11: Notifications fixes
|
||||
0.12: Fix for recorder not stopping at end of run. Bug introduced in 0.11
|
|
@ -59,7 +59,7 @@ function onStartStop() {
|
|||
layout.render();
|
||||
})
|
||||
);
|
||||
} else if (!settings.record && WIDGETS["recorder"]) {
|
||||
} else {
|
||||
prepPromises.push(
|
||||
WIDGETS["recorder"].setRecording(false)
|
||||
);
|
||||
|
@ -68,7 +68,7 @@ function onStartStop() {
|
|||
|
||||
if (!prepPromises.length) // fix for Promise.all bug in 2v12
|
||||
prepPromises.push(Promise.resolve());
|
||||
|
||||
|
||||
Promise.all(prepPromises)
|
||||
.then(() => {
|
||||
if (running) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{ "id": "run",
|
||||
"name": "Run",
|
||||
"version":"0.11",
|
||||
"version":"0.12",
|
||||
"description": "Displays distance, time, steps, cadence, pace and more for runners.",
|
||||
"icon": "app.png",
|
||||
"tags": "run,running,fitness,outdoors,gps",
|
||||
|
|
|
@ -91,7 +91,7 @@
|
|||
];
|
||||
notificationsMenu[/*LANG*/"Dist Pattern"] = {
|
||||
value: Math.max(0,vibTimes.findIndex((p) => JSON.stringify(p) === JSON.stringify(settings.notify.dist.notifications))),
|
||||
min: 0, max: vibTimes.length,
|
||||
min: 0, max: vibTimes.length - 1,
|
||||
format: v => vibPatterns[v]||/*LANG*/"Off",
|
||||
onchange: v => {
|
||||
settings.notify.dist.notifications = vibTimes[v];
|
||||
|
@ -101,7 +101,7 @@
|
|||
}
|
||||
notificationsMenu[/*LANG*/"Step Pattern"] = {
|
||||
value: Math.max(0,vibTimes.findIndex((p) => JSON.stringify(p) === JSON.stringify(settings.notify.step.notifications))),
|
||||
min: 0, max: vibTimes.length,
|
||||
min: 0, max: vibTimes.length - 1,
|
||||
format: v => vibPatterns[v]||/*LANG*/"Off",
|
||||
onchange: v => {
|
||||
settings.notify.step.notifications = vibTimes[v];
|
||||
|
@ -111,7 +111,7 @@
|
|||
}
|
||||
notificationsMenu[/*LANG*/"Time Pattern"] = {
|
||||
value: Math.max(0,vibTimes.findIndex((p) => JSON.stringify(p) === JSON.stringify(settings.notify.time.notifications))),
|
||||
min: 0, max: vibTimes.length,
|
||||
min: 0, max: vibTimes.length - 1,
|
||||
format: v => vibPatterns[v]||/*LANG*/"Off",
|
||||
onchange: v => {
|
||||
settings.notify.time.notifications = vibTimes[v];
|
||||
|
|
|
@ -2,39 +2,63 @@ Todo List
|
|||
========
|
||||
|
||||
This is a simple Todo List application.
|
||||
The content is loaded from a JSON file.
|
||||
A task can be marked as completed or uncompleted.
|
||||
|
||||

|
||||
|
||||
The content is loaded from a JSON file.
|
||||
You can mark a task as completed.
|
||||
Once installed, the list can be modified via the `Download data from app` icon in the [Bangle.js App Store](https://banglejs.com/apps/) (TodoList app).
|
||||
|
||||

|
||||
|
||||
|
||||
JSON file content example:
|
||||
```javascript
|
||||
[
|
||||
{
|
||||
name: "Pro",
|
||||
children: [
|
||||
"name": "Pro",
|
||||
"children": [
|
||||
{
|
||||
name: "Read doc",
|
||||
done: true,
|
||||
children: [],
|
||||
"name": "Read doc",
|
||||
"done": true,
|
||||
"children": []
|
||||
}
|
||||
],
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Pers",
|
||||
children: [
|
||||
"name": "Pers",
|
||||
"children": [
|
||||
{
|
||||
name: "Grocery",
|
||||
children: [
|
||||
{ name: "Milk", done: false, children: [] },
|
||||
{ name: "Eggs", done: false, children: [] },
|
||||
{ name: "Cheese", done: false, children: [] },
|
||||
],
|
||||
"name": "Grocery",
|
||||
"children": [
|
||||
{
|
||||
"name": "Milk",
|
||||
"done": false,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"name": "Eggs",
|
||||
"done": false,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"name": "Cheese",
|
||||
"done": false,
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{ name: "Workout", done: false, children: [] },
|
||||
{ name: "Learn Rust", done: false, children: [] },
|
||||
],
|
||||
},
|
||||
{
|
||||
"name": "Workout",
|
||||
"done": false,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"name": "Learn Rust",
|
||||
"done": false,
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
```
|
|
@ -0,0 +1,135 @@
|
|||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="../../css/spectre.min.css" />
|
||||
|
||||
<style type="text/css">
|
||||
.alert {
|
||||
padding: 20px;
|
||||
background-color: #f44336; /* Red */
|
||||
color: white;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="info"></div>
|
||||
|
||||
<button id="btnReload" class="btn btn-primary">Reload from watch</button>
|
||||
<button id="btnUpload" class="btn btn-primary">Upload to watch</button>
|
||||
<button id="btnDownload" class="btn btn-primary">Download</button>
|
||||
|
||||
<pre id="todos" contenteditable></pre>
|
||||
|
||||
<script src="../../core/lib/interface.js"></script>
|
||||
<script>
|
||||
const fileTodoList = "todolist.json";
|
||||
|
||||
function errorFormat() {
|
||||
var date = new Date();
|
||||
var error =
|
||||
'<p class="alert">' +
|
||||
date.toUTCString() +
|
||||
" : Wrong format, it should be JSON" +
|
||||
"</p>";
|
||||
return error;
|
||||
}
|
||||
|
||||
function getEditableContent() {
|
||||
return document.getElementById("todos").innerHTML.replace(/<[^>]*>/g, '');;
|
||||
}
|
||||
|
||||
function isJsonString(str) {
|
||||
try {
|
||||
JSON.parse(str);
|
||||
} catch (e) {
|
||||
console.log(str)
|
||||
console.log(e)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function uploadFile(fileid, contents) {
|
||||
Puck.write(
|
||||
`\x10(function() {
|
||||
require("Storage").write("${fileid}",'${contents}');
|
||||
Bluetooth.print("OK");
|
||||
})()\n`,
|
||||
(ret) => {
|
||||
console.log("uploadFile", ret);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/* Load settings JSON file from the watch.
|
||||
*/
|
||||
function loadTodos() {
|
||||
document.getElementById("info").innerHTML = "";
|
||||
Util.showModal("Loading...");
|
||||
Puck.eval(`require('Storage').readJSON("${fileTodoList}")`, (data) => {
|
||||
document.getElementById("todos").innerHTML = JSON.stringify(
|
||||
data,
|
||||
null,
|
||||
2
|
||||
);
|
||||
Util.hideModal();
|
||||
});
|
||||
}
|
||||
/* Save settings as a JSON file on the watch.
|
||||
*/
|
||||
function uploadTodos() {
|
||||
document.getElementById("info").innerHTML = "";
|
||||
Util.showModal("Uploading...");
|
||||
let jsonTodos = getEditableContent();
|
||||
if (isJsonString(jsonTodos)) {
|
||||
let shortJsonTodos = JSON.stringify(JSON.parse(jsonTodos));
|
||||
uploadFile(fileTodoList, shortJsonTodos);
|
||||
} else {
|
||||
document.getElementById("info").innerHTML = errorFormat();
|
||||
}
|
||||
Util.hideModal();
|
||||
}
|
||||
|
||||
function downloadTodos() {
|
||||
document.getElementById("info").innerHTML = "";
|
||||
Util.showModal("Downloading...");
|
||||
let jsonTodos = getEditableContent();
|
||||
if (isJsonString(jsonTodos)) {
|
||||
var a = document.createElement("a"),
|
||||
file = new Blob([jsonTodos], { type: "application/json" });
|
||||
var url = URL.createObjectURL(file);
|
||||
a.href = url;
|
||||
a.download = fileTodoList;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
setTimeout(function () {
|
||||
document.body.removeChild(a);
|
||||
window.URL.revokeObjectURL(url);
|
||||
}, 0);
|
||||
} else {
|
||||
document.getElementById("info").innerHTML = errorFormat();
|
||||
}
|
||||
Util.hideModal();
|
||||
}
|
||||
|
||||
document
|
||||
.getElementById("btnUpload")
|
||||
.addEventListener("click", function () {
|
||||
uploadTodos();
|
||||
});
|
||||
document
|
||||
.getElementById("btnDownload")
|
||||
.addEventListener("click", function () {
|
||||
downloadTodos();
|
||||
});
|
||||
document
|
||||
.getElementById("btnReload")
|
||||
.addEventListener("click", function () {
|
||||
loadTodos();
|
||||
});
|
||||
function onInit() {
|
||||
loadTodos();
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -10,6 +10,7 @@
|
|||
"tags": "tool,todo",
|
||||
"supports": ["BANGLEJS", "BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
"interface": "interface.html",
|
||||
"storage": [
|
||||
{ "name": "todolist.app.js", "url": "app.js" },
|
||||
{ "name": "todolist.img", "url": "app-icon.js", "evaluate": true }
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 72 KiB |
|
@ -2,3 +2,4 @@
|
|||
0.02: Add settings menu
|
||||
0.03: Add ability to repeat last timer
|
||||
0.04: Add 5 second count down buzzer
|
||||
0.05: Fix 5 second count down buzzer to be only in the final 5 seconds
|
||||
|
|
|
@ -129,7 +129,12 @@ var main = () => {
|
|||
// Buzz lightly when there are less then 5 seconds left
|
||||
if (settings.countDownBuzz) {
|
||||
var remainingSeconds = timerCountDown.getAdjustedTime().seconds;
|
||||
if (remainingSeconds <= 5 && remainingSeconds > 0) {
|
||||
var remainingMinutes = timerCountDown.getAdjustedTime().minutes;
|
||||
var remainingHours = timerCountDown.getAdjustedTime().hours;
|
||||
if ( remainingSeconds <= 5
|
||||
&& remainingSeconds > 0
|
||||
&& remainingMinutes <= 0
|
||||
&& remainingHours <= 0) {
|
||||
Bangle.buzz();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"id": "touchtimer",
|
||||
"name": "Touch Timer",
|
||||
"shortName": "Touch Timer",
|
||||
"version": "0.04",
|
||||
"version": "0.05",
|
||||
"description": "Quickly and easily create a timer with touch-only input. The time can be easily set with a number pad.",
|
||||
"icon": "app.png",
|
||||
"tags": "tools",
|
||||
|
|
|
@ -135,7 +135,7 @@ Bangle.on("GPS", function(fix) {
|
|||
if (stats["dist"]) stats["dist"].emit("changed",stats["dist"]);
|
||||
var duration = Date.now() - state.startTime; // in ms
|
||||
state.avrSpeed = state.distance * 1000 / duration; // meters/sec
|
||||
state.curSpeed = state.curSpeed*0.8 + fix.speed*0.2/3.6; // meters/sec
|
||||
if (!isNaN(fix.speed)) state.curSpeed = state.curSpeed*0.8 + fix.speed*0.2/3.6; // meters/sec
|
||||
if (stats["pacea"]) stats["pacea"].emit("changed",stats["pacea"]);
|
||||
if (stats["pacec"]) stats["pacec"].emit("changed",stats["pacec"]);
|
||||
if (stats["speed"]) stats["speed"].emit("changed",stats["speed"]);
|
||||
|
@ -299,8 +299,6 @@ exports.getStats = function(statIDs, options) {
|
|||
state.curSpeed = 0;
|
||||
state.BPM = 0;
|
||||
state.BPMage = 0;
|
||||
state.thisGPS = {};
|
||||
state.lastGPS = {};
|
||||
state.notify = options.notify;
|
||||
if (options.notify.dist.increment > 0) {
|
||||
state.notify.dist.next = state.distance + options.notify.dist.increment;
|
||||
|
|
Loading…
Reference in New Issue