From a12895768856a98f01191700dac92ff245b04812 Mon Sep 17 00:00:00 2001 From: FPabl0 Date: Sat, 15 May 2021 02:49:14 -0500 Subject: [PATCH 1/3] fix notEmpty validator behavior in widget.Entry --- widget/entry.go | 25 ++++++++++++------- widget/entry_validation.go | 6 ++--- widget/entry_validation_test.go | 24 ++++++++++++++++++ .../entry/validator_not_empty_focused.xml | 21 ++++++++++++++++ .../entry/validator_not_empty_initial.xml | 20 +++++++++++++++ .../entry/validator_not_empty_unfocused.xml | 21 ++++++++++++++++ 6 files changed, 105 insertions(+), 12 deletions(-) create mode 100644 widget/testdata/entry/validator_not_empty_focused.xml create mode 100644 widget/testdata/entry/validator_not_empty_initial.xml create mode 100644 widget/testdata/entry/validator_not_empty_unfocused.xml diff --git a/widget/entry.go b/widget/entry.go index bc72eddc94..f7ba7d6592 100644 --- a/widget/entry.go +++ b/widget/entry.go @@ -59,6 +59,7 @@ type Entry struct { cursorAnim *entryCursorAnimation + dirty bool focused bool text *textProvider placeholder *textProvider @@ -142,7 +143,7 @@ func (e *Entry) Bind(data binding.String) { val, err := data.Get() if err != nil { convertErr = err - e.SetValidationError(e.Validate()) + e.Validate() return } e.Text = val @@ -156,7 +157,7 @@ func (e *Entry) Bind(data binding.String) { e.OnChanged = func(s string) { convertErr = data.Set(s) - e.SetValidationError(e.Validate()) + e.Validate() } } @@ -303,6 +304,7 @@ func (e *Entry) ExtendBaseWidget(wid fyne.Widget) { // Implements: fyne.Focusable func (e *Entry) FocusGained() { e.setFieldsAndRefresh(func() { + e.dirty = true e.focused = true }) } @@ -1033,6 +1035,10 @@ func (e *Entry) textProvider() *textProvider { return e.text } + if e.Text != "" { + e.dirty = true + } + text := newTextProvider(e.Text, e) text.ExtendBaseWidget(text) text.inset = fyne.NewSize(0, theme.InputBorderSize()) @@ -1080,14 +1086,16 @@ func (e *Entry) updateText(text string) { changed := e.Text != text e.Text = text + if e.Text != "" { + e.dirty = true + } + if changed { callback = e.OnChanged } }) - if validate := e.Validator; validate != nil { - e.SetValidationError(validate(text)) - } + e.Validate() if callback != nil { callback(text) @@ -1287,7 +1295,7 @@ func (r *entryRenderer) Refresh() { } if r.entry.Validator != nil { - if !r.entry.focused && !r.entry.Disabled() && r.entry.Text != "" && r.entry.validationError != nil { + if !r.entry.focused && !r.entry.Disabled() && r.entry.dirty && r.entry.validationError != nil { r.line.FillColor = theme.ErrorColor() } r.ensureValidationSetup() @@ -1306,9 +1314,8 @@ func (r *entryRenderer) ensureValidationSetup() { r.objects = append(r.objects, r.entry.validationStatus) r.Layout(r.entry.size) - if r.entry.Text != "" { - r.entry.Validate() - } + r.entry.Validate() + r.Refresh() } } diff --git a/widget/entry_validation.go b/widget/entry_validation.go index 5a162ea841..a548e46342 100644 --- a/widget/entry_validation.go +++ b/widget/entry_validation.go @@ -95,15 +95,15 @@ func (r *validationStatusRenderer) MinSize() fyne.Size { func (r *validationStatusRenderer) Refresh() { r.entry.propertyLock.RLock() defer r.entry.propertyLock.RUnlock() - if r.entry.Text == "" || r.entry.disabled { + if r.entry.disabled { r.icon.Hide() return } - if r.entry.validationError == nil { + if r.entry.validationError == nil && r.entry.Text != "" { r.icon.Resource = theme.ConfirmIcon() r.icon.Show() - } else if !r.entry.focused { + } else if r.entry.validationError != nil && !r.entry.focused && r.entry.dirty { r.icon.Resource = theme.NewErrorThemedResource(theme.ErrorIcon()) r.icon.Show() } else { diff --git a/widget/entry_validation_test.go b/widget/entry_validation_test.go index 4e72353a9e..83f9320b09 100644 --- a/widget/entry_validation_test.go +++ b/widget/entry_validation_test.go @@ -63,6 +63,30 @@ func TestEntry_Validate(t *testing.T) { assert.Equal(t, entry.Validate(), entry.Validator(entry.Text)) } +func TestEntry_NotEmptyValidator(t *testing.T) { + test.NewApp() + defer test.NewApp() + entry := widget.NewEntry() + entry.Validator = func(s string) error { + if s == "" { + return errors.New("should not be empty") + } + return nil + } + w := test.NewWindow(entry) + defer w.Close() + + test.AssertRendersToMarkup(t, "entry/validator_not_empty_initial.xml", w.Canvas()) + + w.Canvas().Focus(entry) + + test.AssertRendersToMarkup(t, "entry/validator_not_empty_focused.xml", w.Canvas()) + + w.Canvas().Focus(nil) + + test.AssertRendersToMarkup(t, "entry/validator_not_empty_unfocused.xml", w.Canvas()) +} + func TestEntry_SetValidationError(t *testing.T) { entry, window := setupImageTest(t, false) fyne.CurrentApp().Settings().SetTheme(theme.LightTheme()) diff --git a/widget/testdata/entry/validator_not_empty_focused.xml b/widget/testdata/entry/validator_not_empty_focused.xml new file mode 100644 index 0000000000..44486a01c8 --- /dev/null +++ b/widget/testdata/entry/validator_not_empty_focused.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/widget/testdata/entry/validator_not_empty_initial.xml b/widget/testdata/entry/validator_not_empty_initial.xml new file mode 100644 index 0000000000..d0f109da87 --- /dev/null +++ b/widget/testdata/entry/validator_not_empty_initial.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/widget/testdata/entry/validator_not_empty_unfocused.xml b/widget/testdata/entry/validator_not_empty_unfocused.xml new file mode 100644 index 0000000000..e64db69c13 --- /dev/null +++ b/widget/testdata/entry/validator_not_empty_unfocused.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + From 20a6cb68a42af19c5a2d0af5d913aecbde9bc652 Mon Sep 17 00:00:00 2001 From: FPabl0 Date: Sat, 15 May 2021 04:22:39 -0500 Subject: [PATCH 2/3] fix form hint for widget.Entry's --- widget/entry.go | 11 ++++++ widget/form.go | 35 +++++++++++------- widget/form_test.go | 3 -- widget/testdata/form/hint_invalid.png | Bin 8252 -> 6906 bytes .../validation_entry_first_type_invalid.png | Bin 7696 -> 6806 bytes 5 files changed, 33 insertions(+), 16 deletions(-) diff --git a/widget/entry.go b/widget/entry.go index f7ba7d6592..f1b3e63d52 100644 --- a/widget/entry.go +++ b/widget/entry.go @@ -66,6 +66,11 @@ type Entry struct { content *entryContent scroll *widget.Scroll + // useful for Form validation (as the error text should only be shown when + // the entry is unfocused) + onFocusGained func() + onFocusLost func() + // selectRow and selectColumn represent the selection start location // The selection will span from selectRow/Column to CursorRow/Column -- note that the cursor // position may occur before or after the select start position in the text. @@ -307,6 +312,9 @@ func (e *Entry) FocusGained() { e.dirty = true e.focused = true }) + if e.onFocusGained != nil { + e.onFocusGained() + } } // FocusLost is called when the Entry has had focus removed. @@ -317,6 +325,9 @@ func (e *Entry) FocusLost() { e.focused = false e.selectKeyDown = false }) + if e.onFocusLost != nil { + e.onFocusLost() + } } // Hide hides the entry. diff --git a/widget/form.go b/widget/form.go index 170cc1db54..84ff61c85d 100644 --- a/widget/form.go +++ b/widget/form.go @@ -190,21 +190,26 @@ func (f *Form) checkValidation(err error) { } func (f *Form) setUpValidation(widget fyne.CanvasObject, i int) { + updateValidation := func(err error) { + if err == errFormItemInitialState { + return + } + f.Items[i].validationError = err + f.Items[i].invalid = err != nil + f.checkValidation(err) + f.updateHelperText(f.Items[i]) + } if w, ok := widget.(fyne.Validatable); ok { f.Items[i].invalid = w.Validate() != nil - 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 + if e, ok := w.(*Entry); ok { + e.onFocusGained = func() { updateValidation(e.validationError) } + e.onFocusLost = func() { updateValidation(e.validationError) } + if e.Validator != nil && f.Items[i].invalid { + // set initial state error to guarantee next error (if triggers) is always different + e.SetValidationError(errFormItemInitialState) } - f.Items[i].validationError = err - f.Items[i].invalid = err != nil - f.checkValidation(err) - f.updateHelperText(f.Items[i]) - }) + } + w.SetOnValidationChanged(updateValidation) } } @@ -212,7 +217,11 @@ func (f *Form) updateHelperText(item *FormItem) { if item.helperOutput == nil { return // testing probably, either way not rendered yet } - if item.validationError == nil { + showHintIfError := false + if e, ok := item.Widget.(*Entry); ok && (!e.dirty || e.focused) { + showHintIfError = true + } + if item.validationError == nil || showHintIfError { item.helperOutput.Text = item.HintText item.helperOutput.Color = theme.PlaceHolderColor() } else { diff --git a/widget/form_test.go b/widget/form_test.go index 086b00baf6..b60e1dfff7 100644 --- a/widget/form_test.go +++ b/widget/form_test.go @@ -213,9 +213,6 @@ func TestForm_EntryValidation_FirstTypeValid(t *testing.T) { 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") diff --git a/widget/testdata/form/hint_invalid.png b/widget/testdata/form/hint_invalid.png index de16457c114e97819b9c0e01fed6dcb480c6f824..6fe66714710255994f3563d01b089827051432de 100644 GIT binary patch literal 6906 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 IMfLsu2QJbgmjD0& diff --git a/widget/testdata/form/validation_entry_first_type_invalid.png b/widget/testdata/form/validation_entry_first_type_invalid.png index 2b613f3bf184ba731439d5acf6999320b4d33fb3..b887eb68ab331f6dc182dad281ee07409cb8ff9d 100644 GIT binary patch literal 6806 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�lkx!^Ot4t>OJGM+b)^nGn2}a&l@!8bF-^E;IQ% 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 O04T|+$<|0)g!~7|&E@_8 From 51fdd37d1c7012716a75a8af977599caade19bf6 Mon Sep 17 00:00:00 2001 From: FPabl0 Date: Sat, 15 May 2021 13:10:37 -0500 Subject: [PATCH 3/3] replace onFocusGained and onFocusLost by onFocusChanged in widget.Entry --- widget/entry.go | 11 +++++------ widget/form.go | 5 +++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/widget/entry.go b/widget/entry.go index f1b3e63d52..0ae0de4a1a 100644 --- a/widget/entry.go +++ b/widget/entry.go @@ -68,8 +68,7 @@ type Entry struct { // useful for Form validation (as the error text should only be shown when // the entry is unfocused) - onFocusGained func() - onFocusLost func() + onFocusChanged func(bool) // selectRow and selectColumn represent the selection start location // The selection will span from selectRow/Column to CursorRow/Column -- note that the cursor @@ -312,8 +311,8 @@ func (e *Entry) FocusGained() { e.dirty = true e.focused = true }) - if e.onFocusGained != nil { - e.onFocusGained() + if e.onFocusChanged != nil { + e.onFocusChanged(true) } } @@ -325,8 +324,8 @@ func (e *Entry) FocusLost() { e.focused = false e.selectKeyDown = false }) - if e.onFocusLost != nil { - e.onFocusLost() + if e.onFocusChanged != nil { + e.onFocusChanged(false) } } diff --git a/widget/form.go b/widget/form.go index 84ff61c85d..f6c99c4879 100644 --- a/widget/form.go +++ b/widget/form.go @@ -202,8 +202,9 @@ 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.onFocusGained = func() { updateValidation(e.validationError) } - e.onFocusLost = func() { updateValidation(e.validationError) } + e.onFocusChanged = func(bool) { + updateValidation(e.validationError) + } if e.Validator != nil && f.Items[i].invalid { // set initial state error to guarantee next error (if triggers) is always different e.SetValidationError(errFormItemInitialState)