Skip to content

Commit

Permalink
Merge pull request #1985 from fpabl0/fix/1965
Browse files Browse the repository at this point in the history
Guarantee widget.Form tracks all entry validation changes, fixes #1965
  • Loading branch information
Jacalz committed Feb 21, 2021
2 parents 78b4eaf + 59a7a0d commit 7d2b239
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 2 deletions.
14 changes: 12 additions & 2 deletions widget/form.go
@@ -1,13 +1,19 @@
package widget

import (
"errors"

"fyne.io/fyne/v2"
"fyne.io/fyne/v2/canvas"
"fyne.io/fyne/v2/internal/cache"
"fyne.io/fyne/v2/layout"
"fyne.io/fyne/v2/theme"
)

// errFormItemInitialState defines the error if the initial validation for a FormItem result
// in an error
var errFormItemInitialState = errors.New("widget.FormItem initial state error")

// FormItem provides the details for a row in a form
type FormItem struct {
Text string
Expand Down Expand Up @@ -155,10 +161,14 @@ func (f *Form) checkValidation(err error) {
func (f *Form) setUpValidation(widget fyne.CanvasObject, i int) {
if w, ok := widget.(fyne.Validatable); ok {
f.Items[i].invalid = w.Validate() != nil
if e, ok := w.(*Entry); ok && e.Validator != nil {
e.SetValidationError(nil) // clear initial state, will appear when we type
if e, ok := w.(*Entry); ok && e.Validator != nil && f.Items[i].invalid {
// set initial state error to guarantee next error (if triggers) is always different
e.SetValidationError(errFormItemInitialState)
}
w.SetOnValidationChanged(func(err error) {
if err == errFormItemInitialState {
return
}
f.Items[i].validationError = err
f.Items[i].invalid = err != nil
f.checkValidation(err)
Expand Down
44 changes: 44 additions & 0 deletions widget/form_test.go
@@ -1,6 +1,7 @@
package widget

import (
"errors"
"testing"

"fyne.io/fyne/v2"
Expand Down Expand Up @@ -188,3 +189,46 @@ func TestForm_Validation(t *testing.T) {

test.AssertImageMatches(t, "form/validation_valid.png", w.Canvas().Capture())
}

func TestForm_EntryValidation_FirstTypeValid(t *testing.T) {
app := test.NewApp()
defer test.NewApp()
app.Settings().SetTheme(theme.LightTheme())

notEmptyValidator := func(s string) error {
if s == "" {
return errors.New("can't be empty")
}
return nil
}

entry1 := &Entry{Validator: notEmptyValidator, Text: ""}
entry2 := &Entry{Validator: notEmptyValidator, Text: ""}
items := []*FormItem{
{Text: "First", Widget: entry1},
{Text: "Second", Widget: entry2},
}

form := &Form{Items: items, OnSubmit: func() {}, OnCancel: func() {}}
w := test.NewWindow(form)
defer w.Close()

assert.Equal(t, errFormItemInitialState, entry1.validationError)
assert.Equal(t, errFormItemInitialState, entry2.validationError)

test.AssertImageMatches(t, "form/validation_entry_first_type_initial.png", w.Canvas().Capture())

test.Type(entry1, "H")
test.Type(entry2, "L")
entry1.focused = false
entry1.Refresh()
w = test.NewWindow(form)

test.AssertImageMatches(t, "form/validation_entry_first_type_valid.png", w.Canvas().Capture())

entry1.SetText("")
entry2.SetText("")
w = test.NewWindow(form)

test.AssertImageMatches(t, "form/validation_entry_first_type_invalid.png", w.Canvas().Capture())
}
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 7d2b239

Please sign in to comment.