feat: enforce custom Theme colors app-wide, add debug sample trips and poll

Replace all system colors (.secondary, Color(.secondarySystemBackground),
etc.) with Theme.textPrimary/textSecondary/textMuted/cardBackground/
surfaceGlow across 13 views. Remove PostHog debug logging. Add debug
settings for sample trips and hardcoded group poll preview.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Trey t
2026-02-13 08:54:19 -06:00
parent ff6f4b6c2c
commit 1c97f35754
16 changed files with 580 additions and 73 deletions

View File

@@ -79,7 +79,6 @@ final class AnalyticsManager {
} }
#if DEBUG #if DEBUG
config.debug = true
config.flushAt = 1 config.flushAt = 1
#endif #endif

View File

@@ -450,6 +450,9 @@ struct SavedTripsListView: View {
@State private var hasLoadedPolls = false @State private var hasLoadedPolls = false
@State private var showCreatePoll = false @State private var showCreatePoll = false
@State private var selectedPoll: TripPoll? @State private var selectedPoll: TripPoll?
#if DEBUG
@State private var showDebugPoll = false
#endif
/// Trips sorted by most cities (stops) first /// Trips sorted by most cities (stops) first
private var sortedTrips: [SavedTrip] { private var sortedTrips: [SavedTrip] {
@@ -489,6 +492,13 @@ struct SavedTripsListView: View {
.navigationDestination(for: TripPoll.self) { poll in .navigationDestination(for: TripPoll.self) { poll in
PollDetailView(pollId: poll.id) PollDetailView(pollId: poll.id)
} }
#if DEBUG
.sheet(isPresented: $showDebugPoll) {
NavigationStack {
DebugPollPreviewView()
}
}
#endif
} }
// MARK: - Polls Section // MARK: - Polls Section
@@ -519,7 +529,17 @@ struct SavedTripsListView: View {
.frame(maxWidth: .infinity, alignment: .center) .frame(maxWidth: .infinity, alignment: .center)
.padding() .padding()
} else if polls.isEmpty { } else if polls.isEmpty {
#if DEBUG
// Debug sample poll
Button {
showDebugPoll = true
} label: {
PollRowCard(poll: DebugShareExporter.buildSamplePoll())
}
.buttonStyle(.plain)
#else
emptyPollsCard emptyPollsCard
#endif
} else { } else {
ForEach(polls) { poll in ForEach(polls) { poll in
NavigationLink(value: poll) { NavigationLink(value: poll) {
@@ -578,15 +598,16 @@ struct SavedTripsListView: View {
VStack(spacing: 16) { VStack(spacing: 16) {
Image(systemName: "suitcase") Image(systemName: "suitcase")
.font(.largeTitle) .font(.largeTitle)
.foregroundColor(.secondary) .foregroundStyle(Theme.textMuted(colorScheme))
.accessibilityHidden(true) .accessibilityHidden(true)
Text("No Saved Trips") Text("No Saved Trips")
.font(.headline) .font(.headline)
.foregroundStyle(Theme.textPrimary(colorScheme))
Text("Browse featured trips on the Home tab or create your own to get started.") Text("Browse featured trips on the Home tab or create your own to get started.")
.font(.subheadline) .font(.subheadline)
.foregroundColor(.secondary) .foregroundStyle(Theme.textSecondary(colorScheme))
.multilineTextAlignment(.center) .multilineTextAlignment(.center)
} }
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)

View File

@@ -46,6 +46,8 @@ struct PollCreationView: View {
} }
} }
} }
.scrollContentBackground(.hidden)
.themedBackground()
.navigationTitle("Create Poll") .navigationTitle("Create Poll")
.navigationBarTitleDisplayMode(.inline) .navigationBarTitleDisplayMode(.inline)
.toolbar { .toolbar {
@@ -94,6 +96,7 @@ struct PollCreationView: View {
// MARK: - Trip Selection Row // MARK: - Trip Selection Row
private struct TripSelectionRow: View { private struct TripSelectionRow: View {
@Environment(\.colorScheme) private var colorScheme
let trip: Trip let trip: Trip
let isSelected: Bool let isSelected: Bool
let onTap: () -> Void let onTap: () -> Void
@@ -104,18 +107,18 @@ private struct TripSelectionRow: View {
VStack(alignment: .leading, spacing: 4) { VStack(alignment: .leading, spacing: 4) {
Text(trip.displayName) Text(trip.displayName)
.font(.headline) .font(.headline)
.foregroundStyle(.primary) .foregroundStyle(Theme.textPrimary(colorScheme))
Text(tripSummary) Text(tripSummary)
.font(.subheadline) .font(.subheadline)
.foregroundStyle(.secondary) .foregroundStyle(Theme.textSecondary(colorScheme))
} }
Spacer() Spacer()
Image(systemName: isSelected ? "checkmark.circle.fill" : "circle") Image(systemName: isSelected ? "checkmark.circle.fill" : "circle")
.font(.title2) .font(.title2)
.foregroundStyle(isSelected ? Theme.warmOrange : .secondary) .foregroundStyle(isSelected ? Theme.warmOrange : Theme.textMuted(colorScheme))
.accessibilityHidden(true) .accessibilityHidden(true)
} }
.contentShape(Rectangle()) .contentShape(Rectangle())

View File

@@ -452,7 +452,7 @@ private struct TripPreviewCard: View {
Text(trip.displayName) Text(trip.displayName)
.font(.headline) .font(.headline)
.foregroundStyle(.primary) .foregroundStyle(Theme.textPrimary(colorScheme))
} }
// Date range and duration // Date range and duration
@@ -462,7 +462,7 @@ private struct TripPreviewCard: View {
Label("\(trip.tripDuration) days", systemImage: "clock") Label("\(trip.tripDuration) days", systemImage: "clock")
} }
.font(.caption) .font(.caption)
.foregroundStyle(.secondary) .foregroundStyle(Theme.textSecondary(colorScheme))
HStack { HStack {
Label("\(trip.stops.count) stops", systemImage: "mappin.and.ellipse") Label("\(trip.stops.count) stops", systemImage: "mappin.and.ellipse")
@@ -470,13 +470,13 @@ private struct TripPreviewCard: View {
Label("\(trip.stops.flatMap { $0.games }.count) games", systemImage: "sportscourt") Label("\(trip.stops.flatMap { $0.games }.count) games", systemImage: "sportscourt")
} }
.font(.caption) .font(.caption)
.foregroundStyle(.secondary) .foregroundStyle(Theme.textSecondary(colorScheme))
} }
Image(systemName: "chevron.right") Image(systemName: "chevron.right")
.font(.caption) .font(.caption)
.fontWeight(.semibold) .fontWeight(.semibold)
.foregroundStyle(.tertiary) .foregroundStyle(Theme.textMuted(colorScheme))
.accessibilityHidden(true) .accessibilityHidden(true)
} }
.padding() .padding()
@@ -484,7 +484,7 @@ private struct TripPreviewCard: View {
.clipShape(RoundedRectangle(cornerRadius: 12)) .clipShape(RoundedRectangle(cornerRadius: 12))
.overlay( .overlay(
RoundedRectangle(cornerRadius: 12) RoundedRectangle(cornerRadius: 12)
.strokeBorder(Color.secondary.opacity(0.1), lineWidth: 1) .strokeBorder(Theme.surfaceGlow(colorScheme), lineWidth: 1)
) )
} }
} }

View File

@@ -34,17 +34,21 @@ struct PollVotingView: View {
onMoveDown: { viewModel.moveTripDown(at: index) } onMoveDown: { viewModel.moveTripDown(at: index) }
) )
.accessibilityHint("Drag to change ranking position, or use move up and move down buttons") .accessibilityHint("Drag to change ranking position, or use move up and move down buttons")
.listRowBackground(Theme.cardBackground(colorScheme))
.listRowSeparatorTint(Theme.surfaceGlow(colorScheme))
} }
.onMove { source, destination in .onMove { source, destination in
viewModel.moveTrip(from: source, to: destination) viewModel.moveTrip(from: source, to: destination)
} }
} }
.listStyle(.plain) .listStyle(.plain)
.scrollContentBackground(.hidden)
.environment(\.editMode, .constant(.active)) .environment(\.editMode, .constant(.active))
// Submit button // Submit button
submitButton submitButton
} }
.themedBackground()
.navigationTitle("Rank Trips") .navigationTitle("Rank Trips")
.navigationBarTitleDisplayMode(.inline) .navigationBarTitleDisplayMode(.inline)
.toolbar { .toolbar {
@@ -88,10 +92,11 @@ struct PollVotingView: View {
Text("Drag to rank your preferences") Text("Drag to rank your preferences")
.font(.headline) .font(.headline)
.foregroundStyle(Theme.textPrimary(colorScheme))
Text("Your top choice should be at the top. You can drag, or use the move buttons.") Text("Your top choice should be at the top. You can drag, or use the move buttons.")
.font(.subheadline) .font(.subheadline)
.foregroundStyle(.secondary) .foregroundStyle(Theme.textSecondary(colorScheme))
} }
.padding() .padding()
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
@@ -130,6 +135,7 @@ struct PollVotingView: View {
// MARK: - Ranking Row // MARK: - Ranking Row
private struct RankingRow: View { private struct RankingRow: View {
@Environment(\.colorScheme) private var colorScheme
let rank: Int let rank: Int
let trip: Trip let trip: Trip
let canMoveUp: Bool let canMoveUp: Bool
@@ -150,10 +156,11 @@ private struct RankingRow: View {
VStack(alignment: .leading, spacing: 2) { VStack(alignment: .leading, spacing: 2) {
Text(trip.displayName) Text(trip.displayName)
.font(.headline) .font(.headline)
.foregroundStyle(Theme.textPrimary(colorScheme))
Text(tripSummary) Text(tripSummary)
.font(.caption) .font(.caption)
.foregroundStyle(.secondary) .foregroundStyle(Theme.textMuted(colorScheme))
} }
Spacer() Spacer()
@@ -175,7 +182,7 @@ private struct RankingRow: View {
.disabled(!canMoveDown) .disabled(!canMoveDown)
.accessibilityLabel("Move \(trip.displayName) down") .accessibilityLabel("Move \(trip.displayName) down")
} }
.foregroundStyle(.secondary) .foregroundStyle(Theme.textSecondary(colorScheme))
} }
.padding(.vertical, 4) .padding(.vertical, 4)
} }

View File

@@ -1,6 +1,7 @@
import SwiftUI import SwiftUI
struct GamesHistoryRow: View { struct GamesHistoryRow: View {
@Environment(\.colorScheme) private var colorScheme
let visit: StadiumVisit let visit: StadiumVisit
let stadium: Stadium? let stadium: Stadium?
@@ -20,16 +21,17 @@ struct GamesHistoryRow: View {
// Date // Date
Text(visit.visitDate.formatted(date: .abbreviated, time: .omitted)) Text(visit.visitDate.formatted(date: .abbreviated, time: .omitted))
.font(.subheadline.bold()) .font(.subheadline.bold())
.foregroundStyle(Theme.textPrimary(colorScheme))
// Teams (if game) // Teams (if game)
if let matchup = visit.matchupDescription { if let matchup = visit.matchupDescription {
Text(matchup) Text(matchup)
.font(.caption) .font(.caption)
.foregroundStyle(.secondary) .foregroundStyle(Theme.textSecondary(colorScheme))
} else { } else {
Text(visit.stadiumNameAtVisit) Text(visit.stadiumNameAtVisit)
.font(.caption) .font(.caption)
.foregroundStyle(.secondary) .foregroundStyle(Theme.textSecondary(colorScheme))
} }
} }
@@ -38,11 +40,11 @@ struct GamesHistoryRow: View {
// Chevron // Chevron
Image(systemName: "chevron.right") Image(systemName: "chevron.right")
.font(.caption) .font(.caption)
.foregroundStyle(.tertiary) .foregroundStyle(Theme.textMuted(colorScheme))
.accessibilityHidden(true) .accessibilityHidden(true)
} }
.padding() .padding()
.background(Color(.systemBackground)) .background(Theme.cardBackground(colorScheme))
.clipShape(RoundedRectangle(cornerRadius: 10)) .clipShape(RoundedRectangle(cornerRadius: 10))
.accessibilityElement(children: .combine) .accessibilityElement(children: .combine)
} }

View File

@@ -1,6 +1,7 @@
import SwiftUI import SwiftUI
struct VisitListCard: View { struct VisitListCard: View {
@Environment(\.colorScheme) private var colorScheme
let visit: StadiumVisit let visit: StadiumVisit
@State private var isExpanded = false @State private var isExpanded = false
@@ -17,9 +18,10 @@ struct VisitListCard: View {
VStack(alignment: .leading, spacing: 2) { VStack(alignment: .leading, spacing: 2) {
Text(visit.visitDate.formatted(date: .abbreviated, time: .omitted)) Text(visit.visitDate.formatted(date: .abbreviated, time: .omitted))
.font(.subheadline.bold()) .font(.subheadline.bold())
.foregroundStyle(Theme.textPrimary(colorScheme))
Text(visit.visitType.displayName) Text(visit.visitType.displayName)
.font(.caption) .font(.caption)
.foregroundStyle(.secondary) .foregroundStyle(Theme.textSecondary(colorScheme))
} }
Spacer() Spacer()
@@ -28,14 +30,14 @@ struct VisitListCard: View {
if let matchup = visit.matchupDescription { if let matchup = visit.matchupDescription {
Text(matchup) Text(matchup)
.font(.caption) .font(.caption)
.foregroundStyle(.secondary) .foregroundStyle(Theme.textSecondary(colorScheme))
.lineLimit(1) .lineLimit(1)
} }
// Chevron // Chevron
Image(systemName: "chevron.right") Image(systemName: "chevron.right")
.font(.caption) .font(.caption)
.foregroundStyle(.secondary) .foregroundStyle(Theme.textMuted(colorScheme))
.rotationEffect(.degrees(isExpanded ? 90 : 0)) .rotationEffect(.degrees(isExpanded ? 90 : 0))
.accessibilityLabel(isExpanded ? "Collapse details" : "Expand details") .accessibilityLabel(isExpanded ? "Collapse details" : "Expand details")
} }
@@ -79,12 +81,13 @@ struct VisitListCard: View {
.transition(.opacity.combined(with: .move(edge: .top))) .transition(.opacity.combined(with: .move(edge: .top)))
} }
} }
.background(Color(.systemBackground)) .background(Theme.cardBackground(colorScheme))
.clipShape(RoundedRectangle(cornerRadius: 12)) .clipShape(RoundedRectangle(cornerRadius: 12))
} }
} }
private struct GameInfoRow: View { private struct GameInfoRow: View {
@Environment(\.colorScheme) private var colorScheme
let matchup: String let matchup: String
let score: String? let score: String?
@@ -93,11 +96,12 @@ private struct GameInfoRow: View {
VStack(alignment: .leading, spacing: 4) { VStack(alignment: .leading, spacing: 4) {
Text(matchup) Text(matchup)
.font(.subheadline.bold()) .font(.subheadline.bold())
.foregroundStyle(Theme.textPrimary(colorScheme))
if let score { if let score {
Text("Final: \(score)") Text("Final: \(score)")
.font(.caption) .font(.caption)
.foregroundStyle(.secondary) .foregroundStyle(Theme.textSecondary(colorScheme))
} }
} }
@@ -107,6 +111,7 @@ private struct GameInfoRow: View {
} }
private struct InfoRow: View { private struct InfoRow: View {
@Environment(\.colorScheme) private var colorScheme
let icon: String let icon: String
let label: String let label: String
let value: String let value: String
@@ -115,16 +120,17 @@ private struct InfoRow: View {
HStack(spacing: 8) { HStack(spacing: 8) {
Image(systemName: icon) Image(systemName: icon)
.font(.caption) .font(.caption)
.foregroundStyle(.secondary) .foregroundStyle(Theme.textMuted(colorScheme))
.frame(width: 16) .frame(width: 16)
.accessibilityHidden(true) .accessibilityHidden(true)
Text(label) Text(label)
.font(.caption) .font(.caption)
.foregroundStyle(.secondary) .foregroundStyle(Theme.textSecondary(colorScheme))
Text(value) Text(value)
.font(.caption) .font(.caption)
.foregroundStyle(Theme.textPrimary(colorScheme))
.lineLimit(2) .lineLimit(2)
} }
} }

View File

@@ -39,6 +39,7 @@ struct GamesHistoryView: View {
} }
private struct GamesHistoryContent: View { private struct GamesHistoryContent: View {
@Environment(\.colorScheme) private var colorScheme
@Bindable var viewModel: GamesHistoryViewModel @Bindable var viewModel: GamesHistoryViewModel
@Binding var selectedVisit: StadiumVisit? @Binding var selectedVisit: StadiumVisit?
@@ -50,6 +51,7 @@ private struct GamesHistoryContent: View {
HStack { HStack {
Text("\(viewModel.totalGamesCount) Games") Text("\(viewModel.totalGamesCount) Games")
.font(.headline) .font(.headline)
.foregroundStyle(Theme.textPrimary(colorScheme))
Spacer() Spacer()
if !viewModel.selectedSports.isEmpty { if !viewModel.selectedSports.isEmpty {
@@ -68,9 +70,10 @@ private struct GamesHistoryContent: View {
) )
} }
.padding() .padding()
.background(Color(.systemBackground)) .background(Theme.cardBackground(colorScheme))
Divider() Divider()
.overlay(Theme.surfaceGlow(colorScheme))
// Games list grouped by year // Games list grouped by year
if viewModel.filteredVisits.isEmpty { if viewModel.filteredVisits.isEmpty {
@@ -85,7 +88,7 @@ private struct GamesHistoryContent: View {
) )
} }
} }
.background(Color(.systemGroupedBackground)) .background(Theme.backgroundGradient(colorScheme))
} }
} }
@@ -111,6 +114,7 @@ private struct SportFilterChips: View {
} }
private struct SportChip: View { private struct SportChip: View {
@Environment(\.colorScheme) private var colorScheme
let sport: Sport let sport: Sport
let isSelected: Bool let isSelected: Bool
let onTap: () -> Void let onTap: () -> Void
@@ -124,12 +128,12 @@ private struct SportChip: View {
Text(sport.rawValue) Text(sport.rawValue)
.font(.caption.bold()) .font(.caption.bold())
} }
.foregroundStyle(isSelected ? .white : .primary) .foregroundStyle(isSelected ? .white : Theme.textPrimary(colorScheme))
.padding(.horizontal, 12) .padding(.horizontal, 12)
.padding(.vertical, 6) .padding(.vertical, 6)
.background( .background(
Capsule() Capsule()
.fill(isSelected ? sport.themeColor : Color(.systemGray5)) .fill(isSelected ? sport.themeColor : Theme.cardBackgroundElevated(colorScheme))
) )
} }
.buttonStyle(.plain) .buttonStyle(.plain)
@@ -185,33 +189,38 @@ private struct GamesListByYear: View {
} }
private struct YearHeader: View { private struct YearHeader: View {
@Environment(\.colorScheme) private var colorScheme
let year: Int let year: Int
var body: some View { var body: some View {
HStack { HStack {
Text(String(year)) Text(String(year))
.font(.title3.bold()) .font(.title3.bold())
.foregroundStyle(Theme.textPrimary(colorScheme))
Spacer() Spacer()
} }
.padding(.horizontal) .padding(.horizontal)
.padding(.vertical, 8) .padding(.vertical, 8)
.background(Color(.systemGroupedBackground)) .background(Theme.backgroundGradient(colorScheme))
} }
} }
private struct EmptyGamesView: View { private struct EmptyGamesView: View {
@Environment(\.colorScheme) private var colorScheme
var body: some View { var body: some View {
VStack(spacing: 16) { VStack(spacing: 16) {
Image(systemName: "ticket") Image(systemName: "ticket")
.font(.largeTitle) .font(.largeTitle)
.foregroundStyle(.secondary) .foregroundStyle(Theme.textMuted(colorScheme))
Text("No games recorded yet") Text("No games recorded yet")
.font(.headline) .font(.headline)
.foregroundStyle(Theme.textPrimary(colorScheme))
Text("Add your first stadium visit to see it here!") Text("Add your first stadium visit to see it here!")
.font(.subheadline) .font(.subheadline)
.foregroundStyle(.secondary) .foregroundStyle(Theme.textSecondary(colorScheme))
.multilineTextAlignment(.center) .multilineTextAlignment(.center)
} }
.frame(maxWidth: .infinity, maxHeight: .infinity) .frame(maxWidth: .infinity, maxHeight: .infinity)

View File

@@ -65,6 +65,7 @@ struct StadiumVisitHistoryView: View {
} }
private struct VisitHistoryList: View { private struct VisitHistoryList: View {
@Environment(\.colorScheme) private var colorScheme
let visits: [StadiumVisit] let visits: [StadiumVisit]
var body: some View { var body: some View {
@@ -74,6 +75,7 @@ private struct VisitHistoryList: View {
HStack { HStack {
Text("\(visits.count) Visit\(visits.count == 1 ? "" : "s")") Text("\(visits.count) Visit\(visits.count == 1 ? "" : "s")")
.font(.headline) .font(.headline)
.foregroundStyle(Theme.textPrimary(colorScheme))
Spacer() Spacer()
} }
.padding(.horizontal) .padding(.horizontal)
@@ -86,23 +88,26 @@ private struct VisitHistoryList: View {
} }
.padding(.vertical) .padding(.vertical)
} }
.background(Color(.systemGroupedBackground)) .background(Theme.backgroundGradient(colorScheme))
} }
} }
private struct EmptyVisitHistoryView: View { private struct EmptyVisitHistoryView: View {
@Environment(\.colorScheme) private var colorScheme
var body: some View { var body: some View {
VStack(spacing: 16) { VStack(spacing: 16) {
Image(systemName: "calendar.badge.plus") Image(systemName: "calendar.badge.plus")
.font(.largeTitle) .font(.largeTitle)
.foregroundStyle(.secondary) .foregroundStyle(Theme.textMuted(colorScheme))
Text("No visits recorded") Text("No visits recorded")
.font(.headline) .font(.headline)
.foregroundStyle(Theme.textPrimary(colorScheme))
Text("Tap + to add your first visit to this stadium") Text("Tap + to add your first visit to this stadium")
.font(.subheadline) .font(.subheadline)
.foregroundStyle(.secondary) .foregroundStyle(Theme.textSecondary(colorScheme))
.multilineTextAlignment(.center) .multilineTextAlignment(.center)
} }
.padding() .padding()

View File

@@ -0,0 +1,374 @@
//
// DebugPollPreviewView.swift
// SportsTime
//
// Debug-only preview of the poll detail + voting flow with hardcoded data.
//
#if DEBUG
import SwiftUI
struct DebugPollPreviewView: View {
@Environment(\.dismiss) private var dismiss
@Environment(\.colorScheme) private var colorScheme
@State private var showVotingSheet = false
@State private var selectedTrip: Trip?
private let poll: TripPoll
private let votes: [PollVote]
init() {
let p = DebugShareExporter.buildSamplePoll()
self.poll = p
self.votes = DebugShareExporter.buildSampleVotes(for: p)
}
private var results: PollResults {
PollResults(poll: poll, votes: votes)
}
var body: some View {
ScrollView {
VStack(spacing: Theme.Spacing.lg) {
// Share Code Card
shareCodeCard
// Voting Status
votingStatusCard
// Results
resultsSection
// Trip Previews
tripPreviewsSection
}
.padding(.horizontal, Theme.Spacing.md)
.padding(.vertical, Theme.Spacing.lg)
}
.background(Theme.backgroundGradient(colorScheme))
.navigationTitle(poll.title)
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .cancellationAction) {
Button("Done") { dismiss() }
}
ToolbarItem(placement: .primaryAction) {
Button {
if let url = poll.shareURL as URL? {
UIPasteboard.general.string = url.absoluteString
}
} label: {
Image(systemName: "square.and.arrow.up")
}
}
}
.sheet(isPresented: $showVotingSheet) {
PollVotingView(poll: poll, existingVote: nil)
}
.sheet(item: $selectedTrip) { trip in
NavigationStack {
TripDetailView(trip: trip, allowCustomItems: true)
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .cancellationAction) {
Button("Done") { selectedTrip = nil }
}
}
}
}
}
// MARK: - Share Code
@ViewBuilder
private var shareCodeCard: some View {
VStack(spacing: Theme.Spacing.md) {
ZStack {
Circle()
.fill(Theme.warmOrange.opacity(0.15))
.frame(width: 56, height: 56)
Image(systemName: "link.circle.fill")
.font(.title2)
.foregroundStyle(Theme.warmOrange)
}
VStack(spacing: Theme.Spacing.xs) {
Text("Share Code")
.font(.subheadline)
.foregroundStyle(Theme.textSecondary(colorScheme))
Text(poll.shareCode)
.font(.system(.largeTitle, design: .monospaced).weight(.bold))
.foregroundStyle(Theme.warmOrange)
.tracking(4)
.lineLimit(1)
.minimumScaleFactor(0.7)
}
Button {
UIPasteboard.general.string = poll.shareCode
} label: {
Label("Copy Code", systemImage: "doc.on.doc")
.font(.subheadline.weight(.medium))
.foregroundStyle(Theme.warmOrange)
.padding(.horizontal, Theme.Spacing.md)
.padding(.vertical, Theme.Spacing.sm)
.background(Theme.warmOrange.opacity(0.1))
.clipShape(Capsule())
}
}
.frame(maxWidth: .infinity)
.padding(Theme.Spacing.lg)
.background(Theme.cardBackground(colorScheme))
.clipShape(RoundedRectangle(cornerRadius: Theme.CornerRadius.large))
.overlay(
RoundedRectangle(cornerRadius: Theme.CornerRadius.large)
.strokeBorder(Theme.warmOrange.opacity(0.2), lineWidth: 1)
)
}
// MARK: - Voting Status
@ViewBuilder
private var votingStatusCard: some View {
HStack(spacing: Theme.Spacing.md) {
ZStack {
Circle()
.fill(Theme.warmOrange.opacity(0.15))
.frame(width: 44, height: 44)
Image(systemName: "hand.raised.fill")
.font(.title3)
.foregroundStyle(Theme.warmOrange)
}
VStack(alignment: .leading, spacing: 2) {
Text("Cast your vote")
.font(.headline)
.foregroundStyle(Theme.textPrimary(colorScheme))
HStack(spacing: Theme.Spacing.xs) {
Image(systemName: "person.2.fill")
.font(.caption2)
Text("\(votes.count) votes")
.font(.subheadline)
}
.foregroundStyle(Theme.textSecondary(colorScheme))
}
Spacer()
Button {
showVotingSheet = true
} label: {
Text("Vote")
.font(.subheadline.weight(.semibold))
.foregroundStyle(.white)
.padding(.horizontal, Theme.Spacing.md)
.padding(.vertical, Theme.Spacing.sm)
.background(Theme.warmOrange)
.clipShape(Capsule())
}
}
.padding(Theme.Spacing.md)
.background(Theme.cardBackground(colorScheme))
.clipShape(RoundedRectangle(cornerRadius: Theme.CornerRadius.medium))
}
// MARK: - Results
@ViewBuilder
private var resultsSection: some View {
VStack(alignment: .leading, spacing: Theme.Spacing.md) {
HStack(spacing: Theme.Spacing.sm) {
Image(systemName: "chart.bar.fill")
.foregroundStyle(Theme.warmOrange)
Text("Results")
.font(.headline)
.foregroundStyle(Theme.textPrimary(colorScheme))
}
VStack(spacing: Theme.Spacing.sm) {
ForEach(results.tripScores, id: \.tripIndex) { item in
let trip = results.poll.tripSnapshots[item.tripIndex]
let rank = results.tripScores.firstIndex { $0.tripIndex == item.tripIndex }! + 1
DebugResultRow(
rank: rank,
tripName: trip.displayName,
score: item.score,
percentage: results.scorePercentage(for: item.tripIndex),
isLeader: rank == 1 && item.score > 0
)
}
}
}
.padding(Theme.Spacing.md)
.background(Theme.cardBackground(colorScheme))
.clipShape(RoundedRectangle(cornerRadius: Theme.CornerRadius.medium))
}
// MARK: - Trip Previews
@ViewBuilder
private var tripPreviewsSection: some View {
VStack(alignment: .leading, spacing: Theme.Spacing.md) {
HStack(spacing: Theme.Spacing.sm) {
Image(systemName: "map.fill")
.foregroundStyle(Theme.warmOrange)
Text("Trip Options")
.font(.headline)
.foregroundStyle(Theme.textPrimary(colorScheme))
Spacer()
Text("\(poll.tripSnapshots.count) trips")
.font(.caption)
.foregroundStyle(Theme.textMuted(colorScheme))
}
ForEach(Array(poll.tripSnapshots.enumerated()), id: \.element.id) { index, trip in
Button {
selectedTrip = trip
} label: {
DebugTripPreviewCard(trip: trip, index: index + 1)
}
.buttonStyle(.plain)
}
}
}
}
// MARK: - Debug Result Row
private struct DebugResultRow: View {
@Environment(\.colorScheme) private var colorScheme
let rank: Int
let tripName: String
let score: Int
let percentage: Double
var isLeader: Bool = false
private var rankIcon: String {
switch rank {
case 1: return "trophy.fill"
case 2: return "medal.fill"
case 3: return "medal.fill"
default: return "\(rank).circle.fill"
}
}
private var rankColor: Color {
switch rank {
case 1: return Theme.warmOrange
case 2: return .gray
case 3: return .brown
default: return .secondary
}
}
var body: some View {
HStack(spacing: Theme.Spacing.sm) {
ZStack {
Circle()
.fill(rankColor.opacity(0.15))
.frame(width: 36, height: 36)
Image(systemName: rankIcon)
.font(.subheadline)
.foregroundStyle(rankColor)
}
VStack(alignment: .leading, spacing: 4) {
Text(tripName)
.font(.subheadline.weight(isLeader ? .semibold : .regular))
.foregroundStyle(Theme.textPrimary(colorScheme))
GeometryReader { geometry in
ZStack(alignment: .leading) {
RoundedRectangle(cornerRadius: 4)
.fill(Theme.cardBackgroundElevated(colorScheme))
.frame(height: 6)
RoundedRectangle(cornerRadius: 4)
.fill(rankColor)
.frame(width: max(geometry.size.width * percentage, percentage > 0 ? 6 : 0), height: 6)
}
}
.frame(height: 6)
}
Text("\(score)")
.font(.subheadline.weight(.medium).monospacedDigit())
.foregroundStyle(rankColor)
.padding(.horizontal, 10)
.padding(.vertical, 4)
.background(rankColor.opacity(0.1))
.clipShape(Capsule())
}
.padding(.vertical, Theme.Spacing.xs)
}
}
// MARK: - Debug Trip Preview Card
private struct DebugTripPreviewCard: View {
@Environment(\.colorScheme) private var colorScheme
let trip: Trip
let index: Int
var body: some View {
HStack(spacing: 12) {
VStack(alignment: .leading, spacing: 8) {
HStack {
Text("Option \(index)")
.font(.caption)
.fontWeight(.semibold)
.foregroundStyle(.white)
.padding(.horizontal, 8)
.padding(.vertical, 4)
.background(Theme.warmOrange)
.clipShape(Capsule())
Text(trip.displayName)
.font(.headline)
.foregroundStyle(.primary)
}
HStack {
Label(trip.formattedDateRange, systemImage: "calendar")
Spacer()
Label("\(trip.tripDuration) days", systemImage: "clock")
}
.font(.caption)
.foregroundStyle(.secondary)
HStack {
Label("\(trip.stops.count) stops", systemImage: "mappin.and.ellipse")
Spacer()
Label("\(trip.stops.flatMap { $0.games }.count) games", systemImage: "sportscourt")
}
.font(.caption)
.foregroundStyle(.secondary)
}
Image(systemName: "chevron.right")
.font(.caption)
.fontWeight(.semibold)
.foregroundStyle(.tertiary)
}
.padding()
.background(Theme.cardBackground(colorScheme))
.clipShape(RoundedRectangle(cornerRadius: 12))
.overlay(
RoundedRectangle(cornerRadius: 12)
.strokeBorder(Color.secondary.opacity(0.1), lineWidth: 1)
)
}
}
#Preview {
NavigationStack {
DebugPollPreviewView()
}
}
#endif

View File

@@ -381,6 +381,53 @@ final class DebugShareExporter {
isExporting = false isExporting = false
} }
// MARK: - Save Sample Trips
func saveSampleTrips(modelContext: ModelContext) {
let trips = Self.buildDummyTrips()
var savedCount = 0
for trip in trips {
if let savedTrip = SavedTrip.from(trip, status: .planned) {
modelContext.insert(savedTrip)
savedCount += 1
}
}
do {
try modelContext.save()
print("DEBUG: Saved \(savedCount) sample trips")
} catch {
print("DEBUG: Failed to save sample trips: \(error)")
}
}
// MARK: - Build Sample Poll
static func buildSamplePoll() -> TripPoll {
let trips = buildDummyTrips()
let sampleVotes = [
PollVote(pollId: UUID(), odg: "voter1", rankings: [0, 2, 1, 3]),
PollVote(pollId: UUID(), odg: "voter2", rankings: [2, 0, 3, 1]),
PollVote(pollId: UUID(), odg: "voter3", rankings: [0, 1, 2, 3]),
]
_ = sampleVotes // votes are shown via PollResults, we pass them separately
return TripPoll(
title: "Summer 2026 Road Trip",
ownerId: "debug-user",
tripSnapshots: trips
)
}
static func buildSampleVotes(for poll: TripPoll) -> [PollVote] {
[
PollVote(pollId: poll.id, odg: "voter-alex", rankings: [0, 2, 1, 3]),
PollVote(pollId: poll.id, odg: "voter-sam", rankings: [2, 0, 3, 1]),
PollVote(pollId: poll.id, odg: "voter-jordan", rankings: [0, 1, 2, 3]),
]
}
// MARK: - Add All Stadium Visits // MARK: - Add All Stadium Visits
func addAllStadiumVisits(modelContext: ModelContext) async { func addAllStadiumVisits(modelContext: ModelContext) async {

View File

@@ -19,6 +19,8 @@ struct SettingsView: View {
@State private var selectedSyncStatus: EntitySyncStatus? @State private var selectedSyncStatus: EntitySyncStatus?
@State private var exporter = DebugShareExporter() @State private var exporter = DebugShareExporter()
@State private var showExportProgress = false @State private var showExportProgress = false
@State private var showSamplePoll = false
@State private var sampleTripsMessage: String?
#endif #endif
var body: some View { var body: some View {
@@ -570,6 +572,19 @@ struct SettingsView: View {
} label: { } label: {
Label("Add All Stadium Visits", systemImage: "mappin.and.ellipse") Label("Add All Stadium Visits", systemImage: "mappin.and.ellipse")
} }
Button {
exporter.saveSampleTrips(modelContext: modelContext)
sampleTripsMessage = "Saved 4 sample trips!"
} label: {
Label("Save 4 Sample Trips", systemImage: "suitcase.fill")
}
Button {
showSamplePoll = true
} label: {
Label("View Sample Poll", systemImage: "chart.bar.doc.horizontal.fill")
}
} header: { } header: {
Text("Debug") Text("Debug")
} footer: { } footer: {
@@ -579,6 +594,19 @@ struct SettingsView: View {
.sheet(isPresented: $showExportProgress) { .sheet(isPresented: $showExportProgress) {
DebugExportProgressView(exporter: exporter) DebugExportProgressView(exporter: exporter)
} }
.sheet(isPresented: $showSamplePoll) {
NavigationStack {
DebugPollPreviewView()
}
}
.alert("Sample Trips", isPresented: Binding(
get: { sampleTripsMessage != nil },
set: { if !$0 { sampleTripsMessage = nil } }
)) {
Button("OK", role: .cancel) { sampleTripsMessage = nil }
} message: {
Text(sampleTripsMessage ?? "")
}
} }
private var syncStatusSection: some View { private var syncStatusSection: some View {

View File

@@ -93,9 +93,7 @@ private struct CategoryPill: View {
if isSelected { if isSelected {
return Theme.warmOrange.opacity(0.2) return Theme.warmOrange.opacity(0.2)
} else { } else {
return colorScheme == .dark return Theme.cardBackgroundElevated(colorScheme)
? Color.white.opacity(0.08)
: Color.black.opacity(0.04)
} }
} }
@@ -103,9 +101,7 @@ private struct CategoryPill: View {
if isSelected { if isSelected {
return Theme.warmOrange.opacity(0.08) return Theme.warmOrange.opacity(0.08)
} else { } else {
return colorScheme == .dark return Theme.cardBackground(colorScheme)
? Color.white.opacity(0.03)
: Color.black.opacity(0.02)
} }
} }

View File

@@ -137,7 +137,7 @@ struct AddItemSheet: View {
// Search field // Search field
HStack { HStack {
Image(systemName: "magnifyingglass") Image(systemName: "magnifyingglass")
.foregroundStyle(.secondary) .foregroundStyle(Theme.textMuted(colorScheme))
.accessibilityHidden(true) .accessibilityHidden(true)
TextField("Search for a place...", text: $searchQuery) TextField("Search for a place...", text: $searchQuery)
.textFieldStyle(.plain) .textFieldStyle(.plain)
@@ -155,14 +155,14 @@ struct AddItemSheet: View {
selectedPlace = nil selectedPlace = nil
} label: { } label: {
Image(systemName: "xmark.circle.fill") Image(systemName: "xmark.circle.fill")
.foregroundStyle(.secondary) .foregroundStyle(Theme.textMuted(colorScheme))
} }
.minimumHitTarget() .minimumHitTarget()
.accessibilityLabel("Clear search") .accessibilityLabel("Clear search")
} }
} }
.padding(10) .padding(10)
.background(Color(.systemGray6)) .background(Theme.cardBackgroundElevated(colorScheme))
.cornerRadius(10) .cornerRadius(10)
// Search results // Search results
@@ -181,7 +181,7 @@ struct AddItemSheet: View {
} }
} }
.frame(maxHeight: 300) .frame(maxHeight: 300)
.background(Color(.systemBackground)) .background(Theme.cardBackground(colorScheme))
.cornerRadius(10) .cornerRadius(10)
} else if !searchQuery.isEmpty && !isSearching { } else if !searchQuery.isEmpty && !isSearching {
Text("No results found") Text("No results found")

View File

@@ -12,6 +12,7 @@ import SwiftUI
/// Renders a single timeline item (stop, travel, or rest). /// Renders a single timeline item (stop, travel, or rest).
struct TimelineItemView: View { struct TimelineItemView: View {
@Environment(\.colorScheme) private var colorScheme
let item: TimelineItem let item: TimelineItem
let games: [String: RichGame] let games: [String: RichGame]
let isFirst: Bool let isFirst: Bool
@@ -69,7 +70,7 @@ struct TimelineItemView: View {
} }
private var connectorColor: Color { private var connectorColor: Color {
Color.secondary.opacity(0.3) Theme.surfaceGlow(colorScheme)
} }
@ViewBuilder @ViewBuilder
@@ -124,6 +125,7 @@ struct TimelineItemView: View {
// MARK: - Stop Item Content // MARK: - Stop Item Content
struct StopItemContent: View { struct StopItemContent: View {
@Environment(\.colorScheme) private var colorScheme
let stop: ItineraryStop let stop: ItineraryStop
let games: [String: RichGame] let games: [String: RichGame]
@@ -141,14 +143,14 @@ struct StopItemContent: View {
if !stop.state.isEmpty { if !stop.state.isEmpty {
Text(stop.state) Text(stop.state)
.font(.subheadline) .font(.subheadline)
.foregroundStyle(.secondary) .foregroundStyle(Theme.textSecondary(colorScheme))
} }
Spacer() Spacer()
Text(stop.arrivalDate.formatted(date: .abbreviated, time: .omitted)) Text(stop.arrivalDate.formatted(date: .abbreviated, time: .omitted))
.font(.caption) .font(.caption)
.foregroundStyle(.secondary) .foregroundStyle(Theme.textSecondary(colorScheme))
} }
// Games // Games
@@ -159,12 +161,12 @@ struct StopItemContent: View {
} else { } else {
Text(stop.hasGames ? "Game details loading..." : "Waypoint") Text(stop.hasGames ? "Game details loading..." : "Waypoint")
.font(.subheadline) .font(.subheadline)
.foregroundStyle(.secondary) .foregroundStyle(Theme.textMuted(colorScheme))
.italic() .italic()
} }
} }
.padding() .padding()
.background(Color(.secondarySystemBackground)) .background(Theme.cardBackground(colorScheme))
.clipShape(RoundedRectangle(cornerRadius: 12)) .clipShape(RoundedRectangle(cornerRadius: 12))
} }
} }
@@ -172,6 +174,7 @@ struct StopItemContent: View {
// MARK: - Travel Item Content // MARK: - Travel Item Content
struct TravelItemContent: View { struct TravelItemContent: View {
@Environment(\.colorScheme) private var colorScheme
let segment: TravelSegment let segment: TravelSegment
var body: some View { var body: some View {
@@ -182,25 +185,25 @@ struct TravelItemContent: View {
.fontWeight(.medium) .fontWeight(.medium)
Text("\u{2022}") Text("\u{2022}")
.foregroundStyle(.secondary) .foregroundStyle(Theme.textMuted(colorScheme))
.accessibilityHidden(true) .accessibilityHidden(true)
Text(segment.formattedDistance) Text(segment.formattedDistance)
.font(.subheadline) .font(.subheadline)
.foregroundStyle(.secondary) .foregroundStyle(Theme.textSecondary(colorScheme))
Text("\u{2022}") Text("\u{2022}")
.foregroundStyle(.secondary) .foregroundStyle(Theme.textMuted(colorScheme))
.accessibilityHidden(true) .accessibilityHidden(true)
Text(segment.formattedDuration) Text(segment.formattedDuration)
.font(.subheadline) .font(.subheadline)
.foregroundStyle(.secondary) .foregroundStyle(Theme.textSecondary(colorScheme))
} }
Text("\(segment.fromLocation.name) \u{2192} \(segment.toLocation.name)") Text("\(segment.fromLocation.name) \u{2192} \(segment.toLocation.name)")
.font(.caption) .font(.caption)
.foregroundStyle(.secondary) .foregroundStyle(Theme.textSecondary(colorScheme))
.accessibilityLabel("\(segment.fromLocation.name) to \(segment.toLocation.name)") .accessibilityLabel("\(segment.fromLocation.name) to \(segment.toLocation.name)")
// EV Charging stops if applicable // EV Charging stops if applicable
@@ -211,13 +214,13 @@ struct TravelItemContent: View {
.accessibilityHidden(true) .accessibilityHidden(true)
Text("\(segment.evChargingStops.count) charging stop(s)") Text("\(segment.evChargingStops.count) charging stop(s)")
.font(.caption) .font(.caption)
.foregroundStyle(.secondary) .foregroundStyle(Theme.textSecondary(colorScheme))
} }
} }
} }
.padding(.vertical, 8) .padding(.vertical, 8)
.padding(.horizontal, 12) .padding(.horizontal, 12)
.background(Color(.tertiarySystemBackground)) .background(Theme.cardBackgroundElevated(colorScheme))
.clipShape(RoundedRectangle(cornerRadius: 8)) .clipShape(RoundedRectangle(cornerRadius: 8))
} }
} }
@@ -225,6 +228,7 @@ struct TravelItemContent: View {
// MARK: - Rest Item Content // MARK: - Rest Item Content
struct RestItemContent: View { struct RestItemContent: View {
@Environment(\.colorScheme) private var colorScheme
let rest: RestDay let rest: RestDay
var body: some View { var body: some View {
@@ -238,17 +242,17 @@ struct RestItemContent: View {
Text(rest.date.formatted(date: .abbreviated, time: .omitted)) Text(rest.date.formatted(date: .abbreviated, time: .omitted))
.font(.caption) .font(.caption)
.foregroundStyle(.secondary) .foregroundStyle(Theme.textSecondary(colorScheme))
} }
Text(rest.location.name) Text(rest.location.name)
.font(.caption) .font(.caption)
.foregroundStyle(.secondary) .foregroundStyle(Theme.textSecondary(colorScheme))
if let notes = rest.notes { if let notes = rest.notes {
Text(notes) Text(notes)
.font(.caption) .font(.caption)
.foregroundStyle(.secondary) .foregroundStyle(Theme.textMuted(colorScheme))
.italic() .italic()
} }
} }
@@ -262,6 +266,7 @@ struct RestItemContent: View {
// MARK: - Timeline Game Row // MARK: - Timeline Game Row
struct TimelineGameRow: View { struct TimelineGameRow: View {
@Environment(\.colorScheme) private var colorScheme
let richGame: RichGame let richGame: RichGame
var body: some View { var body: some View {
@@ -286,7 +291,7 @@ struct TimelineGameRow: View {
Text(richGame.stadium.name) Text(richGame.stadium.name)
} }
.font(.caption) .font(.caption)
.foregroundStyle(.secondary) .foregroundStyle(Theme.textSecondary(colorScheme))
} }
Spacer() Spacer()
@@ -325,6 +330,7 @@ struct TimelineView: View {
/// Horizontal scrolling timeline for compact display. /// Horizontal scrolling timeline for compact display.
struct HorizontalTimelineView: View { struct HorizontalTimelineView: View {
@Environment(\.colorScheme) private var colorScheme
let option: ItineraryOption let option: ItineraryOption
let games: [String: RichGame] let games: [String: RichGame]
@@ -355,19 +361,19 @@ struct HorizontalTimelineView: View {
if item.isTravel { if item.isTravel {
// Travel already shows direction, minimal connector // Travel already shows direction, minimal connector
Rectangle() Rectangle()
.fill(Color.secondary.opacity(0.3)) .fill(Theme.surfaceGlow(colorScheme))
.frame(width: 20, height: 2) .frame(width: 20, height: 2)
} else { } else {
// Standard connector with arrow // Standard connector with arrow
HStack(spacing: 0) { HStack(spacing: 0) {
Rectangle() Rectangle()
.fill(Color.secondary.opacity(0.3)) .fill(Theme.surfaceGlow(colorScheme))
.frame(width: 16, height: 2) .frame(width: 16, height: 2)
Image(systemName: "chevron.right") Image(systemName: "chevron.right")
.font(.caption2) .font(.caption2)
.foregroundStyle(.secondary) .foregroundStyle(Theme.textMuted(colorScheme))
Rectangle() Rectangle()
.fill(Color.secondary.opacity(0.3)) .fill(Theme.surfaceGlow(colorScheme))
.frame(width: 16, height: 2) .frame(width: 16, height: 2)
} }
} }
@@ -377,6 +383,7 @@ struct HorizontalTimelineView: View {
// MARK: - Horizontal Timeline Item View // MARK: - Horizontal Timeline Item View
struct HorizontalTimelineItemView: View { struct HorizontalTimelineItemView: View {
@Environment(\.colorScheme) private var colorScheme
let item: TimelineItem let item: TimelineItem
let games: [String: RichGame] let games: [String: RichGame]
@@ -386,7 +393,7 @@ struct HorizontalTimelineItemView: View {
Text(shortLabel) Text(shortLabel)
.font(.caption2) .font(.caption2)
.foregroundStyle(.secondary) .foregroundStyle(Theme.textSecondary(colorScheme))
.lineLimit(1) .lineLimit(1)
.frame(width: 60) .frame(width: 60)
} }
@@ -405,7 +412,7 @@ struct HorizontalTimelineItemView: View {
.fontWeight(.bold) .fontWeight(.bold)
} }
.frame(width: 44, height: 44) .frame(width: 44, height: 44)
.background(Circle().fill(Color(.secondarySystemBackground))) .background(Circle().fill(Theme.cardBackgroundElevated(colorScheme)))
case .travel(let segment): case .travel(let segment):
Image(systemName: segment.travelMode == .drive ? "car.fill" : "airplane") Image(systemName: segment.travelMode == .drive ? "car.fill" : "airplane")

View File

@@ -24,6 +24,7 @@ struct LocationSearchSheet: View {
let onAdd: (LocationInput) -> Void let onAdd: (LocationInput) -> Void
@Environment(\.dismiss) private var dismiss @Environment(\.dismiss) private var dismiss
@Environment(\.colorScheme) private var colorScheme
@State private var searchText = "" @State private var searchText = ""
@State private var searchResults: [LocationSearchResult] = [] @State private var searchResults: [LocationSearchResult] = []
@State private var isSearching = false @State private var isSearching = false
@@ -47,7 +48,7 @@ struct LocationSearchSheet: View {
// Search field // Search field
HStack { HStack {
Image(systemName: "magnifyingglass") Image(systemName: "magnifyingglass")
.foregroundStyle(.secondary) .foregroundStyle(Theme.textMuted(colorScheme))
.accessibilityHidden(true) .accessibilityHidden(true)
TextField("Search cities, addresses, places...", text: $searchText) TextField("Search cities, addresses, places...", text: $searchText)
.textFieldStyle(.plain) .textFieldStyle(.plain)
@@ -60,14 +61,14 @@ struct LocationSearchSheet: View {
searchResults = [] searchResults = []
} label: { } label: {
Image(systemName: "xmark.circle.fill") Image(systemName: "xmark.circle.fill")
.foregroundStyle(.secondary) .foregroundStyle(Theme.textMuted(colorScheme))
} }
.minimumHitTarget() .minimumHitTarget()
.accessibilityLabel("Clear search") .accessibilityLabel("Clear search")
} }
} }
.padding() .padding()
.background(Color(.secondarySystemBackground)) .background(Theme.cardBackgroundElevated(colorScheme))
.clipShape(RoundedRectangle(cornerRadius: 10)) .clipShape(RoundedRectangle(cornerRadius: 10))
.padding() .padding()
@@ -91,26 +92,28 @@ struct LocationSearchSheet: View {
.accessibilityHidden(true) .accessibilityHidden(true)
VStack(alignment: .leading) { VStack(alignment: .leading) {
Text(result.name) Text(result.name)
.foregroundStyle(.primary) .foregroundStyle(Theme.textPrimary(colorScheme))
if !result.address.isEmpty { if !result.address.isEmpty {
Text(result.address) Text(result.address)
.font(.caption) .font(.caption)
.foregroundStyle(.secondary) .foregroundStyle(Theme.textSecondary(colorScheme))
} }
} }
Spacer() Spacer()
Image(systemName: "plus.circle") Image(systemName: "plus.circle")
.foregroundStyle(.blue) .foregroundStyle(Theme.warmOrange)
.accessibilityHidden(true) .accessibilityHidden(true)
} }
} }
.buttonStyle(.plain) .buttonStyle(.plain)
} }
.listStyle(.plain) .listStyle(.plain)
.scrollContentBackground(.hidden)
} }
Spacer() Spacer()
} }
.themedBackground()
.navigationTitle(navigationTitle) .navigationTitle(navigationTitle)
.navigationBarTitleDisplayMode(.inline) .navigationBarTitleDisplayMode(.inline)
.toolbar { .toolbar {