diff --git a/src/core/i18n/default.json b/src/core/i18n/default.json index 5764edf..b20e33e 100644 --- a/src/core/i18n/default.json +++ b/src/core/i18n/default.json @@ -7,6 +7,7 @@ "AUTO_DEBUGGER": "Automatically connect to Debugger", "AUTO_DEVTOOLS": "Automatically connect to Devtools", "ASSET_BROWSER": "Asset Browser", + "ASSET_TYPES": "Asset Types", "BRAND": "Brand", "SHIGGYCORD": "ShiggyCord", "SHIGGYCORD_URL": "ShiggyCord URL", diff --git a/src/core/ui/settings/pages/Developer/AssetBrowser.tsx b/src/core/ui/settings/pages/Developer/AssetBrowser.tsx index 639dcb5..53645c6 100644 --- a/src/core/ui/settings/pages/Developer/AssetBrowser.tsx +++ b/src/core/ui/settings/pages/Developer/AssetBrowser.tsx @@ -1,21 +1,98 @@ import AssetDisplay from "@core/ui/settings/pages/Developer/AssetDisplay"; import { iterateAssets } from "@lib/api/assets"; -import { Text } from "@metro/common/components"; +import { findAssetId } from "@lib/api/assets"; +import { Strings } from "@core/i18n"; +import { IconButton, TableCheckboxRow, TableRowGroup, ActionSheet, BottomSheetTitleHeader } from "@metro/common/components"; import { ErrorBoundary, Search } from "@ui/components"; -import { useMemo } from "react"; +import { showSheet } from "@lib/ui/sheets"; +import { useProxy, createProxy } from "@core/vendetta/storage"; +import { useState, useMemo, useCallback } from "react"; import { FlatList, View } from "react-native"; +// Asset type categories +const DISPLAYABLE_IMAGE_TYPES = new Set(["png", "jpg", "jpeg", "svg", "gif"]); +const DISPLAYABLE_TEXT_TYPES = new Set(["jsona", "json", "lottie"]); + +// Define all available filters with their display names +const FILTER_OPTIONS = [ + { id: "images", label: "Images (PNG, JPG, SVG, GIF)", types: DISPLAYABLE_IMAGE_TYPES, defaultEnabled: true }, + { id: "text", label: "Text Types (JSON, JSONA, Lottie)", types: DISPLAYABLE_TEXT_TYPES, defaultEnabled: false }, +]; + +const { proxy: assetBrowserStorage } = createProxy({ + enabledFilters: { + images: true, + text: false, + } +}); + export default function AssetBrowser() { - const [search, setSearch] = React.useState(""); - const all = useMemo(() => Array.from(iterateAssets()), []); + const [search, setSearch] = useState(""); + const [updateTick, setUpdateTick] = useState(0); + + // Use useProxy to make the state reactive + useProxy(assetBrowserStorage); + + const getFilteredAssets = useCallback(() => { + return Array.from(iterateAssets()).filter((asset) => { + const type = String(asset.type ?? "").toLowerCase(); + + // Check if this asset type is enabled in any filter + for (const filter of FILTER_OPTIONS) { + if (assetBrowserStorage.enabledFilters[filter.id as keyof typeof assetBrowserStorage.enabledFilters] && filter.types.has(type)) { + return true; + } + } + return false; + }); + }, [updateTick]); + + const all = useMemo(() => getFilteredAssets(), [getFilteredAssets]); + + const toggleFilter = (filterId: string) => { + assetBrowserStorage.enabledFilters[filterId as keyof typeof assetBrowserStorage.enabledFilters] = !assetBrowserStorage.enabledFilters[filterId as keyof typeof assetBrowserStorage.enabledFilters]; + setUpdateTick(prev => prev + 1); + }; + + const handleFilterPress = () => { + showSheet("AssetBrowserFilter", () => { + useProxy(assetBrowserStorage); + + return ( + + + + + {FILTER_OPTIONS.map(filter => ( + toggleFilter(filter.id)} + /> + ))} + + + + ); + }); + }; return ( - setSearch(v)} - /> + + setSearch(v)} + /> + + - - Some assets types cannot be displayed and will be marked in red. - a.name.includes(search) || a.id.toString() === search, + (a) => (a.name.includes(search) || a.id.toString() === search), )} renderItem={({ item }: any) => } contentContainerStyle={{