From 7b49c6863bcb2328c0993461e64b3bfac8f08964 Mon Sep 17 00:00:00 2001 From: ThePangel <74447121+ThePangel@users.noreply.github.com> Date: Tue, 10 Jun 2025 19:29:03 +0200 Subject: [PATCH] feat(plugins/settings): add ability to sort plugins --------- Co-authored-by: PalmDevs --- .../components/FilterAndSortActionSheet.tsx | 33 ++++++ .../screens/RevengePluginsSettingScreen.tsx | 109 +++++++++++++----- 2 files changed, 112 insertions(+), 30 deletions(-) create mode 100644 src/plugins/init/settings/components/FilterAndSortActionSheet.tsx diff --git a/src/plugins/init/settings/components/FilterAndSortActionSheet.tsx b/src/plugins/init/settings/components/FilterAndSortActionSheet.tsx new file mode 100644 index 0000000..5f8721a --- /dev/null +++ b/src/plugins/init/settings/components/FilterAndSortActionSheet.tsx @@ -0,0 +1,33 @@ +import { Design } from '@revenge-mod/discord/design' +import type { InternalPlugin } from '@revenge-mod/plugins/_' + +export interface FilterAndSortActionSheetProps { + sorts: Record number> + selectedSort: S + onSelectSort: (fn: S) => void +} + +const { ActionSheet, BottomSheetTitleHeader, TableRadioGroup, TableRadioRow } = + Design + +// TODO(plugins/settings): Add filter options +export default function FilterAndSortActionSheet({ + sorts, + selectedSort, + onSelectSort, +}: FilterAndSortActionSheetProps) { + return ( + + + + {Object.keys(sorts).map(label => ( + + ))} + + + ) +} diff --git a/src/plugins/init/settings/screens/RevengePluginsSettingScreen.tsx b/src/plugins/init/settings/screens/RevengePluginsSettingScreen.tsx index 14a9255..61076b5 100644 --- a/src/plugins/init/settings/screens/RevengePluginsSettingScreen.tsx +++ b/src/plugins/init/settings/screens/RevengePluginsSettingScreen.tsx @@ -2,6 +2,7 @@ import { getAssetIdByName } from '@revenge-mod/assets' import FormSwitch from '@revenge-mod/components/FormSwitch' import Page from '@revenge-mod/components/Page' import SearchInput from '@revenge-mod/components/SearchInput' +import { ActionSheetActionCreators } from '@revenge-mod/discord/actions' import { Tokens } from '@revenge-mod/discord/common' import { Stores } from '@revenge-mod/discord/common/flux' import { Design } from '@revenge-mod/discord/design' @@ -20,17 +21,34 @@ import { PluginFlags } from '@revenge-mod/plugins/constants' import { debounce } from '@revenge-mod/utils/callbacks' import { useReRender } from '@revenge-mod/utils/react' import { createElement, useCallback, useMemo, useState } from 'react' -import { Image, useWindowDimensions } from 'react-native' +import { Image, StyleSheet, useWindowDimensions, View } from 'react-native' import { RouteNames, Setting } from '../constants' import type { ReactNavigationParamList } from '@revenge-mod/externals/react-navigation' import type { InternalPlugin } from '@revenge-mod/plugins/_' import type { PluginApi } from '@revenge-mod/plugins/types' +import type { FilterAndSortActionSheetProps } from '../components/FilterAndSortActionSheet' -const { Card, Text, Stack } = Design +const { Card, Text, Stack, IconButton } = Design + +const FilterAndSortActionSheetKey = 'filter-and-sort-plugins' + +const Sorts = { + 'Name (A-Z)': (a, b) => a.manifest.name.localeCompare(b.manifest.name), + 'Name (Z-A)': (a, b) => b.manifest.name.localeCompare(a.manifest.name), + 'Enabled first': (a, b) => + Number(Boolean(b.flags & PluginFlags.Enabled)) - + Number(a.flags & PluginFlags.Enabled), + 'Disabled first': (a, b) => + Number(a.flags & PluginFlags.Enabled) - + Number(b.flags & PluginFlags.Enabled), +} as const satisfies FilterAndSortActionSheetProps['sorts'] + +const DefaultSort: keyof typeof Sorts = 'Name (A-Z)' export default function RevengePluginsSettingScreen() { const [search, setSearch] = useState('') const debouncedSetSearch = useCallback(debounce(setSearch, 100), []) + const [sort, setSort] = useState(DefaultSort) const { width } = useWindowDimensions() const numColumns = Math.floor((width - 16) / 448) @@ -45,24 +63,51 @@ export default function RevengePluginsSettingScreen() { const filteredPlugins = useMemo( () => - plugins.filter(([plugin]) => { - const { name, description, author } = plugin.manifest - const query = search.toLowerCase() - return ( - name.toLowerCase().includes(query) || - description.toLowerCase().includes(query) || - author.toLowerCase().includes(query) - ) - }), - [plugins, search], + plugins + .filter(([plugin]) => { + const { name, description, author } = plugin.manifest + const query = search.toLowerCase() + return ( + name.toLowerCase().includes(query) || + description.toLowerCase().includes(query) || + author.toLowerCase().includes(query) + ) + }) + .slice() + .sort(([a], [b]) => Sorts[sort](a, b)), + [plugins, search, sort], ) return ( - debouncedSetSearch(v)} - size="md" - /> + + + debouncedSetSearch(v)} + size="md" + /> + + + ActionSheetActionCreators.openLazy( + import('../components/FilterAndSortActionSheet'), + FilterAndSortActionSheetKey, + { + sorts: Sorts, + selectedSort: sort, + onSelectSort: key => { + setSort(key as keyof typeof Sorts) + ActionSheetActionCreators.hideActionSheet( + FilterAndSortActionSheetKey, + ) + }, + }, + ) + } + /> + + {name} @@ -167,6 +212,10 @@ function InstalledPluginCard({ reRender() + // TODO(plugins/settings): handle sorting after plugin enabled/disabled + // make an event based system for this, so we can register a listener for when plugins are disabled or enabled + // and sort the list again afterwards + // TODO(plugins/settings): show ReloadRequired modal // make an event based system for this, so we can register a listener for when plugins are disabled // and check its flags afterwards @@ -174,15 +223,15 @@ function InstalledPluginCard({ value={enabled} /> - + by {author} - + {description}