calorimeter/lib/food_entry/enter_food_widget.dart

186 lines
6.5 KiB
Dart
Raw Normal View History

2024-12-07 12:29:34 +00:00
/* SPDX-License-Identifier: GPL-3.0-or-later */
2024-12-07 12:39:11 +00:00
/* Copyright (C) 2024 Marco Groß <mgross@sw-gross.de> */
import 'package:flutter/material.dart';
2024-09-06 17:00:25 +00:00
import 'package:calorimeter/food_entry/food_entry_bloc.dart';
2024-09-06 16:51:24 +00:00
import 'package:calorimeter/utils/row_with_spacers_widget.dart';
2024-12-10 21:37:13 +00:00
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
class EnterFoodWidget extends StatefulWidget {
final Function(BuildContext context, FoodEntryState entry) onAdd;
final Map<String, int> foodEntryLookupDatabase;
2024-06-09 17:06:10 +00:00
const EnterFoodWidget(
{super.key, required this.onAdd, required this.foodEntryLookupDatabase});
@override
State<EnterFoodWidget> createState() => _EnterFoodWidgetState();
}
class _EnterFoodWidgetState extends State<EnterFoodWidget> {
late TextEditingController nameController;
late TextEditingController massController;
late TextEditingController kcalPerMassController;
late bool open;
@override
void initState() {
nameController = TextEditingController();
massController = TextEditingController();
kcalPerMassController = TextEditingController();
open = false;
super.initState();
}
2024-06-01 10:41:58 +00:00
@override
Widget build(BuildContext context) {
return Column(
children: [
Stack(
children: [
if (!open)
RowWidget(
showDividers: false,
null,
null,
null,
ElevatedButton(
style: ElevatedButton.styleFrom(
padding: EdgeInsets.zero,
),
onPressed: () => setState(() => open = true),
child: Icon(Icons.add)),
),
Offstage(
offstage: !open,
child: AnimatedOpacity(
duration: Duration(milliseconds: 250),
opacity: open ? 1.0 : 0.0,
child: RowWidget(
showDividers: true,
Autocomplete<String>(
optionsViewOpenDirection: OptionsViewOpenDirection.down,
fieldViewBuilder:
(context, controller, focusNode, onSubmitted) {
nameController = controller;
return TextFormField(
scrollPadding: EdgeInsets.only(bottom: 100),
controller: controller,
focusNode: focusNode,
decoration: InputDecoration(
label: Text(AppLocalizations.of(context)!.name),
),
);
},
optionsBuilder: (TextEditingValue textEditingValue) {
if (textEditingValue.text == '') {
return const Iterable<String>.empty();
}
return widget.foodEntryLookupDatabase.keys.where(
(name) {
return name
.toLowerCase()
.contains(textEditingValue.text.toLowerCase());
},
);
},
onSelected: (selectedFood) {
int kcalPerMassForSelectedFood =
widget.foodEntryLookupDatabase[selectedFood]!;
setState(() {
nameController.text = selectedFood;
kcalPerMassController.text =
kcalPerMassForSelectedFood.toString();
});
}),
TextField(
scrollPadding: EdgeInsets.only(bottom: 100),
textAlign: TextAlign.end,
decoration: InputDecoration(
label: Directionality(
textDirection: TextDirection.rtl,
child: Text(AppLocalizations.of(context)!.amount),
),
),
keyboardType: TextInputType.number,
controller: massController,
onSubmitted: (value) => onSubmitAction(),
),
TextField(
scrollPadding: EdgeInsets.only(bottom: 100),
textAlign: TextAlign.end,
decoration: InputDecoration(
label: Directionality(
textDirection: TextDirection.rtl,
child: Text(AppLocalizations.of(context)!.kcal))),
keyboardType: TextInputType.number,
controller: kcalPerMassController,
onSubmitted: (value) => onSubmitAction(),
),
ElevatedButton(
style: ElevatedButton.styleFrom(
padding: EdgeInsets.zero,
),
onPressed: () => onSubmitAction(),
child: const Icon(Icons.check)),
),
),
),
],
),
SizedBox(
height: 200,
child: GestureDetector(
onTap: () => setState(() {
open = false;
}))),
],
);
}
void onSubmitAction() {
int massAsNumber = 0;
int kcalPerMassAsNumber = 0;
try {
massAsNumber = int.parse(massController.text.replaceAll(",", "."));
} catch (e) {
2024-12-10 21:37:13 +00:00
var snackbar = SnackBar(
content: Text(AppLocalizations.of(context)!.errAmountNotANumber));
ScaffoldMessenger.of(context).clearSnackBars();
ScaffoldMessenger.of(context).showSnackBar(snackbar);
return;
}
try {
kcalPerMassAsNumber =
int.parse(kcalPerMassController.text.replaceAll(",", "."));
} catch (e) {
2024-12-10 21:37:13 +00:00
var snackbar = SnackBar(
content: Text(AppLocalizations.of(context)!.errKcalNotANumber));
ScaffoldMessenger.of(context).removeCurrentSnackBar();
ScaffoldMessenger.of(context).showSnackBar(snackbar);
return;
}
var entry = FoodEntryState(
name: nameController.text,
mass: massAsNumber,
2024-09-24 15:23:01 +00:00
kcalPer100: kcalPerMassAsNumber,
waitingForNetwork: false,
isSelected: false,
);
widget.onAdd(context, entry);
setState(() {
nameController.text = "";
massController.text = "";
kcalPerMassController.text = "";
open = false;
});
}
}