From e21979bd0815a4863e1ef1f57f22316d2252723d Mon Sep 17 00:00:00 2001 From: Brian Whelan Date: Fri, 7 Feb 2025 21:52:01 +0000 Subject: [PATCH] New app "Shortcuts" Adds a new app that allows you to pin apps to clockfaces that support clock_info --- apps/clkshortcuts/ChangeLog | 1 + apps/clkshortcuts/README.md | 10 + .../clkshortcuts/add_shortcuts_screenshot.png | Bin 0 -> 471 bytes apps/clkshortcuts/app-icon.js | 1 + apps/clkshortcuts/app.js | 224 ++++++++++++++++++ apps/clkshortcuts/app.png | Bin 0 -> 1131 bytes apps/clkshortcuts/clkinfo.js | 45 ++++ .../example_shortcuts_screenshot.png | Bin 0 -> 622 bytes apps/clkshortcuts/metadata.json | 17 ++ 9 files changed, 298 insertions(+) create mode 100644 apps/clkshortcuts/ChangeLog create mode 100644 apps/clkshortcuts/README.md create mode 100644 apps/clkshortcuts/add_shortcuts_screenshot.png create mode 100644 apps/clkshortcuts/app-icon.js create mode 100644 apps/clkshortcuts/app.js create mode 100644 apps/clkshortcuts/app.png create mode 100644 apps/clkshortcuts/clkinfo.js create mode 100644 apps/clkshortcuts/example_shortcuts_screenshot.png create mode 100644 apps/clkshortcuts/metadata.json 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 0000000000000000000000000000000000000000..ea7c6273b9f3d4ab4ad05105873455f8224660f8 GIT binary patch literal 471 zcmeAS@N?(olHy`uVBq!ia0vp^8$g(a8A!&?{Fw`+7>k44ofy`glX(f`u%tWsIx;Y9 z?C1WI$O`0h2Ka=yGW=)w|NlRb7uwr89VA%b5n0T@z;_sg8IR|$NCBD>?&;zfl5y|t zbk0f53L>m0dH>vFcvpXdaf-_UR?YuCX}caX{dl7#GF5`1;j+h3(@4{e9ojei=AYE+ zifxUV7%KXFdvg4pIj(zz;@+%3q2%`G^`ocNA3W~NaE)n^%M{{$2&S+btzkmMCh?l3r5-k<)on|_~=Er%&U#wfGL-2oN zg%5M}I`PA`m8WLNZ+h+9A$Z>}C-`#Z$KO4zH@w`^EOVTCeyBZS-6ZGS^FzKn_iC5K zN7Y9;rxaH|ws>ou?)15lccW|1k8_VsJNEq0J_0tFnZd#O*dK=X$!@D#>el%K!=1s? L)z4*}Q$iB}H6zec literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..66e28fde79af1045cfc8f2a1ea3ebbd8b2a7c204 GIT binary patch literal 1131 zcmV-x1eE)UP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGf6951U69E94oEQKA1OQ1yK~!i%?U_9+ zWKk5yuSoLP7`%QAk95G{ml+M4}=jqFd8Q6tgO|LZwuRPPZFE6lla(XoUER zkHqW_cH-mgIcM*keTV#aGm8f#V?$Dk5m)$?+HJ%gMM-$xa-dvLKPa)6BpT&_5w6wJFC`F@&h6Wua zIvnZ1?d`4Ji=3sUCB5e?eBnqrKR<`6sw(y=D=XtAP=d4_V}}wW3T%ZsQC(fle$hbZB_v3+R zWUTD(??Y*6Df^X_l)&EJo~{Xvv>juI5+e$1*xA{EoSYo?sjI7li;D|g6CPFkY`0Iy*b9 zNkCp+9_;S!29E8p_=>R&+||{^Hg30DmjpvMGjm^{(Vv)@fTpG35iSF)h=C(4h z@Z~ z%nWY_1_o3?K>_c-H&H*0_Vo1dc5G}+;i|;@xNP#awY8PE@g(dNB4{Z!Z()OjgIq>; z*r};0czSx`W2Z3rpv2gAfLL8!#{r$bJaTb#gN{pxj#N6B*q^72_eN9ab zEH5wX8s{+ipu~tfKrAjULUD0%pdorP9UmWum6a7ZJ39k>Gt-vQVdA31utOx!(mFCS z61W4ul*{FU(a}+D9T}E5K{)nKOiQcB<57o)hiZCyTJ`q!DtwSr+1c3&lh;|puCir6#A4+PQyA*+`t^7`n*m*6Ud2va12X6QaKH^iEUHzQT^Z`=(i3z xegsAQi^)K}rc=j1JYuXj|Kv-MAi;-6soz#qUFcx}E6o4^002ovPDHLkV1iM-87BY$ literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..b60a57f5743622691d2ac5c937c4d36887896d39 GIT binary patch literal 622 zcmV-!0+IcRP)Px#1ZP1_K>z@;j|==^1poj52~bQ_MF9T*|Ns900032ug_i&T010qNS#tmY4#NNd z4#NS*Z>VGd00HhvL_t(&-tCtSmV+P+gy9B;8-)8Ga`|+f}a^bTVkCEW*qifr9 z+@k9sY6HP`%WZ)ZO&B}mp+@U@C8q`k@fdjSfOF4ootIj?yjRva_GZ z!@$zq11quq^e2cKQ&p9jC^ExpsbE1?Sc z-PPuN75x{=Q+gioeE&=#2!d`9Ew1^6YSDhFs&`iRI+9;9dU1P&y8!EJV5)-2@4!O1N{5h|ohVD5ok z+eE;G4%b6L?i7m_V6zW}kJmM@t%IXCrc1n|6pGOCnPhko>6XmD;27l;qyo$%!9|ua z9i|%zu&Jk8+-?Ue(k^#4Gr5@k^(n2K$v3}N==xd_xBI~m1T|y_3E-K*G)Mpg`~cYG z#7@6A=`Ig3