2024-06-21 18:38:41 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2024-06-29 01:00:39 +00:00
|
|
|
// "fmt"
|
2024-06-21 18:38:41 +00:00
|
|
|
// "os"
|
2024-07-10 01:35:14 +00:00
|
|
|
// "time"
|
2024-06-29 01:00:39 +00:00
|
|
|
// "io"
|
2024-06-21 18:38:41 +00:00
|
|
|
// "strings"
|
|
|
|
|
2024-06-29 01:00:39 +00:00
|
|
|
// "github.com/charmbracelet/bubbles/list"
|
2024-06-21 18:38:41 +00:00
|
|
|
"github.com/charmbracelet/bubbles/textinput"
|
|
|
|
// textblink "github.com/charmbracelet/bubbles/textinput"
|
|
|
|
// "github.com/erikgeiser/promptkit/textinput"
|
|
|
|
tea "github.com/charmbracelet/bubbletea"
|
2024-06-29 01:00:39 +00:00
|
|
|
// "github.com/charmbracelet/lipgloss"
|
2024-06-21 18:38:41 +00:00
|
|
|
"golang.org/x/term"
|
2024-06-29 01:00:39 +00:00
|
|
|
|
|
|
|
// "github.com/emersion/go-ical"
|
|
|
|
// "github.com/emersion/go-webdav/caldav"
|
|
|
|
|
|
|
|
// "errors"
|
2024-06-21 18:38:41 +00:00
|
|
|
)
|
2024-07-10 01:35:14 +00:00
|
|
|
//TODO NEW FEATURE IMPORTANT - list today/tomorrow - edit TODOs
|
|
|
|
//TODO NEW FEATURE - add search
|
|
|
|
//TODO NEW FEATURE - add custom filter (search that saves with filter)
|
|
|
|
// TODO NEW FEATURE - add tabs for days/searcf/filter?
|
2024-06-21 18:38:41 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2024-06-29 01:00:39 +00:00
|
|
|
type errMsg struct {message string}
|
|
|
|
|
2024-07-02 09:17:21 +00:00
|
|
|
|
2024-07-10 01:35:14 +00:00
|
|
|
//TODO fix multiple errHandlers, rm m.errHandler, rename CLI errHandler (in main.go). rename errHandler_tui to errHandler. Rename ebery call
|
2024-07-02 09:17:21 +00:00
|
|
|
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) {
|
2024-06-29 01:00:39 +00:00
|
|
|
if err != nil {
|
|
|
|
output := desc+": "+err.Error()
|
|
|
|
return func() tea.Msg { return errMsg{output} }
|
|
|
|
// return errMsg{output}
|
|
|
|
// m.Send(output)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
2024-06-21 18:38:41 +00:00
|
|
|
}
|
2024-06-29 01:00:39 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
2024-06-21 18:38:41 +00:00
|
|
|
func (m model) Init() tea.Cmd {
|
|
|
|
return textinput.Blink
|
|
|
|
// return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-06-29 01:00:39 +00:00
|
|
|
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|
|
|
//TODO separate to funcs
|
|
|
|
var cmd tea.Cmd
|
2024-06-21 18:38:41 +00:00
|
|
|
switch msg := msg.(type) {
|
|
|
|
case tea.KeyMsg:
|
2024-07-02 09:17:21 +00:00
|
|
|
switch m.ActiveWindow {
|
2024-07-10 01:35:14 +00:00
|
|
|
case "tomorrow": //TODO rm me debug
|
|
|
|
case "a":
|
|
|
|
m.ActiveWindow = "addTODO"
|
|
|
|
return m, nil
|
2024-07-02 09:17:21 +00:00
|
|
|
case "today": //TODO rm me debug
|
|
|
|
switch keypress := msg.String(); keypress {
|
|
|
|
case "q", "ctrl+c":
|
|
|
|
// m.quitting = true
|
|
|
|
return m, tea.Quit
|
2024-07-10 01:35:14 +00:00
|
|
|
case "a":
|
|
|
|
m.ActiveWindow = "addTODO"
|
|
|
|
return m, nil
|
2024-07-02 09:17:21 +00:00
|
|
|
|
2024-07-10 01:35:14 +00:00
|
|
|
// case "y":
|
2024-07-02 09:17:21 +00:00
|
|
|
// m."2797322749061742597"
|
2024-07-10 01:35:14 +00:00
|
|
|
// 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
|
2024-07-02 09:17:21 +00:00
|
|
|
}
|
|
|
|
case "calendarChoose":
|
2024-06-21 18:38:41 +00:00
|
|
|
switch keypress := msg.String(); keypress {
|
2024-06-29 01:00:39 +00:00
|
|
|
case "q", "ctrl+c":
|
|
|
|
// m.quitting = true
|
2024-06-21 18:38:41 +00:00
|
|
|
return m, tea.Quit
|
2024-06-29 01:00:39 +00:00
|
|
|
|
|
|
|
case "enter":
|
|
|
|
i, ok := m.calendarList.SelectedItem().(item)
|
|
|
|
if ok {
|
|
|
|
m.calendarChoice = string(i) //TODO remove from model - calendarChoice
|
|
|
|
}
|
|
|
|
for _,calendar := range m.Calendars {
|
|
|
|
if calendar.Name == m.calendarChoice {
|
|
|
|
m.Creds.CalendarPath = calendar.Path
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
err := m.CredentialsSave()
|
2024-07-02 09:17:21 +00:00
|
|
|
if err != nil { return m, m.errHandler(err,"Failed to save credentials")}
|
2024-06-29 01:00:39 +00:00
|
|
|
m.CalendarToTodo()
|
|
|
|
return m, nil
|
2024-06-21 18:38:41 +00:00
|
|
|
}
|
2024-06-29 01:00:39 +00:00
|
|
|
|
2024-07-02 09:17:21 +00:00
|
|
|
|
|
|
|
case "login":
|
|
|
|
switch keypress := msg.String(); keypress {
|
2024-07-10 01:35:14 +00:00
|
|
|
// case "ctrl+c", "q"://are you stupid?
|
|
|
|
// return m, tea.Quit
|
2024-07-02 09:17:21 +00:00
|
|
|
case "enter":
|
|
|
|
if m.focused == len(m.loginInputs)-1 {
|
|
|
|
//TODO check that we have all fields not empty and notificate about it
|
|
|
|
for i := range m.loginInputs {
|
|
|
|
m.loginInputs[i], cmd = m.loginInputs[i].Update(msg)
|
|
|
|
}
|
|
|
|
m.Creds.URL = m.loginInputs[url].Value()
|
|
|
|
m.Creds.Username = m.loginInputs[login].Value()
|
|
|
|
m.Creds.Password = m.loginInputs[pass].Value()
|
2024-07-10 01:35:14 +00:00
|
|
|
|
2024-07-02 09:17:21 +00:00
|
|
|
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
|
|
|
|
}
|
2024-07-10 01:35:14 +00:00
|
|
|
m.nextLoginInput()
|
2024-07-02 09:17:21 +00:00
|
|
|
case "shift+tab", "up":
|
2024-07-10 01:35:14 +00:00
|
|
|
// buttonStyle = lipgloss.NewStyle()
|
|
|
|
m.prevLoginInput()
|
2024-07-02 09:17:21 +00:00
|
|
|
case "tab", "down":
|
2024-07-10 01:35:14 +00:00
|
|
|
// buttonStyle = buttonStyle.Background(lipgloss.Color("#7D56F4"))
|
|
|
|
m.nextLoginInput()
|
2024-06-21 18:38:41 +00:00
|
|
|
}
|
2024-07-02 09:17:21 +00:00
|
|
|
for i := range m.loginInputs {
|
|
|
|
m.loginInputs[i].Blur()
|
|
|
|
}
|
|
|
|
m.loginInputs[m.focused].Focus()
|
|
|
|
|
2024-07-10 01:35:14 +00:00
|
|
|
|
|
|
|
|
|
|
|
case "addTODO":
|
|
|
|
switch keypress := msg.String(); keypress {
|
|
|
|
// case "ctrl+c", "q": //are you stupid?
|
|
|
|
// return m, tea.Quit
|
|
|
|
case "enter":
|
|
|
|
if m.focused == len(m.todoAddInputs)-1 {
|
|
|
|
//TODO check that we have all fields not empty or contains wrong value and notify about it (add textinput validator in tui-model.go)
|
|
|
|
|
|
|
|
for i := range m.todoAddInputs {
|
|
|
|
m.todoAddInputs[i], cmd = m.todoAddInputs[i].Update(msg)
|
|
|
|
}
|
|
|
|
|
|
|
|
err := m.AddTODOtoList()
|
|
|
|
if err != nil {return m, m.errHandler(err,"Failed to add TODO")}
|
|
|
|
return m, nil
|
|
|
|
}
|
|
|
|
m.nextTODOInput()
|
|
|
|
m.addTimeFocus = false
|
|
|
|
// return m, nil
|
|
|
|
case "shift+tab", "up":
|
|
|
|
// buttonStyle = lipgloss.NewStyle()
|
|
|
|
m.addTimeFocus = false
|
|
|
|
m.prevTODOInput()
|
|
|
|
// return m, nil
|
|
|
|
case "right":
|
|
|
|
//TODO BUG - cant move left-right, probably just move return in IF statement
|
|
|
|
//TODO BUG - focus todoAddInputsTime only if cursor at last character
|
|
|
|
// if focus Due Time
|
|
|
|
if m.focused == 1 {
|
|
|
|
m.addTimeFocus = true
|
|
|
|
m.todoAddInputs[m.focused].Blur()
|
|
|
|
if m.todoAddInputsTime[1].Focused() {
|
|
|
|
m.todoAddInputsTime[1].Blur()
|
|
|
|
m.todoAddInputsTime[0].Focus()
|
|
|
|
} else {
|
|
|
|
m.todoAddInputsTime[0].Blur()
|
|
|
|
m.todoAddInputsTime[1].Focus()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return m, nil
|
|
|
|
case "left":
|
|
|
|
//TODO BUG - cant move left-right, probably just move return in IF statement
|
|
|
|
//TODO BUG - focus todoAddInputs only if cursor at zero character
|
|
|
|
if m.focused == 1 {
|
|
|
|
m.todoAddInputs[m.focused].Blur()
|
|
|
|
if m.todoAddInputsTime[0].Focused() {
|
|
|
|
m.todoAddInputsTime[0].Blur()
|
|
|
|
m.todoAddInputsTime[1].Focus()
|
|
|
|
} else {
|
|
|
|
m.todoAddInputsTime[0].Blur()
|
|
|
|
m.todoAddInputsTime[1].Blur()
|
|
|
|
m.todoAddInputs[m.focused].Focus()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return m, nil
|
|
|
|
case "tab", "down":
|
|
|
|
// buttonStyle = buttonStyle.Background(lipgloss.Color("#7D56F4"))
|
|
|
|
m.nextTODOInput()
|
|
|
|
m.addTimeFocus = false
|
|
|
|
// return m, nil
|
|
|
|
}
|
|
|
|
// for i := range m.todoAddInputs {
|
|
|
|
// m.todoAddInputs[i].Blur()
|
|
|
|
// }
|
|
|
|
// for i := range m.todoAddInputsTime {
|
|
|
|
// m.todoAddInputsTime[i].Blur()
|
|
|
|
// }
|
|
|
|
// if !m.addTimeFocus {m.todoAddInputs[m.focused].Focus()}
|
|
|
|
|
2024-06-21 18:38:41 +00:00
|
|
|
}
|
2024-06-29 01:00:39 +00:00
|
|
|
|
2024-06-21 18:38:41 +00:00
|
|
|
switch keypress := msg.String(); keypress {
|
|
|
|
case "ctrl+c", "q":
|
|
|
|
return m, tea.Quit
|
|
|
|
// case "right", "l", "n", "tab":
|
|
|
|
//TODO add to help
|
|
|
|
case "tab":
|
|
|
|
if m.LoggedIn {
|
|
|
|
h, v := docStyle.GetFrameSize()
|
|
|
|
width, height, _ := term.GetSize(0)
|
|
|
|
switch m.ActiveWindow {
|
2024-06-29 01:00:39 +00:00
|
|
|
case "today":
|
2024-06-21 18:38:41 +00:00
|
|
|
m.ActiveWindow = "tomorrow"
|
|
|
|
m.TomorrowTab.SetSize(width-h, height-v)
|
2024-06-29 01:00:39 +00:00
|
|
|
case "tomorrow":
|
2024-06-21 18:38:41 +00:00
|
|
|
m.ActiveWindow = "today"
|
|
|
|
m.TodayTab.SetSize(width-h, height-v)
|
|
|
|
}
|
|
|
|
return m, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// case "a" {
|
|
|
|
// TODO add new element
|
|
|
|
// return m, tea.Quit
|
|
|
|
// }
|
2024-07-10 01:35:14 +00:00
|
|
|
// case "t":
|
|
|
|
// // TODO add new element
|
|
|
|
// return m, tea.Quit
|
2024-06-21 18:38:41 +00:00
|
|
|
}
|
2024-06-29 01:00:39 +00:00
|
|
|
|
2024-06-21 18:38:41 +00:00
|
|
|
case tea.WindowSizeMsg:
|
2024-06-29 01:00:39 +00:00
|
|
|
|
2024-06-21 18:38:41 +00:00
|
|
|
switch m.ActiveWindow {
|
2024-07-10 01:35:14 +00:00
|
|
|
//TODO BUG - addTODO/login - output render breaks a bit if errorHandler appeared on screen
|
2024-06-29 01:00:39 +00:00
|
|
|
// case "login": //TODO
|
|
|
|
// m.TodayTab.SetSize(msg.Width-h, msg.Height-v)
|
|
|
|
// case "calendarChoose": //TODO
|
2024-07-10 01:35:14 +00:00
|
|
|
// case "addTODO": //TODO
|
2024-06-29 01:00:39 +00:00
|
|
|
// m.calendarList.SetWidth(msg.Width)
|
|
|
|
case "today":
|
|
|
|
h, v := docStyle.GetFrameSize()
|
|
|
|
m.TodayTab.SetSize(msg.Width-h, msg.Height-v)
|
|
|
|
case "tomorrow":
|
|
|
|
h, v := docStyle.GetFrameSize()
|
|
|
|
m.TomorrowTab.SetSize(msg.Width-h, msg.Height-v)
|
2024-06-21 18:38:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-06-29 01:00:39 +00:00
|
|
|
case errMsg:
|
|
|
|
m.errString = msg.message
|
|
|
|
m.ActiveWindow = ""
|
|
|
|
}
|
2024-06-21 18:38:41 +00:00
|
|
|
|
2024-06-29 01:00:39 +00:00
|
|
|
|
2024-06-21 18:38:41 +00:00
|
|
|
// text input
|
|
|
|
switch m.ActiveWindow {
|
2024-06-29 01:00:39 +00:00
|
|
|
case "login":
|
|
|
|
for i := range m.loginInputs {
|
|
|
|
m.loginInputs[i], cmd = m.loginInputs[i].Update(msg)
|
|
|
|
}
|
2024-07-10 01:35:14 +00:00
|
|
|
case "addTODO":
|
|
|
|
if (m.focused == 1) && (!m.todoAddInputs[m.focused].Focused()) {
|
|
|
|
for i := range m.todoAddInputsTime {
|
|
|
|
m.todoAddInputsTime[i], cmd = m.todoAddInputsTime[i].Update(msg)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for i := range m.todoAddInputs {
|
|
|
|
m.todoAddInputs[i], cmd = m.todoAddInputs[i].Update(msg)
|
|
|
|
}
|
|
|
|
}
|
2024-06-29 01:00:39 +00:00
|
|
|
case "calendarChoose":
|
|
|
|
m.calendarList, cmd = m.calendarList.Update(msg)
|
|
|
|
case "today":
|
|
|
|
m.TodayTab, cmd = m.TodayTab.Update(msg)
|
|
|
|
case "tomorrow":
|
|
|
|
m.TomorrowTab, cmd = m.TomorrowTab.Update(msg)
|
2024-06-21 18:38:41 +00:00
|
|
|
|
2024-06-29 01:00:39 +00:00
|
|
|
case "": //exit on key press
|
|
|
|
switch tmp := msg.(type) { //TODO debug and optimize
|
|
|
|
case tea.KeyMsg:
|
2024-07-10 01:35:14 +00:00
|
|
|
// TODO exit on key press
|
2024-06-29 01:00:39 +00:00
|
|
|
_ = tmp
|
|
|
|
if m.LoggedIn {
|
|
|
|
m.ActiveWindow = "today"
|
|
|
|
} else {m.ActiveWindow = "login"}
|
|
|
|
}
|
|
|
|
}
|
2024-06-21 18:38:41 +00:00
|
|
|
// m.TodayTab, cmd = m.TodayTab.Update(msg)
|
|
|
|
// m.TomorrowTab, cmd = m.TomorrowTab.Update(msg)
|
2024-06-29 01:00:39 +00:00
|
|
|
|
2024-06-21 18:38:41 +00:00
|
|
|
return m, cmd
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m model) View() string {
|
|
|
|
|
|
|
|
var tabOutput string
|
|
|
|
|
|
|
|
switch m.ActiveWindow {
|
2024-06-29 01:00:39 +00:00
|
|
|
case "login":
|
|
|
|
width, height, _ := term.GetSize(0)
|
|
|
|
width -= 2
|
|
|
|
height -= 2
|
|
|
|
loginStyle = loginStyle.
|
|
|
|
// Width(30).
|
|
|
|
// Height(height/5).
|
|
|
|
MarginTop(height / 5).
|
|
|
|
MarginLeft(width/2 - 20)
|
|
|
|
// MarginRight(width/3)
|
|
|
|
tabOutput = loginStyle.Render(m.RenderLogin())
|
|
|
|
// w, h := lipgloss.Size(tabOutput)
|
2024-07-10 01:35:14 +00:00
|
|
|
case "addTODO":
|
|
|
|
width, height, _ := term.GetSize(0)
|
|
|
|
width -= 2
|
|
|
|
height -= 2
|
|
|
|
loginStyle = loginStyle.
|
|
|
|
// Width(30).
|
|
|
|
// Height(height/5).
|
|
|
|
MarginTop(height / 5).
|
|
|
|
MarginLeft(width/2 - 20)
|
|
|
|
// MarginRight(width/3)
|
|
|
|
tabOutput = loginStyle.Render(m.RenderAddTodo())
|
|
|
|
// w, h := lipgloss.Size(tabOutput)
|
2024-06-29 01:00:39 +00:00
|
|
|
case "calendarChoose":
|
|
|
|
width, height, _ := term.GetSize(0)
|
|
|
|
width -= 2
|
|
|
|
height -= 2
|
|
|
|
loginStyle = loginStyle.
|
|
|
|
// Width(30).
|
|
|
|
// Height(height/5).
|
|
|
|
MarginTop(height / 5).
|
|
|
|
MarginLeft(width/2 - 20)
|
|
|
|
// MarginRight(width/3)
|
|
|
|
tabOutput = loginStyle.Render(m.RenderCalendarChooser())
|
|
|
|
// w, h := lipgloss.Size(tabOutput)
|
|
|
|
|
|
|
|
case "today":
|
|
|
|
tabOutput = docStyle.Render(m.TodayTab.View())
|
|
|
|
case "tomorrow":
|
|
|
|
tabOutput = docStyle.Render(m.TomorrowTab.View())
|
|
|
|
case "":
|
|
|
|
width, height, _ := term.GetSize(0)
|
|
|
|
width -= 2
|
|
|
|
height -= 2
|
|
|
|
loginStyle = loginStyle.
|
|
|
|
Width(width / 3).
|
|
|
|
Height(1).
|
|
|
|
MarginTop(height / 2).
|
|
|
|
MarginLeft(width/3 + 2).
|
|
|
|
MarginRight(width / 3)
|
|
|
|
tabOutput = loginStyle.Render("ERROR - " + m.errString)
|
|
|
|
}
|
2024-06-21 18:38:41 +00:00
|
|
|
// if m.activeTab == 0 {
|
|
|
|
// tabOutput = docStyle.Render(m.TodayTab.View())
|
|
|
|
// }
|
|
|
|
// if m.activeTab == 1 {
|
|
|
|
// tabOutput = docStyle.Render(m.TomorrowTab.View())
|
|
|
|
// }
|
2024-06-29 01:00:39 +00:00
|
|
|
|
2024-06-21 18:38:41 +00:00
|
|
|
return tabOutput
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|