Merge branch '24-timer-darf-nur-ein-mal-pro-tag-gedruckt-werden' into 'main'
Tasks können nur ausgeführt werden, wenn gefordert. See merge request Crondung/hsma_cpd!25main
commit
42f4fcd05d
|
@ -5,6 +5,7 @@ import 'package:smoke_cess_app/providers/tasks_provider.dart';
|
||||||
import 'package:smoke_cess_app/services/notification_service.dart';
|
import 'package:smoke_cess_app/services/notification_service.dart';
|
||||||
import 'package:timezone/data/latest.dart' as tz;
|
import 'package:timezone/data/latest.dart' as tz;
|
||||||
import 'globals.dart' as globals;
|
import 'globals.dart' as globals;
|
||||||
|
import 'providers/page_provider.dart';
|
||||||
import 'providers/settings_provider.dart';
|
import 'providers/settings_provider.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
@ -24,18 +25,21 @@ class MyApp extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MaterialApp(
|
return MultiProvider(
|
||||||
title: _title,
|
providers: [
|
||||||
home: MultiProvider(
|
ChangeNotifierProvider(create: (context) => SettingsProvider()),
|
||||||
providers: [
|
ChangeNotifierProxyProvider<SettingsProvider, TasksProvider>(
|
||||||
ChangeNotifierProvider(create: (context) => SettingsProvider()),
|
create: (context) => TasksProvider(null),
|
||||||
ChangeNotifierProxyProvider<SettingsProvider, TasksProvider>(
|
update: (context, value, TasksProvider? previous) =>
|
||||||
create: (context) => TasksProvider(null),
|
TasksProvider(value),
|
||||||
update: (context, value, TasksProvider? previous) =>
|
),
|
||||||
TasksProvider(value),
|
ChangeNotifierProvider(
|
||||||
),
|
create: (context) => PageProvider(),
|
||||||
],
|
),
|
||||||
child: const MyHomePage(),
|
],
|
||||||
|
child: const MaterialApp(
|
||||||
|
title: _title,
|
||||||
|
home: MyHomePage(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ class Mood implements DatabaseRecord {
|
||||||
Mood(this._moodValue, this._comment, this._date);
|
Mood(this._moodValue, this._comment, this._date);
|
||||||
|
|
||||||
DateTime get date => _date;
|
DateTime get date => _date;
|
||||||
|
int get moodValue => _moodValue;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
factory Mood.fromDatabase(Map<String, dynamic> map) {
|
factory Mood.fromDatabase(Map<String, dynamic> map) {
|
||||||
|
|
|
@ -7,6 +7,9 @@ class Relapse implements DatabaseRecord {
|
||||||
|
|
||||||
Relapse(this._category, this._comment, this._date);
|
Relapse(this._category, this._comment, this._date);
|
||||||
|
|
||||||
|
String get category => _category;
|
||||||
|
DateTime get date => _date;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
factory Relapse.fromDatabase(Map<String, dynamic> map) {
|
factory Relapse.fromDatabase(Map<String, dynamic> map) {
|
||||||
DateTime date = DateTime.parse(map['date']);
|
DateTime date = DateTime.parse(map['date']);
|
||||||
|
|
|
@ -12,6 +12,7 @@ class Sleep implements DatabaseRecord {
|
||||||
this._wokeUpAt);
|
this._wokeUpAt);
|
||||||
|
|
||||||
DateTime get date => _date;
|
DateTime get date => _date;
|
||||||
|
int get sleepQualitiyValue => _sleepQualityValue;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
factory Sleep.fromDatabase(Map<String, dynamic> map) {
|
factory Sleep.fromDatabase(Map<String, dynamic> map) {
|
||||||
|
|
|
@ -8,6 +8,8 @@ class Workout implements DatabaseRecord {
|
||||||
Workout(this._motivationBefore, this._motivationAfter, this._workoutDate);
|
Workout(this._motivationBefore, this._motivationAfter, this._workoutDate);
|
||||||
|
|
||||||
DateTime get date => _workoutDate;
|
DateTime get date => _workoutDate;
|
||||||
|
int get motivationBefore => _motivationBefore;
|
||||||
|
int get motivationAfter => _motivationAfter;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
factory Workout.fromDatabase(Map<String, dynamic> map) {
|
factory Workout.fromDatabase(Map<String, dynamic> map) {
|
||||||
|
|
|
@ -1,32 +1,16 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:smoke_cess_app/services/pages_service.dart';
|
||||||
import 'package:smoke_cess_app/providers/timer_provider.dart';
|
import 'package:smoke_cess_app/widgets/workout_form.dart';
|
||||||
import 'package:smoke_cess_app/providers/workout_provider.dart';
|
import 'package:smoke_cess_app/widgets/workout_view.dart';
|
||||||
import 'package:smoke_cess_app/widgets/mute_button.dart';
|
|
||||||
import 'package:smoke_cess_app/widgets/workout_timer_widget.dart';
|
import '../widgets/view_form_page.dart';
|
||||||
|
|
||||||
class IntervalTimerPage extends StatelessWidget {
|
class IntervalTimerPage extends StatelessWidget {
|
||||||
const IntervalTimerPage({super.key});
|
const IntervalTimerPage({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
TimerProvider timerProvider = TimerProvider();
|
return const ViewFormPage(
|
||||||
return MultiProvider(
|
form: WorkoutForm(), view: WorkoutView(), page: Pages.timer);
|
||||||
providers: [
|
|
||||||
ChangeNotifierProvider(create: (context) => timerProvider),
|
|
||||||
ChangeNotifierProvider(
|
|
||||||
create: (context) => WorkoutProvider(timerProvider)),
|
|
||||||
],
|
|
||||||
child: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: const [
|
|
||||||
Align(
|
|
||||||
alignment: Alignment.topLeft,
|
|
||||||
child: MuteButton(),
|
|
||||||
),
|
|
||||||
WorkoutTimerWidget()
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import 'package:awesome_dialog/awesome_dialog.dart';
|
import 'package:awesome_dialog/awesome_dialog.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:smoke_cess_app/providers/page_provider.dart';
|
||||||
import 'package:smoke_cess_app/providers/tasks_provider.dart';
|
import 'package:smoke_cess_app/providers/tasks_provider.dart';
|
||||||
import 'package:smoke_cess_app/services/pages_service.dart';
|
import 'package:smoke_cess_app/services/pages_service.dart';
|
||||||
import 'package:smoke_cess_app/providers/settings_provider.dart';
|
import 'package:smoke_cess_app/providers/settings_provider.dart';
|
||||||
|
@ -19,15 +20,19 @@ class MyHomePageState extends State<MyHomePage> {
|
||||||
bool _isConfigured = false;
|
bool _isConfigured = false;
|
||||||
|
|
||||||
void _onItemTapped(int index) {
|
void _onItemTapped(int index) {
|
||||||
|
PageProvider pageProvider = context.read<PageProvider>();
|
||||||
setState(() {
|
setState(() {
|
||||||
_isConfigured
|
if (_isConfigured) {
|
||||||
? _selectedIndex = index
|
pageProvider.showForm = false;
|
||||||
: AwesomeDialog(
|
_selectedIndex = index;
|
||||||
context: context,
|
return;
|
||||||
dialogType: DialogType.info,
|
}
|
||||||
title: 'Fehlende Konfiguration',
|
AwesomeDialog(
|
||||||
desc: 'Bitte QR Code Scannen!',
|
context: context,
|
||||||
).show();
|
dialogType: DialogType.info,
|
||||||
|
title: 'Fehlende Konfiguration',
|
||||||
|
desc: 'Bitte QR Code Scannen!',
|
||||||
|
).show();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,9 +45,9 @@ class MyHomePageState extends State<MyHomePage> {
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(
|
title: Text(
|
||||||
'${pages.values.elementAt(_selectedIndex)['title']} ${_isConfigured ? "Gruppe ${settingsModel.settings?.group}" : ""}')),
|
'${pages.values.elementAt(_selectedIndex)['title']} ${_isConfigured ? "Gruppe ${settingsModel.settings?.group}" : ""}')),
|
||||||
body: Center(
|
body: SingleChildScrollView(
|
||||||
child: SingleChildScrollView(
|
child: pages.values.elementAt(_selectedIndex)['page'],
|
||||||
child: pages.values.elementAt(_selectedIndex)['page'])),
|
),
|
||||||
bottomNavigationBar: NavigationBar(
|
bottomNavigationBar: NavigationBar(
|
||||||
onDestinationSelected: _onItemTapped,
|
onDestinationSelected: _onItemTapped,
|
||||||
selectedIndex: _selectedIndex,
|
selectedIndex: _selectedIndex,
|
||||||
|
|
|
@ -1,17 +1,15 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:smoke_cess_app/services/pages_service.dart';
|
||||||
import 'package:smoke_cess_app/providers/input_provider.dart';
|
|
||||||
import 'package:smoke_cess_app/widgets/mood_form.dart';
|
import 'package:smoke_cess_app/widgets/mood_form.dart';
|
||||||
|
import 'package:smoke_cess_app/widgets/mood_view.dart';
|
||||||
|
import 'package:smoke_cess_app/widgets/view_form_page.dart';
|
||||||
|
|
||||||
class MoodPage extends StatelessWidget {
|
class MoodPage extends StatelessWidget {
|
||||||
const MoodPage({super.key});
|
const MoodPage({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Center(
|
return const ViewFormPage(
|
||||||
child: ChangeNotifierProvider(
|
form: MoodForm(), view: MoodView(), page: Pages.mood);
|
||||||
create: (context) => InputProvider(),
|
|
||||||
child: const MoodForm(),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,15 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:smoke_cess_app/services/pages_service.dart';
|
||||||
import 'package:smoke_cess_app/widgets/relapse_form.dart';
|
import 'package:smoke_cess_app/widgets/relapse_form.dart';
|
||||||
import '../providers/input_provider.dart';
|
import 'package:smoke_cess_app/widgets/relapse_view.dart';
|
||||||
|
import '../widgets/view_form_page.dart';
|
||||||
|
|
||||||
class RelapsePage extends StatelessWidget {
|
class RelapsePage extends StatelessWidget {
|
||||||
const RelapsePage({super.key});
|
const RelapsePage({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Center(
|
return const ViewFormPage(
|
||||||
child: ChangeNotifierProvider(
|
form: RelapseForm(), view: RelapseView(), page: Pages.relapse);
|
||||||
create: (context) => InputProvider(),
|
|
||||||
child: const RelapseForm(),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,15 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:smoke_cess_app/services/pages_service.dart';
|
||||||
import 'package:smoke_cess_app/providers/input_provider.dart';
|
|
||||||
import 'package:smoke_cess_app/widgets/sleep_form.dart';
|
import 'package:smoke_cess_app/widgets/sleep_form.dart';
|
||||||
|
import 'package:smoke_cess_app/widgets/sleep_view.dart';
|
||||||
|
import 'package:smoke_cess_app/widgets/view_form_page.dart';
|
||||||
|
|
||||||
class SleepPage extends StatelessWidget {
|
class SleepPage extends StatelessWidget {
|
||||||
const SleepPage({super.key});
|
const SleepPage({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Center(
|
return const ViewFormPage(
|
||||||
child: ChangeNotifierProvider(
|
form: SleepForm(), view: SleepView(), page: Pages.sleep);
|
||||||
create: (context) => InputProvider(),
|
|
||||||
child: const SleepForm(),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,22 +11,16 @@ class InputProvider extends ChangeNotifier {
|
||||||
'wokeUpAt': const TimeOfDay(hour: 8, minute: 0),
|
'wokeUpAt': const TimeOfDay(hour: 8, minute: 0),
|
||||||
'sleptAt': const TimeOfDay(hour: 22, minute: 0),
|
'sleptAt': const TimeOfDay(hour: 22, minute: 0),
|
||||||
};
|
};
|
||||||
String _relapseCategory = '';
|
String relapseCategory = '';
|
||||||
|
|
||||||
double get sliderValue => _sliderValue;
|
double get sliderValue => _sliderValue;
|
||||||
TextEditingController get textController => _textController;
|
TextEditingController get textController => _textController;
|
||||||
String get relapseCategory => _relapseCategory;
|
|
||||||
|
|
||||||
set sliderValue(double newValue) {
|
set sliderValue(double newValue) {
|
||||||
_sliderValue = newValue;
|
_sliderValue = newValue;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
set relapseCategory(String newValue) {
|
|
||||||
_relapseCategory = newValue;
|
|
||||||
notifyListeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
TimeOfDay getTimeEntry(String key) {
|
TimeOfDay getTimeEntry(String key) {
|
||||||
return _times[key] ?? const TimeOfDay(hour: 12, minute: 0);
|
return _times[key] ?? const TimeOfDay(hour: 12, minute: 0);
|
||||||
}
|
}
|
||||||
|
@ -53,7 +47,7 @@ class InputProvider extends ChangeNotifier {
|
||||||
|
|
||||||
Future<int> saveRelapse() {
|
Future<int> saveRelapse() {
|
||||||
Relapse relapse =
|
Relapse relapse =
|
||||||
Relapse(_relapseCategory, _textController.text, DateTime.now());
|
Relapse(relapseCategory, _textController.text, DateTime.now());
|
||||||
_resetFields();
|
_resetFields();
|
||||||
return globals.databaseService.addRelapse(relapse);
|
return globals.databaseService.addRelapse(relapse);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class PageProvider extends ChangeNotifier {
|
||||||
|
bool showForm = false;
|
||||||
|
|
||||||
|
void swap() {
|
||||||
|
showForm = !showForm;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:smoke_cess_app/models/relapse.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/models/workout.dart';
|
||||||
import 'package:smoke_cess_app/providers/settings_provider.dart';
|
import 'package:smoke_cess_app/providers/settings_provider.dart';
|
||||||
|
@ -15,8 +16,14 @@ class TasksProvider extends ChangeNotifier {
|
||||||
Pages.timer: true,
|
Pages.timer: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
List<Mood> moodHistory = [];
|
||||||
|
List<Sleep> sleepHistory = [];
|
||||||
|
List<Workout> workoutHistory = [];
|
||||||
|
List<Relapse> relapseHistory = [];
|
||||||
|
|
||||||
TasksProvider(SettingsProvider? settingsProvider) {
|
TasksProvider(SettingsProvider? settingsProvider) {
|
||||||
initTasks();
|
initTasks();
|
||||||
|
initHistories();
|
||||||
}
|
}
|
||||||
|
|
||||||
void setTaskDone(Pages taskName) {
|
void setTaskDone(Pages taskName) {
|
||||||
|
@ -24,13 +31,23 @@ class TasksProvider extends ChangeNotifier {
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void initHistories() async {
|
||||||
|
moodHistory = await globals.databaseService.getMoodRecords();
|
||||||
|
sleepHistory = await globals.databaseService.getSleepRecords();
|
||||||
|
workoutHistory = await globals.databaseService.getWorkoutRecords();
|
||||||
|
relapseHistory = await globals.databaseService.getRelapseRecords();
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
void initTasks() async {
|
void initTasks() async {
|
||||||
|
DateTime now = DateTime.now();
|
||||||
TZDateTime? moodToday = await getTodayMood();
|
TZDateTime? moodToday = await getTodayMood();
|
||||||
if (moodToday != null) {
|
if (moodToday != null) {
|
||||||
List<Mood> moodList = await globals.databaseService.getMoodRecords();
|
List<Mood> moodList = await globals.databaseService.getMoodRecords();
|
||||||
if (moodList.isNotEmpty) {
|
if (moodList.isNotEmpty) {
|
||||||
Mood mood = moodList.last;
|
Mood mood = moodList.last;
|
||||||
tasks[Pages.mood] = !isSameDay(moodToday, mood.date);
|
tasks[Pages.mood] =
|
||||||
|
!isSameDay(moodToday, mood.date) && moodToday.isBefore(now);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
tasks[Pages.mood] = false;
|
tasks[Pages.mood] = false;
|
||||||
|
@ -40,7 +57,8 @@ class TasksProvider extends ChangeNotifier {
|
||||||
List<Sleep> sleepList = await globals.databaseService.getSleepRecords();
|
List<Sleep> sleepList = await globals.databaseService.getSleepRecords();
|
||||||
if (sleepList.isNotEmpty) {
|
if (sleepList.isNotEmpty) {
|
||||||
Sleep sleep = sleepList.last;
|
Sleep sleep = sleepList.last;
|
||||||
tasks[Pages.sleep] = !isSameDay(sleepToday, sleep.date);
|
tasks[Pages.sleep] =
|
||||||
|
!isSameDay(sleepToday, sleep.date) && sleepToday.isBefore(now);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
tasks[Pages.sleep] = false;
|
tasks[Pages.sleep] = false;
|
||||||
|
|
|
@ -21,5 +21,14 @@ class TimerProvider extends ChangeNotifier {
|
||||||
void stopTimer() {
|
void stopTimer() {
|
||||||
started = false;
|
started = false;
|
||||||
_timer?.cancel();
|
_timer?.cancel();
|
||||||
|
_timer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
started = false;
|
||||||
|
_timer?.cancel();
|
||||||
|
_timer = null;
|
||||||
|
super.dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,11 +92,25 @@ class WorkoutProvider extends ChangeNotifier {
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void interruptWorkout() {
|
||||||
|
isWorkoutStarted = false;
|
||||||
|
isWorkoutComplete = false;
|
||||||
|
_audioPlayer.stop();
|
||||||
|
timerProvider.stopTimer();
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
void saveWorkout() {
|
void saveWorkout() {
|
||||||
Workout workout =
|
Workout workout =
|
||||||
Workout(motivationBefore, motivationAfter, DateTime.now());
|
Workout(motivationBefore, motivationAfter, DateTime.now());
|
||||||
globals.databaseService.addWorkout(workout);
|
globals.databaseService.addWorkout(workout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
interruptWorkout();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, Map<String, dynamic>> _workoutPhaseSettings = {
|
Map<String, Map<String, dynamic>> _workoutPhaseSettings = {
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import 'package:smoke_cess_app/services/settings_service.dart';
|
import 'package:smoke_cess_app/services/settings_service.dart';
|
||||||
import 'package:timezone/timezone.dart';
|
import 'package:timezone/timezone.dart';
|
||||||
|
|
||||||
|
import 'pages_service.dart';
|
||||||
|
|
||||||
const int trainingTime = 40;
|
const int trainingTime = 40;
|
||||||
|
|
||||||
const weekDays = {
|
const weekDays = {
|
||||||
|
@ -47,6 +49,45 @@ Future<TZDateTime?> getTodaySleep() async {
|
||||||
return today.isNotEmpty ? today.first : null;
|
return today.isNotEmpty ? today.first : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<Duration> getTimeTillNextMood() async {
|
||||||
|
List<TZDateTime> moodDates = await getDatesforMood();
|
||||||
|
Iterable<TZDateTime> nextDate =
|
||||||
|
moodDates.where((element) => element.isAfter(DateTime.now()));
|
||||||
|
Duration duration = nextDate.isNotEmpty
|
||||||
|
? nextDate.first.difference(DateTime.now())
|
||||||
|
: const Duration(seconds: 0);
|
||||||
|
return duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Duration> getTimeTillNextSleep() async {
|
||||||
|
List<TZDateTime> sleepDates = await getDatesforSleep();
|
||||||
|
Iterable<TZDateTime> nextDate =
|
||||||
|
sleepDates.where((element) => element.isAfter(DateTime.now()));
|
||||||
|
Duration duration = nextDate.isNotEmpty
|
||||||
|
? nextDate.first.difference(DateTime.now())
|
||||||
|
: const Duration(seconds: 0);
|
||||||
|
return duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Duration> getTimeTillNextWorkout() async {
|
||||||
|
DateTime now = DateTime.now();
|
||||||
|
DateTime tomorrow =
|
||||||
|
DateTime(now.year, now.month, now.day).add(const Duration(days: 1));
|
||||||
|
Duration duration = tomorrow.difference(now);
|
||||||
|
return duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Duration> getTimeTill(Pages page) {
|
||||||
|
switch (page) {
|
||||||
|
case Pages.mood:
|
||||||
|
return getTimeTillNextMood();
|
||||||
|
case Pages.sleep:
|
||||||
|
return getTimeTillNextSleep();
|
||||||
|
default:
|
||||||
|
return getTimeTillNextWorkout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
List<TZDateTime> createTZDateTimes(
|
List<TZDateTime> createTZDateTimes(
|
||||||
List<String>? selectedDays, int? selectedHours, int? selectedMinutes) {
|
List<String>? selectedDays, int? selectedHours, int? selectedMinutes) {
|
||||||
final List<TZDateTime> tzDateTimes = [];
|
final List<TZDateTime> tzDateTimes = [];
|
||||||
|
|
|
@ -1,4 +1,14 @@
|
||||||
String formatTime(int seconds) {
|
String formatTime(int seconds) {
|
||||||
Duration duration = Duration(seconds: seconds);
|
Duration duration = Duration(seconds: seconds);
|
||||||
return '${duration.inMinutes.remainder(60).toString().padLeft(2, '0')}:${duration.inSeconds.remainder(60).toString().padLeft(2, '0')}';
|
String formattedTime = '';
|
||||||
|
String twoDigits(int n) => n.toString().padLeft(2, "0");
|
||||||
|
String days = duration.inDays.toString();
|
||||||
|
String hours = twoDigits(duration.inHours.remainder(24));
|
||||||
|
String minutes = twoDigits(duration.inMinutes.remainder(60));
|
||||||
|
String formattedSeconds = twoDigits(duration.inSeconds.remainder(60));
|
||||||
|
if (duration.inDays != 0) formattedTime += '$days:';
|
||||||
|
if (duration.inHours != 0) formattedTime += '$hours:';
|
||||||
|
formattedTime += '$minutes:';
|
||||||
|
formattedTime += formattedSeconds;
|
||||||
|
return formattedTime;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ class DropDown extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var inputModel = context.watch<InputProvider>();
|
var inputModel = context.watch<InputProvider>();
|
||||||
|
inputModel.relapseCategory = _items.isNotEmpty ? _items[0] : '';
|
||||||
return DropdownButtonFormField<String>(
|
return DropdownButtonFormField<String>(
|
||||||
value: _items.isEmpty ? null : _items[0],
|
value: _items.isEmpty ? null : _items[0],
|
||||||
icon: const Icon(Icons.arrow_downward),
|
icon: const Icon(Icons.arrow_downward),
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:syncfusion_flutter_charts/charts.dart';
|
||||||
|
import '../models/mood.dart';
|
||||||
|
import '../providers/tasks_provider.dart';
|
||||||
|
|
||||||
|
class MoodView extends StatelessWidget {
|
||||||
|
const MoodView({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
var tasksModel = context.watch<TasksProvider>();
|
||||||
|
return Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
SfCartesianChart(
|
||||||
|
primaryXAxis: DateTimeAxis(),
|
||||||
|
series: <ChartSeries>[
|
||||||
|
LineSeries<Mood, DateTime>(
|
||||||
|
dataSource: tasksModel.moodHistory,
|
||||||
|
xValueMapper: (Mood value, _) => value.date,
|
||||||
|
yValueMapper: (Mood value, _) => value.moodValue)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Column(
|
||||||
|
children: tasksModel.moodHistory.map((mood) {
|
||||||
|
return Text('${mood.date}: ${mood.moodValue}');
|
||||||
|
}).toList())
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:smoke_cess_app/providers/timer_provider.dart';
|
||||||
|
import 'package:smoke_cess_app/widgets/timer_widget.dart';
|
||||||
|
import '../services/date_service.dart';
|
||||||
|
import '../services/pages_service.dart';
|
||||||
|
|
||||||
|
void showTaskDonePopup(BuildContext context, Pages page) async {
|
||||||
|
Duration duration = await getTimeTill(page);
|
||||||
|
await showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return ChangeNotifierProvider(
|
||||||
|
create: (context) => TimerProvider(),
|
||||||
|
child: TaskDonePopup(
|
||||||
|
duration: duration,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class TaskDonePopup extends StatelessWidget {
|
||||||
|
final Duration duration;
|
||||||
|
const TaskDonePopup({super.key, required this.duration});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
TimerProvider timerProvider = context.read<TimerProvider>();
|
||||||
|
timerProvider.startTimer(duration);
|
||||||
|
return AlertDialog(
|
||||||
|
title: const Text('Schon gemacht'),
|
||||||
|
content: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
const Text('Nächstes mal wieder:'),
|
||||||
|
TimerWidget(duration: duration)
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import '../providers/tasks_provider.dart';
|
||||||
|
|
||||||
|
class RelapseView extends StatelessWidget {
|
||||||
|
const RelapseView({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
var tasksModel = context.watch<TasksProvider>();
|
||||||
|
return Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: tasksModel.relapseHistory.map((relapse) {
|
||||||
|
return Text('${relapse.date}: ${relapse.category}');
|
||||||
|
}).toList());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:smoke_cess_app/models/sleep.dart';
|
||||||
|
import 'package:syncfusion_flutter_charts/charts.dart';
|
||||||
|
import '../providers/tasks_provider.dart';
|
||||||
|
|
||||||
|
class SleepView extends StatelessWidget {
|
||||||
|
const SleepView({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
var tasksModel = context.watch<TasksProvider>();
|
||||||
|
return Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
SfCartesianChart(
|
||||||
|
primaryXAxis: DateTimeAxis(),
|
||||||
|
series: <ChartSeries>[
|
||||||
|
LineSeries<Sleep, DateTime>(
|
||||||
|
dataSource: tasksModel.sleepHistory,
|
||||||
|
xValueMapper: (Sleep value, _) => value.date,
|
||||||
|
yValueMapper: (Sleep value, _) => value.sleepQualitiyValue)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Column(
|
||||||
|
children: tasksModel.sleepHistory.map((sleep) {
|
||||||
|
return Text('${sleep.date}: ${sleep.sleepQualitiyValue}');
|
||||||
|
}).toList())
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,7 @@
|
||||||
import 'package:awesome_dialog/awesome_dialog.dart';
|
import 'package:awesome_dialog/awesome_dialog.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:smoke_cess_app/providers/page_provider.dart';
|
||||||
|
|
||||||
class SubmitFormButton extends StatelessWidget {
|
class SubmitFormButton extends StatelessWidget {
|
||||||
final Future<int> Function() submitCallback;
|
final Future<int> Function() submitCallback;
|
||||||
|
@ -9,21 +11,23 @@ class SubmitFormButton extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
PageProvider pageProvider = context.watch<PageProvider>();
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 16.0),
|
padding: const EdgeInsets.symmetric(vertical: 16.0),
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
int success = await submitCallback();
|
int success = await submitCallback();
|
||||||
if (success != 0) {
|
if (success != 0) {
|
||||||
AwesomeDialog(
|
await AwesomeDialog(
|
||||||
context: context,
|
context: context,
|
||||||
dialogType: DialogType.success,
|
dialogType: DialogType.success,
|
||||||
title: 'Gespeichert',
|
title: 'Gespeichert',
|
||||||
desc: 'Der Eintrag wurde erfolgreich gespeichert',
|
desc: 'Der Eintrag wurde erfolgreich gespeichert',
|
||||||
).show();
|
).show();
|
||||||
updateTasks();
|
updateTasks();
|
||||||
|
pageProvider.swap();
|
||||||
} else {
|
} else {
|
||||||
AwesomeDialog(
|
await AwesomeDialog(
|
||||||
context: context,
|
context: context,
|
||||||
dialogType: DialogType.error,
|
dialogType: DialogType.error,
|
||||||
title: 'Fehler',
|
title: 'Fehler',
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:smoke_cess_app/services/pages_service.dart';
|
||||||
|
import '../providers/input_provider.dart';
|
||||||
|
import '../providers/page_provider.dart';
|
||||||
|
import '../providers/tasks_provider.dart';
|
||||||
|
import 'popup_for_task_done.dart';
|
||||||
|
|
||||||
|
class ViewFormPage extends StatelessWidget {
|
||||||
|
final Widget form;
|
||||||
|
final Widget view;
|
||||||
|
final Pages page;
|
||||||
|
const ViewFormPage(
|
||||||
|
{super.key, required this.form, required this.view, required this.page});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
PageProvider pageProvider = context.watch<PageProvider>();
|
||||||
|
TasksProvider tasksProvider = context.watch<TasksProvider>();
|
||||||
|
return Wrap(children: [
|
||||||
|
Align(
|
||||||
|
alignment: Alignment.topLeft,
|
||||||
|
child: IconButton(
|
||||||
|
icon: pageProvider.showForm
|
||||||
|
? const Icon(Icons.arrow_back, color: Colors.black)
|
||||||
|
: const Icon(Icons.add_outlined, color: Colors.black),
|
||||||
|
onPressed: tasksProvider.tasks[page] ?? true
|
||||||
|
? pageProvider.swap
|
||||||
|
: () => showTaskDonePopup(context, page),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
pageProvider.showForm
|
||||||
|
? Center(
|
||||||
|
child: ChangeNotifierProvider(
|
||||||
|
create: (context) => InputProvider(),
|
||||||
|
child: form,
|
||||||
|
))
|
||||||
|
: Center(child: view)
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import '../providers/timer_provider.dart';
|
||||||
|
import '../providers/workout_provider.dart';
|
||||||
|
import 'mute_button.dart';
|
||||||
|
import 'workout_timer_widget.dart';
|
||||||
|
|
||||||
|
class WorkoutForm extends StatelessWidget {
|
||||||
|
const WorkoutForm({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
TimerProvider timerProvider = TimerProvider();
|
||||||
|
return MultiProvider(
|
||||||
|
providers: [
|
||||||
|
ChangeNotifierProvider(create: (context) => timerProvider),
|
||||||
|
ChangeNotifierProvider(
|
||||||
|
create: (context) => WorkoutProvider(timerProvider)),
|
||||||
|
],
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: const [
|
||||||
|
Align(
|
||||||
|
alignment: Alignment.topLeft,
|
||||||
|
child: MuteButton(),
|
||||||
|
),
|
||||||
|
WorkoutTimerWidget()
|
||||||
|
],
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,9 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:awesome_dialog/awesome_dialog.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:smoke_cess_app/providers/page_provider.dart';
|
||||||
import 'package:smoke_cess_app/providers/tasks_provider.dart';
|
import 'package:smoke_cess_app/providers/tasks_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/services/pages_service.dart';
|
import 'package:smoke_cess_app/services/pages_service.dart';
|
||||||
|
@ -18,19 +20,29 @@ class WorkoutTimerWidget extends StatelessWidget {
|
||||||
TimerProvider timerProvider = context.watch<TimerProvider>();
|
TimerProvider timerProvider = context.watch<TimerProvider>();
|
||||||
WorkoutProvider workoutProvider = context.watch<WorkoutProvider>();
|
WorkoutProvider workoutProvider = context.watch<WorkoutProvider>();
|
||||||
TasksProvider tasksProvider = context.read<TasksProvider>();
|
TasksProvider tasksProvider = context.read<TasksProvider>();
|
||||||
|
PageProvider pageProvider = context.read<PageProvider>();
|
||||||
|
|
||||||
|
void handleStopWorkout() async {
|
||||||
|
await showMotivationPopup(context, (double value) {
|
||||||
|
workoutProvider.motivationAfter = value.toInt();
|
||||||
|
workoutProvider.saveWorkout();
|
||||||
|
tasksProvider.setTaskDone(Pages.timer);
|
||||||
|
}, 'Motivation nach dem Training');
|
||||||
|
await AwesomeDialog(
|
||||||
|
context: context,
|
||||||
|
dialogType: DialogType.success,
|
||||||
|
title: 'Gespeichert',
|
||||||
|
desc: 'Der Eintrag wurde erfolgreich gespeichert',
|
||||||
|
).show();
|
||||||
|
pageProvider.swap();
|
||||||
|
}
|
||||||
|
|
||||||
if (workoutProvider.isPhaseComplete && !workoutProvider.isWorkoutComplete) {
|
if (workoutProvider.isPhaseComplete && !workoutProvider.isWorkoutComplete) {
|
||||||
Timer(const Duration(milliseconds: 1), () => workoutProvider.nextPhase());
|
Timer(const Duration(milliseconds: 1), () => workoutProvider.nextPhase());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (workoutProvider.isWorkoutComplete) {
|
if (workoutProvider.isWorkoutComplete) {
|
||||||
Timer(
|
Timer(const Duration(milliseconds: 1), handleStopWorkout);
|
||||||
const Duration(milliseconds: 1),
|
|
||||||
() => showMotivationPopup(context, (double value) {
|
|
||||||
workoutProvider.motivationAfter = value.toInt();
|
|
||||||
workoutProvider.saveWorkout();
|
|
||||||
tasksProvider.setTaskDone(Pages.timer);
|
|
||||||
}, 'Motivation nach dem Training'));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleStartStopWorkout() {
|
void handleStartStopWorkout() {
|
||||||
|
@ -40,11 +52,8 @@ class WorkoutTimerWidget extends StatelessWidget {
|
||||||
workoutProvider.startWorkout();
|
workoutProvider.startWorkout();
|
||||||
}, 'Motivation vor dem Training');
|
}, 'Motivation vor dem Training');
|
||||||
} else {
|
} else {
|
||||||
workoutProvider.stopWorkout();
|
workoutProvider.interruptWorkout();
|
||||||
showMotivationPopup(
|
handleStopWorkout();
|
||||||
context,
|
|
||||||
(double value) => workoutProvider.motivationAfter = value.toInt(),
|
|
||||||
'Motivation nach dem Training');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:smoke_cess_app/models/workout.dart';
|
||||||
|
import 'package:syncfusion_flutter_charts/charts.dart';
|
||||||
|
import '../providers/tasks_provider.dart';
|
||||||
|
|
||||||
|
class WorkoutView extends StatelessWidget {
|
||||||
|
const WorkoutView({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
var tasksModel = context.watch<TasksProvider>();
|
||||||
|
return Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
SfCartesianChart(
|
||||||
|
primaryXAxis: DateTimeAxis(),
|
||||||
|
series: <ChartSeries>[
|
||||||
|
LineSeries<Workout, DateTime>(
|
||||||
|
dataSource: tasksModel.workoutHistory,
|
||||||
|
xValueMapper: (Workout value, _) => value.date,
|
||||||
|
yValueMapper: (Workout value, _) => value.motivationBefore),
|
||||||
|
LineSeries<Workout, DateTime>(
|
||||||
|
dataSource: tasksModel.workoutHistory,
|
||||||
|
xValueMapper: (Workout value, _) => value.date,
|
||||||
|
yValueMapper: (Workout value, _) => value.motivationAfter)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
21
pubspec.lock
21
pubspec.lock
|
@ -205,6 +205,13 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.0.2"
|
version: "4.0.2"
|
||||||
|
intl:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: intl
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.18.0"
|
||||||
js:
|
js:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -441,6 +448,20 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.1"
|
version: "1.1.1"
|
||||||
|
syncfusion_flutter_charts:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: syncfusion_flutter_charts
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "20.4.52"
|
||||||
|
syncfusion_flutter_core:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: syncfusion_flutter_core
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "20.4.52"
|
||||||
synchronized:
|
synchronized:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -42,6 +42,7 @@ dependencies:
|
||||||
mobile_scanner: ^3.0.0
|
mobile_scanner: ^3.0.0
|
||||||
flutter_local_notifications: ^13.0.0
|
flutter_local_notifications: ^13.0.0
|
||||||
http: ^0.13.5
|
http: ^0.13.5
|
||||||
|
syncfusion_flutter_charts: ^20.4.52
|
||||||
|
|
||||||
# The following adds the Cupertino Icons font to your application.
|
# The following adds the Cupertino Icons font to your application.
|
||||||
# Use with the CupertinoIcons class for iOS style icons.
|
# Use with the CupertinoIcons class for iOS style icons.
|
||||||
|
|
Loading…
Reference in New Issue