Merge pull request #2171 from halemmerich/iconlaunch
iconlaunch - Directly eval apps instead of loading themmaster
commit
dbbedd6d5e
|
|
@ -2,3 +2,4 @@
|
|||
0.02: implemented "direct launch" and "one click exit" settings
|
||||
0.03: Use default Bangle formatter for booleans
|
||||
0.04: Support new fast app switching
|
||||
0.05: Allow to directly eval apps instead of loading
|
||||
|
|
|
|||
|
|
@ -10,3 +10,7 @@ This launcher shows 9 apps per screen, making it much faster to navigate versus
|
|||
## Technical note
|
||||
|
||||
The app uses `E.showScroller`'s code in the app but not the function itself because `E.showScroller` doesn't report the position of a press to the select function.
|
||||
|
||||
### Fastload option
|
||||
|
||||
Fastload clears up the memory used by the launcher and directly evals the code of the app to load. This means if widgets are loaded (fullscreen option) it is possible that widgets stay loaded in apps not expecting that and the widgets may draw over the app.
|
||||
|
|
|
|||
|
|
@ -1,31 +1,21 @@
|
|||
{
|
||||
const s = require("Storage");
|
||||
const settings = s.readJSON("launch.json", true) || { showClocks: true, fullscreen: false,direct:false,oneClickExit:false };
|
||||
|
||||
function returnToClock() {
|
||||
Bangle.setUI();
|
||||
setTimeout(eval,0,s.read(".bootcde"));
|
||||
}
|
||||
|
||||
if( settings.oneClickExit)
|
||||
setWatch(returnToClock, BTN1);
|
||||
|
||||
if (!settings.fullscreen) {
|
||||
if (!global.WIDGETS) Bangle.loadWidgets();
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
}
|
||||
|
||||
var apps = s
|
||||
.list(/\.info$/)
|
||||
.map((app) => {
|
||||
var a = s.readJSON(app, 1);
|
||||
var a = s.readJSON(app, 1);
|
||||
return (
|
||||
a && {
|
||||
name: a.name,
|
||||
type: a.type,
|
||||
icon: a.icon,
|
||||
sortorder: a.sortorder,
|
||||
src: a.src,
|
||||
name: a.name,
|
||||
type: a.type,
|
||||
icon: a.icon,
|
||||
sortorder: a.sortorder,
|
||||
src: a.src,
|
||||
}
|
||||
);
|
||||
})
|
||||
|
|
@ -38,34 +28,29 @@
|
|||
);
|
||||
apps.sort((a, b) => {
|
||||
var n = (0 | a.sortorder) - (0 | b.sortorder);
|
||||
if (n) return n; // do sortorder first
|
||||
if (n) return n;
|
||||
if (a.name < b.name) return -1;
|
||||
if (a.name > b.name) return 1;
|
||||
return 0;
|
||||
});
|
||||
apps.forEach((app) => {
|
||||
if (app.icon) app.icon = s.read(app.icon); // should just be a link to a memory area
|
||||
if (app.icon) app.icon = s.read(app.icon);
|
||||
});
|
||||
|
||||
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;
|
||||
|
||||
function drawItem(itemI, r) {
|
||||
let drawItem = function(itemI, r) {
|
||||
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) {
|
||||
g.setFontAlign(0,0,0).setFont("12x20:2").drawString("?", x + r.x+iconSize/2, r.y + iconSize/2);
|
||||
g.setFontAlign(0, 0, 0).setFont("12x20:2").drawString("?", x + r.x + iconSize / 2, r.y + iconSize / 2);
|
||||
} else {
|
||||
g.drawImage(apps[i].icon, x + r.x, r.y);
|
||||
}
|
||||
|
|
@ -80,9 +65,8 @@
|
|||
x += iconSize;
|
||||
}
|
||||
drawText(itemI);
|
||||
}
|
||||
|
||||
function drawItemAuto(i) {
|
||||
};
|
||||
let drawItemAuto = function(i) {
|
||||
var y = idxToY(i);
|
||||
g.reset().setClipRect(R.x, y, R.x2, y + itemSize);
|
||||
drawItem(i, {
|
||||
|
|
@ -92,11 +76,9 @@
|
|||
h: itemSize
|
||||
});
|
||||
g.setClipRect(0, 0, g.getWidth() - 1, g.getHeight() - 1);
|
||||
}
|
||||
|
||||
};
|
||||
let lastIsDown = false;
|
||||
|
||||
function drawText(i) {
|
||||
let drawText = function(i) {
|
||||
const selectedApp = apps[selectedItem];
|
||||
const idy = (selectedItem - (selectedItem % 3)) / 3;
|
||||
if (!selectedApp || i != idy) return;
|
||||
|
|
@ -111,14 +93,13 @@
|
|||
appY + rect.height / 2
|
||||
);
|
||||
g.drawString(selectedApp.name, R.w / 2, appY);
|
||||
}
|
||||
|
||||
function selectItem(id, e) {
|
||||
};
|
||||
let selectItem = function(id, e) {
|
||||
const iconN = E.clip(Math.floor((e.x - R.x) / itemSize), 0, appsN - 1);
|
||||
const appId = id * appsN + iconN;
|
||||
if( settings.direct && apps[appId])
|
||||
{
|
||||
load(apps[appId].src);
|
||||
loadApp(apps[appId].src);
|
||||
return;
|
||||
}
|
||||
if (appId == selectedItem && apps[appId]) {
|
||||
|
|
@ -126,42 +107,36 @@
|
|||
if (!app.src || s.read(app.src) === undefined) {
|
||||
E.showMessage( /*LANG*/ "App Source\nNot found");
|
||||
} else {
|
||||
load(app.src);
|
||||
loadApp(app.src);
|
||||
}
|
||||
}
|
||||
selectedItem = appId;
|
||||
drawItems();
|
||||
}
|
||||
|
||||
function idxToY(i) {
|
||||
};
|
||||
let idxToY = function(i) {
|
||||
return i * itemSize + R.y - (scroll & ~1);
|
||||
}
|
||||
|
||||
function YtoIdx(y) {
|
||||
};
|
||||
let YtoIdx = function(y) {
|
||||
return Math.floor((y + (scroll & ~1) - R.y) / itemSize);
|
||||
}
|
||||
|
||||
function drawItems() {
|
||||
};
|
||||
let drawItems = function() {
|
||||
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, {
|
||||
x: R.x,
|
||||
y: idxToY(i),
|
||||
w: R.w,
|
||||
h: itemSize,
|
||||
});
|
||||
x: R.x,
|
||||
y: idxToY(i),
|
||||
w: R.w,
|
||||
h: itemSize,
|
||||
});
|
||||
g.setClipRect(0, 0, g.getWidth() - 1, g.getHeight() - 1);
|
||||
}
|
||||
|
||||
};
|
||||
drawItems();
|
||||
g.flip();
|
||||
|
||||
const itemsN = Math.ceil(apps.length / appsN);
|
||||
|
||||
function onDrag(e){
|
||||
let onDrag = function(e) {
|
||||
g.setColor(g.theme.fg);
|
||||
g.setBgColor(g.theme.bg);
|
||||
let dy = e.dy;
|
||||
|
|
@ -190,7 +165,6 @@
|
|||
y += itemSize;
|
||||
}
|
||||
} else {
|
||||
// d>0
|
||||
g.setClipRect(R.x, R.y, R.x2, R.y + dy);
|
||||
let i = YtoIdx(R.y + dy);
|
||||
let y = idxToY(i);
|
||||
|
|
@ -206,8 +180,7 @@
|
|||
}
|
||||
}
|
||||
g.setClipRect(0, 0, g.getWidth() - 1, g.getHeight() - 1);
|
||||
}
|
||||
|
||||
};
|
||||
Bangle.setUI({
|
||||
mode: "custom",
|
||||
drag: onDrag,
|
||||
|
|
@ -217,4 +190,36 @@
|
|||
selectItem(i, e);
|
||||
},
|
||||
});
|
||||
const returnToClock = function() {
|
||||
loadApp(".bootcde");
|
||||
};
|
||||
let watch;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
if (settings.oneClickExit) {
|
||||
watch = setWatch(returnToClock, BTN1);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"id": "iconlaunch",
|
||||
"name": "Icon Launcher",
|
||||
"shortName" : "Icon launcher",
|
||||
"version": "0.04",
|
||||
"version": "0.05",
|
||||
"icon": "app.png",
|
||||
"description": "A launcher inspired by smartphones, with an icon-only scrollable menu.",
|
||||
"tags": "tool,system,launcher",
|
||||
|
|
|
|||
|
|
@ -28,6 +28,10 @@
|
|||
/*LANG*/"One click exit": {
|
||||
value: settings.oneClickExit == true,
|
||||
onchange: (m) => { save("oneClickExit", m) }
|
||||
},
|
||||
/*LANG*/"Fastload": {
|
||||
value: settings.fastload == true,
|
||||
onchange: (m) => { save("fastload", m) }
|
||||
}
|
||||
};
|
||||
E.showMenu(appMenu);
|
||||
|
|
|
|||
Loading…
Reference in New Issue