Merge branch 'espruino:master' into master
|
|
@ -270,7 +270,8 @@ and which gives information about the app for the Launcher.
|
|||
// 'notify' - provides 'notify' library for showing notifications
|
||||
// 'locale' - provides 'locale' library for language-specific date/distance/etc
|
||||
// (a version of 'locale' is included in the firmware)
|
||||
"tags": "", // comma separated tag list for searching
|
||||
// 'defaultconfig' - a set of apps that will can be installed and will wipe out all previously installed apps
|
||||
"tags": "", // comma separated tag list for searching (don't include uppercase or spaces)
|
||||
// common types are:
|
||||
// 'clock' - it's a clock
|
||||
// 'widget' - it is (or provides) a widget
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
"version": "0.02",
|
||||
"description": "A UI/UX for espruino smartwatches, displays dinamically calc. x,y coordinates.",
|
||||
"icon": "app.png",
|
||||
"tags": "Color,input,buttons,touch,UI",
|
||||
"tags": "color,input,buttons,touch,ui",
|
||||
"supports": ["BANGLEJS"],
|
||||
"readme": "README.md",
|
||||
"screenshots": [{"url":"UI4swatch_icon.png"},{"url":"UI4swatch_s1.png"}],
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@
|
|||
"version": "0.04",
|
||||
"description": "Wrist mounted ukulele chords",
|
||||
"icon": "app.png",
|
||||
"tags": "uke, chords",
|
||||
"supports" : ["BANGLEJS2"],
|
||||
"tags": "uke,chords",
|
||||
"supports" : ["BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
"storage": [
|
||||
{"name":"Uke.app.js","url":"app.js"},
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
"description": "A fully featured watch face with a playable game on the side.",
|
||||
"readme":"README.md",
|
||||
"type": "clock",
|
||||
"tags": "clock, game",
|
||||
"tags": "clock,game",
|
||||
"supports" : ["BANGLEJS2"],
|
||||
"storage": [
|
||||
{"name":"bblobface.app.js","url":"app.js"},
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
"version": "0.01",
|
||||
"description": "Aerobic fitness test created by Léger & Lambert",
|
||||
"icon": "beeptest.png",
|
||||
"tags": "Health",
|
||||
"tags": "health",
|
||||
"supports": ["BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
"storage": [
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
"description": "Bangle version of a popular word search game",
|
||||
"supports" : ["BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
"tags": "game, text",
|
||||
"tags": "game,text",
|
||||
"storage": [
|
||||
{"name":"bordle.app.js","url":"bordle.app.js"},
|
||||
{"name":"wordlencr.txt","url":"wordlencr.txt"},
|
||||
|
|
|
|||
|
|
@ -32,4 +32,5 @@ clkinfo.addInteractive that would cause ReferenceError.
|
|||
0.30: Use widget_utils
|
||||
0.31: Use clock_info module as an app
|
||||
0.32: Make the border of the clock_info box extend all the way to the right of the screen.
|
||||
0.33: Fix issue rendering ClockInfos with for fg+bg color set to the same (#2749)
|
||||
0.33: Fix issue rendering ClockInfos with for fg+bg color set to the same (#2749)
|
||||
0.34: Support 12-hour time format
|
||||
|
|
|
|||
|
|
@ -239,11 +239,9 @@ let drawTime = function() {
|
|||
var y = y1;
|
||||
var date = new Date();
|
||||
|
||||
var hours = String(date.getHours());
|
||||
var minutes = date.getMinutes();
|
||||
minutes = minutes < 10 ? String("0") + minutes : minutes;
|
||||
var colon = settings.hideColon ? "" : ":";
|
||||
var timeStr = hours + colon + minutes;
|
||||
var timeStr = locale.time(date, 1);
|
||||
if (settings.hideColon)
|
||||
timeStr = timeStr.replace(":", "");
|
||||
|
||||
// Set y coordinates correctly
|
||||
y += parseInt((H - y)/2) + 5;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "bwclk",
|
||||
"name": "BW Clock",
|
||||
"version": "0.33",
|
||||
"version": "0.34",
|
||||
"description": "A very minimalistic clock.",
|
||||
"readme": "README.md",
|
||||
"icon": "app.png",
|
||||
|
|
|
|||
|
|
@ -35,4 +35,5 @@ clkinfo.addInteractive that would cause ReferenceError.
|
|||
Remove invertion of theme as this doesn'twork very well with fastloading.
|
||||
Do an quick inital fillRect on theclock info area.
|
||||
0.33: Make the border of the clock_info box extend all the way to the right of the screen.
|
||||
0.34: Fix issue rendering ClockInfos with for fg+bg color set to the same (#2749)
|
||||
0.34: Fix issue rendering ClockInfos with for fg+bg color set to the same (#2749)
|
||||
0.35: Support 12-hour time format
|
||||
|
|
|
|||
|
|
@ -199,11 +199,9 @@ let drawTime = function() {
|
|||
let y = y1;
|
||||
let date = new Date();
|
||||
|
||||
let hours = String(date.getHours());
|
||||
let minutes = date.getMinutes();
|
||||
minutes = minutes < 10 ? String("0") + minutes : minutes;
|
||||
let colon = settings.hideColon ? "" : ":";
|
||||
let timeStr = hours + colon + minutes;
|
||||
var timeStr = locale.time(date, 1);
|
||||
if (settings.hideColon)
|
||||
timeStr = timeStr.replace(":", "");
|
||||
|
||||
// Set y coordinates correctly
|
||||
y += parseInt((H - y)/2) + 5;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "bwclklite",
|
||||
"name": "BW Clock Lite",
|
||||
"version": "0.34",
|
||||
"version": "0.35",
|
||||
"description": "A very minimalistic clock. This version of BW Clock is quicker at the cost of the custom font.",
|
||||
"readme": "README.md",
|
||||
"icon": "app.png",
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
"description": "Show the current and upcoming events synchronized from Gadgetbridge",
|
||||
"icon": "calclock.png",
|
||||
"type": "clock",
|
||||
"tags": "clock agenda",
|
||||
"tags": "clock,agenda",
|
||||
"supports": ["BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
"storage": [
|
||||
|
|
|
|||
|
|
@ -19,3 +19,5 @@
|
|||
Display Widgets in menus
|
||||
0.17: Load holidays before events so the latter is not overpainted
|
||||
0.18: Minor code improvements
|
||||
0.19: Read events synchronized from Gadgetbridge
|
||||
0.20: Correct start time of all-day events synchronized from Gadgetbridge
|
||||
|
|
|
|||
|
|
@ -60,6 +60,14 @@ const loadEvents = () => {
|
|||
date.setSeconds(time.s);
|
||||
return {date: date, msg: a.msg, type: "e"};
|
||||
}));
|
||||
// all events synchronized from Gadgetbridge
|
||||
events = events.concat((require("Storage").readJSON("android.calendar.json",1) || []).map(a => {
|
||||
// All-day events always start at 00:00:00 UTC, so we need to "undo" the
|
||||
// timezone offsetting to make sure that the day is correct.
|
||||
const offset = a.allDay ? new Date().getTimezoneOffset() * 60 : 0
|
||||
const date = new Date((a.timestamp+offset) * 1000);
|
||||
return {date: date, msg: a.title, type: a.allDay ? "o" : "e"};
|
||||
}));
|
||||
};
|
||||
|
||||
const loadSettings = () => {
|
||||
|
|
@ -221,8 +229,8 @@ const drawCalendar = function(date) {
|
|||
}, []);
|
||||
let i = 0;
|
||||
g.setFont("8x12", fontSize);
|
||||
for (y = 0; y < rowN - 1; y++) {
|
||||
for (x = 0; x < colN; x++) {
|
||||
for (let y = 0; y < rowN - 1; y++) {
|
||||
for (let x = 0; x < colN; x++) {
|
||||
i++;
|
||||
const day = days[i];
|
||||
const curMonth = day < 15 ? month+1 : day < 50 ? month-1 : month;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "calendar",
|
||||
"name": "Calendar",
|
||||
"version": "0.18",
|
||||
"version": "0.20",
|
||||
"description": "Monthly calendar, displays holidays uploaded from the web interface and scheduled events.",
|
||||
"icon": "calendar.png",
|
||||
"screenshots": [{"url":"screenshot_calendar.png"}],
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
"icon": "app.png",
|
||||
"version": "0.13",
|
||||
"type": "clock",
|
||||
"tags": "clock, weather, cassio, retro",
|
||||
"tags": "clock,weather,cassio,retro",
|
||||
"supports": ["BANGLEJS2"],
|
||||
"allow_emulator": true,
|
||||
"readme": "README.md",
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
"version":"0.01",
|
||||
"description": "Record time active on a task, course, work or anything really.",
|
||||
"icon": "app.png",
|
||||
"tags": "logging, record, work, tasks",
|
||||
"tags": "logging,record,work,tasks",
|
||||
"supports" : ["BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
"screenshots" : [ { "url":"dump.png"}, { "url":"dump1.png" }, { "url":"dump2.png" }, { "url":"dump3.png" }, { "url":"dump4.png" }, { "url":"dump5.png" }, { "url":"dump6.png" } ],
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
0.01: New app!
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
# Shortcuts
|
||||
|
||||
An app that allows you to create custom ClockInfos that act as shortcuts to your favourite apps.
|
||||
|
||||
## Create a Shortcut
|
||||
After installing the app, you can open the app to add and manage existing shortcuts. If no shortcuts exist, the app will display a ``[+] Shortcuts`` button as a ClockInfo on your Clock (see screenshots), which when clicked will quickly launch into the app so you can add new shortcuts.
|
||||
|
||||
When adding a shortcut, first select the app you wish to use, then select the icon you wish to register to the shortcut. If a keyboard is installed, you'll get the option to rename the shortcut before saving.
|
||||
|
||||
Once created, your shortcut will appear on any Clocks with ClockInfo support, and tapping the shortcut will launch the chosen app
|
||||
|
After Width: | Height: | Size: 471 B |
|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("mEw4UB/4ACBIM889VAHmqAAwKCrQLH0oLCuBoFhoLCtJ1HtILBtYLH9ILBtALHlILQlRFCwALSnWwgECBY8O1gLJgeoBaojLHZfqAQILIFwMDBY8CFwMO2QLGhwuBlWuBY0K4ED1aDHBYJUBlQLGnRUChQLIKgJHHBYJUBZY8KgZUBBZHCKgILHh2CBZMC0fABZC+CBZBSBC5JUB14MDcY2q1YLIDAILGtY4EAAXpBYNpBY9pBYNauAKFhulBYWqAAwLCqoLHBQQA6A="))
|
||||
|
|
@ -0,0 +1,224 @@
|
|||
var storage = require("Storage");
|
||||
var keyboard = "textinput";
|
||||
try {
|
||||
keyboard = require(keyboard);
|
||||
} catch (e) {
|
||||
keyboard = null;
|
||||
}
|
||||
|
||||
var icons = [
|
||||
{name:"agenda", img :"GBiBAAAAAAA8AAB+AA/n8B/n+BgAGBgAGBn/mBn/mBgAGBgAGBn/mBn/+BgD/BgHDhn+Bhn8MxgMIxgMIx/8Ew/+BgAHDgAD/AAA8A=="},
|
||||
{name:"alarm", img:"GBiBAAAAAAAAAAYAYA4AcBx+ODn/nAOBwAcA4A4YcAwYMBgYGBgYGBgYGBgYGBgeGBgHGAwBMA4AcAcA4AOBwAH/gAB+AAAAAAAAAA=="},
|
||||
{name:"mail", img:"GBiBAAAAAAAAAAAAAAAAAB//+D///DAADDgAHDwAPDcA7DPDzDDnDDA8DDAYDDAADDAADDAADDAADD///B//+AAAAAAAAAAAAAAAAA=="},
|
||||
{name:"android", img: "GBiBAAAAAAEAgAD/AAD/AAHDgAGBgAMkwAMAwAP/wBv/2BsA2BsA2BsA2BsA2BsA2BsA2Bv/2AP/wADnAADnAADnAADnAADnAAAAAA=="},
|
||||
{name:"add", img:"GBiBAAAAAAAAAAAAAA//8B//+BgAGBgAGBgYGBgYGBgYGBgYGBn/mBn/mBgYGBgYGBgYGBgYGBgAGBgAGB//+A//8AAAAAAAAAAAAA=="},
|
||||
{name:"bangle", img:"GBiBAAD+AAH+AAH+AAH+AAH/AAOHAAYBgAwAwBgwYBgwYBgwIBAwOBAwOBgYIBgMYBgAYAwAwAYBgAOHAAH/AAH+AAH+AAH+AAD+AA=="},
|
||||
{name:"bike", img:"GBiBAAAAAAAAAAAAAAAD+AAD/AADjAABjAfhnAfjyAMDwAcGwB4O+H8M/GGZ5sD7c8fzM8fjM8DDA2GBhn8B/h4AeAAAAAAAAAAAAA=="},
|
||||
{name:"map", img:"GBiBAAAAAAAAAAAAAADgGAf8+B//+BjHGBjDGBjDGBjDGBjDGBjDGBjDGBjDGBjDGBjDGBjDGBjjGB//+B8/4BgHAAAAAAAAAAAAAA=="},
|
||||
{name:"play", img:"GBiBAAAAAAAAAAAAAA//8B//+BgAGBjAGBjwGBj8GBjeGBjHmBjB2BjB2BjHmBjeGBj8GBjwGBjAGBgAGB//+A//8AAAAAAAAAAAAA=="},
|
||||
{name:"fast forward", img:"GBiBAAAAAAAAAAAAAH///v///8AAA8YYA8eeA8f/g8b7w8Y488YYO8YYO8Y488b7w8f/g8eeA8YYA8AAA////3///gAAAAAAAAAAAA=="},
|
||||
{name:"rewind", img:"GBiBAAAAAAAAAAAAAH///v///8AAA8AYY8B548H/48PfY88cY9wYY9wYY88cY8PfY8H/48B548AYY8AAA////3///gAAAAAAAAAAAA=="},
|
||||
{name:"timer", img:"GBiBAAAAAAB+AAB+AAAAMAB+OAH/nAOByAcA4A4YcAwYMBgYGBgYGBgYGBgYGBgAGBgAGAwAMA4AcAcA4AOBwAH/gAB+AAAAAAAAAA=="},
|
||||
{name:"connected", img:"GBiBAAAAAAAAAAAAAA//8B//+BgAGBgAGBngGBn4GBgcGBgOGBnHGBnzGBgxmBgZmBmZmBmZmBgAGBgAGB//+A//8AAAAAAAAAAAAA=="},
|
||||
{name:"lock", img:"GBiBAAAAAAA8AAD/AAHDgAGBgAMAwAMAwAMAwAf/4A//8AwAMAwAMAwAMAwYMAw8MAw8MAwYMAwAMAwAMAwAMA//8Af/4AAAAAAAAA=="},
|
||||
{name:"battery", img:"GBiBAAAAAAAAAAB+AAB+AAHngAPnwAMAwAMAwAMIwAMIwAMYwAM4wAM+wAN8wAMcwAMYwAMQwAMQwAMAwAMAwAP/wAH/gAAAAAAAAA=="},
|
||||
{name:"game", img:"GBiBAAAAAAAAAAAAAAA8AAB+AABmAABmAAB+AAA8AAAYAAAYAAAYAAMYAA//8B//+BgAGBgAGBgAGBgAGB//+A//8AAAAAAAAAAAAA=="},
|
||||
{name:"dice", img:"GBiBAAAAAB//8D//+HAAPGMDHmeHnmeHnmMDHmAAHmMDHmeHnmeHnmMDHmAAHmMDHmeHnmeHnmMDHnAAPn///j///h///g///AAAAA=="},
|
||||
{name:"gear", img:"GBiBAAAAAAAAAAA8AAB+AABmAA3nsA/D8B8A+Dg8HBx+OAznMAzDMAzDMAznMBx+ODg8HB8A+A/D8A3nsABmAAB+AAA8AAAAAAAAAA=="},
|
||||
{name:"wrench", img:"GBiBAAAAAAAAAAAAAAAHgAAfwAA7gAAzEABjOABj+ABh+ABgGADgMAHAcAOP4AcfgA44AB9wADHgADHAADGAAB8AAA4AAAAAAAAAAA=="},
|
||||
{name:"calendar", img:"FhgBDADAMAMP/////////////////////8AADwAAPAAA8AADwAAPAAA8AADwAAPAAA8AADwAAPAAA8AADwAAP///////"},
|
||||
{name:"power", img:"GBiBAAAAAAAAAAB+AAH/gAeBwA4YcAwYMBjbGBnbmDGZjDMYzDMYzDMAzDMAzDGBjBnDmBj/GAw8MA4AcAeB4AH/gAB+AAAAAAAAAA=="},
|
||||
{name:"terminal", img:"GBiBAAAAAAAAAAAAAA//8B//+B//+B//+B//+BgAGBgAGBgAGBmAGBjAGBhgGBhgGBjAGBmPmBgAGBgAGB//+A//8AAAAAAAAAAAAA=="},
|
||||
{name:"camera", img:"GBiBAAAAAAAAAAD/AAH/gAMAwD8A/H8A/mA8BmD/BmHDhmGBhmMAxmMAxmMAxmMAxmGBhmHDhmD/BmA8BmAABn///j///AAAAAAAAA=="},
|
||||
{name:"phone", img:"GBiBAAAAAAAAAAOAAA/AABzgADBgADBgADBgABjgABjAABzAAAxgAA5wAAc58AMf+AGHHADgDABwDAA8GAAfGAAH8AAA4AAAAAAAAA=="},
|
||||
{name:"two prong plug", img:"GBiBAAABgAADwAAHwAAPgACfAAHOAAPkBgHwDwP4Hwf8Pg/+fB//OD//kD//wD//4D//8D//4B//QB/+AD/8AH/4APnwAHAAACAAAA=="},
|
||||
{name:"steps", img:"GBiBAAcAAA+AAA/AAA/AAB/AAB/gAA/g4A/h8A/j8A/D8A/D+AfH+AAH8AHn8APj8APj8AHj4AHg4AADAAAHwAAHwAAHgAAHgAADAA=="},
|
||||
{name:"graph", img:"GBiBAAAAAAAAAAAAAAAAAAAAAADAAADAAAHAAAHjAAHjgAPngH9n/n82/gA+AAA8AAA8AAAcAAAYAAAYAAAAAAAAAAAAAAAAAAAAAA=="},
|
||||
{name:"hills", img:"GBiBAAAAAAAAAAAAAAAAAAAAAAACAAAGAAAPAAEZgAOwwAPwQAZgYAwAMBgAGBAACDAADGAABv///////wAAAAAAAAAAAAAAAAAAAA=="},
|
||||
{name:"sun", img:"GBiBAAAYAAAYAAAYAAgAEBwAOAx+MAD/AAHDgAMAwAcA4AYAYOYAZ+YAZwYAYAcA4AMAwAHDgAD/AAx+MBwAOAgAEAAYAAAYAAAYAA=="},
|
||||
{name:"home", img:"GBiBAAAAAAAAAAAAAAH/gAP/wAdg4A5wYA44MBwf+DgP/BgAGBgAGBgAGBnnmBnnmBnnmBnnmBngGBngGB//+B//+AAAAAAAAAAAAA=="},
|
||||
{name:"bell", img:"GBiBAAAAAAAAAAAfgAB/2ADw+AHAMAOAGAcAGD4ADHgADDgADBwADA4AHAcAGAOAOAHAcAPg4ANxwAM5gAP/AAHvAAAHAAACAAAAAA=="},
|
||||
{name:"bin", img:"GBiBAAAAAAAAAAB+AB//+B//+AwAMAwAMAxmMAZmYAZmYAZmYAZmYAZmYAZmYAZmYAZmYAZmYANmwAMAwAMAwAP/wAH/gAAAAAAAAA=="},
|
||||
];
|
||||
|
||||
let storedApps;
|
||||
var showMainMenu = () => {
|
||||
storedApps = storage.readJSON("clkshortcuts.json", 1) || {};
|
||||
|
||||
var mainMenu = {
|
||||
"": {
|
||||
title: "Shortcuts",
|
||||
},
|
||||
"< Back": () => {
|
||||
load();
|
||||
},
|
||||
"New": () => {
|
||||
// Select the app
|
||||
getSelectedApp().then((app) => {
|
||||
getSelectedIcon().then((icon) => {
|
||||
promptForRename(app.name).then((name) => {
|
||||
E.showMessage("Saving...");
|
||||
storedApps[app.src] = {
|
||||
name: name, src: app.src, icon: icon
|
||||
};
|
||||
storage.writeJSON("clkshortcuts.json", storedApps);
|
||||
showMainMenu();
|
||||
}).catch(() => {
|
||||
E.showMessage("Saving...");
|
||||
storedApps[app.src] = {
|
||||
name: app.name, src: app.src, icon: icon
|
||||
};
|
||||
storage.writeJSON("clkshortcuts.json", storedApps);
|
||||
showMainMenu();
|
||||
} );
|
||||
}).catch(() => {showMainMenu();});
|
||||
}).catch(() => {showMainMenu();});
|
||||
},
|
||||
};
|
||||
getStoredAppsArray(storedApps).forEach((app) => {
|
||||
mainMenu[app.name] = {
|
||||
onchange: () => {
|
||||
showEditMenu(app).then((dirty) => {
|
||||
if (dirty) {
|
||||
E.showMessage("Saving...");
|
||||
storage.writeJSON("clkshortcuts.json", storedApps);
|
||||
}
|
||||
showMainMenu();
|
||||
});
|
||||
},
|
||||
format: v=>"\0" + atob(app.icon)
|
||||
};
|
||||
});
|
||||
E.showMenu(mainMenu);
|
||||
};
|
||||
|
||||
var showEditMenu = (app) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
var editMenu = {
|
||||
"": {
|
||||
title: "Edit " + app.name,
|
||||
},
|
||||
"< Back": () => {
|
||||
resolve(false);
|
||||
},
|
||||
"Name":{
|
||||
onchange: () => {
|
||||
promptForRename(app.name).then((name) => {
|
||||
storedApps[app.src].name = name;
|
||||
resolve(true);
|
||||
}).catch();
|
||||
},
|
||||
format: v=>app.name.substring(0, 7)
|
||||
},
|
||||
"Icon": {
|
||||
onchange: () => {
|
||||
getSelectedIcon().then((icon) => {
|
||||
storedApps[app.src].icon = icon;
|
||||
resolve(true);
|
||||
}).catch(() => resolve(false));
|
||||
},
|
||||
format: v=>"\0" + atob(app.icon)
|
||||
},
|
||||
"Delete": {
|
||||
onchange: () => {
|
||||
delete storedApps[app.src]
|
||||
resolve(true);
|
||||
},
|
||||
format: v=>"\0" + atob("GBiBAAAAAAAAAAB+AB//+B//+AwAMAwAMAxmMAZmYAZmYAZmYAZmYAZmYAZmYAZmYAZmYAZmYANmwAMAwAMAwAP/wAH/gAAAAAAAAA==")
|
||||
}
|
||||
};
|
||||
E.showMenu(editMenu);
|
||||
});
|
||||
};
|
||||
|
||||
var promptForRename = (name) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!keyboard) { reject("No textinput is available"); }
|
||||
else {
|
||||
return require("textinput").input({text:name}).then((result) => resolve(result));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var getStoredAppsArray = (apps) => {
|
||||
var appList = Object.keys(apps);
|
||||
var storedAppArray = [];
|
||||
for (var i = 0; i < appList.length; i++) {
|
||||
var app = "" + appList[i];
|
||||
storedAppArray.push(
|
||||
apps[app]
|
||||
);
|
||||
}
|
||||
return storedAppArray;
|
||||
};
|
||||
|
||||
var getSelectedIcon = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
var iconMenu = {
|
||||
"": {
|
||||
title: "Select Icon",
|
||||
},
|
||||
"< Back": () => {
|
||||
reject("The user cancelled the operation");
|
||||
},
|
||||
};
|
||||
|
||||
icons.forEach((icon) => {
|
||||
iconMenu["\0" + atob(icon.img) + " " + icon.name] = () => {
|
||||
resolve(icon.img);
|
||||
};
|
||||
});
|
||||
|
||||
E.showMenu(iconMenu);
|
||||
});
|
||||
};
|
||||
|
||||
var getAppList = () => {
|
||||
var appList = storage
|
||||
.list(/\.info$/)
|
||||
.map((appInfoFileName) => {
|
||||
var appInfo = storage.readJSON(appInfoFileName, 1);
|
||||
return (
|
||||
appInfo && {
|
||||
name: appInfo.name,
|
||||
sortorder: appInfo.sortorder,
|
||||
src: appInfo.src,
|
||||
}
|
||||
);
|
||||
})
|
||||
.filter((app) => app && !!app.src);
|
||||
appList.sort((a, b) => {
|
||||
var n = (0 | a.sortorder) - (0 | b.sortorder);
|
||||
if (n) return n;
|
||||
if (a.name < b.name) return -1;
|
||||
if (a.name > b.name) return 1;
|
||||
return 0;
|
||||
});
|
||||
|
||||
return appList;
|
||||
};
|
||||
|
||||
var getSelectedApp = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
E.showMessage("Loading apps...");
|
||||
var selectAppMenu = {
|
||||
"": {
|
||||
title: "Select App",
|
||||
},
|
||||
"< Back": () => {
|
||||
reject("The user cancelled the operation");
|
||||
},
|
||||
};
|
||||
|
||||
var appList = getAppList();
|
||||
appList.forEach((app) => {
|
||||
selectAppMenu[app.name] = () => {
|
||||
resolve(app);
|
||||
};
|
||||
});
|
||||
|
||||
E.showMenu(selectAppMenu);
|
||||
});
|
||||
};
|
||||
|
||||
showMainMenu();
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
|
|
@ -0,0 +1,45 @@
|
|||
(function() {
|
||||
var storage = require("Storage");
|
||||
var storedApps = storage.readJSON("clkshortcuts.json", 1) || {};
|
||||
var items = [];
|
||||
if (Object.keys(storedApps).length !== 0) {
|
||||
for (var key in storedApps) {
|
||||
var source = {
|
||||
name: storedApps[key].name,
|
||||
img: storedApps[key].icon,
|
||||
src: storedApps[key].src,
|
||||
get : function() {
|
||||
return {
|
||||
text : this.name,
|
||||
img : atob(this.img)
|
||||
}
|
||||
},
|
||||
run: function() { load(this.src);},
|
||||
show : function() {},
|
||||
hide : function() {},
|
||||
}
|
||||
items.push(source);
|
||||
}
|
||||
}
|
||||
else {
|
||||
var source = {
|
||||
name: "Shortcuts",
|
||||
img: "GBiBAAAAAAAAAAAAAA//8B//+BgAGBgAGBgYGBgYGBgYGBgYGBn/mBn/mBgYGBgYGBgYGBgYGBgAGBgAGB//+A//8AAAAAAAAAAAAA==",
|
||||
src: "clkshortcuts.app.js",
|
||||
get : function() {
|
||||
return {
|
||||
text : this.name,
|
||||
img : atob(this.img)
|
||||
}
|
||||
},
|
||||
run: function() { load(this.src);},
|
||||
show : function() {},
|
||||
hide : function() {},
|
||||
};
|
||||
items = [source];
|
||||
}
|
||||
return {
|
||||
name: "Shortcuts",
|
||||
items: items
|
||||
};
|
||||
})
|
||||
|
After Width: | Height: | Size: 622 B |
|
|
@ -0,0 +1,17 @@
|
|||
{ "id": "clkshortcuts",
|
||||
"name": "Shortcuts",
|
||||
"shortName": "Shortcuts",
|
||||
"version": "0.01",
|
||||
"description": "Add shortcuts to launch your favourite apps straight from the Clock",
|
||||
"icon": "app.png",
|
||||
"screenshots": [{"url":"add_shortcuts_screenshot.png"}, {"url":"example_shortcuts_screenshot.png"}],
|
||||
"tags": "clkinfo,clockinfo",
|
||||
"supports": ["BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
"storage": [
|
||||
{ "name": "clkshortcuts.app.js", "url": "app.js" },
|
||||
{ "name": "clkshortcuts.img", "url": "app-icon.js", "evaluate": true },
|
||||
{"name":"clkshortcuts.clkinfo.js","url":"clkinfo.js"}
|
||||
],
|
||||
"data": [{"name":"clkshortcuts.json"}]
|
||||
}
|
||||
|
|
@ -12,4 +12,5 @@
|
|||
0.11: Prepend swipe listener if possible
|
||||
0.12: Add drawFilledImage to allow drawing icons with a separately coloured middle
|
||||
0.13: Cache loaded ClockInfos so if we have clockInfoWidget and a clock, we don't load them twice (saves ~300ms)
|
||||
0.14: Check for .clkinfocache and use that if exists (from boot 0.64)
|
||||
0.14: Check for .clkinfocache and use that if exists (from boot 0.64)
|
||||
0.15: Fix error when displaying a category with only one clockinfo (fix #3728)
|
||||
|
|
|
|||
|
|
@ -283,7 +283,7 @@ exports.addInteractive = function(menu, options) {
|
|||
//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) &&
|
||||
while ((options.menuB < menu[options.menuA].items.length-1) &&
|
||||
exports.clockInfos.some(m => (m!=options) && m.menuA==options.menuA && m.menuB==options.menuB))
|
||||
options.menuB++;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{ "id": "clock_info",
|
||||
"name": "Clock Info Module",
|
||||
"shortName": "Clock Info",
|
||||
"version":"0.14",
|
||||
"version":"0.15",
|
||||
"description": "A library used by clocks to provide extra information on the clock face (Altitude, BPM, etc)",
|
||||
"icon": "app.png",
|
||||
"type": "module",
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
"version": "0.03",
|
||||
"description": "Displays RGB565 and RGB888 colors, its name and code in screen.",
|
||||
"icon": "app.png",
|
||||
"tags": "Color,input,buttons,touch,UI",
|
||||
"tags": "color,input,buttons,touch,ui",
|
||||
"supports": ["BANGLEJS"],
|
||||
"readme": "README.md",
|
||||
"storage": [
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
0.01: New App!
|
||||
0.02: update to my current preferences.
|
||||
0.03: update app list
|
||||
0.04: change app name "mysetup" -> "anotherconf"
|
||||
0.05: remove apps that are not "core" to the experience.
|
||||
0.06: change name "anotherconf" -> "confthyttan"
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
# Thyttan's Default Config
|
||||
|
||||
A different default set of apps and configurations. Brings many quality of life improvements. Opinionated based on the creators taste. Read more below before installing.
|
||||
|
||||
## Usage
|
||||
|
||||
Before installing do this:
|
||||
|
||||
1. Backup your current setup (via the "More..." tab of the App Loader) so you can restore it later if you want.
|
||||
2. Install this app (you'll be prompted about all data being removed from your Bangle)
|
||||
3. Try it out, switch out apps to your favorites and tweak to your liking!
|
||||
|
||||
## Features
|
||||
|
||||
There will not be a trace of a "Thyttan's Default Config" app on your watch after installation. Only the apps it installed and the configurations.
|
||||
|
||||
On the clock face:
|
||||
- Swipe right on the screen to open the launcher (Desktop Launcher) - or press the hardware button.
|
||||
- Swipe left to open a flashlight app.
|
||||
- Swipe up to open the messages.
|
||||
- Swipe down for quick access to music and podcast controls.
|
||||
- (Do a subsequent left or right swipe to enter the listed apps)
|
||||
- (Check out the "Quick Launch" app readme for more info)
|
||||
|
||||
## Requests
|
||||
|
||||
Add to the espruino/BangleApps issue tracker and mention @thyttan for bug reports and suggestions.
|
||||
|
||||
## Creator
|
||||
|
||||
thyttan
|
||||
|
After Width: | Height: | Size: 1.7 KiB |
|
|
@ -0,0 +1 @@
|
|||
{"mode":0,"apps":[{"name":"Run+","src":"runplus.app.js","files":"runplus.info,runplus.app.js,runplus.img,runplus.settings.js,runplus_karvonen"}],"timeout":10}
|
||||
|
|
@ -0,0 +1 @@
|
|||
{"mode":0,"apps":[{"name":"Calculator","src":"calculator.app.js"},{"name":"SleepLog","src":"sleeplog.app.js"},{"name":"Messages","sortorder":-9,"src":"messagegui.app.js"},{"name":"Messages","sortorder":-9,"src":"messagegui.app.js","files":"messagegui.info,messagegui,messagegui.app.js,messagegui.new.js,messagegui.boot.js,messagegui.img"}],"standardNumSwipeHandlers":5,"standardNumDragHandlers":1}
|
||||
|
|
@ -0,0 +1 @@
|
|||
{"showClocks":true,"showLaunchers":true,"direct":false,"swipeExit":false,"timeOut":"15s"}
|
||||
|
|
@ -0,0 +1 @@
|
|||
{"buzzOnCharge":true,"monthFirst":true,"twentyFourH":true,"showAmPm":false,"showSeconds":true,"showWeather":false,"stepGoal":10000,"stepBar":true,"weekBar":true,"mondayFirst":true,"dayBar":true,"redrawOnStep":false}
|
||||
|
|
@ -0,0 +1 @@
|
|||
{useAppHistory:true,disregardQuicklaunch:true,hideLoading:true}
|
||||
|
|
@ -0,0 +1 @@
|
|||
{"colors":"011","image":"heart","touchOn":"always","oversize":7,"dragDelay":500,"minValue":0.01,"tapToLock":false,"unlockSide":"","tapSide":"","tapOn":"always","tOut":2000,"minFlash":0.2,"isOn":true,"value":0.9109}
|
||||
|
|
@ -0,0 +1 @@
|
|||
{vibrateTimeout:10,vibrate:":",vibrateCalls:":::",flash:false}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
{ "id": "confthyttan",
|
||||
"name": "Thyttan's Default Config",
|
||||
"version":"0.06",
|
||||
"description": "A different default set of apps and configurations. Brings many quality of life improvements. Opinionated based on the creators taste. Read more below before installing.",
|
||||
"icon": "app.png",
|
||||
"type": "defaultconfig",
|
||||
"tags": "system,configuration,config,anotherconfig,thyttan,defaultconfig",
|
||||
"supports" : ["BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
"dependencies" : {
|
||||
"sched":"app",
|
||||
"kbmulti":"app",
|
||||
"messageicons":"app",
|
||||
"widmsggrid":"app",
|
||||
"msgwakefup":"app",
|
||||
"delaylock":"app",
|
||||
"notify":"app",
|
||||
"health":"app",
|
||||
"widminbate":"app",
|
||||
"podadrem":"app",
|
||||
"spotrem":"app",
|
||||
"android":"app",
|
||||
"widanclk":"app",
|
||||
"backswipe":"app",
|
||||
"torch":"app",
|
||||
"calculator":"app",
|
||||
"widbt_notify":"app",
|
||||
"smpltmr":"app",
|
||||
"clkinfostopw":"app",
|
||||
"runplus":"app",
|
||||
"dtlaunch":"app",
|
||||
"quicklaunch":"app",
|
||||
"kineticscroll":"app",
|
||||
"alarm":"app",
|
||||
"recorder":"app",
|
||||
"agenda":"app",
|
||||
"edgeclk":"app",
|
||||
"autoreset":"app",
|
||||
"chargent":"app",
|
||||
"setting":"app",
|
||||
"fastload":"app",
|
||||
"boot":"app",
|
||||
"ateatimer":"app",
|
||||
"drained":"app"
|
||||
},
|
||||
"storage": [
|
||||
{"name":"backswipe.json",
|
||||
"url":"backswipe.json"},
|
||||
{"name":"autoreset.json",
|
||||
"url":"autoreset.json"},
|
||||
{"name":"dtlaunch.json",
|
||||
"url":"dtlaunch.json"},
|
||||
{"name":"fastload.json",
|
||||
"url":"fastload.json"},
|
||||
{"name":"quicklaunch.json",
|
||||
"url":"quicklaunch.json"},
|
||||
{"name":"messages.settings.json",
|
||||
"url":"messages.settings.json"},
|
||||
{"name":"widbt_notify.json",
|
||||
"url":"widbt_notify.json"},
|
||||
{"name":"recorder.json",
|
||||
"url":"recorder.json"},
|
||||
{"name":"edgeclk.settings.json",
|
||||
"url":"edgeclk.settings.json"},
|
||||
{"name":"setting.json",
|
||||
"url":"setting.json"}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
{lapp:{name:"Show Launcher",sortorder:-12,src:"no source"},rapp:{name:"torch",type:"app",sortorder:-11,src:"torch.app.js"},uapp:{name:"Messages",sortorder:-9,src:"messagegui.app.js"},dapp:{name:"Extension",type:"app",sortorder:-11,src:"quicklaunch.app.js"},tapp:{name:""},dlapp:{name:"PA Remote",src:"podadrem.app.js"},drapp:{name:"Remote for Spotify",src:"spotrem.app.js"},duapp:{name:""},ddapp:{name:"Extension",type:"app",sortorder:-11,src:"quicklaunch.app.js"},dtapp:{name:""},ddlapp:{name:"Alarms",src:"alarm.app.js"},ddrapp:{name:"Run+",src:"runplus.app.js"},dduapp:{name:""},dddapp:{name:"Agenda",src:"agenda.app.js"},ddtapp:{name:""},rlapp:{name:""},rrapp:{name:""},ruapp:{name:""},rdapp:{name:""},rtapp:{name:""},trace:"dr"}
|
||||
|
|
@ -0,0 +1 @@
|
|||
{recording:false,period:10,record:["gps","hrm","steps"],file:"recorder.log0.csv"}
|
||||
|
|
@ -0,0 +1 @@
|
|||
{ble:true,blerepl:true,log:false,quiet:0,timeout:10,vibrate:true,beep:true,timezone:2,HID:false,clock:"edgeclk.app.js","12hour":false,firstDayOfWeek:1,brightness:0.5,options:{wakeOnBTN1:true,wakeOnBTN2:true,wakeOnBTN3:true,wakeOnFaceUp:false,wakeOnTouch:false,wakeOnTwist:false,twistThreshold:819.2,twistMaxY:-800,twistTimeout:1000,btnLoadTimeout:700},theme:{fg:65535,bg:0,fg2:65535,bg2:8,fgH:65535,bgH:31,dark:true},clockHasWidgets:true,launcher:"dtlaunch.app.js",touch:{x1:6,y1:14,x2:197,y2:178}}
|
||||
|
|
@ -0,0 +1 @@
|
|||
{showWidget:true,buzzOnConnect:false,buzzOnLoss:false,hideConnected:false,showMessage:false,nextBuzz:30000}
|
||||
|
|
@ -2,3 +2,4 @@
|
|||
0.02: Added Settings & readme
|
||||
0.03: Fix lint warnings
|
||||
0.04: Fix lint warnings
|
||||
0.05: Fix on not reading counter defaults in Settings
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "counter2",
|
||||
"name": "Counter2",
|
||||
"version": "0.04",
|
||||
"version": "0.05",
|
||||
"description": "Dual Counter",
|
||||
"readme":"README.md",
|
||||
"icon": "counter2-icon.png",
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
"": { "title": "Counter2" },
|
||||
"< Back": () => back(),
|
||||
'Default C1': {
|
||||
value: settings[0],
|
||||
value: settings.max0,
|
||||
min: -99, max: 99,
|
||||
onchange: v => {
|
||||
settings.max0 = v;
|
||||
|
|
@ -26,7 +26,7 @@
|
|||
}
|
||||
},
|
||||
'Default C2': {
|
||||
value: settings[2],
|
||||
value: settings.max1,
|
||||
min: -99, max: 99,
|
||||
onchange: v => {
|
||||
settings.max1 = v;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
0.01: First functional release
|
||||
0.02: move moon down, rotate sunrise/sunset, shift Hours/minutes to corners
|
||||
0.03: Change day and night to have different dots
|
||||
0.04: Update ChangeLog, coerce dark theme
|
||||
0.05: Add more screenshots, fix bug in dot colors
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
# DayMoon Circadian
|
||||
This started out with a goal to recreate the Pebble [Fair Circadian watchface](https://setpebble.com/app/fair-circadian) by Matthew Clark for the Bangle.js2.
|
||||
It ended up with me making a mostly new watchface that has the moon phase more prominent, but keeps the single dial 24 hour clock with daylight and sunset highlighted.
|
||||
|
||||
This uses the myLocation app to get your latitude and longitude for proper daylight calculations. If your location isn't set in that app, it will default to Nashua, NH. If your sunrise/sunset times aren't making sense, check that first!
|
||||
|
||||
## Future Development
|
||||
Feature roadmap:
|
||||
- [x] 0.01 Fix blocking widgets
|
||||
- [x] 0.03 Day and Night different color markers
|
||||
- [x] 0.04 Add to App Loader
|
||||
- [x] 0.05 Add more screenshots with different moon phases
|
||||
- [ ] 0.06 add Day of week and month display
|
||||
- [ ] 0.07 Seconds display
|
||||
- [ ] 0.08 Color Themes (and settings/options)
|
||||
- [ ] 0.09 Moon display angle represents how it looks in the sky
|
||||
- [ ] 0.10 custom/bigger/fitted time digits
|
||||
- [ ] 0.20 clockinfo support?
|
||||
- [ ] 0.30 Tap/swipe actions?
|
||||
|
||||
|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("mEw4kA///hADBg/g/9/zuFA4Ocj+Nj+lgP4vP/o8AokAg8Ag0Ao//Mf4AptF2s+ICqNGulmkVkxF0wwsPo+EuUik13s14DBsIu1Iw4XBlGIs41BsAWKgl4vFnu1okVns+GsgyBtOZC5FkOQOHw1ItGGvGEAQWWhIuIxF2w92vAJDxGIs2JxFpC494wUos9HBQtHo2Sk+XRhFyk65ChWqqvAAoN5wUpuyMHxFos6FBCwOq5vM5sAzF3ygMCAAl3vDQBgEPCwOqr285nggFJw9IGA1os2IEIPz/QXB5m84vMGALbBNYsIBANnFwMz1Uzn/MqtbrhiBTgN2JAkHpCzBgGjmfzC4POGAmIo1nuAXEFwIHB+evmYXBrm89vM9nAhFnogvFZgNghU//8/mf69ns8vM93Ag1ovAvEAwOGUgIsB/55B9lc9ld5yRBtF2swXDw92sgXDR4P65h4B93M7gQBoyQEu0iRwKMBXwX/5p1B9nMr0Ao8ivAXDsUilAXC/4XBnQVBrncrfOgFCkUmC4eykUrC4R1B0f/O4PM53O3kAqUikIXDjci7YXB+Z3B1+qCwPsqoDBgG8kXlC4kV7x3B1//C4XMrovCO4O72NVC4fhiI6BhWqIoIXBIYPN5lc4EArtdjYXDhdd8PAC4M/18/F4PM4vF53Agsd7sQC4nB7jLBUgKOB1XFLgIAB4EBMgIzBAAUBiPBWYK+CAANc5wXCgHF8sdE4IvD5mx8JgCAAXO9neFwMAjobBI4kA2vMqOwGAnO9yoBgEF3fBroWEgHsjflWAIwD4tc6ouB5nc8sRC4sO9cd9wPBDAXlFwUO8ve8PQC4sAiPCldbAoIYB5hvC50SlfOCw0AivSkNb2IKF2Mc2Uu9YXHh0V9nrjbjEjsc3sV2qEBAAsigEe53hj3R3vbiMeitbfgK0BCAIADgQCBhtc2O7qOx8si7ns4PNqvgCAQXEDwUO93uj1c2Uilvh8vsaYIQDF4kgAgO+qsRjdSkUrjZKBCAxfEAAXt4PR5kijle5gQIABFdrxeBCBgA/ADg="))
|
||||
|
|
@ -0,0 +1,260 @@
|
|||
const LOCATION_FILE = "mylocation.json";
|
||||
let location;
|
||||
|
||||
var Utils = require("graphics_utils");
|
||||
var SunCalc = require("suncalc");
|
||||
var RADII = {
|
||||
moon: 40,
|
||||
arcMin: 48,
|
||||
arcMax: 63,
|
||||
dots: 55,
|
||||
needle: 54,
|
||||
};
|
||||
var COL = {
|
||||
moon: 65535, //
|
||||
txture: 33792, // 0.5 ,0.5,0
|
||||
shadow: 8196, // .125,0, .125
|
||||
day: 40159, //0.6, 0.6,1
|
||||
night: 6, // 0, 0, 0.2
|
||||
ndots: 2047, // 0, 1, 1 cyan
|
||||
ddots: 0,
|
||||
needle: 63488, // 1, 0, 0 red
|
||||
stime: 2047
|
||||
};
|
||||
const TAU = 2.0 * Math.PI;
|
||||
const MX = g.getWidth() / 2,
|
||||
MY = 24 + 3 + RADII.arcMax;
|
||||
const DAY_MILLIS = 86400000;
|
||||
const M_POS = {
|
||||
x: MX,
|
||||
y: MY,
|
||||
r: RADII.moon
|
||||
};
|
||||
// images
|
||||
const moon_texture = {
|
||||
width: 80,
|
||||
height: 80,
|
||||
bpp: 1,
|
||||
transparent: 0,
|
||||
buffer: require("heatshrink").decompress(atob("ABsRqAJHkEiBA0N0uq1AIEgNVqtRqoJEgUiAAQJEioTBAAIzEl2q12oxATECQdVioJD/eqne60UCHQoADoAJBgf+xWrFIOACYUFCYo8Cj/73f70er0ROHAANUBIM//3///q1WIFAV1qtXCggJB//7CYO6keikBOHKAUDCIInClSgCgonBu4TK1W73ShBMQxkCh5OC//uFIInBi91q5PFCYISC3er//iOwXVE41UCYf+9//9AnCJopVBqEv/+/3//E4P6kUgJw4nDKAP+14TB1Xoq4hBEwYFBqgnB3Wr3e737KB/QnIqp3B32OKAYTBE4Z4BAoYnBEoRSC0fyE5ITBJ4WuCYP4J4J3CeQQFClbvBJgOqn5kBnRPKTwJMB1B4B92qEgQACJ4JTBkYnBYwOilYsBO5NUhYmB9+qxGC9TxBEYTvFqki3Y8B1Uikei3+oionIgGrO4OqwGC9H/xATK1/7E4UAnU7kATIqEAl/uE4WA12u0ATJgSgB/+ikUgnW70EFCY9AgGDE4PowEAlWowEBCZJ4BneggUgkRSBCZEAgEKJoIEBgEIAYQOCKYcVBIMqJgIEBgQSCgAQBqiJDRQIOBEwYAEMgNRiITBqKKBCYJJBE4xQGMQIABlBPHHgInDHQQjEAQJTCHgbFEABg8EBg5SDCgxNDABI="))
|
||||
};
|
||||
const needle = {
|
||||
width: 23,
|
||||
height: 10,
|
||||
bpp: 1,
|
||||
transparent: 0,
|
||||
buffer: atob("//+B///D///AAAHgAADgAAHAAA9///j//+H//gA=")
|
||||
};
|
||||
|
||||
/*
|
||||
now use SunCalc.getMoonIllumination()
|
||||
previously used these:
|
||||
https://github.com/espruino/BangleApps/blob/master/apps/widmp/widget.js
|
||||
https://github.com/deirdreobyrne/LunarPhase
|
||||
modified to be based on millisec instead of sec, and to use tau = 2*pi
|
||||
*/
|
||||
|
||||
// requires the myLocation app
|
||||
function loadLocation() {
|
||||
location = require("Storage").readJSON(LOCATION_FILE, 1) || {
|
||||
"lat": 45,
|
||||
"lon": -71.3,
|
||||
"location": "Nashua"
|
||||
}; //{"lat":51.5072,"lon":0.1276,"location":"London"};
|
||||
}
|
||||
|
||||
function drawMoon(shadowShape) {
|
||||
g.setColor(0, 0, 0).fillCircle(MX, MY, RADII.arcMax + 3);
|
||||
g.setColor(COL.moon).fillCircle(MX, MY, RADII.moon - 1);
|
||||
g.setColor(COL.txture).drawImage(moon_texture, MX, MY, {
|
||||
rotate: 0
|
||||
});
|
||||
// TODO: can set the rotation here to the parallacticAngle from getMoonPosition
|
||||
g.setColor(COL.shadow).fillPoly(shadowShape);
|
||||
// TODO: set rotation of the fillPoly? parallactic-mp.angle I think.
|
||||
// Use g.transformVertices to do the rotation
|
||||
}
|
||||
|
||||
function drawDayRing(times) {
|
||||
let r_ = RADII.arcMin;
|
||||
let rm = RADII.arcMax;
|
||||
let rd = RADII.dots;
|
||||
let radT = [tToRad(times[0]), tToRad(times[1])];
|
||||
let hhmm = [require("locale").time(times[0], 1), require("locale").time(times[1], 1)];
|
||||
g.setColor(COL.day);
|
||||
Utils.fillArc(g, MX, MY, r_, rm, radT[0], radT[1]);
|
||||
g.setColor(COL.night);
|
||||
Utils.fillArc(g, MX, MY, r_, rm, radT[1] - TAU, radT[0]);
|
||||
// write sunrise/sunset times
|
||||
g.setFont('6x8').setColor(COL.stime);
|
||||
g.setFontAlign(0, 1, 3).drawString(hhmm[0], MX - rm - 2, MY);
|
||||
g.setFontAlign(0, 1, 1).drawString(hhmm[1], MX + rm + 2, MY);
|
||||
// draw dots
|
||||
let edges = [];
|
||||
let isDay = false;
|
||||
let flag = false;
|
||||
if (radT[1] > TAU) {
|
||||
edges = [radT[1] - TAU, radT[0]];
|
||||
g.setColor(COL.ddots);
|
||||
isDay = true;
|
||||
} else {
|
||||
edges = [radT[0], radT[1]];
|
||||
g.setColor(COL.ndots);
|
||||
isDay = false;
|
||||
}
|
||||
for (var i = 0; i < 24; i++) {
|
||||
let a = i * TAU / 24;
|
||||
if (!flag && a > edges[0] && a < edges[1]) {
|
||||
//first cross
|
||||
if (isDay) {
|
||||
g.setColor(COL.ndots);
|
||||
} else {
|
||||
g.setColor(COL.ddots);
|
||||
}
|
||||
flag = true;
|
||||
} else if (flag && a > edges[1]) {
|
||||
//second cross
|
||||
if (isDay) {
|
||||
g.setColor(COL.ddots);
|
||||
} else {
|
||||
g.setColor(COL.ndots);
|
||||
}
|
||||
flag = false;
|
||||
}
|
||||
let dotSize = (i % 3 == 0) ? 2 : 1;
|
||||
let pX = MX + Math.cos(a) * rd;
|
||||
let pY = MY + Math.sin(a) * rd;
|
||||
g.fillCircle(pX, pY, dotSize);
|
||||
}
|
||||
let labels = ['6P', '12A', '6A', '12P'];
|
||||
let qX = [rd - 9, 2, 11 - rd, 2];
|
||||
let qY = [1, rd - 10, 1, 12 - rd];
|
||||
g.setFont('4x6').setFontAlign(0, 0, 0).setColor(COL.ndots);
|
||||
for (var j = 0; j < 4; j++) {
|
||||
g.drawString(labels[j], MX + qX[j], MY + qY[j]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function drawHHMM(d) {
|
||||
var HM = require("locale").time(d, 1 /*omit seconds*/ ).split(":");
|
||||
// write digital time
|
||||
g.setBgColor(0, 0, 0).setColor(1, 1, 1).setFontVector(45);
|
||||
g.setFontAlign(1, 1, 0).drawString(" " + HM[0], MX - 20, g.getHeight() + 3);
|
||||
g.setFontAlign(-1, 1, 0).drawString(HM[1] + " ", MX + 30, g.getHeight() + 3);
|
||||
// TODO: use the meridian text AM/PM or blank for 24 hr.
|
||||
// var meridian = require("locale").meridian(d);
|
||||
}
|
||||
|
||||
function moonShade(pos, mp) {
|
||||
pos = pos !== undefined ? pos : M_POS;
|
||||
mp = mp !== undefined ? mp : SunCalc.getMoonIllumination(new Date());
|
||||
// pos has x,y, r for the drawing, mp is from SunCalc Moon Illumination
|
||||
let k = mp.fraction;
|
||||
// k is the percent along the equator of the terminator
|
||||
const pts = Math.min(pos.r >> 1, 32);
|
||||
// this gives r/2 pts on the way down and up, capped at 64 total for polyfill
|
||||
let a = [],
|
||||
b = [],
|
||||
s1 = 1,
|
||||
s2 = 0;
|
||||
// scale s1 is 1 or -1 for fixed edge of the shadow; defined via case switches below
|
||||
// scale s2 factor for the moving edge of the shadow
|
||||
// need to do some computation to simplify for new/full moon if k 'close enough' to 0 or 1/-1
|
||||
//
|
||||
let isWaxing = (mp.phase < 0.5);
|
||||
s1 = isWaxing ? -1 : 1;
|
||||
s2 = isWaxing ? 1 - 2 * k : 2 * k - 1;
|
||||
let tr = (pos.r + 1);
|
||||
for (var i = 0; i < pts; i++) {
|
||||
// down stroke on the outer shadow
|
||||
var t = i * Math.PI / (pts + 1); //pts+1 so we leave the last point for the starting of going up
|
||||
let cirX = Math.sin(t) * tr;
|
||||
let cirY = Math.cos(t) * tr;
|
||||
a.push(pos.x + s1 * cirX); //x
|
||||
a.push(pos.y + cirY); //y
|
||||
b.push(pos.x + s2 * cirX); //x for shadow edge
|
||||
b.push(pos.y - cirY); //y going up for shadow edge
|
||||
}
|
||||
return a.concat(b);
|
||||
}
|
||||
|
||||
function tToRad(date) {
|
||||
date = (date !== undefined) ? new Date(date.getTime()) : new Date();
|
||||
let milli = date - new Date(date.setHours(0, 0, 0, 0));
|
||||
return (milli / DAY_MILLIS + 0.25) * TAU;
|
||||
}
|
||||
|
||||
function draw(date) {
|
||||
var d = date !== undefined ? date : new Date();
|
||||
var a = tToRad(d),
|
||||
shape = moonShade(M_POS, SunCalc.getMoonIllumination(d)),
|
||||
sTimes = SunCalc.getTimes(d, location.lat, location.lon),
|
||||
daylight = [sTimes.sunrise, sTimes.sunset];
|
||||
//clear time area
|
||||
g.clearRect(Bangle.appRect); //g.setColor(0).fillRect(0, 176 - 45, 176, 176);
|
||||
drawMoon(shape);
|
||||
drawDayRing(daylight);
|
||||
drawHHMM(d);
|
||||
// draw pointer
|
||||
// TODO: Maybe later make this an overlay that can be removed?? -avoid drawing so much every minute/second
|
||||
g.setColor(COL.needle).drawImage(needle, MX + RADII.needle * Math.cos(a), MY + RADII.needle * Math.sin(a), {
|
||||
rotate: a
|
||||
});
|
||||
|
||||
}
|
||||
/*
|
||||
const shotTimes = [1720626960000, 1729184400000, 1738298880000, 1717575420000];
|
||||
let desc =`first quarter -2 days moon at 10:20 in the summer
|
||||
jun 10 2024 10:56
|
||||
full moon at 12 noon near fall equinox
|
||||
Sep 17 2024 12:00
|
||||
new moon at 11pm in winter
|
||||
dec 30 2024 23:48
|
||||
3rd quarter moon at 03:17 am
|
||||
May 5 2024 03:17`
|
||||
|
||||
function screenshots(times) {
|
||||
let d = new Date();
|
||||
for (let t of times) {
|
||||
d.setTime(t);
|
||||
draw(d);
|
||||
g.dump();
|
||||
}
|
||||
}
|
||||
*/
|
||||
// Clear the screen once, at startup
|
||||
g.reset();
|
||||
// requires the myLocation app
|
||||
loadLocation();
|
||||
g.setBgColor(0, 0, 0).clear();
|
||||
// draw immediately at first
|
||||
draw();
|
||||
// now draw every second
|
||||
// eventually maybe update the moon just every hour??
|
||||
var secondInterval = setInterval(draw, 10000); //was 1000
|
||||
// Stop updates when LCD is off, restart when on
|
||||
Bangle.on('lcdPower', on => {
|
||||
if (secondInterval) clearInterval(secondInterval);
|
||||
secondInterval = undefined;
|
||||
if (on) {
|
||||
secondInterval = setInterval(draw, 10000); //was 1000
|
||||
draw(); // draw immediately
|
||||
}
|
||||
});
|
||||
/* Show launcher when middle button pressed
|
||||
This should be done *before* Bangle.loadWidgets so that
|
||||
widgets know if they're being loaded into a clock app or not */
|
||||
Bangle.setUI("clock");
|
||||
// Load widgets
|
||||
Bangle.loadWidgets();
|
||||
g.setTheme({
|
||||
fg: "#fff",
|
||||
bg: "#000",
|
||||
fg2: "#fff",
|
||||
bg2: "#004",
|
||||
fgH: "#fff",
|
||||
bgH: "#00f",
|
||||
dark: true
|
||||
});
|
||||
Bangle.drawWidgets();
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
|
|
@ -0,0 +1,17 @@
|
|||
{ "id": "daymoon",
|
||||
"name": "DayMoon Circadian Clock",
|
||||
"version": "0.05",
|
||||
"dependencies": {"mylocation":"app"},
|
||||
"description": "A 24 hour clockface showing the Moon Phase and portion of the day that the Sun is up inspired by Matthew Clark's *Fair Circadian* Pebble watchface",
|
||||
"icon": "daymoon.png",
|
||||
"screenshots": [{"url":"s1.png"},{"url":"s2.png"},{"url":"s3.png"},{"url":"s4.png"}],
|
||||
"type": "clock",
|
||||
"tags": "clock,moon,lunar",
|
||||
"supports": ["BANGLEJS2"],
|
||||
"allow_emulator": true,
|
||||
"readme":"README.md",
|
||||
"storage": [
|
||||
{"name":"daymoon.app.js","url":"app.js"},
|
||||
{"name":"daymoon.img","url":"app-icon.js","evaluate":true}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 4.3 KiB |
|
After Width: | Height: | Size: 3.5 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
|
@ -3,7 +3,7 @@
|
|||
"version":"0.01",
|
||||
"description": "Delay the locking of the screen to 5 seconds after the backlight turns off.",
|
||||
"icon": "app.png",
|
||||
"tags": "settings, configuration, backlight, touchscreen, screen",
|
||||
"tags": "settings,configuration,backlight,touchscreen,screen",
|
||||
"type": "bootloader",
|
||||
"supports" : ["BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
0.01: Begin rewrite from old code.
|
||||
0.02: Changed visuals: uA > mA, info order, battery state indication
|
||||
0.03: Update app icon
|
||||
|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("mEwwcBkmSpIC/AS0nwEHCh5yBggROgP4jgROh1ICKWT4Hkz0AC4NPgFypPgAQIRDyBLBCIMAiVAgECpAGBCInwn4RBg4dBoH/yV4j+ACI0Dz05kARB8gRJgARFgYRBgEB5IRKBwICCI4/8CIdJ/kCGoP+CIMPUIIRBkgRIYop9DgJHCPowDBTwUAyAREiSkBCITCOAX4CuwE5kmT4D1BBYSMByShBhwRCgEkWYQRDUIIRCUIWfEALXBCIsDCIMf+QICvEECIILBBAV5CIUcBAYRFpEEBYIRKnARIgFyHwfk+PAGogREgQIBPQMk+EACI9J/hrCyUHCIMHCJEnwAIByEBCIJrFCI/wWYIROwP5CIShECI7FBgjFDPoTFBgTXGBYICCCI6PDAX4C/ARoA="))
|
||||
|
|
@ -0,0 +1,157 @@
|
|||
// FONTS
|
||||
|
||||
/*
|
||||
Share Tech Mono: https://fonts.google.com/specimen/Share+Tech+Mono
|
||||
Converted with: https://www.espruino.com/Font+Converter
|
||||
*/
|
||||
|
||||
Graphics.prototype.setFontShareTechMonoBig = function(scale) {
|
||||
// Actual height 56 (55 - 0)
|
||||
this.setFontCustom(
|
||||
atob('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB+AAAAAAAAB+AAAAAAAAB+AAAAAAAAB+AAAAAAAAB+AAAAAAAAB+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAAAAAHwAAAAAAAA/wAAAAAAAD/wAAAAAAAf/wAAAAAAB//gAAAAAAP/8AAAAAAA//wAAAAAAH/+AAAAAAA//4AAAAAAD//AAAAAAAf/8AAAAAAB//gAAAAAAP/8AAAAAAB//wAAAAAAH/+AAAAAAA//4AAAAAAD//AAAAAAAf/4AAAAAAB//gAAAAAAP/8AAAAAAA//wAAAAAAA/+AAAAAAAA/4AAAAAAAA/AAAAAAAAA4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf///4AAAAD/////AAAAP/////wAAAf/////4AAA//////8AAA//////8AAB/AAB/j+AAB+AAH/B+AAB8AAP8A+AAB8AA/4A+AAB8AB/gA+AAB8AH/AA+AAB8AP8AA+AAB8A/4AA+AAB8B/gAA+AAB+D/AAB+AAA//+AAP8AAA//////8AAAf/////4AAAP/////wAAAH/////gAAAB////+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPgAAAAeAAAfgAAAA+AAAfAAAAA+AAA/AAAAA+AAA+AAAAA+AAA+AAAAA+AAB+AAAAA+AAB8AAAAA+AAB//////+AAB//////+AAB//////+AAB//////+AAB//////+AAB//////+AAAAAAAAA+AAAAAAAAA+AAAAAAAAA+AAAAAAAAA+AAAAAAAAA+AAAAAAAAA+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB+AAB8AAAAD+AAB8AAAAP+AAB8AAAAf+AAB8AAAB/+AAB8AAAD/+AAB8AAAH/+AAB8AAAf8+AAB8AAA/4+AAB8AAD/w+AAB8AAH/A+AAB+AAf+A+AAB+AA/4A+AAA////wA+AAA////gA+AAAf//+AA+AAAP//8AA+AAAH//wAA+AAAB/+AAA+AAAAAAAAA+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB8AAAAA+AAB8AAAAA+AAB8AB8AA+AAB8AB8AA+AAB8AB8AA+AAB8AB8AA+AAB8AB8AA+AAB8AB8AA+AAB8AB8AA+AAB8AB8AA+AAB8AD8AA+AAB+AH+AB+AAA////gD+AAA//////8AAAf/////8AAAP//P//4AAAH/+H//wAAAA/4D//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAP/wAAAAAAD//wAAAAAB///wAAAAAf///wAAAAH////wAAAB///+HwAAAB///gHwAAAB//wAHwAAAB/4AAHwAAAB+AAAHwAAABAAAAHwAAAAAAP///+AAAAAf///+AAAAAf///+AAAAAf///+AAAAAf///+AAAAAf///+AAAAAAAHwAAAAAAAAHwAAAAAAAAHwAAAAAAAAHwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB///wAA+AAB///wAA+AAB///wAA+AAB///wAA+AAB///wAA+AAB///wAA+AAB8AHwAA+AAB8AHwAA+AAB8AHwAA+AAB8AD4AA+AAB8AD4AA+AAB8AD4AB+AAB8AD+AD+AAB8AD///8AAB8AB///8AAB8AA///4AAB8AAf//wAAB4AAP//gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////AAAAP/////gAAAf/////4AAAf/////4AAA//////8AAA/APgAD+AAB+APgAB+AAB8APgAA+AAB8APgAA+AAB8APgAA+AAB8APgAA+AAB8APgAA+AAB8APgAA+AAB8AHwAA+AAB8AHwAB+AAB8AH+AP8AAB8AH///8AAB8AD///4AAAAAB///wAAAAAA///gAAAAAAP/+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB8AAAAAAAAB8AAAAAAAAB8AAAAAAAAB8AAAAAAAAB8AAAAAOAAB8AAAAD+AAB8AAAAf+AAB8AAAD/+AAB8AAA//+AAB8AAH//+AAB8AB///gAAB8AP//8AAAB8D///AAAAB8f//4AAAAB////AAAAAB///wAAAAAB//+AAAAAAB//gAAAAAAB/8AAAAAAAB/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB//AAAAD/8H//wAAAP//P//4AAAf/////8AAA//////8AAA//////+AAB/AP+AB+AAB8AD8AA+AAB8AD8AA+AAB8AB8AA+AAB8AB8AA+AAB8AB8AA+AAB8AB8AA+AAB8AB8AA+AAB8AD8AA+AAB+AH+AA+AAA////AD+AAA//////8AAAf/////8AAAP//P//4AAAH/+H//wAAAA/4D//gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//4AAAAAAP//+AAAAAAf///AAAAAAf///AA+AAA////gA+AAB/AAfgA+AAB+AAPgA+AAB8AAPwA+AAB8AAHwA+AAB8AAHwA+AAB8AAHwA+AAB8AAHwA+AAB8AAHwA+AAB8AAHwB+AAB+AAHwB+AAA//////8AAA//////8AAAf/////4AAAP/////wAAAH/////gAAAB////+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB+AAB+AAAAB+AAB+AAAAB+AAB+AAAAB+AAB+AAAAB+AAB+AAAAB+AAB+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'),
|
||||
46,
|
||||
32,
|
||||
60+(scale<<8)+(1<<16)
|
||||
);
|
||||
return this;
|
||||
};
|
||||
|
||||
Graphics.prototype.setFontShareTechMono = function(scale) {
|
||||
// Actual height 38 (37 - 0)
|
||||
this.setFontCustom(
|
||||
atob('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHgAAAAAeAAAAAB4AAAAAHgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwAAAAAfAAAAAP8AAAAD/gAAAB/4AAAAf+AAAAP/AAAAH/gAAAB/4AAAA/8AAAAP/AAAAH/gAAAD/wAAAA/8AAAAP+AAAAA/gAAAADwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB//4AAA///8AAP///8AA////wAHwAfvgAeAH4eABwA/A4AHAHwDgAcB+AOAB4PgB4AHj8AHgAf///+AA////wAB///+AAD///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHAAAOAA8AAA4ADwAADgAeAAAOAB4AAA4AH////gAf///+AB////4AH////gAAAAAOAAAAAA4AAAAADgAAAAAOAAAAAA4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB4AHAAAfgAcAAD+ABwAA/4AHAAH/gAcAA/OABwAP44AHgB+DgAfAfwOAA//8A4AD//gDgAH/4AOAAH+AA4AAAAADgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcAAAOABwBwA4AHAHADgAcAcAOABwBwA4AHAHADgAeA+AOAB8H4B4AD////gAP///8AAf+f/gAAPgf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPgAAAAP+AAAAP/4AAAf//gAAf//OAAB//A4AAH+ADgAAcAAOAAAAH//4AAA///gAAD//+AAAP//4AAAAHgAAAAAOAAAAAA4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/+ADgAf/4AOAB//gA4AH/+ADgAcA4AOABwDgA4AHAPADgAcA8AeABwD//4AHAH//AAcAP/4AAAAf/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA///8AAH///4AA////wAH////gAeB4AeABwHgA4AHAeADgAcB4AOABwHgA4AHAeAHgAcA//+ABwD//wAAAH/+AAAAP/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcAAAAABwAAAAAHAAAAgAcAAAeABwAAf4AHAAP/gAcAH/+ABwH/+AAHD//AAAf//AAAB//gAAAH/gAAAAfwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB/gAAP+f/gAD////AAP///+AB//8B4AHgPgDgAcAcAOABwBwA4AHAHADgAcAcAOAB4D4B4AH////gAP///8AAf/f/wAAfw/+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//AAAAH/+AAAA//8A4AH4HwDgAeAHgOABwAeA4AHAB4DgAcAHgOABwAeB4AHgB4HgAf///+AA////wAB///+AAB///gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB4AHgAAHgAeAAAeAB4AAB4AHgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA='),
|
||||
46,
|
||||
22,
|
||||
40+(scale<<8)+(1<<16)
|
||||
);
|
||||
return this;
|
||||
};
|
||||
|
||||
Graphics.prototype.setFontShareTechMonoSmall = function(scale) {
|
||||
// Actual height 23 (22 - 0)
|
||||
this.setFontCustom(
|
||||
atob('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/zgP/zgP/zgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPAAAPwAAPwAAAAAAPwAAPwAAPAAAAAAAAAAAAAAAAAAAAAAAAwYAP//gP//gP//gAwYAP//gP//gP//gAwYAAAAAAAAAAAAAAAAAB4AAD+BgH/Bg+HB8+DB8+DB8GD/gGB/AAAcAAAAAAAAAABAAH7AAP7AAMLAAMbAAP7AAHzfAAG/gAGxgAGxgAG/gAGfAAGAAAAAAAAAADz/AH//gP+DgMOBgMMBgMMBgMP/gAP/gAMAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAPwAAPwAAPgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//wP//8/AA+4AAGgAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAC4AAG/AB+P//8D//wAAAAAAAAAAAAAAAAAAAAAAAADAAADuAAB+AAP4AAfwAAP8AAB+AADsAADAAAAAAAAAAAAAAAAAAAADgAADgAADgAAf8AAf8AAf8AADgAADgAADgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAD+AAD4AAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAADgAADgAADgAADgAADgAADgAADgAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgAADgAADgAAAAAAAAAAAAAAAAAAAAAAAAAAAGAAAeAAD8AAfwAB+AAP4AA/AAH8AAfgAA8AAAwAAAAAAAAAAAAAAAD/+AH//APB/gMDxgMHBgMeBgP//gH//AD/+AAAAAAAAAAAAAAAAAGAAgGABgOABgOABgP//gP//gAABgAABgAABgAAAAAAAAAAAAAAAAAABgMAHgMAPgMA9gMB5gOHxgH/BgD+BgAABgAAAAAAAAAAAAAAAAAAAAMCBgMGBgMGBgMHBgP/DgH//gD5/AAAAAAAAAAAAAAAAAAAAAAD4AA/4AP/4APwYAMAYAAP/gAP/gAAcAAAYAAAAAAAAAAAAAAAAAAAAAP+BgP+BgMGBgMGBgMHDgMH/gMD/AAAAAAAAAAAAAAAAAAAAAD/+AH//AP//gMMBgMMBgMOBgMP/gMH/AAD+AAAAAAAAAAAAAAAAAMAAAMAAAMADgMAfgMH/AM/4AP/AAPwAAGAAAAAAAAAAAAAAAAAAAD5/AH//gP/DgMHBgMGBgMHBgP/jgH//gD5/AAAAAAAAAAAAAAAAAD+AAH/AgP/hgMBhgMBhgMBhgP//gH//AD/+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcDgAcDgAcDgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAcD+AcD4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAHgAAHgAAPwAAMwAAc4AAY4AA4cAA4cABwMAAAAAAAAAAAAAAAAAAMYAAMYAAMYAAMYAAMYAAMYAAMYAAMYAAMYAAAAAAAAAAAAAAAAABwMAA4cAA4cAAY4AAc4AAMwAAPwAAHgAAHgAAAAAAAAAAAAAAAAAAAAAMAAAMABgMDzgMHzgOeAAH8AAD4AAAAAAAAAAAAAAB/8AH//AP//gMHhgMf5gM/9gMwNgM/5gM/8gMAMAP/8AH/8AA/wAAAAAAADgAA/gAP/gD/4AP8YAPAYAP8YAD/4AAP/gAA/gAADgAAAAAAAAAAAAP//gP//gMGBgMGBgMGBgMGBgP/DgH//gD5/AAAAAAAAAAAAAAAAAB/8AH//AP//gOABgMABgMABgMABgMABgMABgAAAAAAAAAAAAAAAAP//gP//gMABgMABgMABgMABgOADgH//gH//AAAAAAAAAAAAAAAAAP//gP//gP//gMGBgMGBgMGBgMGBgMGBgMABgAAAAAAAAAAAAAAAAP//gP//gP//gMHAAMHAAMHAAMHAAMHAAMAAAAAAAAAAAAAAAAAAAD/+AH//AP//gMABgMDBgMDBgMD/gMD/gAD/gAAAAAAAAAAAAAAAAP//gP//gAHAAAHAAAHAAAHAAAHAAP//gP//gAAAAAAAAAAAAAAAAAAAAMABgMABgP//gP//gP//gMABgMABgAAAAAAAAAAAAAAAAAAAAAAAAAABgMABgMABgMABgMAHgP//AP/+AAAAAAAAAAAAAAAAAAAAAP//gP//gAPAAAfgAB/4ADw+APAfgOAHgIABgAAAAAAAAAAAAAAAAAAAAP//gP//gAABgAABgAABgAABgAABgAAAAAAAAAAAAAAAAP//gP//gPgAAP+AAB/gAAHwAB/gAP8AAPgAAP//gP//gAAAAAAAAAAAAP//gP//gPwAAP/AAA/8AAD/gAAPgP//gP//gAAAAAAAAAAAAA/8AH//AH//gOADgMABgMABgMABgOADgH//gH//AA/4AAAAAAAAAAAAAP//gP//gMDgAMDgAMDgAMDgAP/AAH/AAD+AAAAAAAAAAAAAAA/8AH//AH//gOADgMABgMABgMABgOADgH//gH//wA/4wAAAAAAAAH//gP//gP//gMDAAMDAAMDgAOD8AP//AH+PgB4DgAAAgAAAAAAAAAAAAD4AAH+BgP+BgOGBgMHBgMHBgMH/gMD/AAA+AAAAAAAAAAAAAMAAAMAAAMAAAMAAAP//gP//gP//gMAAAMAAAMAAAMAAAAAAAAAAAAAAAP//AP//gAADgAABgAABgAABgAADgP//gP//AAAAAAAAAAAAAMAAAP4AAP/wAA//AAB/gAAHgAD/gB/+AP/AAPwAAIAAAAAAAAAAAP/gAP//gAP/gAAfgAH+AAHwAAD/gAAfgAf/gP//gP8AAAAAAAAAAAAAgOADgPgPgH4+AB/4AAfwAB/4AH4/APgPgOADgAAAgAAAAAAAAMAAAPAAAPwAAD8AAA//gAP/gAf/gD8AAPwAAPAAAIAAAAAAAAAAAAAAAMADgMAPgMA/gMD5gMPhgM+BgP4BgPgBgOABgAAAAAAAAAAAAAAAAAAAAAAAA///+///+wAAGwAAGwAAGAAAAAAAAAAAAAAAAAAAAwAAA+AAAfgAAH8AAA/AAAP4AAB+AAAPwAAD8AAAeAAAGAAAAAAAAAAAAAAAAAAAAwAAGwAAGwAAG///+///+AAAAAAAAAAAAAAAAAAAAAAAAA4AAD4AAPwAAeAAAYAAAeAAAPwAAD4AAAYAAAAAAAAAAAAAGAAAGAAAGAAAGAAAGAAAGAAAGAAAGAAAGAAAGAAAGAAAGAAAGAAAAAAAAAAAAAAAAIAAAMAAAOAAAGAAACAAAAAAAAAAAAAAAAAAAAAAAAAOAAY/gAY/gAZxgAZxgAZxgAZxgAf/gAP/gAABgAAAgAAAAAAAAAAAAP//gP//gAcBgAYBgAYBgAYBgAcDgAf/gAP/AAAAAAAAAAAAAAAAAAAAAAP/AAf/gAYBgAYBgAYBgAYBgAYBgAAAAAAAAAAAAAAAAAAAAAP/AAf/gAcDgAYBgAYBgAYBgAYDgP//gP//gAAAAAAAAAAAAAAAAAP+AAf/gAf/gAYxgAYxgAYxgAfxgAPxgAHwAAAAAAAAAAAAAAAAAAYBgAYBgD//gP//gP//gMYBgMYBgMYBgMQAAAAAAAAAAAAAAAAAAAPwGAf/GAYfGAYfGAYfGAYfGAY7mAf7+Afx8AAAAAAAAAAAAAAAAP//gP//gAcAAAYAAAYAAAYAAAcAAAf/gAP/gAAAAAAAAAAAAAAAAAYAAAYAAAYAAMf/gOf/gMf/gAABgAABgAABgAAAAAAAAAAAAAAAAAAAAAAAGAYAGAYAGAYAGMf/+Of/+Mf/8AAAAAAAAAAAAAAAAAAAAP//gP//gP//gADwAAH8AAefAAcHgAYDgAQAgAAAAAAAAAAAAEAAAMAAAMAAAMAAAP//AP//gAADgAABgAABgAABgAAAgAAAAAAAAAf/gAf/gAYAAAYAAAf/gAf/gAf/gAYAAAYAAAf/gAP/gAAAAAAAAAAAAAf/gAf/gAcAAAYAAAYAAAYAAAcAAAf/gAP/gAAAAAAAAAAAAAAAAAP/AAf/gAcDgAYBgAYBgAYBgAcDgAf/gAP/AAAAAAAAAAAAAAAAAAf/+Af/+AcBgAYBgAYBgAYBgAcDgAf/gAP/AAAAAAAAAAAAAAAAAAP/AAf/gAcDgAYBgAYBgAYBgAYDgAf/+Af/+AAAAAAAAAAAAAAAAAYBgAYBgAf/gAf/gAcBgAYBgAYBgAYAAAYAAAAAAAAAAAAAAAAAAAAAAAPhgAfxgAZxgAYxgAYxgAY/gAYfAAAAAAAAAAAAAAAAAAAAAAYAAAYAAAYAAD//AD//gAYBgAYBgAYBgAYBgAAAAAAAAAAAAAAAAAf+AAf/gAf/gAABgAABgAABgAf/gAf/gAf/gAAAAAAAAAAAAAQAAAeAAAf4AAH/AAAfgAADgAAfgAH/AAf4AAeAAAQAAAAAAAAAAAfAAAf/AAD/gAAPgAD/gAH4AAH/gAAPgAD/gAf+AAfAAAAAAAAAAAAAAAYBgAcHgAfPAAH+AAD4AAH+AAfPgAcDgAQBgAAAAAAAAAAAAAQAAAeAAAfwGAH+GAA/uAAD+AAf8AH/AAf4AAeAAAQAAAAAAAAAAAAAAAABgAYHgAYPgAY/gAZ5gAfxgAfBgAeBgAYAAAAAAAAAAAAAAAAAAAAAAADgAADgAf//8/+/+4AAGwAAGwAAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf//+///+f//+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAGwAAG4AAG/+/+f//8ADgAADgAAAAAAAAAAAAAAAAAAAAAADgAADAAADAAADAAADAAADgAABgAADgAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'),
|
||||
32,
|
||||
atob("DQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0H"),
|
||||
24+(scale<<8)+(1<<16)
|
||||
);
|
||||
return this;
|
||||
};
|
||||
|
||||
{
|
||||
|
||||
// VARS
|
||||
|
||||
let FONT_NAME = "ShareTechMono";
|
||||
let BIG_FONT_HEIGHT = 60;
|
||||
//let NORMAL_FONT_HEIGHT = 40;
|
||||
let SMALL_FONT_HEIGHT = 24;
|
||||
|
||||
let timeDrawTimeout;
|
||||
let infoDrawTimeout;
|
||||
let lockState = Bangle.isLocked();
|
||||
let pressure;
|
||||
|
||||
|
||||
|
||||
// LISTENERS
|
||||
|
||||
Bangle.on('lock', function(isLocked) {
|
||||
lockState = isLocked;
|
||||
timeDraw();
|
||||
infoDraw();
|
||||
});
|
||||
|
||||
|
||||
|
||||
// DRAW FUNCTIONS
|
||||
|
||||
let timeDraw = function() {
|
||||
g.reset();
|
||||
g.clearRect(Bangle.appRect.x, Bangle.appRect.y, Bangle.appRect.x2, Bangle.appRect.y + BIG_FONT_HEIGHT);
|
||||
|
||||
var date = new Date();
|
||||
var timeArray = [date.getHours().toString().padStart(2, "0"),
|
||||
date.getMinutes().toString().padStart(2, "0")];
|
||||
if (!lockState) timeArray.push(date.getSeconds().toString().padStart(2, "0"));
|
||||
var timeString = timeArray.join(":");
|
||||
g.setFontAlign(0, 0).setColor(g.theme.fg).setFont(FONT_NAME + (lockState ? "Big" : ""));
|
||||
g.drawString(timeString, Bangle.appRect.x2/2, Bangle.appRect.y + BIG_FONT_HEIGHT/2);
|
||||
|
||||
if (timeDrawTimeout) clearTimeout(timeDrawTimeout);
|
||||
timeDrawTimeout = setTimeout(function() {
|
||||
timeDrawTimeout = undefined;
|
||||
timeDraw();
|
||||
}, (lockState ? 10000 - (Date.now() % 10000) : 1000 - (Date.now() % 1000))); // if locked, every clock's 10s, otherwise every 1s
|
||||
};
|
||||
|
||||
let infoDraw = function() {
|
||||
g.reset();
|
||||
|
||||
var date = new Date();
|
||||
var dateString = [date.getFullYear().toString().padStart(4,"0"),
|
||||
(date.getMonth()+1).toString().padStart(2,"0"),
|
||||
date.getDate().toString().padStart(2,"0")].join("-");
|
||||
|
||||
var tzOffset = -(date.getTimezoneOffset())/60;
|
||||
var tzOffsetString = (tzOffset >= 0 ? "+" + tzOffset : tzOffset);
|
||||
|
||||
var batteryString = (Bangle.isCharging() ? "+" : "") + E.getBattery() + "%";
|
||||
|
||||
var pressureString = (pressure ? pressure + "hPa" : "(hPa)");
|
||||
|
||||
var powerString = (E.getPowerUsage().total / 1000) + "mA";
|
||||
|
||||
var stepsString = Bangle.getHealthStatus("day").steps + "ST";
|
||||
|
||||
var bluetoothStatus = NRF.getSecurityStatus();
|
||||
var bluetoothString = (bluetoothStatus.connected ? bluetoothStatus.connected_addr.split(" ")[0].substr(-5) : "N/C");
|
||||
|
||||
var infoMatrix = [
|
||||
[dateString + tzOffsetString ],
|
||||
[batteryString, pressureString],
|
||||
[powerString ],
|
||||
[stepsString, bluetoothString ]
|
||||
];
|
||||
|
||||
g.clearRect(Bangle.appRect.x, Bangle.appRect.y + BIG_FONT_HEIGHT, Bangle.appRect.x2, Bangle.appRect.y2);
|
||||
g.setFontAlign(0, -1).setColor(g.theme.fg2).setFont(FONT_NAME+"Small");
|
||||
|
||||
infoMatrix.forEach((lineArray, lineNumber) => {
|
||||
g.drawString(lineArray.join(" "), Bangle.appRect.x2/2, Bangle.appRect.y + BIG_FONT_HEIGHT + SMALL_FONT_HEIGHT*lineNumber);
|
||||
});
|
||||
|
||||
Bangle.getPressure().then(baroValue => { pressure=Math.round(baroValue.pressure); });
|
||||
|
||||
if (infoDrawTimeout) clearTimeout(infoDrawTimeout);
|
||||
infoDrawTimeout = setTimeout(function() {
|
||||
infoDrawTimeout = undefined;
|
||||
infoDraw();
|
||||
}, (lockState ? 60000 : 10000)); // if locked, a minute from now, otherwise in 10s
|
||||
};
|
||||
|
||||
|
||||
|
||||
// DRAW CALLS
|
||||
|
||||
g.clear();
|
||||
|
||||
Bangle.setUI({
|
||||
mode: "clock",
|
||||
remove: function() {
|
||||
if (timeDrawTimeout) clearTimeout(timeDrawTimeout);
|
||||
timeDrawTimeout = undefined;
|
||||
if (infoDrawTimeout) clearTimeout(infoDrawTimeout);
|
||||
infoDrawTimeout = undefined;
|
||||
|
||||
delete Graphics.prototype.setFontShareTechMono;
|
||||
delete Graphics.prototype.setFontShareTechMonoBig;
|
||||
delete Graphics.prototype.setFontShareTechMonoSmall;
|
||||
}});
|
||||
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
|
||||
timeDraw();
|
||||
infoDraw();
|
||||
}
|
||||
|
After Width: | Height: | Size: 4.1 KiB |
|
|
@ -0,0 +1,18 @@
|
|||
{ "id": "denseclock",
|
||||
"name": "Dense Clock",
|
||||
"shortName":"Dense Clock",
|
||||
"version":"0.03",
|
||||
"description": "A clockface dense with text-only information. Switches between showing seconds and minutes when unlocked/locked, in the interest of saving power.",
|
||||
"icon": "app.png",
|
||||
"type": "clock",
|
||||
"tags": "clock",
|
||||
"supports" : ["BANGLEJS2"],
|
||||
"storage": [
|
||||
{"name":"denseclock.app.js","url":"app.js"},
|
||||
{"name":"denseclock.img","url":"app-icon.js","evaluate":true}
|
||||
],
|
||||
"screenshots": [
|
||||
{"url":"screenshot_locked.png"},
|
||||
{"url":"screenshot_unlocked.png"}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 3.5 KiB |
|
After Width: | Height: | Size: 3.5 KiB |
|
|
@ -6,7 +6,7 @@
|
|||
"icon": "app.png",
|
||||
"version": "0.01",
|
||||
"type": "clock",
|
||||
"tags": "clock, weather, dino, trex, chrome",
|
||||
"tags": "clock,weather,dino,trex,chrome",
|
||||
"supports": ["BANGLEJS2"],
|
||||
"allow_emulator": true,
|
||||
"readme": "README.md",
|
||||
|
|
|
|||
|
|
@ -6,3 +6,4 @@
|
|||
0.05: Enhance menu: permit toggling bluetooth
|
||||
0.06: Display clock in green when charging, with "charging" text
|
||||
0.07: Correctly restore full power when the charged threshold is reached
|
||||
0.08: Redisplay immediately on changes to charging status
|
||||
|
|
|
|||
|
|
@ -118,6 +118,7 @@ Bangle.on("charging", function (charging) {
|
|||
drainedInterval = clearInterval(drainedInterval);
|
||||
if (charging)
|
||||
drainedInterval = setInterval(checkCharge, interval * 60 * 1000);
|
||||
draw();
|
||||
});
|
||||
if (!keepStartup) {
|
||||
var storage = require("Storage");
|
||||
|
|
|
|||
|
|
@ -151,6 +151,7 @@ Bangle.on("charging", charging => {
|
|||
drainedInterval = clearInterval(drainedInterval) as undefined;
|
||||
if(charging)
|
||||
drainedInterval = setInterval(checkCharge, interval * 60 * 1000);
|
||||
draw(); // redraw to update charging status on screen
|
||||
});
|
||||
|
||||
if(!keepStartup){
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "drained",
|
||||
"name": "Drained",
|
||||
"version": "0.07",
|
||||
"version": "0.08",
|
||||
"description": "Switches to displaying a simple clock when the battery percentage is low, and disables some peripherals",
|
||||
"readme": "README.md",
|
||||
"icon": "icon.png",
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
"version": "0.02",
|
||||
"description": "Follow The Recipe (FTR) is a bangle.js app to follow a recipe step by step",
|
||||
"type": "app",
|
||||
"tags": "tool, tools, cook",
|
||||
"tags": "tool,tools,cook",
|
||||
"supports": [
|
||||
"BANGLEJS2"
|
||||
],
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
"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",
|
||||
"tags": "tool,voice,tasker",
|
||||
"supports": ["BANGLEJS","BANGLEJS2"],
|
||||
"allow_emulator": false,
|
||||
"storage": [
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
"version":"0.01",
|
||||
"description": "Disconnect from your android device by running this app. The app will forward you to your clock face immediately after triggering the command. (Gadgetbridge nightly required until version 82 is released)",
|
||||
"icon": "app.png",
|
||||
"tags": "android, gadgetbridge, bluetooth, bt",
|
||||
"tags": "android,gadgetbridge,bluetooth,bt",
|
||||
"supports" : ["BANGLEJS", "BANGLEJS2"],
|
||||
"storage": [
|
||||
{"name":"gbdiscon.app.js","url":"app.js"},
|
||||
|
|
|
|||
|
|
@ -12,3 +12,4 @@
|
|||
0.11: Use default Bangle formatter for booleans
|
||||
0.12: Issue newline before GB commands (solves issue with console.log and ignored commands)
|
||||
0.13: Upgrade to new translation system
|
||||
0.14: Fix auto-start saved state; fix clearing track number; allow widget clicks
|
||||
|
|
|
|||
|
|
@ -91,8 +91,7 @@ function rScroller(l) {
|
|||
const w = g.stringWidth(l.label)+40,
|
||||
y = l.y+l.h/2;
|
||||
l.offset = l.offset%w;
|
||||
g.setClipRect(l.x, l.y, l.x+l.w-1, l.y+l.h-1)
|
||||
.setColor(l.col).setBgColor(l.bgCol) // need to set colors: iScroll calls this function outside Layout
|
||||
g.setColor(l.col).setBgColor(l.bgCol) // need to set colors: iScroll calls this function outside Layout
|
||||
.setFontAlign(-1, 0) // left center
|
||||
.clearRect(l.x, l.y, l.x+l.w-1, l.y+l.h-1)
|
||||
.drawString(l.label, l.x-l.offset+40, y)
|
||||
|
|
@ -128,57 +127,8 @@ function rInfo(l) {
|
|||
.setFontAlign(0, -1) // center top
|
||||
.drawString(l.label, l.x+l.w/2, l.y);
|
||||
}
|
||||
/**
|
||||
* Render icon
|
||||
* @param l
|
||||
*/
|
||||
function rIcon(l) {
|
||||
const x2 = l.x+l.w-1,
|
||||
y2 = l.y+l.h-1;
|
||||
switch(l.icon) {
|
||||
case "pause": {
|
||||
const w13 = l.w/3;
|
||||
g.drawRect(l.x, l.y, l.x+w13, y2);
|
||||
g.drawRect(l.x+l.w-w13, l.y, x2, y2);
|
||||
break;
|
||||
}
|
||||
case "play": {
|
||||
g.drawPoly([
|
||||
l.x, l.y,
|
||||
x2, l.y+l.h/2,
|
||||
l.x, y2,
|
||||
], true);
|
||||
break;
|
||||
}
|
||||
case "previous": {
|
||||
const w15 = l.w*1/5;
|
||||
g.drawPoly([
|
||||
x2, l.y,
|
||||
l.x+w15, l.y+l.h/2,
|
||||
x2, y2,
|
||||
], true);
|
||||
g.drawRect(l.x, l.y, l.x+w15, y2);
|
||||
break;
|
||||
}
|
||||
case "next": {
|
||||
const w45 = l.w*4/5;
|
||||
g.drawPoly([
|
||||
l.x, l.y,
|
||||
l.x+w45, l.y+l.h/2,
|
||||
l.x, y2,
|
||||
], true);
|
||||
g.drawRect(l.x+w45, l.y, x2, y2);
|
||||
break;
|
||||
}
|
||||
default: { // red X
|
||||
console.log(`Unknown icon: ${l.icon}`);
|
||||
g.setColor("#f00")
|
||||
.drawRect(l.x, l.y, x2, y2)
|
||||
.drawLine(l.x, l.y, x2, y2)
|
||||
.drawLine(l.x, y2, x2, l.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let layout;
|
||||
function makeUI() {
|
||||
Bangle.loadWidgets();
|
||||
|
|
@ -417,7 +367,7 @@ function handleButton2Press() {
|
|||
let tCommand = {};
|
||||
/**
|
||||
* Send command and highlight corresponding control
|
||||
* @param {string} command - "play"/"pause"/"next"/"previous"/"volumeup"/"volumedown"
|
||||
* @param {"play"|"pause"|"playpause"|"next"|"previous"|"volumeup"|"volumedown"} command
|
||||
*/
|
||||
function sendCommand(command) {
|
||||
Bluetooth.println("");
|
||||
|
|
@ -433,15 +383,21 @@ function sendCommand(command) {
|
|||
drawControls();
|
||||
}
|
||||
|
||||
function handleTouch(btn, pos) {
|
||||
if (pos === undefined || pos.y >= Bangle.appRect.y) {
|
||||
togglePlay();
|
||||
}
|
||||
}
|
||||
|
||||
function togglePlay() {
|
||||
sendCommand(stat==="play" ? "pause" : "play");
|
||||
sendCommand("playpause");
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup touch+swipe for Bangle.js 1
|
||||
*/
|
||||
function touch1() {
|
||||
Bangle.on("touch", togglePlay);
|
||||
Bangle.on("touch", handleTouch);
|
||||
Bangle.on("swipe", dir => {
|
||||
sendCommand(dir===1 ? "previous" : "next");
|
||||
});
|
||||
|
|
@ -450,7 +406,7 @@ function touch1() {
|
|||
* Setup touch+swipe for Bangle.js 2
|
||||
*/
|
||||
function touch2() {
|
||||
Bangle.on("touch", togglePlay);
|
||||
Bangle.on("touch", handleTouch);
|
||||
// swiping
|
||||
let drag;
|
||||
Bangle.on("drag", e => {
|
||||
|
|
@ -483,10 +439,9 @@ function startLCDWatch() {
|
|||
Bangle.on("lcdPower", (on) => {
|
||||
if (on) {
|
||||
// redraw and resume scrolling
|
||||
tick();
|
||||
layout.render();
|
||||
fadeOut();
|
||||
if (offset.offset!==null) {
|
||||
if (layout.title.offset!==null) { // Making an assumption about what offset.offset was supposed to be
|
||||
if (!iScroll) {
|
||||
iScroll = setInterval(scroll, 200);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
setTimeout( // make other boot code run first, so we override e.g. android.boot.js GB
|
||||
() => {
|
||||
const APP = global.__FILE__==="gbmusic.app.js",
|
||||
const APP = globalThis.__FILE__==="gbmusic.app.js",
|
||||
a = !!(require("Storage").readJSON("gbmusic.json", 1) || {}).autoStart;
|
||||
|
||||
let s, i; // state, info
|
||||
|
|
@ -10,7 +10,7 @@ setTimeout( // make other boot code run first, so we override e.g. android.boot.
|
|||
* Only runs while other apps are loaded
|
||||
*/
|
||||
function check() {
|
||||
if (s!=="play" || !i || !a || !Bangle.CLOCK) return; // only launch app if we know which song we are playing, and autoLoad is enabled
|
||||
if ((!s || s.state!=="play") || !i || !a || !Bangle.CLOCK) return; // only launch app if we know which song we are playing, and autoLoad is enabled
|
||||
delete (i.t);
|
||||
// store info and launch music app
|
||||
require("Storage").writeJSON("gbmusic.load.json", {
|
||||
|
|
@ -20,18 +20,19 @@ setTimeout( // make other boot code run first, so we override e.g. android.boot.
|
|||
load("gbmusic.app.js");
|
||||
}
|
||||
|
||||
global.GB = (_GB => e => {
|
||||
|
||||
globalThis.GB = (_GB => e => {
|
||||
// we eat music events!
|
||||
switch(e.t) {
|
||||
case "musicinfo":
|
||||
i = e;
|
||||
return APP ? info(e) : check();
|
||||
return APP ? globalThis.info(e) : check();
|
||||
case "musicstate":
|
||||
s = e.state;
|
||||
return APP ? state(e) : check();
|
||||
s = e;
|
||||
return APP ? globalThis.state(e) : check();
|
||||
default:
|
||||
// pass on other events
|
||||
if (_GB) setTimeout(_GB, 0, e);
|
||||
}
|
||||
})(global.GB);
|
||||
})(globalThis.GB);
|
||||
}, 1);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"id": "gbmusic",
|
||||
"name": "Gadgetbridge Music Controls",
|
||||
"shortName": "Music Controls",
|
||||
"version": "0.13",
|
||||
"version": "0.14",
|
||||
"description": "Control the music on your Gadgetbridge-connected phone",
|
||||
"icon": "icon.png",
|
||||
"screenshots": [{"url":"screenshot_v1_d.png"},{"url":"screenshot_v1_l.png"},
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@
|
|||
"version": "0.03",
|
||||
"description": "This app will provide you with on course data to support your golf game!",
|
||||
"icon": "golfview.png",
|
||||
"tags": "outdoors, gps",
|
||||
"tags": "outdoors,gps",
|
||||
"allow_emulator": true,
|
||||
"supports" : ["BANGLEJS2"],
|
||||
"supports" : ["BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
"custom": "custom.html",
|
||||
"storage": [
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
0.01: New Widget!
|
||||
0.02: rename, new icon, settings menu!
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
# Grandfather Clock
|
||||
|
||||
A widget that runs in the background and chimes on every (configurable) fraction of an hour, similar to Chimer, and counts out the fractions and the o'clock hour.
|
||||
|
||||
## Usage
|
||||
|
||||
Once installed, see the App Settings page for options.
|
||||
|
||||
Defaults:
|
||||
- Twelve hour mode is ENABLED.
|
||||
- Swap meridian is DISABLED. (in the AM, there will be a single buzz after counting the hours. in the PM, there will be two buzzes after counting the hours)
|
||||
- The attention buzz for the hour chime is 1000ms long.
|
||||
- The buzz for each hour count is 250ms long.
|
||||
- The buzz for each fraction count is 250ms long.
|
||||
- The widget will count out 4 fractions of an hour (a 15 min interval).
|
||||
- The time between count buzzes is 500ms.
|
||||
- The meridian buzzes are 50ms long.
|
||||
- The time between meridian buzzes is 300ms.
|
||||
|
||||
## Requests
|
||||
|
||||
Drop me a message at @yogsoy on Discord if you need help / discover a bug that I can squash for you.
|
||||
|
||||
## Creator
|
||||
|
||||
Written by June B (yogsoy), inspired by aaronrolls' Chimer.
|
||||
|
After Width: | Height: | Size: 979 B |
|
|
@ -0,0 +1,18 @@
|
|||
{ "id": "grandfatherclock",
|
||||
"name": "Grandfather Clock Widget",
|
||||
"shortName":"Grandfather Clock",
|
||||
"version":"0.02",
|
||||
"description": "A widget that chimes every fraction of an hour (similar to Chimer), and counts out the fractions and the o'clock hour.",
|
||||
"icon": "icon.png",
|
||||
"type": "widget",
|
||||
"tags": "widget",
|
||||
"supports" : ["BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
"storage": [
|
||||
{"name":"grandfatherclock.wid.js","url":"widget.js"},
|
||||
{"name":"grandfatherclock.settings.js","url":"settings.js"}
|
||||
],
|
||||
"data": [
|
||||
{"name":"grandfatherclock.json"}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
(function(back) {
|
||||
|
||||
const configFile = "grandfatherclock.json";
|
||||
|
||||
let config = Object.assign({
|
||||
draw_widget: true,
|
||||
twelve_hour: true,
|
||||
swap_meridian: false,
|
||||
hour_attention_buzz_ms: 1000,
|
||||
hour_count_buzz_ms: 250,
|
||||
fraction_count_buzz_ms: 250,
|
||||
fractions_of_hour: 4, // 4 = 15min intervals, 6 = 10min intervals
|
||||
wait_ms: 500,
|
||||
meridian_buzz_ms: 50,
|
||||
meridian_buzz_wait_ms: 300
|
||||
}, require('Storage').readJSON("grandfatherclock.json", true) || {});
|
||||
|
||||
let writeConfig = function() {
|
||||
require('Storage').writeJSON(configFile, config);
|
||||
};
|
||||
|
||||
E.showMenu({
|
||||
"": {"title" : "Grandfather Clock"},
|
||||
"< Back": () => back(),
|
||||
"Draw widget": {
|
||||
value: config.draw_widget,
|
||||
onchange: v => {
|
||||
config.draw_widget = v;
|
||||
writeConfig();
|
||||
}
|
||||
},
|
||||
"12 hour": {
|
||||
value: config.twelve_hour,
|
||||
onchange: v => {
|
||||
config.twelve_hour = v;
|
||||
writeConfig();
|
||||
}
|
||||
},"Swap meridian": {
|
||||
value: config.swap_meridian,
|
||||
onchange: v => {
|
||||
config.swap_meridian = v;
|
||||
writeConfig();
|
||||
}
|
||||
},"Hr attn. buzz length (ms)": {
|
||||
value: config.hour_attention_buzz_ms,
|
||||
onchange: v => {
|
||||
config.hour_attention_buzz_ms = v;
|
||||
writeConfig();
|
||||
}
|
||||
},"Hr count buzz (ms)": {
|
||||
value: config.hour_count_buzz_ms,
|
||||
onchange: v => {
|
||||
config.hour_count_buzz_ms = v;
|
||||
writeConfig();
|
||||
}
|
||||
},"Frac. count buzz (ms)": {
|
||||
value: config.fraction_count_buzz_ms,
|
||||
onchange: v => {
|
||||
config.fraction_count_buzz_ms = v;
|
||||
writeConfig();
|
||||
}
|
||||
},"Fracs. of hour": {
|
||||
value: config.fractions_of_hour,
|
||||
onchange: v => {
|
||||
config.fractions_of_hour = v;
|
||||
writeConfig();
|
||||
}
|
||||
},"Count wait (ms)": {
|
||||
value: config.wait_ms,
|
||||
onchange: v => {
|
||||
config.wait_ms = v;
|
||||
writeConfig();
|
||||
}
|
||||
},"Meridian buzz (ms)": {
|
||||
value: config.meridian_buzz_ms,
|
||||
onchange: v => {
|
||||
config.meridian_buzz_ms = v;
|
||||
writeConfig();
|
||||
}
|
||||
},"Meridian wait (ms)": {
|
||||
value: config.meridian_buzz_wait_ms,
|
||||
onchange: v => {
|
||||
config.meridian_buzz_wait_ms = v;
|
||||
writeConfig();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
})
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
(() => {
|
||||
|
||||
// sensible defaults
|
||||
let config = Object.assign({
|
||||
draw_widget: true,
|
||||
twelve_hour: true,
|
||||
swap_meridian: false,
|
||||
hour_attention_buzz_ms: 1000,
|
||||
hour_count_buzz_ms: 250,
|
||||
fraction_count_buzz_ms: 250,
|
||||
fractions_of_hour: 4, // 4 = 15min intervals, 6 = 10min intervals
|
||||
wait_ms: 500,
|
||||
meridian_buzz_ms: 50,
|
||||
meridian_buzz_wait_ms: 300
|
||||
}, require('Storage').readJSON("grandfatherclock.json", true) || {}); // or, load the app settings file.
|
||||
|
||||
WIDGETS["grandfatherclock"] = {
|
||||
area: "tr",
|
||||
width: config.draw_widget ? 16 : 0,
|
||||
draw: function() {
|
||||
if (config.draw_widget) {
|
||||
g.reset();
|
||||
g.drawImage(atob("EBiDASSTJJISSSSZJJJCSSTJ///ISSZP///5CTJ/////ITJ/////ITJ/+B//ITJ/+B//ITJ//+P/ITJ/////ISZP///5CSRJ///ICSQJJJJACSYBJJIBCSYABgABCSYABgABCSYAJAABCSYANgABCSYBtgABCSYNtsABCSYBtgABCSYAMAABCSYAAAABCSZJJJJJCQ=="), this.x, this.y);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let date;
|
||||
let fractionMs = 3600000 / config.fractions_of_hour;
|
||||
|
||||
let chime = function () {
|
||||
date = new Date();
|
||||
let hourFrac = Math.floor(date.getMinutes() / (60 / config.fractions_of_hour));
|
||||
|
||||
if (hourFrac == 0) { // if it's an o'clock hour
|
||||
let chimeHour = (config.twelve_hour ? date.getHours() % 12 : date.getHours());
|
||||
if (chimeHour == 0) (config.twelve_hour ? chimeHour += 12 : chimeHour += 24);
|
||||
|
||||
Bangle.buzz(config.hour_attention_buzz_ms).then(() => { // initial buzz
|
||||
setTimeout(hourChime, config.wait_ms, chimeHour); // wait a period before doing the first chime
|
||||
});
|
||||
} else { // if it's a fraction of an hour
|
||||
fractionChime(hourFrac);
|
||||
}
|
||||
|
||||
queueNextChime();
|
||||
};
|
||||
|
||||
let hourChime = function (hoursLeftToChime) {
|
||||
hoursLeftToChime--;
|
||||
Bangle.buzz(config.hour_count_buzz_ms).then(() => { // recursive. buzz and wait to do the next buzz.
|
||||
if (hoursLeftToChime > 0) {
|
||||
setTimeout(hourChime, config.wait_ms, hoursLeftToChime);
|
||||
} else if (config.twelve_hour) { // once finished with the hour count
|
||||
setTimeout(meridianChime, config.wait_ms, (date.getHours() >= 12)); // if in twelve hour mode, queue up the meridian chime.
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
let fractionChime = function (fractionsLeftToChime) {
|
||||
fractionsLeftToChime--;
|
||||
Bangle.buzz(config.fraction_count_buzz_ms).then(() => { // recursive. buzz and wait to do the next buzz.
|
||||
if (fractionsLeftToChime > 0) setTimeout(fractionChime, config.wait_ms, fractionsLeftToChime);
|
||||
});
|
||||
};
|
||||
|
||||
let meridianChime = function (meridian) {
|
||||
if ((config.swap_meridian ? !meridian : meridian)) { // default: if PM
|
||||
Bangle.buzz(config.meridian_buzz_ms).then(setTimeout(Bangle.buzz, config.meridian_buzz_wait_ms, config.meridian_buzz_ms)); // buzz once, wait, buzz again.
|
||||
} else { // default: if AM
|
||||
Bangle.buzz(config.meridian_buzz_ms); // buzz once.
|
||||
}
|
||||
};
|
||||
|
||||
let queueNextChime = function () {
|
||||
let msUntilNextFraction = fractionMs - (Date.now() % fractionMs);
|
||||
setTimeout(chime, msUntilNextFraction);
|
||||
};
|
||||
|
||||
queueNextChime();
|
||||
})()
|
||||
|
|
@ -4,8 +4,8 @@
|
|||
"version": "0.03",
|
||||
"description": "Wrist mounted guitar chords",
|
||||
"icon": "app.png",
|
||||
"tags": "guitar, chords",
|
||||
"supports" : ["BANGLEJS2"],
|
||||
"tags": "guitar,chords",
|
||||
"supports" : ["BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
"storage": [
|
||||
{"name":"guitar.app.js","url":"app.js"},
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
"description": "Songs lyrics and guitar chords",
|
||||
"icon": "app.png",
|
||||
"screenshots": [{"url": "screenshot.png"}],
|
||||
"tags": "guitar, song, lyrics, chords",
|
||||
"tags": "guitar,song,lyrics,chords",
|
||||
"supports" : ["BANGLEJS2"],
|
||||
"interface": "manage_songs.html",
|
||||
"readme": "README.md",
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
/* eslint-env node */
|
||||
|
||||
var imageconverter = require("../../../webtools/imageconverter.js").imageconverter;
|
||||
var imageconverter = require("../../../webtools/imageconverter.js");
|
||||
var icons = JSON.parse(require("fs").readFileSync(__dirname+"/icon_names.json"));
|
||||
const imgOptions = {
|
||||
mode : "1bit",
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
"icon": "app.png",
|
||||
"version":"0.01",
|
||||
"description": "Interval Timer for workouts, HIIT, or whatever else.",
|
||||
"tags": "timer, interval, hiit, workout",
|
||||
"tags": "timer,interval,hiit,workout",
|
||||
"readme":"README.md",
|
||||
"supports":["BANGLEJS2"],
|
||||
"storage": [
|
||||
|
|
|
|||
|
|
@ -1,23 +1,23 @@
|
|||
{
|
||||
{
|
||||
"id": "kanagsec",
|
||||
"name": "Kanagawa clock",
|
||||
"shortName":"kanagawa",
|
||||
"version": "0.04",
|
||||
"description": "A clock that displays the great wave of kanagawa (image from wikipedia) with seconds in active mode.",
|
||||
"icon": "app.png",
|
||||
"tags": "clock, kanagawa, wave",
|
||||
"tags": "clock,kanagawa,wave",
|
||||
"type": "clock",
|
||||
"supports" : ["BANGLEJS2"],
|
||||
"supports" : ["BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
"allow_emulator":true,
|
||||
"storage":
|
||||
"storage":
|
||||
[
|
||||
{"name":"kanagsec.app.js","url":"app.js"},
|
||||
{"name":"kanagsec.img","url":"app-icon.js","evaluate":true}
|
||||
],
|
||||
"screenshots" :
|
||||
"screenshots" :
|
||||
[
|
||||
{ "url":"screenshot.png" },
|
||||
{ "url":"screenshot2.png" }
|
||||
{ "url":"screenshot2.png" }
|
||||
]
|
||||
}
|
||||
|
|
@ -261,7 +261,7 @@ var locales = {
|
|||
ampm: { 0: "am", 1: "pm" },
|
||||
timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" },
|
||||
datePattern: { 0: "%d %B %Y", "1": "%d/%m/%Y" }, // 1 mars 2020 // 01/03/2020
|
||||
abmonth: "janv,févr,mars,avril,mai,juin,juil,août,sept,oct,nov,déc",
|
||||
abmonth: "janv,févr,mars,avr,mai,juin,juil,août,sept,oct,nov,déc",
|
||||
month: "janvier,février,mars,avril,mai,juin,juillet,août,septembre,octobre,novembre,décembre",
|
||||
abday: "dim,lun,mar,mer,jeu,ven,sam",
|
||||
day: "dimanche,lundi,mardi,mercredi,jeudi,vendredi,samedi",
|
||||
|
|
@ -423,7 +423,7 @@ var locales = {
|
|||
ampm: { 0: "am", 1: "pm" },
|
||||
timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" },
|
||||
datePattern: { 0: "%A %B %d %Y", "1": "%d/%m/%y" }, // dimanche 1 mars 2020 // 01/03/20
|
||||
abmonth: "janv.,févr.,mars,avril,mai,juin,juil.,août,sept.,oct.,nov.,déc.",
|
||||
abmonth: "janv,févr,mars,avr,mai,juin,juil,août,sept,oct,nov,déc",
|
||||
month: "janvier,février,mars,avril,mai,juin,juillet,août,septembre,octobre,novembre,décembre",
|
||||
abday: "dim,lun,mar,mer,jeu,ven,sam",
|
||||
day: "dimanche,lundi,mardi,mercredi,jeudi,vendredi,samedi",
|
||||
|
|
@ -452,7 +452,7 @@ var locales = {
|
|||
speed: "kmh",
|
||||
distance: { 0: "m", 1: "km" },
|
||||
temperature: "°C",
|
||||
ampm: { 0: "vorm", 1: " nachm" },
|
||||
ampm: { 0: "vorm", 1: "nachm" },
|
||||
timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" },
|
||||
datePattern: { 0: "%A, %d. %B %Y", "1": "%d.%m.%Y" }, // Sonntag, 1. März 2020 // 1.3.2020
|
||||
abmonth: "Jan,Feb,März,Apr,Mai,Jun,Jul,Aug,Sep,Okt,Nov,Dez",
|
||||
|
|
@ -471,7 +471,7 @@ var locales = {
|
|||
ampm: { 0: "AM", 1: "PM" },
|
||||
timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" },
|
||||
datePattern: { 0: "%A %d %B %Y", "1": "%d/%m/%y" }, // dimanche 1 mars 2020 // 01/03/20
|
||||
abmonth: "janv.,févr.,mars,avril,mai,juin,juil.,août,sept.,oct.,nov.,déc.",
|
||||
abmonth: "janv,févr,mars,avr,mai,juin,juil,août,sept,oct,nov,déc",
|
||||
month: "janvier,février,mars,avril,mai,juin,juillet,août,septembre,octobre,novembre,décembre",
|
||||
abday: "dim,lun,mar,mer,jeu,ven,sam",
|
||||
day: "dimanche,lundi,mardi,mercredi,jeudi,vendredi,samedi",
|
||||
|
|
@ -567,7 +567,7 @@ var locales = {
|
|||
ampm: { 0: "am", 1: "pm" },
|
||||
timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" },
|
||||
datePattern: { 0: "%A %d %B de %Y", "1": "%d/%m/%Y" }, // dimenge 1 de març de 2020 // 01/03/2020
|
||||
abmonth: "gen.,febr.,març,abril,mai,junh,julh,ago.,set.,oct.,nov.,dec.",
|
||||
abmonth: "gen,febr,març,abril,mai,junh,julh,ago,set,oct,nov,dec",
|
||||
month: "genièr,febrièr,març,abril,mai,junh,julhet,agost,setembre,octòbre,novembre,decembre",
|
||||
abday: "dg,dl,dm,dc,dj,dv,ds",
|
||||
day: "dimenge,diluns,dimars,dimècres,dijòus,divendres,dissabte",
|
||||
|
|
@ -612,10 +612,10 @@ var locales = {
|
|||
speed: "km/h",
|
||||
distance: { 0: "m", 1: "km" },
|
||||
temperature: "°C",
|
||||
ampm: { 0: "dop.", 1: "pop." },
|
||||
ampm: { 0: "dop", 1: "pop" },
|
||||
timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" },
|
||||
datePattern: { 0: "%-d. %b %Y", 1: "%-d.%-m.%Y" }, // "3. jan. 2020" // "3.1.2020"(short)
|
||||
abmonth: "sij.,velj.,ožu.,tra.,svi,lip.,srp.,kol.,ruj.,lis.,stu.,pro.",
|
||||
abmonth: "sij,velj,ožu,tra,svi,lip,srp,kol,ruj,lis,stu,pro",
|
||||
month: "siječanj,veljača,ožujak,travanj,svibanj,lipanj,srpanj,kolovoz,rujan,listopad,studeni,prosinac",
|
||||
abday: "ned.,pon.,uto.,sri.,čet.,pet.,sub.",
|
||||
day: "nedjelja,ponedjeljak,utorak,srijeda,četvrtak,petak,subota",
|
||||
|
|
@ -628,7 +628,7 @@ var locales = {
|
|||
speed: "km/h",
|
||||
distance: { 0: "m", 1: "km" },
|
||||
temperature: "°C",
|
||||
ampm: { 0: "dop.", 1: "pop." },
|
||||
ampm: { 0: "dop", 1: "pop" },
|
||||
timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" },
|
||||
datePattern: { 0: "%-d. %b %Y", 1: "%-d.%-m.%Y" }, // "3. jan. 2020" // "3.1.2020"(short)
|
||||
abmonth: "jan.,feb.,mar.,apr.,maj,jun.,jul.,avg.,sep.,okt.,nov.,dec.",
|
||||
|
|
@ -728,7 +728,7 @@ var locales = {
|
|||
ampm: { 0: "am", 1: "pm" },
|
||||
timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" },
|
||||
datePattern: { 0: "%d %B %Y", "1": "%d/%m/%y" },
|
||||
abmonth: "gen.,febr.,març,abr.,maig,juny,jul.,ag.,set.,oct.,nov.,des.",
|
||||
abmonth: "gen,febr,març,abr,maig,juny,jul,ag,set,oct,nov,des",
|
||||
month: "gener,febrer,març,abril,maig,juny,juliol,agost,setembre,octubre,novembre,desembre",
|
||||
abday: "dg.,dl.,dt.,dc.,dj.,dv.,ds.",
|
||||
day: "diumenge,dilluns,dimarts,dimecres,dijous,divendres,dissabte",
|
||||
|
|
|
|||
|
|
@ -15,6 +15,6 @@
|
|||
{"name":"messagesoverlay.settings.js","url":"settings.js"},
|
||||
{"name":"messagesoverlay.default.json","url":"default.json"}
|
||||
],
|
||||
"data": [{"name":"bthrm.json"}],
|
||||
"data":[{"name":"messagesoverlay.json"}],
|
||||
"screenshots": [{"url":"screen_call.png"} ,{"url":"screen_message.png"} ]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,3 +30,8 @@
|
|||
1.28: increased vibration strength, added some comments, & some QOL
|
||||
1.29: changed image
|
||||
1.30: changed image, again
|
||||
1.40: added various settings for controlling when & how to throw dice
|
||||
1.41: fixed dumb mistake
|
||||
1.42: okay maby I should've read the *whole* error log
|
||||
1.43: playing whackamole with ESLint
|
||||
1.44: fixed (?) settings app
|
||||
|
|
|
|||
|
|
@ -1,12 +1,20 @@
|
|||
var menu = true; // default to have the selection menu open
|
||||
var settings = Object.assign({
|
||||
vibrate: true,
|
||||
shake: true,
|
||||
screen: false,
|
||||
shake_timeout: 200,
|
||||
shake_duration: 100,
|
||||
}, require('Storage').readJSON("multidice.json", true) || {});
|
||||
|
||||
var menu = true; // defaults to having the menu open
|
||||
const DICE_ARRAY = [0, 4, 6, 8, 10, 12, 20, 100]; // 0 means nothing selected
|
||||
const SELECTION_ARRAY = [6, 0, 0, 0, 0, 0, 0, 0]; // default to selecting a single d20
|
||||
|
||||
// function to draw the selection menu
|
||||
function drawMenu() {
|
||||
|
||||
stringArr = new Array ("", "", "", "", "", "", "", "");
|
||||
for (i = 0; i < 8; i++) {
|
||||
var stringArr = new Array ("", "", "", "", "", "", "", "");
|
||||
for (var i = 0; i < 8; i++) {
|
||||
|
||||
if (SELECTION_ARRAY [i] != 0) {
|
||||
|
||||
|
|
@ -41,6 +49,7 @@ function touchHandler (button, xy) {
|
|||
return;
|
||||
}
|
||||
|
||||
var selection;
|
||||
if (xy.x <= 87) { // left
|
||||
|
||||
if (xy.y <= 43) { // first
|
||||
|
|
@ -84,15 +93,30 @@ function touchHandler (button, xy) {
|
|||
drawMenu();
|
||||
}
|
||||
|
||||
var shaken = false;
|
||||
var last_shaken = null;
|
||||
function accelHandler (xyz) {
|
||||
|
||||
// if the screen should be on *and* it isn't, return
|
||||
if (settings.screen && ! Bangle.isBacklightOn()) {
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (xyz.diff >= 0.3) {
|
||||
|
||||
menu = false;
|
||||
mutex (rollDice).catch (() => {
|
||||
shaken = true;
|
||||
last_shaken = Date.now();
|
||||
} else if (shaken && last_shaken !== null) {
|
||||
|
||||
if (Date.now() - last_shaken > settings.shake_timeout) {
|
||||
|
||||
return; // not necessary, but prevents spamming the logs
|
||||
});
|
||||
last_shaken = null;
|
||||
shaken = false;
|
||||
menu = false;
|
||||
|
||||
mutex (rollDice).catch (() => { return; });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -123,8 +147,8 @@ function mutex (functionRef) {
|
|||
// function to roll all selected dice, and display them
|
||||
function rollDice() {
|
||||
|
||||
resultsArr = new Uint8Array (8);
|
||||
for (i = 0; i < 8; i++) {
|
||||
var resultsArr = new Uint8Array (8);
|
||||
for (var i = 0; i < 8; i++) {
|
||||
|
||||
if (SELECTION_ARRAY [i] != 0) {
|
||||
|
||||
|
|
@ -135,7 +159,7 @@ function rollDice() {
|
|||
g.clear();
|
||||
g.setFont ("Vector", 40);
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
for (var i = 0; i < 4; i++) {
|
||||
|
||||
if (SELECTION_ARRAY [i] != 0) {
|
||||
|
||||
|
|
@ -143,7 +167,7 @@ function rollDice() {
|
|||
}
|
||||
}
|
||||
|
||||
for (i = 4; i < 8; i++) {
|
||||
for (var i = 4; i < 8; i++) {
|
||||
|
||||
if (SELECTION_ARRAY [i] != 0) {
|
||||
|
||||
|
|
@ -157,14 +181,19 @@ function rollDice() {
|
|||
// triggers the vibration, then pauses before returning
|
||||
function vibrate() {
|
||||
|
||||
if (! settings.vibrate) {
|
||||
|
||||
return (Promise.resolve (0));
|
||||
}
|
||||
|
||||
return new Promise ((resolve, reject) => {
|
||||
|
||||
return Bangle.buzz (50, 1).then ((value) => {
|
||||
return Bangle.buzz (settings.shake_duration, 1).then ((value) => {
|
||||
|
||||
setTimeout (() => {
|
||||
|
||||
resolve (value);
|
||||
}, 200);
|
||||
}, 2 * settings.shake_duration + settings.shake_timeout);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
@ -177,7 +206,7 @@ function random (max) {
|
|||
|
||||
drawMenu();
|
||||
Bangle.on ('touch', touchHandler);
|
||||
Bangle.on ('accel', accelHandler);
|
||||
if (settings.shake) { Bangle.on ('accel', accelHandler); }
|
||||
setWatch (function() {
|
||||
|
||||
menu = false;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{ "id": "multidice",
|
||||
"name": "multiple dice roller",
|
||||
"shortName":"multidice",
|
||||
"version":"1.30",
|
||||
"version":"1.44",
|
||||
"description": "roll anywhere from 1-8 dice at the same time",
|
||||
"icon": "app.png",
|
||||
"tags": "tool,game",
|
||||
|
|
@ -10,6 +10,8 @@
|
|||
"allow_emulator": true,
|
||||
"storage": [
|
||||
{"name":"multidice.app.js","url":"app.js"},
|
||||
{"name":"multidice.settings.js","url":"settings.js"},
|
||||
{"name":"multidice.img","url":"app-icon.js","evaluate":true}
|
||||
]
|
||||
],
|
||||
"data": [{"name": "multidice.json"}]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,58 @@
|
|||
(function(back) {
|
||||
var settings = Object.assign({
|
||||
vibrate: true,
|
||||
shake: true,
|
||||
screen: false,
|
||||
shake_timeout: 200,
|
||||
shake_duration: 100,
|
||||
}, require('Storage').readJSON("multidice.json", true) || {});
|
||||
|
||||
function writeSettings() {
|
||||
require('Storage').writeJSON("multidice.json", settings);
|
||||
}
|
||||
|
||||
// Show the menu
|
||||
E.showMenu({
|
||||
"" : { "title" : "multi dice roll" },
|
||||
"< Back" : () => back(),
|
||||
'vibrate on roll?': {
|
||||
value: !!settings.vibrate,
|
||||
onchange: v => {
|
||||
settings.vibrate = v;
|
||||
writeSettings();
|
||||
}
|
||||
},
|
||||
'allow shaking?': {
|
||||
value: !!settings.shake,
|
||||
onchange: v => {
|
||||
settings.shake = v;
|
||||
writeSettings();
|
||||
}
|
||||
},
|
||||
'screen on to shake?': {
|
||||
value: !!settings.screen,
|
||||
onchange: v => {
|
||||
settings.screen = v;
|
||||
writeSettings();
|
||||
}
|
||||
},
|
||||
'shake timeout': {
|
||||
value: settings.shake_timeout / 5,
|
||||
min: 10, max: 40,
|
||||
format: v => v * 5,
|
||||
onchange: v => {
|
||||
settings.shake_timeout = v * 5;
|
||||
writeSettings();
|
||||
}
|
||||
},
|
||||
'shake duration': {
|
||||
value: settings.shake_duration / 5,
|
||||
min: 10, max: 40,
|
||||
format: v => v * 5,
|
||||
onchange: v => {
|
||||
settings.shake_duration = v * 5;
|
||||
writeSettings();
|
||||
}
|
||||
},
|
||||
});
|
||||
})
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
"description": "A smart and simple calculator for Ohm's Law calculations, designed specifically for Bangle.js 2 smartwatches. Handles voltage, current, resistance, and power calculations with smart logic to prevent invalid inputs.",
|
||||
"icon": "app.png",
|
||||
"type": "app",
|
||||
"tags": "calculator, utilities, electric",
|
||||
"tags": "calculator,utilities,electric",
|
||||
"supports": ["BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
"allow_emulator": true,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,56 @@
|
|||
## Pacer
|
||||
|
||||

|
||||
|
||||
Run with a virtual partner at your chosen pace, and export the GPX data
|
||||
from the Bangle.js App Store.
|
||||
|
||||
## Usage
|
||||
|
||||
Pacer starts up with a menu.
|
||||
|
||||
* **Recording** - whether to record the run
|
||||
* **Units** - imperial or metric
|
||||
* **Lap** - the multiple of a mile or kilometer to use for splits
|
||||
* **Dark mode** - use black or white background
|
||||
* **Eco battery** - display will turn off after 10 seconds
|
||||
* **Eco storage** - only record GPS position every 10 seconds
|
||||
* **Steps** - display step count or cadence
|
||||
* **Pacer** - pace of virtual partner
|
||||
|
||||
On selecting **Start**, GPS position will be detected. A run cannot be
|
||||
started without a GPS fix. The watch touchscreen is disabled while the
|
||||
app is running.
|
||||
|
||||
The app will run on Bangle.js 1 and 2, although use on Bangle.js 2 is not
|
||||
recommended due to poor GPS accuracy.
|
||||
|
||||
On a Bangle.js 1, the top button reverses the screen colours, the middle
|
||||
button starts, pauses or resumes a run, and the bottom button ends the run.
|
||||
|
||||
On a Bangle.js 2, a short press of the button starts, pauses or resumes a
|
||||
run, and a long press (over 0.5 seconds, but under 2!) ends the run. Note
|
||||
that holding the button for 2 seconds will exit back to the default clock
|
||||
app.
|
||||
|
||||
## Downloading
|
||||
|
||||
GPX tracks can be downloaded using the
|
||||
[App Loader](https://banglejs.com/apps/?id=pacer). Connect the
|
||||
Bangle.js and click on the Pacer app's disk icon to see the tracks
|
||||
available for downloading.
|
||||
|
||||
## Tips
|
||||
|
||||
For best results, only start a run when the satellite signal strength bar is
|
||||
green.
|
||||
|
||||
Use the [Assisted GPS Updater](https://banglejs.com/apps/#AGPS) to improve
|
||||
the time taken to get a GPS fix.
|
||||
|
||||
## Bugs
|
||||
|
||||
The eco settings are unlikely to be useful.
|
||||
|
||||
GPS track smoothing is accomplished simply by reducing the frequency with
|
||||
which readings are taken, depending on signal strength.
|
||||
|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("mEw4cA///un/+2Eqee1nV+X26NjtfNGLsf+AQOg+kzAROnskyfACJs5CINACJshCKAjMgfJBoPwgpHLiGSpMk3kHyneO5OECIMl23Aj+AO5QRD7ZSJgPpknZkmNCIJFJhFJk1wgFtCIN4CJFCpMwAgIRCt5HIoVN8B/BCIVmEZFyt6RCCIb7Ih5SCmYRCkjoM7YRB78k6ARO++kzwQKhgRC4GEzARKswRD8mT///Lg8DtmbCILvEEw8DkmzCIUcCIWTN40bkmWUoUCCIWbCJGSrIpC5YoB5x7HCINLRZcAg3bsgwBsARNtgRBlgRLmyNBCIMlwAQJgLkBtuyMwIRHvJUBpP2GoMGCIOwCI1SBQOSr3bA4PJSQKtGSoWSpXYBAMZAwKcGoQRCpoLCZAOSoARFh5HCk4IDtmpnikMAAMOpO8CJ0KpKQKAAlyfoQANqVMCByGBt4ROgWSfhgACjmTvAROimTCB0A8mbYgwAIwmYEZ/07wRPj/wCJ4AI"))
|
||||