diff --git a/web/particle_background/LICENSE b/web/particle_background/LICENSE deleted file mode 100644 index f1e7e2f51..000000000 --- a/web/particle_background/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2019 Felix Blaschke - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/web/particle_background/README.md b/web/particle_background/README.md deleted file mode 100644 index 00e174861..000000000 --- a/web/particle_background/README.md +++ /dev/null @@ -1,7 +0,0 @@ -Flutter app demonstrating -[simple_animations](https://pub.dev/packages/simple_animations) in action. - -Contributed by Felix Blaschke. - -One of a series of samples -[published here](https://github.com/felixblaschke/simple_animations/tree/2.4.2/example). diff --git a/web/particle_background/analysis_options.yaml b/web/particle_background/analysis_options.yaml deleted file mode 100644 index de149220e..000000000 --- a/web/particle_background/analysis_options.yaml +++ /dev/null @@ -1,11 +0,0 @@ -include: ../../analysis_options.yaml - -analyzer: - strong-mode: - implicit-casts: true - implicit-dynamic: true - -linter: - rules: - constant_identifier_names: false - diff --git a/web/particle_background/assets/preview.png b/web/particle_background/assets/preview.png deleted file mode 100644 index 7a63a7991..000000000 Binary files a/web/particle_background/assets/preview.png and /dev/null differ diff --git a/web/particle_background/lib/main.dart b/web/particle_background/lib/main.dart deleted file mode 100644 index 315c1f715..000000000 --- a/web/particle_background/lib/main.dart +++ /dev/null @@ -1,181 +0,0 @@ -import 'dart:math'; - -import 'package:flutter/material.dart'; -import 'package:particle_background/simple_animations_package.dart'; - -void main() => runApp(const ParticleApp()); - -class ParticleApp extends StatelessWidget { - const ParticleApp({super.key}); - - @override - Widget build(BuildContext context) { - return const MaterialApp( - home: Scaffold( - body: ParticleBackgroundPage(), - ), - ); - } -} - -class ParticleBackgroundPage extends StatelessWidget { - const ParticleBackgroundPage({super.key}); - - @override - Widget build(BuildContext context) { - return Stack( - children: const [ - Positioned.fill(child: AnimatedBackground()), - Positioned.fill(child: Particles(30)), - Positioned.fill(child: CenteredText()), - ], - ); - } -} - -class Particles extends StatefulWidget { - final int numberOfParticles; - - const Particles(this.numberOfParticles, {super.key}); - - @override - State createState() => _ParticlesState(); -} - -class _ParticlesState extends State { - final Random random = Random(); - - final List particles = []; - - @override - void initState() { - List.generate(widget.numberOfParticles, (index) { - particles.add(ParticleModel(random)); - }); - super.initState(); - } - - @override - Widget build(BuildContext context) { - return Rendering( - startTime: const Duration(seconds: 30), - onTick: _simulateParticles, - builder: (context, time) { - return CustomPaint( - painter: ParticlePainter(particles, time), - ); - }, - ); - } - - _simulateParticles(Duration time) { - for (var particle in particles) { - particle.maintainRestart(time); - } - } -} - -class ParticleModel { - late Animatable tween; - late double size; - late AnimationProgress animationProgress; - Random random; - - ParticleModel(this.random) { - restart(); - } - - restart({Duration time = Duration.zero}) { - final startPosition = Offset(-0.2 + 1.4 * random.nextDouble(), 1.2); - final endPosition = Offset(-0.2 + 1.4 * random.nextDouble(), -0.2); - final duration = Duration(milliseconds: 3000 + random.nextInt(6000)); - - tween = MultiTrackTween([ - Track("x").add( - duration, Tween(begin: startPosition.dx, end: endPosition.dx), - curve: Curves.easeInOutSine), - Track("y").add( - duration, Tween(begin: startPosition.dy, end: endPosition.dy), - curve: Curves.easeIn), - ]); - animationProgress = AnimationProgress(duration: duration, startTime: time); - size = 0.2 + random.nextDouble() * 0.4; - } - - maintainRestart(Duration time) { - if (animationProgress.progress(time) == 1.0) { - restart(time: time); - } - } -} - -class ParticlePainter extends CustomPainter { - List particles; - Duration time; - - ParticlePainter(this.particles, this.time); - - @override - void paint(Canvas canvas, Size size) { - final paint = Paint()..color = Colors.white.withAlpha(50); - - for (var particle in particles) { - var progress = particle.animationProgress.progress(time); - final animation = particle.tween.transform(progress); - final position = - Offset(animation["x"] * size.width, animation["y"] * size.height); - canvas.drawCircle(position, size.width * 0.2 * particle.size, paint); - } - } - - @override - bool shouldRepaint(CustomPainter oldDelegate) => true; -} - -class AnimatedBackground extends StatelessWidget { - const AnimatedBackground({super.key}); - - @override - Widget build(BuildContext context) { - final tween = MultiTrackTween([ - Track("color1").add( - const Duration(seconds: 3), - ColorTween( - begin: const Color(0xff8a113a), end: Colors.lightBlue.shade900)), - Track("color2").add(const Duration(seconds: 3), - ColorTween(begin: const Color(0xff440216), end: Colors.blue.shade600)) - ]); - - return ControlledAnimation( - playback: Playback.MIRROR, - tween: tween, - duration: tween.duration, - builder: (context, dynamic animation) { - return Container( - decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topLeft, - end: Alignment.bottomRight, - colors: [animation["color1"], animation["color2"]])), - ); - }, - ); - } -} - -class CenteredText extends StatelessWidget { - const CenteredText({ - super.key, - }); - - @override - Widget build(BuildContext context) { - return const Center( - child: Text( - "Welcome to Flutter for web", - style: TextStyle(color: Colors.white, fontWeight: FontWeight.w200), - textScaleFactor: 4, - ), - ); - } -} diff --git a/web/particle_background/lib/simple_animations_package.dart b/web/particle_background/lib/simple_animations_package.dart deleted file mode 100644 index af5ae7374..000000000 --- a/web/particle_background/lib/simple_animations_package.dart +++ /dev/null @@ -1,455 +0,0 @@ -// Package simple_animations: -// https://pub.dev/packages/simple_animations - -import 'dart:math'; - -import 'package:flutter/scheduler.dart'; -import 'package:flutter/widgets.dart'; - -/// Widget to easily create a continuous animation. -/// -/// You need to specify a [builder] function that gets the build context passed -/// along with the [timeElapsed] (as a [Duration]) since the rendering started. -/// You can use this time to specify custom animations on it. -/// -/// The [builder] rebuilds all sub-widgets every frame. -/// -/// You define an [onTick] function that is called before builder to update -/// you rendered scene. It's also utilized during fast-forwarding the animation. -/// -/// Specify a [startTime] to fast-forward your animation in the beginning. -/// The widget will interpolate the animation by calling the [onTick] function -/// multiple times. (Default value is `20`. You can tune it by setting the -/// [startTimeSimulationTicks] property.) -class Rendering extends StatefulWidget { - final Widget Function(BuildContext context, Duration timeElapsed) builder; - final Function(Duration timeElapsed)? onTick; - final Duration startTime; - final int startTimeSimulationTicks; - - const Rendering( - {required this.builder, - this.onTick, - this.startTime = Duration.zero, - this.startTimeSimulationTicks = 20, - super.key}); - - @override - State createState() => _RenderingState(); -} - -class _RenderingState extends State - with SingleTickerProviderStateMixin { - late Ticker _ticker; - Duration _timeElapsed = const Duration(milliseconds: 0); - - @override - void initState() { - if (widget.startTime > Duration.zero) { - _simulateStartTimeTicks(); - } - - _ticker = createTicker((elapsed) { - _onRender(elapsed + widget.startTime); - }); - _ticker.start(); - super.initState(); - } - - void _onRender(Duration effectiveElapsed) { - if (widget.onTick != null) { - widget.onTick!(effectiveElapsed); - } - setState(() { - _timeElapsed = effectiveElapsed; - }); - } - - void _simulateStartTimeTicks() { - if (widget.onTick != null) { - for (var i in Iterable.generate(widget.startTimeSimulationTicks + 1)) { - final simulatedTime = Duration( - milliseconds: (widget.startTime.inMilliseconds * - i / - widget.startTimeSimulationTicks) - .round()); - widget.onTick!(simulatedTime); - } - } - } - - @override - void dispose() { - _ticker.stop(canceled: true); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return widget.builder(context, _timeElapsed); - } -} - -/// Animatable that tweens multiple parallel properties (called [Track]s). -/// --- -/// The constructor of [MultiTrackTween] expects a list of [Track] objects. -/// You can fetch the specified total duration via [duration] getter. -/// --- -/// Example: -/// -/// ```dart -/// final tween = MultiTrackTween([ -/// Track("color") -/// .add(Duration(seconds: 1), ColorTween(begin: Colors.red, end: Colors.blue)) -/// .add(Duration(seconds: 1), ColorTween(begin: Colors.blue, end: Colors.yellow)), -/// Track("width") -/// .add(Duration(milliseconds: 500), ConstantTween(200.0)) -/// .add(Duration(milliseconds: 1500), Tween(begin: 200.0, end: 400.0), -/// curve: Curves.easeIn) -/// ]); -/// -/// return ControlledAnimation( -/// duration: tween.duration, -/// tween: tween, -/// builder: (context, values) { -/// ... -/// } -/// ); -/// ``` -class MultiTrackTween extends Animatable> { - final _tracksToTween = {}; - var _maxDuration = 0; - - MultiTrackTween(List tracks) - : assert(tracks.isNotEmpty, "Add a List to configure the tween."), - assert(tracks.where((track) => track.items.isEmpty).isEmpty, - "Each Track needs at least one added Tween by using the add()-method.") { - _computeMaxDuration(tracks); - _computeTrackTweens(tracks); - } - - void _computeMaxDuration(List tracks) { - for (var track in tracks) { - final trackDuration = track.items - .map((item) => item.duration.inMilliseconds) - .reduce((sum, item) => sum + item); - _maxDuration = max(_maxDuration, trackDuration); - } - } - - void _computeTrackTweens(List tracks) { - for (var track in tracks) { - final trackDuration = track.items - .map((item) => item.duration.inMilliseconds) - .reduce((sum, item) => sum + item); - - final sequenceItems = track.items - .map((item) => TweenSequenceItem( - tween: item.tween, - weight: item.duration.inMilliseconds / _maxDuration)) - .toList(); - - if (trackDuration < _maxDuration) { - sequenceItems.add(TweenSequenceItem( - tween: ConstantTween(null), - weight: (_maxDuration - trackDuration) / _maxDuration)); - } - - final sequence = TweenSequence(sequenceItems); - - _tracksToTween[track.name] = - _TweenData(tween: sequence, maxTime: trackDuration / _maxDuration); - } - } - - /// Returns the highest duration specified by [Track]s. - /// --- - /// Use it to pass it into an [ControlledAnimation]. - /// - /// You can also scale it by multiplying a double value. - /// - /// Example: - /// ```dart - /// final tween = MultiTrackTween(listOfTracks); - /// - /// return ControlledAnimation( - /// duration: tween.duration * 1.25, // stretch animation by 25% - /// tween: tween, - /// builder: (context, values) { - /// ... - /// } - /// ); - /// ``` - Duration get duration { - return Duration(milliseconds: _maxDuration); - } - - @override - Map transform(double t) { - final Map result = {}; - _tracksToTween.forEach((name, tweenData) { - final double tTween = max(0, min(t, tweenData.maxTime! - 0.0001)); - result[name] = tweenData.tween!.transform(tTween); - }); - return result; - } -} - -/// Single property to tween. Used by [MultiTrackTween]. -class Track { - final String name; - final List items = []; - - Track(this.name); - - /// Adds a "piece of animation" to a [Track]. - /// - /// You need to pass a [duration] and a [tween]. It will return the track, so - /// you can specify a track in a builder's style. - /// - /// Optionally you can set a named parameter [curve] that applies an easing - /// curve to the tween. - Track add(Duration duration, Animatable tween, {Curve? curve}) { - items.add(TrackItem(duration, tween, curve: curve)); - return this; - } -} - -class TrackItem { - final Duration duration; - late Animatable tween; - - TrackItem(this.duration, Animatable tween, {Curve? curve}) { - if (curve != null) { - this.tween = tween.chain(CurveTween(curve: curve)); - } else { - this.tween = tween; - } - } -} - -class _TweenData { - final Animatable? tween; - final double? maxTime; - - _TweenData({this.tween, this.maxTime}); -} - -/// Playback tell the controller of the animation what to do. -enum Playback { - /// Animation stands still. - PAUSE, - - /// Animation plays forwards and stops at the end. - PLAY_FORWARD, - - /// Animation plays backwards and stops at the beginning. - PLAY_REVERSE, - - /// Animation will reset to the beginning and start playing forward. - START_OVER_FORWARD, - - /// Animation will reset to the end and start play backward. - START_OVER_REVERSE, - - /// Animation will play forwards and start over at the beginning when it - /// reaches the end. - LOOP, - - /// Animation will play forward until the end and will reverse playing until - /// it reaches the beginning. Then it starts over playing forward. And so on. - MIRROR -} - -/// Widget to create custom, managed, tween-based animations in a very simple way. -/// -/// --- -/// -/// An internal [AnimationController] will do everything you tell him by -/// dynamically assigning the one [Playback] to [playback] property. -/// By default the animation will start playing forward and stops at the end. -/// -/// A minimum set of properties are [duration] (time span of the animation), -/// [tween] (values to interpolate among the animation) and a [builder] function -/// (defines the animated scene). -/// -/// Instead of using [builder] as building function you can use for performance -/// critical scenarios [builderWithChild] along with a prebuild [child]. -/// -/// --- -/// -/// The following properties are optional: -/// -/// - You can apply a [delay] that forces the animation to pause a -/// specified time before the animation will perform the defined [playback] -/// instruction. -/// -/// - You can specify a [curve] that modifies the [tween] by applying a -/// non-linear animation function. You can find curves in [Curves], for -/// example [Curves.easeOut] or [Curves.easeIn]. -/// -/// - You can track the animation by setting an [AnimationStatusListener] to -/// the property [animationControllerStatusListener]. The internal [AnimationController] then -/// will route out any events that occur. [ControlledAnimation] doesn't filter -/// or modifies these events. These events are currently only reliable for the -/// [playback]-types [Playback.PLAY_FORWARD] and [Playback.PLAY_REVERSE]. -/// -/// - You can set the start position of animation by specifying [startPosition] -/// with a value between *0.0* and *1.0*. The [startPosition] is only -/// evaluated once during the initialization of the widget. -/// -class ControlledAnimation extends StatefulWidget { - final Playback playback; - final Animatable tween; - final Curve curve; - final Duration duration; - final Duration? delay; - final Widget Function(BuildContext buildContext, T animatedValue)? builder; - final Widget Function(BuildContext, Widget? child, T animatedValue)? - builderWithChild; - final Widget? child; - final AnimationStatusListener? animationControllerStatusListener; - final double startPosition; - - const ControlledAnimation( - {this.playback = Playback.PLAY_FORWARD, - required this.tween, - this.curve = Curves.linear, - required this.duration, - this.delay, - this.builder, - this.builderWithChild, - this.child, - this.animationControllerStatusListener, - this.startPosition = 0.0, - super.key}) - : assert( - (builderWithChild != null && child != null && builder == null) || - (builder != null && builderWithChild == null && child == null), - "Either use just builder and keep buildWithChild and child null. " - "Or keep builder null and set a builderWithChild and a child."), - assert( - startPosition >= 0 && startPosition <= 1, - "The property startPosition " - "must have a value between 0.0 and 1.0."); - - @override - State createState() => _ControlledAnimationState(); -} - -class _ControlledAnimationState extends State - with SingleTickerProviderStateMixin { - late AnimationController _controller; - late Animation _animation; - bool _isDisposed = false; - bool _waitForDelay = true; - bool _isCurrentlyMirroring = false; - - @override - void initState() { - _controller = AnimationController(vsync: this, duration: widget.duration) - ..addListener(() { - setState(() {}); - }) - ..value = widget.startPosition; - - _animation = widget.tween - .chain(CurveTween(curve: widget.curve)) - .animate(_controller) as Animation; - - if (widget.animationControllerStatusListener != null) { - _controller.addStatusListener(widget.animationControllerStatusListener!); - } - - initialize(); - super.initState(); - } - - Future initialize() async { - if (widget.delay != null) { - await Future.delayed(widget.delay!); - } - _waitForDelay = false; - await executeInstruction(); - } - - @override - void didUpdateWidget(ControlledAnimation oldWidget) { - _controller.duration = widget.duration; - executeInstruction(); - super.didUpdateWidget(oldWidget); - } - - Future executeInstruction() async { - if (_isDisposed || _waitForDelay) { - return; - } - - if (widget.playback == Playback.PAUSE) { - _controller.stop(); - } - if (widget.playback == Playback.PLAY_FORWARD) { - await _controller.forward(); - } - if (widget.playback == Playback.PLAY_REVERSE) { - await _controller.reverse(); - } - if (widget.playback == Playback.START_OVER_FORWARD) { - await _controller.forward(from: 0.0); - } - if (widget.playback == Playback.START_OVER_REVERSE) { - await _controller.reverse(from: 1.0); - } - if (widget.playback == Playback.LOOP) { - await _controller.repeat(); - } - if (widget.playback == Playback.MIRROR && !_isCurrentlyMirroring) { - _isCurrentlyMirroring = true; - await _controller.repeat(reverse: true); - } - - if (widget.playback != Playback.MIRROR) { - _isCurrentlyMirroring = false; - } - } - - @override - Widget build(BuildContext context) { - if (widget.builder != null) { - return widget.builder!(context, _animation.value); - } else if (widget.builderWithChild != null && widget.child != null) { - return widget.builderWithChild!(context, widget.child, _animation.value); - } - _controller.stop(canceled: true); - throw FlutterError( - "I don't know how to build the animation. Make sure to either specify " - "a builder or a builderWithChild (along with a child)."); - } - - @override - void dispose() { - _isDisposed = true; - _controller.dispose(); - super.dispose(); - } -} - -/// Utility class to compute an animation progress between two points in time. -/// -/// On creation you specify a [startTime] and a [duration]. -/// -/// You can query the progress value - a value between `0.0` and `11.0` - by -/// calling [progress] and passing the current time. -class AnimationProgress { - final Duration duration; - final Duration startTime; - - /// Creates an [AnimationProgress]. - AnimationProgress({required this.duration, required this.startTime}); - - /// Queries the current progress value based on the specified [startTime] and - /// [duration] as a value between `0.0` and `1.0`. It will automatically - /// clamp values this interval to fit in. - double progress(Duration time) => max(0.0, - min((time - startTime).inMilliseconds / duration.inMilliseconds, 1.0)); -} diff --git a/web/particle_background/pubspec.yaml b/web/particle_background/pubspec.yaml deleted file mode 100644 index b99d326ed..000000000 --- a/web/particle_background/pubspec.yaml +++ /dev/null @@ -1,14 +0,0 @@ -name: particle_background -description: Example for the simple_animations package -homepage: https://github.com/felixblaschke/simple_animations - -environment: - sdk: ">=2.17.0-0 <3.0.0" - -dependencies: - flutter: - sdk: flutter - flutter_lints: ^2.0.1 -flutter: - assets: - - preview.png diff --git a/web/particle_background/web/index.html b/web/particle_background/web/index.html deleted file mode 100644 index 1785ebb8b..000000000 --- a/web/particle_background/web/index.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/web/samples_index/lib/src/samples.yaml b/web/samples_index/lib/src/samples.yaml index c702b0b91..f43b7286f 100644 --- a/web/samples_index/lib/src/samples.yaml +++ b/web/samples_index/lib/src/samples.yaml @@ -634,23 +634,6 @@ samples: web: web/github_dataviz type: demo - - name: Particle Background - author: Felix Blaschke - screenshots: - - url: images/particle_background1.png - alt: Particle Background screenshot - source: https://github.com/flutter/samples/tree/main/web/particle_background - description: > - Flutter app demonstrating package:simple_animations in action. - difficulty: intermediate - widgets: [] - packages: [] - platforms: ['web'] - links: [] - tags: ['demo', 'animation'] - web: web/particle_background - type: demo - - name: Dice author: Jaime Blasco screenshots: diff --git a/web/samples_index/web/images/particle_background1.png b/web/samples_index/web/images/particle_background1.png deleted file mode 100644 index 1bf2637d7..000000000 Binary files a/web/samples_index/web/images/particle_background1.png and /dev/null differ