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>;
|
2023-04-15 03:04:48 +01:00
|
|
|
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>) {
|
2023-12-22 11:13:17 +08:00
|
|
|
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>
|
|
|
|
|
)
|
|
|
|
|
}
|