Merge branch 'dev' into github
This commit is contained in:
commit
3bae44e833
27 changed files with 156 additions and 277 deletions
|
|
@ -1,5 +1,5 @@
|
|||
# Kettu
|
||||
A mod for Discord on Android
|
||||
A mod for Discord on Mobile
|
||||
|
||||
### [](https://discord.gg/6cN7wKa8gp) [](https://www.ko-fi.com/cocobo1) 
|
||||
|
||||
|
|
|
|||
11
bun.lock
11
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=="],
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ const config = {
|
|||
constModules: {
|
||||
globals: {
|
||||
"bunny-build-info": {
|
||||
version: `"v1.3.7"`
|
||||
version: `"v1.3.9"`
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -7,5 +7,4 @@ module.exports = {
|
|||
"moment": findByPropsLazy("isMoment"),
|
||||
"chroma-js": findByPropsLazy("brewer"),
|
||||
"lodash": findByPropsLazy("forEachRight"),
|
||||
"@shopify/react-native-skia": findByPropsLazy("useFont")
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
@ -78,6 +80,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",
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -175,7 +175,7 @@ export default function AddonPage<T extends object>({ CardComponent, ...props }:
|
|||
<View style={{ flexDirection: "row", gap: 8 }}>
|
||||
<Search style={{ flexGrow: 1 }} isRound={!!props.sortOptions} onChangeText={v => setSearch(v)} />
|
||||
{props.sortOptions && <IconButton
|
||||
icon={findAssetId("MoreVerticalIcon")}
|
||||
icon={findAssetId("ArrowsUpDownIcon")}
|
||||
variant="tertiary"
|
||||
disabled={!!search}
|
||||
onPress={() => showSimpleActionSheet({
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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: {
|
||||
|
|
@ -60,12 +61,20 @@ export default function Developer() {
|
|||
borderTopRightRadius: 16,
|
||||
overflow: 'hidden'
|
||||
}}>
|
||||
<TableRow
|
||||
label={Strings.CONNECT_TO_DEBUG_WEBSOCKET}
|
||||
icon={<TableRow.Icon source={findAssetId("copy")} />}
|
||||
onPress={() => connectToDebugger(settings.debuggerUrl)}
|
||||
/>
|
||||
<TableSwitchRow
|
||||
label={Strings.AUTO_DEBUGGER}
|
||||
icon={<TableRow.Icon source={findAssetId("copy")} />}
|
||||
value={settings.autoDebugger}
|
||||
onValueChange={(v: boolean) => {
|
||||
settings.autoDebugger = v;
|
||||
}}
|
||||
/>
|
||||
</Stack>
|
||||
<TableRow
|
||||
label={Strings.CONNECT_TO_DEBUG_WEBSOCKET}
|
||||
icon={<TableRow.Icon source={findAssetId("copy")} />}
|
||||
onPress={() => connectToDebugger(settings.debuggerUrl)}
|
||||
/>
|
||||
|
||||
</TableRowGroup>
|
||||
{isReactDevToolsPreloaded() && <>
|
||||
|
|
@ -84,14 +93,23 @@ export default function Developer() {
|
|||
borderTopRightRadius: 16,
|
||||
overflow: 'hidden'
|
||||
}}>
|
||||
<TableRow
|
||||
label={Strings.CONNECT_TO_REACT_DEVTOOLS}
|
||||
<TableSwitchRow
|
||||
label={Strings.AUTO_DEVTOOLS}
|
||||
icon={<TableRow.Icon source={findAssetId("ic_badge_staff")} />}
|
||||
onPress={async () => {
|
||||
if (!settings.devToolsUrl?.trim()) {
|
||||
showToast("Invalid devTools URL!", findAssetId("Small"));
|
||||
return;
|
||||
}
|
||||
value={settings.autoDevTools}
|
||||
onValueChange={(v: boolean) => {
|
||||
settings.autoDevTools = v;
|
||||
}}
|
||||
/>
|
||||
</Stack>
|
||||
<TableRow
|
||||
label={Strings.CONNECT_TO_REACT_DEVTOOLS}
|
||||
icon={<TableRow.Icon source={findAssetId("ic_badge_staff")} />}
|
||||
onPress={async () => {
|
||||
if (!settings.devToolsUrl?.trim()) {
|
||||
showToast("Invalid devTools URL!", findAssetId("Small"));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const devTools = window[getReactDevToolsProp() || "__vendetta_rdc"];
|
||||
|
|
@ -110,8 +128,7 @@ export default function Developer() {
|
|||
}
|
||||
}}
|
||||
|
||||
/>
|
||||
</Stack>
|
||||
/>
|
||||
</TableRowGroup>
|
||||
</>}
|
||||
{isLoaderConfigSupported() && <>
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
<View style={{ height: 64 }}>
|
||||
{typeface
|
||||
? <Skia.Canvas style={{ height: 64 }}>
|
||||
<Skia.Paragraph paragraph={paragraph} x={0} y={0} width={300} />
|
||||
</Skia.Canvas>
|
||||
: <View style={{ justifyContent: "center", alignItems: "center" }}>
|
||||
<Text color="text-muted" variant="heading-lg/semibold">
|
||||
Loading...
|
||||
</Text>
|
||||
</View>}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
export default function FontCard({ item: font }: CardWrapper<FontDefinition>) {
|
||||
useProxy(fonts);
|
||||
|
||||
|
|
@ -111,7 +67,6 @@ export default function FontCard({ item: font }: CardWrapper<FontDefinition>) {
|
|||
</Stack>
|
||||
</View>
|
||||
</View>
|
||||
<FontPreview font={font} />
|
||||
</Stack>
|
||||
</Card>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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({
|
|||
<Text
|
||||
variant="text-md/semibold"
|
||||
color="text-primary"
|
||||
style={{ marginBottom: 4 }}
|
||||
style={{
|
||||
marginBottom: 4,
|
||||
color: semanticColors.HEADER_PRIMARY,
|
||||
}}
|
||||
>
|
||||
Description
|
||||
</Text>
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ async function initializeKettu() {
|
|||
Object.freeze = Object.seal = Object;
|
||||
|
||||
await require("@metro/internals/caches").initMetroCache();
|
||||
await require(".").default();
|
||||
require(".").default();
|
||||
} catch (e) {
|
||||
const { ClientInfoManager } = require("@lib/api/native/modules");
|
||||
const stack = e instanceof Error ? e.stack : undefined;
|
||||
|
|
|
|||
|
|
@ -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,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 { getDebugInfo } from "@lib/api/debug";
|
||||
import { initDebugger } from "@lib/api/debug";
|
||||
|
||||
import * as lib from "./lib";
|
||||
|
||||
|
|
@ -31,7 +31,7 @@ export default async () => {
|
|||
initFetchI18nStrings(),
|
||||
initSettings(),
|
||||
initFixes(),
|
||||
// patchErrorBoundary(),
|
||||
patchErrorBoundary(),
|
||||
updatePlugins(),
|
||||
updateFonts(),
|
||||
initPlugins(),
|
||||
|
|
@ -41,6 +41,8 @@ export default async () => {
|
|||
u => u.forEach(f => f && lib.unload.push(f))
|
||||
);
|
||||
|
||||
initDebugger()
|
||||
|
||||
// Assign window object
|
||||
window.bunny = lib;
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ export interface PluginSettingsStorage {
|
|||
}
|
||||
|
||||
export interface BunnyPluginManifest extends BunnyManifest {
|
||||
name: string;
|
||||
readonly type: "plugin";
|
||||
readonly spec: 3;
|
||||
readonly main: string;
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
@ -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?.(() => {});
|
||||
}
|
||||
|
|
@ -24,18 +24,6 @@ const SEMANTIC_FALLBACK_MAP: Record<string, string> = {
|
|||
|
||||
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<string, string> = {
|
||||
"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);
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -1,57 +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() {
|
||||
|
||||
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") {
|
||||
function applyStatusBar() {
|
||||
const style = getBarStyle();
|
||||
StatusBar.setBarStyle(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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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()) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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?: {
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue