diff --git a/build.mjs b/build.mjs index cffab38..54822f7 100644 --- a/build.mjs +++ b/build.mjs @@ -43,6 +43,26 @@ try { "@types": "src/utils/types.ts", }, plugins: [ + { + name: "runtimeGlobalAlias", + setup: async build => { + const globalMap = { + "react": "globalThis.React", + "react-native": "globalThis.ReactNative" + }; + + Object.keys(globalMap).forEach(key => { + const filter = new RegExp(`^${key}$`); + build.onResolve({ filter }, args => ({ + namespace: "glob-" + key, path: args.path + })); + build.onLoad({ filter, namespace: "glob-" + key }, () => ({ + contents: `Object.defineProperty(module, 'exports', { get: () => ${globalMap[key]} })`, + resolveDir: "src", + })); + }); + } + }, { name: "buildLog", setup: async build => { diff --git a/packages/bunny-types/def.tt b/packages/bunny-types/def.tt index a09596b..74c0b4c 100644 --- a/packages/bunny-types/def.tt +++ b/packages/bunny-types/def.tt @@ -22,10 +22,16 @@ common } ui { - components + components { + discord { + Forms + Redesign + } + } alerts color toasts + styles } utils { constants diff --git a/packages/bunny-types/package.json b/packages/bunny-types/package.json index 9596623..c07a436 100644 --- a/packages/bunny-types/package.json +++ b/packages/bunny-types/package.json @@ -1,6 +1,6 @@ { "name": "bunny-types", - "version": "0.0.3", + "version": "0.0.4", "description": "Types for Bunny, a mod for Discord's mobile apps", "author": "pylixonly", "publishConfig": { @@ -30,4 +30,4 @@ "ts-patch": "^3.1.2", "typescript": "^5.3.3" } -} +} \ No newline at end of file diff --git a/src/core/i18n/default.json b/src/core/i18n/default.json index ce2c3e3..29150a8 100644 --- a/src/core/i18n/default.json +++ b/src/core/i18n/default.json @@ -72,6 +72,7 @@ "THEMES_RELOAD_FOR_CHANGES": "Reload the app to fully apply changes!", "TOASTS_INSTALLED_PLUGIN": "Installed plugin", "TOASTS_SUCCESSFULLY_INSTALLED": "Successfully installed", + "TOASTS_COPIED_TO_CLIPBOARD": "Copied plugin URL to clipboard", "UH_OH": "Uh oh.", "UNINSTALL": "Uninstall", "UNINSTALL_TITLE": "Uninstall {title}", diff --git a/src/core/plugins/quickInstall/forumPost.tsx b/src/core/plugins/quickInstall/forumPost.tsx index e90b174..dce7e09 100644 --- a/src/core/plugins/quickInstall/forumPost.tsx +++ b/src/core/plugins/quickInstall/forumPost.tsx @@ -5,6 +5,7 @@ import { after } from "@lib/api/patcher"; import { useProxy } from "@lib/api/storage"; import { installPlugin, plugins, removePlugin } from "@lib/managers/plugins"; import { installTheme, removeTheme, themes } from "@lib/managers/themes"; +import { Button } from "@lib/ui/components/discord/Redesign"; import { findInReactTree } from "@lib/utils"; import { DISCORD_SERVER_ID, HTTP_REGEX_MULTI, PLUGINS_CHANNEL_ID, PROXY_PREFIX, THEMES_CHANNEL_ID } from "@lib/utils/constants"; import { findByName, findByProps } from "@metro/filters"; @@ -14,7 +15,6 @@ type PostType = "Plugin" | "Theme"; const ForumPostLongPressActionSheet = findByName("ForumPostLongPressActionSheet", false); const { ActionSheetRow } = findByProps("ActionSheetRow"); -const { Button } = findByProps("TableRow"); const { useFirstForumPostMessage } = findByProps("useFirstForumPostMessage"); const forumReactions = findByProps("MostCommonForumPostReaction"); diff --git a/src/core/ui/components/AddonPage.tsx b/src/core/ui/components/AddonPage.tsx index 7b21a7f..b906dc9 100644 --- a/src/core/ui/components/AddonPage.tsx +++ b/src/core/ui/components/AddonPage.tsx @@ -5,10 +5,11 @@ import { useProxy } from "@lib/api/storage"; import { findByProps } from "@lib/metro/filters"; import { settings } from "@lib/settings"; import { HTTP_REGEX_MULTI } from "@lib/utils/constants"; -import { clipboard, ReactNative as RN } from "@metro/common"; +import { clipboard } from "@metro/common"; import { showInputAlert } from "@ui/alerts"; import { ErrorBoundary, HelpMessage, Search } from "@ui/components"; import fuzzysort from "fuzzysort"; +import { FlatList, View } from "react-native"; interface AddonPageProps { title: string; @@ -47,12 +48,12 @@ export default function AddonPage({ title, fetchFunction, items, safeModeMess return ( {/* TODO: Implement better searching than just by ID */} - - {settings.safeMode?.enabled && + {settings.safeMode?.enabled && {safeModeMessage} {safeModeExtras} - } + } setSearch(v.toLowerCase())} diff --git a/src/core/ui/components/AssetDisplay.tsx b/src/core/ui/components/AssetDisplay.tsx index 456c2c0..7743afc 100644 --- a/src/core/ui/components/AssetDisplay.tsx +++ b/src/core/ui/components/AssetDisplay.tsx @@ -1,17 +1,16 @@ import { Asset } from "@lib/api/assets"; -import { clipboard, ReactNative as RN } from "@metro/common"; -import { Forms } from "@ui/components"; +import { FormRow } from "@lib/ui/components/discord/Forms"; +import { clipboard } from "@metro/common"; import { showToast } from "@ui/toasts"; +import { Image } from "react-native"; interface AssetDisplayProps { asset: Asset; } -const { FormRow } = Forms; - export default function AssetDisplay({ asset }: AssetDisplayProps) { return ( } + trailing={} onPress={() => { clipboard.setString(asset.name); showToast.showCopyToClipboard(); diff --git a/src/core/ui/components/Card.tsx b/src/core/ui/components/Card.tsx index 5f8caa8..fcbbbc7 100644 --- a/src/core/ui/components/Card.tsx +++ b/src/core/ui/components/Card.tsx @@ -1,13 +1,12 @@ import { getAssetIDByName } from "@lib/api/assets"; -import { ReactNative as RN, stylesheet } from "@metro/common"; -import { findByProps } from "@metro/filters"; +import { TableCheckboxRow, TableRow, TableRowGroup, TableRowIcon, TableSwitchRow } from "@lib/ui/components/discord/Redesign"; import { semanticColors } from "@ui/color"; import ContextMenu from "@ui/components/ContextMenu"; - -const { TableRow, TableRowIcon, TableSwitchRow, TableCheckboxRow, TableRowGroup } = findByProps("TableRow"); +import { createStyles } from "@ui/styles"; +import { Image, TouchableOpacity, View } from "react-native"; // TODO: These styles work weirdly. iOS has cramped text, Android with low DPI probably does too. Fix? -const styles = stylesheet.createThemedStyleSheet({ +const useStyles = createStyles({ card: { backgroundColor: semanticColors?.BACKGROUND_SECONDARY, borderRadius: 15, @@ -66,6 +65,7 @@ interface CardProps { } export default function Card(props: CardProps) { + const styles = useStyles(); let pressableState = props.toggleValue ?? false; const headerProps = { @@ -75,7 +75,7 @@ export default function Card(props: CardProps) { }; return ( - + {props.toggleType && (props.toggleType === "switch" ? + {props.overflowActions && - - } + children={props => + + } /> } - + } /> - + ); } diff --git a/src/core/ui/components/InstallButton.tsx b/src/core/ui/components/InstallButton.tsx index 4f84f50..1166f6a 100644 --- a/src/core/ui/components/InstallButton.tsx +++ b/src/core/ui/components/InstallButton.tsx @@ -1,11 +1,13 @@ import { Strings } from "@core/i18n"; import { getAssetIDByName } from "@lib/api/assets"; import { HTTP_REGEX_MULTI } from "@lib/utils/constants"; -import { clipboard, ReactNative as RN, stylesheet } from "@metro/common"; +import { clipboard } from "@metro/common"; import { showInputAlert } from "@ui/alerts"; import { semanticColors } from "@ui/color"; +import { createStyles } from "@ui/styles"; +import { Image, TouchableOpacity } from "react-native"; -const styles = stylesheet.createThemedStyleSheet({ +const useStyles = createStyles({ icon: { marginRight: 10, tintColor: semanticColors.HEADER_PRIMARY, @@ -18,8 +20,10 @@ interface InstallButtonProps { } export default function InstallButton({ alertTitle, installFunction: fetchFunction }: InstallButtonProps) { + const styles = useStyles(); + return ( - + clipboard.getString().then(content => showInputAlert({ title: alertTitle, @@ -31,7 +35,7 @@ export default function InstallButton({ alertTitle, installFunction: fetchFuncti }) ) }> - - + + ); } diff --git a/src/core/ui/components/SettingsSection.tsx b/src/core/ui/components/SettingsSection.tsx index 622915f..a13174e 100644 --- a/src/core/ui/components/SettingsSection.tsx +++ b/src/core/ui/components/SettingsSection.tsx @@ -3,10 +3,9 @@ import { getScreens } from "@core/ui/settings/data"; import { getAssetIDByName } from "@lib/api/assets"; import { useProxy } from "@lib/api/storage"; import { settings } from "@lib/settings"; +import { FormDivider, FormRow, FormSection } from "@lib/ui/components/discord/Forms"; import { NavigationNative } from "@metro/common"; -import { ErrorBoundary, Forms } from "@ui/components"; - -const { FormRow, FormSection, FormDivider } = Forms; +import { ErrorBoundary } from "@ui/components"; export default function SettingsSection() { const navigation = NavigationNative.useNavigation(); diff --git a/src/core/ui/components/Version.tsx b/src/core/ui/components/Version.tsx index 4ef8742..66c99c2 100644 --- a/src/core/ui/components/Version.tsx +++ b/src/core/ui/components/Version.tsx @@ -1,7 +1,7 @@ import { getAssetIDByName } from "@lib/api/assets"; -import { findByProps } from "@lib/metro/filters"; +import { FormText } from "@lib/ui/components/discord/Forms"; +import { TableRow } from "@lib/ui/components/discord/Redesign"; import { clipboard } from "@metro/common"; -import { Forms } from "@ui/components"; import { showToast } from "@ui/toasts"; interface VersionProps { @@ -11,9 +11,6 @@ interface VersionProps { padding: boolean; } -const { TableRow } = findByProps("TableRow"); -const { FormText } = Forms; - export default function Version({ label, version, icon, padding }: VersionProps) { return ( ; } -const useStyles = stylesheet.createStyles({ +const useStyles = createStyles({ container: { flex: 1, - backgroundColor: semanticColors.BACKGROUND_MOBILE_PRIMARY + backgroundColor: semanticColors.BACKGROUND_MOBILE_PRIMARY, } }); @@ -133,7 +135,9 @@ export const getYouData = () => { const styles = useStyles(); const { bottom: paddingBottom } = useSafeAreaInsets(); navigation.addListener("focus", () => navigation.setOptions(s.options)); - return ; + return + + ; }); return { diff --git a/src/core/ui/settings/pages/AssetBrowser.tsx b/src/core/ui/settings/pages/AssetBrowser.tsx index 268378c..0cabe5e 100644 --- a/src/core/ui/settings/pages/AssetBrowser.tsx +++ b/src/core/ui/settings/pages/AssetBrowser.tsx @@ -1,28 +1,27 @@ import AssetDisplay from "@core/ui/components/AssetDisplay"; import { all } from "@lib/api/assets"; -import { ReactNative as RN } from "@metro/common"; -import { ErrorBoundary, Forms, Search } from "@ui/components"; - -const { FormDivider } = Forms; +import { FormDivider } from "@lib/ui/components/discord/Forms"; +import { ErrorBoundary, Search } from "@ui/components"; +import { FlatList, View } from "react-native"; export default function AssetBrowser() { const [search, setSearch] = React.useState(""); return ( - + setSearch(v)} placeholder="Search" /> - a.name.includes(search) || a.id.toString() === search)} renderItem={({ item }) => } ItemSeparatorComponent={FormDivider} keyExtractor={item => item.name} /> - + ); } diff --git a/src/core/ui/settings/pages/Developer.tsx b/src/core/ui/settings/pages/Developer.tsx index 9748da3..5872902 100644 --- a/src/core/ui/settings/pages/Developer.tsx +++ b/src/core/ui/settings/pages/Developer.tsx @@ -5,18 +5,19 @@ import { getReactDevToolsProp, getReactDevToolsVersion, isLoaderConfigSupported, import { useProxy } from "@lib/api/storage"; import { connectToDebugger } from "@lib/debug"; import { loaderConfig, settings } from "@lib/settings"; -import { NavigationNative, ReactNative as RN, stylesheet } from "@metro/common"; +import { FormText } from "@lib/ui/components/discord/Forms"; +import { Stack, TableRow, TableRowGroup, TableSwitchRow, TextInput } from "@lib/ui/components/discord/Redesign"; +import { NavigationNative } from "@metro/common"; import { findByProps } from "@metro/filters"; import { semanticColors } from "@ui/color"; -import { ErrorBoundary, Forms } from "@ui/components"; +import { ErrorBoundary } from "@ui/components"; +import { createStyles, TextStyleSheet } from "@ui/styles"; +import { ScrollView, StyleSheet } from "react-native"; -const { Stack, TableRow, TableSwitchRow, TableRowGroup, TextInput } = findByProps("TableRow"); -const { FormText } = Forms; const { hideActionSheet } = findByProps("openLazy", "hideActionSheet"); const { showSimpleActionSheet } = findByProps("showSimpleActionSheet"); -const { TextStyleSheet } = findByProps("TextStyleSheet"); -const styles = stylesheet.createThemedStyleSheet({ +const useStyles = createStyles({ leadingText: { ...TextStyleSheet["heading-md/semibold"], color: semanticColors.TEXT_MUTED, @@ -25,6 +26,7 @@ const styles = stylesheet.createThemedStyleSheet({ }); export default function Developer() { + const styles = useStyles(); const navigation = NavigationNative.useNavigation(); useProxy(settings); @@ -32,7 +34,7 @@ export default function Developer() { return ( - + } onPress={() => window[getReactDevToolsProp() || "__vendetta_rdc"]?.connectToDevTools({ host: settings.debuggerUrl.split(":")?.[0], - resolveRNStyle: RN.StyleSheet.flatten, + resolveRNStyle: StyleSheet.flatten, })} /> } @@ -120,7 +122,7 @@ export default function Developer() { /> - + ); } diff --git a/src/core/ui/settings/pages/General.tsx b/src/core/ui/settings/pages/General.tsx index e06e615..e7b2419 100644 --- a/src/core/ui/settings/pages/General.tsx +++ b/src/core/ui/settings/pages/General.tsx @@ -3,17 +3,18 @@ import Version from "@core/ui/components/Version"; import { getAssetIDByName } from "@lib/api/assets"; import { useProxy } from "@lib/api/storage"; import { getDebugInfo, toggleSafeMode } from "@lib/debug"; -import { findByProps } from "@lib/metro/filters"; import { settings } from "@lib/settings"; +import { Stack, TableRow, TableRowGroup, TableSwitchRow } from "@lib/ui/components/discord/Redesign"; import { DISCORD_SERVER, GITHUB } from "@lib/utils/constants"; -import { ReactNative as RN, stylesheet, url } from "@metro/common"; +import { url } from "@metro/common"; import { semanticColors } from "@ui/color"; import { Summary } from "@ui/components"; +import { createStyles } from "@ui/styles"; +import { NativeModules, Platform, ScrollView } from "react-native"; -const { Stack, TableRow, TableSwitchRow, TableRowGroup } = findByProps("TableRow"); const debugInfo = getDebugInfo(); -const styles = stylesheet.createThemedStyleSheet({ +const useStyles = createStyles({ container: { flex: 1, backgroundColor: semanticColors.BACKGROUND_MOBILE_SECONDARY, @@ -21,6 +22,7 @@ const styles = stylesheet.createThemedStyleSheet({ }); export default function General() { + const styles = useStyles(); useProxy(settings); const versions = [ @@ -83,14 +85,14 @@ export default function General() { icon: "ic_phonelink_24px" }, { - label: RN.Platform.select({ android: Strings.CODENAME, ios: Strings.MACHINE_ID })!, + label: Platform.select({ android: Strings.CODENAME, ios: Strings.MACHINE_ID })!, version: debugInfo.device.codename, icon: "ic_compose_24px" } ]; return ( - + } - onPress={() => RN.NativeModules.BundleUpdaterManager.reload()} + onPress={() => NativeModules.BundleUpdaterManager.reload()} /> - + ); } diff --git a/src/core/vendettaObject.ts b/src/core/vendettaObject.ts index a98daa5..05d7a6b 100644 --- a/src/core/vendettaObject.ts +++ b/src/core/vendettaObject.ts @@ -7,6 +7,9 @@ import * as debug from "@lib/debug"; import * as plugins from "@lib/managers/plugins"; import * as themes from "@lib/managers/themes"; import { loaderConfig, settings } from "@lib/settings"; +import { Forms } from "@lib/ui/components/discord/Forms"; +import { CompatfulRedesign } from "@lib/ui/components/discord/Redesign"; +import { createThemedStyleSheet } from "@lib/ui/styles"; import * as utils from "@lib/utils"; import * as common from "@metro/common"; import * as metro from "@metro/filters"; @@ -39,7 +42,10 @@ export const createVendettaObject = (unloads: any[]): any => ({ i18n: common.i18n, url: common.url, toasts: common.toasts, - stylesheet: common.stylesheet, + stylesheet: { + ...CompatfulRedesign, + createThemedStyleSheet + }, clipboard: common.clipboard, assets: common.assets, invites: common.invites, @@ -80,8 +86,8 @@ export const createVendettaObject = (unloads: any[]): any => ({ }, ui: { components: { - Forms: components.Forms, - General: components.General, + Forms, + General: common.ReactNative, Alert: components.Alert, Button: components.Button, HelpMessage: components.HelpMessage, diff --git a/src/lib/api/commands/index.ts b/src/lib/api/commands/index.ts index 2f33207..75a98aa 100644 --- a/src/lib/api/commands/index.ts +++ b/src/lib/api/commands/index.ts @@ -1,8 +1,7 @@ +import { ApplicationCommand, ApplicationCommandInputType, ApplicationCommandType } from "@lib/api/commands/types"; import { after } from "@lib/api/patcher"; import { commands as commandsModule } from "@metro/common"; -import { ApplicationCommand, ApplicationCommandInputType, ApplicationCommandType } from "./types"; - let commands: ApplicationCommand[] = []; export function patchCommands() { diff --git a/src/lib/api/storage/backends.ts b/src/lib/api/storage/backends.ts index 07f7fe6..0c41fd7 100644 --- a/src/lib/api/storage/backends.ts +++ b/src/lib/api/storage/backends.ts @@ -1,5 +1,5 @@ import { FileManager, MMKVManager } from "@lib/api/native/modules"; -import { ReactNative as RN } from "@metro/common"; +import { Platform } from "react-native"; export interface StorageBackend { get: () => unknown | Promise; @@ -8,7 +8,7 @@ export interface StorageBackend { const ILLEGAL_CHARS_REGEX = /[<>:"/\\|?*]/g; -const filePathFixer = (file: string): string => RN.Platform.select({ +const filePathFixer = (file: string): string => Platform.select({ default: file, ios: FileManager.saveFileToGallery ? file : `Documents/${file}`, }); diff --git a/src/lib/debug.ts b/src/lib/debug.ts index 465ced2..ab0037d 100644 --- a/src/lib/debug.ts +++ b/src/lib/debug.ts @@ -5,10 +5,9 @@ import { after } from "@lib/api/patcher"; import { getThemeFromLoader, selectTheme } from "@lib/managers/themes"; import { settings } from "@lib/settings"; import logger from "@lib/utils/logger"; -import { ReactNative as RN } from "@metro/common"; import { showToast } from "@ui/toasts"; import { version } from "bunny-build"; -import type { PlatformConstants } from "react-native"; +import { Platform, type PlatformConstants } from "react-native"; export let socket: WebSocket; export interface RNConstants extends PlatformConstants { @@ -88,7 +87,7 @@ export function getDebugInfo() { const padding = "for RN "; // RN - const PlatformConstants = RN.Platform.constants as RNConstants; + const PlatformConstants = Platform.constants as RNConstants; const rnVer = PlatformConstants.reactNativeVersion; return { @@ -114,7 +113,7 @@ export function getDebugInfo() { buildType: hermesProps.Build, bytecodeVersion: hermesProps["Bytecode Version"], }, - ...RN.Platform.select( + ...Platform.select( { android: { os: { @@ -131,7 +130,7 @@ export function getDebugInfo() { } } )!, - ...RN.Platform.select( + ...Platform.select( { android: { device: { diff --git a/src/lib/managers/themes.ts b/src/lib/managers/themes.ts index 7c9a7d8..0ae439c 100644 --- a/src/lib/managers/themes.ts +++ b/src/lib/managers/themes.ts @@ -6,8 +6,9 @@ import { awaitSyncWrapper, createFileBackend, createMMKVBackend, createStorage, import { findInReactTree, safeFetch } from "@lib/utils"; import logger from "@lib/utils/logger"; import { Author } from "@lib/utils/types"; -import { chroma, ReactNative as RN } from "@metro/common"; +import { chroma } from "@metro/common"; import { find, findByName, findByProps, findByStoreName } from "@metro/filters"; +import { ImageBackground, Platform, processColor, StyleSheet } from "react-native"; export interface ThemeData { name: string; @@ -71,7 +72,7 @@ export function patchChatBackground() { if (!MessagesWrapper) return; const patches = [ - after("default", MessagesWrapperConnected, (_, ret) => React.createElement(RN.ImageBackground, { + after("default", MessagesWrapperConnected, (_, ret) => React.createElement(ImageBackground, { style: { flex: 1, height: "100%" }, source: currentTheme?.data?.background?.url && { uri: currentTheme.data.background.url } || 0, blurRadius: typeof currentTheme?.data?.background?.blur === "number" ? currentTheme?.data?.background?.blur : 0, @@ -81,7 +82,7 @@ export function patchChatBackground() { const Messages = findInReactTree(ret, x => x && "HACK_fixModalInteraction" in x.props && x?.props?.style); if (Messages) Messages.props.style = Object.assign( - RN.StyleSheet.flatten(Messages.props.style ?? {}), + StyleSheet.flatten(Messages.props.style ?? {}), { backgroundColor: "#0000" } @@ -97,7 +98,7 @@ export function patchChatBackground() { function normalizeToHex(colorString: string): string { if (chroma.valid(colorString)) return chroma(colorString).hex(); - const color = Number(RN.processColor(colorString)); + const color = Number(processColor(colorString)); return chroma.rgb( color >> 16 & 0xff, // red @@ -126,7 +127,7 @@ function processData(data: ThemeData) { data.rawColors[key] = normalizeToHex(rawColors[key]); } - if (RN.Platform.OS === "android") applyAndroidAlphaKeys(rawColors); + if (Platform.OS === "android") applyAndroidAlphaKeys(rawColors); } return data; diff --git a/src/lib/metro/common.ts b/src/lib/metro/common.ts index e64e89d..41a0b59 100644 --- a/src/lib/metro/common.ts +++ b/src/lib/metro/common.ts @@ -1,34 +1,6 @@ -import { find, findByProps, findByStoreName } from "@metro/filters"; -import type { StyleSheet } from "react-native"; +import { find, findByProps } from "@metro/filters"; -export interface DiscordStyleSheet { - [index: string]: any, - createStyles: >(sheet: T | (() => T)) => () => T; - createThemedStyleSheet: typeof import("react-native").StyleSheet.create; -} - -const ThemeStore = findByStoreName("ThemeStore"); const colorModule = findByProps("colors", "unsafe_rawColors"); -const colorResolver = colorModule.internal ??= colorModule.meta; - -// Reimplementation of Discord's createThemedStyleSheet, which was removed since 204201 -// Not exactly a 1:1 reimplementation, but sufficient to keep compatibility with existing plugins -function createThemedStyleSheet>(sheet: T) { - if (!colorModule) return; - for (const key in sheet) { - // @ts-ignore - sheet[key] = new Proxy(ReactNative.StyleSheet.flatten(sheet[key]), { - get(target, prop, receiver) { - const res = Reflect.get(target, prop, receiver); - return colorResolver.isSemanticColor(res) - ? colorResolver.resolveSemanticColor(ThemeStore.theme, res) - : res; - } - }); - } - - return sheet; -} // Discord export const constants = findByProps("Fonts", "Permissions"); @@ -36,14 +8,6 @@ export const channels = findByProps("getVoiceChannelId"); export const i18n = findByProps("Messages"); export const url = findByProps("openURL", "openDeeplink"); export const toasts = find(m => m.open && m.close && !m.startDrag && !m.init && !m.openReplay && !m.setAlwaysOnTop && !m.setAccountFlag); - -// Compatible with pre-204201 versions since createThemedStyleSheet is undefined. -export const stylesheet = { - ...find(m => m.createStyles && !m.ActionSheet), - createThemedStyleSheet, - ...findByProps("createThemedStyleSheet") as {}, -} as DiscordStyleSheet; - export const clipboard = findByProps("setString", "getString", "hasString") as typeof import("@react-native-clipboard/clipboard").default; export const assets = findByProps("registerAsset"); export const invites = findByProps("acceptInviteAndTransitionToInviteChannel"); @@ -59,7 +23,7 @@ export const FluxDispatcher = findByProps("_currentDispatchActionType"); // React export const React = window.React = findByProps("createElement") as typeof import("react"); -export const ReactNative = findByProps("AppRegistry") as typeof import("react-native"); +export const ReactNative = window.ReactNative = findByProps("AppRegistry") as typeof import("react-native"); // Moment export const moment = findByProps("isMoment") as typeof import("moment"); diff --git a/src/lib/settings.ts b/src/lib/settings.ts index 4ef5972..266ebc6 100644 --- a/src/lib/settings.ts +++ b/src/lib/settings.ts @@ -1,7 +1,6 @@ +import { getLoaderConfigPath } from "@lib/api/native/loader"; import { createFileBackend, createMMKVBackend, createStorage, wrapSync } from "@lib/api/storage"; -import { getLoaderConfigPath } from "./api/native/loader"; - export interface Settings { debuggerUrl: string; developerSettings: boolean; diff --git a/src/lib/ui/color.ts b/src/lib/ui/color.ts index 6e98a1c..ce5d339 100644 --- a/src/lib/ui/color.ts +++ b/src/lib/ui/color.ts @@ -1,4 +1,5 @@ import { color } from "@lib/managers/themes"; +import { findByStoreName } from "@lib/metro/filters"; import { constants } from "@metro/common"; //! This module is only found on 165.0+, under the assumption that iOS 165.0 is the same as Android 165.0. @@ -10,8 +11,19 @@ import { constants } from "@metro/common"; // const colorModule = findByProps("colors", "meta"); // ? SemanticColor and default.colors are effectively ThemeColorMap -export const semanticColors = (color?.default?.colors ?? constants?.ThemeColorMap); +export const semanticColors = (color?.default?.colors ?? constants?.ThemeColorMap) as Record; // ? RawColor and default.unsafe_rawColors are effectively Colors //* Note that constants.Colors does still appear to exist on newer versions despite Discord not internally using it - what the fuck? -export const rawColors = (color?.default?.unsafe_rawColors ?? constants?.Colors); +export const rawColors = (color?.default?.unsafe_rawColors ?? constants?.Colors) as Record; + +const ThemeStore = findByStoreName("ThemeStore"); +const colorResolver = color.default.internal ??= color.default.meta; + +export function isSemanticColor(sym: Symbol): boolean { + return colorResolver.isSemanticColor(sym); +} + +export function resolveSemanticColor(sym: Symbol, theme = ThemeStore.theme): string { + return colorResolver.resolveSemanticColor(theme, sym); +} diff --git a/src/lib/ui/components/Codeblock.tsx b/src/lib/ui/components/Codeblock.tsx index a6d7c20..868fe13 100644 --- a/src/lib/ui/components/Codeblock.tsx +++ b/src/lib/ui/components/Codeblock.tsx @@ -1,13 +1,15 @@ -import { constants,ReactNative as RN, stylesheet } from "@metro/common"; +import { constants } from "@metro/common"; import { semanticColors } from "@ui/color"; +import { createStyles } from "@ui/styles"; +import { Platform, Text, TextInput, type TextStyle } from "react-native"; export interface CodeblockProps { selectable?: boolean; - style?: import("react-native").TextStyle; + style?: TextStyle; children?: string; } -const styles = stylesheet.createThemedStyleSheet({ +const useStyles = createStyles({ codeBlock: { fontFamily: constants.Fonts.CODE_SEMIBOLD, fontSize: 12, @@ -22,13 +24,13 @@ const styles = stylesheet.createThemedStyleSheet({ }); // iOS doesn't support the selectable property on RN.Text... -const InputBasedCodeblock = ({ style, children }: CodeblockProps) => ; -const TextBasedCodeblock = ({ selectable, style, children }: CodeblockProps) => {children}; +const InputBasedCodeblock = ({ style, children }: CodeblockProps) => ; +const TextBasedCodeblock = ({ selectable, style, children }: CodeblockProps) => {children}; export default function Codeblock({ selectable, style, children }: CodeblockProps) { if (!selectable) return ; - return RN.Platform.select({ + return Platform.select({ ios: , default: , }); diff --git a/src/lib/ui/components/ContextMenu.tsx b/src/lib/ui/components/ContextMenu.tsx index c6fc708..4c26cbe 100644 --- a/src/lib/ui/components/ContextMenu.tsx +++ b/src/lib/ui/components/ContextMenu.tsx @@ -1,9 +1,8 @@ import { instead } from "@lib/api/patcher"; -import { ReactNative } from "@lib/metro/common"; import { findByProps } from "@lib/metro/filters"; +import { AccessibilityInfo, Platform, View } from "react-native"; const { ContextMenu: _ContextMenu } = findByProps("ContextMenu"); -const { AccessibilityInfo } = ReactNative; type ContextMenuItem = { label: string, @@ -26,7 +25,7 @@ export default function ContextMenu(props: ContextMenuProps) { React.useEffect(() => { // hacky discord fix for android where pressing back with context menu open crashes the client - if (ReactNative.Platform.OS !== "android") return; + if (Platform.OS !== "android") return; // @ts-ignore const ctxMenuReactTag = ref.current?._children?.[0]?._nativeTag; @@ -44,9 +43,9 @@ export default function ContextMenu(props: ContextMenuProps) { }; }, []); - return + return <_ContextMenu {...props} /> - ; + ; } diff --git a/src/lib/ui/components/ErrorBoundary.tsx b/src/lib/ui/components/ErrorBoundary.tsx index 1fddeea..c17cb7c 100644 --- a/src/lib/ui/components/ErrorBoundary.tsx +++ b/src/lib/ui/components/ErrorBoundary.tsx @@ -1,6 +1,11 @@ import { Strings } from "@core/i18n"; -import { React, ReactNative as RN, stylesheet } from "@metro/common"; -import { Button, Codeblock, Forms } from "@ui/components"; +import { React } from "@metro/common"; +import { Button, Codeblock } from "@ui/components"; +import { ScrollView } from "react-native"; + +import { createThemedStyleSheet } from "../styles"; +import { FormText } from "./discord/Forms"; + interface ErrorBoundaryState { hasErr: boolean; @@ -11,7 +16,7 @@ export interface ErrorBoundaryProps { children: JSX.Element | JSX.Element[]; } -const styles = stylesheet.createThemedStyleSheet({ +const styles = createThemedStyleSheet({ view: { flex: 1, flexDirection: "column", @@ -36,8 +41,8 @@ export default class ErrorBoundary extends React.Component - {Strings.UH_OH} + + {Strings.UH_OH} {this.state.errText}