@@ -2,14 +2,10 @@ import 'package:flutter/material.dart';
22import 'package:flutter_curve_visualizer/screen_mode.dart' ;
33import 'package:flutter_curve_visualizer/utils/curves_enum.dart' ;
44import 'package:flutter_curve_visualizer/utils/extension/string.dart' ;
5- import 'package:flutter_curve_visualizer/utils/theme/theme_provider.dart' ;
65import 'package:flutter_curve_visualizer/views/widgets/animated_box/animated_box_widget.dart' ;
6+ import 'package:flutter_curve_visualizer/views/widgets/appbar.dart' ;
77import 'package:flutter_curve_visualizer/views/widgets/dropdown_menu.dart' ;
88import 'package:flutter_curve_visualizer/views/widgets/graph/graph_widget.dart' ;
9- import 'package:flutter_svg/flutter_svg.dart' ;
10- import 'package:provider/provider.dart' ;
11- import 'package:url_launcher/url_launcher.dart' ;
12-
139import 'widgets/code_block.dart' ;
1410
1511class HomePage extends StatefulWidget {
@@ -20,20 +16,15 @@ class HomePage extends StatefulWidget {
2016}
2117
2218class _HomePageState extends State <HomePage > with TickerProviderStateMixin {
19+ late AnimationController playPauseController;
2320 late AnimationController controller;
24-
25- late CurvedAnimation animation;
21+ late CurvedAnimation curveAnimation;
2622
2723 late String selectedCategory;
28-
2924 late CurvesEnum selectedCurve;
3025
3126 late int animationTime;
3227
33- late AnimationController playPauseController;
34-
35- bool showCurveOutline = true ;
36-
3728 @override
3829 void initState () {
3930 super .initState ();
@@ -45,44 +36,33 @@ class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
4536 playPauseController = AnimationController (
4637 vsync: this ,
4738 duration: Duration (milliseconds: 250 ),
48- );
39+ ).. forward () ;
4940
5041 controller = AnimationController (
5142 vsync: this ,
5243 duration: Duration (seconds: animationTime),
53- );
44+ ).. repeat (reverse : true ) ;
5445
55- animation = CurvedAnimation (
46+ curveAnimation = CurvedAnimation (
5647 parent: controller,
5748 curve: selectedCurve.curve,
5849 );
59-
60- controller.repeat (reverse: true );
61-
62- controller.addListener (playPauseListener);
63- }
64-
65- void playPauseListener () {
66- if (controller.isAnimating) {
67- playPauseController.forward ();
68- } else {
69- playPauseController.reset ();
70- }
7150 }
7251
7352 @override
7453 void dispose () {
75- controller.removeListener (playPauseListener);
7654 playPauseController.dispose ();
7755 controller.dispose ();
7856 super .dispose ();
7957 }
8058
8159 void updateCategory (String ? category) {
60+ if (category == null ) return ;
61+
8262 setState (() {
83- selectedCategory = category! ;
63+ selectedCategory = category;
8464 selectedCurve = CurvesEnum .list[category]! .first;
85- animation = CurvedAnimation (
65+ curveAnimation = CurvedAnimation (
8666 parent: controller,
8767 curve: selectedCurve.curve,
8868 );
@@ -92,55 +72,66 @@ class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
9272 void updateCurve (CurvesEnum curve) {
9373 setState (() {
9474 selectedCurve = curve;
95-
96- animation = CurvedAnimation (
97- parent: controller,
98- curve: selectedCurve.curve,
99- );
75+ curveAnimation.curve = curve.curve;
10076 });
10177 }
10278
10379 void updateAnimationTime (double seconds) {
104- animationTime = seconds.toInt ();
105- controller = AnimationController (
106- vsync: this ,
107- duration: Duration (seconds: animationTime),
108- );
109- setState (() {});
80+ // return if both values are same
81+ if (animationTime == seconds.toInt ()) return ;
11082
111- animation = CurvedAnimation (
112- parent: controller,
113- curve: selectedCurve.curve,
114- );
115- controller.repeat (reverse: true );
116- playPauseController.forward ();
83+ setState (() {
84+ animationTime = seconds.toInt ();
85+
86+ controller.duration = Duration (seconds: animationTime);
87+
88+ curveAnimation.curve = selectedCurve.curve;
89+
90+ if (controller.isForwardOrCompleted) {
91+ controller.repeat (reverse: true );
92+ } else {
93+ controller.reverse ().then ((value) => controller.repeat (reverse: true ));
94+ }
95+
96+ playPauseController.forward ();
97+ });
98+ }
99+
100+ void playPauseAnimation () {
101+ if (controller.isAnimating) {
102+ controller.stop ();
103+ playPauseController.animateBack (0.0 );
104+ } else {
105+ controller.repeat (reverse: true );
106+ playPauseController.forward ();
107+ }
117108 }
118109
119110 @override
120111 Widget build (BuildContext context) {
121112 final screenMode = ScreenModeWidget .of (context);
122113
123- final theme = Theme .of (context);
124-
125- final decoration = BoxDecoration (
126- color: Theme .of (context).colorScheme.onPrimaryFixed,
127- borderRadius: BorderRadius .circular (10 ),
128- );
114+ final double spacing = switch (screenMode) {
115+ ScreenMode .mobile => 20 ,
116+ ScreenMode .tablet => 30 ,
117+ ScreenMode .web => 30 ,
118+ };
129119
130120 final animationWidget = Column (
131121 children: [
132122 // Graph
133123 GraphWidget (
134- showCurveOutline: showCurveOutline,
135124 controller: controller,
136- animation: animation ,
125+ animation: curveAnimation ,
137126 ),
127+
128+ // Box Animations
138129 SizedBox (
139130 width: MediaQuery .of (context).size.width /
140131 (screenMode.isMobileOrTablet ? 1 : 3 ),
141132 child: Wrap (
142- spacing: 8.0 ,
143- runSpacing: 8.0 ,
133+ spacing: spacing / 2 ,
134+ runSpacing: spacing / 2 ,
144135 runAlignment: WrapAlignment .center,
145136 alignment: WrapAlignment .center,
146137 children: AnimationType .values.map (
@@ -154,7 +145,7 @@ class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
154145 dimension: 100 ,
155146 child: AnimatedBoxWidget (
156147 animationType: animationType,
157- animation: animation ,
148+ animation: curveAnimation ,
158149 ),
159150 ),
160151 ],
@@ -172,22 +163,22 @@ class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
172163 ),
173164 child: Column (
174165 mainAxisSize: MainAxisSize .min,
175- spacing: 20 ,
166+ spacing: spacing ,
176167 children: [
177168 // Code block
178169 CodeBlock (curve: selectedCurve),
179170
180171 // Curve category
181172 DropdownMenuWidget <String >(
182- title: "Curve Category" ,
173+ title: "Category" ,
183174 value: selectedCategory,
184175 items: CurvesEnum .list.keys.toList (),
185176 onChanged: updateCategory,
186177 ),
187178
188179 // Curve type
189180 DropdownMenuWidget <CurvesEnum >(
190- title: "Curve Type" ,
181+ title: "Type" ,
191182 value: selectedCurve,
192183 items: CurvesEnum .list[selectedCategory]! ..toList (),
193184 onChanged: (value) => updateCurve (value! ),
@@ -199,7 +190,10 @@ class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
199190 // Curve type
200191 Container (
201192 padding: EdgeInsets .symmetric (horizontal: 12.0 , vertical: 8.0 ),
202- decoration: decoration,
193+ decoration: BoxDecoration (
194+ color: Theme .of (context).colorScheme.onPrimaryFixed,
195+ borderRadius: BorderRadius .circular (10 ),
196+ ),
203197 child: Column (
204198 crossAxisAlignment: CrossAxisAlignment .start,
205199 children: [
@@ -221,59 +215,16 @@ class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
221215 );
222216
223217 return Scaffold (
224- appBar: AppBar (
225- title: const Text ('Flutter Curve Visualizer' ),
226- actions: [
227- Padding (
228- padding: const EdgeInsets .only (right: 12.0 ),
229- child: IconButton (
230- onPressed: () {
231- launchUrl (Uri .parse (
232- "https://github.com/vchib1/flutter-curve-visualizer" ));
233- },
234- icon: SvgPicture .asset (
235- "assets/svg/github.svg" ,
236- width: theme.iconTheme.size ?? 24 ,
237- height: theme.iconTheme.size ?? 24 ,
238- colorFilter: ColorFilter .mode (
239- theme.iconTheme.color ?? Colors .black,
240- BlendMode .srcIn,
241- ),
242- ),
243- ),
244- ),
245- Padding (
246- padding: const EdgeInsets .only (right: 12.0 ),
247- child: Consumer <ThemeProvider >(
248- builder: (context, value, child) {
249- final iconData = value.getThemeMode () == ThemeMode .dark
250- ? Icons .light_mode
251- : Icons .dark_mode;
252-
253- return IconButton (
254- onPressed: () => value.toggleTheme (),
255- icon: Icon (iconData),
256- );
257- },
258- ),
259- ),
260- ],
261- ),
218+ appBar: HomeAppBar (),
262219 floatingActionButton: FloatingActionButton (
220+ onPressed: playPauseAnimation,
263221 child: Padding (
264222 padding: const EdgeInsets .all (8.0 ),
265223 child: AnimatedIcon (
266- icon: AnimatedIcons .play_pause, progress: playPauseController),
224+ icon: AnimatedIcons .play_pause,
225+ progress: playPauseController,
226+ ),
267227 ),
268- onPressed: () {
269- if (controller.isAnimating) {
270- controller.stop ();
271- playPauseController.animateBack (0.0 );
272- } else {
273- controller.repeat (reverse: true );
274- playPauseController.forward ();
275- }
276- },
277228 ),
278229 body: SingleChildScrollView (
279230 child: Container (
@@ -282,23 +233,23 @@ class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
282233 padding: const EdgeInsets .symmetric (horizontal: 16.0 ),
283234 child: switch (ScreenModeWidget .of (context)) {
284235 ScreenMode .mobile => Column (
285- spacing: 10 ,
236+ spacing: spacing ,
286237 children: [
287238 animationWidget,
288239 controlsWidget,
289240 const SizedBox (height: 10 ),
290241 ],
291242 ),
292243 ScreenMode .tablet => Column (
293- spacing: 20 ,
244+ spacing: spacing ,
294245 children: [
295246 animationWidget,
296247 controlsWidget,
297248 const SizedBox (height: 20 ),
298249 ],
299250 ),
300251 ScreenMode .web => Row (
301- spacing: 10 ,
252+ spacing: spacing ,
302253 children: [
303254 Expanded (
304255 flex: 1 ,
0 commit comments