@@ -52,6 +52,7 @@ final class AppModel {
5252 private static let selectedEndpointKey = " selectedEndpoint "
5353 private static let streamConfigKey = " streamConfig "
5454 private static let hapticsEnabledKey = " hapticsEnabled "
55+ private static let touchOverlayVisibleKey = " touchOverlayVisible "
5556 private static let lastFrameCacheDirectoryName = " LastStreamFrames "
5657
5758 var endpoint : SimDeckEndpoint ?
@@ -70,6 +71,8 @@ final class AppModel {
7071 var chromeImage : UIImage ?
7172 var chromeScreenMask : UIImage ?
7273 var streamDiagnostics = StreamDiagnostics ( )
74+ var streamReconnects = 0
75+ var streamReconnectReason = " "
7376 var bootingSimulatorID : String ?
7477 var streamDisplayToken = 0
7578 var hasCurrentStreamFrame = false
@@ -80,6 +83,11 @@ final class AppModel {
8083 UserDefaults . standard. set ( hapticsEnabled, forKey: Self . hapticsEnabledKey)
8184 }
8285 }
86+ var touchOverlayVisible = AppModel . loadTouchOverlayVisible ( ) {
87+ didSet {
88+ UserDefaults . standard. set ( touchOverlayVisible, forKey: Self . touchOverlayVisibleKey)
89+ }
90+ }
8391
8492 @ObservationIgnored private var streamClient : WebRTCClient ?
8593 @ObservationIgnored private var hasAutoConnected = false
@@ -449,7 +457,7 @@ final class AppModel {
449457 self . scheduleStreamReconnect ( reason: reason)
450458 }
451459 }
452- let loadedChromeAssets = await chromeAssets ( api: api, endpoint: endpoint, simulatorID: selectedSimulatorID)
460+ let loadedChromeAssets = await chromeAssets ( api: api, endpoint: endpoint, simulatorID: selectedSimulatorID, forceRefresh : true )
453461 guard isCurrentStreamRequest ( generation, simulatorID: selectedSimulatorID) else {
454462 client. disconnect ( )
455463 return false
@@ -502,7 +510,7 @@ final class AppModel {
502510 status = " Loading device chrome. "
503511
504512 let api = SimDeckAPI ( endpoint: endpoint)
505- let loadedChromeAssets = await chromeAssets ( api: api, endpoint: endpoint, simulatorID: selectedSimulatorID)
513+ let loadedChromeAssets = await chromeAssets ( api: api, endpoint: endpoint, simulatorID: selectedSimulatorID, forceRefresh : true )
506514 guard isCurrentStreamRequest ( generation, simulatorID: selectedSimulatorID) else { return }
507515 applyChromeAssets ( loadedChromeAssets)
508516 status = selectedSimulator? . isBooted == true ? " Ready. " : " Ready to boot. "
@@ -767,6 +775,12 @@ final class AppModel {
767775 updateStreamConfig { $0. quality = quality }
768776 }
769777
778+ func setTouchOverlayVisible( _ isVisible: Bool ) {
779+ guard touchOverlayVisible != isVisible else { return }
780+ touchOverlayVisible = isVisible
781+ hapticSelection ( )
782+ }
783+
770784 private func autoConnectIfNeeded( _ endpoint: SimDeckEndpoint ) async {
771785 guard !hasAutoConnected, !isAutoConnecting, self . endpoint == nil , authEndpoint == nil else { return }
772786 await autoConnectToAvailableEndpointIfNeeded ( preferredEndpoint: endpoint)
@@ -843,6 +857,8 @@ final class AppModel {
843857 self . selectedSimulatorID != nil ,
844858 self . selectedSimulator? . isBooted == true {
845859 attempt += 1
860+ self . streamReconnects += 1
861+ self . streamReconnectReason = reason
846862 self . lastReconnectStartedAt = Date ( )
847863 self . status = attempt == 1
848864 ? ( reason == " foreground " ? " Resuming stream. " : " Recovering stream. " )
@@ -941,17 +957,19 @@ final class AppModel {
941957 private func chromeAssets(
942958 api: SimDeckAPI ,
943959 endpoint: SimDeckEndpoint ,
944- simulatorID: String
960+ simulatorID: String ,
961+ forceRefresh: Bool = false
945962 ) async -> ChromeAssets {
946- if let cached = cachedChromeAssets ( endpoint: endpoint, simulatorID: simulatorID) {
963+ if !forceRefresh , let cached = cachedChromeAssets ( endpoint: endpoint, simulatorID: simulatorID) {
947964 return cached
948965 }
949966
950967 let loadedProfile = try ? await api. chromeProfile ( udid: simulatorID)
951- let loadedImage = try ? await api. chromeImage ( udid: simulatorID)
968+ let assetStamp = loadedProfile? . assetStamp
969+ let loadedImage = try ? await api. chromeImage ( udid: simulatorID, stamp: assetStamp)
952970 let loadedScreenMask : UIImage ?
953971 if loadedProfile? . hasScreenMask == true {
954- loadedScreenMask = try ? await api. screenMaskImage ( udid: simulatorID)
972+ loadedScreenMask = try ? await api. screenMaskImage ( udid: simulatorID, stamp : assetStamp )
955973 } else {
956974 loadedScreenMask = nil
957975 }
@@ -1406,6 +1424,10 @@ final class AppModel {
14061424 UserDefaults . standard. object ( forKey: hapticsEnabledKey) as? Bool ?? true
14071425 }
14081426
1427+ private static func loadTouchOverlayVisible( ) -> Bool {
1428+ UserDefaults . standard. object ( forKey: touchOverlayVisibleKey) as? Bool ?? true
1429+ }
1430+
14091431 func hapticSelection( ) {
14101432 guard hapticsEnabled else { return }
14111433 UISelectionFeedbackGenerator ( ) . selectionChanged ( )
0 commit comments