Merge branch 'main' into testing_branch
|
@ -31,6 +31,7 @@ migrate_working_dir/
|
|||
.pub-cache/
|
||||
.pub/
|
||||
/build/
|
||||
pubspec.lock
|
||||
|
||||
# Symbolication related
|
||||
app.*.symbols
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
image: cirrusci/flutter:latest
|
||||
image: cirrusci/flutter:3.7.5
|
||||
|
||||
stages:
|
||||
- analyze
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.example.smoke_cess_app">
|
||||
<!-- Required to fetch data from the internet. -->
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<application
|
||||
android:label="smoke_cess_app"
|
||||
android:label="ZI SmokeFree"
|
||||
android:name="${applicationName}"
|
||||
android:icon="@mipmap/ic_launcher">
|
||||
android:icon="@mipmap/launcher_icon">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
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"],
|
||||
"mood_query": {
|
||||
"days": ["Montag", "Freitag"],
|
||||
"days": ["Montag", "Donnerstag"],
|
||||
"hours": 10,
|
||||
"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>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>Smoke Cess App</string>
|
||||
<string>ZI SmokeFree</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
|
@ -15,7 +15,7 @@
|
|||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>smoke_cess_app</string>
|
||||
<string>ZI SmokeFree</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.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:timezone/data/latest.dart' as tz;
|
||||
import 'globals.dart' as globals;
|
||||
import 'providers/page_provider.dart';
|
||||
import 'providers/settings_provider.dart';
|
||||
|
||||
void main() {
|
||||
|
@ -23,11 +25,21 @@ class MyApp extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
title: _title,
|
||||
home: ChangeNotifierProvider(
|
||||
create: (context) => SettingsProvider(),
|
||||
child: const MyHomePage(),
|
||||
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,
|
||||
home: 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/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';
|
||||
// ignore: depend_on_referenced_packages
|
||||
import 'package:sqflite_common/sqlite_api.dart';
|
||||
|
||||
class DatabaseMock implements DatabaseService {
|
||||
|
@ -15,7 +16,7 @@ class DatabaseMock implements DatabaseService {
|
|||
final List<Mood> _moodRecords = [];
|
||||
final List<Sleep> _sleepRecords = [];
|
||||
final List<Relapse> _relapseRecords = [];
|
||||
final List<DatabaseRecord> _workoutRecords = [];
|
||||
final List<Workout> _workoutRecords = [];
|
||||
|
||||
@override
|
||||
Future<int> addMood(Mood mood) {
|
||||
|
@ -29,6 +30,12 @@ class DatabaseMock implements DatabaseService {
|
|||
return Future.value(1);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<int> addWorkout(Workout workout) {
|
||||
_workoutRecords.add(workout);
|
||||
return Future.value(1);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<int> addRelapse(Relapse relapse) {
|
||||
_relapseRecords.add(relapse);
|
||||
|
@ -36,7 +43,6 @@ class DatabaseMock implements DatabaseService {
|
|||
}
|
||||
|
||||
@override
|
||||
// TODO: implement database
|
||||
Future<Database> get database => DatabaseService.instance.database;
|
||||
|
||||
@override
|
||||
|
@ -53,4 +59,9 @@ class DatabaseMock implements DatabaseService {
|
|||
Future<List<Relapse>> getRelapseRecords() {
|
||||
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);
|
||||
|
||||
DateTime get date => _date;
|
||||
int get moodValue => _moodValue;
|
||||
|
||||
@override
|
||||
factory Mood.fromDatabase(Map<String, dynamic> map) {
|
||||
DateTime date = DateTime.parse(map['date']);
|
||||
|
|
|
@ -7,6 +7,9 @@ class Relapse implements DatabaseRecord {
|
|||
|
||||
Relapse(this._category, this._comment, this._date);
|
||||
|
||||
String get category => _category;
|
||||
DateTime get date => _date;
|
||||
|
||||
@override
|
||||
factory Relapse.fromDatabase(Map<String, dynamic> map) {
|
||||
DateTime date = DateTime.parse(map['date']);
|
||||
|
|
|
@ -11,6 +11,9 @@ class Sleep implements DatabaseRecord {
|
|||
Sleep(this._sleepQualityValue, this._comment, this._date, this._sleptAt,
|
||||
this._wokeUpAt);
|
||||
|
||||
DateTime get date => _date;
|
||||
int get sleepQualitiyValue => _sleepQualityValue;
|
||||
|
||||
@override
|
||||
factory Sleep.fromDatabase(Map<String, dynamic> map) {
|
||||
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:provider/provider.dart';
|
||||
import 'package:smoke_cess_app/providers/timer_provider.dart';
|
||||
import 'package:smoke_cess_app/widgets/popup_for_start_and_stop.dart';
|
||||
import 'package:smoke_cess_app/widgets/timer_widget.dart';
|
||||
import 'package:smoke_cess_app/services/pages_service.dart';
|
||||
import 'package:smoke_cess_app/widgets/workout_form.dart';
|
||||
import 'package:smoke_cess_app/widgets/workout_view.dart';
|
||||
|
||||
import '../providers/input_provider.dart';
|
||||
import '../widgets/view_form_page.dart';
|
||||
|
||||
class IntervalTimerPage extends StatefulWidget {
|
||||
const IntervalTimerPage({Key? key}) : super(key: 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));
|
||||
}
|
||||
class IntervalTimerPage extends StatelessWidget {
|
||||
const IntervalTimerPage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ChangeNotifierProvider(
|
||||
create: (context) => TimerProvider(),
|
||||
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();
|
||||
}
|
||||
},
|
||||
),
|
||||
// ),
|
||||
],
|
||||
),
|
||||
],
|
||||
)));
|
||||
return ViewFormPage(
|
||||
form: WorkoutForm(), view: const WorkoutView(), page: Pages.timer);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
import 'package:awesome_dialog/awesome_dialog.dart';
|
||||
import 'package:flutter/material.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/providers/settings_provider.dart';
|
||||
|
||||
import '../widgets/todo_icon.dart';
|
||||
|
||||
class MyHomePage extends StatefulWidget {
|
||||
const MyHomePage({super.key});
|
||||
|
||||
|
@ -16,38 +20,43 @@ class MyHomePageState extends State<MyHomePage> {
|
|||
bool _isConfigured = false;
|
||||
|
||||
void _onItemTapped(int index) {
|
||||
PageProvider pageProvider = context.read<PageProvider>();
|
||||
setState(() {
|
||||
_isConfigured
|
||||
? _selectedIndex = index
|
||||
: AwesomeDialog(
|
||||
context: context,
|
||||
dialogType: DialogType.info,
|
||||
title: 'Fehlende Konfiguration',
|
||||
desc: 'Bitte QR Code Scannen!',
|
||||
).show();
|
||||
if (_isConfigured) {
|
||||
pageProvider.showForm = false;
|
||||
_selectedIndex = index;
|
||||
return;
|
||||
}
|
||||
AwesomeDialog(
|
||||
context: context,
|
||||
dialogType: DialogType.info,
|
||||
title: 'Fehlende Konfiguration',
|
||||
desc: 'Bitte QR Code Scannen!',
|
||||
).show();
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var settingsModel = context.watch<SettingsProvider>();
|
||||
var group = settingsModel.settings?.group;
|
||||
var tasksModel = context.watch<TasksProvider>();
|
||||
_isConfigured = settingsModel.initialized;
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(
|
||||
'${pages.keys.elementAt(_selectedIndex)} ${_isConfigured ? "Gruppe $group" : ""}')),
|
||||
body: Center(
|
||||
child: SingleChildScrollView(
|
||||
child: pages.values.elementAt(_selectedIndex)['page'])),
|
||||
'${pages.values.elementAt(_selectedIndex)['title']} ${_isConfigured ? "Gruppe ${settingsModel.settings?.group}" : ""}')),
|
||||
body: SingleChildScrollView(
|
||||
child: pages.values.elementAt(_selectedIndex)['page'],
|
||||
),
|
||||
bottomNavigationBar: NavigationBar(
|
||||
onDestinationSelected: _onItemTapped,
|
||||
selectedIndex: _selectedIndex,
|
||||
destinations: pages.keys.map((key) {
|
||||
return NavigationDestination(
|
||||
icon: pages[key]!['icon'] ??
|
||||
const Icon(Icons.disabled_by_default),
|
||||
label: key);
|
||||
icon: tasksModel.tasks[key] ?? false
|
||||
? MyToDoIcon(pages[key]?['icon'])
|
||||
: pages[key]!['icon'],
|
||||
label: pages[key]?['title']);
|
||||
}).toList()),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,17 +1,15 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:smoke_cess_app/providers/input_provider.dart';
|
||||
import 'package:smoke_cess_app/services/pages_service.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 {
|
||||
const MoodPage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Center(
|
||||
child: ChangeNotifierProvider(
|
||||
create: (context) => InputProvider(),
|
||||
child: const MoodForm(),
|
||||
));
|
||||
return const ViewFormPage(
|
||||
form: MoodForm(), view: MoodView(), page: Pages.mood);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +1,15 @@
|
|||
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 '../providers/input_provider.dart';
|
||||
import 'package:smoke_cess_app/widgets/relapse_view.dart';
|
||||
import '../widgets/view_form_page.dart';
|
||||
|
||||
class RelapsePage extends StatelessWidget {
|
||||
const RelapsePage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Center(
|
||||
child: ChangeNotifierProvider(
|
||||
create: (context) => InputProvider(),
|
||||
child: const RelapseForm(),
|
||||
));
|
||||
return const ViewFormPage(
|
||||
form: RelapseForm(), view: RelapseView(), page: Pages.relapse);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,31 +1,18 @@
|
|||
import 'package:awesome_dialog/awesome_dialog.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:smoke_cess_app/models/mood.dart';
|
||||
import 'package:smoke_cess_app/models/relapse.dart';
|
||||
import 'package:smoke_cess_app/services/export_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/widgets/scanner.dart';
|
||||
import '../models/sleep.dart';
|
||||
import '../providers/settings_provider.dart';
|
||||
import '../globals.dart' as globals;
|
||||
|
||||
class ScannerPage extends StatelessWidget {
|
||||
const ScannerPage({super.key});
|
||||
|
||||
void export() async {
|
||||
List<Mood> moods = await globals.databaseService.getMoodRecords();
|
||||
List<Sleep> sleeps = await globals.databaseService.getSleepRecords();
|
||||
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());
|
||||
}
|
||||
ExportService exportService = ExportService();
|
||||
exportService.exportData();
|
||||
}
|
||||
|
||||
void loadJSON(BuildContext context) async {
|
||||
|
@ -33,12 +20,14 @@ class ScannerPage extends StatelessWidget {
|
|||
await loadSettingsFromLocalJSON();
|
||||
settingsModel.initSettings();
|
||||
NotificationService().setAllNotifications();
|
||||
AwesomeDialog(
|
||||
context: context,
|
||||
dialogType: DialogType.success,
|
||||
title: 'Geschafft',
|
||||
desc: 'Die Einstellung wurden erfolgreich gespeichert',
|
||||
).show();
|
||||
if (context.mounted) {
|
||||
AwesomeDialog(
|
||||
context: context,
|
||||
dialogType: DialogType.success,
|
||||
title: 'Geschafft',
|
||||
desc: 'Die Einstellung wurden erfolgreich gespeichert',
|
||||
).show();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -1,17 +1,15 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:smoke_cess_app/providers/input_provider.dart';
|
||||
import 'package:smoke_cess_app/services/pages_service.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 {
|
||||
const SleepPage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Center(
|
||||
child: ChangeNotifierProvider(
|
||||
create: (context) => InputProvider(),
|
||||
child: const SleepForm(),
|
||||
));
|
||||
return const ViewFormPage(
|
||||
form: SleepForm(), view: SleepView(), page: Pages.sleep);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 '../globals.dart' as globals;
|
||||
|
||||
enum SleepTimes {
|
||||
wokeUpAt,
|
||||
sleptAt,
|
||||
}
|
||||
|
||||
class InputProvider extends ChangeNotifier {
|
||||
double _sliderValue = 50;
|
||||
final TextEditingController _textController = TextEditingController(text: '');
|
||||
final Map<String, TimeOfDay> _times = {
|
||||
'wokeUpAt': const TimeOfDay(hour: 8, minute: 0),
|
||||
'sleptAt': const TimeOfDay(hour: 22, minute: 0),
|
||||
final Map<SleepTimes, TimeOfDay> _times = {
|
||||
SleepTimes.wokeUpAt: const TimeOfDay(hour: 8, minute: 0),
|
||||
SleepTimes.sleptAt: const TimeOfDay(hour: 22, minute: 0),
|
||||
};
|
||||
String _relapseCategory = '';
|
||||
String relapseCategory = '';
|
||||
|
||||
double get sliderValue => _sliderValue;
|
||||
TextEditingController get textController => _textController;
|
||||
String get relapseCategory => _relapseCategory;
|
||||
|
||||
set sliderValue(double newValue) {
|
||||
_sliderValue = newValue;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
set relapseCategory(String newValue) {
|
||||
_relapseCategory = newValue;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
TimeOfDay getTimeEntry(String key) {
|
||||
TimeOfDay getTimeEntry(SleepTimes key) {
|
||||
return _times[key] ?? const TimeOfDay(hour: 12, minute: 0);
|
||||
}
|
||||
|
||||
void setTime(String key, TimeOfDay time) {
|
||||
void setTime(SleepTimes key, TimeOfDay time) {
|
||||
_times[key] = time;
|
||||
notifyListeners();
|
||||
}
|
||||
|
@ -39,8 +38,8 @@ class InputProvider extends ChangeNotifier {
|
|||
void _resetFields() {
|
||||
_sliderValue = 50;
|
||||
_textController.text = '';
|
||||
setTime('wokeUpAt', const TimeOfDay(hour: 8, minute: 0));
|
||||
setTime('sleptAt', const TimeOfDay(hour: 22, minute: 0));
|
||||
setTime(SleepTimes.wokeUpAt, const TimeOfDay(hour: 8, minute: 0));
|
||||
setTime(SleepTimes.sleptAt, const TimeOfDay(hour: 22, minute: 0));
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
|
@ -53,12 +52,12 @@ class InputProvider extends ChangeNotifier {
|
|||
|
||||
Future<int> saveRelapse() {
|
||||
Relapse relapse =
|
||||
Relapse(_relapseCategory, _textController.text, DateTime.now());
|
||||
Relapse(relapseCategory, _textController.text, DateTime.now());
|
||||
_resetFields();
|
||||
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,
|
||||
DateTime.now(), getTimeEntry(sleptKey), getTimeEntry(wokeUpKey));
|
||||
_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) {
|
||||
started = true;
|
||||
print('starting timer');
|
||||
_timer = Timer.periodic(const Duration(seconds: 1), ((timer) {
|
||||
if (timer.tick >= duration.inSeconds) {
|
||||
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:smoke_cess_app/models/mood.dart';
|
||||
import 'package:smoke_cess_app/models/workout.dart';
|
||||
import 'package:smoke_cess_app/models/relapse.dart';
|
||||
import 'package:sqflite/sqflite.dart';
|
||||
// ignore: depend_on_referenced_packages
|
||||
|
@ -35,7 +36,6 @@ class DatabaseService {
|
|||
await db.execute(_createWorkoutTable);
|
||||
}
|
||||
|
||||
//TODO use generic function?
|
||||
Future<List<Mood>> getMoodRecords() async {
|
||||
Database db = await instance.database;
|
||||
var moodRecords = await db.query('mood');
|
||||
|
@ -63,6 +63,15 @@ class DatabaseService {
|
|||
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 {
|
||||
Database db = await instance.database;
|
||||
return await db.insert('mood', mood.toMap());
|
||||
|
@ -73,13 +82,17 @@ class DatabaseService {
|
|||
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 {
|
||||
Database db = await instance.database;
|
||||
return await db.insert('relapse', relapse.toMap());
|
||||
}
|
||||
}
|
||||
|
||||
String _createMoodTable = '''
|
||||
final String _createMoodTable = '''
|
||||
CREATE TABLE IF NOT EXISTS mood(
|
||||
id INTEGER PRIMARY KEY,
|
||||
value INTEGER,
|
||||
|
@ -88,7 +101,7 @@ String _createMoodTable = '''
|
|||
)
|
||||
''';
|
||||
|
||||
String _createSleepTable = '''
|
||||
final String _createSleepTable = '''
|
||||
CREATE TABLE IF NOT EXISTS sleep(
|
||||
id INTEGER PRIMARY KEY,
|
||||
value INTEGER,
|
||||
|
@ -101,7 +114,7 @@ String _createSleepTable = '''
|
|||
)
|
||||
''';
|
||||
|
||||
String _createRelapseTable = '''
|
||||
final String _createRelapseTable = '''
|
||||
CREATE TABLE IF NOT EXISTS relapse(
|
||||
id INTEGER PRIMARY KEY,
|
||||
date TEXT,
|
||||
|
@ -110,14 +123,12 @@ String _createRelapseTable = '''
|
|||
)
|
||||
''';
|
||||
|
||||
String _createWorkoutTable = '''
|
||||
final String _createWorkoutTable = '''
|
||||
CREATE TABLE IF NOT EXISTS workout(
|
||||
id INTEGER PRIMARY KEY,
|
||||
date TEXT,
|
||||
motivationBefore INTEGER,
|
||||
commentBefore TEXT,
|
||||
motivationAfter INTEGER,
|
||||
commentAfter TEXT,
|
||||
completed INTEGER
|
||||
)
|
||||
''';
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import 'package:smoke_cess_app/services/settings_service.dart';
|
||||
import 'package:timezone/timezone.dart';
|
||||
|
||||
import 'pages_service.dart';
|
||||
|
||||
const int trainingTime = 40;
|
||||
|
||||
const weekDays = {
|
||||
|
@ -13,6 +15,12 @@ const weekDays = {
|
|||
"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 {
|
||||
final List<String>? selectedDays = await getMoodQueryDaysCategories();
|
||||
final int? selectedHours = await getMoodQueryHours();
|
||||
|
@ -27,6 +35,59 @@ Future<List<TZDateTime>> getDatesforSleep() async {
|
|||
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<String>? selectedDays, int? selectedHours, int? selectedMinutes) {
|
||||
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/sleep_page.dart';
|
||||
|
||||
const pages = {
|
||||
'Stimmung': {
|
||||
enum Pages {
|
||||
mood,
|
||||
sleep,
|
||||
relapse,
|
||||
timer,
|
||||
settings,
|
||||
}
|
||||
|
||||
const Map<Pages, Map<String, dynamic>> pages = {
|
||||
Pages.mood: {
|
||||
'title': 'Stimmung',
|
||||
'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(),
|
||||
'icon': Icon(Icons.bedtime_outlined, color: Colors.black)
|
||||
'icon': Icon(Icons.bedtime_outlined, color: Colors.black),
|
||||
},
|
||||
'Timer': {
|
||||
Pages.timer: {
|
||||
'title': 'Timer',
|
||||
'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(),
|
||||
'icon': Icon(Icons.smoke_free_outlined, color: Colors.black),
|
||||
},
|
||||
'Scanner': {
|
||||
Pages.settings: {
|
||||
'title': 'Scanner',
|
||||
'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?> 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) =>
|
||||
SharedPreferences.getInstance()
|
||||
.then((pref) => pref.setInt(settingKey, settingValue));
|
||||
|
|
|
@ -1,4 +1,14 @@
|
|||
String formatTime(int 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
|
||||
Widget build(BuildContext context) {
|
||||
var inputModel = context.watch<InputProvider>();
|
||||
inputModel.relapseCategory = _items.isNotEmpty ? _items[0] : '';
|
||||
return DropdownButtonFormField<String>(
|
||||
value: _items.isEmpty ? null : _items[0],
|
||||
icon: const Icon(Icons.arrow_downward),
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:smoke_cess_app/models/mood.dart';
|
||||
import 'package:smoke_cess_app/services/database_service.dart';
|
||||
import 'package:smoke_cess_app/providers/tasks_provider.dart';
|
||||
import 'package:smoke_cess_app/services/pages_service.dart';
|
||||
import 'package:smoke_cess_app/widgets/slider.dart';
|
||||
import 'package:smoke_cess_app/widgets/submit_form_button.dart';
|
||||
import 'package:smoke_cess_app/widgets/text_formfield.dart';
|
||||
|
@ -15,6 +15,7 @@ class MoodForm extends StatelessWidget {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var inputModel = context.watch<InputProvider>();
|
||||
var tasksModel = context.watch<TasksProvider>();
|
||||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
|
@ -32,6 +33,7 @@ class MoodForm extends StatelessWidget {
|
|||
),
|
||||
SubmitFormButton(
|
||||
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:provider/provider.dart';
|
||||
import 'package:smoke_cess_app/providers/input_provider.dart';
|
||||
import 'package:smoke_cess_app/widgets/slider.dart';
|
||||
import 'package:smoke_cess_app/widgets/text_formfield.dart';
|
||||
|
||||
Future showMotivationPopup(
|
||||
BuildContext context, Function onSave, String title) {
|
||||
return showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return ChangeNotifierProvider(
|
||||
create: (context) => InputProvider(),
|
||||
child: TimerStartStopPopup(
|
||||
title: title,
|
||||
onSaveAction: onSave,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
class TimerStartStopPopup extends StatelessWidget {
|
||||
final String title;
|
||||
|
||||
const TimerStartStopPopup({Key? key, required this.title}) : super(key: key);
|
||||
final Function onSaveAction;
|
||||
const TimerStartStopPopup(
|
||||
{Key? key, required this.title, required this.onSaveAction})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
InputProvider inputProvider = context.watch<InputProvider>();
|
||||
|
||||
return AlertDialog(
|
||||
title: Text(title),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: const [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 8),
|
||||
children: [
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(top: 8),
|
||||
child: MySlider(),
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
MyTextFormField('Beschreibe deinen Motivation'),
|
||||
const SizedBox(height: 16),
|
||||
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: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/submit_form_button.dart';
|
||||
import 'package:smoke_cess_app/widgets/text_formfield.dart';
|
||||
|
||||
import '../providers/input_provider.dart';
|
||||
import '../providers/settings_provider.dart';
|
||||
import '../services/pages_service.dart';
|
||||
import 'elevated_card.dart';
|
||||
|
||||
class RelapseForm extends StatelessWidget {
|
||||
|
@ -15,6 +16,7 @@ class RelapseForm extends StatelessWidget {
|
|||
Widget build(BuildContext context) {
|
||||
var inputModel = context.watch<InputProvider>();
|
||||
var settingsModel = context.watch<SettingsProvider>();
|
||||
var tasksModel = context.watch<TasksProvider>();
|
||||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
|
@ -29,7 +31,10 @@ class RelapseForm extends StatelessWidget {
|
|||
const SizedBox(
|
||||
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,12 +37,28 @@ 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) {
|
||||
final List<Barcode> barcodes = capture.barcodes;
|
||||
for (final barcode in barcodes) {
|
||||
if (barcode.rawValue != null) {
|
||||
return handleSucces(barcode.rawValue);
|
||||
try {
|
||||
final List<Barcode> barcodes = capture.barcodes;
|
||||
for (final barcode in barcodes) {
|
||||
if (barcode.rawValue != null) {
|
||||
return handleSucces(barcode.rawValue);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
handleError();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import 'package:flutter/material.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/slider.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 '../providers/input_provider.dart';
|
||||
import '../services/pages_service.dart';
|
||||
|
||||
class SleepForm extends StatelessWidget {
|
||||
const SleepForm({Key? key}) : super(key: key);
|
||||
|
@ -14,20 +16,19 @@ class SleepForm extends StatelessWidget {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
InputProvider inputModel = context.watch<InputProvider>();
|
||||
String wokeUpKey = 'wokeUpAt';
|
||||
String sleptKey = 'sleptAt';
|
||||
TasksProvider tasksModel = context.watch<TasksProvider>();
|
||||
|
||||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
ElevatedCard(
|
||||
const ElevatedCard(
|
||||
title: 'Einschlafzeit',
|
||||
child: TimePicker(sleptKey),
|
||||
child: TimePicker(SleepTimes.sleptAt),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
ElevatedCard(
|
||||
const ElevatedCard(
|
||||
title: 'Aufwachzeit',
|
||||
child: TimePicker(wokeUpKey),
|
||||
child: TimePicker(SleepTimes.wokeUpAt),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const ElevatedCard(
|
||||
|
@ -43,7 +44,9 @@ class SleepForm extends StatelessWidget {
|
|||
height: 80,
|
||||
),
|
||||
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:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:smoke_cess_app/providers/page_provider.dart';
|
||||
|
||||
class SubmitFormButton extends StatelessWidget {
|
||||
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
|
||||
Widget build(BuildContext context) {
|
||||
PageProvider pageProvider = context.watch<PageProvider>();
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16.0),
|
||||
child: ElevatedButton(
|
||||
onPressed: () async {
|
||||
int success = await submitCallback();
|
||||
success != 0
|
||||
? AwesomeDialog(
|
||||
context: context,
|
||||
dialogType: DialogType.success,
|
||||
title: 'Gespeichert',
|
||||
desc: 'Der Eintrag wurde erfolgreich gespeichert',
|
||||
).show()
|
||||
: AwesomeDialog(
|
||||
context: context,
|
||||
dialogType: DialogType.error,
|
||||
title: 'Fehler',
|
||||
desc: 'Der Eintrag konnte nicht gespeichert werden',
|
||||
).show();
|
||||
if (context.mounted) {
|
||||
if (success != 0) {
|
||||
await AwesomeDialog(
|
||||
context: context,
|
||||
dialogType: DialogType.success,
|
||||
title: 'Gespeichert',
|
||||
desc: 'Der Eintrag wurde erfolgreich gespeichert',
|
||||
).show();
|
||||
updateTasks();
|
||||
pageProvider.swap();
|
||||
} else {
|
||||
await AwesomeDialog(
|
||||
context: context,
|
||||
dialogType: DialogType.error,
|
||||
title: 'Fehler',
|
||||
desc: 'Der Eintrag konnte nicht gespeichert werden',
|
||||
).show();
|
||||
}
|
||||
}
|
||||
},
|
||||
child: const Text('Speichern'),
|
||||
),
|
||||
|
|
|
@ -3,7 +3,7 @@ import 'package:smoke_cess_app/providers/input_provider.dart';
|
|||
import 'package:provider/provider.dart';
|
||||
|
||||
class TimePicker extends StatelessWidget {
|
||||
final String keyMap;
|
||||
final SleepTimes keyMap;
|
||||
|
||||
const TimePicker(this.keyMap, {super.key});
|
||||
|
||||
|
|
|
@ -14,11 +14,6 @@ class TimerWidget extends StatelessWidget {
|
|||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
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
|
||||
description: A new Flutter project.
|
||||
|
||||
# The following line prevents the package from being accidentally published to
|
||||
# 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
|
||||
publish_to: 'none'
|
||||
|
||||
# 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
|
||||
|
||||
environment:
|
||||
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:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
|
@ -36,38 +16,28 @@ dependencies:
|
|||
path_provider: ^2.0.12
|
||||
provider: ^6.0.5
|
||||
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
|
||||
shared_preferences: ^2.0.17
|
||||
audioplayers: ^3.0.1
|
||||
mobile_scanner: ^3.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:
|
||||
flutter_test:
|
||||
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_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:
|
||||
# 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
|
||||
|
||||
# To add assets to your application, add an assets section, like this:
|
||||
assets:
|
||||
- assets/beep.mp3
|
||||
- assets/go.mp3
|
||||
|
@ -77,31 +47,3 @@ flutter:
|
|||
- assets/finish.mp3
|
||||
- assets/group1.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
|
||||
|
|