Skip to content

feat(ios): rebuild the UI as a Material 3 clone of the Android app - #7

Closed
z44d wants to merge 9 commits into
masterfrom
feat/ios-android-clone
Closed

z44d wants to merge 9 commits into
masterfrom
feat/ios-android-clone

Conversation

@z44d

@z44d z44d commented Oct 24, 2026

Copy link
Copy Markdown
Owner

What

Rebuilds the entire iOS UI as a faithful SwiftUI clone of the Android app's Material 3 interface (ArchiveTune fork), keeping the Carmen server data layer, playback/download infra and every on-device store untouched.

  • Design system (new): Views/Theme/Theme.swift — 19 M3 color roles derived live from the artwork/settings accent (ED5564 fallback), Poppins type scale (font copied from android/app/src/main/res/font), shape/dimension tokens, press-scale; Views/Components/ — the shared kit (TopAppBar, ListRow, GridTile, chips, cards, shimmers, M3 state panes, sheet menus, buttons, ArtworkView).
  • Shell: 3 tabs (Home / Search / Library) behind a floating pill nav; the mini player stacks onto the pill as one connected blob (Android's CONNECTED navigation bar, 32↔28 radius lerp). Queue tab removed — the queue lives in the player as a panel (Lyrics / Queue / Related). Settings moves from a 4th tab to the per-screen overflow sheet.
  • Screens: Home, Search (+ pushed results with filter chips/sort/grouping), Library (Mix/Playlists/Songs/Artists/Albums/Downloads pages), Album/Artist/Playlist details with the M3 hero anatomy, the full player (custom scrubber, transport, panel takeover), and the Settings hub — all 1:1 in behavior with the previous UI.
  • Removed: legacy Components.swift, QueueView.swift; no Liquid Glass anywhere (iOS 18 floor).

Notes

  • No local build possible on this machine — ios-check on CI is the compile gate; fix commits will follow if it flags anything.
  • Niche Android modules (SponsorBlock, last.fm, Shazam, equalizer, stats, news, onboarding, podcasts/Spotify tabs, AOD, canvas) are intentionally not ported — core experience first.

z44d added 9 commits October 24, 2026 17:17
…les)

- bundle Poppins (copied from android/app/src/main/res/font) via UIAppFonts
- M3Roles: 19 roles derived from the live accent seed, light + dark
- Color.carmen family moved Components.swift -> Theme/Theme.swift
- M3 type scale, shape/dimension tokens, press-scale modifier
…t menus)

- Buttons: filled/tonal/text/icon styles + FAB, 40pt capsules & circles
- Chips: FilterChip (selected = secondaryContainer + checkmark), TagChip
- Rows: ListRow (72pt/56pt r10 + kebab sheet menu), GridTile (old CardTile
  routing incl. play-context/route/station), SectionHeader w/ Play all,
  PlayingIndicator (4 animated bars), TrackSheetMenu
- Surfaces: M3Card, shimmer (block/list/grid skeletons), loading/error/empty
- Chrome: TopAppBar, M3SearchDock/M3SearchField, .bottomSheetMenu (own
  NavigationStack so Go to Album/Artist push), SheetMenuRow(Label)
- Actions: Favorite/Download/PlaylistPicker ported verbatim (same stores)
- ArtworkView + ExplicitBadge moved verbatim; old copies removed from
  Components.swift (no duplicate declarations)
- Route/CarmenDestinations/carmenDestinations/playableTracks move verbatim
- new Route.searchResults(query:) + destination -> SearchResultsView
- Components.swift header notes it is legacy-only now
Home, Search (+ results), Library, Album/Artist/Playlist details, the
mini bar, the full player (lyrics/queue/related panels) and Settings,
restyled as a faithful clone of the Android app's Material 3 UI on top
of the new Theme/ kit. Data layer, playback, downloads and every
setting's behavior are unchanged — this is a visual/port parity pass.
RootView now hosts Home/Search/Library behind a floating pill nav
(FloatingNavBlob — Android's CONNECTED bar: mini player stacked on the
pill as one surfaceContainer blob, 32↔28 radius lerp, bottom
safeAreaInset so scrolls end above it), mounts .m3Theme() outermost,
and keeps the expansion-driven player overlay. Settings moves from a
tab to the per-screen overflow sheet. Deletes the superseded Queue tab
(QueueView.swift) and the legacy Components.swift — the kit owns all
shared UI now.
…menu init

In type position (menuItems: @ViewBuilder () -> Menu) the compiler reads
the attribute as a type attribute and rejects it as unknown — it must
precede the parameter name. Caught by the ios-check job on PR #7.
- DetailHero's init re-declared <Trailing> shadowing the struct's own
  generic, leaving the type parameter unbound at call sites (could not
  be inferred). The init now uses the struct's generic parameter.
- presentationGrabber does not exist as a View member in this SDK; the
  sheet grabber is presentationDragIndicator(.visible).
Replace ForEach(Array(upcoming.enumerated()), id: \.offset) with
ForEach(upcoming.indices, id: \.self): ArraySlice indices are already
absolute queue positions, so the pair/offset arithmetic disappears and
the constraint system that ios-check choked on goes with it.
A bare upcoming.indices resolves to the SDK RangeSet-returning
indices(where:) method instead of the Collection property, so ForEach
received a function type. Expose the slice bounds as an explicitly
typed Range<Int> from a getter instead.
z44d added a commit that referenced this pull request Oct 28, 2026
…nt kit, 3-tab pill shell (#8)

Squash-merge of PR #8 (reviewed: all 8 checks green on head 93abae0, full Swift parse clean, no secrets, changes confined to ios/ + AGENTS.md).

Contains all 9 commits of PR #7 plus 6 follow-up fixes/parity commits:
- Material 3 theme foundation (Poppins, seed-derived roles) + component kit
- 3-tab pill shell (FloatingNavBlob) with connected mini player, Settings as sheet
- Home parity: hero carousel, resume cards, tonal bands, speed dial, forgotten favorites
- Library podcasts tab, QueuePanel extraction, Transferable drag payloads

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@z44d

z44d commented Oct 28, 2026

Copy link
Copy Markdown
Owner Author

Closing in favour of #8 — this PR's head (29c2c23) is an ancestor of #8's head (93abae0), so all 9 commits here already landed on master via the squash-merge of #8 (508056a).

Also worth noting: this branch's head does not compile — ios/Carmen/Views/QueuePanel.swift:114 fails the iOS compile check (cannot convert value of type 'Range<Int>' to expected argument type 'Binding<C>'), which is why it couldn't be merged directly. That error is fixed by the follow-up commits contained in #8.

No work was lost; #8 is a strict superset of this PR.

@z44d z44d closed this Oct 28, 2026
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