diff --git a/apps/frontend/src/RootLayout.tsx b/apps/frontend/src/RootLayout.tsx index 9fbeb69..d9e11a2 100644 --- a/apps/frontend/src/RootLayout.tsx +++ b/apps/frontend/src/RootLayout.tsx @@ -1,5 +1,6 @@ import { getProgramInfo } from '@onelauncher/client'; import AnimatedRoutes from '~ui/components/AnimatedRoutes'; +import { NotificationProvider } from '~ui/hooks/useNotifications'; import { onMount, type ParentProps } from 'solid-js'; import { MultiProvider } from './ui/components/MultiProvider'; import { AccountControllerProvider } from './ui/components/overlay/account/AddAccountModal'; @@ -39,6 +40,7 @@ function GlobalContexts(props: ParentProps) { -
+
{props.title} - {props.message} + {props.message}
diff --git a/apps/frontend/src/ui/components/overlay/notifications/NotificationOverlay.tsx b/apps/frontend/src/ui/components/overlay/notifications/NotificationOverlay.tsx index f34f00f..2c24027 100644 --- a/apps/frontend/src/ui/components/overlay/notifications/NotificationOverlay.tsx +++ b/apps/frontend/src/ui/components/overlay/notifications/NotificationOverlay.tsx @@ -4,7 +4,7 @@ import Popup from '../Popup'; import NotificationComponent from './NotificationComponent'; export default function NotificationOverlay() { - const [notifications] = useNotifications(); + const notifications = useNotifications(); return ( true} >
- + {notification => ( )} diff --git a/apps/frontend/src/ui/components/overlay/notifications/NotificationPopup.tsx b/apps/frontend/src/ui/components/overlay/notifications/NotificationPopup.tsx index 1f3be8d..fde2073 100644 --- a/apps/frontend/src/ui/components/overlay/notifications/NotificationPopup.tsx +++ b/apps/frontend/src/ui/components/overlay/notifications/NotificationPopup.tsx @@ -7,22 +7,22 @@ import Popup, { type PopupProps } from '../Popup'; import NotificationComponent from './NotificationComponent'; function NotificationPopup(props: PopupProps) { - const [notifications, setNotifications] = useNotifications(); + const notifications = useNotifications(); let inner!: HTMLDivElement; let parent!: HTMLDivElement; - createEffect(on(notifications, () => { + createEffect(on(notifications.list, () => { if (inner && parent) { const rect = inner.getBoundingClientRect(); parent.style.height = `${rect.height}px`; } })); - const memoedNotifications = createMemo(() => Object.values(notifications())); + const memoedNotifications = createMemo(() => Object.values(notifications.list())); function clearNotifications() { - setNotifications({}); + notifications.clear(); } return ( diff --git a/apps/frontend/src/ui/hooks/useNotifications.ts b/apps/frontend/src/ui/hooks/useNotifications.ts deleted file mode 100644 index 0846143..0000000 --- a/apps/frontend/src/ui/hooks/useNotifications.ts +++ /dev/null @@ -1,40 +0,0 @@ -import type { UnlistenFn } from '@tauri-apps/api/event'; -import type { NotificationData } from '~ui/components/overlay/notifications/NotificationComponent'; -import { events } from '@onelauncher/client/bindings'; -import { createSignal, onCleanup, onMount, type Signal } from 'solid-js'; - -type Notifications = Record; -type OnUpdateFn = () => unknown; - -function useNotifications(onUpdate?: OnUpdateFn): Signal { - const [notifications, setNotifications] = createSignal({}); - let unlisten: UnlistenFn | undefined; - - async function update(id: string, data: NotificationData) { - setNotifications((notifications) => { - notifications[id] = data; - return { - ...notifications, - }; - }); - - if (onUpdate) - onUpdate(); - } - - onMount(() => { - events.ingressPayload.listen(e => update(e.payload.ingress_uuid, { - title: e.payload.event.type.replaceAll('_', ' '), - message: e.payload.message, - fraction: e.payload.fraction ?? undefined, - })).then(u => unlisten = u); - }); - - onCleanup(() => { - unlisten?.(); - }); - - return [notifications, setNotifications]; -} - -export default useNotifications; diff --git a/apps/frontend/src/ui/hooks/useNotifications.tsx b/apps/frontend/src/ui/hooks/useNotifications.tsx new file mode 100644 index 0000000..a874084 --- /dev/null +++ b/apps/frontend/src/ui/hooks/useNotifications.tsx @@ -0,0 +1,54 @@ +import type { UnlistenFn } from '@tauri-apps/api/event'; +import type { NotificationData } from '~ui/components/overlay/notifications/NotificationComponent'; +import { events } from '@onelauncher/client/bindings'; +import { type Accessor, type Context, createContext, createSignal, onCleanup, onMount, type ParentProps, type Signal, useContext } from 'solid-js'; + +type Notifications = Record; + +interface HookReturn { + list: Accessor; + set: (id: string, data: NotificationData) => void; + clear: () => void; +} + +const NotificationContext = createContext() as Context>; + +export function NotificationProvider(props: ParentProps) { + const [notifications, setNotifications] = createSignal({}); + let unlisten: UnlistenFn | undefined; + + onMount(() => { + events.ingressPayload.listen((e) => { + setNotifications(notifications => ({ + ...notifications, + [e.payload.ingress_uuid]: { + title: e.payload.event.type.replaceAll('_', ' '), + message: e.payload.message, + fraction: e.payload.fraction ?? undefined, + }, + })); + }).then(u => unlisten = u); + }); + + onCleanup(() => { + unlisten?.(); + }); + + return ( + + {props.children} + + ); +} + +function useNotifications(): HookReturn { + const [notifications, setNotifications] = useContext(NotificationContext); + + return { + list: notifications, + set: (id, data) => setNotifications(notifications => ({ ...notifications, [id]: data })), + clear: () => setNotifications({}), + }; +} + +export default useNotifications; diff --git a/apps/frontend/src/ui/pages/settings/about/SettingsDeveloper.tsx b/apps/frontend/src/ui/pages/settings/about/SettingsDeveloper.tsx index 041dbc2..17c64d5 100644 --- a/apps/frontend/src/ui/pages/settings/about/SettingsDeveloper.tsx +++ b/apps/frontend/src/ui/pages/settings/about/SettingsDeveloper.tsx @@ -1,21 +1,35 @@ import { useNavigate } from '@solidjs/router'; -import { CodeBrowserIcon, EyeIcon, GitMergeIcon, LinkExternal01Icon, RefreshCcw05Icon } from '@untitled-theme/icons-solid'; +import { CodeBrowserIcon, EyeIcon, GitMergeIcon, LinkExternal01Icon, PlusIcon, RefreshCcw05Icon } from '@untitled-theme/icons-solid'; import Button from '~ui/components/base/Button'; import Toggle from '~ui/components/base/Toggle'; import ScrollableContainer from '~ui/components/ScrollableContainer'; import SettingsRow from '~ui/components/SettingsRow'; import Sidebar from '~ui/components/Sidebar'; +import useNotifications from '~ui/hooks/useNotifications'; import useSettings from '~ui/hooks/useSettings'; +import { createSignal } from 'solid-js'; function SettingsDeveloper() { + const notifications = useNotifications(); const { settings, saveOnLeave } = useSettings(); const navigate = useNavigate(); + const [notiCounter, setNotiCounter] = createSignal(0); + saveOnLeave(() => ({ debug_mode: settings().debug_mode!, onboarding_completed: settings().onboarding_completed!, })); + function createTestNotification() { + notifications.set(`test_notification${notiCounter()}`, { + title: `Test Notification ${notiCounter()}`, + message: 'Test Notification Message body', + }); + + setNotiCounter(count => count + 1); + } + return (

Developer Options

@@ -70,6 +84,18 @@ function SettingsDeveloper() { /> + } + title="Create Test Notification" + > +