Skip to content

Implementation

Offline SwiftUI math practice for iOS/iPadOS 17+, using Swift 6 strict concurrency. No backend, accounts, analytics, ads, or runtime networking. Native-reader, educator, accessibility, and physical-device approval remain release requirements.

Behavior

  • Every fresh scene starts with a branded launch page shown for at least two seconds, then a short fade (no fade under Reduce Motion). A thin native progress bar tracks the two-second intro using monotonic elapsed time, not network or data loading. It updates without added animation and is decorative for VoiceOver; the Mongolian app name remains the semantic content. Returning from the background does not replay it or reset navigation. First-install Welcome remains separate and still requires Start; completed onboarding stays persisted. The launch page reuses the existing Mongolian app name, adapts to light/dark appearance, landscape, and Dynamic Type, and has no new wording, controls, or loading claims. The system launch surface uses the same appearance-adaptive canvas.
  • Practice mixes four arithmetic operations and comparison across eight ranges, with configurable round length. Arithmetic has four unique positive choices; comparison uses <, =, >. Addition/subtraction keep both operands in range; multiplication/division cap facts and choices at the range ceiling and division is exact. Seeded sessions are deterministic.
  • Answers evaluate immediately. Correct answers advance automatically; mistakes retain the question. Non-Review mistakes append at most two reinforcement encounters per original question. Outcomes remain first try, independent retry, assisted, or guided.
  • Help and answer feedback open a separate scrollable explanation sheet. Closing preserves the question and counting marks; Help alone adds no duplicate feedback tile. Guided answers wait for Next/Finish. Practice scrolls when content cannot fit; first-range quantity prompts use provisional exact-count animal emoji.
  • Complete rounds save once. Early exit offers Keep (save resolved progress), Drop (no History entry), and Resume (continue unchanged). Terminated rounds do not resume.
  • Mistakes or Help queue deduplicated review questions. Due-only review uses 1, 3, 7, 14, and 30-day intervals; independent success advances and eventually graduates a question, while incorrect, assisted, or guided work returns to one day.
  • Daily goals repeat; weekly goals aggregate Monday–Sunday. Completed and kept Practice/Review progress count once. Only daily goals use an optional local app-icon badge.
  • Settings persist round length, missing-term position, independent question/answer number words, the default-on buged connector, and Tsagaan/Qimed/Agola typeface. Number words apply to ranges ending at or below 100. Privacy rows are noninteractive.
  • iOS 26 uses native icon-only tabs; earlier systems use the material footer. Shared controls respect Dynamic Type, Reduce Motion/Transparency, and Increase Contrast. Sound cues are bundled and reproducible with tools/generate_sounds.py.

Architecture and storage

project.yml is the XcodeGen source of truth; do not hand-edit the generated Xcode project.

Path Responsibility
MyangatKids/App Transient launch, persisted welcome, navigation, plan badges
MyangatKids/Models Deterministic questions, sessions, history, review, plans
MyangatKids/Views Render model state; never calculate correctness
MyangatKids/DesignSystem Centralized copy, theme, Mongolian rendering
MyangatKidsTests Model and presentation regression tests

History uses atomic version-4 JSON in Application Support, migrating the earlier UserDefaults archive. It records planned counts, facts, choices, attempts, and outcomes; older records retain only available details. Review and plans use versioned UserDefaults archives. Plan version 2 migrates per-date goals into temporary overrides. Unknown or unreadable archives block writes; app updates preserve the container.

MenkLetter copy converts locally through pinned MongolConvertSwift v0.7.1 to bundled Z52 fonts. See rendering rules and the copy inventory. Deferred SwiftUI builders snapshot main-actor state into nonisolated content; UIKit drawing and callbacks remain main-actor-isolated.

Build and verification

Requires Xcode 26+ and XcodeGen:

make prepare-ios
make test-ios
make build-ios
python3 tools/validate_copy.py
python3 -m unittest discover -s tools -p 'test_*.py'
uv run --locked mkdocs build --strict

SIMULATOR defaults to iPhone 17 Pro; the destination resolver chooses its newest available iOS runtime. DESTINATION overrides discovery. Preparation downloads and SHA-256-verifies the pinned converter through tools/prepare_mongol_convert.sh; this is build-time only. When available, xcode-build-server refreshes editor configuration; reload the editor afterward.

Launch-page verification: 108 tests and a build passed on the iOS 26.5 iPhone 17 Pro simulator, including the two-second minimum, clamped elapsed-time progress, repeated fresh entries after completed onboarding, first-install routing, foreground-return stability, bundled artwork, and five light/dark, small-phone, landscape, largest-text, and iPad-sized hosted layouts. All four launch tests also passed on the iOS 26.5 iPad mini (A17 Pro) simulator. The launch snapshots and new icon were visually inspected. Actual VoiceOver and system Reduce Motion/Transparency settings were not exercised; their existing rendering/transition paths are preserved. The app icon is an opaque 1024×1024 export; the launch emblem is an independent vector PDF. Four destination-resolver tests previously passed. Earlier checks covered Settings concurrency, History rendering, range limits, exact-count prompts, sounds, and adaptive layouts. Copy validation passed for 146 entries; the approval-gate test remains blocked by existing draft copy. Simulator results do not replace physical-device, VoiceOver, or native-reader review; broader iPad feature verification remains pending.

Icon-only revision: the app icon now uses a wider, lower ivory ger outline and four upright math symbols on forest green, with a long gold stove pipe. The earlier launch illustration has a separate SVG source, and its shipped PDF was verified byte-for-byte unchanged. Opaque 1024×1024 RGB export, masked 20–180-point previews on light/dark backgrounds, make build-ios, and all 107 iPhone simulator tests passed. The subsequent width/roof/chimney adjustment was re-exported, visually checked at full and 120-pixel sizes, and built successfully; XCTest was not rerun for that asset-only adjustment. Physical-device icon review was not run.

Documentation and marketing

The MkDocs overview links to public Support and Privacy pages. Support uses public GitHub issues; neither page changes app behavior. The Material theme override in overrides/partials/comments.html enables Giscus comments on documentation pages, backed by the Announcements category in russhustle/comments-support and mapped by pathname. Set comments: false in a page's YAML front matter to disable comments there. Comments are public, posting requires a GitHub account, and the website's third-party integration does not add networking to the offline app. Giscus verification: strict MkDocs build, embeds on all six pages, front-matter opt-out, and no embed on the 404 page passed; live sign-in and posting were not exercised. Documentation is condensed without changing localization rows or legal notices. Verification: strict MkDocs build and copy validation passed; 14/15 Python tests passed, with the existing draft-copy approval gate failing. Native tests were not run for these documentation-only changes.

reviews/app-store/ contains a separate six-page iPhone/iPad screenshot editor with English, Simplified Chinese, and Cyrillic Mongolian captions—not new app languages. Supplied iPhone images stay unchanged; iPad sources came from a disposable simulator XCTest workspace. Export checks cover fonts, captions, opacity, missing images, and dimensions; the iPad capture test passed. Target exports are 1206×2622 and 2064×2752. Translation review and App Store Connect acceptance remain pending; see reviews/app-store/README.md for provenance and licenses.

Remaining release checks

Draft copy, number-word grammar, Z52 glyphs, spoken accessibility, work mats, provisional animal emoji, sound/motion feedback, and small-screen/iPad layouts need native-reader, educator, and physical-device review. Older history cannot reconstruct missing attempts. Badge display requires permission, and active rounds are not restored after termination.

Comments

Comments are public and posting requires a GitHub account. Parents, guardians, and educators: do not share children's or other personal information.