Skip to content

feat(v1.9.8): "Horizon" — iOS store-readiness - #203

Merged
doublegate merged 2 commits into
mainfrom
feat/v1.9.8-horizon
Jun 26, 2026
Merged

doublegate merged 2 commits into
mainfrom
feat/v1.9.8-horizon

Conversation

@doublegate

Copy link
Copy Markdown
Owner

v1.9.8 "Horizon" — iOS store-readiness

The iOS store-readiness pass (the analogue of Android v1.8.8 "Atlas") — a broad pre-launch release. All SwiftUI-shell work — no Rust / core / bridge changes; only CARGO_PKG_VERSION moves 1.9.7 → 1.9.8, so the core stays byte-identical and AccuracyCoin holds 100% (139/139). Interim TestFlight.

Added

  • Accessibility — VoiceOver labels/hints/values across the pill menu / top bar / library / palette + save-state rows / Settings; Dynamic Type (scalable pill icons, decorative symbols hidden); built-in High-contrast + Okabe-Ito colourblind palettes (AccessibilityPalettes.swift, generated deterministically, feeding the same loadPalette path), selectable globally + per-game.
  • EN / ES i18n — a String Catalog (Localizable.xcstrings, source en, 84 ES entries) via SwiftUI's automatic LocalizedStringKey lookup; English stays byte-identical (keys are the English strings); CFBundleLocalizations en,es. Full coverage incremental.
  • ReplayKit — a Record toggle → RPScreenRecorder start/stop → RPPreviewViewController; graceful not-available/denied; PiP a documented follow-up.
  • Game Center (GameCenterModel, opt-in, default off) — GKLocalPlayer auth + GKAccessPoint; no app-defined achievements (RetroAchievements stays the system); GKSavedGame flagged as a future CloudKit alternative; no-op when unavailable.
  • Privacy manifest — discloses RetroAchievements (UserID, linked/functionality) + Game Center (OtherDataTypes); CloudKit intentionally not listed (the user's own private DB); FileTimestamp C617.1 + UserDefaults CA92.1 reasons added; NSPrivacyTracking false.
  • foss / StoreKit seam — an APPSTORE_BUILD compile flag (SWIFT_ACTIVE_COMPILATION_CONDITIONS, default foss; BuildChannel.swift) + a dormant StoreManager (real StoreKit 2 calls behind a default-off guard) — both channels behave identically (fully unlocked, no ads) until the v2.1.0 split (ADR 0027). ReplayKit/GameKit/StoreKit frameworks linked.

Host gates green (fmt / clippy -D warnings) + markdownlint clean; the String Catalog + plists validated. On-device validation of the accessibility/i18n/ReplayKit/Game-Center paths remains the documented TestFlight carryover.

🤖 Generated with Claude Code

The iOS store-readiness pass (the analogue of Android v1.8.8 "Atlas"): accessibility,
EN/ES i18n, ReplayKit capture, Game Center, a 4.7 + privacy-manifest pass, and the
dormant StoreKit / foss-vs-App-Store seam. No Rust/core/bridge changes; only
CARGO_PKG_VERSION moves 1.9.7 -> 1.9.8, so the shipped/native/no_std/wasm core stays
byte-identical and AccuracyCoin holds 100% (139/139). Interim TestFlight.

- Accessibility: VoiceOver labels/hints/values across the pill menu / top bar /
  library cells / palette + save-state rows / Settings; Dynamic Type (pill icons ->
  scalable .title3, decorative symbols hidden); built-in High-contrast + Okabe-Ito
  colourblind palettes (AccessibilityPalettes.swift, generated deterministically,
  feeding the same loadPalette path), selectable globally + per-game.
- EN/ES i18n: a String Catalog (Localizable.xcstrings, sourceLanguage en, 84 ES
  entries) via SwiftUI's automatic LocalizedStringKey lookup; English byte-identical
  (keys are the English strings). CFBundleLocalizations en,es. Full coverage incremental.
- ReplayKit: a Record toggle (pill menu + Settings) -> RPScreenRecorder start/stop ->
  RPPreviewViewController; graceful not-available/denied; PiP a documented follow-up.
- Game Center (GameCenterModel.swift, opt-in, default off): GKLocalPlayer auth +
  GKAccessPoint; no app-defined achievements (RA stays the achievement system);
  GKSavedGame flagged as a future CloudKit alternative; no-op when unavailable.
- Privacy manifest: discloses RetroAchievements (UserID, linked/functionality) +
  Game Center (OtherDataTypes); CloudKit intentionally not listed (user's own private
  DB); FileTimestamp C617.1 + UserDefaults CA92.1 reasons added; NSPrivacyTracking false.
- foss/StoreKit seam: an APPSTORE_BUILD compile flag (SWIFT_ACTIVE_COMPILATION_
  CONDITIONS, default foss; BuildChannel.swift) + a dormant StoreManager (real
  StoreKit 2 calls behind a default-off guard) -- both channels behave identically
  (fully unlocked, no ads) until the v2.1.0 split (ADR 0027). ReplayKit/GameKit/
  StoreKit frameworks linked in project.yml.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings June 26, 2026 04:35

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request prepares the iOS SwiftUI shell of RustyNES for store-readiness (v1.9.8 "Horizon") by adding accessibility features (VoiceOver support and custom high-contrast/colorblind palettes), EN/ES internationalization via a String Catalog, gameplay video capture using ReplayKit, and opt-in Game Center integration. It also updates the privacy manifest and introduces a dormant StoreKit 2 scaffold along with a compile-time FOSS vs. App Store build channel seam. The review feedback highlights several critical improvements: in GameCenterModel, the authentication handler should guard against disabled states, clear pending auth requests to prevent stuck UI, and clean up state when disabled; in Entitlements, the entitlement reconciliation logic needs to properly reset the purchase status to handle refunded or revoked transactions.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread ios/RustyNES/GameCenterModel.swift
Comment thread ios/RustyNES/GameCenterModel.swift
Comment thread ios/RustyNES/Entitlements.swift

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

iOS v1.9.8 “Horizon” store-readiness pass focused on SwiftUI-shell improvements (accessibility, i18n, ReplayKit, Game Center, privacy manifest) plus distribution seams and version bumps, while keeping the Rust core byte-identical.

Changes:

  • Adds opt-in Game Center authentication/presence and ReplayKit screen recording flows (with SwiftUI hosts for system controllers).
  • Introduces EN/ES localization via a String Catalog and broad VoiceOver/Dynamic Type improvements across UI surfaces.
  • Adds privacy manifest disclosures, dormant StoreKit scaffolding + foss/appstore build-channel seam, and bumps versioning/docs.

Reviewed changes

Copilot reviewed 21 out of 22 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
ios/RustyNES/SettingsView.swift Adds Settings sections for Game Center + screen recording; enhances palette picker accessibility/localization.
ios/RustyNES/ScreenRecorder.swift Implements ReplayKit recording + preview presentation host.
ios/RustyNES/SaveStatesView.swift Improves save-state UI accessibility (decorative icon hiding; button labels).
ios/RustyNES/PrivacyInfo.xcprivacy Updates privacy manifest for optional RA/Game Center + required-reason APIs.
ios/RustyNES/PillMenu.swift Adds Record pill and expands VoiceOver labels/hints + Dynamic Type-friendly icon sizing.
ios/RustyNES/OnboardingView.swift Adjusts onboarding strings to flow through String Catalog + improves accessibility.
ios/RustyNES/Localizable.xcstrings Adds EN source String Catalog with ES translations for key strings.
ios/RustyNES/Info.plist Declares supported localizations (en, es).
ios/RustyNES/GameView.swift Wires pill menu recorder + preview host and improves top-bar accessibility.
ios/RustyNES/GameCenterModel.swift Adds opt-in Game Center model + SwiftUI host for GameKit auth UI.
ios/RustyNES/Entitlements.swift Adds dormant StoreKit 2 scaffold (StoreManager) and links StoreKit.
ios/RustyNES/ContentView.swift Adds Game Center auth host and improves library tile accessibility.
ios/RustyNES/BuildChannel.swift Adds foss vs App Store compile-time channel seam.
ios/RustyNES/AppModel.swift Wires new iOS models and adds built-in accessibility palette resolution + localized error string usage.
ios/RustyNES/AccessibilityPalettes.swift Adds deterministic built-in accessibility palettes and lookup helpers.
ios/RustyNES/AboutView.swift Makes ownership notice localizable via String Catalog.
ios/project.yml Links ReplayKit/GameKit/StoreKit and documents build-channel/i18n notes for XcodeGen.
docs/STATUS.md Updates status matrix for v1.9.8 release.
CHANGELOG.md Adds v1.9.8 release notes.
Cargo.toml Bumps workspace version to 1.9.8.
Cargo.lock Bumps crate versions to 1.9.8.
android/app/build.gradle.kts Bumps Android versionCode/versionName to 1.9.8.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread ios/RustyNES/AppModel.swift Outdated
Comment thread ios/RustyNES/GameCenterModel.swift
Comment thread ios/RustyNES/SaveStatesView.swift Outdated
Comment thread ios/RustyNES/SaveStatesView.swift Outdated
Comment thread ios/RustyNES/ContentView.swift Outdated
Comment thread ios/RustyNES/GameView.swift Outdated
… reset, ES localization

Resolve the v1.9.8 "Horizon" bot-review threads (all confined to ios/RustyNES/):

- GameCenterModel: clear authenticateHandler + deactivate access point + reset
  published state on disable so stale callbacks can't fire; guard `enabled`
  inside the handler before presenting.
- Entitlements.reconcileEntitlements: track unlock in a local var and assign
  purchased after the loop so a refund/revoke flips purchased back to false.
- Localization: route the palette + HD-pack load errors through
  String(format: String(localized:), ...); wrap interpolated accessibility
  labels/hints/values (save-state slots, library item, mute control) in Text(...)
  so they resolve as LocalizedStringKey and pick up the ES catalog.
- Localizable.xcstrings: add 8 EN source keys + ES translations.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@doublegate
doublegate merged commit fa00dd6 into main Jun 26, 2026
23 checks passed
@doublegate
doublegate deleted the feat/v1.9.8-horizon branch June 26, 2026 12:40
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.

2 participants