From 2b357839e95492bb7d9767ca5cc5dd24a0adf913 Mon Sep 17 00:00:00 2001 From: Brian Buller Date: Tue, 9 Mar 2021 08:20:54 -0600 Subject: [PATCH] When no active timer show summary on i3status --- helpers.go | 17 ++++++ model.go | 107 ++++++++++++++++++++++++++++++++---- timer_ops.go | 149 ++++++++++++++++++--------------------------------- 3 files changed, 166 insertions(+), 107 deletions(-) diff --git a/helpers.go b/helpers.go index 97cee35..d7d817d 100644 --- a/helpers.go +++ b/helpers.go @@ -283,3 +283,20 @@ func diff(a, b time.Time) (year, month, day, hour, min, sec int) { return } + +func BeginningOfDay() time.Time { + now := time.Now() + return time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()) +} + +func BeginningOfWeek() time.Time { + now := time.Now() + t := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()) + weekday := int(t.Weekday()) + return t.AddDate(0, 0, -weekday) +} + +func BeginningOfMonth() time.Time { + now := time.Now() + return time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location()) +} diff --git a/model.go b/model.go index bd7c8ee..a04c022 100644 --- a/model.go +++ b/model.go @@ -1,26 +1,113 @@ package main import ( + "fmt" "strings" "time" timertxt "git.bullercodeworks.com/brian/go-timertxt" ) +// If we have an active timer in timer.txt, return the most recent one +// Otherwise, check if we have a more recent completed timer in done.txt +// Return the most recent done from timer.txt or dont.txt func (a *AppState) getMostRecentTimer() (*timertxt.Timer, error) { - wrk, err := a.TimerList.GetMostRecentTimer() - if err != nil { - // Couldn't find a timer in the 'timer.txt'... Check the 'done' file - if err = a.LoadDoneList(); err != nil { - return nil, err - } + work, wErr := a.TimerList.GetMostRecentTimer() + if wErr != nil && work.FinishDate.IsZero() { + return work, nil + } - wrk, err = a.DoneList.GetMostRecentTimer() - if err != nil { - return nil, err + if err := a.LoadDoneList(); err != nil { + return nil, err + } + done, dErr := a.DoneList.GetMostRecentTimer() + if dErr != nil { + return nil, dErr + } + if !done.FinishDate.IsZero() && done.FinishDate.After(work.FinishDate) { + return done, nil + } + return work, nil +} + +func (a *AppState) getFilteredTimerList(args []string) *timertxt.TimerList { + var includeArchive bool + var err error + start := time.Time{} + end := time.Now() + var contextFilters []string + var projectFilters []string + + var allFilters []func(timertxt.Timer) bool + + if len(args) > 0 { + contextFilters, args = getContextsFromSlice(args) + projectFilters, args = getProjectsFromSlice(args) + } + if len(args) > 0 { + if args[0] == "--a" { + includeArchive = true + args = args[1:] } } - return wrk, nil + if len(args) > 0 { + if start, err = parseFuzzyTime(args[0]); err != nil { + y, m, d := time.Now().Date() + start = time.Date(y, m, d, 0, 0, 0, 0, time.Now().Location()) + } else { + args = args[1:] + } + if len(args) > 0 { + if end, err = parseFuzzyTime(args[0]); err != nil { + y, m, d := time.Now().Date() + end = time.Date(y, m, d, 23, 59, 59, 0, time.Now().Location()) + } else { + args = args[1:] + } + } + } + list := a.TimerList.GetTimersInRange(start, end) + + if includeArchive { + if err = a.LoadDoneList(); err != nil { + fmt.Println("Error loading done.txt entries") + fmt.Println(err.Error()) + return nil + } + *list = append(*list, (*a.DoneList.GetTimersInRange(start, end))...) + } + if len(contextFilters) > 0 { + allFilters = append(allFilters, func(t timertxt.Timer) bool { + for _, v := range contextFilters { + v = strings.TrimPrefix(v, "@") + if !t.HasContext(v) { + return false + } + } + return true + }) + } + if len(projectFilters) > 0 { + allFilters = append(allFilters, func(t timertxt.Timer) bool { + for _, v := range projectFilters { + v = strings.TrimPrefix(v, "+") + if !t.HasProject(v) { + return false + } + } + return true + }) + } + doFilters := func(t timertxt.Timer) bool { + for _, v := range allFilters { + if !v(t) { + return false + } + } + // If we made it all the way down here, it matches + return true + } + return list.Filter(doFilters) } func (a *AppState) SetTimerFinished(id int, end time.Time) error { diff --git a/timer_ops.go b/timer_ops.go index ab20533..a29c3f4 100644 --- a/timer_ops.go +++ b/timer_ops.go @@ -17,33 +17,67 @@ func (a *AppState) opI3Status(args []string) int { fmt.Print("{\"icon\":\"time\",\"state\":\"Critical\", \"text\": \"Error loading timer entry\"}") return 0 } - - // TODO: Get Weekly/Daily totals var text string - if wrk.Finished { + if !wrk.Finished { wrkDur := wrk.Duration().Round(time.Minute * 15) hrs := int(wrkDur.Hours()) mins := int(wrkDur.Minutes()) - hrs*60 if hrs > 0 { text = fmt.Sprintf("%dh%dm", hrs, mins) } else { - text = fmt.Sprintf("%d", mins) + text = fmt.Sprintf("%dm", mins) + } + if !wrk.Finished { + // If the current time is before 7AM, after 5PM, or a weekend, use a Warning state + cTime := time.Now() + if cTime.Weekday() == time.Sunday || cTime.Weekday() == time.Saturday || cTime.Hour() < 7 || cTime.Hour() > 17 { + state = "Warning" + } else { + state = "Good" + } + } + for _, ctx := range wrk.Contexts { + text = fmt.Sprintf("%s @%s", text, ctx) + } + for _, prj := range wrk.Projects { + text = fmt.Sprintf("%s +%s", text, prj) } } else { - text = fmt.Sprint(wrk.Duration().Round(time.Minute)) - // If the current time is before 7AM, after 5PM, or a weekend, use a Warning state - cTime := time.Now() - if cTime.Weekday() == time.Sunday || cTime.Weekday() == time.Saturday || cTime.Hour() < 7 || cTime.Hour() > 17 { - state = "Warning" - } else { - state = "Good" + text = "(" + for _, ctx := range wrk.Contexts { + text = fmt.Sprintf("%s@%s ", text, ctx) } - } - for _, ctx := range wrk.Contexts { - text = fmt.Sprintf("%s @%s", text, ctx) - } - for _, prj := range wrk.Projects { - text = fmt.Sprintf("%s +%s", text, prj) + for _, prj := range wrk.Projects { + text = fmt.Sprintf("%s+%s ", text, prj) + } + if text[len(text)-1] == ' ' { + text = text[:len(text)-1] + } + text = text + ")" + getListTotal := func(list *timertxt.TimerList) string { + var isActive bool + var total time.Duration + for _, v := range *list { + dur := v.FinishDate.Sub(v.StartDate) + if v.FinishDate.IsZero() { + dur = time.Now().Sub(v.StartDate) + isActive = true + } + total += dur + } + total = total.Round(GetRoundToDuration()) + if isActive { + return fmt.Sprintf("%.2f+", DurationToDecimal(total)) + } else { + return fmt.Sprintf("%.2f", DurationToDecimal(total)) + } + } + dayList := a.getFilteredTimerList([]string{"--a", BeginningOfDay().Format("2006-01-02"), "@bcw"}) + text = text + " d:" + getListTotal(dayList) + weekList := a.getFilteredTimerList([]string{"--a", BeginningOfWeek().Format("2006-01-02"), "@bcw"}) + text = text + " w:" + getListTotal(weekList) + monthList := a.getFilteredTimerList([]string{"--a", BeginningOfMonth().Format("2006-01-02"), "@bcw"}) + text = text + " m:" + getListTotal(monthList) } fmt.Printf("{\"icon\":\"time\",\"state\":\"%s\", \"text\": \"%s\"}", state, text) return 0 @@ -82,86 +116,7 @@ func (a *AppState) opStatus(args []string) int { * Just output the time given the filters */ func (a *AppState) opShowTime(args []string) int { - var includeArchive bool - var err error - start := time.Time{} - end := time.Now() - var contextFilters []string - var projectFilters []string - - var allFilters []func(timertxt.Timer) bool - - if len(args) > 0 { - contextFilters, args = getContextsFromSlice(args) - projectFilters, args = getProjectsFromSlice(args) - } - if len(args) > 0 { - if args[0] == "--a" { - includeArchive = true - args = args[1:] - } - } - if len(args) > 0 { - if start, err = parseFuzzyTime(args[0]); err != nil { - y, m, d := time.Now().Date() - start = time.Date(y, m, d, 0, 0, 0, 0, time.Now().Location()) - } else { - args = args[1:] - } - if len(args) > 0 { - if end, err = parseFuzzyTime(args[0]); err != nil { - y, m, d := time.Now().Date() - end = time.Date(y, m, d, 23, 59, 59, 0, time.Now().Location()) - } else { - args = args[1:] - } - } - } - if includeArchive { - if err = a.LoadDoneList(); err != nil { - fmt.Println("Error loading done.txt entries") - fmt.Println(err.Error()) - return 1 - } - } - - list := a.TimerList.GetTimersInRange(start, end) - if includeArchive { - *list = append(*list, (*a.DoneList.GetTimersInRange(start, end))...) - } - if len(contextFilters) > 0 { - allFilters = append(allFilters, func(t timertxt.Timer) bool { - for _, v := range contextFilters { - v = strings.TrimPrefix(v, "@") - if !t.HasContext(v) { - return false - } - } - return true - }) - } - if len(projectFilters) > 0 { - allFilters = append(allFilters, func(t timertxt.Timer) bool { - for _, v := range projectFilters { - v = strings.TrimPrefix(v, "+") - if !t.HasProject(v) { - return false - } - } - return true - }) - } - doFilters := func(t timertxt.Timer) bool { - for _, v := range allFilters { - if !v(t) { - return false - } - } - // If we made it all the way down here, it matches - return true - } - list = list.Filter(doFilters) - + list := a.getFilteredTimerList(args) var isActive bool var total time.Duration for _, v := range *list {