From f184c3cc0d0393174c3007669a0ddae5d38500f4 Mon Sep 17 00:00:00 2001 From: j0ntz Date: Thu, 26 Feb 2026 17:53:49 -0800 Subject: [PATCH 1/8] Add debug settings scene --- CHANGELOG.md | 4 + src/components/Main.tsx | 9 + src/components/scenes/DebugScene.tsx | 733 ++++++++++++++++++++++++ src/components/scenes/SettingsScene.tsx | 10 + src/locales/en_US.ts | 17 + src/locales/strings/enUS.json | 17 + src/types/routerTypes.tsx | 1 + 7 files changed, 791 insertions(+) create mode 100644 src/components/scenes/DebugScene.tsx diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e919961dbf..97424431f97 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # edge-react-gui +## Unreleased (develop) + +- added: Debug settings scene (Developer Mode only) with nodes/servers inspection, engine `dataDump` viewer, and log viewer + ## 4.45.0 (staging) - fixed: Fixed Zano token minting transaction detection issues. diff --git a/src/components/Main.tsx b/src/components/Main.tsx index ac7c71d8729..71de1794e5d 100644 --- a/src/components/Main.tsx +++ b/src/components/Main.tsx @@ -71,6 +71,7 @@ import { CreateWalletImportScene as CreateWalletImportSceneComponent } from './s import { CreateWalletSelectCryptoScene as CreateWalletSelectCryptoSceneComponent } from './scenes/CreateWalletSelectCryptoScene' import { CurrencyNotificationScene as CurrencyNotificationSceneComponent } from './scenes/CurrencyNotificationScene' import { CurrencySettingsScene as CurrencySettingsSceneComponent } from './scenes/CurrencySettingsScene' +import { DebugScene as DebugSceneComponent } from './scenes/DebugScene' import { DefaultFiatSettingScene as DefaultFiatSettingSceneComponent } from './scenes/DefaultFiatSettingScene' import { DevTestScene } from './scenes/DevTestScene' import { DuressModeHowToScene as DuressModeHowToSceneComponent } from './scenes/DuressModeHowToScene' @@ -209,6 +210,7 @@ const CreateWalletSelectFiatScene = ifLoggedIn( ) const CurrencyNotificationScene = ifLoggedIn(CurrencyNotificationSceneComponent) const CurrencySettingsScene = ifLoggedIn(CurrencySettingsSceneComponent) +const DebugScene = ifLoggedIn(DebugSceneComponent) const DefaultFiatSettingScene = ifLoggedIn(DefaultFiatSettingSceneComponent) const EarnScene = ifLoggedIn(EarnSceneComponent) const EdgeLoginScene = ifLoggedIn(EdgeLoginSceneComponent) @@ -1105,6 +1107,13 @@ const EdgeAppStack: React.FC = () => { options={{ headerShown: false }} /> + + +interface DumpResult { + dump?: EdgeDataDump + error?: string +} + +const formatJson = (value: unknown): string => { + try { + return JSON.stringify(value, null, 2) + } catch (error: unknown) { + return error instanceof Error ? error.message : String(error) + } +} + +// --------------------------------------------------------------------------- +// Sub-components for per-wallet rows (avoids inline arrow fns in JSX) +// --------------------------------------------------------------------------- + +interface NodesWalletSectionProps { + wallet: EdgeCurrencyWallet + dumpResult: DumpResult | undefined + isExpanded: boolean + isLoading: boolean + onToggle: (walletId: string) => void + onLongPress: (walletId: string) => void +} + +const NodesWalletSection: React.FC = props => { + const { wallet, dumpResult, isExpanded, isLoading, onToggle, onLongPress } = + props + const theme = useTheme() + const styles = getStyles(theme) + + const handleToggle = useHandler(() => { + onToggle(wallet.id) + }) + + const handleLongPress = useHandler(() => { + onLongPress(wallet.id) + }) + + const walletLabel = `${wallet.name ?? wallet.currencyInfo.currencyCode} (${ + wallet.currencyInfo.pluginId + })` + + const data = dumpResult?.dump?.data + + return ( + + + + {walletLabel} + + {isLoading ? ( + + ) : ( + + )} + + {isExpanded && data != null ? ( + + + {lstrings.settings_debug_defaults} + + + + {formatJson(data.defaultServers ?? {})} + + + + + {lstrings.settings_debug_info_servers} + + + + {formatJson(data.infoServerServers ?? {})} + + + + + {lstrings.settings_debug_custom_servers} + + + + {formatJson(data.customServers ?? {})} + + + + + {lstrings.settings_debug_user_settings} + + + + {formatJson(wallet.currencyConfig.userSettings ?? {})} + + + + {data.networkConfig != null ? ( + <> + + {lstrings.settings_debug_network_config} + + + + {formatJson(data.networkConfig)} + + + + ) : null} + + ) : null} + {isExpanded && dumpResult?.error != null ? ( + + {dumpResult.error} + + ) : null} + + ) +} + +interface DumpWalletRowProps { + wallet: EdgeCurrencyWallet + dumpResult: DumpResult | undefined + isExpanded: boolean + isLoading: boolean + onPress: (walletId: string) => void + onLongPress: (walletId: string) => void +} + +const DumpWalletRow: React.FC = props => { + const { wallet, dumpResult, isExpanded, isLoading, onPress, onLongPress } = + props + const theme = useTheme() + const styles = getStyles(theme) + + const handlePress = useHandler(() => { + onPress(wallet.id) + }) + + const handleLongPress = useHandler(() => { + onLongPress(wallet.id) + }) + + const walletLabel = `${wallet.name ?? wallet.currencyInfo.currencyCode} (${ + wallet.currencyInfo.pluginId + })` + + return ( + + + + {walletLabel} + + {isLoading ? ( + + ) : ( + + )} + + {isExpanded && dumpResult?.dump != null ? ( + + + {formatJson(dumpResult.dump)} + + + ) : null} + {isExpanded && dumpResult?.error != null ? ( + + {dumpResult.error} + + ) : null} + + ) +} + +// --------------------------------------------------------------------------- +// Main scene +// --------------------------------------------------------------------------- + +export const DebugScene: React.FC = () => { + const theme = useTheme() + const styles = getStyles(theme) + const account = useSelector(state => state.core.account) + const wallets = Object.values(account.currencyWallets) + + const [showNodesAndServers, setShowNodesAndServers] = React.useState(false) + const [showDataDump, setShowDataDump] = React.useState(false) + const [showLogs, setShowLogs] = React.useState(false) + const [walletDumpMap, setWalletDumpMap] = React.useState< + Record + >({}) + const [walletExpandedMap, setWalletExpandedMap] = React.useState< + Record + >({}) + const [loadingWallets, setLoadingWallets] = React.useState< + Record + >({}) + const [logsInfo, setLogsInfo] = React.useState('') + const [logsActivity, setLogsActivity] = React.useState('') + const [showInfoLog, setShowInfoLog] = React.useState(false) + const [showActivityLog, setShowActivityLog] = React.useState(false) + + const logsLoadedRef = React.useRef(false) + + // --- Core async operations --- + + const loadWalletDump = useHandler(async (walletId: string): Promise => { + const wallet = account.currencyWallets[walletId] + if (wallet == null) return + setLoadingWallets(prev => ({ ...prev, [walletId]: true })) + try { + const dump = await wallet.dumpData() + setWalletDumpMap(prev => ({ ...prev, [walletId]: { dump } })) + } catch (error: unknown) { + setWalletDumpMap(prev => ({ + ...prev, + [walletId]: { + error: error instanceof Error ? error.message : String(error) + } + })) + showError(error) + } finally { + setLoadingWallets(prev => ({ ...prev, [walletId]: false })) + } + }) + + const handleRefreshLogs = useHandler(async (): Promise => { + const [info, activity] = await Promise.all([ + readLogs('info'), + readLogs('activity') + ]) + setLogsInfo(info ?? '') + setLogsActivity(activity ?? '') + }) + + // --- Section toggle handlers --- + + const handleToggleNodesAndServers = useHandler(() => { + setShowNodesAndServers(prev => !prev) + }) + + const handleToggleDataDump = useHandler(() => { + setShowDataDump(prev => !prev) + }) + + const handleToggleLogs = useHandler(() => { + setShowLogs(prev => !prev) + }) + + // --- Long press (copy) handlers for top-level sections --- + + const handleLongPressNodesAndServers = useHandler(() => { + const nodesData: Record = {} + for (const wallet of wallets) { + const data = walletDumpMap[wallet.id]?.dump?.data + if (data != null) { + const key = `${wallet.name ?? wallet.currencyInfo.currencyCode} (${ + wallet.currencyInfo.pluginId + })` + nodesData[key] = { + defaultServers: data.defaultServers ?? {}, + infoServerServers: data.infoServerServers ?? {}, + customServers: data.customServers ?? {}, + userSettings: wallet.currencyConfig.userSettings ?? {}, + ...(data.networkConfig != null + ? { networkConfig: data.networkConfig } + : {}) + } + } + } + Clipboard.setString(formatJson(nodesData)) + showToast( + sprintf( + lstrings.settings_debug_copied_1s, + lstrings.settings_debug_nodes_servers + ) + ) + }) + + const handleLongPressDataDump = useHandler(() => { + const dumpData: Record = {} + for (const wallet of wallets) { + const dump = walletDumpMap[wallet.id]?.dump + if (dump != null) { + const key = `${wallet.name ?? wallet.currencyInfo.currencyCode} (${ + wallet.currencyInfo.pluginId + })` + dumpData[key] = dump + } + } + Clipboard.setString(formatJson(dumpData)) + showToast( + sprintf( + lstrings.settings_debug_copied_1s, + lstrings.settings_debug_engine_dump + ) + ) + }) + + const handleLongPressLogs = useHandler(() => { + const allLogs = `=== Info Log ===\n${logsInfo}\n\n=== Activity Log ===\n${logsActivity}` + Clipboard.setString(allLogs) + showToast( + sprintf(lstrings.settings_debug_copied_1s, lstrings.settings_debug_logs) + ) + }) + + // --- Long press (copy) handlers for log sub-sections --- + + const handleLongPressInfoLog = useHandler(() => { + Clipboard.setString(logsInfo) + showToast( + sprintf( + lstrings.settings_debug_copied_1s, + lstrings.settings_debug_info_log + ) + ) + }) + + const handleLongPressActivityLog = useHandler(() => { + Clipboard.setString(logsActivity) + showToast( + sprintf( + lstrings.settings_debug_copied_1s, + lstrings.settings_debug_activity_log + ) + ) + }) + + // --- Per-wallet handlers --- + + const handleNodesWalletToggle = useHandler((walletId: string): void => { + setWalletExpandedMap(prev => ({ + ...prev, + [`nodes:${walletId}`]: !(prev[`nodes:${walletId}`] ?? false) + })) + }) + + const handleNodesWalletLongPress = useHandler((walletId: string): void => { + const wallet = account.currencyWallets[walletId] + const data = walletDumpMap[walletId]?.dump?.data + if (data != null && wallet != null) { + const content = { + defaultServers: data.defaultServers ?? {}, + infoServerServers: data.infoServerServers ?? {}, + customServers: data.customServers ?? {}, + userSettings: wallet.currencyConfig.userSettings ?? {}, + ...(data.networkConfig != null + ? { networkConfig: data.networkConfig } + : {}) + } + Clipboard.setString(formatJson(content)) + const label = `${wallet.name ?? wallet.currencyInfo.currencyCode} (${ + wallet.currencyInfo.pluginId + })` + showToast(sprintf(lstrings.settings_debug_copied_1s, label)) + } + }) + + const handleDumpWalletPress = useHandler((walletId: string): void => { + const dumpResult = walletDumpMap[walletId] + if (dumpResult == null && !(loadingWallets[walletId] ?? false)) { + loadWalletDump(walletId).catch((error: unknown) => { + showError(error) + }) + setWalletExpandedMap(prev => ({ + ...prev, + [`dump:${walletId}`]: true + })) + } else { + setWalletExpandedMap(prev => ({ + ...prev, + [`dump:${walletId}`]: !(prev[`dump:${walletId}`] ?? false) + })) + } + }) + + const handleDumpWalletLongPress = useHandler((walletId: string): void => { + const dump = walletDumpMap[walletId]?.dump + if (dump != null) { + const wallet = account.currencyWallets[walletId] + Clipboard.setString(formatJson(dump)) + const label = + wallet != null + ? `${wallet.name ?? wallet.currencyInfo.currencyCode} (${ + wallet.currencyInfo.pluginId + })` + : walletId + showToast(sprintf(lstrings.settings_debug_copied_1s, label)) + } + }) + + const handleToggleInfoLog = useHandler(() => { + setShowInfoLog(prev => !prev) + }) + + const handleToggleActivityLog = useHandler(() => { + setShowActivityLog(prev => !prev) + }) + + // --- Auto-load effects --- + + React.useEffect(() => { + if (!showNodesAndServers) return + for (const wallet of wallets) { + if ( + walletDumpMap[wallet.id] == null && + !(loadingWallets[wallet.id] ?? false) + ) { + loadWalletDump(wallet.id).catch((error: unknown) => { + showError(error) + }) + } + } + // Intentionally triggers only on section open. loadWalletDump is stable + // via useHandler; wallets/walletDumpMap are read from the current closure. + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [showNodesAndServers]) + + React.useEffect(() => { + if (showLogs && !logsLoadedRef.current) { + logsLoadedRef.current = true + handleRefreshLogs().catch((error: unknown) => { + showError(error) + }) + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [showLogs]) + + // --- Render --- + + return ( + + + {lstrings.settings_debug_long_press_hint} + + + + {/* Nodes & Servers */} + + + + {lstrings.settings_debug_nodes_servers} + + + + {showNodesAndServers + ? wallets.map(wallet => ( + + )) + : null} + + + {/* Engine dataDump */} + + + + {lstrings.settings_debug_engine_dump} + + + + {showDataDump && wallets.length === 0 ? ( + + {lstrings.settings_debug_no_wallets} + + ) : null} + {showDataDump + ? wallets.map(wallet => ( + + )) + : null} + + + {/* Log Viewer */} + + + + {lstrings.settings_debug_logs} + + + + {showLogs ? ( + <> + + + + + {lstrings.settings_debug_info_log} + + + + {showInfoLog ? ( + + {__DEV__ ? ( + + {lstrings.settings_debug_info_log_dev} + + ) : logsInfo.trim() !== '' ? ( + + {logsInfo} + + ) : ( + + {lstrings.settings_debug_no_logs} + + )} + + ) : null} + + + + {lstrings.settings_debug_activity_log} + + + + {showActivityLog ? ( + + {logsActivity.trim() !== '' ? ( + + {logsActivity} + + ) : ( + + {lstrings.settings_debug_no_logs} + + )} + + ) : null} + + ) : null} + + + + ) +} + +// --------------------------------------------------------------------------- +// Styles +// --------------------------------------------------------------------------- + +const getStyles = cacheStyles((theme: Theme) => ({ + hintText: { + fontSize: theme.rem(0.7), + color: theme.deactivatedText, + textAlign: 'center' as const, + paddingVertical: theme.rem(0.5) + }, + sectionHeader: { + flexDirection: 'row' as const, + justifyContent: 'space-between' as const, + alignItems: 'center' as const, + padding: theme.rem(0.75) + }, + sectionTitle: { + fontSize: theme.rem(1), + fontFamily: theme.fontFaceMedium + }, + walletHeader: { + flexDirection: 'row' as const, + justifyContent: 'space-between' as const, + alignItems: 'center' as const, + paddingVertical: theme.rem(0.5), + paddingHorizontal: theme.rem(0.75) + }, + walletTitle: { + fontSize: theme.rem(0.875), + fontFamily: theme.fontFaceMedium, + flexShrink: 1, + marginRight: theme.rem(0.5) + }, + walletContent: { + paddingHorizontal: theme.rem(0.75), + paddingBottom: theme.rem(0.5) + }, + subLabel: { + fontSize: theme.rem(0.8), + fontFamily: theme.fontFaceBold, + marginTop: theme.rem(0.5), + marginBottom: theme.rem(0.25) + }, + jsonBox: { + maxHeight: theme.rem(12), + marginBottom: theme.rem(0.25), + padding: theme.rem(0.5), + backgroundColor: theme.tileBackground, + borderRadius: theme.rem(0.5), + borderWidth: 1, + borderColor: theme.lineDivider + }, + logText: { + fontSize: theme.rem(0.5), + fontFamily: Platform.OS === 'ios' ? 'Menlo' : 'monospace', + color: theme.primaryText + }, + logSubHeader: { + flexDirection: 'row' as const, + justifyContent: 'space-between' as const, + alignItems: 'center' as const, + paddingVertical: theme.rem(0.5), + paddingHorizontal: theme.rem(0.75) + }, + logSectionLabel: { + fontSize: theme.rem(0.9), + fontFamily: theme.fontFaceBold + }, + logBox: { + maxHeight: theme.rem(20), + marginHorizontal: theme.rem(0.5), + marginBottom: theme.rem(0.5), + padding: theme.rem(0.5), + backgroundColor: theme.tileBackground, + borderRadius: theme.rem(0.5), + borderWidth: 1, + borderColor: theme.lineDivider + }, + logEmptyText: { + fontSize: theme.rem(0.75), + color: theme.deactivatedText + }, + errorText: { + fontSize: theme.rem(0.65), + fontFamily: Platform.OS === 'ios' ? 'Menlo' : 'monospace', + color: theme.dangerText, + padding: theme.rem(0.5) + }, + emptyText: { + padding: theme.rem(0.75) + } +})) diff --git a/src/components/scenes/SettingsScene.tsx b/src/components/scenes/SettingsScene.tsx index 6f87e29bd85..fe8fb3f3540 100644 --- a/src/components/scenes/SettingsScene.tsx +++ b/src/components/scenes/SettingsScene.tsx @@ -416,6 +416,10 @@ export const SettingsScene: React.FC = props => { navigation.navigate('swapSettings') }) + const handleOpenDebugSettings = useHandler((): void => { + navigation.navigate('debugSettings') + }) + const handleSpendingLimits = useHandler(async (): Promise => { if (await hasLock()) return navigation.navigate('spendingLimits') @@ -732,6 +736,12 @@ export const SettingsScene: React.FC = props => { }} /> )} + {developerModeOn && ( + + )} )} diff --git a/src/locales/en_US.ts b/src/locales/en_US.ts index 5f6b1d5a827..9b1c1693cbf 100644 --- a/src/locales/en_US.ts +++ b/src/locales/en_US.ts @@ -513,6 +513,23 @@ const strings = { settings_button_change_password: 'Change Password', settings_button_change_username: 'Change Username', settings_developer_mode: 'Developer Mode', + settings_debug_title: 'Debug', + settings_debug_nodes_servers: 'Nodes & Servers', + settings_debug_engine_dump: 'Engine dataDump', + settings_debug_logs: 'Info/Activity Logs', + settings_debug_refresh_logs: 'Refresh', + settings_debug_defaults: 'Defaults', + settings_debug_info_servers: 'Info-Server Added', + settings_debug_custom_servers: 'User Added', + settings_debug_user_settings: 'User Settings', + settings_debug_network_config: 'Network Config', + settings_debug_no_wallets: 'No wallets available', + settings_debug_info_log: 'Info Log', + settings_debug_activity_log: 'Activity Log', + settings_debug_no_logs: 'No logs available', + settings_debug_info_log_dev: 'Not available in __DEV__', + settings_debug_long_press_hint: 'Long press any header to copy', + settings_debug_copied_1s: 'Copied: %1$s', settings_verbose_logging: 'Verbose Logging', settings_theme: 'Theme', settings_theme_light: 'Light', diff --git a/src/locales/strings/enUS.json b/src/locales/strings/enUS.json index 2ce36adcf86..5aabb0ecdb6 100644 --- a/src/locales/strings/enUS.json +++ b/src/locales/strings/enUS.json @@ -367,6 +367,23 @@ "settings_button_change_password": "Change Password", "settings_button_change_username": "Change Username", "settings_developer_mode": "Developer Mode", + "settings_debug_title": "Debug", + "settings_debug_nodes_servers": "Nodes & Servers", + "settings_debug_engine_dump": "Engine dataDump", + "settings_debug_logs": "Info/Activity Logs", + "settings_debug_refresh_logs": "Refresh", + "settings_debug_defaults": "Defaults", + "settings_debug_info_servers": "Info-Server Added", + "settings_debug_custom_servers": "User Added", + "settings_debug_user_settings": "User Settings", + "settings_debug_network_config": "Network Config", + "settings_debug_no_wallets": "No wallets available", + "settings_debug_info_log": "Info Log", + "settings_debug_activity_log": "Activity Log", + "settings_debug_no_logs": "No logs available", + "settings_debug_info_log_dev": "Not available in __DEV__", + "settings_debug_long_press_hint": "Long press any header to copy", + "settings_debug_copied_1s": "Copied: %1$s", "settings_verbose_logging": "Verbose Logging", "settings_theme": "Theme", "settings_theme_light": "Light", diff --git a/src/types/routerTypes.tsx b/src/types/routerTypes.tsx index 9c53eddc19f..549cd757894 100644 --- a/src/types/routerTypes.tsx +++ b/src/types/routerTypes.tsx @@ -181,6 +181,7 @@ export type EdgeAppStackParamList = {} & { createWalletSelectCryptoNewAccount: CreateWalletSelectCryptoParams currencyNotificationSettings: CurrencyNotificationParams currencySettings: CurrencySettingsParams + debugSettings: undefined defaultFiatSetting: undefined duressModeHowTo: undefined duressModeSetting: undefined From a106ef53877c28fb643ab1be19418f29c6aa3b34 Mon Sep 17 00:00:00 2001 From: j0ntz Date: Wed, 4 Mar 2026 10:41:08 -0800 Subject: [PATCH 2/8] fixup! Add debug settings scene Addressing Sam's comments. --- src/components/scenes/DebugScene.tsx | 416 ++++++++++++++------------- 1 file changed, 216 insertions(+), 200 deletions(-) diff --git a/src/components/scenes/DebugScene.tsx b/src/components/scenes/DebugScene.tsx index 8bc7607a63f..fdb75801b3d 100644 --- a/src/components/scenes/DebugScene.tsx +++ b/src/components/scenes/DebugScene.tsx @@ -31,18 +31,6 @@ interface DumpResult { error?: string } -const formatJson = (value: unknown): string => { - try { - return JSON.stringify(value, null, 2) - } catch (error: unknown) { - return error instanceof Error ? error.message : String(error) - } -} - -// --------------------------------------------------------------------------- -// Sub-components for per-wallet rows (avoids inline arrow fns in JSX) -// --------------------------------------------------------------------------- - interface NodesWalletSectionProps { wallet: EdgeCurrencyWallet dumpResult: DumpResult | undefined @@ -52,107 +40,6 @@ interface NodesWalletSectionProps { onLongPress: (walletId: string) => void } -const NodesWalletSection: React.FC = props => { - const { wallet, dumpResult, isExpanded, isLoading, onToggle, onLongPress } = - props - const theme = useTheme() - const styles = getStyles(theme) - - const handleToggle = useHandler(() => { - onToggle(wallet.id) - }) - - const handleLongPress = useHandler(() => { - onLongPress(wallet.id) - }) - - const walletLabel = `${wallet.name ?? wallet.currencyInfo.currencyCode} (${ - wallet.currencyInfo.pluginId - })` - - const data = dumpResult?.dump?.data - - return ( - - - - {walletLabel} - - {isLoading ? ( - - ) : ( - - )} - - {isExpanded && data != null ? ( - - - {lstrings.settings_debug_defaults} - - - - {formatJson(data.defaultServers ?? {})} - - - - - {lstrings.settings_debug_info_servers} - - - - {formatJson(data.infoServerServers ?? {})} - - - - - {lstrings.settings_debug_custom_servers} - - - - {formatJson(data.customServers ?? {})} - - - - - {lstrings.settings_debug_user_settings} - - - - {formatJson(wallet.currencyConfig.userSettings ?? {})} - - - - {data.networkConfig != null ? ( - <> - - {lstrings.settings_debug_network_config} - - - - {formatJson(data.networkConfig)} - - - - ) : null} - - ) : null} - {isExpanded && dumpResult?.error != null ? ( - - {dumpResult.error} - - ) : null} - - ) -} - interface DumpWalletRowProps { wallet: EdgeCurrencyWallet dumpResult: DumpResult | undefined @@ -162,60 +49,6 @@ interface DumpWalletRowProps { onLongPress: (walletId: string) => void } -const DumpWalletRow: React.FC = props => { - const { wallet, dumpResult, isExpanded, isLoading, onPress, onLongPress } = - props - const theme = useTheme() - const styles = getStyles(theme) - - const handlePress = useHandler(() => { - onPress(wallet.id) - }) - - const handleLongPress = useHandler(() => { - onLongPress(wallet.id) - }) - - const walletLabel = `${wallet.name ?? wallet.currencyInfo.currencyCode} (${ - wallet.currencyInfo.pluginId - })` - - return ( - - - - {walletLabel} - - {isLoading ? ( - - ) : ( - - )} - - {isExpanded && dumpResult?.dump != null ? ( - - - {formatJson(dumpResult.dump)} - - - ) : null} - {isExpanded && dumpResult?.error != null ? ( - - {dumpResult.error} - - ) : null} - - ) -} - // --------------------------------------------------------------------------- // Main scene // --------------------------------------------------------------------------- @@ -297,9 +130,7 @@ export const DebugScene: React.FC = () => { for (const wallet of wallets) { const data = walletDumpMap[wallet.id]?.dump?.data if (data != null) { - const key = `${wallet.name ?? wallet.currencyInfo.currencyCode} (${ - wallet.currencyInfo.pluginId - })` + const key = getWalletLabel(wallet) nodesData[key] = { defaultServers: data.defaultServers ?? {}, infoServerServers: data.infoServerServers ?? {}, @@ -311,7 +142,11 @@ export const DebugScene: React.FC = () => { } } } - Clipboard.setString(formatJson(nodesData)) + try { + Clipboard.setString(JSON.stringify(nodesData, null, 2)) + } catch (error: unknown) { + showError(error) + } showToast( sprintf( lstrings.settings_debug_copied_1s, @@ -325,13 +160,15 @@ export const DebugScene: React.FC = () => { for (const wallet of wallets) { const dump = walletDumpMap[wallet.id]?.dump if (dump != null) { - const key = `${wallet.name ?? wallet.currencyInfo.currencyCode} (${ - wallet.currencyInfo.pluginId - })` + const key = getWalletLabel(wallet) dumpData[key] = dump } } - Clipboard.setString(formatJson(dumpData)) + try { + Clipboard.setString(JSON.stringify(dumpData, null, 2)) + } catch (error: unknown) { + showError(error) + } showToast( sprintf( lstrings.settings_debug_copied_1s, @@ -392,15 +229,19 @@ export const DebugScene: React.FC = () => { ? { networkConfig: data.networkConfig } : {}) } - Clipboard.setString(formatJson(content)) - const label = `${wallet.name ?? wallet.currencyInfo.currencyCode} (${ - wallet.currencyInfo.pluginId - })` + try { + Clipboard.setString(JSON.stringify(content, null, 2)) + } catch (error: unknown) { + showError(error) + } + const label = getWalletLabel(wallet) showToast(sprintf(lstrings.settings_debug_copied_1s, label)) } }) const handleDumpWalletPress = useHandler((walletId: string): void => { + // `walletDumpMap` is shared with Nodes & Servers; that section may have + // already loaded the dump for this wallet. const dumpResult = walletDumpMap[walletId] if (dumpResult == null && !(loadingWallets[walletId] ?? false)) { loadWalletDump(walletId).catch((error: unknown) => { @@ -422,13 +263,12 @@ export const DebugScene: React.FC = () => { const dump = walletDumpMap[walletId]?.dump if (dump != null) { const wallet = account.currencyWallets[walletId] - Clipboard.setString(formatJson(dump)) - const label = - wallet != null - ? `${wallet.name ?? wallet.currencyInfo.currencyCode} (${ - wallet.currencyInfo.pluginId - })` - : walletId + try { + Clipboard.setString(JSON.stringify(dump, null, 2)) + } catch (error: unknown) { + showError(error) + } + const label = wallet != null ? getWalletLabel(wallet) : walletId showToast(sprintf(lstrings.settings_debug_copied_1s, label)) } }) @@ -455,10 +295,13 @@ export const DebugScene: React.FC = () => { }) } } - // Intentionally triggers only on section open. loadWalletDump is stable - // via useHandler; wallets/walletDumpMap are read from the current closure. - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [showNodesAndServers]) + }, [ + loadingWallets, + loadWalletDump, + showNodesAndServers, + walletDumpMap, + wallets + ]) React.useEffect(() => { if (showLogs && !logsLoadedRef.current) { @@ -495,6 +338,11 @@ export const DebugScene: React.FC = () => { color={theme.iconTappable} /> + {showNodesAndServers && wallets.length === 0 ? ( + + {lstrings.settings_debug_no_wallets} + + ) : null} {showNodesAndServers ? wallets.map(wallet => ( = () => { ) } +// --------------------------------------------------------------------------- +// Sub-components (avoid inline arrow fns in JSX handlers) +// --------------------------------------------------------------------------- + +const NodesWalletSection: React.FC = props => { + const { wallet, dumpResult, isExpanded, isLoading, onToggle, onLongPress } = + props + const theme = useTheme() + const styles = getStyles(theme) + + const handleToggle = useHandler(() => { + onToggle(wallet.id) + }) + + const handleLongPress = useHandler(() => { + onLongPress(wallet.id) + }) + + const walletLabel = getWalletLabel(wallet) + + const data = dumpResult?.dump?.data + + return ( + + + + {walletLabel} + + {isLoading ? ( + + ) : ( + + )} + + {isExpanded && data != null ? ( + + + {lstrings.settings_debug_defaults} + + + + {JSON.stringify(data.defaultServers ?? {}, null, 2)} + + + + + {lstrings.settings_debug_info_servers} + + + + {JSON.stringify(data.infoServerServers ?? {}, null, 2)} + + + + + {lstrings.settings_debug_custom_servers} + + + + {JSON.stringify(data.customServers ?? {}, null, 2)} + + + + + {lstrings.settings_debug_user_settings} + + + + {JSON.stringify( + wallet.currencyConfig.userSettings ?? {}, + null, + 2 + )} + + + + {data.networkConfig != null ? ( + <> + + {lstrings.settings_debug_network_config} + + + + {JSON.stringify(data.networkConfig, null, 2)} + + + + ) : null} + + ) : null} + {isExpanded && dumpResult?.error != null ? ( + + {dumpResult.error} + + ) : null} + + ) +} + +const DumpWalletRow: React.FC = props => { + const { wallet, dumpResult, isExpanded, isLoading, onPress, onLongPress } = + props + const theme = useTheme() + const styles = getStyles(theme) + + const handlePress = useHandler(() => { + onPress(wallet.id) + }) + + const handleLongPress = useHandler(() => { + onLongPress(wallet.id) + }) + + const walletLabel = getWalletLabel(wallet) + + return ( + + + + {walletLabel} + + {isLoading ? ( + + ) : ( + + )} + + {isExpanded && dumpResult?.dump != null ? ( + + + {JSON.stringify(dumpResult.dump, null, 2)} + + + ) : null} + {isExpanded && dumpResult?.error != null ? ( + + {dumpResult.error} + + ) : null} + + ) +} + +// --------------------------------------------------------------------------- +// Utilities +// --------------------------------------------------------------------------- + +const getWalletLabel = (wallet: EdgeCurrencyWallet): string => + `${wallet.name ?? wallet.currencyInfo.currencyCode} (${ + wallet.currencyInfo.pluginId + })` + // --------------------------------------------------------------------------- // Styles // --------------------------------------------------------------------------- @@ -646,13 +662,13 @@ const getStyles = cacheStyles((theme: Theme) => ({ hintText: { fontSize: theme.rem(0.7), color: theme.deactivatedText, - textAlign: 'center' as const, + textAlign: 'center', paddingVertical: theme.rem(0.5) }, sectionHeader: { - flexDirection: 'row' as const, - justifyContent: 'space-between' as const, - alignItems: 'center' as const, + flexDirection: 'row', + justifyContent: 'space-between', + alignItems: 'center', padding: theme.rem(0.75) }, sectionTitle: { @@ -660,9 +676,9 @@ const getStyles = cacheStyles((theme: Theme) => ({ fontFamily: theme.fontFaceMedium }, walletHeader: { - flexDirection: 'row' as const, - justifyContent: 'space-between' as const, - alignItems: 'center' as const, + flexDirection: 'row', + justifyContent: 'space-between', + alignItems: 'center', paddingVertical: theme.rem(0.5), paddingHorizontal: theme.rem(0.75) }, @@ -697,9 +713,9 @@ const getStyles = cacheStyles((theme: Theme) => ({ color: theme.primaryText }, logSubHeader: { - flexDirection: 'row' as const, - justifyContent: 'space-between' as const, - alignItems: 'center' as const, + flexDirection: 'row', + justifyContent: 'space-between', + alignItems: 'center', paddingVertical: theme.rem(0.5), paddingHorizontal: theme.rem(0.75) }, From 59b0065bd236020b61ab6bb0af851ebf17d4101e Mon Sep 17 00:00:00 2001 From: j0ntz Date: Wed, 4 Mar 2026 11:18:25 -0800 Subject: [PATCH 3/8] fixup! Add debug settings scene Addressing Bugbot comments. --- src/components/scenes/DebugScene.tsx | 88 +++++++++++----------------- 1 file changed, 33 insertions(+), 55 deletions(-) diff --git a/src/components/scenes/DebugScene.tsx b/src/components/scenes/DebugScene.tsx index fdb75801b3d..a1b0ffc1402 100644 --- a/src/components/scenes/DebugScene.tsx +++ b/src/components/scenes/DebugScene.tsx @@ -80,24 +80,27 @@ export const DebugScene: React.FC = () => { // --- Core async operations --- - const loadWalletDump = useHandler(async (walletId: string): Promise => { + const loadWalletDump = useHandler((walletId: string): void => { const wallet = account.currencyWallets[walletId] if (wallet == null) return setLoadingWallets(prev => ({ ...prev, [walletId]: true })) - try { - const dump = await wallet.dumpData() - setWalletDumpMap(prev => ({ ...prev, [walletId]: { dump } })) - } catch (error: unknown) { - setWalletDumpMap(prev => ({ - ...prev, - [walletId]: { - error: error instanceof Error ? error.message : String(error) - } - })) - showError(error) - } finally { - setLoadingWallets(prev => ({ ...prev, [walletId]: false })) - } + wallet + .dumpData() + .then(dump => { + setWalletDumpMap(prev => ({ ...prev, [walletId]: { dump } })) + }) + .catch((error: unknown) => { + setWalletDumpMap(prev => ({ + ...prev, + [walletId]: { + error: error instanceof Error ? error.message : String(error) + } + })) + showError(error) + }) + .finally(() => { + setLoadingWallets(prev => ({ ...prev, [walletId]: false })) + }) }) const handleRefreshLogs = useHandler(async (): Promise => { @@ -125,6 +128,15 @@ export const DebugScene: React.FC = () => { // --- Long press (copy) handlers for top-level sections --- + const handleCopyJson = useHandler((json: unknown, label: string): void => { + try { + Clipboard.setString(JSON.stringify(json, null, 2)) + showToast(sprintf(lstrings.settings_debug_copied_1s, label)) + } catch (error: unknown) { + showError(error) + } + }) + const handleLongPressNodesAndServers = useHandler(() => { const nodesData: Record = {} for (const wallet of wallets) { @@ -142,17 +154,7 @@ export const DebugScene: React.FC = () => { } } } - try { - Clipboard.setString(JSON.stringify(nodesData, null, 2)) - } catch (error: unknown) { - showError(error) - } - showToast( - sprintf( - lstrings.settings_debug_copied_1s, - lstrings.settings_debug_nodes_servers - ) - ) + handleCopyJson(nodesData, lstrings.settings_debug_nodes_servers) }) const handleLongPressDataDump = useHandler(() => { @@ -164,17 +166,7 @@ export const DebugScene: React.FC = () => { dumpData[key] = dump } } - try { - Clipboard.setString(JSON.stringify(dumpData, null, 2)) - } catch (error: unknown) { - showError(error) - } - showToast( - sprintf( - lstrings.settings_debug_copied_1s, - lstrings.settings_debug_engine_dump - ) - ) + handleCopyJson(dumpData, lstrings.settings_debug_engine_dump) }) const handleLongPressLogs = useHandler(() => { @@ -229,13 +221,8 @@ export const DebugScene: React.FC = () => { ? { networkConfig: data.networkConfig } : {}) } - try { - Clipboard.setString(JSON.stringify(content, null, 2)) - } catch (error: unknown) { - showError(error) - } const label = getWalletLabel(wallet) - showToast(sprintf(lstrings.settings_debug_copied_1s, label)) + handleCopyJson(content, label) } }) @@ -244,9 +231,7 @@ export const DebugScene: React.FC = () => { // already loaded the dump for this wallet. const dumpResult = walletDumpMap[walletId] if (dumpResult == null && !(loadingWallets[walletId] ?? false)) { - loadWalletDump(walletId).catch((error: unknown) => { - showError(error) - }) + loadWalletDump(walletId) setWalletExpandedMap(prev => ({ ...prev, [`dump:${walletId}`]: true @@ -263,13 +248,8 @@ export const DebugScene: React.FC = () => { const dump = walletDumpMap[walletId]?.dump if (dump != null) { const wallet = account.currencyWallets[walletId] - try { - Clipboard.setString(JSON.stringify(dump, null, 2)) - } catch (error: unknown) { - showError(error) - } const label = wallet != null ? getWalletLabel(wallet) : walletId - showToast(sprintf(lstrings.settings_debug_copied_1s, label)) + handleCopyJson(dump, label) } }) @@ -290,9 +270,7 @@ export const DebugScene: React.FC = () => { walletDumpMap[wallet.id] == null && !(loadingWallets[wallet.id] ?? false) ) { - loadWalletDump(wallet.id).catch((error: unknown) => { - showError(error) - }) + loadWalletDump(wallet.id) } } }, [ From e625e3936e9026fb0de6e805966655db320321ad Mon Sep 17 00:00:00 2001 From: j0ntz Date: Wed, 4 Mar 2026 12:16:04 -0800 Subject: [PATCH 4/8] fixup! Add debug settings scene Addressing Bugbot comments. --- src/components/scenes/DebugScene.tsx | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/components/scenes/DebugScene.tsx b/src/components/scenes/DebugScene.tsx index a1b0ffc1402..e0867615a36 100644 --- a/src/components/scenes/DebugScene.tsx +++ b/src/components/scenes/DebugScene.tsx @@ -12,6 +12,7 @@ import Ionicons from 'react-native-vector-icons/Ionicons' import { sprintf } from 'sprintf-js' import { useHandler } from '../../hooks/useHandler' +import { useWatch } from '../../hooks/useWatch' import { lstrings } from '../../locales/strings' import { useSelector } from '../../types/reactRedux' import type { EdgeAppSceneProps } from '../../types/routerTypes' @@ -57,7 +58,8 @@ export const DebugScene: React.FC = () => { const theme = useTheme() const styles = getStyles(theme) const account = useSelector(state => state.core.account) - const wallets = Object.values(account.currencyWallets) + const currencyWallets = useWatch(account, 'currencyWallets') + const wallets = Object.values(currencyWallets) const [showNodesAndServers, setShowNodesAndServers] = React.useState(false) const [showDataDump, setShowDataDump] = React.useState(false) @@ -81,7 +83,7 @@ export const DebugScene: React.FC = () => { // --- Core async operations --- const loadWalletDump = useHandler((walletId: string): void => { - const wallet = account.currencyWallets[walletId] + const wallet = currencyWallets[walletId] if (wallet == null) return setLoadingWallets(prev => ({ ...prev, [walletId]: true })) wallet @@ -142,8 +144,8 @@ export const DebugScene: React.FC = () => { for (const wallet of wallets) { const data = walletDumpMap[wallet.id]?.dump?.data if (data != null) { - const key = getWalletLabel(wallet) - nodesData[key] = { + nodesData[wallet.id] = { + label: getWalletLabel(wallet), defaultServers: data.defaultServers ?? {}, infoServerServers: data.infoServerServers ?? {}, customServers: data.customServers ?? {}, @@ -162,8 +164,10 @@ export const DebugScene: React.FC = () => { for (const wallet of wallets) { const dump = walletDumpMap[wallet.id]?.dump if (dump != null) { - const key = getWalletLabel(wallet) - dumpData[key] = dump + dumpData[wallet.id] = { + label: getWalletLabel(wallet), + dump + } } } handleCopyJson(dumpData, lstrings.settings_debug_engine_dump) From 1b4598c5d00d9feba4a00278d4f1633d127016ef Mon Sep 17 00:00:00 2001 From: j0ntz Date: Wed, 4 Mar 2026 12:53:26 -0800 Subject: [PATCH 5/8] fixup! Add debug settings scene Addressing Bugbot comments. --- src/components/scenes/DebugScene.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/components/scenes/DebugScene.tsx b/src/components/scenes/DebugScene.tsx index e0867615a36..10b2a4d561b 100644 --- a/src/components/scenes/DebugScene.tsx +++ b/src/components/scenes/DebugScene.tsx @@ -59,7 +59,10 @@ export const DebugScene: React.FC = () => { const styles = getStyles(theme) const account = useSelector(state => state.core.account) const currencyWallets = useWatch(account, 'currencyWallets') - const wallets = Object.values(currencyWallets) + const wallets = React.useMemo( + () => Object.values(currencyWallets), + [currencyWallets] + ) const [showNodesAndServers, setShowNodesAndServers] = React.useState(false) const [showDataDump, setShowDataDump] = React.useState(false) @@ -234,7 +237,7 @@ export const DebugScene: React.FC = () => { // `walletDumpMap` is shared with Nodes & Servers; that section may have // already loaded the dump for this wallet. const dumpResult = walletDumpMap[walletId] - if (dumpResult == null && !(loadingWallets[walletId] ?? false)) { + if (dumpResult?.dump == null && !(loadingWallets[walletId] ?? false)) { loadWalletDump(walletId) setWalletExpandedMap(prev => ({ ...prev, From 47061628a2a22ebf692bbfb81480fa4f5e6c2c58 Mon Sep 17 00:00:00 2001 From: j0ntz Date: Wed, 4 Mar 2026 14:28:19 -0800 Subject: [PATCH 6/8] fixup! Add debug settings scene Addressing Bugbot comments. --- src/components/scenes/DebugScene.tsx | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/components/scenes/DebugScene.tsx b/src/components/scenes/DebugScene.tsx index 10b2a4d561b..b876b9cee89 100644 --- a/src/components/scenes/DebugScene.tsx +++ b/src/components/scenes/DebugScene.tsx @@ -237,17 +237,22 @@ export const DebugScene: React.FC = () => { // `walletDumpMap` is shared with Nodes & Servers; that section may have // already loaded the dump for this wallet. const dumpResult = walletDumpMap[walletId] - if (dumpResult?.dump == null && !(loadingWallets[walletId] ?? false)) { + const dumpKey = `dump:${walletId}` + const isExpanded = walletExpandedMap[dumpKey] ?? false + const nextExpanded = !isExpanded + + setWalletExpandedMap(prev => ({ + ...prev, + [dumpKey]: nextExpanded + })) + + // Only retry when expanding: + if ( + nextExpanded && + dumpResult?.dump == null && + !(loadingWallets[walletId] ?? false) + ) { loadWalletDump(walletId) - setWalletExpandedMap(prev => ({ - ...prev, - [`dump:${walletId}`]: true - })) - } else { - setWalletExpandedMap(prev => ({ - ...prev, - [`dump:${walletId}`]: !(prev[`dump:${walletId}`] ?? false) - })) } }) From 337d49a1f6e08689acc6cb80bfe108975450908e Mon Sep 17 00:00:00 2001 From: j0ntz Date: Wed, 4 Mar 2026 15:28:18 -0800 Subject: [PATCH 7/8] fixup! Add debug settings scene Integrating changes needed for PR feedback from currency plugins & accountbased --- src/components/scenes/DebugScene.tsx | 104 ++++++++++++++++----------- src/locales/en_US.ts | 2 +- src/locales/strings/enUS.json | 2 +- 3 files changed, 65 insertions(+), 43 deletions(-) diff --git a/src/components/scenes/DebugScene.tsx b/src/components/scenes/DebugScene.tsx index b876b9cee89..e2bb99c7ad8 100644 --- a/src/components/scenes/DebugScene.tsx +++ b/src/components/scenes/DebugScene.tsx @@ -149,13 +149,7 @@ export const DebugScene: React.FC = () => { if (data != null) { nodesData[wallet.id] = { label: getWalletLabel(wallet), - defaultServers: data.defaultServers ?? {}, - infoServerServers: data.infoServerServers ?? {}, - customServers: data.customServers ?? {}, - userSettings: wallet.currencyConfig.userSettings ?? {}, - ...(data.networkConfig != null - ? { networkConfig: data.networkConfig } - : {}) + ...getNodesContent(data, wallet) } } } @@ -219,17 +213,8 @@ export const DebugScene: React.FC = () => { const wallet = account.currencyWallets[walletId] const data = walletDumpMap[walletId]?.dump?.data if (data != null && wallet != null) { - const content = { - defaultServers: data.defaultServers ?? {}, - infoServerServers: data.infoServerServers ?? {}, - customServers: data.customServers ?? {}, - userSettings: wallet.currencyConfig.userSettings ?? {}, - ...(data.networkConfig != null - ? { networkConfig: data.networkConfig } - : {}) - } const label = getWalletLabel(wallet) - handleCopyJson(content, label) + handleCopyJson(getNodesContent(data, wallet), label) } }) @@ -497,6 +482,7 @@ const NodesWalletSection: React.FC = props => { const walletLabel = getWalletLabel(wallet) const data = dumpResult?.dump?.data + const pluginState = data?.pluginState as Record | undefined return ( @@ -520,32 +506,40 @@ const NodesWalletSection: React.FC = props => { {isExpanded && data != null ? ( - - {lstrings.settings_debug_defaults} - - - - {JSON.stringify(data.defaultServers ?? {}, null, 2)} - - + {pluginState != null ? ( + <> + + {lstrings.settings_debug_active_servers} + + + + {JSON.stringify( + pluginState['pluginState.servers_'] ?? {}, + null, + 2 + )} + + - - {lstrings.settings_debug_info_servers} - - - - {JSON.stringify(data.infoServerServers ?? {}, null, 2)} - - + + {lstrings.settings_debug_info_servers} + + + + {JSON.stringify(pluginState.infoServers ?? [], null, 2)} + + - - {lstrings.settings_debug_custom_servers} - - - - {JSON.stringify(data.customServers ?? {}, null, 2)} - - + + {lstrings.settings_debug_custom_servers} + + + + {JSON.stringify(pluginState.customServers ?? [], null, 2)} + + + + ) : null} {lstrings.settings_debug_user_settings} @@ -644,6 +638,34 @@ const getWalletLabel = (wallet: EdgeCurrencyWallet): string => wallet.currencyInfo.pluginId })` +/** + * Build the nodes/servers content object for a wallet. + * UTXO wallets nest server lists under `data.pluginState`. + * Accountbased wallets provide `data.networkConfig` instead. + */ +const getNodesContent = ( + data: Record, + wallet: EdgeCurrencyWallet +): Record => { + const pluginState = data.pluginState as Record | undefined + const content: Record = {} + + if (pluginState != null) { + content.activeServers = pluginState['pluginState.servers_'] ?? {} + content.infoServers = pluginState.infoServers ?? [] + content.customServers = pluginState.customServers ?? [] + content.enableCustomServers = pluginState.enableCustomServers ?? false + } + + content.userSettings = wallet.currencyConfig.userSettings ?? {} + + if (data.networkConfig != null) { + content.networkConfig = data.networkConfig + } + + return content +} + // --------------------------------------------------------------------------- // Styles // --------------------------------------------------------------------------- diff --git a/src/locales/en_US.ts b/src/locales/en_US.ts index 9b1c1693cbf..ee62a7b5c18 100644 --- a/src/locales/en_US.ts +++ b/src/locales/en_US.ts @@ -518,7 +518,7 @@ const strings = { settings_debug_engine_dump: 'Engine dataDump', settings_debug_logs: 'Info/Activity Logs', settings_debug_refresh_logs: 'Refresh', - settings_debug_defaults: 'Defaults', + settings_debug_active_servers: 'Active Servers', settings_debug_info_servers: 'Info-Server Added', settings_debug_custom_servers: 'User Added', settings_debug_user_settings: 'User Settings', diff --git a/src/locales/strings/enUS.json b/src/locales/strings/enUS.json index 5aabb0ecdb6..61d495de24f 100644 --- a/src/locales/strings/enUS.json +++ b/src/locales/strings/enUS.json @@ -372,7 +372,7 @@ "settings_debug_engine_dump": "Engine dataDump", "settings_debug_logs": "Info/Activity Logs", "settings_debug_refresh_logs": "Refresh", - "settings_debug_defaults": "Defaults", + "settings_debug_active_servers": "Active Servers", "settings_debug_info_servers": "Info-Server Added", "settings_debug_custom_servers": "User Added", "settings_debug_user_settings": "User Settings", From ef65fb3cc6d2db64dbe75ce991d2e8e2b7199293 Mon Sep 17 00:00:00 2001 From: j0ntz Date: Wed, 4 Mar 2026 21:38:44 -0800 Subject: [PATCH 8/8] fixup! Add debug settings scene --- src/components/scenes/DebugScene.tsx | 56 ++++++++++++++++------------ 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/src/components/scenes/DebugScene.tsx b/src/components/scenes/DebugScene.tsx index e2bb99c7ad8..8b13e0d7a02 100644 --- a/src/components/scenes/DebugScene.tsx +++ b/src/components/scenes/DebugScene.tsx @@ -171,33 +171,45 @@ export const DebugScene: React.FC = () => { }) const handleLongPressLogs = useHandler(() => { - const allLogs = `=== Info Log ===\n${logsInfo}\n\n=== Activity Log ===\n${logsActivity}` - Clipboard.setString(allLogs) - showToast( - sprintf(lstrings.settings_debug_copied_1s, lstrings.settings_debug_logs) - ) + try { + const allLogs = `=== Info Log ===\n${logsInfo}\n\n=== Activity Log ===\n${logsActivity}` + Clipboard.setString(allLogs) + showToast( + sprintf(lstrings.settings_debug_copied_1s, lstrings.settings_debug_logs) + ) + } catch (error: unknown) { + showError(error) + } }) // --- Long press (copy) handlers for log sub-sections --- const handleLongPressInfoLog = useHandler(() => { - Clipboard.setString(logsInfo) - showToast( - sprintf( - lstrings.settings_debug_copied_1s, - lstrings.settings_debug_info_log + try { + Clipboard.setString(logsInfo) + showToast( + sprintf( + lstrings.settings_debug_copied_1s, + lstrings.settings_debug_info_log + ) ) - ) + } catch (error: unknown) { + showError(error) + } }) const handleLongPressActivityLog = useHandler(() => { - Clipboard.setString(logsActivity) - showToast( - sprintf( - lstrings.settings_debug_copied_1s, - lstrings.settings_debug_activity_log + try { + Clipboard.setString(logsActivity) + showToast( + sprintf( + lstrings.settings_debug_copied_1s, + lstrings.settings_debug_activity_log + ) ) - ) + } catch (error: unknown) { + showError(error) + } }) // --- Per-wallet handlers --- @@ -270,18 +282,14 @@ export const DebugScene: React.FC = () => { loadWalletDump(wallet.id) } } - }, [ - loadingWallets, - loadWalletDump, - showNodesAndServers, - walletDumpMap, - wallets - ]) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [loadWalletDump, showNodesAndServers, wallets]) React.useEffect(() => { if (showLogs && !logsLoadedRef.current) { logsLoadedRef.current = true handleRefreshLogs().catch((error: unknown) => { + logsLoadedRef.current = false showError(error) }) }