()
| 91 | }; |
| 92 | |
| 93 | const DetailViewStackScreensStack = () => { |
| 94 | const theme = useTheme(); |
| 95 | const navigation = useExtendedNavigation(); |
| 96 | const { walletTransactionUpdateStatus } = useStorage(); |
| 97 | const { isElectrumDisabled } = useSettings(); |
| 98 | const { sizeClass } = useSizeClass(); |
| 99 | const [electrumConnected, setElectrumConnected] = useState<boolean | null>(null); |
| 100 | |
| 101 | // Probe connection health from the UI (e.g. WalletsList focus / 30s timer). |
| 102 | // BlueElectrum.ping() reflects the result into the shared connection state, which |
| 103 | // we observe via the subscription below — no need to set local state here. |
| 104 | const pollConnection = useCallback(async () => { |
| 105 | if (isElectrumDisabled) return; |
| 106 | await BlueElectrum.ping(); |
| 107 | }, [isElectrumDisabled]); |
| 108 | |
| 109 | // Mirror BlueElectrum's connection state into local UI state. |
| 110 | useEffect(() => { |
| 111 | if (isElectrumDisabled) { |
| 112 | setElectrumConnected(null); |
| 113 | return; |
| 114 | } |
| 115 | const sync = () => setElectrumConnected(BlueElectrum.isConnected()); |
| 116 | sync(); |
| 117 | const unsubscribe = BlueElectrum.subscribeConnectionState(sync); |
| 118 | // Kick off an initial probe so the header pill reflects reality after mount. |
| 119 | BlueElectrum.ping().catch(() => {}); |
| 120 | return unsubscribe; |
| 121 | }, [isElectrumDisabled]); |
| 122 | |
| 123 | // On foreground transition, proactively heal: ensureConnected() takes the fast |
| 124 | // ping path when the socket is alive (no-op) and rebuilds the connection only |
| 125 | // when needed. This replaces the old "ping → maybe show network alert" path that |
| 126 | // could surface a false alert after iOS suspend/resume. |
| 127 | useEffect(() => { |
| 128 | if (isElectrumDisabled) return; |
| 129 | const subscription = AppState.addEventListener('change', nextState => { |
| 130 | if (nextState === 'active') { |
| 131 | BlueElectrum.ensureConnected().catch(() => {}); |
| 132 | } |
| 133 | }); |
| 134 | return () => subscription.remove(); |
| 135 | }, [isElectrumDisabled]); |
| 136 | |
| 137 | // While we believe we're disconnected, ask BlueElectrum to keep trying to |
| 138 | // reconnect (silently — the red "Not connected" pill is the only UI signal). |
| 139 | useEffect(() => { |
| 140 | if (isElectrumDisabled || electrumConnected !== false) return; |
| 141 | const interval = setInterval(() => { |
| 142 | BlueElectrum.ensureConnected().catch(() => {}); |
| 143 | }, 3000); |
| 144 | return () => clearInterval(interval); |
| 145 | }, [isElectrumDisabled, electrumConnected]); |
| 146 | |
| 147 | const connectionPollContextValue = useMemo(() => ({ pollConnection }), [pollConnection]); |
| 148 | |
| 149 | const navigateToAddWallet = useCallback(() => { |
| 150 | navigation.navigate('AddWalletRoot'); |
nothing calls this directly
no test coverage detected