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
- Atomic Draft Transactions: Edits are applied to an isolated draft buffer and committed in a single pulse.
- Deep/Shallow Equality Guarding: Suppresses downstream notifications if the draft results in no net changes.
- Immutability Enforcement: The underlying payload is stored as unmodifiable collections to prevent mutation leaks.
Warning (Anti-Pattern Prevention):
- Do NOT attempt to mutate
.datain-place directly (e.g.controller.data.add(...)), as.datareturns 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
nullif not in a hasData state.no setterinherited - debugCreationLocation → String?
-
Available on BloomController<
The exact code location where this controller was instantiated in debug mode.T> , provided by the BloomControllerDebugExtension extensionno setter - debugLabel ↔ String?
-
Available on BloomController<
A developer-defined label to identify this specific controller in debug mode.T> , provided by the BloomControllerDebugExtension extensiongetter/setter pair - emptyReason → Object?
-
The optional reason explaining why this state is empty, or
nullif 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
fallbackif not in a hasData state.inherited -
debugTrace(
[String? label, int traceCount = 5]) → void -
Available on BloomController<
Captures the current stack trace and assigns an optional label to this controller.T> , provided by the BloomControllerDebugExtension extension -
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
recipeon 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
otherusing an optional customequalscomparator.inherited -
noSuchMethod(
Invocation invocation) → dynamic -
Invoked when a nonexistent method or property is accessed.
inherited
-
set(
C data) → void -
Injects
datainto 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
testand 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<
Assigns a developer-defined debug label and returns this controller.T> , provided by the BloomControllerDebugExtension extension
Operators
-
operator ==(
Object other) → bool -
The equality operator.
inherited