Add race control visuals and driver names in laps view

This commit is contained in:
2026-05-25 15:55:36 -04:00
parent 3eb74a9083
commit a2aa772838
21 changed files with 458 additions and 118 deletions

View File

@@ -272,6 +272,13 @@ func (m AppModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.calendar.loading = true
m.standings.year = m.year
m.standings.loading = true
m.standings.err = nil
m.standings.stale = false
m.standings.driverStandings = nil
m.standings.teamStandings = nil
m.standings.drivers = make(map[int]models.Driver)
m.standings.cursor = 0
m.standings.scroll = 0
return m, tea.Batch(
m.calendar.Init(),

View File

@@ -5,19 +5,23 @@ import "github.com/AmanTahiliani/box-box/internal/models"
// driverChampionshipLoadedMsg carries the loaded driver championship data.
type driverChampionshipLoadedMsg struct {
standings []models.ChampionshipDriver
year int
err error
}
// teamChampionshipLoadedMsg carries the loaded team championship data.
type teamChampionshipLoadedMsg struct {
standings []models.ChampionshipTeam
year int
err error
}
// standingsDriversLoadedMsg carries drivers for the standings join.
type standingsDriversLoadedMsg struct {
drivers []models.Driver
err error
drivers []models.Driver
year int
sessionKey int
err error
}
// meetingsLoadedMsg carries the full meeting list for the calendar.

View File

@@ -499,7 +499,13 @@ func (m ReplayModel) renderReplay() string {
name := fmt.Sprintf("#%d", dp.driverNum)
teamColor := colorMuted
if ok {
name = d.NameAcronym
name = d.FullName
if name == "" {
name = d.BroadcastName
}
if name == "" {
name = d.NameAcronym
}
if d.TeamColour != "" {
teamColor = "#" + d.TeamColour
} else {
@@ -508,7 +514,10 @@ func (m ReplayModel) renderReplay() string {
}
colorBar := lipgloss.NewStyle().Foreground(lipgloss.Color(teamColor)).Render("┃")
nameStyled := lipgloss.NewStyle().Foreground(lipgloss.Color(teamColor)).Bold(true).Render(padRight(name, 4))
numberStyled := lipgloss.NewStyle().Foreground(lipgloss.Color(teamColor)).Bold(true).
Render(padRight(fmt.Sprintf("%d", dp.driverNum), 4))
nameStyled := lipgloss.NewStyle().Foreground(lipgloss.Color(teamColor)).Bold(true).
Render(padRight(truncate(name, 18), 18))
posStyled := renderPosition(dp.pos)
// Lap time
@@ -524,9 +533,10 @@ func (m ReplayModel) renderReplay() string {
Render(fmt.Sprintf("PIT %.1fs", dur))
}
sb.WriteString(fmt.Sprintf(" %s %s %s %s %s\n",
sb.WriteString(fmt.Sprintf(" %s %s%s %s %s %s\n",
padRightVisible(posStyled, 4),
colorBar,
numberStyled,
nameStyled,
ltStr,
pitStr,

View File

@@ -65,21 +65,21 @@ func (m StandingsModel) Init() tea.Cmd {
func fetchDriverChampionship(client *api.OpenF1Client, year int) tea.Cmd {
return func() tea.Msg {
standings, err := client.GetDriverChampionshipForYear(year)
return driverChampionshipLoadedMsg{standings: standings, err: err}
return driverChampionshipLoadedMsg{standings: standings, year: year, err: err}
}
}
func fetchTeamChampionship(client *api.OpenF1Client, year int) tea.Cmd {
return func() tea.Msg {
standings, err := client.GetTeamChampionshipForYear(year)
return teamChampionshipLoadedMsg{standings: standings, err: err}
return teamChampionshipLoadedMsg{standings: standings, year: year, err: err}
}
}
func fetchStandingsDrivers(client *api.OpenF1Client, sessionKey int) tea.Cmd {
func fetchStandingsDrivers(client *api.OpenF1Client, year, sessionKey int) tea.Cmd {
return func() tea.Msg {
drivers, err := client.GetDriversForSession(sessionKey)
return standingsDriversLoadedMsg{drivers: drivers, err: err}
return standingsDriversLoadedMsg{drivers: drivers, year: year, sessionKey: sessionKey, err: err}
}
}
@@ -99,21 +99,28 @@ func (m StandingsModel) Update(msg tea.Msg) (StandingsModel, tea.Cmd) {
}
case driverChampionshipLoadedMsg:
if msg.year != m.year {
return m, nil
}
if msg.err != nil {
m.err = msg.err
m.loading = false
return m, nil
}
m.driverStandings = msg.standings
m.drivers = make(map[int]models.Driver)
if m.client.LastResponseWasStale() {
m.stale = true
}
if len(msg.standings) > 0 {
return m, fetchStandingsDrivers(m.client, msg.standings[0].SessionKey)
return m, fetchStandingsDrivers(m.client, msg.year, msg.standings[0].SessionKey)
}
m.loading = false
case teamChampionshipLoadedMsg:
if msg.year != m.year {
return m, nil
}
if msg.err != nil {
m.err = msg.err
return m, nil
@@ -124,6 +131,12 @@ func (m StandingsModel) Update(msg tea.Msg) (StandingsModel, tea.Cmd) {
}
case standingsDriversLoadedMsg:
if msg.year != m.year {
return m, nil
}
if len(m.driverStandings) > 0 && msg.sessionKey != m.driverStandings[0].SessionKey {
return m, nil
}
if msg.err != nil {
m.err = msg.err
m.loading = false