revenge-bundle-next/src/plugins/start/settings/index.ts
2025-08-13 01:27:49 +07:00

142 lines
4.4 KiB
TypeScript

import { sRefresher, sSections } from '@revenge-mod/discord/_/modules/settings'
import { onSettingsModulesLoaded } from '@revenge-mod/discord/modules/settings'
import {
waitForModuleByImportedPath,
waitForModules,
} from '@revenge-mod/modules/finders'
import { byName } from '@revenge-mod/modules/finders/filters'
import { instead } from '@revenge-mod/patcher'
import { InternalPluginFlags, registerPlugin } from '@revenge-mod/plugins/_'
import { PluginFlags } from '@revenge-mod/plugins/constants'
import { useEffect } from 'react'
import type { FC } from 'react'
import './register-routes'
import { React } from '@revenge-mod/react'
import { noop } from '@revenge-mod/utils/callback'
import { useReRender } from '@revenge-mod/utils/react'
const pluginSettings = registerPlugin(
{
id: 'revenge.settings',
name: 'Settings',
description: 'Settings UI for Revenge.',
author: 'Revenge',
icon: 'SettingsIcon',
},
{
start() {
onSettingsModulesLoaded(() => {
require('./register')
})
waitForModuleByImportedPath(
'modules/main_tabs_v2/native/settings/SettingsNavigator.tsx',
exports => {
patchSettingsNavigator(exports)
},
)
const unsubSOS = waitForModules(
byName('SettingsOverviewScreen'),
exports => {
unsubSOS()
patchSettingsOverviewScreen(exports)
},
{
cached: true,
returnNamespace: true,
},
)
},
},
PluginFlags.Enabled,
InternalPluginFlags.Internal | InternalPluginFlags.Essential,
)
function patchSettingsNavigator(exports: any) {
instead(exports.default, 'type', (args, orig) => {
const reRender = useReRender()
useEffect(() => {
sRefresher.callNavigator = reRender
return () => {
sRefresher.navigator = false
sRefresher.callNavigator = noop
}
}, [reRender])
// useMemo(() => getSettingScreens(), [])
const unpatchMemo = instead(React, 'useMemo', (args, orig) => {
if (!args[1]?.length && sRefresher.navigator) {
args[1] = undefined
sRefresher.navigator = false
}
return Reflect.apply(orig, React, args)
})
const fiber = Reflect.apply(orig, undefined, args)
unpatchMemo()
return fiber
})
}
let sectionsInst: object | undefined
function patchSettingsOverviewScreen(exports: any) {
instead(
exports as {
default: FC
},
'default',
(args, orig) => {
const reRender = useReRender()
useEffect(() => {
sRefresher.callOverviewScreen = reRender
return () => {
sRefresher.overviewScreen = false
sRefresher.callOverviewScreen = noop
}
}, [reRender])
/**
* In useOverviewSettings (called by SettingsOverviewScreen):
*
* const hasPremiumSubscriptionToDisplay = useHasPremiumSubscriptionToDisplay()
* const sections = useMemo(() =>
* (...constructed sections array...),
* [hasPremiumSubscriptionToDisplay])
*/
const unpatchMemo = instead(React, 'useMemo', (args, orig) => {
if (sRefresher.overviewScreen) args[1] = undefined
let sections = Reflect.apply(orig, React, args)
// Add our custom sections here, and only do this per instance!
if (sectionsInst !== sections) {
for (const section of Object.values(sSections))
if (section.index)
sections.splice(section.index, 0, section)
else sections.unshift(section)
sectionsInst = sections
}
if (sRefresher.overviewScreen) {
sections = sectionsInst = [...sections]
sRefresher.overviewScreen = false
}
return sections
})
const fiber = Reflect.apply(orig, undefined, args)
unpatchMemo()
return fiber
},
)
}
export default pluginSettings