This commit is contained in:
2024-03-22 08:52:47 +01:00
parent fb1ca9c06e
commit 5d06b63840
3 changed files with 164 additions and 84 deletions
-21
View File
@@ -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]!),
];
+48 -18
View File
@@ -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<GroceryList> {
void _addItem() {
Navigator.of(context).push(
MaterialPageRoute(builder: (ctx) => const NewItem()),
final List<GroceryItem> _groceryItems = [];
void _addItem() async {
final newItem = await Navigator.of(context).push<GroceryItem>(
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<GroceryList> {
),
],
),
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,
);
}
}
+116 -45
View File
@@ -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<NewItem> {
final _formKey = GlobalKey<FormState>();
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<NewItem> {
),
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'),
),
],
),
],
),
),
),
);