Remove the card-like design for food entries and make the 'delete' button dynamically appear

This commit is contained in:
Marco 2024-09-06 02:23:47 +02:00
parent 1db4e5e351
commit 6552756702
6 changed files with 150 additions and 91 deletions

View File

@ -34,7 +34,10 @@ class _EnterFoodWidgetState extends State<EnterFoodWidget> {
return TextFormField( return TextFormField(
controller: controller, controller: controller,
focusNode: focusNode, focusNode: focusNode,
decoration: const InputDecoration(label: Text("Name"))); decoration: const InputDecoration(
label: Text("Name"),
),
);
}, },
optionsBuilder: (TextEditingValue textEditingValue) { optionsBuilder: (TextEditingValue textEditingValue) {
if (textEditingValue.text == '') { if (textEditingValue.text == '') {
@ -57,30 +60,54 @@ class _EnterFoodWidgetState extends State<EnterFoodWidget> {
}); });
var massWidget = TextField( var massWidget = TextField(
decoration: const InputDecoration(label: Text("Menge")), textAlign: TextAlign.end,
decoration: const InputDecoration(
label: Align(alignment: Alignment.centerRight, child: Text("Menge")),
),
keyboardType: TextInputType.number, keyboardType: TextInputType.number,
controller: massController, controller: massController,
onSubmitted: (value) => onSubmitAction(),
); );
var kcalPerMassWidget = TextField( var kcalPerMassWidget = TextField(
decoration: const InputDecoration(label: Text("kcal pro")), textAlign: TextAlign.end,
decoration: const InputDecoration(
label:
Align(alignment: Alignment.centerRight, child: Text("kcal pro"))),
keyboardType: TextInputType.number, keyboardType: TextInputType.number,
controller: kcalPerMassController); controller: kcalPerMassController,
onSubmitted: (value) => onSubmitAction(),
);
var enterButton = ElevatedButton( var enterButton = ElevatedButton(
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
), ),
onPressed: () { onPressed: () => onSubmitAction(),
child: const Icon(Icons.add));
return Padding(
padding: const EdgeInsets.only(left: 8.0, right: 4.0),
child: RowWidget(
nameWidget,
massWidget,
kcalPerMassWidget,
Padding(
padding: const EdgeInsets.only(left: 16.0),
child: enterButton,
),
),
);
}
void onSubmitAction() {
double massAsNumber = 0.0; double massAsNumber = 0.0;
double kcalPerMassAsNumber = 0.0; double kcalPerMassAsNumber = 0.0;
try { try {
massAsNumber = massAsNumber = double.parse(massController.text.replaceAll(",", "."));
double.parse(massController.text.replaceAll(",", "."));
} catch (e) { } catch (e) {
var snackbar = var snackbar = const SnackBar(content: Text("Menge muss eine Zahl sein"));
const SnackBar(content: Text("Menge muss eine Zahl sein"));
ScaffoldMessenger.of(context).clearSnackBars(); ScaffoldMessenger.of(context).clearSnackBars();
ScaffoldMessenger.of(context).showSnackBar(snackbar); ScaffoldMessenger.of(context).showSnackBar(snackbar);
return; return;
@ -90,18 +117,16 @@ class _EnterFoodWidgetState extends State<EnterFoodWidget> {
kcalPerMassAsNumber = kcalPerMassAsNumber =
double.parse(kcalPerMassController.text.replaceAll(",", ".")); double.parse(kcalPerMassController.text.replaceAll(",", "."));
} catch (e) { } catch (e) {
var snackbar = const SnackBar( var snackbar =
content: Text("'kcal pro 100g' muss eine Zahl sein")); const SnackBar(content: Text("'kcal pro 100g' muss eine Zahl sein"));
ScaffoldMessenger.of(context).clearSnackBars(); ScaffoldMessenger.of(context).clearSnackBars();
ScaffoldMessenger.of(context).showSnackBar(snackbar); ScaffoldMessenger.of(context).showSnackBar(snackbar);
return; return;
} }
try { try {
massAsNumber = massAsNumber = double.parse(massController.text.replaceAll(",", "."));
double.parse(massController.text.replaceAll(",", "."));
} catch (e) { } catch (e) {
var snackbar = var snackbar = const SnackBar(content: Text("Menge muss eine Zahl sein"));
const SnackBar(content: Text("Menge muss eine Zahl sein"));
ScaffoldMessenger.of(context).clearSnackBars(); ScaffoldMessenger.of(context).clearSnackBars();
ScaffoldMessenger.of(context).showSnackBar(snackbar); ScaffoldMessenger.of(context).showSnackBar(snackbar);
return; return;
@ -113,18 +138,5 @@ class _EnterFoodWidgetState extends State<EnterFoodWidget> {
kcalPerMass: kcalPerMassAsNumber); kcalPerMass: kcalPerMassAsNumber);
widget.onAdd(context, entry); widget.onAdd(context, entry);
},
child: const Icon(Icons.add));
return Padding(
padding: const EdgeInsets.only(left: 8.0, right: 4.0),
child: RowWidget(
nameWidget,
massWidget,
kcalPerMassWidget,
null,
enterButton,
),
);
} }
} }

View File

@ -2,38 +2,94 @@ import 'package:flutter/material.dart';
import 'package:calodiary/food_entry_bloc.dart'; import 'package:calodiary/food_entry_bloc.dart';
import 'package:calodiary/row_with_spacers_widget.dart'; import 'package:calodiary/row_with_spacers_widget.dart';
class FoodEntryWidget extends StatelessWidget { class FoodEntryWidget extends StatefulWidget {
final FoodEntry entry; final FoodEntry entry;
final Function(BuildContext context, String id) onDelete; final Function(BuildContext context, String id) onDelete;
const FoodEntryWidget( const FoodEntryWidget(
{super.key, required this.entry, required this.onDelete}); {super.key, required this.entry, required this.onDelete});
@override
State<FoodEntryWidget> createState() => _FoodEntryWidgetState();
}
class _FoodEntryWidgetState extends State<FoodEntryWidget> {
late bool showCancelAndDelete;
@override
void initState() {
showCancelAndDelete = false;
super.initState();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Dismissible( return GestureDetector(
key: ValueKey(entry.id), onTap: () {
onDismissed: (direction) { setState(() {
onDelete(context, entry.id); showCancelAndDelete = !showCancelAndDelete;
});
}, },
child: Card( child: Stack(
elevation: 5.0, children: [
Positioned.fill(
child: Stack(children: [
Positioned.fill(
child: Padding( child: Padding(
padding: const EdgeInsets.only(left: 4.0), padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: RowWidget( child: RowWidget(
Text(entry.name), Text(widget.entry.name),
Text(entry.mass.ceil().toString()), Text(widget.entry.mass.ceil().toString(),
Text(entry.kcalPerMass.ceil().toString()), textAlign: TextAlign.end),
Text((entry.mass * entry.kcalPerMass / 100).ceil().toString()), Text(widget.entry.kcalPerMass.ceil().toString(),
IconButton( textAlign: TextAlign.end),
style: IconButton.styleFrom(padding: EdgeInsets.zero), Opacity(
onPressed: () { opacity: showCancelAndDelete ? 0.0 : 1.0,
onDelete(context, entry.id); child: Text(
}, (widget.entry.mass * widget.entry.kcalPerMass / 100)
icon: const Icon(Icons.delete_forever_rounded)), .ceil()
.toString(),
textAlign: TextAlign.end),
), ),
), ),
), ),
),
Opacity(
opacity: showCancelAndDelete ? 0.66 : 0.0,
child: Container(
color: Theme.of(context).colorScheme.secondary)),
]),
),
Opacity(
opacity: showCancelAndDelete ? 1.0 : 0.0,
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
SizedBox(
child: IconButton(
padding: EdgeInsets.all(0.0),
icon: const Icon(Icons.cancel),
onPressed: showCancelAndDelete
? () => setState(() {
showCancelAndDelete = false;
})
: null,
),
),
SizedBox(
child: IconButton(
padding: EdgeInsets.all(0.0),
iconSize: 24,
icon: const Icon(Icons.delete),
color: Colors.redAccent,
onPressed: showCancelAndDelete
? () => widget.onDelete(context, widget.entry.id)
: null),
),
],
),
),
],
),
); );
} }
} }

View File

@ -68,6 +68,7 @@ class MainApp extends StatelessWidget {
Locale('de'), Locale('de'),
], ],
theme: ThemeData( theme: ThemeData(
dividerTheme: const DividerThemeData(space: 2),
colorScheme: ColorScheme.fromSeed( colorScheme: ColorScheme.fromSeed(
seedColor: Colors.lightBlue, seedColor: Colors.lightBlue,
brightness: newBrightness, brightness: newBrightness,

View File

@ -94,6 +94,7 @@ class _PerDateWidgetState extends State<PerDateWidget> {
return Column( return Column(
children: [ children: [
FoodEntryWidget( FoodEntryWidget(
key: ValueKey(state.foodEntries[entryIndex].id),
entry: state.foodEntries[entryIndex], entry: state.foodEntries[entryIndex],
onDelete: (callbackContext, id) { onDelete: (callbackContext, id) {
callbackContext callbackContext
@ -103,7 +104,6 @@ class _PerDateWidgetState extends State<PerDateWidget> {
)); ));
}, },
), ),
if (listIndex != state.foodEntries.length - 1)
const Divider(), const Divider(),
], ],
); );

View File

@ -1,31 +1,22 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class RowWidget extends StatefulWidget { class RowWidget extends StatelessWidget {
final Widget? widget1; final Widget? widget1;
final Widget? widget2; final Widget? widget2;
final Widget? widget3; final Widget? widget3;
final Widget? widget4; final Widget? widget4;
final Widget? widget5;
const RowWidget( const RowWidget(this.widget1, this.widget2, this.widget3, this.widget4,
this.widget1, this.widget2, this.widget3, this.widget4, this.widget5,
{super.key}); {super.key});
@override
State<RowWidget> createState() => _RowWidgetState();
}
class _RowWidgetState extends State<RowWidget> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Row( return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Expanded(flex: 10, child: widget.widget1 ?? Container()), Expanded(flex: 10, child: widget1 ?? Container()),
Expanded(flex: 6, child: widget.widget2 ?? Container()), Expanded(flex: 6, child: widget2 ?? Container()),
Expanded(flex: 6, child: widget.widget3 ?? Container()), Expanded(flex: 6, child: widget3 ?? Container()),
Expanded(flex: 8, child: widget.widget4 ?? Container()), Expanded(flex: 6, child: widget4 ?? Container()),
Expanded(flex: 3, child: widget.widget5 ?? Container()),
], ],
); );
} }

View File

@ -33,7 +33,6 @@ class _SumWidgetState extends State<SumWidget> {
null, null,
null, null,
null, null,
null,
); );
}, },
); );