diff --git a/lib/client.dart b/lib/client.dart index 380bcb8..3efc0cc 100644 --- a/lib/client.dart +++ b/lib/client.dart @@ -211,4 +211,12 @@ class ApiClient { throw Exception("Failed to register"); } } + + Future addMeal({required String name, required int diaryId, required int order}) async { + await post("/meal", { + "name": name, + "diary_id": diaryId, + "order": order, + }); + } } diff --git a/lib/screens/add_entry.dart b/lib/screens/add_entry.dart index 35d2249..338ec2a 100644 --- a/lib/screens/add_entry.dart +++ b/lib/screens/add_entry.dart @@ -1,7 +1,9 @@ import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:fooder_web/screens/based.dart'; import 'package:fooder_web/models/product.dart'; import 'package:fooder_web/models/diary.dart'; +import 'package:fooder_web/models/meal.dart'; import 'package:fooder_web/widgets/product.dart'; @@ -18,6 +20,7 @@ class AddEntryScreen extends BasedScreen { class _AddEntryScreen extends State { final gramsController = TextEditingController(); final productNameController = TextEditingController(); + Meal? meal; List products = []; @override @@ -36,6 +39,9 @@ class _AddEntryScreen extends State { @override void initState () { super.initState(); + setState(() { + meal = widget.diary.meals[0]; + }); _getProducts().then((value) => null); } @@ -90,10 +96,33 @@ class _AddEntryScreen extends State { padding: const EdgeInsets.all(10), child: ListView( children: [ + DropdownButton( + value: meal, + // Callback that sets the selected popup menu item. + onChanged: (Meal? meal) { + if (meal == null) { + return; + } + setState(() { + this.meal = meal; + }); + }, + items: >[ + for (var meal in widget.diary.meals) + DropdownMenuItem( + value: meal, + child: Text(meal.name), + ), + ], + ), TextFormField( decoration: const InputDecoration( labelText: 'Grams', ), + keyboardType:const TextInputType.numberWithOptions(decimal: true), + inputFormatters: [ + FilteringTextInputFormatter.allow(RegExp(r'^(\d+)?\.?\d{0,2}')), + ], controller: gramsController, ), TextFormField( @@ -108,6 +137,7 @@ class _AddEntryScreen extends State { onTap: () { setState(() { products = [product]; + productNameController.text = product.name; }); }, title: ProductWidget( diff --git a/lib/screens/add_meal.dart b/lib/screens/add_meal.dart new file mode 100644 index 0000000..c3bba1d --- /dev/null +++ b/lib/screens/add_meal.dart @@ -0,0 +1,75 @@ +import 'package:flutter/material.dart'; +import 'package:fooder_web/screens/based.dart'; +import 'package:fooder_web/models/diary.dart'; + + +class AddMealScreen extends BasedScreen { + final Diary diary; + + const AddMealScreen({super.key, required super.apiClient, required this.diary}); + + @override + State createState() => _AddMealScreen(); +} + + +class _AddMealScreen extends State { + final nameController = TextEditingController(); + + @override + void dispose() { + nameController.dispose(); + super.dispose(); + } + + void popMeDady() { + Navigator.pop( + context, + ); + } + + void showError(String message) + { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(message, textAlign: TextAlign.center), + backgroundColor: Theme.of(context).colorScheme.error, + ), + ); + } + + Future _addMeal() async { + await widget.apiClient.addMeal( + name: nameController.text, + diaryId: widget.diary.id, + order: widget.diary.meals.length, + ); + 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: TextFormField( + decoration: const InputDecoration( + labelText: 'Meal name', + ), + controller: nameController, + ), + ) + ), + floatingActionButton: FloatingActionButton( + onPressed: _addMeal, + child: const Icon(Icons.add), + ), + ); + } +} diff --git a/lib/screens/edit_entry.dart b/lib/screens/edit_entry.dart index 9510c45..84ba57e 100644 --- a/lib/screens/edit_entry.dart +++ b/lib/screens/edit_entry.dart @@ -1,8 +1,10 @@ import 'package:flutter/material.dart'; +import 'package:flutter/services.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'; +import 'package:fooder_web/models/meal.dart'; class EditEntryScreen extends BasedScreen { @@ -20,6 +22,7 @@ class _EditEntryScreen extends State { final productNameController = TextEditingController(); List products = []; + @override void dispose() { gramsController.dispose(); @@ -102,6 +105,10 @@ class _EditEntryScreen extends State { decoration: const InputDecoration( labelText: 'Grams', ), + keyboardType:const TextInputType.numberWithOptions(decimal: true), + inputFormatters: [ + FilteringTextInputFormatter.allow(RegExp(r'^(\d+)?\.?\d{0,2}')), + ], controller: gramsController, ), TextFormField( @@ -116,6 +123,7 @@ class _EditEntryScreen extends State { onTap: () { setState(() { products = [product]; + productNameController.text = product.name; }); }, title: ProductWidget( diff --git a/lib/screens/login.dart b/lib/screens/login.dart index 9436721..a244088 100644 --- a/lib/screens/login.dart +++ b/lib/screens/login.dart @@ -91,7 +91,7 @@ class _LoginScreen extends State { return Scaffold( appBar: AppBar( backgroundColor: Theme.of(context).colorScheme.inversePrimary, - title: const Text("FOODER"), + title: const Text("πŸ…΅πŸ…ΎπŸ…ΎπŸ…³πŸ…΄πŸ†"), ), body: Center( child: Container( diff --git a/lib/screens/register.dart b/lib/screens/register.dart index afe9669..4ae3fac 100644 --- a/lib/screens/register.dart +++ b/lib/screens/register.dart @@ -71,7 +71,7 @@ class _RegisterScreen extends State { return Scaffold( appBar: AppBar( backgroundColor: Theme.of(context).colorScheme.inversePrimary, - title: const Text("FOODER"), + title: const Text("πŸ…΅πŸ…ΎπŸ…ΎπŸ…³πŸ…΄πŸ†"), ), body: Center( child: Container( diff --git a/lib/widgets/diary.dart b/lib/widgets/diary.dart index fb803a1..608ddbc 100644 --- a/lib/widgets/diary.dart +++ b/lib/widgets/diary.dart @@ -3,6 +3,7 @@ import 'package:fooder_web/models/diary.dart'; import 'package:fooder_web/widgets/meal.dart'; import 'package:fooder_web/widgets/macro.dart'; import 'package:fooder_web/client.dart'; +import 'package:fooder_web/screens/add_meal.dart'; import 'dart:core'; @@ -21,8 +22,9 @@ class DiaryWidget extends StatelessWidget { slivers: [ SliverAppBar( title: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - const Spacer(), + Spacer(), Text( "${diary.calories.toStringAsFixed(1)} kcal", style: Theme.of(context).textTheme.headlineLarge!.copyWith( @@ -40,16 +42,38 @@ class DiaryWidget extends StatelessWidget { 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, + 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, + ), + child: TextButton( + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => AddMealScreen( + apiClient: apiClient, + diary: diary, + ), + ), + ).then((_) { + refreshParent(); + }); + }, + child: Text( + "Add meal", + style: Theme.of(context).textTheme.bodyMedium!.copyWith( + color: Theme.of(context).colorScheme.onSecondary, + fontWeight: FontWeight.bold, + ), + ), + ), ), - ), + ) ), - ), SliverList( delegate: SliverChildListDelegate( [ diff --git a/lib/widgets/macro.dart b/lib/widgets/macro.dart index 896d413..5a4c4dd 100644 --- a/lib/widgets/macro.dart +++ b/lib/widgets/macro.dart @@ -8,11 +8,13 @@ class MacroWidget extends StatelessWidget { final double carb; final double fat; final TextStyle style; + final Widget? child; const MacroWidget({ Key? key, this.calories, this.amount, + this.child, required this.protein, required this.carb, required this.fat, @@ -74,7 +76,16 @@ class MacroWidget extends StatelessWidget { ); } - if (amount == null && calories == null) { + if (child != null) { + elements.add( + Expanded( + flex: 1, + child: child!, + ), + ); + } + + if (amount == null && calories == null && child == null) { elements.add( Expanded( flex: 1,