Last changes not published

This commit is contained in:
vjrj 2026-03-05 01:18:27 +01:00
parent ac65ccf990
commit 21ec08303a
43 changed files with 607 additions and 613 deletions

View file

@ -3,7 +3,6 @@
// found in the LICENSE file.
import 'package:flutter/material.dart';
// TODO(dragostis): Missing functionality:
// * mobile horizontal mode with adding/removing steps
// * alternative labeling
@ -53,7 +52,8 @@ const Color _kCircleActiveDark = Colors.black87;
const Color _kDisabledLight = Colors.black38;
const Color _kDisabledDark = Colors.white30;
const double _kCustomStepSize = 24.0;
const double _kTriangleHeight = _kCustomStepSize * 0.866025; // Triangle height. sqrt(3.0) / 2.0
const double _kTriangleHeight =
_kCustomStepSize * 0.866025; // Triangle height. sqrt(3.0) / 2.0
/// A material step used in [CustomStepper]. The step can have a title and subtitle,
/// an icon within its circle, some content and a state that governs its
@ -75,9 +75,9 @@ class CustomStep {
@required this.content,
this.state: CustomStepState.indexed,
this.isActive: false,
}) : assert(title != null),
assert(content != null),
assert(state != null);
}) : assert(title != null),
assert(content != null),
assert(state != null);
/// The title of the step that typically describes it.
final Widget title;
@ -130,11 +130,11 @@ class CustomStepper extends StatefulWidget {
this.onCustomStepTapped,
this.onCustomStepContinue,
this.onCustomStepCancel,
}) : assert(steps != null),
assert(type != null),
assert(currentCustomStep != null),
assert(0 <= currentCustomStep && currentCustomStep < steps.length),
super(key: key);
}) : assert(steps != null),
assert(type != null),
assert(currentCustomStep != null),
assert(0 <= currentCustomStep && currentCustomStep < steps.length),
super(key: key);
/// The steps of the stepper whose titles, subtitles, icons always get shown.
///
@ -177,7 +177,7 @@ class _CustomStepperState extends State<CustomStepper> {
super.initState();
_keys = new List<GlobalKey>.generate(
widget.steps.length,
(int i) => new GlobalKey(),
(int i) => new GlobalKey(),
);
for (int i = 0; i < widget.steps.length; i += 1)
@ -218,7 +218,8 @@ class _CustomStepperState extends State<CustomStepper> {
}
Widget _buildCircleChild(int index, bool oldState) {
final CustomStepState state = oldState ? _oldStates[index] : widget.steps[index].state;
final CustomStepState state =
oldState ? _oldStates[index] : widget.steps[index].state;
final bool isDarkActive = _isDark() && widget.steps[index].isActive;
assert(state != null);
switch (state) {
@ -226,7 +227,9 @@ class _CustomStepperState extends State<CustomStepper> {
case CustomStepState.disabled:
return new Text(
'${index + 1}',
style: isDarkActive ? _kCustomStepStyle.copyWith(color: Colors.black87) : _kCustomStepStyle,
style: isDarkActive
? _kCustomStepStyle.copyWith(color: Colors.black87)
: _kCustomStepStyle,
);
case CustomStepState.editing:
return new Icon(
@ -247,9 +250,13 @@ class _CustomStepperState extends State<CustomStepper> {
Color _circleColor(int index) {
final ThemeData themeData = Theme.of(context);
if (!_isDark()) {
return widget.steps[index].isActive ? themeData.primaryColor : Colors.black38;
return widget.steps[index].isActive
? themeData.primaryColor
: Colors.black38;
} else {
return widget.steps[index].isActive ? themeData.accentColor : themeData.backgroundColor;
return widget.steps[index].isActive
? themeData.accentColor
: themeData.backgroundColor;
}
}
@ -266,7 +273,8 @@ class _CustomStepperState extends State<CustomStepper> {
shape: BoxShape.circle,
),
child: new Center(
child: _buildCircleChild(index, oldState && widget.steps[index].state == CustomStepState.error),
child: _buildCircleChild(index,
oldState && widget.steps[index].state == CustomStepState.error),
),
),
);
@ -280,14 +288,19 @@ class _CustomStepperState extends State<CustomStepper> {
child: new Center(
child: new SizedBox(
width: _kCustomStepSize,
height: _kTriangleHeight, // Height of 24dp-long-sided equilateral triangle.
height:
_kTriangleHeight, // Height of 24dp-long-sided equilateral triangle.
child: new CustomPaint(
painter: new _TrianglePainter(
color: _isDark() ? _kErrorDark : _kErrorLight,
),
child: new Align(
alignment: const Alignment(0.0, 0.8), // 0.8 looks better than the geometrical 0.33.
child: _buildCircleChild(index, oldState && widget.steps[index].state != CustomStepState.error),
alignment: const Alignment(
0.0, 0.8), // 0.8 looks better than the geometrical 0.33.
child: _buildCircleChild(
index,
oldState &&
widget.steps[index].state != CustomStepState.error),
),
),
),
@ -303,7 +316,9 @@ class _CustomStepperState extends State<CustomStepper> {
firstCurve: const Interval(0.0, 0.6, curve: Curves.fastOutSlowIn),
secondCurve: const Interval(0.4, 1.0, curve: Curves.fastOutSlowIn),
sizeCurve: Curves.fastOutSlowIn,
crossFadeState: widget.steps[index].state == CustomStepState.error ? CrossFadeState.showSecond : CrossFadeState.showFirst,
crossFadeState: widget.steps[index].state == CustomStepState.error
? CrossFadeState.showSecond
: CrossFadeState.showFirst,
duration: kThemeAnimationDuration,
);
} else {
@ -328,8 +343,9 @@ class _CustomStepperState extends State<CustomStepper> {
assert(cancelColor != null);
final ThemeData themeData = Theme.of(context);
final MaterialLocalizations localizations = MaterialLocalizations.of(context);
// final ThemeData themeData = Theme.of(context);
// final MaterialLocalizations localizations =
// MaterialLocalizations.of(context);
return new Container(
margin: const EdgeInsets.only(top: 16.0),
@ -368,15 +384,13 @@ class _CustomStepperState extends State<CustomStepper> {
case CustomStepState.indexed:
case CustomStepState.editing:
case CustomStepState.complete:
return textTheme.body2;
return textTheme.bodyText1;
case CustomStepState.disabled:
return textTheme.body2.copyWith(
color: _isDark() ? _kDisabledDark : _kDisabledLight
);
return textTheme.bodyText1
.copyWith(color: _isDark() ? _kDisabledDark : _kDisabledLight);
case CustomStepState.error:
return textTheme.body2.copyWith(
color: _isDark() ? _kErrorDark : _kErrorLight
);
return textTheme.bodyText1
.copyWith(color: _isDark() ? _kErrorDark : _kErrorLight);
}
return null;
}
@ -392,13 +406,11 @@ class _CustomStepperState extends State<CustomStepper> {
case CustomStepState.complete:
return textTheme.caption;
case CustomStepState.disabled:
return textTheme.caption.copyWith(
color: _isDark() ? _kDisabledDark : _kDisabledLight
);
return textTheme.caption
.copyWith(color: _isDark() ? _kDisabledDark : _kDisabledLight);
case CustomStepState.error:
return textTheme.caption.copyWith(
color: _isDark() ? _kErrorDark : _kErrorLight
);
return textTheme.caption
.copyWith(color: _isDark() ? _kErrorDark : _kErrorLight);
}
return null;
}
@ -427,33 +439,26 @@ class _CustomStepperState extends State<CustomStepper> {
);
return new Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: children
);
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: children);
}
Widget _buildVerticalHeader(int index) {
return new Container(
margin: const EdgeInsets.symmetric(horizontal: 24.0),
child: new Row(
children: <Widget>[
new Column(
children: <Widget>[
// Line parts are always added in order for the ink splash to
// flood the tips of the connector lines.
_buildLine(!_isFirst(index)),
_buildIcon(index),
_buildLine(!_isLast(index)),
]
),
margin: const EdgeInsets.symmetric(horizontal: 24.0),
child: new Row(children: <Widget>[
new Column(children: <Widget>[
// Line parts are always added in order for the ink splash to
// flood the tips of the connector lines.
_buildLine(!_isFirst(index)),
_buildIcon(index),
_buildLine(!_isLast(index)),
]),
new Container(
margin: const EdgeInsetsDirectional.only(start: 12.0),
child: _buildHeaderText(index)
)
]
)
);
margin: const EdgeInsetsDirectional.only(start: 12.0),
child: _buildHeaderText(index))
]));
}
Widget _buildVerticalBody(int index) {
@ -493,7 +498,9 @@ class _CustomStepperState extends State<CustomStepper> {
firstCurve: const Interval(0.0, 0.6, curve: Curves.fastOutSlowIn),
secondCurve: const Interval(0.4, 1.0, curve: Curves.fastOutSlowIn),
sizeCurve: Curves.fastOutSlowIn,
crossFadeState: _isCurrent(index) ? CrossFadeState.showSecond : CrossFadeState.showFirst,
crossFadeState: _isCurrent(index)
? CrossFadeState.showSecond
: CrossFadeState.showFirst,
duration: kThemeAnimationDuration,
),
],
@ -504,29 +511,25 @@ class _CustomStepperState extends State<CustomStepper> {
final List<Widget> children = <Widget>[];
for (int i = 0; i < widget.steps.length; i += 1) {
children.add(
new Column(
key: _keys[i],
children: <Widget>[
new InkWell(
onTap: widget.steps[i].state != CustomStepState.disabled ? () {
// In the vertical case we need to scroll to the newly tapped
// step.
Scrollable.ensureVisible(
_keys[i].currentContext,
curve: Curves.fastOutSlowIn,
duration: kThemeAnimationDuration,
);
children.add(new Column(key: _keys[i], children: <Widget>[
new InkWell(
onTap: widget.steps[i].state != CustomStepState.disabled
? () {
// In the vertical case we need to scroll to the newly tapped
// step.
Scrollable.ensureVisible(
_keys[i].currentContext,
curve: Curves.fastOutSlowIn,
duration: kThemeAnimationDuration,
);
if (widget.onCustomStepTapped != null)
widget.onCustomStepTapped(i);
} : null,
child: _buildVerticalHeader(i)
),
_buildVerticalBody(i)
]
)
);
if (widget.onCustomStepTapped != null)
widget.onCustomStepTapped(i);
}
: null,
child: _buildVerticalHeader(i)),
_buildVerticalBody(i)
]));
}
return new ListView(
@ -541,10 +544,12 @@ class _CustomStepperState extends State<CustomStepper> {
for (int i = 0; i < widget.steps.length; i += 1) {
children.add(
new InkResponse(
onTap: widget.steps[i].state != CustomStepState.disabled ? () {
if (widget.onCustomStepTapped != null)
widget.onCustomStepTapped(i);
} : null,
onTap: widget.steps[i].state != CustomStepState.disabled
? () {
if (widget.onCustomStepTapped != null)
widget.onCustomStepTapped(i);
}
: null,
child: new Row(
children: <Widget>[
new Container(
@ -593,7 +598,7 @@ class _CustomStepperState extends State<CustomStepper> {
new AnimatedSize(
curve: Curves.fastOutSlowIn,
duration: kThemeAnimationDuration,
//vsync: this,
vsync: null,
child: widget.steps[widget.currentCustomStep].content,
),
_buildVerticalControls(),
@ -608,12 +613,11 @@ class _CustomStepperState extends State<CustomStepper> {
Widget build(BuildContext context) {
assert(debugCheckHasMaterial(context));
assert(() {
if (context.ancestorWidgetOfExactType(CustomStepper) != null)
if (context.findAncestorWidgetOfExactType<CustomStepper>() != null)
throw new FlutterError(
'CustomSteppers must not be nested. The material specification advises '
'CustomSteppers must not be nested. The material specification advises '
'that one should avoid embedding steppers within steppers. '
'https://material.google.com/components/steppers.html#steppers-usage\n'
);
'https://material.google.com/components/steppers.html#steppers-usage\n');
return true;
}());
assert(widget.type != null);
@ -630,9 +634,7 @@ class _CustomStepperState extends State<CustomStepper> {
// Paints a triangle whose base is the bottom of the bounding rectangle and its
// top vertex the middle of its top.
class _TrianglePainter extends CustomPainter {
_TrianglePainter({
this.color
});
_TrianglePainter({this.color});
final Color color;