Skip to content

feat(ios): Android-parity SwiftUI rebuild (Material 3 home carousel, tonal bands, token fixes) - #8

Merged
z44d merged 15 commits into
masterfrom
android-ios-clone
Oct 28, 2026
Merged

z44d merged 15 commits into
masterfrom
android-ios-clone

Conversation

@z44d

@z44d z44d commented Oct 25, 2026

Copy link
Copy Markdown
Owner

What

Continues the Android→SwiftUI parity work on the iOS app (ios/). This branch carries the M3 rebuild already committed on feat/ios-android-clone plus the further parity pass:

  • Home now mirrors Android's Carmen home: the 430pt primaryContainer → secondaryContainer → clear tonal wash, a "Suggested for you" hero carousel (full-bleed artwork, bottom-weighted black scrim, white title over it, live playing-pill in the corner, snap scrolling, exact Android card width/height math) and "Keep listening" wide resume cards (surfaceContainerHigh + 1pt outlineVariant border, 96pt thumb, filled play/pause, artist • duration subtitle).
  • Library gets the same tonal band behind the chip-tabs pager, same as Android's LibraryScreen.
  • Components: GridTile follows Android's GridItem tokens (one-line bold bodyLarge title, secondary-coloured bodyMedium subtitle, badges beside the subtitle), and SectionHeader follows HomeSectionHeader (min 64pt row, 8pt vertical padding, semibold title).
  • QueuePanel: extracted queueRow + explicit upcoming range (carry-over of the pending fix on the old branch).
  • Player / mini player / search / detail screens audited against the Android sources; they already follow the documented panel-takeover and MediaDetailHero anatomy, so no structural change there.

Verification

No local compile (user's machine has no Xcode). The ios-check CI job (Xcode 26 SDK, swift format lint parse) is the gate for this PR.

z44d and others added 15 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.
…nal bands

Match Android's Carmen home: a 430pt primary→secondary container wash, the
"Suggested for you" hero carousel (full-bleed artwork, bottom scrim, white
title, now-playing pill, snap scrolling), and "Keep listening" wide resume
cards (surfaceContainerHigh + outline border, 96pt thumb, filled play).
Libraries get the same wash behind the pager, and GridTile/SectionHeader now
carry Android's exact GridItem/HomeSectionHeader tokens (bold one-line title,
secondary subtitle, 64pt header row).

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
…me module notes

- Home: Android's SpeedDialSection (paged 3x3 pinned tiles with page dots,
  playlist stand-ins + random tile) and ForgottenFavoritesSection (4-row
  snapped 47.5% grid of favorites not recently played).
- Library: matching Android's default chip order, a Podcasts tab backed by
  on-device saved shows, and long-press save/unsave on podcast search cards.
- Search/nav: podcast cards become kind .podcast, push the new PodcastView
  detail screen (/podcasts/podcast/{id}) and play its episode rows.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
…it left behind

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
…astView episode-list call

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
…k, not a shape overlay

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
@z44d
z44d merged commit 508056a into master Oct 28, 2026
8 checks passed
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