Merge branch 'main' into '8-datenbank-einbinden'

# Conflicts:
#   lib/main.dart
main
Julian Gegner 2023-02-25 18:00:30 +00:00
commit 9d08c15119
12 changed files with 286 additions and 21 deletions

View File

@ -1,11 +1,16 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:smoke_cess_app/pages/main_page.dart'; import 'package:smoke_cess_app/pages/main_page.dart';
import 'package:smoke_cess_app/service/database_service.dart'; import 'package:smoke_cess_app/service/database_service.dart';
import 'package:smoke_cess_app/service/notification_service.dart';
import 'package:timezone/data/latest.dart' as tz;
void main() async { void main() {
// to ensure all the widgets are initialized.
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
//init database //init database
DatabaseService.instance; DatabaseService.instance;
tz.initializeTimeZones();
NotificationService().initNotification();
runApp(const MyApp()); runApp(const MyApp());
} }

View File

@ -1,6 +1,7 @@
import 'dart:async'; import 'dart:async';
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/widgets/popup_for_start_and_stop.dart';
class IntervalTimerPage extends StatefulWidget { class IntervalTimerPage extends StatefulWidget {
const IntervalTimerPage({Key? key}) : super(key: key); const IntervalTimerPage({Key? key}) : super(key: key);
@ -38,11 +39,18 @@ class _IntervalTimerPageState extends State<IntervalTimerPage> {
super.dispose(); super.dispose();
} }
void _startTimer() { void _startTimer() async {
await showDialog(
context: context,
builder: (BuildContext context) {
return const TimerStartStopPopup(
title: 'Motivation vor dem Training',
);
},
);
_isPaused = false; _isPaused = false;
() async {
await AudioPlayer().play(UrlSource('assets/go.mp3')); await AudioPlayer().play(UrlSource('assets/go.mp3'));
}();
_timer = Timer.periodic(const Duration(seconds: 1), (_) => _tick()); _timer = Timer.periodic(const Duration(seconds: 1), (_) => _tick());
Future.delayed(const Duration(seconds: 1)).then((value) { Future.delayed(const Duration(seconds: 1)).then((value) {
_playWarmUpMusic(); _playWarmUpMusic();
@ -51,9 +59,9 @@ class _IntervalTimerPageState extends State<IntervalTimerPage> {
void _resetTimer() { void _resetTimer() {
() async { () async {
await coolDownPlayer.dispose(); await coolDownPlayer.stop();
await warmUpPlayer.dispose(); await warmUpPlayer.stop();
await workoutPlayer.dispose(); await workoutPlayer.stop();
}(); }();
_isPaused = true; _isPaused = true;
_timer?.cancel(); _timer?.cancel();
@ -61,6 +69,14 @@ class _IntervalTimerPageState extends State<IntervalTimerPage> {
_currentDuration = _warmupDuration; _currentDuration = _warmupDuration;
_totalDuration = const Duration(minutes: 35); _totalDuration = const Duration(minutes: 35);
setState(() {}); setState(() {});
showDialog(
context: context,
builder: (BuildContext context) {
return const TimerStartStopPopup(
title: 'Motivation nach dem Training',
);
},
);
} }
Future<void> _playWarmUpMusic() async { Future<void> _playWarmUpMusic() async {
@ -69,8 +85,9 @@ class _IntervalTimerPageState extends State<IntervalTimerPage> {
} }
Future<void> _playWorkoutMusic() async { Future<void> _playWorkoutMusic() async {
await warmUpPlayer.dispose(); await warmUpPlayer.stop();
Future.delayed(const Duration(microseconds: 600)).then((value) async { Future.delayed(const Duration(microseconds: 600)).then((value) async {
await workoutPlayer.setReleaseMode(ReleaseMode.loop);
await workoutPlayer.play(UrlSource('assets/workout.mp3')); await workoutPlayer.play(UrlSource('assets/workout.mp3'));
}); });
} }
@ -105,7 +122,8 @@ class _IntervalTimerPageState extends State<IntervalTimerPage> {
_currentBlock++; _currentBlock++;
_currentDuration = _cooldownDuration; _currentDuration = _cooldownDuration;
() async { () async {
await workoutPlayer.dispose(); await workoutPlayer.stop();
await coolDownPlayer.setReleaseMode(ReleaseMode.loop);
await coolDownPlayer.play(UrlSource('assets/cool_down.mp3')); await coolDownPlayer.play(UrlSource('assets/cool_down.mp3'));
}(); }();
} else { } else {

View File

@ -5,6 +5,7 @@ import 'package:smoke_cess_app/models/settings.dart';
import 'package:smoke_cess_app/service/database_service.dart'; import 'package:smoke_cess_app/service/database_service.dart';
import 'package:smoke_cess_app/service/json_service.dart'; import 'package:smoke_cess_app/service/json_service.dart';
import 'package:smoke_cess_app/service/settings_service.dart'; import 'package:smoke_cess_app/service/settings_service.dart';
import 'package:smoke_cess_app/service/notification_service.dart';
import '../models/sleep.dart'; import '../models/sleep.dart';
import '../widgets/missing_config_popup.dart'; import '../widgets/missing_config_popup.dart';
@ -70,6 +71,7 @@ class ScannerPageState extends State<ScannerPage> {
textStyle: const TextStyle(fontSize: 20)), textStyle: const TextStyle(fontSize: 20)),
onPressed: () { onPressed: () {
loadSettingsFromLocalJSON(); loadSettingsFromLocalJSON();
NotificationService().setAllNotifications();
}, },
child: const Text('Read JSON'), child: const Text('Read JSON'),
), ),

View File

@ -0,0 +1,57 @@
import 'package:smoke_cess_app/service/settings_service.dart';
import 'package:timezone/timezone.dart';
const int trainingTime = 40;
const weekDays = {
"Montag": 1,
"Dienstag": 2,
"Mittwoch": 3,
"Donnerstag": 4,
"Freitag": 5,
"Samstag": 6,
"Sonntag": 7,
};
Future<List<TZDateTime>> getDatesforAll() async {
List<TZDateTime> allDates = [];
List<TZDateTime> moodDates = await getDatesforMood();
List<TZDateTime> sleepDates = await getDatesforSleep();
allDates.addAll(moodDates);
allDates.addAll(sleepDates);
return allDates;
}
Future<List<TZDateTime>> getDatesforMood() async {
final List<String>? selectedDays = await getMoodQueryDaysCategories();
final int? selectedHours = await getMoodQueryHours();
final int? selectedMinutes = await getMoodQueryMinutes();
return createTZDateTimes(selectedDays, selectedHours, selectedMinutes);
}
Future<List<TZDateTime>> getDatesforSleep() async {
final List<String>? selectedDays = await getSleepQueryDaysCategories();
final int? selectedHours = await getSleepQueryHours();
final int? selectedMinutes = await getSleepQueryMinutes();
return createTZDateTimes(selectedDays, selectedHours, selectedMinutes);
}
List<TZDateTime> createTZDateTimes(
List<String>? selectedDays, int? selectedHours, int? selectedMinutes) {
List<TZDateTime> tzDateTimes = [];
if (selectedDays == null ||
selectedHours == null ||
selectedMinutes == null) {
return tzDateTimes;
}
final Iterable<int?> selectedDaysInt =
selectedDays.map((day) => weekDays[day]);
for (int i = 0; i < trainingTime; i++) {
final DateTime date = DateTime.now().add(Duration(days: i));
if (selectedDaysInt.contains(date.weekday)) {
tzDateTimes.add(TZDateTime.local(date.year, date.month, date.day,
selectedHours, selectedMinutes, 0, 0, 0));
}
}
return tzDateTimes;
}

View File

@ -0,0 +1,81 @@
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:smoke_cess_app/service/date_service.dart';
import 'package:timezone/timezone.dart';
class NotificationService {
static final NotificationService _notificationService =
NotificationService._internal();
factory NotificationService() {
return _notificationService;
}
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
NotificationService._internal();
Future<void> initNotification() async {
// Android initialization
const AndroidInitializationSettings initializationSettingsAndroid =
AndroidInitializationSettings('@mipmap/ic_launcher');
// ios initialization
const IOSInitializationSettings initializationSettingsIOS =
IOSInitializationSettings(
requestAlertPermission: false,
requestBadgePermission: false,
requestSoundPermission: false,
);
const InitializationSettings initializationSettings =
InitializationSettings(
android: initializationSettingsAndroid,
iOS: initializationSettingsIOS);
// the initialization settings are initialized after they are setted
await flutterLocalNotificationsPlugin.initialize(initializationSettings);
}
Future<void> setAllNotifications() async {
List<TZDateTime> moodDates = await getDatesforMood();
List<TZDateTime> sleepDates = await getDatesforSleep();
for (var date in moodDates) {
setNotification(1, "Mood", "Evaluate your mood", date);
print("mood");
}
for (var date in sleepDates) {
setNotification(1, "Sleep", "Evaluate your sleep", date);
print("sleep");
}
}
Future<void> setNotification(
int id, String title, String body, TZDateTime tzDateTime) async {
await flutterLocalNotificationsPlugin.zonedSchedule(
id,
title,
body,
tzDateTime, //schedule the notification to show after 2 seconds.
const NotificationDetails(
// Android details
android: AndroidNotificationDetails('main_channel', 'Main Channel',
channelDescription: "ashwin",
importance: Importance.max,
priority: Priority.max),
// iOS details
iOS: IOSNotificationDetails(
sound: 'default.wav',
presentAlert: true,
presentBadge: true,
presentSound: true,
),
),
// Type of time interpretation
uiLocalNotificationDateInterpretation:
UILocalNotificationDateInterpretation.absoluteTime,
androidAllowWhileIdle:
true, // To show notification even when the app is closed
);
}
}

View File

@ -18,18 +18,18 @@ class ElevatedCard extends StatelessWidget {
borderRadius: BorderRadius.circular(16.0), borderRadius: BorderRadius.circular(16.0),
), ),
child: Padding( child: Padding(
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(14.0),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
title, title,
style: TextStyle( style: const TextStyle(
fontSize: 18.0, fontSize: 16.0,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
), ),
SizedBox(height: 8.0), const SizedBox(height: 8.0),
child, child,
], ],
), ),

View File

@ -16,7 +16,7 @@ class MoodForm extends StatefulWidget {
class _MoodFormState extends State<MoodForm> { class _MoodFormState extends State<MoodForm> {
final GlobalKey<FormState> _moodFormKey = GlobalKey<FormState>(); final GlobalKey<FormState> _moodFormKey = GlobalKey<FormState>();
MySlider slider = const MySlider(''); MySlider slider = const MySlider();
String _textInput = ""; String _textInput = "";
void submitForm() { void submitForm() {

View File

@ -0,0 +1,43 @@
import 'package:flutter/material.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';
class TimerStartStopPopup extends StatefulWidget {
final String title;
const TimerStartStopPopup({Key? key, required this.title}) : super(key: key);
@override
TimerStartStopPopupState createState() => TimerStartStopPopupState();
}
class TimerStartStopPopupState extends State<TimerStartStopPopup> {
final MySlider slider = const MySlider();
void submitForm(BuildContext context) {
Navigator.of(context).pop();
}
void onFormFieldSave(String? newValue) => newValue!;
@override
Widget build(BuildContext context) {
return AlertDialog(
title: Text(widget.title),
content: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Padding(
padding: EdgeInsets.only(top: 8),
child: MySlider(labelText: 'Motivation'),
),
const SizedBox(height: 16),
MyTextFormField('Beschreibe deinen Motivation', onFormFieldSave),
SubmitFormButton(() => submitForm(context)),
],
),
);
}
}

View File

@ -16,7 +16,7 @@ class SleepForm extends StatefulWidget {
class _SleepFormState extends State<SleepForm> { class _SleepFormState extends State<SleepForm> {
final GlobalKey<FormState> _sleepFormKey = GlobalKey<FormState>(); final GlobalKey<FormState> _sleepFormKey = GlobalKey<FormState>();
MySlider slider = const MySlider(''); MySlider slider = const MySlider();
String _textInput = ""; String _textInput = "";
TimePicker sleepTimePicker = TimePicker( TimePicker sleepTimePicker = TimePicker(
const TimeOfDay(hour: 22, minute: 00), const TimeOfDay(hour: 22, minute: 00),

View File

@ -3,8 +3,10 @@ import 'package:flutter/material.dart';
double _currentSliderValue = 50; double _currentSliderValue = 50;
class MySlider extends StatefulWidget { class MySlider extends StatefulWidget {
final String _title; final String _labelText;
const MySlider(this._title, {Key? key}) : super(key: key); const MySlider({Key? key, String labelText = 'Stimmung'})
: _labelText = labelText,
super(key: key);
@override @override
State<StatefulWidget> createState() => SliderState(); State<StatefulWidget> createState() => SliderState();
@ -30,7 +32,6 @@ class SliderState extends State<MySlider> {
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Text(widget._title),
SizedBox(height: 16), SizedBox(height: 16),
Row( Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
@ -58,7 +59,7 @@ class SliderState extends State<MySlider> {
controller: _textFieldController, controller: _textFieldController,
keyboardType: TextInputType.number, keyboardType: TextInputType.number,
decoration: InputDecoration( decoration: InputDecoration(
labelText: 'Stimmung', labelText: widget._labelText,
errorText: _errorText, errorText: _errorText,
), ),
onChanged: (text) { onChanged: (text) {

View File

@ -1,6 +1,13 @@
# Generated by pub # Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile # See https://dart.dev/tools/pub/glossary#lockfile
packages: packages:
args:
dependency: transitive
description:
name: args
url: "https://pub.dartlang.org"
source: hosted
version: "2.4.0"
async: async:
dependency: transitive dependency: transitive
description: description:
@ -99,6 +106,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.5" version: "1.0.5"
dbus:
dependency: transitive
description:
name: dbus
url: "https://pub.dartlang.org"
source: hosted
version: "0.7.8"
fake_async: fake_async:
dependency: transitive dependency: transitive
description: description:
@ -132,6 +146,27 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.0.1" version: "2.0.1"
flutter_local_notifications:
dependency: "direct main"
description:
name: flutter_local_notifications
url: "https://pub.dartlang.org"
source: hosted
version: "9.9.1"
flutter_local_notifications_linux:
dependency: transitive
description:
name: flutter_local_notifications_linux
url: "https://pub.dartlang.org"
source: hosted
version: "0.5.1"
flutter_local_notifications_platform_interface:
dependency: transitive
description:
name: flutter_local_notifications_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "5.0.0"
flutter_test: flutter_test:
dependency: "direct dev" dependency: "direct dev"
description: flutter description: flutter
@ -247,6 +282,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.1.3" version: "2.1.3"
petitparser:
dependency: transitive
description:
name: petitparser
url: "https://pub.dartlang.org"
source: hosted
version: "5.1.0"
platform: platform:
dependency: transitive dependency: transitive
description: description:
@ -385,6 +427,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.4.12" version: "0.4.12"
timezone:
dependency: "direct main"
description:
name: timezone
url: "https://pub.dartlang.org"
source: hosted
version: "0.8.0"
typed_data: typed_data:
dependency: transitive dependency: transitive
description: description:
@ -419,7 +468,14 @@ packages:
name: xdg_directories name: xdg_directories
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.0" version: "0.2.0+3"
xml:
dependency: transitive
description:
name: xml
url: "https://pub.dartlang.org"
source: hosted
version: "6.1.0"
sdks: sdks:
dart: ">=2.18.2 <3.0.0" dart: ">=2.18.2 <3.0.0"
flutter: ">=3.3.0" flutter: ">=3.3.0"

View File

@ -38,6 +38,8 @@ dependencies:
# 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.
cupertino_icons: ^1.0.2 cupertino_icons: ^1.0.2
flutter_local_notifications: ^9.3.1
timezone: ^0.8.0
shared_preferences: ^2.0.17 shared_preferences: ^2.0.17
audioplayers: ^3.0.1 audioplayers: ^3.0.1
mobile_scanner: ^3.0.0 mobile_scanner: ^3.0.0