Merge branch 'main' into 29-provider-refactoring
commit
da0bf43087
|
@ -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(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Mood> _moodRecords = [];
|
||||
final List<Sleep> _sleepRecords = [];
|
||||
final List<Relapse> _relapseRecords = [];
|
||||
final List<DatabaseRecord> _workoutRecords = [];
|
||||
|
||||
@override
|
||||
|
@ -34,6 +36,12 @@ class DatabaseMock implements DatabaseService {
|
|||
return Future.value(1);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<int> addRelapse(Relapse relapse) {
|
||||
_relapseRecords.add(relapse);
|
||||
return Future.value(1);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Database> get database => DatabaseService.instance.database;
|
||||
|
||||
|
@ -46,4 +54,9 @@ class DatabaseMock implements DatabaseService {
|
|||
Future<List<Sleep>> getSleepRecords() {
|
||||
return Future.value(_sleepRecords);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<Relapse>> getRelapseRecords() {
|
||||
return Future.value(_relapseRecords);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<String, dynamic> map) {
|
||||
DateTime date = DateTime.parse(map['date']);
|
||||
return Relapse(map['category'], map['comment'], date);
|
||||
}
|
||||
|
||||
@override
|
||||
String toCSV() {
|
||||
return "${_date.toIso8601String()}, $_category, $_comment";
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
'category': _category,
|
||||
'comment': _comment,
|
||||
'date': _date.toIso8601String(),
|
||||
};
|
||||
}
|
||||
}
|
|
@ -3,8 +3,8 @@ import 'package:smoke_cess_app/services/json_service.dart';
|
|||
class Settings {
|
||||
final int group;
|
||||
final List<String>? 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<String>? 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);
|
||||
|
||||
|
|
|
@ -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<MyHomePage> {
|
||||
int _selectedIndex = 2;
|
||||
int? _gruppe;
|
||||
int _selectedIndex = 4;
|
||||
bool _isConfigured = false;
|
||||
|
||||
final List<String> _titles = [
|
||||
'Stimmung',
|
||||
'Schlaf',
|
||||
'Timer',
|
||||
'Rückfall',
|
||||
'Scanner'
|
||||
];
|
||||
static const List<Widget> _widgetOptions = <Widget>[
|
||||
MoodPage(),
|
||||
SleepPage(),
|
||||
IntervalTimerPage(),
|
||||
RelapsePage(),
|
||||
ScannerPage(),
|
||||
];
|
||||
|
||||
Future<void> _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(
|
||||
dialogType: DialogType.info,
|
||||
title: 'Fehlende Konfiguration',
|
||||
text: 'Bitte QR Code Scannen!',
|
||||
);
|
||||
});
|
||||
desc: 'Bitte QR Code Scannen!',
|
||||
).show();
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var settingsModel = context.watch<SettingsProvider>();
|
||||
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 <Widget>[
|
||||
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,
|
||||
),
|
||||
destinations: pages.keys.map((key) {
|
||||
return NavigationDestination(
|
||||
icon: pages[key]!['icon'] ??
|
||||
const Icon(Icons.disabled_by_default),
|
||||
label: key);
|
||||
}).toList()),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<StatefulWidget> createState() => ScannerPageState();
|
||||
}
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
class ScannerPageState extends State<ScannerPage> {
|
||||
bool scanning = false;
|
||||
void loadJSON(BuildContext context) async {
|
||||
var settingsModel = context.read<SettingsProvider>();
|
||||
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<ScannerPage> {
|
|||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
scanning
|
||||
? Expanded(
|
||||
child: MobileScanner(
|
||||
fit: BoxFit.contain,
|
||||
controller: MobileScannerController(
|
||||
detectionTimeoutMs: 2000,
|
||||
),
|
||||
onDetect: (capture) {
|
||||
//TODO Errorhandling!!
|
||||
final List<Barcode> barcodes = capture.barcodes;
|
||||
for (final barcode in barcodes) {
|
||||
if (barcode.rawValue != null) {
|
||||
String qrText = barcode.rawValue!;
|
||||
Map<String, dynamic> 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<Mood> moods = await globals.databaseService.getMoodRecords();
|
||||
List<Sleep> 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'),
|
||||
)
|
||||
],
|
||||
|
|
|
@ -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<int> 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<int> saveRelapse() {
|
||||
Relapse relapse =
|
||||
Relapse(_relapseCategory, _textController.text, DateTime.now());
|
||||
_resetFields();
|
||||
return globals.databaseService.addRelapse(relapse);
|
||||
}
|
||||
|
||||
Future<int> 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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<List<Mood>> getMoodRecords() async {
|
||||
Database db = await instance.database;
|
||||
var moodRecords = await db.query('mood');
|
||||
|
@ -54,6 +54,15 @@ class DatabaseService {
|
|||
return sleepList;
|
||||
}
|
||||
|
||||
Future<List<Relapse>> getRelapseRecords() async {
|
||||
Database db = await instance.database;
|
||||
var relapseRecords = await db.query('relapse');
|
||||
List<Relapse> relapseList = relapseRecords.isNotEmpty
|
||||
? relapseRecords.map((e) => Relapse.fromDatabase(e)).toList()
|
||||
: [];
|
||||
return relapseList;
|
||||
}
|
||||
|
||||
Future<int> 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<int> 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,
|
||||
)
|
||||
''';
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
},
|
||||
};
|
|
@ -54,14 +54,37 @@ Future<void> 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<Settings?> loadSettings() async {
|
||||
int? group = await getGroup();
|
||||
List<String>? relapseCategories = await getRelapseCategories();
|
||||
int? moodHours = await getMoodQueryHours();
|
||||
int? moodMinutes = await getMoodQueryMinutes();
|
||||
List<String>? moodDays = await getMoodQueryDaysCategories();
|
||||
int? sleepHours = await getSleepQueryHours();
|
||||
int? sleepMinutes = await getSleepQueryMinutes();
|
||||
List<String>? 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;
|
||||
}
|
||||
|
|
|
@ -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<String> _items;
|
||||
const DropDown(this._items, {super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var inputModel = context.watch<InputProvider>();
|
||||
return DropdownButtonFormField<String>(
|
||||
value: _items.isEmpty ? null : _items[0],
|
||||
icon: const Icon(Icons.arrow_downward),
|
||||
elevation: 16,
|
||||
onChanged: (String? value) {
|
||||
inputModel.relapseCategory = value ?? '';
|
||||
},
|
||||
items: _items.map<DropdownMenuItem<String>>((String value) {
|
||||
return DropdownMenuItem<String>(
|
||||
value: value,
|
||||
child: Text(value),
|
||||
);
|
||||
}).toList(),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -30,9 +30,8 @@ class MoodForm extends StatelessWidget {
|
|||
const SizedBox(
|
||||
height: 80,
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () => inputModel.saveMood(),
|
||||
child: const Text('Speichern'),
|
||||
SubmitFormButton(
|
||||
submitCallback: inputModel.saveMood,
|
||||
)
|
||||
],
|
||||
);
|
||||
|
|
|
@ -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<InputProvider>();
|
||||
var settingsModel = context.watch<SettingsProvider>();
|
||||
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)
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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<StatefulWidget> createState() => MyScannerState();
|
||||
}
|
||||
|
||||
class MyScannerState extends State<MyScanner> {
|
||||
bool scanning = false;
|
||||
|
||||
void handleSucces(String? rawValue) {
|
||||
String qrText = rawValue!;
|
||||
Map<String, dynamic> json = stringToJSON(qrText);
|
||||
Settings settings = Settings.fromJson(json);
|
||||
saveSettings(settings);
|
||||
var settingsModel = context.read<SettingsProvider>();
|
||||
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<Barcode> 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'),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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<int> 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'),
|
||||
),
|
||||
);
|
||||
|
|
21
pubspec.lock
21
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:
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue