added editing entries and deleting them
This commit is contained in:
		
							parent
							
								
									fa9a0569fb
								
							
						
					
					
						commit
						955c506b92
					
				
					 9 changed files with 369 additions and 101 deletions
				
			
		| 
						 | 
					@ -76,7 +76,7 @@ class ApiClient {
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Future<Map<String, dynamic>> delete(String path) async {
 | 
					  Future<void> delete(String path) async {
 | 
				
			||||||
    final response = await httpClient.delete(
 | 
					    final response = await httpClient.delete(
 | 
				
			||||||
      Uri.parse('$baseUrl$path'),
 | 
					      Uri.parse('$baseUrl$path'),
 | 
				
			||||||
      headers: headers(),
 | 
					      headers: headers(),
 | 
				
			||||||
| 
						 | 
					@ -85,8 +85,6 @@ class ApiClient {
 | 
				
			||||||
    if (response.statusCode != 200) {
 | 
					    if (response.statusCode != 200) {
 | 
				
			||||||
      throw Exception('Response returned status code: ${response.statusCode}');
 | 
					      throw Exception('Response returned status code: ${response.statusCode}');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    return _jsonDecode(response);
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Future<Map<String, dynamic>> patch(String path, Map<String, dynamic> body) async {
 | 
					  Future<Map<String, dynamic>> patch(String path, Map<String, dynamic> body) async {
 | 
				
			||||||
| 
						 | 
					@ -182,4 +180,22 @@ class ApiClient {
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    await post("/entry", entry);
 | 
					    await post("/entry", entry);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Future<void> deleteEntry(int id) async {
 | 
				
			||||||
 | 
					    await delete("/entry/$id");
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Future<void> updateEntry(int id, {
 | 
				
			||||||
 | 
					    required double grams,
 | 
				
			||||||
 | 
					    required int productId,
 | 
				
			||||||
 | 
					    required int mealId,
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  ) async {
 | 
				
			||||||
 | 
					    var entry = {
 | 
				
			||||||
 | 
					      "grams": grams,
 | 
				
			||||||
 | 
					      "product_id": productId,
 | 
				
			||||||
 | 
					      "meal_id": mealId,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    await patch("/entry/$id", entry);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -65,7 +65,6 @@ class _AddEntryScreen extends State<AddEntryScreen> {
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
      double.parse(gramsController.text);
 | 
					      double.parse(gramsController.text);
 | 
				
			||||||
    } catch (e) {
 | 
					    } catch (e) {
 | 
				
			||||||
      print(e);
 | 
					 | 
				
			||||||
      showError("Grams must be a number");
 | 
					      showError("Grams must be a number");
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -106,10 +105,10 @@ class _AddEntryScreen extends State<AddEntryScreen> {
 | 
				
			||||||
              ),
 | 
					              ),
 | 
				
			||||||
              for (var product in products)
 | 
					              for (var product in products)
 | 
				
			||||||
                ListTile(
 | 
					                ListTile(
 | 
				
			||||||
                  onTap: () {
 | 
					                onTap: () {
 | 
				
			||||||
                    setState(() {
 | 
					                  setState(() {
 | 
				
			||||||
                    products = [product];
 | 
					                    products = [product];
 | 
				
			||||||
                  });
 | 
					                    });
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
                title: ProductWidget(
 | 
					                title: ProductWidget(
 | 
				
			||||||
                  product: product,
 | 
					                  product: product,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										146
									
								
								lib/screens/edit_entry.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								lib/screens/edit_entry.dart
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,146 @@
 | 
				
			||||||
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
 | 
					import 'package:fooder_web/screens/based.dart';
 | 
				
			||||||
 | 
					import 'package:fooder_web/models/product.dart';
 | 
				
			||||||
 | 
					import 'package:fooder_web/models/entry.dart';
 | 
				
			||||||
 | 
					import 'package:fooder_web/widgets/product.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class EditEntryScreen extends BasedScreen {
 | 
				
			||||||
 | 
					  final Entry entry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const EditEntryScreen({super.key, required super.apiClient, required this.entry});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  State<EditEntryScreen> createState() => _EditEntryScreen();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class _EditEntryScreen extends State<EditEntryScreen> {
 | 
				
			||||||
 | 
					  final gramsController = TextEditingController();
 | 
				
			||||||
 | 
					  final productNameController = TextEditingController();
 | 
				
			||||||
 | 
					  List<Product> products = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  void dispose() {
 | 
				
			||||||
 | 
					    gramsController.dispose();
 | 
				
			||||||
 | 
					    productNameController.dispose();
 | 
				
			||||||
 | 
					    super.dispose();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void popMeDady() {
 | 
				
			||||||
 | 
					    Navigator.pop(context);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  void initState () {
 | 
				
			||||||
 | 
					    super.initState();
 | 
				
			||||||
 | 
					    setState(() {
 | 
				
			||||||
 | 
					      gramsController.text = widget.entry.grams.toString();
 | 
				
			||||||
 | 
					      productNameController.text = widget.entry.product.name;
 | 
				
			||||||
 | 
					      products = [widget.entry.product];
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Future<void> _getProducts() async {
 | 
				
			||||||
 | 
					    var productsMap = await widget.apiClient.getProducts(productNameController.text);
 | 
				
			||||||
 | 
					    setState(() {
 | 
				
			||||||
 | 
					      products = (productsMap['products'] as List<dynamic>).map((e) => Product.fromJson(e as Map<String, dynamic>)).toList();
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void showError(String message)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    ScaffoldMessenger.of(context).showSnackBar(
 | 
				
			||||||
 | 
					      SnackBar(
 | 
				
			||||||
 | 
					        content: Text(message, textAlign: TextAlign.center),
 | 
				
			||||||
 | 
					        backgroundColor: Theme.of(context).colorScheme.error,
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Future<void> _saveEntry() async {
 | 
				
			||||||
 | 
					    if (products.length != 1) {
 | 
				
			||||||
 | 
					      showError("Pick product first");
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      double.parse(gramsController.text);
 | 
				
			||||||
 | 
					    } catch (e) {
 | 
				
			||||||
 | 
					      showError("Grams must be a number");
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await widget.apiClient.updateEntry(
 | 
				
			||||||
 | 
					      widget.entry.id,
 | 
				
			||||||
 | 
					      grams: double.parse(gramsController.text),
 | 
				
			||||||
 | 
					      productId: products[0].id,
 | 
				
			||||||
 | 
					      mealId: widget.entry.mealId,
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    popMeDady();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Future<void> _deleteEntry() async {
 | 
				
			||||||
 | 
					    await widget.apiClient.deleteEntry(widget.entry.id);
 | 
				
			||||||
 | 
					    popMeDady();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  Widget build(BuildContext context) {
 | 
				
			||||||
 | 
					    return Scaffold(
 | 
				
			||||||
 | 
					      appBar: AppBar(
 | 
				
			||||||
 | 
					        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
 | 
				
			||||||
 | 
					        title: const Text("🅵🅾🅾🅳🅴🆁"),
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
 | 
					      body: Center(
 | 
				
			||||||
 | 
					        child: Container(
 | 
				
			||||||
 | 
					          constraints: const BoxConstraints(maxWidth: 720),
 | 
				
			||||||
 | 
					          padding: const EdgeInsets.all(10),
 | 
				
			||||||
 | 
					          child: ListView(
 | 
				
			||||||
 | 
					            children: <Widget>[
 | 
				
			||||||
 | 
					              TextFormField(
 | 
				
			||||||
 | 
					                decoration: const InputDecoration(
 | 
				
			||||||
 | 
					                  labelText: 'Grams',
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					                controller: gramsController,
 | 
				
			||||||
 | 
					              ),
 | 
				
			||||||
 | 
					              TextFormField(
 | 
				
			||||||
 | 
					                decoration: const InputDecoration(
 | 
				
			||||||
 | 
					                  labelText: 'Product name',
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					                controller: productNameController,
 | 
				
			||||||
 | 
					                onChanged: (_) => _getProducts(),
 | 
				
			||||||
 | 
					              ),
 | 
				
			||||||
 | 
					              for (var product in products)
 | 
				
			||||||
 | 
					                ListTile(
 | 
				
			||||||
 | 
					                onTap: () {
 | 
				
			||||||
 | 
					                  setState(() {
 | 
				
			||||||
 | 
					                    products = [product];
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                title: ProductWidget(
 | 
				
			||||||
 | 
					                  product: product,
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					              ),
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					          )
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
 | 
					      floatingActionButton: Row(
 | 
				
			||||||
 | 
					        mainAxisAlignment: MainAxisAlignment.end,
 | 
				
			||||||
 | 
					        children: <Widget>[
 | 
				
			||||||
 | 
					          FloatingActionButton(
 | 
				
			||||||
 | 
					            onPressed: _deleteEntry,
 | 
				
			||||||
 | 
					            heroTag: null,
 | 
				
			||||||
 | 
					            child: const Icon(Icons.delete),
 | 
				
			||||||
 | 
					          ),
 | 
				
			||||||
 | 
					          FloatingActionButton(
 | 
				
			||||||
 | 
					            onPressed: _saveEntry,
 | 
				
			||||||
 | 
					            heroTag: null,
 | 
				
			||||||
 | 
					            child: const Icon(Icons.save),
 | 
				
			||||||
 | 
					          ),
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -69,7 +69,7 @@ class _MainScreen extends State<MainScreen> {
 | 
				
			||||||
      content = Container(
 | 
					      content = Container(
 | 
				
			||||||
        constraints: const BoxConstraints(maxWidth: 720),
 | 
					        constraints: const BoxConstraints(maxWidth: 720),
 | 
				
			||||||
        padding: const EdgeInsets.all(10),
 | 
					        padding: const EdgeInsets.all(10),
 | 
				
			||||||
        child: DiaryWidget(diary: diary!),
 | 
					        child: DiaryWidget(diary: diary!, apiClient: widget.apiClient, refreshParent: _asyncInitState),
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
      title = Row(
 | 
					      title = Row(
 | 
				
			||||||
        mainAxisAlignment: MainAxisAlignment.center,
 | 
					        mainAxisAlignment: MainAxisAlignment.center,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,55 +1,67 @@
 | 
				
			||||||
import 'package:flutter/material.dart';
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
import 'package:fooder_web/models/diary.dart';
 | 
					import 'package:fooder_web/models/diary.dart';
 | 
				
			||||||
import 'package:fooder_web/widgets/meal.dart';
 | 
					import 'package:fooder_web/widgets/meal.dart';
 | 
				
			||||||
 | 
					import 'package:fooder_web/widgets/macro.dart';
 | 
				
			||||||
 | 
					import 'package:fooder_web/client.dart';
 | 
				
			||||||
import 'dart:core';
 | 
					import 'dart:core';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class DiaryWidget extends StatelessWidget {
 | 
					class DiaryWidget extends StatelessWidget {
 | 
				
			||||||
  final Diary diary;
 | 
					  final Diary diary;
 | 
				
			||||||
 | 
					  final ApiClient apiClient;
 | 
				
			||||||
 | 
					  final Function() refreshParent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const DiaryWidget({super.key, required this.diary});
 | 
					  const DiaryWidget({super.key, required this.diary, required this.apiClient, required this.refreshParent});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  Widget build(BuildContext context) {
 | 
					  Widget build(BuildContext context) {
 | 
				
			||||||
    return Container(
 | 
					    return Container(
 | 
				
			||||||
      padding: const EdgeInsets.all(8),
 | 
					      padding: const EdgeInsets.all(8),
 | 
				
			||||||
      child: ListView(
 | 
					      child: CustomScrollView(
 | 
				
			||||||
        padding: const EdgeInsets.all(8),
 | 
					        slivers: <Widget>[
 | 
				
			||||||
        children: <Widget>[
 | 
					          SliverAppBar(
 | 
				
			||||||
          for (var meal in diary.meals)
 | 
					            title: Row(
 | 
				
			||||||
            MealWidget(
 | 
					              children: <Widget>[
 | 
				
			||||||
              meal: meal,
 | 
					                const Spacer(),
 | 
				
			||||||
              ),
 | 
					                Text(
 | 
				
			||||||
          Card(
 | 
					                  "${diary.calories.toStringAsFixed(1)} kcal",
 | 
				
			||||||
            child: Padding(
 | 
					                  style: Theme.of(context).textTheme.headlineLarge!.copyWith(
 | 
				
			||||||
              padding: const EdgeInsets.all(8.0),
 | 
					                    color: Theme.of(context).colorScheme.onSecondary,
 | 
				
			||||||
              child: Column(
 | 
					                    fontWeight: FontWeight.bold,
 | 
				
			||||||
                children: <Widget>[
 | 
					 | 
				
			||||||
                  Row(
 | 
					 | 
				
			||||||
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
 | 
					 | 
				
			||||||
                    children: <Widget>[
 | 
					 | 
				
			||||||
                      Text(
 | 
					 | 
				
			||||||
                        "carb: ${diary.carb.toStringAsFixed(2)}",
 | 
					 | 
				
			||||||
                        style: TextStyle(color: Theme.of(context).colorScheme.secondary),
 | 
					 | 
				
			||||||
                      ),
 | 
					 | 
				
			||||||
                      Text(
 | 
					 | 
				
			||||||
                        "fat: ${diary.fat.toStringAsFixed(2)}",
 | 
					 | 
				
			||||||
                        style: TextStyle(color: Theme.of(context).colorScheme.secondary),
 | 
					 | 
				
			||||||
                      ),
 | 
					 | 
				
			||||||
                      Text(
 | 
					 | 
				
			||||||
                        "protein: ${diary.protein.toStringAsFixed(2)}",
 | 
					 | 
				
			||||||
                        style: TextStyle(color: Theme.of(context).colorScheme.secondary),
 | 
					 | 
				
			||||||
                      ),
 | 
					 | 
				
			||||||
                      Text(
 | 
					 | 
				
			||||||
                        "calories: ${diary.calories.toStringAsFixed(2)}",
 | 
					 | 
				
			||||||
                        style: TextStyle(color: Theme.of(context).colorScheme.primary),
 | 
					 | 
				
			||||||
                      ),
 | 
					 | 
				
			||||||
                    ],
 | 
					 | 
				
			||||||
                  ),
 | 
					                  ),
 | 
				
			||||||
                ],
 | 
					                ),
 | 
				
			||||||
 | 
					              ]
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            expandedHeight: 128,
 | 
				
			||||||
 | 
					            backgroundColor: Theme.of(context).colorScheme.secondary,
 | 
				
			||||||
 | 
					            shape: RoundedRectangleBorder(
 | 
				
			||||||
 | 
					              borderRadius: BorderRadius.circular(8),
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            floating: true,
 | 
				
			||||||
 | 
					            flexibleSpace: FlexibleSpaceBar(
 | 
				
			||||||
 | 
					              title: MacroWidget(
 | 
				
			||||||
 | 
					                protein: diary.protein,
 | 
				
			||||||
 | 
					                carb: diary.carb,
 | 
				
			||||||
 | 
					                fat: diary.fat,
 | 
				
			||||||
 | 
					                style: Theme.of(context).textTheme.bodyMedium!.copyWith(
 | 
				
			||||||
 | 
					                  color: Theme.of(context).colorScheme.onSecondary,
 | 
				
			||||||
 | 
					                  fontWeight: FontWeight.bold,
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
              ),
 | 
					              ),
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
          )
 | 
					          ),
 | 
				
			||||||
 | 
					          SliverList(
 | 
				
			||||||
 | 
					            delegate: SliverChildListDelegate(
 | 
				
			||||||
 | 
					              [
 | 
				
			||||||
 | 
					                for (var meal in diary.meals)
 | 
				
			||||||
 | 
					                  MealWidget(
 | 
				
			||||||
 | 
					                    meal: meal,
 | 
				
			||||||
 | 
					                    apiClient: apiClient,
 | 
				
			||||||
 | 
					                    refreshParent: refreshParent,
 | 
				
			||||||
 | 
					                    ),
 | 
				
			||||||
 | 
					              ],
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					          ),
 | 
				
			||||||
        ],
 | 
					        ],
 | 
				
			||||||
      ),
 | 
					      ),
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,6 @@
 | 
				
			||||||
import 'package:flutter/material.dart';
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
import 'package:fooder_web/models/entry.dart';
 | 
					import 'package:fooder_web/models/entry.dart';
 | 
				
			||||||
 | 
					import 'package:fooder_web/widgets/macro.dart';
 | 
				
			||||||
import 'dart:core';
 | 
					import 'dart:core';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,29 +23,17 @@ class EntryWidget extends StatelessWidget {
 | 
				
			||||||
                  style: Theme.of(context).textTheme.titleLarge,
 | 
					                  style: Theme.of(context).textTheme.titleLarge,
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
              ),
 | 
					              ),
 | 
				
			||||||
              Text("${entry.calories.toStringAsFixed(2)} kcal"),
 | 
					              Text("${entry.calories.toStringAsFixed(1)} kcal"),
 | 
				
			||||||
            ],
 | 
					            ],
 | 
				
			||||||
          ),
 | 
					          ),
 | 
				
			||||||
          Row(
 | 
					          MacroWidget(
 | 
				
			||||||
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
 | 
					            protein: entry.protein,
 | 
				
			||||||
            children: <Widget>[
 | 
					            carb: entry.carb,
 | 
				
			||||||
              Text(
 | 
					            fat: entry.fat,
 | 
				
			||||||
                "carb: ${entry.carb.toStringAsFixed(2)}",
 | 
					            amount: entry.grams,
 | 
				
			||||||
                style: TextStyle(color: Theme.of(context).colorScheme.secondary),
 | 
					            style: Theme.of(context).textTheme.bodyMedium!.copyWith(
 | 
				
			||||||
              ),
 | 
					              color: Theme.of(context).colorScheme.secondary,
 | 
				
			||||||
              Text(
 | 
					            ),
 | 
				
			||||||
                "fat: ${entry.fat.toStringAsFixed(2)}",
 | 
					 | 
				
			||||||
                style: TextStyle(color: Theme.of(context).colorScheme.secondary),
 | 
					 | 
				
			||||||
              ),
 | 
					 | 
				
			||||||
              Text(
 | 
					 | 
				
			||||||
                "protein: ${entry.protein.toStringAsFixed(2)}",
 | 
					 | 
				
			||||||
                style: TextStyle(color: Theme.of(context).colorScheme.secondary),
 | 
					 | 
				
			||||||
              ),
 | 
					 | 
				
			||||||
              Text(
 | 
					 | 
				
			||||||
                "amount: ${entry.grams.toStringAsFixed(2)}",
 | 
					 | 
				
			||||||
                style: TextStyle(color: Theme.of(context).colorScheme.secondary),
 | 
					 | 
				
			||||||
              ),
 | 
					 | 
				
			||||||
            ],
 | 
					 | 
				
			||||||
          ),
 | 
					          ),
 | 
				
			||||||
        ],
 | 
					        ],
 | 
				
			||||||
      ),
 | 
					      ),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										102
									
								
								lib/widgets/macro.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								lib/widgets/macro.dart
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,102 @@
 | 
				
			||||||
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class MacroWidget extends StatelessWidget {
 | 
				
			||||||
 | 
					  final double? amount;
 | 
				
			||||||
 | 
					  final double? calories;
 | 
				
			||||||
 | 
					  final double protein;
 | 
				
			||||||
 | 
					  final double carb;
 | 
				
			||||||
 | 
					  final double fat;
 | 
				
			||||||
 | 
					  final TextStyle style;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const MacroWidget({
 | 
				
			||||||
 | 
					    Key? key,
 | 
				
			||||||
 | 
					    this.calories,
 | 
				
			||||||
 | 
					    this.amount,
 | 
				
			||||||
 | 
					    required this.protein,
 | 
				
			||||||
 | 
					    required this.carb,
 | 
				
			||||||
 | 
					    required this.fat,
 | 
				
			||||||
 | 
					    required this.style,
 | 
				
			||||||
 | 
					  }) : super(key: key);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  Widget build(BuildContext context) {
 | 
				
			||||||
 | 
					    var elements = <Widget>[
 | 
				
			||||||
 | 
					    Expanded(
 | 
				
			||||||
 | 
					      flex: 1,
 | 
				
			||||||
 | 
					      child: Text(
 | 
				
			||||||
 | 
					        "C: ${carb.toStringAsFixed(1)} g",
 | 
				
			||||||
 | 
					        style: style,
 | 
				
			||||||
 | 
					        textAlign: TextAlign.center,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
 | 
					    Expanded(
 | 
				
			||||||
 | 
					      flex: 1,
 | 
				
			||||||
 | 
					      child: Text(
 | 
				
			||||||
 | 
					        "F: ${fat.toStringAsFixed(1)} g",
 | 
				
			||||||
 | 
					        style: style,
 | 
				
			||||||
 | 
					        textAlign: TextAlign.center,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
 | 
					    Expanded(
 | 
				
			||||||
 | 
					      flex: 1,
 | 
				
			||||||
 | 
					      child: Text(
 | 
				
			||||||
 | 
					        "P: ${protein.toStringAsFixed(1)} g",
 | 
				
			||||||
 | 
					        style: style,
 | 
				
			||||||
 | 
					        textAlign: TextAlign.center,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (calories != null) {
 | 
				
			||||||
 | 
					      elements.add(
 | 
				
			||||||
 | 
					        Expanded(
 | 
				
			||||||
 | 
					          flex: 1,
 | 
				
			||||||
 | 
					          child: Text(
 | 
				
			||||||
 | 
					            "${calories!.toStringAsFixed(1)} kcal",
 | 
				
			||||||
 | 
					            style: style,
 | 
				
			||||||
 | 
					            textAlign: TextAlign.center,
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					          ),
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (amount != null) {
 | 
				
			||||||
 | 
					      elements.add(
 | 
				
			||||||
 | 
					        Expanded(
 | 
				
			||||||
 | 
					          flex: 1,
 | 
				
			||||||
 | 
					          child: Text(
 | 
				
			||||||
 | 
					            "${amount!.toStringAsFixed(1)} g",
 | 
				
			||||||
 | 
					            style: style,
 | 
				
			||||||
 | 
					            textAlign: TextAlign.center,
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					          ),
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (amount == null && calories == null) {
 | 
				
			||||||
 | 
					      elements.add(
 | 
				
			||||||
 | 
					        Expanded(
 | 
				
			||||||
 | 
					          flex: 1,
 | 
				
			||||||
 | 
					          child: Text(
 | 
				
			||||||
 | 
					            "",
 | 
				
			||||||
 | 
					            style: style,
 | 
				
			||||||
 | 
					            textAlign: TextAlign.center,
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					          ),
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return Padding(
 | 
				
			||||||
 | 
					      padding: const EdgeInsets.only(
 | 
				
			||||||
 | 
					        top: 4.0,
 | 
				
			||||||
 | 
					        bottom: 4.0,
 | 
				
			||||||
 | 
					        left: 8.0,
 | 
				
			||||||
 | 
					        right: 8.0,
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
 | 
					      child: Row(
 | 
				
			||||||
 | 
					        children: elements,
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,13 +1,18 @@
 | 
				
			||||||
import 'package:flutter/material.dart';
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
import 'package:fooder_web/models/meal.dart';
 | 
					import 'package:fooder_web/models/meal.dart';
 | 
				
			||||||
import 'package:fooder_web/widgets/entry.dart';
 | 
					import 'package:fooder_web/widgets/entry.dart';
 | 
				
			||||||
 | 
					import 'package:fooder_web/widgets/macro.dart';
 | 
				
			||||||
 | 
					import 'package:fooder_web/screens/edit_entry.dart';
 | 
				
			||||||
 | 
					import 'package:fooder_web/client.dart';
 | 
				
			||||||
import 'dart:core';
 | 
					import 'dart:core';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class MealWidget extends StatelessWidget {
 | 
					class MealWidget extends StatelessWidget {
 | 
				
			||||||
  final Meal meal;
 | 
					  final Meal meal;
 | 
				
			||||||
 | 
					  final ApiClient apiClient;
 | 
				
			||||||
 | 
					  final Function() refreshParent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const MealWidget({super.key, required this.meal});
 | 
					  const MealWidget({super.key, required this.meal, required this.apiClient, required this.refreshParent});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  Widget build(BuildContext context) {
 | 
					  Widget build(BuildContext context) {
 | 
				
			||||||
| 
						 | 
					@ -26,33 +31,39 @@ class MealWidget extends StatelessWidget {
 | 
				
			||||||
                        style: Theme.of(context).textTheme.titleLarge,
 | 
					                        style: Theme.of(context).textTheme.titleLarge,
 | 
				
			||||||
                      ),
 | 
					                      ),
 | 
				
			||||||
                    ),
 | 
					                    ),
 | 
				
			||||||
                    Text("${meal.calories.toStringAsFixed(2)} kcal"),
 | 
					                    Text("${meal.calories.toStringAsFixed(1)} kcal"),
 | 
				
			||||||
                  ],
 | 
					                  ],
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
                Row(
 | 
					                MacroWidget(
 | 
				
			||||||
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
 | 
					                  protein: meal.protein,
 | 
				
			||||||
                  children: <Widget>[
 | 
					                  carb: meal.carb,
 | 
				
			||||||
                    Text(
 | 
					                  fat: meal.fat,
 | 
				
			||||||
                      "carb: ${meal.carb.toStringAsFixed(2)}",
 | 
					                  style: Theme.of(context).textTheme.bodyMedium!.copyWith(
 | 
				
			||||||
                      style: TextStyle(color: Theme.of(context).colorScheme.secondary),
 | 
					                    color: Theme.of(context).colorScheme.secondary,
 | 
				
			||||||
                    ),
 | 
					                  ),
 | 
				
			||||||
                    Text(
 | 
					 | 
				
			||||||
                      "fat: ${meal.fat.toStringAsFixed(2)}",
 | 
					 | 
				
			||||||
                      style: TextStyle(color: Theme.of(context).colorScheme.secondary),
 | 
					 | 
				
			||||||
                    ),
 | 
					 | 
				
			||||||
                    Text(
 | 
					 | 
				
			||||||
                      "protein: ${meal.protein.toStringAsFixed(2)}",
 | 
					 | 
				
			||||||
                      style: TextStyle(color: Theme.of(context).colorScheme.secondary),
 | 
					 | 
				
			||||||
                    ),
 | 
					 | 
				
			||||||
                  ],
 | 
					 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
              ],
 | 
					              ],
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            children: <Widget>[
 | 
					            children: <Widget>[
 | 
				
			||||||
              for (var entry in meal.entries)
 | 
					              for (var entry in meal.entries)
 | 
				
			||||||
                EntryWidget(
 | 
					                ListTile(
 | 
				
			||||||
                  entry: entry,
 | 
					                  title: EntryWidget(
 | 
				
			||||||
 | 
					                    entry: entry,
 | 
				
			||||||
                  ),
 | 
					                  ),
 | 
				
			||||||
 | 
					                onTap: () {
 | 
				
			||||||
 | 
					                  Navigator.push(
 | 
				
			||||||
 | 
					                    context,
 | 
				
			||||||
 | 
					                    MaterialPageRoute(
 | 
				
			||||||
 | 
					                      builder: (context) => EditEntryScreen(
 | 
				
			||||||
 | 
					                        apiClient: apiClient,
 | 
				
			||||||
 | 
					                        entry: entry,
 | 
				
			||||||
 | 
					                      ),
 | 
				
			||||||
 | 
					                    ),
 | 
				
			||||||
 | 
					                  ).then((_) {
 | 
				
			||||||
 | 
					                    refreshParent();
 | 
				
			||||||
 | 
					                  });
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
          ],
 | 
					          ],
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
      ),
 | 
					      ),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,6 @@
 | 
				
			||||||
import 'package:flutter/material.dart';
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
import 'package:fooder_web/models/product.dart';
 | 
					import 'package:fooder_web/models/product.dart';
 | 
				
			||||||
 | 
					import 'package:fooder_web/widgets/macro.dart';
 | 
				
			||||||
import 'dart:core';
 | 
					import 'dart:core';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,25 +23,17 @@ class ProductWidget extends StatelessWidget {
 | 
				
			||||||
                  style: Theme.of(context).textTheme.titleLarge,
 | 
					                  style: Theme.of(context).textTheme.titleLarge,
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
              ),
 | 
					              ),
 | 
				
			||||||
              Text("${product.calories.toStringAsFixed(2)} kcal"),
 | 
					              Text("${product.calories.toStringAsFixed(1)} kcal"),
 | 
				
			||||||
            ],
 | 
					            ],
 | 
				
			||||||
          ),
 | 
					          ),
 | 
				
			||||||
          Row(
 | 
					          MacroWidget(
 | 
				
			||||||
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
 | 
					            protein: product.protein,
 | 
				
			||||||
            children: <Widget>[
 | 
					            carb: product.carb,
 | 
				
			||||||
              Text(
 | 
					            fat: product.fat,
 | 
				
			||||||
                "carb: ${product.carb.toStringAsFixed(2)}",
 | 
					            style: Theme.of(context).textTheme.bodyMedium!.copyWith(
 | 
				
			||||||
                style: TextStyle(color: Theme.of(context).colorScheme.secondary),
 | 
					              color: Theme.of(context).colorScheme.secondary,
 | 
				
			||||||
              ),
 | 
					              fontWeight: FontWeight.bold,
 | 
				
			||||||
              Text(
 | 
					            ),
 | 
				
			||||||
                "fat: ${product.fat.toStringAsFixed(2)}",
 | 
					 | 
				
			||||||
                style: TextStyle(color: Theme.of(context).colorScheme.secondary),
 | 
					 | 
				
			||||||
              ),
 | 
					 | 
				
			||||||
              Text(
 | 
					 | 
				
			||||||
                "protein: ${product.protein.toStringAsFixed(2)}",
 | 
					 | 
				
			||||||
                style: TextStyle(color: Theme.of(context).colorScheme.secondary),
 | 
					 | 
				
			||||||
              ),
 | 
					 | 
				
			||||||
            ],
 | 
					 | 
				
			||||||
          ),
 | 
					          ),
 | 
				
			||||||
        ],
 | 
					        ],
 | 
				
			||||||
      ),
 | 
					      ),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue