feat(ui/plugins): overflow actions
This commit is contained in:
parent
d6d0801731
commit
51c6b62f5c
5 changed files with 168 additions and 4 deletions
|
|
@ -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<BunnyPlugin>) {
|
||||
const navigation = NavigationNative.useNavigation();
|
||||
useProxy(plugin);
|
||||
|
||||
return (
|
||||
|
|
@ -94,10 +96,16 @@ export default function PluginCard({ item: plugin }: CardWrapper<BunnyPlugin>) {
|
|||
<View style={{ marginLeft: "auto" }}>
|
||||
<Stack spacing={12} direction="horizontal">
|
||||
<IconButton
|
||||
onPress={() => { }}
|
||||
onPress={() => {
|
||||
showSheet(
|
||||
"PluginInfoActionSheet",
|
||||
import("./sheets/PluginInfoActionSheet"),
|
||||
{ plugin, navigation }
|
||||
);
|
||||
}}
|
||||
size="sm"
|
||||
variant="secondary"
|
||||
icon={requireAssetIndex("SettingsIcon")}
|
||||
icon={requireAssetIndex("MoreHorizontalIcon")}
|
||||
/>
|
||||
<TableSwitch
|
||||
value={plugin.enabled}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,135 @@
|
|||
import { formatString, Strings } from "@core/i18n";
|
||||
import { requireAssetIndex } from "@lib/api/assets";
|
||||
import { purgeStorage } from "@lib/api/storage";
|
||||
import { BunnyPlugin, fetchPlugin, getSettings, removePlugin, startPlugin, stopPlugin } from "@lib/managers/plugins";
|
||||
import { showConfirmationAlert } from "@lib/ui/alerts";
|
||||
import { hideSheet } from "@lib/ui/sheets";
|
||||
import { showToast } from "@lib/ui/toasts";
|
||||
import { ButtonColors } from "@lib/utils/types";
|
||||
import { clipboard } from "@metro/common";
|
||||
import { ActionSheet, IconButton, TableRow, TableRowGroup, Text } from "@metro/common/components";
|
||||
import { ScrollView, View } from "react-native";
|
||||
|
||||
interface InfoProps {
|
||||
plugin: BunnyPlugin;
|
||||
navigation: any;
|
||||
}
|
||||
|
||||
export default function PluginInfoActionSheet({ plugin, navigation }: InfoProps) {
|
||||
const settings = getSettings(plugin.id);
|
||||
|
||||
return <ActionSheet scrollable>
|
||||
<ScrollView style={{ gap: 12 }}>
|
||||
<View style={{ flexDirection: "row", alignItems: "center", paddingVertical: 24 }}>
|
||||
<Text variant="heading-xl/semibold">
|
||||
{plugin.manifest.name}
|
||||
</Text>
|
||||
<View style={{ marginLeft: "auto" }}>
|
||||
{settings && <IconButton
|
||||
size="md"
|
||||
variant="secondary"
|
||||
icon={requireAssetIndex("SettingsIcon")}
|
||||
onPress={() => {
|
||||
hideSheet("PluginInfoActionSheet");
|
||||
navigation.push("VendettaCustomPage", {
|
||||
title: plugin.manifest.name,
|
||||
render: settings,
|
||||
});
|
||||
}}
|
||||
/>}
|
||||
</View>
|
||||
</View>
|
||||
<TableRowGroup>
|
||||
<TableRow
|
||||
label={Strings.REFETCH}
|
||||
icon={<TableRow.Icon source={requireAssetIndex("RetryIcon")} />}
|
||||
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);
|
||||
}}
|
||||
/>
|
||||
<TableRow
|
||||
label={Strings.COPY_URL}
|
||||
icon={<TableRow.Icon source={requireAssetIndex("copy")} />}
|
||||
onPress={() => {
|
||||
clipboard.setString(plugin.id);
|
||||
showToast.showCopyToClipboard();
|
||||
}}
|
||||
/>
|
||||
<TableRow
|
||||
label={plugin.update ? Strings.DISABLE_UPDATES : Strings.ENABLE_UPDATES}
|
||||
icon={<TableRow.Icon source={requireAssetIndex("ic_download_24px")} />}
|
||||
onPress={() => {
|
||||
plugin.update = !plugin.update;
|
||||
showToast(formatString("TOASTS_PLUGIN_UPDATE", {
|
||||
update: plugin.update,
|
||||
name: plugin.manifest.name
|
||||
}), requireAssetIndex("toast_image_saved"));
|
||||
}}
|
||||
/>
|
||||
<TableRow
|
||||
label={Strings.CLEAR_DATA}
|
||||
icon={<TableRow.Icon source={requireAssetIndex("ic_duplicate")} />}
|
||||
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);
|
||||
}
|
||||
})}
|
||||
/>
|
||||
<TableRow
|
||||
label={Strings.DELETE}
|
||||
icon={<TableRow.Icon source={requireAssetIndex("ic_message_delete")} />}
|
||||
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"));
|
||||
}
|
||||
}
|
||||
})}
|
||||
/>
|
||||
</TableRowGroup>
|
||||
</ScrollView>
|
||||
</ActionSheet>;
|
||||
}
|
||||
15
src/lib/ui/sheets.ts
Normal file
15
src/lib/ui/sheets.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import { findByPropsProxy } from "@metro/utils";
|
||||
|
||||
const actionSheet = findByPropsProxy("openLazy", "hideActionSheet");
|
||||
|
||||
export function showSheet<T extends React.ComponentType<any>>(
|
||||
key: string,
|
||||
lazyImport: Promise<{ default: T; }>,
|
||||
props?: React.ComponentProps<T>
|
||||
) {
|
||||
actionSheet.openLazy(lazyImport, key, props ?? {});
|
||||
}
|
||||
|
||||
export function hideSheet(key: string) {
|
||||
actionSheet.hideActionSheet(key);
|
||||
}
|
||||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -122,6 +122,12 @@ interface FABProps {
|
|||
|
||||
export type FloatingActionButton = React.FC<FABProps>;
|
||||
|
||||
interface ActionSheetProps {
|
||||
scrollable?: boolean;
|
||||
}
|
||||
|
||||
export type ActionSheet = React.FC<React.PropsWithChildren<ActionSheetProps>>;
|
||||
|
||||
type TextProps = React.ComponentProps<typeof RN.Text> & {
|
||||
variant?: DiscordTextStyles;
|
||||
color?: string; // TODO: type this
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue