mirror of
https://github.com/bggRGjQaUbCoE/PiliPlus.git
synced 2026-05-31 16:18:22 +08:00
opt: m3e loading (#1877)
* opt: loading * feat: refresh m3e * restore refreshIndicator --------- Co-authored-by: dom <githubaccount56556@proton.me>
This commit is contained in:
committed by
GitHub
parent
f0050dd6e6
commit
886c53c7d8
@@ -10,23 +10,21 @@ class CustomToast extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final ThemeData theme = Theme.of(context);
|
final colorScheme = ColorScheme.of(context);
|
||||||
return Container(
|
return Container(
|
||||||
margin: EdgeInsets.only(
|
margin: EdgeInsets.only(
|
||||||
bottom: MediaQuery.viewPaddingOf(context).bottom + 30,
|
bottom: MediaQuery.viewPaddingOf(context).bottom + 30,
|
||||||
),
|
),
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 17, vertical: 10),
|
padding: const EdgeInsets.symmetric(horizontal: 17, vertical: 10),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: theme.colorScheme.primaryContainer.withValues(
|
color: colorScheme.primaryContainer.withValues(alpha: toastOpacity),
|
||||||
alpha: toastOpacity,
|
|
||||||
),
|
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(20)),
|
borderRadius: const BorderRadius.all(Radius.circular(20)),
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
msg,
|
msg,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 13,
|
fontSize: 13,
|
||||||
color: theme.colorScheme.onPrimaryContainer,
|
color: colorScheme.onPrimaryContainer,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -41,7 +39,7 @@ class LoadingWidget extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final ThemeData theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
final onSurfaceVariant = theme.colorScheme.onSurfaceVariant;
|
final onSurfaceVariant = theme.colorScheme.onSurfaceVariant;
|
||||||
return Container(
|
return Container(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 30, vertical: 20),
|
padding: const EdgeInsets.symmetric(horizontal: 30, vertical: 20),
|
||||||
@@ -58,7 +56,6 @@ class LoadingWidget extends StatelessWidget {
|
|||||||
strokeWidth: 3,
|
strokeWidth: 3,
|
||||||
valueColor: AlwaysStoppedAnimation(onSurfaceVariant),
|
valueColor: AlwaysStoppedAnimation(onSurfaceVariant),
|
||||||
),
|
),
|
||||||
|
|
||||||
//msg
|
//msg
|
||||||
Text(msg, style: TextStyle(color: onSurfaceVariant)),
|
Text(msg, style: TextStyle(color: onSurfaceVariant)),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -217,8 +217,8 @@ class RefreshIndicatorState extends State<RefreshIndicator>
|
|||||||
RefreshIndicatorStatus? _status;
|
RefreshIndicatorStatus? _status;
|
||||||
late Future<void> _pendingRefreshFuture;
|
late Future<void> _pendingRefreshFuture;
|
||||||
double? _dragOffset;
|
double? _dragOffset;
|
||||||
late Color _effectiveValueColor =
|
late Color _effectiveValueColor;
|
||||||
widget.color ?? Theme.of(context).colorScheme.primary;
|
// late Color _backgroundColor;
|
||||||
|
|
||||||
static final Animatable<double> _threeQuarterTween = Tween<double>(
|
static final Animatable<double> _threeQuarterTween = Tween<double>(
|
||||||
begin: 0.0,
|
begin: 0.0,
|
||||||
@@ -274,9 +274,10 @@ class RefreshIndicatorState extends State<RefreshIndicator>
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _setupColorTween() {
|
void _setupColorTween() {
|
||||||
|
final colorScheme = ColorScheme.of(context);
|
||||||
|
// _backgroundColor = colorScheme.surfaceContainerHighest;
|
||||||
// Reset the current value color.
|
// Reset the current value color.
|
||||||
_effectiveValueColor =
|
_effectiveValueColor = widget.color ?? colorScheme.primary;
|
||||||
widget.color ?? Theme.of(context).colorScheme.primary;
|
|
||||||
final Color color = _effectiveValueColor;
|
final Color color = _effectiveValueColor;
|
||||||
if (color.a == 0) {
|
if (color.a == 0) {
|
||||||
// Set an always stopped animation instead of a driven tween.
|
// Set an always stopped animation instead of a driven tween.
|
||||||
@@ -558,14 +559,52 @@ class RefreshIndicatorState extends State<RefreshIndicator>
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool _onDrag(double offset, double viewportDimension) {
|
bool _onDrag(double offset, double viewportDimension) {
|
||||||
if (_positionController.value > 0.0 &&
|
if (_positionController.value > 0.0 && _status == .drag) {
|
||||||
_status == RefreshIndicatorStatus.drag) {
|
|
||||||
_dragOffset = _dragOffset! + offset;
|
_dragOffset = _dragOffset! + offset;
|
||||||
_checkDragOffset(viewportDimension);
|
_checkDragOffset(viewportDimension);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// late final _refreshKey = GlobalKey();
|
||||||
|
// Widget _m3eRefreshProgressIndicator(bool showIndeterminateIndicator) {
|
||||||
|
// const indicatorMargin = EdgeInsets.all(4);
|
||||||
|
// const indicatorPadding = EdgeInsets.all(6);
|
||||||
|
// const indicatorSize = 41.0;
|
||||||
|
|
||||||
|
// final progress = _value.value;
|
||||||
|
// return Padding(
|
||||||
|
// padding: indicatorMargin,
|
||||||
|
// child: SizedBox(
|
||||||
|
// width: indicatorSize,
|
||||||
|
// height: indicatorSize,
|
||||||
|
// child: Material(
|
||||||
|
// type: MaterialType.circle,
|
||||||
|
// color: _backgroundColor,
|
||||||
|
// elevation: widget.elevation,
|
||||||
|
// child: Padding(
|
||||||
|
// padding: indicatorPadding,
|
||||||
|
// child: showIndeterminateIndicator
|
||||||
|
// ? M3ELoadingIndicator(
|
||||||
|
// childKey: _refreshKey,
|
||||||
|
// color: _effectiveValueColor,
|
||||||
|
// morphs: Morphs.refreshMorphs,
|
||||||
|
// size: null,
|
||||||
|
// )
|
||||||
|
// : RawM3ELoadingIndicator(
|
||||||
|
// key: _refreshKey,
|
||||||
|
// morph: Morphs.manualMorph,
|
||||||
|
// progress: progress,
|
||||||
|
// angle: -progress * math.pi,
|
||||||
|
// color: _valueColor.value!,
|
||||||
|
// size: null,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
// ignore: camel_case_types
|
// ignore: camel_case_types
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
import 'dart:math' show pi;
|
import 'dart:math' show pi;
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/semantics.dart' show SemanticsConfiguration;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// created by dom on 2026/02/14
|
/// created by dom on 2026/02/14
|
||||||
@@ -73,6 +74,7 @@ class RenderLoadingIndicator extends RenderBox {
|
|||||||
if (_progress == value) return;
|
if (_progress == value) return;
|
||||||
_progress = value;
|
_progress = value;
|
||||||
markNeedsPaint();
|
markNeedsPaint();
|
||||||
|
markNeedsSemanticsUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -119,6 +121,16 @@ class RenderLoadingIndicator extends RenderBox {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void describeSemanticsConfiguration(SemanticsConfiguration config) {
|
||||||
|
super.describeSemanticsConfiguration(config);
|
||||||
|
config
|
||||||
|
..role = .progressBar
|
||||||
|
..minValue = '0'
|
||||||
|
..maxValue = '100'
|
||||||
|
..value = (_progress * 100).round().toString();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool get isRepaintBoundary => true;
|
bool get isRepaintBoundary => true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ import 'package:flutter/material.dart';
|
|||||||
|
|
||||||
const Widget m3eLoading = Center(child: M3ELoadingIndicator());
|
const Widget m3eLoading = Center(child: M3ELoadingIndicator());
|
||||||
|
|
||||||
const Widget circularLoading = Center(child: CircularProgressIndicator());
|
|
||||||
|
|
||||||
const Widget linearLoading = SliverToBoxAdapter(
|
const Widget linearLoading = SliverToBoxAdapter(
|
||||||
child: LinearProgressIndicator(),
|
child: LinearProgressIndicator(),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -17,14 +17,27 @@
|
|||||||
|
|
||||||
import 'dart:math' as math;
|
import 'dart:math' as math;
|
||||||
|
|
||||||
|
import 'package:PiliPlus/common/widgets/loading_widget/morphs.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/physics.dart' show SpringSimulation;
|
import 'package:flutter/physics.dart' show SpringSimulation;
|
||||||
|
import 'package:flutter/semantics.dart';
|
||||||
import 'package:material_new_shapes/material_new_shapes.dart';
|
import 'package:material_new_shapes/material_new_shapes.dart';
|
||||||
|
|
||||||
/// reimplement of https://github.com/EmilyMoonstone/material_3_expressive/tree/main/packages/loading_indicator_m3e
|
/// reimplement of https://github.com/EmilyMoonstone/material_3_expressive/tree/main/packages/loading_indicator_m3e
|
||||||
|
|
||||||
class M3ELoadingIndicator extends StatefulWidget {
|
class M3ELoadingIndicator extends StatefulWidget {
|
||||||
const M3ELoadingIndicator({super.key});
|
const M3ELoadingIndicator({
|
||||||
|
super.key,
|
||||||
|
// this.childKey,
|
||||||
|
this.morphs,
|
||||||
|
this.color,
|
||||||
|
this.size = const Size.square(40),
|
||||||
|
});
|
||||||
|
final List<Morph>? morphs;
|
||||||
|
|
||||||
|
final Color? color;
|
||||||
|
final Size size;
|
||||||
|
// final Key? childKey;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<M3ELoadingIndicator> createState() => _M3ELoadingIndicatorState();
|
State<M3ELoadingIndicator> createState() => _M3ELoadingIndicatorState();
|
||||||
@@ -32,42 +45,25 @@ class M3ELoadingIndicator extends StatefulWidget {
|
|||||||
|
|
||||||
class _M3ELoadingIndicatorState extends State<M3ELoadingIndicator>
|
class _M3ELoadingIndicatorState extends State<M3ELoadingIndicator>
|
||||||
with SingleTickerProviderStateMixin {
|
with SingleTickerProviderStateMixin {
|
||||||
static final List<Morph> _morphs = () {
|
|
||||||
final List<RoundedPolygon> shapes = [
|
|
||||||
MaterialShapes.softBurst,
|
|
||||||
MaterialShapes.cookie9Sided,
|
|
||||||
MaterialShapes.pentagon,
|
|
||||||
MaterialShapes.pill,
|
|
||||||
MaterialShapes.sunny,
|
|
||||||
MaterialShapes.cookie4Sided,
|
|
||||||
MaterialShapes.oval,
|
|
||||||
];
|
|
||||||
return [
|
|
||||||
for (var i = 0; i < shapes.length; i++)
|
|
||||||
Morph(
|
|
||||||
shapes[i],
|
|
||||||
shapes[(i + 1) % shapes.length],
|
|
||||||
),
|
|
||||||
];
|
|
||||||
}();
|
|
||||||
|
|
||||||
static const int _morphIntervalMs = 650;
|
static const int _morphIntervalMs = 650;
|
||||||
static const double _fullRotation = 360.0;
|
static const double _fullRotation = 2 * math.pi;
|
||||||
static const int _globalRotationDurationMs = 4666;
|
static const int _globalRotationDurationMs = 4666;
|
||||||
static const double _quarterRotation = _fullRotation / 4;
|
static const double _quarterRotation = _fullRotation / 4;
|
||||||
|
|
||||||
|
late final List<Morph> _morphs;
|
||||||
late final AnimationController _controller;
|
late final AnimationController _controller;
|
||||||
|
|
||||||
int _morphIndex = 1;
|
int _morphIndex = 1;
|
||||||
|
|
||||||
double _morphRotationTargetAngle = _quarterRotation;
|
double _morphRotationTarget = _quarterRotation;
|
||||||
|
|
||||||
final _morphAnimationSpec = SpringSimulation(
|
static final _morphAnimationSpec = SpringSimulation(
|
||||||
SpringDescription.withDampingRatio(ratio: 0.6, stiffness: 200.0, mass: 1.0),
|
SpringDescription.withDampingRatio(ratio: 0.6, stiffness: 200.0, mass: 1.0),
|
||||||
0.0,
|
0.0,
|
||||||
1.0,
|
1.0,
|
||||||
5.0,
|
5.0,
|
||||||
snapToEnd: true,
|
snapToEnd: true,
|
||||||
|
// tolerance: const Tolerance(velocity: 0.1, distance: 0.1),
|
||||||
);
|
);
|
||||||
|
|
||||||
void _statusListener(AnimationStatus status) {
|
void _statusListener(AnimationStatus status) {
|
||||||
@@ -78,23 +74,21 @@ class _M3ELoadingIndicatorState extends State<M3ELoadingIndicator>
|
|||||||
|
|
||||||
void _startAnimation() {
|
void _startAnimation() {
|
||||||
_morphIndex++;
|
_morphIndex++;
|
||||||
_morphRotationTargetAngle =
|
_morphRotationTarget =
|
||||||
(_morphRotationTargetAngle + _quarterRotation) % _fullRotation;
|
(_morphRotationTarget + _quarterRotation) % _fullRotation;
|
||||||
_controller
|
_controller.animateWith(_morphAnimationSpec);
|
||||||
..value = 0.0
|
|
||||||
..animateWith(_morphAnimationSpec);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
_morphs = widget.morphs ?? Morphs.loadingMorphs;
|
||||||
_controller =
|
_controller =
|
||||||
AnimationController(
|
AnimationController(
|
||||||
vsync: this,
|
vsync: this,
|
||||||
duration: const Duration(milliseconds: _morphIntervalMs),
|
duration: const Duration(milliseconds: _morphIntervalMs),
|
||||||
)
|
)
|
||||||
..addStatusListener(_statusListener)
|
..addStatusListener(_statusListener)
|
||||||
..value = 0.0
|
|
||||||
..animateWith(_morphAnimationSpec);
|
..animateWith(_morphAnimationSpec);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,82 +104,86 @@ class _M3ELoadingIndicatorState extends State<M3ELoadingIndicator>
|
|||||||
final elapsedInMs =
|
final elapsedInMs =
|
||||||
_morphIntervalMs * (_morphIndex - 1) +
|
_morphIntervalMs * (_morphIndex - 1) +
|
||||||
(_controller.lastElapsedDuration?.inMilliseconds ?? 0);
|
(_controller.lastElapsedDuration?.inMilliseconds ?? 0);
|
||||||
final globalRotationControllerValue =
|
final globalRotation =
|
||||||
(elapsedInMs % _globalRotationDurationMs) / _globalRotationDurationMs;
|
(elapsedInMs % _globalRotationDurationMs) /
|
||||||
final globalRotationDegrees = globalRotationControllerValue * _fullRotation;
|
_globalRotationDurationMs *
|
||||||
final totalRotationDegrees =
|
_fullRotation;
|
||||||
progress * _quarterRotation +
|
|
||||||
_morphRotationTargetAngle +
|
return progress * _quarterRotation + _morphRotationTarget + globalRotation;
|
||||||
globalRotationDegrees;
|
|
||||||
return totalRotationDegrees * (math.pi / 180.0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final color = Theme.of(context).colorScheme.secondaryFixedDim;
|
final color = widget.color ?? ColorScheme.of(context).secondaryFixedDim;
|
||||||
return AnimatedBuilder(
|
return AnimatedBuilder(
|
||||||
animation: _controller,
|
animation: _controller,
|
||||||
builder: (context, child) {
|
builder: (context, child) {
|
||||||
final progress = _controller.value;
|
final progress = _controller.value;
|
||||||
return _M3ELoadingIndicator(
|
return RawM3ELoadingIndicator(
|
||||||
|
// key: widget.childKey,
|
||||||
morph: _morphs[_morphIndex % _morphs.length],
|
morph: _morphs[_morphIndex % _morphs.length],
|
||||||
progress: progress,
|
progress: progress,
|
||||||
angle: _calcAngle(progress),
|
angle: _calcAngle(progress),
|
||||||
color: color,
|
color: color,
|
||||||
|
size: widget.size,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _M3ELoadingIndicator extends LeafRenderObjectWidget {
|
class RawM3ELoadingIndicator extends LeafRenderObjectWidget {
|
||||||
const _M3ELoadingIndicator({
|
const RawM3ELoadingIndicator({
|
||||||
|
super.key,
|
||||||
required this.morph,
|
required this.morph,
|
||||||
required this.progress,
|
required this.progress,
|
||||||
required this.angle,
|
required this.angle,
|
||||||
required this.color,
|
required this.color,
|
||||||
|
required this.size,
|
||||||
});
|
});
|
||||||
|
|
||||||
final Morph morph;
|
final Morph morph;
|
||||||
|
|
||||||
final double progress;
|
final double progress;
|
||||||
|
|
||||||
final double angle;
|
final double angle;
|
||||||
|
|
||||||
final Color color;
|
final Color color;
|
||||||
|
final Size size;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
RenderObject createRenderObject(BuildContext context) {
|
RenderObject createRenderObject(BuildContext context) {
|
||||||
return _RenderM3ELoadingIndicator(
|
return RenderM3ELoadingIndicator(
|
||||||
morph: morph,
|
morph: morph,
|
||||||
progress: progress,
|
progress: progress,
|
||||||
angle: angle,
|
angle: angle,
|
||||||
color: color,
|
color: color,
|
||||||
|
size: size,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void updateRenderObject(
|
void updateRenderObject(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
_RenderM3ELoadingIndicator renderObject,
|
RenderM3ELoadingIndicator renderObject,
|
||||||
) {
|
) {
|
||||||
renderObject
|
renderObject
|
||||||
..morph = morph
|
..morph = morph
|
||||||
..progress = progress
|
..progress = progress
|
||||||
..angle = angle
|
..angle = angle
|
||||||
..color = color;
|
..color = color
|
||||||
|
..preferredSize = size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _RenderM3ELoadingIndicator extends RenderBox {
|
class RenderM3ELoadingIndicator extends RenderBox {
|
||||||
_RenderM3ELoadingIndicator({
|
RenderM3ELoadingIndicator({
|
||||||
required Morph morph,
|
required Morph morph,
|
||||||
required double progress,
|
required double progress,
|
||||||
required double angle,
|
required double angle,
|
||||||
required Color color,
|
required Color color,
|
||||||
|
required Size size,
|
||||||
}) : _morph = morph,
|
}) : _morph = morph,
|
||||||
_progress = progress,
|
_progress = progress,
|
||||||
_angle = angle,
|
_angle = angle,
|
||||||
|
_preferredSize = size,
|
||||||
_color = color,
|
_color = color,
|
||||||
_paint = Paint()
|
_paint = Paint()
|
||||||
..style = PaintingStyle.fill
|
..style = PaintingStyle.fill
|
||||||
@@ -223,17 +221,35 @@ class _RenderM3ELoadingIndicator extends RenderBox {
|
|||||||
markNeedsPaint();
|
markNeedsPaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Size _preferredSize;
|
||||||
|
set preferredSize(Size value) {
|
||||||
|
if (_preferredSize == value) return;
|
||||||
|
_preferredSize = size;
|
||||||
|
markNeedsLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Size computeDryLayout(covariant BoxConstraints constraints) {
|
||||||
|
return constraints.constrain(_preferredSize);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void performLayout() {
|
void performLayout() {
|
||||||
size = constraints.constrainDimensions(40, 40);
|
size = computeDryLayout(constraints);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void describeSemanticsConfiguration(SemanticsConfiguration config) {
|
||||||
|
super.describeSemanticsConfiguration(config);
|
||||||
|
config.role = .loadingSpinner;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void paint(PaintingContext context, Offset offset) {
|
void paint(PaintingContext context, Offset offset) {
|
||||||
final width = size.width;
|
final width = size.width;
|
||||||
final value = size.width / 2;
|
final value = size.width / 2;
|
||||||
final matrix = Matrix4.identity()
|
final matrix =
|
||||||
..translateByDouble(offset.dx + value, offset.dy + value, 0.0, 1.0)
|
Matrix4.translationValues(offset.dx + value, offset.dy + value, 0.0)
|
||||||
..rotateZ(angle)
|
..rotateZ(angle)
|
||||||
..translateByDouble(-value, -value, 0.0, 1.0)
|
..translateByDouble(-value, -value, 0.0, 1.0)
|
||||||
..scaleByDouble(width, width, width, 1.0);
|
..scaleByDouble(width, width, width, 1.0);
|
||||||
|
|||||||
41
lib/common/widgets/loading_widget/morphs.dart
Normal file
41
lib/common/widgets/loading_widget/morphs.dart
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import 'package:material_new_shapes/material_new_shapes.dart';
|
||||||
|
|
||||||
|
abstract final class Morphs {
|
||||||
|
static List<Morph> buildMorph(
|
||||||
|
List<RoundedPolygon> shapes, {
|
||||||
|
bool loop = true,
|
||||||
|
}) {
|
||||||
|
assert(shapes.length >= 2);
|
||||||
|
return [
|
||||||
|
for (var i = 0; i < shapes.length - 1; i++)
|
||||||
|
Morph(shapes[i], shapes[i + 1]),
|
||||||
|
if (loop) Morph(shapes[shapes.length - 1], shapes[0]),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
static final loadingMorphs = buildMorph([
|
||||||
|
MaterialShapes.softBurst,
|
||||||
|
MaterialShapes.cookie9Sided,
|
||||||
|
MaterialShapes.pentagon,
|
||||||
|
MaterialShapes.pill,
|
||||||
|
MaterialShapes.sunny,
|
||||||
|
MaterialShapes.cookie4Sided,
|
||||||
|
MaterialShapes.oval,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// static final refreshMorphs = buildMorph([
|
||||||
|
// MaterialShapes.softBurst,
|
||||||
|
// MaterialShapes.cookie9Sided,
|
||||||
|
// MaterialShapes.gem,
|
||||||
|
// MaterialShapes.flower,
|
||||||
|
// MaterialShapes.sunny,
|
||||||
|
// MaterialShapes.cookie4Sided,
|
||||||
|
// MaterialShapes.oval,
|
||||||
|
// MaterialShapes.cookie12Sided,
|
||||||
|
// ]);
|
||||||
|
|
||||||
|
// static final manualMorph = Morph(
|
||||||
|
// MaterialShapes.circle,
|
||||||
|
// MaterialShapes.softBurst,
|
||||||
|
// );
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user