final
This commit is contained in:
@@ -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]!),
|
||||
];
|
||||
@@ -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
@@ -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'),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user