diff --git a/chapter_05/lib/login_screen.dart b/chapter_05/lib/login_screen.dart index f5ee105..55d1c65 100644 --- a/chapter_05/lib/login_screen.dart +++ b/chapter_05/lib/login_screen.dart @@ -1,14 +1,17 @@ import 'package:flutter/material.dart'; -import 'stopwatch.dart'; +import './stopwatch.dart'; class LoginScreen extends StatefulWidget { static const route = '/login'; + + const LoginScreen({Key? key}) : super(key: key); + @override _LoginScreenState createState() => _LoginScreenState(); } class _LoginScreenState extends State { - String name; + late String name; final _nameController = TextEditingController(); final _emailController = TextEditingController(); final _formKey = GlobalKey(); @@ -17,7 +20,7 @@ class _LoginScreenState extends State { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: Text('Login'), + title: const Text('Login'), ), body: Center( child: _buildLoginForm(), @@ -37,14 +40,14 @@ class _LoginScreenState extends State { controller: _nameController, decoration: InputDecoration(labelText: 'Runner'), validator: (text) => - text.isEmpty ? 'Enter the runner\'s name.' : null, + text!.isEmpty ? 'Enter the runner\'s name.' : null, ), TextFormField( controller: _emailController, keyboardType: TextInputType.emailAddress, decoration: InputDecoration(labelText: 'Email'), validator: (text) { - if (text.isEmpty) { + if (text!.isEmpty) { return 'Enter the runner\'s email.'; } @@ -56,9 +59,9 @@ class _LoginScreenState extends State { return null; }, ), - SizedBox(height: 20), + const SizedBox(height: 20), ElevatedButton( - child: Text('Continue'), + child: const Text('Continue'), onPressed: _validate, ), ], @@ -67,7 +70,7 @@ class _LoginScreenState extends State { void _validate() { final form = _formKey.currentState; - if (!form.validate()) { + if (!form!.validate()) { return; } final name = _nameController.text; diff --git a/chapter_05/lib/main.dart b/chapter_05/lib/main.dart index 0805ef7..67c5d17 100644 --- a/chapter_05/lib/main.dart +++ b/chapter_05/lib/main.dart @@ -2,19 +2,23 @@ import 'package:flutter/material.dart'; import 'package:stopwatch/login_screen.dart'; import './stopwatch.dart'; -void main() => runApp(StopwatchApp()); +void main() => runApp(const StopwatchApp()); class StopwatchApp extends StatelessWidget { + const StopwatchApp({Key? key}) : super(key: key); + @override Widget build(BuildContext context) { return MaterialApp( routes: { - '/': (context) => LoginScreen(), + '/': (context) => const LoginScreen(), LoginScreen.route: (context) => LoginScreen(), - StopWatch.route: (context) => StopWatch(), + StopWatch.route: (context) => StopWatch( + email: '', + name: '', + ), }, initialRoute: '/', - ); } } diff --git a/chapter_05/lib/platform_alert.dart b/chapter_05/lib/platform_alert.dart index 894f77a..779f259 100644 --- a/chapter_05/lib/platform_alert.dart +++ b/chapter_05/lib/platform_alert.dart @@ -5,9 +5,8 @@ class PlatformAlert { final String title; final String message; - const PlatformAlert({@required this.title, @required this.message}) - : assert(title != null), - assert(message != null); + const PlatformAlert({required this.title, required this.message}); + void show(BuildContext context) { final platform = Theme.of(context).platform; @@ -42,7 +41,7 @@ class PlatformAlert { content: Text(message), actions: [ CupertinoButton( - child: Text('Close'), + child: const Text('Close'), onPressed: () => Navigator.of(context).pop()) ]); }); diff --git a/chapter_05/lib/stopwatch.dart b/chapter_05/lib/stopwatch.dart index 76b18b6..219dca5 100644 --- a/chapter_05/lib/stopwatch.dart +++ b/chapter_05/lib/stopwatch.dart @@ -1,26 +1,33 @@ import 'dart:async'; import 'package:flutter/material.dart'; -import 'platform_alert.dart'; - class StopWatch extends StatefulWidget { static const route = '/stopwatch'; final String name; final String email; - const StopWatch({Key key, this.name, this.email}) : super(key: key); + const StopWatch({Key? key, required this.name, required this.email}) + : super(key: key); + @override - State createState() => StopWatchState(); + State createState() => StopWatchState(); } class StopWatchState extends State { - int milliseconds = 0; - int seconds = 0; + late int milliseconds; final itemHeight = 60.0; final scrollController = ScrollController(); - Timer timer; - final laps = []; - bool isTicking = false; + late Timer timer; + final laps = []; + late bool isTicking = false; + + @override + void initState() { + super.initState(); + + isTicking = false; + milliseconds = 0; + } void _onTick(Timer time) { setState(() { @@ -30,14 +37,14 @@ class StopWatchState extends State { @override Widget build(BuildContext context) { - String name = ModalRoute.of(context).settings.arguments; + String name = ModalRoute.of(context)!.settings.arguments as String; return Scaffold( appBar: AppBar( title: Text(name), ), body: Column( - children: [ + children: [ Expanded(child: _buildCounter(context)), Expanded(child: _buildLapDisplay()), ], @@ -50,56 +57,56 @@ class StopWatchState extends State { color: Theme.of(context).primaryColor, child: Column( mainAxisAlignment: MainAxisAlignment.center, - children: [ + children: [ Text( 'Lap ${laps.length + 1}', style: Theme.of(context) .textTheme .subtitle1 - .copyWith(color: Colors.white), + ?.copyWith(color: Colors.white), ), Text( _secondsText(milliseconds), style: Theme.of(context) .textTheme .headline5 - .copyWith(color: Colors.white), + ?.copyWith(color: Colors.white), ), - SizedBox(height: 20), _buildControls() ], ), ); } - Row _buildControls() { + Widget _buildControls() { return Row( mainAxisAlignment: MainAxisAlignment.center, - children: [ + children: [ ElevatedButton( style: ButtonStyle( - backgroundColor: MaterialStateProperty.all(Colors.green), - foregroundColor: MaterialStateProperty.all(Colors.white), + backgroundColor: MaterialStateProperty.all(Colors.green), + foregroundColor: MaterialStateProperty.all(Colors.white), ), - child: Text('Start'), + child: const Text('Start'), onPressed: isTicking ? null : _startTimer, ), - SizedBox(width: 20), + const SizedBox(width: 20), ElevatedButton( style: ButtonStyle( - backgroundColor: MaterialStateProperty.all(Colors.yellow), + backgroundColor: MaterialStateProperty.all(Colors.yellow), + foregroundColor: MaterialStateProperty.all(Colors.black), ), - child: Text('Lap'), + child: const Text('Lap'), onPressed: isTicking ? _lap : null, ), - SizedBox(width: 20), + const SizedBox(width: 20), Builder( - builder: (context) => TextButton( + builder: (context) => ElevatedButton( style: ButtonStyle( - backgroundColor: MaterialStateProperty.all(Colors.red), - foregroundColor: MaterialStateProperty.all(Colors.white), + backgroundColor: MaterialStateProperty.all(Colors.red), + foregroundColor: MaterialStateProperty.all(Colors.white), ), - child: Text('Stop'), + child: const Text('Stop'), onPressed: isTicking ? () => _stopTimer(context) : null, ), ), @@ -108,7 +115,10 @@ class StopWatchState extends State { } void _startTimer() { - timer = Timer.periodic(Duration(milliseconds: 100), _onTick); + timer = Timer.periodic( + const Duration(milliseconds: 100), + _onTick, + ); setState(() { laps.clear(); isTicking = true; @@ -116,20 +126,17 @@ class StopWatchState extends State { } void _stopTimer(BuildContext context) { - timer.cancel(); setState(() { + timer.cancel(); isTicking = false; }); - // final totalRuntime = laps.fold(milliseconds, (total, lap) => total + lap); - // final alert = PlatformAlert( - // title: 'Run Completed!', - // message: 'Total Run Time is ${_secondsText(totalRuntime)}.', - // ); - // alert.show(context); - final controller = - showBottomSheet(context: context, builder: _buildRunCompleteSheet); - - Future.delayed(Duration(seconds: 5)).then((_) { + + final controller = showBottomSheet( + context: context, + builder: _buildRunCompleteSheet, + ); + + Future.delayed(const Duration(seconds: 5)).then((_) { controller.close(); }); } @@ -142,7 +149,7 @@ class StopWatchState extends State { void _lap() { scrollController.animateTo( itemHeight * laps.length, - duration: Duration(milliseconds: 500), + duration: const Duration(milliseconds: 500), curve: Curves.easeIn, ); setState(() { @@ -162,33 +169,40 @@ class StopWatchState extends State { return ListTile( contentPadding: EdgeInsets.symmetric(horizontal: 50), title: Text('Lap ${index + 1}'), - trailing: Text(_secondsText(milliseconds)), + trailing: Text( + _secondsText(milliseconds), + ), ); }, ), ); } - @override - void dispose() { - timer.cancel(); - super.dispose(); - } - Widget _buildRunCompleteSheet(BuildContext context) { - final totalRuntime = laps.fold(milliseconds, (total, lap) => total + lap); + final totalRuntime = + laps.fold(milliseconds, (total, lap) => (total as dynamic) + lap); final textTheme = Theme.of(context).textTheme; return SafeArea( - child: Container( - color: Theme.of(context).cardColor, - width: double.infinity, - child: Padding( + child: Container( + color: Theme.of(context).cardColor, + width: double.infinity, + child: Padding( padding: EdgeInsets.symmetric(vertical: 30.0), - child: Column(mainAxisSize: MainAxisSize.min, children: [ - Text('Run Finished!', style: textTheme.headline6), - Text('Total Run Time is ${_secondsText(totalRuntime)}.') - ])), - )); + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + 'Run Finished!', + style: textTheme.headline6, + ), + Text( + 'Total Run Time is ${_secondsText(totalRuntime)}.', + ) + ], + ), + ), + ), + ); } }