feat(schedule): group games by sport instead of date

Games in schedule view now display in sport sections (MLB, NBA, etc.)
with games sorted by date within each section. Each game row shows its
date since the section header now shows sport instead.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Trey t
2026-01-10 17:36:22 -06:00
parent 6db0bdefcd
commit 5ed4e309bd
3 changed files with 39 additions and 11 deletions

View File

@@ -37,7 +37,7 @@ Build a functional iOS sports trip planning app that helps users plan multi-stop
## Active Tasks
- [x] Fix "By Games" Mode Game Selection
- [ ] Group Schedule View Games by Sport
- [x] Group Schedule View Games by Sport
- [ ] Remove Buffer Days from Trip Planner
## Completed Tasks

View File

@@ -50,6 +50,21 @@ final class ScheduleViewModel {
return grouped.sorted { $0.key < $1.key }.map { ($0.key, $0.value) }
}
var gamesBySport: [(sport: Sport, games: [RichGame])] {
let grouped = Dictionary(grouping: filteredGames) { game in
game.game.sport
}
// Sort by sport order (use allCases index for consistent ordering)
// Within each sport, games are sorted by date
return grouped
.sorted { lhs, rhs in
let lhsIndex = Sport.allCases.firstIndex(of: lhs.key) ?? 0
let rhsIndex = Sport.allCases.firstIndex(of: rhs.key) ?? 0
return lhsIndex < rhsIndex
}
.map { (sport: $0.key, games: $0.value.sorted { $0.game.dateTime < $1.game.dateTime }) }
}
var hasFilters: Bool {
selectedSports.count < Sport.supported.count || !searchText.isEmpty
}

View File

@@ -89,14 +89,17 @@ struct ScheduleListView: View {
.listRowBackground(Color.clear)
}
ForEach(viewModel.gamesByDate, id: \.date) { dateGroup in
ForEach(viewModel.gamesBySport, id: \.sport) { sportGroup in
Section {
ForEach(dateGroup.games) { richGame in
GameRowView(game: richGame)
ForEach(sportGroup.games) { richGame in
GameRowView(game: richGame, showDate: true)
}
} header: {
Text(formatSectionDate(dateGroup.date))
.font(.headline)
HStack(spacing: 8) {
Image(systemName: sportGroup.sport.iconName)
Text(sportGroup.sport.rawValue)
}
.font(.headline)
}
.listRowBackground(Theme.cardBackground(colorScheme))
}
@@ -204,9 +207,18 @@ struct SportFilterChip: View {
struct GameRowView: View {
let game: RichGame
var showDate: Bool = false
var body: some View {
VStack(alignment: .leading, spacing: 8) {
// Date (when grouped by sport)
if showDate {
Text(formattedDate)
.font(.caption)
.fontWeight(.medium)
.foregroundStyle(.secondary)
}
// Teams
HStack {
VStack(alignment: .leading, spacing: 4) {
@@ -220,11 +232,6 @@ struct GameRowView: View {
}
Spacer()
// Sport badge
Image(systemName: game.game.sport.iconName)
.font(.caption)
.foregroundStyle(.secondary)
}
// Game info
@@ -241,6 +248,12 @@ struct GameRowView: View {
}
.padding(.vertical, 4)
}
private var formattedDate: String {
let formatter = DateFormatter()
formatter.dateFormat = "EEE, MMM d"
return formatter.string(from: game.game.dateTime)
}
}
// MARK: - Team Badge