Expand description
The Material 3 Expressive progress indicators: linear and circular, each flat or wavy, each determinate or indeterminate — the reference’s four named constructors over two widgets.
Ported from material_3_expressive v1.0.8 (MIT, © 2026 Paa Developments),
lib/components/progress_indicators/ (retrieved 2026-08-19).
Upstream: https://github.com/paadevelopments/material_3_expressive
This module owns the View/Widget wiring, colour resolution, and every
paint call; motion owns the five animation
controllers and the curve tables that drive them, and
linear/circular own the
geometry those numbers feed.
§Constructors: the reference’s named-constructor split, kept
M3EProgressIndicator ships four Dart named constructors over one widget
class (m3e_progress_indicators.dart:29-100). All four are sibling
functions here, so the mapping stays one-to-one:
| Reference | Here |
|---|---|
M3EProgressIndicator.linear(...) | linear_progress (alias LinearProgress) |
M3EProgressIndicator.linearWavy(...) | linear_wavy_progress (alias LinearWavyProgress) |
M3EProgressIndicator.circular(...) | circular_progress (alias CircularProgress) |
M3EProgressIndicator.circularWavy(...) | circular_wavy_progress (alias CircularWavyProgress) |
Every knob a constructor only accepts when it is meaningful — amplitude/
amplitudeForProgress/wavelength/waveSpeed/trackStrokeWidth/
gapSize on the wavy ones, stopSize on linearWavy — is a builder
method here instead, documented as inert where it has no use (the same
shape [crate::slider]’s port takes, for the same reason: a
constructor-gated builder would need a view type per variant).
LinearProgressView::wavy/CircularProgressView::wavy flip a flat
view to its wavy sibling, so linear_progress(v).wavy() and
linear_wavy_progress(v) are the same thing.
§Controlled, like every other value-carrying widget here
Both views carry the app’s ProgressValue every frame —
Determinate(f) for a known 0.0..=1.0 fraction, Indeterminate for an
unknown-duration loop — and neither ever writes its own value
(docs/CODE_STANDARDS.md’s Interaction Semantics). There is no callback: a
progress indicator has no user interaction to report.
§Indeterminate motion is the reference choreography, transcribed
Indeterminate progress is not a single sweeping segment. Upstream runs
five independent animation controllers, and this port transcribes their
durations, curves, and timing tables exactly
(motion carries the per-constant citations):
- Linear — one 1750 ms cycle drives four separately-delayed,
separately-eased fractions (
firstHead/firstTail/secondHead/secondTail, all onCubic(0.3, 0, 0.8, 0.15)), painting two traveling lines with track and gaps between and around them. - Circular — a 6000 ms global rotation (1080°) and a 4500 ms additional rotation (360°) sum into the arc’s start angle, while a 1300 ms controller ping-pongs the arc’s own sweep between 10% and 87% of the circle. The classic and wavy circular variants share all three.
Every controller advances from the frame clock during paint
(docs/WIDGETS_CODE_STANDARDS.md), never from stacked implicit animations
and never from a wall clock.
§Wavy variants
A wavy indicator replaces the flat active track with a sine path: linear
oscillates the track’s centreline, circular oscillates the ring’s radius.
Both take their amplitude as a factor in 0..=1 scaled by the family’s
own peak offset (linear 3dp, circular 1.6dp), resolved in the reference’s
precedence order — an app-supplied curve of progress, then an app-supplied
constant, then the default ramp, which flattens the wave entirely below
0.1 and at/above 0.95 progress so it never fights the round caps.
The phase itself never gates on progress upstream (_needsWavePhase is
_isWavy alone); the amplitude ramp is what stills the wave near either
end. This port keeps that rule and adds one documented divergence: when the
resolved amplitude is 0 the phase clock is not advanced and no frame is
requested, since a flat line’s phase is unobservable and a perpetual
repaint for no visible motion is exactly what the paced-frame convention
exists to avoid.
Reduce-motion: every loop here is perpetual and decorative, so it asks
for paced frames (TickClass::CosmeticLoop) and, under
MotionScheme::reduce_motion, freezes wherever it sits and stops
requesting frames — the crate convention, matching
[crate::slider]/[crate::loading_indicator].
§Round caps are load-bearing
Every span here is a stroke, not a filled rect: the reference paints all
of them with StrokeCap.round, and its gap arithmetic already budgets for
the half-stroke each cap adds past its endpoint (_visualGap inflates the
gap by a whole stroke; the wavy indeterminate arm insets by another half).
PaintScene::stroke_line/stroke_path reach kurbo::Stroke::new, whose
caps and joins are round by default — a backend that squared them would
shorten every span by a half stroke and reopen the gaps this module
deliberately closes.
Structs§
- Circular
Progress View - A circular progress indicator, classic or wavy. See the module docs.
- Circular
Progress Widget - The retained widget for a
CircularProgressView. See the module docs. - Linear
Progress View - A linear progress indicator, flat or wavy. See the module docs.
- Linear
Progress Widget - The retained widget for a
LinearProgressView. See the module docs.
Enums§
- Progress
Size - Track-thickness variant of a flat linear indicator
(
M3EProgressIndicatorSize). Inert on every other variant: the wavy linear indicator sizes from its own stroke/amplitude, and the circular ones from their diameter. - Progress
Value - A progress indicator’s controlled value (see the module docs).
Functions§
- Circular
Progress - PascalCase alias for
circular_progress, matching the widget-fn vocabulary (Button/Image/…). - Circular
Wavy Progress - PascalCase alias for
circular_wavy_progress. - Linear
Progress - PascalCase alias for
linear_progress, matching the widget-fn vocabulary (Button/Image/…). - Linear
Wavy Progress - PascalCase alias for
linear_wavy_progress. - circular_
progress - Create a classic circular progress indicator driven by
value(M3EProgressIndicator.circular). - circular_
wavy_ progress - Create a wavy circular progress indicator driven by
value(M3EProgressIndicator.circularWavy). - linear_
progress - Create a flat linear progress indicator driven by
value(M3EProgressIndicator.linear). - linear_
wavy_ progress - Create a wavy linear progress indicator driven by
value(M3EProgressIndicator.linearWavy).
Type Aliases§
- Amplitude
Curve - An app-supplied amplitude factor as a function of progress
(
M3EProgressIndicator.amplitudeForProgress).Rc, notBox, so a view can be cloned into its widget the same waycrate::slider’sAmplitudeCurveis.