Add more validation
This commit is contained in:
parent
9d35e65c07
commit
71aa5ed835
105
main.go
105
main.go
@ -6,6 +6,7 @@ import (
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/charmbracelet/bubbles/progress"
|
||||
@ -44,6 +45,7 @@ type model struct {
|
||||
fullscreen bool
|
||||
width int
|
||||
height int
|
||||
err error
|
||||
}
|
||||
|
||||
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 {
|
||||
inputs[i] = textinput.New()
|
||||
inputs[i].CharLimit = 10 // Increase char limit to allow duration strings
|
||||
|
||||
if i == 0 {
|
||||
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].Validate = validateDuration
|
||||
inputs[1].Placeholder = "Break length (minutes or duration)"
|
||||
inputs[1].Validate = validateDuration
|
||||
inputs[2].Placeholder = "Number of intervals"
|
||||
inputs[2].Validate = validateInt
|
||||
|
||||
return model{
|
||||
inputs: inputs,
|
||||
@ -79,6 +95,7 @@ func (m model) Init() tea.Cmd {
|
||||
// Handle Ctrl+C for graceful exit
|
||||
c := make(chan os.Signal, 1)
|
||||
signal.Notify(c, os.Interrupt)
|
||||
|
||||
go func() {
|
||||
<-c
|
||||
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 {
|
||||
focusTime, err := parseDuration(m.inputs[0].Value())
|
||||
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())
|
||||
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.breakTime = breakTime
|
||||
m.remaining = focusTime
|
||||
@ -203,24 +227,41 @@ func tick() tea.Cmd {
|
||||
|
||||
// View rendering for input and timer screens
|
||||
func (m model) View() string {
|
||||
var s strings.Builder
|
||||
|
||||
switch m.currentScreen {
|
||||
case inputScreen:
|
||||
return m.inputScreenView()
|
||||
s.WriteString(m.inputScreenView())
|
||||
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
|
||||
func (m model) inputScreenView() string {
|
||||
var builder string
|
||||
builder = "Enter your Pomodoro settings:\n\n"
|
||||
var builder strings.Builder
|
||||
|
||||
builder.WriteString("Enter your Pomodoro settings:\n\n")
|
||||
|
||||
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
|
||||
@ -236,6 +277,7 @@ func (m model) timerScreenView() string {
|
||||
if m.fullscreen {
|
||||
return lipgloss.NewStyle().Width(m.width).Height(m.height).Align(lipgloss.Center, lipgloss.Center).Render(timerView)
|
||||
}
|
||||
|
||||
return timerView
|
||||
}
|
||||
|
||||
@ -256,6 +298,7 @@ func (m *model) runCommands(commands []string) {
|
||||
cmd := exec.Command("sh", "-c", cmdStr)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
if err := cmd.Run(); err != nil {
|
||||
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 {
|
||||
return time.Duration(minutes) * time.Minute, nil
|
||||
}
|
||||
return time.ParseDuration(input)
|
||||
}
|
||||
|
||||
// Helper to convert string to int
|
||||
func atoi(s string) int {
|
||||
n, _ := strconv.Atoi(s)
|
||||
return n
|
||||
d, err := time.ParseDuration(input)
|
||||
if err != nil {
|
||||
return d, fmt.Errorf("error parsing duration: %w", err)
|
||||
}
|
||||
|
||||
return d, nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
@ -299,26 +342,29 @@ func main() {
|
||||
Usage: "Enable fullscreen mode",
|
||||
},
|
||||
&cli.DurationFlag{
|
||||
Name: "focus",
|
||||
Usage: "Focus time duration (default prompt for input)",
|
||||
Name: "focus",
|
||||
Usage: "Focus time duration",
|
||||
DefaultText: "prompt for input",
|
||||
},
|
||||
&cli.DurationFlag{
|
||||
Name: "break",
|
||||
Usage: "Break time duration (default prompt for input)",
|
||||
Name: "break",
|
||||
Usage: "Break time duration",
|
||||
DefaultText: "prompt for input",
|
||||
},
|
||||
&cli.IntFlag{
|
||||
Name: "intervals",
|
||||
Usage: "Number of intervals (default prompt for input)",
|
||||
Name: "intervals",
|
||||
Usage: "Number of intervals",
|
||||
DefaultText: "prompt for input",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "color-left",
|
||||
Usage: "Left color for progress bar",
|
||||
DefaultText: "#ffdd57",
|
||||
Name: "color-left",
|
||||
Usage: "Left color for progress bar",
|
||||
Value: "#ffdd57",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "color-right",
|
||||
Usage: "Right color for progress bar",
|
||||
DefaultText: "#57ddff",
|
||||
Name: "color-right",
|
||||
Usage: "Right color for progress bar",
|
||||
Value: "#57ddff",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "version",
|
||||
@ -352,6 +398,7 @@ func main() {
|
||||
// Start tea program
|
||||
p := tea.NewProgram(m, tea.WithAltScreen())
|
||||
_, err := p.Run()
|
||||
|
||||
return err
|
||||
},
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user