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

77 lines
3.4 KiB
TypeScript
Raw Normal View History

2023-12-21 03:30:21 +08:00
import { NavigationNative, ReactNative as RN, clipboard } from "@metro/common";
2023-04-15 02:57:03 +01:00
import { useProxy } from "@lib/storage";
import { HelpMessage, ErrorBoundary, Search } from "@ui/components";
import { CardWrapper } from "@ui/settings/components/Card";
import settings from "@lib/settings";
2023-12-21 03:30:21 +08:00
import { findByProps } from "@/lib/metro/filters";
import { HTTP_REGEX_MULTI } from "@/lib/constants";
import { showInputAlert } from "@/ui/alerts";
import { getAssetIDByName } from "@/ui/assets";
2023-04-15 02:57:03 +01:00
interface AddonPageProps<T> {
2023-12-21 03:30:21 +08:00
title: string;
fetchFunction: (url: string) => Promise<void>;
items: Record<string, T & { id: string }>;
2023-04-15 02:57:03 +01:00
safeModeMessage: string;
safeModeExtras?: JSX.Element | JSX.Element[];
card: React.ComponentType<CardWrapper<T>>;
}
2023-12-21 03:30:21 +08:00
const reanimated = findByProps("useSharedValue");
const { FloatingActionButton } = findByProps("FloatingActionButton");
export default function AddonPage<T>({ title, fetchFunction, items, safeModeMessage, safeModeExtras, card: CardComponent }: AddonPageProps<T>) {
useProxy(settings);
2023-04-15 02:57:03 +01:00
useProxy(items);
2023-12-21 03:30:21 +08:00
const collapseText = reanimated.useSharedValue(0);
const yOffset = React.useRef<number>(0);
2023-04-15 02:57:03 +01:00
const [search, setSearch] = React.useState("");
return (
<ErrorBoundary>
2023-05-13 00:15:11 +01:00
{/* TODO: Implement better searching than just by ID */}
<RN.FlatList
ListHeaderComponent={<>
{settings.safeMode?.enabled && <RN.View style={{ marginBottom: 10 }}>
<HelpMessage messageType={0}>{safeModeMessage}</HelpMessage>
{safeModeExtras}
</RN.View>}
<Search
2023-12-21 03:30:21 +08:00
style={{ marginBottom: 15 }}
2023-05-13 00:15:11 +01:00
onChangeText={(v: string) => setSearch(v.toLowerCase())}
placeholder="Search"
/>
</>}
2023-12-21 03:30:21 +08:00
onScroll={e => {
if (e.nativeEvent.contentOffset.y <= 0) return;
collapseText.value = Number(e.nativeEvent.contentOffset.y > yOffset.current);
yOffset.current = e.nativeEvent.contentOffset.y;
}}
onMomentumScrollEnd={() => collapseText.value = 0}
2023-05-13 00:15:11 +01:00
style={{ paddingHorizontal: 10, paddingTop: 10 }}
2023-12-21 03:30:21 +08:00
contentContainerStyle={{ paddingBottom: 70 }}
2023-05-13 00:15:11 +01:00
data={Object.values(items).filter(i => i.id?.toLowerCase().includes(search))}
renderItem={({ item, index }) => <CardComponent item={item} index={index} />}
/>
2023-12-21 03:30:21 +08:00
<FloatingActionButton
text={`Install ${title}`}
icon={getAssetIDByName("DownloadIcon")}
state={{ collapseText }}
onPress={() => {
// from ./InstallButton.tsx
clipboard.getString().then((content) =>
showInputAlert({
title: `Install ${title}`,
initialValue: content.match(HTTP_REGEX_MULTI)?.[0] ?? "",
placeholder: "https://example.com/",
onConfirm: (input: string) => fetchFunction(input),
confirmText: "Install",
cancelText: "Cancel",
})
)
}}
/>
2023-04-15 02:57:03 +01:00
</ErrorBoundary>
)
}