From 241ffd5b5130e48d3bbe5680536646fe80285df2 Mon Sep 17 00:00:00 2001 From: cocobo1 Date: Tue, 4 Nov 2025 18:04:39 +0100 Subject: [PATCH 01/16] readme: update platforms --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 116de2d..633cb8b 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # Kettu -A mod for Discord on Android +A mod for Discord on Mobile ### [![Discord](https://img.shields.io/discord/1368145952266911755?logo=discord&logoColor=%23ffffffff&color=%231D88CF&link=https%3A%2F%2Fdiscord.gg%2F6cN7wKa8gp)](https://discord.gg/6cN7wKa8gp) [![Static Badge](https://img.shields.io/badge/kofi-cocobo1-%23FF6433?style=flat&logo=ko-fi&labelColor=%23ffffff)](https://www.ko-fi.com/cocobo1) ![Codeberg Last Commit](https://img.shields.io/gitea/last-commit/cocobo1/Kettu?gitea_url=https%3A%2F%2Fwww.codeberg.org&logo=codeberg&logoColor=%23ffffffff) From 4392b81822ef123a7a51a4d81a9dd7f0fc2e18eb Mon Sep 17 00:00:00 2001 From: cocobo1 Date: Fri, 14 Nov 2025 19:57:56 +0200 Subject: [PATCH 02/16] fix(settings): make settings not appear in EVERY menu --- src/lib/ui/settings/patches/tabs.tsx | 41 ++++++++++++++++------------ 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/src/lib/ui/settings/patches/tabs.tsx b/src/lib/ui/settings/patches/tabs.tsx index 5d9c029..9623034 100644 --- a/src/lib/ui/settings/patches/tabs.tsx +++ b/src/lib/ui/settings/patches/tabs.tsx @@ -80,27 +80,34 @@ export function patchTabsUI(unpatches: (() => void | boolean)[]) { }); try{ - unpatches.push(after("createList", createListModule, function(args, ret) { - const [config] = args; + unpatches.push(after("createList", createListModule, function(args, ret) { + const [config] = args; - if (config?.sections && Array.isArray(config.sections)) { - const sections = config.sections; - // Credit to @palmdevs - https://discord.com/channels/1196075698301968455/1243605828783571024/1307940348378742816 - let index = -~sections.findIndex((i: any) => i.settings?.includes("ACCOUNT")) || 1; + if (config?.sections && Array.isArray(config.sections)) { + const sections = config.sections; + + const accountSectionIndex = sections.findIndex((i: any) => i.settings?.includes("ACCOUNT")); + + if (accountSectionIndex !== -1) { + // Credit to @palmdevs - https://discord.com/channels/1196075698301968455/1243605828783571024/1307940348378742816 - Object.keys(registeredSections).forEach(sect => { - const alreadyExists = sections.some((s: any) => s.label === sect); - if (!alreadyExists) { - sections.splice(index++, 0, { - label: sect, - title: sect, - settings: registeredSections[sect].map(a => a.key) + let index = accountSectionIndex + 1; + + Object.keys(registeredSections).forEach(sect => { + const alreadyExists = sections.some((s: any) => s.label === sect); + if (!alreadyExists) { + sections.splice(index++, 0, { + label: sect, + title: sect, + settings: registeredSections[sect].map(a => a.key) + }); + } }); } - }); - } - return ret; - },)); + } + return ret; + },)); + }catch{ unpatches.push(after("default", SettingsOverviewScreen, (_, ret) => { if (useIsFirstRender()) return; // :shrug: From 0bfc83b4d97f2b26c579889d88e3816de1bcb41b Mon Sep 17 00:00:00 2001 From: cocobo1 Date: Fri, 14 Nov 2025 22:35:29 +0200 Subject: [PATCH 03/16] block(plugins): block plugins that violate TOS --- src/core/vendetta/plugins.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/vendetta/plugins.ts b/src/core/vendetta/plugins.ts index f95f0f2..aa72a90 100644 --- a/src/core/vendetta/plugins.ts +++ b/src/core/vendetta/plugins.ts @@ -110,7 +110,7 @@ export const VdPluginManager = { async startPlugin(id: string) { if (!id.endsWith("/")) id += "/"; const plugin = plugins[id]; - if (plugin.id.includes("heartdevv") == true || plugin.id.includes("helloworldsmother") == true || plugin.id.includes("messaging") == true) { + if (plugin.id.includes("xxjust") == true || plugin.id.includes("DevNjay") == true) { return } if (!plugin) throw new Error("Attempted to start non-existent plugin"); From b7f0a710d3b3675e0efbb18b7b72bc92f3bf0b5d Mon Sep 17 00:00:00 2001 From: Quinx Date: Sun, 16 Nov 2025 11:30:03 +0100 Subject: [PATCH 04/16] Update src/core/ui/settings/index.ts --- src/core/ui/settings/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/ui/settings/index.ts b/src/core/ui/settings/index.ts index 020a79f..494e9cd 100644 --- a/src/core/ui/settings/index.ts +++ b/src/core/ui/settings/index.ts @@ -37,7 +37,7 @@ export default function initSettings() { { key: "BUNNY_FONTS", title: () => Strings.FONTS, - icon: findAssetId("ic_add_text"), + icon: findAssetId("LettersIcon"), render: () => import("@core/ui/settings/pages/Fonts"), usePredicate: () => isFontSupported() }, From f79e6936ba17291f6b2cbf2a9fcad74cb084ba7c Mon Sep 17 00:00:00 2001 From: Quinx Date: Sun, 16 Nov 2025 11:45:05 +0100 Subject: [PATCH 05/16] Update src/core/ui/components/AddonPage.tsx --- src/core/ui/components/AddonPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/ui/components/AddonPage.tsx b/src/core/ui/components/AddonPage.tsx index 8d624a5..35a5dcc 100644 --- a/src/core/ui/components/AddonPage.tsx +++ b/src/core/ui/components/AddonPage.tsx @@ -175,7 +175,7 @@ export default function AddonPage({ CardComponent, ...props }: setSearch(v)} /> {props.sortOptions && showSimpleActionSheet({ From 01b36e797876ae10de30ac274d91c83b42d8daab Mon Sep 17 00:00:00 2001 From: cocobo1 Date: Sun, 16 Nov 2025 19:40:27 +0200 Subject: [PATCH 06/16] fix(statusbar): make the statusbar work on ios + greatly improve loadtimes --- src/lib/addons/plugins/types.ts | 1 - src/lib/addons/themes/colors/statusbar.ts | 21 ++++++--------------- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/src/lib/addons/plugins/types.ts b/src/lib/addons/plugins/types.ts index 17894ed..0b6baea 100644 --- a/src/lib/addons/plugins/types.ts +++ b/src/lib/addons/plugins/types.ts @@ -24,7 +24,6 @@ export interface PluginSettingsStorage { } export interface BunnyPluginManifest extends BunnyManifest { - name: string; readonly type: "plugin"; readonly spec: 3; readonly main: string; diff --git a/src/lib/addons/themes/colors/statusbar.ts b/src/lib/addons/themes/colors/statusbar.ts index f57c5f7..3f5f655 100644 --- a/src/lib/addons/themes/colors/statusbar.ts +++ b/src/lib/addons/themes/colors/statusbar.ts @@ -29,29 +29,20 @@ function getBarStyle() { } export default function fixStatusBar() { - + const origSetBarStyle = StatusBar.setBarStyle; if (Platform.OS == "android") { - const origSetBarStyle = StatusBar.setBarStyle; StatusBar.setBarStyle = function (_style: any, ...args: any[]) { return origSetBarStyle.call(this, getBarStyle(), ...args); }; } - - if (Platform.OS == "ios") { + + if (Platform.OS === "ios") { function applyStatusBar() { const style = getBarStyle(); - StatusBar.setBarStyle(style, true); + origSetBarStyle.call(StatusBar, style, true); } - - const unsubscribe = ThemeStore?.addChangeListener?.(applyStatusBar); - StatusBar.setBarStyle(getBarStyle()); - - let delay = 200; - for (let i = 0; i < 5; i++, delay *= 2) { - setTimeout(applyStatusBar, delay); - } - - return unsubscribe; + applyStatusBar(); + setInterval(applyStatusBar, 500); } } \ No newline at end of file From f5ddffdd7babdfa18215e9beed33c323ec471a05 Mon Sep 17 00:00:00 2001 From: cocobo1 Date: Sun, 16 Nov 2025 19:56:05 +0200 Subject: [PATCH 07/16] feat(speedup): massively speedup launch times --- scripts/build.mjs | 2 +- src/entry.ts | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/build.mjs b/scripts/build.mjs index 4c16f2e..899ab6b 100644 --- a/scripts/build.mjs +++ b/scripts/build.mjs @@ -74,7 +74,7 @@ const config = { constModules: { globals: { "bunny-build-info": { - version: `"v1.3.7"` + version: `"v1.4.0-alpha"` } } }, diff --git a/src/entry.ts b/src/entry.ts index c0f7e4a..5e67916 100644 --- a/src/entry.ts +++ b/src/entry.ts @@ -11,7 +11,8 @@ async function initializeKettu() { Object.freeze = Object.seal = Object; await require("@metro/internals/caches").initMetroCache(); - await require(".").default(); + // "savage" approach of just nuking the await, but the speedup could be amazing + require(".").default(); } catch (e) { const { ClientInfoManager } = require("@lib/api/native/modules"); const stack = e instanceof Error ? e.stack : undefined; From 85af53e537789e3fab6d1a60f41e471fe31f5f74 Mon Sep 17 00:00:00 2001 From: cocobo1 Date: Mon, 17 Nov 2025 14:28:28 +0200 Subject: [PATCH 08/16] fix(fonts): remove font previews to fix crashes --- scripts/build.mjs | 2 +- shims/depsModule.ts | 1 - src/core/ui/settings/pages/Fonts/FontCard.tsx | 45 ------------------- src/entry.ts | 1 - 4 files changed, 1 insertion(+), 48 deletions(-) diff --git a/scripts/build.mjs b/scripts/build.mjs index 899ab6b..5574a91 100644 --- a/scripts/build.mjs +++ b/scripts/build.mjs @@ -74,7 +74,7 @@ const config = { constModules: { globals: { "bunny-build-info": { - version: `"v1.4.0-alpha"` + version: `"v1.3.8"` } } }, diff --git a/shims/depsModule.ts b/shims/depsModule.ts index 8df1d12..cccc4d5 100644 --- a/shims/depsModule.ts +++ b/shims/depsModule.ts @@ -7,5 +7,4 @@ module.exports = { "moment": findByPropsLazy("isMoment"), "chroma-js": findByPropsLazy("brewer"), "lodash": findByPropsLazy("forEachRight"), - "@shopify/react-native-skia": findByPropsLazy("useFont") }; diff --git a/src/core/ui/settings/pages/Fonts/FontCard.tsx b/src/core/ui/settings/pages/Fonts/FontCard.tsx index bc350b8..dec6441 100644 --- a/src/core/ui/settings/pages/Fonts/FontCard.tsx +++ b/src/core/ui/settings/pages/Fonts/FontCard.tsx @@ -9,56 +9,12 @@ import { lazyDestructure } from "@lib/utils/lazy"; import { findByProps } from "@metro"; import { NavigationNative, tokens } from "@metro/common"; import { Button, Card, IconButton, Stack, Text } from "@metro/common/components"; -import * as Skia from "@shopify/react-native-skia"; -import { TextStyleSheet } from "@ui/styles"; -import { useMemo } from "react"; import { View } from "react-native"; import FontEditor from "./FontEditor"; const { useToken } = lazyDestructure(() => findByProps("useToken")); -function FontPreview({ font }: { font: FontDefinition; }) { - const TEXT_NORMAL = useToken(tokens.colors.TEXT_NORMAL); - const { fontFamily: fontFamilyList, fontSize } = TextStyleSheet["text-md/medium"]; - const fontFamily = fontFamilyList!.split(/,/g)[0]; - - const typeface = Skia.useFont(font.main[fontFamily])?.getTypeface(); - - const paragraph = useMemo(() => { - if (!typeface) return null; - - const fMgr = SkiaApi.TypefaceFontProvider.Make(); - fMgr.registerFont(typeface, fontFamily); - - - return SkiaApi.ParagraphBuilder.Make({}, fMgr) - .pushStyle({ - color: SkiaApi.Color(TEXT_NORMAL), - fontFamilies: [fontFamily], - fontSize, - }) - .addText("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.") - .pop() - .build(); - }, [typeface]); - - return ( - // This does not work, actually :woeis: - - {typeface - ? - - - : - - Loading... - - } - - ); -} - export default function FontCard({ item: font }: CardWrapper) { useProxy(fonts); @@ -111,7 +67,6 @@ export default function FontCard({ item: font }: CardWrapper) { - ); diff --git a/src/entry.ts b/src/entry.ts index 5e67916..5202d28 100644 --- a/src/entry.ts +++ b/src/entry.ts @@ -11,7 +11,6 @@ async function initializeKettu() { Object.freeze = Object.seal = Object; await require("@metro/internals/caches").initMetroCache(); - // "savage" approach of just nuking the await, but the speedup could be amazing require(".").default(); } catch (e) { const { ClientInfoManager } = require("@lib/api/native/modules"); From b678d6c602481bacd35bbcba9c73fc5df501fc9c Mon Sep 17 00:00:00 2001 From: Bwlok Date: Mon, 24 Nov 2025 00:37:21 +0100 Subject: [PATCH 09/16] Fix missing text for ios --- src/core/i18n/default.json | 1 + src/core/ui/settings/pages/General/About.tsx | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/core/i18n/default.json b/src/core/i18n/default.json index 3ab3350..15268af 100644 --- a/src/core/i18n/default.json +++ b/src/core/i18n/default.json @@ -78,6 +78,7 @@ "MODAL_UNPROXIED_PLUGIN_DESC": "The plugin you are trying to install has not been proxied/verified by staff. Are you sure you want to continue?", "MODAL_UNPROXIED_PLUGIN_HEADER": "Unproxied Plugin", "MODEL": "Model", + "MODELID": "Model Identifier", "OPEN_IN_BROWSER": "Open in Browser", "OPERATING_SYSTEM": "Operating System", "OVERFLOW_PLUGIN_SETTINGS": "Plugin Settings", diff --git a/src/core/ui/settings/pages/General/About.tsx b/src/core/ui/settings/pages/General/About.tsx index 94f7135..15378b7 100644 --- a/src/core/ui/settings/pages/General/About.tsx +++ b/src/core/ui/settings/pages/General/About.tsx @@ -60,18 +60,18 @@ export default function About() { version: debugInfo.device.manufacturer, icon: "WrenchIcon" }, - { + ...(Platform.OS !== "ios" ? [{ label: Strings.BRAND, version: debugInfo.device.brand, icon: "MagicWandIcon" - }, + }] : []), { label: Strings.MODEL, version: debugInfo.device.model, icon: "MobilePhoneIcon" }, { - label: Platform.select({ android: Strings.CODENAME })!, + label: Platform.select({ android: Strings.CODENAME, ios: Strings.MODELID })!, version: debugInfo.device.codename, icon: "TagIcon" } From ee81cf5be51efa691d2a1ed407a5a45ccbed4fa7 Mon Sep 17 00:00:00 2001 From: cocobo1 Date: Mon, 24 Nov 2025 12:52:30 +0200 Subject: [PATCH 10/16] fix(themes): correct themes loading on v307.5+ --- bun.lock | 11 ---- package.json | 1 - src/index.ts | 5 +- src/lib/addons/themes/colors/index.ts | 11 +--- src/lib/addons/themes/colors/keyboard.ts | 64 ------------------- .../addons/themes/colors/patches/resolver.ts | 20 ------ src/lib/addons/themes/colors/statusbar.ts | 48 -------------- 7 files changed, 5 insertions(+), 155 deletions(-) delete mode 100644 src/lib/addons/themes/colors/keyboard.ts delete mode 100644 src/lib/addons/themes/colors/statusbar.ts diff --git a/bun.lock b/bun.lock index 37e6667..c8be63b 100644 --- a/bun.lock +++ b/bun.lock @@ -5,7 +5,6 @@ "name": "Kettu", "dependencies": { "@gullerya/object-observer": "^6.1.4", - "@shopify/react-native-skia": "^1.12.4", "@tanstack/react-query": "^5.83.0", "@types/chroma-js": "~2.4.5", "@types/lodash": "~4.17.20", @@ -473,8 +472,6 @@ "@semantic-release/release-notes-generator": ["@semantic-release/release-notes-generator@14.0.3", "", { "dependencies": { "conventional-changelog-angular": "^8.0.0", "conventional-changelog-writer": "^8.0.0", "conventional-commits-filter": "^5.0.0", "conventional-commits-parser": "^6.0.0", "debug": "^4.0.0", "get-stream": "^7.0.0", "import-from-esm": "^2.0.0", "into-stream": "^7.0.0", "lodash-es": "^4.17.21", "read-package-up": "^11.0.0" }, "peerDependencies": { "semantic-release": ">=20.1.0" } }, "sha512-XxAZRPWGwO5JwJtS83bRdoIhCiYIx8Vhr+u231pQAsdFIAbm19rSVJLdnBN+Avvk7CKvNQE/nJ4y7uqKH6WTiw=="], - "@shopify/react-native-skia": ["@shopify/react-native-skia@1.12.4", "", { "dependencies": { "canvaskit-wasm": "0.40.0", "react-reconciler": "0.27.0" }, "peerDependencies": { "react": ">=18.0 <19.0.0", "react-native": ">=0.64 <0.78.0", "react-native-reanimated": ">=2.0.0" }, "optionalPeers": ["react-native", "react-native-reanimated"], "bin": { "setup-skia-web": "scripts/setup-canvaskit.js" } }, "sha512-8QDIBKSU7XB3Lc1kAv4jSFddTQK8AE+1AEoJnQLNllsiex1gufLQ8kN7rs9zii+iboSY8tYKT7ocV+5cE2Exdw=="], - "@sinclair/typebox": ["@sinclair/typebox@0.27.8", "", {}, "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA=="], "@sindresorhus/is": ["@sindresorhus/is@4.6.0", "", {}, "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw=="], @@ -569,8 +566,6 @@ "@ungap/structured-clone": ["@ungap/structured-clone@1.3.0", "", {}, "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g=="], - "@webgpu/types": ["@webgpu/types@0.1.21", "", {}, "sha512-pUrWq3V5PiSGFLeLxoGqReTZmiiXwY3jRkIG5sLLKjyqNxrwm/04b4nw7LSmGWJcKk59XOM/YRTUwOzo4MMlow=="], - "JSONStream": ["JSONStream@1.3.5", "", { "dependencies": { "jsonparse": "^1.2.0", "through": ">=2.2.7 <3" }, "bin": { "JSONStream": "./bin.js" } }, "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ=="], "abort-controller": ["abort-controller@3.0.0", "", { "dependencies": { "event-target-shim": "^5.0.0" } }, "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg=="], @@ -685,8 +680,6 @@ "caniuse-lite": ["caniuse-lite@1.0.30001727", "", {}, "sha512-pB68nIHmbN6L/4C6MH1DokyR3bYqFwjaSs/sWDHGj4CTcFtQUQMuJftVwWkXq7mNWOybD3KhUv3oWHoGxgP14Q=="], - "canvaskit-wasm": ["canvaskit-wasm@0.40.0", "", { "dependencies": { "@webgpu/types": "0.1.21" } }, "sha512-Od2o+ZmoEw9PBdN/yCGvzfu0WVqlufBPEWNG452wY7E9aT8RBE+ChpZF526doOlg7zumO4iCS+RAeht4P0Gbpw=="], - "chalk": ["chalk@5.4.1", "", {}, "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w=="], "char-regex": ["char-regex@1.0.2", "", {}, "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw=="], @@ -1413,8 +1406,6 @@ "react-native-reanimated": ["react-native-reanimated@3.19.0", "", { "dependencies": { "@babel/plugin-transform-arrow-functions": "^7.0.0-0", "@babel/plugin-transform-class-properties": "^7.0.0-0", "@babel/plugin-transform-classes": "^7.0.0-0", "@babel/plugin-transform-nullish-coalescing-operator": "^7.0.0-0", "@babel/plugin-transform-optional-chaining": "^7.0.0-0", "@babel/plugin-transform-shorthand-properties": "^7.0.0-0", "@babel/plugin-transform-template-literals": "^7.0.0-0", "@babel/plugin-transform-unicode-regex": "^7.0.0-0", "@babel/preset-typescript": "^7.16.7", "convert-source-map": "^2.0.0", "invariant": "^2.2.4", "react-native-is-edge-to-edge": "1.1.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0", "react": "*", "react-native": "*" } }, "sha512-FNfqLuPuVHsW9KcsZtnJqIPlMQvuySnSFJXgSt9fVDPqptbSUkiAF6MthUwd4Mxt05hCRcbV+T65CENgVS5iCg=="], - "react-reconciler": ["react-reconciler@0.27.0", "", { "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.21.0" }, "peerDependencies": { "react": "^18.0.0" } }, "sha512-HmMDKciQjYmBRGuuhIaKA1ba/7a+UsM5FzOZsMO2JYHt9Jh8reCb7j1eDC95NOyUlKM9KRyvdx0flBuDvYSBoA=="], - "react-refresh": ["react-refresh@0.14.2", "", {}, "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA=="], "read-package-up": ["read-package-up@11.0.0", "", { "dependencies": { "find-up-simple": "^1.0.0", "read-pkg": "^9.0.0", "type-fest": "^4.6.0" } }, "sha512-MbgfoNPANMdb4oRBNg5eqLbB2t2r+o5Ua1pNt8BqGp4I0FJZhuVSOj3PaBPni4azWuSzEdNn2evevzVmEk1ohQ=="], @@ -2219,8 +2210,6 @@ "react-native/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], - "react-reconciler/scheduler": ["scheduler@0.21.0", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-1r87x5fz9MXqswA2ERLo0EbOAU74DpIUO090gIasYTqlVoJeMcl+Z1Rg7WHz+qtPujhS/hGIt9kxZOYBV3faRQ=="], - "read-pkg/parse-json": ["parse-json@8.3.0", "", { "dependencies": { "@babel/code-frame": "^7.26.2", "index-to-position": "^1.1.0", "type-fest": "^4.39.1" } }, "sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ=="], "read-pkg/unicorn-magic": ["unicorn-magic@0.1.0", "", {}, "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ=="], diff --git a/package.json b/package.json index 498be0a..78d95d7 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,6 @@ }, "dependencies": { "@gullerya/object-observer": "^6.1.4", - "@shopify/react-native-skia": "^1.12.4", "@tanstack/react-query": "^5.83.0", "@types/chroma-js": "~2.4.5", "@types/lodash": "~4.17.20", diff --git a/src/index.ts b/src/index.ts index 4d1db27..89aaccf 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,4 @@ -// import patchErrorBoundary from "@core/debug/patches/patchErrorBoundary"; +import patchErrorBoundary from "@core/debug/patches/patchErrorBoundary"; import initFixes from "@core/fixes"; import { initFetchI18nStrings } from "@core/i18n"; import initSettings from "@core/ui/settings"; @@ -13,7 +13,6 @@ import { injectFluxInterceptor } from "@lib/api/flux"; import { patchJsx } from "@lib/api/react/jsx"; import { logger } from "@lib/utils/logger"; import { patchSettings } from "@ui/settings"; -import { getDebugInfo } from "@lib/api/debug"; import * as lib from "./lib"; @@ -31,7 +30,7 @@ export default async () => { initFetchI18nStrings(), initSettings(), initFixes(), -// patchErrorBoundary(), + patchErrorBoundary(), updatePlugins(), updateFonts(), initPlugins(), diff --git a/src/lib/addons/themes/colors/index.ts b/src/lib/addons/themes/colors/index.ts index 60a3fc8..1da31dc 100644 --- a/src/lib/addons/themes/colors/index.ts +++ b/src/lib/addons/themes/colors/index.ts @@ -1,5 +1,3 @@ -import fixStatusBar from "./statusbar"; -import fixKeyboard from "./keyboard"; import patchChatBackground from "./patches/background"; import patchDefinitionAndResolver from "./patches/resolver"; import patchStorage from "./patches/storage"; @@ -8,16 +6,13 @@ import { updateBunnyColor } from "./updater"; /** @internal */ export default function initColors(manifest: ColorManifest | null) { + if (manifest) updateBunnyColor(manifest, { update: false }); + const patches = [ patchStorage(), patchDefinitionAndResolver(), patchChatBackground() ]; - fixStatusBar(); - fixKeyboard(); - - if (manifest) updateBunnyColor(manifest, { update: false }); - return () => patches.forEach(p => p()); -} +} \ No newline at end of file diff --git a/src/lib/addons/themes/colors/keyboard.ts b/src/lib/addons/themes/colors/keyboard.ts deleted file mode 100644 index 47d819e..0000000 --- a/src/lib/addons/themes/colors/keyboard.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { TextInput, Platform, NativeModules } from "react-native"; -import { findByStoreNameLazy } from "@metro/wrappers"; -import { _colorRef } from "./updater"; - -const ThemeStore = findByStoreNameLazy("ThemeStore"); - -function getKeyboardAppearance() { - // Check for custom theme - const custom = _colorRef.current; - if (custom) { - // Bunny theme (spec 3) - if (custom.spec === 3 && custom.reference) { - return custom.reference === "light" ? "light" : "dark"; - } - // Vendetta theme (spec 2) - if (custom.spec === 2 && custom.reference) { - return custom.reference === "light" ? "light" : "dark"; - } - } - - // Fallback to Discord theme string - const theme = ThemeStore?.theme; - if (typeof theme === "string") { - const lowerTheme = theme.toLowerCase(); - return (lowerTheme.includes("dark") || lowerTheme.includes("midnight")) - ? "dark" - : "light"; - } - - return "dark"; -} - -export default function fixKeyboard() { - if (Platform.OS !== "ios") return; - - const UIManager = NativeModules.UIManager; - - const origUpdateView = UIManager?.updateView; - const origCreateView = UIManager?.createView; - - if (origUpdateView) { - UIManager.updateView = function(viewTag: number, viewName: string, props: any) { - if (props && typeof props === 'object') { - if (viewName.toLowerCase().includes('text') || viewName.toLowerCase().includes('input')) { - props.keyboardAppearance = getKeyboardAppearance(); - } - } - return origUpdateView.call(this, viewTag, viewName, props); - }; - } - - if (origCreateView) { - UIManager.createView = function(reactTag: number, viewName: string, rootTag: number, props: any) { - if (props && typeof props === 'object') { - if (viewName.toLowerCase().includes('text') || viewName.toLowerCase().includes('input')) { - props.keyboardAppearance = getKeyboardAppearance(); - } - } - return origCreateView.call(this, reactTag, viewName, rootTag, props); - }; - } - - return ThemeStore?.addChangeListener?.(() => {}); -} \ No newline at end of file diff --git a/src/lib/addons/themes/colors/patches/resolver.ts b/src/lib/addons/themes/colors/patches/resolver.ts index 08a63b5..c6411f2 100644 --- a/src/lib/addons/themes/colors/patches/resolver.ts +++ b/src/lib/addons/themes/colors/patches/resolver.ts @@ -24,18 +24,6 @@ const SEMANTIC_FALLBACK_MAP: Record = { const origRawColor = { ...tokenReference.RawColor }; -function getRawFallback(key: string): string | undefined { - const isDark = isThemeModule.isThemeDark?.(_colorRef.current?.reference); - - if (!isDark) return undefined; - - const DARK_MODE_RAW_FALLBACK: Record = { - "PRIMARY_230": origRawColor.PLUM_19 || "#000000" - }; - - return DARK_MODE_RAW_FALLBACK[key]; -} - export default function patchDefinitionAndResolver() { const callback = ([theme]: any[]) => theme === _colorRef.key ? [_colorRef.current!.reference] : void 0; @@ -47,9 +35,6 @@ export default function patchDefinitionAndResolver() { const ret = _colorRef.current?.raw[key]; if (ret) return ret; - const fallback = getRawFallback(key); - if (fallback) return fallback; - return origRawColor[key]; } }); @@ -83,11 +68,6 @@ export default function patchDefinitionAndResolver() { return colorDef.opacity === 1 ? rawValue : chroma(rawValue).alpha(colorDef.opacity).hex(); } - const fallbackValue = getRawFallback(colorDef.raw); - if (fallbackValue) { - return colorDef.opacity === 0 ? fallbackValue : chroma(fallbackValue).alpha(colorDef.opacity).hex(); - } - // Fallback to default return orig(...args); }), diff --git a/src/lib/addons/themes/colors/statusbar.ts b/src/lib/addons/themes/colors/statusbar.ts deleted file mode 100644 index 3f5f655..0000000 --- a/src/lib/addons/themes/colors/statusbar.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { StatusBar, TextInput, Platform } from "react-native"; -import { findByStoreNameLazy } from "@metro/wrappers"; -import { _colorRef } from "./updater"; - -const ThemeStore = findByStoreNameLazy("ThemeStore"); - -function getBarStyle() { - // Check for custom theme - const custom = _colorRef.current; - if (custom) { - // Bunny theme (spec 3) - if (custom.spec === 3 && custom.reference) { - return custom.reference === "light" ? "dark-content" : "light-content"; - } - // Vendetta theme (spec 2) - if (custom.spec === 2 && custom.reference) { - return custom.reference === "light" ? "dark-content" : "light-content"; - } - } - - // Fallback to Discord theme string - const theme = ThemeStore?.theme; - if (typeof theme === "string") { - const lowerTheme = theme.toLowerCase(); - return (lowerTheme.includes("dark") || lowerTheme.includes("midnight")) ? "light-content" : "dark-content"; - } - - return "dark-content"; -} - -export default function fixStatusBar() { - const origSetBarStyle = StatusBar.setBarStyle; - if (Platform.OS == "android") { - StatusBar.setBarStyle = function (_style: any, ...args: any[]) { - return origSetBarStyle.call(this, getBarStyle(), ...args); - }; - } - - if (Platform.OS === "ios") { - function applyStatusBar() { - const style = getBarStyle(); - origSetBarStyle.call(StatusBar, style, true); - } - - applyStatusBar(); - setInterval(applyStatusBar, 500); - } -} \ No newline at end of file From 65fc41e2643a79e620514f03e39f89f474816884 Mon Sep 17 00:00:00 2001 From: cocobo1 Date: Tue, 2 Dec 2025 19:38:51 +0200 Subject: [PATCH 11/16] fix(themes): correct discord interpreting all themes as light --- src/core/i18n/index.ts | 4 +- src/lib/addons/themes/colors/updater.ts | 49 ++++++++++++++++--------- 2 files changed, 33 insertions(+), 20 deletions(-) diff --git a/src/core/i18n/index.ts b/src/core/i18n/index.ts index efeea3b..3ddf999 100644 --- a/src/core/i18n/index.ts +++ b/src/core/i18n/index.ts @@ -44,8 +44,8 @@ export function initFetchI18nStrings() { if (!_loadedLocale.has(resolvedLocale)) { _loadedLocale.add(resolvedLocale); - - fetch(`https://raw.githubusercontent.com/C0C0B01/i18n/main/resources/${resolvedLocale}/kettu.json`) + + fetch(`https://codeberg.org/cocobo1/kettu-i18n/src/branch/main/base/${resolvedLocale}.json`) .then(r => r.json()) .then(strings => _loadedStrings[resolvedLocale] = strings) .then(() => resolvedLocale === _lastSetLocale && (_currentLocale = resolvedLocale)) diff --git a/src/lib/addons/themes/colors/updater.ts b/src/lib/addons/themes/colors/updater.ts index c7b265b..8c3d85b 100644 --- a/src/lib/addons/themes/colors/updater.ts +++ b/src/lib/addons/themes/colors/updater.ts @@ -9,6 +9,7 @@ const origRawColor = { ...tokenRef.RawColor }; const AppearanceManager = findByPropsLazy("updateTheme"); const ThemeStore = findByStoreNameLazy("ThemeStore"); const FormDivider = findByPropsLazy("DIVIDER_COLORS"); +import { colorsPref } from "./preferences"; let _inc = 1; @@ -30,30 +31,42 @@ export const _colorRef: InternalColorRef = { export function updateBunnyColor(colorManifest: ColorManifest | null, { update = true } ) { if (settings.safeMode?.enabled) return; + const resolveType = (type = "dark") => (colorsPref.type ?? type) === "dark" ? "darker" : "light"; const internalDef = colorManifest ? parseColorManifest(colorManifest) : null; - const ref = Object.assign(_colorRef, { - current: internalDef, - key: `bn-theme-${++_inc}`, - lastSetDiscordTheme: !ThemeStore.theme.startsWith("bn-theme-") - ? ThemeStore.theme - : _colorRef.lastSetDiscordTheme - }); - if (internalDef != null) { - tokenRef.Theme[ref.key.toUpperCase()] = ref.key; - FormDivider.DIVIDER_COLORS[ref.key] = FormDivider.DIVIDER_COLORS[ref.current!.reference]; + if (resolveType() == "light" || update) { + var ref = Object.assign(_colorRef, { + current: internalDef, + key: `bn-theme-${++_inc}`, + lastSetDiscordTheme: !ThemeStore.theme.startsWith("bn-theme-") || !ThemeStore.theme.startsWith("darker") + ? ThemeStore.theme + : _colorRef.lastSetDiscordTheme + }); + } else { + var ref = Object.assign(_colorRef, { + current: internalDef, + key: `dark`, + lastSetDiscordTheme: !ThemeStore.theme.startsWith("bn-theme-") || !ThemeStore.theme.startsWith("darker") + ? ThemeStore.theme + : _colorRef.lastSetDiscordTheme + }); + } - Object.keys(tokenRef.Shadow).forEach(k => tokenRef.Shadow[k][ref.key] = tokenRef.Shadow[k][ref.current!.reference]); - Object.keys(tokenRef.SemanticColor).forEach(k => { - tokenRef.SemanticColor[k][ref.key] = { - ...tokenRef.SemanticColor[k][ref.current!.reference] - }; - }); - } + if (internalDef != null) { + tokenRef.Theme[ref.key.toUpperCase()] = ref.key; + FormDivider.DIVIDER_COLORS[ref.key] = FormDivider.DIVIDER_COLORS[ref.current!.reference]; + + Object.keys(tokenRef.Shadow).forEach(k => tokenRef.Shadow[k][ref.key] = tokenRef.Shadow[k][ref.current!.reference]); + Object.keys(tokenRef.SemanticColor).forEach(k => { + tokenRef.SemanticColor[k][ref.key] = { + ...tokenRef.SemanticColor[k][ref.current!.reference] + }; + }); + } if (update) { AppearanceManager.setShouldSyncAppearanceSettings(false); - AppearanceManager.updateTheme(internalDef != null ? ref.key : ref.lastSetDiscordTheme); + AppearanceManager.updateTheme(internalDef != null ? ref.key : "darker"); } } From 0755d3321e6d2fc3f55dbf37735df5e5019c62a6 Mon Sep 17 00:00:00 2001 From: cocobo1 Date: Wed, 3 Dec 2025 23:09:06 +0200 Subject: [PATCH 12/16] fix(safemode) --- src/lib/addons/themes/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lib/addons/themes/index.ts b/src/lib/addons/themes/index.ts index aaedeb4..4dcf455 100644 --- a/src/lib/addons/themes/index.ts +++ b/src/lib/addons/themes/index.ts @@ -4,7 +4,7 @@ import { getStoredTheme, getThemeFilePath, isPyonLoader, isThemeSupported } from import { awaitStorage as newAwaitStorage } from "@lib/api/storage"; import { safeFetch } from "@lib/utils"; import { Platform } from "react-native"; - +import { settings } from "@lib/api/settings"; import initColors from "./colors"; import { applyAndroidAlphaKeys, normalizeToHex } from "./colors/parser"; import { colorsPref } from "./colors/preferences"; @@ -149,6 +149,7 @@ export function getThemeFromLoader(): VdThemeInfo | null { */ export async function initThemes() { if (!isThemeSupported()) return; + if (settings.safeMode?.enabled) return; try { if (isPyonLoader()) { From 8d9ba48e449af8d452c836a0be33a8e68fe28925 Mon Sep 17 00:00:00 2001 From: cocobo1 Date: Thu, 4 Dec 2025 18:14:12 +0200 Subject: [PATCH 13/16] chore: bump version --- scripts/build.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/build.mjs b/scripts/build.mjs index 5574a91..7338d2c 100644 --- a/scripts/build.mjs +++ b/scripts/build.mjs @@ -74,7 +74,7 @@ const config = { constModules: { globals: { "bunny-build-info": { - version: `"v1.3.8"` + version: `"v1.3.9"` } } }, From 6f27419124c8d384cb878493cb003a33e96b98d3 Mon Sep 17 00:00:00 2001 From: Bwlok Date: Sat, 6 Dec 2025 21:12:10 +0100 Subject: [PATCH 14/16] Add options to auto connect to debuggers --- src/core/i18n/default.json | 2 + .../ui/settings/pages/Developer/index.tsx | 44 +++++++++++++------ src/index.ts | 3 ++ src/lib/api/debug.ts | 37 +++++++++++++++- src/lib/api/settings.ts | 2 + 5 files changed, 73 insertions(+), 15 deletions(-) diff --git a/src/core/i18n/default.json b/src/core/i18n/default.json index 15268af..466be29 100644 --- a/src/core/i18n/default.json +++ b/src/core/i18n/default.json @@ -35,7 +35,9 @@ "COPY_URL": "Copy URL", "DEBUG": "Debug", "DEBUGGER_URL": "Debugger URL", + "AUTO_DEBUGGER": "Automatically connect to Debugger", "DEVTOOLS_URL": "DevTools URL", + "AUTO_DEVTOOLS": "Automatically connect to Devtools", "DELETE": "Delete", "DESC_EXTRACT_FONTS_FROM_THEME": "Looks out for \"fonts\" field in your currently applied theme and install it.", "DEVELOPER": "Developer", diff --git a/src/core/ui/settings/pages/Developer/index.tsx b/src/core/ui/settings/pages/Developer/index.tsx index 788f0b1..4e9e23c 100644 --- a/src/core/ui/settings/pages/Developer/index.tsx +++ b/src/core/ui/settings/pages/Developer/index.tsx @@ -60,12 +60,20 @@ export default function Developer() { borderTopRightRadius: 16, overflow: 'hidden' }}> - } - onPress={() => connectToDebugger(settings.debuggerUrl)} - /> + } + value={settings.autoDebugger} + onValueChange={(v: boolean) => { + settings.autoDebugger = v; + }} + /> + } + onPress={() => connectToDebugger(settings.debuggerUrl)} + /> {isReactDevToolsPreloaded() && <> @@ -84,14 +92,23 @@ export default function Developer() { borderTopRightRadius: 16, overflow: 'hidden' }}> - } - onPress={async () => { - if (!settings.devToolsUrl?.trim()) { - showToast("Invalid devTools URL!", findAssetId("Small")); - return; - } + value={settings.autoDevTools} + onValueChange={(v: boolean) => { + settings.autoDevTools = v; + }} + /> + + } + onPress={async () => { + if (!settings.devToolsUrl?.trim()) { + showToast("Invalid devTools URL!", findAssetId("Small")); + return; + } try { const devTools = window[getReactDevToolsProp() || "__vendetta_rdc"]; @@ -110,8 +127,7 @@ export default function Developer() { } }} - /> - + /> } {isLoaderConfigSupported() && <> diff --git a/src/index.ts b/src/index.ts index 89aaccf..340ab31 100644 --- a/src/index.ts +++ b/src/index.ts @@ -13,6 +13,7 @@ import { injectFluxInterceptor } from "@lib/api/flux"; import { patchJsx } from "@lib/api/react/jsx"; import { logger } from "@lib/utils/logger"; import { patchSettings } from "@ui/settings"; +import { initDebugger } from "@lib/api/debug"; import * as lib from "./lib"; @@ -40,6 +41,8 @@ export default async () => { u => u.forEach(f => f && lib.unload.push(f)) ); + initDebugger() + // Assign window object window.bunny = lib; diff --git a/src/lib/api/debug.ts b/src/lib/api/debug.ts index 8d301c2..870739b 100644 --- a/src/lib/api/debug.ts +++ b/src/lib/api/debug.ts @@ -1,6 +1,6 @@ import { getThemeFromLoader, selectTheme, themes } from "@lib/addons/themes"; import { findAssetId } from "@lib/api/assets"; -import { getLoaderName, getLoaderVersion, isThemeSupported } from "@lib/api/native/loader"; +import { getLoaderName, getLoaderVersion, isThemeSupported, getReactDevToolsProp } from "@lib/api/native/loader"; import { BundleUpdaterManager, NativeClientInfoModule, NativeDeviceModule } from "@lib/api/native/modules"; import { after } from "@lib/api/patcher"; import { settings } from "@lib/api/settings"; @@ -8,6 +8,7 @@ import { logger } from "@lib/utils/logger"; import { showToast } from "@ui/toasts"; import { version } from "bunny-build-info"; import { Platform, type PlatformConstants } from "react-native"; +import { StyleSheet } from "react-native"; export interface RNConstants extends PlatformConstants { // Android @@ -164,3 +165,37 @@ export function getDebugInfo() { )! }; } + + +/** + * @internal + */ +export function initDebugger() { + if (settings.autoDebugger) { + try { + connectToDebugger(settings.debuggerUrl); + } catch (e) { + logger.error("Failed to connect to Debugger during startup:", e); + } + } + if (settings.autoDevTools) { + try { + (async () => { + const devTools = window[getReactDevToolsProp() || "__vendetta_rdc"]; + + if (!devTools?.connectToDevTools) { + showToast("Invalid devTools URL!", findAssetId("Small")); + return; + } + + await devTools.connectToDevTools({ + host: settings.devToolsUrl.split(":")?.[0], + resolveRNStyle: StyleSheet.flatten, + }); + })(); + } catch (e) { + logger.error("Failed to connect to ReactDevTools during startup:", e); + } + } + +} diff --git a/src/lib/api/settings.ts b/src/lib/api/settings.ts index 85e5eeb..6d8ffb7 100644 --- a/src/lib/api/settings.ts +++ b/src/lib/api/settings.ts @@ -4,6 +4,8 @@ import { getLoaderConfigPath } from "@lib/api/native/loader"; export interface Settings { debuggerUrl: string; devToolsUrl: string; + autoDebugger: boolean; + autoDevTools: boolean; developerSettings: boolean; enableDiscordDeveloperSettings: boolean; safeMode?: { From 533292834bdd55b659dbfbc186fcb72411de193e Mon Sep 17 00:00:00 2001 From: cocobo1 Date: Sun, 7 Dec 2025 19:49:13 +0200 Subject: [PATCH 15/16] fix(devtools): update devtools version --- src/core/ui/settings/pages/Developer/index.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/core/ui/settings/pages/Developer/index.tsx b/src/core/ui/settings/pages/Developer/index.tsx index 788f0b1..2eab444 100644 --- a/src/core/ui/settings/pages/Developer/index.tsx +++ b/src/core/ui/settings/pages/Developer/index.tsx @@ -22,7 +22,8 @@ const { showSimpleActionSheet } = lazyDestructure(() => findByProps("showSimpleA const { openAlert } = lazyDestructure(() => findByProps("openAlert", "dismissAlert")); const { AlertModal, AlertActionButton } = lazyDestructure(() => findByProps("AlertModal", "AlertActions")); -const RDT_EMBED_LINK = "https://cdn.bwlok.dev/rdt/devTools.js"; +// todo: This link isnt minified, but it probably should be +const RDT_EMBED_LINK = "https://codeberg.org/raincord/Devtools/raw/branch/main/reactDevtools.js"; const useStyles = createStyles({ leadingText: { From 18890891892cb6a593d7abec2f9b948c7f1dd2cd Mon Sep 17 00:00:00 2001 From: cocobo1 Date: Fri, 12 Dec 2025 20:08:43 +0200 Subject: [PATCH 16/16] fix(text): correct text colouring --- src/core/ui/components/AddonCard.tsx | 4 ++-- .../settings/pages/Plugins/sheets/PluginInfoActionSheet.tsx | 6 +++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/core/ui/components/AddonCard.tsx b/src/core/ui/components/AddonCard.tsx index a0486d4..973ee38 100644 --- a/src/core/ui/components/AddonCard.tsx +++ b/src/core/ui/components/AddonCard.tsx @@ -32,7 +32,7 @@ const useStyles = createStyles({ }, headerLabel: { ...TextStyleSheet["heading-md/semibold"], - color: semanticColors.TEXT_NORMAL, + color: semanticColors.HEADER_PRIMARY, }, headerSubtitle: { ...TextStyleSheet["text-md/semibold"], @@ -40,7 +40,7 @@ const useStyles = createStyles({ }, descriptionLabel: { ...TextStyleSheet["text-md/semibold"], - color: semanticColors.TEXT_NORMAL, + color: semanticColors.HEADER_PRIMARY, }, actions: { flexDirection: "row-reverse", diff --git a/src/core/ui/settings/pages/Plugins/sheets/PluginInfoActionSheet.tsx b/src/core/ui/settings/pages/Plugins/sheets/PluginInfoActionSheet.tsx index b9e9858..d857f28 100644 --- a/src/core/ui/settings/pages/Plugins/sheets/PluginInfoActionSheet.tsx +++ b/src/core/ui/settings/pages/Plugins/sheets/PluginInfoActionSheet.tsx @@ -11,6 +11,7 @@ import { useState } from "react"; import { ScrollView, View } from "react-native"; import TitleComponent from "./TitleComponent"; import { PluginInfoActionSheetProps } from "./common"; +import { semanticColors } from "@lib/ui/color"; function PluginInfoIconButton(props) { const { onPress } = props; @@ -205,7 +206,10 @@ export default function PluginInfoActionSheet({ Description