Repository navigation
feat(ios): Android-parity SwiftUI rebuild (Material 3 home carousel, tonal bands, token fixes) - #8
Merged
Merged
Conversation
…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>
This was referenced Oct 28, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Continues the Android→SwiftUI parity work on the iOS app (
ios/). This branch carries the M3 rebuild already committed onfeat/ios-android-cloneplus the further parity pass:primaryContainer → secondaryContainer → cleartonal 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).LibraryScreen.GridTilefollows Android'sGridItemtokens (one-line boldbodyLargetitle,secondary-colouredbodyMediumsubtitle, badges beside the subtitle), andSectionHeaderfollowsHomeSectionHeader(min 64pt row, 8pt vertical padding, semibold title).queueRow+ explicit upcoming range (carry-over of the pending fix on the old branch).Verification
No local compile (user's machine has no Xcode). The
ios-checkCI job (Xcode 26 SDK,swift format lintparse) is the gate for this PR.