init todo buttons, fix delTodo
This commit is contained in:
parent
f4fe3f301d
commit
6a4650cfd2
206
caldav.go
206
caldav.go
@ -11,6 +11,9 @@ import (
|
|||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"time"
|
"time"
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
|
"net/http"
|
||||||
|
// "net/url"
|
||||||
// "fmt"
|
// "fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -339,10 +342,9 @@ func ParseDueDateTODOs(calObjs []caldav.CalendarObject, date time.Time) ([]ical.
|
|||||||
// //TODO UID:7ed30f40-fce1-422c-be3b-0486dcfe8943
|
// //TODO UID:7ed30f40-fce1-422c-be3b-0486dcfe8943
|
||||||
// //TODO RELATED-TO:7ed30f40-fce1-422c-be3b-0486dcfe8943 # subtask
|
// //TODO RELATED-TO:7ed30f40-fce1-422c-be3b-0486dcfe8943 # subtask
|
||||||
// //TODO PRIORITY:1 #1-high, 5-mid, 9-low
|
// //TODO PRIORITY:1 #1-high, 5-mid, 9-low
|
||||||
//TODO repeat function???
|
//TODO on complete -repeat function
|
||||||
|
//TODO repeate - RRULE:FREQ=DAILY;INTERVAL=1
|
||||||
//TODO on complete -repeat function
|
// RRULE:FREQ=WEEKLY;INTERVAL=1
|
||||||
// RRULE:FREQ=WEEKLY;INTERVAL=1
|
|
||||||
|
|
||||||
//TODO if no repeat - mark as complted
|
//TODO if no repeat - mark as complted
|
||||||
// STATUS:COMPLETED
|
// STATUS:COMPLETED
|
||||||
@ -376,40 +378,88 @@ func ParseDueDateTODOs(calObjs []caldav.CalendarObject, date time.Time) ([]ical.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
// type todoInterface struct {
|
type TodoInterface struct {
|
||||||
// name string
|
name string
|
||||||
// description string
|
description string
|
||||||
// priority int
|
priority int
|
||||||
// dueTime time.Time
|
dueTime time.Time
|
||||||
// name string
|
alarmOffset string
|
||||||
// }
|
repeat string
|
||||||
|
//TODO repeat
|
||||||
|
//TODO subtasks
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
func CreateTodo(name,description string, priority int, dueTime time.Time) (event ical.Event,err error) {
|
func CreateTodo(info TodoInterface) (event ical.Event,err error) {
|
||||||
uid, err := uuid.NewUUID()
|
uid, err := uuid.NewUUID()
|
||||||
if err != nil {return}
|
if err != nil {return}
|
||||||
event = *ical.NewEvent()
|
event = *ical.NewEvent()
|
||||||
|
event.Name = ical.CompToDo //VTODO
|
||||||
event.Props.SetText(ical.PropUID, uid.String())
|
event.Props.SetText(ical.PropUID, uid.String())
|
||||||
event.Props.SetText(ical.PropSummary, name)
|
event.Props.SetText(ical.PropSummary, info.name)
|
||||||
event.Props.SetText(ical.PropDescription, description)
|
event.Props.SetText(ical.PropDescription, info.description)
|
||||||
if !dueTime.IsZero() {event.Props.SetDateTime(ical.PropDateTimeEnd, dueTime)} // 'zero' time is `time.Time{}`
|
if !info.dueTime.IsZero() {event.Props.SetDateTime(ical.PropDue, info.dueTime)} // 'zero' time is `time.Time{}`
|
||||||
switch priority {
|
//TODO add alarm
|
||||||
|
switch info.priority {
|
||||||
case 0: //No priority
|
case 0: //No priority
|
||||||
event.Props.SetText(ical.PropPriority, "0")
|
event.Props.SetText(ical.PropPriority, "0")
|
||||||
case 1: //Light
|
case 1: //Light
|
||||||
event.Props.SetText(ical.PropPriority, "1")
|
event.Props.SetText(ical.PropPriority, "9")
|
||||||
case 2: //Medium
|
case 2: //Medium
|
||||||
event.Props.SetText(ical.PropPriority, "5")
|
event.Props.SetText(ical.PropPriority, "5")
|
||||||
case 3: //Urgent
|
case 3: //Urgent
|
||||||
event.Props.SetText(ical.PropPriority, "9")
|
event.Props.SetText(ical.PropPriority, "1")
|
||||||
default:
|
default:
|
||||||
err = errors.New("Wrong priority, expecting 0-3")
|
err = errors.New("Wrong priority, expecting 0-3")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
//TODO repeat - RRULE:FREQ=DAILY;INTERVAL=1
|
||||||
|
if info.alarmOffset != "" {
|
||||||
|
|
||||||
|
// alarmComponent := ical.Component{Name:ical.CompAlarm}
|
||||||
|
alarmComponent := ical.NewComponent(ical.CompAlarm)
|
||||||
|
|
||||||
|
|
||||||
|
alarmComponent.Props.SetText(ical.PropAction,"DISPLAY")
|
||||||
|
// alarmComponent.Props.Add(&ical.Prop{Name:ical.PropAction,Value:"DISPLAY",})
|
||||||
|
alarmComponent.Props.Add(&ical.Prop{Name:ical.PropDescription,Value:"Default Alarm Tempus description",})
|
||||||
|
alarmComponent.Props.SetText(ical.PropDescription,"Default Alarm Tempus description")
|
||||||
|
// ACTION:DISPLAY
|
||||||
|
// DESCRIPTION:Default Tasks.org description
|
||||||
|
var value string
|
||||||
|
if info.alarmOffset == "0" {
|
||||||
|
// TRIGGER;RELATED=END:PT0S
|
||||||
|
value = "PT0S"
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.HasSuffix(info.alarmOffset,"h") {
|
||||||
|
offset,_ := strings.CutSuffix(info.alarmOffset,"h")
|
||||||
|
value="-PT" + offset + "H"
|
||||||
|
// TRIGGER;RELATED=END:-PT1H
|
||||||
|
|
||||||
|
}
|
||||||
|
//TODO stop next if
|
||||||
|
if strings.HasSuffix(info.alarmOffset,"m") {
|
||||||
|
offset,_ := strings.CutSuffix(info.alarmOffset,"m")
|
||||||
|
value="-PT" + offset + "M"
|
||||||
|
// TRIGGER;RELATED=END:-PT10M
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.HasSuffix(info.alarmOffset,"d") {
|
||||||
|
offset,_ := strings.CutSuffix(info.alarmOffset,"d")
|
||||||
|
value="-P" + offset + "D"
|
||||||
|
// TRIGGER;RELATED=END:-P1D
|
||||||
|
}
|
||||||
|
alarmComponent.Props.SetText("TRIGGER;RELATED=END",value)
|
||||||
|
event.Children = append(event.Children,alarmComponent)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
event.Props.SetDateTime(ical.PropDateTimeStamp, time.Now().UTC())
|
event.Props.SetDateTime(ical.PropDateTimeStamp, time.Now().UTC())
|
||||||
event.Props.SetDateTime(ical.PropCreated, time.Now().UTC()) //TODO if it don't exist already (in case if we edit todo)
|
event.Props.SetDateTime(ical.PropCreated, time.Now().UTC()) //TODO if it don't exist already (in case if we edit todo)
|
||||||
event.Props.SetDateTime(ical.PropLastModified, time.Now().UTC())
|
event.Props.SetDateTime(ical.PropLastModified, time.Now().UTC())
|
||||||
|
//TODO add a function to verify event (exist in ical lib)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -417,54 +467,102 @@ func CreateTodo(name,description string, priority int, dueTime time.Time) (event
|
|||||||
|
|
||||||
func (m model) UploadTodo(event ical.Event) (err error) {
|
func (m model) UploadTodo(event ical.Event) (err error) {
|
||||||
// event.Props.SetDateTime(ical.PropDateTimeStart, startDateTime)
|
// event.Props.SetDateTime(ical.PropDateTimeStart, startDateTime)
|
||||||
//TODO PropPriority = "PRIORITY"
|
|
||||||
// TODO Alarm component properties
|
// TODO Alarm component properties
|
||||||
// PropAction = "ACTION"
|
// PropAction = "ACTION"
|
||||||
// PropRepeat = "REPEAT"
|
// PropRepeat = "REPEAT"
|
||||||
// PropTrigger = "TRIGGER"}
|
// PropTrigger = "TRIGGER"}
|
||||||
|
|
||||||
calendar, err := client.GetCalendarObject(ctx, m.Creds.CalendarPath)
|
// calendar, err := client.GetCalendarObject(ctx, m.Creds.CalendarPath) //makes error on nextcloud
|
||||||
if err != nil {return}
|
// if err != nil {return err}
|
||||||
calendar.Data.Component.Children = append(calendar.Data.Component.Children, event.Component)
|
|
||||||
var buf strings.Builder
|
calendar := ical.NewCalendar()
|
||||||
encoder := ical.NewEncoder(&buf)
|
calendar.Props.SetText(ical.PropProductID, "+//Casual//Tempus//EN")
|
||||||
err = encoder.Encode(calendar.Data)
|
calendar.Props.SetText(ical.PropVersion, "2.0")
|
||||||
if err != nil {return}
|
calendar.Component.Children = append(calendar.Component.Children, event.Component)
|
||||||
_, err = client.PutCalendarObject(ctx, m.Creds.CalendarPath, calendar.Data)
|
|
||||||
if err != nil {return}
|
todoGUID,err := event.Props.Get(ical.PropUID).Text()
|
||||||
return nil
|
if err != nil {return err}
|
||||||
|
//TODO check GUID uniq and regenerate if needed
|
||||||
|
|
||||||
|
var buf strings.Builder
|
||||||
|
encoder := ical.NewEncoder(&buf)
|
||||||
|
err = encoder.Encode(calendar)
|
||||||
|
if err != nil {return err}
|
||||||
|
_, err = client.PutCalendarObject(ctx, m.Creds.CalendarPath+todoGUID+".isc", calendar)
|
||||||
|
if err != nil {return err}
|
||||||
|
return nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (m model) DelTodo(todo ical.Event) (err error) {
|
func (m model) DelTodo(delUID string) (err error) {
|
||||||
|
// func (m model) DelTodo(todo ical.Event) (err error) {
|
||||||
|
|
||||||
delUID,err := todo.Props.Get(ical.PropUID).Text()
|
// delUID,err := todo.Props.Get(ical.PropUID).Text()
|
||||||
if err != nil {return}
|
// if err != nil {return}
|
||||||
|
|
||||||
calendar, err := client.GetCalendarObject(ctx, m.Creds.CalendarPath)
|
// calendar, err := client.GetCalendarObject(ctx, m.Creds.CalendarPath+delUID+".isc")
|
||||||
if err != nil {return}
|
// if err != nil {return}
|
||||||
|
//
|
||||||
|
// var newEvents []*ical.Component
|
||||||
|
// for _, component := range calendar.Data.Component.Children {
|
||||||
|
// if component.Name == ical.CompEvent {
|
||||||
|
// var uid string
|
||||||
|
// uid, err = component.Props.Text(ical.PropUID)
|
||||||
|
// if err != nil {return}
|
||||||
|
// if uid != delUID {
|
||||||
|
// newEvents = append(newEvents, component)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// calendar.Data.Component.Children = newEvents
|
||||||
|
// var buf strings.Builder
|
||||||
|
// encoder := ical.NewEncoder(&buf)
|
||||||
|
// err = encoder.Encode(calendar.Data)
|
||||||
|
// if err != nil {return}
|
||||||
|
//
|
||||||
|
// _, err = client.PutCalendarObject(ctx, m.Creds.CalendarPath, calendar.Data)
|
||||||
|
// if err != nil {return}
|
||||||
|
|
||||||
var newEvents []*ical.Component
|
// req := http.Request{
|
||||||
for _, component := range calendar.Data.Component.Children {
|
// Method: "DELETE",
|
||||||
if component.Name == ical.CompEvent {
|
// URL: url.Parse(m.Creds.URL + m.Creds.CalendarPath + delUID + ".isc"),
|
||||||
var uid string
|
//
|
||||||
uid, err = component.Props.Text(ical.PropUID)
|
// }
|
||||||
if err != nil {return}
|
client := &http.Client{}
|
||||||
if uid != delUID {
|
|
||||||
newEvents = append(newEvents, component)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
calendar.Data.Component.Children = newEvents
|
parts := strings.Split(m.Creds.URL, "/")
|
||||||
var buf strings.Builder
|
baseURL := parts[0]+"//"+parts[2]
|
||||||
encoder := ical.NewEncoder(&buf)
|
// Create request
|
||||||
err = encoder.Encode(calendar.Data)
|
req, err := http.NewRequest("DELETE", baseURL + m.Creds.CalendarPath + delUID + ".isc", nil)
|
||||||
if err != nil {return}
|
if err != nil {
|
||||||
|
// fmt.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
req.SetBasicAuth(m.Creds.Username, m.Creds.Password)
|
||||||
|
|
||||||
_, err = client.PutCalendarObject(ctx, m.Creds.CalendarPath, calendar.Data)
|
// Fetch Request
|
||||||
if err != nil {return}
|
resp, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
// fmt.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
// Read Response Body
|
||||||
|
// respBody, err := ioutil.ReadAll(resp.Body)
|
||||||
|
// if err != nil {
|
||||||
|
// // fmt.Println(err)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
|
if resp.Status != "204 No Content" {return errors.New("Can't delete, response status: "+resp.Status+".")}
|
||||||
|
// Display Results
|
||||||
|
// fmt.Println("response Status : ", resp.Status)
|
||||||
|
// fmt.Println("response Headers : ", resp.Header)
|
||||||
|
// fmt.Println("response Body : ", string(respBody))
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -472,8 +570,10 @@ func (m model) DelTodo(todo ical.Event) (err error) {
|
|||||||
|
|
||||||
func (m model) EditTodo(todo ical.Event) (err error) {
|
func (m model) EditTodo(todo ical.Event) (err error) {
|
||||||
//TODO is there proper edit function ???
|
//TODO is there proper edit function ???
|
||||||
|
uid,err := todo.Props.Get(ical.PropUID).Text()
|
||||||
|
if err != nil {return}
|
||||||
|
|
||||||
err = m.DelTodo(todo)
|
err = m.DelTodo(uid)
|
||||||
if err != nil {return}
|
if err != nil {return}
|
||||||
|
|
||||||
err = m.UploadTodo(todo)
|
err = m.UploadTodo(todo)
|
||||||
|
13
main.go
13
main.go
@ -3,6 +3,8 @@ package main
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"net/http"
|
||||||
|
"crypto/tls"
|
||||||
// "sync"
|
// "sync"
|
||||||
// "time"
|
// "time"
|
||||||
|
|
||||||
@ -26,6 +28,7 @@ func errHandler(err error, message string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
|
||||||
options, err := ParseOptions()
|
options, err := ParseOptions()
|
||||||
errHandler(err, "Error parsing options")
|
errHandler(err, "Error parsing options")
|
||||||
m := InitModel()
|
m := InitModel()
|
||||||
@ -61,6 +64,11 @@ func main() {
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
m.LoginToCalendar()
|
||||||
|
m.GatherTodos()
|
||||||
|
|
||||||
|
|
||||||
// calendarObjects, err := GetTODOs(calPath)
|
// calendarObjects, err := GetTODOs(calPath)
|
||||||
// errHandler(err, "Error getting TODOs")
|
// errHandler(err, "Error getting TODOs")
|
||||||
//
|
//
|
||||||
@ -142,7 +150,10 @@ func main() {
|
|||||||
|
|
||||||
|
|
||||||
//DEBUG stuff
|
//DEBUG stuff
|
||||||
|
// task, err := CreateTodo("testName","description",3,time.Now())
|
||||||
|
// errHandler(err,"test fail")
|
||||||
|
// err = m.UploadTodo(task)
|
||||||
|
// errHandler(err,"test fail2")
|
||||||
//DEBUG stuff
|
//DEBUG stuff
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"os"
|
||||||
"errors"
|
"errors"
|
||||||
"github.com/projectdiscovery/goflags"
|
"github.com/projectdiscovery/goflags"
|
||||||
"sync"
|
"sync"
|
||||||
@ -18,6 +19,8 @@ type Options struct {
|
|||||||
|
|
||||||
User string
|
User string
|
||||||
Password string
|
Password string
|
||||||
|
|
||||||
|
Proxy string
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseOptions() (*Options, error) {
|
func ParseOptions() (*Options, error) {
|
||||||
@ -39,6 +42,7 @@ func ParseOptions() (*Options, error) {
|
|||||||
flagSet.StringVarP(&options.User, "l", "login", "", "WebDAV login username"),
|
flagSet.StringVarP(&options.User, "l", "login", "", "WebDAV login username"),
|
||||||
flagSet.StringVarP(&options.Password, "p", "password", "", "WebDAV password (forbid filesystem access in WebDAV and don't forget to clean shell history!)"),
|
flagSet.StringVarP(&options.Password, "p", "password", "", "WebDAV password (forbid filesystem access in WebDAV and don't forget to clean shell history!)"),
|
||||||
flagSet.StringVarP(&options.Calendar, "c", "calendar", "", "CalDAV calendar (to-do list) name to use (works only with -u,-l,-p flags)"),
|
flagSet.StringVarP(&options.Calendar, "c", "calendar", "", "CalDAV calendar (to-do list) name to use (works only with -u,-l,-p flags)"),
|
||||||
|
flagSet.StringVarP(&options.Proxy, "P", "proxy", "", "HTTP proxy to debug errors"),
|
||||||
// flagSet.BoolVarP(&options.SkipSave, "s", "no-save", false, "skip save to keyring"), //TODO
|
// flagSet.BoolVarP(&options.SkipSave, "s", "no-save", false, "skip save to keyring"), //TODO
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -64,5 +68,8 @@ func (options *Options) SanityCheck() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if options.Proxy != "" {os.Setenv("HTTP_PROXY", options.Proxy)}
|
||||||
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
95
tui-todo-keys.go
Normal file
95
tui-todo-keys.go
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
|
||||||
|
// "github.com/emersion/go-ical"
|
||||||
|
// "time"
|
||||||
|
"github.com/charmbracelet/bubbles/list"
|
||||||
|
"github.com/charmbracelet/bubbles/key"
|
||||||
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
|
"github.com/charmbracelet/lipgloss"
|
||||||
|
// "strings"
|
||||||
|
// "errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
appStyle = lipgloss.NewStyle().Padding(1, 2)
|
||||||
|
|
||||||
|
// titleStyle = lipgloss.NewStyle().
|
||||||
|
// Foreground(lipgloss.Color("#FFFDF5")).
|
||||||
|
// Background(lipgloss.Color("#25A065")).
|
||||||
|
// Padding(0, 1)
|
||||||
|
|
||||||
|
statusMessageStyle = lipgloss.NewStyle().
|
||||||
|
Foreground(lipgloss.AdaptiveColor{Light: "#04B575", Dark: "#04B575"}).
|
||||||
|
Render
|
||||||
|
)
|
||||||
|
|
||||||
|
// buttons
|
||||||
|
func (m model) newItemDelegate(keys *delegateKeyMap) list.DefaultDelegate {
|
||||||
|
d := list.NewDefaultDelegate()
|
||||||
|
|
||||||
|
d.UpdateFunc = func(msg tea.Msg, ml *list.Model) tea.Cmd {
|
||||||
|
var title string
|
||||||
|
var todoUID string
|
||||||
|
|
||||||
|
if i, ok := ml.SelectedItem().(TODO); ok {
|
||||||
|
title = i.Title()
|
||||||
|
todoUID = i.UID()
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch msg := msg.(type) {
|
||||||
|
case tea.KeyMsg:
|
||||||
|
switch {
|
||||||
|
case key.Matches(msg, keys.choose):
|
||||||
|
return ml.NewStatusMessage(statusMessageStyle("You chose " + title))
|
||||||
|
|
||||||
|
case key.Matches(msg, keys.remove):
|
||||||
|
err := m.DelTodo(todoUID)
|
||||||
|
if err != nil {return errHandler_tui(err,"can't delete item")}
|
||||||
|
index := ml.Index()
|
||||||
|
ml.RemoveItem(index)
|
||||||
|
if len(ml.Items()) == 0 {
|
||||||
|
keys.remove.SetEnabled(false)
|
||||||
|
}
|
||||||
|
return ml.NewStatusMessage(statusMessageStyle("Deleted " + title))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
help := []key.Binding{keys.choose, keys.remove}
|
||||||
|
|
||||||
|
d.ShortHelpFunc = func() []key.Binding {
|
||||||
|
return help
|
||||||
|
}
|
||||||
|
|
||||||
|
d.FullHelpFunc = func() [][]key.Binding {
|
||||||
|
return [][]key.Binding{help}
|
||||||
|
}
|
||||||
|
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type delegateKeyMap struct {
|
||||||
|
choose key.Binding
|
||||||
|
remove key.Binding
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func newDelegateKeyMap() *delegateKeyMap {
|
||||||
|
return &delegateKeyMap{
|
||||||
|
choose: key.NewBinding(
|
||||||
|
key.WithKeys("enter"),
|
||||||
|
key.WithHelp("enter", "choose"),
|
||||||
|
),
|
||||||
|
remove: key.NewBinding(
|
||||||
|
key.WithKeys("x", "backspace"),
|
||||||
|
key.WithHelp("x", "delete"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
34
tui-todo.go
34
tui-todo.go
@ -5,6 +5,8 @@ import (
|
|||||||
"github.com/emersion/go-ical"
|
"github.com/emersion/go-ical"
|
||||||
"time"
|
"time"
|
||||||
"github.com/charmbracelet/bubbles/list"
|
"github.com/charmbracelet/bubbles/list"
|
||||||
|
"strings"
|
||||||
|
"errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -15,6 +17,11 @@ func (i TODO) Title() string {
|
|||||||
if err != nil {return "<EMPTY>"}
|
if err != nil {return "<EMPTY>"}
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
func (i TODO) UID() string {
|
||||||
|
out,err := i.Props.Get(ical.PropUID).Text()
|
||||||
|
if err != nil {return "<EMPTY>"}
|
||||||
|
return out
|
||||||
|
}
|
||||||
func (i TODO) Description() string {
|
func (i TODO) Description() string {
|
||||||
out,err := i.Props.Get(ical.PropDescription).Text()
|
out,err := i.Props.Get(ical.PropDescription).Text()
|
||||||
if err != nil {return ""}
|
if err != nil {return ""}
|
||||||
@ -29,6 +36,9 @@ func (i TODO) FilterValue() string {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
func (m *model) GatherTodos() (err error) {
|
func (m *model) GatherTodos() (err error) {
|
||||||
//TODO more modular approach
|
//TODO more modular approach
|
||||||
calendarObjects, err := GetTODOs(m.Creds.CalendarPath)
|
calendarObjects, err := GetTODOs(m.Creds.CalendarPath)
|
||||||
@ -64,10 +74,30 @@ func (m *model) GatherTodos() (err error) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
m.TodayTab = list.New(itemsToday, list.NewDefaultDelegate(), 0, 0)
|
delegateKeys := newDelegateKeyMap()
|
||||||
|
delegate := m.newItemDelegate(delegateKeys)
|
||||||
|
// m.TodayTab = list.New(itemsToday, list.NewDefaultDelegate(), 0, 0)
|
||||||
|
m.TodayTab = list.New(itemsToday, delegate, 0, 0)
|
||||||
m.TodayTab.Title = "Today"
|
m.TodayTab.Title = "Today"
|
||||||
m.TomorrowTab = list.New(itemsTomorrow, list.NewDefaultDelegate(), 0, 0)
|
// m.TomorrowTab = list.New(itemsTomorrow, list.NewDefaultDelegate(), 0, 0)
|
||||||
|
m.TomorrowTab = list.New(itemsTomorrow, delegate, 0, 0)
|
||||||
m.TomorrowTab.Title = "Tomorrow"
|
m.TomorrowTab.Title = "Tomorrow"
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func (m *model) UpdateTodos(todo ical.Event) (err error) {
|
||||||
|
today := time.Now()
|
||||||
|
tomorrow := time.Now().AddDate(0, 0, 1)
|
||||||
|
errorI := 0
|
||||||
|
if strings.HasPrefix(todo.Props["DUE"][0].Value, today.Format("20060102")) {m.TodayTab.InsertItem(-1,TODO(todo))} else {errorI += 1}
|
||||||
|
if strings.HasPrefix(todo.Props["DUE"][0].Value, tomorrow.Format("20060102")) {m.TomorrowTab.InsertItem(-1,TODO(todo)) } else {errorI += 1}
|
||||||
|
|
||||||
|
if errorI == 2 {return errors.New("don't match today and tomorrow")}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
135
tui.go
135
tui.go
@ -3,7 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
// "fmt"
|
// "fmt"
|
||||||
// "os"
|
// "os"
|
||||||
// "time"
|
"time"
|
||||||
// "io"
|
// "io"
|
||||||
// "strings"
|
// "strings"
|
||||||
|
|
||||||
@ -33,7 +33,20 @@ import (
|
|||||||
|
|
||||||
type errMsg struct {message string}
|
type errMsg struct {message string}
|
||||||
|
|
||||||
func (m model) errHandler(desc string,err error) (tea.Cmd) {
|
|
||||||
|
//TODO fix multiple errHandlers
|
||||||
|
//TODO rm me
|
||||||
|
func (m model) errHandler(err error,desc string) (tea.Cmd) {
|
||||||
|
if err != nil {
|
||||||
|
output := desc+": "+err.Error()
|
||||||
|
return func() tea.Msg { return errMsg{output} }
|
||||||
|
// return errMsg{output}
|
||||||
|
// m.Send(output)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func errHandler_tui(err error,desc string) (tea.Cmd) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
output := desc+": "+err.Error()
|
output := desc+": "+err.Error()
|
||||||
return func() tea.Msg { return errMsg{output} }
|
return func() tea.Msg { return errMsg{output} }
|
||||||
@ -46,34 +59,46 @@ func (m model) errHandler(desc string,err error) (tea.Cmd) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
func (m model) Init() tea.Cmd {
|
func (m model) Init() tea.Cmd {
|
||||||
return textinput.Blink
|
return textinput.Blink
|
||||||
// return nil
|
// return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//TODO add changing calendar
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
//TODO separate to funcs
|
//TODO separate to funcs
|
||||||
var cmd tea.Cmd
|
var cmd tea.Cmd
|
||||||
switch msg := msg.(type) {
|
switch msg := msg.(type) {
|
||||||
case tea.KeyMsg:
|
case tea.KeyMsg:
|
||||||
if m.ActiveWindow == "calendarChoose" {
|
switch m.ActiveWindow {
|
||||||
|
case "today": //TODO rm me debug
|
||||||
|
switch keypress := msg.String(); keypress {
|
||||||
|
case "q", "ctrl+c":
|
||||||
|
// m.quitting = true
|
||||||
|
return m, tea.Quit
|
||||||
|
|
||||||
|
case "y":
|
||||||
|
// m."2797322749061742597"
|
||||||
|
case "h":
|
||||||
|
|
||||||
|
todoInfo := TodoInterface{
|
||||||
|
name: "testName1",
|
||||||
|
description: "description",
|
||||||
|
priority: 3,
|
||||||
|
dueTime: time.Now(),
|
||||||
|
alarmOffset: "1h",
|
||||||
|
}
|
||||||
|
task, err := CreateTodo(todoInfo)
|
||||||
|
if err != nil {return m, m.errHandler(err,"test fail")}
|
||||||
|
err = m.UploadTodo(task)
|
||||||
|
if err != nil {return m, m.errHandler(err,"test fail2")}
|
||||||
|
m.UpdateTodos(task)
|
||||||
|
// fmt.Println(&task)
|
||||||
|
// fmt.Println(err)
|
||||||
|
// time.Sleep(2*time.Second)
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
case "calendarChoose":
|
||||||
switch keypress := msg.String(); keypress {
|
switch keypress := msg.String(); keypress {
|
||||||
case "q", "ctrl+c":
|
case "q", "ctrl+c":
|
||||||
// m.quitting = true
|
// m.quitting = true
|
||||||
@ -91,48 +116,48 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
err := m.CredentialsSave()
|
err := m.CredentialsSave()
|
||||||
if err != nil { return m, m.errHandler("Failed to save credentials",err)}
|
if err != nil { return m, m.errHandler(err,"Failed to save credentials")}
|
||||||
m.CalendarToTodo()
|
m.CalendarToTodo()
|
||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if m.ActiveWindow == "login" {
|
|
||||||
switch keypress := msg.String(); keypress {
|
|
||||||
case "ctrl+c", "q":
|
|
||||||
return m, tea.Quit
|
|
||||||
case "enter":
|
|
||||||
if m.focused == len(m.loginInputs)-1 {
|
|
||||||
//TODO check that we have all fields not empty and notificate about it
|
|
||||||
//TODO submit
|
|
||||||
for i := range m.loginInputs {
|
|
||||||
m.loginInputs[i], cmd = m.loginInputs[i].Update(msg)
|
|
||||||
}
|
|
||||||
// fmt.Println(m.loginInputs[url].Value())//DEBUG
|
|
||||||
m.Creds.URL = m.loginInputs[url].Value()
|
|
||||||
m.Creds.Username = m.loginInputs[login].Value()
|
|
||||||
m.Creds.Password = m.loginInputs[pass].Value()
|
|
||||||
// fmt.Println(m.Creds.URL)//DEBUG
|
|
||||||
|
|
||||||
// time.Sleep(1 * time.Second) ///DEBUG
|
case "login":
|
||||||
// m.Creds.
|
switch keypress := msg.String(); keypress {
|
||||||
// return m, nil
|
case "ctrl+c", "q":
|
||||||
err := m.LoginToCalendar()
|
return m, tea.Quit
|
||||||
if err != nil {return m, m.errHandler("Failed to authenticate",err)}
|
case "enter":
|
||||||
// try login -> choose calendar -> store -> move to getting stuff
|
if m.focused == len(m.loginInputs)-1 {
|
||||||
return m, nil
|
//TODO check that we have all fields not empty and notificate about it
|
||||||
// return m, tea.Quit
|
//TODO submit
|
||||||
|
for i := range m.loginInputs {
|
||||||
|
m.loginInputs[i], cmd = m.loginInputs[i].Update(msg)
|
||||||
|
}
|
||||||
|
// fmt.Println(m.loginInputs[url].Value())//DEBUG
|
||||||
|
m.Creds.URL = m.loginInputs[url].Value()
|
||||||
|
m.Creds.Username = m.loginInputs[login].Value()
|
||||||
|
m.Creds.Password = m.loginInputs[pass].Value()
|
||||||
|
// fmt.Println(m.Creds.URL)//DEBUG
|
||||||
|
|
||||||
|
// time.Sleep(1 * time.Second) ///DEBUG
|
||||||
|
// m.Creds.
|
||||||
|
// return m, nil
|
||||||
|
err := m.LoginToCalendar()
|
||||||
|
if err != nil {return m, m.errHandler(err,"Failed to authenticate")}
|
||||||
|
// try login -> choose calendar -> store -> move to getting stuff
|
||||||
|
return m, nil
|
||||||
|
// return m, tea.Quit
|
||||||
|
}
|
||||||
|
m.nextInput()
|
||||||
|
case "shift+tab", "up":
|
||||||
|
m.prevInput()
|
||||||
|
case "tab", "down":
|
||||||
|
m.nextInput()
|
||||||
}
|
}
|
||||||
m.nextInput()
|
for i := range m.loginInputs {
|
||||||
case "shift+tab", "up":
|
m.loginInputs[i].Blur()
|
||||||
m.prevInput()
|
}
|
||||||
case "tab", "down":
|
m.loginInputs[m.focused].Focus()
|
||||||
m.nextInput()
|
|
||||||
}
|
|
||||||
for i := range m.loginInputs {
|
|
||||||
m.loginInputs[i].Blur()
|
|
||||||
}
|
|
||||||
m.loginInputs[m.focused].Focus()
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user