From 17cfbbc5fe7b8ccac5d2cd313f2b1be9f76fd786 Mon Sep 17 00:00:00 2001 From: Brian Buller Date: Wed, 15 Mar 2017 14:38:37 -0500 Subject: [PATCH] Several Updates * Caching the day's events (for 6 hours) * Up the Calendar List Cache expiration to a week * Setting things up for a 'UI' mode --- interactive_mode.go => config_mode.go | 21 +++--- main.go | 99 ++++++++++++++++++--------- struct_account.go | 28 ++++++-- struct_calendar.go | 4 +- struct_event.go | 24 ++++++- struct_screen.go | 7 +- ui_mode.go | 37 ++++++++++ 7 files changed, 167 insertions(+), 53 deletions(-) rename interactive_mode.go => config_mode.go (88%) create mode 100644 ui_mode.go diff --git a/interactive_mode.go b/config_mode.go similarity index 88% rename from interactive_mode.go rename to config_mode.go index c2c099b..e65e529 100644 --- a/interactive_mode.go +++ b/config_mode.go @@ -103,19 +103,18 @@ func toggleCalendar(g *gocui.Gui, v *gocui.View) error { _, cy := v.Cursor() var removed bool calList := state.account.GetCalendarList() - if v != nil { - for i := range state.defaultCalendars { - if state.defaultCalendars[i] == calList[cy].Id { - // Remove calendar from defaults - state.defaultCalendars = append(state.defaultCalendars[:i], state.defaultCalendars[i+1:]...) - state.StatusMsg = "Calendar Removed from Defaults" - removed = true - } + for i := range state.defaultCalendars { + if state.defaultCalendars[i] == calList[cy].Id { + // Remove calendar from defaults + state.defaultCalendars = append(state.defaultCalendars[:i], state.defaultCalendars[i+1:]...) + state.StatusMsg = "Calendar '" + calList[cy].Summary + "' Removed from Defaults" + removed = true + break } } if !removed { // Add calendar to defaults - state.StatusMsg = "Calendar Added to Defaults" + state.StatusMsg = "Calendar '" + calList[cy].Summary + "' Added to Defaults" state.defaultCalendars = append(state.defaultCalendars, calList[cy].Id) } updateViews(g) @@ -138,6 +137,10 @@ func cursorUp(g *gocui.Gui, v *gocui.View) error { func cursorDown(g *gocui.Gui, v *gocui.View) error { if v != nil { cx, cy := v.Cursor() + calList := state.account.GetCalendarList() + if cy+1 > len(calList)-1 { + return nil + } if err := v.SetCursor(cx, cy+1); err != nil { ox, oy := v.Origin() if err := v.SetOrigin(ox, oy+1); err != nil { diff --git a/main.go b/main.go index b4c93bb..ef24941 100644 --- a/main.go +++ b/main.go @@ -6,7 +6,6 @@ import ( "io/ioutil" "log" "os" - "sort" "strings" "time" @@ -69,37 +68,44 @@ func main() { case "today": // Show everything on the calendar for today InitComm() - // TODO: Get calendars flagged as default - list := state.account.GetCalendarList() - var todayEvents []Event - if len(list) > 0 { - for defIdx := range state.defaultCalendars { - for i := range list { - if list[i].Deleted { - // Deleted calendar, next please - continue - } - if state.defaultCalendars[defIdx] == list[i].Id { - todayEvents = append(todayEvents, list[i].GetTodaysEvents()...) - } - } - } - sort.Sort(ByStartTime(todayEvents)) - for _, e := range todayEvents { - if e.GetStartTimeString() == "00:00:00" { - color.New(color.FgGreen).Println("[All Day ] " + e.Summary) - } else { - if time.Until(e.GetStartTime()) < time.Hour { - color.New(color.FgYellow).Add(color.Bold).Println("[" + e.GetStartTimeString() + "] " + e.Summary) - } else if time.Until(e.GetStartTime()) < time.Minute*30 { - color.New(color.FgRed).Add(color.Bold).Println("[" + e.GetStartTimeString() + "] " + e.Summary) - } else { - fmt.Println("[" + e.GetStartTimeString() + "] " + e.Summary) - } - } - } + events := state.account.GetTodaysEvents() + if len(events) == 0 { + fmt.Println("No Events Found") } else { - fmt.Printf("No calendars found.\n") + for _, e := range events { + isOnCal := false + for _, idx := range state.defaultCalendars { + if idx == e.CalendarId { + isOnCal = true + break + } + } + if !isOnCal { + continue + } + stTmStr := e.GetStartTimeString() + durStr := "(" + e.GetEndTime().Sub(e.GetStartTime()).String() + ")" + if stTmStr == "00:00" { + stTmStr = "All Day" + durStr = "" + } else { + stTmStr = " " + stTmStr + } + + eventString := "[" + stTmStr + "] " + e.Summary + " " + durStr + if time.Until(e.GetStartTime()) < 0 && time.Until(e.GetEndTime()) < 0 { + // Event is in the past + color.New(color.FgGreen).Add(color.Bold).Println(eventString) + } else if time.Until(e.GetStartTime()) < 0 && time.Until(e.GetEndTime()) > 0 { + // Event is NOW + color.New(color.FgRed).Add(color.Bold).Println(eventString) + } else if time.Until(e.GetStartTime()) < time.Hour { + // Event is in less than an hour + color.New(color.FgYellow).Add(color.Bold).Println(eventString) + } else { + fmt.Println(eventString) + } + } } case "config": @@ -107,9 +113,17 @@ func main() { InitComm() DoConfig() + case "ui": + // Open the UI mode + InitComm() + DoUIMode() + case "defaults": // Show Defaults InitComm() + for i := range state.defaultCalendars { + fmt.Println(state.defaultCalendars[i]) + } case "add": // Quick event add to primary calendar @@ -196,6 +210,15 @@ func saveAccountState() { fmt.Println("saveAccountState:calListUseBy error:", err) } } + var evListJson []byte + if evListJson, err = json.Marshal(state.account.EventList); err == nil { + if err = state.cfg.SetBytes("eventList", evListJson); err != nil { + fmt.Println("saveAccountState:eventList error:", err) + } + if err = state.cfg.SetDateTime("eventListUseBy", state.account.EventListUseBy); err != nil { + fmt.Println("saveAccountState:eventListUseBy error:", err) + } + } if err = state.cfg.SetArray("defaultCalendars", state.defaultCalendars); err != nil { fmt.Println("saveAccountState:defaultCalendars error:", err) } @@ -221,6 +244,20 @@ func loadAccountState() { } else { fmt.Println("error: ", err) } + var evListJson []byte + evListJson = state.cfg.GetBytes("eventList") + if err = json.Unmarshal(evListJson, &state.account.EventList); err == nil { + if len(state.account.EventList) > 0 { + if err != nil { + fmt.Println("error: ", err) + } + if state.account.EventListUseBy, err = state.cfg.GetDateTime("eventListUseBy"); err != nil { + fmt.Println("error: ", err) + } + } + } else { + fmt.Println("error: ", err) + } // If the 'defaultCalendars' cfg is set to 'primary' (or not at all) // we need to actually but the primary cal id in there diff --git a/struct_account.go b/struct_account.go index 39de5dd..ff822f8 100644 --- a/struct_account.go +++ b/struct_account.go @@ -8,6 +8,7 @@ import ( "fmt" "log" "net/http" + "sort" "time" "golang.org/x/oauth2" @@ -17,10 +18,12 @@ import ( ) type Account struct { - CC *CalClient - Service *calendar.Service - CalendarList []Calendar - CalListUseBy time.Time + CC *CalClient + Service *calendar.Service + CalendarList []Calendar + CalListUseBy time.Time + EventList []Event // Today's Events + EventListUseBy time.Time } func GetAccount(secret, token []byte) (*Account, error) { @@ -39,9 +42,22 @@ func GetAccount(secret, token []byte) (*Account, error) { return a, nil } +// Get Todays Events gets events for today from all calendars func (a *Account) GetTodaysEvents() []Event { + if time.Now().Before(a.EventListUseBy) { + return a.EventList + } var ret []Event - + list := a.GetCalendarList() + for i := range list { + if list[i].Deleted { + continue + } + ret = append(ret, list[i].GetTodaysEvents()...) + } + sort.Sort(ByStartTime(ret)) + a.EventList = ret + a.EventListUseBy = time.Now().Add(time.Hour * 6) return ret } @@ -63,7 +79,7 @@ func (a *Account) GetCalendarList() []Calendar { ret = append(ret, *GoogleCalendarToLocal(c)) } a.CalendarList = ret - a.CalListUseBy = time.Now().Add(time.Hour * 6) + a.CalListUseBy = time.Now().Add(time.Hour * 24 * 7) return ret } diff --git a/struct_calendar.go b/struct_calendar.go index bd9ddae..1cd248e 100644 --- a/struct_calendar.go +++ b/struct_calendar.go @@ -78,7 +78,7 @@ func (c *Calendar) GetTodaysEvents() []Event { return ret } for _, e := range events.Items { - ret = append(ret, *GoogleEventToLocal(e)) + ret = append(ret, *GoogleEventToLocalWithId(e, c.Id)) } return ret } @@ -91,7 +91,7 @@ func (c *Calendar) GetCalendarEvents() []Event { return ret } for _, e := range events.Items { - ret = append(ret, *GoogleEventToLocal(e)) + ret = append(ret, *GoogleEventToLocalWithId(e, c.Id)) } return ret } diff --git a/struct_event.go b/struct_event.go index dc21bc7..3eadf6c 100644 --- a/struct_event.go +++ b/struct_event.go @@ -10,6 +10,7 @@ import ( type Event struct { //Attachments []EventAttachment // Google Drive files Attendees []EventAttendee + CalendarId string ColorId string Created string Creator *EventAttendee @@ -51,9 +52,9 @@ func (e *Event) ToCLIString() string { func (e *Event) GetStartTimeString() string { tm, err := time.Parse(time.RFC3339, e.Start.DateTime) if err != nil { - return "00:00:00" + return "00:00" } - return tm.Local().Format("15:04:05") + return tm.Local().Format("15:04") } func (e *Event) GetStartTime() time.Time { @@ -61,6 +62,25 @@ func (e *Event) GetStartTime() time.Time { return tm } +func (e *Event) GetEndTimeString() string { + tm, err := time.Parse(time.RFC3339, e.End.DateTime) + if err != nil { + return "00:00" + } + return tm.Local().Format("15:04") +} + +func (e *Event) GetEndTime() time.Time { + tm, _ := time.Parse(time.RFC3339, e.End.DateTime) + return tm +} + +func GoogleEventToLocalWithId(e *calendar.Event, cId string) *Event { + ret := GoogleEventToLocal(e) + ret.CalendarId = cId + return ret +} + func GoogleEventToLocal(e *calendar.Event) *Event { return &Event{ //Attachments []EventAttachment // Google Drive files diff --git a/struct_screen.go b/struct_screen.go index f9732ce..2bed9f2 100644 --- a/struct_screen.go +++ b/struct_screen.go @@ -3,9 +3,10 @@ package main import "github.com/jroimartin/gocui" type screen interface { - setViewDefaults(*gocui.View) - setViewTextAndCursor(*gocui.View, string) - getViewValue(*gocui.Gui) + getGoCuiGui() *gocui.Gui + updateViews(*gocui.Gui) + layoutManger(*gocui.Gui) error + addView(string, int, int, int, int) } type position struct { diff --git a/ui_mode.go b/ui_mode.go new file mode 100644 index 0000000..f5a624e --- /dev/null +++ b/ui_mode.go @@ -0,0 +1,37 @@ +package main + +import ( + "log" + + "github.com/jroimartin/gocui" +) + +func DoUIMode() { + g, err := gocui.NewGui(gocui.Output256) + if err != nil { + log.Panicln(err) + } + defer g.Close() + g.Cursor = true + g.SetManagerFunc(uiLayout) + + if err := g.MainLoop(); err != nil && err != gocui.ErrQuit { + log.Panicln(err) + } +} + +func updateUiViews(g *gocui.Gui) { + for _, v := range g.Views() { + v.Clear() + } +} + +func uiLayout(g *gocui.Gui) error { + if v, err := g.SetView("cal_view", 0, 0, 20, 20); err != nil { + if err != gocui.ErrUnknownView { + return err + } + _ = v + } + return nil +}