add task system and task model for viewing task details

This commit is contained in:
Robin Olsen
2026-02-12 20:40:55 +01:00
parent da8ab0833e
commit 183f13895b
7 changed files with 234 additions and 0 deletions

View File

@@ -0,0 +1,22 @@
package tasks
import (
"context"
"github.com/LazyBachelor/LazyPM/internal/service"
tea "github.com/charmbracelet/bubbletea"
)
func (t *Task) IntroduceTask() error {
_, err := tea.NewProgram(t.aboutScreen, tea.WithAltScreen()).Run()
return err
}
func (t *Task) StartInterface(ctx context.Context, cfg service.Config) error {
return t.interfaceType.Run(ctx, cfg)
}
func (t *Task) StartQuestionnaire() error {
_, err := tea.NewProgram(t.questionnaire, tea.WithAltScreen()).Run()
return err
}

45
cmd/survey/tasks/task.go Normal file
View File

@@ -0,0 +1,45 @@
// task.go
package tasks
import (
"context"
"errors"
"github.com/LazyBachelor/LazyPM/internal/service"
tea "github.com/charmbracelet/bubbletea"
)
func NewTask(interfaceType Interface, aboutScreen tea.Model, questionnaire tea.Model) *Task {
return &Task{
interfaceType: interfaceType,
aboutScreen: aboutScreen,
questionnaire: questionnaire,
}
}
func (t *Task) SetValidateFunc(fn ValidateFunc) {
t.validateFunc = fn
}
func (t *Task) SetDbStateFunc(fn DbStateFunc) {
t.dbStateFunc = fn
}
func (t *Task) SetInterface(interfaceType Interface) {
t.interfaceType = interfaceType
}
func (t *Task) Validate(ctx context.Context, svc *service.Services) (bool, error) {
if t.validateFunc == nil {
return false, errors.New("validateFunc is not set")
}
return t.validateFunc(ctx, svc)
}
func (t *Task) MigrateToTask(ctx context.Context, svc *service.Services, task *Task) error {
t = task
if t.dbStateFunc == nil {
return errors.New("dbStateFunc is not set")
}
return t.dbStateFunc(ctx, svc)
}

29
cmd/survey/tasks/types.go Normal file
View File

@@ -0,0 +1,29 @@
package tasks
import (
"context"
"github.com/LazyBachelor/LazyPM/internal/service"
tea "github.com/charmbracelet/bubbletea"
)
type Interface interface {
Run(context.Context, service.Config) error
}
type ValidateFunc func(context.Context, *service.Services) (ok bool, err error)
type DbStateFunc func(context.Context, *service.Services) error
type Task struct {
interfaceType Interface
aboutScreen tea.Model
questionnaire tea.Model
validateFunc ValidateFunc
dbStateFunc DbStateFunc
}
type TaskList struct {
Todo []*Task
Done []*Task
}

27
cmd/survey/ui/help.go Normal file
View File

@@ -0,0 +1,27 @@
package ui
import "github.com/charmbracelet/bubbles/key"
type TaskHelpKeys struct {
Quit key.Binding
Continue key.Binding
}
var DefaultTaskKeys = TaskHelpKeys{
Quit: key.NewBinding(
key.WithKeys("q", "ctrl+c"),
key.WithHelp("q", "Quit"),
),
Continue: key.NewBinding(
key.WithKeys(" "),
key.WithHelp("space", "Continue"),
),
}
func (h TaskHelpKeys) ShortHelp() []key.Binding {
return []key.Binding{h.Continue, h.Quit}
}
func (h TaskHelpKeys) FullHelp() [][]key.Binding {
return [][]key.Binding{{h.Continue, h.Quit}}
}

14
cmd/survey/ui/style.go Normal file
View File

@@ -0,0 +1,14 @@
package ui
import (
"github.com/charmbracelet/huh"
"github.com/charmbracelet/lipgloss"
)
func theme() *huh.Theme {
theme := huh.ThemeBase16()
theme.Focused.Base = lipgloss.NewStyle().Align(lipgloss.Center)
return theme
}

69
cmd/survey/ui/task.go Normal file
View File

@@ -0,0 +1,69 @@
package ui
import (
"charm.land/lipgloss/v2"
"github.com/charmbracelet/bubbles/help"
"github.com/charmbracelet/bubbles/key"
tea "github.com/charmbracelet/bubbletea"
)
func NewTaskModel(details TaskDetails) TaskModel {
return TaskModel{
TaskDetails: details,
keys: DefaultTaskKeys,
help: help.New(),
}
}
func (m TaskModel) Init() tea.Cmd {
return nil
}
func (t TaskModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.WindowSizeMsg:
t.SetSize(msg.Width, msg.Height)
case tea.KeyMsg:
switch {
case key.Matches(msg, t.keys.Quit):
return t, tea.Quit
case key.Matches(msg, t.keys.Continue):
return t, tea.Quit
}
}
return t, nil
}
func (m TaskModel) View() string {
padding := 3
header := lipgloss.NewStyle().
PaddingTop(padding).Width(m.width).Align(lipgloss.Center).
Bold(true).Render(m.Title)
headerHeight := lipgloss.Height(header)
helpView := lipgloss.NewStyle().
PaddingBottom(padding).
Width(m.width).Align(lipgloss.Center).
Render(m.help.View(m.keys))
helpHeigh := lipgloss.Height(helpView)
details := lipgloss.NewStyle().Align(lipgloss.Center).
Width(m.width).PaddingBottom(1).Render("Time to complete:", m.TimeToComplete, "Difficulty:", m.Difficulty)
detailsHeight := lipgloss.Height(details)
content := lipgloss.NewStyle().
Width(m.width).Height(m.height-headerHeight-helpHeigh-detailsHeight).
Align(lipgloss.Center, lipgloss.Center).
Render(m.Description)
return lipgloss.JoinVertical(lipgloss.Top, header, content, details, helpView)
}
func (m *TaskModel) SetSize(width, height int) {
m.width, m.height = width, height
}

28
cmd/survey/ui/types.go Normal file
View File

@@ -0,0 +1,28 @@
package ui
import (
"github.com/charmbracelet/bubbles/help"
"github.com/charmbracelet/huh"
)
type TaskDetails struct {
Title string
Description string
TimeToComplete string
Difficulty string
}
type TaskModel struct {
TaskDetails
keys TaskHelpKeys
help help.Model
width, height int
}
type Questions []*huh.Group
type QuestionnaireModel struct {
Questions
form *huh.Form
width, height int
}