diff --git a/lib/main.dart b/lib/main.dart index 2c2245d..a1cf5ac 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,8 +1,10 @@ import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; import 'package:smoke_cess_app/pages/main_page.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/settings_provider.dart'; void main() { // to ensure all the widgets are initialized. @@ -21,6 +23,11 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { - return const MaterialApp(title: _title, home: MyHomePage()); + return MaterialApp( + title: _title, + home: ChangeNotifierProvider( + create: (context) => SettingsProvider(), + child: const MyHomePage(), + )); } } diff --git a/lib/mock/db_mock.dart b/lib/mock/db_mock.dart index 6daa0c4..68e3b4d 100644 --- a/lib/mock/db_mock.dart +++ b/lib/mock/db_mock.dart @@ -1,5 +1,6 @@ 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'; @@ -14,6 +15,7 @@ class DatabaseMock implements DatabaseService { final List _moodRecords = []; final List _sleepRecords = []; + final List _relapseRecords = []; final List _workoutRecords = []; @override @@ -34,6 +36,12 @@ class DatabaseMock implements DatabaseService { return Future.value(1); } + @override + Future addRelapse(Relapse relapse) { + _relapseRecords.add(relapse); + return Future.value(1); + } + @override Future get database => DatabaseService.instance.database; @@ -46,4 +54,9 @@ class DatabaseMock implements DatabaseService { Future> getSleepRecords() { return Future.value(_sleepRecords); } + + @override + Future> getRelapseRecords() { + return Future.value(_relapseRecords); + } } diff --git a/lib/models/relapse.dart b/lib/models/relapse.dart new file mode 100644 index 0000000..0271d31 --- /dev/null +++ b/lib/models/relapse.dart @@ -0,0 +1,29 @@ +import 'package:smoke_cess_app/interface/db_record.dart'; + +class Relapse implements DatabaseRecord { + final String _category; + final String _comment; + final DateTime _date; + + Relapse(this._category, this._comment, this._date); + + @override + factory Relapse.fromDatabase(Map map) { + DateTime date = DateTime.parse(map['date']); + return Relapse(map['category'], map['comment'], date); + } + + @override + String toCSV() { + return "${_date.toIso8601String()}, $_category, $_comment"; + } + + @override + Map toMap() { + return { + 'category': _category, + 'comment': _comment, + 'date': _date.toIso8601String(), + }; + } +} diff --git a/lib/models/settings.dart b/lib/models/settings.dart index 0e7cf30..83fad43 100644 --- a/lib/models/settings.dart +++ b/lib/models/settings.dart @@ -3,8 +3,8 @@ import 'package:smoke_cess_app/services/json_service.dart'; class Settings { final int group; final List? relapseCategories; - final QueryConfig moodQuery; - final QueryConfig sleepQuery; + final QueryConfig? moodQuery; + final QueryConfig? sleepQuery; final TimeConfig? chessTime; Settings(this.group, this.relapseCategories, this.moodQuery, this.sleepQuery, @@ -21,8 +21,8 @@ class Settings { } class QueryConfig { - final int hours; - final int minutes; + final int? hours; + final int? minutes; final List? days; QueryConfig(this.hours, this.minutes, this.days); @@ -34,8 +34,8 @@ class QueryConfig { } class TimeConfig { - final int hours; - final int minutes; + final int? hours; + final int? minutes; TimeConfig(this.hours, this.minutes); diff --git a/lib/pages/main_page.dart b/lib/pages/main_page.dart index 9b6127f..b45b479 100644 --- a/lib/pages/main_page.dart +++ b/lib/pages/main_page.dart @@ -1,11 +1,8 @@ +import 'package:awesome_dialog/awesome_dialog.dart'; import 'package:flutter/material.dart'; -import 'package:smoke_cess_app/pages/mood_page.dart'; -import 'package:smoke_cess_app/pages/relapse_page.dart'; -import 'package:smoke_cess_app/pages/scanner_page.dart'; -import 'package:smoke_cess_app/pages/sleep_page.dart'; -import 'package:smoke_cess_app/pages/interval_page.dart'; -import 'package:smoke_cess_app/services/settings_service.dart'; -import 'package:smoke_cess_app/widgets/missing_config_popup.dart'; +import 'package:provider/provider.dart'; +import 'package:smoke_cess_app/services/pages_service.dart'; +import 'package:smoke_cess_app/providers/settings_provider.dart'; class MyHomePage extends StatefulWidget { const MyHomePage({super.key}); @@ -15,74 +12,43 @@ class MyHomePage extends StatefulWidget { } class MyHomePageState extends State { - int _selectedIndex = 2; - int? _gruppe; + int _selectedIndex = 4; + bool _isConfigured = false; - final List _titles = [ - 'Stimmung', - 'Schlaf', - 'Timer', - 'Rückfall', - 'Scanner' - ]; - static const List _widgetOptions = [ - MoodPage(), - SleepPage(), - IntervalTimerPage(), - RelapsePage(), - ScannerPage(), - ]; - - Future _onItemTapped(int index) async { - _gruppe = await getGroup(); - bool isConfigured = _gruppe != null; + void _onItemTapped(int index) { setState(() { - isConfigured + _isConfigured ? _selectedIndex = index - : showDialog( + : AwesomeDialog( context: context, - builder: (BuildContext context) { - return const MissingConfigPopup( - title: 'Fehlende Konfiguration', - text: 'Bitte QR Code Scannen!', - ); - }); + dialogType: DialogType.info, + title: 'Fehlende Konfiguration', + desc: 'Bitte QR Code Scannen!', + ).show(); }); } @override Widget build(BuildContext context) { + var settingsModel = context.watch(); + var group = settingsModel.settings?.group; + _isConfigured = settingsModel.initialized; return Scaffold( appBar: AppBar( title: Text( - '${_titles[_selectedIndex]} ${_gruppe != null ? "Gruppe $_gruppe" : ""}')), - body: _widgetOptions.elementAt(_selectedIndex), + '${pages.keys.elementAt(_selectedIndex)} ${_isConfigured ? "Gruppe $group" : ""}')), + body: Center( + child: SingleChildScrollView( + child: pages.values.elementAt(_selectedIndex)['page'])), bottomNavigationBar: NavigationBar( - onDestinationSelected: _onItemTapped, - selectedIndex: _selectedIndex, - destinations: const [ - NavigationDestination( - icon: Icon(Icons.mood_outlined, color: Colors.black), - label: 'Stimmung'), - NavigationDestination( - icon: Icon(Icons.bedtime_outlined, color: Colors.black), - label: 'Schlaf'), - NavigationDestination( - icon: Icon( - Icons.timer_outlined, - color: Colors.black, - ), - label: 'Timer'), - NavigationDestination( - icon: Icon(Icons.smoke_free_outlined, color: Colors.black), - label: 'Rückfall'), - NavigationDestination( - icon: Icon(Icons.camera_alt_outlined, color: Colors.black), - label: 'Settings'), - ], - - //onTap: _onItemTapped, - ), + onDestinationSelected: _onItemTapped, + selectedIndex: _selectedIndex, + destinations: pages.keys.map((key) { + return NavigationDestination( + icon: pages[key]!['icon'] ?? + const Icon(Icons.disabled_by_default), + label: key); + }).toList()), ); } } diff --git a/lib/pages/relapse_page.dart b/lib/pages/relapse_page.dart index 7710e10..75e007d 100644 --- a/lib/pages/relapse_page.dart +++ b/lib/pages/relapse_page.dart @@ -1,10 +1,17 @@ import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:smoke_cess_app/widgets/relapse_form.dart'; +import '../providers/input_provider.dart'; class RelapsePage extends StatelessWidget { const RelapsePage({super.key}); @override Widget build(BuildContext context) { - return const Center(child: Text('Hier werden Rückfälle dokumentiert')); + return Center( + child: ChangeNotifierProvider( + create: (context) => InputProvider(), + child: const RelapseForm(), + )); } } diff --git a/lib/pages/scanner_page.dart b/lib/pages/scanner_page.dart index 7159694..29cf8a7 100644 --- a/lib/pages/scanner_page.dart +++ b/lib/pages/scanner_page.dart @@ -1,25 +1,45 @@ +import 'package:awesome_dialog/awesome_dialog.dart'; import 'package:flutter/material.dart'; -import 'package:mobile_scanner/mobile_scanner.dart'; +import 'package:provider/provider.dart'; import 'package:smoke_cess_app/models/mood.dart'; -import 'package:smoke_cess_app/models/settings.dart'; -import 'package:smoke_cess_app/services/database_service.dart'; -import 'package:smoke_cess_app/services/json_service.dart'; +import 'package:smoke_cess_app/models/relapse.dart'; import 'package:smoke_cess_app/services/settings_service.dart'; import 'package:smoke_cess_app/services/notification_service.dart'; - +import 'package:smoke_cess_app/widgets/scanner.dart'; import '../models/sleep.dart'; -import '../widgets/missing_config_popup.dart'; +import '../providers/settings_provider.dart'; import '../globals.dart' as globals; -class ScannerPage extends StatefulWidget { +class ScannerPage extends StatelessWidget { const ScannerPage({super.key}); - @override - State createState() => ScannerPageState(); -} + void export() async { + List moods = await globals.databaseService.getMoodRecords(); + List sleeps = await globals.databaseService.getSleepRecords(); + List 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()); + } + } -class ScannerPageState extends State { - bool scanning = false; + void loadJSON(BuildContext context) async { + var settingsModel = context.read(); + await loadSettingsFromLocalJSON(); + settingsModel.initSettings(); + NotificationService().setAllNotifications(); + AwesomeDialog( + context: context, + dialogType: DialogType.success, + title: 'Geschafft', + desc: 'Die Einstellung wurden erfolgreich gespeichert', + ).show(); + } @override Widget build(BuildContext context) { @@ -27,70 +47,19 @@ class ScannerPageState extends State { child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - scanning - ? Expanded( - child: MobileScanner( - fit: BoxFit.contain, - controller: MobileScannerController( - detectionTimeoutMs: 2000, - ), - onDetect: (capture) { - //TODO Errorhandling!! - final List barcodes = capture.barcodes; - for (final barcode in barcodes) { - if (barcode.rawValue != null) { - String qrText = barcode.rawValue!; - Map json = stringToJSON(qrText); - Settings settings = Settings.fromJson(json); - saveSettings(settings); - setState(() { - scanning = false; - showDialog( - context: context, - builder: (BuildContext context) { - return MissingConfigPopup( - title: 'Konfiguration erfolgreich', - text: 'Du gehörst zu Gruppe ${settings.group}', - ); - }); - }); - } - } - }, - )) - : ElevatedButton( - style: ElevatedButton.styleFrom( - textStyle: const TextStyle(fontSize: 20)), - onPressed: () { - setState(() => scanning = true); - }, - child: const Text('Scan QR Code'), - ), + const MyScanner(), const SizedBox(height: 30), ElevatedButton( style: ElevatedButton.styleFrom( textStyle: const TextStyle(fontSize: 20)), - onPressed: () { - loadSettingsFromLocalJSON(); - NotificationService().setAllNotifications(); - }, + onPressed: () => loadJSON(context), child: const Text('Read JSON'), ), const SizedBox(height: 30), ElevatedButton( style: ElevatedButton.styleFrom( textStyle: const TextStyle(fontSize: 20)), - onPressed: () async { - List moods = await globals.databaseService.getMoodRecords(); - List sleeps = - await globals.databaseService.getSleepRecords(); - for (Mood mood in moods) { - print(mood.toCSV()); - } - for (Sleep sleep in sleeps) { - print(sleep.toCSV()); - } - }, + onPressed: export, child: const Text('Export'), ) ], diff --git a/lib/providers/input_provider.dart b/lib/providers/input_provider.dart index 881ce2c..a61514f 100644 --- a/lib/providers/input_provider.dart +++ b/lib/providers/input_provider.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.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 '../globals.dart' as globals; @@ -10,15 +11,22 @@ class InputProvider extends ChangeNotifier { 'wokeUpAt': const TimeOfDay(hour: 8, minute: 0), 'sleptAt': const TimeOfDay(hour: 22, minute: 0), }; + 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) { return _times[key] ?? const TimeOfDay(hour: 12, minute: 0); } @@ -36,17 +44,24 @@ class InputProvider extends ChangeNotifier { notifyListeners(); } - void saveMood() { + Future saveMood() { Mood mood = Mood(_sliderValue.toInt(), _textController.text, DateTime.now()); - globals.databaseService.addMood(mood); _resetFields(); + return globals.databaseService.addMood(mood); } - void saveSleep(String wokeUpKey, String sleptKey) { + Future saveRelapse() { + Relapse relapse = + Relapse(_relapseCategory, _textController.text, DateTime.now()); + _resetFields(); + return globals.databaseService.addRelapse(relapse); + } + + Future saveSleep(String wokeUpKey, String sleptKey) { Sleep sleep = Sleep(_sliderValue.toInt(), _textController.text, DateTime.now(), getTimeEntry(sleptKey), getTimeEntry(wokeUpKey)); - globals.databaseService.addSleep(sleep); _resetFields(); + return globals.databaseService.addSleep(sleep); } } diff --git a/lib/providers/settings_provider.dart b/lib/providers/settings_provider.dart new file mode 100644 index 0000000..f51c5e1 --- /dev/null +++ b/lib/providers/settings_provider.dart @@ -0,0 +1,22 @@ +import 'package:flutter/material.dart'; +import 'package:smoke_cess_app/services/settings_service.dart'; + +import '../models/settings.dart'; + +class SettingsProvider extends ChangeNotifier { + Settings? _settings; + bool _initialized = false; + + Settings? get settings => _settings; + bool get initialized => _initialized; + + SettingsProvider() { + initSettings(); + } + + void initSettings() async { + _settings = await loadSettings(); + _initialized = _settings != null ? true : false; + notifyListeners(); + } +} diff --git a/lib/services/database_service.dart b/lib/services/database_service.dart index 3dcc943..311bf88 100644 --- a/lib/services/database_service.dart +++ b/lib/services/database_service.dart @@ -3,6 +3,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 import 'package:path_provider/path_provider.dart'; @@ -35,7 +36,6 @@ class DatabaseService { await db.execute(_createWorkoutTable); } - //TODO use generic function? Future> getMoodRecords() async { Database db = await instance.database; var moodRecords = await db.query('mood'); @@ -54,6 +54,15 @@ class DatabaseService { return sleepList; } + Future> getRelapseRecords() async { + Database db = await instance.database; + var relapseRecords = await db.query('relapse'); + List relapseList = relapseRecords.isNotEmpty + ? relapseRecords.map((e) => Relapse.fromDatabase(e)).toList() + : []; + return relapseList; + } + Future addMood(Mood mood) async { Database db = await instance.database; return await db.insert('mood', mood.toMap()); @@ -68,9 +77,13 @@ class DatabaseService { Database db = await instance.database; return await db.insert('workout', workout.toMap()); } -} -String _createMoodTable = ''' + Future addRelapse(Relapse relapse) async { + Database db = await instance.database; + return await db.insert('relapse', relapse.toMap()); + } + + String _createMoodTable = ''' CREATE TABLE IF NOT EXISTS mood( id INTEGER PRIMARY KEY, value INTEGER, @@ -79,7 +92,7 @@ String _createMoodTable = ''' ) '''; -String _createSleepTable = ''' + String _createSleepTable = ''' CREATE TABLE IF NOT EXISTS sleep( id INTEGER PRIMARY KEY, value INTEGER, @@ -92,7 +105,7 @@ String _createSleepTable = ''' ) '''; -String _createRelapseTable = ''' + String _createRelapseTable = ''' CREATE TABLE IF NOT EXISTS relapse( id INTEGER PRIMARY KEY, date TEXT, @@ -101,7 +114,7 @@ String _createRelapseTable = ''' ) '''; -String _createWorkoutTable = ''' + String _createWorkoutTable = ''' CREATE TABLE IF NOT EXISTS workout( id INTEGER PRIMARY KEY, date TEXT, @@ -109,3 +122,4 @@ String _createWorkoutTable = ''' motivationAfter INTEGER, ) '''; +} diff --git a/lib/services/pages_service.dart b/lib/services/pages_service.dart new file mode 100644 index 0000000..8f3ab37 --- /dev/null +++ b/lib/services/pages_service.dart @@ -0,0 +1,29 @@ +import 'package:flutter/material.dart'; +import '../pages/interval_page.dart'; +import '../pages/mood_page.dart'; +import '../pages/relapse_page.dart'; +import '../pages/scanner_page.dart'; +import '../pages/sleep_page.dart'; + +const pages = { + 'Stimmung': { + 'page': MoodPage(), + 'icon': Icon(Icons.mood_outlined, color: Colors.black) + }, + 'Schlaf': { + 'page': SleepPage(), + 'icon': Icon(Icons.bedtime_outlined, color: Colors.black) + }, + 'Timer': { + 'page': IntervalTimerPage(), + 'icon': Icon(Icons.timer_outlined, color: Colors.black) + }, + 'Rückfall': { + 'page': RelapsePage(), + 'icon': Icon(Icons.smoke_free_outlined, color: Colors.black), + }, + 'Scanner': { + 'page': ScannerPage(), + 'icon': Icon(Icons.camera_alt_outlined, color: Colors.black) + }, +}; diff --git a/lib/services/settings_service.dart b/lib/services/settings_service.dart index 52028bd..8c7e7a7 100644 --- a/lib/services/settings_service.dart +++ b/lib/services/settings_service.dart @@ -54,14 +54,37 @@ Future loadSettingsFromLocalJSON() async { void saveSettings(Settings settings) { _setIntSetting('group', settings.group); _setStringListSetting('relapse_categories', settings.relapseCategories!); - _setStringListSetting('mood_query_days', settings.moodQuery.days!); - _setIntSetting('mood_query_hours', settings.moodQuery.hours); - _setIntSetting('mood_query_minutes', settings.moodQuery.minutes); - _setStringListSetting('sleep_query_days', settings.sleepQuery.days!); - _setIntSetting('sleep_query_hours', settings.sleepQuery.hours); - _setIntSetting('sleep_query_minutes', settings.sleepQuery.minutes); + _setStringListSetting('mood_query_days', settings.moodQuery!.days!); + _setIntSetting('mood_query_hours', settings.moodQuery!.hours!); + _setIntSetting('mood_query_minutes', settings.moodQuery!.minutes!); + _setStringListSetting('sleep_query_days', settings.sleepQuery!.days!); + _setIntSetting('sleep_query_hours', settings.sleepQuery!.hours!); + _setIntSetting('sleep_query_minutes', settings.sleepQuery!.minutes!); if (settings.chessTime != null) { - _setIntSetting('chess_hours', settings.chessTime!.hours); - _setIntSetting('chess_minutes', settings.chessTime!.minutes); + _setIntSetting('chess_hours', settings.chessTime!.hours!); + _setIntSetting('chess_minutes', settings.chessTime!.minutes!); } } + +Future loadSettings() async { + int? group = await getGroup(); + List? relapseCategories = await getRelapseCategories(); + int? moodHours = await getMoodQueryHours(); + int? moodMinutes = await getMoodQueryMinutes(); + List? moodDays = await getMoodQueryDaysCategories(); + int? sleepHours = await getSleepQueryHours(); + int? sleepMinutes = await getSleepQueryMinutes(); + List? sleepDays = await getSleepQueryDaysCategories(); + int? chessHours = await getChessHours(); + int? chessMinutes = await getChessMinutes(); + + if (group != null) { + return Settings( + group, + relapseCategories, + QueryConfig(moodHours, moodMinutes, moodDays), + QueryConfig(sleepHours, sleepMinutes, sleepDays), + TimeConfig(chessHours, chessMinutes)); + } + return null; +} diff --git a/lib/widgets/drop_down.dart b/lib/widgets/drop_down.dart new file mode 100644 index 0000000..5f06d89 --- /dev/null +++ b/lib/widgets/drop_down.dart @@ -0,0 +1,27 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import '../providers/input_provider.dart'; + +class DropDown extends StatelessWidget { + final List _items; + const DropDown(this._items, {super.key}); + + @override + Widget build(BuildContext context) { + var inputModel = context.watch(); + return DropdownButtonFormField( + value: _items.isEmpty ? null : _items[0], + icon: const Icon(Icons.arrow_downward), + elevation: 16, + onChanged: (String? value) { + inputModel.relapseCategory = value ?? ''; + }, + items: _items.map>((String value) { + return DropdownMenuItem( + value: value, + child: Text(value), + ); + }).toList(), + ); + } +} diff --git a/lib/widgets/mood_form.dart b/lib/widgets/mood_form.dart index a997d01..b9a0e05 100644 --- a/lib/widgets/mood_form.dart +++ b/lib/widgets/mood_form.dart @@ -30,9 +30,8 @@ class MoodForm extends StatelessWidget { const SizedBox( height: 80, ), - ElevatedButton( - onPressed: () => inputModel.saveMood(), - child: const Text('Speichern'), + SubmitFormButton( + submitCallback: inputModel.saveMood, ) ], ); diff --git a/lib/widgets/relapse_form.dart b/lib/widgets/relapse_form.dart new file mode 100644 index 0000000..88e555c --- /dev/null +++ b/lib/widgets/relapse_form.dart @@ -0,0 +1,36 @@ +import 'package:flutter/material.dart'; +import 'package:provider/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 'elevated_card.dart'; + +class RelapseForm extends StatelessWidget { + const RelapseForm({super.key}); + + @override + Widget build(BuildContext context) { + var inputModel = context.watch(); + var settingsModel = context.watch(); + return Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + ElevatedCard( + title: 'Rückfallkategorie', + child: DropDown(settingsModel.settings?.relapseCategories ?? []), + ), + const ElevatedCard( + title: 'Beschreibe deinen Rückfall', + child: MyTextFormField('Beschreibe deinen Rückfall'), + ), + const SizedBox( + height: 80, + ), + SubmitFormButton(submitCallback: inputModel.saveRelapse) + ], + ); + } +} diff --git a/lib/widgets/scanner.dart b/lib/widgets/scanner.dart new file mode 100644 index 0000000..46f8c8a --- /dev/null +++ b/lib/widgets/scanner.dart @@ -0,0 +1,68 @@ +import 'package:awesome_dialog/awesome_dialog.dart'; +import 'package:flutter/material.dart'; +import 'package:mobile_scanner/mobile_scanner.dart'; +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 '../providers/settings_provider.dart'; +import '../services/notification_service.dart'; + +class MyScanner extends StatefulWidget { + const MyScanner({super.key}); + + @override + State createState() => MyScannerState(); +} + +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); + 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 onDetect(capture) { + final List barcodes = capture.barcodes; + for (final barcode in barcodes) { + if (barcode.rawValue != null) { + return handleSucces(barcode.rawValue); + } + } + } + + @override + Widget build(BuildContext context) { + return scanning + ? Expanded( + child: 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'), + ); + } +} diff --git a/lib/widgets/sleep_form.dart b/lib/widgets/sleep_form.dart index 5cb7352..8b4389c 100644 --- a/lib/widgets/sleep_form.dart +++ b/lib/widgets/sleep_form.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:provider/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/text_formfield.dart'; import 'package:smoke_cess_app/widgets/timepicker.dart'; @@ -41,9 +42,9 @@ class SleepForm extends StatelessWidget { const SizedBox( height: 80, ), - ElevatedButton( - onPressed: () => inputModel.saveSleep(wokeUpKey, sleptKey), - child: const Text('Speichern')) + SubmitFormButton( + submitCallback: () => inputModel.saveSleep(wokeUpKey, sleptKey), + ) ], ); } diff --git a/lib/widgets/submit_form_button.dart b/lib/widgets/submit_form_button.dart index 58f28c8..3242b18 100644 --- a/lib/widgets/submit_form_button.dart +++ b/lib/widgets/submit_form_button.dart @@ -1,15 +1,31 @@ +import 'package:awesome_dialog/awesome_dialog.dart'; import 'package:flutter/material.dart'; class SubmitFormButton extends StatelessWidget { - final VoidCallback submitCallback; - const SubmitFormButton(this.submitCallback, {super.key}); + final Future Function() submitCallback; + const SubmitFormButton({super.key, required this.submitCallback}); @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.symmetric(vertical: 16.0), child: ElevatedButton( - onPressed: submitCallback, + 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(); + }, child: const Text('Speichern'), ), ); diff --git a/pubspec.lock b/pubspec.lock index b899dd9..08b0b74 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -64,6 +64,13 @@ packages: 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: @@ -177,6 +184,13 @@ packages: 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: @@ -324,6 +338,13 @@ packages: 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: diff --git a/pubspec.yaml b/pubspec.yaml index 9204ca9..5c61553 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -35,6 +35,7 @@ dependencies: path: 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.