mirror of https://github.com/espruino/BangleApps
Merge pull request #2720 from bobrippling/apps/popcon
New launcher/boot app: popconpull/2735/head^2
commit
2defa08b86
|
@ -0,0 +1 @@
|
|||
0.01: New App!
|
|
@ -0,0 +1,8 @@
|
|||
Popcon
|
||||
======
|
||||
|
||||
Display apps sorted by regular use. No config - install the app and all your launchers will sort apps by most popular, based off launch counts within the last month, and then sort them by the most recently launched app.
|
||||
|
||||
:warning: Warning: this app overrides [`Storage.readJSON`], so may slow down your watch when using apps that perform I/O.
|
||||
|
||||
[`Storage.readJSON`]: https://www.espruino.com/ReferenceBANGLEJS2#l_Storage_readJSON
|
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
|
@ -0,0 +1,81 @@
|
|||
{
|
||||
var oldRead_1 = require("Storage").readJSON;
|
||||
var monthAgo_1 = Date.now() - 1000 * 86400 * 28;
|
||||
var cache_1;
|
||||
var ensureCache_1 = function () {
|
||||
if (!cache_1) {
|
||||
cache_1 = oldRead_1("popcon.cache.json", true);
|
||||
if (!cache_1)
|
||||
cache_1 = {};
|
||||
}
|
||||
return cache_1;
|
||||
};
|
||||
var saveCache_1 = function (orderChanged) {
|
||||
require("Storage").writeJSON("popcon.cache.json", cache_1);
|
||||
if (orderChanged) {
|
||||
var info = oldRead_1("popcon.info", true);
|
||||
info.cacheBuster = !info.cacheBuster;
|
||||
require("Storage").writeJSON("popcon.info", info);
|
||||
}
|
||||
};
|
||||
var sortCache_1 = function () {
|
||||
var ents = Object.values(cache_1);
|
||||
ents.sort(function (a, b) {
|
||||
var n;
|
||||
var am = (a.last > monthAgo_1);
|
||||
var bm = (b.last > monthAgo_1);
|
||||
n = bm - am;
|
||||
if (n)
|
||||
return n;
|
||||
n = b.pop - a.pop;
|
||||
if (n)
|
||||
return n;
|
||||
n = b.last - a.last;
|
||||
if (n)
|
||||
return n;
|
||||
if (a.name < b.name)
|
||||
return -1;
|
||||
if (a.name > b.name)
|
||||
return 1;
|
||||
return 0;
|
||||
});
|
||||
var i = 0;
|
||||
var orderChanged = false;
|
||||
for (var _i = 0, ents_1 = ents; _i < ents_1.length; _i++) {
|
||||
var ent = ents_1[_i];
|
||||
if (ent.sortorder !== i)
|
||||
orderChanged = true;
|
||||
ent.sortorder = i++;
|
||||
}
|
||||
return orderChanged;
|
||||
};
|
||||
require("Storage").readJSON = (function (fname, skipExceptions) {
|
||||
var _a;
|
||||
var j = oldRead_1(fname, skipExceptions);
|
||||
if (/\.info$/.test(fname)) {
|
||||
var cache_2 = ensureCache_1();
|
||||
var so = void 0;
|
||||
if (j.src && (so = (_a = cache_2[j.src]) === null || _a === void 0 ? void 0 : _a.sortorder) != null)
|
||||
j.sortorder = so;
|
||||
else
|
||||
j.sortorder = 99;
|
||||
}
|
||||
return j;
|
||||
});
|
||||
var oldLoad_1 = load;
|
||||
global.load = function (src) {
|
||||
if (src) {
|
||||
var cache_3 = ensureCache_1();
|
||||
var ent = cache_3[src] || (cache_3[src] = {
|
||||
pop: 0,
|
||||
last: 0,
|
||||
sortorder: -10,
|
||||
});
|
||||
ent.pop++;
|
||||
ent.last = Date.now();
|
||||
var orderChanged = sortCache_1();
|
||||
saveCache_1(orderChanged);
|
||||
}
|
||||
return oldLoad_1(src);
|
||||
};
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
{
|
||||
type Timestamp = number;
|
||||
|
||||
const oldRead = require("Storage").readJSON;
|
||||
const monthAgo = Date.now() - 1000 * 86400 * 28;
|
||||
let cache: undefined | {
|
||||
[key: string]: {
|
||||
sortorder: number,
|
||||
pop: number, // amount of launches
|
||||
last: Timestamp,
|
||||
}
|
||||
};
|
||||
|
||||
const ensureCache = (): NonNull<typeof cache> => {
|
||||
if(!cache){
|
||||
cache = oldRead("popcon.cache.json", true);
|
||||
if(!cache)
|
||||
cache = {};
|
||||
}
|
||||
return cache;
|
||||
};
|
||||
|
||||
const saveCache = (orderChanged: boolean) => {
|
||||
require("Storage").writeJSON("popcon.cache.json", cache);
|
||||
if(orderChanged){
|
||||
// ensure launchers reload their caches:
|
||||
const info: AppInfo & { cacheBuster?: boolean } = oldRead("popcon.info", true);
|
||||
info.cacheBuster = !info.cacheBuster;
|
||||
require("Storage").writeJSON("popcon.info", info);
|
||||
}
|
||||
};
|
||||
|
||||
const sortCache = () => {
|
||||
const ents = Object.values(cache);
|
||||
|
||||
ents.sort((a, b) => {
|
||||
// group the most recently launched apps in the last month,
|
||||
// then sort by launch count
|
||||
// then by name
|
||||
let n;
|
||||
|
||||
const am = (a.last > monthAgo) as unknown as number;
|
||||
const bm = (b.last > monthAgo) as unknown as number;
|
||||
n = bm - am;
|
||||
if(n) return n;
|
||||
|
||||
n = b.pop - a.pop;
|
||||
if(n) return n;
|
||||
|
||||
// pops are the same, sort by most recent
|
||||
n = b.last - a.last;
|
||||
if(n) return n;
|
||||
|
||||
if(a.name<b.name) return -1;
|
||||
if(a.name>b.name) return 1;
|
||||
return 0;
|
||||
});
|
||||
|
||||
let i = 0;
|
||||
let orderChanged = false;
|
||||
for(const ent of ents){
|
||||
if(ent.sortorder !== i) orderChanged = true;
|
||||
ent.sortorder = i++;
|
||||
}
|
||||
return orderChanged;
|
||||
};
|
||||
|
||||
require("Storage").readJSON = ((fname, skipExceptions) => {
|
||||
const j: AppInfo = oldRead(fname, skipExceptions);
|
||||
// ^ technically only AppInfo if we're "*.info"
|
||||
|
||||
if(/\.info$/.test(fname)){
|
||||
const cache = ensureCache();
|
||||
let so;
|
||||
|
||||
if(j.src && (so = cache[j.src]?.sortorder) != null)
|
||||
j.sortorder = so;
|
||||
else
|
||||
j.sortorder = 99;
|
||||
}
|
||||
|
||||
return j;
|
||||
}) satisfies typeof oldRead;
|
||||
|
||||
const oldLoad = load;
|
||||
global.load = (src: string) => {
|
||||
if(src){
|
||||
const cache = ensureCache();
|
||||
const ent = cache[src] ||= {
|
||||
pop: 0,
|
||||
last: 0,
|
||||
sortorder: -10,
|
||||
};
|
||||
ent.pop++;
|
||||
ent.last = Date.now();
|
||||
const orderChanged = sortCache();
|
||||
saveCache(orderChanged);
|
||||
}
|
||||
|
||||
return oldLoad(src);
|
||||
};
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("mEwxH+AH4A/AEvNAAItq6YAFGoYEBF9I1GQ7vTAIIAMS7YqIRAQADBYwunGAyTYFyAyJLzIlJGBYvYXJowcRRaaHCAYveAoYuIF4/NdzQATF6f+45KD6vV6gfD44ME6gNBBgguU3YAB4/U64AD6fHBYQMB6YME6gMDFyoAB6wiE6wLEBhgvWEInX6AvF6ANFF7fREInRF4oMLF6xSLNhgv/GA3JF6PJFywv/F8nCF6PCF8XBBYfBF/4vSQZabLF/4wI6IvP6IuYF4nQF5/QF/4vN5IvP5Iv/F6fIBQfIF8ZUKNRQvVGAYvUFywvz3YvPRzQvE6IvN6IvfACYv/AH4A/AH4Ar"))
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"id": "popconlaunch",
|
||||
"name": "Popcon Launcher",
|
||||
"shortName": "Popcon",
|
||||
"version": "0.01",
|
||||
"description": "Launcher modification - your launchers will display your favourite (popular) apps first. Overrides `readJSON`, may slow down your watch",
|
||||
"readme": "README.md",
|
||||
"icon": "app.png",
|
||||
"type": "bootloader",
|
||||
"tags": "tool,system,launcher",
|
||||
"supports": ["BANGLEJS2"],
|
||||
"storage": [
|
||||
{"name":"popcon.boot.js","url":"boot.js"},
|
||||
{"name":"popcon.img","url":"icon.js","evaluate":true}
|
||||
],
|
||||
"data": [
|
||||
{"name":"popcon.cache.json"}
|
||||
],
|
||||
"sortorder": -10
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
type AppInfo = {
|
||||
src: string,
|
||||
img: string,
|
||||
icon: string,
|
||||
name: string,
|
||||
type: AppType,
|
||||
sortorder?: number,
|
||||
};
|
||||
|
||||
type AppType = "app" | "clock" | "widget" | "module" | "bootloader" |
|
||||
"settings" | "clkinfo" | "RAM" | "launch" | "textinput" | "scheduler" |
|
||||
"notify" | "locale";
|
Loading…
Reference in New Issue