From 1eba87c816045c11c65aa6a7161e0b26cd3c0e90 Mon Sep 17 00:00:00 2001 From: Alexandre Roux Date: Fri, 11 Oct 2024 23:23:15 +0200 Subject: [PATCH] feat: add face in --- app_widget/analysis_options.yaml | 6 +- app_widget/lib/src/confirm_dialog.dart | 1 + app_widget/lib/view/fade_in.dart | 148 +++++++++++++++++++++++++ 3 files changed, 154 insertions(+), 1 deletion(-) create mode 100644 app_widget/lib/view/fade_in.dart diff --git a/app_widget/analysis_options.yaml b/app_widget/analysis_options.yaml index 6fcd113..8e81fbf 100644 --- a/app_widget/analysis_options.yaml +++ b/app_widget/analysis_options.yaml @@ -1,2 +1,6 @@ # tekartik flutter recommended lints (extension over google lints and pedantic) -include: package:tekartik_lints_flutter/strict.yaml \ No newline at end of file +include: package:tekartik_lints_flutter/package.yaml + +linter: + rules: + public_member_api_docs: false \ No newline at end of file diff --git a/app_widget/lib/src/confirm_dialog.dart b/app_widget/lib/src/confirm_dialog.dart index f05a118..e6c9223 100644 --- a/app_widget/lib/src/confirm_dialog.dart +++ b/app_widget/lib/src/confirm_dialog.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; +/// A simple dialog button class DialogButton extends StatelessWidget { final String text; final VoidCallback onPressed; diff --git a/app_widget/lib/view/fade_in.dart b/app_widget/lib/view/fade_in.dart new file mode 100644 index 0000000..af0033c --- /dev/null +++ b/app_widget/lib/view/fade_in.dart @@ -0,0 +1,148 @@ +import 'dart:async'; + +import 'package:flutter/widgets.dart'; + +class FadeIn extends StatefulWidget { + /// Fade-in controller + final FadeInController? controller; + + /// Child widget to fade-in + final Widget? child; + + /// Duration of fade-in. Defaults to 250ms + final Duration duration; + + /// Fade-in curve. Defaults to [Curves.easeIn] + final Curve curve; + + const FadeIn({ + super.key, + this.controller, + this.child, + this.duration = const Duration(milliseconds: 250), + this.curve = Curves.easeIn, + }); + + @override + State createState() => _FadeInState(); +} + +enum FadeInAction { + fadeIn, + fadeOut, +} + +/// Fade-in controller which dispatches fade-in/fade-out actions +class FadeInController { + final _streamController = StreamController(); + + /// Automatically starts the initial fade-in. Defaults to false + final bool autoStart; + + FadeInController({this.autoStart = false}); + + void dispose() => _streamController.close(); + + /// Fades-in child + void fadeIn() => run(FadeInAction.fadeIn); + + /// Fades-out child + void fadeOut() => run(FadeInAction.fadeOut); + + /// Dispatches a [FadeInAction] + void run(FadeInAction action) => _streamController.add(action); + + /// Stream of [FadeInAction]s dispatched by this controller + Stream get stream => _streamController.stream; +} + +class _FadeInState extends State with TickerProviderStateMixin { + late AnimationController _controller; + StreamSubscription? _listener; + + @override + void initState() { + super.initState(); + + _controller = AnimationController( + vsync: this, + duration: widget.duration, + ); + + _setupCurve(); + + if (widget.controller?.autoStart != false) { + fadeIn(); + } + + _listen(); + } + + void _setupCurve() { + final curve = CurvedAnimation(parent: _controller, curve: widget.curve); + + Tween( + begin: 0.0, + end: 1.0, + ).animate(curve); + } + + void _listen() { + if (_listener != null) { + _listener!.cancel(); + _listener = null; + } + + if (widget.controller != null) { + _listener = widget.controller!.stream.listen(_onAction); + } + } + + void _onAction(FadeInAction action) { + switch (action) { + case FadeInAction.fadeIn: + fadeIn(); + break; + case FadeInAction.fadeOut: + fadeOut(); + break; + } + } + + @override + void didUpdateWidget(FadeIn oldWidget) { + if (oldWidget.controller != widget.controller) { + _listen(); + } + + if (oldWidget.duration != widget.duration) { + _controller.duration = widget.duration; + } + + if (oldWidget.curve != widget.curve) { + _setupCurve(); + } + + super.didUpdateWidget(oldWidget); + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return FadeTransition( + opacity: _controller, + child: widget.child, + ); + } + + /// Fades-in child + void fadeIn() => _controller.forward(); + + /// Fades-out child + void fadeOut() => _controller.reverse(); +}