Skip to content

Commit

Permalink
chore: merge dev to main (#58)
Browse files Browse the repository at this point in the history
  • Loading branch information
PalmDevs authored Dec 26, 2024
2 parents 5a25e4e + 130e77a commit 050a72b
Show file tree
Hide file tree
Showing 71 changed files with 1,579 additions and 819 deletions.
File renamed without changes.
File renamed without changes.
30 changes: 29 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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)


Expand Down
1 change: 1 addition & 0 deletions scripts/build.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const {

let context = null;

/** @type {import("esbuild").BuildOptions} */
const config = {
entryPoints: ["src/entry.ts"],
bundle: true,
Expand Down
2 changes: 1 addition & 1 deletion scripts/serve.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
Expand Down
17 changes: 17 additions & 0 deletions src/core/debug/safeMode.ts
Original file line number Diff line number Diff line change
@@ -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);
}
71 changes: 40 additions & 31 deletions src/core/ui/components/AddonPage.tsx
Original file line number Diff line number Diff line change
@@ -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 | ((obj: any & {}) => string)>;
type SearchKeywords<T> = Array<string | ((obj: T & {}) => string)>;

interface AddonPageProps<T extends object, I = any> {
title: string;
items: I[];
searchKeywords: SearchKeywords;
sortOptions?: Record<string, (a: I, b: I) => number>;
searchKeywords: SearchKeywords<T>;
sortOptions?: Record<string, (a: T, b: T) => number>;
resolveItem?: (value: I) => T | undefined;
safeModeHint?: {
message?: string;
Expand All @@ -34,13 +34,14 @@ interface AddonPageProps<T extends object, I = any> {
fetchFn?: (url: string) => Promise<void>;
onPress?: () => void;
};

OptionsActionSheetComponent?: ComponentType<any>;

CardComponent: ComponentType<CardWrapper<T>>;
ListHeaderComponent?: ComponentType<any>;
ListFooterComponent?: ComponentType<any>;
}

const useSafeAreaInsets = proxyLazy(() => findByProps("useSafeAreaInsets").useSafeAreaInsets);

function InputAlert(props: { label: string, fetchFn: (url: string) => Promise<void>; }) {
const [value, setValue] = React.useState("");
const [error, setError] = React.useState("");
Expand All @@ -57,7 +58,7 @@ function InputAlert(props: { label: string, fetchFn: (url: string) => Promise<vo

return <AlertModal
title={props.label}
content="Enter the URL of the source you want to install from:"
content="Type in the source URL you want to install from:"
extraContent={
<Stack style={{ marginTop: -12 }}>
<TextInput
Expand Down Expand Up @@ -109,16 +110,28 @@ function InputAlert(props: { label: string, fetchFn: (url: string) => Promise<vo
}

export default function AddonPage<T extends object>({ CardComponent, ...props }: AddonPageProps<T>) {
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: () => <IconButton
size="sm"
variant="secondary"
icon={findAssetId("MoreHorizontalIcon")}
onPress={() => 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 });
Expand All @@ -137,7 +150,7 @@ export default function AddonPage<T extends object>({ CardComponent, ...props }:
if (results.length === 0 && !search) {
return <View style={{ gap: 32, flexGrow: 1, justifyContent: "center", alignItems: "center" }}>
<View style={{ gap: 8, alignItems: "center" }}>
<Image source={findAssetId("empty_quick_switcher")} />
<Image source={findAssetId("empty_quick_switcher")!} />
<Text variant="text-lg/semibold" color="text-normal">
Oops! Nothing to see here… yet!
</Text>
Expand Down Expand Up @@ -178,7 +191,7 @@ export default function AddonPage<T extends object>({ CardComponent, ...props }:
})}
/>}
</View>
{props.ListHeaderComponent && !search && <props.ListHeaderComponent />}
{props.ListHeaderComponent && <props.ListHeaderComponent />}
</View>
);

Expand All @@ -190,25 +203,21 @@ export default function AddonPage<T extends object>({ CardComponent, ...props }:
estimatedItemSize={136}
ListHeaderComponent={headerElement}
ListEmptyComponent={() => <View style={{ gap: 12, padding: 12, alignItems: "center" }}>
<Image source={findAssetId("devices_not_found")} />
<Image source={findAssetId("devices_not_found")!} />
<Text variant="text-lg/semibold" color="text-normal">
Hmmm... could not find that!
</Text>
</View>}
contentContainerStyle={{ padding: 8, paddingHorizontal: 12 }}
contentContainerStyle={{ padding: 8, paddingHorizontal: 12, paddingBottom: 90 }}
ItemSeparatorComponent={() => <View style={{ height: 8 }} />}
ListFooterComponent={props.ListFooterComponent}
renderItem={({ item }: any) => <CardComponent item={item.obj} result={item} />}
/>
{props.installAction && (
<View style={{ paddingBottom: insets.bottom }}>
<FloatingActionButton
positionBottom={insets.bottom + 16}
icon={findAssetId("PlusLargeIcon")}
onPress={onInstallPress}
/>
</View>
)}
{props.installAction && <FloatingActionButton
positionBottom={bottomInset + 8}
icon={findAssetId("PlusLargeIcon")}
onPress={onInstallPress}
/>}
</ErrorBoundary>
);
}
2 changes: 1 addition & 1 deletion src/core/ui/hooks/useFS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export enum CheckState {
export function useFileExists(path: string, prefix?: string): [CheckState, typeof fs] {
const [state, setState] = useState<CheckState>(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));

Expand Down
38 changes: 20 additions & 18 deletions src/core/ui/reporter/components/ErrorBoundaryScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -29,22 +29,24 @@ export default function ErrorBoundaryScreen(props: {
const debugInfo = getDebugInfo();

return <ErrorBoundary>
<SafeAreaView style={styles.container}>
<View style={{ gap: 4 }}>
<Text variant="display-lg">Uh oh.</Text>
<Text variant="text-md/normal">A crash occured while rendering a component. This could be caused by a plugin, Bunny or Discord itself.</Text>
<Text variant="text-sm/normal" color="text-muted">{debugInfo.os.name}; {debugInfo.discord.build} ({debugInfo.discord.version}); {debugInfo.bunny.version}</Text>
</View>
<ScrollView fadingEdgeLength={64} contentContainerStyle={{ gap: 12 }}>
<Codeblock selectable={true}>{props.error.message}</Codeblock>
{hasStack(props.error) && <ErrorStackCard error={props.error} />}
{isComponentStack(props.error) ? <ErrorComponentStackCard componentStack={props.error.componentStack} /> : null}
</ScrollView>
<Card style={{ gap: 6 }}>
<Button text="Reload Discord" onPress={() => BundleUpdaterManager.reload()} />
{!settings.safeMode?.enabled && <Button text="Reload in Safe Mode" onPress={() => toggleSafeMode()} />}
<Button variant="destructive" text="Retry Render" onPress={() => props.rerender()} />
</Card>
</SafeAreaView>
<SafeAreaProvider>
<SafeAreaView style={styles.container}>
<View style={{ gap: 4 }}>
<Text variant="display-lg">Uh oh.</Text>
<Text variant="text-md/normal">A crash occurred while rendering a component. This could be caused by a plugin, Revenge, or Discord itself.</Text>
<Text variant="text-sm/normal" color="text-muted">{debugInfo.os.name}; {debugInfo.discord.build} ({debugInfo.discord.version}); {debugInfo.bunny.version}</Text>
</View>
<ScrollView fadingEdgeLength={64} contentContainerStyle={{ gap: 12 }}>
<Codeblock selectable={true}>{props.error.message}</Codeblock>
{hasStack(props.error) && <ErrorStackCard error={props.error} />}
{isComponentStack(props.error) ? <ErrorComponentStackCard componentStack={props.error.componentStack} /> : null}
</ScrollView>
<Card style={{ gap: 6 }}>
<Button text="Reload Discord" onPress={() => BundleUpdaterManager.reload()} />
{!settings.safeMode?.enabled && <Button text="Reload in Safe Mode" onPress={() => toggleSafeMode()} />}
<Button variant="destructive" text="Retry Render" onPress={() => props.rerender()} />
</Card>
</SafeAreaView>
</SafeAreaProvider>
</ErrorBoundary>;
}
7 changes: 5 additions & 2 deletions src/core/ui/settings/pages/Developer/AssetBrowser.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import AssetDisplay from "@core/ui/settings/pages/Developer/AssetDisplay";
import { assetsMap } from "@lib/api/assets";
import { iterateAssets } from "@lib/api/assets";
import { Text } from "@metro/common/components";
import { ErrorBoundary, Search } from "@ui/components";
import { useMemo } from "react";
import { FlatList, View } from "react-native";

export default function AssetBrowser() {
const [search, setSearch] = React.useState("");
const all = useMemo(() => Array.from(iterateAssets()), []);

return (
<ErrorBoundary>
Expand All @@ -17,9 +19,10 @@ export default function AssetBrowser() {
<View style={{ flex: 1, borderRadius: 16, paddingHorizontal: 12, overflow: 'hidden', backgroundColor: 'transparent' }}>
<Text variant='text-sm/medium' color='text-danger' style={{ marginBottom: 16 }}>Some assets types cannot be displayed and will be marked in red.</Text>
<FlatList
data={Object.values(assetsMap).filter(a => a.name.includes(search) || a.id.toString() === search)}
data={all.filter(a => a.name.includes(search) || a.id.toString() === search)}
renderItem={({ item }: any) => <AssetDisplay asset={item} />}
contentContainerStyle={{ overflow: 'hidden', backgroundColor: 'transparent', borderRadius: 16 }}
keyExtractor={a => a.name}
/>
</View>
</View>
Expand Down
10 changes: 5 additions & 5 deletions src/core/ui/settings/pages/Developer/AssetDisplay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ export default function AssetDisplay({ asset }: AssetDisplayProps) {
<TableRow
variant={displayable.has(asset.type) ? 'default' : 'danger'}
label={asset.name}
subLabel={`Index: ${asset.index} Type: ${asset.type}`}
subLabel={`Index: ${asset.id} Type: ${asset.type}`}
icon={
displayable.has(asset.type)
? <Image source={asset.index} style={{ width: 32, height: 32 }} />
? <Image source={asset.id} style={{ width: 32, height: 32 }} />
: <TableRow.Icon
variant='danger'
source={findAssetId(asset.type in iconMap ? iconMap[asset.type as keyof typeof iconMap] : iconMap.default)}
Expand All @@ -39,18 +39,18 @@ export default function AssetDisplay({ asset }: AssetDisplayProps) {
onPress={() =>
openAlert("revenge-asset-display-details", <AlertModal
title={asset.name}
content={`Index: ${asset.index}\nModule ID: ${asset.moduleId}\nType: ${asset.type}`}
content={`Index: ${asset.id}\nModule ID: ${asset.moduleId}\nType: ${asset.type}`}
extraContent={
displayable.has(asset.type)
? <Image resizeMode="contain" source={asset.index} style={{ flex: 1, width: 'auto', height: 192 }} />
? <Image resizeMode="contain" source={asset.id} style={{ flex: 1, width: 'auto', height: 192 }} />
: (<Text variant='text-sm/medium' color="text-danger" style={{ width: '100%', textAlign: 'center' }}>
Asset type {asset.type.toUpperCase()} is not supported for preview.
</Text>)
}
actions={
<Stack>
<AlertActionButton text="Copy asset name" variant="primary" onPress={() => copyToClipboard(asset.name)} />
<AlertActionButton text="Copy asset index" variant="secondary" onPress={() => copyToClipboard(asset.index.toString())} />
<AlertActionButton text="Copy asset index" variant="secondary" onPress={() => copyToClipboard(asset.id.toString())} />
</Stack>
}
/>)
Expand Down
2 changes: 1 addition & 1 deletion src/core/ui/settings/pages/Developer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ export default function Developer() {
label={Strings.ENABLE_EVAL_COMMAND}
subLabel={Strings.ENABLE_EVAL_COMMAND_DESC}
icon={<TableRow.Icon source={findAssetId("PencilIcon")} />}
value={settings.enableEvalCommand}
value={!!settings.enableEvalCommand}
onValueChange={(v: boolean) => {
settings.enableEvalCommand = v;
}}
Expand Down
Loading

0 comments on commit 050a72b

Please sign in to comment.