From b4c0015847250ed652538f84a261787f5515032b Mon Sep 17 00:00:00 2001 From: Crondung <1922635@stud.hs-mannheim.de> Date: Mon, 27 Feb 2023 01:20:00 +0100 Subject: [PATCH 01/12] added workout widget and workout provider to handle different workout phases and durations --- lib/pages/interval_page.dart | 11 ++++++++- lib/pages/main_page.dart | 2 +- lib/providers/timer_provider.dart | 2 +- lib/providers/workout_provider.dart | 33 +++++++++++++++++++++++++++ lib/widgets/workout_timer_widget.dart | 31 +++++++++++++++++++++++++ 5 files changed, 76 insertions(+), 3 deletions(-) create mode 100644 lib/providers/workout_provider.dart create mode 100644 lib/widgets/workout_timer_widget.dart diff --git a/lib/pages/interval_page.dart b/lib/pages/interval_page.dart index f6d2fcd..74ccffa 100644 --- a/lib/pages/interval_page.dart +++ b/lib/pages/interval_page.dart @@ -3,8 +3,10 @@ import 'package:audioplayers/audioplayers.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:smoke_cess_app/providers/timer_provider.dart'; +import 'package:smoke_cess_app/providers/workout_provider.dart'; import 'package:smoke_cess_app/widgets/popup_for_start_and_stop.dart'; import 'package:smoke_cess_app/widgets/timer_widget.dart'; +import 'package:smoke_cess_app/widgets/workout_timer_widget.dart'; import '../providers/input_provider.dart'; @@ -168,7 +170,14 @@ class _IntervalTimerPageState extends State { @override Widget build(BuildContext context) { - return ChangeNotifierProvider( + return MultiProvider( + providers: [ + ChangeNotifierProvider(create: (context) => TimerProvider()), + ChangeNotifierProvider(create: (context) => WorkoutProvider()) + ], + child: WorkoutTimerWidget(), + ); + ChangeNotifierProvider( create: (context) => TimerProvider(), child: TimerWidget( duration: Duration(seconds: 5), diff --git a/lib/pages/main_page.dart b/lib/pages/main_page.dart index 2af4f13..9b6127f 100644 --- a/lib/pages/main_page.dart +++ b/lib/pages/main_page.dart @@ -15,7 +15,7 @@ class MyHomePage extends StatefulWidget { } class MyHomePageState extends State { - int _selectedIndex = 4; + int _selectedIndex = 2; int? _gruppe; final List _titles = [ diff --git a/lib/providers/timer_provider.dart b/lib/providers/timer_provider.dart index 0601b39..f5a7689 100644 --- a/lib/providers/timer_provider.dart +++ b/lib/providers/timer_provider.dart @@ -9,9 +9,9 @@ class TimerProvider extends ChangeNotifier { void startTimer(Duration duration) { started = true; - print('starting timer'); _timer = Timer.periodic(const Duration(seconds: 1), ((timer) { if (timer.tick >= duration.inSeconds) { + print(elapsedSeconds); timer.cancel(); started = false; } diff --git a/lib/providers/workout_provider.dart b/lib/providers/workout_provider.dart new file mode 100644 index 0000000..0505347 --- /dev/null +++ b/lib/providers/workout_provider.dart @@ -0,0 +1,33 @@ +import 'package:flutter/material.dart'; + +class WorkoutProvider extends ChangeNotifier { + final List _workoutPhases = [ + 'Warm-Up', + 'High Intensity', + 'Low Intensity', + 'High Intensity', + 'Low Intensity', + 'High Intensity', + 'Low Intensity', + 'High Intensity', + 'Cool-down' + ]; + final Map _phasesDuration = { + 'Warm-Up': const Duration(seconds: 5), + 'High Intensity': const Duration(seconds: 4), + 'Low Intensity': const Duration(seconds: 3), + 'Cool-down': const Duration(seconds: 5) + }; + int _workoutPhaseIndex = 0; + + String get currentPhase => _workoutPhases[_workoutPhaseIndex]; + Duration get currentPhaseDuration => + _phasesDuration[currentPhase] ?? const Duration(seconds: 0); + + void nextPhase() { + _workoutPhaseIndex < _workoutPhases.length + ? _workoutPhaseIndex += 1 + : _workoutPhaseIndex = 0; + //notifyListeners(); + } +} diff --git a/lib/widgets/workout_timer_widget.dart b/lib/widgets/workout_timer_widget.dart new file mode 100644 index 0000000..1ba501c --- /dev/null +++ b/lib/widgets/workout_timer_widget.dart @@ -0,0 +1,31 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:smoke_cess_app/providers/workout_provider.dart'; +import 'package:smoke_cess_app/widgets/timer_widget.dart'; + +import '../providers/timer_provider.dart'; + +class WorkoutTimerWidget extends StatelessWidget { + const WorkoutTimerWidget({super.key}); + + @override + Widget build(BuildContext context) { + TimerProvider timerProvider = context.watch(); + WorkoutProvider workoutProvider = context.watch(); + + if (timerProvider.elapsedSeconds == + workoutProvider.currentPhaseDuration.inSeconds) { + print('Timer abgelaufen'); + workoutProvider.nextPhase(); + timerProvider.startTimer(workoutProvider.currentPhaseDuration); + } + + return Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text(workoutProvider.currentPhase), + TimerWidget(duration: workoutProvider.currentPhaseDuration) + ], + ); + } +} From b01485f27ab07303512c4b8d5639d6c172032946 Mon Sep 17 00:00:00 2001 From: Crondung <1922635@stud.hs-mannheim.de> Date: Tue, 28 Feb 2023 13:05:51 +0100 Subject: [PATCH 02/12] playing music and iterating throug workout --- lib/pages/interval_page.dart | 6 ++++-- lib/providers/timer_provider.dart | 1 - lib/providers/workout_provider.dart | 26 ++++++++++++++++++++++---- lib/widgets/workout_timer_widget.dart | 6 +++--- 4 files changed, 29 insertions(+), 10 deletions(-) diff --git a/lib/pages/interval_page.dart b/lib/pages/interval_page.dart index 74ccffa..3537f03 100644 --- a/lib/pages/interval_page.dart +++ b/lib/pages/interval_page.dart @@ -170,10 +170,12 @@ class _IntervalTimerPageState extends State { @override Widget build(BuildContext context) { + TimerProvider timerProvider = TimerProvider(); return MultiProvider( providers: [ - ChangeNotifierProvider(create: (context) => TimerProvider()), - ChangeNotifierProvider(create: (context) => WorkoutProvider()) + ChangeNotifierProvider(create: (context) => timerProvider), + ChangeNotifierProvider( + create: (context) => WorkoutProvider(timerProvider)) ], child: WorkoutTimerWidget(), ); diff --git a/lib/providers/timer_provider.dart b/lib/providers/timer_provider.dart index f5a7689..8073309 100644 --- a/lib/providers/timer_provider.dart +++ b/lib/providers/timer_provider.dart @@ -11,7 +11,6 @@ class TimerProvider extends ChangeNotifier { started = true; _timer = Timer.periodic(const Duration(seconds: 1), ((timer) { if (timer.tick >= duration.inSeconds) { - print(elapsedSeconds); timer.cancel(); started = false; } diff --git a/lib/providers/workout_provider.dart b/lib/providers/workout_provider.dart index 0505347..6b38b12 100644 --- a/lib/providers/workout_provider.dart +++ b/lib/providers/workout_provider.dart @@ -1,6 +1,16 @@ +import 'dart:async'; + +import 'package:audioplayers/audioplayers.dart'; import 'package:flutter/material.dart'; +import 'package:smoke_cess_app/providers/timer_provider.dart'; class WorkoutProvider extends ChangeNotifier { + TimerProvider timerProvider; + + final AudioPlayer _audioPlayer = AudioPlayer(); + + WorkoutProvider(this.timerProvider); + final List _workoutPhases = [ 'Warm-Up', 'High Intensity', @@ -18,6 +28,12 @@ class WorkoutProvider extends ChangeNotifier { 'Low Intensity': const Duration(seconds: 3), 'Cool-down': const Duration(seconds: 5) }; + final Map _phaseSongSources = { + 'Warm-Up': AssetSource('warmUp.mp3'), + 'High Intensity': AssetSource('workout.mp3'), + 'Low Intensity': AssetSource('workout.mp3'), + 'Cool-down': AssetSource('cool_down.mp3') + }; int _workoutPhaseIndex = 0; String get currentPhase => _workoutPhases[_workoutPhaseIndex]; @@ -25,9 +41,11 @@ class WorkoutProvider extends ChangeNotifier { _phasesDuration[currentPhase] ?? const Duration(seconds: 0); void nextPhase() { - _workoutPhaseIndex < _workoutPhases.length - ? _workoutPhaseIndex += 1 - : _workoutPhaseIndex = 0; - //notifyListeners(); + _audioPlayer.stop(); + if (_workoutPhaseIndex < _workoutPhases.length - 1) { + _workoutPhaseIndex += 1; + _audioPlayer.play(_phaseSongSources[currentPhase]!); + timerProvider.startTimer(currentPhaseDuration); + } } } diff --git a/lib/widgets/workout_timer_widget.dart b/lib/widgets/workout_timer_widget.dart index 1ba501c..bc12bac 100644 --- a/lib/widgets/workout_timer_widget.dart +++ b/lib/widgets/workout_timer_widget.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:smoke_cess_app/providers/workout_provider.dart'; @@ -15,9 +17,7 @@ class WorkoutTimerWidget extends StatelessWidget { if (timerProvider.elapsedSeconds == workoutProvider.currentPhaseDuration.inSeconds) { - print('Timer abgelaufen'); - workoutProvider.nextPhase(); - timerProvider.startTimer(workoutProvider.currentPhaseDuration); + Timer(const Duration(milliseconds: 1), () => workoutProvider.nextPhase()); } return Column( From 4144bbaf6966765682019e1638d00717ac458561 Mon Sep 17 00:00:00 2001 From: Crondung <1922635@stud.hs-mannheim.de> Date: Tue, 28 Feb 2023 14:58:32 +0100 Subject: [PATCH 03/12] wip trying to wrap timerprovider in prokoutprovider --- lib/providers/workout_provider.dart | 23 +++++++++++++++++++---- lib/widgets/timer_widget.dart | 5 ----- lib/widgets/workout_timer_widget.dart | 8 +++++--- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/lib/providers/workout_provider.dart b/lib/providers/workout_provider.dart index 6b38b12..d2c07cf 100644 --- a/lib/providers/workout_provider.dart +++ b/lib/providers/workout_provider.dart @@ -1,5 +1,3 @@ -import 'dart:async'; - import 'package:audioplayers/audioplayers.dart'; import 'package:flutter/material.dart'; import 'package:smoke_cess_app/providers/timer_provider.dart'; @@ -8,6 +6,8 @@ class WorkoutProvider extends ChangeNotifier { TimerProvider timerProvider; final AudioPlayer _audioPlayer = AudioPlayer(); + final Source _finishedSoundSource = AssetSource('finish.mp3'); + final Source _beepSoundSource = AssetSource('beep.mp3'); WorkoutProvider(this.timerProvider); @@ -39,13 +39,28 @@ class WorkoutProvider extends ChangeNotifier { String get currentPhase => _workoutPhases[_workoutPhaseIndex]; Duration get currentPhaseDuration => _phasesDuration[currentPhase] ?? const Duration(seconds: 0); + bool get isPhaseComplete => + timerProvider.elapsedSeconds - currentPhaseDuration.inSeconds == 0; void nextPhase() { _audioPlayer.stop(); if (_workoutPhaseIndex < _workoutPhases.length - 1) { + _audioPlayer.play(_beepSoundSource); _workoutPhaseIndex += 1; - _audioPlayer.play(_phaseSongSources[currentPhase]!); - timerProvider.startTimer(currentPhaseDuration); + _audioPlayer.onPlayerComplete.listen((event) { + _audioPlayer.play(_phaseSongSources[currentPhase]!); + timerProvider.startTimer(currentPhaseDuration); + }); + } else { + _audioPlayer.play(_finishedSoundSource); } } + + void startWorkout() { + _audioPlayer.play(_beepSoundSource); + _audioPlayer.onPlayerComplete.listen((event) { + _audioPlayer.play(_phaseSongSources[currentPhase]!); + timerProvider.startTimer(currentPhaseDuration); + }); + } } diff --git a/lib/widgets/timer_widget.dart b/lib/widgets/timer_widget.dart index 875697f..4cf1d51 100644 --- a/lib/widgets/timer_widget.dart +++ b/lib/widgets/timer_widget.dart @@ -14,11 +14,6 @@ class TimerWidget extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.center, children: [ Text(formatTime(duration.inSeconds - timerProvider.elapsedSeconds)), - ElevatedButton( - onPressed: () => timerProvider.started - ? timerProvider.stopTimer() - : timerProvider.startTimer(duration), - child: Text(timerProvider.started ? 'Stop' : 'Start')) ], ); } diff --git a/lib/widgets/workout_timer_widget.dart b/lib/widgets/workout_timer_widget.dart index bc12bac..49baf08 100644 --- a/lib/widgets/workout_timer_widget.dart +++ b/lib/widgets/workout_timer_widget.dart @@ -15,8 +15,7 @@ class WorkoutTimerWidget extends StatelessWidget { TimerProvider timerProvider = context.watch(); WorkoutProvider workoutProvider = context.watch(); - if (timerProvider.elapsedSeconds == - workoutProvider.currentPhaseDuration.inSeconds) { + if (workoutProvider.isPhaseComplete) { Timer(const Duration(milliseconds: 1), () => workoutProvider.nextPhase()); } @@ -24,7 +23,10 @@ class WorkoutTimerWidget extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.center, children: [ Text(workoutProvider.currentPhase), - TimerWidget(duration: workoutProvider.currentPhaseDuration) + TimerWidget(duration: workoutProvider.currentPhaseDuration), + ElevatedButton( + onPressed: () => workoutProvider.startWorkout(), + child: Text(timerProvider.started ? 'Stop' : 'Start')) ], ); } From c1cf3cce30cdc94ceb604b02473e0a762b427f05 Mon Sep 17 00:00:00 2001 From: Crondung <1922635@stud.hs-mannheim.de> Date: Tue, 28 Feb 2023 15:07:47 +0100 Subject: [PATCH 04/12] handle stop --- lib/providers/timer_provider.dart | 5 ++++- lib/providers/workout_provider.dart | 10 ++++++++++ lib/widgets/workout_timer_widget.dart | 4 +++- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/lib/providers/timer_provider.dart b/lib/providers/timer_provider.dart index 8073309..ee34b19 100644 --- a/lib/providers/timer_provider.dart +++ b/lib/providers/timer_provider.dart @@ -18,5 +18,8 @@ class TimerProvider extends ChangeNotifier { })); } - void stopTimer() => _timer?.cancel(); + void stopTimer() { + started = false; + _timer?.cancel(); + } } diff --git a/lib/providers/workout_provider.dart b/lib/providers/workout_provider.dart index d2c07cf..2d31dc7 100644 --- a/lib/providers/workout_provider.dart +++ b/lib/providers/workout_provider.dart @@ -8,6 +8,7 @@ class WorkoutProvider extends ChangeNotifier { final AudioPlayer _audioPlayer = AudioPlayer(); final Source _finishedSoundSource = AssetSource('finish.mp3'); final Source _beepSoundSource = AssetSource('beep.mp3'); + bool isWorkoutStarted = false; WorkoutProvider(this.timerProvider); @@ -57,10 +58,19 @@ class WorkoutProvider extends ChangeNotifier { } void startWorkout() { + isWorkoutStarted = true; _audioPlayer.play(_beepSoundSource); _audioPlayer.onPlayerComplete.listen((event) { _audioPlayer.play(_phaseSongSources[currentPhase]!); timerProvider.startTimer(currentPhaseDuration); }); } + + void stopWorkout() { + isWorkoutStarted = false; + _workoutPhaseIndex = 0; + _audioPlayer.stop(); + timerProvider.stopTimer(); + notifyListeners(); + } } diff --git a/lib/widgets/workout_timer_widget.dart b/lib/widgets/workout_timer_widget.dart index 49baf08..131229c 100644 --- a/lib/widgets/workout_timer_widget.dart +++ b/lib/widgets/workout_timer_widget.dart @@ -25,7 +25,9 @@ class WorkoutTimerWidget extends StatelessWidget { Text(workoutProvider.currentPhase), TimerWidget(duration: workoutProvider.currentPhaseDuration), ElevatedButton( - onPressed: () => workoutProvider.startWorkout(), + onPressed: !workoutProvider.isWorkoutStarted + ? () => workoutProvider.startWorkout() + : () => workoutProvider.stopWorkout(), child: Text(timerProvider.started ? 'Stop' : 'Start')) ], ); From 9eff2ad177079caf5320fef3bc13fc3d0e15e177 Mon Sep 17 00:00:00 2001 From: Crondung <1922635@stud.hs-mannheim.de> Date: Wed, 1 Mar 2023 12:34:35 +0100 Subject: [PATCH 05/12] add circular progress indicator --- lib/pages/interval_page.dart | 228 ++------------------------ lib/providers/workout_provider.dart | 13 ++ lib/widgets/mute_button.dart | 21 +++ lib/widgets/workout_timer_widget.dart | 3 + 4 files changed, 50 insertions(+), 215 deletions(-) create mode 100644 lib/widgets/mute_button.dart diff --git a/lib/pages/interval_page.dart b/lib/pages/interval_page.dart index 3537f03..5a78b48 100644 --- a/lib/pages/interval_page.dart +++ b/lib/pages/interval_page.dart @@ -4,169 +4,11 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:smoke_cess_app/providers/timer_provider.dart'; import 'package:smoke_cess_app/providers/workout_provider.dart'; -import 'package:smoke_cess_app/widgets/popup_for_start_and_stop.dart'; -import 'package:smoke_cess_app/widgets/timer_widget.dart'; +import 'package:smoke_cess_app/widgets/mute_button.dart'; import 'package:smoke_cess_app/widgets/workout_timer_widget.dart'; -import '../providers/input_provider.dart'; - -class IntervalTimerPage extends StatefulWidget { - const IntervalTimerPage({Key? key}) : super(key: key); - - @override - _IntervalTimerPageState createState() => _IntervalTimerPageState(); -} - -class _IntervalTimerPageState extends State { - final Duration _warmupDuration = const Duration(seconds: 5); - final Duration _cooldownDuration = const Duration(seconds: 5); - final Duration _highIntensityDuration = const Duration(seconds: 4); - final Duration _lowIntensityDuration = const Duration(seconds: 3); - late Duration _totalDuration = const Duration(minutes: 35); - AudioPlayer warmUpPlayer = AudioPlayer(); - AudioPlayer workoutPlayer = AudioPlayer(); - AudioPlayer coolDownPlayer = AudioPlayer(); - final AudioCache _audioCache = AudioCache(); - final int _numHighIntensityBlocks = 4; - final int _numLowIntensityBlocks = 3; - - Timer? _timer; - int _currentBlock = 0; - Duration _currentDuration = const Duration(); - bool _isPaused = true; - - @override - void initState() { - _currentDuration = _warmupDuration; - super.initState(); - } - - @override - void dispose() { - _timer?.cancel(); - super.dispose(); - } - - void _startTimer() async { - await showDialog( - context: context, - builder: (BuildContext context) { - return ChangeNotifierProvider( - create: (context) => InputProvider(), - child: const TimerStartStopPopup( - title: 'Motivation vor dem Training', - )); - }, - ); - _isPaused = false; - Source source = AssetSource('go.mp3'); - await AudioPlayer().play(source); - - _timer = Timer.periodic(const Duration(seconds: 1), (_) => _tick()); - Future.delayed(const Duration(seconds: 1)).then((value) { - _playWarmUpMusic(); - }); - } - - void _resetTimer() { - () async { - await coolDownPlayer.stop(); - await warmUpPlayer.stop(); - await workoutPlayer.stop(); - }(); - _isPaused = true; - _timer?.cancel(); - _currentBlock = 0; - _currentDuration = _warmupDuration; - _totalDuration = const Duration(minutes: 35); - setState(() {}); - showDialog( - context: context, - builder: (BuildContext context) { - return const TimerStartStopPopup( - title: 'Motivation nach dem Training', - ); - }, - ); - } - - Future _playWarmUpMusic() async { - Source source = AssetSource('warmUp.mp3'); - await warmUpPlayer.setReleaseMode(ReleaseMode.loop); - await warmUpPlayer.play(source); - } - - Future _playWorkoutMusic() async { - await warmUpPlayer.stop(); - Future.delayed(const Duration(microseconds: 600)).then((value) async { - Source source = AssetSource('workout.mp3'); - await workoutPlayer.setReleaseMode(ReleaseMode.loop); - await workoutPlayer.play(source); - }); - } - - Future _intervalChange() async { - Source source = AssetSource('beep.mp3'); - await AudioPlayer().play(source); - } - - void _tick() { - setState(() { - _currentDuration = Duration( - seconds: _currentDuration.inSeconds - 1, - ); - _totalDuration = Duration( - seconds: _totalDuration.inSeconds - 1, - ); - if (_currentDuration.inSeconds < 1) { - if (_currentBlock < _numHighIntensityBlocks + _numLowIntensityBlocks) { - _intervalChange(); - if (_currentBlock == 0) { - _playWorkoutMusic(); - } - _currentBlock++; - - if (_currentBlock % 2 == 1) { - _currentDuration = _highIntensityDuration; - } else { - _currentDuration = _lowIntensityDuration; - } - } else if (_currentBlock < _numHighIntensityBlocks * 2) { - _intervalChange(); - _currentBlock++; - _currentDuration = _cooldownDuration; - () async { - await workoutPlayer.stop(); - Source source = AssetSource('cool_down.mp3'); - await coolDownPlayer.setReleaseMode(ReleaseMode.loop); - await coolDownPlayer.play(source); - }(); - } else { - () async { - Future.delayed(const Duration(microseconds: 900)) - .then((value) async { - Source source = AssetSource('finish.mp3'); - await AudioPlayer().play(source); - }); - }(); - _resetTimer(); - } - } - }); - } - - String _formatDuration(Duration duration) { - String twoDigits(int n) => n.toString().padLeft(2, '0'); - final minutes = twoDigits(duration.inMinutes.remainder(60)); - final seconds = twoDigits(duration.inSeconds.remainder(60)); - return '$minutes:$seconds'; - } - - String _formatTotalDuration(Duration duration) { - final minutes = duration.inMinutes; - final seconds = duration.inSeconds.remainder(60); - return _formatDuration(Duration(minutes: minutes, seconds: seconds)); - } +class IntervalTimerPage extends StatelessWidget { + const IntervalTimerPage({super.key}); @override Widget build(BuildContext context) { @@ -177,60 +19,16 @@ class _IntervalTimerPageState extends State { ChangeNotifierProvider( create: (context) => WorkoutProvider(timerProvider)) ], - child: WorkoutTimerWidget(), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: const [ + Align( + alignment: Alignment.topLeft, + child: MuteButton(), + ), + WorkoutTimerWidget() + ], + ), ); - ChangeNotifierProvider( - create: (context) => TimerProvider(), - child: TimerWidget( - duration: Duration(seconds: 5), - )); - return Center( - child: ChangeNotifierProvider( - create: (context) => InputProvider(), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - _currentBlock == 0 - ? 'Warm-up' - : _currentBlock % 2 == 1 - ? 'High Intensity' - : _currentBlock < _numHighIntensityBlocks * 2 - ? 'Low Intensity' - : 'Cool-down', - style: const TextStyle(fontSize: 32.0), - ), - const SizedBox(height: 16.0), - Text( - _formatDuration(_currentDuration), - style: const TextStyle(fontSize: 80.0), - ), - const SizedBox(height: 32.0), - Text( - 'Total: ${_formatTotalDuration(_totalDuration)}', - style: const TextStyle(fontSize: 24.0), - ), - const SizedBox(height: 32.0), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - IconButton( - icon: Icon(_isPaused - ? Icons.play_arrow_rounded - : Icons.stop_rounded), - iconSize: 48.0, - onPressed: () { - if (_isPaused) { - _startTimer(); - } else { - _resetTimer(); - } - }, - ), - // ), - ], - ), - ], - ))); } } diff --git a/lib/providers/workout_provider.dart b/lib/providers/workout_provider.dart index 2d31dc7..f9fc206 100644 --- a/lib/providers/workout_provider.dart +++ b/lib/providers/workout_provider.dart @@ -9,6 +9,19 @@ class WorkoutProvider extends ChangeNotifier { final Source _finishedSoundSource = AssetSource('finish.mp3'); final Source _beepSoundSource = AssetSource('beep.mp3'); bool isWorkoutStarted = false; + bool isMuted = false; + + void mutePlayer() { + isMuted = true; + _audioPlayer.setVolume(0); + notifyListeners(); + } + + void unMutePlayer() { + isMuted = false; + _audioPlayer.setVolume(1); + notifyListeners(); + } WorkoutProvider(this.timerProvider); diff --git a/lib/widgets/mute_button.dart b/lib/widgets/mute_button.dart new file mode 100644 index 0000000..863bb52 --- /dev/null +++ b/lib/widgets/mute_button.dart @@ -0,0 +1,21 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:smoke_cess_app/providers/workout_provider.dart'; + +class MuteButton extends StatelessWidget { + const MuteButton({super.key}); + + @override + Widget build(BuildContext context) { + WorkoutProvider workoutProvider = context.watch(); + + return IconButton( + onPressed: workoutProvider.isMuted + ? workoutProvider.unMutePlayer + : workoutProvider.mutePlayer, + icon: Icon(workoutProvider.isMuted + ? Icons.volume_off_outlined + : Icons.volume_up_outlined), + ); + } +} diff --git a/lib/widgets/workout_timer_widget.dart b/lib/widgets/workout_timer_widget.dart index 131229c..3eb1368 100644 --- a/lib/widgets/workout_timer_widget.dart +++ b/lib/widgets/workout_timer_widget.dart @@ -23,6 +23,9 @@ class WorkoutTimerWidget extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.center, children: [ Text(workoutProvider.currentPhase), + CircularProgressIndicator( + value: timerProvider.elapsedSeconds / + workoutProvider.currentPhaseDuration.inSeconds), TimerWidget(duration: workoutProvider.currentPhaseDuration), ElevatedButton( onPressed: !workoutProvider.isWorkoutStarted From da7c820dbd0f744222207d5c191b06e8ffce2e9e Mon Sep 17 00:00:00 2001 From: Crondung <1922635@stud.hs-mannheim.de> Date: Wed, 1 Mar 2023 12:57:02 +0100 Subject: [PATCH 06/12] better positioning, fixed endless workout --- lib/providers/workout_provider.dart | 1 + lib/widgets/workout_timer_widget.dart | 24 ++++++++++++++++++++---- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/lib/providers/workout_provider.dart b/lib/providers/workout_provider.dart index f9fc206..73b32f8 100644 --- a/lib/providers/workout_provider.dart +++ b/lib/providers/workout_provider.dart @@ -67,6 +67,7 @@ class WorkoutProvider extends ChangeNotifier { }); } else { _audioPlayer.play(_finishedSoundSource); + stopWorkout(); } } diff --git a/lib/widgets/workout_timer_widget.dart b/lib/widgets/workout_timer_widget.dart index 3eb1368..d789c15 100644 --- a/lib/widgets/workout_timer_widget.dart +++ b/lib/widgets/workout_timer_widget.dart @@ -23,10 +23,26 @@ class WorkoutTimerWidget extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.center, children: [ Text(workoutProvider.currentPhase), - CircularProgressIndicator( - value: timerProvider.elapsedSeconds / - workoutProvider.currentPhaseDuration.inSeconds), - TimerWidget(duration: workoutProvider.currentPhaseDuration), + const SizedBox( + height: 20, + ), + Stack( + alignment: Alignment.center, + children: [ + SizedBox( + height: 100, + width: 100, + child: CircularProgressIndicator( + value: (workoutProvider.currentPhaseDuration.inSeconds + .toDouble() - + timerProvider.elapsedSeconds) / + workoutProvider.currentPhaseDuration.inSeconds)), + TimerWidget(duration: workoutProvider.currentPhaseDuration), + ], + ), + const SizedBox( + height: 20, + ), ElevatedButton( onPressed: !workoutProvider.isWorkoutStarted ? () => workoutProvider.startWorkout() From 556daa9e90af9e1676aa3ab4140559012cbe7a17 Mon Sep 17 00:00:00 2001 From: Crondung <1922635@stud.hs-mannheim.de> Date: Wed, 1 Mar 2023 13:07:01 +0100 Subject: [PATCH 07/12] show phase colors in circularprogressindi --- lib/providers/workout_provider.dart | 8 ++++++++ lib/widgets/workout_timer_widget.dart | 1 + 2 files changed, 9 insertions(+) diff --git a/lib/providers/workout_provider.dart b/lib/providers/workout_provider.dart index 73b32f8..4c89b84 100644 --- a/lib/providers/workout_provider.dart +++ b/lib/providers/workout_provider.dart @@ -25,6 +25,7 @@ class WorkoutProvider extends ChangeNotifier { WorkoutProvider(this.timerProvider); + //TODO: outsource all Maps to JSON File! final List _workoutPhases = [ 'Warm-Up', 'High Intensity', @@ -48,6 +49,12 @@ class WorkoutProvider extends ChangeNotifier { 'Low Intensity': AssetSource('workout.mp3'), 'Cool-down': AssetSource('cool_down.mp3') }; + final Map _phaseColors = { + 'Warm-Up': Colors.green, + 'High Intensity': Colors.red, + 'Low Intensity': Colors.orange, + 'Cool-down': Colors.blue + }; int _workoutPhaseIndex = 0; String get currentPhase => _workoutPhases[_workoutPhaseIndex]; @@ -55,6 +62,7 @@ class WorkoutProvider extends ChangeNotifier { _phasesDuration[currentPhase] ?? const Duration(seconds: 0); bool get isPhaseComplete => timerProvider.elapsedSeconds - currentPhaseDuration.inSeconds == 0; + Color get currentPhaseColor => _phaseColors[currentPhase] ?? Colors.blue; void nextPhase() { _audioPlayer.stop(); diff --git a/lib/widgets/workout_timer_widget.dart b/lib/widgets/workout_timer_widget.dart index d789c15..df9fae4 100644 --- a/lib/widgets/workout_timer_widget.dart +++ b/lib/widgets/workout_timer_widget.dart @@ -33,6 +33,7 @@ class WorkoutTimerWidget extends StatelessWidget { height: 100, width: 100, child: CircularProgressIndicator( + color: workoutProvider.currentPhaseColor, value: (workoutProvider.currentPhaseDuration.inSeconds .toDouble() - timerProvider.elapsedSeconds) / From cd88b483cf0235449448aa1f8339a71879ce37a9 Mon Sep 17 00:00:00 2001 From: Crondung <1922635@stud.hs-mannheim.de> Date: Wed, 1 Mar 2023 13:30:12 +0100 Subject: [PATCH 08/12] return slider value after popup --- lib/pages/interval_page.dart | 5 ++--- lib/widgets/popup_for_start_and_stop.dart | 18 +++++++++++++----- lib/widgets/workout_timer_widget.dart | 20 +++++++++++++++++++- 3 files changed, 34 insertions(+), 9 deletions(-) diff --git a/lib/pages/interval_page.dart b/lib/pages/interval_page.dart index 5a78b48..bf26c40 100644 --- a/lib/pages/interval_page.dart +++ b/lib/pages/interval_page.dart @@ -1,7 +1,6 @@ -import 'dart:async'; -import 'package:audioplayers/audioplayers.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; +import 'package:smoke_cess_app/providers/input_provider.dart'; import 'package:smoke_cess_app/providers/timer_provider.dart'; import 'package:smoke_cess_app/providers/workout_provider.dart'; import 'package:smoke_cess_app/widgets/mute_button.dart'; @@ -17,7 +16,7 @@ class IntervalTimerPage extends StatelessWidget { providers: [ ChangeNotifierProvider(create: (context) => timerProvider), ChangeNotifierProvider( - create: (context) => WorkoutProvider(timerProvider)) + create: (context) => WorkoutProvider(timerProvider)), ], child: Column( mainAxisAlignment: MainAxisAlignment.center, diff --git a/lib/widgets/popup_for_start_and_stop.dart b/lib/widgets/popup_for_start_and_stop.dart index e1af268..d79a83f 100644 --- a/lib/widgets/popup_for_start_and_stop.dart +++ b/lib/widgets/popup_for_start_and_stop.dart @@ -1,4 +1,6 @@ import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:smoke_cess_app/providers/input_provider.dart'; import 'package:smoke_cess_app/widgets/slider.dart'; import 'package:smoke_cess_app/widgets/text_formfield.dart'; @@ -9,18 +11,24 @@ class TimerStartStopPopup extends StatelessWidget { @override Widget build(BuildContext context) { + InputProvider inputProvider = context.watch(); + return AlertDialog( title: Text(title), content: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, - children: const [ - Padding( - padding: const EdgeInsets.only(top: 8), + children: [ + const Padding( + padding: EdgeInsets.only(top: 8), child: MySlider(), ), - SizedBox(height: 16), - MyTextFormField('Beschreibe deinen Motivation'), + const SizedBox(height: 16), + const MyTextFormField('Beschreibe deinen Motivation'), + ElevatedButton( + onPressed: () => + Navigator.pop(context, inputProvider.sliderValue), + child: const Text('Speichern')) ], ), ); diff --git a/lib/widgets/workout_timer_widget.dart b/lib/widgets/workout_timer_widget.dart index df9fae4..5a14911 100644 --- a/lib/widgets/workout_timer_widget.dart +++ b/lib/widgets/workout_timer_widget.dart @@ -5,11 +5,15 @@ import 'package:provider/provider.dart'; import 'package:smoke_cess_app/providers/workout_provider.dart'; import 'package:smoke_cess_app/widgets/timer_widget.dart'; +import '../providers/input_provider.dart'; import '../providers/timer_provider.dart'; +import 'popup_for_start_and_stop.dart'; class WorkoutTimerWidget extends StatelessWidget { const WorkoutTimerWidget({super.key}); + void _onStartButtonPressed(BuildContext context) {} + @override Widget build(BuildContext context) { TimerProvider timerProvider = context.watch(); @@ -46,7 +50,21 @@ class WorkoutTimerWidget extends StatelessWidget { ), ElevatedButton( onPressed: !workoutProvider.isWorkoutStarted - ? () => workoutProvider.startWorkout() + ? () async { + double sliderValue = await showDialog( + context: context, + builder: (BuildContext context) { + return ChangeNotifierProvider( + create: (context) => InputProvider(), + child: const TimerStartStopPopup( + title: 'Motivation vor dem Training', + ), + ); + }, + ); + print(sliderValue); + workoutProvider.startWorkout(); + } : () => workoutProvider.stopWorkout(), child: Text(timerProvider.started ? 'Stop' : 'Start')) ], From 5587f049e1c101b834d5a723e88d4a43199a2267 Mon Sep 17 00:00:00 2001 From: Crondung <1922635@stud.hs-mannheim.de> Date: Thu, 2 Mar 2023 13:19:08 +0100 Subject: [PATCH 09/12] wip finishing workout and saving model --- lib/mock/db_mock.dart | 8 ++- lib/models/hiit_workout.dart | 32 ---------- lib/models/workout.dart | 28 +++++++++ lib/providers/workout_provider.dart | 71 ++++++++++++++--------- lib/services/database_service.dart | 9 ++- lib/widgets/popup_for_start_and_stop.dart | 30 ++++++++-- lib/widgets/workout_timer_widget.dart | 43 +++++++------- 7 files changed, 132 insertions(+), 89 deletions(-) delete mode 100644 lib/models/hiit_workout.dart create mode 100644 lib/models/workout.dart diff --git a/lib/mock/db_mock.dart b/lib/mock/db_mock.dart index a06f003..6daa0c4 100644 --- a/lib/mock/db_mock.dart +++ b/lib/mock/db_mock.dart @@ -1,6 +1,7 @@ import 'package:smoke_cess_app/interface/db_record.dart'; import 'package:smoke_cess_app/models/mood.dart'; import 'package:smoke_cess_app/models/sleep.dart'; +import 'package:smoke_cess_app/models/workout.dart'; import 'package:smoke_cess_app/services/database_service.dart'; import 'package:sqflite_common/sqlite_api.dart'; @@ -28,7 +29,12 @@ class DatabaseMock implements DatabaseService { } @override - // TODO: implement database + Future addWorkout(Workout workout) { + _workoutRecords.add(workout); + return Future.value(1); + } + + @override Future get database => DatabaseService.instance.database; @override diff --git a/lib/models/hiit_workout.dart b/lib/models/hiit_workout.dart deleted file mode 100644 index c4ec0da..0000000 --- a/lib/models/hiit_workout.dart +++ /dev/null @@ -1,32 +0,0 @@ -import 'package:smoke_cess_app/interface/db_record.dart'; - -class HIITWorkout implements DatabaseRecord { - Duration _workoutDuration; - String _commentBefore; - String _commentAfter; - DateTime _workoutDate; - - HIITWorkout(this._workoutDuration, this._commentBefore, this._commentAfter, - this._workoutDate); - - //TODO Felder anpassen - @override - factory HIITWorkout.fromMap(Map map) { - return HIITWorkout(map['_workoutDuration'], map['_commentBefore'], - map['_commentAfter'], map['_workoutDate']); - } - - @override - String toCSV() => - "${_workoutDate.toIso8601String()}, $_workoutDuration, $_commentBefore, $_commentAfter"; - - @override - Map toMap() { - return { - 'workoutDuration': _workoutDuration, - 'commentBefore': _commentBefore, - 'commentAfter': _commentAfter, - 'workoutDate': _workoutDate, - }; - } -} diff --git a/lib/models/workout.dart b/lib/models/workout.dart new file mode 100644 index 0000000..0bba86a --- /dev/null +++ b/lib/models/workout.dart @@ -0,0 +1,28 @@ +import 'package:smoke_cess_app/interface/db_record.dart'; + +class Workout implements DatabaseRecord { + int _motivationBefore; + int _motivationAfter; + DateTime _workoutDate; + + Workout(this._motivationBefore, this._motivationAfter, this._workoutDate); + + @override + factory Workout.fromMap(Map map) { + return Workout(map['_workoutDuration'], map['_motivationBefore'], + map['_motivationAfter']); + } + + @override + String toCSV() => + "${_workoutDate.toIso8601String()}, $_motivationBefore, $_motivationAfter"; + + @override + Map toMap() { + return { + 'motivationBefore': _motivationBefore, + 'motivationAfter': _motivationAfter, + 'workoutDate': _workoutDate, + }; + } +} diff --git a/lib/providers/workout_provider.dart b/lib/providers/workout_provider.dart index 4c89b84..c15c04c 100644 --- a/lib/providers/workout_provider.dart +++ b/lib/providers/workout_provider.dart @@ -1,6 +1,8 @@ import 'package:audioplayers/audioplayers.dart'; import 'package:flutter/material.dart'; +import 'package:smoke_cess_app/models/workout.dart'; import 'package:smoke_cess_app/providers/timer_provider.dart'; +import '../globals.dart' as globals; class WorkoutProvider extends ChangeNotifier { TimerProvider timerProvider; @@ -10,6 +12,8 @@ class WorkoutProvider extends ChangeNotifier { final Source _beepSoundSource = AssetSource('beep.mp3'); bool isWorkoutStarted = false; bool isMuted = false; + int motivationBefore = 50; + int motivationAfter = 50; void mutePlayer() { isMuted = true; @@ -25,44 +29,29 @@ class WorkoutProvider extends ChangeNotifier { WorkoutProvider(this.timerProvider); - //TODO: outsource all Maps to JSON File! final List _workoutPhases = [ 'Warm-Up', - 'High Intensity', + /*'High Intensity', 'Low Intensity', 'High Intensity', 'Low Intensity', 'High Intensity', 'Low Intensity', - 'High Intensity', + 'High Intensity', */ 'Cool-down' ]; - final Map _phasesDuration = { - 'Warm-Up': const Duration(seconds: 5), - 'High Intensity': const Duration(seconds: 4), - 'Low Intensity': const Duration(seconds: 3), - 'Cool-down': const Duration(seconds: 5) - }; - final Map _phaseSongSources = { - 'Warm-Up': AssetSource('warmUp.mp3'), - 'High Intensity': AssetSource('workout.mp3'), - 'Low Intensity': AssetSource('workout.mp3'), - 'Cool-down': AssetSource('cool_down.mp3') - }; - final Map _phaseColors = { - 'Warm-Up': Colors.green, - 'High Intensity': Colors.red, - 'Low Intensity': Colors.orange, - 'Cool-down': Colors.blue - }; int _workoutPhaseIndex = 0; String get currentPhase => _workoutPhases[_workoutPhaseIndex]; Duration get currentPhaseDuration => - _phasesDuration[currentPhase] ?? const Duration(seconds: 0); + _workoutPhaseSettings[currentPhase]!['duration']; bool get isPhaseComplete => timerProvider.elapsedSeconds - currentPhaseDuration.inSeconds == 0; - Color get currentPhaseColor => _phaseColors[currentPhase] ?? Colors.blue; + Color get currentPhaseColor => _workoutPhaseSettings[currentPhase]!['color']; + AssetSource get currentPhaseSource => + _workoutPhaseSettings[currentPhase]!['source']; + bool get isWorkoutComplete => + _workoutPhaseIndex == _workoutPhases.length - 1 && isPhaseComplete; void nextPhase() { _audioPlayer.stop(); @@ -70,10 +59,11 @@ class WorkoutProvider extends ChangeNotifier { _audioPlayer.play(_beepSoundSource); _workoutPhaseIndex += 1; _audioPlayer.onPlayerComplete.listen((event) { - _audioPlayer.play(_phaseSongSources[currentPhase]!); + _audioPlayer.play(currentPhaseSource); timerProvider.startTimer(currentPhaseDuration); }); } else { + //workout completed _audioPlayer.play(_finishedSoundSource); stopWorkout(); } @@ -83,16 +73,45 @@ class WorkoutProvider extends ChangeNotifier { isWorkoutStarted = true; _audioPlayer.play(_beepSoundSource); _audioPlayer.onPlayerComplete.listen((event) { - _audioPlayer.play(_phaseSongSources[currentPhase]!); + _audioPlayer.play(currentPhaseSource); timerProvider.startTimer(currentPhaseDuration); }); } void stopWorkout() { isWorkoutStarted = false; - _workoutPhaseIndex = 0; + //_workoutPhaseIndex = 0; _audioPlayer.stop(); timerProvider.stopTimer(); notifyListeners(); } + + void saveWorkout() { + Workout workout = + Workout(motivationBefore, motivationAfter, DateTime.now()); + globals.databaseService.addWorkout(workout); + } } + +Map> _workoutPhaseSettings = { + 'Warm-Up': { + 'duration': const Duration(seconds: 5), + 'source': AssetSource('warmUp.mp3'), + 'color': Colors.green + }, + 'High Intensity': { + 'duration': const Duration(seconds: 4), + 'source': AssetSource('workout.mp3'), + 'color': Colors.red + }, + 'Low Intensity': { + 'duration': const Duration(seconds: 3), + 'source': AssetSource('workout.mp3'), + 'color': Colors.orange + }, + 'Cool-down': { + 'duration': const Duration(seconds: 5), + 'source': AssetSource('cool_down.mp3'), + 'color': Colors.blue + } +}; diff --git a/lib/services/database_service.dart b/lib/services/database_service.dart index 8dc8788..3dcc943 100644 --- a/lib/services/database_service.dart +++ b/lib/services/database_service.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:path/path.dart'; import 'package:smoke_cess_app/models/mood.dart'; +import 'package:smoke_cess_app/models/workout.dart'; import 'package:sqflite/sqflite.dart'; // ignore: depend_on_referenced_packages import 'package:path_provider/path_provider.dart'; @@ -62,6 +63,11 @@ class DatabaseService { Database db = await instance.database; return await db.insert('sleep', sleep.toMap()); } + + Future addWorkout(Workout workout) async { + Database db = await instance.database; + return await db.insert('workout', workout.toMap()); + } } String _createMoodTable = ''' @@ -100,9 +106,6 @@ String _createWorkoutTable = ''' id INTEGER PRIMARY KEY, date TEXT, motivationBefore INTEGER, - commentBefore TEXT, motivationAfter INTEGER, - commentAfter TEXT, - completed INTEGER ) '''; diff --git a/lib/widgets/popup_for_start_and_stop.dart b/lib/widgets/popup_for_start_and_stop.dart index d79a83f..4883737 100644 --- a/lib/widgets/popup_for_start_and_stop.dart +++ b/lib/widgets/popup_for_start_and_stop.dart @@ -2,12 +2,29 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:smoke_cess_app/providers/input_provider.dart'; import 'package:smoke_cess_app/widgets/slider.dart'; -import 'package:smoke_cess_app/widgets/text_formfield.dart'; + +Future showMotivationPopup( + BuildContext context, Function onSave, String title) async { + return await showDialog( + context: context, + builder: (BuildContext context) { + return ChangeNotifierProvider( + create: (context) => InputProvider(), + child: TimerStartStopPopup( + title: title, + onSaveAction: onSave, + ), + ); + }, + ); +} class TimerStartStopPopup extends StatelessWidget { final String title; - - const TimerStartStopPopup({Key? key, required this.title}) : super(key: key); + final Function onSaveAction; + const TimerStartStopPopup( + {Key? key, required this.title, required this.onSaveAction}) + : super(key: key); @override Widget build(BuildContext context) { @@ -24,10 +41,11 @@ class TimerStartStopPopup extends StatelessWidget { child: MySlider(), ), const SizedBox(height: 16), - const MyTextFormField('Beschreibe deinen Motivation'), ElevatedButton( - onPressed: () => - Navigator.pop(context, inputProvider.sliderValue), + onPressed: () { + onSaveAction(inputProvider.sliderValue); + Navigator.pop(context); + }, child: const Text('Speichern')) ], ), diff --git a/lib/widgets/workout_timer_widget.dart b/lib/widgets/workout_timer_widget.dart index 5a14911..2e39175 100644 --- a/lib/widgets/workout_timer_widget.dart +++ b/lib/widgets/workout_timer_widget.dart @@ -5,24 +5,41 @@ import 'package:provider/provider.dart'; import 'package:smoke_cess_app/providers/workout_provider.dart'; import 'package:smoke_cess_app/widgets/timer_widget.dart'; -import '../providers/input_provider.dart'; import '../providers/timer_provider.dart'; import 'popup_for_start_and_stop.dart'; class WorkoutTimerWidget extends StatelessWidget { const WorkoutTimerWidget({super.key}); - void _onStartButtonPressed(BuildContext context) {} - @override Widget build(BuildContext context) { TimerProvider timerProvider = context.watch(); WorkoutProvider workoutProvider = context.watch(); - if (workoutProvider.isPhaseComplete) { + if (workoutProvider.isPhaseComplete && workoutProvider.isWorkoutStarted) { Timer(const Duration(milliseconds: 1), () => workoutProvider.nextPhase()); } + void handleStartStopWorkout() async { + if (!workoutProvider.isWorkoutStarted) { + await showMotivationPopup( + context, + (double value) => workoutProvider.motivationBefore = value.toInt(), + 'Motivation vor dem Training'); + workoutProvider.startWorkout(); + } else { + workoutProvider.stopWorkout(); + await showMotivationPopup( + context, + (double value) => workoutProvider.motivationAfter = value.toInt(), + 'Motivation nach dem Training'); + } + } + + if (workoutProvider.isWorkoutComplete) { + handleStartStopWorkout(); + } + return Column( mainAxisAlignment: MainAxisAlignment.center, children: [ @@ -49,23 +66,7 @@ class WorkoutTimerWidget extends StatelessWidget { height: 20, ), ElevatedButton( - onPressed: !workoutProvider.isWorkoutStarted - ? () async { - double sliderValue = await showDialog( - context: context, - builder: (BuildContext context) { - return ChangeNotifierProvider( - create: (context) => InputProvider(), - child: const TimerStartStopPopup( - title: 'Motivation vor dem Training', - ), - ); - }, - ); - print(sliderValue); - workoutProvider.startWorkout(); - } - : () => workoutProvider.stopWorkout(), + onPressed: handleStartStopWorkout, child: Text(timerProvider.started ? 'Stop' : 'Start')) ], ); From fa8d2f63145da701275044a7992b0c4c23d1b1e0 Mon Sep 17 00:00:00 2001 From: Crondung <1922635@stud.hs-mannheim.de> Date: Thu, 2 Mar 2023 15:08:39 +0100 Subject: [PATCH 10/12] fix onlisten stream error --- lib/providers/workout_provider.dart | 24 +++++++++++++++--------- lib/widgets/workout_timer_widget.dart | 6 +----- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/lib/providers/workout_provider.dart b/lib/providers/workout_provider.dart index c15c04c..add88de 100644 --- a/lib/providers/workout_provider.dart +++ b/lib/providers/workout_provider.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:audioplayers/audioplayers.dart'; import 'package:flutter/material.dart'; import 'package:smoke_cess_app/models/workout.dart'; @@ -8,9 +10,11 @@ class WorkoutProvider extends ChangeNotifier { TimerProvider timerProvider; final AudioPlayer _audioPlayer = AudioPlayer(); + late StreamSubscription _onCompleteSubscription; final Source _finishedSoundSource = AssetSource('finish.mp3'); final Source _beepSoundSource = AssetSource('beep.mp3'); bool isWorkoutStarted = false; + bool isWorkoutComplete = false; bool isMuted = false; int motivationBefore = 50; int motivationAfter = 50; @@ -50,18 +54,19 @@ class WorkoutProvider extends ChangeNotifier { Color get currentPhaseColor => _workoutPhaseSettings[currentPhase]!['color']; AssetSource get currentPhaseSource => _workoutPhaseSettings[currentPhase]!['source']; - bool get isWorkoutComplete => - _workoutPhaseIndex == _workoutPhases.length - 1 && isPhaseComplete; + /* bool get isWorkoutComplete => + _workoutPhaseIndex == _workoutPhases.length - 1 && isPhaseComplete; */ void nextPhase() { + _onCompleteSubscription.cancel(); _audioPlayer.stop(); if (_workoutPhaseIndex < _workoutPhases.length - 1) { _audioPlayer.play(_beepSoundSource); _workoutPhaseIndex += 1; - _audioPlayer.onPlayerComplete.listen((event) { + _onCompleteSubscription = _audioPlayer.onPlayerComplete.listen((event) { _audioPlayer.play(currentPhaseSource); - timerProvider.startTimer(currentPhaseDuration); }); + timerProvider.startTimer(currentPhaseDuration); } else { //workout completed _audioPlayer.play(_finishedSoundSource); @@ -71,19 +76,20 @@ class WorkoutProvider extends ChangeNotifier { void startWorkout() { isWorkoutStarted = true; - _audioPlayer.play(_beepSoundSource); - _audioPlayer.onPlayerComplete.listen((event) { + isWorkoutComplete = false; + _audioPlayer.play(_beepSoundSource).whenComplete(() => null); + _onCompleteSubscription = _audioPlayer.onPlayerComplete.listen((event) { _audioPlayer.play(currentPhaseSource); - timerProvider.startTimer(currentPhaseDuration); }); + timerProvider.startTimer(currentPhaseDuration); } void stopWorkout() { isWorkoutStarted = false; - //_workoutPhaseIndex = 0; + isWorkoutComplete = true; _audioPlayer.stop(); timerProvider.stopTimer(); - notifyListeners(); + //notifyListeners(); } void saveWorkout() { diff --git a/lib/widgets/workout_timer_widget.dart b/lib/widgets/workout_timer_widget.dart index 2e39175..8023770 100644 --- a/lib/widgets/workout_timer_widget.dart +++ b/lib/widgets/workout_timer_widget.dart @@ -16,7 +16,7 @@ class WorkoutTimerWidget extends StatelessWidget { TimerProvider timerProvider = context.watch(); WorkoutProvider workoutProvider = context.watch(); - if (workoutProvider.isPhaseComplete && workoutProvider.isWorkoutStarted) { + if (workoutProvider.isPhaseComplete && !workoutProvider.isWorkoutComplete) { Timer(const Duration(milliseconds: 1), () => workoutProvider.nextPhase()); } @@ -36,10 +36,6 @@ class WorkoutTimerWidget extends StatelessWidget { } } - if (workoutProvider.isWorkoutComplete) { - handleStartStopWorkout(); - } - return Column( mainAxisAlignment: MainAxisAlignment.center, children: [ From d1600b174ed0f1dfd763a9be61d53742ed203255 Mon Sep 17 00:00:00 2001 From: Crondung <1922635@stud.hs-mannheim.de> Date: Thu, 2 Mar 2023 16:06:24 +0100 Subject: [PATCH 11/12] save workout when completed --- lib/providers/workout_provider.dart | 8 ++++---- lib/widgets/popup_for_start_and_stop.dart | 4 ++-- lib/widgets/workout_timer_widget.dart | 22 +++++++++++++++------- 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/lib/providers/workout_provider.dart b/lib/providers/workout_provider.dart index add88de..5c0a80b 100644 --- a/lib/providers/workout_provider.dart +++ b/lib/providers/workout_provider.dart @@ -35,13 +35,13 @@ class WorkoutProvider extends ChangeNotifier { final List _workoutPhases = [ 'Warm-Up', - /*'High Intensity', - 'Low Intensity', 'High Intensity', 'Low Intensity', 'High Intensity', 'Low Intensity', - 'High Intensity', */ + 'High Intensity', + 'Low Intensity', + 'High Intensity', 'Cool-down' ]; int _workoutPhaseIndex = 0; @@ -89,7 +89,7 @@ class WorkoutProvider extends ChangeNotifier { isWorkoutComplete = true; _audioPlayer.stop(); timerProvider.stopTimer(); - //notifyListeners(); + notifyListeners(); } void saveWorkout() { diff --git a/lib/widgets/popup_for_start_and_stop.dart b/lib/widgets/popup_for_start_and_stop.dart index 4883737..77411a4 100644 --- a/lib/widgets/popup_for_start_and_stop.dart +++ b/lib/widgets/popup_for_start_and_stop.dart @@ -4,8 +4,8 @@ import 'package:smoke_cess_app/providers/input_provider.dart'; import 'package:smoke_cess_app/widgets/slider.dart'; Future showMotivationPopup( - BuildContext context, Function onSave, String title) async { - return await showDialog( + BuildContext context, Function onSave, String title) { + return showDialog( context: context, builder: (BuildContext context) { return ChangeNotifierProvider( diff --git a/lib/widgets/workout_timer_widget.dart b/lib/widgets/workout_timer_widget.dart index 8023770..59f67d4 100644 --- a/lib/widgets/workout_timer_widget.dart +++ b/lib/widgets/workout_timer_widget.dart @@ -20,16 +20,24 @@ class WorkoutTimerWidget extends StatelessWidget { Timer(const Duration(milliseconds: 1), () => workoutProvider.nextPhase()); } - void handleStartStopWorkout() async { + if (workoutProvider.isWorkoutComplete) { + Timer( + const Duration(milliseconds: 1), + () => showMotivationPopup(context, (double value) { + workoutProvider.motivationAfter = value.toInt(); + workoutProvider.saveWorkout(); + }, 'Motivation nach dem Training')); + } + + void handleStartStopWorkout() { if (!workoutProvider.isWorkoutStarted) { - await showMotivationPopup( - context, - (double value) => workoutProvider.motivationBefore = value.toInt(), - 'Motivation vor dem Training'); - workoutProvider.startWorkout(); + showMotivationPopup(context, (double value) { + workoutProvider.motivationBefore = value.toInt(); + workoutProvider.startWorkout(); + }, 'Motivation vor dem Training'); } else { workoutProvider.stopWorkout(); - await showMotivationPopup( + showMotivationPopup( context, (double value) => workoutProvider.motivationAfter = value.toInt(), 'Motivation nach dem Training'); From 5b3d615c8e24a87e606a1b5a2216ac8939d26616 Mon Sep 17 00:00:00 2001 From: Crondung <1922635@stud.hs-mannheim.de> Date: Thu, 2 Mar 2023 16:12:54 +0100 Subject: [PATCH 12/12] fix flutter analyze problems --- lib/mock/db_mock.dart | 1 + lib/pages/interval_page.dart | 1 - lib/pages/scanner_page.dart | 12 +++--------- lib/services/database_service.dart | 8 ++++---- lib/services/settings_service.dart | 7 ------- lib/widgets/mood_form.dart | 2 -- 6 files changed, 8 insertions(+), 23 deletions(-) diff --git a/lib/mock/db_mock.dart b/lib/mock/db_mock.dart index 68e3b4d..313cece 100644 --- a/lib/mock/db_mock.dart +++ b/lib/mock/db_mock.dart @@ -4,6 +4,7 @@ import 'package:smoke_cess_app/models/relapse.dart'; import 'package:smoke_cess_app/models/sleep.dart'; import 'package:smoke_cess_app/models/workout.dart'; import 'package:smoke_cess_app/services/database_service.dart'; +// ignore: depend_on_referenced_packages import 'package:sqflite_common/sqlite_api.dart'; class DatabaseMock implements DatabaseService { diff --git a/lib/pages/interval_page.dart b/lib/pages/interval_page.dart index bf26c40..1c0d64f 100644 --- a/lib/pages/interval_page.dart +++ b/lib/pages/interval_page.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import 'package:smoke_cess_app/providers/input_provider.dart'; import 'package:smoke_cess_app/providers/timer_provider.dart'; import 'package:smoke_cess_app/providers/workout_provider.dart'; import 'package:smoke_cess_app/widgets/mute_button.dart'; diff --git a/lib/pages/scanner_page.dart b/lib/pages/scanner_page.dart index 29cf8a7..de394f9 100644 --- a/lib/pages/scanner_page.dart +++ b/lib/pages/scanner_page.dart @@ -17,15 +17,9 @@ class ScannerPage extends StatelessWidget { List moods = await globals.databaseService.getMoodRecords(); List sleeps = await globals.databaseService.getSleepRecords(); List relapses = await globals.databaseService.getRelapseRecords(); - for (Mood mood in moods) { - print(mood.toCSV()); - } - for (Sleep sleep in sleeps) { - print(sleep.toCSV()); - } - for (Relapse relapse in relapses) { - print(relapse.toCSV()); - } + moods; + sleeps; + relapses; } void loadJSON(BuildContext context) async { diff --git a/lib/services/database_service.dart b/lib/services/database_service.dart index 311bf88..3996883 100644 --- a/lib/services/database_service.dart +++ b/lib/services/database_service.dart @@ -83,7 +83,7 @@ class DatabaseService { return await db.insert('relapse', relapse.toMap()); } - String _createMoodTable = ''' + final String _createMoodTable = ''' CREATE TABLE IF NOT EXISTS mood( id INTEGER PRIMARY KEY, value INTEGER, @@ -92,7 +92,7 @@ class DatabaseService { ) '''; - String _createSleepTable = ''' + final String _createSleepTable = ''' CREATE TABLE IF NOT EXISTS sleep( id INTEGER PRIMARY KEY, value INTEGER, @@ -105,7 +105,7 @@ class DatabaseService { ) '''; - String _createRelapseTable = ''' + final String _createRelapseTable = ''' CREATE TABLE IF NOT EXISTS relapse( id INTEGER PRIMARY KEY, date TEXT, @@ -114,7 +114,7 @@ class DatabaseService { ) '''; - String _createWorkoutTable = ''' + final String _createWorkoutTable = ''' CREATE TABLE IF NOT EXISTS workout( id INTEGER PRIMARY KEY, date TEXT, diff --git a/lib/services/settings_service.dart b/lib/services/settings_service.dart index 8c7e7a7..f28556a 100644 --- a/lib/services/settings_service.dart +++ b/lib/services/settings_service.dart @@ -23,13 +23,6 @@ Future getMoodQueryMinutes() => _getIntSetting('mood_query_minutes'); Future getChessHours() => _getIntSetting('chess_hours'); Future getChessMinutes() => _getIntSetting('chess_minutes'); -void _setStringSetting(String settingKey, String settingValue) => - SharedPreferences.getInstance() - .then((pref) => pref.setString(settingKey, settingValue)); - -Future _getStringSetting(String settingKey) => - SharedPreferences.getInstance().then((pref) => pref.getString(settingKey)); - void _setIntSetting(String settingKey, int settingValue) => SharedPreferences.getInstance() .then((pref) => pref.setInt(settingKey, settingValue)); diff --git a/lib/widgets/mood_form.dart b/lib/widgets/mood_form.dart index b9a0e05..b461ce7 100644 --- a/lib/widgets/mood_form.dart +++ b/lib/widgets/mood_form.dart @@ -1,7 +1,5 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import 'package:smoke_cess_app/models/mood.dart'; -import 'package:smoke_cess_app/services/database_service.dart'; import 'package:smoke_cess_app/widgets/slider.dart'; import 'package:smoke_cess_app/widgets/submit_form_button.dart'; import 'package:smoke_cess_app/widgets/text_formfield.dart';