[PC TV] Apple-TV-style depth on focused cards#4579
Closed
david-gonzalez-a8c wants to merge 10 commits into
Closed
Conversation
Three pieces that work together to give focused cards more depth, in the spirit of the Apple TV home screen carousels: - New `focusedCardDepth(isFocused:cornerRadius:)` view modifier that layers a soft drop shadow and a diagonal "lit from above" sheen on a focused card surface. - RootView background swapped from a flat fill to a subtle top→bottom gradient (new `pcBackgroundTop` / `pcBackgroundBottom` tokens). The gradient is a touch lighter than `pcBackgroundSurface` at the top so the new shadows have something to read against. - Applied the modifier to `DiscoverCategoryCell`, `PlaylistCell`, and `DiscoverFeaturedPodcastCell`, with explicit `RoundedRectangle` clips on the first two (the existing `.clipped()` was a bare rectangle). Co-Authored-By: Claude <noreply@anthropic.com>
- pcBackgroundActive steps back from the white/black extremes (#FBFBFC → #D4D6DB in dark, #161718 → #2A2D31 in light) so focused cards read as silvery/charcoal and let the depth treatment do the lifting instead of raw brightness. - Sheen gradient stops bumped (top white .22 → .45, bottom black .10 → .28) and blend mode switched from .plusLighter to .overlay; the old mode was silently swallowing the dark side of the gradient. - Shadow opacity .45 → .6, radius 32 → 44, y-offset 20 → 26. Co-Authored-By: Claude <noreply@anthropic.com>
…ills Extend the depth treatment to the three pill types that were missing it from the Home screen: - `DiscoverVideoEpisodeCell` (Made for TV row) - `NowPlayingRowLabel` (currently-playing pill) - `EpisodeRow` (Up Next pills, also picked up wherever EpisodeRow is used elsewhere) Also push the inner sheen harder: highlight stop bumped to .85 and the gradient now ramps through .45 → .15 → clear → .45 black so the lit edge has a more pronounced glint rather than a uniform glow. Co-Authored-By: Claude <noreply@anthropic.com>
The full diagonal sheen looks great on artwork cards but muddies the cover and text on content-heavy cards. Split the modifier into two styles sharing the same drop shadow: - `.surface` (default): the existing full diagonal sheen, for cards that are mostly artwork or a flat colour. - `.content`: a thin inner stroke that lights the top edge and lays a subtle rim line at the bottom, leaving the body of the card alone. `DiscoverVideoEpisodeCell`, `NowPlayingRow`, and `EpisodeRow` switch to `.content`. The other three (DiscoverCategoryCell, PlaylistCell, DiscoverFeaturedPodcastCell) keep `.surface` via the default. Co-Authored-By: Claude <noreply@anthropic.com>
…on bare covers Three tweaks following on-device review: - PlaylistCell switched to .content — the diagonal sheen was washing the "New playlist" / "Smart playlist" / episode-count text on the left side of the pill. - .surface highlight rebuilt as two stacked passes: a `.plusLighter` top-leading glint that's purely additive (always brightens, never darkens, so it pops on busy artwork) plus an `.overlay`-blended bottom-trailing falloff. The single `.overlay` pass was capping the highlight intensity against artwork; splitting makes it specular. - DiscoverPodcastRow's bare cover thumbnails now get the .surface treatment via a small `FocusedPodcastCover` wrapper that reads the `.card` button's `\.isFocused`. Co-Authored-By: Claude <noreply@anthropic.com>
The Podcasts tab grid was using `NavigationLink + PodcastImage + .buttonStyle(.card)` with no depth treatment, so its covers felt flat next to Discover rows like "You might like" (which I'd already wired up with the depth modifier). Added a parameterless `focusedCardDepth(cornerRadius:style:)` overload that reads `\.isFocused` from the environment, so any view sitting inside a Button/NavigationLink label can opt in without a wrapper struct. Used it for the Your Podcasts grid, and refactored the DiscoverPodcastRow wrapper away to share the same call shape. Co-Authored-By: Claude <noreply@anthropic.com>
The .surface specular was reading as too aggressive in the on-device review. Halved the plus-lighter highlight stops (.55/.25/.08 → .28/.12/ .04) and roughly halved the overlay falloff (.30/.55 → .16/.30) so it reads as a subtle gleam rather than a metallic sheen. In return, push the shared drop shadow harder across both styles — opacity .6 → .85, radius 44 → 60, y 26 → 36 — so cards feel more clearly lifted off the page now that the highlight is doing less of the lifting itself. Co-Authored-By: Claude <noreply@anthropic.com>
Collaborator
Generated by 🚫 Danger |
- Respect `accessibilityReduceTransparency`: skip the blend-mode sheen (the shadow still lifts the card, just without the translucent overlay). - Respect `accessibilityReduceMotion`: drop the easeInOut timing curve on focus state changes. - `FolderCardView` now also picks up `.surface` depth so folder cells match the podcasts they sit next to in the Podcasts grid. - Added a `#Preview` showing both styles side by side for future tuning. Co-Authored-By: Claude <noreply@anthropic.com>
`EpisodeRow` paints its own background, clip, and focused-card depth when used standalone (Up Next, podcast detail list, player button). Inside `EpisodeRowWithActions`, the outer container needs to be the single card surface so the depth treatment renders across both the row and the more-button gutter — previously the inner row's shadow got clipped by the wider outer clipShape, leaving the depth half-applied. Adds a `providesCardSurface` flag (default true) on `EpisodeRow` with a `fileprivate` init for same-file callers, and moves the card surface onto the outer container in `EpisodeRowWithActions`. Co-Authored-By: Claude <noreply@anthropic.com>
This reverts commit 3b4fb58.
Contributor
There was a problem hiding this comment.
Pull request overview
This PR updates the tvOS app’s focus visuals to better match Apple TV carousel cards by introducing a reusable focused-card “depth” treatment (shadow + highlight) and applying it across key TV UI surfaces, along with a subtle page background gradient and retuned focus highlight color.
Changes:
- Added a new
focusedCardDepth(...)SwiftUI modifier with two highlight styles and accessibility-aware behavior. - Applied the modifier across multiple tvOS card/row views, including a small
EpisodeRow/EpisodeRowWithActionsrefactor to avoid double-painted card surfaces. - Updated the tvOS root background from a flat fill to a top→bottom gradient using new background tokens, and retuned the global focused-surface color token.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| podcasts.xcodeproj/project.pbxproj | Project file adjustment (FirebaseManager build file entry ordering). |
| Pocket Casts TV App/UI/Style/FocusedCardDepth.swift | Introduces the new focused-card depth modifier (shadow + highlight styles). |
| Pocket Casts TV App/UI/Style/Color+Style.swift | Adds top/bottom background tokens and retunes pcBackgroundActive. |
| Pocket Casts TV App/UI/RootView.swift | Switches the root background to a subtle vertical gradient. |
| Pocket Casts TV App/UI/Podcasts/PodcastsView.swift | Applies depth treatment to podcast cover cards in the grid. |
| Pocket Casts TV App/UI/Podcasts/FolderCardView.swift | Applies depth treatment to folder cards. |
| Pocket Casts TV App/UI/Podcasts/EpisodeRow.swift | Adds optional surface-providing behavior and applies depth treatment. |
| Pocket Casts TV App/UI/Playlists/PlaylistCell.swift | Updates clipping to rounded corners and applies depth treatment. |
| Pocket Casts TV App/UI/Player/NowPlayingRow.swift | Applies depth treatment to the Now Playing card. |
| Pocket Casts TV App/UI/Discover/DiscoverVideoEpisodeCell.swift | Applies depth treatment to the “Made for TV” episode card. |
| Pocket Casts TV App/UI/Discover/DiscoverPodcastRow.swift | Applies depth treatment to bare podcast cover cards. |
| Pocket Casts TV App/UI/Discover/DiscoverFeaturedPodcastCell.swift | Applies depth treatment to the featured podcast card. |
| Pocket Casts TV App/UI/Discover/DiscoverCategoryCell.swift | Updates clipping to rounded corners and applies depth treatment. |
Comments suppressed due to low confidence (2)
Pocket Casts TV App/UI/Podcasts/EpisodeRow.swift:83
focusedCardDepthdraws its highlight using a.continuousrounded rect, but this card is clipped with the default rounded-rect style. That can cause subtle corner mismatches (highlight/shadow not aligning with the clipped surface).
struct MoreButtonStyle: ButtonStyle {
@Environment(\.isFocused) var isFocused: Bool
Pocket Casts TV App/UI/Podcasts/EpisodeRow.swift:160
- Same as above: the outer container applies
focusedCardDepth, but the card is clipped with the default rounded-rect style. Using.continuoushere keeps the clip shape aligned with the depth modifier's highlight/shadow.
}
.contextMenu {
EpisodeActionButtons(model: model, context: context, isShowingShowNotes: $isShowingShowNotes)
Comment on lines
+50
to
54
| // Focus highlight (`bg-active`). The focused surface inverts against the page but stays a | ||
| // step back from pure black/white — a silvery card in dark mode, a charcoal card in light — | ||
| // so the sheen and shadow on focused cards do the lifting instead of raw brightness. | ||
| static let pcBackgroundActive = Color(uiColor: .appearance(light: "#2A2D31", dark: "#D4D6DB")) | ||
|
|
Comment on lines
79
to
82
| .clipShape(RoundedRectangle(cornerRadius: 12)) | ||
| .clipped() | ||
| .focusedCardDepth(isFocused: isFocused, cornerRadius: 12, style: .content) | ||
| .focusSection() |
| @@ -67,6 +67,7 @@ private struct NowPlayingRowLabel: View { | |||
| .padding(32) | |||
| .background(isFocused ? Color.pcBackgroundActive : Color.pcBackgroundSunken) | |||
| .clipShape(RoundedRectangle(cornerRadius: 12)) | |||
| @@ -113,7 +113,7 @@ struct DiscoverFeaturedPodcastCell: View { | |||
| } | |||
| .background(Color.pcBackgroundSunken) | |||
| .clipShape(RoundedRectangle(cornerRadius: 12)) | |||
| @@ -31,6 +31,7 @@ struct FolderCardView: View { | |||
| .frame(width: cardSize, height: cardSize) | |||
| .background(Color(uiColor: AppTheme.folderColor(colorInt: model.folder.color))) | |||
| .clipShape(RoundedRectangle(cornerRadius: 12)) | |||
Comment on lines
+75
to
+80
| .shadow( | ||
| color: .black.opacity(isFocused ? 0.85 : 0), | ||
| radius: isFocused ? 60 : 0, | ||
| x: 0, | ||
| y: isFocused ? 36 : 0 | ||
| ) |
Contributor
Author
|
Closing in favour of #4580 to get a clean review history (Copilot's earlier comments were against superseded code). |
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.
Summary
Adds depth to focused cards across the tvOS app: each focused surface gets a soft drop shadow and a focus highlight tuned to its content (full diagonal sheen for artwork cards, edge-stroke highlight for text-heavy ones). A subtle top-to-bottom page gradient replaces the flat background so the shadows have something to read against, and
pcBackgroundActiveis stepped back from pure white/black so the focused surface reads as a silvery/charcoal material instead of raw brightness.What changed
focusedCardDepth(...)modifier (FocusedCardDepth.swift) with two styles —.surface(full diagonal specular sheen for artwork) and.content(1.5pt inner-stroke highlight for cover-plus-text cards). Both share the same drop shadow. Accessibility-aware: respectsaccessibilityReduceTransparency(drops the sheen, keeps the shadow) andaccessibilityReduceMotion(drops the easing).PlaylistCell,EpisodeRow,NowPlayingRow.RootViewbackground: flatpcBackgroundSurface→ top→bottomLinearGradientvia newpcBackgroundTop/pcBackgroundBottomtokens.pcBackgroundActiveretuned: dark#FBFBFC→#D4D6DB, light#161718→#2A2D31. Global focus-highlight token — touches every focused surface in the TV app.DiscoverCategoryCellandPlaylistCell(16pt) where they were previously.clipped()rectangles, so the depth overlay matches a real card shape.To test
Checklist
CHANGELOG.mdif necessary. (Visual refinement only; no behavioural change.)#PreviewinFocusedCardDepth.swift.)