diff --git a/src/plugins/start/settings.plugins/components/PluginOptionsActionSheet.tsx b/src/plugins/start/settings.plugins/components/PluginOptionsActionSheet.tsx index 440b3e7..a3a4c42 100644 --- a/src/plugins/start/settings.plugins/components/PluginOptionsActionSheet.tsx +++ b/src/plugins/start/settings.plugins/components/PluginOptionsActionSheet.tsx @@ -23,7 +23,11 @@ import { runPluginLate, stopPlugin, } from '@revenge-mod/plugins/_' -import { listRepos } from '@revenge-mod/plugins/_/repositories' +import { + listRepoPlugins, + listRepos, + refreshRepo, +} from '@revenge-mod/plugins/_/repositories' import { PluginStatus } from '@revenge-mod/plugins/constants' import { formatVersion } from '@revenge-mod/plugins/utils' import { lookupGeneratedIconComponent } from '@revenge-mod/utils/discord' @@ -35,7 +39,7 @@ import { showPluginClearDataConfirmation, showPluginUninstallConfirmation, } from '../utils/alerts' -import { messageOf, showErrorToast } from '../utils/repos' +import { messageOf, runInstallFlow, showErrorToast } from '../utils/repos' import { InstalledPluginSwitch, PluginInfo } from './PluginCard' import { usePluginEnabled, usePluginStatus } from './PluginStateProvider' import PluginTooltipsProvider, { @@ -43,13 +47,22 @@ import PluginTooltipsProvider, { usePluginTooltip, } from './TooltipProvider' import type { AnyPlugin } from '@revenge-mod/plugins/_' +import type { RepoPluginListing } from '@revenge-mod/plugins/_/repositories' export interface PluginOptionsActionSheetProps { plugin: AnyPlugin sheetKey: string } -const { ActionSheet, IconButton, TableRowGroup, TableRow, Stack } = Design +const { + ActionSheet, + IconButton, + TableRowGroup, + TableRow, + TableRadioGroup, + TableRadioRow, + Stack, +} = Design const FileWarningIcon = getAssetIdByName('FileWarningIcon', 'png')! const PlayIcon = getAssetIdByName('PlayIcon', 'png')! @@ -118,7 +131,7 @@ function PluginOptions({ plugin, sheetKey }: PluginOptionsActionSheetProps) { }} /> - + ) } @@ -158,7 +171,94 @@ function StatusSection({ plugin }: { plugin: AnyPlugin }) { ) } -function AdvancedSection({ plugin }: { plugin: AnyPlugin }) { +function ChannelSection({ + plugin, + sheetKey, +}: { + plugin: AnyPlugin + sheetKey: string +}) { + const meta = getInternalPluginMeta(plugin) + const source = meta.source + if (isPluginInternal(meta) || !source?.repo) return null + + const [listing, setListing] = useState(null) + const [resetKey, setResetKey] = useState(0) + + useEffect(() => { + let cancelled = false + ;(async () => { + try { + const listings = await listRepoPlugins(source.repo) + const found = listings.find(l => l.id === plugin.manifest.id) + if (found && !cancelled) setListing(found) + } catch { + try { + await refreshRepo(source.repo) + const listings = await listRepoPlugins(source.repo) + const found = listings.find(l => l.id === plugin.manifest.id) + if (found && !cancelled) setListing(found) + } catch {} + } + })() + return () => { + cancelled = true + } + }, [source.repo, plugin.manifest.id]) + + if (!listing || Object.keys(listing.channels).length === 0) return null + + const handleChange = async (selected: string) => { + if (selected === source.channel) return + + const targetVersion = listing.channels[selected] + if (!targetVersion) return + + if (targetVersion === plugin.manifest.version) { + setResetKey(k => k + 1) + ToastActionCreators.open({ + key: 'REVENGE_PLUGIN_CHANNEL_UP_TO_DATE', + content: 'This channel is already installed', + IconComponent: () => , + }) + return + } + + const repos = await listRepos() + const internalUrls = repos + .filter(r => r.internal) + .map(r => r.url) + + ActionSheetActionCreators.hideActionSheet(sheetKey) + runInstallFlow( + plugin.manifest.id, + undefined, + selected, + [...internalUrls, source.repo], + ) + } + + return ( + handleChange(v as string)} + > + {Object.keys(listing.channels).map(c => ( + + ))} + + ) +} + +function AdvancedSection({ + plugin, + sheetKey, +}: { + plugin: AnyPlugin + sheetKey: string +}) { const meta = getInternalPluginMeta(plugin) const dependents = getPluginDependents(plugin, true) const dependencies = getPluginDependencies(plugin, false) @@ -166,70 +266,73 @@ function AdvancedSection({ plugin }: { plugin: AnyPlugin }) { const { id, name } = plugin.manifest return ( - - - - } - label="Flags" - subLabel={bitFieldToString(PluginFlags, meta.flags)} - /> - {meta.iflags > 0 && ( + <> + + + + } - label="Internal Flags" - subLabel={bitFieldToString( - InternalPluginFlags, - meta.iflags, - )} + label="Flags" + subLabel={bitFieldToString(PluginFlags, meta.flags)} /> - )} - {dependencies.length > 0 && ( - } - label="Dependencies" - subLabel={`${name} depends on ${dependencies.length} other plugins`} - onPress={() => { - ActionSheetActionCreators.openLazy( - import('./PluginRelationsListActionSheet'), - `plugin-deps-${id}`, - { - title: `Dependencies of ${name}`, - unsatisfiedTitle: `Unsatisfied dependencies of ${name}`, - unsatisfiedPlugins: - meta.unsatisfiedOptionalDependencies.map( - id => pList.get(id) ?? id, - ), - plugins: dependencies, - dependencyMap: plugin.manifest.dependencies!, - }, - 'stack', - ) - }} - /> - )} - {dependents.length > 0 && ( - } - label="Dependents" - subLabel={`${dependents.length} other plugins depend on ${name}`} - onPress={() => { - ActionSheetActionCreators.openLazy( - import('./PluginRelationsListActionSheet'), - `plugin-dependents-${id}`, - { - title: `Dependents of ${name}`, - plugins: dependents, - }, - 'stack', - ) - }} - /> - )} - + {meta.iflags > 0 && ( + } + label="Internal Flags" + subLabel={bitFieldToString( + InternalPluginFlags, + meta.iflags, + )} + /> + )} + {dependencies.length > 0 && ( + } + label="Dependencies" + subLabel={`${name} depends on ${dependencies.length} other plugins`} + onPress={() => { + ActionSheetActionCreators.openLazy( + import('./PluginRelationsListActionSheet'), + `plugin-deps-${id}`, + { + title: `Dependencies of ${name}`, + unsatisfiedTitle: `Unsatisfied dependencies of ${name}`, + unsatisfiedPlugins: + meta.unsatisfiedOptionalDependencies.map( + id => pList.get(id) ?? id, + ), + plugins: dependencies, + dependencyMap: plugin.manifest.dependencies!, + }, + 'stack', + ) + }} + /> + )} + {dependents.length > 0 && ( + } + label="Dependents" + subLabel={`${dependents.length} other plugins depend on ${name}`} + onPress={() => { + ActionSheetActionCreators.openLazy( + import('./PluginRelationsListActionSheet'), + `plugin-dependents-${id}`, + { + title: `Dependents of ${name}`, + plugins: dependents, + }, + 'stack', + ) + }} + /> + )} + + ) }