2022-09-27 18:44:48 +00:00
|
|
|
{
|
|
|
|
const s = require("Storage");
|
|
|
|
const settings = s.readJSON("launch.json", true) || { showClocks: true, fullscreen: false,direct:false,oneClickExit:false };
|
|
|
|
if (!settings.fullscreen) {
|
2022-10-13 20:26:33 +00:00
|
|
|
Bangle.loadWidgets();
|
2022-09-27 18:44:48 +00:00
|
|
|
Bangle.drawWidgets();
|
2022-05-24 00:18:26 +00:00
|
|
|
}
|
2022-10-20 16:46:06 +00:00
|
|
|
let launchCache = s.readJSON("launch.cache.json", true)||{};
|
|
|
|
let launchHash = require("Storage").hash(/\.info/);
|
|
|
|
if (launchCache.hash!=launchHash) {
|
|
|
|
launchCache = {
|
|
|
|
hash : launchHash,
|
|
|
|
apps : s.list(/\.info$/)
|
|
|
|
.map(app=>{var a=s.readJSON(app,1);return a&&{name:a.name,type:a.type,icon:a.icon,sortorder:a.sortorder,src:a.src};})
|
|
|
|
.filter(app=>app && (app.type=="app" || (app.type=="clock" && settings.showClocks) || !app.type))
|
|
|
|
.sort((a,b)=>{
|
|
|
|
var n=(0|a.sortorder)-(0|b.sortorder);
|
|
|
|
if (n) return n; // do sortorder first
|
|
|
|
if (a.name<b.name) return -1;
|
|
|
|
if (a.name>b.name) return 1;
|
|
|
|
return 0;
|
|
|
|
}) };
|
|
|
|
s.writeJSON("launch.cache.json", launchCache);
|
|
|
|
}
|
|
|
|
let apps = launchCache.apps;
|
2022-09-27 18:44:48 +00:00
|
|
|
apps.forEach((app) => {
|
2022-10-07 06:23:21 +00:00
|
|
|
if (app.icon) app.icon = s.read(app.icon);
|
2022-05-24 00:18:26 +00:00
|
|
|
});
|
2022-09-27 18:44:48 +00:00
|
|
|
let scroll = 0;
|
|
|
|
let selectedItem = -1;
|
|
|
|
const R = Bangle.appRect;
|
|
|
|
const iconSize = 48;
|
|
|
|
const appsN = Math.floor(R.w / iconSize);
|
|
|
|
const whitespace = (R.w - appsN * iconSize) / (appsN + 1);
|
|
|
|
const itemSize = iconSize + whitespace;
|
2022-10-06 18:06:12 +00:00
|
|
|
let drawItem = function(itemI, r) {
|
2022-09-27 18:44:48 +00:00
|
|
|
g.clearRect(r.x, r.y, r.x + r.w - 1, r.y + r.h - 1);
|
|
|
|
let x = 0;
|
|
|
|
for (let i = itemI * appsN; i < appsN * (itemI + 1); i++) {
|
|
|
|
if (!apps[i]) break;
|
|
|
|
x += whitespace;
|
|
|
|
if (!apps[i].icon) {
|
2022-10-07 06:23:21 +00:00
|
|
|
g.setFontAlign(0, 0, 0).setFont("12x20:2").drawString("?", x + r.x + iconSize / 2, r.y + iconSize / 2);
|
2022-09-27 18:44:48 +00:00
|
|
|
} else {
|
|
|
|
g.drawImage(apps[i].icon, x + r.x, r.y);
|
|
|
|
}
|
|
|
|
if (selectedItem == i) {
|
|
|
|
g.drawRect(
|
|
|
|
x + r.x - 1,
|
|
|
|
r.y - 1,
|
|
|
|
x + r.x + iconSize + 1,
|
|
|
|
r.y + iconSize + 1
|
|
|
|
);
|
|
|
|
}
|
|
|
|
x += iconSize;
|
|
|
|
}
|
|
|
|
drawText(itemI);
|
2022-10-06 18:06:12 +00:00
|
|
|
};
|
|
|
|
let drawItemAuto = function(i) {
|
2022-09-27 18:44:48 +00:00
|
|
|
var y = idxToY(i);
|
|
|
|
g.reset().setClipRect(R.x, y, R.x2, y + itemSize);
|
2022-05-24 00:18:26 +00:00
|
|
|
drawItem(i, {
|
|
|
|
x: R.x,
|
2022-09-27 18:44:48 +00:00
|
|
|
y: y,
|
2022-05-24 00:18:26 +00:00
|
|
|
w: R.w,
|
2022-09-27 18:44:48 +00:00
|
|
|
h: itemSize
|
2022-05-24 00:18:26 +00:00
|
|
|
});
|
2022-09-27 18:44:48 +00:00
|
|
|
g.setClipRect(0, 0, g.getWidth() - 1, g.getHeight() - 1);
|
2022-10-06 18:06:12 +00:00
|
|
|
};
|
2022-09-27 18:44:48 +00:00
|
|
|
let lastIsDown = false;
|
2022-10-06 18:06:12 +00:00
|
|
|
let drawText = function(i) {
|
2022-09-27 18:44:48 +00:00
|
|
|
const selectedApp = apps[selectedItem];
|
|
|
|
const idy = (selectedItem - (selectedItem % 3)) / 3;
|
|
|
|
if (!selectedApp || i != idy) return;
|
|
|
|
const appY = idxToY(idy) + iconSize / 2;
|
|
|
|
g.setFontAlign(0, 0, 0);
|
|
|
|
g.setFont("12x20");
|
|
|
|
const rect = g.stringMetrics(selectedApp.name);
|
|
|
|
g.clearRect(
|
|
|
|
R.w / 2 - rect.width / 2,
|
|
|
|
appY - rect.height / 2,
|
|
|
|
R.w / 2 + rect.width / 2,
|
|
|
|
appY + rect.height / 2
|
|
|
|
);
|
|
|
|
g.drawString(selectedApp.name, R.w / 2, appY);
|
2022-10-06 18:06:12 +00:00
|
|
|
};
|
|
|
|
let selectItem = function(id, e) {
|
2022-09-27 18:44:48 +00:00
|
|
|
const iconN = E.clip(Math.floor((e.x - R.x) / itemSize), 0, appsN - 1);
|
|
|
|
const appId = id * appsN + iconN;
|
|
|
|
if( settings.direct && apps[appId])
|
|
|
|
{
|
2022-10-06 18:06:12 +00:00
|
|
|
loadApp(apps[appId].src);
|
2022-09-27 18:44:48 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (appId == selectedItem && apps[appId]) {
|
|
|
|
const app = apps[appId];
|
|
|
|
if (!app.src || s.read(app.src) === undefined) {
|
|
|
|
E.showMessage( /*LANG*/ "App Source\nNot found");
|
|
|
|
} else {
|
2022-10-13 20:09:51 +00:00
|
|
|
loadApp(app.src);
|
2022-09-27 18:44:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
selectedItem = appId;
|
|
|
|
drawItems();
|
2022-10-06 18:06:12 +00:00
|
|
|
};
|
|
|
|
let idxToY = function(i) {
|
2022-09-27 18:44:48 +00:00
|
|
|
return i * itemSize + R.y - (scroll & ~1);
|
2022-10-06 18:06:12 +00:00
|
|
|
};
|
|
|
|
let YtoIdx = function(y) {
|
2022-09-27 18:44:48 +00:00
|
|
|
return Math.floor((y + (scroll & ~1) - R.y) / itemSize);
|
2022-10-06 18:06:12 +00:00
|
|
|
};
|
|
|
|
let drawItems = function() {
|
2022-09-27 18:44:48 +00:00
|
|
|
g.reset().clearRect(R.x, R.y, R.x2, R.y2);
|
|
|
|
g.setClipRect(R.x, R.y, R.x2, R.y2);
|
|
|
|
var a = YtoIdx(R.y);
|
|
|
|
var b = Math.min(YtoIdx(R.y2), 99);
|
|
|
|
for (var i = a; i <= b; i++)
|
|
|
|
drawItem(i, {
|
2022-10-07 06:23:21 +00:00
|
|
|
x: R.x,
|
|
|
|
y: idxToY(i),
|
|
|
|
w: R.w,
|
|
|
|
h: itemSize,
|
|
|
|
});
|
2022-09-27 18:44:48 +00:00
|
|
|
g.setClipRect(0, 0, g.getWidth() - 1, g.getHeight() - 1);
|
2022-10-06 18:06:12 +00:00
|
|
|
};
|
2022-09-27 18:44:48 +00:00
|
|
|
drawItems();
|
|
|
|
g.flip();
|
|
|
|
const itemsN = Math.ceil(apps.length / appsN);
|
2022-10-07 06:23:21 +00:00
|
|
|
let onDrag = function(e) {
|
2022-06-05 12:49:27 +00:00
|
|
|
g.setColor(g.theme.fg);
|
|
|
|
g.setBgColor(g.theme.bg);
|
2022-05-24 00:18:26 +00:00
|
|
|
let dy = e.dy;
|
|
|
|
if (scroll + R.h - dy > itemsN * itemSize) {
|
|
|
|
dy = scroll + R.h - itemsN * itemSize;
|
|
|
|
}
|
|
|
|
if (scroll - dy < 0) {
|
|
|
|
dy = scroll;
|
|
|
|
}
|
|
|
|
scroll -= dy;
|
|
|
|
scroll = E.clip(scroll, 0, itemSize * (itemsN - 1));
|
|
|
|
g.setClipRect(R.x, R.y, R.x2, R.y2);
|
|
|
|
g.scroll(0, dy);
|
|
|
|
if (dy < 0) {
|
|
|
|
g.setClipRect(R.x, R.y2 - (1 - dy), R.x2, R.y2);
|
|
|
|
let i = YtoIdx(R.y2 - (1 - dy));
|
|
|
|
let y = idxToY(i);
|
|
|
|
while (y < R.y2) {
|
|
|
|
drawItem(i, {
|
|
|
|
x: R.x,
|
|
|
|
y: y,
|
|
|
|
w: R.w,
|
|
|
|
h: itemSize,
|
|
|
|
});
|
|
|
|
i++;
|
|
|
|
y += itemSize;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
g.setClipRect(R.x, R.y, R.x2, R.y + dy);
|
|
|
|
let i = YtoIdx(R.y + dy);
|
|
|
|
let y = idxToY(i);
|
|
|
|
while (y > R.y - itemSize) {
|
|
|
|
drawItem(i, {
|
|
|
|
x: R.x,
|
|
|
|
y: y,
|
|
|
|
w: R.w,
|
|
|
|
h: itemSize,
|
|
|
|
});
|
|
|
|
y -= itemSize;
|
|
|
|
i--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
g.setClipRect(0, 0, g.getWidth() - 1, g.getHeight() - 1);
|
2022-10-06 18:06:12 +00:00
|
|
|
};
|
2022-09-27 18:44:48 +00:00
|
|
|
Bangle.setUI({
|
|
|
|
mode: "custom",
|
|
|
|
drag: onDrag,
|
|
|
|
touch: (_, e) => {
|
|
|
|
if (e.y < R.y - 4) return;
|
|
|
|
var i = YtoIdx(e.y);
|
|
|
|
selectItem(i, e);
|
|
|
|
},
|
|
|
|
});
|
2022-10-06 18:06:12 +00:00
|
|
|
const returnToClock = function() {
|
|
|
|
loadApp(".bootcde");
|
|
|
|
};
|
2022-10-07 06:23:21 +00:00
|
|
|
let watch;
|
2022-10-13 20:09:51 +00:00
|
|
|
let loadApp;
|
|
|
|
if (settings.fastload){
|
|
|
|
loadApp = function(name) {
|
|
|
|
Bangle.setUI();
|
|
|
|
if (watch) clearWatch(watch);
|
|
|
|
apps = [];
|
|
|
|
delete drawItemAuto;
|
|
|
|
delete drawText;
|
|
|
|
delete selectItem;
|
|
|
|
delete onDrag;
|
|
|
|
delete drawItems;
|
|
|
|
delete drawItem;
|
|
|
|
delete returnToClock;
|
|
|
|
delete idxToY;
|
|
|
|
delete YtoIdx;
|
|
|
|
delete settings;
|
|
|
|
setTimeout(eval, 0, s.read(name));
|
|
|
|
return;
|
|
|
|
};
|
|
|
|
} else {
|
|
|
|
loadApp = function(name) {
|
|
|
|
load(name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-07 06:23:21 +00:00
|
|
|
if (settings.oneClickExit) {
|
|
|
|
watch = setWatch(returnToClock, BTN1);
|
2022-10-06 18:06:12 +00:00
|
|
|
}
|
2022-09-27 18:44:48 +00:00
|
|
|
}
|