import { Route, Router } from "@solidjs/router"; import { ThemeProvider } from "@suid/material"; import { Component, createEffect, createMemo, createRenderEffect, createSignal, ErrorBoundary, lazy, onCleanup, } from "solid-js"; import { useRootTheme } from "./material/mui.js"; import { Provider as ClientProvider, createMastoClientFor, } from "./masto/clients.js"; import { $accounts, updateAcctInf } from "./accounts/stores.js"; import { useStore } from "@nanostores/solid"; import { DateFnScope, useLanguage } from "./platform/i18n.jsx"; import { useRegisterSW } from "virtual:pwa-register/solid"; import { isJSONRPCResult, ResultDispatcher, type JSONRPC, } from "./serviceworker/workerrpc.js"; import { Service } from "./serviceworker/services.js" import { makeEventListener } from "@solid-primitives/event-listener"; import { ServiceWorkerProvider } from "./platform/host.js"; const AccountSignIn = lazy(() => import("./accounts/SignIn.js")); const AccountMastodonOAuth2Callback = lazy( () => import("./accounts/MastodonOAuth2Callback.js"), ); const TimelineHome = lazy(() => import("./timelines/Home.js")); const Settings = lazy(() => import("./settings/Settings.js")); const TootBottomSheet = lazy(() => import("./timelines/TootBottomSheet.js")); const MotionSettings = lazy(() => import("./settings/Motions.js")); const LanguageSettings = lazy(() => import("./settings/Language.js")); const RegionSettings = lazy(() => import("./settings/Region.jsx")); const UnexpectedError = lazy(() => import("./UnexpectedError.js")); const Routing: Component = () => { return ( ); }; const App: Component = () => { const theme = useRootTheme(); const accts = useStore($accounts); const lang = useLanguage(); const [serviceWorker, setServiceWorker] = createSignal(); const dispatcher = new ResultDispatcher(); let checkAge = 0; const untilServiceWorkerAlive = async ( worker: ServiceWorker, expectedAge: number, ) => { const [call, ret] = dispatcher.createTypedCall("ping"); worker.postMessage(await call); const result = await ret; console.assert(!result.error, result); if (expectedAge === checkAge) { setServiceWorker(worker); } }; makeEventListener(window, "message", (event: MessageEvent) => { if (isJSONRPCResult(event.data)) { dispatcher.dispatch(event.data.id, event.data); } }); const { needRefresh: [needRefresh], offlineReady: [offlineReady], } = useRegisterSW({ onRegisteredSW(scriptUrl, reg) { console.info("service worker is registered from %s", scriptUrl); const active = reg?.active; if (!active) { console.warn("No service is in activating or activated"); return; } untilServiceWorkerAlive(active, checkAge++); }, }); const clients = createMemo(() => { return accts().map((x) => ({ account: x, client: createMastoClientFor(x), })); }); createEffect(() => { const neededUpdates = accts() .map((x, i) => [i, x] as const) .filter(([, x]) => !x.inf); if (neededUpdates.length > 0) { // FIXME: we might need some kind of concurrent control Promise.all(neededUpdates.map(([i]) => updateAcctInf(i))).then( (x) => { console.info("acct info updated for %d acct(s)", x.length); }, (reason) => { console.error("acct info update is fail", reason); }, ); } }); createRenderEffect(() => { const root = document.querySelector(":root")!; root.setAttribute("lang", lang()); }); onCleanup(() => { const root = document.querySelector(":root")!; root.removeAttribute("lang"); }); return ( { console.error(err); return ; }} > ); }; export default App;