301 lines
7.8 KiB
Go
301 lines
7.8 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
// "github.com/charmbracelet/bubbles/list"
|
|
"github.com/charmbracelet/lipgloss"
|
|
"time"
|
|
"errors"
|
|
"strconv"
|
|
"regexp"
|
|
"strings"
|
|
|
|
)
|
|
|
|
const (
|
|
name = iota
|
|
dueDate
|
|
|
|
description
|
|
priority
|
|
//TODO add support for subtasks
|
|
alarmOffset
|
|
)
|
|
|
|
const (
|
|
dueTimeMinute = iota
|
|
dueTimeHour
|
|
)
|
|
|
|
func (m model) RenderAddTodo() string {
|
|
|
|
return fmt.Sprintf(
|
|
`%s
|
|
|
|
%s
|
|
%s
|
|
|
|
%s
|
|
%s %0-0s%s
|
|
|
|
%s
|
|
%s
|
|
|
|
%s
|
|
%s
|
|
|
|
%s
|
|
%s
|
|
|
|
|
|
%s
|
|
`,
|
|
|
|
inputStyle.Width(30).Align(lipgloss.Center).Render("Create TODO"),
|
|
inputStyle.Width(30).Foreground(lipgloss.AdaptiveColor{Dark: "50"}).Render("Name"),
|
|
m.todoAddInputs[name].View(),
|
|
inputStyle.Width(30).Foreground(lipgloss.AdaptiveColor{Dark: "50"}).Render("Due Time"),
|
|
m.todoAddInputs[dueDate].View(),
|
|
m.todoAddInputsTime[dueTimeHour].View(),
|
|
m.todoAddInputsTime[dueTimeMinute].View(),
|
|
inputStyle.Width(30).Foreground(lipgloss.AdaptiveColor{Dark: "50"}).Render("Description"),
|
|
m.todoAddInputs[description].View(),
|
|
inputStyle.Width(30).Foreground(lipgloss.AdaptiveColor{Dark: "50"}).Render("Priority"),
|
|
//TODO add support for subtasks
|
|
m.todoAddInputs[priority].View(),
|
|
inputStyle.Width(30).Foreground(lipgloss.AdaptiveColor{Dark: "50"}).Render("Alarm offset"),
|
|
m.todoAddInputs[alarmOffset].View(),
|
|
buttonStyle.Render(" Add "),
|
|
)
|
|
// .Align(lipgloss.Center).BorderStyle(lipgloss.NormalBorder())
|
|
|
|
}
|
|
|
|
func (m *model) nextTODOInput() {
|
|
|
|
m.todoAddInputsTime[0].Blur()
|
|
m.todoAddInputsTime[1].Blur()
|
|
m.todoAddInputs[m.focused].Blur()
|
|
|
|
if m.focused == len(m.todoAddInputs)-1 {
|
|
|
|
if m.btnFocus == true {
|
|
m.btnFocus = false
|
|
buttonStyle = lipgloss.NewStyle()
|
|
m.focused = (m.focused + 1) % len(m.todoAddInputs)
|
|
//TODO do smth with blinking cursor?
|
|
} else {
|
|
buttonStyle = buttonStyle.Background(lipgloss.Color("#7D56F4"))
|
|
m.btnFocus = true
|
|
}
|
|
} else {
|
|
// buttonStyle = lipgloss.NewStyle()
|
|
m.focused = (m.focused + 1) % len(m.todoAddInputs)
|
|
}
|
|
|
|
|
|
m.todoAddInputs[m.focused].Focus()
|
|
}
|
|
|
|
// prevInput focuses the previous input field
|
|
func (m *model) prevTODOInput() {
|
|
m.todoAddInputs[m.focused].Blur()
|
|
if m.focused == len(m.todoAddInputs)-1 {
|
|
if m.btnFocus == true {
|
|
m.btnFocus = false
|
|
buttonStyle = lipgloss.NewStyle()
|
|
//TODO do smth with blinking cursor?
|
|
// m.focused = (m.focused + 1) % len(m.loginInputs)
|
|
} else {
|
|
m.focused--
|
|
// Wrap around
|
|
if m.focused < 0 {
|
|
m.focused = len(m.todoAddInputs) - 1
|
|
}
|
|
}
|
|
} else {
|
|
m.focused--
|
|
// Wrap around
|
|
if m.focused < 0 {
|
|
m.focused = len(m.todoAddInputs) - 1
|
|
}
|
|
}
|
|
m.todoAddInputs[m.focused].Focus()
|
|
}
|
|
|
|
func (m *model) AddTODOtoList() (err error) {
|
|
|
|
//TODO BUG - we can get another due date to timezon differs from UTC
|
|
//TODO BUG - need to fix `PRIORITY;VALUE=TEXT:0` - shouldn't be TEXT thing
|
|
now := time.Now()
|
|
// time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location())
|
|
// _, offset := now.Zone() // substract timezone offset because after `now.Truncate(24 * time.Hour)` it makes this -> 2024-07-08 03:00:00 +0300 MSK. so start of a day still in UTC??!? wtf
|
|
// timezoneOffset := time.Duration(-offset) * time.Second
|
|
// now = now.Add(timezoneOffset)
|
|
now = time.Date(now.Year(), now.Month(), now.Day(),0,0,0,0, now.Location())
|
|
// now := time.Now().UTC()
|
|
todoInfo := TodoInterface{
|
|
name: m.todoAddInputs[name].Value(),
|
|
description: m.todoAddInputs[description].Value(),
|
|
// priority: priorityTmp,
|
|
// dueTime: time.Now(),
|
|
// alarmOffset: m.todoAddInputs[alarmOffset].Value(),
|
|
}
|
|
|
|
|
|
var dueDateTime time.Time
|
|
|
|
m.todoAddInputs[dueDate].Value()
|
|
|
|
|
|
//t\d
|
|
tdigitRegexp := regexp.MustCompile(`t\d{1,2}`) //tXX
|
|
digitRegexp := regexp.MustCompile(`\d{1,2}`) // XX
|
|
dayMonthRegexp := regexp.MustCompile(`\d{1,2}\.\d{1,2}`) // xx.xx
|
|
fullDateRegexp := regexp.MustCompile(`\d{1,2}\.\d{1,2}\.\d{2,4}`) //xx.xx.xxxx
|
|
|
|
//Date
|
|
date := m.todoAddInputs[dueDate].Value()
|
|
switch {
|
|
// case "":
|
|
//no due date
|
|
case date == "t":
|
|
//if t = today (without time)
|
|
// now := time.Now()
|
|
dueDateTime = now
|
|
// dueDateTime = now.Truncate(24 * time.Hour)
|
|
// dueDateTime = now.Truncate(24 * time.Hour).UTC()
|
|
// return errors.New(fmt.Sprint(offset))
|
|
case tdigitRegexp.MatchString(date):
|
|
//if tX = today + x days (without time) //TODO notify user about this feature somehow
|
|
// now := time.Now()
|
|
addDays,err := strconv.Atoi(strings.TrimPrefix(date,"t"))
|
|
|
|
dueDateTime = now
|
|
// dueDateTime = now.Truncate(24 * time.Hour)
|
|
if err == nil {dueDateTime = dueDateTime.AddDate(0,0, addDays)
|
|
} else {return errors.New("Can't convert tXX date. Examples: t1, t7, t14")} //TODO return error?
|
|
|
|
|
|
case fullDateRegexp.MatchString(date):
|
|
//if 12.08.2024 / = you know
|
|
// if 12.08.24 = you know
|
|
sep := strings.Split(date, ".")
|
|
year,err1 := strconv.Atoi(sep[2])
|
|
monthInt,err2 := strconv.Atoi(sep[1])
|
|
day,err3 := strconv.Atoi(sep[0])
|
|
|
|
if year <=2000 {year+=2000}
|
|
// year := time.Year(yearInt)
|
|
month := time.Month(monthInt)
|
|
// day := time.Day(dayInt)
|
|
|
|
//TODO if it's not full year???
|
|
if err1== nil&&err2== nil&&err3 == nil {
|
|
dueDateTime = time.Date(year, month,day, 0, 0, 0, 0, time.Local)
|
|
|
|
}
|
|
case dayMonthRegexp.MatchString(date):
|
|
//if 12.08 = 12th day of 8th month of this year
|
|
currentYear := now.Year()
|
|
sep := strings.Split(date, ".")
|
|
monthInt,err2 := strconv.Atoi(sep[1])
|
|
month := time.Month(monthInt)
|
|
day,err3 := strconv.Atoi(sep[0])
|
|
if err2== nil&&err3 == nil {
|
|
dueDateTime = time.Date(currentYear, month,day, 0, 0, 0, 0, time.Local)
|
|
}
|
|
case digitRegexp.MatchString(date):
|
|
//if 12 = 12th day of this month of this year
|
|
// now := time.Now()
|
|
currentMonth := now.Month()
|
|
currentYear := now.Year()
|
|
intDate,err := strconv.Atoi(date)
|
|
if err != nil {_=err} //TODO return error?
|
|
dueDateTime = time.Date(currentYear, currentMonth, intDate, 0, 0, 0, 0, time.Local)
|
|
// case
|
|
// default:
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//Time
|
|
//if hour!="" add to date
|
|
//if monute!="" add to date
|
|
hour,err1 := strconv.Atoi(m.todoAddInputsTime[1].Value())
|
|
minute,err2 := strconv.Atoi(m.todoAddInputsTime[0].Value())
|
|
if (hour != 0 && err1 ==nil ) || (err2 == nil && minute != 0) {
|
|
if dueDateTime.IsZero() { //set to today
|
|
dueDateTime = now
|
|
// dueDateTime = now.Truncate(24 * time.Hour)
|
|
}
|
|
dueDateTime = dueDateTime.Add(time.Hour * time.Duration(hour) + time.Minute * time.Duration(minute))
|
|
}
|
|
|
|
if !dueDateTime.IsZero() {
|
|
todoInfo.dueTime = dueDateTime
|
|
// todoInfo.dueTime = dueDateTime.Add(timezoneOffset)
|
|
// return errors.New(fmt.Sprint(todoInfo.dueTime)) //TODO RM ME DEBUG
|
|
}
|
|
|
|
|
|
todoInfo.priority = 0
|
|
var priorityTmp int
|
|
if m.todoAddInputs[priority].Value() != "" {
|
|
var err error
|
|
priorityTmp,err = strconv.Atoi(m.todoAddInputs[priority].Value())
|
|
if err != nil {return err} //TODO debug. do like in next line
|
|
// if err != nil {priorityTmp = 0}
|
|
} else {}
|
|
|
|
alarmOffsetTmp := m.todoAddInputs[alarmOffset].Value()
|
|
|
|
|
|
|
|
if priorityTmp != 0 {
|
|
todoInfo.priority = priorityTmp
|
|
}
|
|
if !dueDateTime.IsZero() && alarmOffsetTmp != "" {
|
|
todoInfo.alarmOffset = alarmOffsetTmp
|
|
}
|
|
|
|
|
|
|
|
|
|
task, err := CreateTodo(todoInfo)
|
|
// if err != nil {return m.errHandler(err,"Failed to creating todo")}
|
|
if err != nil {return err}
|
|
err = m.UploadTodo(task)
|
|
// if err != nil {return m.errHandler(err,"Failed to uploade todo")}
|
|
if err != nil {return err}
|
|
err = m.UpdateTodos(task)
|
|
// if err != nil {return m.errHandler(err,"Failed updating todo list")} //Useless
|
|
if err != nil {return err}
|
|
//TODO deal with errors - append comment on what broken?
|
|
|
|
m.ActiveWindow = "today" //TODO remove to previus window
|
|
|
|
|
|
//TODO clean previous input
|
|
for i,_ := range m.todoAddInputsTime {
|
|
m.todoAddInputsTime[i].Blur()
|
|
m.todoAddInputsTime[i].Reset()
|
|
}
|
|
for i,_ := range m.todoAddInputs {
|
|
m.todoAddInputs[i].Blur()
|
|
m.todoAddInputs[i].Reset()
|
|
}
|
|
|
|
m.focused = 0
|
|
m.todoAddInputs[m.focused].Focus()
|
|
// m.todoAddInputsTime.Reset()
|
|
// m.todoAddInputs.Reset()
|
|
|
|
|
|
|
|
return nil
|
|
}
|