iOS redesign aligned with the handoff (FlarePurge iOS Spec.md + 6 artboards). Kicks off in parallel with 1.5.0 going up to TestFlight. Delivered in phases: this first batch brings tokens, atomic components, navigation refactor and the first screen redesigns.
Decisions made before starting
- ✅ Selective Purge
Tags + Prefix tabs out (Enterprise-only, consistent with the Mac's decision #9). - ✅
Zone.planName + Zone.createdOn added to the CloudflareKit model (backward-compatible, optional decoding). - ✅ Recent purges → volatile memory for now (option B; full SwiftData deferred to v1.7).
- ✅ CSV export out of scope.
- ✅ The Dark/Light/System picker is kept (consistent with Mac, ignores the spec's "dark-only" restriction).
- ✅ Version bump to 1.6.0 for a new screen (Account switcher) + substantial navigation change.
- ✅ Custom floating tab bar (not native
TabView) for fidelity with the mockup.
Phase A — Infra + tokens (done)
CloudflareKit/Sources/CloudflareKit/Models/Zone.swift — new planName: String? and createdOn: Date? fields. Tolerant decoding with ISO8601 (with and without fractional seconds), backward-compatible with the existing on-disk cache.App/DesignTokens.swift — new FPColor.iOS namespace (iOS-specific palette: #000 OLED bg, #1A1D23 card, #0E1014 bgElev, #C7CAD1 textDim, etc.). Different palette from the Mac one for OLED contrast and warmths. New FPRadiusIOS (card=18, container=20, iconChip=12, search=14).MARKETING_VERSION 1.5.0 → 1.6.0, build 4 → 5.
Phase B — iOS atomic components (done)
New file Views/Components/IOSComponents.swift (14 types):
IOSGlobeIcon · globe with border+fill at color@40%/8%.IOSPill(color, label, soft) · Active/OK/Draft pill, soft vs filled.IOSStarIcon(filled, size) · yellow filled or mutedDim outline.IOSChevron · mutedDim right arrow.IOSOverline(text, color) · §CAPS uppercase 10pt tracking 0.8.IOSMetaCell(label, value, mono) · overline + value (mono optional).IOSCard(padding){} · 18pt radius card wrapper with border.IOSSearchBar(text, placeholder) · visible inline search (not native .searchable).IOSAccountPill(name, action) · top-right pill with circular accent avatar.IOSRoundIconButton · 40pt round button.IOSFloatingCTA(label, action) · orange pill with gradient + glow + flame.IOSFloatingTabBar(active) · floating pill with blur, 2 icon+label tabs.IOSPurgeGradientCTA(title, subtitle, action) · primary button gradient accent→accentHot with glow.IOSActionCard(icon, iconColor, title, subtitle?, monoAccessory?, action) · secondary card with 44×44 icon chip.
Phase C (partial — checkpoint)
- iOS MainTabView — full refactor for compact layout: ZStack with content +
IOSFloatingTabBar overlay (pill with blur, bottom 18). Local activeTab state replaces the native TabView. Mac and iPad (regular/desktop) keep the legacy TabView. AccountMenu adapted: on iOS it shows an IOSAccountPill that opens AccountSwitcherSheet; on Mac it keeps the native Menu.AccountSwitcherSheet (new, Views/Main/AccountSwitcherSheet.swift) — .medium sheet with a "Switch account" overline title, rows with a flame avatar (accent when active) + label + mono zone count + accent checkmark, a separate "+ Add API key" row.- iOS
ZoneListView — the round corner FAB replaced by IOSFloatingCTA (wide pill with gradient + glow) positioned above the floating tab bar. Bottom padding adjusted so it doesn't collide with the tab bar. - iOS
ZoneDetailView — ActionCards replaced by IOSPurgeGradientCTA (primary with gradient and glow) + IOSActionCard (selective) + a new "Copy zone ID" card with a mono preview of the id (uses UIPasteboard + success haptic). - iOS
SettingsView — green hero card at the top "Tokens stay on this device / Stored in Keychain · No backend · No tracking". navigationBarTitleDisplayMode changed to .large for a prominent "Settings" title. Bottom safe area 120pt so it doesn't collide with the floating tab bar.
Localization
- 2 new iOS-specific keys EN+ES:
ios.tokens.stayOnDevice.title, ios.tokens.stayOnDevice.sub.
Following batches (applied in the same 1.6.0 cycle)
- iOS ZoneListView full redesign — big title
Zones 28/800 + mono count + inline IOSSearchBar + FAVORITES section as a card container + collapsible account groups with card + rows with IOSGlobeIcon + star toggle + chevron + context menu (favorite/purge/copy). Nav bar hidden on iOS. iPad/Mac keep the legacy List. - iOS Zone detail 2×2 meta grid —
IOSGlobeIcon 52 + title 24/800 + active IOSPill + star. Separator + 4 meta cells (Zone ID / Name servers / Plan / Added) leveraging the new Zone.planName + Zone.createdOn. - iOS Selective purge (mock6) — zone header card + custom URLs/Hosts segmented picker + mono hint "Paste up to 30 URLs" + numbered list (00, 01, 02…) with mono rows + an X button per entry + a final input row with placeholder + orange + button + mono counter
N URLs · (30-N) remaining in this batch + Purge N CTA in the toolbar. Native Form removed on iOS. - iOS Add API key 1-step form (mock4) — new file
AddAPIKeyIOSView.swift. Eyebrow § CREDENTIALS + h1 "Paste your token." + body + LABEL card + mono API TOKEN card with eye toggle + orange-bordered "Paste from clipboard" button + REQUIRED PERMISSIONS section with 3 rows. Native Cancel/Save toolbar. Bypasses the multistep TokenWizardView on iOS; Mac keeps the wizard. AddAccountSheet routes to the new view on iOS.
Localization
- 11 new keys translated into full 21 languages (228 translations):
ios.tokens.stayOnDevice.*, ios.zones.count.unit, ios.zone.copyId, ios.zone.meta.added, mac.zone.meta.zoneId, ios.selective.hint, ios.selective.remaining, ios.selective.purgeCount, ios.addKey.title, ios.addKey.body, action.save. Scripts persisted in scripts/translate_ios_keys.py.
Final polish (in the same 1.6.0 cycle)
- iOS Settings icon chips larger (32px vs 28px on Mac) with a 16pt icon. Haptics tint changed from
.pink → .red (consistent with mock5). Haptics toggle with .tint(.orange) on iOS. - Recent purges section in iOS Zone Detail — new
PurgeHistoryStore singleton @MainActor @Observable in memory (cap 20 events, no persistence). Automatic record on every purge (total or selective, success or failure). UI shows the last 3 events of the current zone with a tinted flame icon, title by kind (Everything / N URLs / N hosts), relative mono timestamp and an IOSPill OK/Failed.
Final v1.6.0 polish (done)
- iOS empty states —
EmptyStateView redesigned: 96pt circular hero with an orange blur halo + inner tinted circle + accent stroke, 40pt accent icon, title 22/800, body 14pt, CTA as an orange pill with glow. Mac keeps its previous layout. - Tinted pull-to-refresh —
.tint(FPColor.accent) applied in iOS ZoneListView so the native pull-to-refresh spinner renders in brand orange instead of the system blue.
Final 1.6.0 build
- Mac + iOS Simulator both
BUILD SUCCEEDED. - Ready for archive + upload to TestFlight.
Build
- Mac + iOS Simulator both
BUILD SUCCEEDED.