2025-07-26 23:31:00 +02:00
|
|
|
package common
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"encoding/json"
|
|
|
|
|
"fmt"
|
2026-01-12 21:20:59 +01:00
|
|
|
"github.com/charmbracelet/lipgloss"
|
|
|
|
|
"github.com/google/uuid"
|
2026-01-12 20:48:52 +01:00
|
|
|
"hash/fnv"
|
2025-08-23 19:14:16 +02:00
|
|
|
"strings"
|
2026-01-11 18:40:38 +01:00
|
|
|
"time"
|
2025-07-26 23:31:00 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func (todo Todo) Store(store *BoltStore, user string) error {
|
|
|
|
|
if todo.Owner != user {
|
|
|
|
|
return fmt.Errorf("unauthorized user")
|
|
|
|
|
}
|
2026-01-12 21:20:59 +01:00
|
|
|
if todo.Id == "" {
|
|
|
|
|
todo.Id = uuid.New().String()
|
|
|
|
|
}
|
|
|
|
|
todo.Id = uuid.New().String()
|
2026-01-11 18:40:38 +01:00
|
|
|
todo.LastModified = time.Now()
|
2025-07-26 23:31:00 +02:00
|
|
|
todoJson, err := json.Marshal(todo)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2026-01-12 21:20:59 +01:00
|
|
|
return store.SaveValueToBucket(user, todo.Id, string(todoJson))
|
2025-07-26 23:31:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (todoRequest StoreTodoRequest) Store(store *BoltStore, user string) error {
|
|
|
|
|
todo := Todo{
|
2026-01-12 21:20:59 +01:00
|
|
|
Id: uuid.New().String(),
|
2026-01-11 18:40:38 +01:00
|
|
|
Name: todoRequest.Name,
|
|
|
|
|
Description: todoRequest.Description,
|
|
|
|
|
Status: todoRequest.Status,
|
|
|
|
|
Owner: user,
|
|
|
|
|
LastModified: time.Now(),
|
2025-07-26 23:31:00 +02:00
|
|
|
}
|
|
|
|
|
todoJson, err := json.Marshal(todo)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2026-01-12 21:20:59 +01:00
|
|
|
return store.SaveValueToBucket(user, todo.Id, string(todoJson))
|
2025-07-26 23:31:00 +02:00
|
|
|
}
|
|
|
|
|
|
2025-08-23 19:14:16 +02:00
|
|
|
func (todoList TodoList) FindByName(name string) (Todo, bool) {
|
|
|
|
|
for _, todo := range todoList.Todos {
|
2025-07-26 23:31:00 +02:00
|
|
|
if todo.Name == name {
|
|
|
|
|
return todo, true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return Todo{}, false
|
|
|
|
|
}
|
2025-08-23 19:14:16 +02:00
|
|
|
|
|
|
|
|
func (todo Todo) PrintIndexed(index int) {
|
2026-01-11 18:40:38 +01:00
|
|
|
|
|
|
|
|
if todo.Deleted {
|
|
|
|
|
return
|
|
|
|
|
}
|
2025-08-23 19:14:16 +02:00
|
|
|
var statusColor string
|
|
|
|
|
|
|
|
|
|
// Select color based on the status (case-insensitive)
|
|
|
|
|
switch strings.ToLower(todo.Status) {
|
|
|
|
|
case Done:
|
|
|
|
|
statusColor = ColorGreen
|
|
|
|
|
case WIP:
|
|
|
|
|
statusColor = ColorYellow
|
2025-08-23 21:51:33 +02:00
|
|
|
case Pending, NotStarted:
|
2025-08-23 19:14:16 +02:00
|
|
|
statusColor = ColorBlue
|
|
|
|
|
case Blocked, Failed:
|
|
|
|
|
statusColor = ColorRed
|
|
|
|
|
default:
|
2026-01-12 20:48:52 +01:00
|
|
|
statusColor = ColorWhite // No color for unknown statuses
|
2025-08-23 19:14:16 +02:00
|
|
|
}
|
|
|
|
|
|
2026-01-12 21:20:59 +01:00
|
|
|
var renderedLabels []string
|
|
|
|
|
|
|
|
|
|
for _, l := range todo.Labels {
|
|
|
|
|
h := fnv.New32a()
|
|
|
|
|
h.Write([]byte(l))
|
|
|
|
|
colorID := fmt.Sprint(1 + (h.Sum32() % 6))
|
|
|
|
|
|
|
|
|
|
style := lipgloss.NewStyle().
|
|
|
|
|
Bold(true).
|
|
|
|
|
Foreground(lipgloss.Color("0")).
|
|
|
|
|
Background(lipgloss.Color(colorID)).
|
|
|
|
|
Padding(0, 1).
|
|
|
|
|
MarginRight(1).
|
|
|
|
|
Border(lipgloss.RoundedBorder()).
|
|
|
|
|
BorderForeground(lipgloss.Color(colorID)).
|
|
|
|
|
BorderBackground(lipgloss.Color(""))
|
|
|
|
|
|
|
|
|
|
renderedLabels = append(renderedLabels, style.Render(l))
|
2026-01-12 20:48:52 +01:00
|
|
|
}
|
|
|
|
|
|
2026-01-12 21:20:59 +01:00
|
|
|
fmt.Println(lipgloss.JoinHorizontal(lipgloss.Top, renderedLabels...))
|
|
|
|
|
|
|
|
|
|
fmt.Printf("%s%d)%s %s%-20s%s", ColorCyan, index, ColorReset, ColorWhite, todo.Name, ColorReset)
|
2026-01-12 20:48:52 +01:00
|
|
|
|
|
|
|
|
fmt.Printf(" %s %s%s\n", statusColor, strings.ToUpper(todo.Status), ColorReset)
|
2026-01-11 18:40:38 +01:00
|
|
|
|
2026-01-12 20:48:52 +01:00
|
|
|
// 5. Description (Indented and slightly dimmer if possible, or standard)
|
|
|
|
|
fmt.Printf(" %s\n", todo.Description)
|
2026-01-12 21:20:59 +01:00
|
|
|
uuidStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("240"))
|
2026-01-12 20:48:52 +01:00
|
|
|
lastMod := todo.LastModified.Format("2006-01-02 15:04")
|
2026-01-12 21:20:59 +01:00
|
|
|
metaLine := fmt.Sprintf(" Last Modified: %s • ID: %s", lastMod, todo.Id)
|
|
|
|
|
fmt.Println(uuidStyle.Render(metaLine))
|
2026-01-12 20:48:52 +01:00
|
|
|
|
|
|
|
|
fmt.Printf(" %s----------------------------%s\n", ColorGray, ColorReset)
|
|
|
|
|
}
|
2026-01-11 18:40:38 +01:00
|
|
|
|
|
|
|
|
func (t Todo) IsEqual(other Todo) bool {
|
|
|
|
|
return t.Name == other.Name &&
|
|
|
|
|
t.Description == other.Description &&
|
|
|
|
|
t.Status == other.Status &&
|
|
|
|
|
t.Owner == other.Owner &&
|
|
|
|
|
t.Deleted == other.Deleted
|
2025-08-23 19:14:16 +02:00
|
|
|
}
|
2026-01-11 19:04:18 +01:00
|
|
|
|
|
|
|
|
func (t Todo) IsEqualIgnoringStatus(other Todo) bool {
|
|
|
|
|
return t.Name == other.Name &&
|
|
|
|
|
t.Description == other.Description &&
|
|
|
|
|
t.Owner == other.Owner &&
|
|
|
|
|
t.Deleted == other.Deleted
|
|
|
|
|
}
|