Merge branch '43-ausklappbares-listitem' into 'main'

Resolve "Ausklappbares ListItem"

Closes #43

See merge request Crondung/hsma_cpd!33
main
Kai Mannweiler 2023-03-06 15:12:49 +00:00
commit 134bf1ae59
15 changed files with 118 additions and 51 deletions

View File

@ -9,6 +9,7 @@ class Mood implements DatabaseRecord {
DateTime get date => _date; DateTime get date => _date;
int get moodValue => _moodValue; int get moodValue => _moodValue;
String get comment => _comment;
@override @override
factory Mood.fromDatabase(Map<String, dynamic> map) { factory Mood.fromDatabase(Map<String, dynamic> map) {

View File

@ -9,6 +9,7 @@ class Relapse implements DatabaseRecord {
String get category => _category; String get category => _category;
DateTime get date => _date; DateTime get date => _date;
String get comment => _comment;
@override @override
factory Relapse.fromDatabase(Map<String, dynamic> map) { factory Relapse.fromDatabase(Map<String, dynamic> map) {

View File

@ -13,6 +13,7 @@ class Sleep implements DatabaseRecord {
this._wokeUpAt); this._wokeUpAt);
DateTime get date => _date; DateTime get date => _date;
String get comment => _comment;
int get sleepQualitiyValue => _sleepQualityValue; int get sleepQualitiyValue => _sleepQualityValue;
TimeOfDay get sleepDuration => _sleptAt.durationBetween(_wokeUpAt); TimeOfDay get sleepDuration => _sleptAt.durationBetween(_wokeUpAt);

View File

@ -1,10 +1,10 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class RoundButton extends StatelessWidget { class RoundIconButton extends StatelessWidget {
final VoidCallback onPressed; final VoidCallback onPressed;
final IconData iconData; final IconData iconData;
const RoundButton( const RoundIconButton(
{super.key, required this.onPressed, required this.iconData}); {super.key, required this.onPressed, required this.iconData});
@override @override

View File

@ -2,6 +2,7 @@ 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 'package:smoke_cess_app/providers/page_provider.dart'; import 'package:smoke_cess_app/providers/page_provider.dart';
import 'package:smoke_cess_app/widgets/buttons/round_button_widget.dart';
class SubmitFormButton extends StatelessWidget { class SubmitFormButton extends StatelessWidget {
final Future<int> Function() submitCallback; final Future<int> Function() submitCallback;
@ -14,7 +15,7 @@ class SubmitFormButton extends StatelessWidget {
PageProvider pageProvider = context.watch<PageProvider>(); PageProvider pageProvider = context.watch<PageProvider>();
return Padding( return Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0), padding: const EdgeInsets.symmetric(vertical: 16.0),
child: ElevatedButton( child: RoundIconButton(
onPressed: () async { onPressed: () async {
int success = await submitCallback(); int success = await submitCallback();
if (context.mounted) { if (context.mounted) {
@ -37,7 +38,7 @@ class SubmitFormButton extends StatelessWidget {
} }
} }
}, },
child: const Text('Speichern'), iconData: Icons.check_outlined,
), ),
); );
} }

View File

@ -0,0 +1,33 @@
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
class EntryDetailTitle extends StatelessWidget {
final DateTime date;
final String entryData;
const EntryDetailTitle(
{super.key, required this.date, required this.entryData});
@override
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
DateFormat.MMMd('de').format(date),
style:
const TextStyle(color: Colors.white, fontWeight: FontWeight.bold),
),
Flexible(
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 5.0),
child: Text(
entryData,
overflow: TextOverflow.ellipsis,
style: const TextStyle(
color: Colors.white, fontWeight: FontWeight.bold),
)))
],
);
}
}

View File

@ -1,41 +1,58 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:intl/intl.dart'; import 'package:smoke_cess_app/widgets/entry_detail_title.dart';
class EntryDetail extends StatelessWidget { class EntryDetail extends StatelessWidget {
final DateTime date; final DateTime date;
final String entryData; final String entryData;
final IconData icon; final String? entryComment;
final IconData iconData;
const EntryDetail( const EntryDetail(
{super.key, {super.key,
required this.date, required this.date,
required this.entryData, required this.entryData,
required this.icon}); required this.iconData,
required this.entryComment});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Card( final Icon icon = Icon(iconData, color: Colors.white);
child: ListTile( final ShapeBorder shape = RoundedRectangleBorder(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0), borderRadius: BorderRadius.circular(10.0),
), );
leading: Icon(icon, color: Colors.white), final Color color = Theme.of(context).colorScheme.primary.withOpacity(0.8);
title: Row( final Widget title = EntryDetailTitle(date: date, entryData: entryData);
mainAxisAlignment: MainAxisAlignment.spaceEvenly, return entryComment != null
children: [ ? ExpansionTile(
Text( iconColor: Colors.white,
DateFormat.MMMd('de').format(date), collapsedIconColor: Colors.white,
collapsedShape: shape,
shape: shape,
leading: icon,
title: title,
collapsedBackgroundColor: color,
backgroundColor:
Theme.of(context).colorScheme.secondary.withOpacity(0.8),
children: entryComment != null
? [
Row(mainAxisAlignment: MainAxisAlignment.start, children: [
Padding(
padding: const EdgeInsets.fromLTRB(10, 0, 10, 10),
child: Text(
entryComment ?? '',
style: const TextStyle( style: const TextStyle(
color: Colors.white, fontWeight: FontWeight.bold), color: Colors.white,
), fontWeight: FontWeight.bold),
Text( ))
entryData, ])
style: const TextStyle( ]
color: Colors.white, fontWeight: FontWeight.bold), : [],
) )
], : ListTile(
), shape: shape,
tileColor: Theme.of(context).colorScheme.primary.withOpacity(0.8), leading: icon,
)); title: title,
tileColor: color,
);
} }
} }

View File

@ -6,6 +6,7 @@ class HistoryList<T> extends StatelessWidget {
final DateTime Function(T) dateSelector; final DateTime Function(T) dateSelector;
final String Function(T) entryDataSelector; final String Function(T) entryDataSelector;
final IconData Function(T)? iconDataSelector; final IconData Function(T)? iconDataSelector;
final String Function(T)? entryCommentSelector;
final IconData? icon; final IconData? icon;
const HistoryList( const HistoryList(
@ -14,7 +15,8 @@ class HistoryList<T> extends StatelessWidget {
required this.dateSelector, required this.dateSelector,
required this.entryDataSelector, required this.entryDataSelector,
this.iconDataSelector, this.iconDataSelector,
this.icon}); this.icon,
this.entryCommentSelector});
IconData _getIcon(T entry) { IconData _getIcon(T entry) {
if (icon != null) { if (icon != null) {
@ -25,15 +27,26 @@ class HistoryList<T> extends StatelessWidget {
return Icons.circle; return Icons.circle;
} }
String? _getComment(T entry) {
if (entryCommentSelector != null) {
return entryCommentSelector!(entry);
}
return null;
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Expanded( return Expanded(
child: ListView( child: ListView(
padding: const EdgeInsets.fromLTRB(10, 10, 10, 10),
children: history.map((T entry) { children: history.map((T entry) {
return EntryDetail( return Padding(
padding: const EdgeInsets.only(bottom: 5),
child: EntryDetail(
date: dateSelector(entry), date: dateSelector(entry),
entryData: entryDataSelector(entry), entryData: entryDataSelector(entry),
icon: _getIcon(entry)); entryComment: _getComment(entry),
iconData: _getIcon(entry)));
}).toList())); }).toList()));
} }
} }

View File

@ -16,6 +16,7 @@ class MoodForm extends StatelessWidget {
var inputModel = context.watch<InputProvider>(); var inputModel = context.watch<InputProvider>();
var tasksModel = context.watch<TasksProvider>(); var tasksModel = context.watch<TasksProvider>();
return ListView( return ListView(
padding: const EdgeInsets.fromLTRB(10, 10, 10, 10),
children: [ children: [
const ElevatedCard( const ElevatedCard(
title: 'Stimmungsbewertung', title: 'Stimmungsbewertung',
@ -26,9 +27,6 @@ class MoodForm extends StatelessWidget {
title: 'Beschreibe deine Stimmung', title: 'Beschreibe deine Stimmung',
child: MyTextFormField('Beschreibe deine Stimmung'), child: MyTextFormField('Beschreibe deine Stimmung'),
), ),
const SizedBox(
height: 80,
),
SubmitFormButton( SubmitFormButton(
submitCallback: inputModel.saveMood, submitCallback: inputModel.saveMood,
updateTasks: () => tasksModel.setTaskDone(Pages.mood), updateTasks: () => tasksModel.setTaskDone(Pages.mood),

View File

@ -25,6 +25,7 @@ class MoodView extends StatelessWidget {
history: tasksModel.moodHistory, history: tasksModel.moodHistory,
dateSelector: (Mood mood) => mood.date, dateSelector: (Mood mood) => mood.date,
entryDataSelector: (Mood mood) => 'Stimmung: ${mood.moodValue}', entryDataSelector: (Mood mood) => 'Stimmung: ${mood.moodValue}',
entryCommentSelector: (Mood mood) => 'Kommentar: ${mood.comment}',
iconDataSelector: (Mood mood) => mood.moodValue >= 50 iconDataSelector: (Mood mood) => mood.moodValue >= 50
? Icons.mood_outlined ? Icons.mood_outlined
: Icons.mood_bad_outlined, : Icons.mood_bad_outlined,

View File

@ -18,6 +18,7 @@ class RelapseForm extends StatelessWidget {
var settingsModel = context.watch<SettingsProvider>(); var settingsModel = context.watch<SettingsProvider>();
var tasksModel = context.watch<TasksProvider>(); var tasksModel = context.watch<TasksProvider>();
return ListView( return ListView(
padding: const EdgeInsets.fromLTRB(10, 10, 10, 10),
children: [ children: [
ElevatedCard( ElevatedCard(
title: 'Rückfallkategorie', title: 'Rückfallkategorie',
@ -27,9 +28,6 @@ class RelapseForm extends StatelessWidget {
title: 'Beschreibe deinen Rückfall', title: 'Beschreibe deinen Rückfall',
child: MyTextFormField('Beschreibe deinen Rückfall'), child: MyTextFormField('Beschreibe deinen Rückfall'),
), ),
const SizedBox(
height: 80,
),
SubmitFormButton( SubmitFormButton(
submitCallback: inputModel.saveRelapse, submitCallback: inputModel.saveRelapse,
updateTasks: () => tasksModel.setTaskDone(Pages.mood), updateTasks: () => tasksModel.setTaskDone(Pages.mood),

View File

@ -10,11 +10,15 @@ class RelapseView extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
TasksProvider tasksModel = context.watch<TasksProvider>(); TasksProvider tasksModel = context.watch<TasksProvider>();
return HistoryList<Relapse>( return Column(children: [
HistoryList<Relapse>(
history: tasksModel.relapseHistory, history: tasksModel.relapseHistory,
dateSelector: (Relapse relapse) => relapse.date, dateSelector: (Relapse relapse) => relapse.date,
entryDataSelector: (Relapse relapse) => 'Grund: ${relapse.category}', entryDataSelector: (Relapse relapse) => relapse.category,
entryCommentSelector: (Relapse relapse) =>
'Kommentar: ${relapse.comment}',
icon: Icons.smoke_free_outlined, icon: Icons.smoke_free_outlined,
); )
]);
} }
} }

View File

@ -19,6 +19,7 @@ class SleepForm extends StatelessWidget {
TasksProvider tasksModel = context.watch<TasksProvider>(); TasksProvider tasksModel = context.watch<TasksProvider>();
return ListView( return ListView(
padding: const EdgeInsets.fromLTRB(10, 10, 10, 10),
children: [ children: [
const ElevatedCard( const ElevatedCard(
title: 'Einschlafzeit', title: 'Einschlafzeit',
@ -39,9 +40,6 @@ class SleepForm extends StatelessWidget {
title: 'Schlafbeschreibung', title: 'Schlafbeschreibung',
child: MyTextFormField('Beschreibe deinen Schlaf'), child: MyTextFormField('Beschreibe deinen Schlaf'),
), ),
const SizedBox(
height: 80,
),
SubmitFormButton( SubmitFormButton(
submitCallback: () => submitCallback: () =>
inputModel.saveSleep(SleepTimes.wokeUpAt, SleepTimes.sleptAt), inputModel.saveSleep(SleepTimes.wokeUpAt, SleepTimes.sleptAt),

View File

@ -28,6 +28,7 @@ class SleepView extends StatelessWidget {
dateSelector: (Sleep sleep) => sleep.date, dateSelector: (Sleep sleep) => sleep.date,
entryDataSelector: (Sleep sleep) => entryDataSelector: (Sleep sleep) =>
'${sleep.sleepDuration.hour}:${sleep.sleepDuration.minute}', '${sleep.sleepDuration.hour}:${sleep.sleepDuration.minute}',
entryCommentSelector: (Sleep sleep) => 'Kommentar: ${sleep.comment}',
icon: Icons.bedtime_outlined, icon: Icons.bedtime_outlined,
) )
], ],

View File

@ -32,7 +32,7 @@ class ViewFormPage extends StatelessWidget {
if (!pageProvider.showForm) if (!pageProvider.showForm)
Container( Container(
margin: EdgeInsets.symmetric(vertical: height * 0.02), margin: EdgeInsets.symmetric(vertical: height * 0.02),
child: RoundButton( child: RoundIconButton(
iconData: Icons.add_outlined, iconData: Icons.add_outlined,
onPressed: tasksProvider.tasks[page] ?? true onPressed: tasksProvider.tasks[page] ?? true
? () => pageProvider.swap() ? () => pageProvider.swap()