Skip to content

Instantly share code, notes, and snippets.

@mihalycsaba
Created July 20, 2025 11:18
Show Gist options
  • Save mihalycsaba/acd411b511512473e3711aa30f2125b8 to your computer and use it in GitHub Desktop.
Save mihalycsaba/acd411b511512473e3711aa30f2125b8 to your computer and use it in GitHub Desktop.
shopping list with callbacks
import 'package:flutter/material.dart';
typedef CartChangedCallback = void Function(Product product);
typedef CartDeleteCallback = void Function(Product product);
void main() {
runApp(const MaterialApp(
title: 'Shopping App',
home: ShoppingList(),
));
}
class Product {
Product({required this.inCart, required this.name});
final String name;
bool inCart;
}
class ShoppingListItem extends StatelessWidget {
ShoppingListItem(
{required this.product, required this.onCartChanged, this.onCartDelete})
: super(key: ObjectKey(product));
final Product product;
final CartChangedCallback onCartChanged;
final CartDeleteCallback? onCartDelete;
Color _getColor(BuildContext context) {
return product.inCart //
? Colors.black54
: Theme.of(context).primaryColor;
}
TextStyle? _getTextStyle(BuildContext context) {
if (!product.inCart) return null;
return const TextStyle(
color: Colors.black54,
decoration: TextDecoration.lineThrough,
);
}
@override
Widget build(BuildContext context) {
return ListTile(
onLongPress: () {
onCartDelete!(product);
},
onTap: () {
onCartChanged(product);
},
leading: CircleAvatar(
backgroundColor: _getColor(context),
child: Text(product.name[0]),
),
title: Text(product.name, style: _getTextStyle(context)),
);
}
}
class ShoppingList extends StatefulWidget {
const ShoppingList({super.key});
@override
_ShoppingListState createState() => _ShoppingListState();
}
class _ShoppingListState extends State<ShoppingList> {
List<Product> products = List<Product>.empty(growable: true);
final TextEditingController _textFieldController = TextEditingController();
late String valueText;
void _handleCartChanged(Product product) async {
setState(() {
if (!product.inCart) {
product.inCart = true;
} else {
product.inCart = false;
}
});
}
void _handleCartDelete(Product product) {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: const Text('Attention'),
content: const Text('Do you want to delete the item?'),
actions: <Widget>[
TextButton(
style: TextButton.styleFrom(
foregroundColor: Colors.red,
),
child: const Text('CANCEL'),
onPressed: () {
setState(() {
Navigator.pop(context);
});
},
),
TextButton(
child: const Text('YES'),
onPressed: () async {
products.removeWhere((item) => item.name == product.name);
setState(() {
Navigator.pop(context);
});
},
),
]);
});
}
void _addProduct(BuildContext context) async {
return showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: const Text('Item'),
content: TextField(
onChanged: (value) {
setState(() {
valueText = value;
});
},
controller: _textFieldController,
decoration: const InputDecoration(hintText: "Add"),
),
actions: <Widget>[
TextButton(
style: TextButton.styleFrom(
foregroundColor: Colors.red,
),
child: const Text('CANCEL'),
onPressed: () {
setState(() {
_textFieldController.clear();
Navigator.pop(context);
});
},
),
TextButton(
child: const Text('OK'),
onPressed: () async {
products.add(Product(inCart: true, name: valueText));
_handleCartChanged(products.last);
setState(() {
_textFieldController.clear();
Navigator.pop(context);
});
},
),
],
);
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Shopping List'),
),
body: ListView.builder(
itemCount: products.length,
itemBuilder: (context, index) {
return ShoppingListItem(
product: products[index],
onCartChanged: _handleCartChanged,
onCartDelete: _handleCartDelete,
);
}),
floatingActionButton: FloatingActionButton(
onPressed: () => _addProduct(context),
tooltip: 'Add',
child: const Icon(Icons.add),
),
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment