@@ -31,7 +31,9 @@ struct AppScene: View {
3131 @StateObject private var pubkyProfile = PubkyProfileManager ( )
3232 @StateObject private var contactsManager = ContactsManager ( )
3333 @State private var keyboardManager = KeyboardManager ( )
34- @State private var trezorViewModel = TrezorViewModel ( )
34+ @State private var trezorManager : TrezorManager
35+ @State private var trezorViewModel : TrezorViewModel
36+ @State private var hwWalletManager : HwWalletManager
3537 @State private var calculatorInputManager = CalculatorInputManager ( )
3638
3739 @State private var hideSplash = false
@@ -82,6 +84,12 @@ struct AppScene: View {
8284
8385 _transferTracking = StateObject ( wrappedValue: TransferTrackingManager ( service: transferService) )
8486
87+ let trezorManager = TrezorManager ( )
88+ let trezorViewModel = TrezorViewModel ( connection: trezorManager)
89+ _trezorManager = State ( initialValue: trezorManager)
90+ _trezorViewModel = State ( initialValue: trezorViewModel)
91+ _hwWalletManager = State ( initialValue: HwWalletManager ( ) )
92+
8593 CoreService . shared. activity. setPrivatePaykitContactResolvers (
8694 invoice: { paymentHash in
8795 await PrivatePaykitService . shared. contactPublicKey ( forPrivateInvoicePaymentHash: paymentHash)
@@ -106,6 +114,13 @@ struct AppScene: View {
106114 . onChange ( of: wallet. nodeLifecycleState) { _, newValue in handleNodeLifecycleChange ( newValue) }
107115 . onChange ( of: scenePhase, initial: true ) { _, newValue in handleScenePhaseChange ( newValue) }
108116 . onChange ( of: network. isConnected) { _, isConnected in handleNetworkChange ( isConnected) }
117+ // Bridge Trezor device state into the watch-only manager without coupling the two:
118+ // TrezorManager bumps devicesRevision on any device/connection change.
119+ . onChange ( of: trezorManager. devicesRevision) { _, _ in pushHardwareDevices ( ) }
120+ . onChange ( of: isPinVerified) { _, verified in
121+ if verified { Task { await trezorManager. autoReconnect ( ) } }
122+ }
123+ . onReceive ( settings. settingsPublisher) { _ in hwWalletManager. reconcileForSettingsChange ( ) }
109124 . onChange ( of: migrations. isShowingMigrationLoading) { _, isLoading in
110125 if !isLoading {
111126 SettingsViewModel . shared. updatePinEnabledState ( )
@@ -148,7 +163,9 @@ struct AppScene: View {
148163 . environmentObject ( pubkyProfile)
149164 . environmentObject ( contactsManager)
150165 . environment ( keyboardManager)
166+ . environment ( trezorManager)
151167 . environment ( trezorViewModel)
168+ . environment ( hwWalletManager)
152169 . environment ( calculatorInputManager)
153170 . onChange ( of: pubkyProfile. authState, initial: true ) { _, authState in
154171 if authState == . authenticated, let pk = pubkyProfile. publicKey {
@@ -470,6 +487,12 @@ struct AppScene: View {
470487 await checkAndPerformRNMigration ( )
471488 try wallet. setWalletExistsState ( )
472489
490+ // Load any paired hardware devices from storage and feed the watch-only manager so its
491+ // watchers start at launch (no-op until a device is paired). loadKnownDevices() also
492+ // bumps devicesRevision, but push explicitly so the initial state is delivered.
493+ trezorManager. loadKnownDevices ( )
494+ pushHardwareDevices ( )
495+
473496 // Setup TimedSheetManager with all timed sheets
474497 TimedSheetManager . shared. setup (
475498 sheetViewModel: sheets,
@@ -601,6 +624,10 @@ struct AppScene: View {
601624 }
602625
603626 if newPhase == . active {
627+ // Reconnect a known hardware device so its connection indicator turns green again;
628+ if isPinVerified || !settings. pinEnabled {
629+ Task { await trezorManager. autoReconnect ( ) }
630+ }
604631 if wallet. walletExists == true {
605632 Task {
606633 await clearDeliveredNotifications ( )
@@ -634,6 +661,15 @@ struct AppScene: View {
634661 center. removeDeliveredNotifications ( withIdentifiers: deliveredNotifications. map ( \. request. identifier) )
635662 }
636663
664+ /// Feed the current Trezor device snapshot into the watch-only manager. This is the only link
665+ /// between the two managers, kept in the composition root so neither type references the other.
666+ private func pushHardwareDevices( ) {
667+ hwWalletManager. updateDevices (
668+ knownDevices: trezorManager. knownDevices,
669+ connectedDeviceId: trezorManager. connectedDevice? . id
670+ )
671+ }
672+
637673 private func handleNetworkChange( _ isConnected: Bool ) {
638674 Logger . info ( " Network changed: \( isConnected ? " connected " : " disconnected " ) " , context: " AppScene " )
639675
0 commit comments