1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
|
package tui
import (
"fmt"
tea "github.com/charmbracelet/bubbletea"
)
// NewTimerBoxModel creates a new timer box model
func NewTimerBoxModel() TimerBoxModel {
return TimerBoxModel{}
}
// Update handles messages for the timer box
func (m TimerBoxModel) Update(msg tea.Msg) (TimerBoxModel, tea.Cmd) {
return m, nil
}
// View renders the timer box
func (m TimerBoxModel) View(width, height int, isSelected bool) string {
var content string
if m.timerInfo.IsActive {
content = m.renderActiveTimer()
} else {
content = m.renderInactiveTimer()
}
// Apply box styling
style := unselectedBoxStyle
if isSelected {
style = selectedBoxStyle
}
var title string
if m.timerInfo.IsActive {
title = "⏱ Active Timer"
} else {
title = "⚪ Timer (Inactive)"
}
return style.Width(width).Height(height).Render(
fmt.Sprintf("%s\n\n%s", title, content),
)
}
// renderActiveTimer renders the active timer display
func (m TimerBoxModel) renderActiveTimer() string {
var content string
// Timer duration
timerLine := fmt.Sprintf("Duration: %s", FormatDuration(m.timerInfo.Duration))
content += activeTimerStyle.Render(timerLine) + "\n\n"
// Project/Client info
if m.timerInfo.ProjectName != "" {
projectLine := fmt.Sprintf("Project: %s / %s", m.timerInfo.ClientName, m.timerInfo.ProjectName)
content += projectLine + "\n"
} else {
clientLine := fmt.Sprintf("Client: %s", m.timerInfo.ClientName)
content += clientLine + "\n"
}
// Start time (convert from UTC to local)
localStartTime := m.timerInfo.StartTime.Local()
startLine := fmt.Sprintf("Started: %s", localStartTime.Format("3:04 PM"))
content += startLine + "\n"
// Description if available
if m.timerInfo.Description != "" {
content += "\n"
descLine := fmt.Sprintf("Description: %s", m.timerInfo.Description)
content += descLine + "\n"
}
// Billable rate if available
if m.timerInfo.BillableRate != nil {
rateLine := fmt.Sprintf("Rate: $%.2f/hr", *m.timerInfo.BillableRate)
content += rateLine + "\n"
}
return content
}
// renderInactiveTimer renders the inactive timer display
func (m TimerBoxModel) renderInactiveTimer() string {
var content string
content += "No active timer\n\n"
content += "Ready to start tracking time.\n"
content += "Use 'i' to punch in or select\n"
content += "a client/project from the left."
return content
}
// UpdateTimerInfo updates the timer info
func (m TimerBoxModel) UpdateTimerInfo(timerInfo TimerInfo) TimerBoxModel {
m.timerInfo = timerInfo
return m
}
|