Add more validation

This commit is contained in:
IamTheFij 2024-10-18 12:21:55 -07:00
parent 9d35e65c07
commit 71aa5ed835

105
main.go
View File

@ -6,6 +6,7 @@ import (
"os/exec" "os/exec"
"os/signal" "os/signal"
"strconv" "strconv"
"strings"
"time" "time"
"github.com/charmbracelet/bubbles/progress" "github.com/charmbracelet/bubbles/progress"
@ -44,6 +45,7 @@ type model struct {
fullscreen bool fullscreen bool
width int width int
height int height int
err error
} }
func initialModel(fullscreen bool, colorLeft string, colorRight string) model { func initialModel(fullscreen bool, colorLeft string, colorRight string) model {
@ -53,14 +55,28 @@ func initialModel(fullscreen bool, colorLeft string, colorRight string) model {
for i := range inputs { for i := range inputs {
inputs[i] = textinput.New() inputs[i] = textinput.New()
inputs[i].CharLimit = 10 // Increase char limit to allow duration strings inputs[i].CharLimit = 10 // Increase char limit to allow duration strings
if i == 0 { if i == 0 {
inputs[i].Focus() // Start focus on first input inputs[i].Focus() // Start focus on first input
} }
} }
validateDuration := func(text string) error {
_, err := parseDuration(text)
return err
}
validateInt := func(text string) error {
_, err := strconv.Atoi(text)
return fmt.Errorf("invalid int input: %w", err)
}
inputs[0].Placeholder = "Interval length (minutes or duration)" inputs[0].Placeholder = "Interval length (minutes or duration)"
inputs[0].Validate = validateDuration
inputs[1].Placeholder = "Break length (minutes or duration)" inputs[1].Placeholder = "Break length (minutes or duration)"
inputs[1].Validate = validateDuration
inputs[2].Placeholder = "Number of intervals" inputs[2].Placeholder = "Number of intervals"
inputs[2].Validate = validateInt
return model{ return model{
inputs: inputs, inputs: inputs,
@ -79,6 +95,7 @@ func (m model) Init() tea.Cmd {
// Handle Ctrl+C for graceful exit // Handle Ctrl+C for graceful exit
c := make(chan os.Signal, 1) c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt) signal.Notify(c, os.Interrupt)
go func() { go func() {
<-c <-c
fmt.Println("\nExiting...") fmt.Println("\nExiting...")
@ -114,15 +131,22 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
if m.focusIndex == len(m.inputs)-1 { if m.focusIndex == len(m.inputs)-1 {
focusTime, err := parseDuration(m.inputs[0].Value()) focusTime, err := parseDuration(m.inputs[0].Value())
if err != nil { if err != nil {
focusTime, _ = time.ParseDuration(m.inputs[0].Value() + "m") m.err = fmt.Errorf("error parsing focus time duration: %w", err)
return m, nil
} }
breakTime, err := parseDuration(m.inputs[1].Value()) breakTime, err := parseDuration(m.inputs[1].Value())
if err != nil { if err != nil {
breakTime, _ = time.ParseDuration(m.inputs[1].Value() + "m") m.err = fmt.Errorf("error parsing break time duration: %w", err)
return m, nil
}
m.intervals, err = strconv.Atoi(m.inputs[2].Value())
if err != nil {
m.err = fmt.Errorf("error parsing interval: %w", err)
return m, nil
} }
m.intervals = atoi(m.inputs[2].Value())
m.focusTime = focusTime m.focusTime = focusTime
m.breakTime = breakTime m.breakTime = breakTime
m.remaining = focusTime m.remaining = focusTime
@ -203,24 +227,41 @@ func tick() tea.Cmd {
// View rendering for input and timer screens // View rendering for input and timer screens
func (m model) View() string { func (m model) View() string {
var s strings.Builder
switch m.currentScreen { switch m.currentScreen {
case inputScreen: case inputScreen:
return m.inputScreenView() s.WriteString(m.inputScreenView())
case timerScreen: case timerScreen:
return m.timerScreenView() s.WriteString(m.timerScreenView())
} }
return ""
if m.err != nil {
s.WriteString(fmt.Sprintf("\n\nError: %v", m.err))
}
return s.String()
} }
// View for input screen // View for input screen
func (m model) inputScreenView() string { func (m model) inputScreenView() string {
var builder string var builder strings.Builder
builder = "Enter your Pomodoro settings:\n\n"
builder.WriteString("Enter your Pomodoro settings:\n\n")
for i := range m.inputs { for i := range m.inputs {
builder += m.inputs[i].View() + "\n" builder.WriteString(m.inputs[i].View())
if m.inputs[i].Value() != "" && m.inputs[i].Err != nil {
builder.WriteString(fmt.Sprintf("Error: %v", m.inputs[i].Err))
}
builder.WriteString("\n")
} }
builder += "\nUse TAB to navigate, ENTER to start."
return builder builder.WriteString("\nUse TAB to navigate, ENTER to start.")
return builder.String()
} }
// View for timer screen with optional fullscreen centering // View for timer screen with optional fullscreen centering
@ -236,6 +277,7 @@ func (m model) timerScreenView() string {
if m.fullscreen { if m.fullscreen {
return lipgloss.NewStyle().Width(m.width).Height(m.height).Align(lipgloss.Center, lipgloss.Center).Render(timerView) return lipgloss.NewStyle().Width(m.width).Height(m.height).Align(lipgloss.Center, lipgloss.Center).Render(timerView)
} }
return timerView return timerView
} }
@ -256,6 +298,7 @@ func (m *model) runCommands(commands []string) {
cmd := exec.Command("sh", "-c", cmdStr) cmd := exec.Command("sh", "-c", cmdStr)
cmd.Stdout = os.Stdout cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil { if err := cmd.Run(); err != nil {
fmt.Printf("Error running command: %v\n", err) fmt.Printf("Error running command: %v\n", err)
} }
@ -267,13 +310,13 @@ func parseDuration(input string) (time.Duration, error) {
if minutes, err := strconv.Atoi(input); err == nil { if minutes, err := strconv.Atoi(input); err == nil {
return time.Duration(minutes) * time.Minute, nil return time.Duration(minutes) * time.Minute, nil
} }
return time.ParseDuration(input)
}
// Helper to convert string to int d, err := time.ParseDuration(input)
func atoi(s string) int { if err != nil {
n, _ := strconv.Atoi(s) return d, fmt.Errorf("error parsing duration: %w", err)
return n }
return d, nil
} }
func main() { func main() {
@ -299,26 +342,29 @@ func main() {
Usage: "Enable fullscreen mode", Usage: "Enable fullscreen mode",
}, },
&cli.DurationFlag{ &cli.DurationFlag{
Name: "focus", Name: "focus",
Usage: "Focus time duration (default prompt for input)", Usage: "Focus time duration",
DefaultText: "prompt for input",
}, },
&cli.DurationFlag{ &cli.DurationFlag{
Name: "break", Name: "break",
Usage: "Break time duration (default prompt for input)", Usage: "Break time duration",
DefaultText: "prompt for input",
}, },
&cli.IntFlag{ &cli.IntFlag{
Name: "intervals", Name: "intervals",
Usage: "Number of intervals (default prompt for input)", Usage: "Number of intervals",
DefaultText: "prompt for input",
}, },
&cli.StringFlag{ &cli.StringFlag{
Name: "color-left", Name: "color-left",
Usage: "Left color for progress bar", Usage: "Left color for progress bar",
DefaultText: "#ffdd57", Value: "#ffdd57",
}, },
&cli.StringFlag{ &cli.StringFlag{
Name: "color-right", Name: "color-right",
Usage: "Right color for progress bar", Usage: "Right color for progress bar",
DefaultText: "#57ddff", Value: "#57ddff",
}, },
&cli.BoolFlag{ &cli.BoolFlag{
Name: "version", Name: "version",
@ -352,6 +398,7 @@ func main() {
// Start tea program // Start tea program
p := tea.NewProgram(m, tea.WithAltScreen()) p := tea.NewProgram(m, tea.WithAltScreen())
_, err := p.Run() _, err := p.Run()
return err return err
}, },
} }