789 lines
22 KiB
JavaScript
789 lines
22 KiB
JavaScript
//const URI = "https://my.patachina2.casacam.net";
|
||
//const USER = "fabio.micheluz@gmail.com";
|
||
//const PASSW = "master66";
|
||
|
||
// ==========================================================================
|
||
// Salvataggio dati
|
||
// ==========================================================================
|
||
|
||
const SECRET_KEY = "chiave-super-segreta-123"; // puoi cambiarla
|
||
|
||
function saveConfig(url, user, password) {
|
||
const data = { url, user, password };
|
||
|
||
const encrypted = CryptoJS.AES.encrypt(
|
||
JSON.stringify(data),
|
||
SECRET_KEY
|
||
).toString();
|
||
|
||
localStorage.setItem("launcherConfig", encrypted);
|
||
}
|
||
|
||
function loadConfig() {
|
||
const encrypted = localStorage.getItem("launcherConfig");
|
||
if (!encrypted) return null;
|
||
|
||
try {
|
||
const bytes = CryptoJS.AES.decrypt(encrypted, SECRET_KEY);
|
||
return JSON.parse(bytes.toString(CryptoJS.enc.Utf8));
|
||
} catch {
|
||
return null;
|
||
}
|
||
}
|
||
|
||
function showSetupPage() {
|
||
document.getElementById("setup-page").classList.remove("hidden");
|
||
}
|
||
|
||
function hideSetupPage() {
|
||
document.getElementById("setup-page").classList.add("hidden");
|
||
}
|
||
|
||
let tapCount = 0;
|
||
let tapTimer = null;
|
||
|
||
document.addEventListener("click", () => {
|
||
tapCount++;
|
||
|
||
if (tapTimer) clearTimeout(tapTimer);
|
||
|
||
tapTimer = setTimeout(() => {
|
||
tapCount = 0;
|
||
}, 600);
|
||
|
||
if (tapCount >= 6) {
|
||
tapCount = 0;
|
||
showSetupPage();
|
||
}
|
||
});
|
||
|
||
|
||
|
||
document.addEventListener("DOMContentLoaded", () => {
|
||
|
||
// ==========================================================================
|
||
// Salva config
|
||
// ==========================================================================
|
||
document.getElementById("cfg-save").addEventListener("click", () => {
|
||
const url = document.getElementById("cfg-url").value;
|
||
const user = document.getElementById("cfg-user").value;
|
||
const pass = document.getElementById("cfg-pass").value;
|
||
|
||
saveConfig(url, user, pass);
|
||
hideSetupPage();
|
||
startLauncher();
|
||
});
|
||
|
||
|
||
|
||
|
||
// Blocca il menu contestuale nativo
|
||
document.addEventListener("contextmenu", e => e.preventDefault());
|
||
|
||
// ==========================================================================
|
||
// RIFERIMENTI DOM
|
||
// ==========================================================================
|
||
const folderEl = document.getElementById("folder");
|
||
const contextMenuEl = document.getElementById("context-menu");
|
||
|
||
// ==========================================================================
|
||
// STATO GLOBALE
|
||
// ==========================================================================
|
||
let appsData = [];
|
||
let appsOrder = [];
|
||
let editMode = false;
|
||
|
||
// Zoom
|
||
let zoomLevel;
|
||
let zoomMax;
|
||
let initialPinchDistance = null;
|
||
let lastTapTime = 0;
|
||
let zoomAnimFrame = null;
|
||
|
||
// Long‑press / drag
|
||
let longPressTimer = null;
|
||
let longPressTarget = null;
|
||
let contextMenuTargetId = null;
|
||
const MOVE_TOLERANCE = 18;
|
||
|
||
let draggingIcon = null;
|
||
let draggingId = null;
|
||
let dragOffsetX = 0;
|
||
let dragOffsetY = 0;
|
||
let dragStartX = 0;
|
||
let dragStartY = 0;
|
||
|
||
// ==========================================================================
|
||
// CARICAMENTO APPS
|
||
// ==========================================================================
|
||
function loadOrder() {
|
||
try {
|
||
const val = localStorage.getItem("appsOrder");
|
||
if (!val) return null;
|
||
const parsed = JSON.parse(val);
|
||
return Array.isArray(parsed) ? parsed : null;
|
||
} catch {
|
||
return null;
|
||
}
|
||
}
|
||
|
||
function saveOrder() {
|
||
localStorage.setItem("appsOrder", JSON.stringify(appsOrder));
|
||
}
|
||
|
||
function renderApps() {
|
||
folderEl.innerHTML = "";
|
||
|
||
appsOrder.forEach(id => {
|
||
const app = appsData.find(a => a.id === id);
|
||
if (!app) return;
|
||
|
||
const div = document.createElement("div");
|
||
div.className = "app-icon";
|
||
div.dataset.id = app.id;
|
||
|
||
div.innerHTML = `
|
||
<img src="${app.icon}" alt="${app.name}">
|
||
<span>${app.name}</span>
|
||
`;
|
||
|
||
div.addEventListener("click", () => {
|
||
if (!editMode) window.open(app.url, "_blank", "noopener");
|
||
});
|
||
|
||
folderEl.appendChild(div);
|
||
});
|
||
}
|
||
|
||
async function loadApps() {
|
||
const apps = await fetch("apps.json").then(r => r.json());
|
||
console.log(apps);
|
||
appsData = apps.map((app, i) => ({
|
||
id: app.id || `app-${i}`,
|
||
name: app.name,
|
||
url: app.url,
|
||
icon: app.icon
|
||
}));
|
||
|
||
const stored = loadOrder();
|
||
if (stored) {
|
||
appsOrder = stored.filter(id => appsData.some(a => a.id === id));
|
||
appsData.forEach(a => {
|
||
if (!appsOrder.includes(a.id)) appsOrder.push(a.id);
|
||
});
|
||
} else {
|
||
appsOrder = appsData.map(a => a.id);
|
||
}
|
||
|
||
renderApps();
|
||
}
|
||
|
||
// ==========================================================================
|
||
// UTILITY POINTER (TOUCH + MOUSE)
|
||
// ==========================================================================
|
||
function getPointerPosition(e) {
|
||
if (e.touches && e.touches.length > 0) {
|
||
return {
|
||
pageX: e.touches[0].pageX,
|
||
pageY: e.touches[0].pageY,
|
||
clientX: e.touches[0].clientX,
|
||
clientY: e.touches[0].clientY
|
||
};
|
||
}
|
||
return {
|
||
pageX: e.pageX,
|
||
pageY: e.pageY,
|
||
clientX: e.clientX,
|
||
clientY: e.clientY
|
||
};
|
||
}
|
||
|
||
// ==========================================================================
|
||
// ZOOM STILE IPHONE (PINCH ELASTICO) + WHEEL SU PC
|
||
// ==========================================================================
|
||
function computeDynamicMaxZoom() {
|
||
return Math.min(window.innerWidth / 85, 4.0);
|
||
}
|
||
|
||
function loadInitialZoom() {
|
||
const v = parseFloat(localStorage.getItem("zoomLevel"));
|
||
if (!isFinite(v) || v <= 0) return 1;
|
||
return Math.min(Math.max(v, 0.5), computeDynamicMaxZoom());
|
||
}
|
||
|
||
function applyZoom(z) {
|
||
zoomLevel = (!isFinite(z) || z <= 0) ? 1 : z;
|
||
document.documentElement.style.setProperty("--zoom", zoomLevel);
|
||
localStorage.setItem("zoomLevel", String(zoomLevel));
|
||
}
|
||
|
||
function getPinchDistance(touches) {
|
||
const [a, b] = touches;
|
||
return Math.hypot(a.clientX - b.clientX, a.clientY - b.clientY);
|
||
}
|
||
|
||
function elasticEase(x) {
|
||
return Math.sin(x * Math.PI * 0.5) * 1.05;
|
||
}
|
||
|
||
function initZoomHandlers() {
|
||
zoomMax = computeDynamicMaxZoom();
|
||
zoomLevel = loadInitialZoom();
|
||
applyZoom(zoomLevel);
|
||
|
||
// Pinch su mobile
|
||
document.addEventListener("touchmove", e => {
|
||
if (e.touches.length === 2) e.preventDefault();
|
||
}, { passive: false });
|
||
|
||
document.addEventListener("touchstart", e => {
|
||
if (e.touches.length === 2) {
|
||
initialPinchDistance = getPinchDistance(e.touches);
|
||
if (zoomAnimFrame) cancelAnimationFrame(zoomAnimFrame);
|
||
}
|
||
|
||
const now = Date.now();
|
||
if (e.touches.length === 1 && now - lastTapTime < 300) {
|
||
zoomMax = computeDynamicMaxZoom();
|
||
applyZoom(Math.min(zoomLevel * 1.15, zoomMax));
|
||
}
|
||
lastTapTime = now;
|
||
});
|
||
|
||
document.addEventListener("touchmove", e => {
|
||
if (e.touches.length === 2 && initialPinchDistance) {
|
||
const newDist = getPinchDistance(e.touches);
|
||
const scale = newDist / initialPinchDistance;
|
||
|
||
let newZoom = zoomLevel * scale;
|
||
zoomMax = computeDynamicMaxZoom();
|
||
|
||
if (newZoom > zoomMax) newZoom = zoomMax + (newZoom - zoomMax) * 0.25;
|
||
if (newZoom < 0.5) newZoom = 0.5 - (0.5 - newZoom) * 0.25;
|
||
|
||
applyZoom(newZoom);
|
||
initialPinchDistance = newDist;
|
||
e.preventDefault();
|
||
}
|
||
}, { passive: false });
|
||
|
||
document.addEventListener("touchend", e => {
|
||
if (e.touches.length < 2 && initialPinchDistance) {
|
||
initialPinchDistance = null;
|
||
|
||
zoomMax = computeDynamicMaxZoom();
|
||
const target = Math.min(Math.max(zoomLevel, 0.5), zoomMax);
|
||
const start = zoomLevel;
|
||
const duration = 250;
|
||
const startTime = performance.now();
|
||
|
||
function animate(t) {
|
||
const p = Math.min((t - startTime) / duration, 1);
|
||
const eased = start + (target - start) * elasticEase(p);
|
||
applyZoom(eased);
|
||
if (p < 1) zoomAnimFrame = requestAnimationFrame(animate);
|
||
}
|
||
|
||
zoomAnimFrame = requestAnimationFrame(animate);
|
||
}
|
||
});
|
||
|
||
// Zoom con wheel su PC
|
||
document.addEventListener("wheel", e => {
|
||
// Se vuoi zoomare solo con CTRL, scommenta:
|
||
// if (!e.ctrlKey) return;
|
||
|
||
e.preventDefault();
|
||
|
||
zoomMax = computeDynamicMaxZoom();
|
||
|
||
const direction = e.deltaY < 0 ? 1 : -1;
|
||
const factor = 1 + direction * 0.1;
|
||
|
||
let newZoom = zoomLevel * factor;
|
||
|
||
if (newZoom > zoomMax) newZoom = zoomMax + (newZoom - zoomMax) * 0.25;
|
||
if (newZoom < 0.5) newZoom = 0.5 - (0.5 - newZoom) * 0.25;
|
||
|
||
applyZoom(newZoom);
|
||
}, { passive: false });
|
||
}
|
||
|
||
// ==========================================================================
|
||
// EDIT MODE + MENU CONTESTUALE + WIGGLE
|
||
// ==========================================================================
|
||
function enterEditMode() {
|
||
editMode = true;
|
||
document.body.classList.add("edit-mode");
|
||
}
|
||
|
||
function exitEditMode() {
|
||
editMode = false;
|
||
document.body.classList.remove("edit-mode");
|
||
hideContextMenu();
|
||
}
|
||
|
||
function showContextMenuFor(id, x, y) {
|
||
contextMenuTargetId = id;
|
||
contextMenuEl.style.left = `${x}px`;
|
||
contextMenuEl.style.top = `${y}px`;
|
||
contextMenuEl.classList.remove("hidden");
|
||
}
|
||
|
||
function hideContextMenu() {
|
||
contextMenuEl.classList.add("hidden");
|
||
contextMenuTargetId = null;
|
||
}
|
||
|
||
// ==========================================================================
|
||
// LONG PRESS MOBILE + PC
|
||
// ==========================================================================
|
||
function initLongPressHandlers() {
|
||
// --- TOUCH ---
|
||
document.addEventListener("touchstart", e => {
|
||
if (e.touches.length !== 1) return;
|
||
|
||
const touch = e.touches[0];
|
||
const icon = touch.target.closest(".app-icon");
|
||
|
||
if (icon) {
|
||
longPressTarget = icon;
|
||
|
||
longPressTimer = setTimeout(() => {
|
||
if (!editMode) {
|
||
enterEditMode();
|
||
if (navigator.vibrate) navigator.vibrate(10);
|
||
return;
|
||
}
|
||
|
||
const r = icon.getBoundingClientRect();
|
||
showContextMenuFor(
|
||
icon.dataset.id,
|
||
r.left + r.width / 2,
|
||
r.top + r.height
|
||
);
|
||
if (navigator.vibrate) navigator.vibrate(10);
|
||
}, 350);
|
||
|
||
return;
|
||
}
|
||
|
||
// Long press fuori icone → esce da edit mode
|
||
longPressTimer = setTimeout(() => {
|
||
if (editMode) exitEditMode();
|
||
}, 350);
|
||
|
||
}, { passive: true });
|
||
|
||
document.addEventListener("touchmove", e => {
|
||
if (!longPressTimer) return;
|
||
|
||
const touch = e.touches[0];
|
||
const dx = touch.clientX - (longPressTarget?.getBoundingClientRect().left ?? touch.clientX);
|
||
const dy = touch.clientY - (longPressTarget?.getBoundingClientRect().top ?? touch.clientY);
|
||
|
||
if (Math.hypot(dx, dy) > 15) {
|
||
clearTimeout(longPressTimer);
|
||
longPressTimer = null;
|
||
longPressTarget = null;
|
||
}
|
||
}, { passive: true });
|
||
|
||
document.addEventListener("touchend", () => {
|
||
if (longPressTimer) {
|
||
clearTimeout(longPressTimer);
|
||
longPressTimer = null;
|
||
longPressTarget = null;
|
||
}
|
||
}, { passive: true });
|
||
|
||
// --- MOUSE ---
|
||
document.addEventListener("mousedown", e => {
|
||
if (e.button !== 0) return;
|
||
|
||
const icon = e.target.closest(".app-icon");
|
||
|
||
longPressTarget = icon ?? null;
|
||
|
||
longPressTimer = setTimeout(() => {
|
||
if (!editMode) {
|
||
enterEditMode();
|
||
return;
|
||
}
|
||
|
||
if (icon) {
|
||
const r = icon.getBoundingClientRect();
|
||
showContextMenuFor(
|
||
icon.dataset.id,
|
||
r.left + r.width / 2,
|
||
r.top + r.height
|
||
);
|
||
}
|
||
}, 350);
|
||
});
|
||
|
||
document.addEventListener("mousemove", e => {
|
||
if (!longPressTimer) return;
|
||
|
||
if (longPressTarget) {
|
||
const r = longPressTarget.getBoundingClientRect();
|
||
const dx = e.clientX - (r.left + r.width / 2);
|
||
const dy = e.clientY - (r.top + r.height / 2);
|
||
|
||
if (Math.hypot(dx, dy) > 15) {
|
||
clearTimeout(longPressTimer);
|
||
longPressTimer = null;
|
||
longPressTarget = null;
|
||
}
|
||
}
|
||
});
|
||
|
||
document.addEventListener("mouseup", () => {
|
||
if (longPressTimer) {
|
||
clearTimeout(longPressTimer);
|
||
longPressTimer = null;
|
||
longPressTarget = null;
|
||
}
|
||
});
|
||
}
|
||
|
||
// ==========================================================================
|
||
// DRAG FLUIDO STILE IPHONE CON PLACEHOLDER + FIX "SOTTO IL DITO"
|
||
// ==========================================================================
|
||
function startDrag(icon, pos) {
|
||
draggingId = icon.dataset.id;
|
||
|
||
const r = icon.getBoundingClientRect();
|
||
dragOffsetX = pos.pageX - r.left;
|
||
dragOffsetY = pos.pageY - r.top;
|
||
|
||
draggingIcon = icon;
|
||
draggingIcon.classList.add("dragging");
|
||
draggingIcon.style.position = "fixed";
|
||
draggingIcon.style.left = `${r.left}px`;
|
||
draggingIcon.style.top = `${r.top}px`;
|
||
draggingIcon.style.width = `${r.width}px`;
|
||
draggingIcon.style.height = `${r.height}px`;
|
||
draggingIcon.style.zIndex = "1000";
|
||
draggingIcon.style.pointerEvents = "none";
|
||
draggingIcon.style.transform = "translate3d(0,0,0)";
|
||
|
||
const placeholder = icon.cloneNode(true);
|
||
placeholder.classList.add("placeholder");
|
||
placeholder.style.visibility = "hidden";
|
||
icon.parentNode.insertBefore(placeholder, icon);
|
||
|
||
hideContextMenu();
|
||
}
|
||
|
||
function updateDragPosition(pos) {
|
||
if (!draggingIcon) return;
|
||
|
||
const x = pos.pageX - dragOffsetX;
|
||
const y = pos.pageY - dragOffsetY;
|
||
|
||
draggingIcon.style.left = `${x}px`;
|
||
draggingIcon.style.top = `${y}px`;
|
||
|
||
const elem = document.elementFromPoint(pos.clientX, pos.clientY);
|
||
const targetIcon = elem && elem.closest(".app-icon:not(.dragging):not(.placeholder)");
|
||
if (!targetIcon) return;
|
||
|
||
const from = appsOrder.indexOf(draggingId);
|
||
const to = appsOrder.indexOf(targetIcon.dataset.id);
|
||
if (from === -1 || to === -1 || from === to) return;
|
||
|
||
appsOrder.splice(from, 1);
|
||
appsOrder.splice(to, 0, draggingId);
|
||
saveOrder();
|
||
}
|
||
|
||
// ==========================================================================
|
||
// DROP PRECISO NELLA CELLA CORRETTA
|
||
// ==========================================================================
|
||
function endDrag() {
|
||
if (!draggingIcon) return;
|
||
|
||
const icon = draggingIcon;
|
||
draggingIcon = null;
|
||
|
||
const placeholder = folderEl.querySelector(".app-icon.placeholder");
|
||
if (placeholder) placeholder.remove();
|
||
|
||
const left = parseFloat(icon.style.left) || 0;
|
||
const top = parseFloat(icon.style.top) || 0;
|
||
const dropXClient = left + icon.offsetWidth / 2;
|
||
const dropYClient = top + icon.offsetHeight / 2;
|
||
|
||
const elem = document.elementFromPoint(dropXClient, dropYClient);
|
||
const targetIcon = elem && elem.closest(".app-icon:not(.dragging)");
|
||
|
||
if (targetIcon) {
|
||
const from = appsOrder.indexOf(icon.dataset.id);
|
||
const to = appsOrder.indexOf(targetIcon.dataset.id);
|
||
|
||
if (from !== -1 && to !== -1 && from !== to) {
|
||
appsOrder.splice(from, 1);
|
||
appsOrder.splice(to, 0, icon.dataset.id);
|
||
saveOrder();
|
||
}
|
||
}
|
||
|
||
icon.classList.remove("dragging");
|
||
icon.style.position = "";
|
||
icon.style.left = "";
|
||
icon.style.top = "";
|
||
icon.style.width = "";
|
||
icon.style.height = "";
|
||
icon.style.zIndex = "";
|
||
icon.style.pointerEvents = "";
|
||
icon.style.transform = "";
|
||
|
||
renderApps();
|
||
}
|
||
|
||
function initDragHandlers() {
|
||
// --- TOUCH ---
|
||
document.addEventListener("touchstart", e => {
|
||
if (!editMode) return;
|
||
if (e.touches.length !== 1) return;
|
||
if (contextMenuTargetId) return;
|
||
|
||
const pos = getPointerPosition(e);
|
||
const icon = e.touches[0].target.closest(".app-icon");
|
||
if (!icon) return;
|
||
|
||
dragStartX = pos.clientX;
|
||
dragStartY = pos.clientY;
|
||
draggingIcon = null;
|
||
draggingId = null;
|
||
}, { passive: true });
|
||
|
||
document.addEventListener("touchmove", e => {
|
||
if (!editMode) return;
|
||
if (e.touches.length !== 1) return;
|
||
|
||
const pos = getPointerPosition(e);
|
||
|
||
if (!draggingIcon) {
|
||
const dx = pos.clientX - dragStartX;
|
||
const dy = pos.clientY - dragStartY;
|
||
if (Math.hypot(dx, dy) > 10) {
|
||
const icon = e.touches[0].target.closest(".app-icon");
|
||
if (icon) {
|
||
if (longPressTimer) {
|
||
clearTimeout(longPressTimer);
|
||
longPressTimer = null;
|
||
longPressTarget = null;
|
||
}
|
||
startDrag(icon, pos);
|
||
}
|
||
}
|
||
} else {
|
||
updateDragPosition(pos);
|
||
e.preventDefault();
|
||
}
|
||
}, { passive: false });
|
||
|
||
document.addEventListener("touchend", e => {
|
||
if (!editMode) return;
|
||
if (draggingIcon && (!e.touches || e.touches.length === 0)) {
|
||
endDrag();
|
||
}
|
||
}, { passive: true });
|
||
|
||
// --- MOUSE ---
|
||
document.addEventListener("mousedown", e => {
|
||
if (!editMode) return;
|
||
if (e.button !== 0) return;
|
||
if (contextMenuTargetId) return;
|
||
|
||
const icon = e.target.closest(".app-icon");
|
||
if (!icon) return;
|
||
|
||
const pos = getPointerPosition(e);
|
||
dragStartX = pos.clientX;
|
||
dragStartY = pos.clientY;
|
||
draggingIcon = null;
|
||
draggingId = null;
|
||
});
|
||
|
||
document.addEventListener("mousemove", e => {
|
||
if (!editMode) return;
|
||
|
||
const pos = getPointerPosition(e);
|
||
|
||
if (!draggingIcon) {
|
||
if (!dragStartX && !dragStartY) return;
|
||
|
||
const dx = pos.clientX - dragStartX;
|
||
const dy = pos.clientY - dragStartY;
|
||
if (Math.hypot(dx, dy) > 10) {
|
||
const icon = e.target.closest(".app-icon");
|
||
if (icon) {
|
||
if (longPressTimer) {
|
||
clearTimeout(longPressTimer);
|
||
longPressTimer = null;
|
||
longPressTarget = null;
|
||
}
|
||
startDrag(icon, pos);
|
||
}
|
||
}
|
||
} else {
|
||
updateDragPosition(pos);
|
||
}
|
||
});
|
||
|
||
document.addEventListener("mouseup", () => {
|
||
if (!editMode) return;
|
||
dragStartX = 0;
|
||
dragStartY = 0;
|
||
if (draggingIcon) {
|
||
endDrag();
|
||
}
|
||
});
|
||
}
|
||
|
||
// ==========================================================================
|
||
// MENU CONTESTUALE: AZIONI
|
||
// ==========================================================================
|
||
function initContextMenuActions() {
|
||
contextMenuEl.addEventListener("click", e => {
|
||
const btn = e.target.closest("button");
|
||
if (!btn || !contextMenuTargetId) return;
|
||
|
||
const action = btn.dataset.action;
|
||
const app = appsData.find(a => a.id === contextMenuTargetId);
|
||
if (!app) return;
|
||
|
||
if (action === "rename") {
|
||
const nuovoNome = prompt("Nuovo nome app:", app.name);
|
||
if (nuovoNome && nuovoNome.trim()) {
|
||
app.name = nuovoNome.trim();
|
||
renderApps();
|
||
saveOrder();
|
||
}
|
||
}
|
||
|
||
if (action === "change-icon") {
|
||
const nuovaIcona = prompt("URL nuova icona:", app.icon);
|
||
if (nuovaIcona && nuovaIcona.trim()) {
|
||
app.icon = nuovaIcona.trim();
|
||
renderApps();
|
||
saveOrder();
|
||
}
|
||
}
|
||
|
||
if (action === "remove") {
|
||
if (confirm("Rimuovere questa app dalla griglia?")) {
|
||
appsOrder = appsOrder.filter(id => id !== app.id);
|
||
saveOrder();
|
||
renderApps();
|
||
}
|
||
}
|
||
|
||
hideContextMenu();
|
||
});
|
||
}
|
||
|
||
function initGlobalCloseHandlers() {
|
||
document.addEventListener("pointerdown", e => {
|
||
const isIcon = e.target.closest(".app-icon");
|
||
const isMenu = e.target.closest("#context-menu");
|
||
|
||
// 1️⃣ Clic fuori dal menu → chiudi menu
|
||
if (!isMenu && !isIcon && !contextMenuEl.classList.contains("hidden")) {
|
||
hideContextMenu();
|
||
}
|
||
|
||
// 2️⃣ Clic fuori dalle icone → esci da wiggle mode
|
||
if (!isIcon && editMode) {
|
||
exitEditMode();
|
||
}
|
||
});
|
||
}
|
||
// ==========================================================================
|
||
// LOAD APPS
|
||
// ==========================================================================
|
||
|
||
async function login(email, password) {
|
||
const res = await fetch(`${URI}/auth/login`, {
|
||
method: "POST",
|
||
headers: { "Content-Type": "application/json" },
|
||
body: JSON.stringify({ email, password })
|
||
});
|
||
|
||
const data = await res.json();
|
||
return data.token;
|
||
}
|
||
|
||
async function getLinks() {
|
||
const token = await login(USER, PASSW);
|
||
|
||
const res = await fetch(`${URI}/links`, {
|
||
headers: {
|
||
"Authorization": `Bearer ${token}`,
|
||
"Accept": "application/json"
|
||
}
|
||
});
|
||
|
||
const json = await res.json();
|
||
//console.log(json);
|
||
appsData = json.map((json, i) => ({
|
||
id: json.id || `app-${i}`,
|
||
name: json.name,
|
||
url: json.url,
|
||
icon: `${URI}${json.icon}`
|
||
}));
|
||
console.log(appsData);
|
||
|
||
const stored = loadOrder();
|
||
if (stored) {
|
||
appsOrder = stored.filter(id => appsData.some(a => a.id === id));
|
||
appsData.forEach(a => {
|
||
if (!appsOrder.includes(a.id)) appsOrder.push(a.id);
|
||
});
|
||
} else {
|
||
appsOrder = appsData.map(a => a.id);
|
||
}
|
||
|
||
renderApps();
|
||
|
||
}
|
||
|
||
|
||
const config = loadConfig();
|
||
let URI;
|
||
let USER;
|
||
let PASSW;
|
||
|
||
|
||
if (!config) {
|
||
showSetupPage();
|
||
} else {
|
||
hideSetupPage();
|
||
startLauncher(); // la tua funzione
|
||
}
|
||
|
||
|
||
// ==========================================================================
|
||
// INIT GLOBALE
|
||
// ==========================================================================
|
||
|
||
|
||
async function startLauncher() {
|
||
//(async function init() {
|
||
//await loadApps();
|
||
const conf = loadConfig();
|
||
URI = conf.url;
|
||
USER = conf.user;
|
||
PASSW = conf.password
|
||
await getLinks();
|
||
initZoomHandlers();
|
||
initLongPressHandlers();
|
||
initDragHandlers();
|
||
initContextMenuActions();
|
||
initGlobalCloseHandlers();
|
||
// })();
|
||
}
|
||
});
|