BloomDraftController<C> class abstract base

Producer controller managing a reactive state with transactional draft edits.

Combines zero-overhead immutable replacement (set, data) with transactional draft edits (edit, editGuarded).

Modifying elements inside an edit closure guarantees that changes are compared via equality, frozen into an unmodifiable collection, and committed in at most one downstream Push-Dirty pulse.

System Architectural Flow

[BloomDraftController] ──> .edit((draft) { draft.add(item); })
                                   │
                                   ▼ (Compares Equality with Previous)
                        [Modified? ── Yes ──> Freezes Unmodifiable & Push-Dirty (1 Pulse)]
                                   └── No   ──> No-Op (Zero Downstream Recomputations)

Architectural Benefits

  1. Atomic Draft Transactions: Edits are applied to an isolated draft buffer and committed in a single pulse.
  2. Deep/Shallow Equality Guarding: Suppresses downstream notifications if the draft results in no net changes.
  3. Immutability Enforcement: The underlying payload is stored as unmodifiable collections to prevent mutation leaks.

Warning (Anti-Pattern Prevention):

  • Do NOT attempt to mutate .data in-place directly (e.g. controller.data.add(...)), as .data returns an unmodifiable collection and throws an UnsupportedError. Always use edit or assign a new collection via set.

BAD:

// [Anti-Pattern] Mutating unmodifiable collection directly throws UnsupportedError
final listCtrl = blooming.list([1, 2]);
listCtrl.data.add(3); // Throws UnsupportedError!

GOOD:

// [Recommended] Use transactional edit to safely mutate draft and commit
final listCtrl = blooming.list([1, 2]);
listCtrl.edit((draft) => draft.add(3)); // Commits atomically as immutable list

Examples

// Primary: construct via blooming functor
final numbers = blooming.list([1, 2, 3]);
numbers.edit((draft) {
  draft.add(4);
  draft.remove(1);
});
print(numbers.data); // [2, 3, 4]

final tags = blooming.set({'flutter', 'dart'});
tags.edit((draft) => draft.add('reactive'));

final scores = blooming.map({'Alice': 90});
scores.edit((draft) => draft['Bob'] = 85);
Implemented types
Available extensions

Properties

bloom → Bloom<C>
The encapsulated read-only reactive node view exposed to downstream consumers.
no setteroverride
data ↔ C
Extracts the underlying data synchronously from this node or state.
getter/setter pairinherited
dataOrNull → C?
Safely extracts the underlying data, returning null if not in a hasData state.
no setterinherited
debugCreationLocation → String?

Available on BloomController<T>, provided by the BloomControllerDebugExtension extension

The exact code location where this controller was instantiated in debug mode.
no setter
debugLabel ↔ String?

Available on BloomController<T>, provided by the BloomControllerDebugExtension extension

A developer-defined label to identify this specific controller in debug mode.
getter/setter pair
emptyReason → Object?
The optional reason explaining why this state is empty, or null if unspecified or not empty.
no setterinherited
error → Object
Extracts the underlying exception or failure object from an error state.
no setterinherited
hasData → bool
Whether this state contains a valid, extractable data payload.
no setterinherited
hasError → bool
Whether this state is in a corrupted state containing an error or exception.
no setterinherited
hashCode → int
The hash code for this object.
no setterinherited
isActive → bool
Whether this controller's target node is currently observed by downstream subscribers.
no setterinherited
isEmpty → bool
Whether this state is in an uninitialized or dormant state.
no setterinherited
phase → BloomPhase
The operational phase (BloomPhase.valid, BloomPhase.empty, or BloomPhase.error) of this state.
no setterinherited
runtimeType → Type
A representation of the runtime type of the object.
no setterinherited
snapshot → BloomSnapshot<C>
The underlying snapshot representing this entity's current state.
no setterinherited
stackTrace → StackTrace
Extracts the call stack trace at the point of failure from an error state.
no setterinherited

Methods

dataOrElse(C fallback()) → C
Safely extracts the underlying data, returning the result of fallback if not in a hasData state.
inherited
debugTrace([String? label, int traceCount = 5]) → void

Available on BloomController<T>, provided by the BloomControllerDebugExtension extension

Captures the current stack trace and assigns an optional label to this controller.
edit(void recipe(C draft)) → void
Edits the current state in-place via a temporary draft buffer.
editGuarded(void recipe(C draft)) → void
Safely executes recipe on a temporary draft buffer and commits modifications, or catches any thrown exceptions and transitions this controller to an error state.
empty([Object? reason]) → void
Injects an empty (uninitialized) state into the pipeline, clearing the current value.
inherited
equals(covariant BloomState<C> other, [bool equals(C previous, C next)?]) → bool
Determines if this state is equivalent to other using an optional custom equals comparator.
inherited
noSuchMethod(Invocation invocation) → dynamic
Invoked when a nonexistent method or property is accessed.
inherited
set(C data) → void
Injects data into the pipeline, propagating dirty signals downstream.
inherited
setError(Object error, [StackTrace? stackTrace]) → void
Injects an error state into the pipeline with optional stackTrace.
inherited
setGuarded(C test()) → void
Safely executes test and injects the returned payload or catches thrown exceptions.
inherited
toString() → String
A string representation of this object.
inherited
withDebugLabel<C extends BloomController<T>>(String label) → C

Available on BloomController<T>, provided by the BloomControllerDebugExtension extension

Assigns a developer-defined debug label and returns this controller.

Operators

operator ==(Object other) → bool
The equality operator.
inherited