import HTML from '../HTML' import { AppClosedEvent, AppOpenedEvent, Process } from '../types' import { getTime } from '../utils' import nullIcon from '../assets/icons/application-default-icon.svg' import { parse } from 'js-ini' import { v4 as uuid } from 'uuid' const BootLoader: Process = { config: { name: 'Bootloader', type: 'process', targetVer: '1.0.0-indev.0' }, run: async (process) => { const splashScreen = await process.loadLibrary('lib/SplashScreen') const splashElement = splashScreen.getElement() splashElement.appendTo(document.body) const { fs } = process const wm = await process.loadLibrary('lib/WindowManager') const launcher = await process.loadLibrary('lib/Launcher') const config = Buffer.from(await fs.readFile('/etc/flow')).toString() process.kernel.setConfig(parse(config)) if ('serviceWorker' in navigator) { const registrations = await navigator.serviceWorker.getRegistrations() for (const registration of registrations) { await registration.unregister() } try { await navigator.serviceWorker.register(`/uv-sw.js?url=${encodeURIComponent(btoa(process.kernel.config.SERVER))}&e=${uuid()}`, { scope: '/service/' }) } catch (e) { console.error(e) } } else { console.warn('Service workers are not supported.') } const input = new HTML('input').attr({ type: 'text', placeholder: 'Search' }).on('keyup', () => { apps.elm.innerHTML = '' renderApps().catch(e => console.error(e)) }).appendTo(launcher.element) const apps = new HTML('apps').appendTo(launcher.element) const renderApps = async (): Promise => { apps.html('') const files = await fs.readdir('/home/Applications/') files .filter((x: string) => x.endsWith('.app') && ((input.elm as HTMLInputElement) !== null ? x.toLowerCase().includes((input.elm as HTMLInputElement).value.toLowerCase()) : true)) .forEach((file: string) => { fs.readFile(`/home/Applications/${file}`).then(async (data: Uint8Array) => { const path = Buffer.from(data).toString() const executable = await process.kernel.getExecutable(path) as Process const appElement = new HTML('app').on('click', () => { process.launch(path).catch((e: any) => console.error(e)) launcher.toggle() }).appendTo(apps) new HTML('img').attr({ src: executable.config.icon ?? nullIcon, alt: `${executable.config.name} icon` }).appendTo(appElement) new HTML('div').text(executable.config.name).appendTo(appElement) }).catch((e: any) => console.error(e)) }) } await renderApps() document.addEventListener('fs_update', () => { renderApps().catch(e => console.error(e)) }) launcher.element.on('click', (e: Event) => { if (e.target !== e.currentTarget) return launcher.toggle() }) const statusBar = await process.loadLibrary('lib/StatusBar') statusBar.element.html(`
space_dashboard
expand_less
battery_2_bar signal_cellular_4_bar
`) setInterval((): any => { getTime().then((time) => { statusBar.element.qs('div[data-toolbar-id="calendar"]')?.text(time) }).catch(e => console.error) }, 1000) statusBar.element.qs('div[data-toolbar-id="start"]')?.on('click', () => { launcher.toggle() }) if ('getBattery' in navigator) { (navigator as any).getBattery().then((battery: any) => { statusBar.updateBatteryIcon(battery) battery.addEventListener('levelchange', () => { statusBar.updateBatteryIcon(battery) }) battery.addEventListener('chargingchange', () => { statusBar.updateBatteryIcon(battery) }) }) } else { const batteryDiv = document.querySelector('div[data-toolbar-id="controls"] > .battery') if (batteryDiv != null) { batteryDiv.innerHTML = 'battery_unknown' } } async function ping (startTime: number): Promise { fetch(`${process.kernel.config.SERVER as string}/bare/`) .then(() => { const endTime = performance.now() const pingTime = endTime - startTime statusBar.updateIcon(pingTime) }) .catch(() => { (document.querySelector('div[data-toolbar-id="controls"] > .signal') as HTMLElement).innerHTML = 'signal_cellular_connected_no_internet_4_bar' }) } setInterval((): any => ping(performance.now()), 10_000) document.addEventListener('app_opened', (e: AppOpenedEvent): void => { new HTML('app').appendMany( new HTML('img').attr({ alt: `${e.detail.proc.config.name} icon`, 'data-id': e.detail.token, src: e.detail.proc.config.icon ?? nullIcon }).on('click', () => { e.detail.win.focus() e.detail.win.toggleMin() }) ).appendTo(statusBar.element.qs('div[data-toolbar-id="apps"]')?.elm as HTMLElement) }) document.addEventListener('app_closed', (e: AppClosedEvent): void => { statusBar.element.qs('div[data-toolbar-id="apps"]')?.qs(`img[data-id="${e.detail.token}"]`)?.elm.parentElement?.remove() }) document.body.style.flexDirection = 'column-reverse' await statusBar.element.appendTo(document.body) await launcher.element.appendTo(document.body) await wm.windowArea.appendTo(document.body) splashElement.cleanup() } } export default BootLoader