mirror of
https://github.com/SteamDeckHomebrew/decky-frontend-lib.git
synced 2026-05-22 19:08:46 +02:00
Add necessary stuff to properly patch into play section (#18)
* feat(utils): Add singleShot option for patch functions * chore(static-classes): add playSectionClasses * feat(static-classes): Convert callbacks to one-liners
This commit is contained in:
@@ -208,53 +208,108 @@ type UpdaterFieldClasses = Record<
|
||||
string
|
||||
>;
|
||||
|
||||
type PlaySectionClasses = Record<
|
||||
| "AchievementCountLabel"
|
||||
| "AchievementProgressRow"
|
||||
| "ActionSection"
|
||||
| "AppButtonsContainer"
|
||||
| "Arrow"
|
||||
| "AvatarAndPersona"
|
||||
| "BreakNarrow"
|
||||
| "BreakShort"
|
||||
| "BreakTall"
|
||||
| "BreakUltraWide"
|
||||
| "BreakWide"
|
||||
| "ClickablePlayBarItem"
|
||||
| "CloudStatusIcon"
|
||||
| "CloudStatusLabel"
|
||||
| "CloudStatusRow"
|
||||
| "CloudSyncProblem"
|
||||
| "CloudSynching"
|
||||
| "ComingSoon"
|
||||
| "Container"
|
||||
| "DetailsProgressBar"
|
||||
| "DetailsProgressContainer"
|
||||
| "DetailsSection"
|
||||
| "DetailsSectionExtra"
|
||||
| "DetailsSectionStatus"
|
||||
| "DotDotDot"
|
||||
| "DownloadPaused"
|
||||
| "DownloadProgressBar"
|
||||
| "Downloading"
|
||||
| "FavoriteButton"
|
||||
| "Favorited"
|
||||
| "GameInfoButton"
|
||||
| "GameStat"
|
||||
| "GameStatIcon"
|
||||
| "GameStatIconForced"
|
||||
| "GameStatRight"
|
||||
| "GameStatsSection"
|
||||
| "GamepadUIBreakNarrow"
|
||||
| "GamepadUIBreakShort"
|
||||
| "GamepadUIBreakWide"
|
||||
| "Glassy"
|
||||
| "HideWhenNarrow"
|
||||
| "Icon"
|
||||
| "Icons"
|
||||
| "InPage"
|
||||
| "InnerContainer"
|
||||
| "InvalidPlatform"
|
||||
| "ItemFocusAnim-darkGrey"
|
||||
| "ItemFocusAnim-darkerGrey"
|
||||
| "ItemFocusAnim-darkerGrey-nocolor"
|
||||
| "ItemFocusAnim-green"
|
||||
| "ItemFocusAnim-grey"
|
||||
| "ItemFocusAnimBorder-darkGrey"
|
||||
| "Label"
|
||||
| "LastPlayed"
|
||||
| "LastPlayedInfo"
|
||||
| "MenuActive"
|
||||
| "MenuButton"
|
||||
| "MiniAchievements"
|
||||
| "OfflineMode"
|
||||
| "OnlyDownloadBar"
|
||||
| "PermanentlyUnavailable"
|
||||
| "PlayBar"
|
||||
| "PlayBarCloudStatusContainer"
|
||||
| "PlayBarDetailLabel"
|
||||
| "PlayBarGameIcon"
|
||||
| "PlayBarGameName"
|
||||
| "PlayBarIconAndGame"
|
||||
| "PlayBarLabel"
|
||||
| "Playtime"
|
||||
| "PlaytimeIcon"
|
||||
| "PlaytimeIconForced"
|
||||
| "PortraitBar"
|
||||
| "Presale"
|
||||
| "RecentlyUpdated"
|
||||
| "RecentlyUpdatedIcon"
|
||||
| "RecentlyUpdatedLink"
|
||||
| "RecentlyUpdatedText"
|
||||
| "RightBreakNarrow"
|
||||
| "RightBreakUltraNarrow"
|
||||
| "RightBreakUltraWide"
|
||||
| "RightBreakWide"
|
||||
| "RightControls"
|
||||
| "Row"
|
||||
| "SharedLibrary"
|
||||
| "StatusAndStats"
|
||||
| "StatusNameContainer"
|
||||
| "StickyHeader"
|
||||
| "StickyHeaderShadow"
|
||||
| "SuperimposedGridItems"
|
||||
| "SyncAnim"
|
||||
| "Visible"
|
||||
| "duration-app-launch"
|
||||
| "favorited"
|
||||
| "focusAnimation"
|
||||
| "hoverAnimation",
|
||||
string
|
||||
>;
|
||||
|
||||
export const staticClasses: StaticClasses = findModule((mod) => {
|
||||
if (typeof mod !== 'object') return false;
|
||||
|
||||
if (mod.TransitionMenuDelay) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
export const scrollClasses: ScrollClasses = findModule((mod) => {
|
||||
if (typeof mod !== 'object') return false;
|
||||
|
||||
if (mod.ScrollPanel && mod.ScrollY) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
export const gamepadDialogClasses: GamepadDialogClasses = findModule((mod) => {
|
||||
if (typeof mod !== 'object') return false;
|
||||
|
||||
if (mod.WithFirstRow) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
export const quickAccessControlsClasses: QuickAccessControlsClasses = findModule((mod) => {
|
||||
if (typeof mod !== 'object') return false;
|
||||
|
||||
if (mod.PanelSectionRow) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
export const updaterFieldClasses: UpdaterFieldClasses = findModule((mod) => {
|
||||
if (typeof mod !== 'object') return false;
|
||||
|
||||
if (mod.PatchNotes && mod.PostedTime) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
export const staticClasses: StaticClasses = findModule((mod) => typeof mod === 'object' && mod.TransitionMenuDelay);
|
||||
export const scrollClasses: ScrollClasses = findModule((mod) => typeof mod === 'object' && mod.ScrollPanel && mod.ScrollY);
|
||||
export const gamepadDialogClasses: GamepadDialogClasses = findModule((mod) => typeof mod === 'object' && mod.WithFirstRow);
|
||||
export const quickAccessControlsClasses: QuickAccessControlsClasses = findModule((mod) => typeof mod === 'object' && mod.PanelSectionRow);
|
||||
export const updaterFieldClasses: UpdaterFieldClasses = findModule((mod) => typeof mod === 'object' && mod.PatchNotes && mod.PostedTime);
|
||||
export const playSectionClasses: PlaySectionClasses = findModule((mod) => typeof mod === 'object' && mod.MenuButton && mod.MenuActive);
|
||||
|
||||
48
src/utils.ts
48
src/utils.ts
@@ -42,22 +42,18 @@ export function fakeRenderComponent(fun: Function): any {
|
||||
return res;
|
||||
}
|
||||
|
||||
export function beforePatch(obj: any, name: string, fnc: (args: any[]) => any): void {
|
||||
export interface PatchOptions {
|
||||
singleShot?: boolean
|
||||
}
|
||||
|
||||
export function beforePatch(obj: any, name: string, fnc: (args: any[]) => any, options: PatchOptions = {}): void {
|
||||
const orig = obj[name];
|
||||
obj[name] = function (...args: any[]) {
|
||||
fnc.call(this, args);
|
||||
return orig.call(this, ...args);
|
||||
}
|
||||
Object.assign(obj[name], orig);
|
||||
obj[name].toString = () => orig.toString();
|
||||
obj[name].__deckyOrig = orig;
|
||||
}
|
||||
|
||||
export function afterPatch(obj: any, name: string, fnc: (args: any[], ret: any) => any): void {
|
||||
const orig = obj[name];
|
||||
obj[name] = function (...args: any[]) {
|
||||
let ret = orig.call(this, ...args);
|
||||
ret = fnc.call(this, args, ret);
|
||||
const ret = orig.call(this, ...args);
|
||||
if (options.singleShot) {
|
||||
unpatch(obj, name);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
Object.assign(obj[name], orig);
|
||||
@@ -65,11 +61,29 @@ export function afterPatch(obj: any, name: string, fnc: (args: any[], ret: any)
|
||||
obj[name].__deckyOrig = orig;
|
||||
}
|
||||
|
||||
export function replacePatch(obj: any, name: string, fnc: (args: any[]) => any): void {
|
||||
export function afterPatch(obj: any, name: string, fnc: (args: any[], ret: any) => any, options: PatchOptions = {}): void {
|
||||
const orig = obj[name];
|
||||
obj[name] = function (...args: any[]) {
|
||||
let ret = orig.call(this, ...args);
|
||||
ret = fnc.call(this, args, ret);
|
||||
if (options.singleShot) {
|
||||
unpatch(obj, name);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
Object.assign(obj[name], orig);
|
||||
obj[name].toString = () => orig.toString();
|
||||
obj[name].__deckyOrig = orig;
|
||||
}
|
||||
|
||||
export function replacePatch(obj: any, name: string, fnc: (args: any[]) => any, options: PatchOptions = {}): void {
|
||||
const orig = obj[name];
|
||||
obj[name] = function (...args: any[]) {
|
||||
const ret = fnc.call(this, args);
|
||||
if (ret == 'CALL_ORIGINAL') return orig.call(this, ...args);
|
||||
if (ret == 'CALL_ORIGINAL') ret = orig.call(this, ...args);
|
||||
if (options.singleShot) {
|
||||
unpatch(obj, name);
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
Object.assign(obj[name], orig);
|
||||
@@ -79,7 +93,9 @@ export function replacePatch(obj: any, name: string, fnc: (args: any[]) => any):
|
||||
|
||||
// TODO allow one method to be patched and unpatched multiple times independently using IDs in a Map or something
|
||||
export function unpatch(obj: any, name: any): void {
|
||||
obj[name] = obj[name].__deckyOrig;
|
||||
if (obj[name].__deckyOrig !== undefined) {
|
||||
obj[name] = obj[name].__deckyOrig;
|
||||
}
|
||||
}
|
||||
|
||||
export function wrapReactType(node: any, prop: any = 'type') {
|
||||
|
||||
Reference in New Issue
Block a user