From fdbc508fa8cb9ad3629486cacc1c92abb2500794 Mon Sep 17 00:00:00 2001 From: AAGaming Date: Sat, 31 Dec 2022 21:53:39 -0500 Subject: Main menu and overlay patching API --- frontend/src/components/DeckyMenuState.tsx | 147 +++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 frontend/src/components/DeckyMenuState.tsx (limited to 'frontend/src/components/DeckyMenuState.tsx') diff --git a/frontend/src/components/DeckyMenuState.tsx b/frontend/src/components/DeckyMenuState.tsx new file mode 100644 index 00000000..a4a6a999 --- /dev/null +++ b/frontend/src/components/DeckyMenuState.tsx @@ -0,0 +1,147 @@ +import { CustomMainMenuItem, ItemPatch, OverlayPatch } from 'decky-frontend-lib'; +import { FC, ReactNode, createContext, useContext, useEffect, useState } from 'react'; + +interface PublicDeckyMenuState { + items: Set; + itemPatches: Map>; + overlayPatches: Set; + overlayComponents: Set; +} + +export class DeckyMenuState { + private _items = new Set(); + private _itemPatches = new Map>(); + private _overlayPatches = new Set(); + private _overlayComponents = new Set(); + + public eventBus = new EventTarget(); + + publicState(): PublicDeckyMenuState { + return { + items: this._items, + itemPatches: this._itemPatches, + overlayPatches: this._overlayPatches, + overlayComponents: this._overlayComponents, + }; + } + + addItem(item: CustomMainMenuItem) { + this._items.add(item); + this.notifyUpdate(); + return item; + } + + addPatch(path: string, patch: ItemPatch) { + let patchList = this._itemPatches.get(path); + if (!patchList) { + patchList = new Set(); + this._itemPatches.set(path, patchList); + } + patchList.add(patch); + this.notifyUpdate(); + return patch; + } + + addOverlayPatch(patch: OverlayPatch) { + this._overlayPatches.add(patch); + this.notifyUpdate(); + return patch; + } + + addOverlayComponent(component: ReactNode) { + this._overlayComponents.add(component); + this.notifyUpdate(); + return component; + } + + removePatch(path: string, patch: ItemPatch) { + const patchList = this._itemPatches.get(path); + patchList?.delete(patch); + if (patchList?.size == 0) { + this._itemPatches.delete(path); + } + this.notifyUpdate(); + } + + removeItem(item: CustomMainMenuItem) { + this._items.delete(item); + this.notifyUpdate(); + return item; + } + + removeOverlayPatch(patch: OverlayPatch) { + this._overlayPatches.delete(patch); + this.notifyUpdate(); + } + + removeOverlayComponent(component: ReactNode) { + this._overlayComponents.delete(component); + this.notifyUpdate(); + } + + private notifyUpdate() { + this.eventBus.dispatchEvent(new Event('update')); + } +} + +interface DeckyMenuStateContext extends PublicDeckyMenuState { + addItem: DeckyMenuState['addItem']; + addPatch: DeckyMenuState['addPatch']; + addOverlayPatch: DeckyMenuState['addOverlayPatch']; + addOverlayComponent: DeckyMenuState['addOverlayComponent']; + removePatch: DeckyMenuState['removePatch']; + removeOverlayPatch: DeckyMenuState['removeOverlayPatch']; + removeOverlayComponent: DeckyMenuState['removeOverlayComponent']; + removeItem: DeckyMenuState['removeItem']; +} + +const DeckyMenuStateContext = createContext(null as any); + +export const useDeckyMenuState = () => useContext(DeckyMenuStateContext); + +interface Props { + deckyMenuState: DeckyMenuState; +} + +export const DeckyMenuStateContextProvider: FC = ({ children, deckyMenuState }) => { + const [publicDeckyMenuState, setPublicDeckyMenuState] = useState({ + ...deckyMenuState.publicState(), + }); + + useEffect(() => { + function onUpdate() { + setPublicDeckyMenuState({ ...deckyMenuState.publicState() }); + } + + deckyMenuState.eventBus.addEventListener('update', onUpdate); + + return () => deckyMenuState.eventBus.removeEventListener('update', onUpdate); + }, []); + + const addItem = deckyMenuState.addItem.bind(deckyMenuState); + const addPatch = deckyMenuState.addPatch.bind(deckyMenuState); + const addOverlayPatch = deckyMenuState.addOverlayPatch.bind(deckyMenuState); + const addOverlayComponent = deckyMenuState.addOverlayComponent.bind(deckyMenuState); + const removePatch = deckyMenuState.removePatch.bind(deckyMenuState); + const removeOverlayPatch = deckyMenuState.removeOverlayPatch.bind(deckyMenuState); + const removeOverlayComponent = deckyMenuState.removeOverlayComponent.bind(deckyMenuState); + const removeItem = deckyMenuState.removeItem.bind(deckyMenuState); + + return ( + + {children} + + ); +}; -- cgit v1.2.3