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')) ], );