import 'package:expandable/expandable.dart';
import 'package:flutter/material.dart';
import 'package:stop_watch_timer/stop_watch_timer.dart';
void main() async {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: HomePageWidget(),
title: 'FitnessApp',
debugShowCheckedModeBanner: false,
);
}
}
// This is the main widget for the home page of the app.
class HomePageWidget extends StatefulWidget {
const HomePageWidget({super.key});
@override
State<HomePageWidget> createState() => _HomePageWidgetState();
}
// This is the state class for the HomePageWidget.
class _HomePageWidgetState extends State<HomePageWidget> {
// Controllers for expandable panels (to control their open/close state).
final ExpandableController _expandableController1 =
ExpandableController(initialExpanded: false);
final ExpandableController _expandableController2 =
ExpandableController(initialExpanded: false);
final ExpandableController _expandableController3 =
ExpandableController(initialExpanded: false);
final ExpandableController _expandableController4 =
ExpandableController(initialExpanded: false);
final ExpandableController _expandableController5 =
ExpandableController(initialExpanded: false);
// Timers for each exercise.
final StopWatchTimer _timerA = StopWatchTimer();
final StopWatchTimer _timerB = StopWatchTimer();
final StopWatchTimer _timerC = StopWatchTimer();
final StopWatchTimer _timerD = StopWatchTimer();
final StopWatchTimer _timerE = StopWatchTimer();
@override
void dispose() {
// Clean up the timers when the widget is removed from the screen.
_timerA.dispose();
_timerB.dispose();
_timerC.dispose();
_timerD.dispose();
_timerE.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
// Set the background color to white.
backgroundColor: Colors.white,
appBar: AppBar(
// Set the app bar color.
backgroundColor: const Color(0xFF308D46),
// Hide the back button.
automaticallyImplyLeading: false,
title: const Align(
alignment: Alignment.center,
child: Text(
// App bar title.
'Fitness App',
style: TextStyle(
fontSize: 40.0,
color: Colors.white,
),
),
),
// Add a shadow to the app bar.
elevation: 2.0,
),
body: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
// Title for the exercise selection section.
const Padding(
padding: EdgeInsets.all(10.0),
child: Text(
'Select Exercise',
style: TextStyle(
color: Color(0xFF308D46),
fontSize: 25.0,
),
),
),
// Widgets for each exercise.
// Walk exercise.
ExerciseWidget(
expandableController: _expandableController1,
timer: _timerA,
title: "Walk",
iconData: Icons.directions_walk),
// Swim exercise.
ExerciseWidget(
expandableController: _expandableController2,
timer: _timerB,
title: "Swim",
iconData: Icons.pool),
// Gymnastics exercise.
ExerciseWidget(
expandableController: _expandableController3,
timer: _timerC,
title: "Gymnastics",
iconData: Icons.sports_gymnastics_outlined),
// Running exercise.
ExerciseWidget(
expandableController: _expandableController4,
timer: _timerD,
title: "Running",
iconData: Icons.run_circle_outlined),
// Cycling exercise.
ExerciseWidget(
expandableController: _expandableController5,
timer: _timerE,
title: "Cycling",
iconData: Icons.directions_bike_outlined),
],
),
);
}
}
// This widget represents a single exercise with an expandable panel.
class ExerciseWidget extends StatelessWidget {
const ExerciseWidget({
super.key,
required ExpandableController expandableController,
required StopWatchTimer timer,
required String title,
required IconData iconData,
}) : _expandableController = expandableController,
_timer = timer,
title = title,
iconData = iconData;
// Controller for the expandable panel.
final ExpandableController _expandableController;
// Timer for the exercise.
final StopWatchTimer _timer;
// Title of the exercise.
final String title;
// Icon for the exercise.
final IconData iconData;
@override
Widget build(BuildContext context) {
return Expanded(
child: Container(
width: double.infinity,
color: Colors.white,
child: ExpandableNotifier(
controller: _expandableController,
child: ExpandablePanel(
header: Center(
child: Text(
// Display the exercise title.
title,
style: TextStyle(fontWeight: FontWeight.w600, fontSize: 24),
),
),
collapsed: Center(
child: Icon(
// Display the exercise icon when collapsed.
iconData,
size: 100,
)),
// Show the stopwatch when expanded.
expanded: StopWatchWidget(timer: _timer),
theme: const ExpandableThemeData(
// Allow tapping the header to expand.
tapHeaderToExpand: true,
tapBodyToExpand: false,
tapBodyToCollapse: false,
headerAlignment: ExpandablePanelHeaderAlignment.center,
// Show an arrow icon in the header.
hasIcon: true,
),
),
),
),
);
}
}
// This widget displays the stopwatch and controls for starting/stopping the timer.
class StopWatchWidget extends StatelessWidget {
const StopWatchWidget({
super.key,
required StopWatchTimer timer,
}) : _timer = timer;
// Timer for the stopwatch.
final StopWatchTimer _timer;
@override
Widget build(BuildContext context) {
return StreamBuilder<int>(
// Listen to the timer's stream.
stream: _timer.rawTime,
initialData: 0,
builder: (context, snapshot) {
final value = snapshot.data!;
// Format the time to display minutes and seconds.
final displayTime = StopWatchTimer.getDisplayTime(value,
hours: false, milliSecond: false);
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// Display the current time.
Text(
displayTime,
style: const TextStyle(
fontSize: 24.0,
),
),
SizedBox(
width: 30,
),
// Button to start or stop the timer.
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: _timer.isRunning ? Colors.red : Colors.green,
foregroundColor: Colors.white),
onPressed: () {
// Toggle between start and stop.
_timer.isRunning ? _timer.onStopTimer() : _timer.onStartTimer();
},
child: Text(_timer.isRunning ? 'Stop' : 'Start'),
),
],
);
},
);
}
}