diff --git a/src/plugins/init/developer-settings/constants.ts b/src/plugins/init/developer-settings/constants.ts
index 1a32afe..37e4d32 100644
--- a/src/plugins/init/developer-settings/constants.ts
+++ b/src/plugins/init/developer-settings/constants.ts
@@ -6,6 +6,7 @@ export const MobileSetting = {
// SUBSETTINGS
REACT_DEVTOOLS_VERSION: 'REACT_DEVTOOLS_VERSION',
+ REACT_DEVTOOLS_AUTO_CONNECT: 'REACT_DEVTOOLS_AUTO_CONNECT',
REACT_DEVTOOLS_CONNECT: 'REACT_DEVTOOLS_CONNECT',
REACT_DEVTOOLS_DISCONNECT: 'REACT_DEVTOOLS_DISCONNECT',
EVALUATE_JAVASCRIPT: 'EVALUATE_JAVASCRIPT',
diff --git a/src/plugins/init/developer-settings/definitions/ReactDevToolsAutoConnectSetting.tsx b/src/plugins/init/developer-settings/definitions/ReactDevToolsAutoConnectSetting.tsx
new file mode 100644
index 0000000..f73caf3
--- /dev/null
+++ b/src/plugins/init/developer-settings/definitions/ReactDevToolsAutoConnectSetting.tsx
@@ -0,0 +1,22 @@
+import { React } from '@revenge-mod/react'
+
+import TableRowAssetIcon from '~/components/TableRowAssetIcon'
+
+import { api } from '..'
+import { MobileSetting } from '../constants'
+import { DevToolsContext } from '../react-devtools'
+
+import type { SettingsItem } from '@revenge-mod/discord/modules/settings'
+
+const ReactDevToolsAutoConnectSetting: SettingsItem = {
+ parent: MobileSetting.REVENGE_DEVELOPER,
+ IconComponent: () => ,
+ title: () => 'Auto-connect to React DevTools',
+ useDescription: () => 'Automatically connect to React DevTools during startup.',
+ usePredicate: () => DevToolsContext.available,
+ useValue: () => api.storage.use(s => s.devtools?.autoConnect !== undefined)!.devtools.autoConnect,
+ onValueChange: v => api.storage.set({ devtools: { autoConnect: v } }),
+ type: 'toggle',
+}
+
+export default ReactDevToolsAutoConnectSetting
diff --git a/src/plugins/init/developer-settings/definitions/ReactDevToolsConnectSetting.tsx b/src/plugins/init/developer-settings/definitions/ReactDevToolsConnectSetting.tsx
index 334c515..c26d071 100644
--- a/src/plugins/init/developer-settings/definitions/ReactDevToolsConnectSetting.tsx
+++ b/src/plugins/init/developer-settings/definitions/ReactDevToolsConnectSetting.tsx
@@ -3,7 +3,7 @@ import { React } from '@revenge-mod/react'
import TableRowAssetIcon from '~/components/TableRowAssetIcon'
import { MobileSetting } from '../constants'
-import { DevToolsContext, connectToDevTools, useIsDevToolsOpen } from '../devtools'
+import { DevToolsContext, connectToDevTools, useIsDevToolsOpen } from '../react-devtools'
import type { SettingsItem } from '@revenge-mod/discord/modules/settings'
diff --git a/src/plugins/init/developer-settings/definitions/ReactDevToolsDisconnectSetting.tsx b/src/plugins/init/developer-settings/definitions/ReactDevToolsDisconnectSetting.tsx
index 294ceda..0917101 100644
--- a/src/plugins/init/developer-settings/definitions/ReactDevToolsDisconnectSetting.tsx
+++ b/src/plugins/init/developer-settings/definitions/ReactDevToolsDisconnectSetting.tsx
@@ -3,7 +3,7 @@ import { React } from '@revenge-mod/react'
import TableRowAssetIcon from '~/components/TableRowAssetIcon'
import { MobileSetting } from '../constants'
-import { disconnectFromDevTools, useIsDevToolsOpen } from '../devtools'
+import { disconnectFromDevTools, useIsDevToolsOpen } from '../react-devtools'
import type { SettingsItem } from '@revenge-mod/discord/modules/settings'
diff --git a/src/plugins/init/developer-settings/definitions/ReactDevToolsVersionSetting.tsx b/src/plugins/init/developer-settings/definitions/ReactDevToolsVersionSetting.tsx
index 46b3b9e..8c17270 100644
--- a/src/plugins/init/developer-settings/definitions/ReactDevToolsVersionSetting.tsx
+++ b/src/plugins/init/developer-settings/definitions/ReactDevToolsVersionSetting.tsx
@@ -3,7 +3,7 @@ import { React } from '@revenge-mod/react'
import TableRowAssetIcon from '~/components/TableRowAssetIcon'
import { MobileSetting } from '../constants'
-import { DevToolsContext } from '../devtools'
+import { DevToolsContext } from '../react-devtools'
import type { SettingsItem } from '@revenge-mod/discord/modules/settings'
diff --git a/src/plugins/init/developer-settings/index.ts b/src/plugins/init/developer-settings/index.ts
index 90320f1..8770734 100644
--- a/src/plugins/init/developer-settings/index.ts
+++ b/src/plugins/init/developer-settings/index.ts
@@ -6,7 +6,21 @@ import { isSettingsModulesLoaded, onSettingsModulesLoaded } from '@revenge-mod/d
import type { PluginApi } from '@revenge-mod/plugins/types'
-registerPlugin(
+interface Storage {
+ devtools: {
+ address: string
+ autoConnect: boolean
+ }
+}
+
+const defaultStorage: Storage = {
+ devtools: {
+ address: 'localhost:8097',
+ autoConnect: false,
+ },
+}
+
+registerPlugin(
{
id: 'revenge.settings.developer',
name: 'Developer Settings',
@@ -15,10 +29,19 @@ registerPlugin(
icon: 'WrenchIcon',
},
{
+ storage: {
+ load: true,
+ default: defaultStorage,
+ },
start(api_) {
api = api_
+
if (isSettingsModulesLoaded()) require('./register').register()
else onSettingsModulesLoaded(() => require('./register').register())
+
+ api.storage.get().then(settings => {
+ if (settings.devtools.autoConnect) import('./react-devtools').then(it => it.connectToDevTools())
+ })
},
},
PluginFlags.Enabled,
@@ -26,4 +49,4 @@ registerPlugin(
)
// Expose to EvaluateJavaScriptSetting
-export let api: PluginApi
+export let api: PluginApi
diff --git a/src/plugins/init/developer-settings/devtools.ts b/src/plugins/init/developer-settings/react-devtools.ts
similarity index 98%
rename from src/plugins/init/developer-settings/devtools.ts
rename to src/plugins/init/developer-settings/react-devtools.ts
index c1c27bd..9d293fb 100644
--- a/src/plugins/init/developer-settings/devtools.ts
+++ b/src/plugins/init/developer-settings/react-devtools.ts
@@ -29,7 +29,7 @@ subscriptions.add((e, err) => {
api.logger.error('React DevTools error:', actualError)
ToastActionCreators.open({
- key: 'DEVTOOLS_ERROR',
+ key: 'REACT_DEVTOOLS_ERROR',
IconComponent: CircleXIcon,
content: actualError,
})
diff --git a/src/plugins/init/developer-settings/register.ts b/src/plugins/init/developer-settings/register.ts
index e07bc26..0219556 100644
--- a/src/plugins/init/developer-settings/register.ts
+++ b/src/plugins/init/developer-settings/register.ts
@@ -4,6 +4,7 @@ import { MobileSetting } from './constants'
import AssetBrowserSetting from './definitions/AssetBrowserSetting'
import EvaluateJavaScriptSetting from './definitions/EvaluateJavaScriptSetting'
+import ReactDevToolsAutoConnectSetting from './definitions/ReactDevToolsAutoConnectSetting'
import ReactDevToolsConnectSetting from './definitions/ReactDevToolsConnectSetting'
import ReactDevToolsDisconnectSetting from './definitions/ReactDevToolsDisconnectSetting'
import ReactDevToolsVersionSetting from './definitions/ReactDevToolsVersionSetting'
@@ -16,6 +17,7 @@ export function register() {
registerSettingsItems({
[MobileSetting.REVENGE_DEVELOPER]: RevengeDeveloperSetting,
[MobileSetting.REACT_DEVTOOLS_VERSION]: ReactDevToolsVersionSetting,
+ [MobileSetting.REACT_DEVTOOLS_AUTO_CONNECT]: ReactDevToolsAutoConnectSetting,
[MobileSetting.REACT_DEVTOOLS_CONNECT]: ReactDevToolsConnectSetting,
[MobileSetting.REACT_DEVTOOLS_DISCONNECT]: ReactDevToolsDisconnectSetting,
[MobileSetting.EVALUATE_JAVASCRIPT]: EvaluateJavaScriptSetting,
diff --git a/src/plugins/init/developer-settings/screens/AssetBrowserSettingScreen.tsx b/src/plugins/init/developer-settings/screens/AssetBrowserSettingScreen.tsx
index 1afb61e..9bf4dec 100644
--- a/src/plugins/init/developer-settings/screens/AssetBrowserSettingScreen.tsx
+++ b/src/plugins/init/developer-settings/screens/AssetBrowserSettingScreen.tsx
@@ -8,12 +8,13 @@ import Page from '~/components/Page'
import SearchInput from '~/components/SearchInput'
import TableRowAssetIcon from '~/components/TableRowAssetIcon'
-import { getAllAssets, getAssetId } from '@revenge-mod/assets'
+import { getAllAssets, getAssetId, getAssetModuleId } from '@revenge-mod/assets'
import type { Asset, AssetId } from '@revenge-mod/assets/types'
+import type { Metro } from '@revenge-mod/modules/types'
-const { Image, StyleSheet, View } = ReactNative
-const { AlertModal, AlertActionButton, TableRow, Text, Stack } = Design
+const { Image, StyleSheet } = ReactNative
+const { AlertModal, AlertActionButton, TableRow, TableRowGroup, Text } = Design
const Displayable = new Set(['png', 'jpg', 'svg', 'webp'])
const UndisplayableFallback = {
@@ -27,7 +28,7 @@ const UndisplayableFallback = {
export default function AssetBrowserSettingScreen() {
const [search, setSearch] = React.useState('')
const assets = React.useMemo(
- () => [...getAllAssets()].map(asset => [getAssetId(asset)!, asset] as const),
+ () => [...getAllAssets()].map(asset => [getAssetId(asset)!, getAssetModuleId(asset)!, asset] as const),
[getAllAssets],
)
@@ -35,39 +36,58 @@ export default function AssetBrowserSettingScreen() {
() =>
!search.length
? assets
- : assets.filter(([_, asset]) => asset.name.toLowerCase().includes(search.toLowerCase())),
+ : assets.filter(([, , asset]) => asset.name.toLowerCase().includes(search.toLowerCase())),
[assets, search],
)
return (
setSearch(v)} />
-
- }
- estimatedItemSize={80}
- />
-
+ id.toString()}
+ renderItem={({ item: [id, moduleId, asset], index }) => (
+
+ )}
+ estimatedItemSize={80}
+ />
)
}
function AssetDisplay({
id,
+ moduleId,
asset,
+ start,
+ end,
}: {
id: AssetId
+ moduleId: Metro.ModuleID
asset: Asset
+ start?: boolean
+ end?: boolean
}) {
const isDisplayable = Displayable.has(asset.type)
- const metadata = [`ID: ${id}`, `Type: ${asset.type}`]
+ const metadata = [
+ ['ID', id.toString()],
+ ['Type', asset.type],
+ ['Module ID', moduleId.toString()],
+ ] as const
return (
`${name}: ${value}`).join(' • ')}
icon={
isDisplayable ? (
@@ -82,40 +102,50 @@ function AssetDisplay({
/>
)
}
- onPress={() =>
- AlertActionCreators.openAlert(
- 'asset-display',
-
- ) : (
-
- )
- }
- actions={
-
- Clipboard.setString(asset.name)}
- />
- Clipboard.setString(id.toString())}
- />
-
- }
- />,
- )
- }
+ onPress={() => openAssetDisplayAlert(asset, id, metadata)}
/>
)
}
+function openAssetDisplayAlert(
+ asset: Asset,
+ id: AssetId,
+ metadata: Readonly[]> | [string, string][],
+) {
+ const isDisplayable = Displayable.has(asset.type)
+
+ AlertActionCreators.openAlert(
+ 'asset-display',
+
+ {isDisplayable ? (
+
+ ) : (
+
+ )}
+
+ {metadata.map(([name, value]) => (
+ Clipboard.setString(value)}
+ />
+ ))}
+
+
+ Note: Asset IDs and module IDs are not consistent between app launches and app versions
+ respectively and should only be used when absolutely needed.
+
+ >
+ }
+ actions={}
+ />,
+ )
+}
+
function PreviewUnavailable({ type }: { type: string }) {
return (
@@ -125,11 +155,6 @@ function PreviewUnavailable({ type }: { type: string }) {
}
const styles = StyleSheet.create({
- listContainer: {
- flex: 1,
- borderRadius: 16,
- overflow: 'hidden',
- },
smallPreview: {
height: 32,
width: 32,
diff --git a/src/plugins/init/developer-settings/screens/RevengeDeveloperSettingScreen.tsx b/src/plugins/init/developer-settings/screens/RevengeDeveloperSettingScreen.tsx
index 69dfc19..a17fe93 100644
--- a/src/plugins/init/developer-settings/screens/RevengeDeveloperSettingScreen.tsx
+++ b/src/plugins/init/developer-settings/screens/RevengeDeveloperSettingScreen.tsx
@@ -3,7 +3,16 @@ import { SettingListRenderer } from '@revenge-mod/discord/modules/settings/rende
import { React, ReactNative } from '@revenge-mod/react'
import { MobileSetting } from '../constants'
-import { DevToolsContext } from '../devtools'
+import { DevToolsContext, useIsDevToolsOpen } from '../react-devtools'
+import { api } from '..'
+import { ToastActionCreators } from '@revenge-mod/discord/actions'
+import { lookupGeneratedIconComponent } from '@revenge-mod/utils/discord'
+
+const CircleCheckIcon = lookupGeneratedIconComponent(
+ 'CircleCheckIcon',
+ 'CircleCheckIcon-secondary',
+ 'CircleCheckIcon-primary',
+)
// TODO(plugins/settings): debug bridge
export default function RevengeDeveloperSettingScreen() {
@@ -18,6 +27,7 @@ export default function RevengeDeveloperSettingScreen() {
{
settings: [
MobileSetting.REACT_DEVTOOLS_VERSION,
+ MobileSetting.REACT_DEVTOOLS_AUTO_CONNECT,
MobileSetting.REACT_DEVTOOLS_CONNECT,
MobileSetting.REACT_DEVTOOLS_DISCONNECT,
],
@@ -33,15 +43,33 @@ export default function RevengeDeveloperSettingScreen() {
}
export function ReactDevToolsAddressSetting() {
+ const open = useIsDevToolsOpen()
+ const settings = api.storage.use(s => s.devtools?.address)
+
return (
(DevToolsContext.address = text)}
+ onBlur={() => {
+ api.storage
+ .set({
+ devtools: {
+ address: DevToolsContext.address,
+ },
+ })
+ .then(() => {
+ ToastActionCreators.open({
+ IconComponent: CircleCheckIcon,
+ key: 'REACT_DEVTOOLS_ADDRESS_SAVED',
+ content: 'Address saved',
+ })
+ })
+ }}
returnKeyType="done"
/>