Merge branch 'main' into testing_branch
|
@ -31,6 +31,7 @@ migrate_working_dir/
|
||||||
.pub-cache/
|
.pub-cache/
|
||||||
.pub/
|
.pub/
|
||||||
/build/
|
/build/
|
||||||
|
pubspec.lock
|
||||||
|
|
||||||
# Symbolication related
|
# Symbolication related
|
||||||
app.*.symbols
|
app.*.symbols
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
image: cirrusci/flutter:latest
|
image: cirrusci/flutter:3.7.5
|
||||||
|
|
||||||
stages:
|
stages:
|
||||||
- analyze
|
- analyze
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="com.example.smoke_cess_app">
|
package="com.example.smoke_cess_app">
|
||||||
|
<!-- Required to fetch data from the internet. -->
|
||||||
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<application
|
<application
|
||||||
android:label="smoke_cess_app"
|
android:label="ZI SmokeFree"
|
||||||
android:name="${applicationName}"
|
android:name="${applicationName}"
|
||||||
android:icon="@mipmap/ic_launcher">
|
android:icon="@mipmap/launcher_icon">
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
|
|
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 4.8 KiB |
After Width: | Height: | Size: 7.2 KiB |
After Width: | Height: | Size: 9.8 KiB |
After Width: | Height: | Size: 36 KiB |
|
@ -7,7 +7,7 @@
|
||||||
},
|
},
|
||||||
"relapse_categories": ["App stresst mich", "langeweile", "lunge braucht es"],
|
"relapse_categories": ["App stresst mich", "langeweile", "lunge braucht es"],
|
||||||
"mood_query": {
|
"mood_query": {
|
||||||
"days": ["Montag", "Freitag"],
|
"days": ["Montag", "Donnerstag"],
|
||||||
"hours": 10,
|
"hours": 10,
|
||||||
"minutes": 30
|
"minutes": 30
|
||||||
},
|
},
|
||||||
|
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 87 KiB |
Before Width: | Height: | Size: 564 B After Width: | Height: | Size: 796 B |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 4.3 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 4.0 KiB |
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 6.1 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 5.1 KiB |
After Width: | Height: | Size: 2.7 KiB |
After Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 6.1 KiB |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 9.2 KiB |
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 7.2 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 7.7 KiB |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 8.4 KiB |
|
@ -7,7 +7,7 @@
|
||||||
<key>CFBundleDevelopmentRegion</key>
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||||
<key>CFBundleDisplayName</key>
|
<key>CFBundleDisplayName</key>
|
||||||
<string>Smoke Cess App</string>
|
<string>ZI SmokeFree</string>
|
||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
<string>$(EXECUTABLE_NAME)</string>
|
<string>$(EXECUTABLE_NAME)</string>
|
||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
|
@ -15,7 +15,7 @@
|
||||||
<key>CFBundleInfoDictionaryVersion</key>
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
<string>6.0</string>
|
<string>6.0</string>
|
||||||
<key>CFBundleName</key>
|
<key>CFBundleName</key>
|
||||||
<string>smoke_cess_app</string>
|
<string>ZI SmokeFree</string>
|
||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
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/pages/main_page.dart';
|
import 'package:smoke_cess_app/pages/main_page.dart';
|
||||||
|
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() {
|
||||||
|
@ -23,11 +25,21 @@ class MyApp extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MaterialApp(
|
return MultiProvider(
|
||||||
|
providers: [
|
||||||
|
ChangeNotifierProvider(create: (context) => SettingsProvider()),
|
||||||
|
ChangeNotifierProxyProvider<SettingsProvider, TasksProvider>(
|
||||||
|
create: (context) => TasksProvider(null),
|
||||||
|
update: (context, value, TasksProvider? previous) =>
|
||||||
|
TasksProvider(value),
|
||||||
|
),
|
||||||
|
ChangeNotifierProvider(
|
||||||
|
create: (context) => PageProvider(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
child: const MaterialApp(
|
||||||
title: _title,
|
title: _title,
|
||||||
home: ChangeNotifierProvider(
|
home: MyHomePage(),
|
||||||
create: (context) => SettingsProvider(),
|
|
||||||
child: const MyHomePage(),
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
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/relapse.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/services/database_service.dart';
|
import 'package:smoke_cess_app/services/database_service.dart';
|
||||||
|
// ignore: depend_on_referenced_packages
|
||||||
import 'package:sqflite_common/sqlite_api.dart';
|
import 'package:sqflite_common/sqlite_api.dart';
|
||||||
|
|
||||||
class DatabaseMock implements DatabaseService {
|
class DatabaseMock implements DatabaseService {
|
||||||
|
@ -15,7 +16,7 @@ class DatabaseMock implements DatabaseService {
|
||||||
final List<Mood> _moodRecords = [];
|
final List<Mood> _moodRecords = [];
|
||||||
final List<Sleep> _sleepRecords = [];
|
final List<Sleep> _sleepRecords = [];
|
||||||
final List<Relapse> _relapseRecords = [];
|
final List<Relapse> _relapseRecords = [];
|
||||||
final List<DatabaseRecord> _workoutRecords = [];
|
final List<Workout> _workoutRecords = [];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<int> addMood(Mood mood) {
|
Future<int> addMood(Mood mood) {
|
||||||
|
@ -29,6 +30,12 @@ class DatabaseMock implements DatabaseService {
|
||||||
return Future.value(1);
|
return Future.value(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<int> addWorkout(Workout workout) {
|
||||||
|
_workoutRecords.add(workout);
|
||||||
|
return Future.value(1);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<int> addRelapse(Relapse relapse) {
|
Future<int> addRelapse(Relapse relapse) {
|
||||||
_relapseRecords.add(relapse);
|
_relapseRecords.add(relapse);
|
||||||
|
@ -36,7 +43,6 @@ class DatabaseMock implements DatabaseService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
// TODO: implement database
|
|
||||||
Future<Database> get database => DatabaseService.instance.database;
|
Future<Database> get database => DatabaseService.instance.database;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -53,4 +59,9 @@ class DatabaseMock implements DatabaseService {
|
||||||
Future<List<Relapse>> getRelapseRecords() {
|
Future<List<Relapse>> getRelapseRecords() {
|
||||||
return Future.value(_relapseRecords);
|
return Future.value(_relapseRecords);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<List<Workout>> getWorkoutRecords() {
|
||||||
|
return Future.value(_workoutRecords);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -7,6 +7,9 @@ class Mood implements DatabaseRecord {
|
||||||
|
|
||||||
Mood(this._moodValue, this._comment, this._date);
|
Mood(this._moodValue, this._comment, this._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) {
|
||||||
DateTime date = DateTime.parse(map['date']);
|
DateTime date = DateTime.parse(map['date']);
|
||||||
|
|
|
@ -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']);
|
||||||
|
|
|
@ -11,6 +11,9 @@ class Sleep implements DatabaseRecord {
|
||||||
Sleep(this._sleepQualityValue, this._comment, this._date, this._sleptAt,
|
Sleep(this._sleepQualityValue, this._comment, this._date, this._sleptAt,
|
||||||
this._wokeUpAt);
|
this._wokeUpAt);
|
||||||
|
|
||||||
|
DateTime get date => _date;
|
||||||
|
int get sleepQualitiyValue => _sleepQualityValue;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
factory Sleep.fromDatabase(Map<String, dynamic> map) {
|
factory Sleep.fromDatabase(Map<String, dynamic> map) {
|
||||||
DateTime date = DateTime.parse(map['date']);
|
DateTime date = DateTime.parse(map['date']);
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
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);
|
||||||
|
|
||||||
|
DateTime get date => _workoutDate;
|
||||||
|
int get motivationBefore => _motivationBefore;
|
||||||
|
int get motivationAfter => _motivationAfter;
|
||||||
|
|
||||||
|
@override
|
||||||
|
factory Workout.fromDatabase(Map<String, dynamic> map) {
|
||||||
|
return Workout(map['motivationBefore'], map['motivationAfter'],
|
||||||
|
DateTime.parse(map['workoutDate']));
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
factory Workout.fromMap(Map<String, dynamic> map) {
|
||||||
|
return Workout(
|
||||||
|
map['motivationBefore'], map['motivationAfter'], map['workoutDate']);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toCSV() =>
|
||||||
|
"${_workoutDate.toIso8601String()}, $_motivationBefore, $_motivationAfter";
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> toMap() {
|
||||||
|
return {
|
||||||
|
'motivationBefore': _motivationBefore,
|
||||||
|
'motivationAfter': _motivationAfter,
|
||||||
|
'workoutDate': _workoutDate.toIso8601String(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,225 +1,16 @@
|
||||||
import 'dart:async';
|
|
||||||
import 'package:audioplayers/audioplayers.dart';
|
|
||||||
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/widgets/popup_for_start_and_stop.dart';
|
import 'package:smoke_cess_app/widgets/workout_view.dart';
|
||||||
import 'package:smoke_cess_app/widgets/timer_widget.dart';
|
|
||||||
|
|
||||||
import '../providers/input_provider.dart';
|
import '../widgets/view_form_page.dart';
|
||||||
|
|
||||||
class IntervalTimerPage extends StatefulWidget {
|
class IntervalTimerPage extends StatelessWidget {
|
||||||
const IntervalTimerPage({Key? key}) : super(key: key);
|
const IntervalTimerPage({super.key});
|
||||||
|
|
||||||
@override
|
|
||||||
_IntervalTimerPageState createState() => _IntervalTimerPageState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _IntervalTimerPageState extends State<IntervalTimerPage> {
|
|
||||||
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<void> _playWarmUpMusic() async {
|
|
||||||
Source source = AssetSource('warmUp.mp3');
|
|
||||||
await warmUpPlayer.setReleaseMode(ReleaseMode.loop);
|
|
||||||
await warmUpPlayer.play(source);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _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<void> _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));
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ChangeNotifierProvider(
|
return ViewFormPage(
|
||||||
create: (context) => TimerProvider(),
|
form: WorkoutForm(), view: const WorkoutView(), page: Pages.timer);
|
||||||
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();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
// ),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
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/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';
|
||||||
|
|
||||||
|
import '../widgets/todo_icon.dart';
|
||||||
|
|
||||||
class MyHomePage extends StatefulWidget {
|
class MyHomePage extends StatefulWidget {
|
||||||
const MyHomePage({super.key});
|
const MyHomePage({super.key});
|
||||||
|
|
||||||
|
@ -16,10 +20,14 @@ 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;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
AwesomeDialog(
|
||||||
context: context,
|
context: context,
|
||||||
dialogType: DialogType.info,
|
dialogType: DialogType.info,
|
||||||
title: 'Fehlende Konfiguration',
|
title: 'Fehlende Konfiguration',
|
||||||
|
@ -31,23 +39,24 @@ class MyHomePageState extends State<MyHomePage> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var settingsModel = context.watch<SettingsProvider>();
|
var settingsModel = context.watch<SettingsProvider>();
|
||||||
var group = settingsModel.settings?.group;
|
var tasksModel = context.watch<TasksProvider>();
|
||||||
_isConfigured = settingsModel.initialized;
|
_isConfigured = settingsModel.initialized;
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(
|
title: Text(
|
||||||
'${pages.keys.elementAt(_selectedIndex)} ${_isConfigured ? "Gruppe $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,
|
||||||
destinations: pages.keys.map((key) {
|
destinations: pages.keys.map((key) {
|
||||||
return NavigationDestination(
|
return NavigationDestination(
|
||||||
icon: pages[key]!['icon'] ??
|
icon: tasksModel.tasks[key] ?? false
|
||||||
const Icon(Icons.disabled_by_default),
|
? MyToDoIcon(pages[key]?['icon'])
|
||||||
label: key);
|
: pages[key]!['icon'],
|
||||||
|
label: pages[key]?['title']);
|
||||||
}).toList()),
|
}).toList()),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,31 +1,18 @@
|
||||||
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/models/mood.dart';
|
import 'package:smoke_cess_app/services/export_service.dart';
|
||||||
import 'package:smoke_cess_app/models/relapse.dart';
|
|
||||||
import 'package:smoke_cess_app/services/settings_service.dart';
|
import 'package:smoke_cess_app/services/settings_service.dart';
|
||||||
import 'package:smoke_cess_app/services/notification_service.dart';
|
import 'package:smoke_cess_app/services/notification_service.dart';
|
||||||
import 'package:smoke_cess_app/widgets/scanner.dart';
|
import 'package:smoke_cess_app/widgets/scanner.dart';
|
||||||
import '../models/sleep.dart';
|
|
||||||
import '../providers/settings_provider.dart';
|
import '../providers/settings_provider.dart';
|
||||||
import '../globals.dart' as globals;
|
|
||||||
|
|
||||||
class ScannerPage extends StatelessWidget {
|
class ScannerPage extends StatelessWidget {
|
||||||
const ScannerPage({super.key});
|
const ScannerPage({super.key});
|
||||||
|
|
||||||
void export() async {
|
void export() async {
|
||||||
List<Mood> moods = await globals.databaseService.getMoodRecords();
|
ExportService exportService = ExportService();
|
||||||
List<Sleep> sleeps = await globals.databaseService.getSleepRecords();
|
exportService.exportData();
|
||||||
List<Relapse> 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());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void loadJSON(BuildContext context) async {
|
void loadJSON(BuildContext context) async {
|
||||||
|
@ -33,6 +20,7 @@ class ScannerPage extends StatelessWidget {
|
||||||
await loadSettingsFromLocalJSON();
|
await loadSettingsFromLocalJSON();
|
||||||
settingsModel.initSettings();
|
settingsModel.initSettings();
|
||||||
NotificationService().setAllNotifications();
|
NotificationService().setAllNotifications();
|
||||||
|
if (context.mounted) {
|
||||||
AwesomeDialog(
|
AwesomeDialog(
|
||||||
context: context,
|
context: context,
|
||||||
dialogType: DialogType.success,
|
dialogType: DialogType.success,
|
||||||
|
@ -40,6 +28,7 @@ class ScannerPage extends StatelessWidget {
|
||||||
desc: 'Die Einstellung wurden erfolgreich gespeichert',
|
desc: 'Die Einstellung wurden erfolgreich gespeichert',
|
||||||
).show();
|
).show();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
|
|
@ -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(),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:audioplayers/audioplayers.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
|
||||||
|
class AudioProvider extends ChangeNotifier {
|
||||||
|
final AudioPlayer _audioPlayer = AudioPlayer();
|
||||||
|
bool _isMuted = false;
|
||||||
|
final Source _finishedSoundSource = AssetSource('finish.mp3');
|
||||||
|
final Source _beepSoundSource = AssetSource('beep.mp3');
|
||||||
|
StreamSubscription? _onCompleteSubscription;
|
||||||
|
|
||||||
|
bool get isMuted => _isMuted;
|
||||||
|
|
||||||
|
void stop() => _resetPlayer();
|
||||||
|
|
||||||
|
void playFinishSound() {
|
||||||
|
_resetPlayer();
|
||||||
|
_audioPlayer.play(_finishedSoundSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mutePlayer() {
|
||||||
|
_isMuted = true;
|
||||||
|
_audioPlayer.setVolume(0);
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
void unMutePlayer() {
|
||||||
|
_isMuted = false;
|
||||||
|
_audioPlayer.setVolume(1);
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
//resets player position and delete listening subscription
|
||||||
|
void _resetPlayer() {
|
||||||
|
_audioPlayer.stop();
|
||||||
|
_onCompleteSubscription?.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
void playSourceAfterBeep(AssetSource source) {
|
||||||
|
_resetPlayer();
|
||||||
|
_audioPlayer.play(_beepSoundSource);
|
||||||
|
_onCompleteSubscription = _audioPlayer.onPlayerComplete.listen((event) {
|
||||||
|
_audioPlayer.play(source);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,34 +4,33 @@ 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 '../globals.dart' as globals;
|
import '../globals.dart' as globals;
|
||||||
|
|
||||||
|
enum SleepTimes {
|
||||||
|
wokeUpAt,
|
||||||
|
sleptAt,
|
||||||
|
}
|
||||||
|
|
||||||
class InputProvider extends ChangeNotifier {
|
class InputProvider extends ChangeNotifier {
|
||||||
double _sliderValue = 50;
|
double _sliderValue = 50;
|
||||||
final TextEditingController _textController = TextEditingController(text: '');
|
final TextEditingController _textController = TextEditingController(text: '');
|
||||||
final Map<String, TimeOfDay> _times = {
|
final Map<SleepTimes, TimeOfDay> _times = {
|
||||||
'wokeUpAt': const TimeOfDay(hour: 8, minute: 0),
|
SleepTimes.wokeUpAt: const TimeOfDay(hour: 8, minute: 0),
|
||||||
'sleptAt': const TimeOfDay(hour: 22, minute: 0),
|
SleepTimes.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) {
|
TimeOfDay getTimeEntry(SleepTimes key) {
|
||||||
_relapseCategory = newValue;
|
|
||||||
notifyListeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
TimeOfDay getTimeEntry(String key) {
|
|
||||||
return _times[key] ?? const TimeOfDay(hour: 12, minute: 0);
|
return _times[key] ?? const TimeOfDay(hour: 12, minute: 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setTime(String key, TimeOfDay time) {
|
void setTime(SleepTimes key, TimeOfDay time) {
|
||||||
_times[key] = time;
|
_times[key] = time;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
@ -39,8 +38,8 @@ class InputProvider extends ChangeNotifier {
|
||||||
void _resetFields() {
|
void _resetFields() {
|
||||||
_sliderValue = 50;
|
_sliderValue = 50;
|
||||||
_textController.text = '';
|
_textController.text = '';
|
||||||
setTime('wokeUpAt', const TimeOfDay(hour: 8, minute: 0));
|
setTime(SleepTimes.wokeUpAt, const TimeOfDay(hour: 8, minute: 0));
|
||||||
setTime('sleptAt', const TimeOfDay(hour: 22, minute: 0));
|
setTime(SleepTimes.sleptAt, const TimeOfDay(hour: 22, minute: 0));
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,12 +52,12 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<int> saveSleep(String wokeUpKey, String sleptKey) {
|
Future<int> saveSleep(SleepTimes wokeUpKey, SleepTimes sleptKey) {
|
||||||
Sleep sleep = Sleep(_sliderValue.toInt(), _textController.text,
|
Sleep sleep = Sleep(_sliderValue.toInt(), _textController.text,
|
||||||
DateTime.now(), getTimeEntry(sleptKey), getTimeEntry(wokeUpKey));
|
DateTime.now(), getTimeEntry(sleptKey), getTimeEntry(wokeUpKey));
|
||||||
_resetFields();
|
_resetFields();
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class PageProvider extends ChangeNotifier {
|
||||||
|
bool showForm = false;
|
||||||
|
|
||||||
|
void swap() {
|
||||||
|
showForm = !showForm;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
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/workout.dart';
|
||||||
|
import 'package:smoke_cess_app/providers/settings_provider.dart';
|
||||||
|
import 'package:smoke_cess_app/services/date_service.dart';
|
||||||
|
import 'package:smoke_cess_app/services/pages_service.dart';
|
||||||
|
import 'package:timezone/browser.dart';
|
||||||
|
import '../globals.dart' as globals;
|
||||||
|
import '../models/mood.dart';
|
||||||
|
|
||||||
|
class TasksProvider extends ChangeNotifier {
|
||||||
|
Map<Pages, bool> tasks = {
|
||||||
|
Pages.mood: true,
|
||||||
|
Pages.sleep: true,
|
||||||
|
Pages.timer: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
List<Mood> moodHistory = [];
|
||||||
|
List<Sleep> sleepHistory = [];
|
||||||
|
List<Workout> workoutHistory = [];
|
||||||
|
List<Relapse> relapseHistory = [];
|
||||||
|
|
||||||
|
TasksProvider(SettingsProvider? settingsProvider) {
|
||||||
|
initTasks();
|
||||||
|
initHistories();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setTaskDone(Pages taskName) {
|
||||||
|
tasks[taskName] = false;
|
||||||
|
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 {
|
||||||
|
DateTime now = DateTime.now();
|
||||||
|
TZDateTime? moodToday = await getTodayMood();
|
||||||
|
if (moodToday != null) {
|
||||||
|
List<Mood> moodList = await globals.databaseService.getMoodRecords();
|
||||||
|
if (moodList.isNotEmpty) {
|
||||||
|
Mood mood = moodList.last;
|
||||||
|
tasks[Pages.mood] =
|
||||||
|
!isSameDay(moodToday, mood.date) && moodToday.isBefore(now);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tasks[Pages.mood] = false;
|
||||||
|
}
|
||||||
|
TZDateTime? sleepToday = await getTodaySleep();
|
||||||
|
if (sleepToday != null) {
|
||||||
|
List<Sleep> sleepList = await globals.databaseService.getSleepRecords();
|
||||||
|
if (sleepList.isNotEmpty) {
|
||||||
|
Sleep sleep = sleepList.last;
|
||||||
|
tasks[Pages.sleep] =
|
||||||
|
!isSameDay(sleepToday, sleep.date) && sleepToday.isBefore(now);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tasks[Pages.sleep] = false;
|
||||||
|
}
|
||||||
|
List<Workout> workoutList =
|
||||||
|
await globals.databaseService.getWorkoutRecords();
|
||||||
|
if (workoutList.isNotEmpty) {
|
||||||
|
Workout mood = workoutList.last;
|
||||||
|
tasks[Pages.timer] = !isSameDay(DateTime.now(), mood.date);
|
||||||
|
}
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,7 +9,6 @@ class TimerProvider extends ChangeNotifier {
|
||||||
|
|
||||||
void startTimer(Duration duration) {
|
void startTimer(Duration duration) {
|
||||||
started = true;
|
started = true;
|
||||||
print('starting timer');
|
|
||||||
_timer = Timer.periodic(const Duration(seconds: 1), ((timer) {
|
_timer = Timer.periodic(const Duration(seconds: 1), ((timer) {
|
||||||
if (timer.tick >= duration.inSeconds) {
|
if (timer.tick >= duration.inSeconds) {
|
||||||
timer.cancel();
|
timer.cancel();
|
||||||
|
@ -19,5 +18,17 @@ class TimerProvider extends ChangeNotifier {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
void stopTimer() => _timer?.cancel();
|
void stopTimer() {
|
||||||
|
started = false;
|
||||||
|
_timer?.cancel();
|
||||||
|
_timer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
started = false;
|
||||||
|
_timer?.cancel();
|
||||||
|
_timer = null;
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,125 @@
|
||||||
|
import 'package:audioplayers/audioplayers.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:smoke_cess_app/models/workout.dart';
|
||||||
|
import 'package:smoke_cess_app/providers/audio_provider.dart';
|
||||||
|
import 'package:smoke_cess_app/providers/timer_provider.dart';
|
||||||
|
import '../globals.dart' as globals;
|
||||||
|
|
||||||
|
enum WorkoutPhases {
|
||||||
|
warmUp,
|
||||||
|
highIntensity,
|
||||||
|
lowIntensity,
|
||||||
|
coolDown,
|
||||||
|
}
|
||||||
|
|
||||||
|
class WorkoutProvider extends ChangeNotifier {
|
||||||
|
final TimerProvider timerProvider;
|
||||||
|
final AudioProvider audioProvider;
|
||||||
|
|
||||||
|
bool isWorkoutStarted = false;
|
||||||
|
bool isWorkoutComplete = false;
|
||||||
|
int motivationBefore = 50;
|
||||||
|
int motivationAfter = 50;
|
||||||
|
|
||||||
|
int _workoutPhaseIndex = 0;
|
||||||
|
final List<WorkoutPhases> _workoutPhases = [
|
||||||
|
WorkoutPhases.warmUp,
|
||||||
|
WorkoutPhases.highIntensity,
|
||||||
|
WorkoutPhases.lowIntensity,
|
||||||
|
WorkoutPhases.highIntensity,
|
||||||
|
WorkoutPhases.lowIntensity,
|
||||||
|
WorkoutPhases.highIntensity,
|
||||||
|
WorkoutPhases.lowIntensity,
|
||||||
|
WorkoutPhases.highIntensity,
|
||||||
|
WorkoutPhases.coolDown,
|
||||||
|
];
|
||||||
|
|
||||||
|
WorkoutProvider(this.timerProvider, this.audioProvider);
|
||||||
|
|
||||||
|
WorkoutPhases get currentPhase => _workoutPhases[_workoutPhaseIndex];
|
||||||
|
Duration get currentPhaseDuration =>
|
||||||
|
_workoutPhaseSettings[currentPhase]!['duration'];
|
||||||
|
bool get isPhaseComplete =>
|
||||||
|
timerProvider.elapsedSeconds - currentPhaseDuration.inSeconds == 0;
|
||||||
|
Color get currentPhaseColor => _workoutPhaseSettings[currentPhase]!['color'];
|
||||||
|
AssetSource get currentPhaseSource =>
|
||||||
|
_workoutPhaseSettings[currentPhase]!['source'];
|
||||||
|
String get currentPhaseTitle => _workoutPhaseSettings[currentPhase]!['title'];
|
||||||
|
|
||||||
|
void nextPhase() {
|
||||||
|
if (_workoutPhaseIndex < _workoutPhases.length - 1) {
|
||||||
|
_workoutPhaseIndex += 1;
|
||||||
|
audioProvider.playSourceAfterBeep(currentPhaseSource);
|
||||||
|
timerProvider.startTimer(currentPhaseDuration);
|
||||||
|
} else {
|
||||||
|
//workout completed
|
||||||
|
audioProvider.playFinishSound;
|
||||||
|
stopWorkout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void startWorkout() {
|
||||||
|
isWorkoutStarted = true;
|
||||||
|
isWorkoutComplete = false;
|
||||||
|
audioProvider.playSourceAfterBeep(currentPhaseSource);
|
||||||
|
timerProvider.startTimer(currentPhaseDuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
void stopWorkout() {
|
||||||
|
isWorkoutStarted = false;
|
||||||
|
isWorkoutComplete = true;
|
||||||
|
_cleanUp();
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
void interruptWorkout() {
|
||||||
|
isWorkoutStarted = false;
|
||||||
|
isWorkoutComplete = false;
|
||||||
|
_cleanUp();
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _cleanUp() {
|
||||||
|
audioProvider.stop();
|
||||||
|
timerProvider.stopTimer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void saveWorkout() {
|
||||||
|
Workout workout =
|
||||||
|
Workout(motivationBefore, motivationAfter, DateTime.now());
|
||||||
|
globals.databaseService.addWorkout(workout);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_cleanUp();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<WorkoutPhases, Map<String, dynamic>> _workoutPhaseSettings = {
|
||||||
|
WorkoutPhases.warmUp: {
|
||||||
|
'title': 'Warm Up',
|
||||||
|
'duration': const Duration(seconds: 5),
|
||||||
|
'source': AssetSource('warmUp.mp3'),
|
||||||
|
'color': Colors.green
|
||||||
|
},
|
||||||
|
WorkoutPhases.highIntensity: {
|
||||||
|
'title': 'High Intensity',
|
||||||
|
'duration': const Duration(seconds: 4),
|
||||||
|
'source': AssetSource('workout.mp3'),
|
||||||
|
'color': Colors.red
|
||||||
|
},
|
||||||
|
WorkoutPhases.lowIntensity: {
|
||||||
|
'title': 'Low Intensity',
|
||||||
|
'duration': const Duration(seconds: 3),
|
||||||
|
'source': AssetSource('workout.mp3'),
|
||||||
|
'color': Colors.orange
|
||||||
|
},
|
||||||
|
WorkoutPhases.coolDown: {
|
||||||
|
'title': 'Cool Down',
|
||||||
|
'duration': const Duration(seconds: 5),
|
||||||
|
'source': AssetSource('cool_down.mp3'),
|
||||||
|
'color': Colors.blue
|
||||||
|
}
|
||||||
|
};
|
|
@ -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:smoke_cess_app/models/relapse.dart';
|
import 'package:smoke_cess_app/models/relapse.dart';
|
||||||
import 'package:sqflite/sqflite.dart';
|
import 'package:sqflite/sqflite.dart';
|
||||||
// ignore: depend_on_referenced_packages
|
// ignore: depend_on_referenced_packages
|
||||||
|
@ -35,7 +36,6 @@ class DatabaseService {
|
||||||
await db.execute(_createWorkoutTable);
|
await db.execute(_createWorkoutTable);
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO use generic function?
|
|
||||||
Future<List<Mood>> getMoodRecords() async {
|
Future<List<Mood>> getMoodRecords() async {
|
||||||
Database db = await instance.database;
|
Database db = await instance.database;
|
||||||
var moodRecords = await db.query('mood');
|
var moodRecords = await db.query('mood');
|
||||||
|
@ -63,6 +63,15 @@ class DatabaseService {
|
||||||
return relapseList;
|
return relapseList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<List<Workout>> getWorkoutRecords() async {
|
||||||
|
Database db = await instance.database;
|
||||||
|
var workoutRecords = await db.query('workout');
|
||||||
|
List<Workout> workoutList = workoutRecords.isNotEmpty
|
||||||
|
? workoutRecords.map((e) => Workout.fromDatabase(e)).toList()
|
||||||
|
: [];
|
||||||
|
return workoutList;
|
||||||
|
}
|
||||||
|
|
||||||
Future<int> addMood(Mood mood) async {
|
Future<int> addMood(Mood mood) async {
|
||||||
Database db = await instance.database;
|
Database db = await instance.database;
|
||||||
return await db.insert('mood', mood.toMap());
|
return await db.insert('mood', mood.toMap());
|
||||||
|
@ -73,13 +82,17 @@ class DatabaseService {
|
||||||
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());
|
||||||
|
}
|
||||||
|
|
||||||
Future<int> addRelapse(Relapse relapse) async {
|
Future<int> addRelapse(Relapse relapse) async {
|
||||||
Database db = await instance.database;
|
Database db = await instance.database;
|
||||||
return await db.insert('relapse', relapse.toMap());
|
return await db.insert('relapse', relapse.toMap());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
String _createMoodTable = '''
|
final String _createMoodTable = '''
|
||||||
CREATE TABLE IF NOT EXISTS mood(
|
CREATE TABLE IF NOT EXISTS mood(
|
||||||
id INTEGER PRIMARY KEY,
|
id INTEGER PRIMARY KEY,
|
||||||
value INTEGER,
|
value INTEGER,
|
||||||
|
@ -88,7 +101,7 @@ String _createMoodTable = '''
|
||||||
)
|
)
|
||||||
''';
|
''';
|
||||||
|
|
||||||
String _createSleepTable = '''
|
final String _createSleepTable = '''
|
||||||
CREATE TABLE IF NOT EXISTS sleep(
|
CREATE TABLE IF NOT EXISTS sleep(
|
||||||
id INTEGER PRIMARY KEY,
|
id INTEGER PRIMARY KEY,
|
||||||
value INTEGER,
|
value INTEGER,
|
||||||
|
@ -101,7 +114,7 @@ String _createSleepTable = '''
|
||||||
)
|
)
|
||||||
''';
|
''';
|
||||||
|
|
||||||
String _createRelapseTable = '''
|
final String _createRelapseTable = '''
|
||||||
CREATE TABLE IF NOT EXISTS relapse(
|
CREATE TABLE IF NOT EXISTS relapse(
|
||||||
id INTEGER PRIMARY KEY,
|
id INTEGER PRIMARY KEY,
|
||||||
date TEXT,
|
date TEXT,
|
||||||
|
@ -110,14 +123,12 @@ String _createRelapseTable = '''
|
||||||
)
|
)
|
||||||
''';
|
''';
|
||||||
|
|
||||||
String _createWorkoutTable = '''
|
final String _createWorkoutTable = '''
|
||||||
CREATE TABLE IF NOT EXISTS workout(
|
CREATE TABLE IF NOT EXISTS workout(
|
||||||
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
|
|
||||||
)
|
)
|
||||||
''';
|
''';
|
||||||
|
}
|
||||||
|
|
|
@ -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 = {
|
||||||
|
@ -13,6 +15,12 @@ const weekDays = {
|
||||||
"Sonntag": 7,
|
"Sonntag": 7,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool isSameDay(DateTime? dateA, DateTime? dateB) {
|
||||||
|
return dateA?.year == dateB?.year &&
|
||||||
|
dateA?.month == dateB?.month &&
|
||||||
|
dateA?.day == dateB?.day;
|
||||||
|
}
|
||||||
|
|
||||||
Future<List<TZDateTime>> getDatesforMood() async {
|
Future<List<TZDateTime>> getDatesforMood() async {
|
||||||
final List<String>? selectedDays = await getMoodQueryDaysCategories();
|
final List<String>? selectedDays = await getMoodQueryDaysCategories();
|
||||||
final int? selectedHours = await getMoodQueryHours();
|
final int? selectedHours = await getMoodQueryHours();
|
||||||
|
@ -27,6 +35,59 @@ Future<List<TZDateTime>> getDatesforSleep() async {
|
||||||
return createTZDateTimes(selectedDays, selectedHours, selectedMinutes);
|
return createTZDateTimes(selectedDays, selectedHours, selectedMinutes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<TZDateTime?> getTodayMood() async {
|
||||||
|
List<TZDateTime> moodDates = await getDatesforMood();
|
||||||
|
Iterable<TZDateTime> today =
|
||||||
|
moodDates.where((element) => isSameDay(element, DateTime.now()));
|
||||||
|
return today.isNotEmpty ? today.first : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<TZDateTime?> getTodaySleep() async {
|
||||||
|
List<TZDateTime> sleepDates = await getDatesforSleep();
|
||||||
|
Iterable<TZDateTime> today =
|
||||||
|
sleepDates.where((element) => isSameDay(element, DateTime.now()));
|
||||||
|
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 = [];
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
import 'package:smoke_cess_app/models/mood.dart';
|
||||||
|
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';
|
||||||
|
import '../globals.dart' as globals;
|
||||||
|
|
||||||
|
class ExportService {
|
||||||
|
Uri url = Uri.parse('http://localhost:3000/data');
|
||||||
|
final DatabaseService _databaseService = globals.databaseService;
|
||||||
|
|
||||||
|
Future<Map<String, List<String>>> _loadRecords() async {
|
||||||
|
List<Mood> moodRecords = await _databaseService.getMoodRecords();
|
||||||
|
List<Sleep> sleepRecords = await _databaseService.getSleepRecords();
|
||||||
|
List<Relapse> relapseRecords = await _databaseService.getRelapseRecords();
|
||||||
|
List<Workout> workoutRecords = await _databaseService.getWorkoutRecords();
|
||||||
|
return {
|
||||||
|
'Stimmung':
|
||||||
|
moodRecords.map((Mood mood) => jsonEncode(mood.toMap())).toList(),
|
||||||
|
'Schlaf':
|
||||||
|
sleepRecords.map((Sleep sleep) => jsonEncode(sleep.toMap())).toList(),
|
||||||
|
'Rückfall': relapseRecords
|
||||||
|
.map((Relapse relapse) => jsonEncode(relapse.toMap()))
|
||||||
|
.toList(),
|
||||||
|
'Workout': workoutRecords
|
||||||
|
.map((Workout workout) => jsonEncode(workout.toMap()))
|
||||||
|
.toList()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<int> exportData() async {
|
||||||
|
Map<String, List<String>> body = await _loadRecords();
|
||||||
|
final response = await http.post(url,
|
||||||
|
headers: <String, String>{
|
||||||
|
'Content-Type': 'application/json; charset=UTF-8',
|
||||||
|
},
|
||||||
|
body: jsonEncode(body));
|
||||||
|
return response.statusCode >= 400 ? 0 : 1;
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,25 +5,38 @@ import '../pages/relapse_page.dart';
|
||||||
import '../pages/scanner_page.dart';
|
import '../pages/scanner_page.dart';
|
||||||
import '../pages/sleep_page.dart';
|
import '../pages/sleep_page.dart';
|
||||||
|
|
||||||
const pages = {
|
enum Pages {
|
||||||
'Stimmung': {
|
mood,
|
||||||
|
sleep,
|
||||||
|
relapse,
|
||||||
|
timer,
|
||||||
|
settings,
|
||||||
|
}
|
||||||
|
|
||||||
|
const Map<Pages, Map<String, dynamic>> pages = {
|
||||||
|
Pages.mood: {
|
||||||
|
'title': 'Stimmung',
|
||||||
'page': MoodPage(),
|
'page': MoodPage(),
|
||||||
'icon': Icon(Icons.mood_outlined, color: Colors.black)
|
'icon': Icon(Icons.mood_outlined, color: Colors.black),
|
||||||
},
|
},
|
||||||
'Schlaf': {
|
Pages.sleep: {
|
||||||
|
'title': 'Schlaf',
|
||||||
'page': SleepPage(),
|
'page': SleepPage(),
|
||||||
'icon': Icon(Icons.bedtime_outlined, color: Colors.black)
|
'icon': Icon(Icons.bedtime_outlined, color: Colors.black),
|
||||||
},
|
},
|
||||||
'Timer': {
|
Pages.timer: {
|
||||||
|
'title': 'Timer',
|
||||||
'page': IntervalTimerPage(),
|
'page': IntervalTimerPage(),
|
||||||
'icon': Icon(Icons.timer_outlined, color: Colors.black)
|
'icon': Icon(Icons.timer_outlined, color: Colors.black),
|
||||||
},
|
},
|
||||||
'Rückfall': {
|
Pages.relapse: {
|
||||||
|
'title': 'Rückfall',
|
||||||
'page': RelapsePage(),
|
'page': RelapsePage(),
|
||||||
'icon': Icon(Icons.smoke_free_outlined, color: Colors.black),
|
'icon': Icon(Icons.smoke_free_outlined, color: Colors.black),
|
||||||
},
|
},
|
||||||
'Scanner': {
|
Pages.settings: {
|
||||||
|
'title': 'Scanner',
|
||||||
'page': ScannerPage(),
|
'page': ScannerPage(),
|
||||||
'icon': Icon(Icons.camera_alt_outlined, color: Colors.black)
|
'icon': Icon(Icons.camera_alt_outlined, color: Colors.black),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -23,13 +23,6 @@ Future<int?> getMoodQueryMinutes() => _getIntSetting('mood_query_minutes');
|
||||||
Future<int?> getChessHours() => _getIntSetting('chess_hours');
|
Future<int?> getChessHours() => _getIntSetting('chess_hours');
|
||||||
Future<int?> getChessMinutes() => _getIntSetting('chess_minutes');
|
Future<int?> getChessMinutes() => _getIntSetting('chess_minutes');
|
||||||
|
|
||||||
void _setStringSetting(String settingKey, String settingValue) =>
|
|
||||||
SharedPreferences.getInstance()
|
|
||||||
.then((pref) => pref.setString(settingKey, settingValue));
|
|
||||||
|
|
||||||
Future<String?> _getStringSetting(String settingKey) =>
|
|
||||||
SharedPreferences.getInstance().then((pref) => pref.getString(settingKey));
|
|
||||||
|
|
||||||
void _setIntSetting(String settingKey, int settingValue) =>
|
void _setIntSetting(String settingKey, int settingValue) =>
|
||||||
SharedPreferences.getInstance()
|
SharedPreferences.getInstance()
|
||||||
.then((pref) => pref.setInt(settingKey, settingValue));
|
.then((pref) => pref.setInt(settingKey, settingValue));
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
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/models/mood.dart';
|
import 'package:smoke_cess_app/providers/tasks_provider.dart';
|
||||||
import 'package:smoke_cess_app/services/database_service.dart';
|
import 'package:smoke_cess_app/services/pages_service.dart';
|
||||||
import 'package:smoke_cess_app/widgets/slider.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/submit_form_button.dart';
|
||||||
import 'package:smoke_cess_app/widgets/text_formfield.dart';
|
import 'package:smoke_cess_app/widgets/text_formfield.dart';
|
||||||
|
@ -15,6 +15,7 @@ class MoodForm extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var inputModel = context.watch<InputProvider>();
|
var inputModel = context.watch<InputProvider>();
|
||||||
|
var tasksModel = context.watch<TasksProvider>();
|
||||||
return Column(
|
return Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
|
@ -32,6 +33,7 @@ class MoodForm extends StatelessWidget {
|
||||||
),
|
),
|
||||||
SubmitFormButton(
|
SubmitFormButton(
|
||||||
submitCallback: inputModel.saveMood,
|
submitCallback: inputModel.saveMood,
|
||||||
|
updateTasks: () => tasksModel.setTaskDone(Pages.mood),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
|
@ -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,22 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
import '../providers/audio_provider.dart';
|
||||||
|
|
||||||
|
class MuteButton extends StatelessWidget {
|
||||||
|
const MuteButton({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
AudioProvider workoutProvider = context.watch<AudioProvider>();
|
||||||
|
|
||||||
|
return IconButton(
|
||||||
|
onPressed: workoutProvider.isMuted
|
||||||
|
? workoutProvider.unMutePlayer
|
||||||
|
: workoutProvider.mutePlayer,
|
||||||
|
icon: Icon(workoutProvider.isMuted
|
||||||
|
? Icons.volume_off_outlined
|
||||||
|
: Icons.volume_up_outlined),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,26 +1,52 @@
|
||||||
import 'package:flutter/material.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/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) {
|
||||||
|
return 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) {
|
||||||
|
InputProvider inputProvider = context.watch<InputProvider>();
|
||||||
|
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
title: Text(title),
|
title: Text(title),
|
||||||
content: Column(
|
content: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: const [
|
children: [
|
||||||
Padding(
|
const Padding(
|
||||||
padding: const EdgeInsets.only(top: 8),
|
padding: EdgeInsets.only(top: 8),
|
||||||
child: MySlider(),
|
child: MySlider(),
|
||||||
),
|
),
|
||||||
SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
MyTextFormField('Beschreibe deinen Motivation'),
|
ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
onSaveAction(inputProvider.sliderValue);
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
child: const Text('Speichern'))
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
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);
|
||||||
|
if (context.mounted) {
|
||||||
|
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)
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,11 +1,12 @@
|
||||||
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/tasks_provider.dart';
|
||||||
import 'package:smoke_cess_app/widgets/drop_down.dart';
|
import 'package:smoke_cess_app/widgets/drop_down.dart';
|
||||||
import 'package:smoke_cess_app/widgets/submit_form_button.dart';
|
import 'package:smoke_cess_app/widgets/submit_form_button.dart';
|
||||||
import 'package:smoke_cess_app/widgets/text_formfield.dart';
|
import 'package:smoke_cess_app/widgets/text_formfield.dart';
|
||||||
|
|
||||||
import '../providers/input_provider.dart';
|
import '../providers/input_provider.dart';
|
||||||
import '../providers/settings_provider.dart';
|
import '../providers/settings_provider.dart';
|
||||||
|
import '../services/pages_service.dart';
|
||||||
import 'elevated_card.dart';
|
import 'elevated_card.dart';
|
||||||
|
|
||||||
class RelapseForm extends StatelessWidget {
|
class RelapseForm extends StatelessWidget {
|
||||||
|
@ -15,6 +16,7 @@ class RelapseForm extends StatelessWidget {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var inputModel = context.watch<InputProvider>();
|
var inputModel = context.watch<InputProvider>();
|
||||||
var settingsModel = context.watch<SettingsProvider>();
|
var settingsModel = context.watch<SettingsProvider>();
|
||||||
|
var tasksModel = context.watch<TasksProvider>();
|
||||||
return Column(
|
return Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
|
@ -29,7 +31,10 @@ class RelapseForm extends StatelessWidget {
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 80,
|
height: 80,
|
||||||
),
|
),
|
||||||
SubmitFormButton(submitCallback: inputModel.saveRelapse)
|
SubmitFormButton(
|
||||||
|
submitCallback: inputModel.saveRelapse,
|
||||||
|
updateTasks: () => tasksModel.setTaskDone(Pages.mood),
|
||||||
|
)
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
|
@ -37,13 +37,29 @@ class MyScannerState extends State<MyScanner> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void handleError() {
|
||||||
|
setState(() {
|
||||||
|
scanning = false;
|
||||||
|
AwesomeDialog(
|
||||||
|
context: context,
|
||||||
|
dialogType: DialogType.error,
|
||||||
|
title: 'Fehler',
|
||||||
|
desc: 'Der QR-Code war fehlerhaft!',
|
||||||
|
).show();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void onDetect(capture) {
|
void onDetect(capture) {
|
||||||
|
try {
|
||||||
final List<Barcode> barcodes = capture.barcodes;
|
final List<Barcode> barcodes = capture.barcodes;
|
||||||
for (final barcode in barcodes) {
|
for (final barcode in barcodes) {
|
||||||
if (barcode.rawValue != null) {
|
if (barcode.rawValue != null) {
|
||||||
return handleSucces(barcode.rawValue);
|
return handleSucces(barcode.rawValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (e) {
|
||||||
|
handleError();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
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/tasks_provider.dart';
|
||||||
import 'package:smoke_cess_app/widgets/elevated_card.dart';
|
import 'package:smoke_cess_app/widgets/elevated_card.dart';
|
||||||
import 'package:smoke_cess_app/widgets/slider.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/submit_form_button.dart';
|
||||||
|
@ -7,6 +8,7 @@ import 'package:smoke_cess_app/widgets/text_formfield.dart';
|
||||||
import 'package:smoke_cess_app/widgets/timepicker.dart';
|
import 'package:smoke_cess_app/widgets/timepicker.dart';
|
||||||
|
|
||||||
import '../providers/input_provider.dart';
|
import '../providers/input_provider.dart';
|
||||||
|
import '../services/pages_service.dart';
|
||||||
|
|
||||||
class SleepForm extends StatelessWidget {
|
class SleepForm extends StatelessWidget {
|
||||||
const SleepForm({Key? key}) : super(key: key);
|
const SleepForm({Key? key}) : super(key: key);
|
||||||
|
@ -14,20 +16,19 @@ class SleepForm extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
InputProvider inputModel = context.watch<InputProvider>();
|
InputProvider inputModel = context.watch<InputProvider>();
|
||||||
String wokeUpKey = 'wokeUpAt';
|
TasksProvider tasksModel = context.watch<TasksProvider>();
|
||||||
String sleptKey = 'sleptAt';
|
|
||||||
|
|
||||||
return Column(
|
return Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
ElevatedCard(
|
const ElevatedCard(
|
||||||
title: 'Einschlafzeit',
|
title: 'Einschlafzeit',
|
||||||
child: TimePicker(sleptKey),
|
child: TimePicker(SleepTimes.sleptAt),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
ElevatedCard(
|
const ElevatedCard(
|
||||||
title: 'Aufwachzeit',
|
title: 'Aufwachzeit',
|
||||||
child: TimePicker(wokeUpKey),
|
child: TimePicker(SleepTimes.wokeUpAt),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
const ElevatedCard(
|
const ElevatedCard(
|
||||||
|
@ -43,7 +44,9 @@ class SleepForm extends StatelessWidget {
|
||||||
height: 80,
|
height: 80,
|
||||||
),
|
),
|
||||||
SubmitFormButton(
|
SubmitFormButton(
|
||||||
submitCallback: () => inputModel.saveSleep(wokeUpKey, sleptKey),
|
submitCallback: () =>
|
||||||
|
inputModel.saveSleep(SleepTimes.wokeUpAt, SleepTimes.sleptAt),
|
||||||
|
updateTasks: () => tasksModel.setTaskDone(Pages.mood),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
|
@ -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,30 +1,41 @@
|
||||||
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;
|
||||||
const SubmitFormButton({super.key, required this.submitCallback});
|
final void Function() updateTasks;
|
||||||
|
const SubmitFormButton(
|
||||||
|
{super.key, required this.submitCallback, required this.updateTasks});
|
||||||
|
|
||||||
@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();
|
||||||
success != 0
|
if (context.mounted) {
|
||||||
? AwesomeDialog(
|
if (success != 0) {
|
||||||
|
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();
|
||||||
: AwesomeDialog(
|
updateTasks();
|
||||||
|
pageProvider.swap();
|
||||||
|
} else {
|
||||||
|
await AwesomeDialog(
|
||||||
context: context,
|
context: context,
|
||||||
dialogType: DialogType.error,
|
dialogType: DialogType.error,
|
||||||
title: 'Fehler',
|
title: 'Fehler',
|
||||||
desc: 'Der Eintrag konnte nicht gespeichert werden',
|
desc: 'Der Eintrag konnte nicht gespeichert werden',
|
||||||
).show();
|
).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
child: const Text('Speichern'),
|
child: const Text('Speichern'),
|
||||||
),
|
),
|
||||||
|
|
|
@ -3,7 +3,7 @@ import 'package:smoke_cess_app/providers/input_provider.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
class TimePicker extends StatelessWidget {
|
class TimePicker extends StatelessWidget {
|
||||||
final String keyMap;
|
final SleepTimes keyMap;
|
||||||
|
|
||||||
const TimePicker(this.keyMap, {super.key});
|
const TimePicker(this.keyMap, {super.key});
|
||||||
|
|
||||||
|
|
|
@ -14,11 +14,6 @@ class TimerWidget extends StatelessWidget {
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Text(formatTime(duration.inSeconds - timerProvider.elapsedSeconds)),
|
Text(formatTime(duration.inSeconds - timerProvider.elapsedSeconds)),
|
||||||
ElevatedButton(
|
|
||||||
onPressed: () => timerProvider.started
|
|
||||||
? timerProvider.stopTimer()
|
|
||||||
: timerProvider.startTimer(duration),
|
|
||||||
child: Text(timerProvider.started ? 'Stop' : 'Start'))
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class MyToDoIcon extends StatelessWidget {
|
||||||
|
final Icon _icon;
|
||||||
|
const MyToDoIcon(this._icon, {super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Stack(children: <Widget>[
|
||||||
|
_icon,
|
||||||
|
const Positioned(
|
||||||
|
// draw a red marble
|
||||||
|
top: 0.0,
|
||||||
|
right: 0.0,
|
||||||
|
child: Icon(Icons.brightness_1, size: 10.0, color: Colors.redAccent),
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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,36 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:smoke_cess_app/providers/audio_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 {
|
||||||
|
WorkoutForm({super.key});
|
||||||
|
|
||||||
|
final TimerProvider timerProvider = TimerProvider();
|
||||||
|
final AudioProvider audioProvider = AudioProvider();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return MultiProvider(
|
||||||
|
providers: [
|
||||||
|
ChangeNotifierProvider(create: (context) => timerProvider),
|
||||||
|
ChangeNotifierProvider(create: (context) => audioProvider),
|
||||||
|
ChangeNotifierProvider(
|
||||||
|
create: (context) =>
|
||||||
|
WorkoutProvider(timerProvider, audioProvider)),
|
||||||
|
],
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: const [
|
||||||
|
Align(
|
||||||
|
alignment: Alignment.topLeft,
|
||||||
|
child: MuteButton(),
|
||||||
|
),
|
||||||
|
WorkoutTimerWidget()
|
||||||
|
],
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,93 @@
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:awesome_dialog/awesome_dialog.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
import '../providers/page_provider.dart';
|
||||||
|
import '../providers/tasks_provider.dart';
|
||||||
|
import '../providers/workout_provider.dart';
|
||||||
|
import '../services/pages_service.dart';
|
||||||
|
import '../widgets/timer_widget.dart';
|
||||||
|
import '../providers/timer_provider.dart';
|
||||||
|
import 'popup_for_start_and_stop.dart';
|
||||||
|
|
||||||
|
class WorkoutTimerWidget extends StatelessWidget {
|
||||||
|
const WorkoutTimerWidget({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
TimerProvider timerProvider = context.watch<TimerProvider>();
|
||||||
|
WorkoutProvider workoutProvider = context.watch<WorkoutProvider>();
|
||||||
|
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');
|
||||||
|
if (context.mounted) {
|
||||||
|
await AwesomeDialog(
|
||||||
|
context: context,
|
||||||
|
dialogType: DialogType.success,
|
||||||
|
title: 'Gespeichert',
|
||||||
|
desc: 'Der Eintrag wurde erfolgreich gespeichert',
|
||||||
|
).show();
|
||||||
|
pageProvider.swap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (workoutProvider.isPhaseComplete && !workoutProvider.isWorkoutComplete) {
|
||||||
|
Timer(const Duration(milliseconds: 1), () => workoutProvider.nextPhase());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (workoutProvider.isWorkoutComplete) {
|
||||||
|
Timer(const Duration(milliseconds: 1), handleStopWorkout);
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleStartStopWorkout() {
|
||||||
|
if (!workoutProvider.isWorkoutStarted) {
|
||||||
|
showMotivationPopup(context, (double value) {
|
||||||
|
workoutProvider.motivationBefore = value.toInt();
|
||||||
|
workoutProvider.startWorkout();
|
||||||
|
}, 'Motivation vor dem Training');
|
||||||
|
} else {
|
||||||
|
workoutProvider.interruptWorkout();
|
||||||
|
handleStopWorkout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Text(workoutProvider.currentPhaseTitle),
|
||||||
|
const SizedBox(
|
||||||
|
height: 20,
|
||||||
|
),
|
||||||
|
Stack(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
height: 100,
|
||||||
|
width: 100,
|
||||||
|
child: CircularProgressIndicator(
|
||||||
|
color: workoutProvider.currentPhaseColor,
|
||||||
|
value: (workoutProvider.currentPhaseDuration.inSeconds
|
||||||
|
.toDouble() -
|
||||||
|
timerProvider.elapsedSeconds) /
|
||||||
|
workoutProvider.currentPhaseDuration.inSeconds)),
|
||||||
|
TimerWidget(duration: workoutProvider.currentPhaseDuration),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 20,
|
||||||
|
),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: handleStartStopWorkout,
|
||||||
|
child: Text(timerProvider.started ? 'Stop' : 'Start'))
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
516
pubspec.lock
|
@ -1,516 +0,0 @@
|
||||||
# Generated by pub
|
|
||||||
# See https://dart.dev/tools/pub/glossary#lockfile
|
|
||||||
packages:
|
|
||||||
args:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: args
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "2.4.0"
|
|
||||||
async:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: async
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "2.9.0"
|
|
||||||
audioplayers:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: audioplayers
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "3.0.1"
|
|
||||||
audioplayers_android:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: audioplayers_android
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "2.0.0"
|
|
||||||
audioplayers_darwin:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: audioplayers_darwin
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "3.0.1"
|
|
||||||
audioplayers_linux:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: audioplayers_linux
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.0.4"
|
|
||||||
audioplayers_platform_interface:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: audioplayers_platform_interface
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "4.0.0"
|
|
||||||
audioplayers_web:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: audioplayers_web
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "2.2.0"
|
|
||||||
audioplayers_windows:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: audioplayers_windows
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.1.3"
|
|
||||||
awesome_dialog:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: awesome_dialog
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "3.0.2"
|
|
||||||
boolean_selector:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: boolean_selector
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "2.1.0"
|
|
||||||
characters:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: characters
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.2.1"
|
|
||||||
clock:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: clock
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.1.1"
|
|
||||||
collection:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: collection
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.16.0"
|
|
||||||
crypto:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: crypto
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "3.0.2"
|
|
||||||
cupertino_icons:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: cupertino_icons
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.0.5"
|
|
||||||
dbus:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: dbus
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "0.7.8"
|
|
||||||
fake_async:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: fake_async
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.3.1"
|
|
||||||
ffi:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: ffi
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "2.0.1"
|
|
||||||
file:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: file
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "6.1.4"
|
|
||||||
flutter:
|
|
||||||
dependency: "direct main"
|
|
||||||
description: flutter
|
|
||||||
source: sdk
|
|
||||||
version: "0.0.0"
|
|
||||||
flutter_lints:
|
|
||||||
dependency: "direct dev"
|
|
||||||
description:
|
|
||||||
name: flutter_lints
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "2.0.1"
|
|
||||||
flutter_local_notifications:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: flutter_local_notifications
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "13.0.0"
|
|
||||||
flutter_local_notifications_linux:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: flutter_local_notifications_linux
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "3.0.0+1"
|
|
||||||
flutter_local_notifications_platform_interface:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: flutter_local_notifications_platform_interface
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "6.0.0"
|
|
||||||
flutter_test:
|
|
||||||
dependency: "direct dev"
|
|
||||||
description: flutter
|
|
||||||
source: sdk
|
|
||||||
version: "0.0.0"
|
|
||||||
flutter_web_plugins:
|
|
||||||
dependency: transitive
|
|
||||||
description: flutter
|
|
||||||
source: sdk
|
|
||||||
version: "0.0.0"
|
|
||||||
graphs:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: graphs
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "2.2.0"
|
|
||||||
http:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: http
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "0.13.5"
|
|
||||||
http_parser:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: http_parser
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "4.0.2"
|
|
||||||
js:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: js
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "0.6.4"
|
|
||||||
lints:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: lints
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "2.0.1"
|
|
||||||
matcher:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: matcher
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "0.12.12"
|
|
||||||
material_color_utilities:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: material_color_utilities
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "0.1.5"
|
|
||||||
meta:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: meta
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.8.0"
|
|
||||||
mobile_scanner:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: mobile_scanner
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "3.0.0"
|
|
||||||
nested:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: nested
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.0.0"
|
|
||||||
path:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: path
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.8.2"
|
|
||||||
path_provider:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: path_provider
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "2.0.12"
|
|
||||||
path_provider_android:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: path_provider_android
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "2.0.22"
|
|
||||||
path_provider_foundation:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: path_provider_foundation
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "2.1.1"
|
|
||||||
path_provider_linux:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: path_provider_linux
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "2.1.8"
|
|
||||||
path_provider_platform_interface:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: path_provider_platform_interface
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "2.0.5"
|
|
||||||
path_provider_windows:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: path_provider_windows
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "2.1.3"
|
|
||||||
petitparser:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: petitparser
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "5.1.0"
|
|
||||||
platform:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: platform
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "3.1.0"
|
|
||||||
plugin_platform_interface:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: plugin_platform_interface
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "2.1.3"
|
|
||||||
process:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: process
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "4.2.4"
|
|
||||||
provider:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: provider
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "6.0.5"
|
|
||||||
rive:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: rive
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "0.9.1"
|
|
||||||
shared_preferences:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: shared_preferences
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "2.0.17"
|
|
||||||
shared_preferences_android:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: shared_preferences_android
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "2.0.15"
|
|
||||||
shared_preferences_foundation:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: shared_preferences_foundation
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "2.1.3"
|
|
||||||
shared_preferences_linux:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: shared_preferences_linux
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "2.1.3"
|
|
||||||
shared_preferences_platform_interface:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: shared_preferences_platform_interface
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "2.1.0"
|
|
||||||
shared_preferences_web:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: shared_preferences_web
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "2.0.4"
|
|
||||||
shared_preferences_windows:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: shared_preferences_windows
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "2.1.3"
|
|
||||||
sky_engine:
|
|
||||||
dependency: transitive
|
|
||||||
description: flutter
|
|
||||||
source: sdk
|
|
||||||
version: "0.0.99"
|
|
||||||
source_span:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: source_span
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.9.0"
|
|
||||||
sqflite:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: sqflite
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "2.2.4+1"
|
|
||||||
sqflite_common:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: sqflite_common
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "2.4.2+2"
|
|
||||||
stack_trace:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: stack_trace
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.10.0"
|
|
||||||
stream_channel:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: stream_channel
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "2.1.0"
|
|
||||||
string_scanner:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: string_scanner
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.1.1"
|
|
||||||
synchronized:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: synchronized
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "3.0.1"
|
|
||||||
term_glyph:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: term_glyph
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.2.1"
|
|
||||||
test_api:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: test_api
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "0.4.12"
|
|
||||||
timezone:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: timezone
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "0.9.1"
|
|
||||||
typed_data:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: typed_data
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.3.1"
|
|
||||||
uuid:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: uuid
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "3.0.7"
|
|
||||||
vector_math:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: vector_math
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "2.1.2"
|
|
||||||
win32:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: win32
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "3.1.3"
|
|
||||||
xdg_directories:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: xdg_directories
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "0.2.0+3"
|
|
||||||
xml:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: xml
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "6.1.0"
|
|
||||||
sdks:
|
|
||||||
dart: ">=2.18.2 <3.0.0"
|
|
||||||
flutter: ">=3.3.0"
|
|
76
pubspec.yaml
|
@ -1,33 +1,13 @@
|
||||||
name: smoke_cess_app
|
name: smoke_cess_app
|
||||||
description: A new Flutter project.
|
description: A new Flutter project.
|
||||||
|
|
||||||
# The following line prevents the package from being accidentally published to
|
publish_to: 'none'
|
||||||
# pub.dev using `flutter pub publish`. This is preferred for private packages.
|
|
||||||
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
|
||||||
|
|
||||||
# The following defines the version and build number for your application.
|
|
||||||
# A version number is three numbers separated by dots, like 1.2.43
|
|
||||||
# followed by an optional build number separated by a +.
|
|
||||||
# Both the version and the builder number may be overridden in flutter
|
|
||||||
# build by specifying --build-name and --build-number, respectively.
|
|
||||||
# In Android, build-name is used as versionName while build-number used as versionCode.
|
|
||||||
# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
|
|
||||||
# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion.
|
|
||||||
# Read more about iOS versioning at
|
|
||||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
|
||||||
# In Windows, build-name is used as the major, minor, and patch parts
|
|
||||||
# of the product and file versions while build-number is used as the build suffix.
|
|
||||||
version: 1.0.0+1
|
version: 1.0.0+1
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=2.18.2 <3.0.0'
|
sdk: '>=2.18.2 <3.0.0'
|
||||||
|
|
||||||
# Dependencies specify other packages that your package needs in order to work.
|
|
||||||
# To automatically upgrade your package dependencies to the latest versions
|
|
||||||
# consider running `flutter pub upgrade --major-versions`. Alternatively,
|
|
||||||
# dependencies can be manually updated by changing the version numbers below to
|
|
||||||
# the latest version available on pub.dev. To see which dependencies have newer
|
|
||||||
# versions available, run `flutter pub outdated`.
|
|
||||||
dependencies:
|
dependencies:
|
||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
@ -36,38 +16,28 @@ dependencies:
|
||||||
path_provider: ^2.0.12
|
path_provider: ^2.0.12
|
||||||
provider: ^6.0.5
|
provider: ^6.0.5
|
||||||
awesome_dialog: ^3.0.2
|
awesome_dialog: ^3.0.2
|
||||||
|
|
||||||
# The following adds the Cupertino Icons font to your application.
|
|
||||||
# Use with the CupertinoIcons class for iOS style icons.
|
|
||||||
cupertino_icons: ^1.0.2
|
|
||||||
timezone: ^0.9.0
|
timezone: ^0.9.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
|
||||||
flutter_local_notifications: ^13.0.0
|
flutter_local_notifications: ^13.0.0
|
||||||
|
http: ^0.13.5
|
||||||
|
syncfusion_flutter_charts: ^20.4.52
|
||||||
|
cupertino_icons: ^1.0.2
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
|
||||||
# The "flutter_lints" package below contains a set of recommended lints to
|
|
||||||
# encourage good coding practices. The lint set provided by the package is
|
|
||||||
# activated in the `analysis_options.yaml` file located at the root of your
|
|
||||||
# package. See that file for information about deactivating specific lint
|
|
||||||
# rules and activating additional ones.
|
|
||||||
flutter_lints: ^2.0.0
|
flutter_lints: ^2.0.0
|
||||||
|
flutter_launcher_icons: ^0.12.0
|
||||||
|
flutter_icons:
|
||||||
|
android: 'launcher_icon'
|
||||||
|
ios: true
|
||||||
|
image_path: 'assets/ZI_logo.png'
|
||||||
|
|
||||||
# For information on the generic Dart part of this file, see the
|
|
||||||
# following page: https://dart.dev/tools/pub/pubspec
|
|
||||||
|
|
||||||
# The following section is specific to Flutter packages.
|
|
||||||
flutter:
|
flutter:
|
||||||
# The following line ensures that the Material Icons font is
|
|
||||||
# included with your application, so that you can use the icons in
|
|
||||||
# the material Icons class.
|
|
||||||
uses-material-design: true
|
uses-material-design: true
|
||||||
|
|
||||||
# To add assets to your application, add an assets section, like this:
|
|
||||||
assets:
|
assets:
|
||||||
- assets/beep.mp3
|
- assets/beep.mp3
|
||||||
- assets/go.mp3
|
- assets/go.mp3
|
||||||
|
@ -77,31 +47,3 @@ flutter:
|
||||||
- assets/finish.mp3
|
- assets/finish.mp3
|
||||||
- assets/group1.json
|
- assets/group1.json
|
||||||
- assets/group3.json
|
- assets/group3.json
|
||||||
# - images/a_dot_burr.jpeg
|
|
||||||
# - images/a_dot_ham.jpeg
|
|
||||||
|
|
||||||
# An image asset can refer to one or more resolution-specific "variants", see
|
|
||||||
# https://flutter.dev/assets-and-images/#resolution-aware
|
|
||||||
|
|
||||||
# For details regarding adding assets from package dependencies, see
|
|
||||||
# https://flutter.dev/assets-and-images/#from-packages
|
|
||||||
|
|
||||||
# To add custom fonts to your application, add a fonts section here,
|
|
||||||
# in this "flutter" section. Each entry in this list should have a
|
|
||||||
# "family" key with the font family name, and a "fonts" key with a
|
|
||||||
# list giving the asset and other descriptors for the font. For
|
|
||||||
# example:
|
|
||||||
# fonts:
|
|
||||||
# - family: Schyler
|
|
||||||
# fonts:
|
|
||||||
# - asset: fonts/Schyler-Regular.ttf
|
|
||||||
# - asset: fonts/Schyler-Italic.ttf
|
|
||||||
# style: italic
|
|
||||||
# - family: Trajan Pro
|
|
||||||
# fonts:
|
|
||||||
# - asset: fonts/TrajanPro.ttf
|
|
||||||
# - asset: fonts/TrajanPro_Bold.ttf
|
|
||||||
# weight: 700
|
|
||||||
#
|
|
||||||
# For details regarding fonts from package dependencies,
|
|
||||||
# see https://flutter.dev/custom-fonts/#from-packages
|
|
||||||
|
|