From da1acfcb9210c7dca60597e06baacbb292cebc6c Mon Sep 17 00:00:00 2001 From: Thibault Deckers Date: Fri, 16 Jul 2021 17:13:05 +0900 Subject: [PATCH] show timer for actionable snackbar --- .../common/action_mixins/feedback.dart | 72 ++++++++++++++++++- 1 file changed, 70 insertions(+), 2 deletions(-) diff --git a/lib/widgets/common/action_mixins/feedback.dart b/lib/widgets/common/action_mixins/feedback.dart index 06c3ff7c6..3a57a6f8c 100644 --- a/lib/widgets/common/action_mixins/feedback.dart +++ b/lib/widgets/common/action_mixins/feedback.dart @@ -1,3 +1,4 @@ +import 'dart:async'; import 'dart:math'; import 'package:aves/theme/durations.dart'; @@ -14,10 +15,14 @@ mixin FeedbackMixin { // provide the messenger if feedback happens as the widget is disposed void showFeedbackWithMessenger(ScaffoldMessengerState messenger, String message, [SnackBarAction? action]) { + final duration = action != null ? Durations.opToastActionDisplay : Durations.opToastDisplay; messenger.showSnackBar(SnackBar( - content: Text(message), + content: _FeedbackMessage( + message: message, + duration: action != null ? duration : null, + ), action: action, - duration: action != null ? Durations.opToastActionDisplay : Durations.opToastDisplay, + duration: duration, )); } @@ -136,3 +141,66 @@ class _ReportOverlayState extends State> with SingleTickerPr ); } } + +class _FeedbackMessage extends StatefulWidget { + final String message; + final Duration? duration; + + const _FeedbackMessage({ + Key? key, + required this.message, + this.duration, + }) : super(key: key); + + @override + _FeedbackMessageState createState() => _FeedbackMessageState(); +} + +class _FeedbackMessageState extends State<_FeedbackMessage> { + late int _totalSecs, _elapsedSecs = 0; + Timer? _timer; + + @override + void initState() { + super.initState(); + final duration = widget.duration; + if (duration != null) { + _totalSecs = duration.inSeconds; + _timer = Timer.periodic(const Duration(seconds: 1), (_) { + setState(() => _elapsedSecs++); + }); + } + } + + @override + void dispose() { + _timer?.cancel(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final text = Text(widget.message); + final duration = widget.duration; + return duration == null + ? text + : Row( + children: [ + Expanded(child: text), + const SizedBox(width: 16), + CircularPercentIndicator( + percent: (_elapsedSecs.toDouble() / (_totalSecs - 1)).clamp(0.0, 1.0), + lineWidth: 2, + radius: 32, + backgroundColor: Theme.of(context).accentColor, + progressColor: Colors.grey, + animation: true, + animationDuration: 1000, + center: Text('${_totalSecs - _elapsedSecs}'), + animateFromLastPercent: true, + reverse: true, + ), + ], + ); + } +}