fix(plugins): handle unhandled cases

This commit is contained in:
amsyarasyiq 2024-08-15 01:24:09 +08:00
parent 65d1f346b7
commit 61286d8980
6 changed files with 42 additions and 49 deletions

View file

@ -4,12 +4,12 @@ import { findAssetId } from "@lib/api/assets";
import { settings } from "@lib/api/settings";
import { useProxy } from "@lib/api/storage";
import { HTTP_REGEX_MULTI } from "@lib/utils/constants";
import { clipboard, NavigationNative } from "@metro/common";
import { clipboard } from "@metro/common";
import { FlashList, FloatingActionButton, HelpMessage } from "@metro/common/components";
import { showInputAlert } from "@ui/alerts";
import { ErrorBoundary, Search } from "@ui/components";
import fuzzysort from "fuzzysort";
import { ComponentType, ReactNode, useCallback, useMemo } from "react";
import { ComponentType, ReactNode, useMemo } from "react";
import { View } from "react-native";
type SearchKeywords = Array<string | ((obj: any & {}) => string)>;
@ -30,14 +30,6 @@ interface AddonPageProps<T extends object> {
export default function AddonPage<T extends object>({ card: CardComponent, ...props }: AddonPageProps<T>) {
useProxy(settings);
const [, forceUpdate] = React.useReducer(s => ~s, 0);
NavigationNative.useFocusEffect(
useCallback(() => {
console.log("giler", items);
forceUpdate();
}, [])
);
const [search, setSearch] = React.useState("");
const items = useMemo(() => {
@ -51,33 +43,26 @@ export default function AddonPage<T extends object>({ card: CardComponent, ...pr
return fuzzysort.go(search, items, { keys: props.searchKeywords }).map(r => r.obj);
}, [items, search]);
const headerElement = useMemo(() => (
<View>
const headerElement = (
<View style={{ paddingBottom: 8 }}>
{settings.safeMode?.enabled && <View style={{ marginBottom: 10 }}>
<HelpMessage messageType={0}>{props.safeModeMessage}</HelpMessage>
{props.safeModeExtras}
</View>}
<Search
style={{ padding: 8 }}
onChangeText={v => setSearch(v)}
/>
<Search onChangeText={v => setSearch(v)} />
</View>
), []);
);
return (
<ErrorBoundary>
{/*
I've spent countless hours on these, but FlashList and FlatList refuse to rerender (unless if you reopen the page)
*even* if the data totally changed. Solutions online suggest putting extraData prop,
but that doesn't work either. I wonder what could have caused this
*/}
<FlashList
data={data}
extraData={search}
keyExtractor={(i: any) => i?.id}
estimatedItemSize={136}
ListHeaderComponent={headerElement}
contentContainerStyle={{ paddingBottom: 90, paddingHorizontal: 5 }}
contentContainerStyle={{ padding: 8, paddingHorizontal: 12 }}
ItemSeparatorComponent={() => <View style={{ height: 8 }} />}
ListFooterComponent={props.ListFooterComponent}
renderItem={({ item }: any) => (
<CardComponent item={item} />

View file

@ -104,16 +104,12 @@ export default function Plugins() {
]
});
return <View
style={{
margin: 8,
gap: 8,
alignItems: "center",
justifyContent: "center",
height: "100%"
}}
>
<SegmentedControl state={state} />
<SegmentedControlPages state={state} />
</View>;
return (
<View style={{ alignItems: "center", justifyContent: "center", height: "100%" }}>
<View style={{ padding: 8, paddingBottom: 0 }}>
<SegmentedControl state={state} />
</View>
<SegmentedControlPages state={state} />
</View>
);
}

View file

@ -14,7 +14,7 @@ const storagePromiseSymbol = Symbol.for("bunny.storage.promise");
const _loadedPath = {} as Record<string, any>;
function createFileBackend<T>(filePath: string): StorageBackend<T> {
function createFileBackend<T = any>(filePath: string): StorageBackend<T> {
return {
get: async () => {
try {
@ -187,13 +187,19 @@ export const createStorage = <T>(path: string, dflt = {} as T): T & { [key: symb
};
export async function preloadStorageIfExists(path: string) {
if (_loadedPath[path]) return;
if (!await fileExists(path)) return;
if (_loadedPath[path]) return _loadedPath[path];
const data = await createFileBackend<any>(path).get();
_loadedPath[path] = data;
const backend = createFileBackend(path);
if (await backend.exists()) {
return _loadedPath[path] = await backend.get();
}
console.log("no " + path);
}
export function getPreloadedStorage<T>(path: string): T {
return _loadedPath[path];
}
export function awaitStorage(...proxies: any[]) {
return Promise.all(proxies.map(proxy => proxy[storagePromiseSymbol]));
}

View file

@ -1,6 +1,6 @@
import { getCorePlugins } from "@core/plugins";
import { readFile, removeFile, writeFile } from "@lib/api/native/fs";
import { awaitStorage, createStorage, preloadStorageIfExists, updateStorageAsync } from "@lib/api/storage/new";
import { awaitStorage, createStorage, getPreloadedStorage, preloadStorageIfExists, updateStorageAsync } from "@lib/api/storage/new";
import { safeFetch } from "@lib/utils";
import { semver } from "@metro/common";
@ -155,19 +155,24 @@ export async function updateRepository(repoUrl: string) {
}
}
await Promise.all(Object.keys(repo).map(async plugin => {
if (!storedRepo || !storedRepo[plugin] || repo[plugin].alwaysFetch || newerThan(repo[plugin].version, storedRepo[plugin].version)) {
await Promise.all(Object.keys(repo).map(async pluginId => {
if (!storedRepo || !storedRepo[pluginId] || repo[pluginId].alwaysFetch || newerThan(repo[pluginId].version, storedRepo[pluginId].version)) {
updated = true;
pluginRepositories[repoUrl][plugin] = repo[plugin];
await updateAndWritePlugin(repoUrl, plugin, Boolean(storedRepo && pluginSettings[plugin]));
pluginRepositories[repoUrl][pluginId] = repo[pluginId];
await updateAndWritePlugin(repoUrl, pluginId, Boolean(storedRepo && pluginSettings[pluginId]));
} else {
await preloadStorageIfExists(`plugins/manifests/${plugin}.json`);
const manifest = await preloadStorageIfExists(`plugins/manifests/${pluginId}.json`);
if (manifest === undefined) { // File does not exist, so do refetch and stuff
await updateAndWritePlugin(repoUrl, pluginId, Boolean(storedRepo && pluginSettings[pluginId]));
}
}
}));
// Register plugins in this repository
for (const id in repo) {
const manifest = createStorage<t.BunnyPluginManifest>(`plugins/manifests/${id}.json`);
const manifest = getPreloadedStorage<t.BunnyPluginManifest>(`plugins/manifests/${id}.json`);
if (manifest === undefined) continue; // shouldn't happen, but just incase if it does
const existing = registeredPlugins.get(id);
// Skip if this version isn't any higher

View file

@ -2,12 +2,12 @@ import { Strings } from "@core/i18n";
import { findAssetId } from "@lib/api/assets";
import { TextInput } from "@metro/common/components";
import ErrorBoundary from "@ui/components/ErrorBoundary";
import { Image, View } from "react-native";
import { Image, View, ViewStyle } from "react-native";
export interface SearchProps {
onChangeText?: (v: string) => void;
placeholder?: string;
style?: import("react-native").TextStyle;
style?: ViewStyle;
}
function SearchIcon() {

View file

@ -60,6 +60,7 @@ export interface SegmentedControlState {
interface SegmentedControlProps {
state: SegmentedControlState;
variant?: string;
}
export type SegmentedControl = React.FC<SegmentedControlProps>;