wip finishing workout and saving model

main
Julian Gegner 2023-03-02 13:19:08 +01:00
parent cd88b483cf
commit 5587f049e1
7 changed files with 132 additions and 89 deletions

View File

@ -1,6 +1,7 @@
import 'package:smoke_cess_app/interface/db_record.dart'; import 'package:smoke_cess_app/interface/db_record.dart';
import 'package:smoke_cess_app/models/mood.dart'; import 'package:smoke_cess_app/models/mood.dart';
import 'package:smoke_cess_app/models/sleep.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:smoke_cess_app/services/database_service.dart';
import 'package:sqflite_common/sqlite_api.dart'; import 'package:sqflite_common/sqlite_api.dart';
@ -28,7 +29,12 @@ class DatabaseMock implements DatabaseService {
} }
@override @override
// TODO: implement database Future<int> addWorkout(Workout workout) {
_workoutRecords.add(workout);
return Future.value(1);
}
@override
Future<Database> get database => DatabaseService.instance.database; Future<Database> get database => DatabaseService.instance.database;
@override @override

View File

@ -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<String, dynamic> map) {
return HIITWorkout(map['_workoutDuration'], map['_commentBefore'],
map['_commentAfter'], map['_workoutDate']);
}
@override
String toCSV() =>
"${_workoutDate.toIso8601String()}, $_workoutDuration, $_commentBefore, $_commentAfter";
@override
Map<String, dynamic> toMap() {
return {
'workoutDuration': _workoutDuration,
'commentBefore': _commentBefore,
'commentAfter': _commentAfter,
'workoutDate': _workoutDate,
};
}
}

View File

@ -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<String, dynamic> map) {
return Workout(map['_workoutDuration'], map['_motivationBefore'],
map['_motivationAfter']);
}
@override
String toCSV() =>
"${_workoutDate.toIso8601String()}, $_motivationBefore, $_motivationAfter";
@override
Map<String, dynamic> toMap() {
return {
'motivationBefore': _motivationBefore,
'motivationAfter': _motivationAfter,
'workoutDate': _workoutDate,
};
}
}

View File

@ -1,6 +1,8 @@
import 'package:audioplayers/audioplayers.dart'; import 'package:audioplayers/audioplayers.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:smoke_cess_app/models/workout.dart';
import 'package:smoke_cess_app/providers/timer_provider.dart'; import 'package:smoke_cess_app/providers/timer_provider.dart';
import '../globals.dart' as globals;
class WorkoutProvider extends ChangeNotifier { class WorkoutProvider extends ChangeNotifier {
TimerProvider timerProvider; TimerProvider timerProvider;
@ -10,6 +12,8 @@ class WorkoutProvider extends ChangeNotifier {
final Source _beepSoundSource = AssetSource('beep.mp3'); final Source _beepSoundSource = AssetSource('beep.mp3');
bool isWorkoutStarted = false; bool isWorkoutStarted = false;
bool isMuted = false; bool isMuted = false;
int motivationBefore = 50;
int motivationAfter = 50;
void mutePlayer() { void mutePlayer() {
isMuted = true; isMuted = true;
@ -25,44 +29,29 @@ class WorkoutProvider extends ChangeNotifier {
WorkoutProvider(this.timerProvider); WorkoutProvider(this.timerProvider);
//TODO: outsource all Maps to JSON File!
final List<String> _workoutPhases = [ final List<String> _workoutPhases = [
'Warm-Up', 'Warm-Up',
'High Intensity', /*'High Intensity',
'Low Intensity', 'Low Intensity',
'High Intensity', 'High Intensity',
'Low Intensity', 'Low Intensity',
'High Intensity', 'High Intensity',
'Low Intensity', 'Low Intensity',
'High Intensity', 'High Intensity', */
'Cool-down' 'Cool-down'
]; ];
final Map<String, Duration> _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<String, Source> _phaseSongSources = {
'Warm-Up': AssetSource('warmUp.mp3'),
'High Intensity': AssetSource('workout.mp3'),
'Low Intensity': AssetSource('workout.mp3'),
'Cool-down': AssetSource('cool_down.mp3')
};
final Map<String, Color> _phaseColors = {
'Warm-Up': Colors.green,
'High Intensity': Colors.red,
'Low Intensity': Colors.orange,
'Cool-down': Colors.blue
};
int _workoutPhaseIndex = 0; int _workoutPhaseIndex = 0;
String get currentPhase => _workoutPhases[_workoutPhaseIndex]; String get currentPhase => _workoutPhases[_workoutPhaseIndex];
Duration get currentPhaseDuration => Duration get currentPhaseDuration =>
_phasesDuration[currentPhase] ?? const Duration(seconds: 0); _workoutPhaseSettings[currentPhase]!['duration'];
bool get isPhaseComplete => bool get isPhaseComplete =>
timerProvider.elapsedSeconds - currentPhaseDuration.inSeconds == 0; 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() { void nextPhase() {
_audioPlayer.stop(); _audioPlayer.stop();
@ -70,10 +59,11 @@ class WorkoutProvider extends ChangeNotifier {
_audioPlayer.play(_beepSoundSource); _audioPlayer.play(_beepSoundSource);
_workoutPhaseIndex += 1; _workoutPhaseIndex += 1;
_audioPlayer.onPlayerComplete.listen((event) { _audioPlayer.onPlayerComplete.listen((event) {
_audioPlayer.play(_phaseSongSources[currentPhase]!); _audioPlayer.play(currentPhaseSource);
timerProvider.startTimer(currentPhaseDuration); timerProvider.startTimer(currentPhaseDuration);
}); });
} else { } else {
//workout completed
_audioPlayer.play(_finishedSoundSource); _audioPlayer.play(_finishedSoundSource);
stopWorkout(); stopWorkout();
} }
@ -83,16 +73,45 @@ class WorkoutProvider extends ChangeNotifier {
isWorkoutStarted = true; isWorkoutStarted = true;
_audioPlayer.play(_beepSoundSource); _audioPlayer.play(_beepSoundSource);
_audioPlayer.onPlayerComplete.listen((event) { _audioPlayer.onPlayerComplete.listen((event) {
_audioPlayer.play(_phaseSongSources[currentPhase]!); _audioPlayer.play(currentPhaseSource);
timerProvider.startTimer(currentPhaseDuration); timerProvider.startTimer(currentPhaseDuration);
}); });
} }
void stopWorkout() { void stopWorkout() {
isWorkoutStarted = false; isWorkoutStarted = false;
_workoutPhaseIndex = 0; //_workoutPhaseIndex = 0;
_audioPlayer.stop(); _audioPlayer.stop();
timerProvider.stopTimer(); timerProvider.stopTimer();
notifyListeners(); notifyListeners();
} }
void saveWorkout() {
Workout workout =
Workout(motivationBefore, motivationAfter, DateTime.now());
globals.databaseService.addWorkout(workout);
}
} }
Map<String, Map<String, dynamic>> _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
}
};

View File

@ -2,6 +2,7 @@ import 'dart:async';
import 'package:path/path.dart'; import 'package:path/path.dart';
import 'package:smoke_cess_app/models/mood.dart'; import 'package:smoke_cess_app/models/mood.dart';
import 'package:smoke_cess_app/models/workout.dart';
import 'package:sqflite/sqflite.dart'; import 'package:sqflite/sqflite.dart';
// ignore: depend_on_referenced_packages // ignore: depend_on_referenced_packages
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
@ -62,6 +63,11 @@ class DatabaseService {
Database db = await instance.database; Database db = await instance.database;
return await db.insert('sleep', sleep.toMap()); return await db.insert('sleep', sleep.toMap());
} }
Future<int> addWorkout(Workout workout) async {
Database db = await instance.database;
return await db.insert('workout', workout.toMap());
}
} }
String _createMoodTable = ''' String _createMoodTable = '''
@ -100,9 +106,6 @@ String _createWorkoutTable = '''
id INTEGER PRIMARY KEY, id INTEGER PRIMARY KEY,
date TEXT, date TEXT,
motivationBefore INTEGER, motivationBefore INTEGER,
commentBefore TEXT,
motivationAfter INTEGER, motivationAfter INTEGER,
commentAfter TEXT,
completed INTEGER
) )
'''; ''';

View File

@ -2,12 +2,29 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:smoke_cess_app/providers/input_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/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 { class TimerStartStopPopup extends StatelessWidget {
final String title; final String title;
final Function onSaveAction;
const TimerStartStopPopup({Key? key, required this.title}) : super(key: key); const TimerStartStopPopup(
{Key? key, required this.title, required this.onSaveAction})
: super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -24,10 +41,11 @@ class TimerStartStopPopup extends StatelessWidget {
child: MySlider(), child: MySlider(),
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
const MyTextFormField('Beschreibe deinen Motivation'),
ElevatedButton( ElevatedButton(
onPressed: () => onPressed: () {
Navigator.pop(context, inputProvider.sliderValue), onSaveAction(inputProvider.sliderValue);
Navigator.pop(context);
},
child: const Text('Speichern')) child: const Text('Speichern'))
], ],
), ),

View File

@ -5,24 +5,41 @@ import 'package:provider/provider.dart';
import 'package:smoke_cess_app/providers/workout_provider.dart'; import 'package:smoke_cess_app/providers/workout_provider.dart';
import 'package:smoke_cess_app/widgets/timer_widget.dart'; import 'package:smoke_cess_app/widgets/timer_widget.dart';
import '../providers/input_provider.dart';
import '../providers/timer_provider.dart'; import '../providers/timer_provider.dart';
import 'popup_for_start_and_stop.dart'; import 'popup_for_start_and_stop.dart';
class WorkoutTimerWidget extends StatelessWidget { class WorkoutTimerWidget extends StatelessWidget {
const WorkoutTimerWidget({super.key}); const WorkoutTimerWidget({super.key});
void _onStartButtonPressed(BuildContext context) {}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
TimerProvider timerProvider = context.watch<TimerProvider>(); TimerProvider timerProvider = context.watch<TimerProvider>();
WorkoutProvider workoutProvider = context.watch<WorkoutProvider>(); WorkoutProvider workoutProvider = context.watch<WorkoutProvider>();
if (workoutProvider.isPhaseComplete) { if (workoutProvider.isPhaseComplete && workoutProvider.isWorkoutStarted) {
Timer(const Duration(milliseconds: 1), () => workoutProvider.nextPhase()); 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( return Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
@ -49,23 +66,7 @@ class WorkoutTimerWidget extends StatelessWidget {
height: 20, height: 20,
), ),
ElevatedButton( ElevatedButton(
onPressed: !workoutProvider.isWorkoutStarted onPressed: handleStartStopWorkout,
? () 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')) child: Text(timerProvider.started ? 'Stop' : 'Start'))
], ],
); );