100 lines
3.0 KiB
Go
100 lines
3.0 KiB
Go
package mujica
|
|
|
|
import (
|
|
"log/slog"
|
|
"strings"
|
|
|
|
"github.com/egoist/mygo/ui"
|
|
|
|
"mujicaui/internal"
|
|
"mujicaui/theme"
|
|
)
|
|
|
|
// TaskItemOptions configure a TaskItem.
|
|
type TaskItemOptions struct {
|
|
Members []ProjectMember
|
|
// Today anchors the overdue mark; zero uses the system clock.
|
|
Today Date
|
|
Disabled bool
|
|
}
|
|
|
|
// taskItemEdit is a title being edited inline.
|
|
type taskItemEdit struct {
|
|
on bool
|
|
draft string
|
|
}
|
|
|
|
// TaskItem displays task fields with completion and inline editing.
|
|
func TaskItem(c *ui.Context, task *Task, opts TaskItemOptions) ProjectResult {
|
|
projectCheckPriority(task.Priority)
|
|
for _, id := range task.Assignees {
|
|
projectMember(opts.Members, id)
|
|
}
|
|
k := Tokens(c)
|
|
d := Density(c)
|
|
today := datetimeToday(c, opts.Today)
|
|
r := ProjectResult{}
|
|
row := ui.Row(c).MinHeight(d.ControlHeight()).Gap(d.Unit() * 3).AlignItems(ui.Center).PaddingX(d.Unit() * 2).
|
|
Role(ui.RoleListItem).Label(task.Title).Disabled(opts.Disabled)
|
|
r.Element = row
|
|
edit := ui.Local(row, "task-item-edit", func() taskItemEdit { return taskItemEdit{} })
|
|
if row.Hovered() {
|
|
row.Background(k.SurfaceHover)
|
|
}
|
|
row.Children(func() {
|
|
done := task.Done
|
|
if Checkbox(c, &done, "", CheckboxOptions{Disabled: opts.Disabled}).Label(task.Title).Changed() && !row.IsDisabled() {
|
|
task.Done, r.changed = done, task.ID
|
|
slog.Debug("mujica: task_item done", "id", task.ID, "done", done)
|
|
}
|
|
if edit.on && !row.IsDisabled() {
|
|
in := TextInput(c, &edit.draft, TextInputOptions{Label: msg(c, "task_item.rename")})
|
|
in.Element.Grow(1)
|
|
in.Input.AutoFocus()
|
|
switch {
|
|
case in.Submitted() && strings.TrimSpace(edit.draft) != "":
|
|
if t := strings.TrimSpace(edit.draft); t != task.Title {
|
|
task.Title, r.changed = t, task.ID
|
|
slog.Debug("mujica: task_item rename", "id", task.ID)
|
|
}
|
|
edit.on = false
|
|
case in.Input.Shortcut(0, ui.KeyEscape):
|
|
edit.on = false
|
|
}
|
|
return
|
|
}
|
|
edit.on = false
|
|
title := ui.ButtonBase(c).Grow(1).Shrink(1).Justify(ui.Start).MinHeight(theme.MinHitSize).Radius(theme.ControlRadius).Label(task.Title)
|
|
internal.Ring(title, k.Focus, theme.ControlRadius)
|
|
title.Children(func() {
|
|
t := ui.Text(c, task.Title).SingleLine().Ellipsis("…").TextColor(k.Text)
|
|
if task.Done {
|
|
t.Strikethrough().TextColor(k.TextMuted)
|
|
}
|
|
})
|
|
if !title.IsDisabled() {
|
|
if title.DoubleClicked() || title.Shortcut(0, ui.KeyF2) {
|
|
*edit = taskItemEdit{on: true, draft: task.Title}
|
|
} else if title.Clicked() {
|
|
r.opened = task.ID
|
|
}
|
|
}
|
|
PriorityIndicator(c, task.Priority, PriorityIndicatorOptions{IconOnly: true})
|
|
if text, late := projectDueText(c, task.Due, today, task.Done); text != "" {
|
|
fg := k.TextMuted
|
|
if late {
|
|
fg = k.Danger
|
|
}
|
|
ui.Text(c, text).FontSize(FontSize(c, theme.CaptionSize)).TextColor(fg).SingleLine().Shrink(0)
|
|
}
|
|
if len(task.Assignees) > 0 {
|
|
items := make([]AvatarItem, len(task.Assignees))
|
|
for i, id := range task.Assignees {
|
|
items[i] = AvatarItem{Name: projectMember(opts.Members, id).Name}
|
|
}
|
|
AvatarGroup(c, items, AvatarGroupOptions{Max: 2, Size: 24})
|
|
}
|
|
})
|
|
return r
|
|
}
|