add exit mechanicm to each stage
remove types and moved struct to appropriate files
This commit is contained in:
@@ -1,11 +1,13 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/LazyBachelor/LazyPM/internal/style"
|
"errors"
|
||||||
|
|
||||||
tea "github.com/charmbracelet/bubbletea"
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
"github.com/charmbracelet/huh"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var ErrUserQuit = errors.New("user quit")
|
||||||
|
|
||||||
const (
|
const (
|
||||||
IntroTitle = "Welcome to the Task Survey!"
|
IntroTitle = "Welcome to the Task Survey!"
|
||||||
|
|
||||||
@@ -21,54 +23,60 @@ By participating, you consent to the collection and use of your data as describe
|
|||||||
)
|
)
|
||||||
|
|
||||||
type introModel struct {
|
type introModel struct {
|
||||||
form *huh.Form
|
stage int
|
||||||
width, height int
|
width, height int
|
||||||
|
userQuit bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func newIntroModel() introModel {
|
func newIntroModel() introModel {
|
||||||
return introModel{
|
return introModel{
|
||||||
form: huh.NewForm(
|
stage: 0,
|
||||||
huh.NewGroup(
|
|
||||||
huh.NewNote().Title(IntroTitle).Description(IntroductionText),
|
|
||||||
),
|
|
||||||
huh.NewGroup(
|
|
||||||
huh.NewNote().Title("Disclaimer").Description(Disclaimer),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m introModel) Init() tea.Cmd {
|
func (m introModel) Init() tea.Cmd {
|
||||||
m.form.Init()
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m introModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
func (m introModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
switch msg := msg.(type) {
|
switch msg := msg.(type) {
|
||||||
case tea.KeyMsg:
|
|
||||||
switch msg.Type {
|
|
||||||
case tea.KeyEsc, tea.KeyCtrlC:
|
|
||||||
return m, tea.Quit
|
|
||||||
}
|
|
||||||
case tea.WindowSizeMsg:
|
case tea.WindowSizeMsg:
|
||||||
m.SetSize(msg.Width, msg.Height)
|
m.SetSize(msg.Width, msg.Height)
|
||||||
|
case tea.KeyMsg:
|
||||||
|
switch msg.Type {
|
||||||
|
case tea.KeyEnter, tea.KeySpace:
|
||||||
|
m.stage++
|
||||||
|
if m.stage > 1 {
|
||||||
|
return m, tea.Quit
|
||||||
|
}
|
||||||
|
case tea.KeyEsc, tea.KeyCtrlC:
|
||||||
|
m.userQuit = true
|
||||||
|
return m, tea.Quit
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
form, cmd := m.form.Update(msg)
|
return m, nil
|
||||||
if f, ok := form.(*huh.Form); ok {
|
|
||||||
m.form = f
|
|
||||||
}
|
|
||||||
|
|
||||||
return m, cmd
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m introModel) View() string {
|
func (m introModel) View() string {
|
||||||
return m.form.WithTheme(style.HuhCenterTheme()).View()
|
switch m.stage {
|
||||||
|
case 0:
|
||||||
|
return IntroductionText
|
||||||
|
case 1:
|
||||||
|
return Disclaimer
|
||||||
|
}
|
||||||
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m introModel) Run() error {
|
func (m introModel) Run() error {
|
||||||
_, err := tea.NewProgram(m, tea.WithAltScreen()).Run()
|
model, err := tea.NewProgram(m, tea.WithAltScreen()).Run()
|
||||||
return err
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if m, ok := model.(introModel); ok && m.userQuit {
|
||||||
|
return ErrUserQuit
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *introModel) SetSize(width, height int) {
|
func (m *introModel) SetSize(width, height int) {
|
||||||
|
|||||||
@@ -2,9 +2,11 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
"os"
|
||||||
|
|
||||||
"github.com/LazyBachelor/LazyPM/internal/service"
|
"github.com/LazyBachelor/LazyPM/internal/service"
|
||||||
"github.com/LazyBachelor/LazyPM/pkg/task"
|
"github.com/LazyBachelor/LazyPM/pkg/task"
|
||||||
@@ -14,6 +16,9 @@ func main() {
|
|||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
if err := newIntroModel().Run(); err != nil {
|
if err := newIntroModel().Run(); err != nil {
|
||||||
|
if errors.Is(err, ErrUserQuit) {
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
log.Fatalf("Failed to run intro screen: %v\n", err)
|
log.Fatalf("Failed to run intro screen: %v\n", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27,6 +32,9 @@ func main() {
|
|||||||
interfaces := initInterfaces()
|
interfaces := initInterfaces()
|
||||||
|
|
||||||
if err := taskLoop(ctx, svc, surveyTasks, interfaces); err != nil {
|
if err := taskLoop(ctx, svc, surveyTasks, interfaces); err != nil {
|
||||||
|
if errors.Is(err, task.ErrUserQuit) {
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
log.Fatalf("Task loop failed: %v\n", err)
|
log.Fatalf("Task loop failed: %v\n", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -34,23 +42,26 @@ func main() {
|
|||||||
func taskLoop(ctx context.Context, svc *service.Services, surveyTasks []*task.Task, interfaces []task.Interface) error {
|
func taskLoop(ctx context.Context, svc *service.Services, surveyTasks []*task.Task, interfaces []task.Interface) error {
|
||||||
interfaceIndex := rand.Int() % len(interfaces)
|
interfaceIndex := rand.Int() % len(interfaces)
|
||||||
|
|
||||||
for _, task := range surveyTasks {
|
for _, t := range surveyTasks {
|
||||||
|
|
||||||
task.SetInterface(interfaces[interfaceIndex])
|
t.SetInterface(interfaces[interfaceIndex])
|
||||||
|
|
||||||
if err := task.Initialize(ctx, svc); err != nil {
|
if err := t.Initialize(ctx, svc); err != nil {
|
||||||
return fmt.Errorf("failed to initialize task: %w", err)
|
return fmt.Errorf("failed to initialize task: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := task.IntroduceTask(); err != nil {
|
if err := t.IntroduceTask(); err != nil {
|
||||||
|
if errors.Is(err, task.ErrUserQuit) {
|
||||||
|
return task.ErrUserQuit
|
||||||
|
}
|
||||||
return fmt.Errorf("failed to display task introduction screen: %w", err)
|
return fmt.Errorf("failed to display task introduction screen: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := task.StartInterface(ctx, task.Config); err != nil {
|
if err := t.StartInterface(ctx, t.Config); err != nil {
|
||||||
return fmt.Errorf("failed to start task interface: %w", err)
|
return fmt.Errorf("failed to start task interface: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ok, err := task.Validate(ctx, svc)
|
ok, err := t.Validate(ctx, svc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("validation error: %w", err)
|
return fmt.Errorf("validation error: %w", err)
|
||||||
}
|
}
|
||||||
@@ -58,7 +69,10 @@ func taskLoop(ctx context.Context, svc *service.Services, surveyTasks []*task.Ta
|
|||||||
return fmt.Errorf("task validation failed: task did not meet requirements")
|
return fmt.Errorf("task validation failed: task did not meet requirements")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := task.StartQuestionnaire(); err != nil {
|
if err := t.StartQuestionnaire(); err != nil {
|
||||||
|
if errors.Is(err, task.ErrUserQuit) {
|
||||||
|
return task.ErrUserQuit
|
||||||
|
}
|
||||||
return fmt.Errorf("failed to start questionnaire: %w", err)
|
return fmt.Errorf("failed to start questionnaire: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,8 +11,14 @@ func (t *Task) IntroduceTask() error {
|
|||||||
if t.aboutScreen == nil {
|
if t.aboutScreen == nil {
|
||||||
return fmt.Errorf("aboutScreen is not set")
|
return fmt.Errorf("aboutScreen is not set")
|
||||||
}
|
}
|
||||||
_, err := tea.NewProgram(t.aboutScreen, tea.WithAltScreen()).Run()
|
model, err := tea.NewProgram(t.aboutScreen, tea.WithAltScreen()).Run()
|
||||||
return err
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if m, ok := model.(interface{ GetUserQuit() bool }); ok && m.GetUserQuit() {
|
||||||
|
return ErrUserQuit
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Task) StartInterface(ctx context.Context, cfg TaskConfig) error {
|
func (t *Task) StartInterface(ctx context.Context, cfg TaskConfig) error {
|
||||||
@@ -27,6 +33,12 @@ func (t *Task) StartQuestionnaire() error {
|
|||||||
if t.questionnaire == nil {
|
if t.questionnaire == nil {
|
||||||
return fmt.Errorf("questionnaire is not set")
|
return fmt.Errorf("questionnaire is not set")
|
||||||
}
|
}
|
||||||
_, err := tea.NewProgram(t.questionnaire, tea.WithAltScreen()).Run()
|
model, err := tea.NewProgram(t.questionnaire, tea.WithAltScreen()).Run()
|
||||||
return err
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if m, ok := model.(interface{ GetUserQuit() bool }); ok && m.GetUserQuit() {
|
||||||
|
return ErrUserQuit
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,10 +2,13 @@ package task
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
|
|
||||||
"github.com/LazyBachelor/LazyPM/internal/service"
|
"github.com/LazyBachelor/LazyPM/internal/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var ErrUserQuit = errors.New("user quit")
|
||||||
|
|
||||||
type TaskConfig = service.Config
|
type TaskConfig = service.Config
|
||||||
|
|
||||||
type Interface interface {
|
type Interface interface {
|
||||||
|
|||||||
@@ -7,6 +7,15 @@ import (
|
|||||||
"github.com/charmbracelet/huh"
|
"github.com/charmbracelet/huh"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Questions []*huh.Group
|
||||||
|
|
||||||
|
type QuestionnaireModel struct {
|
||||||
|
Questions
|
||||||
|
form *huh.Form
|
||||||
|
width, height int
|
||||||
|
userQuit bool
|
||||||
|
}
|
||||||
|
|
||||||
func NewQuestionnaireModel(questions Questions) *QuestionnaireModel {
|
func NewQuestionnaireModel(questions Questions) *QuestionnaireModel {
|
||||||
form := huh.NewForm(questions...).
|
form := huh.NewForm(questions...).
|
||||||
WithTheme(style.HuhCenterTheme()).WithLayout(huh.LayoutGrid(1, 1))
|
WithTheme(style.HuhCenterTheme()).WithLayout(huh.LayoutGrid(1, 1))
|
||||||
@@ -28,6 +37,7 @@ func (q *QuestionnaireModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
case tea.KeyMsg:
|
case tea.KeyMsg:
|
||||||
switch msg.String() {
|
switch msg.String() {
|
||||||
case "q", "ctrl+c":
|
case "q", "ctrl+c":
|
||||||
|
q.userQuit = true
|
||||||
return q, tea.Quit
|
return q, tea.Quit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -52,3 +62,7 @@ func (q *QuestionnaireModel) View() string {
|
|||||||
func (q *QuestionnaireModel) SetSize(width, height int) {
|
func (q *QuestionnaireModel) SetSize(width, height int) {
|
||||||
q.width, q.height = width, height
|
q.width, q.height = width, height
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (q QuestionnaireModel) GetUserQuit() bool {
|
||||||
|
return q.userQuit
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package taskui
|
package taskui
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"charm.land/lipgloss/v2"
|
"charm.land/lipgloss/v2"
|
||||||
@@ -9,6 +10,23 @@ import (
|
|||||||
tea "github.com/charmbracelet/bubbletea"
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var ErrUserQuit = errors.New("user quit")
|
||||||
|
|
||||||
|
type TaskDetails struct {
|
||||||
|
Title string
|
||||||
|
Description string
|
||||||
|
TimeToComplete string
|
||||||
|
Difficulty string
|
||||||
|
}
|
||||||
|
|
||||||
|
type TaskModel struct {
|
||||||
|
TaskDetails
|
||||||
|
keys TaskHelpKeys
|
||||||
|
help help.Model
|
||||||
|
width, height int
|
||||||
|
userQuit bool
|
||||||
|
}
|
||||||
|
|
||||||
func NewTaskModel(details TaskDetails) TaskModel {
|
func NewTaskModel(details TaskDetails) TaskModel {
|
||||||
return TaskModel{
|
return TaskModel{
|
||||||
TaskDetails: details,
|
TaskDetails: details,
|
||||||
@@ -28,6 +46,7 @@ func (m TaskModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
case tea.KeyMsg:
|
case tea.KeyMsg:
|
||||||
switch {
|
switch {
|
||||||
case key.Matches(msg, m.keys.Quit):
|
case key.Matches(msg, m.keys.Quit):
|
||||||
|
m.userQuit = true
|
||||||
return m, tea.Quit
|
return m, tea.Quit
|
||||||
case key.Matches(msg, m.keys.Continue):
|
case key.Matches(msg, m.keys.Continue):
|
||||||
return m, tea.Quit
|
return m, tea.Quit
|
||||||
@@ -70,3 +89,7 @@ func (m TaskModel) View() string {
|
|||||||
func (m *TaskModel) SetSize(width, height int) {
|
func (m *TaskModel) SetSize(width, height int) {
|
||||||
m.width, m.height = width, height
|
m.width, m.height = width, height
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m TaskModel) GetUserQuit() bool {
|
||||||
|
return m.userQuit
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
package taskui
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user