From 51c6b62f5c11c49fe92e4a74424d13ca3a1f33b8 Mon Sep 17 00:00:00 2001 From: amsyarasyiq <82711525+amsyarasyiq@users.noreply.github.com> Date: Thu, 23 May 2024 23:20:23 +0800 Subject: [PATCH] feat(ui/plugins): overflow actions --- .../ui/settings/pages/Plugins/PluginCard.tsx | 14 +- .../Plugins/sheets/PluginInfoActionSheet.tsx | 135 ++++++++++++++++++ src/lib/ui/sheets.ts | 15 ++ src/metro/common/components.ts | 2 +- src/metro/common/types/components.ts | 6 + 5 files changed, 168 insertions(+), 4 deletions(-) create mode 100644 src/core/ui/settings/pages/Plugins/sheets/PluginInfoActionSheet.tsx create mode 100644 src/lib/ui/sheets.ts diff --git a/src/core/ui/settings/pages/Plugins/PluginCard.tsx b/src/core/ui/settings/pages/Plugins/PluginCard.tsx index 7d6d82f..19dfd6b 100644 --- a/src/core/ui/settings/pages/Plugins/PluginCard.tsx +++ b/src/core/ui/settings/pages/Plugins/PluginCard.tsx @@ -2,9 +2,10 @@ import { CardWrapper } from "@core/ui/components/AddonCard"; import { requireAssetIndex } from "@lib/api/assets"; import { useProxy } from "@lib/api/storage"; import { BunnyPlugin, startPlugin, stopPlugin } from "@lib/managers/plugins"; +import { showSheet } from "@lib/ui/sheets"; import { lazyDestructure } from "@lib/utils/lazy"; import { findByProps } from "@metro"; -import { tokens } from "@metro/common"; +import { NavigationNative, tokens } from "@metro/common"; import { Card, IconButton, Stack, TableSwitch, Text } from "@metro/common/components"; import { createContext, useContext } from "react"; import { Image, View } from "react-native"; @@ -79,6 +80,7 @@ function Status() { } export default function PluginCard({ item: plugin }: CardWrapper) { + const navigation = NavigationNative.useNavigation(); useProxy(plugin); return ( @@ -94,10 +96,16 @@ export default function PluginCard({ item: plugin }: CardWrapper) { { }} + onPress={() => { + showSheet( + "PluginInfoActionSheet", + import("./sheets/PluginInfoActionSheet"), + { plugin, navigation } + ); + }} size="sm" variant="secondary" - icon={requireAssetIndex("SettingsIcon")} + icon={requireAssetIndex("MoreHorizontalIcon")} /> + + + + {plugin.manifest.name} + + + {settings && { + hideSheet("PluginInfoActionSheet"); + navigation.push("VendettaCustomPage", { + title: plugin.manifest.name, + render: settings, + }); + }} + />} + + + + } + onPress={async () => { + if (plugin.enabled) stopPlugin(plugin.id, false); + + try { + await fetchPlugin(plugin.id); + showToast(Strings.PLUGIN_REFETCH_SUCCESSFUL, requireAssetIndex("toast_image_saved")); + } catch { + showToast(Strings.PLUGIN_REFETCH_FAILED, requireAssetIndex("Small")); + } + + if (plugin.enabled) await startPlugin(plugin.id); + }} + /> + } + onPress={() => { + clipboard.setString(plugin.id); + showToast.showCopyToClipboard(); + }} + /> + } + onPress={() => { + plugin.update = !plugin.update; + showToast(formatString("TOASTS_PLUGIN_UPDATE", { + update: plugin.update, + name: plugin.manifest.name + }), requireAssetIndex("toast_image_saved")); + }} + /> + } + onPress={() => showConfirmationAlert({ + title: Strings.HOLD_UP, + content: formatString("ARE_YOU_SURE_TO_CLEAR_DATA", { name: plugin.manifest.name }), + confirmText: Strings.CLEAR, + cancelText: Strings.CANCEL, + confirmColor: ButtonColors.RED, + onConfirm: async () => { + if (plugin.enabled) stopPlugin(plugin.id, false); + + try { + await fetchPlugin(plugin.id); + showToast(Strings.PLUGIN_REFETCH_SUCCESSFUL, requireAssetIndex("toast_image_saved")); + } catch { + showToast(Strings.PLUGIN_REFETCH_FAILED, requireAssetIndex("Small")); + } + + let message: any[]; + try { + purgeStorage(plugin.id); + message = ["CLEAR_DATA_SUCCESSFUL", "trash"]; + } catch { + message = ["CLEAR_DATA_FAILED", "Small"]; + } + + showToast( + formatString(message[0], { name: plugin.manifest.name }), + requireAssetIndex(message[1]) + ); + + if (plugin.enabled) await startPlugin(plugin.id); + } + })} + /> + } + onPress={() => showConfirmationAlert({ + title: Strings.HOLD_UP, + content: formatString("ARE_YOU_SURE_TO_DELETE_PLUGIN", { name: plugin.manifest.name }), + confirmText: Strings.DELETE, + cancelText: Strings.CANCEL, + confirmColor: ButtonColors.RED, + onConfirm: () => { + try { + removePlugin(plugin.id); + } catch (e) { + showToast(String(e), requireAssetIndex("Small")); + } + } + })} + /> + + + ; +} diff --git a/src/lib/ui/sheets.ts b/src/lib/ui/sheets.ts new file mode 100644 index 0000000..10bd79e --- /dev/null +++ b/src/lib/ui/sheets.ts @@ -0,0 +1,15 @@ +import { findByPropsProxy } from "@metro/utils"; + +const actionSheet = findByPropsProxy("openLazy", "hideActionSheet"); + +export function showSheet>( + key: string, + lazyImport: Promise<{ default: T; }>, + props?: React.ComponentProps +) { + actionSheet.openLazy(lazyImport, key, props ?? {}); +} + +export function hideSheet(key: string) { + actionSheet.hideActionSheet(key); +} diff --git a/src/metro/common/components.ts b/src/metro/common/components.ts index 237e34c..e04c847 100644 --- a/src/metro/common/components.ts +++ b/src/metro/common/components.ts @@ -57,7 +57,7 @@ export const SegmentedControl = findProp("SegmentedControl") as t.SegmentedContr export const CompatSegmentedControl = findProp("CompatSegmentedControl") as t.CompatSegmentedControl; export const FloatingActionButton = findProp("FloatingActionButton") as t.FloatingActionButton; -export const ActionSheet = findProp("ActionSheet"); +export const ActionSheet = findProp("ActionSheet") as t.ActionSheet; export const BottomSheetTitleHeader = findProp("BottomSheetTitleHeader"); const textsModule = findByPropsProxy("Text", "LegacyText"); diff --git a/src/metro/common/types/components.ts b/src/metro/common/types/components.ts index 0b5e70f..ffa5708 100644 --- a/src/metro/common/types/components.ts +++ b/src/metro/common/types/components.ts @@ -122,6 +122,12 @@ interface FABProps { export type FloatingActionButton = React.FC; +interface ActionSheetProps { + scrollable?: boolean; +} + +export type ActionSheet = React.FC>; + type TextProps = React.ComponentProps & { variant?: DiscordTextStyles; color?: string; // TODO: type this