| 
									
										
										
										
											2024-07-14 20:28:44 +08:00
										 |  |  | import { Route, Router } from "@solidjs/router"; | 
					
						
							|  |  |  | import { ThemeProvider } from "@suid/material"; | 
					
						
							| 
									
										
										
										
											2024-07-15 13:59:10 +08:00
										 |  |  | import { | 
					
						
							|  |  |  |   Component, | 
					
						
							| 
									
										
										
										
											2024-10-11 16:39:42 +08:00
										 |  |  |   createEffect, | 
					
						
							|  |  |  |   createMemo, | 
					
						
							| 
									
										
										
										
											2024-07-15 13:59:10 +08:00
										 |  |  |   createRenderEffect, | 
					
						
							| 
									
										
										
										
											2024-10-15 20:30:08 +08:00
										 |  |  |   createSignal, | 
					
						
							| 
									
										
										
										
											2024-07-15 13:59:10 +08:00
										 |  |  |   ErrorBoundary, | 
					
						
							|  |  |  |   lazy, | 
					
						
							| 
									
										
										
										
											2024-09-26 17:23:40 +08:00
										 |  |  |   onCleanup, | 
					
						
							| 
									
										
										
										
											2024-07-15 13:59:10 +08:00
										 |  |  | } from "solid-js"; | 
					
						
							| 
									
										
										
										
											2024-10-24 22:21:37 +08:00
										 |  |  | import { useRootTheme } from "./material/theme.js"; | 
					
						
							| 
									
										
										
										
											2024-07-15 13:59:10 +08:00
										 |  |  | import { | 
					
						
							|  |  |  |   Provider as ClientProvider, | 
					
						
							|  |  |  |   createMastoClientFor, | 
					
						
							|  |  |  | } from "./masto/clients.js"; | 
					
						
							| 
									
										
										
										
											2024-10-11 16:39:42 +08:00
										 |  |  | import { $accounts, updateAcctInf } from "./accounts/stores.js"; | 
					
						
							| 
									
										
										
										
											2024-07-15 13:59:10 +08:00
										 |  |  | import { useStore } from "@nanostores/solid"; | 
					
						
							| 
									
										
										
										
											2024-09-26 17:23:40 +08:00
										 |  |  | import { DateFnScope, useLanguage } from "./platform/i18n.jsx"; | 
					
						
							| 
									
										
										
										
											2024-10-15 20:30:08 +08:00
										 |  |  | import { useRegisterSW } from "virtual:pwa-register/solid"; | 
					
						
							|  |  |  | import { | 
					
						
							|  |  |  |   isJSONRPCResult, | 
					
						
							|  |  |  |   ResultDispatcher, | 
					
						
							|  |  |  |   type JSONRPC, | 
					
						
							| 
									
										
										
										
											2024-10-16 22:42:25 +08:00
										 |  |  | } from "./serviceworker/workerrpc.js"; | 
					
						
							| 
									
										
										
										
											2024-10-18 19:15:35 +08:00
										 |  |  | import { Service } from "./serviceworker/services.js"; | 
					
						
							| 
									
										
										
										
											2024-10-15 20:30:08 +08:00
										 |  |  | import { makeEventListener } from "@solid-primitives/event-listener"; | 
					
						
							|  |  |  | import { ServiceWorkerProvider } from "./platform/host.js"; | 
					
						
							| 
									
										
										
										
											2024-11-16 20:04:55 +08:00
										 |  |  | import StackedRouter from "./platform/StackedRouter.js"; | 
					
						
							| 
									
										
										
										
											2024-07-14 20:28:44 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | const AccountSignIn = lazy(() => import("./accounts/SignIn.js")); | 
					
						
							| 
									
										
										
										
											2024-07-15 13:59:10 +08:00
										 |  |  | const AccountMastodonOAuth2Callback = lazy( | 
					
						
							|  |  |  |   () => import("./accounts/MastodonOAuth2Callback.js"), | 
					
						
							|  |  |  | ); | 
					
						
							|  |  |  | const TimelineHome = lazy(() => import("./timelines/Home.js")); | 
					
						
							| 
									
										
										
										
											2024-07-22 21:57:04 +08:00
										 |  |  | const Settings = lazy(() => import("./settings/Settings.js")); | 
					
						
							| 
									
										
										
										
											2024-08-12 17:25:03 +08:00
										 |  |  | const TootBottomSheet = lazy(() => import("./timelines/TootBottomSheet.js")); | 
					
						
							| 
									
										
										
										
											2024-10-09 18:45:19 +08:00
										 |  |  | const MotionSettings = lazy(() => import("./settings/Motions.js")); | 
					
						
							| 
									
										
										
										
											2024-10-09 23:27:20 +08:00
										 |  |  | const LanguageSettings = lazy(() => import("./settings/Language.js")); | 
					
						
							| 
									
										
										
										
											2024-11-16 20:04:55 +08:00
										 |  |  | const RegionSettings = lazy(() => import("./settings/Region.js")); | 
					
						
							| 
									
										
										
										
											2024-10-11 16:39:42 +08:00
										 |  |  | const UnexpectedError = lazy(() => import("./UnexpectedError.js")); | 
					
						
							| 
									
										
										
										
											2024-10-18 19:15:35 +08:00
										 |  |  | const Profile = lazy(() => import("./profiles/Profile.js")); | 
					
						
							| 
									
										
										
										
											2024-07-14 20:28:44 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | const Routing: Component = () => { | 
					
						
							|  |  |  |   return ( | 
					
						
							| 
									
										
										
										
											2024-11-16 20:04:55 +08:00
										 |  |  |     <StackedRouter> | 
					
						
							|  |  |  |       <Route path="/" component={TimelineHome} /> | 
					
						
							|  |  |  |       <Route path="/settings" component={Settings} /> | 
					
						
							|  |  |  |       <Route path="/settings/language" component={LanguageSettings} /> | 
					
						
							|  |  |  |       <Route path="/settings/region" component={RegionSettings} /> | 
					
						
							|  |  |  |       <Route path="/motions" component={MotionSettings} /> | 
					
						
							|  |  |  |       <Route path="/:acct/toot/:id" component={TootBottomSheet} /> | 
					
						
							|  |  |  |       <Route path="/:acct/profile/:id" component={Profile} /> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-14 20:28:44 +08:00
										 |  |  |       <Route path={"/accounts"}> | 
					
						
							|  |  |  |         <Route path={"/sign-in"} component={AccountSignIn} /> | 
					
						
							| 
									
										
										
										
											2024-07-15 13:59:10 +08:00
										 |  |  |         <Route | 
					
						
							|  |  |  |           path={"/oauth2/mastodon"} | 
					
						
							|  |  |  |           component={AccountMastodonOAuth2Callback} | 
					
						
							|  |  |  |         /> | 
					
						
							| 
									
										
										
										
											2024-07-14 20:28:44 +08:00
										 |  |  |       </Route> | 
					
						
							| 
									
										
										
										
											2024-11-16 20:04:55 +08:00
										 |  |  |     </StackedRouter> | 
					
						
							| 
									
										
										
										
											2024-07-14 20:28:44 +08:00
										 |  |  |   ); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const App: Component = () => { | 
					
						
							|  |  |  |   const theme = useRootTheme(); | 
					
						
							| 
									
										
										
										
											2024-07-15 13:59:10 +08:00
										 |  |  |   const accts = useStore($accounts); | 
					
						
							| 
									
										
										
										
											2024-09-26 17:23:40 +08:00
										 |  |  |   const lang = useLanguage(); | 
					
						
							| 
									
										
										
										
											2024-11-16 20:04:55 +08:00
										 |  |  |   const [serviceWorker, setServiceWorker] = createSignal< | 
					
						
							|  |  |  |     ServiceWorker | undefined | 
					
						
							|  |  |  |   >(undefined, { name: "serviceWorker" }); | 
					
						
							| 
									
										
										
										
											2024-10-15 20:30:08 +08:00
										 |  |  |   const dispatcher = new ResultDispatcher(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   let checkAge = 0; | 
					
						
							|  |  |  |   const untilServiceWorkerAlive = async ( | 
					
						
							|  |  |  |     worker: ServiceWorker, | 
					
						
							|  |  |  |     expectedAge: number, | 
					
						
							|  |  |  |   ) => { | 
					
						
							| 
									
										
										
										
											2024-10-16 22:42:25 +08:00
										 |  |  |     const [call, ret] = dispatcher.createTypedCall<Service>("ping"); | 
					
						
							| 
									
										
										
										
											2024-10-15 20:30:08 +08:00
										 |  |  |     worker.postMessage(await call); | 
					
						
							|  |  |  |     const result = await ret; | 
					
						
							|  |  |  |     console.assert(!result.error, result); | 
					
						
							|  |  |  |     if (expectedAge === checkAge) { | 
					
						
							|  |  |  |       setServiceWorker(worker); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   makeEventListener(window, "message", (event: MessageEvent<JSONRPC>) => { | 
					
						
							|  |  |  |     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++); | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2024-07-15 13:59:10 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-11 16:39:42 +08:00
										 |  |  |   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); | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |       ); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-07-15 13:59:10 +08:00
										 |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-26 17:23:40 +08:00
										 |  |  |   createRenderEffect(() => { | 
					
						
							|  |  |  |     const root = document.querySelector(":root")!; | 
					
						
							|  |  |  |     root.setAttribute("lang", lang()); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   onCleanup(() => { | 
					
						
							|  |  |  |     const root = document.querySelector(":root")!; | 
					
						
							|  |  |  |     root.removeAttribute("lang"); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-14 20:28:44 +08:00
										 |  |  |   return ( | 
					
						
							| 
									
										
										
										
											2024-07-15 13:59:10 +08:00
										 |  |  |     <ErrorBoundary | 
					
						
							|  |  |  |       fallback={(err, reset) => { | 
					
						
							|  |  |  |         console.error(err); | 
					
						
							| 
									
										
										
										
											2024-08-05 16:24:34 +08:00
										 |  |  |         return <UnexpectedError error={err} />; | 
					
						
							| 
									
										
										
										
											2024-07-15 13:59:10 +08:00
										 |  |  |       }} | 
					
						
							|  |  |  |     > | 
					
						
							| 
									
										
										
										
											2024-10-24 23:47:44 +08:00
										 |  |  |       <ThemeProvider theme={theme}> | 
					
						
							| 
									
										
										
										
											2024-09-26 17:23:40 +08:00
										 |  |  |         <DateFnScope> | 
					
						
							| 
									
										
										
										
											2024-10-11 16:39:42 +08:00
										 |  |  |           <ClientProvider value={clients}> | 
					
						
							| 
									
										
										
										
											2024-10-15 20:30:08 +08:00
										 |  |  |             <ServiceWorkerProvider | 
					
						
							|  |  |  |               value={{ | 
					
						
							|  |  |  |                 needRefresh, | 
					
						
							|  |  |  |                 offlineReady, | 
					
						
							|  |  |  |                 serviceWorker, | 
					
						
							|  |  |  |               }} | 
					
						
							|  |  |  |             > | 
					
						
							|  |  |  |               <Routing /> | 
					
						
							|  |  |  |             </ServiceWorkerProvider> | 
					
						
							| 
									
										
										
										
											2024-09-26 17:23:40 +08:00
										 |  |  |           </ClientProvider> | 
					
						
							|  |  |  |         </DateFnScope> | 
					
						
							| 
									
										
										
										
											2024-07-15 13:59:10 +08:00
										 |  |  |       </ThemeProvider> | 
					
						
							|  |  |  |     </ErrorBoundary> | 
					
						
							| 
									
										
										
										
											2024-07-14 20:28:44 +08:00
										 |  |  |   ); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export default App; |