From 395e1e9ef93ecb3c31b1ef7e67699baf4d0cf5e2 Mon Sep 17 00:00:00 2001 From: PalmDevs Date: Fri, 27 Dec 2024 02:01:12 +0700 Subject: [PATCH] chore: merge `upstream/main` to `dev` --- .github/ISSUE_TEMPLATE/bug-report.yml | 191 +++++++++ .github/ISSUE_TEMPLATE/config.yml | 4 + .github/ISSUE_TEMPLATE/feature-request.yml | 43 ++ .github/workflows/build.yml | 53 +++ scripts/build.mjs | 1 + scripts/serve.mjs | 2 +- src/core/debug/safeMode.ts | 17 + src/core/ui/components/AddonPage.tsx | 71 ++-- src/core/ui/hooks/useFS.ts | 2 +- .../components/ErrorBoundaryScreen.tsx | 38 +- .../settings/pages/Developer/AssetBrowser.tsx | 7 +- .../settings/pages/Developer/AssetDisplay.tsx | 10 +- .../ui/settings/pages/Developer/index.tsx | 2 +- src/core/ui/settings/pages/General/About.tsx | 23 +- .../ui/settings/pages/General/Version.tsx | 5 +- src/core/ui/settings/pages/General/index.tsx | 53 ++- .../ui/settings/pages/PluginBrowser/index.tsx | 194 ++++++--- .../pages/Plugins/components/PluginCard.tsx | 38 +- src/core/ui/settings/pages/Plugins/index.tsx | 34 +- .../ui/settings/pages/Plugins/models/bunny.ts | 33 +- .../ui/settings/pages/Plugins/models/index.ts | 23 ++ .../settings/pages/Plugins/models/vendetta.ts | 5 +- .../Plugins/sheets/PluginInfoActionSheet.tsx | 117 ++++-- .../pages/Plugins/sheets/TitleComponent.tsx | 57 +++ .../sheets/VdPluginInfoActionSheet.tsx | 10 +- .../settings/pages/Plugins/sheets/common.ts | 2 +- .../pages/Plugins/usePluginCardStyles.ts | 12 + .../ui/settings/pages/Themes/ThemeCard.tsx | 7 +- src/core/ui/settings/pages/Themes/index.tsx | 50 ++- src/core/vendetta/api.tsx | 21 +- src/core/vendetta/storage.ts | 48 ++- src/index.ts | 21 +- src/lib/addons/plugins/api.ts | 11 +- src/lib/addons/plugins/index.ts | 54 ++- src/lib/addons/plugins/types.ts | 32 +- src/lib/addons/themes/colors/index.ts | 19 + src/lib/addons/themes/colors/parser.ts | 138 +++++++ .../themes/colors/patches/background.tsx | 51 +++ .../addons/themes/colors/patches/resolver.ts | 89 ++++ .../addons/themes/colors/patches/storage.ts | 38 ++ src/lib/addons/themes/colors/preferences.ts | 18 + src/lib/addons/themes/colors/types.ts | 52 +++ src/lib/addons/themes/colors/updater.ts | 59 +++ src/lib/addons/themes/index.ts | 382 +++--------------- src/lib/addons/types.ts | 19 +- src/lib/api/assets.ts | 95 ----- src/lib/api/assets/index.ts | 79 ++++ src/lib/api/assets/patches.ts | 25 ++ src/lib/api/debug.ts | 16 +- src/lib/api/native/fs.ts | 22 +- src/lib/api/native/loader.ts | 4 +- src/lib/api/native/modules/index.ts | 12 +- src/lib/api/storage/index.ts | 4 +- src/lib/ui/alerts.ts | 4 + src/lib/ui/color.ts | 5 +- src/lib/ui/components/Search.tsx | 2 +- src/lib/ui/index.ts | 1 + src/lib/ui/settings/patches/tabs.tsx | 4 +- src/lib/ui/styles.ts | 4 +- src/lib/ui/types.ts | 3 +- src/lib/utils/types.ts | 1 + src/metro/common/components.ts | 32 +- src/metro/common/index.ts | 6 +- src/metro/common/stores.ts | 3 + src/metro/common/types/components.ts | 111 ++++- src/metro/finders.ts | 1 + src/metro/internals/caches.ts | 44 +- src/metro/internals/enums.ts | 3 +- src/metro/internals/modules.ts | 15 +- src/metro/types.ts | 2 +- src/metro/wrappers.ts | 4 +- 71 files changed, 1839 insertions(+), 819 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/bug-report.yml create mode 100644 .github/ISSUE_TEMPLATE/feature-request.yml create mode 100644 .github/workflows/build.yml create mode 100644 src/core/debug/safeMode.ts create mode 100644 src/core/ui/settings/pages/Plugins/models/index.ts create mode 100644 src/core/ui/settings/pages/Plugins/sheets/TitleComponent.tsx create mode 100644 src/lib/addons/themes/colors/index.ts create mode 100644 src/lib/addons/themes/colors/parser.ts create mode 100644 src/lib/addons/themes/colors/patches/background.tsx create mode 100644 src/lib/addons/themes/colors/patches/resolver.ts create mode 100644 src/lib/addons/themes/colors/patches/storage.ts create mode 100644 src/lib/addons/themes/colors/preferences.ts create mode 100644 src/lib/addons/themes/colors/types.ts create mode 100644 src/lib/addons/themes/colors/updater.ts delete mode 100644 src/lib/api/assets.ts create mode 100644 src/lib/api/assets/index.ts create mode 100644 src/lib/api/assets/patches.ts create mode 100644 src/lib/ui/alerts.ts create mode 100644 src/lib/utils/types.ts create mode 100644 src/metro/common/stores.ts diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml new file mode 100644 index 0000000..cb92112 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -0,0 +1,191 @@ +name: Bug report +description: Create a bug report to help us improve +title: "[bug]: " +labels: [bug] +body: + - type: markdown + attributes: + value: | + > [!IMPORTANT] + > ## Before you submit this issue... + > We might reject any issues that can't be solved within the repository, or reports that are too general. For example: + > + >
+ > "Bunny crashes upon starting..." + > > There are lots of different things that could be causing this, but it's probably not related to this repository. + >
+ >
+ > "Bunny freezes on splash screen..." + > > The issue is too general and should be reported only when it occurs after an update to a specific Discord version or after a specific action or configuration has been made within Bunny. + >
+ >
+ > "Bunny refuses to install/stuck on downloading..." + > > This is an external issue (sideloading) that does not have a place in this repository. If it's a problem with Bunny Manager, report it to the appropriate repository. + >
+ > + > If you think that your problem belongs to one of these, you should avoid submitting this report unless you are told to do so. + > + > Please report the problem or ask for help in the appropriate place. For example, if the problem occurs in BunnyManager, report it in the BunnyManager repository. If an error occurs when trying to sideload the prepatched IPA, reach out support for the sideloader you're using. + + - type: checkboxes + id: checklist + attributes: + label: Checklist + description: You should ensure the completion of the task before proceeding to check it off the checklist. Neglecting to do so may impede the efficiency of the issue resolution process. The developer has the right to delete the issue directly if you check the list blindly. + options: + - label: I am able to reproduce the bug with the latest version of Bunny and Discord. + required: true + - label: I've checked that there is no open or closed issue about this bug. + required: true + - label: The title of this issue accurately describes the bug. + required: true + - label: This is not a feature request or a general question. + required: true + - label: This bug can be reproduced consistently and is not caused by a plugin. + required: true + - label: I have read the notes above and ensured that my issue is clear and within this repository. + required: true + + - type: textarea + id: reproduce-steps + attributes: + label: Steps to reproduce the bug + description: What did you do for the bug to show up? + placeholder: | + Example: + 1. Go to '...' + 2. Click on '....' + 3. Scroll down to '....' + 4. See error + validations: + required: true + + - type: textarea + id: expected-behavior + attributes: + label: Expected behavior + placeholder: | + Example: + "This should happen..." + validations: + required: true + + - type: textarea + id: actual-behavior + attributes: + label: Actual behavior + placeholder: | + Example: + "This happened instead..." + validations: + required: true + + - type: textarea + id: sreen-media + attributes: + label: Screenshots/Screen recordings + description: | + A picture or video helps us understand the bug more. + + You can upload them directly in the text box. + + - type: textarea + id: logs + attributes: + label: Logs + description: | + Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. + render: shell + + - type: dropdown + id: platform + attributes: + label: What platform did you produce this issue on? + options: + - Android + - iOS + validations: + required: true + + - type: input + id: discord-version + attributes: + label: Discord version + description: | + The version of Discord you are using. You can find this in the settings. You may leave both the version number and the build number. + placeholder: | + Example: + "253.2 (66074)" + validations: + required: true + + - type: input + id: version + attributes: + label: Version + description: | + The version of Bunny the issue is occuring on. You can find this in the settings. Bunny version is in formatted like the following: `beaf689-main` and NOT like this: `0.2.3`. + placeholder: | + Example: + "beaf689-main" + + - type: input + id: loader-version + attributes: + label: Loader version + description: | + The version of the loader you are using. You can find this in the settings. + placeholder: | + Example: + "BunnyTweak (0.3.2)" + validations: + required: true + + - type: input + id: device + attributes: + label: Device + description: | + The device model you are using. + placeholder: | + Example: + "iPhone 13 Pro Max" + validations: + required: true + + - type: input + id: os-version + attributes: + label: OS version + description: | + The version of the operating system you are using. + placeholder: | + Example: + "iOS 15.0.1" + validations: + required: true + + - type: textarea + id: debug-info + attributes: + label: Debug information + description: | + Debug information is important for the developer to understand the environment in which the bug occurred. You can get this information by sending `/debug` in the chat. + placeholder: | + Example: + Bunny: beaf689-main (BunnyXposed 0.2.4) + Discord: 255.2 (255202) + React: 18.3.1 (RN 0.74.5-discord-11) + Hermes: for RN 0.74.5-discord-11 (bcv96) + System: Android 13 (SDK 33) + Device: M2101K7BG (secret) + + - type: textarea + id: additional-information + attributes: + label: Additional information + placeholder: | + Example: + "I have tried to do this..." + "This only happens in this situation..." + "This could be related to..." \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index a5d6ffa..8e5577e 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,5 +1,9 @@ +<<<<<<< HEAD blank_issues_enabled: false contact_links: - name: 🗨 Discussions url: https://discord.gg/ddcQf3s2Uq about: Have something unspecific to Revenge in mind? Join us on Discord! +======= +blank_issues_enabled: false +>>>>>>> upstream/main diff --git a/.github/ISSUE_TEMPLATE/feature-request.yml b/.github/ISSUE_TEMPLATE/feature-request.yml new file mode 100644 index 0000000..ff169a7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request.yml @@ -0,0 +1,43 @@ +name: Feature request +description: Suggest an idea for Bunny +title: "[feature]: " +labels: [enhancement] +body: + - type: checkboxes + id: checklist + attributes: + label: Checklist + description: You should ensure the completion of the task before proceeding to check it off the checklist. Neglecting to do so may impede the efficiency of the issue resolution process. The developer has the right to delete the issue directly if you check the list blindly. + options: + - label: This is not a plugin request. + required: true + - label: I've checked that there is no other issue about this feature request. + required: true + - label: This issue contains only one feature request. + required: true + - label: The title of this issue accurately describes the feature request. + required: true + + - type: textarea + id: feature-description + attributes: + label: Feature description + description: What feature you want Bunny to have? Provide detailed description about what it should look like or where it should be added. + validations: + required: true + + - type: textarea + id: why-is-the-feature-requested + attributes: + label: Why do you want this feature? + description: Describe the problem or limitation that motivates you to want this feature to be added. + validations: + required: true + + - type: textarea + id: additional-information + attributes: + label: Additional information + description: Add any other context or screenshots about the feature request here. + placeholder: | + Additional details and attachments. \ No newline at end of file diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..0e66bfc --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,53 @@ +name: Build +on: + push: + branches: [main, dev] + paths-ignore: + - "**/*.md" + +jobs: + build: + name: Build and push + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Checkout builds + uses: actions/checkout@v4 + with: + repository: "bunny-mod/builds" + path: "builds" + token: ${{ secrets.BUILDS_TOKEN }} + ref: ${{ github.ref_name }} + + - uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: Install pnpm and dependencies + run: | + npm i -g pnpm + pnpm i\ + + - name: Build + run: pnpm build --release-branch=${{ github.ref_name }} --build-minify + + # TODO: Check for linting? + + - name: Push builds + run: | + rm $GITHUB_WORKSPACE/builds/* || true + cp -r dist/* $GITHUB_WORKSPACE/builds || true + cd $GITHUB_WORKSPACE/builds + git config --local user.email "actions@github.com" + git config --local user.name "GitHub Actions" + git add . + git commit -m "Build $GITHUB_SHA" || exit 0 + git push + + - name: Purge CDN cache + run: | + curl https://purge.jsdelivr.net/gh/pyoncord/bunny-build-infos@${{ github.ref_name }}/bunny.js + 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 f5cfa50..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 occurred while rendering a component. This could be caused by a plugin, Revenge, 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} - - -