diff --git a/README.md b/README.md
index 274732f..ee7623a 100644
--- a/README.md
+++ b/README.md
@@ -14,3 +14,13 @@ Die App lässt sich als Android- und iOS App ausführen und zu Debugzwecken eben
## App bedienen
Um die App nutzen zu können, müssen Settings eingelesen werden. Dazu kann entweder ein in die App integrierter QR-Code Scanner (mit dem beigefügten [QR-Code](./gruppe1_QR.png)) benutzt werden, oder zu Debugzwecken mit dem dafür vorgesehenen Button auf der Scannerseite über eine lokale JSON-Datei.
+Es ist zu beachten, dass das verwendete QR-Code Scanner Package für Mobilgeräte optimiert ist. Deshalb kann es zu Abstürzen beim Verwenden des Scanners mit der Web-Version kommen.
+Beim Verwenden der Web-Version sollten die Settings mit der lokalen JSON-Datei eingelesen werden.
+Der Button zum Einlesen der lokalen JSON-Datei kann über die Variable bool useLocalConfig
in der Datei [globals.dart](./lib/globals.dart) ein- und ausgeblendet werden.
+
+## Authoren
+
+- Hinrik Ehrenfried 2012537
+- Patrick Meßmer 1911768
+- Kai Mannweiler 2012491
+- Julian Gegner 1922635
diff --git a/android/app/build.gradle b/android/app/build.gradle
index af69fb2..24b12bc 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -70,5 +70,7 @@ flutter {
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
+ implementation 'androidx.window:window:1.0.0'
+ implementation 'androidx.window:window-java:1.0.0'
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
}
diff --git a/lib/globals.dart b/lib/globals.dart
index 58229d9..3cdf823 100644
--- a/lib/globals.dart
+++ b/lib/globals.dart
@@ -3,5 +3,8 @@ library app.globals;
import 'package:smoke_cess_app/mock/db_mock.dart';
import 'package:smoke_cess_app/services/database_service.dart';
-DatabaseService databaseService = DatabaseMock();
+DatabaseService databaseService = DatabaseMock();
// DatabaseService databaseService = DatabaseService.instance;
+
+// set this to read settings from local json file instead of scanning a qr code
+bool useLocalConfig = false;
diff --git a/lib/main.dart b/lib/main.dart
index 4a49cd4..33f19bc 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
+import 'package:intl/date_symbol_data_local.dart';
import 'package:provider/provider.dart';
import 'package:smoke_cess_app/pages/main_page.dart';
import 'package:smoke_cess_app/providers/tasks_provider.dart';
@@ -14,6 +15,7 @@ void main() {
//init database
globals.databaseService;
tz.initializeTimeZones();
+ initializeDateFormatting('de');
NotificationService().initNotification();
runApp(const MyApp());
}
diff --git a/lib/models/mood.dart b/lib/models/mood.dart
index 9d34051..27a41d0 100644
--- a/lib/models/mood.dart
+++ b/lib/models/mood.dart
@@ -9,6 +9,7 @@ class Mood implements DatabaseRecord {
DateTime get date => _date;
int get moodValue => _moodValue;
+ String get comment => _comment;
@override
factory Mood.fromDatabase(Map map) {
diff --git a/lib/models/relapse.dart b/lib/models/relapse.dart
index 1507188..6bb6ea0 100644
--- a/lib/models/relapse.dart
+++ b/lib/models/relapse.dart
@@ -9,6 +9,7 @@ class Relapse implements DatabaseRecord {
String get category => _category;
DateTime get date => _date;
+ String get comment => _comment;
@override
factory Relapse.fromDatabase(Map map) {
diff --git a/lib/models/settings.dart b/lib/models/settings.dart
index 83fad43..dfa79be 100644
--- a/lib/models/settings.dart
+++ b/lib/models/settings.dart
@@ -6,9 +6,10 @@ class Settings {
final QueryConfig? moodQuery;
final QueryConfig? sleepQuery;
final TimeConfig? chessTime;
+ final DateTime startedAt;
Settings(this.group, this.relapseCategories, this.moodQuery, this.sleepQuery,
- this.chessTime);
+ this.chessTime, this.startedAt);
Settings.fromJson(Map json)
: group = json['group'] as int,
@@ -17,7 +18,8 @@ class Settings {
sleepQuery = QueryConfig.fromJson(json['sleep_query']),
chessTime = json['chess_time'] != null
? TimeConfig.fromJson(json['chess_time'])
- : null;
+ : null,
+ startedAt = DateTime.parse(json['startedAt']);
}
class QueryConfig {
diff --git a/lib/models/sleep.dart b/lib/models/sleep.dart
index 4447be4..e6a0b80 100644
--- a/lib/models/sleep.dart
+++ b/lib/models/sleep.dart
@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:smoke_cess_app/interface/db_record.dart';
+import 'package:smoke_cess_app/utils/timer_util.dart';
class Sleep implements DatabaseRecord {
final int _sleepQualityValue;
@@ -12,7 +13,9 @@ class Sleep implements DatabaseRecord {
this._wokeUpAt);
DateTime get date => _date;
+ String get comment => _comment;
int get sleepQualitiyValue => _sleepQualityValue;
+ TimeOfDay get sleepDuration => _sleptAt.durationBetween(_wokeUpAt);
@override
factory Sleep.fromDatabase(Map map) {
diff --git a/lib/pages/interval_page.dart b/lib/pages/interval_page.dart
index 2326168..484ae20 100644
--- a/lib/pages/interval_page.dart
+++ b/lib/pages/interval_page.dart
@@ -1,9 +1,8 @@
import 'package:flutter/material.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 '../widgets/view_form_page.dart';
+import 'package:smoke_cess_app/widgets/view_form/workout_form.dart';
+import 'package:smoke_cess_app/widgets/view_form/workout_view.dart';
+import 'package:smoke_cess_app/widgets/view_form/view_form_page.dart';
class IntervalTimerPage extends StatelessWidget {
const IntervalTimerPage({super.key});
diff --git a/lib/pages/main_page.dart b/lib/pages/main_page.dart
index 10ff0ec..9d6c77b 100644
--- a/lib/pages/main_page.dart
+++ b/lib/pages/main_page.dart
@@ -8,52 +8,49 @@ import 'package:smoke_cess_app/providers/settings_provider.dart';
import '../widgets/todo_icon.dart';
-class MyHomePage extends StatefulWidget {
+class MyHomePage extends StatelessWidget {
const MyHomePage({super.key});
- @override
- MyHomePageState createState() => MyHomePageState();
-}
-
-class MyHomePageState extends State {
- int _selectedIndex = 4;
- bool _isConfigured = false;
-
- void _onItemTapped(int index) {
- PageProvider pageProvider = context.read();
- setState(() {
- 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();
- var tasksModel = context.watch();
- _isConfigured = settingsModel.initialized;
+ SettingsProvider settingsProvider = context.watch();
+ TasksProvider tasksProvider = context.watch();
+ PageProvider pageProvider = context.watch();
+ bool isConfigured = settingsProvider.initialized;
+
return Scaffold(
appBar: AppBar(
- title: Text(
- '${pages.values.elementAt(_selectedIndex)['title']} ${_isConfigured ? "Gruppe ${settingsModel.settings?.group}" : ""}')),
- body: SingleChildScrollView(
- child: pages.values.elementAt(_selectedIndex)['page'],
- ),
+ title: Row(
+ children: [
+ Stack(
+ children: [
+ const SizedBox(
+ width: 70,
+ ),
+ if (pageProvider.showForm)
+ IconButton(
+ icon: const Icon(Icons.arrow_back, color: Colors.white),
+ onPressed: pageProvider.swap),
+ ],
+ ),
+ Text(
+ '${pageProvider.currentPageData['title']} ${isConfigured ? "Gruppe ${settingsProvider.settings?.group}" : ""}')
+ ],
+ )),
+ body: pageProvider.currentPageData['page'],
bottomNavigationBar: NavigationBar(
- onDestinationSelected: _onItemTapped,
- selectedIndex: _selectedIndex,
+ onDestinationSelected: isConfigured
+ ? pageProvider.setCurrentPage
+ : (value) => AwesomeDialog(
+ context: context,
+ dialogType: DialogType.info,
+ title: 'Fehlende Konfiguration',
+ desc: 'Bitte QR Code Scannen!',
+ ).show(),
+ selectedIndex: pageProvider.currentPageIndex,
destinations: pages.keys.map((key) {
return NavigationDestination(
- icon: tasksModel.tasks[key] ?? false
+ icon: tasksProvider.tasks[key] ?? false
? MyToDoIcon(pages[key]?['icon'])
: pages[key]!['icon'],
label: pages[key]?['title']);
diff --git a/lib/pages/mood_page.dart b/lib/pages/mood_page.dart
index 8c2447d..f5b8009 100644
--- a/lib/pages/mood_page.dart
+++ b/lib/pages/mood_page.dart
@@ -1,8 +1,8 @@
import 'package:flutter/material.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';
+import 'package:smoke_cess_app/widgets/view_form/mood_form.dart';
+import 'package:smoke_cess_app/widgets/view_form/mood_view.dart';
+import 'package:smoke_cess_app/widgets/view_form/view_form_page.dart';
class MoodPage extends StatelessWidget {
const MoodPage({super.key});
diff --git a/lib/pages/relapse_page.dart b/lib/pages/relapse_page.dart
index e7b6127..db75e86 100644
--- a/lib/pages/relapse_page.dart
+++ b/lib/pages/relapse_page.dart
@@ -1,8 +1,8 @@
import 'package:flutter/material.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_view.dart';
-import '../widgets/view_form_page.dart';
+import 'package:smoke_cess_app/widgets/view_form/relapse_form.dart';
+import 'package:smoke_cess_app/widgets/view_form/relapse_view.dart';
+import 'package:smoke_cess_app/widgets/view_form/view_form_page.dart';
class RelapsePage extends StatelessWidget {
const RelapsePage({super.key});
diff --git a/lib/pages/scanner_page.dart b/lib/pages/scanner_page.dart
index ebba252..eee7dd0 100644
--- a/lib/pages/scanner_page.dart
+++ b/lib/pages/scanner_page.dart
@@ -4,8 +4,10 @@ import 'package:provider/provider.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/buttons/text_icon_button.dart';
import 'package:smoke_cess_app/widgets/scanner.dart';
import '../providers/settings_provider.dart';
+import '../globals.dart' as globals;
class ScannerPage extends StatelessWidget {
const ScannerPage({super.key});
@@ -16,7 +18,7 @@ class ScannerPage extends StatelessWidget {
}
void loadJSON(BuildContext context) async {
- var settingsModel = context.read();
+ SettingsProvider settingsModel = context.read();
await loadSettingsFromLocalJSON();
settingsModel.initSettings();
NotificationService().setAllNotifications();
@@ -32,25 +34,26 @@ class ScannerPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
+ SettingsProvider settingsProvider = context.watch();
+
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const MyScanner(),
const SizedBox(height: 30),
- ElevatedButton(
- style: ElevatedButton.styleFrom(
- textStyle: const TextStyle(fontSize: 20)),
- onPressed: () => loadJSON(context),
- child: const Text('Read JSON'),
- ),
- const SizedBox(height: 30),
- ElevatedButton(
- style: ElevatedButton.styleFrom(
- textStyle: const TextStyle(fontSize: 20)),
- onPressed: export,
- child: const Text('Export'),
- )
+ if (!settingsProvider.scanning)
+ TextIconButton(
+ text: 'Export',
+ onPressed: ExportService().exportData,
+ iconData: Icons.upload),
+ if (globals.useLocalConfig && !settingsProvider.scanning)
+ ElevatedButton(
+ style: ElevatedButton.styleFrom(
+ textStyle: const TextStyle(fontSize: 20)),
+ onPressed: () => loadJSON(context),
+ child: const Text('Read JSON'),
+ ),
],
));
}
diff --git a/lib/pages/sleep_page.dart b/lib/pages/sleep_page.dart
index 3cf3fd5..8d9842d 100644
--- a/lib/pages/sleep_page.dart
+++ b/lib/pages/sleep_page.dart
@@ -1,8 +1,8 @@
import 'package:flutter/material.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';
+import 'package:smoke_cess_app/widgets/view_form/sleep_form.dart';
+import 'package:smoke_cess_app/widgets/view_form/sleep_view.dart';
+import 'package:smoke_cess_app/widgets/view_form/view_form_page.dart';
class SleepPage extends StatelessWidget {
const SleepPage({super.key});
diff --git a/lib/providers/page_provider.dart b/lib/providers/page_provider.dart
index a17ff26..8184ee7 100644
--- a/lib/providers/page_provider.dart
+++ b/lib/providers/page_provider.dart
@@ -1,10 +1,22 @@
import 'package:flutter/material.dart';
+import 'package:smoke_cess_app/services/pages_service.dart';
class PageProvider extends ChangeNotifier {
bool showForm = false;
+ Pages _currentPage = Pages.settings;
void swap() {
showForm = !showForm;
notifyListeners();
}
+
+ Map get currentPageData => pages[_currentPage]!;
+
+ int get currentPageIndex => _currentPage.index;
+
+ void setCurrentPage(int index) {
+ showForm = false;
+ _currentPage = Pages.values[index];
+ notifyListeners();
+ }
}
diff --git a/lib/providers/settings_provider.dart b/lib/providers/settings_provider.dart
index f51c5e1..121ff0d 100644
--- a/lib/providers/settings_provider.dart
+++ b/lib/providers/settings_provider.dart
@@ -6,9 +6,16 @@ import '../models/settings.dart';
class SettingsProvider extends ChangeNotifier {
Settings? _settings;
bool _initialized = false;
+ bool _scanning = false;
Settings? get settings => _settings;
bool get initialized => _initialized;
+ bool get scanning => _scanning;
+
+ set scanning(bool value) {
+ _scanning = value;
+ notifyListeners();
+ }
SettingsProvider() {
initSettings();
diff --git a/lib/providers/tasks_provider.dart b/lib/providers/tasks_provider.dart
index d3fc042..2fed9b8 100644
--- a/lib/providers/tasks_provider.dart
+++ b/lib/providers/tasks_provider.dart
@@ -5,7 +5,7 @@ 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 'package:timezone/timezone.dart';
import '../globals.dart' as globals;
import '../models/mood.dart';
diff --git a/lib/providers/timer_provider.dart b/lib/providers/timer_provider.dart
index f355d7d..298316a 100644
--- a/lib/providers/timer_provider.dart
+++ b/lib/providers/timer_provider.dart
@@ -5,13 +5,18 @@ import 'package:flutter/material.dart';
class TimerProvider extends ChangeNotifier {
Timer? _timer;
bool started = false;
- int get elapsedSeconds => _timer != null ? _timer!.tick : 0;
+ Duration _duration = const Duration();
+ int get elapsedSeconds => _duration.inSeconds;
+ int get elapsedMilliseconds => _duration.inMilliseconds;
+ final Duration _tickRate = const Duration(milliseconds: 20);
void startTimer(Duration duration) {
+ _duration = Duration.zero;
started = true;
- _timer = Timer.periodic(const Duration(seconds: 1), ((timer) {
- if (timer.tick >= duration.inSeconds) {
- timer.cancel();
+ _timer = Timer.periodic(_tickRate, ((timer) {
+ _duration += _tickRate;
+ if (elapsedSeconds >= duration.inSeconds) {
+ _timer?.cancel();
started = false;
}
notifyListeners();
@@ -22,13 +27,12 @@ class TimerProvider extends ChangeNotifier {
started = false;
_timer?.cancel();
_timer = null;
+ _duration = Duration.zero;
}
@override
void dispose() {
- started = false;
- _timer?.cancel();
- _timer = null;
+ stopTimer();
super.dispose();
}
}
diff --git a/lib/services/pages_service.dart b/lib/services/pages_service.dart
index 0c19383..9ec00d6 100644
--- a/lib/services/pages_service.dart
+++ b/lib/services/pages_service.dart
@@ -8,8 +8,8 @@ import '../pages/sleep_page.dart';
enum Pages {
mood,
sleep,
- relapse,
timer,
+ relapse,
settings,
}
diff --git a/lib/services/settings_service.dart b/lib/services/settings_service.dart
index f28556a..ec8a656 100644
--- a/lib/services/settings_service.dart
+++ b/lib/services/settings_service.dart
@@ -23,6 +23,8 @@ Future getMoodQueryMinutes() => _getIntSetting('mood_query_minutes');
Future getChessHours() => _getIntSetting('chess_hours');
Future getChessMinutes() => _getIntSetting('chess_minutes');
+Future getStartDay() => _getStringSetting('startedAt');
+
void _setIntSetting(String settingKey, int settingValue) =>
SharedPreferences.getInstance()
.then((pref) => pref.setInt(settingKey, settingValue));
@@ -30,6 +32,13 @@ void _setIntSetting(String settingKey, int settingValue) =>
Future _getIntSetting(String settingKey) =>
SharedPreferences.getInstance().then((pref) => pref.getInt(settingKey));
+void _setStringSetting(String settingKey, String settingValue) =>
+ SharedPreferences.getInstance()
+ .then((pref) => pref.setString(settingKey, settingValue));
+
+Future _getStringSetting(String settingKey) =>
+ SharedPreferences.getInstance().then((pref) => pref.getString(settingKey));
+
void _setStringListSetting(String settingKey, List list) =>
SharedPreferences.getInstance()
.then((pref) => pref.setStringList(settingKey, list));
@@ -40,6 +49,7 @@ Future?> _getStringListSetting(String settingKey) =>
Future loadSettingsFromLocalJSON() async {
Map configJSON = await loadLocalConfigJSON();
+ configJSON['startedAt'] = DateTime.now().toIso8601String();
Settings settings = Settings.fromJson(configJSON);
saveSettings(settings);
}
@@ -53,6 +63,7 @@ void saveSettings(Settings settings) {
_setStringListSetting('sleep_query_days', settings.sleepQuery!.days!);
_setIntSetting('sleep_query_hours', settings.sleepQuery!.hours!);
_setIntSetting('sleep_query_minutes', settings.sleepQuery!.minutes!);
+ _setStringSetting('startedAt', DateTime.now().toIso8601String());
if (settings.chessTime != null) {
_setIntSetting('chess_hours', settings.chessTime!.hours!);
_setIntSetting('chess_minutes', settings.chessTime!.minutes!);
@@ -70,6 +81,8 @@ Future loadSettings() async {
List? sleepDays = await getSleepQueryDaysCategories();
int? chessHours = await getChessHours();
int? chessMinutes = await getChessMinutes();
+ DateTime startedAt =
+ DateTime.parse(await getStartDay() ?? DateTime.now().toIso8601String());
if (group != null) {
return Settings(
@@ -77,7 +90,8 @@ Future loadSettings() async {
relapseCategories,
QueryConfig(moodHours, moodMinutes, moodDays),
QueryConfig(sleepHours, sleepMinutes, sleepDays),
- TimeConfig(chessHours, chessMinutes));
+ TimeConfig(chessHours, chessMinutes),
+ startedAt);
}
return null;
}
diff --git a/lib/utils/timer_util.dart b/lib/utils/timer_util.dart
index a63030f..57b9f9c 100644
--- a/lib/utils/timer_util.dart
+++ b/lib/utils/timer_util.dart
@@ -1,3 +1,5 @@
+import 'package:flutter/material.dart';
+
String formatTime(int seconds) {
Duration duration = Duration(seconds: seconds);
String formattedTime = '';
@@ -6,9 +8,20 @@ String formatTime(int seconds) {
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.inDays != 0) {
+ formattedTime += '$days Tag ${duration.inDays > 1 ? "e" : ""}, ';
+ }
if (duration.inHours != 0) formattedTime += '$hours:';
formattedTime += '$minutes:';
formattedTime += formattedSeconds;
return formattedTime;
}
+
+extension TimeOfDayExtension on TimeOfDay {
+ TimeOfDay durationBetween(TimeOfDay time) {
+ int hourOffset = time.minute - minute < 0 ? 1 : 0;
+ return TimeOfDay(
+ hour: (time.hour - hour - hourOffset) % 24,
+ minute: (time.minute - minute) % 60);
+ }
+}
diff --git a/lib/widgets/mute_button.dart b/lib/widgets/buttons/mute_button.dart
similarity index 92%
rename from lib/widgets/mute_button.dart
rename to lib/widgets/buttons/mute_button.dart
index 29bebf7..d74eb97 100644
--- a/lib/widgets/mute_button.dart
+++ b/lib/widgets/buttons/mute_button.dart
@@ -1,7 +1,6 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
-
-import '../providers/audio_provider.dart';
+import '../../providers/audio_provider.dart';
class MuteButton extends StatelessWidget {
const MuteButton({super.key});
diff --git a/lib/widgets/buttons/round_button_widget.dart b/lib/widgets/buttons/round_button_widget.dart
new file mode 100644
index 0000000..9e8d7ac
--- /dev/null
+++ b/lib/widgets/buttons/round_button_widget.dart
@@ -0,0 +1,27 @@
+import 'package:flutter/material.dart';
+
+class RoundIconButton extends StatelessWidget {
+ final VoidCallback onPressed;
+ final IconData iconData;
+
+ const RoundIconButton(
+ {super.key, required this.onPressed, required this.iconData});
+
+ @override
+ Widget build(BuildContext context) {
+ return ElevatedButton(
+ onPressed: onPressed,
+ style: ElevatedButton.styleFrom(
+ shape: const CircleBorder(),
+ padding: const EdgeInsets.all(20),
+ backgroundColor: Colors.green, // <-- Button color
+ foregroundColor: Colors.blue, // <-- Splash color
+ ),
+ child: Icon(
+ iconData,
+ color: Colors.white,
+ size: MediaQuery.of(context).size.height * 0.05,
+ ),
+ );
+ }
+}
diff --git a/lib/widgets/submit_form_button.dart b/lib/widgets/buttons/submit_form_button.dart
similarity index 90%
rename from lib/widgets/submit_form_button.dart
rename to lib/widgets/buttons/submit_form_button.dart
index f9cb784..f338339 100644
--- a/lib/widgets/submit_form_button.dart
+++ b/lib/widgets/buttons/submit_form_button.dart
@@ -2,6 +2,7 @@ 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/widgets/buttons/round_button_widget.dart';
class SubmitFormButton extends StatelessWidget {
final Future Function() submitCallback;
@@ -14,7 +15,7 @@ class SubmitFormButton extends StatelessWidget {
PageProvider pageProvider = context.watch();
return Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
- child: ElevatedButton(
+ child: RoundIconButton(
onPressed: () async {
int success = await submitCallback();
if (context.mounted) {
@@ -37,7 +38,7 @@ class SubmitFormButton extends StatelessWidget {
}
}
},
- child: const Text('Speichern'),
+ iconData: Icons.check_outlined,
),
);
}
diff --git a/lib/widgets/buttons/text_icon_button.dart b/lib/widgets/buttons/text_icon_button.dart
new file mode 100644
index 0000000..85534e2
--- /dev/null
+++ b/lib/widgets/buttons/text_icon_button.dart
@@ -0,0 +1,29 @@
+import 'package:flutter/material.dart';
+
+class TextIconButton extends StatelessWidget {
+ final String text;
+ final VoidCallback onPressed;
+ final IconData iconData;
+
+ const TextIconButton(
+ {super.key,
+ required this.text,
+ required this.onPressed,
+ required this.iconData});
+
+ @override
+ Widget build(BuildContext context) {
+ return SizedBox(
+ width: MediaQuery.of(context).size.width * 0.4,
+ child: FloatingActionButton.extended(
+ label: Text(text),
+ backgroundColor: Theme.of(context).colorScheme.primary,
+ icon: Icon(
+ iconData,
+ size: 24.0,
+ ),
+ onPressed: onPressed,
+ ),
+ );
+ }
+}
diff --git a/lib/widgets/timer_button.dart b/lib/widgets/buttons/timer_button.dart
similarity index 100%
rename from lib/widgets/timer_button.dart
rename to lib/widgets/buttons/timer_button.dart
diff --git a/lib/widgets/entry_detail_title.dart b/lib/widgets/entry_detail_title.dart
new file mode 100644
index 0000000..110e38f
--- /dev/null
+++ b/lib/widgets/entry_detail_title.dart
@@ -0,0 +1,33 @@
+import 'package:flutter/material.dart';
+import 'package:intl/intl.dart';
+
+class EntryDetailTitle extends StatelessWidget {
+ final DateTime date;
+ final String entryData;
+
+ const EntryDetailTitle(
+ {super.key, required this.date, required this.entryData});
+
+ @override
+ Widget build(BuildContext context) {
+ return Row(
+ mainAxisAlignment: MainAxisAlignment.start,
+ children: [
+ Text(
+ DateFormat.MMMd('de').format(date),
+ style:
+ const TextStyle(color: Colors.white, fontWeight: FontWeight.bold),
+ ),
+ Flexible(
+ child: Container(
+ padding: const EdgeInsets.symmetric(horizontal: 5.0),
+ child: Text(
+ entryData,
+ overflow: TextOverflow.ellipsis,
+ style: const TextStyle(
+ color: Colors.white, fontWeight: FontWeight.bold),
+ )))
+ ],
+ );
+ }
+}
diff --git a/lib/widgets/entry_detail_widget.dart b/lib/widgets/entry_detail_widget.dart
new file mode 100644
index 0000000..0f7a70e
--- /dev/null
+++ b/lib/widgets/entry_detail_widget.dart
@@ -0,0 +1,58 @@
+import 'package:flutter/material.dart';
+import 'package:smoke_cess_app/widgets/entry_detail_title.dart';
+
+class EntryDetail extends StatelessWidget {
+ final DateTime date;
+ final String entryData;
+ final String? entryComment;
+ final IconData iconData;
+
+ const EntryDetail(
+ {super.key,
+ required this.date,
+ required this.entryData,
+ required this.iconData,
+ required this.entryComment});
+
+ @override
+ Widget build(BuildContext context) {
+ final Icon icon = Icon(iconData, color: Colors.white);
+ final ShapeBorder shape = RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(10.0),
+ );
+ final Color color = Theme.of(context).colorScheme.primary.withOpacity(0.8);
+ final Widget title = EntryDetailTitle(date: date, entryData: entryData);
+ return entryComment != null
+ ? ExpansionTile(
+ iconColor: Colors.white,
+ collapsedIconColor: Colors.white,
+ collapsedShape: shape,
+ shape: shape,
+ leading: icon,
+ title: title,
+ collapsedBackgroundColor: color,
+ backgroundColor:
+ Theme.of(context).colorScheme.secondary.withOpacity(0.8),
+ children: entryComment != null
+ ? [
+ Row(mainAxisAlignment: MainAxisAlignment.start, children: [
+ Padding(
+ padding: const EdgeInsets.fromLTRB(10, 0, 10, 10),
+ child: Text(
+ entryComment ?? '',
+ style: const TextStyle(
+ color: Colors.white,
+ fontWeight: FontWeight.bold),
+ ))
+ ])
+ ]
+ : [],
+ )
+ : ListTile(
+ shape: shape,
+ leading: icon,
+ title: title,
+ tileColor: color,
+ );
+ }
+}
diff --git a/lib/widgets/history_list_widget.dart b/lib/widgets/history_list_widget.dart
new file mode 100644
index 0000000..de434e1
--- /dev/null
+++ b/lib/widgets/history_list_widget.dart
@@ -0,0 +1,52 @@
+import 'package:flutter/material.dart';
+import 'package:smoke_cess_app/widgets/entry_detail_widget.dart';
+
+class HistoryList extends StatelessWidget {
+ final List history;
+ final DateTime Function(T) dateSelector;
+ final String Function(T) entryDataSelector;
+ final IconData Function(T)? iconDataSelector;
+ final String Function(T)? entryCommentSelector;
+ final IconData? icon;
+
+ const HistoryList(
+ {super.key,
+ required this.history,
+ required this.dateSelector,
+ required this.entryDataSelector,
+ this.iconDataSelector,
+ this.icon,
+ this.entryCommentSelector});
+
+ IconData _getIcon(T entry) {
+ if (icon != null) {
+ return icon!;
+ } else if (iconDataSelector != null) {
+ return iconDataSelector!(entry);
+ }
+ return Icons.circle;
+ }
+
+ String? _getComment(T entry) {
+ if (entryCommentSelector != null) {
+ return entryCommentSelector!(entry);
+ }
+ return null;
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Expanded(
+ child: ListView(
+ padding: const EdgeInsets.fromLTRB(10, 10, 10, 10),
+ children: history.map((T entry) {
+ return Padding(
+ padding: const EdgeInsets.only(bottom: 5),
+ child: EntryDetail(
+ date: dateSelector(entry),
+ entryData: entryDataSelector(entry),
+ entryComment: _getComment(entry),
+ iconData: _getIcon(entry)));
+ }).toList()));
+ }
+}
diff --git a/lib/widgets/line_chart_widget.dart b/lib/widgets/line_chart_widget.dart
new file mode 100644
index 0000000..de24754
--- /dev/null
+++ b/lib/widgets/line_chart_widget.dart
@@ -0,0 +1,31 @@
+import 'package:flutter/material.dart';
+import 'package:intl/intl.dart';
+import 'package:provider/provider.dart';
+import 'package:smoke_cess_app/providers/settings_provider.dart';
+import 'package:syncfusion_flutter_charts/charts.dart';
+
+class LineChart extends StatelessWidget {
+ final List> series;
+ const LineChart({
+ super.key,
+ required this.series,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ SettingsProvider settingsProvider = context.watch();
+
+ return SfCartesianChart(
+ primaryXAxis: DateTimeAxis(
+ minimum: settingsProvider.settings?.startedAt,
+ maximum: settingsProvider.settings?.startedAt
+ .add(const Duration(days: 7 * 6)),
+ interval: 7,
+ dateFormat: DateFormat.Md('de'),
+ ),
+ primaryYAxis:
+ NumericAxis(isVisible: false, minimum: 0, maximum: 100, interval: 20),
+ series: series,
+ );
+ }
+}
diff --git a/lib/widgets/mood_view.dart b/lib/widgets/mood_view.dart
deleted file mode 100644
index 14884b9..0000000
--- a/lib/widgets/mood_view.dart
+++ /dev/null
@@ -1,32 +0,0 @@
-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();
- return Column(
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- SfCartesianChart(
- primaryXAxis: DateTimeAxis(),
- series: [
- LineSeries(
- 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())
- ],
- );
- }
-}
diff --git a/lib/widgets/missing_config_popup.dart b/lib/widgets/popup/missing_config_popup.dart
similarity index 100%
rename from lib/widgets/missing_config_popup.dart
rename to lib/widgets/popup/missing_config_popup.dart
diff --git a/lib/widgets/popup_for_start_and_stop.dart b/lib/widgets/popup/popup_for_start_and_stop.dart
similarity index 100%
rename from lib/widgets/popup_for_start_and_stop.dart
rename to lib/widgets/popup/popup_for_start_and_stop.dart
diff --git a/lib/widgets/popup/popup_for_task_done.dart b/lib/widgets/popup/popup_for_task_done.dart
new file mode 100644
index 0000000..4565aca
--- /dev/null
+++ b/lib/widgets/popup/popup_for_task_done.dart
@@ -0,0 +1,45 @@
+import 'package:awesome_dialog/awesome_dialog.dart';
+import 'package:flutter/material.dart';
+import 'package:provider/provider.dart';
+import 'package:smoke_cess_app/services/date_service.dart';
+import 'package:smoke_cess_app/services/pages_service.dart';
+import 'package:smoke_cess_app/widgets/timer_widget.dart';
+
+import '../../providers/timer_provider.dart';
+
+void showTaskDonePopup(BuildContext context, Pages page) async {
+ Duration duration = await getTimeTill(page);
+ if (context.mounted) {
+ AwesomeDialog(
+ context: context,
+ dialogType: DialogType.info,
+ body: Column(
+ children: [
+ Text(
+ '${pages[page]?['title']} schon eingegeben',
+ style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
+ ),
+ const SizedBox(
+ height: 10,
+ ),
+ const Text(
+ 'Nächste Abfrage in',
+ ),
+ const SizedBox(
+ height: 8,
+ ),
+ ChangeNotifierProvider(
+ create: (context) => TimerProvider(),
+ builder: (context, child) {
+ TimerProvider timerProvider = context.read();
+ timerProvider.startTimer(duration);
+ return TimerWidget(duration: duration);
+ },
+ ),
+ const SizedBox(
+ height: 15,
+ ),
+ ],
+ )).show();
+ }
+}
diff --git a/lib/widgets/popup_for_task_done.dart b/lib/widgets/popup_for_task_done.dart
deleted file mode 100644
index fbaa65d..0000000
--- a/lib/widgets/popup_for_task_done.dart
+++ /dev/null
@@ -1,43 +0,0 @@
-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.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)
- ]));
- }
-}
diff --git a/lib/widgets/relapse_view.dart b/lib/widgets/relapse_view.dart
deleted file mode 100644
index 48c9829..0000000
--- a/lib/widgets/relapse_view.dart
+++ /dev/null
@@ -1,17 +0,0 @@
-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();
- return Column(
- mainAxisAlignment: MainAxisAlignment.center,
- children: tasksModel.relapseHistory.map((relapse) {
- return Text('${relapse.date}: ${relapse.category}');
- }).toList());
- }
-}
diff --git a/lib/widgets/scanner.dart b/lib/widgets/scanner.dart
index b635d67..c292bf4 100644
--- a/lib/widgets/scanner.dart
+++ b/lib/widgets/scanner.dart
@@ -5,80 +5,81 @@ import 'package:provider/provider.dart';
import 'package:smoke_cess_app/models/settings.dart';
import 'package:smoke_cess_app/services/json_service.dart';
import 'package:smoke_cess_app/services/settings_service.dart';
+import 'package:smoke_cess_app/widgets/buttons/text_icon_button.dart';
import '../providers/settings_provider.dart';
import '../services/notification_service.dart';
-class MyScanner extends StatefulWidget {
+class MyScanner extends StatelessWidget {
const MyScanner({super.key});
@override
- State createState() => MyScannerState();
-}
+ Widget build(BuildContext context) {
+ SettingsProvider settingsProvider = context.watch();
-class MyScannerState extends State {
- bool scanning = false;
+ void handleSucces(String? rawValue) {
+ String qrText = rawValue!;
+ Map json = stringToJSON(qrText);
+ Settings settings = Settings.fromJson(json);
+ saveSettings(settings);
+ settingsProvider.initSettings();
+ NotificationService().setAllNotifications();
+ settingsProvider.scanning = false;
- void handleSucces(String? rawValue) {
- String qrText = rawValue!;
- Map json = stringToJSON(qrText);
- Settings settings = Settings.fromJson(json);
- saveSettings(settings);
- var settingsModel = context.read();
- settingsModel.initSettings();
- NotificationService().setAllNotifications();
- setState(() {
- scanning = false;
AwesomeDialog(
context: context,
dialogType: DialogType.success,
title: 'Geschafft',
desc: 'Der Code wurde erfolgreich gescannt!',
).show();
- });
- }
+ }
+
+ void handleError() {
+ settingsProvider.scanning = false;
- void handleError() {
- setState(() {
- scanning = false;
AwesomeDialog(
context: context,
dialogType: DialogType.error,
title: 'Fehler',
desc: 'Der QR-Code war fehlerhaft!',
).show();
- });
- }
-
- void onDetect(capture) {
- try {
- final List barcodes = capture.barcodes;
- for (final barcode in barcodes) {
- if (barcode.rawValue != null) {
- return handleSucces(barcode.rawValue);
- }
- }
- } catch (e) {
- handleError();
}
- }
- @override
- Widget build(BuildContext context) {
- return scanning
+ void onDetect(capture) {
+ try {
+ final List barcodes = capture.barcodes;
+ for (final barcode in barcodes) {
+ if (barcode.rawValue != null) {
+ return handleSucces(barcode.rawValue);
+ }
+ }
+ } catch (e) {
+ handleError();
+ }
+ }
+
+ return settingsProvider.scanning
? Expanded(
- child: MobileScanner(
+ child: Stack(
+ alignment: Alignment.center,
+ children: [
+ MobileScanner(
fit: BoxFit.contain,
controller: MobileScannerController(
detectionTimeoutMs: 2000,
),
- onDetect: onDetect))
- : ElevatedButton(
- style: ElevatedButton.styleFrom(
- textStyle: const TextStyle(fontSize: 20)),
- onPressed: () {
- setState(() => scanning = true);
- },
- child: const Text('Scan QR Code'),
- );
+ onDetect: onDetect,
+ ),
+ ClipRRect(
+ borderRadius: BorderRadius.circular(20),
+ child: Container(
+ height: MediaQuery.of(context).size.height / 3,
+ width: MediaQuery.of(context).size.width * 0.8,
+ color: Colors.white.withOpacity(0.4))),
+ ],
+ ))
+ : TextIconButton(
+ text: "Scan",
+ onPressed: () => settingsProvider.scanning = true,
+ iconData: Icons.qr_code_scanner_outlined);
}
}
diff --git a/lib/widgets/mood_form.dart b/lib/widgets/view_form/mood_form.dart
similarity index 78%
rename from lib/widgets/mood_form.dart
rename to lib/widgets/view_form/mood_form.dart
index e43e97d..588d542 100644
--- a/lib/widgets/mood_form.dart
+++ b/lib/widgets/view_form/mood_form.dart
@@ -3,11 +3,10 @@ import 'package:provider/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/widgets/slider.dart';
-import 'package:smoke_cess_app/widgets/submit_form_button.dart';
+import 'package:smoke_cess_app/widgets/buttons/submit_form_button.dart';
import 'package:smoke_cess_app/widgets/text_formfield.dart';
-
-import '../providers/input_provider.dart';
-import 'elevated_card.dart';
+import 'package:smoke_cess_app/providers/input_provider.dart';
+import 'package:smoke_cess_app/widgets/elevated_card.dart';
class MoodForm extends StatelessWidget {
const MoodForm({super.key});
@@ -16,8 +15,8 @@ class MoodForm extends StatelessWidget {
Widget build(BuildContext context) {
var inputModel = context.watch();
var tasksModel = context.watch();
- return Column(
- mainAxisAlignment: MainAxisAlignment.center,
+ return ListView(
+ padding: const EdgeInsets.fromLTRB(10, 10, 10, 10),
children: [
const ElevatedCard(
title: 'Stimmungsbewertung',
@@ -28,9 +27,6 @@ class MoodForm extends StatelessWidget {
title: 'Beschreibe deine Stimmung',
child: MyTextFormField('Beschreibe deine Stimmung'),
),
- const SizedBox(
- height: 80,
- ),
SubmitFormButton(
submitCallback: inputModel.saveMood,
updateTasks: () => tasksModel.setTaskDone(Pages.mood),
diff --git a/lib/widgets/view_form/mood_view.dart b/lib/widgets/view_form/mood_view.dart
new file mode 100644
index 0000000..3438f59
--- /dev/null
+++ b/lib/widgets/view_form/mood_view.dart
@@ -0,0 +1,36 @@
+import 'package:flutter/material.dart';
+import 'package:provider/provider.dart';
+import 'package:smoke_cess_app/widgets/history_list_widget.dart';
+import 'package:smoke_cess_app/widgets/line_chart_widget.dart';
+import 'package:syncfusion_flutter_charts/charts.dart';
+import 'package:smoke_cess_app/models/mood.dart';
+import 'package:smoke_cess_app/providers/tasks_provider.dart';
+
+class MoodView extends StatelessWidget {
+ const MoodView({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ var tasksModel = context.watch();
+ return Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ LineChart(series: [
+ LineSeries(
+ dataSource: tasksModel.moodHistory,
+ xValueMapper: (Mood value, _) => value.date,
+ yValueMapper: (Mood value, _) => value.moodValue)
+ ]),
+ HistoryList(
+ history: tasksModel.moodHistory,
+ dateSelector: (Mood mood) => mood.date,
+ entryDataSelector: (Mood mood) => 'Stimmung: ${mood.moodValue}',
+ entryCommentSelector: (Mood mood) => 'Kommentar: ${mood.comment}',
+ iconDataSelector: (Mood mood) => mood.moodValue >= 50
+ ? Icons.mood_outlined
+ : Icons.mood_bad_outlined,
+ )
+ ],
+ );
+ }
+}
diff --git a/lib/widgets/relapse_form.dart b/lib/widgets/view_form/relapse_form.dart
similarity index 72%
rename from lib/widgets/relapse_form.dart
rename to lib/widgets/view_form/relapse_form.dart
index 9451277..6131880 100644
--- a/lib/widgets/relapse_form.dart
+++ b/lib/widgets/view_form/relapse_form.dart
@@ -2,12 +2,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/buttons/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';
+import 'package:smoke_cess_app/providers/input_provider.dart';
+import 'package:smoke_cess_app/providers/settings_provider.dart';
+import 'package:smoke_cess_app/services/pages_service.dart';
+import 'package:smoke_cess_app/widgets/elevated_card.dart';
class RelapseForm extends StatelessWidget {
const RelapseForm({super.key});
@@ -17,8 +17,8 @@ class RelapseForm extends StatelessWidget {
var inputModel = context.watch();
var settingsModel = context.watch();
var tasksModel = context.watch();
- return Column(
- mainAxisAlignment: MainAxisAlignment.center,
+ return ListView(
+ padding: const EdgeInsets.fromLTRB(10, 10, 10, 10),
children: [
ElevatedCard(
title: 'Rückfallkategorie',
@@ -28,9 +28,6 @@ class RelapseForm extends StatelessWidget {
title: 'Beschreibe deinen Rückfall',
child: MyTextFormField('Beschreibe deinen Rückfall'),
),
- const SizedBox(
- height: 80,
- ),
SubmitFormButton(
submitCallback: inputModel.saveRelapse,
updateTasks: () => tasksModel.setTaskDone(Pages.mood),
diff --git a/lib/widgets/view_form/relapse_view.dart b/lib/widgets/view_form/relapse_view.dart
new file mode 100644
index 0000000..98c011b
--- /dev/null
+++ b/lib/widgets/view_form/relapse_view.dart
@@ -0,0 +1,24 @@
+import 'package:flutter/material.dart';
+import 'package:provider/provider.dart';
+import 'package:smoke_cess_app/models/relapse.dart';
+import 'package:smoke_cess_app/providers/tasks_provider.dart';
+import 'package:smoke_cess_app/widgets/history_list_widget.dart';
+
+class RelapseView extends StatelessWidget {
+ const RelapseView({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ TasksProvider tasksModel = context.watch();
+ return Column(children: [
+ HistoryList(
+ history: tasksModel.relapseHistory,
+ dateSelector: (Relapse relapse) => relapse.date,
+ entryDataSelector: (Relapse relapse) => relapse.category,
+ entryCommentSelector: (Relapse relapse) =>
+ 'Kommentar: ${relapse.comment}',
+ icon: Icons.smoke_free_outlined,
+ )
+ ]);
+ }
+}
diff --git a/lib/widgets/sleep_form.dart b/lib/widgets/view_form/sleep_form.dart
similarity index 84%
rename from lib/widgets/sleep_form.dart
rename to lib/widgets/view_form/sleep_form.dart
index 4996da7..a9998ec 100644
--- a/lib/widgets/sleep_form.dart
+++ b/lib/widgets/view_form/sleep_form.dart
@@ -3,12 +3,12 @@ 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';
+import 'package:smoke_cess_app/widgets/buttons/submit_form_button.dart';
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';
+import 'package:smoke_cess_app/providers/input_provider.dart';
+import 'package:smoke_cess_app/services/pages_service.dart';
class SleepForm extends StatelessWidget {
const SleepForm({Key? key}) : super(key: key);
@@ -18,8 +18,8 @@ class SleepForm extends StatelessWidget {
InputProvider inputModel = context.watch();
TasksProvider tasksModel = context.watch();
- return Column(
- mainAxisAlignment: MainAxisAlignment.center,
+ return ListView(
+ padding: const EdgeInsets.fromLTRB(10, 10, 10, 10),
children: [
const ElevatedCard(
title: 'Einschlafzeit',
@@ -40,9 +40,6 @@ class SleepForm extends StatelessWidget {
title: 'Schlafbeschreibung',
child: MyTextFormField('Beschreibe deinen Schlaf'),
),
- const SizedBox(
- height: 80,
- ),
SubmitFormButton(
submitCallback: () =>
inputModel.saveSleep(SleepTimes.wokeUpAt, SleepTimes.sleptAt),
diff --git a/lib/widgets/sleep_view.dart b/lib/widgets/view_form/sleep_view.dart
similarity index 50%
rename from lib/widgets/sleep_view.dart
rename to lib/widgets/view_form/sleep_view.dart
index 90a005c..e53837c 100644
--- a/lib/widgets/sleep_view.dart
+++ b/lib/widgets/view_form/sleep_view.dart
@@ -1,31 +1,36 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:smoke_cess_app/models/sleep.dart';
+import 'package:smoke_cess_app/widgets/history_list_widget.dart';
+import 'package:smoke_cess_app/widgets/line_chart_widget.dart';
+import 'package:smoke_cess_app/providers/tasks_provider.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 tasksModel = context.watch();
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
- SfCartesianChart(
- primaryXAxis: DateTimeAxis(),
- series: [
+ LineChart(
+ series: [
LineSeries(
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())
+ HistoryList(
+ history: tasksModel.sleepHistory,
+ dateSelector: (Sleep sleep) => sleep.date,
+ entryDataSelector: (Sleep sleep) =>
+ '${sleep.sleepDuration.hour}:${sleep.sleepDuration.minute}',
+ entryCommentSelector: (Sleep sleep) => 'Kommentar: ${sleep.comment}',
+ icon: Icons.bedtime_outlined,
+ )
],
);
}
diff --git a/lib/widgets/view_form/view_form_page.dart b/lib/widgets/view_form/view_form_page.dart
new file mode 100644
index 0000000..828b9af
--- /dev/null
+++ b/lib/widgets/view_form/view_form_page.dart
@@ -0,0 +1,44 @@
+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/buttons/round_button_widget.dart';
+import 'package:smoke_cess_app/providers/input_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/widgets/popup/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) {
+ final height = MediaQuery.of(context).size.height;
+ PageProvider pageProvider = context.watch();
+ TasksProvider tasksProvider = context.watch();
+ return Column(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
+ Expanded(
+ child: Center(
+ child: pageProvider.showForm
+ ? ChangeNotifierProvider(
+ create: (context) => InputProvider(),
+ child: form,
+ )
+ : view,
+ )),
+ if (!pageProvider.showForm)
+ Container(
+ margin: EdgeInsets.symmetric(vertical: height * 0.02),
+ child: RoundIconButton(
+ iconData: Icons.add_outlined,
+ onPressed: tasksProvider.tasks[page] ?? true
+ ? () => pageProvider.swap()
+ : () => showTaskDonePopup(context, page),
+ ),
+ )
+ ]);
+ }
+}
diff --git a/lib/widgets/workout_form.dart b/lib/widgets/view_form/workout_form.dart
similarity index 79%
rename from lib/widgets/workout_form.dart
rename to lib/widgets/view_form/workout_form.dart
index 3e75882..8a678c1 100644
--- a/lib/widgets/workout_form.dart
+++ b/lib/widgets/view_form/workout_form.dart
@@ -1,10 +1,10 @@
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';
+import 'package:smoke_cess_app/providers/timer_provider.dart';
+import 'package:smoke_cess_app/providers/workout_provider.dart';
+import 'package:smoke_cess_app/widgets/buttons/mute_button.dart';
+import 'package:smoke_cess_app/widgets/workout_timer_widget.dart';
class WorkoutForm extends StatelessWidget {
WorkoutForm({super.key});
diff --git a/lib/widgets/view_form/workout_view.dart b/lib/widgets/view_form/workout_view.dart
new file mode 100644
index 0000000..3e904e6
--- /dev/null
+++ b/lib/widgets/view_form/workout_view.dart
@@ -0,0 +1,38 @@
+import 'package:flutter/material.dart';
+import 'package:provider/provider.dart';
+import 'package:smoke_cess_app/models/workout.dart';
+import 'package:smoke_cess_app/widgets/history_list_widget.dart';
+import 'package:smoke_cess_app/widgets/line_chart_widget.dart';
+import 'package:syncfusion_flutter_charts/charts.dart';
+import 'package:smoke_cess_app/providers/tasks_provider.dart';
+
+class WorkoutView extends StatelessWidget {
+ const WorkoutView({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ TasksProvider tasksModel = context.watch();
+ return Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ LineChart(series: [
+ LineSeries(
+ dataSource: tasksModel.workoutHistory,
+ xValueMapper: (Workout value, _) => value.date,
+ yValueMapper: (Workout value, _) => value.motivationBefore),
+ LineSeries(
+ dataSource: tasksModel.workoutHistory,
+ xValueMapper: (Workout value, _) => value.date,
+ yValueMapper: (Workout value, _) => value.motivationAfter)
+ ]),
+ HistoryList(
+ history: tasksModel.workoutHistory,
+ dateSelector: (Workout workout) => workout.date,
+ entryDataSelector: (Workout workout) =>
+ '${workout.motivationBefore} : ${workout.motivationAfter}',
+ icon: Icons.sports_score_outlined,
+ )
+ ],
+ );
+ }
+}
diff --git a/lib/widgets/view_form_page.dart b/lib/widgets/view_form_page.dart
deleted file mode 100644
index 57b9271..0000000
--- a/lib/widgets/view_form_page.dart
+++ /dev/null
@@ -1,41 +0,0 @@
-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();
- TasksProvider tasksProvider = context.watch();
- 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)
- ]);
- }
-}
diff --git a/lib/widgets/workout_timer_widget.dart b/lib/widgets/workout_timer_widget.dart
index 4f1b64c..51e7f0c 100644
--- a/lib/widgets/workout_timer_widget.dart
+++ b/lib/widgets/workout_timer_widget.dart
@@ -4,13 +4,13 @@ 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';
+import 'package:smoke_cess_app/providers/page_provider.dart';
+import 'package:smoke_cess_app/providers/tasks_provider.dart';
+import 'package:smoke_cess_app/providers/workout_provider.dart';
+import 'package:smoke_cess_app/services/pages_service.dart';
+import 'package:smoke_cess_app/widgets/timer_widget.dart';
+import 'package:smoke_cess_app/providers/timer_provider.dart';
+import 'package:smoke_cess_app/widgets/popup/popup_for_start_and_stop.dart';
class WorkoutTimerWidget extends StatelessWidget {
const WorkoutTimerWidget({super.key});
@@ -74,10 +74,12 @@ class WorkoutTimerWidget extends StatelessWidget {
width: 100,
child: CircularProgressIndicator(
color: workoutProvider.currentPhaseColor,
- value: (workoutProvider.currentPhaseDuration.inSeconds
- .toDouble() -
- timerProvider.elapsedSeconds) /
- workoutProvider.currentPhaseDuration.inSeconds)),
+ value:
+ (workoutProvider.currentPhaseDuration.inMilliseconds -
+ timerProvider.elapsedMilliseconds)
+ .toDouble() /
+ workoutProvider.currentPhaseDuration.inMilliseconds
+ .toDouble())),
TimerWidget(duration: workoutProvider.currentPhaseDuration),
],
),
diff --git a/lib/widgets/workout_view.dart b/lib/widgets/workout_view.dart
deleted file mode 100644
index d0deb4d..0000000
--- a/lib/widgets/workout_view.dart
+++ /dev/null
@@ -1,32 +0,0 @@
-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();
- return Column(
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- SfCartesianChart(
- primaryXAxis: DateTimeAxis(),
- series: [
- LineSeries(
- dataSource: tasksModel.workoutHistory,
- xValueMapper: (Workout value, _) => value.date,
- yValueMapper: (Workout value, _) => value.motivationBefore),
- LineSeries(
- dataSource: tasksModel.workoutHistory,
- xValueMapper: (Workout value, _) => value.date,
- yValueMapper: (Workout value, _) => value.motivationAfter)
- ],
- ),
- ],
- );
- }
-}
diff --git a/pubspec.yaml b/pubspec.yaml
index 690527f..ac1fafe 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -24,6 +24,7 @@ dependencies:
http: ^0.13.5
syncfusion_flutter_charts: ^20.4.52
cupertino_icons: ^1.0.2
+ intl: ^0.18.0
dev_dependencies:
flutter_test: