/* SPDX-License-Identifier: GPL-3.0-or-later */ /* Copyright (C) 2024 Marco Groß */ import 'package:flutter/material.dart'; import 'package:calorimeter/food_entry/food_entry_bloc.dart'; import 'package:calorimeter/utils/row_with_spacers_widget.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; class FoodEntryWidget extends StatefulWidget { final FoodEntryState entry; final Function(BuildContext context, String id) onDelete; final Function(BuildContext context, FoodEntryState entry) onChange; final Function(BuildContext context, FoodEntryState entry) onTap; const FoodEntryWidget({ super.key, required this.entry, required this.onDelete, required this.onChange, required this.onTap, }); @override State createState() => _FoodEntryWidgetState(); } class _FoodEntryWidgetState extends State { @override void initState() { super.initState(); } @override Widget build(BuildContext context) { return GestureDetector( onTap: () => widget.onTap(context, widget.entry), child: Stack( children: [ Positioned.fill( child: Stack(children: [ Positioned.fill( child: Padding( padding: const EdgeInsets.symmetric(horizontal: 8.0), child: RowWidget( widget.entry.waitingForNetwork ? const Center(child: CircularProgressIndicator()) : Text(widget.entry.name), widget.entry.waitingForNetwork ? Container() : Text(widget.entry.mass.ceil().toString(), textAlign: TextAlign.end), Opacity( opacity: widget.entry.isSelected ? 0.0 : 1.0, child: widget.entry.waitingForNetwork ? Container() : Text(widget.entry.kcalPer100.ceil().toString(), textAlign: TextAlign.end), ), Opacity( opacity: widget.entry.isSelected ? 0.0 : 1.0, child: widget.entry.waitingForNetwork ? Container() : Text( (widget.entry.mass * widget.entry.kcalPer100 / 100) .ceil() .toString(), textAlign: TextAlign.end), ), ), ), ), Opacity( opacity: widget.entry.isSelected ? 0.66 : 0.0, child: Container( color: Theme.of(context).colorScheme.secondary)), ]), ), Opacity( opacity: widget.entry.isSelected ? 1.0 : 0.0, child: Row( mainAxisAlignment: MainAxisAlignment.end, children: [ SizedBox( child: IconButton( padding: const EdgeInsets.all(0.0), icon: const Icon(Icons.edit), onPressed: widget.entry.isSelected ? () async { widget.onTap(context, widget.entry); await showDialog( context: context, builder: (dialogContext) { return FoodEntryChangeDialog( entry: widget.entry, onChange: (context, entry) { widget.onChange(context, entry); }); }, ); } : null), ), SizedBox( child: IconButton( padding: const EdgeInsets.all(0.0), iconSize: 24, icon: const Icon(Icons.delete), color: Colors.redAccent, onPressed: widget.entry.isSelected ? () => widget.onDelete(context, widget.entry.id) : null), ), ], ), ), ], ), ); } } class FoodEntryChangeDialog extends StatefulWidget { final FoodEntryState entry; final Function(BuildContext context, FoodEntryState entry) onChange; const FoodEntryChangeDialog( {required this.entry, super.key, required this.onChange}); @override State createState() => _FoodEntryChangeDialogState(); } class _FoodEntryChangeDialogState extends State { late TextEditingController nameController; late TextEditingController massController; late TextEditingController kcalPer100Controller; static const textFieldVerticalPadding = 16.0; static const textFieldHorizontalPadding = 16.0; @override void initState() { nameController = TextEditingController(); nameController.text = widget.entry.name; massController = TextEditingController(); massController.text = widget.entry.mass.toString(); kcalPer100Controller = TextEditingController(); kcalPer100Controller.text = widget.entry.kcalPer100.toString(); super.initState(); } @override Widget build(BuildContext context) { return AlertDialog( content: Column( mainAxisSize: MainAxisSize.min, children: [ Padding( padding: const EdgeInsets.symmetric( vertical: textFieldVerticalPadding, horizontal: textFieldHorizontalPadding), child: TextField( onSubmitted: (val) => _onSubmitAction(), controller: nameController, decoration: InputDecoration( label: Text(AppLocalizations.of(context)!.name), ), ), ), Padding( padding: const EdgeInsets.symmetric( vertical: textFieldVerticalPadding, horizontal: textFieldHorizontalPadding), child: TextField( onSubmitted: (val) => _onSubmitAction(), controller: massController, decoration: InputDecoration( label: Text(AppLocalizations.of(context)!.amountPer), ), ), ), Padding( padding: const EdgeInsets.symmetric( vertical: textFieldVerticalPadding, horizontal: textFieldHorizontalPadding), child: TextField( onSubmitted: (val) => _onSubmitAction(), controller: kcalPer100Controller, decoration: InputDecoration( label: Text(AppLocalizations.of(context)!.kcalper), ), ), ) ], ), actions: [ IconButton( onPressed: () { Navigator.of(context).pop(); }, icon: const Icon(Icons.cancel)), IconButton( onPressed: () => _onSubmitAction(), icon: const Icon(Icons.check), ) ], ); } void _onSubmitAction() { int mass; int kcalPer100; try { mass = int.parse(massController.text); } catch (e) { mass = 0; } try { kcalPer100 = int.parse(kcalPer100Controller.text); } catch (e) { kcalPer100 = 0; } var newEntry = FoodEntryState.withID( id: widget.entry.id, name: nameController.text, mass: mass, kcalPer100: kcalPer100, waitingForNetwork: widget.entry.waitingForNetwork, isSelected: false, ); widget.onChange(context, newEntry); Navigator.of(context).pop(); } }