Merge branch 'beautify' into 'main'

Beautify

Closes #41

See merge request Crondung/hsma_cpd!30
main
Kai Mannweiler 2023-03-06 12:17:17 +00:00
commit 3831f85eb8
39 changed files with 428 additions and 230 deletions

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:intl/date_symbol_data_local.dart';
import 'package:provider/provider.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/providers/tasks_provider.dart'; import 'package:smoke_cess_app/providers/tasks_provider.dart';
@ -14,6 +15,7 @@ void main() {
//init database //init database
globals.databaseService; globals.databaseService;
tz.initializeTimeZones(); tz.initializeTimeZones();
initializeDateFormatting('de');
NotificationService().initNotification(); NotificationService().initNotification();
runApp(const MyApp()); runApp(const MyApp());
} }

View File

@ -6,9 +6,10 @@ class Settings {
final QueryConfig? moodQuery; final QueryConfig? moodQuery;
final QueryConfig? sleepQuery; final QueryConfig? sleepQuery;
final TimeConfig? chessTime; final TimeConfig? chessTime;
final DateTime startedAt;
Settings(this.group, this.relapseCategories, this.moodQuery, this.sleepQuery, Settings(this.group, this.relapseCategories, this.moodQuery, this.sleepQuery,
this.chessTime); this.chessTime, this.startedAt);
Settings.fromJson(Map<String, dynamic> json) Settings.fromJson(Map<String, dynamic> json)
: group = json['group'] as int, : group = json['group'] as int,
@ -17,7 +18,8 @@ class Settings {
sleepQuery = QueryConfig.fromJson(json['sleep_query']), sleepQuery = QueryConfig.fromJson(json['sleep_query']),
chessTime = json['chess_time'] != null chessTime = json['chess_time'] != null
? TimeConfig.fromJson(json['chess_time']) ? TimeConfig.fromJson(json['chess_time'])
: null; : null,
startedAt = DateTime.parse(json['startedAt']);
} }
class QueryConfig { class QueryConfig {

View File

@ -1,5 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:smoke_cess_app/interface/db_record.dart'; import 'package:smoke_cess_app/interface/db_record.dart';
import 'package:smoke_cess_app/utils/timer_util.dart';
class Sleep implements DatabaseRecord { class Sleep implements DatabaseRecord {
final int _sleepQualityValue; final int _sleepQualityValue;
@ -13,6 +14,7 @@ class Sleep implements DatabaseRecord {
DateTime get date => _date; DateTime get date => _date;
int get sleepQualitiyValue => _sleepQualityValue; int get sleepQualitiyValue => _sleepQualityValue;
TimeOfDay get sleepDuration => _sleptAt.durationBetween(_wokeUpAt);
@override @override
factory Sleep.fromDatabase(Map<String, dynamic> map) { factory Sleep.fromDatabase(Map<String, dynamic> map) {

View File

@ -1,9 +1,8 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:smoke_cess_app/services/pages_service.dart'; import 'package:smoke_cess_app/services/pages_service.dart';
import 'package:smoke_cess_app/widgets/workout_form.dart'; import 'package:smoke_cess_app/widgets/view_form/workout_form.dart';
import 'package:smoke_cess_app/widgets/workout_view.dart'; import 'package:smoke_cess_app/widgets/view_form/workout_view.dart';
import 'package:smoke_cess_app/widgets/view_form/view_form_page.dart';
import '../widgets/view_form_page.dart';
class IntervalTimerPage extends StatelessWidget { class IntervalTimerPage extends StatelessWidget {
const IntervalTimerPage({super.key}); const IntervalTimerPage({super.key});

View File

@ -8,52 +8,49 @@ import 'package:smoke_cess_app/providers/settings_provider.dart';
import '../widgets/todo_icon.dart'; import '../widgets/todo_icon.dart';
class MyHomePage extends StatefulWidget { class MyHomePage extends StatelessWidget {
const MyHomePage({super.key}); const MyHomePage({super.key});
@override @override
MyHomePageState createState() => MyHomePageState(); Widget build(BuildContext context) {
} SettingsProvider settingsProvider = context.watch<SettingsProvider>();
TasksProvider tasksProvider = context.watch<TasksProvider>();
PageProvider pageProvider = context.watch<PageProvider>();
bool isConfigured = settingsProvider.initialized;
class MyHomePageState extends State<MyHomePage> { return Scaffold(
int _selectedIndex = 4; appBar: AppBar(
bool _isConfigured = false; title: Row(
children: [
void _onItemTapped(int index) { Stack(
PageProvider pageProvider = context.read<PageProvider>(); children: [
setState(() { const SizedBox(
if (_isConfigured) { width: 70,
pageProvider.showForm = false; ),
_selectedIndex = index; if (pageProvider.showForm)
return; IconButton(
} icon: const Icon(Icons.arrow_back, color: Colors.white),
AwesomeDialog( onPressed: pageProvider.swap),
],
),
Text(
'${pageProvider.currentPageData['title']} ${isConfigured ? "Gruppe ${settingsProvider.settings?.group}" : ""}')
],
)),
body: pageProvider.currentPageData['page'],
bottomNavigationBar: NavigationBar(
onDestinationSelected: isConfigured
? pageProvider.setCurrentPage
: (value) => AwesomeDialog(
context: context, context: context,
dialogType: DialogType.info, dialogType: DialogType.info,
title: 'Fehlende Konfiguration', title: 'Fehlende Konfiguration',
desc: 'Bitte QR Code Scannen!', desc: 'Bitte QR Code Scannen!',
).show(); ).show(),
}); selectedIndex: pageProvider.currentPageIndex,
}
@override
Widget build(BuildContext context) {
var settingsModel = context.watch<SettingsProvider>();
var tasksModel = context.watch<TasksProvider>();
_isConfigured = settingsModel.initialized;
return Scaffold(
appBar: AppBar(
title: Text(
'${pages.values.elementAt(_selectedIndex)['title']} ${_isConfigured ? "Gruppe ${settingsModel.settings?.group}" : ""}')),
body: SingleChildScrollView(
child: pages.values.elementAt(_selectedIndex)['page'],
),
bottomNavigationBar: NavigationBar(
onDestinationSelected: _onItemTapped,
selectedIndex: _selectedIndex,
destinations: pages.keys.map((key) { destinations: pages.keys.map((key) {
return NavigationDestination( return NavigationDestination(
icon: tasksModel.tasks[key] ?? false icon: tasksProvider.tasks[key] ?? false
? MyToDoIcon(pages[key]?['icon']) ? MyToDoIcon(pages[key]?['icon'])
: pages[key]!['icon'], : pages[key]!['icon'],
label: pages[key]?['title']); label: pages[key]?['title']);

View File

@ -1,8 +1,8 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:smoke_cess_app/services/pages_service.dart'; import 'package:smoke_cess_app/services/pages_service.dart';
import 'package:smoke_cess_app/widgets/mood_form.dart'; import 'package:smoke_cess_app/widgets/view_form/mood_form.dart';
import 'package:smoke_cess_app/widgets/mood_view.dart'; import 'package:smoke_cess_app/widgets/view_form/mood_view.dart';
import 'package:smoke_cess_app/widgets/view_form_page.dart'; import 'package:smoke_cess_app/widgets/view_form/view_form_page.dart';
class MoodPage extends StatelessWidget { class MoodPage extends StatelessWidget {
const MoodPage({super.key}); const MoodPage({super.key});

View File

@ -1,8 +1,8 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:smoke_cess_app/services/pages_service.dart'; import 'package:smoke_cess_app/services/pages_service.dart';
import 'package:smoke_cess_app/widgets/relapse_form.dart'; import 'package:smoke_cess_app/widgets/view_form/relapse_form.dart';
import 'package:smoke_cess_app/widgets/relapse_view.dart'; import 'package:smoke_cess_app/widgets/view_form/relapse_view.dart';
import '../widgets/view_form_page.dart'; import 'package:smoke_cess_app/widgets/view_form/view_form_page.dart';
class RelapsePage extends StatelessWidget { class RelapsePage extends StatelessWidget {
const RelapsePage({super.key}); const RelapsePage({super.key});

View File

@ -1,8 +1,8 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:smoke_cess_app/services/pages_service.dart'; import 'package:smoke_cess_app/services/pages_service.dart';
import 'package:smoke_cess_app/widgets/sleep_form.dart'; import 'package:smoke_cess_app/widgets/view_form/sleep_form.dart';
import 'package:smoke_cess_app/widgets/sleep_view.dart'; import 'package:smoke_cess_app/widgets/view_form/sleep_view.dart';
import 'package:smoke_cess_app/widgets/view_form_page.dart'; import 'package:smoke_cess_app/widgets/view_form/view_form_page.dart';
class SleepPage extends StatelessWidget { class SleepPage extends StatelessWidget {
const SleepPage({super.key}); const SleepPage({super.key});

View File

@ -1,10 +1,22 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:smoke_cess_app/services/pages_service.dart';
class PageProvider extends ChangeNotifier { class PageProvider extends ChangeNotifier {
bool showForm = false; bool showForm = false;
Pages _currentPage = Pages.settings;
void swap() { void swap() {
showForm = !showForm; showForm = !showForm;
notifyListeners(); notifyListeners();
} }
Map<String, dynamic> get currentPageData => pages[_currentPage]!;
int get currentPageIndex => _currentPage.index;
void setCurrentPage(int index) {
showForm = false;
_currentPage = Pages.values[index];
notifyListeners();
}
} }

View File

@ -5,7 +5,7 @@ import 'package:smoke_cess_app/models/workout.dart';
import 'package:smoke_cess_app/providers/settings_provider.dart'; import 'package:smoke_cess_app/providers/settings_provider.dart';
import 'package:smoke_cess_app/services/date_service.dart'; import 'package:smoke_cess_app/services/date_service.dart';
import 'package:smoke_cess_app/services/pages_service.dart'; import 'package:smoke_cess_app/services/pages_service.dart';
import 'package:timezone/browser.dart'; import 'package:timezone/timezone.dart';
import '../globals.dart' as globals; import '../globals.dart' as globals;
import '../models/mood.dart'; import '../models/mood.dart';

View File

@ -5,13 +5,18 @@ import 'package:flutter/material.dart';
class TimerProvider extends ChangeNotifier { class TimerProvider extends ChangeNotifier {
Timer? _timer; Timer? _timer;
bool started = false; bool started = false;
int get elapsedSeconds => _timer != null ? _timer!.tick : 0; Duration _duration = const Duration();
int get elapsedSeconds => _duration.inSeconds;
int get elapsedMilliseconds => _duration.inMilliseconds;
final Duration _tickRate = const Duration(milliseconds: 20);
void startTimer(Duration duration) { void startTimer(Duration duration) {
_duration = Duration.zero;
started = true; started = true;
_timer = Timer.periodic(const Duration(seconds: 1), ((timer) { _timer = Timer.periodic(_tickRate, ((timer) {
if (timer.tick >= duration.inSeconds) { _duration += _tickRate;
timer.cancel(); if (elapsedSeconds >= duration.inSeconds) {
_timer?.cancel();
started = false; started = false;
} }
notifyListeners(); notifyListeners();
@ -22,13 +27,12 @@ class TimerProvider extends ChangeNotifier {
started = false; started = false;
_timer?.cancel(); _timer?.cancel();
_timer = null; _timer = null;
_duration = Duration.zero;
} }
@override @override
void dispose() { void dispose() {
started = false; stopTimer();
_timer?.cancel();
_timer = null;
super.dispose(); super.dispose();
} }
} }

View File

@ -8,8 +8,8 @@ import '../pages/sleep_page.dart';
enum Pages { enum Pages {
mood, mood,
sleep, sleep,
relapse,
timer, timer,
relapse,
settings, settings,
} }

View File

@ -23,6 +23,8 @@ Future<int?> getMoodQueryMinutes() => _getIntSetting('mood_query_minutes');
Future<int?> getChessHours() => _getIntSetting('chess_hours'); Future<int?> getChessHours() => _getIntSetting('chess_hours');
Future<int?> getChessMinutes() => _getIntSetting('chess_minutes'); Future<int?> getChessMinutes() => _getIntSetting('chess_minutes');
Future<String?> getStartDay() => _getStringSetting('startedAt');
void _setIntSetting(String settingKey, int settingValue) => void _setIntSetting(String settingKey, int settingValue) =>
SharedPreferences.getInstance() SharedPreferences.getInstance()
.then((pref) => pref.setInt(settingKey, settingValue)); .then((pref) => pref.setInt(settingKey, settingValue));
@ -30,6 +32,13 @@ void _setIntSetting(String settingKey, int settingValue) =>
Future<int?> _getIntSetting(String settingKey) => Future<int?> _getIntSetting(String settingKey) =>
SharedPreferences.getInstance().then((pref) => pref.getInt(settingKey)); SharedPreferences.getInstance().then((pref) => pref.getInt(settingKey));
void _setStringSetting(String settingKey, String settingValue) =>
SharedPreferences.getInstance()
.then((pref) => pref.setString(settingKey, settingValue));
Future<String?> _getStringSetting(String settingKey) =>
SharedPreferences.getInstance().then((pref) => pref.getString(settingKey));
void _setStringListSetting(String settingKey, List<String> list) => void _setStringListSetting(String settingKey, List<String> list) =>
SharedPreferences.getInstance() SharedPreferences.getInstance()
.then((pref) => pref.setStringList(settingKey, list)); .then((pref) => pref.setStringList(settingKey, list));
@ -40,6 +49,7 @@ Future<List<String>?> _getStringListSetting(String settingKey) =>
Future<void> loadSettingsFromLocalJSON() async { Future<void> loadSettingsFromLocalJSON() async {
Map<String, dynamic> configJSON = await loadLocalConfigJSON(); Map<String, dynamic> configJSON = await loadLocalConfigJSON();
configJSON['startedAt'] = DateTime.now().toIso8601String();
Settings settings = Settings.fromJson(configJSON); Settings settings = Settings.fromJson(configJSON);
saveSettings(settings); saveSettings(settings);
} }
@ -53,6 +63,7 @@ void saveSettings(Settings settings) {
_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!);
_setStringSetting('startedAt', DateTime.now().toIso8601String());
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!);
@ -70,6 +81,8 @@ Future<Settings?> loadSettings() async {
List<String>? sleepDays = await getSleepQueryDaysCategories(); List<String>? sleepDays = await getSleepQueryDaysCategories();
int? chessHours = await getChessHours(); int? chessHours = await getChessHours();
int? chessMinutes = await getChessMinutes(); int? chessMinutes = await getChessMinutes();
DateTime startedAt =
DateTime.parse(await getStartDay() ?? DateTime.now().toIso8601String());
if (group != null) { if (group != null) {
return Settings( return Settings(
@ -77,7 +90,8 @@ Future<Settings?> loadSettings() async {
relapseCategories, relapseCategories,
QueryConfig(moodHours, moodMinutes, moodDays), QueryConfig(moodHours, moodMinutes, moodDays),
QueryConfig(sleepHours, sleepMinutes, sleepDays), QueryConfig(sleepHours, sleepMinutes, sleepDays),
TimeConfig(chessHours, chessMinutes)); TimeConfig(chessHours, chessMinutes),
startedAt);
} }
return null; return null;
} }

View File

@ -1,3 +1,5 @@
import 'package:flutter/material.dart';
String formatTime(int seconds) { String formatTime(int seconds) {
Duration duration = Duration(seconds: seconds); Duration duration = Duration(seconds: seconds);
String formattedTime = ''; String formattedTime = '';
@ -12,3 +14,12 @@ String formatTime(int seconds) {
formattedTime += formattedSeconds; formattedTime += formattedSeconds;
return formattedTime; return formattedTime;
} }
extension TimeOfDayExtension on TimeOfDay {
TimeOfDay durationBetween(TimeOfDay time) {
int hourOffset = time.minute - minute < 0 ? 1 : 0;
return TimeOfDay(
hour: (time.hour - hour - hourOffset) % 24,
minute: (time.minute - minute) % 60);
}
}

View File

@ -1,7 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import '../../providers/audio_provider.dart';
import '../providers/audio_provider.dart';
class MuteButton extends StatelessWidget { class MuteButton extends StatelessWidget {
const MuteButton({super.key}); const MuteButton({super.key});

View File

@ -0,0 +1,27 @@
import 'package:flutter/material.dart';
class RoundAddButton extends StatelessWidget {
final VoidCallback onPressed;
final IconData iconData;
const RoundAddButton(
{super.key, required this.onPressed, required this.iconData});
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: onPressed,
style: ElevatedButton.styleFrom(
shape: const CircleBorder(),
padding: const EdgeInsets.all(20),
backgroundColor: Colors.green, // <-- Button color
foregroundColor: Colors.blue, // <-- Splash color
),
child: Icon(
iconData,
color: Colors.white,
size: MediaQuery.of(context).size.height * 0.05,
),
);
}
}

View File

@ -0,0 +1,41 @@
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
class EntryDetail extends StatelessWidget {
final DateTime date;
final String entryData;
final IconData icon;
const EntryDetail(
{super.key,
required this.date,
required this.entryData,
required this.icon});
@override
Widget build(BuildContext context) {
return Card(
child: ListTile(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
leading: Icon(icon, color: Colors.white),
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text(
DateFormat.MMMd('de').format(date),
style: const TextStyle(
color: Colors.white, fontWeight: FontWeight.bold),
),
Text(
entryData,
style: const TextStyle(
color: Colors.white, fontWeight: FontWeight.bold),
)
],
),
tileColor: Theme.of(context).colorScheme.primary.withOpacity(0.8),
));
}
}

View File

@ -0,0 +1,39 @@
import 'package:flutter/material.dart';
import 'package:smoke_cess_app/widgets/entry_detail_widget.dart';
class HistoryList<T> extends StatelessWidget {
final List<T> history;
final DateTime Function(T) dateSelector;
final String Function(T) entryDataSelector;
final IconData Function(T)? iconDataSelector;
final IconData? icon;
const HistoryList(
{super.key,
required this.history,
required this.dateSelector,
required this.entryDataSelector,
this.iconDataSelector,
this.icon});
IconData _getIcon(T entry) {
if (icon != null) {
return icon!;
} else if (iconDataSelector != null) {
return iconDataSelector!(entry);
}
return Icons.circle;
}
@override
Widget build(BuildContext context) {
return Expanded(
child: ListView(
children: history.map((T entry) {
return EntryDetail(
date: dateSelector(entry),
entryData: entryDataSelector(entry),
icon: _getIcon(entry));
}).toList()));
}
}

View File

@ -0,0 +1,31 @@
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import 'package:smoke_cess_app/providers/settings_provider.dart';
import 'package:syncfusion_flutter_charts/charts.dart';
class LineChart<T> extends StatelessWidget {
final List<LineSeries<T, DateTime>> series;
const LineChart({
super.key,
required this.series,
});
@override
Widget build(BuildContext context) {
SettingsProvider settingsProvider = context.watch<SettingsProvider>();
return SfCartesianChart(
primaryXAxis: DateTimeAxis(
minimum: settingsProvider.settings?.startedAt,
maximum: settingsProvider.settings?.startedAt
.add(const Duration(days: 7 * 6)),
interval: 7,
dateFormat: DateFormat.Md('de'),
),
primaryYAxis:
NumericAxis(isVisible: false, minimum: 0, maximum: 100, interval: 20),
series: series,
);
}
}

View File

@ -1,32 +0,0 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:syncfusion_flutter_charts/charts.dart';
import '../models/mood.dart';
import '../providers/tasks_provider.dart';
class MoodView extends StatelessWidget {
const MoodView({super.key});
@override
Widget build(BuildContext context) {
var tasksModel = context.watch<TasksProvider>();
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SfCartesianChart(
primaryXAxis: DateTimeAxis(),
series: <ChartSeries>[
LineSeries<Mood, DateTime>(
dataSource: tasksModel.moodHistory,
xValueMapper: (Mood value, _) => value.date,
yValueMapper: (Mood value, _) => value.moodValue)
],
),
Column(
children: tasksModel.moodHistory.map((mood) {
return Text('${mood.date}: ${mood.moodValue}');
}).toList())
],
);
}
}

View File

@ -2,8 +2,8 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:smoke_cess_app/providers/timer_provider.dart'; import 'package:smoke_cess_app/providers/timer_provider.dart';
import 'package:smoke_cess_app/widgets/timer_widget.dart'; import 'package:smoke_cess_app/widgets/timer_widget.dart';
import '../services/date_service.dart'; import 'package:smoke_cess_app/services/date_service.dart';
import '../services/pages_service.dart'; import 'package:smoke_cess_app/services/pages_service.dart';
void showTaskDonePopup(BuildContext context, Pages page) async { void showTaskDonePopup(BuildContext context, Pages page) async {
Duration duration = await getTimeTill(page); Duration duration = await getTimeTill(page);

View File

@ -1,17 +0,0 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../providers/tasks_provider.dart';
class RelapseView extends StatelessWidget {
const RelapseView({super.key});
@override
Widget build(BuildContext context) {
var tasksModel = context.watch<TasksProvider>();
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: tasksModel.relapseHistory.map((relapse) {
return Text('${relapse.date}: ${relapse.category}');
}).toList());
}
}

View File

@ -3,11 +3,10 @@ import 'package:provider/provider.dart';
import 'package:smoke_cess_app/providers/tasks_provider.dart'; import 'package:smoke_cess_app/providers/tasks_provider.dart';
import 'package:smoke_cess_app/services/pages_service.dart'; import 'package:smoke_cess_app/services/pages_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/buttons/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/providers/input_provider.dart';
import '../providers/input_provider.dart'; import 'package:smoke_cess_app/widgets/elevated_card.dart';
import 'elevated_card.dart';
class MoodForm extends StatelessWidget { class MoodForm extends StatelessWidget {
const MoodForm({super.key}); const MoodForm({super.key});
@ -16,8 +15,7 @@ class MoodForm extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
var inputModel = context.watch<InputProvider>(); var inputModel = context.watch<InputProvider>();
var tasksModel = context.watch<TasksProvider>(); var tasksModel = context.watch<TasksProvider>();
return Column( return ListView(
mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
const ElevatedCard( const ElevatedCard(
title: 'Stimmungsbewertung', title: 'Stimmungsbewertung',

View File

@ -0,0 +1,35 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:smoke_cess_app/widgets/history_list_widget.dart';
import 'package:smoke_cess_app/widgets/line_chart_widget.dart';
import 'package:syncfusion_flutter_charts/charts.dart';
import 'package:smoke_cess_app/models/mood.dart';
import 'package:smoke_cess_app/providers/tasks_provider.dart';
class MoodView extends StatelessWidget {
const MoodView({super.key});
@override
Widget build(BuildContext context) {
var tasksModel = context.watch<TasksProvider>();
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
LineChart(series: [
LineSeries<Mood, DateTime>(
dataSource: tasksModel.moodHistory,
xValueMapper: (Mood value, _) => value.date,
yValueMapper: (Mood value, _) => value.moodValue)
]),
HistoryList<Mood>(
history: tasksModel.moodHistory,
dateSelector: (Mood mood) => mood.date,
entryDataSelector: (Mood mood) => 'Stimmung: ${mood.moodValue}',
iconDataSelector: (Mood mood) => mood.moodValue >= 50
? Icons.mood_outlined
: Icons.mood_bad_outlined,
)
],
);
}
}

View File

@ -2,12 +2,12 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:smoke_cess_app/providers/tasks_provider.dart'; import 'package:smoke_cess_app/providers/tasks_provider.dart';
import 'package:smoke_cess_app/widgets/drop_down.dart'; import 'package:smoke_cess_app/widgets/drop_down.dart';
import 'package:smoke_cess_app/widgets/submit_form_button.dart'; import 'package:smoke_cess_app/widgets/buttons/submit_form_button.dart';
import 'package:smoke_cess_app/widgets/text_formfield.dart'; import 'package:smoke_cess_app/widgets/text_formfield.dart';
import '../providers/input_provider.dart'; import 'package:smoke_cess_app/providers/input_provider.dart';
import '../providers/settings_provider.dart'; import 'package:smoke_cess_app/providers/settings_provider.dart';
import '../services/pages_service.dart'; import 'package:smoke_cess_app/services/pages_service.dart';
import 'elevated_card.dart'; import 'package:smoke_cess_app/widgets/elevated_card.dart';
class RelapseForm extends StatelessWidget { class RelapseForm extends StatelessWidget {
const RelapseForm({super.key}); const RelapseForm({super.key});
@ -17,8 +17,7 @@ class RelapseForm extends StatelessWidget {
var inputModel = context.watch<InputProvider>(); var inputModel = context.watch<InputProvider>();
var settingsModel = context.watch<SettingsProvider>(); var settingsModel = context.watch<SettingsProvider>();
var tasksModel = context.watch<TasksProvider>(); var tasksModel = context.watch<TasksProvider>();
return Column( return ListView(
mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
ElevatedCard( ElevatedCard(
title: 'Rückfallkategorie', title: 'Rückfallkategorie',

View File

@ -0,0 +1,20 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:smoke_cess_app/models/relapse.dart';
import 'package:smoke_cess_app/providers/tasks_provider.dart';
import 'package:smoke_cess_app/widgets/history_list_widget.dart';
class RelapseView extends StatelessWidget {
const RelapseView({super.key});
@override
Widget build(BuildContext context) {
TasksProvider tasksModel = context.watch<TasksProvider>();
return HistoryList<Relapse>(
history: tasksModel.relapseHistory,
dateSelector: (Relapse relapse) => relapse.date,
entryDataSelector: (Relapse relapse) => 'Grund: ${relapse.category}',
icon: Icons.smoke_free_outlined,
);
}
}

View File

@ -3,12 +3,12 @@ import 'package:provider/provider.dart';
import 'package:smoke_cess_app/providers/tasks_provider.dart'; import 'package:smoke_cess_app/providers/tasks_provider.dart';
import 'package:smoke_cess_app/widgets/elevated_card.dart'; import 'package:smoke_cess_app/widgets/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/buttons/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';
import '../providers/input_provider.dart'; import 'package:smoke_cess_app/providers/input_provider.dart';
import '../services/pages_service.dart'; import 'package:smoke_cess_app/services/pages_service.dart';
class SleepForm extends StatelessWidget { class SleepForm extends StatelessWidget {
const SleepForm({Key? key}) : super(key: key); const SleepForm({Key? key}) : super(key: key);
@ -18,8 +18,7 @@ class SleepForm extends StatelessWidget {
InputProvider inputModel = context.watch<InputProvider>(); InputProvider inputModel = context.watch<InputProvider>();
TasksProvider tasksModel = context.watch<TasksProvider>(); TasksProvider tasksModel = context.watch<TasksProvider>();
return Column( return ListView(
mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
const ElevatedCard( const ElevatedCard(
title: 'Einschlafzeit', title: 'Einschlafzeit',

View File

@ -1,31 +1,35 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:smoke_cess_app/models/sleep.dart'; import 'package:smoke_cess_app/models/sleep.dart';
import 'package:smoke_cess_app/widgets/history_list_widget.dart';
import 'package:smoke_cess_app/widgets/line_chart_widget.dart';
import 'package:smoke_cess_app/providers/tasks_provider.dart';
import 'package:syncfusion_flutter_charts/charts.dart'; import 'package:syncfusion_flutter_charts/charts.dart';
import '../providers/tasks_provider.dart';
class SleepView extends StatelessWidget { class SleepView extends StatelessWidget {
const SleepView({super.key}); const SleepView({super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var tasksModel = context.watch<TasksProvider>(); TasksProvider tasksModel = context.watch<TasksProvider>();
return Column( return Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
SfCartesianChart( LineChart<Sleep>(
primaryXAxis: DateTimeAxis(), series: [
series: <ChartSeries>[
LineSeries<Sleep, DateTime>( LineSeries<Sleep, DateTime>(
dataSource: tasksModel.sleepHistory, dataSource: tasksModel.sleepHistory,
xValueMapper: (Sleep value, _) => value.date, xValueMapper: (Sleep value, _) => value.date,
yValueMapper: (Sleep value, _) => value.sleepQualitiyValue) yValueMapper: (Sleep value, _) => value.sleepQualitiyValue)
], ],
), ),
Column( HistoryList<Sleep>(
children: tasksModel.sleepHistory.map((sleep) { history: tasksModel.sleepHistory,
return Text('${sleep.date}: ${sleep.sleepQualitiyValue}'); dateSelector: (Sleep sleep) => sleep.date,
}).toList()) entryDataSelector: (Sleep sleep) =>
'${sleep.sleepDuration.hour}:${sleep.sleepDuration.minute}',
icon: Icons.bedtime_outlined,
)
], ],
); );
} }

View File

@ -0,0 +1,44 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:smoke_cess_app/services/pages_service.dart';
import 'package:smoke_cess_app/widgets/buttons/round_button_widget.dart';
import 'package:smoke_cess_app/providers/input_provider.dart';
import 'package:smoke_cess_app/providers/page_provider.dart';
import 'package:smoke_cess_app/providers/tasks_provider.dart';
import 'package:smoke_cess_app/widgets/popup/popup_for_task_done.dart';
class ViewFormPage extends StatelessWidget {
final Widget form;
final Widget view;
final Pages page;
const ViewFormPage(
{super.key, required this.form, required this.view, required this.page});
@override
Widget build(BuildContext context) {
final height = MediaQuery.of(context).size.height;
PageProvider pageProvider = context.watch<PageProvider>();
TasksProvider tasksProvider = context.watch<TasksProvider>();
return Column(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
Expanded(
child: Center(
child: pageProvider.showForm
? ChangeNotifierProvider(
create: (context) => InputProvider(),
child: form,
)
: view,
)),
if (!pageProvider.showForm)
Container(
margin: EdgeInsets.symmetric(vertical: height * 0.02),
child: RoundAddButton(
iconData: Icons.add_outlined,
onPressed: tasksProvider.tasks[page] ?? true
? () => pageProvider.swap()
: () => showTaskDonePopup(context, page),
),
)
]);
}
}

View File

@ -1,10 +1,10 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:smoke_cess_app/providers/audio_provider.dart'; import 'package:smoke_cess_app/providers/audio_provider.dart';
import '../providers/timer_provider.dart'; import 'package:smoke_cess_app/providers/timer_provider.dart';
import '../providers/workout_provider.dart'; import 'package:smoke_cess_app/providers/workout_provider.dart';
import 'mute_button.dart'; import 'package:smoke_cess_app/widgets/buttons/mute_button.dart';
import 'workout_timer_widget.dart'; import 'package:smoke_cess_app/widgets/workout_timer_widget.dart';
class WorkoutForm extends StatelessWidget { class WorkoutForm extends StatelessWidget {
WorkoutForm({super.key}); WorkoutForm({super.key});

View File

@ -0,0 +1,38 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:smoke_cess_app/models/workout.dart';
import 'package:smoke_cess_app/widgets/history_list_widget.dart';
import 'package:smoke_cess_app/widgets/line_chart_widget.dart';
import 'package:syncfusion_flutter_charts/charts.dart';
import 'package:smoke_cess_app/providers/tasks_provider.dart';
class WorkoutView extends StatelessWidget {
const WorkoutView({super.key});
@override
Widget build(BuildContext context) {
TasksProvider tasksModel = context.watch<TasksProvider>();
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
LineChart(series: [
LineSeries<Workout, DateTime>(
dataSource: tasksModel.workoutHistory,
xValueMapper: (Workout value, _) => value.date,
yValueMapper: (Workout value, _) => value.motivationBefore),
LineSeries<Workout, DateTime>(
dataSource: tasksModel.workoutHistory,
xValueMapper: (Workout value, _) => value.date,
yValueMapper: (Workout value, _) => value.motivationAfter)
]),
HistoryList<Workout>(
history: tasksModel.workoutHistory,
dateSelector: (Workout workout) => workout.date,
entryDataSelector: (Workout workout) =>
'${workout.motivationBefore} : ${workout.motivationAfter}',
icon: Icons.sports_score_outlined,
)
],
);
}
}

View File

@ -1,41 +0,0 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:smoke_cess_app/services/pages_service.dart';
import '../providers/input_provider.dart';
import '../providers/page_provider.dart';
import '../providers/tasks_provider.dart';
import 'popup_for_task_done.dart';
class ViewFormPage extends StatelessWidget {
final Widget form;
final Widget view;
final Pages page;
const ViewFormPage(
{super.key, required this.form, required this.view, required this.page});
@override
Widget build(BuildContext context) {
PageProvider pageProvider = context.watch<PageProvider>();
TasksProvider tasksProvider = context.watch<TasksProvider>();
return Wrap(children: [
Align(
alignment: Alignment.topLeft,
child: IconButton(
icon: pageProvider.showForm
? const Icon(Icons.arrow_back, color: Colors.black)
: const Icon(Icons.add_outlined, color: Colors.black),
onPressed: tasksProvider.tasks[page] ?? true
? pageProvider.swap
: () => showTaskDonePopup(context, page),
),
),
pageProvider.showForm
? Center(
child: ChangeNotifierProvider(
create: (context) => InputProvider(),
child: form,
))
: Center(child: view)
]);
}
}

View File

@ -4,13 +4,13 @@ import 'package:awesome_dialog/awesome_dialog.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import '../providers/page_provider.dart'; import 'package:smoke_cess_app/providers/page_provider.dart';
import '../providers/tasks_provider.dart'; import 'package:smoke_cess_app/providers/tasks_provider.dart';
import '../providers/workout_provider.dart'; import 'package:smoke_cess_app/providers/workout_provider.dart';
import '../services/pages_service.dart'; import 'package:smoke_cess_app/services/pages_service.dart';
import '../widgets/timer_widget.dart'; import 'package:smoke_cess_app/widgets/timer_widget.dart';
import '../providers/timer_provider.dart'; import 'package:smoke_cess_app/providers/timer_provider.dart';
import 'popup_for_start_and_stop.dart'; import 'package:smoke_cess_app/widgets/popup/popup_for_start_and_stop.dart';
class WorkoutTimerWidget extends StatelessWidget { class WorkoutTimerWidget extends StatelessWidget {
const WorkoutTimerWidget({super.key}); const WorkoutTimerWidget({super.key});
@ -74,10 +74,12 @@ class WorkoutTimerWidget extends StatelessWidget {
width: 100, width: 100,
child: CircularProgressIndicator( child: CircularProgressIndicator(
color: workoutProvider.currentPhaseColor, color: workoutProvider.currentPhaseColor,
value: (workoutProvider.currentPhaseDuration.inSeconds value:
.toDouble() - (workoutProvider.currentPhaseDuration.inMilliseconds -
timerProvider.elapsedSeconds) / timerProvider.elapsedMilliseconds)
workoutProvider.currentPhaseDuration.inSeconds)), .toDouble() /
workoutProvider.currentPhaseDuration.inMilliseconds
.toDouble())),
TimerWidget(duration: workoutProvider.currentPhaseDuration), TimerWidget(duration: workoutProvider.currentPhaseDuration),
], ],
), ),

View File

@ -1,32 +0,0 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:smoke_cess_app/models/workout.dart';
import 'package:syncfusion_flutter_charts/charts.dart';
import '../providers/tasks_provider.dart';
class WorkoutView extends StatelessWidget {
const WorkoutView({super.key});
@override
Widget build(BuildContext context) {
var tasksModel = context.watch<TasksProvider>();
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SfCartesianChart(
primaryXAxis: DateTimeAxis(),
series: <ChartSeries>[
LineSeries<Workout, DateTime>(
dataSource: tasksModel.workoutHistory,
xValueMapper: (Workout value, _) => value.date,
yValueMapper: (Workout value, _) => value.motivationBefore),
LineSeries<Workout, DateTime>(
dataSource: tasksModel.workoutHistory,
xValueMapper: (Workout value, _) => value.date,
yValueMapper: (Workout value, _) => value.motivationAfter)
],
),
],
);
}
}

View File

@ -24,6 +24,7 @@ dependencies:
http: ^0.13.5 http: ^0.13.5
syncfusion_flutter_charts: ^20.4.52 syncfusion_flutter_charts: ^20.4.52
cupertino_icons: ^1.0.2 cupertino_icons: ^1.0.2
intl: ^0.18.0
dev_dependencies: dev_dependencies:
flutter_test: flutter_test: