Skip to content

Gear store: /gear website page + in-app Settings entry#151

Open
darioalessandro wants to merge 4 commits into
masterfrom
gear-store
Open

Gear store: /gear website page + in-app Settings entry#151
darioalessandro wants to merge 4 commits into
masterfrom
gear-store

Conversation

@darioalessandro

@darioalessandro darioalessandro commented Jul 13, 2026

Copy link
Copy Markdown
Member

GAMEPLAN play #6 (hardware affiliate channel): the gear store, web + app.

Website (/gear)

  • New route with 12 hand-picked products in three price-laddered sections: phone tripods ($23–160, incl. Manfrotto Element MII Mobile), mounts & clamps ($10–35), mobile lenses ($35–150: Xenvo → Sirui → Sandmarc → Moment T-Series). Catalog lives in one data file, website/src/lib/gear.ts.
  • AmazonLink swaps the Associates tracking ID to remoteshutter-app-20 when the page is opened with ?src=app, so app-driven clicks attribute separately from organic web in Amazon's own reports — no analytics script needed.
  • Amazon's required disclosure at top and bottom; rel="sponsored" on all buy links; header nav + sitemap + home-page teaser wired in.
  • marketing_url.txt now points at the website instead of the GitHub repo (ships with next release).

App — two entry points

  • Role picker: "Recommended Gear" glass panel (bag icon, lighter-gold tint) as the LAST item, after Camera/Remote/Watch Remote — core actions first, recommendation as the footer. Subtitle localized in all 15 locales.
  • Settings → About: "Recommended Gear" row.
  • Both open the page in-app via SFSafariViewController (default browser on Mac Catalyst, where SFSafariVC is unavailable) with ?src=app for attribution.

Before the links earn anything

  • Apply for Amazon Associates with the live site once merged (Dario)
  • Replace placeholder tracking IDs in website/src/lib/gear.ts with the approved ones
  • Product photos are manufacturer marketing images for now — swap to Amazon PA-API images once the Associates account is approved (licensing)

Verified: static export builds with /gear prerendered; jest green; all 12 buy links + disclosure present in generated HTML; iOS Simulator build passes; CI green on both iOS and Mac Catalyst.

🤖 Generated with Claude Code

darioalessandro and others added 2 commits July 13, 2026 00:29
Adds a row in the Settings > About section linking to the recommended-gear
page (https://security-union.github.io/remote-shutter/gear?src=app). On
iOS/iPadOS it presents an in-app SFSafariViewController from the top view
controller; on Mac Catalyst, where SFSafariViewController is unavailable, it
opens the URL in the default browser via UIApplication.open. The user-facing
"Recommended Gear" string is localized across all 15 shipped locales.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ates links

Products and copy per the reviewed design prototype. AmazonLink swaps the
tracking ID to remoteshutter-app-20 when opened with ?src=app so app-driven
clicks attribute separately. Tags are placeholders until the Associates
account is approved. marketing_url now points at the website instead of the
GitHub repo.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

📊 Test Coverage Report

449/455 tests passed · ⏭️ 6 skipped

Metric Coverage
App code (excl. generated + vendored Theater) ████████░░░░░░░░░░░░ 42.2% 🔴
Whole target █████████░░░░░░░░░░░ 43.6% 🔴

🎥 Capture & session core

File Coverage Lines
CaptureEngine.swift ██░░░░░░░░░░░░░░░░░░ 11.3% 164/1448 🔴
RecordingPipeline.swift ████████████░░░░░░░░ 59.1% 272/460 🟡
FrameStreamingCoordinator.swift ░░░░░░░░░░░░░░░░░░░░ 0.0% 0/61 🔴
FrameStreamer.swift ██████████░░░░░░░░░░ 51.9% 28/54 🟡
RemoteCmdFlatBuffers.swift ███████████████████░ 96.6% 1120/1160 🟢
📁 Full report — 79 files
File Coverage Lines
HEICFrameEncoder.swift ████████████████████ 100.0% 16/16 🟢
AppActivityMonitor.swift ████████████████████ 100.0% 31/31 🟢
Locked.swift ████████████████████ 100.0% 19/19 🟢
DebugLog.swift ████████████████████ 100.0% 2/2 🟢
FrameCodecs.swift ████████████████████ 100.0% 22/22 🟢
DeviceScannerViewModel.swift ████████████████████ 100.0% 78/78 🟢
StreamingConfig.swift ████████████████████ 100.0% 14/14 🟢
SceneDelegate.swift ████████████████████ 100.0% 8/8 🟢
AppDelegate.swift ████████████████████ 100.0% 17/17 🟢
FrameCreditWindow.swift ████████████████████ 100.0% 9/9 🟢
AppTheme.swift ████████████████████ 100.0% 33/33 🟢
ScannerLobby.swift ████████████████████ 100.0% 5/5 🟢
CountdownTimer.swift ████████████████████ 100.0% 48/48 🟢
Messages.swift ████████████████████ 100.0% 7/7 🟢
JPEGFrameEncoder.swift ████████████████████ 100.0% 11/11 🟢
FrameSender.swift ████████████████████ 98.3% 117/119 🟢
RemoteCmdFlatBuffers.swift ███████████████████░ 96.6% 1120/1160 🟢
RemoteCmds.swift ███████████████████░ 95.5% 279/292 🟢
WatchPreviewStreamer.swift ███████████████████░ 93.6% 44/47 🟢
WatchSharedTypes.swift ███████████████████░ 92.9% 197/212 🟢
WelcomeView.swift ██████████████████░░ 90.4% 489/541 🟢
VideoTransferProgressView.swift █████████████████░░░ 84.0% 295/351 🟢
UIImage+gif.swift █████████████████░░░ 83.2% 129/155 🟢
CameraDeviceDescriptor.swift ████████████████░░░░ 81.0% 34/42 🟢
RolePickerView.swift ████████████████░░░░ 80.2% 275/343 🟢
FrameStreamReceiver.swift ████████████████░░░░ 79.9% 107/134 🟡
CameraProgressOverlayView.swift ████████████████░░░░ 78.5% 186/237 🟡
UIAlertController.swift ███████████████░░░░░ 77.4% 41/53 🟡
MonitorView.swift ███████████████░░░░░ 77.2% 1422/1841 🟡
FlatBufferSchemas_generated.swift (excluded from app-code metric) ███████████████░░░░░ 75.3% 712/945 🟡
RecordingTimer.swift ███████████████░░░░░ 73.5% 61/83 🟡
CameraRecordingTimerView.swift ███████████████░░░░░ 73.4% 127/173 🟡
SettingsViewModel.swift ██████████████░░░░░░ 71.6% 73/102 🟡
WelcomeViewModel.swift ██████████████░░░░░░ 70.2% 85/121 🟡
DeviceScannerView.swift ██████████████░░░░░░ 68.0% 876/1289 🟡
MultipeerMessages.swift █████████████░░░░░░░ 66.7% 8/12 🟡
SessionCoordinator.swift █████████████░░░░░░░ 62.9% 1272/2022 🟡
MonitorPresenter.swift ████████████░░░░░░░░ 61.9% 135/218 🟡
UIAlertPresenter.swift ████████████░░░░░░░░ 60.5% 26/43 🟡
RecordingPipeline.swift ████████████░░░░░░░░ 59.1% 272/460 🟡
MediaProcessors.swift ████████████░░░░░░░░ 58.3% 7/12 🟡
CameraViewModel.swift ███████████░░░░░░░░░ 54.9% 117/213 🟡
FrameStreamer.swift ██████████░░░░░░░░░░ 51.9% 28/54 🟡
StoreManager.swift ██████████░░░░░░░░░░ 50.4% 58/115 🟡
UIViewController+SwiftUIHosting.swift ██████████░░░░░░░░░░ 48.4% 15/31 🔴
WelcomeViewController.swift █████████░░░░░░░░░░░ 46.6% 41/88 🔴
EnumExtensions.swift █████████░░░░░░░░░░░ 43.2% 51/118 🔴
MonitorViewModel.swift ████████░░░░░░░░░░░░ 41.9% 186/444 🔴
PurchaseManaging.swift ████████░░░░░░░░░░░░ 40.8% 20/49 🔴
MonitorViewController.swift ████████░░░░░░░░░░░░ 40.0% 70/175 🔴
CameraScreenView.swift ███████░░░░░░░░░░░░░ 34.6% 72/208 🔴
WatchSessionManager.swift █████░░░░░░░░░░░░░░░ 23.1% 37/160 🔴
UICmds.swift █████░░░░░░░░░░░░░░░ 22.6% 72/319 🔴
Try.swift ████░░░░░░░░░░░░░░░░ 20.9% 14/67 🔴
DeviceScannerViewController.swift ████░░░░░░░░░░░░░░░░ 20.6% 79/383 🔴
SoundManager.swift ████░░░░░░░░░░░░░░░░ 20.0% 4/20 🔴
MonitorViewController+SwiftUI.swift ███░░░░░░░░░░░░░░░░░ 13.8% 59/427 🔴
CaptureEngine.swift ██░░░░░░░░░░░░░░░░░░ 11.3% 164/1448 🔴
RolePickerController.swift ██░░░░░░░░░░░░░░░░░░ 10.2% 23/226 🔴
WatchRemoteCameraController.swift █░░░░░░░░░░░░░░░░░░░ 3.3% 9/275 🔴
CameraHostController.swift ░░░░░░░░░░░░░░░░░░░░ 0.0% 0/189 🔴
MicrophonePermissionPromptView.swift ░░░░░░░░░░░░░░░░░░░░ 0.0% 0/347 🔴
CameraPermissionErrorView.swift ░░░░░░░░░░░░░░░░░░░░ 0.0% 0/416 🔴
OrientationUtils.swift ░░░░░░░░░░░░░░░░░░░░ 0.0% 0/18 🔴
SettingsView.swift ░░░░░░░░░░░░░░░░░░░░ 0.0% 0/710 🔴
LocalNetworkPermissionView.swift ░░░░░░░░░░░░░░░░░░░░ 0.0% 0/747 🔴
Photos.swift ░░░░░░░░░░░░░░░░░░░░ 0.0% 0/12 🔴
RemoteShutterHelpView.swift ░░░░░░░░░░░░░░░░░░░░ 0.0% 0/1373 🔴
FrameStreamingCoordinator.swift ░░░░░░░░░░░░░░░░░░░░ 0.0% 0/61 🔴
SwiftConstants.swift ░░░░░░░░░░░░░░░░░░░░ 0.0% 0/65 🔴
Data+MD5.swift ░░░░░░░░░░░░░░░░░░░░ 0.0% 0/4 🔴
PhotosAccessDeniedView.swift ░░░░░░░░░░░░░░░░░░░░ 0.0% 0/606 🔴
CameraCountdownTorch.swift ░░░░░░░░░░░░░░░░░░░░ 0.0% 0/61 🔴
MultipeerService.swift ░░░░░░░░░░░░░░░░░░░░ 0.0% 0/120 🔴
StreamLog.swift ░░░░░░░░░░░░░░░░░░░░ 0.0% 0/1 🔴
PhotosAccessHelper.swift ░░░░░░░░░░░░░░░░░░░░ 0.0% 0/324 🔴
PermissionManager.swift ░░░░░░░░░░░░░░░░░░░░ 0.0% 0/159 🔴
CameraRig.swift ░░░░░░░░░░░░░░░░░░░░ 0.0% 0/540 🔴
CameraPermissionsView.swift ░░░░░░░░░░░░░░░░░░░░ 0.0% 0/640 🔴

Generated from 617b04a · workflow run

darioalessandro and others added 2 commits July 13, 2026 00:45
Same glass-panel style as the role buttons (lighter gold tint, bag icon),
opens the gear page via openGearPage(). Subtitle localized in all 15 locales.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Core actions first; the recommendation reads as a footer, not an ad.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant