GoonCord/src/core/ui/components/AddonPage.tsx

85 lines
3.4 KiB
TypeScript
Raw Normal View History

2024-03-08 02:54:20 +08:00
import { Strings } from "@core/i18n";
import { CardWrapper } from "@core/ui/components/AddonCard";
2024-07-09 15:53:34 +08:00
import { findAssetId } from "@lib/api/assets";
2024-07-30 00:18:01 +08:00
import { settings } from "@lib/api/settings";
2024-07-30 07:20:22 +08:00
import { useProxy } from "@lib/api/storage";
2024-03-06 01:57:59 +08:00
import { HTTP_REGEX_MULTI } from "@lib/utils/constants";
2024-08-15 01:24:09 +08:00
import { clipboard } from "@metro/common";
import { FlashList, FloatingActionButton, HelpMessage } from "@metro/common/components";
import { showInputAlert } from "@ui/alerts";
2024-03-07 12:35:07 +08:00
import { ErrorBoundary, Search } from "@ui/components";
2024-02-28 21:43:55 +08:00
import fuzzysort from "fuzzysort";
2024-08-15 01:24:09 +08:00
import { ComponentType, ReactNode, useMemo } from "react";
import { View } from "react-native";
2023-04-15 02:57:03 +01:00
type SearchKeywords = Array<string | ((obj: any & {}) => string)>;
2024-06-25 02:28:04 +08:00
interface AddonPageProps<T extends object> {
2023-12-21 03:30:21 +08:00
title: string;
2024-07-30 20:42:10 +08:00
fetchFunction?: (url: string) => Promise<void>;
2024-07-31 17:06:17 +08:00
items: any[];
2024-06-18 02:19:31 +08:00
resolveItem?: (value: any) => T | undefined;
2023-04-15 02:57:03 +01:00
safeModeMessage: string;
2024-07-31 17:06:17 +08:00
safeModeExtras?: ReactNode;
card: ComponentType<CardWrapper<T>>;
searchKeywords: SearchKeywords;
2024-07-31 17:06:17 +08:00
onFabPress?: () => void;
2024-08-15 01:58:23 +08:00
ListHeaderComponent?: ComponentType<any>;
ListFooterComponent?: ComponentType<any>;
2023-04-15 02:57:03 +01:00
}
2024-06-25 02:28:04 +08:00
export default function AddonPage<T extends object>({ card: CardComponent, ...props }: AddonPageProps<T>) {
useProxy(settings);
2023-12-21 03:30:21 +08:00
2023-04-15 02:57:03 +01:00
const [search, setSearch] = React.useState("");
2024-08-28 15:45:50 +08:00
const results = useMemo(() => {
2024-07-31 17:06:17 +08:00
let values = props.items;
2024-06-18 02:19:31 +08:00
if (props.resolveItem) values = values.map(props.resolveItem);
2024-08-28 15:45:50 +08:00
const items = values.filter(i => i && typeof i === "object");
2024-08-28 15:45:50 +08:00
return fuzzysort.go(search, items, { keys: props.searchKeywords, all: true });
}, [props.items, search]);
2024-08-15 01:24:09 +08:00
const headerElement = (
<View style={{ paddingBottom: 8 }}>
2024-08-15 01:58:23 +08:00
{props.ListHeaderComponent && <props.ListHeaderComponent />}
{settings.safeMode?.enabled && <View style={{ marginBottom: 10 }}>
<HelpMessage messageType={0}>{props.safeModeMessage}</HelpMessage>
{props.safeModeExtras}
</View>}
2024-08-15 01:24:09 +08:00
<Search onChangeText={v => setSearch(v)} />
</View>
2024-08-15 01:24:09 +08:00
);
2023-04-15 02:57:03 +01:00
return (
<ErrorBoundary>
<FlashList
2024-08-28 15:45:50 +08:00
data={results}
extraData={search}
estimatedItemSize={136}
ListHeaderComponent={headerElement}
2024-08-15 01:24:09 +08:00
contentContainerStyle={{ padding: 8, paddingHorizontal: 12 }}
ItemSeparatorComponent={() => <View style={{ height: 8 }} />}
2024-07-31 17:06:17 +08:00
ListFooterComponent={props.ListFooterComponent}
2024-08-28 15:45:50 +08:00
renderItem={({ item }: any) => <CardComponent item={item.obj} result={item} />}
2023-05-13 00:15:11 +01:00
/>
2024-07-31 17:06:17 +08:00
{(props.fetchFunction ?? props.onFabPress) && <FloatingActionButton
2024-07-09 15:53:34 +08:00
icon={findAssetId("PlusLargeIcon")}
2024-07-31 17:06:17 +08:00
onPress={props.onFabPress ?? (() => {
2023-12-21 03:30:21 +08:00
// from ./InstallButton.tsx
clipboard.getString().then((content: string) =>
2023-12-21 03:30:21 +08:00
showInputAlert({
initialValue: content.match(HTTP_REGEX_MULTI)?.[0] ?? "",
2024-03-08 02:54:20 +08:00
placeholder: Strings.URL_PLACEHOLDER,
2024-07-30 20:42:10 +08:00
onConfirm: (input: string) => props.fetchFunction!(input),
2024-02-27 17:22:23 +08:00
confirmText: Strings.INSTALL,
cancelText: Strings.CANCEL,
2023-12-21 03:30:21 +08:00
})
2024-03-06 01:57:59 +08:00
);
2024-05-20 00:04:25 +08:00
})}
2024-07-30 20:42:10 +08:00
/>}
2023-04-15 02:57:03 +01:00
</ErrorBoundary>
2024-03-06 01:57:59 +08:00
);
}