gotd/bubbletea.go

214 lines
4.2 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package main
import (
"fmt"
"regexp"
"time"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
)
func (m model) Init() tea.Cmd {
// Just return `nil`, which means "no I/O right now, please."
return nil
}
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
var cmd tea.Cmd
if m.addTask {
m.textinput, cmd = m.textinput.Update(msg)
}
switch msg := msg.(type) {
// Is it a key press?
case tea.KeyMsg:
// Cool, what was the actual key pressed?
switch msg.String() {
// These keys should exit the program.
case "ctrl+c", "q":
return m, tea.Quit
// The "up" and "k" keys move the cursor up
case "up", "k":
if m.cursor > 0 && !m.addTask {
m.cursor--
}
// The "down" and "j" keys move the cursor down
case "down", "j":
if m.cursor < len(m.todos)-1 && !m.addTask {
m.cursor++
}
case "left", "h":
if m.tab > 0 && !m.addTask {
m.tab--
}
case "right", "l":
if m.tab < 4 && !m.addTask {
m.tab++
}
// new task
case "n":
if !m.addTask {
m.addTask = true
m.textinput.Focus()
m.textinput.Reset()
}
case "esc":
if m.addTask {
m.addTask = false
m.textinput.Reset()
}
case "enter":
if m.addTask {
AddNewTask(&m)
m.addTask = false
m.textinput.Reset()
}
// The "enter" key and the spacebar (a literal space) toggle
// the selected state for the item that the cursor is pointing at.
case " ":
if !m.addTask {
if m.todos[m.cursor].done {
m.todos[m.cursor].done = false
} else {
m.todos[m.cursor].done = true
}
}
}
}
// Return the updated model to the Bubble Tea runtime for processing.
// Note that we're not returning a command.
return m, cmd
}
func AddNewTask(m *model) {
taskTitle := m.textinput.Value()
// parse date in title
var doDate int64 = -1
var deadline int64 = -1
reDate := regexp.MustCompile("\\d{1,2}/\\d{1,2}")
date := reDate.FindStringSubmatch(taskTitle)
if len(date) > 0 {
// what the fuck Go
date, _ := time.Parse("02/01/2006", "10/03/2025")
doDate = date.Unix()
}
t := todo{
name: taskTitle,
done: false,
startdate: doDate,
deadline: deadline,
priority: 1,
isInbox: true,
}
m.todos = append(m.todos, t)
}
func (m model) View() string {
// The header
s := ""
currentList := []todo{}
s += "GOTD\n\n"
switch m.tab {
case 0:
// s += "Inbox"
taskFilter := func(t todo) bool { return t.isInbox }
currentList = filter(m.todos, taskFilter)
case 1:
// s += "Today"
taskFilter := func(t todo) bool { return t.startdate == midnightToUnix() || t.deadline == midnightToUnix() }
currentList = filter(m.todos, taskFilter)
case 2:
// s += "Tomorrow"
// 86400 seconds in 24h, add it on to today's midnight for tomorrow's midnight
taskFilter := func(t todo) bool { return t.startdate == midnightToUnix() + 86400 || t.deadline == midnightToUnix() + 86400}
currentList = filter(m.todos, taskFilter)
case 3:
// s += "Scheduled"
taskFilter := func(t todo) bool { return t.startdate != -1 }
currentList = filter(m.todos, taskFilter)
case 4:
// s += "Anytime"
taskFilter := func(t todo) bool { return t.startdate == -1 }
currentList = filter(m.todos, taskFilter)
}
// Iterate over our choices
for i, value := range currentList {
// Is the cursor pointing at this choice?
cursor := " " // no cursor
if m.cursor == i {
cursor = ">" // cursor!
}
// Is this choice selected?
checked := " " // not selected
// if _, ok := m.selected[i]; ok {
// checked = "x" // selected!
// }
if value.done {
checked = "x"
}
renderedTime := time.Unix(value.startdate, 0)
// Render the row
s += fmt.Sprintf("%s [%s] %s %s\n", cursor, checked, value.name, renderedTime)
}
s += "\n\n"
// render tab bar
for i, v := range []string{"Inbox", "Today", "Tomorrow", "Scheduled", "Anytime"} {
if i == m.tab {
s += lipgloss.NewStyle().
Bold(true).
Underline(true).
PaddingRight(3).
Render(v)
} else {
s += lipgloss.NewStyle().
PaddingRight(3).
Render(v)
}
}
// The footer
s += "\nn: new"
if m.addTask {
s += ": "
s += m.textinput.View()
}
s += "\nq: quit.\n"
// Send the UI for rendering
return s
}