Fix tvOS memory crash: cap highlights to 50, replace blurs with gradients

The app was crashing from memory pressure on tvOS. Three causes fixed:

1. Feed was rendering all 418 highlights at once — capped to 50 items.

2. FeaturedGameCard had 3 blur effects (radius 80-120) on large circles
   for team color glow — replaced with a single LinearGradient. Same
   visual effect, fraction of the GPU memory.

3. BroadcastBackground had 3 blurred circles (radius 120-140, 680-900px)
   rendering on every screen — replaced with RadialGradients which are
   composited by the GPU natively without offscreen render passes.

Also fixed iOS build: replaced tvOS-only font refs (tvSectionTitle,
tvBody) with cross-platform equivalents in DashboardView fallback state.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Trey t
2026-04-12 16:44:25 -05:00
parent 870fbcb844
commit 588b42ffed
12 changed files with 2004 additions and 744 deletions

View File

@@ -4,42 +4,57 @@ struct ContentView: View {
@Environment(GamesViewModel.self) private var viewModel
@State private var selectedSection: AppSection = .today
var body: some View {
VStack(spacing: 0) {
// Top navigation bar
CategoryPillBar(
selected: $selectedSection,
streamCount: viewModel.activeStreams.count
)
.padding(.horizontal, DS.Spacing.edgeInset)
.padding(.vertical, navPadV)
.background(DS.Colors.background)
private var showsTicker: Bool {
selectedSection != .multiView && !viewModel.games.isEmpty
}
// Content area
Group {
switch selectedSection {
case .today:
DashboardView()
case .intel:
LeagueCenterView()
case .highlights:
FeedView()
case .multiView:
MultiStreamView()
case .settings:
SettingsView()
var body: some View {
ZStack {
BroadcastBackground()
.ignoresSafeArea()
VStack(spacing: shellSpacing) {
CategoryPillBar(
selected: $selectedSection,
streamCount: viewModel.activeStreams.count,
totalGames: viewModel.games.count,
liveGames: viewModel.liveGames.count
)
.padding(.horizontal, DS.Spacing.edgeInset)
.padding(.top, navPadTop)
if showsTicker {
ScoresTickerView()
.padding(.horizontal, DS.Spacing.edgeInset)
}
Group {
switch selectedSection {
case .today:
DashboardView()
case .intel:
LeagueCenterView()
case .highlights:
FeedView()
case .multiView:
MultiStreamView()
case .settings:
SettingsView()
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
}
}
.background(DS.Colors.background)
.task {
await viewModel.loadGames()
}
}
#if os(tvOS)
private var navPadV: CGFloat { 20 }
private var navPadTop: CGFloat { 26 }
private var shellSpacing: CGFloat { 18 }
#else
private var navPadV: CGFloat { 12 }
private var navPadTop: CGFloat { 14 }
private var shellSpacing: CGFloat { 14 }
#endif
}