tempus/tui-addTodo.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
}