diff --git a/lib/plugins/src/_internal.ts b/lib/plugins/src/_internal.ts index c0216ca..8fd8215 100644 --- a/lib/plugins/src/_internal.ts +++ b/lib/plugins/src/_internal.ts @@ -63,6 +63,7 @@ export function registerPlugin( start: options.start, stop: options.stop, }, + SettingsComponent: options.SettingsComponent, status: 0, flags, disable: () => disablePlugin(plugin), diff --git a/lib/plugins/src/types.ts b/lib/plugins/src/types.ts index 16b2053..097b856 100644 --- a/lib/plugins/src/types.ts +++ b/lib/plugins/src/types.ts @@ -1,5 +1,6 @@ import type { Storage, StorageOptions } from '@revenge-mod/storage' import type { AnyObject } from '@revenge-mod/utils/types' +import type { FunctionComponent } from 'react' import type { PluginApiModules } from './apis/modules' import type { PluginApiPlugins } from './apis/plugins' import type { PluginApiReact } from './apis/react' @@ -114,6 +115,7 @@ export interface PluginManifest { export interface PluginOptions extends PluginLifecycles { + SettingsComponent?: PluginSettingsComponent storage?: Omit, 'directory'> } @@ -176,6 +178,11 @@ export interface Plugin { */ errors: unknown[] + /** + * The plugin settings page. + */ + SettingsComponent?: PluginSettingsComponent + /** * Disable the plugin. This will also stop the plugin if it is running. */ @@ -185,3 +192,6 @@ export interface Plugin { */ stop(): Promise } + +export type PluginSettingsComponent = + FunctionComponent<{ api: PluginApi }> diff --git a/src/plugins/init/settings/screens/RevengePluginsSettingScreen.tsx b/src/plugins/init/settings/screens/RevengePluginsSettingScreen.tsx index cbe786e..663bcce 100644 --- a/src/plugins/init/settings/screens/RevengePluginsSettingScreen.tsx +++ b/src/plugins/init/settings/screens/RevengePluginsSettingScreen.tsx @@ -4,6 +4,7 @@ import Page from '@revenge-mod/components/Page' import SearchInput from '@revenge-mod/components/SearchInput' import { Tokens } from '@revenge-mod/discord/common' import { Design } from '@revenge-mod/discord/design' +import { RootNavigationRef } from '@revenge-mod/discord/modules/main_tabs_v2' import { FlashList } from '@revenge-mod/externals/shopify' import { _metas, @@ -17,9 +18,11 @@ import { import { PluginFlags } from '@revenge-mod/plugins/constants' import { debounce } from '@revenge-mod/utils/callbacks' import { useReRender } from '@revenge-mod/utils/react' -import { useCallback, useMemo, useState } from 'react' +import { createElement, useCallback, useMemo, useState } from 'react' import { Image, useWindowDimensions } from 'react-native' +import { RouteNames, Setting } from '../constants' import type { InternalPlugin } from '@revenge-mod/plugins/_' +import type { PluginApi } from '@revenge-mod/plugins/types' const { Card, Text, Stack } = Design @@ -141,6 +144,14 @@ function InstalledPluginCard({ /> {name} + {plugin.SettingsComponent && ( + navigatePluginSettings(plugin)} + /> + )} ) } + +// TODO(plugins/settings): Register a custom route instead, so plugin "settings" can actually be pinned and navigated to without hassle. +// This would require us to implement the event-based plugin management system first, so we can listen to plugin enable/disable events and update the settings accordingly. +export function navigatePluginSettings(plugin: InternalPlugin) { + const [api] = _metas.get(plugin.manifest.id)! + const navigation = RootNavigationRef.getRootNavigationRef() + if (!navigation.isReady()) return + + navigation.navigate(RouteNames[Setting.RevengeCustomPage], { + render: () => + createElement(plugin.SettingsComponent!, { + api: api as PluginApi, + }), + options: { + title: plugin.manifest.name, + }, + }) +}