Skip to content

[WIP] epic: rewrite forms around ChangeNotifier - #52

Draft
mateusz-pietras wants to merge 61 commits into
mainfrom
refactor/forms-rework
Draft

[WIP] epic: rewrite forms around ChangeNotifier#52
mateusz-pietras wants to merge 61 commits into
mainfrom
refactor/forms-rework

Conversation

@mateusz-pietras

@mateusz-pietras mateusz-pietras commented Aug 10, 2026

Copy link
Copy Markdown
Member
  • drop excessive dependencies, rely only on flutter and collection
  • fix pre-existing validation issues
  • fix bugs and findings from issues & jira

aydinguven-leancode and others added 28 commits August 14, 2026 12:16
…nagement

Migrated from Cubit (Bloc) to value notifier.
Removed dependencies: flutter_bloc, rx_dart, equatable,
Changes are reflected on examples
Changes are reflected on tests
Removed unnecessary //ignore commands
Reverted version change on leancode_lint in example project
Added debugLabel
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Removed the bits about previous versions from EXAMPLES.md
Added `child` param to fieldBuilder class to fully support builder closures
Various minor fixes
Examples modified
FormGroupState is renamed into FormState
Examples and tests modified accordingly
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* Added FocusNode support in AdvancedTextFieldController

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
extract common code like copyWith methods; apply leancode architecture standards (field ordering, codestyle); remove maintainer docs from public-facing api
clean up code; fix issue where if async validator thrown an error, the error wouldnt be reported until caught in zone, while the form field got stuck in `validating` status
mateusz-pietras and others added 25 commits August 14, 2026 12:22
Every validation pass now belongs to the value it was started for. `setValue`,
`setError`, `clearErrors`, `reset`, `markReadOnly`, `setValidationEnabled(false)`
and `dispose` all abort the pending or in-flight round, which can then never
write state, notify, or report. That closes a family of bugs where a stale
result resurrected an earlier value or undid a just-applied change.

A round settles exactly once, so nothing can await a result that never arrives,
and a validator that throws before its first `await` takes the same path as a
rejected future instead of wedging the field on `validating`. A settled answer
is reused while it still describes the value, so a second submit on an
unchanged form makes no network calls.

`validate()` is now `Future<bool>` on both controllers and runs the async
validators; calling it again before the first call finishes gives the same
result. Form aggregates — `validating`, `canSubmit`, `hasFailedValidation`,
`validationErrors` — are derived from the fields on read, so they cannot
outlive the child that justified them.

Adds `AsyncValidation.timeout` and `failureToError`,
`FieldStatus.failedValidation` and `AdvancedFieldController.lastFailure`.
Splits `AdvancedFieldState` and `AsyncValidation` into their own files, and
replaces `CancelableFuture` with `CoalescingCall`.

BREAKING CHANGE: `validate()` returns `Future<bool>`; `AsyncValidation.onError`
is now `onFailure`; `autovalidate` gates the async validator too; `reset()`
keeps `autovalidate` and `readOnly`; `setError(null)` clears the error.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0141bii9YkhiH3V77uRiabsU
Covers round ownership and every abort point, terminal states for a validator
that throws or times out, verdict reuse, `validate()` sharing one pass across
concurrent calls, the `failedValidation` status and `lastFailure`, the derived
form aggregates, and the text controller reconciling after a rejected write.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0141bii9YkhiH3V77uRiabsU
Describes the validation model in the README, the upgrade path in MIGRATION.md
and the API delta in the changelog, and moves the recipes in EXAMPLES.md to the
async `validate()` and the `AsyncValidation` object.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0141bii9YkhiH3V77uRiabsU
Updates every screen to the controller API and the async `validate()`, and adds
an optimized-rendering screen that demonstrates the builder's `child` parameter.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0141bii9YkhiH3V77uRiabsU
throw when calling controller methods when disposed
Written and hardened over 5 test-verify-refine iterations: 15 agent
builds from the skill alone (all flutter-analyze clean), every claim
adjudicated against package source, disputed semantics locked by
executed tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Fix the false claim that super-parameters cannot combine with an
  explicit super(...) call; the PhoneFieldController example now uses
  super.validator.
- Async validation is available on every field controller, selects
  included — drop the "text and boolean only" restriction.
- Soften "one ErrorTranslator per error enum": the same error code often
  needs different wording per field.
- Spell out the "at least one traveler" cross-field example.
- Drop the dispose() override snippet for detached subforms; state the
  ownership rule in prose instead.
- Realign with the rebased base: the validate() gate sweep no longer
  consults validationEnabled in that order, and subscribeToFields /
  registerFields throw on disposed controllers.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
feat(validation): refine validation pipeline; fix validation issues
docs: add AI agent skill for building forms with leancode_forms
feat(form): add addRelation for cross-field value dependencies
Full quality pass over the tracked markdown docs: README, CHANGELOG,
MIGRATION, and example/README, run as an iterative analyze -> verify ->
implement loop, followed by a two-axis review (standards + spec) and a
PR review pass (#56).

- README: added title, badges, license footer, API-reference link;
  fixed false claims (dependency list vs pubspec, asyncValidation
  support on select controllers); quickstart compiles as shown;
  Validation section trimmed to the happy path; renamed "validation
  round" to "validation pass" throughout.
- CHANGELOG: 0.2.0 regrouped into Breaking / Added / Changed / Fixed /
  Deprecated; rename bullets kept as a sublist; missing entries added
  (Flutter SDK floor raise, revalidateSync); reworded imprecise wording.
- MIGRATION: before-code no longer shows an API that never existed in
  0.1.x; every behavior change has its own linkable heading; undefined
  refreshFor() replaced with the real revalidateSync().
- example/README: replaced the flutter create placeholder with run
  instructions and a screen guide table, pointing at README anchors.
- Removed EXAMPLES.md (introduced during drafting, decided against in
  review — example/, README and the SKILL cover the same ground) and
  every reference to it across the other docs.
- Removed DOCS_SPEC.md, the working spec used to drive this pass
  (process artifact, not shipped documentation).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
docs: overhaul package documentation against a written spec
- Cross-field logic: replace the raw addListener + setValue pattern with
  AdvancedFormController.addRelation (select/onChange, ==-compared, cleaned
  up in dispose, no call at registration, StateError on disposed).
- Document validateWithAutovalidate() next to validateAll, and state that
  validateAll is that same primitive run on every value change.
- Point 0.1.x migration tasks at MIGRATION.md / CHANGELOG.md instead of
  this skill.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
docs(skill): sync leancode-forms skill with refactor/forms-rework
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.

3 participants