diff --git a/src/index.ts b/src/index.ts index ce354f1..010341e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,10 +2,13 @@ import patcher from "@lib/patcher"; import logger from "@lib/logger"; import * as metro from "@metro/filters"; import * as common from "@metro/common"; +import initSettings from "./ui/settings"; console.log("Hello from Vendetta!"); try { + initSettings(); + window.vendetta = { patcher: patcher, metro: { ...metro, common: common }, diff --git a/src/lib/metro/common.ts b/src/lib/metro/common.ts index 9c276fd..5c89d25 100644 --- a/src/lib/metro/common.ts +++ b/src/lib/metro/common.ts @@ -3,4 +3,8 @@ import { findByProps } from "@metro/filters"; // Discord export const Constants = findByProps("API_HOST"); export const channels = findByProps("getVoiceChannelId"); -export const i18n = findByProps("Messages"); \ No newline at end of file +export const i18n = findByProps("Messages"); + +// React +export const React = findByProps("createElement") as typeof import("react"); +export const ReactNative = findByProps("Text", "Image") as typeof import("react-native"); \ No newline at end of file diff --git a/src/ui/settings/components/Settings.tsx b/src/ui/settings/components/Settings.tsx new file mode 100644 index 0000000..c5f7e9f --- /dev/null +++ b/src/ui/settings/components/Settings.tsx @@ -0,0 +1,48 @@ +import { React, ReactNative as RN } from "@metro/common"; +import { findByProps } from "@metro/filters"; +import Version from "./Version"; + +const { FormRow, FormSection, FormText } = findByProps("FormSection"); +const hermesProps = window.HermesInternal.getRuntimeProperties(); +const rnVer = RN.Platform.constants.reactNativeVersion; + +export default function Settings() { + const versions = [ + { + label: "Discord", + version: RN.NativeModules.InfoDictionaryManager.Version, + }, + { + label: "React", + version: React.version, + }, + { + label: "React Native", + version: `${rnVer.major || 0}.${rnVer.minor || 0}.${rnVer.patch || 0}`, + }, + { + label: "Hermes", + version: `${hermesProps["OSS Release Version"]} ${hermesProps["Build"]}`, + }, + { + label: "Bytecode", + version: hermesProps["Bytecode Version"], + }, + ]; + + return ( + <> + {/* Why is there still a divider? */} + + RN.NativeModules.BundleUpdaterManager.reload()} + /> + + + {versions.map((v) => )} + + + ) +} \ No newline at end of file diff --git a/src/ui/settings/components/SettingsSection.tsx b/src/ui/settings/components/SettingsSection.tsx new file mode 100644 index 0000000..0818822 --- /dev/null +++ b/src/ui/settings/components/SettingsSection.tsx @@ -0,0 +1,20 @@ +import { React } from "@metro/common"; +import { findByProps } from "@metro/filters"; + +const { FormRow, FormSection } = findByProps("FormSection"); + +interface SettingsSectionProps { + navigation: any; +} + +export default function SettingsSection({ navigation }: SettingsSectionProps) { + return ( + + navigation.push("VendettaSettings")} + /> + + ) +} \ No newline at end of file diff --git a/src/ui/settings/components/Version.tsx b/src/ui/settings/components/Version.tsx new file mode 100644 index 0000000..a5d5ad9 --- /dev/null +++ b/src/ui/settings/components/Version.tsx @@ -0,0 +1,18 @@ +import { React } from "@metro/common"; +import { findByProps } from "@metro/filters"; + +interface VersionProps { + label: string; + version: string +} + +const { FormRow, FormText } = findByProps("FormSection"); + +export default function Version({ label, version }: VersionProps) { + return ( + {version}} + /> + ) +} \ No newline at end of file diff --git a/src/ui/settings/index.tsx b/src/ui/settings/index.tsx new file mode 100644 index 0000000..994669c --- /dev/null +++ b/src/ui/settings/index.tsx @@ -0,0 +1,38 @@ +import { React, i18n } from "@metro/common"; +import { findByDisplayName } from "@metro/filters"; +import { after } from "@lib/patcher"; +import findInReactTree from "@utils/findInReactTree"; +import Settings from "./components/Settings"; +import SettingsSection from "./components/SettingsSection"; + +const screensModule = findByDisplayName("getScreens", false); +const settingsModule = findByDisplayName("UserSettingsOverviewWrapper", false); + +export default function initSettings() { + const screensPatch = after("default", screensModule, (args, ret) => { + return { + ...ret, + VendettaSettings: { + title: "Vendetta Settings", + render: Settings + } + } + }); + + const settingsPatch = after("default", settingsModule, (args, _ret) => { + settingsPatch(); + const toPatch = findInReactTree(_ret.props.children, i => i.type && i.type.name === "UserSettingsOverview"); + + // Upload logs button gone + after("renderSupportAndAcknowledgements", toPatch.type.prototype, (args, { props: { children } }) => { + const index = children.findIndex((c: any) => c?.type?.name === "UploadLogsButton"); + if (index !== -1) children.splice(index, 1); + }); + + after("render", toPatch.type.prototype, (args, { props: { children } }) => { + const titles = [i18n.Messages["BILLING_SETTINGS"], i18n.Messages["PREMIUM_SETTINGS"]]; + const index = children.findIndex((c: any) => titles.includes(c.props.title)); + children.splice(index === -1 ? 4 : index, 0, ); + }); + }); +} \ No newline at end of file