Skip to content

Commit 2b1e7fb

Browse files
committed
pass time provider as a dependency
1 parent 70049e3 commit 2b1e7fb

File tree

9 files changed

+84
-43
lines changed

9 files changed

+84
-43
lines changed

internal/types/types.go

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,24 @@ type TaskReportEntry struct {
6060
SecsSpent int
6161
}
6262

63+
type TimeProvider interface {
64+
Now() time.Time
65+
}
66+
67+
type RealTimeProvider struct{}
68+
69+
func (RealTimeProvider) Now() time.Time {
70+
return time.Now()
71+
}
72+
73+
type TestTimeProvider struct {
74+
FixedTime time.Time
75+
}
76+
77+
func (t TestTimeProvider) Now() time.Time {
78+
return t.FixedTime
79+
}
80+
6381
func (t *Task) UpdateListTitle() {
6482
var trackingIndicator string
6583
if t.TrackingActive {
@@ -69,15 +87,15 @@ func (t *Task) UpdateListTitle() {
6987
t.ListTitle = trackingIndicator + t.Summary
7088
}
7189

72-
func (t *Task) UpdateListDesc() {
90+
func (t *Task) UpdateListDesc(timeProvider TimeProvider) {
7391
var timeSpent string
7492

7593
if t.SecsSpent != 0 {
7694
timeSpent = "worked on for " + HumanizeDuration(t.SecsSpent)
7795
} else {
7896
timeSpent = "no time spent"
7997
}
80-
lastUpdated := fmt.Sprintf("last updated: %s", humanize.Time(t.UpdatedAt))
98+
lastUpdated := fmt.Sprintf("last updated: %s", humanize.RelTime(t.UpdatedAt, timeProvider.Now(), "ago", "from now"))
8199

82100
t.ListDesc = fmt.Sprintf("%s %s", utils.RightPadTrim(lastUpdated, 60, true), timeSpent)
83101
}
@@ -86,13 +104,13 @@ func (tl *TaskLogEntry) UpdateListTitle() {
86104
tl.ListTitle = utils.TrimWithMoreLinesIndicator(tl.GetComment(), 60)
87105
}
88106

89-
func (tl *TaskLogEntry) UpdateListDesc() {
107+
func (tl *TaskLogEntry) UpdateListDesc(timeProvider TimeProvider) {
90108
timeSpentStr := HumanizeDuration(tl.SecsSpent)
91109

92110
var timeStr string
93111
var durationMsg string
94112

95-
endTSRelative := getTSRelative(tl.EndTS, time.Now())
113+
endTSRelative := getTSRelative(tl.EndTS, timeProvider.Now())
96114

97115
switch endTSRelative {
98116
case tsFromToday:
@@ -102,7 +120,7 @@ func (tl *TaskLogEntry) UpdateListDesc() {
102120
case tsFromThisWeek:
103121
durationMsg = tl.EndTS.Format(dayFormat)
104122
default:
105-
durationMsg = humanize.Time(tl.EndTS)
123+
durationMsg = humanize.RelTime(tl.EndTS, timeProvider.Now(), "ago", "from now")
106124
}
107125

108126
timeStr = fmt.Sprintf("%s (%s)",

internal/ui/handle.go

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ func (m *Model) getCmdToUpdateActiveTL() tea.Cmd {
5454
return nil
5555
}
5656

57-
if beginTS.After(time.Now()) {
57+
if beginTS.After(m.timeProvider.Now()) {
5858
m.message = errMsgQuick(beginTsCannotBeInTheFutureMsg)
5959
return nil
6060
}
@@ -76,7 +76,7 @@ func (m *Model) getCmdToFinishTrackingActiveTL() tea.Cmd {
7676
return nil
7777
}
7878

79-
now := time.Now()
79+
now := m.timeProvider.Now()
8080
if beginTS.After(now) {
8181
m.message = errMsgQuick(beginTsCannotBeInTheFutureMsg)
8282
return nil
@@ -117,7 +117,7 @@ func (m *Model) getCmdToFinishTrackingActiveTL() tea.Cmd {
117117
}
118118

119119
func (m *Model) getCmdToFinishActiveTLWithoutComment() tea.Cmd {
120-
now := time.Now().Truncate(time.Second)
120+
now := m.timeProvider.Now().Truncate(time.Second)
121121
if !m.isDurationValid(m.activeTLBeginTS, now) {
122122
return nil
123123
}
@@ -134,7 +134,7 @@ func (m *Model) getCmdToCreateOrEditTL() tea.Cmd {
134134
return nil
135135
}
136136

137-
now := time.Now()
137+
now := m.timeProvider.Now()
138138
if beginTS.After(now) {
139139
m.message = errMsgQuick(beginTsCannotBeInTheFutureMsg)
140140
return nil
@@ -392,7 +392,7 @@ func (m *Model) handleRequestToEditActiveTL() {
392392
func (m *Model) handleRequestToCreateManualTL() {
393393
m.activeView = manualTasklogEntryView
394394
m.tasklogSaveType = tasklogInsert
395-
currentTime := time.Now()
395+
currentTime := m.timeProvider.Now()
396396
currentTimeStr := currentTime.Format(timeFormat)
397397

398398
m.tLInputs[entryBeginTS].SetValue(currentTimeStr)
@@ -486,13 +486,13 @@ func (m *Model) getCmdToStartTracking() tea.Cmd {
486486
}
487487

488488
m.changesLocked = true
489-
m.activeTLBeginTS = time.Now().Truncate(time.Second)
489+
m.activeTLBeginTS = m.timeProvider.Now().Truncate(time.Second)
490490
return toggleTracking(m.db, task.ID, m.activeTLBeginTS, m.activeTLEndTS, nil)
491491
}
492492

493493
func (m *Model) handleRequestToStopTracking() {
494494
m.activeView = finishActiveTLView
495-
m.activeTLEndTS = time.Now()
495+
m.activeTLEndTS = m.timeProvider.Now()
496496

497497
beginTimeStr := m.activeTLBeginTS.Format(timeFormat)
498498
currentTimeStr := m.activeTLEndTS.Format(timeFormat)
@@ -521,7 +521,7 @@ func (m *Model) getCmdToQuickSwitchTracking() tea.Cmd {
521521

522522
if !m.trackingActive {
523523
m.changesLocked = true
524-
m.activeTLBeginTS = time.Now().Truncate(time.Second)
524+
m.activeTLBeginTS = m.timeProvider.Now().Truncate(time.Second)
525525
return toggleTracking(m.db,
526526
task.ID,
527527
m.activeTLBeginTS,
@@ -530,7 +530,7 @@ func (m *Model) getCmdToQuickSwitchTracking() tea.Cmd {
530530
)
531531
}
532532

533-
return quickSwitchActiveIssue(m.db, task.ID, time.Now())
533+
return quickSwitchActiveIssue(m.db, task.ID, m.timeProvider.Now())
534534
}
535535

536536
func (m *Model) handleRequestToCreateTask() {
@@ -697,7 +697,7 @@ func (m *Model) handleTasksFetchedMsg(msg tasksFetchedMsg) tea.Cmd {
697697
tasks := make([]list.Item, len(msg.tasks))
698698
for i, task := range msg.tasks {
699699
task.UpdateListTitle()
700-
task.UpdateListDesc()
700+
task.UpdateListDesc(m.timeProvider)
701701
tasks[i] = &task
702702
m.taskMap[task.ID] = &task
703703
m.taskIndexMap[task.ID] = i
@@ -711,7 +711,7 @@ func (m *Model) handleTasksFetchedMsg(msg tasksFetchedMsg) tea.Cmd {
711711
inactiveTasks := make([]list.Item, len(msg.tasks))
712712
for i, inactiveTask := range msg.tasks {
713713
inactiveTask.UpdateListTitle()
714-
inactiveTask.UpdateListDesc()
714+
inactiveTask.UpdateListDesc(m.timeProvider)
715715
inactiveTasks[i] = &inactiveTask
716716
}
717717
m.inactiveTasksList.SetItems(inactiveTasks)
@@ -765,7 +765,7 @@ func (m *Model) handleTLSFetchedMsg(msg tLsFetchedMsg) {
765765
var indexToFocusOnFound bool
766766
for i, e := range msg.entries {
767767
e.UpdateListTitle()
768-
e.UpdateListDesc()
768+
e.UpdateListDesc(m.timeProvider)
769769
items[i] = e
770770
if !indexToFocusOnFound && msg.tlIDToFocusOn != nil && e.ID == *msg.tlIDToFocusOn {
771771
indexToFocusOn = &i

internal/ui/initial.go

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,12 @@ const (
1515
textInputWidth = 80
1616
)
1717

18-
func InitialModel(db *sql.DB, style Style, debug bool, logFramesCfg logFramesConfig) Model {
18+
func InitialModel(db *sql.DB,
19+
style Style,
20+
timeProvider types.TimeProvider,
21+
debug bool,
22+
logFramesCfg logFramesConfig,
23+
) Model {
1924
var activeTaskItems []list.Item
2025
var inactiveTaskItems []list.Item
2126
var tasklogListItems []list.Item
@@ -49,8 +54,9 @@ This can be used to record details about your work on this task.`
4954
taskInputs[entryBeginTS].Width = textInputWidth
5055

5156
m := Model{
52-
db: db,
53-
style: style,
57+
db: db,
58+
style: style,
59+
timeProvider: timeProvider,
5460
activeTasksList: list.New(activeTaskItems,
5561
newItemDelegate(style.listItemTitleColor,
5662
style.listItemDescColor,
@@ -116,20 +122,22 @@ func initialRecordsModel(
116122
kind recordsKind,
117123
db *sql.DB,
118124
style Style,
125+
timeProvider types.TimeProvider,
119126
dateRange types.DateRange,
120127
period string,
121128
taskStatus types.TaskStatus,
122129
plain bool,
123130
initialData string,
124131
) recordsModel {
125132
return recordsModel{
126-
kind: kind,
127-
db: db,
128-
style: style,
129-
dateRange: dateRange,
130-
period: period,
131-
taskStatus: taskStatus,
132-
plain: plain,
133-
report: initialData,
133+
kind: kind,
134+
db: db,
135+
style: style,
136+
timeProvider: timeProvider,
137+
dateRange: dateRange,
138+
period: period,
139+
taskStatus: taskStatus,
140+
plain: plain,
141+
report: initialData,
134142
}
135143
}

internal/ui/log.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ func RenderTaskLog(db *sql.DB,
4949
reportLogs,
5050
db,
5151
style,
52+
types.RealTimeProvider{},
5253
dateRange,
5354
period,
5455
taskStatus,

internal/ui/model.go

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ type Model struct {
103103
lastViewBeforeInsufficientDims stateView
104104
db *sql.DB
105105
style Style
106+
timeProvider types.TimeProvider
106107
activeTasksList list.Model
107108
inactiveTasksList list.Model
108109
taskMap map[int]*types.Task
@@ -153,17 +154,18 @@ func (m Model) Init() tea.Cmd {
153154
}
154155

155156
type recordsModel struct {
156-
db *sql.DB
157-
style Style
158-
kind recordsKind
159-
dateRange types.DateRange
160-
period string
161-
plain bool
162-
taskStatus types.TaskStatus
163-
report string
164-
quitting bool
165-
busy bool
166-
err error
157+
db *sql.DB
158+
style Style
159+
timeProvider types.TimeProvider
160+
kind recordsKind
161+
dateRange types.DateRange
162+
period string
163+
plain bool
164+
taskStatus types.TaskStatus
165+
report string
166+
quitting bool
167+
busy bool
168+
err error
167169
}
168170

169171
func (recordsModel) Init() tea.Cmd {

internal/ui/report.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ func RenderReport(db *sql.DB,
5454
analyticsType,
5555
db,
5656
style,
57+
types.RealTimeProvider{},
5758
dateRange,
5859
period,
5960
taskStatus,

internal/ui/stats.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ func RenderStats(db *sql.DB,
6060
reportStats,
6161
db,
6262
style,
63+
types.RealTimeProvider{},
6364
*dateRange,
6465
period,
6566
taskStatus,

internal/ui/ui.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"time"
1010

1111
tea "github.com/charmbracelet/bubbletea"
12+
"github.com/dhth/hours/internal/types"
1213
)
1314

1415
var (
@@ -39,7 +40,16 @@ func RenderUI(db *sql.DB, style Style) error {
3940
logFramesCfg.framesDir = framesDir
4041
}
4142

42-
p := tea.NewProgram(InitialModel(db, style, debug, logFramesCfg), tea.WithAltScreen())
43+
p := tea.NewProgram(
44+
InitialModel(
45+
db,
46+
style,
47+
types.RealTimeProvider{},
48+
debug,
49+
logFramesCfg,
50+
),
51+
tea.WithAltScreen(),
52+
)
4353
_, err := p.Run()
4454

4555
return err

internal/ui/update.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
336336
if msg.err != nil {
337337
m.message = errMsg(fmt.Sprintf("Error updating task status: %s", msg.err))
338338
} else {
339-
msg.tsk.UpdateListDesc()
339+
msg.tsk.UpdateListDesc(m.timeProvider)
340340
}
341341
case tLDeletedMsg:
342342
updateCmds := m.handleTLDeleted(msg)
@@ -428,14 +428,14 @@ func (m recordsModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
428428

429429
switch m.period {
430430
case types.TimePeriodWeek:
431-
now := time.Now()
431+
now := m.timeProvider.Now()
432432
weekday := now.Weekday()
433433
offset := (7 + weekday - time.Monday) % 7
434434
startOfWeek := now.AddDate(0, 0, -int(offset))
435435
dr.Start = time.Date(startOfWeek.Year(), startOfWeek.Month(), startOfWeek.Day(), 0, 0, 0, 0, startOfWeek.Location())
436436
dr.NumDays = 7
437437
default:
438-
now := time.Now()
438+
now := m.timeProvider.Now()
439439
nDaysBack := now.AddDate(0, 0, -1*(m.dateRange.NumDays-1))
440440

441441
dr.Start = time.Date(nDaysBack.Year(), nDaysBack.Month(), nDaysBack.Day(), 0, 0, 0, 0, nDaysBack.Location())

0 commit comments

Comments
 (0)