From 5d06b638402b301b2754914e3f2ca9d18bbd4103 Mon Sep 17 00:00:00 2001 From: Herwig Birke Date: Fri, 22 Mar 2024 08:52:47 +0100 Subject: [PATCH] final --- lib/data/dummy_items.dart | 21 ----- lib/widgets/grocery_list.dart | 66 ++++++++++---- lib/widgets/new_item.dart | 161 ++++++++++++++++++++++++---------- 3 files changed, 164 insertions(+), 84 deletions(-) delete mode 100644 lib/data/dummy_items.dart diff --git a/lib/data/dummy_items.dart b/lib/data/dummy_items.dart deleted file mode 100644 index 19d3967..0000000 --- a/lib/data/dummy_items.dart +++ /dev/null @@ -1,21 +0,0 @@ -import 'package:flutter_shopping_list/models/grocery_item.dart'; -import 'package:flutter_shopping_list/models/category.dart'; -import 'package:flutter_shopping_list/data/categories.dart'; - -final groceryItems = [ - GroceryItem( - id: 'a', - name: 'Milk', - quantity: 1, - category: categories[Categories.dairy]!), - GroceryItem( - id: 'b', - name: 'Bananas', - quantity: 5, - category: categories[Categories.fruit]!), - GroceryItem( - id: 'c', - name: 'Beef Steak', - quantity: 1, - category: categories[Categories.meat]!), -]; diff --git a/lib/widgets/grocery_list.dart b/lib/widgets/grocery_list.dart index 4ced9b1..5e682bb 100644 --- a/lib/widgets/grocery_list.dart +++ b/lib/widgets/grocery_list.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; -import 'package:flutter_shopping_list/data/dummy_items.dart'; +import 'package:flutter_shopping_list/models/grocery_item.dart'; import 'package:flutter_shopping_list/widgets/new_item.dart'; class GroceryList extends StatefulWidget { @@ -11,14 +11,57 @@ class GroceryList extends StatefulWidget { } class _GroceryListState extends State { - void _addItem() { - Navigator.of(context).push( - MaterialPageRoute(builder: (ctx) => const NewItem()), + final List _groceryItems = []; + + void _addItem() async { + final newItem = await Navigator.of(context).push( + MaterialPageRoute( + builder: (ctx) => const NewItem(), + ), ); + + if (newItem == null) { + return; + } + + setState(() { + _groceryItems.add(newItem); + }); + } + + void _removeItem(GroceryItem item) { + setState(() { + _groceryItems.remove(item); + }); } @override Widget build(BuildContext context) { + Widget content = const Center(child: Text('No items added yet.')); + + if (_groceryItems.isNotEmpty) { + content = ListView.builder( + itemCount: _groceryItems.length, + itemBuilder: (ctx, index) => Dismissible( + onDismissed: (direction) { + _removeItem(_groceryItems[index]); + }, + key: ValueKey(_groceryItems[index].id), + child: ListTile( + title: Text(_groceryItems[index].name), + leading: Container( + width: 24, + height: 24, + color: _groceryItems[index].category.color, + ), + trailing: Text( + _groceryItems[index].quantity.toString(), + ), + ), + ), + ); + } + return Scaffold( appBar: AppBar( title: const Text('Your Groceries'), @@ -29,20 +72,7 @@ class _GroceryListState extends State { ), ], ), - body: ListView.builder( - itemCount: groceryItems.length, - itemBuilder: (ctx, index) => ListTile( - title: Text(groceryItems[index].name), - leading: Container( - width: 24, - height: 24, - color: groceryItems[index].category.color, - ), - trailing: Text( - groceryItems[index].quantity.toString(), - ), - ), - ), + body: content, ); } } diff --git a/lib/widgets/new_item.dart b/lib/widgets/new_item.dart index 3744a35..11cfa02 100644 --- a/lib/widgets/new_item.dart +++ b/lib/widgets/new_item.dart @@ -1,5 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_shopping_list/data/categories.dart'; +import 'package:flutter_shopping_list/models/category.dart'; +import 'package:flutter_shopping_list/models/grocery_item.dart'; class NewItem extends StatefulWidget { const NewItem({super.key}); @@ -11,6 +13,24 @@ class NewItem extends StatefulWidget { } class _NewItemState extends State { + final _formKey = GlobalKey(); + var _enteredName = ''; + var _enteredQuantity = 1; + var _selectedCategory = categories[Categories.vegetables]!; + + void _saveItem() { + if (_formKey.currentState!.validate()) { + _formKey.currentState!.save(); + Navigator.of(context).pop( + GroceryItem( + id: DateTime.now().toString(), + name: _enteredName, + quantity: _enteredQuantity, + category: _selectedCategory), + ); + } + } + @override Widget build(BuildContext context) { return Scaffold( @@ -19,53 +39,104 @@ class _NewItemState extends State { ), body: Padding( padding: const EdgeInsets.all(12), - child: Column( - children: [ - TextFormField( - maxLength: 50, - decoration: InputDecoration( - label: Text('name'), + child: Form( + key: _formKey, + child: Column( + children: [ + TextFormField( + maxLength: 50, + decoration: InputDecoration( + label: Text('name'), + ), + validator: (value) { + if (value == null || + value.isEmpty || + value.trim().length <= 1 || + value.trim().length > 50) { + return 'Must be between 1 and 50 characters.'; + } + return null; + }, + onSaved: (value) { + _enteredName = value!; + }, ), - validator: (value) { - return 'Demo...'; - }, - ), - Row( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Expanded( - child: TextFormField( - decoration: const InputDecoration( - label: Text('Quantity'), - ), - initialValue: '1', - ), - ), - const SizedBox( - width: 8, - ), - Expanded( - child: DropdownButtonFormField(items: [ - for (final category in categories.entries) - DropdownMenuItem( - value: category.value, - child: Row( - children: [ - Container( - width: 16, - height: 16, - color: category.value.color, - ), - const SizedBox(width: 6), - Text(category.value.title), - ], - ), + Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Expanded( + child: TextFormField( + decoration: const InputDecoration( + label: Text('Quantity'), ), - ], onChanged: (value) {}), - ), - ], - ), - ], + keyboardType: TextInputType.number, + initialValue: _enteredQuantity.toString(), + validator: (value) { + if (value == null || + value.isEmpty || + int.tryParse(value) == null || + int.tryParse(value)! <= 0) { + return 'Must be a valid, positive number.'; + } + return null; + }, + onSaved: (value) { + _enteredQuantity = int.parse(value!); + }, + ), + ), + const SizedBox( + width: 8, + ), + Expanded( + child: DropdownButtonFormField( + value: _selectedCategory, + items: [ + for (final category in categories.entries) + DropdownMenuItem( + value: category.value, + child: Row( + children: [ + Container( + width: 16, + height: 16, + color: category.value.color, + ), + const SizedBox(width: 6), + Text(category.value.title), + ], + ), + ), + ], + onChanged: (value) { + setState(() { + _selectedCategory = value!; + }); + }, + ), + ), + ], + ), + const SizedBox( + height: 12, + ), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + TextButton( + onPressed: () { + _formKey.currentState!.reset(); + }, + child: const Text('Reset'), + ), + ElevatedButton( + onPressed: _saveItem, + child: const Text('Add Item'), + ), + ], + ), + ], + ), ), ), );