Skip to content

Fix #1459: Validator highlights on tap-away, not just VKB Enter#5123

Merged
shai-almog merged 1 commit into
masterfrom
fix-1459-validator-focus-loss-highlight
May 30, 2026
Merged

Fix #1459: Validator highlights on tap-away, not just VKB Enter#5123
shai-almog merged 1 commit into
masterfrom
fix-1459-validator-focus-loss-highlight

Conversation

@shai-almog
Copy link
Copy Markdown
Collaborator

Summary

Closes #1459. The 2015 reporter noted that when an invalid value was left in a TextField and the user moved focus by tapping into a different field (rather than the VKB 'next' / Enter button), the leaving field was not highlighted as invalid until the user returned to it.

Root cause

Validator.bindDataListener wires the validator up two ways:

  1. An action / data-changed listener on the component, which fires on VKB Enter / next (this is what the reporter said did highlight correctly).
  2. A focus listener — but it only registered the listener when showErrorMessageForFocusedComponent was set, and the focusLost handler was empty.

So a tap into another field never went through the action-listener path and the focus listener (when registered at all) just discarded the event.

Fix

Register an unconditional focus listener at the top of bindDataListener whose only job is to call validate(cmp) on focus loss. The conditional error-popup listener stays as it was; this new listener fires alongside it and runs regardless of the popup config, so every binding path now catches the tap-away case the 2015 reporter described.

Test plan

  • New regression test ValidatorFocusLossHighlightTest with two cases:
    • focusLossOnAnotherFieldFlagsTheLeftFieldAsInvalid: start with a valid value, clear it to an invalid value, requestFocus on the first field, then requestFocus on the second. The first must now report v.isValid(first) == false. Pre-fix this stayed true until the field regained focus — that's the 2015 symptom.
    • focusLossDoesNotFalselyInvalidateAValidField: same sequence with valid content. Focus loss must not flip a valid field to invalid.
  • Full *Validator* sweep — 15 tests including ValidatorTest, Validator#3Test — stays green.
  • ASCII-only sources verified.
  • CI verification.

🤖 Generated with Claude Code

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 30, 2026

✅ Continuous Quality Report

Test & Coverage

Static Analysis

  • SpotBugs [Report archive]
    • ByteCodeTranslator: 0 findings (no issues)
    • android: 0 findings (no issues)
    • codenameone-maven-plugin: 0 findings (no issues)
    • core-unittests: 0 findings (no issues)
    • ios: 0 findings (no issues)
  • PMD: 0 findings (no issues) [Report archive]
  • Checkstyle: 0 findings (no issues) [Report archive]

Generated automatically by the PR CI workflow.

@github-actions
Copy link
Copy Markdown
Contributor

Cloudflare Preview

@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 30, 2026

Compared 122 screenshots: 122 matched.

Native Android coverage

  • 📊 Line coverage: 12.81% (7461/58222 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 10.42% (37369/358465), branch 4.34% (1468/33850), complexity 5.42% (1764/32532), method 9.46% (1442/15249), class 15.52% (330/2126)
    • Lowest covered classes
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysKt – 0.00% (0/6327 lines covered)
      • kotlin.collections.unsigned.kotlin.collections.unsigned.UArraysKt___UArraysKt – 0.00% (0/2384 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.ClassReader – 0.00% (0/1519 lines covered)
      • kotlin.collections.kotlin.collections.CollectionsKt___CollectionsKt – 0.00% (0/1148 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.MethodWriter – 0.00% (0/923 lines covered)
      • kotlin.sequences.kotlin.sequences.SequencesKt___SequencesKt – 0.00% (0/730 lines covered)
      • kotlin.text.kotlin.text.StringsKt___StringsKt – 0.00% (0/623 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.Frame – 0.00% (0/564 lines covered)
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysJvmKt – 0.00% (0/495 lines covered)
      • kotlinx.coroutines.kotlinx.coroutines.JobSupport – 0.00% (0/423 lines covered)

✅ Native Android screenshot tests passed.

Native Android coverage

  • 📊 Line coverage: 12.81% (7461/58222 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 10.42% (37369/358465), branch 4.34% (1468/33850), complexity 5.42% (1764/32532), method 9.46% (1442/15249), class 15.52% (330/2126)
    • Lowest covered classes
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysKt – 0.00% (0/6327 lines covered)
      • kotlin.collections.unsigned.kotlin.collections.unsigned.UArraysKt___UArraysKt – 0.00% (0/2384 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.ClassReader – 0.00% (0/1519 lines covered)
      • kotlin.collections.kotlin.collections.CollectionsKt___CollectionsKt – 0.00% (0/1148 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.MethodWriter – 0.00% (0/923 lines covered)
      • kotlin.sequences.kotlin.sequences.SequencesKt___SequencesKt – 0.00% (0/730 lines covered)
      • kotlin.text.kotlin.text.StringsKt___StringsKt – 0.00% (0/623 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.Frame – 0.00% (0/564 lines covered)
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysJvmKt – 0.00% (0/495 lines covered)
      • kotlinx.coroutines.kotlinx.coroutines.JobSupport – 0.00% (0/423 lines covered)

Benchmark Results

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 1203.000 ms
Base64 CN1 encode 135.000 ms
Base64 encode ratio (CN1/native) 0.112x (88.8% faster)
Base64 native decode 1204.000 ms
Base64 CN1 decode 316.000 ms
Base64 decode ratio (CN1/native) 0.262x (73.8% faster)
Image encode benchmark status skipped (SIMD unsupported)

…1459)

The 2015 reporter noted that when an invalid value was left in a
TextField and the user moved focus by tapping into a different field
(rather than the VKB 'next' / Enter button), the leaving field was
not highlighted as invalid until the user returned to it. The
action-listener path Validator.bindDataListener wired up only fires
for VKB Enter / action, so tapping a different field skipped the
validation entirely. The class did register a focus listener -- but
only when showErrorMessageForFocusedComponent was set, and its
focusLost handler was empty.

Register an unconditional focus listener at the top of
bindDataListener whose only job is to call validate(cmp) on focus
loss. The conditional error-popup listener stays as it was; this new
listener fires before it and runs regardless of the popup config so
every binding path catches the tap-away case.

Closes #1459.

Adds maven/core-unittests/.../ValidatorFocusLossHighlightTest.java:

- focusLossOnAnotherFieldFlagsTheLeftFieldAsInvalid: start with a
  valid value, clear it to an invalid value, requestFocus on the
  first field, then requestFocus on the second; the first must now
  report v.isValid(first) == false. Pre-fix this stayed true until
  the field regained focus.
- focusLossDoesNotFalselyInvalidateAValidField: same sequence with
  valid content -- focus loss must not flip a valid field to invalid.

Full Validator sweep (15 tests) stays green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@shai-almog shai-almog force-pushed the fix-1459-validator-focus-loss-highlight branch from 03d2012 to 1fb9af0 Compare May 30, 2026 17:32
@shai-almog shai-almog merged commit bbad80c into master May 30, 2026
22 checks passed
@shai-almog shai-almog deleted the fix-1459-validator-focus-loss-highlight branch May 30, 2026 19:12
@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 30, 2026

Compared 122 screenshots: 122 matched.
✅ Native iOS screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 249 seconds

Build and Run Timing

Metric Duration
Simulator Boot 70000 ms
Simulator Boot (Run) 1000 ms
App Install 14000 ms
App Launch 10000 ms
Test Execution 344000 ms

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 692.000 ms
Base64 CN1 encode 1257.000 ms
Base64 encode ratio (CN1/native) 1.816x (81.6% slower)
Base64 native decode 349.000 ms
Base64 CN1 decode 928.000 ms
Base64 decode ratio (CN1/native) 2.659x (165.9% slower)
Base64 SIMD encode 370.000 ms
Base64 encode ratio (SIMD/native) 0.535x (46.5% faster)
Base64 encode ratio (SIMD/CN1) 0.294x (70.6% faster)
Base64 SIMD decode 373.000 ms
Base64 decode ratio (SIMD/native) 1.069x (6.9% slower)
Base64 decode ratio (SIMD/CN1) 0.402x (59.8% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 57.000 ms
Image createMask (SIMD on) 10.000 ms
Image createMask ratio (SIMD on/off) 0.175x (82.5% faster)
Image applyMask (SIMD off) 118.000 ms
Image applyMask (SIMD on) 68.000 ms
Image applyMask ratio (SIMD on/off) 0.576x (42.4% faster)
Image modifyAlpha (SIMD off) 119.000 ms
Image modifyAlpha (SIMD on) 54.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.454x (54.6% faster)
Image modifyAlpha removeColor (SIMD off) 131.000 ms
Image modifyAlpha removeColor (SIMD on) 60.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.458x (54.2% faster)
Image PNG encode (SIMD off) 910.000 ms
Image PNG encode (SIMD on) 817.000 ms
Image PNG encode ratio (SIMD on/off) 0.898x (10.2% faster)
Image JPEG encode 412.000 ms

@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 30, 2026

Compared 122 screenshots: 122 matched.
✅ Native iOS Metal screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 152 seconds

Build and Run Timing

Metric Duration
Simulator Boot 60000 ms
Simulator Boot (Run) 0 ms
App Install 11000 ms
App Launch 3000 ms
Test Execution 284000 ms

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 584.000 ms
Base64 CN1 encode 1468.000 ms
Base64 encode ratio (CN1/native) 2.514x (151.4% slower)
Base64 native decode 347.000 ms
Base64 CN1 decode 1082.000 ms
Base64 decode ratio (CN1/native) 3.118x (211.8% slower)
Base64 SIMD encode 628.000 ms
Base64 encode ratio (SIMD/native) 1.075x (7.5% slower)
Base64 encode ratio (SIMD/CN1) 0.428x (57.2% faster)
Base64 SIMD decode 422.000 ms
Base64 decode ratio (SIMD/native) 1.216x (21.6% slower)
Base64 decode ratio (SIMD/CN1) 0.390x (61.0% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 58.000 ms
Image createMask (SIMD on) 9.000 ms
Image createMask ratio (SIMD on/off) 0.155x (84.5% faster)
Image applyMask (SIMD off) 120.000 ms
Image applyMask (SIMD on) 130.000 ms
Image applyMask ratio (SIMD on/off) 1.083x (8.3% slower)
Image modifyAlpha (SIMD off) 369.000 ms
Image modifyAlpha (SIMD on) 56.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.152x (84.8% faster)
Image modifyAlpha removeColor (SIMD off) 480.000 ms
Image modifyAlpha removeColor (SIMD on) 98.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.204x (79.6% faster)
Image PNG encode (SIMD off) 1335.000 ms
Image PNG encode (SIMD on) 853.000 ms
Image PNG encode ratio (SIMD on/off) 0.639x (36.1% faster)
Image JPEG encode 381.000 ms

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Validator is not highlighting properly

1 participant