From 6b9499dfd04c454352431b81b8594b7622eb548a Mon Sep 17 00:00:00 2001 From: CatoG <47473856+CatoG@users.noreply.github.com> Date: Sun, 6 Sep 2026 15:54:24 +0200 Subject: [PATCH] Skip launch paywall; move multicam add-camera control to top bar App now opens straight to the role picker instead of the Welcome/ upgrade screen on every cold launch (Settings still has its own purchase UI, so nothing is lost). The multicam director's "Add camera" tile moves from the bottom camera strip (focus mode only) to a top-bar button next to flash/torch, so it's reachable in grid mode too. Co-Authored-By: Claude Sonnet 5 --- CLAUDE.md | 4 ++-- RemoteCam/MulticamView.swift | 26 +++++++------------------- RemoteCam/SceneDelegate.swift | 2 +- 3 files changed, 10 insertions(+), 22 deletions(-) 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