diff --git a/CLAUDE.md b/CLAUDE.md index e6a40841..5b71dc71 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -80,8 +80,8 @@ When adding new remote commands, add a table to `FlatBufferSchemas.fbs`, regener ### UI Architecture Every screen is a SwiftUI view hosted by a thin UIKit shell (no storyboards or xibs; the window is built programmatically in `SceneDelegate`): -- **WelcomeViewController** — entry point (root of the nav controller), hosts `WelcomeView` -- **RolePickerController** — role selection, hosts `RolePickerView` +- **WelcomeViewController** — upgrade/paywall screen, hosts `WelcomeView`; no longer part of the launch flow (Settings has its own separate purchase UI); kept for its test coverage but not currently pushed anywhere in the app +- **RolePickerController** — entry point (root of the nav controller), role selection, hosts `RolePickerView` - **DeviceScannerViewController** — peer discovery, hosts `DeviceScannerView`; owns the `SessionCoordinator` + `FrameSender` lifecycle - **MonitorViewController** — hosts `MonitorView`; implements `MonitorDisplay`, the protocol seam through which `MonitorPresenter` drives the screen - **CameraHostController** — hosts `CameraScreenView` (preview + chrome) and owns a `CameraRig`, which holds the capture stack (`CaptureEngine` + `RecordingPipeline` + `FrameStreamingCoordinator`) diff --git a/RemoteCam/MulticamView.swift b/RemoteCam/MulticamView.swift index 78e8620f..f4a16753 100644 --- a/RemoteCam/MulticamView.swift +++ b/RemoteCam/MulticamView.swift @@ -196,6 +196,11 @@ struct MulticamView: View { focusedCameraChip .padding(.leading, 8) Spacer(minLength: 0) + GlassCircleButton(systemImage: "plus", + size: 44, glyphSize: 20, + isEnabled: true, + action: onAddCamera) + .padding(.trailing, 8) ControlCapsule(showsFlash: viewModel.mode == .photo, showsTorch: viewModel.showsTorchButton, isFlashEnabled: viewModel.focusedFlashOn, @@ -483,8 +488,8 @@ struct MulticamView: View { } /// The camera strip — multicam's one added element. Thumbnails of the other - /// cameras plus the Add tile, laid out along `axis` so it tucks into the - /// action area on either dock. Tap a thumbnail to focus it; long-press for + /// cameras, laid out along `axis` so it tucks into the action area on + /// either dock. Tap a thumbnail to focus it; long-press for /// "Disconnect Camera". @ViewBuilder private func cameraStrip(axis: Axis) -> some View { @@ -510,23 +515,6 @@ struct MulticamView: View { .onTapGesture { onFocusLane(lane) } .contextMenu { disconnectButton(for: lane) } } - addCameraTile.frame(width: size.width, height: size.height) - } - - /// The "add camera" affordance at the end of the strip. The host decides - /// whether tapping opens the sheet or the paywall (at the tier cap). - private var addCameraTile: some View { - Button(action: onAddCamera) { - VStack(spacing: 6) { - Image(systemName: "plus.circle.fill").font(.title) - Text(NSLocalizedString("Add camera", comment: "add a camera to the multicam rig")) - .font(.caption2) - } - .foregroundColor(.white) - .frame(maxWidth: .infinity, maxHeight: .infinity) - .background(Color.white.opacity(0.12)) - .clipShape(RoundedRectangle(cornerRadius: 10)) - } } } diff --git a/RemoteCam/SceneDelegate.swift b/RemoteCam/SceneDelegate.swift index 97bb1900..25baf6a5 100644 --- a/RemoteCam/SceneDelegate.swift +++ b/RemoteCam/SceneDelegate.swift @@ -39,7 +39,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { let window = UIWindow(windowScene: windowScene) let navigationController = UINavigationController( navigationBarClass: PassThroughNavigationBar.self, toolbarClass: nil) - navigationController.setViewControllers([WelcomeViewController()], animated: false) + navigationController.setViewControllers([RolePickerController()], animated: false) window.rootViewController = navigationController window.makeKeyAndVisible() self.window = window