Work and Progress
Every FdcDataSet owns a lightweight observable work model through dataSet.work.
It reports dataset operations such as opening, filtering, sorting, searching, applying updates, explicit loading, and application-defined work.
final work = dataSet.work;
if (work.isWorking) {
debugPrint('${work.phase}: ${work.message}');
}
Work phases
FdcDataSetWorkPhase describes the coarse operation currently running:
| Phase | Meaning |
|---|---|
idle | No reported work is active |
open | Opening or reloading rows |
filter | Filtering or rebuilding the filtered view |
sort | Sorting or rebuilding sorted order |
search | Global search query or local search rebuild |
applyUpdates | Applying pending changes through the adapter |
load | Explicit row loading or aggregate-style data work |
custom | Application-defined dataset work |
The enum is intentionally small. It identifies the user-relevant type of work without turning the dataset into a general task framework.
Determinate and indeterminate work
switch (dataSet.work.mode) {
case FdcDataSetWorkMode.determinate:
final progress = dataSet.work.progress ?? 0.0;
break;
case FdcDataSetWorkMode.indeterminate:
// Show an indeterminate indicator.
break;
case null:
// Idle.
break;
}
For determinate work, progress is normalized to 0.0..1.0.
For indeterminate work, progress is null.
Listen for lifecycle transitions
FdcDataSetWork is a ChangeNotifier:
void handleWorkTransition() {
final work = dataSet.work;
if (work.isWorking) {
debugPrint('Started ${work.phase}: ${work.message}');
} else if (work.error != null) {
debugPrint('Work failed: ${work.error}');
} else {
debugPrint('Work completed');
}
}
dataSet.work.addListener(handleWorkTransition);
Notifications are emitted when work starts, completes, or fails.
Progress updates are intentionally silent
Granular progress updates do not call notifyListeners().
This is deliberate: a large operation may update progress many times, and broadcasting every increment through the widget tree would create a notification storm.
UI that needs continuously updated percentage progress should poll dataSet.work.progress while isWorking is true. Lifecycle listeners are still useful for starting and stopping that polling loop.
Conceptually:
work starts
→ listener notified
→ UI begins lightweight polling
→ progress changes silently
→ work completes or fails
→ listener notified
→ UI stops polling
Current work snapshot
While work is active, dataSet.work.current exposes an immutable FdcDataSetWorkInfo snapshot:
final current = dataSet.work.current;
if (current != null) {
debugPrint('Work id: ${current.id}');
debugPrint('Started: ${current.startedAt}');
debugPrint('Phase: ${current.phase}');
debugPrint('Mode: ${current.mode}');
}
Each work operation receives a dataset-local monotonic id.
The snapshot contains:
id,phase,mode,startedAt,- optional
message, - error and stack trace on failed lifecycle snapshots.
Failure state
After a failed operation:
final error = dataSet.work.error;
final stackTrace = dataSet.work.stackTrace;
These properties retain the most recently captured work failure until a new work operation begins.
Adapter and dataset errors still flow through the normal FDC error pipeline; the work model provides operation-state observability rather than replacing error handling.
See Error Handling.
Lifecycle callbacks
Dataset lifecycle callbacks provide another way to react to work transitions:
FdcDataSet(
fields: fields,
onWorkStarted: (dataSet, info) {
// Operation started.
},
onWorkCompleted: (dataSet, info) {
// Operation completed.
},
onWorkError: (dataSet, info) {
// Operation failed.
},
)
Use callbacks for dataset/business orchestration. Use dataSet.work when a UI or observer needs current state.
See Lifecycle Callbacks.
Grid progress UI
The grid can visualize dataset work through its progress components. The important architectural rule is that the DataSet owns work state; the grid only renders it.
This keeps long-running operation state reusable outside the grid and avoids coupling data execution strategy to one widget.