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:
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user