feat(ui): simplify some components
and show bunny plugins on the page
This commit is contained in:
parent
1d4dfd311f
commit
4d881835a6
6 changed files with 93 additions and 106 deletions
|
|
@ -27,19 +27,19 @@ interface AddonPageProps<T extends object, I = any> {
|
|||
safeModeHint?: {
|
||||
message?: string;
|
||||
footer?: ReactNode;
|
||||
}
|
||||
};
|
||||
installAction?: {
|
||||
label?: string;
|
||||
// Ignored when onPress is defined!
|
||||
fetchFn?: (url: string) => Promise<void>;
|
||||
onPress?: () => void;
|
||||
}
|
||||
};
|
||||
CardComponent: ComponentType<CardWrapper<T>>;
|
||||
ListHeaderComponent?: ComponentType<any>;
|
||||
ListFooterComponent?: ComponentType<any>;
|
||||
}
|
||||
|
||||
function InputAlert(props: { label: string, fetchFn: (url: string) => Promise<void> }) {
|
||||
function InputAlert(props: { label: string, fetchFn: (url: string) => Promise<void>; }) {
|
||||
const [value, setValue] = React.useState("");
|
||||
const [error, setError] = React.useState("");
|
||||
const [isFetching, setIsFetching] = React.useState(false);
|
||||
|
|
@ -122,7 +122,7 @@ export default function AddonPage<T extends object>({ CardComponent, ...props }:
|
|||
}, [props.items, sortFn, search]);
|
||||
|
||||
const onInstallPress = useCallback(() => {
|
||||
if (!props.installAction) return () => {};
|
||||
if (!props.installAction) return () => { };
|
||||
const { label, onPress, fetchFn } = props.installAction;
|
||||
if (fetchFn) {
|
||||
openAlert("AddonInputAlert", <InputAlert label={label ?? "Install"} fetchFn={fetchFn} />);
|
||||
|
|
@ -175,7 +175,7 @@ export default function AddonPage<T extends object>({ CardComponent, ...props }:
|
|||
})}
|
||||
/>}
|
||||
</View>
|
||||
{props.ListHeaderComponent && <props.ListHeaderComponent />}
|
||||
{props.ListHeaderComponent && !search && <props.ListHeaderComponent />}
|
||||
</View>
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import { Image, View } from "react-native";
|
|||
|
||||
import { UnifiedPluginModel } from "..";
|
||||
|
||||
const CardContext = createContext<{ plugin: UnifiedPluginModel, result: Fuzzysort.KeysResult<UnifiedPluginModel> }>(null!);
|
||||
const CardContext = createContext<{ plugin: UnifiedPluginModel, result: Fuzzysort.KeysResult<UnifiedPluginModel>; }>(null!);
|
||||
const useCardContext = () => useContext(CardContext);
|
||||
|
||||
function getHighlightColor(): import("react-native").ColorValue {
|
||||
|
|
@ -92,7 +92,7 @@ function Description() {
|
|||
</Text>;
|
||||
}
|
||||
|
||||
const Actions = memo(() => {
|
||||
const Actions = () => {
|
||||
const { plugin } = useCardContext();
|
||||
const navigation = NavigationNative.useNavigation();
|
||||
|
||||
|
|
@ -118,7 +118,7 @@ const Actions = memo(() => {
|
|||
)}
|
||||
/>
|
||||
</View>;
|
||||
});
|
||||
};
|
||||
|
||||
export default function PluginCard({ result, item: plugin }: CardWrapper<UnifiedPluginModel>) {
|
||||
plugin.usePluginState();
|
||||
|
|
|
|||
|
|
@ -5,18 +5,30 @@ import { VdPluginManager } from "@core/vendetta/plugins";
|
|||
import { findAssetId } from "@lib/api/assets";
|
||||
import { settings } from "@lib/api/settings";
|
||||
import { useProxy } from "@lib/api/storage";
|
||||
import { useProxy as useNewProxy } from "@lib/api/storage/new";
|
||||
import { showToast } from "@lib/ui/toasts";
|
||||
import { BUNNY_PROXY_PREFIX, VD_PROXY_PREFIX } from "@lib/utils/constants";
|
||||
import { lazyDestructure } from "@lib/utils/lazy";
|
||||
import { Author } from "@lib/utils/types";
|
||||
import { findByProps } from "@metro";
|
||||
import { NavigationNative } from "@metro/common";
|
||||
import { Button, Card, FlashList, IconButton, Stack, Text } from "@metro/common/components";
|
||||
import { NavigationNative, tokens } from "@metro/common";
|
||||
import { Card, FlashList, IconButton, PressableScale, Stack, Text } from "@metro/common/components";
|
||||
import { ComponentProps } from "react";
|
||||
import { Image, View } from "react-native";
|
||||
|
||||
import unifyVdPlugin from "./models/vendetta";
|
||||
import { isCorePlugin, isPluginInstalled, pluginSettings, registeredPlugins } from "@lib/plugins";
|
||||
import unifyBunnyPlugin from "./models/bunny";
|
||||
import { createStyles } from "@lib/ui/styles";
|
||||
|
||||
const useStyles = createStyles({
|
||||
xButton: {
|
||||
position: "absolute",
|
||||
right: 8,
|
||||
top: 8,
|
||||
tintColor: tokens.colors.INTERACTIVE_NORMAL
|
||||
}
|
||||
});
|
||||
export interface UnifiedPluginModel {
|
||||
id: string;
|
||||
name: string;
|
||||
|
|
@ -67,45 +79,63 @@ export default function Plugins() {
|
|||
const navigation = NavigationNative.useNavigation();
|
||||
|
||||
return <PluginPage
|
||||
useItems={() => useProxy(VdPluginManager.plugins) && Object.values(VdPluginManager.plugins)}
|
||||
resolveItem={unifyVdPlugin}
|
||||
useItems={() => {
|
||||
useProxy(VdPluginManager.plugins);
|
||||
useNewProxy(pluginSettings);
|
||||
|
||||
const vdPlugins = Object.values(VdPluginManager.plugins).map(unifyVdPlugin);
|
||||
const bnPlugins = [...registeredPlugins.values()].filter(p => isPluginInstalled(p.id) && !isCorePlugin(p.id)).map(unifyBunnyPlugin);
|
||||
|
||||
return [...vdPlugins, ...bnPlugins];
|
||||
}}
|
||||
ListHeaderComponent={() => {
|
||||
const styles = useStyles();
|
||||
const unproxiedPlugins = Object.values(VdPluginManager.plugins).filter(p => !p.id.startsWith(VD_PROXY_PREFIX) && !p.id.startsWith(BUNNY_PROXY_PREFIX));
|
||||
if (!unproxiedPlugins.length) return null;
|
||||
|
||||
return <Card style={{ marginVertical: 12, marginHorizontal: 10 }} border="strong">
|
||||
<View style={{ flex: 1, justifyContent: "center", alignItems: "center", flexDirection: "row" }}>
|
||||
<View style={{ gap: 6, flexShrink: 1 }}>
|
||||
<Text variant="heading-md/bold">Unproxied Plugins Found</Text>
|
||||
<Text variant="text-sm/medium" color="text-muted">
|
||||
Plugins installed from unproxied sources may run unverified code in this app without your awareness.
|
||||
</Text>
|
||||
return <View style={{ marginVertical: 12, marginHorizontal: 10 }}>
|
||||
<Card border="strong">
|
||||
{/* <PressableScale
|
||||
style={styles.xButton}
|
||||
onPress={() => {
|
||||
|
||||
}}
|
||||
>
|
||||
<Image source={findAssetId("XSmallIcon")} />
|
||||
</PressableScale> */}
|
||||
<View style={{ flex: 1, justifyContent: "center", alignItems: "center", flexDirection: "row" }}>
|
||||
<View style={{ gap: 6, flexShrink: 1 }}>
|
||||
<Text variant="heading-md/bold">Unproxied Plugins Found</Text>
|
||||
<Text variant="text-sm/medium" color="text-muted">
|
||||
Plugins installed from unproxied sources may run unverified code in this app without your awareness.
|
||||
</Text>
|
||||
</View>
|
||||
<View style={{ marginLeft: "auto" }}>
|
||||
<IconButton
|
||||
size="sm"
|
||||
variant="secondary"
|
||||
icon={findAssetId("CircleInformationIcon-primary")}
|
||||
style={{ marginLeft: 8 }}
|
||||
onPress={() => {
|
||||
navigation.push("BUNNY_CUSTOM_PAGE", {
|
||||
title: "Unproxied Plugins",
|
||||
render: () => {
|
||||
return <FlashList
|
||||
data={unproxiedPlugins}
|
||||
contentContainerStyle={{ padding: 8 }}
|
||||
ItemSeparatorComponent={() => <View style={{ height: 8 }} />}
|
||||
renderItem={({ item: p }: any) => <Card>
|
||||
<Text variant="heading-md/semibold">{p.id}</Text>
|
||||
</Card>}
|
||||
/>;
|
||||
}
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
<View style={{ marginLeft: "auto" }}>
|
||||
<IconButton
|
||||
size="sm"
|
||||
variant="secondary"
|
||||
icon={findAssetId("CircleInformationIcon-primary")}
|
||||
style={{ marginLeft: 8 }}
|
||||
onPress={() => {
|
||||
navigation.push("BUNNY_CUSTOM_PAGE", {
|
||||
title: "Unproxied Plugins",
|
||||
render: () => {
|
||||
return <FlashList
|
||||
data={unproxiedPlugins}
|
||||
contentContainerStyle={{ padding: 8 }}
|
||||
ItemSeparatorComponent={() => <View style={{ height: 8 }} />}
|
||||
renderItem={({ item: p }: any) => <Card>
|
||||
<Text variant="heading-md/semibold">{p.id}</Text>
|
||||
</Card>}
|
||||
/>;
|
||||
}
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
</Card>;
|
||||
</Card>
|
||||
</View>;
|
||||
}}
|
||||
installAction={{
|
||||
label: "Install a plugin",
|
||||
|
|
@ -135,61 +165,4 @@ export default function Plugins() {
|
|||
}
|
||||
}}
|
||||
/>;
|
||||
|
||||
// const navigation = NavigationNative.useNavigation();
|
||||
// const { width: pageWidth } = useWindowDimensions();
|
||||
|
||||
// const state = useSegmentedControlState({
|
||||
// pageWidth,
|
||||
// items: [
|
||||
// {
|
||||
// label: "Vendetta",
|
||||
// id: "vendetta-plugins",
|
||||
// page: (
|
||||
// <PluginPage
|
||||
// useItems={() => useProxy(VdPluginManager.plugins) && Object.values(VdPluginManager.plugins)}
|
||||
// resolveItem={unifyVdPlugin}
|
||||
// fetchFunction={(url: string) => VdPluginManager.installPlugin(url)}
|
||||
// />
|
||||
// )
|
||||
// },
|
||||
// {
|
||||
// label: "Bunny",
|
||||
// id: "bunny-plugins",
|
||||
// page: (
|
||||
// <PluginPage
|
||||
// useItems={() => (useNewProxy(pluginSettings), [...registeredPlugins.values()].filter(p => isPluginInstalled(p.id)))}
|
||||
// resolveItem={unifyBunnyPlugin}
|
||||
// ListHeaderComponent={() => (
|
||||
// <View style={{ marginBottom: 10 }}>
|
||||
// <HelpMessage messageType={0}>
|
||||
// Bunny plugin system is in no way ready, try not getting yourself burnt ⚠️
|
||||
// </HelpMessage>
|
||||
// </View>
|
||||
// )}
|
||||
// ListFooterComponent={() => (
|
||||
// <View style={{ alignItems: "center", justifyContent: "center", paddingTop: 16, gap: 12 }}>
|
||||
// <Text variant="heading-lg/bold">{"Looking for more?"}</Text>
|
||||
// <Button
|
||||
// size="lg"
|
||||
// text="Browse plugins"
|
||||
// icon={findAssetId("discover")}
|
||||
// onPress={() => navigateToPluginBrowser(navigation)}
|
||||
// />
|
||||
// </View>
|
||||
// )}
|
||||
// />
|
||||
// )
|
||||
// },
|
||||
// ]
|
||||
// });
|
||||
|
||||
// return (
|
||||
// <View style={{ alignItems: "center", justifyContent: "center", height: "100%" }}>
|
||||
// <View style={{ padding: 8, paddingBottom: 0 }}>
|
||||
// <SegmentedControl state={state} />
|
||||
// </View>
|
||||
// <SegmentedControlPages state={state} />
|
||||
// </View>
|
||||
// );
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { useProxy } from "@lib/api/storage/new";
|
||||
import { disablePlugin, enablePlugin, getId, getPluginSettingsComponent,isPluginEnabled, pluginSettings } from "@lib/plugins";
|
||||
import { disablePlugin, enablePlugin, getId, getPluginSettingsComponent, isPluginEnabled, pluginSettings } from "@lib/plugins";
|
||||
import { BunnyPluginManifest } from "@lib/plugins/types";
|
||||
|
||||
import { UnifiedPluginModel } from "..";
|
||||
|
|
|
|||
|
|
@ -9,11 +9,16 @@ export default function PluginInfoActionSheet({ plugin, navigation }: PluginInfo
|
|||
plugin.usePluginState();
|
||||
|
||||
return <ActionSheet>
|
||||
<ScrollView>
|
||||
<ScrollView contentContainerStyle={{ gap: 8, marginBottom: 12 }}>
|
||||
<View style={{ flexDirection: "row", alignItems: "center", paddingVertical: 24 }}>
|
||||
<Text variant="heading-xl/semibold">
|
||||
{plugin.name}
|
||||
</Text>
|
||||
<View style={{ gap: 4 }}>
|
||||
<Text variant="heading-xl/semibold">
|
||||
{plugin.name}
|
||||
</Text>
|
||||
<Text variant="text-md/medium" color="text-muted">
|
||||
{plugin.description}
|
||||
</Text>
|
||||
</View>
|
||||
<View style={{ marginLeft: "auto" }}>
|
||||
{plugin.getPluginSettingsComponent() && <Button
|
||||
size="md"
|
||||
|
|
@ -30,6 +35,11 @@ export default function PluginInfoActionSheet({ plugin, navigation }: PluginInfo
|
|||
/>}
|
||||
</View>
|
||||
</View>
|
||||
<View style={{ flexDirection: "row", justifyContent: "center", alignContent: "center" }}>
|
||||
<Text variant="text-lg/medium">
|
||||
Oops, you shouldn't see this!
|
||||
</Text>
|
||||
</View>
|
||||
</ScrollView>
|
||||
</ActionSheet>;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,6 +51,10 @@ function isExternalPlugin(manifest: t.BunnyPluginManifest): manifest is t.BunnyP
|
|||
return "parentRepository" in manifest;
|
||||
}
|
||||
|
||||
export function isCorePlugin(id: string) {
|
||||
return corePluginInstances.has(id);
|
||||
}
|
||||
|
||||
export function getId<T extends t.BunnyPluginManifest>(manifest: T): string {
|
||||
const id = manifestToId.get(manifest);
|
||||
assert(id, manifest?.name ?? "unknown", "getting ID from an unregistered/invalid manifest");
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue