diff --git a/Sources/App/piRemoteApp.swift b/Sources/App/piRemoteApp.swift index ffb23cc..70f9c42 100644 --- a/Sources/App/piRemoteApp.swift +++ b/Sources/App/piRemoteApp.swift @@ -1,4 +1,5 @@ import SwiftUI +import UserNotifications @main struct piRemoteApp: App { diff --git a/Sources/Core/Network/WebSocketClient.swift b/Sources/Core/Network/WebSocketClient.swift index 6d8e519..6fbb4b4 100644 --- a/Sources/Core/Network/WebSocketClient.swift +++ b/Sources/Core/Network/WebSocketClient.swift @@ -192,8 +192,11 @@ private final class DelegateAdapter: WebSocketDelegate, @unchecked Sendable { func didReceive(event: WebSocketEvent, client: any Starscream.WebSocketClient) { guard let owner else { return } + // DelegateAdapter is @unchecked Sendable; silence Sendable check on + // Starscream's WebSocketEvent which doesn't conform but is safe here. + nonisolated(unsafe) let e = event Task { @MainActor [owner] in - owner.handle(event: event) + owner.handle(event: e) } } } diff --git a/Sources/Core/Push/NotificationDelegate.swift b/Sources/Core/Push/NotificationDelegate.swift index 2aa80ee..eedbb14 100644 --- a/Sources/Core/Push/NotificationDelegate.swift +++ b/Sources/Core/Push/NotificationDelegate.swift @@ -58,13 +58,12 @@ final class NotificationDelegate: NSObject, UNUserNotificationCenterDelegate, Ob ) { let sessionId = notification.request.content.userInfo["sessionId"] as? String + nonisolated(unsafe) let ch = completionHandler Task { @MainActor in if let sessionId, sessionId == self.visibleSessionId { - // Session is already visible — suppress the banner entirely. - completionHandler([]) + ch([]) } else { - // Show banner + sound + badge update. - completionHandler([.banner, .sound, .badge]) + ch([.banner, .sound, .badge]) } } } @@ -78,12 +77,13 @@ final class NotificationDelegate: NSObject, UNUserNotificationCenterDelegate, Ob ) { let sessionId = response.notification.request.content.userInfo["sessionId"] as? String + nonisolated(unsafe) let ch = completionHandler Task { @MainActor in NotificationCenter.default.post( name: Notification.Name("piRemote.openSession"), object: sessionId ) - completionHandler() + ch() } } } diff --git a/Sources/Core/Sessions/SessionConnection.swift b/Sources/Core/Sessions/SessionConnection.swift index e504f31..694c3d8 100644 --- a/Sources/Core/Sessions/SessionConnection.swift +++ b/Sources/Core/Sessions/SessionConnection.swift @@ -36,7 +36,7 @@ public final class SessionConnection: ObservableObject { public let stateEvents = PassthroughSubject() /// Tracks the WebSocket lifecycle. - @Published public private(set) var connectionState: WebSocketClient.ConnectionState = .disconnected + @Published public private(set) var connectionState: ConnectionState = .disconnected // MARK: - Scrollback @@ -54,7 +54,7 @@ public final class SessionConnection: ObservableObject { /// Creates a `SessionConnection` for `id` authenticated with `credential`. /// /// Does **not** open a WebSocket. Call `resume(from:)` to connect. - public init(id: String, credential: SidecarCredential) { + init(id: String, credential: SidecarCredential) { self.id = id self.credential = credential self.scrollback = ScrollbackCache(sessionId: id) diff --git a/Sources/UI/Input/ModifierBar.swift b/Sources/UI/Input/ModifierBar.swift index 7c0dfe8..d5e7c7e 100644 --- a/Sources/UI/Input/ModifierBar.swift +++ b/Sources/UI/Input/ModifierBar.swift @@ -196,7 +196,7 @@ private struct BarButton: View { /// repeats every 100 ms after an initial 400 ms delay while the finger /// remains pressed. @MainActor -private struct RepeatingBarButton: View { +struct RepeatingBarButton: View { let title: String let action: () -> Void @@ -207,6 +207,11 @@ private struct RepeatingBarButton: View { @State private var repeatTask: Task? + init(title: String, action: @escaping () -> Void) { + self.title = title + self.action = action + } + var body: some View { Text(title) .font(.system(size: 14, weight: .medium, design: .monospaced)) diff --git a/Sources/UI/Pairing/QRScannerView.swift b/Sources/UI/Pairing/QRScannerView.swift index a649568..b1b6b2b 100644 --- a/Sources/UI/Pairing/QRScannerView.swift +++ b/Sources/UI/Pairing/QRScannerView.swift @@ -54,7 +54,7 @@ struct QRScannerView: UIViewRepresentable { coordinator.previewLayer = previewLayer // Start capture on a background thread to avoid blocking the main queue. - Task.detached(priority: .userInitiated) { + DispatchQueue.global(qos: .userInitiated).async { [session] in session.startRunning() } @@ -90,10 +90,11 @@ struct QRScannerView: UIViewRepresentable { didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection ) { + nonisolated(unsafe) let objects = metadataObjects MainActor.assumeIsolated { guard !hasScanned else { return } guard - let object = metadataObjects.first as? AVMetadataMachineReadableCodeObject, + let object = objects.first as? AVMetadataMachineReadableCodeObject, object.type == .qr, let string = object.stringValue else { return } @@ -106,7 +107,7 @@ struct QRScannerView: UIViewRepresentable { func stop() { guard session.isRunning else { return } - Task.detached(priority: .userInitiated) { [session] in + DispatchQueue.global(qos: .userInitiated).async { [session] in session.stopRunning() } } diff --git a/piRemote.xcodeproj/project.pbxproj b/piRemote.xcodeproj/project.pbxproj index 6423505..f29c9ae 100644 --- a/piRemote.xcodeproj/project.pbxproj +++ b/piRemote.xcodeproj/project.pbxproj @@ -7,11 +7,42 @@ objects = { /* Begin PBXBuildFile section */ + 05CD861F694B84577A4B5A27 /* PairingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9BAF4FBE6CC23FDD9B40040 /* PairingTests.swift */; }; + 09AC16350B4E83B71B05A9D5 /* ResumeCursor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7961BE126AFEEE4B7AA6621 /* ResumeCursor.swift */; }; + 16095F16FAB72320676A729D /* ResumeCursorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7607FF3804A2602B1C6A05D4 /* ResumeCursorTests.swift */; }; + 1F353AB548615ECD7D241EF7 /* SessionConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67F95D26CD899B18D07AB0B2 /* SessionConnection.swift */; }; + 2AA3AC859917D32C1444FC5B /* FrameCodec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15B6B497329B98A4508D963B /* FrameCodec.swift */; }; + 2D8C05476A83F5CAB9A55A11 /* SidecarCredential.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3FCCEE1BAA0983D83FC84DD /* SidecarCredential.swift */; }; + 304D26AD20F8DCE216490695 /* REVIEW_NOTES_2.md in Resources */ = {isa = PBXBuildFile; fileRef = 55DAE4BC86AE950146CD7B94 /* REVIEW_NOTES_2.md */; }; 30E07FF586EABBBB8C70AE60 /* piRemoteApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73D747BC787A24B4E225B142 /* piRemoteApp.swift */; }; + 3486C15393498F5306C8F43B /* ScrollbackCacheTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22658EED98A0B3C2183AACDD /* ScrollbackCacheTests.swift */; }; + 3AC56484E8AC068C10F31324 /* REVIEW_NOTES.md in Resources */ = {isa = PBXBuildFile; fileRef = 6DE4A325EEA53870390B89D9 /* REVIEW_NOTES.md */; }; + 4877B4085C529C640FBBE6AB /* ThemeStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC48E39D19238178A180B30C /* ThemeStore.swift */; }; 56096DB64F700FC00C4D58CE /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = AFF032BC30D513204211ADA5 /* Assets.xcassets */; }; + 5F82D50C477F47893FADA8CB /* PasteSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3F776605A4109C047E44A89 /* PasteSheet.swift */; }; + 5F8F5E6D2D5277CB90FA98A0 /* ThemeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99FA0A0FD737901834AD5705 /* ThemeTests.swift */; }; + 7936EDE3DC79D02CF66F8863 /* QRScannerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AF0B5FBC3ACEC8EF5C3FF12 /* QRScannerView.swift */; }; + 7BD37B4A99532FD542D21526 /* TerminalViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A75BE928FA90D8AF2C56615D /* TerminalViewController.swift */; }; 873DC9D5342E8F4AF2C5BEE9 /* Starscream in Frameworks */ = {isa = PBXBuildFile; productRef = CCBD990EEA7AD9DCF714DF97 /* Starscream */; }; + 909A26B85FA298A870E407CD /* DeviceTokenRegistrar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03ABB7E636E55917562D9A2C /* DeviceTokenRegistrar.swift */; }; + 9855E1E1C856E20B339F2A0A /* NotificationDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844A9C78194E7644A78FFA23 /* NotificationDelegate.swift */; }; + 9AC28FD7FD38F250FE477441 /* ScrollbackCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = C98EF1F714A1A5E8D4C3DA2B /* ScrollbackCache.swift */; }; + A1B807C3E8586E99507463B9 /* FrameCodecTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A85D5F5AF59E84DDC3AE168B /* FrameCodecTests.swift */; }; + A3144EA79E01CB9D2DD552C8 /* PairingFlowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A38B86E930CB34DEB9E4C144 /* PairingFlowView.swift */; }; + A56F82D6CEC7C6654C02C7BB /* WebSocketClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5205F823929F91450C58D4CA /* WebSocketClient.swift */; }; + AF1F7740D9A9F40BA8308052 /* TerminalViewRepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39536FD31585716EF30C84C6 /* TerminalViewRepresentable.swift */; }; + B3809456CF2E96F1B1B862C2 /* FontStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12767F24EC6ECFA77B280A8D /* FontStore.swift */; }; + B73AD1B4B8830C1DEE8A78AE /* ModifierStateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 278215F3FD64C681C55F23A4 /* ModifierStateTests.swift */; }; + B8800C5E81FBB0C3CE9C6E7D /* ModifierState.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD8434E1D87FFE2616683652 /* ModifierState.swift */; }; + C1F266B0DC9D7029E5E5B203 /* DeviceTokenRegistrarTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83446A0D895B866E880D4F2D /* DeviceTokenRegistrarTests.swift */; }; + C776D609DB29E5B4C90881F9 /* Keychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = B772854E3FADA8998C93DAF5 /* Keychain.swift */; }; + C823749124F98D46FB993247 /* KeychainTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F47CA5A1045A264958B360BF /* KeychainTests.swift */; }; + D3E1C0562B97260D28FF1C11 /* Pairing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F544C25D53F52291E2FDB6F /* Pairing.swift */; }; + D3E8D6064F38E4024A6863C9 /* TerminalTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = E3A7FB4B9C4D2B63B016E11A /* TerminalTheme.swift */; }; D77D662C3311D9646BE57596 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6BDDFB0C0D1D6D6FB490BA8D /* Preview Assets.xcassets */; }; + E9126D5D059DAD3717FA2398 /* ModifierBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = F553E905D716538D9DA442E7 /* ModifierBar.swift */; }; F6C311D17A8DAA4F19464E25 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 188683139B863ED1AC03A1BB /* ContentView.swift */; }; + F8CBA52AE2CC3D8496361D45 /* TerminalFont.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5B05BBDD469F51657ED89B0 /* TerminalFont.swift */; }; FADABBF0D0229D84832D3B78 /* SwiftTerm in Frameworks */ = {isa = PBXBuildFile; productRef = D095700C52C60FDA2CB38679 /* SwiftTerm */; }; /* End PBXBuildFile section */ @@ -26,14 +57,45 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 03ABB7E636E55917562D9A2C /* DeviceTokenRegistrar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceTokenRegistrar.swift; sourceTree = ""; }; + 0AF0B5FBC3ACEC8EF5C3FF12 /* QRScannerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRScannerView.swift; sourceTree = ""; }; 0E401DECD467A1D3AB030610 /* piRemote.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = piRemote.entitlements; sourceTree = ""; }; + 0F544C25D53F52291E2FDB6F /* Pairing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Pairing.swift; sourceTree = ""; }; + 12767F24EC6ECFA77B280A8D /* FontStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FontStore.swift; sourceTree = ""; }; + 15B6B497329B98A4508D963B /* FrameCodec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FrameCodec.swift; sourceTree = ""; }; 188683139B863ED1AC03A1BB /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; + 22658EED98A0B3C2183AACDD /* ScrollbackCacheTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollbackCacheTests.swift; sourceTree = ""; }; + 278215F3FD64C681C55F23A4 /* ModifierStateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModifierStateTests.swift; sourceTree = ""; }; 2E2370A3190FDC144C822FF6 /* piRemote.app */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.application; path = piRemote.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 39536FD31585716EF30C84C6 /* TerminalViewRepresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerminalViewRepresentable.swift; sourceTree = ""; }; + 5205F823929F91450C58D4CA /* WebSocketClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebSocketClient.swift; sourceTree = ""; }; + 55DAE4BC86AE950146CD7B94 /* REVIEW_NOTES_2.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = REVIEW_NOTES_2.md; sourceTree = ""; }; 658CB2FCA96A8913B1753B1C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; + 67F95D26CD899B18D07AB0B2 /* SessionConnection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionConnection.swift; sourceTree = ""; }; 6BDDFB0C0D1D6D6FB490BA8D /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; + 6DE4A325EEA53870390B89D9 /* REVIEW_NOTES.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = REVIEW_NOTES.md; sourceTree = ""; }; 73D747BC787A24B4E225B142 /* piRemoteApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = piRemoteApp.swift; sourceTree = ""; }; + 7607FF3804A2602B1C6A05D4 /* ResumeCursorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResumeCursorTests.swift; sourceTree = ""; }; + 83446A0D895B866E880D4F2D /* DeviceTokenRegistrarTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceTokenRegistrarTests.swift; sourceTree = ""; }; + 844A9C78194E7644A78FFA23 /* NotificationDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationDelegate.swift; sourceTree = ""; }; + 99FA0A0FD737901834AD5705 /* ThemeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeTests.swift; sourceTree = ""; }; + A38B86E930CB34DEB9E4C144 /* PairingFlowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PairingFlowView.swift; sourceTree = ""; }; + A3F776605A4109C047E44A89 /* PasteSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasteSheet.swift; sourceTree = ""; }; + A75BE928FA90D8AF2C56615D /* TerminalViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerminalViewController.swift; sourceTree = ""; }; + A85D5F5AF59E84DDC3AE168B /* FrameCodecTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FrameCodecTests.swift; sourceTree = ""; }; AFF032BC30D513204211ADA5 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + B772854E3FADA8998C93DAF5 /* Keychain.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Keychain.swift; sourceTree = ""; }; + BC48E39D19238178A180B30C /* ThemeStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeStore.swift; sourceTree = ""; }; + C5B05BBDD469F51657ED89B0 /* TerminalFont.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerminalFont.swift; sourceTree = ""; }; + C7961BE126AFEEE4B7AA6621 /* ResumeCursor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResumeCursor.swift; sourceTree = ""; }; + C98EF1F714A1A5E8D4C3DA2B /* ScrollbackCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollbackCache.swift; sourceTree = ""; }; CD24C7095F23AF63CCFB23F0 /* piRemoteTests.xctest */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.cfbundle; path = piRemoteTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + D3FCCEE1BAA0983D83FC84DD /* SidecarCredential.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidecarCredential.swift; sourceTree = ""; }; + DD8434E1D87FFE2616683652 /* ModifierState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModifierState.swift; sourceTree = ""; }; + E3A7FB4B9C4D2B63B016E11A /* TerminalTheme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerminalTheme.swift; sourceTree = ""; }; + E9BAF4FBE6CC23FDD9B40040 /* PairingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PairingTests.swift; sourceTree = ""; }; + F47CA5A1045A264958B360BF /* KeychainTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainTests.swift; sourceTree = ""; }; + F553E905D716538D9DA442E7 /* ModifierBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModifierBar.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -61,6 +123,7 @@ 1909DBD374F6922644BF6B4D /* Sessions */ = { isa = PBXGroup; children = ( + 67F95D26CD899B18D07AB0B2 /* SessionConnection.swift */, ); path = Sessions; sourceTree = ""; @@ -77,16 +140,15 @@ path = Core; sourceTree = ""; }; - 35F24B7F065B257F93810E5B /* Sessions */ = { - isa = PBXGroup; - children = ( - ); - path = Sessions; - sourceTree = ""; - }; 49209A78102230A37C0FF8D0 /* Terminal */ = { isa = PBXGroup; children = ( + 12767F24EC6ECFA77B280A8D /* FontStore.swift */, + C5B05BBDD469F51657ED89B0 /* TerminalFont.swift */, + E3A7FB4B9C4D2B63B016E11A /* TerminalTheme.swift */, + A75BE928FA90D8AF2C56615D /* TerminalViewController.swift */, + 39536FD31585716EF30C84C6 /* TerminalViewRepresentable.swift */, + BC48E39D19238178A180B30C /* ThemeStore.swift */, ); path = Terminal; sourceTree = ""; @@ -110,6 +172,8 @@ 8A477F7D38B42EEB3F70323F /* Pairing */ = { isa = PBXGroup; children = ( + A38B86E930CB34DEB9E4C144 /* PairingFlowView.swift */, + 0AF0B5FBC3ACEC8EF5C3FF12 /* QRScannerView.swift */, ); path = Pairing; sourceTree = ""; @@ -117,6 +181,8 @@ 8E5B4A1E4AE8D09F6E581E02 /* Push */ = { isa = PBXGroup; children = ( + 03ABB7E636E55917562D9A2C /* DeviceTokenRegistrar.swift */, + 844A9C78194E7644A78FFA23 /* NotificationDelegate.swift */, ); path = Push; sourceTree = ""; @@ -133,6 +199,9 @@ 9DF960DFB90BF425282C35D0 /* Input */ = { isa = PBXGroup; children = ( + F553E905D716538D9DA442E7 /* ModifierBar.swift */, + DD8434E1D87FFE2616683652 /* ModifierState.swift */, + A3F776605A4109C047E44A89 /* PasteSheet.swift */, ); path = Input; sourceTree = ""; @@ -140,17 +209,20 @@ C06242078CD1DD2BD7C7A4FA /* CoreTests */ = { isa = PBXGroup; children = ( + 83446A0D895B866E880D4F2D /* DeviceTokenRegistrarTests.swift */, + A85D5F5AF59E84DDC3AE168B /* FrameCodecTests.swift */, + F47CA5A1045A264958B360BF /* KeychainTests.swift */, + 278215F3FD64C681C55F23A4 /* ModifierStateTests.swift */, + E9BAF4FBE6CC23FDD9B40040 /* PairingTests.swift */, + 7607FF3804A2602B1C6A05D4 /* ResumeCursorTests.swift */, + 55DAE4BC86AE950146CD7B94 /* REVIEW_NOTES_2.md */, + 6DE4A325EEA53870390B89D9 /* REVIEW_NOTES.md */, + 22658EED98A0B3C2183AACDD /* ScrollbackCacheTests.swift */, + 99FA0A0FD737901834AD5705 /* ThemeTests.swift */, ); path = CoreTests; sourceTree = ""; }; - C7FBB3C467939760D2971070 /* Status */ = { - isa = PBXGroup; - children = ( - ); - path = Status; - sourceTree = ""; - }; C8D95B3C16FEE9C9FBE38FDE /* Sources */ = { isa = PBXGroup; children = ( @@ -164,6 +236,7 @@ D484C43F0BAEF3990BB88D8F /* Persistence */ = { isa = PBXGroup; children = ( + C98EF1F714A1A5E8D4C3DA2B /* ScrollbackCache.swift */, ); path = Persistence; sourceTree = ""; @@ -171,6 +244,9 @@ DCF268D44CD471E86B6192B0 /* Network */ = { isa = PBXGroup; children = ( + 15B6B497329B98A4508D963B /* FrameCodec.swift */, + C7961BE126AFEEE4B7AA6621 /* ResumeCursor.swift */, + 5205F823929F91450C58D4CA /* WebSocketClient.swift */, ); path = Network; sourceTree = ""; @@ -180,9 +256,6 @@ children = ( 9DF960DFB90BF425282C35D0 /* Input */, 8A477F7D38B42EEB3F70323F /* Pairing */, - 35F24B7F065B257F93810E5B /* Sessions */, - F681ED5F43C5283558361FAC /* Settings */, - C7FBB3C467939760D2971070 /* Status */, 49209A78102230A37C0FF8D0 /* Terminal */, ); path = UI; @@ -204,17 +277,13 @@ ED7AFC5C0EF365C5831C7245 /* Auth */ = { isa = PBXGroup; children = ( + B772854E3FADA8998C93DAF5 /* Keychain.swift */, + 0F544C25D53F52291E2FDB6F /* Pairing.swift */, + D3FCCEE1BAA0983D83FC84DD /* SidecarCredential.swift */, ); path = Auth; sourceTree = ""; }; - F681ED5F43C5283558361FAC /* Settings */ = { - isa = PBXGroup; - children = ( - ); - path = Settings; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -223,6 +292,7 @@ buildConfigurationList = C553B125FB09A7C04D602AE2 /* Build configuration list for PBXNativeTarget "piRemoteTests" */; buildPhases = ( 6DDDB771E08071591D668B0A /* Sources */, + 69F2CE4274A9B3A8BBB13CA5 /* Resources */, ); buildRules = ( ); @@ -310,6 +380,15 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 69F2CE4274A9B3A8BBB13CA5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 3AC56484E8AC068C10F31324 /* REVIEW_NOTES.md in Resources */, + 304D26AD20F8DCE216490695 /* REVIEW_NOTES_2.md in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -318,6 +397,27 @@ buildActionMask = 2147483647; files = ( F6C311D17A8DAA4F19464E25 /* ContentView.swift in Sources */, + 909A26B85FA298A870E407CD /* DeviceTokenRegistrar.swift in Sources */, + B3809456CF2E96F1B1B862C2 /* FontStore.swift in Sources */, + 2AA3AC859917D32C1444FC5B /* FrameCodec.swift in Sources */, + C776D609DB29E5B4C90881F9 /* Keychain.swift in Sources */, + E9126D5D059DAD3717FA2398 /* ModifierBar.swift in Sources */, + B8800C5E81FBB0C3CE9C6E7D /* ModifierState.swift in Sources */, + 9855E1E1C856E20B339F2A0A /* NotificationDelegate.swift in Sources */, + D3E1C0562B97260D28FF1C11 /* Pairing.swift in Sources */, + A3144EA79E01CB9D2DD552C8 /* PairingFlowView.swift in Sources */, + 5F82D50C477F47893FADA8CB /* PasteSheet.swift in Sources */, + 7936EDE3DC79D02CF66F8863 /* QRScannerView.swift in Sources */, + 09AC16350B4E83B71B05A9D5 /* ResumeCursor.swift in Sources */, + 9AC28FD7FD38F250FE477441 /* ScrollbackCache.swift in Sources */, + 1F353AB548615ECD7D241EF7 /* SessionConnection.swift in Sources */, + 2D8C05476A83F5CAB9A55A11 /* SidecarCredential.swift in Sources */, + F8CBA52AE2CC3D8496361D45 /* TerminalFont.swift in Sources */, + D3E8D6064F38E4024A6863C9 /* TerminalTheme.swift in Sources */, + 7BD37B4A99532FD542D21526 /* TerminalViewController.swift in Sources */, + AF1F7740D9A9F40BA8308052 /* TerminalViewRepresentable.swift in Sources */, + 4877B4085C529C640FBBE6AB /* ThemeStore.swift in Sources */, + A56F82D6CEC7C6654C02C7BB /* WebSocketClient.swift in Sources */, 30E07FF586EABBBB8C70AE60 /* piRemoteApp.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -326,6 +426,14 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + C1F266B0DC9D7029E5E5B203 /* DeviceTokenRegistrarTests.swift in Sources */, + A1B807C3E8586E99507463B9 /* FrameCodecTests.swift in Sources */, + C823749124F98D46FB993247 /* KeychainTests.swift in Sources */, + B73AD1B4B8830C1DEE8A78AE /* ModifierStateTests.swift in Sources */, + 05CD861F694B84577A4B5A27 /* PairingTests.swift in Sources */, + 16095F16FAB72320676A729D /* ResumeCursorTests.swift in Sources */, + 3486C15393498F5306C8F43B /* ScrollbackCacheTests.swift in Sources */, + 5F8F5E6D2D5277CB90FA98A0 /* ThemeTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; };