diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.yml similarity index 100% rename from .github/ISSUE_TEMPLATE/bug-report.md rename to .github/ISSUE_TEMPLATE/bug-report.yml diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.yml similarity index 100% rename from .github/ISSUE_TEMPLATE/feature-request.md rename to .github/ISSUE_TEMPLATE/feature-request.yml diff --git a/CHANGELOG.md b/CHANGELOG.md index 95b9ed2..39ddae3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,38 @@ -## [1.5.3](https://github.com/revenge-mod/revenge-bundle/compare/v1.5.2...v1.5.3) (2024-12-05) +## [1.5.4-dev.1](https://github.com/revenge-mod/revenge-bundle/compare/v1.5.3...v1.5.4-dev.1) (2024-12-26) ### Bug Fixes +* change `Bunny` to `Revenge` in `ErrorBoundary` content ([89f1b18](https://github.com/revenge-mod/revenge-bundle/commit/89f1b18ebb8995f9b26e3eaa83223cea54c0bc3d)) +* **lib/ui/settings:** fix icon not showing up ([2fc7715](https://github.com/revenge-mod/revenge-bundle/commit/2fc7715fa4494c0b105a6399edc4877a155d3512)) +* **ui/components/ErrorBoundaryScreen:** minor misspelling & update branding ([#57](https://github.com/revenge-mod/revenge-bundle/issues/57)) ([a71dd7d](https://github.com/revenge-mod/revenge-bundle/commit/a71dd7d0eb4c5e5003ff9743bcceab43ba2897c3)) + +## [1.5.3-dev.3](https://github.com/revenge-mod/revenge-bundle/compare/v1.5.3-dev.2...v1.5.3-dev.3) (2024-12-26) + + +### Bug Fixes + +* change `Bunny` to `Revenge` in `ErrorBoundary` content ([89f1b18](https://github.com/revenge-mod/revenge-bundle/commit/89f1b18ebb8995f9b26e3eaa83223cea54c0bc3d)) + +## [1.5.3-dev.2](https://github.com/revenge-mod/revenge-bundle/compare/v1.5.3-dev.1...v1.5.3-dev.2) (2024-12-26) + + +### Bug Fixes + +* **ui/components/ErrorBoundaryScreen:** minor misspelling & update branding ([#57](https://github.com/revenge-mod/revenge-bundle/issues/57)) ([a71dd7d](https://github.com/revenge-mod/revenge-bundle/commit/a71dd7d0eb4c5e5003ff9743bcceab43ba2897c3)) + +## [1.5.3](https://github.com/revenge-mod/revenge-bundle/compare/v1.5.2...v1.5.3) (2024-12-05) + + * backport iOS invalid element type crash fix ([afacfa0](https://github.com/revenge-mod/revenge-bundle/commit/afacfa06480f60d461840a211c09abb363dc8546)) +## [1.5.3-dev.1](https://github.com/revenge-mod/revenge-bundle/compare/v1.5.2...v1.5.3-dev.1) (2024-11-24) + + +### Bug Fixes + +* **lib/ui/settings:** fix icon not showing up ([2fc7715](https://github.com/revenge-mod/revenge-bundle/commit/2fc7715fa4494c0b105a6399edc4877a155d3512)) + ## [1.5.2](https://github.com/revenge-mod/revenge-bundle/compare/v1.5.1...v1.5.2) (2024-11-13) diff --git a/scripts/build.mjs b/scripts/build.mjs index 091e69a..53f6ba1 100644 --- a/scripts/build.mjs +++ b/scripts/build.mjs @@ -26,6 +26,7 @@ const { let context = null; +/** @type {import("esbuild").BuildOptions} */ const config = { entryPoints: ["src/entry.ts"], bundle: true, diff --git a/scripts/serve.mjs b/scripts/serve.mjs index 9987bfe..2b0a893 100644 --- a/scripts/serve.mjs +++ b/scripts/serve.mjs @@ -80,7 +80,7 @@ if (args.adb && isADBAvailableAndAppInstalled()) { if (key.name === "r") { console.info(chalk.yellow(`${chalk.bold("↻ Reloading")} ${packageName}`)); - restartAppFromADB(server.port) + restartAppFromADB(server.address().port) .then(() => console.info(chalk.greenBright(`${chalk.bold("✔ Executed")} reload command`))) .catch(e => console.error(e)); } diff --git a/src/core/debug/safeMode.ts b/src/core/debug/safeMode.ts new file mode 100644 index 0000000..f44bf06 --- /dev/null +++ b/src/core/debug/safeMode.ts @@ -0,0 +1,17 @@ +import { getCurrentTheme, writeThemeToNative } from "@lib/addons/themes"; +import { BundleUpdaterManager } from "@lib/api/native/modules"; +import { settings } from "@lib/api/settings"; + +export function isSafeMode() { + return settings.safeMode?.enabled === true; +} + +export async function toggleSafeMode({ + to = !isSafeMode(), + reload = true +} = {}) { + const enabled = (settings.safeMode ??= { enabled: to }).enabled = to; + const currentColor = getCurrentTheme(); + await writeThemeToNative(enabled ? {} : currentColor?.data ?? {}); + if (reload) setTimeout(() => BundleUpdaterManager.reload(), 500); +} diff --git a/src/core/ui/components/AddonPage.tsx b/src/core/ui/components/AddonPage.tsx index 21e2e3a..c802d6f 100644 --- a/src/core/ui/components/AddonPage.tsx +++ b/src/core/ui/components/AddonPage.tsx @@ -1,28 +1,28 @@ import { CardWrapper } from "@core/ui/components/AddonCard"; -import { useProxy } from "@core/vendetta/storage"; import { findAssetId } from "@lib/api/assets"; import { settings } from "@lib/api/settings"; -import AlertModal, { AlertActionButton } from "@lib/ui/components/wrappers/AlertModal"; +import { dismissAlert, openAlert } from "@lib/ui/alerts"; +import { showSheet } from "@lib/ui/sheets"; import isValidHttpUrl from "@lib/utils/isValidHttpUrl"; import { lazyDestructure, proxyLazy } from "@lib/utils/lazy"; import { findByProps } from "@metro"; -import { clipboard } from "@metro/common"; -import { Button, FlashList, FloatingActionButton, HelpMessage, IconButton, Stack, Text, TextInput } from "@metro/common/components"; +import { clipboard, NavigationNative } from "@metro/common"; +import { AlertActionButton, AlertModal, Button, FlashList, FloatingActionButton, HelpMessage, IconButton, Stack, Text, TextInput, useSafeAreaInsets } from "@metro/common/components"; import { ErrorBoundary, Search } from "@ui/components"; +import { isNotNil } from "es-toolkit"; import fuzzysort from "fuzzysort"; -import { ComponentType, ReactNode, useCallback, useMemo } from "react"; +import { ComponentType, ReactNode, useCallback, useEffect, useMemo } from "react"; import { Image, ScrollView, View } from "react-native"; const { showSimpleActionSheet, hideActionSheet } = lazyDestructure(() => findByProps("showSimpleActionSheet")); -const { openAlert, dismissAlert } = lazyDestructure(() => findByProps("openAlert", "dismissAlert")); -type SearchKeywords = Array string)>; +type SearchKeywords = Array string)>; interface AddonPageProps { title: string; items: I[]; - searchKeywords: SearchKeywords; - sortOptions?: Record number>; + searchKeywords: SearchKeywords; + sortOptions?: Record number>; resolveItem?: (value: I) => T | undefined; safeModeHint?: { message?: string; @@ -34,13 +34,14 @@ interface AddonPageProps { fetchFn?: (url: string) => Promise; onPress?: () => void; }; + + OptionsActionSheetComponent?: ComponentType; + CardComponent: ComponentType>; ListHeaderComponent?: ComponentType; ListFooterComponent?: ComponentType; } -const useSafeAreaInsets = proxyLazy(() => findByProps("useSafeAreaInsets").useSafeAreaInsets); - function InputAlert(props: { label: string, fetchFn: (url: string) => Promise; }) { const [value, setValue] = React.useState(""); const [error, setError] = React.useState(""); @@ -57,7 +58,7 @@ function InputAlert(props: { label: string, fetchFn: (url: string) => Promise Promise({ CardComponent, ...props }: AddonPageProps) { - useProxy(settings); - const [search, setSearch] = React.useState(""); - const [sortFn, setSortFn] = React.useState<((a: unknown, b: unknown) => number) | null>(() => null); - const insets = useSafeAreaInsets(); + const [sortFn, setSortFn] = React.useState<((a: T, b: T) => number) | null>(() => null); + const { bottom: bottomInset } = useSafeAreaInsets(); + const navigation = NavigationNative.useNavigation(); + + useEffect(() => { + if (props.OptionsActionSheetComponent) { + navigation.setOptions({ + headerRight: () => showSheet("AddonMoreSheet", props.OptionsActionSheetComponent!)} + /> + }); + } + }, [navigation]); const results = useMemo(() => { let values = props.items; - if (props.resolveItem) values = values.map(props.resolveItem); - const items = values.filter(i => i && typeof i === "object"); + if (props.resolveItem) values = values.map(props.resolveItem).filter(isNotNil); + const items = values.filter(i => isNotNil(i) && typeof i === "object"); if (!search && sortFn) items.sort(sortFn); return fuzzysort.go(search, items, { keys: props.searchKeywords, all: true }); @@ -137,7 +150,7 @@ export default function AddonPage({ CardComponent, ...props }: if (results.length === 0 && !search) { return - + Oops! Nothing to see here… yet! @@ -178,7 +191,7 @@ export default function AddonPage({ CardComponent, ...props }: })} />} - {props.ListHeaderComponent && !search && } + {props.ListHeaderComponent && } ); @@ -190,25 +203,21 @@ export default function AddonPage({ CardComponent, ...props }: estimatedItemSize={136} ListHeaderComponent={headerElement} ListEmptyComponent={() => - + Hmmm... could not find that! } - contentContainerStyle={{ padding: 8, paddingHorizontal: 12 }} + contentContainerStyle={{ padding: 8, paddingHorizontal: 12, paddingBottom: 90 }} ItemSeparatorComponent={() => } ListFooterComponent={props.ListFooterComponent} renderItem={({ item }: any) => } /> - {props.installAction && ( - - - - )} + {props.installAction && } ); } diff --git a/src/core/ui/hooks/useFS.ts b/src/core/ui/hooks/useFS.ts index 3577450..6de18c3 100644 --- a/src/core/ui/hooks/useFS.ts +++ b/src/core/ui/hooks/useFS.ts @@ -11,7 +11,7 @@ export enum CheckState { export function useFileExists(path: string, prefix?: string): [CheckState, typeof fs] { const [state, setState] = useState(CheckState.LOADING); - const check = () => fs.fileExists(path, prefix) + const check = () => fs.fileExists(path, { prefix }) .then(exists => setState(exists ? CheckState.TRUE : CheckState.FALSE)) .catch(() => setState(CheckState.ERROR)); diff --git a/src/core/ui/reporter/components/ErrorBoundaryScreen.tsx b/src/core/ui/reporter/components/ErrorBoundaryScreen.tsx index af164ad..bf4824e 100644 --- a/src/core/ui/reporter/components/ErrorBoundaryScreen.tsx +++ b/src/core/ui/reporter/components/ErrorBoundaryScreen.tsx @@ -5,7 +5,7 @@ import { settings } from "@lib/api/settings"; import { Codeblock, ErrorBoundary } from "@lib/ui/components"; import { createStyles } from "@lib/ui/styles"; import { tokens } from "@metro/common"; -import { Button, Card, SafeAreaView, Text } from "@metro/common/components"; +import { Button, Card, SafeAreaProvider, SafeAreaView, Text } from "@metro/common/components"; import { ScrollView, View } from "react-native"; import ErrorComponentStackCard from "./ErrorComponentStackCard"; @@ -29,22 +29,24 @@ export default function ErrorBoundaryScreen(props: { const debugInfo = getDebugInfo(); return - - - Uh oh. - A crash occured while rendering a component. This could be caused by a plugin, Bunny or Discord itself. - {debugInfo.os.name}; {debugInfo.discord.build} ({debugInfo.discord.version}); {debugInfo.bunny.version} - - - {props.error.message} - {hasStack(props.error) && } - {isComponentStack(props.error) ? : null} - - -