// Device status bar: always-visible strip (below the page title, above // the tabs -- see _device_status_bar.html) showing last-seen/firmware/ // battery, so it's not tucked away on just the Stats tab. Shared by // every frame page; each sets window.FRAME_API before this loads. let lastDeviceStatus = null; function renderDeviceStatusBar(device) { const el = document.getElementById('device-status'); if (!el) return; el.innerHTML = ''; if (!device || !device.last_seen) { el.innerHTML = '
The frame hasn\'t checked in yet.
'; return; } const now = Date.now() / 1000; const rows = []; const ago = formatDuration(Math.max(0, now - device.last_seen)); rows.push(['Last seen', `${ago} ago`, device.overdue]); if (device.firmware_version) { let fw = `v${device.firmware_version}`; if (device.firmware_available && device.firmware_available !== device.firmware_version) { fw += ` (v${device.firmware_available} waiting)`; } rows.push(['Firmware', fw, false]); } if (device.battery) { rows.push(['Battery', `${device.battery.percent}%`, false]); } if (device.on_battery_since) { rows.push(['On battery for', formatDuration(now - device.on_battery_since), false]); } if (device.battery_estimate_s !== null && device.battery_estimate_s !== undefined) { rows.push(['Est. remaining', `~${formatDuration(device.battery_estimate_s)}`, false]); } for (const [label, value, alert] of rows) { const stat = document.createElement('span'); stat.className = 'device-stat' + (alert ? ' alert' : ''); const labelPart = document.createTextNode(label + ': '); const valuePart = document.createElement('strong'); valuePart.textContent = value; stat.appendChild(labelPart); stat.appendChild(valuePart); el.appendChild(stat); } } async function loadDeviceStatusBar() { try { const resp = await fetch(`${window.FRAME_API}/queue`); if (!resp.ok) { return; } const data = await resp.json(); lastDeviceStatus = data.device; renderDeviceStatusBar(data.device); } catch (e) { /* retried on the next poll */ } } loadDeviceStatusBar(); document.addEventListener('themechange', () => { if (lastDeviceStatus) { renderDeviceStatusBar(lastDeviceStatus); } }); // Fast tick: re-renders "Last seen"/"On battery for" from already- // fetched data every second so they count up smoothly without hitting // the server that often. setInterval(() => { if (lastDeviceStatus) { renderDeviceStatusBar(lastDeviceStatus); } }, 1000); setInterval(loadDeviceStatusBar, 10000);