Merge branch '32-success-or-failure-alert-after-save' into 'main'
Resolve "Success or failure alert after save" Closes #32 See merge request Crondung/hsma_cpd!18main
commit
cfdd566dd8
|
@ -0,0 +1,7 @@
|
||||||
|
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 = DatabaseService.instance;
|
|
@ -1,14 +1,16 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
import 'package:smoke_cess_app/pages/main_page.dart';
|
import 'package:smoke_cess_app/pages/main_page.dart';
|
||||||
import 'package:smoke_cess_app/service/database_service.dart';
|
import 'package:smoke_cess_app/services/notification_service.dart';
|
||||||
import 'package:smoke_cess_app/service/notification_service.dart';
|
|
||||||
import 'package:timezone/data/latest.dart' as tz;
|
import 'package:timezone/data/latest.dart' as tz;
|
||||||
|
import 'globals.dart' as globals;
|
||||||
|
import 'providers/settings_provider.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
// to ensure all the widgets are initialized.
|
// to ensure all the widgets are initialized.
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
//init database
|
//init database
|
||||||
DatabaseService.instance;
|
globals.databaseService;
|
||||||
tz.initializeTimeZones();
|
tz.initializeTimeZones();
|
||||||
NotificationService().initNotification();
|
NotificationService().initNotification();
|
||||||
runApp(const MyApp());
|
runApp(const MyApp());
|
||||||
|
@ -21,6 +23,11 @@ class MyApp extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return const MaterialApp(title: _title, home: MyHomePage());
|
return MaterialApp(
|
||||||
|
title: _title,
|
||||||
|
home: ChangeNotifierProvider(
|
||||||
|
create: (context) => SettingsProvider(),
|
||||||
|
child: const MyHomePage(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,23 +1,56 @@
|
||||||
import 'package:smoke_cess_app/interface/db_record.dart';
|
import 'package:smoke_cess_app/interface/db_record.dart';
|
||||||
import 'package:smoke_cess_app/models/mood.dart';
|
import 'package:smoke_cess_app/models/mood.dart';
|
||||||
|
import 'package:smoke_cess_app/models/relapse.dart';
|
||||||
import 'package:smoke_cess_app/models/sleep.dart';
|
import 'package:smoke_cess_app/models/sleep.dart';
|
||||||
|
import 'package:smoke_cess_app/services/database_service.dart';
|
||||||
|
import 'package:sqflite_common/sqlite_api.dart';
|
||||||
|
|
||||||
class DatabaseMock {
|
class DatabaseMock implements DatabaseService {
|
||||||
final List<DatabaseRecord> _moodRecords = [];
|
static final DatabaseMock _databaseMock = DatabaseMock._internal();
|
||||||
final List<DatabaseRecord> _sleepRecords = [];
|
factory DatabaseMock() {
|
||||||
|
return _databaseMock;
|
||||||
|
}
|
||||||
|
DatabaseMock._internal();
|
||||||
|
|
||||||
|
final List<Mood> _moodRecords = [];
|
||||||
|
final List<Sleep> _sleepRecords = [];
|
||||||
|
final List<Relapse> _relapseRecords = [];
|
||||||
final List<DatabaseRecord> _workoutRecords = [];
|
final List<DatabaseRecord> _workoutRecords = [];
|
||||||
|
|
||||||
void saveRecord(DatabaseRecord record) {
|
@override
|
||||||
if (record is Mood) {
|
Future<int> addMood(Mood mood) {
|
||||||
_moodRecords.add(record);
|
_moodRecords.add(mood);
|
||||||
} else if (record is Sleep) {
|
return Future.value(1);
|
||||||
_sleepRecords.add(record);
|
|
||||||
} else {
|
|
||||||
_workoutRecords.add(record);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
List<DatabaseRecord> getMoodRecords() => _moodRecords;
|
@override
|
||||||
List<DatabaseRecord> getSleepRecords() => _sleepRecords;
|
Future<int> addSleep(Sleep sleep) {
|
||||||
List<DatabaseRecord> getWorkoutRecords() => _workoutRecords;
|
_sleepRecords.add(sleep);
|
||||||
|
return Future.value(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<int> addRelapse(Relapse relapse) {
|
||||||
|
_relapseRecords.add(relapse);
|
||||||
|
return Future.value(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
// TODO: implement database
|
||||||
|
Future<Database> get database => DatabaseService.instance.database;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<List<Mood>> getMoodRecords() {
|
||||||
|
return Future.value(_moodRecords);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
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(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,10 +1,10 @@
|
||||||
import 'package:smoke_cess_app/service/json_service.dart';
|
import 'package:smoke_cess_app/services/json_service.dart';
|
||||||
|
|
||||||
class Settings {
|
class Settings {
|
||||||
final int group;
|
final int group;
|
||||||
final List<String>? relapseCategories;
|
final List<String>? relapseCategories;
|
||||||
final QueryConfig moodQuery;
|
final QueryConfig? moodQuery;
|
||||||
final QueryConfig sleepQuery;
|
final QueryConfig? sleepQuery;
|
||||||
final TimeConfig? chessTime;
|
final TimeConfig? chessTime;
|
||||||
|
|
||||||
Settings(this.group, this.relapseCategories, this.moodQuery, this.sleepQuery,
|
Settings(this.group, this.relapseCategories, this.moodQuery, this.sleepQuery,
|
||||||
|
@ -21,8 +21,8 @@ class Settings {
|
||||||
}
|
}
|
||||||
|
|
||||||
class QueryConfig {
|
class QueryConfig {
|
||||||
final int hours;
|
final int? hours;
|
||||||
final int minutes;
|
final int? minutes;
|
||||||
final List<String>? days;
|
final List<String>? days;
|
||||||
|
|
||||||
QueryConfig(this.hours, this.minutes, this.days);
|
QueryConfig(this.hours, this.minutes, this.days);
|
||||||
|
@ -34,8 +34,8 @@ class QueryConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
class TimeConfig {
|
class TimeConfig {
|
||||||
final int hours;
|
final int? hours;
|
||||||
final int minutes;
|
final int? minutes;
|
||||||
|
|
||||||
TimeConfig(this.hours, this.minutes);
|
TimeConfig(this.hours, this.minutes);
|
||||||
|
|
||||||
|
|
|
@ -5,25 +5,25 @@ class Sleep implements DatabaseRecord {
|
||||||
final int _sleepQualityValue;
|
final int _sleepQualityValue;
|
||||||
final String _comment;
|
final String _comment;
|
||||||
final DateTime _date;
|
final DateTime _date;
|
||||||
final TimeOfDay _sleepedAt;
|
final TimeOfDay _sleptAt;
|
||||||
final TimeOfDay _wokeUpAt;
|
final TimeOfDay _wokeUpAt;
|
||||||
|
|
||||||
Sleep(this._sleepQualityValue, this._comment, this._date, this._sleepedAt,
|
Sleep(this._sleepQualityValue, this._comment, this._date, this._sleptAt,
|
||||||
this._wokeUpAt);
|
this._wokeUpAt);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
factory Sleep.fromDatabase(Map<String, dynamic> map) {
|
factory Sleep.fromDatabase(Map<String, dynamic> map) {
|
||||||
DateTime date = DateTime.parse(map['date']);
|
DateTime date = DateTime.parse(map['date']);
|
||||||
TimeOfDay sleepedAt =
|
TimeOfDay sleptAt =
|
||||||
TimeOfDay(hour: map['sleepedAtHour'], minute: map['sleepedAtMinute']);
|
TimeOfDay(hour: map['sleptAtHour'], minute: map['sleptAtMinute']);
|
||||||
TimeOfDay wokeUpAt =
|
TimeOfDay wokeUpAt =
|
||||||
TimeOfDay(hour: map['wokeUpAtHour'], minute: map['wokeUpAtMinute']);
|
TimeOfDay(hour: map['wokeUpAtHour'], minute: map['wokeUpAtMinute']);
|
||||||
return Sleep(map['value'], map['comment'], date, sleepedAt, wokeUpAt);
|
return Sleep(map['value'], map['comment'], date, sleptAt, wokeUpAt);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toCSV() {
|
String toCSV() {
|
||||||
return "${_date.toIso8601String()}, $_sleepQualityValue, ${_sleepedAt.hour}:${_sleepedAt.minute}, ${_wokeUpAt.hour}:${_wokeUpAt.minute}, $_comment";
|
return "${_date.toIso8601String()}, $_sleepQualityValue, ${_sleptAt.hour}:${_sleptAt.minute}, ${_wokeUpAt.hour}:${_wokeUpAt.minute}, $_comment";
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -32,8 +32,8 @@ class Sleep implements DatabaseRecord {
|
||||||
'value': _sleepQualityValue,
|
'value': _sleepQualityValue,
|
||||||
'comment': _comment,
|
'comment': _comment,
|
||||||
'date': _date.toIso8601String(),
|
'date': _date.toIso8601String(),
|
||||||
'sleepedAtHour': _sleepedAt.hour,
|
'sleptAtHour': _sleptAt.hour,
|
||||||
'sleepedAtMinute': _sleepedAt.minute,
|
'sleptAtMinute': _sleptAt.minute,
|
||||||
'wokeUpAtHour': _wokeUpAt.hour,
|
'wokeUpAtHour': _wokeUpAt.hour,
|
||||||
'wokeUpAtMinute': _wokeUpAt.minute,
|
'wokeUpAtMinute': _wokeUpAt.minute,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,7 +1,12 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'package:audioplayers/audioplayers.dart';
|
import 'package:audioplayers/audioplayers.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:smoke_cess_app/providers/timer_provider.dart';
|
||||||
import 'package:smoke_cess_app/widgets/popup_for_start_and_stop.dart';
|
import 'package:smoke_cess_app/widgets/popup_for_start_and_stop.dart';
|
||||||
|
import 'package:smoke_cess_app/widgets/timer_widget.dart';
|
||||||
|
|
||||||
|
import '../providers/input_provider.dart';
|
||||||
|
|
||||||
class IntervalTimerPage extends StatefulWidget {
|
class IntervalTimerPage extends StatefulWidget {
|
||||||
const IntervalTimerPage({Key? key}) : super(key: key);
|
const IntervalTimerPage({Key? key}) : super(key: key);
|
||||||
|
@ -44,9 +49,11 @@ class _IntervalTimerPageState extends State<IntervalTimerPage> {
|
||||||
await showDialog(
|
await showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return const TimerStartStopPopup(
|
return ChangeNotifierProvider(
|
||||||
|
create: (context) => InputProvider(),
|
||||||
|
child: const TimerStartStopPopup(
|
||||||
title: 'Motivation vor dem Training',
|
title: 'Motivation vor dem Training',
|
||||||
);
|
));
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
_isPaused = false;
|
_isPaused = false;
|
||||||
|
@ -161,8 +168,14 @@ class _IntervalTimerPageState extends State<IntervalTimerPage> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return ChangeNotifierProvider(
|
||||||
body: Center(
|
create: (context) => TimerProvider(),
|
||||||
|
child: TimerWidget(
|
||||||
|
duration: Duration(seconds: 5),
|
||||||
|
));
|
||||||
|
return Center(
|
||||||
|
child: ChangeNotifierProvider(
|
||||||
|
create: (context) => InputProvider(),
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
|
@ -191,8 +204,9 @@ class _IntervalTimerPageState extends State<IntervalTimerPage> {
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: Icon(
|
icon: Icon(_isPaused
|
||||||
_isPaused ? Icons.play_arrow_rounded : Icons.stop_rounded),
|
? Icons.play_arrow_rounded
|
||||||
|
: Icons.stop_rounded),
|
||||||
iconSize: 48.0,
|
iconSize: 48.0,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
if (_isPaused) {
|
if (_isPaused) {
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
|
import 'package:awesome_dialog/awesome_dialog.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:smoke_cess_app/pages/mood_page.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:smoke_cess_app/pages/relapse_page.dart';
|
import 'package:smoke_cess_app/services/pages_service.dart';
|
||||||
import 'package:smoke_cess_app/pages/scanner_page.dart';
|
import 'package:smoke_cess_app/providers/settings_provider.dart';
|
||||||
import 'package:smoke_cess_app/pages/sleep_page.dart';
|
|
||||||
import 'package:smoke_cess_app/pages/interval_page.dart';
|
|
||||||
import 'package:smoke_cess_app/service/settings_service.dart';
|
|
||||||
import 'package:smoke_cess_app/widgets/missing_config_popup.dart';
|
|
||||||
|
|
||||||
class MyHomePage extends StatefulWidget {
|
class MyHomePage extends StatefulWidget {
|
||||||
const MyHomePage({super.key});
|
const MyHomePage({super.key});
|
||||||
|
@ -16,73 +13,42 @@ class MyHomePage extends StatefulWidget {
|
||||||
|
|
||||||
class MyHomePageState extends State<MyHomePage> {
|
class MyHomePageState extends State<MyHomePage> {
|
||||||
int _selectedIndex = 4;
|
int _selectedIndex = 4;
|
||||||
int? _gruppe;
|
bool _isConfigured = false;
|
||||||
|
|
||||||
final List<String> _titles = [
|
void _onItemTapped(int index) {
|
||||||
'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;
|
|
||||||
setState(() {
|
setState(() {
|
||||||
isConfigured
|
_isConfigured
|
||||||
? _selectedIndex = index
|
? _selectedIndex = index
|
||||||
: showDialog(
|
: AwesomeDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
dialogType: DialogType.info,
|
||||||
return const MissingConfigPopup(
|
|
||||||
title: 'Fehlende Konfiguration',
|
title: 'Fehlende Konfiguration',
|
||||||
text: 'Bitte QR Code Scannen!',
|
desc: 'Bitte QR Code Scannen!',
|
||||||
);
|
).show();
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
var settingsModel = context.watch<SettingsProvider>();
|
||||||
|
var group = settingsModel.settings?.group;
|
||||||
|
_isConfigured = settingsModel.initialized;
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(
|
title: Text(
|
||||||
'${_titles[_selectedIndex]} ${_gruppe != null ? "Gruppe $_gruppe" : ""}')),
|
'${pages.keys.elementAt(_selectedIndex)} ${_isConfigured ? "Gruppe $group" : ""}')),
|
||||||
body: _widgetOptions.elementAt(_selectedIndex),
|
body: Center(
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
child: pages.values.elementAt(_selectedIndex)['page'])),
|
||||||
bottomNavigationBar: NavigationBar(
|
bottomNavigationBar: NavigationBar(
|
||||||
onDestinationSelected: _onItemTapped,
|
onDestinationSelected: _onItemTapped,
|
||||||
selectedIndex: _selectedIndex,
|
selectedIndex: _selectedIndex,
|
||||||
destinations: const <Widget>[
|
destinations: pages.keys.map((key) {
|
||||||
NavigationDestination(
|
return NavigationDestination(
|
||||||
icon: Icon(Icons.mood_outlined, color: Colors.black),
|
icon: pages[key]!['icon'] ??
|
||||||
label: 'Stimmung'),
|
const Icon(Icons.disabled_by_default),
|
||||||
NavigationDestination(
|
label: key);
|
||||||
icon: Icon(Icons.bedtime_outlined, color: Colors.black),
|
}).toList()),
|
||||||
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,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:smoke_cess_app/providers/input_provider.dart';
|
||||||
import 'package:smoke_cess_app/widgets/mood_form.dart';
|
import 'package:smoke_cess_app/widgets/mood_form.dart';
|
||||||
|
|
||||||
class MoodPage extends StatelessWidget {
|
class MoodPage extends StatelessWidget {
|
||||||
|
@ -6,8 +8,10 @@ class MoodPage extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return const Center(
|
return Center(
|
||||||
child: MoodForm(),
|
child: ChangeNotifierProvider(
|
||||||
);
|
create: (context) => InputProvider(),
|
||||||
|
child: const MoodForm(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,17 @@
|
||||||
import 'package:flutter/material.dart';
|
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 {
|
class RelapsePage extends StatelessWidget {
|
||||||
const RelapsePage({super.key});
|
const RelapsePage({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
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,24 +1,45 @@
|
||||||
|
import 'package:awesome_dialog/awesome_dialog.dart';
|
||||||
import 'package:flutter/material.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/mood.dart';
|
||||||
import 'package:smoke_cess_app/models/settings.dart';
|
import 'package:smoke_cess_app/models/relapse.dart';
|
||||||
import 'package:smoke_cess_app/service/database_service.dart';
|
import 'package:smoke_cess_app/services/settings_service.dart';
|
||||||
import 'package:smoke_cess_app/service/json_service.dart';
|
import 'package:smoke_cess_app/services/notification_service.dart';
|
||||||
import 'package:smoke_cess_app/service/settings_service.dart';
|
import 'package:smoke_cess_app/widgets/scanner.dart';
|
||||||
import 'package:smoke_cess_app/service/notification_service.dart';
|
|
||||||
|
|
||||||
import '../models/sleep.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});
|
const ScannerPage({super.key});
|
||||||
|
|
||||||
@override
|
void export() async {
|
||||||
State<StatefulWidget> createState() => ScannerPageState();
|
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> {
|
void loadJSON(BuildContext context) async {
|
||||||
bool scanning = false;
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -26,70 +47,19 @@ class ScannerPageState extends State<ScannerPage> {
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
scanning
|
const MyScanner(),
|
||||||
? 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 SizedBox(height: 30),
|
const SizedBox(height: 30),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
textStyle: const TextStyle(fontSize: 20)),
|
textStyle: const TextStyle(fontSize: 20)),
|
||||||
onPressed: () {
|
onPressed: () => loadJSON(context),
|
||||||
loadSettingsFromLocalJSON();
|
|
||||||
NotificationService().setAllNotifications();
|
|
||||||
},
|
|
||||||
child: const Text('Read JSON'),
|
child: const Text('Read JSON'),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 30),
|
const SizedBox(height: 30),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
textStyle: const TextStyle(fontSize: 20)),
|
textStyle: const TextStyle(fontSize: 20)),
|
||||||
onPressed: () async {
|
onPressed: export,
|
||||||
List<Mood> moods = await DatabaseService.instance.getMoodRecords();
|
|
||||||
List<Sleep> sleeps =
|
|
||||||
await DatabaseService.instance.getSleepRecords();
|
|
||||||
for (Mood mood in moods) {
|
|
||||||
print(mood.toCSV());
|
|
||||||
}
|
|
||||||
for (Sleep sleep in sleeps) {
|
|
||||||
print(sleep.toCSV());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
child: const Text('Export'),
|
child: const Text('Export'),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:smoke_cess_app/providers/input_provider.dart';
|
||||||
import 'package:smoke_cess_app/widgets/sleep_form.dart';
|
import 'package:smoke_cess_app/widgets/sleep_form.dart';
|
||||||
|
|
||||||
class SleepPage extends StatelessWidget {
|
class SleepPage extends StatelessWidget {
|
||||||
|
@ -6,6 +8,10 @@ class SleepPage extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return const Center(child: SleepForm());
|
return Center(
|
||||||
|
child: ChangeNotifierProvider(
|
||||||
|
create: (context) => InputProvider(),
|
||||||
|
child: const SleepForm(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
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;
|
||||||
|
|
||||||
|
class InputProvider extends ChangeNotifier {
|
||||||
|
double _sliderValue = 50;
|
||||||
|
final TextEditingController _textController = TextEditingController(text: '');
|
||||||
|
final Map<String, TimeOfDay> _times = {
|
||||||
|
'wokeUpAt': const TimeOfDay(hour: 8, minute: 0),
|
||||||
|
'sleptAt': const TimeOfDay(hour: 22, minute: 0),
|
||||||
|
};
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setTime(String key, TimeOfDay time) {
|
||||||
|
_times[key] = time;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _resetFields() {
|
||||||
|
_sliderValue = 50;
|
||||||
|
_textController.text = '';
|
||||||
|
setTime('wokeUpAt', const TimeOfDay(hour: 8, minute: 0));
|
||||||
|
setTime('sleptAt', const TimeOfDay(hour: 22, minute: 0));
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<int> saveMood() {
|
||||||
|
Mood mood =
|
||||||
|
Mood(_sliderValue.toInt(), _textController.text, DateTime.now());
|
||||||
|
_resetFields();
|
||||||
|
return globals.databaseService.addMood(mood);
|
||||||
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
_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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class TimerProvider extends ChangeNotifier {
|
||||||
|
Timer? _timer;
|
||||||
|
bool started = false;
|
||||||
|
int get elapsedSeconds => _timer != null ? _timer!.tick : 0;
|
||||||
|
|
||||||
|
void startTimer(Duration duration) {
|
||||||
|
started = true;
|
||||||
|
print('starting timer');
|
||||||
|
_timer = Timer.periodic(const Duration(seconds: 1), ((timer) {
|
||||||
|
if (timer.tick >= duration.inSeconds) {
|
||||||
|
timer.cancel();
|
||||||
|
started = false;
|
||||||
|
}
|
||||||
|
notifyListeners();
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
void stopTimer() => _timer?.cancel();
|
||||||
|
}
|
|
@ -1,21 +0,0 @@
|
||||||
import 'package:smoke_cess_app/interface/db_record.dart';
|
|
||||||
import 'package:smoke_cess_app/mock/db_mock.dart';
|
|
||||||
|
|
||||||
class QueryService {
|
|
||||||
final DatabaseMock _database;
|
|
||||||
|
|
||||||
QueryService(this._database);
|
|
||||||
|
|
||||||
void addRecord(DatabaseRecord record) => _database.saveRecord(record);
|
|
||||||
List<DatabaseRecord> getWorkoutRecords() => _database.getWorkoutRecords();
|
|
||||||
List<DatabaseRecord> getMoodRecords() => _database.getMoodRecords();
|
|
||||||
List<DatabaseRecord> getSleepRecords() => _database.getSleepRecords();
|
|
||||||
|
|
||||||
String recordsToCSV(List<DatabaseRecord> records) {
|
|
||||||
String csv = "";
|
|
||||||
for (DatabaseRecord record in records) {
|
|
||||||
csv += '${record.toCSV()}\n';
|
|
||||||
}
|
|
||||||
return csv;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -2,6 +2,7 @@ import 'dart:async';
|
||||||
|
|
||||||
import 'package:path/path.dart';
|
import 'package:path/path.dart';
|
||||||
import 'package:smoke_cess_app/models/mood.dart';
|
import 'package:smoke_cess_app/models/mood.dart';
|
||||||
|
import 'package:smoke_cess_app/models/relapse.dart';
|
||||||
import 'package:sqflite/sqflite.dart';
|
import 'package:sqflite/sqflite.dart';
|
||||||
// ignore: depend_on_referenced_packages
|
// ignore: depend_on_referenced_packages
|
||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
@ -53,6 +54,15 @@ class DatabaseService {
|
||||||
return sleepList;
|
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 {
|
Future<int> addMood(Mood mood) async {
|
||||||
Database db = await instance.database;
|
Database db = await instance.database;
|
||||||
return await db.insert('mood', mood.toMap());
|
return await db.insert('mood', mood.toMap());
|
||||||
|
@ -62,6 +72,11 @@ class DatabaseService {
|
||||||
Database db = await instance.database;
|
Database db = await instance.database;
|
||||||
return await db.insert('sleep', sleep.toMap());
|
return await db.insert('sleep', sleep.toMap());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<int> addRelapse(Relapse relapse) async {
|
||||||
|
Database db = await instance.database;
|
||||||
|
return await db.insert('relapse', relapse.toMap());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String _createMoodTable = '''
|
String _createMoodTable = '''
|
||||||
|
@ -79,8 +94,8 @@ String _createSleepTable = '''
|
||||||
value INTEGER,
|
value INTEGER,
|
||||||
date TEXT,
|
date TEXT,
|
||||||
comment TEXT,
|
comment TEXT,
|
||||||
sleepedAtHour INTEGER,
|
sleptAtHour INTEGER,
|
||||||
sleepedAtMinute INTEGER,
|
sleptAtMinute INTEGER,
|
||||||
wokeUpAtHour INTEGER,
|
wokeUpAtHour INTEGER,
|
||||||
wokeUpAtMinute INTEGER
|
wokeUpAtMinute INTEGER
|
||||||
)
|
)
|
|
@ -1,4 +1,4 @@
|
||||||
import 'package:smoke_cess_app/service/settings_service.dart';
|
import 'package:smoke_cess_app/services/settings_service.dart';
|
||||||
import 'package:timezone/timezone.dart';
|
import 'package:timezone/timezone.dart';
|
||||||
|
|
||||||
const int trainingTime = 40;
|
const int trainingTime = 40;
|
||||||
|
@ -13,15 +13,6 @@ const weekDays = {
|
||||||
"Sonntag": 7,
|
"Sonntag": 7,
|
||||||
};
|
};
|
||||||
|
|
||||||
Future<List<TZDateTime>> getDatesforAll() async {
|
|
||||||
List<TZDateTime> allDates = [];
|
|
||||||
List<TZDateTime> moodDates = await getDatesforMood();
|
|
||||||
List<TZDateTime> sleepDates = await getDatesforSleep();
|
|
||||||
allDates.addAll(moodDates);
|
|
||||||
allDates.addAll(sleepDates);
|
|
||||||
return allDates;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<List<TZDateTime>> getDatesforMood() async {
|
Future<List<TZDateTime>> getDatesforMood() async {
|
||||||
final List<String>? selectedDays = await getMoodQueryDaysCategories();
|
final List<String>? selectedDays = await getMoodQueryDaysCategories();
|
||||||
final int? selectedHours = await getMoodQueryHours();
|
final int? selectedHours = await getMoodQueryHours();
|
|
@ -1,5 +1,5 @@
|
||||||
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
||||||
import 'package:smoke_cess_app/service/date_service.dart';
|
import 'package:smoke_cess_app/services/date_service.dart';
|
||||||
import 'package:timezone/timezone.dart';
|
import 'package:timezone/timezone.dart';
|
||||||
|
|
||||||
class NotificationService {
|
class NotificationService {
|
||||||
|
@ -36,29 +36,6 @@ class NotificationService {
|
||||||
await flutterLocalNotificationsPlugin.initialize(initializationSettings);
|
await flutterLocalNotificationsPlugin.initialize(initializationSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> showNotification() async {
|
|
||||||
await flutterLocalNotificationsPlugin.show(
|
|
||||||
0,
|
|
||||||
'test',
|
|
||||||
'test',
|
|
||||||
//schedule the notification to show after 2 seconds.
|
|
||||||
const NotificationDetails(
|
|
||||||
// Android details
|
|
||||||
android: AndroidNotificationDetails('main_channel', 'Main Channel',
|
|
||||||
channelDescription: "ashwin",
|
|
||||||
importance: Importance.max,
|
|
||||||
priority: Priority.max),
|
|
||||||
// iOS details
|
|
||||||
iOS: DarwinNotificationDetails(
|
|
||||||
sound: 'default.wav',
|
|
||||||
presentAlert: true,
|
|
||||||
presentBadge: true,
|
|
||||||
presentSound: true,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> setAllNotifications() async {
|
Future<void> setAllNotifications() async {
|
||||||
List<TZDateTime> moodDates = await getDatesforMood();
|
List<TZDateTime> moodDates = await getDatesforMood();
|
||||||
List<TZDateTime> sleepDates = await getDatesforSleep();
|
List<TZDateTime> sleepDates = await getDatesforSleep();
|
|
@ -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)
|
||||||
|
},
|
||||||
|
};
|
|
@ -1,6 +1,6 @@
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import 'package:smoke_cess_app/models/settings.dart';
|
import 'package:smoke_cess_app/models/settings.dart';
|
||||||
import 'package:smoke_cess_app/service/json_service.dart';
|
import 'package:smoke_cess_app/services/json_service.dart';
|
||||||
|
|
||||||
//access group setting which was saved in local storage
|
//access group setting which was saved in local storage
|
||||||
Future<int?> getGroup() => _getIntSetting('group');
|
Future<int?> getGroup() => _getIntSetting('group');
|
||||||
|
@ -54,14 +54,37 @@ Future<void> loadSettingsFromLocalJSON() async {
|
||||||
void saveSettings(Settings settings) {
|
void saveSettings(Settings settings) {
|
||||||
_setIntSetting('group', settings.group);
|
_setIntSetting('group', settings.group);
|
||||||
_setStringListSetting('relapse_categories', settings.relapseCategories!);
|
_setStringListSetting('relapse_categories', settings.relapseCategories!);
|
||||||
_setStringListSetting('mood_query_days', settings.moodQuery.days!);
|
_setStringListSetting('mood_query_days', settings.moodQuery!.days!);
|
||||||
_setIntSetting('mood_query_hours', settings.moodQuery.hours);
|
_setIntSetting('mood_query_hours', settings.moodQuery!.hours!);
|
||||||
_setIntSetting('mood_query_minutes', settings.moodQuery.minutes);
|
_setIntSetting('mood_query_minutes', settings.moodQuery!.minutes!);
|
||||||
_setStringListSetting('sleep_query_days', settings.sleepQuery.days!);
|
_setStringListSetting('sleep_query_days', settings.sleepQuery!.days!);
|
||||||
_setIntSetting('sleep_query_hours', settings.sleepQuery.hours);
|
_setIntSetting('sleep_query_hours', settings.sleepQuery!.hours!);
|
||||||
_setIntSetting('sleep_query_minutes', settings.sleepQuery.minutes);
|
_setIntSetting('sleep_query_minutes', settings.sleepQuery!.minutes!);
|
||||||
if (settings.chessTime != null) {
|
if (settings.chessTime != null) {
|
||||||
_setIntSetting('chess_hours', settings.chessTime!.hours);
|
_setIntSetting('chess_hours', settings.chessTime!.hours!);
|
||||||
_setIntSetting('chess_minutes', settings.chessTime!.minutes);
|
_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,4 @@
|
||||||
|
String formatTime(int seconds) {
|
||||||
|
Duration duration = Duration(seconds: seconds);
|
||||||
|
return '${duration.inMinutes.remainder(60).toString().padLeft(2, '0')}:${duration.inSeconds.remainder(60).toString().padLeft(2, '0')}';
|
||||||
|
}
|
|
@ -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(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,54 +1,39 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
import 'package:smoke_cess_app/models/mood.dart';
|
import 'package:smoke_cess_app/models/mood.dart';
|
||||||
import 'package:smoke_cess_app/service/database_service.dart';
|
import 'package:smoke_cess_app/services/database_service.dart';
|
||||||
import 'package:smoke_cess_app/widgets/slider.dart';
|
import 'package:smoke_cess_app/widgets/slider.dart';
|
||||||
import 'package:smoke_cess_app/widgets/submit_form_button.dart';
|
import 'package:smoke_cess_app/widgets/submit_form_button.dart';
|
||||||
import 'package:smoke_cess_app/widgets/text_formfield.dart';
|
import 'package:smoke_cess_app/widgets/text_formfield.dart';
|
||||||
|
|
||||||
|
import '../providers/input_provider.dart';
|
||||||
import 'elevated_card.dart';
|
import 'elevated_card.dart';
|
||||||
|
|
||||||
class MoodForm extends StatefulWidget {
|
class MoodForm extends StatelessWidget {
|
||||||
const MoodForm({super.key});
|
const MoodForm({super.key});
|
||||||
|
|
||||||
@override
|
|
||||||
State<MoodForm> createState() => _MoodFormState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _MoodFormState extends State<MoodForm> {
|
|
||||||
final GlobalKey<FormState> _moodFormKey = GlobalKey<FormState>();
|
|
||||||
MySlider slider = MySlider();
|
|
||||||
String _textInput = "";
|
|
||||||
|
|
||||||
void submitForm() {
|
|
||||||
if (_moodFormKey.currentState!.validate()) {
|
|
||||||
_moodFormKey.currentState?.save(); //call every onSave Method
|
|
||||||
Mood mood = Mood(slider.sliderValue.toInt(), _textInput, DateTime.now());
|
|
||||||
DatabaseService.instance.addMood(mood);
|
|
||||||
_moodFormKey.currentState?.reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void onFormFieldSave(String? newValue) => _textInput = newValue!;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Form(
|
var inputModel = context.watch<InputProvider>();
|
||||||
key: _moodFormKey,
|
return Column(
|
||||||
child: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
ElevatedCard(
|
const ElevatedCard(
|
||||||
title: 'Stimmungsbewertung',
|
title: 'Stimmungsbewertung',
|
||||||
child: slider,
|
child: MySlider(),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
ElevatedCard(
|
const ElevatedCard(
|
||||||
title: 'Beschreibe deine Stimmung',
|
title: 'Beschreibe deine Stimmung',
|
||||||
child:
|
child: MyTextFormField('Beschreibe deine Stimmung'),
|
||||||
MyTextFormField('Beschreibe deine Stimmung', onFormFieldSave),
|
|
||||||
),
|
),
|
||||||
SubmitFormButton(submitForm)
|
const SizedBox(
|
||||||
|
height: 80,
|
||||||
|
),
|
||||||
|
SubmitFormButton(
|
||||||
|
submitCallback: inputModel.saveMood,
|
||||||
|
)
|
||||||
],
|
],
|
||||||
));
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,41 +1,26 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:smoke_cess_app/widgets/slider.dart';
|
import 'package:smoke_cess_app/widgets/slider.dart';
|
||||||
import 'package:smoke_cess_app/widgets/submit_form_button.dart';
|
|
||||||
import 'package:smoke_cess_app/widgets/text_formfield.dart';
|
import 'package:smoke_cess_app/widgets/text_formfield.dart';
|
||||||
|
|
||||||
class TimerStartStopPopup extends StatefulWidget {
|
class TimerStartStopPopup extends StatelessWidget {
|
||||||
final String title;
|
final String title;
|
||||||
|
|
||||||
const TimerStartStopPopup({Key? key, required this.title}) : super(key: key);
|
const TimerStartStopPopup({Key? key, required this.title}) : super(key: key);
|
||||||
|
|
||||||
@override
|
|
||||||
TimerStartStopPopupState createState() => TimerStartStopPopupState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class TimerStartStopPopupState extends State<TimerStartStopPopup> {
|
|
||||||
final MySlider slider = MySlider();
|
|
||||||
|
|
||||||
void submitForm(BuildContext context) {
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
void onFormFieldSave(String? newValue) => newValue!;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
title: Text(widget.title),
|
title: Text(title),
|
||||||
content: Column(
|
content: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: const [
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(top: 8),
|
padding: const EdgeInsets.only(top: 8),
|
||||||
child: MySlider(),
|
child: MySlider(),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
SizedBox(height: 16),
|
||||||
MyTextFormField('Beschreibe deinen Motivation', onFormFieldSave),
|
MyTextFormField('Beschreibe deinen Motivation'),
|
||||||
SubmitFormButton(() => submitForm(context)),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -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'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,94 +1,51 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:smoke_cess_app/models/sleep.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:smoke_cess_app/service/database_service.dart';
|
|
||||||
import 'package:smoke_cess_app/widgets/elevated_card.dart';
|
import 'package:smoke_cess_app/widgets/elevated_card.dart';
|
||||||
import 'package:smoke_cess_app/widgets/slider.dart';
|
import 'package:smoke_cess_app/widgets/slider.dart';
|
||||||
import 'package:smoke_cess_app/widgets/submit_form_button.dart';
|
import 'package:smoke_cess_app/widgets/submit_form_button.dart';
|
||||||
import 'package:smoke_cess_app/widgets/text_formfield.dart';
|
import 'package:smoke_cess_app/widgets/text_formfield.dart';
|
||||||
import 'package:smoke_cess_app/widgets/timepicker.dart';
|
import 'package:smoke_cess_app/widgets/timepicker.dart';
|
||||||
|
|
||||||
class SleepForm extends StatefulWidget {
|
import '../providers/input_provider.dart';
|
||||||
|
|
||||||
|
class SleepForm extends StatelessWidget {
|
||||||
const SleepForm({Key? key}) : super(key: key);
|
const SleepForm({Key? key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
|
||||||
State<SleepForm> createState() => _SleepFormState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _SleepFormState extends State<SleepForm> {
|
|
||||||
final GlobalKey<FormState> _sleepFormKey = GlobalKey<FormState>();
|
|
||||||
MySlider slider = MySlider();
|
|
||||||
String _textInput = "";
|
|
||||||
TimePicker sleepTimePicker = TimePicker(
|
|
||||||
const TimeOfDay(hour: 22, minute: 00),
|
|
||||||
);
|
|
||||||
TimePicker wakeUpTimePicker = TimePicker(
|
|
||||||
const TimeOfDay(hour: 8, minute: 00),
|
|
||||||
);
|
|
||||||
|
|
||||||
void submitForm() {
|
|
||||||
if (_sleepFormKey.currentState!.validate()) {
|
|
||||||
_sleepFormKey.currentState?.save(); //call every onSave Method
|
|
||||||
Sleep sleep = Sleep(
|
|
||||||
slider.sliderValue.toInt(),
|
|
||||||
_textInput,
|
|
||||||
DateTime.now(),
|
|
||||||
sleepTimePicker.getCurrentTime,
|
|
||||||
wakeUpTimePicker.getCurrentTime);
|
|
||||||
DatabaseService.instance.addSleep(sleep);
|
|
||||||
_sleepFormKey.currentState?.reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void onFormFieldSave(String? newValue) => _textInput = newValue!;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Form(
|
InputProvider inputModel = context.watch<InputProvider>();
|
||||||
key: _sleepFormKey,
|
String wokeUpKey = 'wokeUpAt';
|
||||||
child: Stack(
|
String sleptKey = 'sleptAt';
|
||||||
children: [
|
|
||||||
SingleChildScrollView(
|
return Column(
|
||||||
child: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
||||||
children: [
|
children: [
|
||||||
ElevatedCard(
|
ElevatedCard(
|
||||||
title: 'Einschlafzeit',
|
title: 'Einschlafzeit',
|
||||||
child: sleepTimePicker,
|
child: TimePicker(sleptKey),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
ElevatedCard(
|
ElevatedCard(
|
||||||
title: 'Aufwachzeit',
|
title: 'Aufwachzeit',
|
||||||
child: wakeUpTimePicker,
|
child: TimePicker(wokeUpKey),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
ElevatedCard(
|
const ElevatedCard(
|
||||||
title: 'Schlafbewertung',
|
title: 'Schlafbewertung',
|
||||||
child: slider,
|
child: MySlider(),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
ElevatedCard(
|
const ElevatedCard(
|
||||||
title: 'Schlafbeschreibung',
|
title: 'Schlafbeschreibung',
|
||||||
child: MyTextFormField(
|
child: MyTextFormField('Beschreibe deinen Schlaf'),
|
||||||
'Beschreibe deinen Schlaf', onFormFieldSave),
|
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 80,
|
height: 80,
|
||||||
),
|
),
|
||||||
|
SubmitFormButton(
|
||||||
|
submitCallback: () => inputModel.saveSleep(wokeUpKey, sleptKey),
|
||||||
|
)
|
||||||
],
|
],
|
||||||
),
|
|
||||||
),
|
|
||||||
Positioned(
|
|
||||||
bottom: 0,
|
|
||||||
right: 0,
|
|
||||||
child: SizedBox(
|
|
||||||
width: 140,
|
|
||||||
height: 80,
|
|
||||||
child: SubmitFormButton(submitForm),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,25 +1,19 @@
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:smoke_cess_app/providers/input_provider.dart';
|
||||||
|
|
||||||
// ignore: must_be_immutable
|
class MySlider extends StatelessWidget {
|
||||||
class MySlider extends StatefulWidget {
|
const MySlider({super.key});
|
||||||
double _currentSliderValue = 50;
|
|
||||||
MySlider({Key? key}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<StatefulWidget> createState() => SliderState();
|
|
||||||
|
|
||||||
double get sliderValue => _currentSliderValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
class SliderState extends State<MySlider> {
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
InputProvider inputModel = context.watch<InputProvider>();
|
||||||
return Center(
|
return Center(
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
Text('${widget._currentSliderValue.toInt()}',
|
Text('${inputModel.sliderValue.toInt()}',
|
||||||
style: const TextStyle(fontSize: 22)),
|
style: const TextStyle(fontSize: 22)),
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
@ -27,31 +21,25 @@ class SliderState extends State<MySlider> {
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Icons.remove_outlined),
|
icon: const Icon(Icons.remove_outlined),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
setState(() {
|
inputModel.sliderValue -= 1;
|
||||||
widget._currentSliderValue -= 1;
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Slider(
|
child: Slider(
|
||||||
value: widget._currentSliderValue,
|
value: inputModel.sliderValue,
|
||||||
min: 0,
|
min: 0,
|
||||||
max: 100,
|
max: 100,
|
||||||
divisions: 100,
|
divisions: 100,
|
||||||
label: widget._currentSliderValue.round().toString(),
|
label: '${inputModel.sliderValue.toInt()}',
|
||||||
onChanged: (double value) {
|
onChanged: (double value) {
|
||||||
setState(() {
|
inputModel.sliderValue = value;
|
||||||
widget._currentSliderValue = value;
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Icons.add_outlined),
|
icon: const Icon(Icons.add_outlined),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
setState(() {
|
inputModel.sliderValue += 1;
|
||||||
widget._currentSliderValue += 1;
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
|
@ -1,15 +1,31 @@
|
||||||
|
import 'package:awesome_dialog/awesome_dialog.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class SubmitFormButton extends StatelessWidget {
|
class SubmitFormButton extends StatelessWidget {
|
||||||
final VoidCallback submitCallback;
|
final Future<int> Function() submitCallback;
|
||||||
const SubmitFormButton(this.submitCallback, {super.key});
|
const SubmitFormButton({super.key, required this.submitCallback});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 16.0),
|
padding: const EdgeInsets.symmetric(vertical: 16.0),
|
||||||
child: ElevatedButton(
|
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'),
|
child: const Text('Speichern'),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,18 +1,19 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:smoke_cess_app/providers/input_provider.dart';
|
||||||
|
|
||||||
class MyTextFormField extends StatelessWidget {
|
class MyTextFormField extends StatelessWidget {
|
||||||
final String _description;
|
final String _description;
|
||||||
final Function(String?) onSaveAction;
|
|
||||||
const MyTextFormField(
|
const MyTextFormField(
|
||||||
this._description,
|
this._description, {
|
||||||
this.onSaveAction, {
|
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
var inputProvider = context.watch<InputProvider>();
|
||||||
return TextFormField(
|
return TextFormField(
|
||||||
onSaved: onSaveAction,
|
controller: inputProvider.textController,
|
||||||
decoration: InputDecoration(hintText: _description),
|
decoration: InputDecoration(hintText: _description),
|
||||||
validator: (String? value) =>
|
validator: (String? value) =>
|
||||||
value == null || value.isEmpty ? 'Text eingeben' : null,
|
value == null || value.isEmpty ? 'Text eingeben' : null,
|
||||||
|
|
|
@ -1,34 +1,28 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:smoke_cess_app/providers/input_provider.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
class TimePicker extends StatefulWidget {
|
class TimePicker extends StatelessWidget {
|
||||||
TimeOfDay _initialTime;
|
final String keyMap;
|
||||||
TimePicker(this._initialTime, {Key? key});
|
|
||||||
|
|
||||||
TimeOfDay get getCurrentTime => _initialTime;
|
const TimePicker(this.keyMap, {super.key});
|
||||||
|
|
||||||
@override
|
|
||||||
State<StatefulWidget> createState() => TimePickerState();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class TimePickerState extends State<TimePicker> {
|
|
||||||
TimePickerState();
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
InputProvider inputModel = context.watch<InputProvider>();
|
||||||
|
|
||||||
return Center(
|
return Center(
|
||||||
child: Row(mainAxisAlignment: MainAxisAlignment.center, children: [
|
child: Row(mainAxisAlignment: MainAxisAlignment.center, children: [
|
||||||
Text(
|
Text(
|
||||||
'${widget._initialTime.hour.toString().padLeft(2, '0')}:${widget._initialTime.minute.toString().padLeft(2, '0')}',
|
'${inputModel.getTimeEntry(keyMap).hour.toString().padLeft(2, '0')}:${inputModel.getTimeEntry(keyMap).minute.toString().padLeft(2, '0')}',
|
||||||
style: const TextStyle(fontSize: 22),
|
style: const TextStyle(fontSize: 22),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 16),
|
const SizedBox(width: 16),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
//TODO auslagern
|
|
||||||
TimeOfDay? newTime = await showTimePicker(
|
TimeOfDay? newTime = await showTimePicker(
|
||||||
context: context,
|
context: context,
|
||||||
initialTime: widget._initialTime,
|
initialTime: inputModel.getTimeEntry(keyMap),
|
||||||
builder: (context, child) {
|
builder: (context, child) {
|
||||||
return MediaQuery(
|
return MediaQuery(
|
||||||
data: MediaQuery.of(context)
|
data: MediaQuery.of(context)
|
||||||
|
@ -38,9 +32,7 @@ class TimePickerState extends State<TimePicker> {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
if (newTime == null) return;
|
if (newTime == null) return;
|
||||||
setState(() {
|
inputModel.setTime(keyMap, newTime);
|
||||||
widget._initialTime = newTime;
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
child: const Text('Zeit einstellen'))
|
child: const Text('Zeit einstellen'))
|
||||||
]),
|
]),
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:smoke_cess_app/providers/timer_provider.dart';
|
||||||
|
import 'package:smoke_cess_app/utils/timer_util.dart';
|
||||||
|
|
||||||
|
class TimerWidget extends StatelessWidget {
|
||||||
|
final Duration duration;
|
||||||
|
const TimerWidget({super.key, required this.duration});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
TimerProvider timerProvider = context.watch<TimerProvider>();
|
||||||
|
return Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Text(formatTime(duration.inSeconds - timerProvider.elapsedSeconds)),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () => timerProvider.started
|
||||||
|
? timerProvider.stopTimer()
|
||||||
|
: timerProvider.startTimer(duration),
|
||||||
|
child: Text(timerProvider.started ? 'Stop' : 'Start'))
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
35
pubspec.lock
35
pubspec.lock
|
@ -64,6 +64,13 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.3"
|
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:
|
boolean_selector:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -177,6 +184,13 @@ packages:
|
||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
graphs:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: graphs
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.2.0"
|
||||||
http:
|
http:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -233,6 +247,13 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.0"
|
version: "3.0.0"
|
||||||
|
nested:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: nested
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.0"
|
||||||
path:
|
path:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -310,6 +331,20 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.2.4"
|
version: "4.2.4"
|
||||||
|
provider:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: provider
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "6.0.5"
|
||||||
|
rive:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: rive
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.9.1"
|
||||||
shared_preferences:
|
shared_preferences:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -34,6 +34,8 @@ dependencies:
|
||||||
sqflite:
|
sqflite:
|
||||||
path:
|
path:
|
||||||
path_provider: ^2.0.12
|
path_provider: ^2.0.12
|
||||||
|
provider: ^6.0.5
|
||||||
|
awesome_dialog: ^3.0.2
|
||||||
|
|
||||||
# The following adds the Cupertino Icons font to your application.
|
# The following adds the Cupertino Icons font to your application.
|
||||||
# Use with the CupertinoIcons class for iOS style icons.
|
# Use with the CupertinoIcons class for iOS style icons.
|
||||||
|
|
Loading…
Reference in New Issue