import type { ToastData } from '@decky/api'; import { Focusable, Navigation, findClassModule, joinClassNames } from '@decky/ui'; import { FC, memo } from 'react'; import Logger from '../logger'; import TranslationHelper, { TranslationClass } from '../utils/TranslationHelper'; const logger = new Logger('ToastRenderer'); // TODO there are more of these export enum ToastLocation { /** Big Picture popup toasts */ GAMEPADUI_POPUP = 1, /** QAM Notifications tab */ GAMEPADUI_QAM = 3, } interface ToastProps { toast: ToastData; } interface ToastRendererProps extends ToastProps { location: ToastLocation; } const templateClasses = findClassModule((m) => m.ShortTemplate) || {}; // These are memoized as they like to randomly rerender const GamepadUIPopupToast: FC = memo(({ toast }) => { return (
{toast.logo &&
{toast.logo}
}
{toast.icon &&
{toast.icon}
}
{toast.title}
{toast.body}
); }); const GamepadUIQAMToast: FC = memo(({ toast }) => { // The fields aren't mismatched, the logic for these is just a bit weird. return ( { Navigation.CloseSideMenus(); toast.onClick?.(); }} className={joinClassNames( templateClasses.StandardTemplateContainer, toast.className || '', 'DeckyGamepadUIQAMToast', )} >
{toast.logo &&
{toast.logo}
}
{toast.icon &&
{toast.icon}
}
{toast.header || ( )}
{/* timestamp should always be defined by toaster */} {/* TODO check how valve does this */} {toast.timestamp && (
{toast.timestamp.toLocaleTimeString(undefined, { timeStyle: 'short' })}
)}
{toast.title}
{toast.body}
{/* TODO support NewIndicator */} {/*
*/}
); }); export const ToastRenderer: FC = memo(({ toast, location }) => { switch (location) { default: logger.warn(`Toast UI not implemented for location ${location}! Falling back to GamepadUIPopupToast.`); case ToastLocation.GAMEPADUI_POPUP: return ; case ToastLocation.GAMEPADUI_QAM: return ; } }); export default ToastRenderer;