gal/main.go

340 lines
8.0 KiB
Go

package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"os"
"sort"
"strings"
"time"
"github.com/br0xen/user-config"
"github.com/jroimartin/gocui"
)
const (
AppName = "gocal"
AppVersion = 1
)
type AppState struct {
Name string
Version int
ClientSecret []byte
cfg *userConfig.Config
account *Account
defaultCalendars []string
StatusMsg string
}
var state *AppState
func main() {
var err error
var op string
state = &AppState{Name: AppName, Version: AppVersion}
state.cfg, err = userConfig.NewConfig(state.Name)
if err != nil {
panic(err)
}
if len(os.Args) > 1 {
op = os.Args[1]
} else {
op = "today"
}
DoVersionCheck()
switch op {
case "--reinit":
// Reset all config
for _, v := range state.cfg.GetKeyList() {
fmt.Println("Deleting Key: " + v)
state.cfg.DeleteKey(v)
}
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.GetStartTime() == "00:00:00" {
fmt.Println("[All Day ] " + e.Summary)
} else {
fmt.Println("[" + e.GetStartTime() + "] " + e.Summary)
}
}
} else {
fmt.Printf("No calendars found.\n")
}
case "config":
InitComm()
DoConfig()
case "defaults":
// Show Defaults
InitComm()
case "add":
// Quick event add to primary calendar
quickAddText := strings.Join(os.Args[2:], " ")
e, err := state.account.GetDefaultCalendar().QuickAdd(quickAddText)
if err != nil {
fmt.Println(err.Error())
} else {
fmt.Println(e.ToCLIString())
}
case "bail":
// Just initialize communications and bail
InitComm()
}
// All done, save the account state
saveAccountState()
}
func InitComm() {
var err error
sec := state.cfg.GetBytes("ClientSecret")
tkn := state.cfg.GetBytes("Token")
state.account, err = GetAccount(sec, tkn)
if err != nil {
log.Fatalf("Unable to get Account: %v", err)
}
// Save the Raw Token
state.cfg.SetBytes("Token", state.account.CC.GetRawToken())
// If the 'defaultCalendars' cfg is set to 'primary' (or not at all)
// we need to actually but the primary cal id in there
var defCal []string
defCal, err = state.cfg.GetArray("defaultCalendars")
if len(defCal) == 0 || (len(defCal) == 1 && defCal[0] == "primary") {
gCal, err := state.account.Service.CalendarList.Get("primary").Do()
if err == nil {
defCal = []string{gCal.Id}
state.cfg.SetArray("defaultCalendars", defCal)
}
}
state.defaultCalendars = defCal
loadAccountState()
}
func DoVersionCheck() {
confVer, _ := state.cfg.GetInt("version")
for confVer < state.Version {
// Update from confVer to state.Version
switch confVer {
case 0: // Initializing the app
fmt.Println("Initializing gocal")
for {
fmt.Println("Client Secret Filename (Ctrl-C to exit): ")
var fn string
if _, err := fmt.Scan(&fn); err == nil {
var b []byte
b, err = ioutil.ReadFile(fn)
if len(b) > 0 && err == nil {
state.cfg.SetBytes("ClientSecret", b)
break
}
}
}
state.cfg.SetInt("version", 1)
state.cfg.SetArray("defaultCalendars", []string{"primary"})
}
state.ClientSecret = state.cfg.GetBytes("ClientSecret")
// Refetch the version from the config
confVer, _ = state.cfg.GetInt("version")
}
}
// saveAccountState saves all the bits of cache from the account
// into our config
func saveAccountState() {
var err error
var calListJson []byte
if calListJson, err = json.Marshal(state.account.CalendarList); err == nil {
if err = state.cfg.SetBytes("calendarList", calListJson); err != nil {
fmt.Println("saveAccountState:calendarList error:", err)
}
if err = state.cfg.SetDateTime("calListUseBy", state.account.CalListUseBy); err != nil {
fmt.Println("saveAccountState:calListUseBy error:", err)
}
}
if err = state.cfg.SetArray("defaultCalendars", state.defaultCalendars); err != nil {
fmt.Println("saveAccountState:defaultCalendars error:", err)
}
}
// loadAccountState loads all the bits of cache from the config
// into the account
func loadAccountState() {
var err error
var calListJson []byte
calListJson = state.cfg.GetBytes("calendarList")
if err = json.Unmarshal(calListJson, &state.account.CalendarList); err == nil {
if len(state.account.CalendarList) > 0 {
if err != nil {
fmt.Println("error: ", err)
}
if state.account.CalListUseBy, err = state.cfg.GetDateTime("calListUseBy"); err != nil {
fmt.Println("error: ", err)
}
}
} else {
fmt.Println("error: ", err)
}
}
// BEGIN CONFIG SCREEN FUNCTIONS //
func DoConfig() {
g, err := gocui.NewGui(gocui.Output256)
if err != nil {
log.Panicln(err)
}
defer g.Close()
g.Cursor = true
g.SetManagerFunc(configLayout)
// Set up some keybindings
if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {
log.Panicln(err)
}
if err := g.SetKeybinding("default_calendars", gocui.KeyArrowUp, gocui.ModNone, cursorUp); err != nil {
log.Panicln(err)
}
if err := g.SetKeybinding("default_calendars", 'k', gocui.ModNone, cursorUp); err != nil {
log.Panicln(err)
}
if err := g.SetKeybinding("default_calendars", gocui.KeyArrowDown, gocui.ModNone, cursorDown); err != nil {
log.Panicln(err)
}
if err := g.SetKeybinding("default_calendars", 'j', gocui.ModNone, cursorDown); err != nil {
log.Panicln(err)
}
if err := g.SetKeybinding("default_calendars", gocui.KeySpace, gocui.ModNone, toggleCalendar); err != nil {
log.Panicln(err)
}
if err := g.SetKeybinding("default_calendars", gocui.KeyEnter, gocui.ModNone, toggleCalendar); err != nil {
log.Panicln(err)
}
// Kick off the main loop
if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
log.Panicln(err)
}
}
func configLayout(g *gocui.Gui) error {
list := state.account.GetCalendarList()
height := len(list) + 4
width, _ := g.Size()
if v, err := g.SetView("default_calendars", 0, 0, width-1, height); err != nil {
v.Highlight = true
v.SelBgColor = gocui.ColorGreen
v.SelFgColor = gocui.ColorBlack
if err != gocui.ErrUnknownView {
return err
}
drawCalList(g, v)
if _, err := g.SetCurrentView("default_calendars"); err != nil {
return err
}
}
return nil
}
func quit(g *gocui.Gui, v *gocui.View) error {
return gocui.ErrQuit
}
func toggleCalendar(g *gocui.Gui, v *gocui.View) error {
_, cy := v.Cursor()
calList := state.account.GetCalendarList()
if v != nil {
for i := range state.defaultCalendars {
state.StatusMsg = time.Now().Format(time.RFC3339)
if state.defaultCalendars[i] == calList[cy].Id {
}
}
}
drawCalList(g, v)
return nil
}
func cursorUp(g *gocui.Gui, v *gocui.View) error {
if v != nil {
ox, oy := v.Origin()
cx, cy := v.Cursor()
if err := v.SetCursor(cx, cy-1); err != nil && oy > 0 {
if err := v.SetOrigin(ox, oy-1); err != nil {
return err
}
}
}
return nil
}
func cursorDown(g *gocui.Gui, v *gocui.View) error {
if v != nil {
cx, cy := v.Cursor()
if err := v.SetCursor(cx, cy+1); err != nil {
ox, oy := v.Origin()
if err := v.SetOrigin(ox, oy+1); err != nil {
return err
}
}
}
return nil
}
func drawCalList(g *gocui.Gui, v *gocui.View) error {
width, _ := g.Size()
list := state.account.GetCalendarList()
for i := range list {
isDef := false
for defIdx := range state.defaultCalendars {
if list[i].Id == state.defaultCalendars[defIdx] {
isDef = true
break
}
}
calSumTxt := "["
if isDef {
calSumTxt += "*"
} else {
calSumTxt += " "
}
calSumTxt += "] " + list[i].Summary
spc := strings.Repeat(" ", width-len(calSumTxt)-2)
fmt.Fprintln(v, calSumTxt+spc)
}
fmt.Fprintln(v, "Status: "+state.StatusMsg)
return nil
}
// END CONFIG SCREEN FUNCTIONS //