275 lines
6.7 KiB
Go
275 lines
6.7 KiB
Go
package tui
|
|
|
|
import (
|
|
"time"
|
|
|
|
"github.com/gdamore/tcell/v2"
|
|
"github.com/rivo/tview"
|
|
"suruatoel.xyz/timefiles/lib"
|
|
)
|
|
|
|
const (
|
|
PageNameTimer = "set"
|
|
)
|
|
|
|
type DayUI struct {
|
|
*tview.Pages
|
|
app *TUI
|
|
summaryList *tview.Table
|
|
totalsList *tview.Table
|
|
trackButtons *tview.Flex
|
|
startButton *tview.Button
|
|
stopButton *tview.Button
|
|
setButton *tview.Button
|
|
timerModal *ProActModal
|
|
currentTimer *lib.Time
|
|
summaryCount int
|
|
}
|
|
|
|
func NewDayUI(app *TUI) *DayUI {
|
|
ui := DayUI{
|
|
Pages: tview.NewPages(),
|
|
app: app,
|
|
}
|
|
|
|
main := tview.NewFlex().SetDirection(tview.FlexRow)
|
|
ui.AddPage("main", main, true, true)
|
|
|
|
summary := tview.NewFlex().SetDirection(tview.FlexColumn)
|
|
main.AddItem(summary, 0, 1, false)
|
|
|
|
ui.summaryList = tview.NewTable()
|
|
ui.summaryList.SetBorder(true).SetTitle("List")
|
|
ui.summaryList.SetSelectable(true, false)
|
|
summary.AddItem(ui.summaryList, 0, 1, false)
|
|
|
|
ui.totalsList = tview.NewTable()
|
|
ui.totalsList.SetBorder(true).SetTitle(" Totals ")
|
|
summary.AddItem(ui.totalsList, 0, 1, false)
|
|
|
|
track := tview.NewFlex().SetDirection(tview.FlexRow)
|
|
track.SetBorder(true).SetTitle(" Track ")
|
|
main.AddItem(track, 3, 0, true)
|
|
|
|
ui.trackButtons = tview.NewFlex().SetDirection(tview.FlexColumn)
|
|
track.AddItem(ui.trackButtons, 1, 0, true)
|
|
ui.startButton = tview.NewButton("start (n)")
|
|
ui.trackButtons.AddItem(ui.startButton, 0, 1, false)
|
|
ui.trackButtons.AddItem(nil, 1, 0, false)
|
|
ui.stopButton = tview.NewButton("stop (r)")
|
|
ui.trackButtons.AddItem(ui.stopButton, 0, 1, false)
|
|
ui.trackButtons.AddItem(nil, 1, 0, false)
|
|
ui.setButton = tview.NewButton("set (s)")
|
|
ui.trackButtons.AddItem(ui.setButton, 0, 1, false)
|
|
|
|
ui.timerModal = NewProActModal(app, "Timer")
|
|
ui.AddPage(PageNameTimer, ui.timerModal, true, false)
|
|
|
|
ui.assignHandlers()
|
|
|
|
return &ui
|
|
}
|
|
|
|
func (ui *DayUI) SetTimer(timer *lib.Time) {
|
|
if ui.currentTimer != nil {
|
|
ui.summaryList.RemoveRow(ui.summaryCount)
|
|
}
|
|
ui.currentTimer = timer
|
|
ui.setInputStates()
|
|
|
|
if timer == nil {
|
|
ui.app.Focus(ui.startButton)
|
|
ui.timerModal.SetValues(nil, nil)
|
|
} else {
|
|
ui.timerModal.SetValues(ui.resolveTimerValues(timer.ProjectID, timer.ActivityID))
|
|
|
|
if timer.ProjectID == "" || timer.ActivityID == "" {
|
|
ui.openTimerModal()
|
|
} else {
|
|
ui.app.Focus(ui.stopButton)
|
|
}
|
|
|
|
ui.includeTimerInSummary()
|
|
}
|
|
}
|
|
|
|
func (ui *DayUI) SetSummary(summary []*lib.Time) {
|
|
ui.summaryCount = len(summary)
|
|
ui.summaryList.Clear()
|
|
for i, entry := range summary {
|
|
ui.setSummaryLine(entry, i)
|
|
}
|
|
|
|
ui.includeTimerInSummary()
|
|
}
|
|
|
|
func (ui *DayUI) SetTotals(totalTime lib.TotalTime) {
|
|
ui.totalsList.Clear()
|
|
for i, entry := range totalTime.Totals {
|
|
projectLabel := entry.Project
|
|
var projectAttrs tcell.AttrMask
|
|
activityLabel := entry.Activity
|
|
var activityAttrs tcell.AttrMask
|
|
|
|
if entry.Project == "" {
|
|
projectLabel = "not set"
|
|
projectAttrs = tcell.AttrItalic
|
|
}
|
|
if entry.Activity == "" {
|
|
activityLabel = "not set"
|
|
activityAttrs = tcell.AttrItalic
|
|
}
|
|
|
|
ui.totalsList.SetCell(i, 0, tview.NewTableCell(projectLabel).SetExpansion(1).SetAttributes(projectAttrs))
|
|
ui.totalsList.SetCell(i, 1, tview.NewTableCell(activityLabel).SetExpansion(1))
|
|
ui.totalsList.SetCell(i, 2, tview.NewTableCell(entry.Duration.Round(time.Second).String()).SetExpansion(0).SetAttributes(activityAttrs))
|
|
}
|
|
|
|
ui.totalsList.SetCell(len(totalTime.Totals), 0, tview.NewTableCell("Total").SetExpansion(1).SetAttributes(tcell.AttrBold))
|
|
ui.totalsList.SetCell(len(totalTime.Totals), 2, tview.NewTableCell(totalTime.TotalSum.Round(time.Second).String()).SetExpansion(0).SetAttributes(tcell.AttrBold))
|
|
}
|
|
|
|
func (ui *DayUI) setSummaryLine(entry *lib.Time, line int) {
|
|
projectAttrs := tcell.AttrItalic
|
|
activityAttrs := tcell.AttrItalic
|
|
projectLabel := "not set"
|
|
activityLabel := "not set"
|
|
|
|
project, activity := ui.resolveTimerValues(entry.ProjectID, entry.ActivityID)
|
|
if project != nil {
|
|
projectLabel = project.Title
|
|
projectAttrs = tcell.AttrNone
|
|
if activity != nil {
|
|
activityLabel = activity.Title
|
|
activityAttrs = tcell.AttrNone
|
|
}
|
|
}
|
|
|
|
ui.summaryList.SetCell(line, 0, tview.NewTableCell(projectLabel).SetExpansion(1).SetAttributes(projectAttrs))
|
|
ui.summaryList.SetCell(line, 1, tview.NewTableCell(activityLabel).SetExpansion(1).SetAttributes(activityAttrs))
|
|
if !entry.Start.IsZero() {
|
|
ui.summaryList.SetCell(line, 2, tview.NewTableCell(formatTime(entry.Start)).SetExpansion(0))
|
|
}
|
|
if !entry.End.IsZero() {
|
|
ui.summaryList.SetCell(line, 3, tview.NewTableCell(formatTime(entry.End)).SetExpansion(0))
|
|
}
|
|
}
|
|
|
|
func (ui *DayUI) includeTimerInSummary() {
|
|
if ui.currentTimer == nil {
|
|
return
|
|
}
|
|
ui.setSummaryLine(ui.currentTimer, ui.summaryCount)
|
|
}
|
|
|
|
func (ui *DayUI) assignHandlers() {
|
|
ui.startButton.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
|
|
switch event.Key() {
|
|
case tcell.KeyTAB:
|
|
ui.app.Focus(ui.stopButton)
|
|
return nil
|
|
}
|
|
|
|
return event
|
|
})
|
|
ui.startButton.SetSelectedFunc(func() {
|
|
ui.start()
|
|
})
|
|
|
|
ui.stopButton.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
|
|
switch event.Key() {
|
|
case tcell.KeyTAB:
|
|
ui.app.Focus(ui.setButton)
|
|
return nil
|
|
}
|
|
|
|
return event
|
|
})
|
|
ui.stopButton.SetSelectedFunc(func() {
|
|
ui.stop()
|
|
})
|
|
|
|
ui.setButton.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
|
|
switch event.Key() {
|
|
case tcell.KeyTAB:
|
|
ui.app.Focus(ui.summaryList)
|
|
return nil
|
|
}
|
|
|
|
return event
|
|
})
|
|
ui.setButton.SetSelectedFunc(func() {
|
|
ui.openTimerModal()
|
|
})
|
|
|
|
ui.timerModal.SetCloseFunc(func(project string, activity string, success bool) {
|
|
ui.HidePage(PageNameTimer)
|
|
|
|
if success {
|
|
ui.setDetails(project, activity)
|
|
ui.app.Focus(ui.stopButton)
|
|
} else {
|
|
ui.app.Focus(ui.setButton)
|
|
}
|
|
})
|
|
|
|
ui.trackButtons.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
|
|
switch event.Rune() {
|
|
case 'n':
|
|
ui.start()
|
|
return nil
|
|
case 'r':
|
|
ui.stop()
|
|
return nil
|
|
case 's':
|
|
ui.openTimerModal()
|
|
return nil
|
|
}
|
|
|
|
return event
|
|
})
|
|
}
|
|
|
|
func (ui *DayUI) setInputStates() {
|
|
ui.stopButton.SetDisabled(ui.currentTimer == nil)
|
|
ui.setButton.SetDisabled(ui.currentTimer == nil)
|
|
}
|
|
|
|
func (ui *DayUI) start() {
|
|
ui.app.timeApp.StartTimer()
|
|
}
|
|
|
|
func (ui *DayUI) stop() {
|
|
if ui.currentTimer != nil {
|
|
ui.app.timeApp.StopTimer()
|
|
}
|
|
}
|
|
|
|
func (ui *DayUI) openTimerModal() {
|
|
if ui.currentTimer != nil {
|
|
ui.ShowPage(PageNameTimer)
|
|
ui.app.Focus(ui.timerModal)
|
|
}
|
|
}
|
|
|
|
func (ui *DayUI) setDetails(project, activity string) {
|
|
if ui.currentTimer == nil {
|
|
return
|
|
}
|
|
|
|
ui.app.timeApp.UpdateTimer(project, activity)
|
|
}
|
|
|
|
func (ui *DayUI) resolveTimerValues(projectID, activityID string) (*lib.Project, *lib.Activity) {
|
|
project := ui.app.timeApp.GetProject(projectID)
|
|
if project != nil {
|
|
activity := ui.app.timeApp.GetActivity(project, activityID)
|
|
return project, activity
|
|
}
|
|
|
|
return project, nil
|
|
}
|
|
|
|
func formatTime(t time.Time) string {
|
|
return t.Format("15:04:05")
|
|
}
|