diff --git a/README.md b/README.md index ddcf23f25..b9b770b37 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/apps/UI4swatch/metadata.json b/apps/UI4swatch/metadata.json index bcb0e6c51..5b4abf406 100644 --- a/apps/UI4swatch/metadata.json +++ b/apps/UI4swatch/metadata.json @@ -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"}], diff --git a/apps/Uke/metadata.json b/apps/Uke/metadata.json index 5a3f17639..1185c7202 100644 --- a/apps/Uke/metadata.json +++ b/apps/Uke/metadata.json @@ -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"}, diff --git a/apps/bblobface/metadata.json b/apps/bblobface/metadata.json index 6af247c91..8393755b0 100644 --- a/apps/bblobface/metadata.json +++ b/apps/bblobface/metadata.json @@ -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"}, diff --git a/apps/beeptest/metadata.json b/apps/beeptest/metadata.json index a9856bc93..7c25a3848 100644 --- a/apps/beeptest/metadata.json +++ b/apps/beeptest/metadata.json @@ -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": [ diff --git a/apps/bordle/metadata.json b/apps/bordle/metadata.json index f6011f798..0dbcf09f9 100644 --- a/apps/bordle/metadata.json +++ b/apps/bordle/metadata.json @@ -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"}, diff --git a/apps/bwclk/ChangeLog b/apps/bwclk/ChangeLog index 191bb51e5..74b80b73b 100644 --- a/apps/bwclk/ChangeLog +++ b/apps/bwclk/ChangeLog @@ -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) \ No newline at end of file +0.33: Fix issue rendering ClockInfos with for fg+bg color set to the same (#2749) +0.34: Support 12-hour time format diff --git a/apps/bwclk/app.js b/apps/bwclk/app.js index fdb82df73..5053dafbb 100644 --- a/apps/bwclk/app.js +++ b/apps/bwclk/app.js @@ -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; diff --git a/apps/bwclk/metadata.json b/apps/bwclk/metadata.json index d4091c2fe..de84ba947 100644 --- a/apps/bwclk/metadata.json +++ b/apps/bwclk/metadata.json @@ -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", diff --git a/apps/bwclklite/ChangeLog b/apps/bwclklite/ChangeLog index c68c62edc..bba66928b 100644 --- a/apps/bwclklite/ChangeLog +++ b/apps/bwclklite/ChangeLog @@ -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) \ No newline at end of file +0.34: Fix issue rendering ClockInfos with for fg+bg color set to the same (#2749) +0.35: Support 12-hour time format diff --git a/apps/bwclklite/app.js b/apps/bwclklite/app.js index 05f61ec58..794b39aa9 100644 --- a/apps/bwclklite/app.js +++ b/apps/bwclklite/app.js @@ -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; diff --git a/apps/bwclklite/metadata.json b/apps/bwclklite/metadata.json index f8dffdca9..14af7131c 100644 --- a/apps/bwclklite/metadata.json +++ b/apps/bwclklite/metadata.json @@ -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", diff --git a/apps/calclock/metadata.json b/apps/calclock/metadata.json index c339e8ce0..31dcb88d0 100644 --- a/apps/calclock/metadata.json +++ b/apps/calclock/metadata.json @@ -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": [ diff --git a/apps/calendar/ChangeLog b/apps/calendar/ChangeLog index 9a4f81491..d737ec6d4 100644 --- a/apps/calendar/ChangeLog +++ b/apps/calendar/ChangeLog @@ -19,3 +19,4 @@ 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 diff --git a/apps/calendar/calendar.js b/apps/calendar/calendar.js index e140ff576..ea06b70e8 100644 --- a/apps/calendar/calendar.js +++ b/apps/calendar/calendar.js @@ -60,6 +60,12 @@ 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 => { + // timestamp is in seconds, Date requires milliseconds + const date = new Date(a.timestamp * 1000); + return {date: date, msg: a.title, type: "e"}; + })); }; const loadSettings = () => { @@ -221,8 +227,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; diff --git a/apps/calendar/metadata.json b/apps/calendar/metadata.json index 468bceabb..5f5f21b27 100644 --- a/apps/calendar/metadata.json +++ b/apps/calendar/metadata.json @@ -1,7 +1,7 @@ { "id": "calendar", "name": "Calendar", - "version": "0.18", + "version": "0.19", "description": "Monthly calendar, displays holidays uploaded from the web interface and scheduled events.", "icon": "calendar.png", "screenshots": [{"url":"screenshot_calendar.png"}], diff --git a/apps/cassioWatch/metadata.json b/apps/cassioWatch/metadata.json index fb7dfd401..5ec12e751 100644 --- a/apps/cassioWatch/metadata.json +++ b/apps/cassioWatch/metadata.json @@ -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", diff --git a/apps/chronlog/metadata.json b/apps/chronlog/metadata.json index 8ed618b27..50a9166bf 100644 --- a/apps/chronlog/metadata.json +++ b/apps/chronlog/metadata.json @@ -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" } ], diff --git a/apps/clkshortcuts/ChangeLog b/apps/clkshortcuts/ChangeLog new file mode 100644 index 000000000..759f68777 --- /dev/null +++ b/apps/clkshortcuts/ChangeLog @@ -0,0 +1 @@ +0.01: New app! \ No newline at end of file diff --git a/apps/clkshortcuts/README.md b/apps/clkshortcuts/README.md new file mode 100644 index 000000000..0d4b72318 --- /dev/null +++ b/apps/clkshortcuts/README.md @@ -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 \ No newline at end of file diff --git a/apps/clkshortcuts/add_shortcuts_screenshot.png b/apps/clkshortcuts/add_shortcuts_screenshot.png new file mode 100644 index 000000000..ea7c6273b Binary files /dev/null and b/apps/clkshortcuts/add_shortcuts_screenshot.png differ diff --git a/apps/clkshortcuts/app-icon.js b/apps/clkshortcuts/app-icon.js new file mode 100644 index 000000000..99f51a2e8 --- /dev/null +++ b/apps/clkshortcuts/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEw4UB/4ACBIM889VAHmqAAwKCrQLH0oLCuBoFhoLCtJ1HtILBtYLH9ILBtALHlILQlRFCwALSnWwgECBY8O1gLJgeoBaojLHZfqAQILIFwMDBY8CFwMO2QLGhwuBlWuBY0K4ED1aDHBYJUBlQLGnRUChQLIKgJHHBYJUBZY8KgZUBBZHCKgILHh2CBZMC0fABZC+CBZBSBC5JUB14MDcY2q1YLIDAILGtY4EAAXpBYNpBY9pBYNauAKFhulBYWqAAwLCqoLHBQQA6A=")) \ No newline at end of file diff --git a/apps/clkshortcuts/app.js b/apps/clkshortcuts/app.js new file mode 100644 index 000000000..197ca70cf --- /dev/null +++ b/apps/clkshortcuts/app.js @@ -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(); \ No newline at end of file diff --git a/apps/clkshortcuts/app.png b/apps/clkshortcuts/app.png new file mode 100644 index 000000000..66e28fde7 Binary files /dev/null and b/apps/clkshortcuts/app.png differ diff --git a/apps/clkshortcuts/clkinfo.js b/apps/clkshortcuts/clkinfo.js new file mode 100644 index 000000000..842ae2747 --- /dev/null +++ b/apps/clkshortcuts/clkinfo.js @@ -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 + }; +}) \ No newline at end of file diff --git a/apps/clkshortcuts/example_shortcuts_screenshot.png b/apps/clkshortcuts/example_shortcuts_screenshot.png new file mode 100644 index 000000000..b60a57f57 Binary files /dev/null and b/apps/clkshortcuts/example_shortcuts_screenshot.png differ diff --git a/apps/clkshortcuts/metadata.json b/apps/clkshortcuts/metadata.json new file mode 100644 index 000000000..3b58bcb48 --- /dev/null +++ b/apps/clkshortcuts/metadata.json @@ -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"}] +} \ No newline at end of file diff --git a/apps/clock_info/ChangeLog b/apps/clock_info/ChangeLog index 7d2043899..cf7da2fa1 100644 --- a/apps/clock_info/ChangeLog +++ b/apps/clock_info/ChangeLog @@ -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) \ No newline at end of file +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) diff --git a/apps/clock_info/lib.js b/apps/clock_info/lib.js index 0e20ab855..cb6a19abb 100644 --- a/apps/clock_info/lib.js +++ b/apps/clock_info/lib.js @@ -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++; } diff --git a/apps/clock_info/metadata.json b/apps/clock_info/metadata.json index 1d9a73ce3..9e9079c28 100644 --- a/apps/clock_info/metadata.json +++ b/apps/clock_info/metadata.json @@ -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", diff --git a/apps/color_catalog/metadata.json b/apps/color_catalog/metadata.json index 4d49308ef..e445e3175 100644 --- a/apps/color_catalog/metadata.json +++ b/apps/color_catalog/metadata.json @@ -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": [ diff --git a/apps/confthyttan/ChangeLog b/apps/confthyttan/ChangeLog new file mode 100644 index 000000000..77d527619 --- /dev/null +++ b/apps/confthyttan/ChangeLog @@ -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" diff --git a/apps/confthyttan/README.md b/apps/confthyttan/README.md new file mode 100644 index 000000000..e9b952c82 --- /dev/null +++ b/apps/confthyttan/README.md @@ -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 diff --git a/apps/confthyttan/app.png b/apps/confthyttan/app.png new file mode 100644 index 000000000..24ff01b8a Binary files /dev/null and b/apps/confthyttan/app.png differ diff --git a/apps/confthyttan/autoreset.json b/apps/confthyttan/autoreset.json new file mode 100644 index 000000000..18e94a282 --- /dev/null +++ b/apps/confthyttan/autoreset.json @@ -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} \ No newline at end of file diff --git a/apps/confthyttan/backswipe.json b/apps/confthyttan/backswipe.json new file mode 100644 index 000000000..aa66bd534 --- /dev/null +++ b/apps/confthyttan/backswipe.json @@ -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} diff --git a/apps/confthyttan/dtlaunch.json b/apps/confthyttan/dtlaunch.json new file mode 100644 index 000000000..5417cca3b --- /dev/null +++ b/apps/confthyttan/dtlaunch.json @@ -0,0 +1 @@ +{"showClocks":true,"showLaunchers":true,"direct":false,"swipeExit":false,"timeOut":"15s"} \ No newline at end of file diff --git a/apps/confthyttan/edgeclk.settings.json b/apps/confthyttan/edgeclk.settings.json new file mode 100644 index 000000000..bdf875621 --- /dev/null +++ b/apps/confthyttan/edgeclk.settings.json @@ -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} diff --git a/apps/confthyttan/fastload.json b/apps/confthyttan/fastload.json new file mode 100644 index 000000000..beef5d0cc --- /dev/null +++ b/apps/confthyttan/fastload.json @@ -0,0 +1 @@ +{useAppHistory:true,disregardQuicklaunch:true,hideLoading:true} \ No newline at end of file diff --git a/apps/confthyttan/lightswitch.json b/apps/confthyttan/lightswitch.json new file mode 100644 index 000000000..818aa6b07 --- /dev/null +++ b/apps/confthyttan/lightswitch.json @@ -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} \ No newline at end of file diff --git a/apps/confthyttan/messages.settings.json b/apps/confthyttan/messages.settings.json new file mode 100644 index 000000000..88efa6082 --- /dev/null +++ b/apps/confthyttan/messages.settings.json @@ -0,0 +1 @@ +{vibrateTimeout:10,vibrate:":",vibrateCalls:":::",flash:false} \ No newline at end of file diff --git a/apps/confthyttan/metadata.json b/apps/confthyttan/metadata.json new file mode 100644 index 000000000..5fd18c7e9 --- /dev/null +++ b/apps/confthyttan/metadata.json @@ -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", + "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"} + ] +} diff --git a/apps/confthyttan/quicklaunch.json b/apps/confthyttan/quicklaunch.json new file mode 100644 index 000000000..4edbb083b --- /dev/null +++ b/apps/confthyttan/quicklaunch.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"} diff --git a/apps/confthyttan/recorder.json b/apps/confthyttan/recorder.json new file mode 100644 index 000000000..f598b41d2 --- /dev/null +++ b/apps/confthyttan/recorder.json @@ -0,0 +1 @@ +{recording:false,period:10,record:["gps","hrm","steps"],file:"recorder.log0.csv"} \ No newline at end of file diff --git a/apps/confthyttan/setting.json b/apps/confthyttan/setting.json new file mode 100644 index 000000000..ece0c87ed --- /dev/null +++ b/apps/confthyttan/setting.json @@ -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}} diff --git a/apps/confthyttan/widbt_notify.json b/apps/confthyttan/widbt_notify.json new file mode 100644 index 000000000..fbcd97f76 --- /dev/null +++ b/apps/confthyttan/widbt_notify.json @@ -0,0 +1 @@ +{showWidget:true,buzzOnConnect:false,buzzOnLoss:false,hideConnected:false,showMessage:false,nextBuzz:30000} \ No newline at end of file diff --git a/apps/counter2/ChangeLog b/apps/counter2/ChangeLog index 58eacf613..d952c505b 100644 --- a/apps/counter2/ChangeLog +++ b/apps/counter2/ChangeLog @@ -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 diff --git a/apps/counter2/metadata.json b/apps/counter2/metadata.json index 400abf267..04b00487f 100644 --- a/apps/counter2/metadata.json +++ b/apps/counter2/metadata.json @@ -1,7 +1,7 @@ { "id": "counter2", "name": "Counter2", - "version": "0.04", + "version": "0.05", "description": "Dual Counter", "readme":"README.md", "icon": "counter2-icon.png", diff --git a/apps/counter2/settings.js b/apps/counter2/settings.js index f97d49ad3..d74d9269f 100644 --- a/apps/counter2/settings.js +++ b/apps/counter2/settings.js @@ -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; diff --git a/apps/delaylock/metadata.json b/apps/delaylock/metadata.json index dff4d9219..7441d822b 100644 --- a/apps/delaylock/metadata.json +++ b/apps/delaylock/metadata.json @@ -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", diff --git a/apps/dinoClock/metadata.json b/apps/dinoClock/metadata.json index a61ce122b..1455e84a6 100644 --- a/apps/dinoClock/metadata.json +++ b/apps/dinoClock/metadata.json @@ -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", diff --git a/apps/followtherecipe/metadata.json b/apps/followtherecipe/metadata.json index 0c1de0817..59fabc8c5 100644 --- a/apps/followtherecipe/metadata.json +++ b/apps/followtherecipe/metadata.json @@ -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" ], diff --git a/apps/gassist/metadata.json b/apps/gassist/metadata.json index 995c44adb..bd38cdfb8 100644 --- a/apps/gassist/metadata.json +++ b/apps/gassist/metadata.json @@ -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": [ diff --git a/apps/gbdiscon/metadata.json b/apps/gbdiscon/metadata.json index ecc92d01c..904b4c6a2 100644 --- a/apps/gbdiscon/metadata.json +++ b/apps/gbdiscon/metadata.json @@ -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"}, diff --git a/apps/golfview/metadata.json b/apps/golfview/metadata.json index bc3a00f90..cf77f3a26 100644 --- a/apps/golfview/metadata.json +++ b/apps/golfview/metadata.json @@ -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": [ diff --git a/apps/guitar/metadata.json b/apps/guitar/metadata.json index 0dc6893d6..7b4683c47 100644 --- a/apps/guitar/metadata.json +++ b/apps/guitar/metadata.json @@ -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"}, diff --git a/apps/guitarsongs/metadata.json b/apps/guitarsongs/metadata.json index 242850a70..18e1f7146 100644 --- a/apps/guitarsongs/metadata.json +++ b/apps/guitarsongs/metadata.json @@ -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", diff --git a/apps/icons/gen/generate.js b/apps/icons/gen/generate.js index b91eedcdc..fd97a1ce9 100755 --- a/apps/icons/gen/generate.js +++ b/apps/icons/gen/generate.js @@ -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", diff --git a/apps/intervalTimer/metadata.json b/apps/intervalTimer/metadata.json index 2722473c1..a0489833c 100644 --- a/apps/intervalTimer/metadata.json +++ b/apps/intervalTimer/metadata.json @@ -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": [ diff --git a/apps/kanagsec/metadata.json b/apps/kanagsec/metadata.json index c00ec9d7a..2e3376c5b 100644 --- a/apps/kanagsec/metadata.json +++ b/apps/kanagsec/metadata.json @@ -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" } ] } \ No newline at end of file diff --git a/apps/locale/locales.js b/apps/locale/locales.js index c704e0f90..1e3081227 100644 --- a/apps/locale/locales.js +++ b/apps/locale/locales.js @@ -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", diff --git a/apps/messagesoverlay/metadata.json b/apps/messagesoverlay/metadata.json index 26095eb33..ba5f005c3 100644 --- a/apps/messagesoverlay/metadata.json +++ b/apps/messagesoverlay/metadata.json @@ -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"} ] } diff --git a/apps/multidice/ChangeLog b/apps/multidice/ChangeLog index cb0cce2aa..ca17e1833 100644 --- a/apps/multidice/ChangeLog +++ b/apps/multidice/ChangeLog @@ -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 diff --git a/apps/multidice/app.js b/apps/multidice/app.js index 53f67e21e..fe869626a 100644 --- a/apps/multidice/app.js +++ b/apps/multidice/app.js @@ -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; diff --git a/apps/multidice/metadata.json b/apps/multidice/metadata.json index 304c789e4..dd6941060 100644 --- a/apps/multidice/metadata.json +++ b/apps/multidice/metadata.json @@ -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"}] } diff --git a/apps/multidice/settings.js b/apps/multidice/settings.js new file mode 100644 index 000000000..446a785e1 --- /dev/null +++ b/apps/multidice/settings.js @@ -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(); + } + }, + }); +}) diff --git a/apps/ohmcalc/metadata.json b/apps/ohmcalc/metadata.json index c72727a4c..2ab25947f 100644 --- a/apps/ohmcalc/metadata.json +++ b/apps/ohmcalc/metadata.json @@ -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, diff --git a/apps/pastel/metadata.json b/apps/pastel/metadata.json index 532aa8ccc..5d1f925fe 100644 --- a/apps/pastel/metadata.json +++ b/apps/pastel/metadata.json @@ -8,7 +8,7 @@ "dependencies": {"mylocation":"app","weather":"app"}, "screenshots": [{"url":"screenshot_pastel.png"}, {"url":"weather_icons.png"}], "type": "clock", - "tags": "clock, weather, tool", + "tags": "clock,weather,tool", "supports": ["BANGLEJS","BANGLEJS2"], "readme": "README.md", "storage": [ diff --git a/apps/poweroff/metadata.json b/apps/poweroff/metadata.json index 218e4b441..b9a7d60ea 100644 --- a/apps/poweroff/metadata.json +++ b/apps/poweroff/metadata.json @@ -4,7 +4,7 @@ "version": "0.05", "description": "Simple app to power off your Bangle.js", "icon": "app.png", -"tags": "tool, poweroff, shutdown", +"tags": "tool,poweroff,shutdown", "supports" : ["BANGLEJS", "BANGLEJS2"], "readme": "README.md", "allow_emulator": true, diff --git a/apps/quicklaunch/metadata.json b/apps/quicklaunch/metadata.json index 15c40dfdc..95ae0b014 100644 --- a/apps/quicklaunch/metadata.json +++ b/apps/quicklaunch/metadata.json @@ -5,7 +5,7 @@ "version": "0.16", "description": "Tap or swipe left/right/up/down on your clock face to launch up to five apps of your choice. Configurations can be accessed through Settings->Apps.", "type": "bootloader", - "tags": "tools, system", + "tags": "tools,system", "readme": "README.md", "supports": ["BANGLEJS2"], "storage": [ diff --git a/apps/rescalc/metadata.json b/apps/rescalc/metadata.json index cd2b7ea31..f7f7c5e29 100644 --- a/apps/rescalc/metadata.json +++ b/apps/rescalc/metadata.json @@ -10,7 +10,7 @@ {"url": "screenshot-2.png"} ], "description": "An intuitive, easy-to-use app that aids in the interpretation of resistor color codes and calculation of resistance values.", - "tags": "app, tool, electricity, ohms, converter", + "tags": "app,tool,electricity,ohms,converter", "supports": ["BANGLEJS2"], "readme": "README.md", "allow_emulator": true, diff --git a/apps/sched/README.md b/apps/sched/README.md index 1216a1a11..0fa780405 100644 --- a/apps/sched/README.md +++ b/apps/sched/README.md @@ -49,7 +49,7 @@ Alarms are stored in an array in `sched.json`, and take the form: // e.g. repeat every 2 months: { interval: "month", num: 2 }. // Supported intervals: day, week, month, year vibrate : "...", // OPTIONAL pattern of '.', '-' and ' ' to use for when buzzing out this alarm (defaults to '..' if not set) - hidden : false, // OPTIONAL if false, the widget should not show an icon for this alarm + hidden : false, // OPTIONAL if true, the widget should not show an icon for this alarm as : false, // auto snooze timer : 5*60*1000, // OPTIONAL - if set, this is a timer and it's the time in ms del : false, // OPTIONAL - if true, delete the timer after expiration diff --git a/apps/scribble/metadata.json b/apps/scribble/metadata.json index 2c31be931..19c6c707c 100644 --- a/apps/scribble/metadata.json +++ b/apps/scribble/metadata.json @@ -6,7 +6,7 @@ "description": "A keyboard on your wrist! Swipe right for space, left for delete.", "icon": "app.png", "allow_emulator": true, - "tags": "tools, keyboard, text, scribble", + "tags": "tools,keyboard,text,scribble", "supports" : ["BANGLEJS2"], "readme": "README.md", "storage": [ diff --git a/apps/sevenmin/metadata.json b/apps/sevenmin/metadata.json index 5103a5f97..8a1867e4a 100644 --- a/apps/sevenmin/metadata.json +++ b/apps/sevenmin/metadata.json @@ -5,7 +5,7 @@ "description": "A basic implementation of the famous consice workout", "icon": "icon.png", "type":"app", - "tags": "Training, Workout", + "tags": "training,workout", "supports": ["BANGLEJS2"], "readme": "README.md", "allow_emulator":true, diff --git a/apps/spaceclock/metadata.json b/apps/spaceclock/metadata.json index 1e8bc266f..cff458d08 100644 --- a/apps/spaceclock/metadata.json +++ b/apps/spaceclock/metadata.json @@ -5,8 +5,8 @@ "description": "Watch face in the style of Casio Prototype Space Resist", "icon": "app-icon.png", "type": "clock", - "tags": "clock, casio, retro", - "supports" : ["BANGLEJS2"], + "tags": "clock,casio,retro", + "supports" : ["BANGLEJS2"], "readme": "README.md", "storage": [ {"name":"spaceclock.app.js","url":"app.js"}, diff --git a/apps/swiperclocklaunch/metadata.json b/apps/swiperclocklaunch/metadata.json index d474b38e3..6bb24987e 100644 --- a/apps/swiperclocklaunch/metadata.json +++ b/apps/swiperclocklaunch/metadata.json @@ -5,7 +5,7 @@ "description": "Navigate between clock and launcher with Swipe action", "icon": "swiperclocklaunch.png", "type": "bootloader", - "tags": "tools, system", + "tags": "tools,system", "supports": ["BANGLEJS", "BANGLEJS2"], "storage": [ {"name":"swiperclocklaunch.boot.js","url":"boot.js"}, diff --git a/apps/tabanchi/metadata.json b/apps/tabanchi/metadata.json index db81707b5..43ebc62ac 100644 --- a/apps/tabanchi/metadata.json +++ b/apps/tabanchi/metadata.json @@ -7,7 +7,7 @@ "description": "Tamagotchi WatchApp", "icon": "app.png", "allow_emulator": true, - "tags": "clock, watch, virtual pet", + "tags": "clock,watch,virtualpet", "supports": [ "BANGLEJS2" ], diff --git a/apps/testuserinput/metadata.json b/apps/testuserinput/metadata.json index 409843198..39fab86af 100644 --- a/apps/testuserinput/metadata.json +++ b/apps/testuserinput/metadata.json @@ -5,7 +5,7 @@ "version": "0.08", "description": "App to test the bangle.js input interface. It displays the user action in text, circle buttons or on/off switch UI elements.", "icon": "app.png", - "tags": "input,interface,buttons,touch,UI", + "tags": "input,interface,buttons,touch,ui", "supports": ["BANGLEJS"], "readme": "README.md", "storage": [ diff --git a/apps/timestamplog/metadata.json b/apps/timestamplog/metadata.json index e1aa0eb23..6f0126c4a 100644 --- a/apps/timestamplog/metadata.json +++ b/apps/timestamplog/metadata.json @@ -7,7 +7,7 @@ "description": "Conveniently record a series of date/time stamps", "screenshots": [ {"url": "screenshot.png" } ], "readme": "README.md", - "tags": "timestamp, log", + "tags": "timestamp,log", "supports": ["BANGLEJS2"], "interface": "interface.html", "storage": [ diff --git a/apps/tinydraw/metadata.json b/apps/tinydraw/metadata.json index 21ea1eb89..61f4129e8 100644 --- a/apps/tinydraw/metadata.json +++ b/apps/tinydraw/metadata.json @@ -6,7 +6,7 @@ "description": "Draw stuff in your wrist", "icon": "app.png", "allow_emulator": true, - "tags": "tools, keyboard, text, scribble", + "tags": "tools,keyboard,text,scribble", "supports" : ["BANGLEJS2"], "readme": "README.md", "storage": [ diff --git a/apps/txtreader/ChangeLog b/apps/txtreader/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/txtreader/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/txtreader/README.md b/apps/txtreader/README.md new file mode 100644 index 000000000..1cede764c --- /dev/null +++ b/apps/txtreader/README.md @@ -0,0 +1,20 @@ +# txtreader + +Very basic text reader with an integrated file selector. + +## Features + +- select files from storage (.txt) +- display their contents +- browse pages + +## Controls + +Bangle.js 2 +- tap the right side of the screen to flip to the next page +- tap the left side of the screen to flip to the previous page +- exit by pressing the physical button + +## Creator + + diff --git a/apps/txtreader/app-icon.js b/apps/txtreader/app-icon.js new file mode 100644 index 000000000..a8c210baf --- /dev/null +++ b/apps/txtreader/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwkCkQA/AH4A/AAcosd2m9jw04AQlyC5WL1e63YCG3lUC5WPj/x/8f+H/h4CBj/3jYXLv/3/4CCt4FC/IXM/4AI/YXk/WZzOfCgWfAoIXN/F3u9/C4V/AoIvUI6H3F4p3oC6/73e734XTR4wXQ/vd7vfC6f85gAG55HQAAppBC5n5xAAGz4vmzIAGF/33F49/C5v6F4+vC5rrFd6JHCv4XTI4WfF6lms1vF6mq1WvC6Z3WxfdABHVugXKlFUogAHoVCC5QA/AH4A6A")) \ No newline at end of file diff --git a/apps/txtreader/app.js b/apps/txtreader/app.js new file mode 100644 index 000000000..1e4fd30e9 --- /dev/null +++ b/apps/txtreader/app.js @@ -0,0 +1,88 @@ +function showFileSelector() { + let files = require("Storage").list().filter(f => f.endsWith('.txt')); + + let menuItems = {}; + files.forEach(file => { + menuItems[file] = () => { + E.showPrompt(`Select ${file}?`).then(confirm => { + if (confirm) { + onFileSelected(file); + } else { + showFileSelector(); + } + }); + }; + }); + + menuItems['< Back'] = () => { load(); }; + E.showMenu(menuItems); +} + +function onFileSelected(file) { + const chunkSize = 1024; + let currentOffset = 0; + let currentPage = 1; + let history = []; + + function displayText(offset, pageNumber) { + g.clear(); + g.setFont("6x8", 1); + g.setColor(g.theme.fg); + g.drawString("Page " + pageNumber, 10, 2); + //g.drawString("Offset " + offset, 60, 2); + g.drawString(file, g.getWidth() - file.length * 6, 2); + + var text = require("Storage").read(file, offset, chunkSize); + var lines = text.split("\n"); + var y = 15; // Text start, top row reserved for page number + var linesDisplayed = 0; // Lines per page + var totalCharsDisplayed = 0; // Total characters per page + + for (var i = 0; i < lines.length; i++) { + var wrappedLines = g.wrapString(lines[i], g.getWidth() - 20); + for (var j = 0; j < wrappedLines.length; j++) { + g.drawString(wrappedLines[j], 10, y); + y += 10; // Move down for the next line + linesDisplayed++; + totalCharsDisplayed += wrappedLines[j].length + (j < wrappedLines.length - 1 ? 0 : 1); // Add newline character for the last wrapped line + if (y >= g.getHeight() - 10) { + // If we run out of space, stop drawing + return { nextOffset: offset + totalCharsDisplayed, linesDisplayed: linesDisplayed }; + } + } + } + return null; // No more lines to display + } + + // Initial display + var result = displayText(currentOffset, currentPage); + history.push({ offset: currentOffset, linesDisplayed: result.linesDisplayed }); + + // Handle touch events + Bangle.on('touch', function(button) { + if (button === 2) { // Right side of the screen (next page) + var nextOffset = displayText(currentOffset, currentPage + 1); + if (nextOffset !== null) { + currentOffset = nextOffset.nextOffset; + currentPage++; + history.push({ offset: currentOffset, linesDisplayed: nextOffset.linesDisplayed }); + displayText(currentOffset, currentPage); + } else { + currentOffset = 0; + currentPage = 1; + history = [{ offset: currentOffset, linesDisplayed: result.linesDisplayed }]; + displayText(currentOffset, currentPage); + } + } else if (button === 1) { // Left side of the screen (previous page) + if (currentPage > 1) { + history.pop(); // Remove current page from history + var previousPage = history[history.length - 1]; + currentOffset = previousPage.offset; + currentPage--; + displayText(currentOffset, currentPage); + } + } + }); +} + +showFileSelector(); \ No newline at end of file diff --git a/apps/txtreader/metadata.json b/apps/txtreader/metadata.json new file mode 100644 index 000000000..985b8e5ea --- /dev/null +++ b/apps/txtreader/metadata.json @@ -0,0 +1,16 @@ +{ + "id": "txtreader", + "name": "txtreader", + "shortName": "txtreader", + "version": "0.01", + "description": "Basic text reader with pages and a file selector.", + "icon": "txtreader.png", + "screenshots": [{"url":"screenshot_txtreader.png"}], + "tags": "app,tool", + "supports": ["BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name":"txtreader.app.js","url":"app.js"}, + {"name":"txtreader.img","url":"app-icon.js","evaluate":true} + ] +} diff --git a/apps/txtreader/screenshot_txtreader.png b/apps/txtreader/screenshot_txtreader.png new file mode 100644 index 000000000..1b565024a Binary files /dev/null and b/apps/txtreader/screenshot_txtreader.png differ diff --git a/apps/txtreader/txtreader.png b/apps/txtreader/txtreader.png new file mode 100644 index 000000000..a60ee8647 Binary files /dev/null and b/apps/txtreader/txtreader.png differ diff --git a/apps/txtreader/txtreader_transparent.png b/apps/txtreader/txtreader_transparent.png new file mode 100644 index 000000000..a60ee8647 Binary files /dev/null and b/apps/txtreader/txtreader_transparent.png differ diff --git a/apps/weatherClock/metadata.json b/apps/weatherClock/metadata.json index 88057c8dd..b1b586a21 100644 --- a/apps/weatherClock/metadata.json +++ b/apps/weatherClock/metadata.json @@ -8,7 +8,7 @@ "dependencies": {"weather":"app"}, "screenshots": [{"url":"screens/screen1.png"}], "type": "clock", - "tags": "clock, weather", + "tags": "clock,weather", "supports": ["BANGLEJS","BANGLEJS2"], "allow_emulator": true, "readme": "README.md", diff --git a/apps/widscrlock/metadata.json b/apps/widscrlock/metadata.json index 5110d76c1..568c61b93 100644 --- a/apps/widscrlock/metadata.json +++ b/apps/widscrlock/metadata.json @@ -3,9 +3,9 @@ "shortName":"Screenlock", "version":"0.03", "description": "Lock a Bangle 2 screen by tapping a widget.", - "icon": "widget.png", + "icon": "widget.png", "type": "widget", - "tags": "widget, screenlock", + "tags": "widget,screenlock", "supports" : ["BANGLEJS2"], "readme": "README.md", "storage": [ diff --git a/bin/sanitycheck.js b/bin/sanitycheck.js index 086c2e551..75f740d4f 100755 --- a/bin/sanitycheck.js +++ b/bin/sanitycheck.js @@ -2,6 +2,31 @@ /* Checks for any obvious problems in apps.json */ +var BASEDIR = __dirname+"/../"; +var APPSDIR_RELATIVE = "apps/"; +var APPSDIR = BASEDIR + APPSDIR_RELATIVE; +var showAllErrors = process.argv.includes("--show-all"); + +if (process.argv.includes("--help")) { + console.log(`BangleApps Sanity Check +------------------------ + +Checks apps in this repository for common issues that might +cause problems. + +USAGE: + +bin/sanitycheck.js + - default, runs all tests (hides known errors) +bin/sanitycheck.js --show-all + - show all warnings/errors (including known ones) +bin/sanitycheck.js --help + - show this message +`); + process.exit(0); +} + + var fs = require("fs"); var vm = require("vm"); var heatshrink = require("../webtools/heatshrink"); @@ -27,40 +52,42 @@ var jsparse = (() => { return str => acorn.parse(str, { ecmaVersion: 2020 }); })(); -var BASEDIR = __dirname+"/../"; -var APPSDIR_RELATIVE = "apps/"; -var APPSDIR = BASEDIR + APPSDIR_RELATIVE; + var knownWarningCount = 0; var knownErrorCount = 0; var warningCount = 0; var errorCount = 0; +var warningList = []; +var errorList = []; + function ERROR(msg, opt) { // file=app.js,line=1,col=5,endColumn=7 opt = opt||{}; + errorList.push(msg); if (KNOWN_ERRORS.includes(msg)) { - console.log(`Known error : ${msg}`); knownErrorCount++; - } else { - console.log(`::error${Object.keys(opt).length?" ":""}${Object.keys(opt).map(k=>k+"="+opt[k]).join(",")}::${msg}`); - errorCount++; + if (!showAllErrors) return; + msg += " (KNOWN)" } + console.log(`::error${Object.keys(opt).length?" ":""}${Object.keys(opt).map(k=>k+"="+opt[k]).join(",")}::${msg}`); + errorCount++; } function WARN(msg, opt) { // file=app.js,line=1,col=5,endColumn=7 opt = opt||{}; + warningList.push(msg); if (KNOWN_WARNINGS.includes(msg)) { - console.log(`Known warning : ${msg}`); knownWarningCount++; - } else { - console.log(`::warning${Object.keys(opt).length?" ":""}${Object.keys(opt).map(k=>k+"="+opt[k]).join(",")}::${msg}`); - warningCount++; + if (!showAllErrors) return; + msg += " (KNOWN)" } + console.log(`::warning${Object.keys(opt).length?" ":""}${Object.keys(opt).map(k=>k+"="+opt[k]).join(",")}::${msg}`); + warningCount++; } /* These are errors that we temporarily allow */ var KNOWN_ERRORS = [ "In locale en_CA, long date output must be shorter than 15 characters (Wednesday, September 10, 2024 -> 29)", "In locale fr_FR, long date output must be shorter than 15 characters (10 septembre 2024 -> 17)", - "In locale fr_FR, short month must be shorter than 5 characters", "In locale sv_SE, speed must be shorter than 5 characters", "In locale en_SE, long date output must be shorter than 15 characters (September 10 2024 -> 17)", "In locale en_NZ, long date output must be shorter than 15 characters (Wednesday, September 10, 2024 -> 29)", @@ -69,51 +96,23 @@ var KNOWN_ERRORS = [ "In locale en_IL, long date output must be shorter than 15 characters (Wednesday, September 10, 2024 -> 29)", "In locale es_ES, long date output must be shorter than 15 characters (miércoles, 10 de septiembre de 2024 -> 35)", "In locale fr_BE, long date output must be shorter than 15 characters (dimanche septembre 10 2024 -> 26)", - "In locale fr_BE, short month must be shorter than 5 characters", - "In locale fr_BE, short month must be shorter than 5 characters", - "In locale fr_BE, short month must be shorter than 5 characters", - "In locale fr_BE, short month must be shorter than 5 characters", - "In locale fr_BE, short month must be shorter than 5 characters", "In locale fi_FI, long date output must be shorter than 15 characters (keskiviikkona 10. maaliskuuta 2024 -> 34)", "In locale fi_FI, short month must be shorter than 5 characters", - "In locale fi_FI, short month must be shorter than 5 characters", - "In locale fi_FI, short month must be shorter than 5 characters", - "In locale fi_FI, short month must be shorter than 5 characters", - "In locale fi_FI, short month must be shorter than 5 characters", - "In locale fi_FI, short month must be shorter than 5 characters", - "In locale fi_FI, short month must be shorter than 5 characters", - "In locale fi_FI, short month must be shorter than 5 characters", - "In locale fi_FI, short month must be shorter than 5 characters", - "In locale fi_FI, short month must be shorter than 5 characters", - "In locale fi_FI, short month must be shorter than 5 characters", "In locale de_CH, meridian must be shorter than 4 characters", "In locale de_CH, meridian must be shorter than 4 characters", "In locale de_CH, long date output must be shorter than 15 characters (Donnerstag, 10. September 2024 -> 30)", "In locale fr_CH, long date output must be shorter than 15 characters (dimanche 10 septembre 2024 -> 26)", - "In locale fr_CH, short month must be shorter than 5 characters", - "In locale fr_CH, short month must be shorter than 5 characters", - "In locale fr_CH, short month must be shorter than 5 characters", - "In locale fr_CH, short month must be shorter than 5 characters", - "In locale fr_CH, short month must be shorter than 5 characters", "In locale wae_CH, long date output must be shorter than 15 characters (Sunntag, 10. Herbštmánet 2024 -> 29)", "In locale tr_TR, long date output must be shorter than 15 characters (10 Haziran 2024 Pazartesi -> 25)", "In locale hu_HU, long date output must be shorter than 15 characters (2024 Szep 10, Csütörtök -> 23)", "In locale oc_FR, long date output must be shorter than 15 characters (divendres 10 setembre de 2024 -> 29)", "In locale oc_FR, short month must be shorter than 5 characters", - "In locale oc_FR, short month must be shorter than 5 characters", - "In locale hr_HR, meridian must be shorter than 4 characters", - "In locale hr_HR, meridian must be shorter than 4 characters", - "In locale hr_HR, short month must be shorter than 5 characters", - "In locale sl_SI, meridian must be shorter than 4 characters", - "In locale sl_SI, meridian must be shorter than 4 characters", "In locale ca_ES, long date output must be shorter than 15 characters (10 setembre 2024 -> 16)", - "In locale ca_ES, short month must be shorter than 5 characters", ]; /* These are warnings we know about but don't want in our output */ var KNOWN_WARNINGS = [ "App gpsrec data file wildcard .gpsrc? does not include app ID", "App owmweather data file weather.json is also listed as data file for app weather", - "App messagegui storage file messagegui is also listed as storage file for app messagelist", "App carcrazy has a setting file but no corresponding data entry (add `\"data\":[{\"name\":\"carcrazy.settings.json\"}]`)", "App loadingscreen has a setting file but no corresponding data entry (add `\"data\":[{\"name\":\"loadingscreen.settings.json\"}]`)", "App trex has a setting file but no corresponding data entry (add `\"data\":[{\"name\":\"trex.settings.json\"}]`)", @@ -169,7 +168,7 @@ const APP_KEYS = [ const STORAGE_KEYS = ['name', 'url', 'content', 'evaluate', 'noOverwite', 'supports', 'noOverwrite']; const DATA_KEYS = ['name', 'wildcard', 'storageFile', 'url', 'content', 'evaluate']; const SUPPORTS_DEVICES = ["BANGLEJS","BANGLEJS2"]; // device IDs allowed for 'supports' -const METADATA_TYPES = ["app","clock","widget","bootloader","RAM","launch","scheduler","notify","locale","settings","textinput","module","clkinfo"]; // values allowed for "type" field +const METADATA_TYPES = ["app","clock","widget","bootloader","RAM","launch","scheduler","notify","locale","settings","textinput","module","clkinfo","defaultconfig"]; // values allowed for "type" field - listed in README.md const FORBIDDEN_FILE_NAME_CHARS = /[,;]/; // used as separators in appid.info const VALID_DUPLICATES = [ '.tfmodel', '.tfnames' ]; const GRANDFATHERED_ICONS = ["s7clk", "snek", "astral", "alpinenav", "slomoclock", "arrow", "pebble", "rebble"]; @@ -207,6 +206,10 @@ apps.forEach((app,appIdx) => { if (!app.name) ERROR(`App ${app.id} has no name`, {file:metadataFile}); var isApp = !app.type || app.type=="app"; var appTags = app.tags ? app.tags.split(",") : []; + if (appTags.some(tag => tag!=tag.trim())) + WARN(`App ${app.id} 'tag' list contains whitespace ("${app.tags}")`, {file:metadataFile}); + if (appTags.some(tag => tag!=tag.toLowerCase())) + WARN(`App ${app.id} 'tag' list contains uppercase ("${app.tags}")`, {file:metadataFile}); if (app.name.length>20 && !app.shortName && isApp) ERROR(`App ${app.id} has a long name, but no shortName`, {file:metadataFile}); if (app.type && !METADATA_TYPES.includes(app.type)) ERROR(`App ${app.id} 'type' is one one of `+METADATA_TYPES, {file:metadataFile}); @@ -296,7 +299,8 @@ apps.forEach((app,appIdx) => { if (INTERNAL_FILES_IN_APP_TYPE[app.type].includes(file.name)) fileInternal = true; } - allFiles.push({app: app.id, file: file.name, internal:fileInternal}); + if (!app.type=="defaultconfig") + allFiles.push({app: app.id, file: file.name, internal:fileInternal}); if (file.url) if (!fs.existsSync(appDir+file.url)) ERROR(`App ${app.id} file ${file.url} doesn't exist`, {file:metadataFile}); if (!file.url && !file.content && !app.custom) ERROR(`App ${app.id} file ${file.name} has no contents`, {file:metadataFile}); var fileContents = ""; @@ -494,7 +498,7 @@ while(fileA=allFiles.pop()) { if (isGlob(nameA)||isGlob(nameB)) ERROR(`App ${fileB.app} ${typeB} file ${nameB} matches app ${fileA.app} ${typeB} file ${nameA}`); else if (fileA.app != fileB.app && (!fileA.internal) && (!fileB.internal)) - WARN(`App ${fileB.app} ${typeB} file ${nameB} is also listed as ${typeA} file for app ${fileA.app}`); + WARN(`App ${fileB.app} ${typeB} file ${nameB} is also listed as ${typeA} file for app ${fileA.app}`, {file:APPSDIR_RELATIVE+fileB.app+"/metadata.json"}); } }) } @@ -520,8 +524,17 @@ function sanityCheckLocales(){ } promise.then(function() { + KNOWN_ERRORS.forEach(msg => { + if (!errorList.includes(msg)) + WARN(`Known error '${msg}' no longer occurs`); + }); + KNOWN_WARNINGS.forEach(msg => { + if (!warningList.includes(msg)) + WARN(`Known warning '${msg}' no longer occurs`); + }); console.log("=================================="); - console.log(`${errorCount} errors, ${warningCount} warnings (and ${knownErrorCount} known errors, ${knownWarningCount} known warnings)`); + console.log(`${errorCount} errors, ${warningCount} warnings`); + console.log(`${knownErrorCount} known errors, ${knownWarningCount} known warnings${(knownErrorCount||knownWarningCount)?", run with --show-all to see them":""}`); console.log("=================================="); if (errorCount) { process.exit(1); diff --git a/core b/core index bf08b4848..3ec8e289a 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit bf08b484830ef4e811faf67ec663ebf839b5d09b +Subproject commit 3ec8e289a26a545d0d0c50f6945978584fb3d7f8 diff --git a/typescript/types/info.d.ts b/typescript/types/info.d.ts index c305b0261..21014ff8f 100644 --- a/typescript/types/info.d.ts +++ b/typescript/types/info.d.ts @@ -14,4 +14,4 @@ type AppInfo = { type AppType = "app" | "clock" | "widget" | "module" | "bootloader" | "settings" | "clkinfo" | "RAM" | "launch" | "textinput" | "scheduler" | - "notify" | "locale"; + "notify" | "locale" | "defaultconfig";