Skip to content

Instantly share code, notes, and snippets.

@100xA
Created October 15, 2025 08:52
Show Gist options
  • Select an option

  • Save 100xA/d93f72289928641b49a8e52a325efb85 to your computer and use it in GitHub Desktop.

Select an option

Save 100xA/d93f72289928641b49a8e52a325efb85 to your computer and use it in GitHub Desktop.
Provider/ChangeNotifier
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() {
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => CartModel()),
Provider<ApiService>(create: (_) => ApiService()),
ChangeNotifierProvider(create: (_) => CounterModel()),
],
child: const MyApp(),
),
);
}
class CounterModel extends ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners();
}
}
class CartModel extends ChangeNotifier {
final Map<String, int> _lines = {};
Map<String, int> get lines => Map.from(_lines);
void add(String productId) {
_lines.update(productId, (q) => q + 1, ifAbsent: () => 1);
notifyListeners();
}
void clear() {
_lines.clear();
notifyListeners();
}
int get totalItems => _lines.values.fold(0, (a, b) => a + b);
}
class ApiService {
List<Product> fetchProducts() {
return const [
Product(id: 'a', name: 'Apfel', price: 9.99),
Product(id: 'b', name: 'Banane', price: 12.50),
Product(id: 'c', name: 'Brot', price: 7.25),
];
}
}
class Product {
final String id;
final String name;
final double price;
const Product({required this.id, required this.name, required this.price});
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(useMaterial3: true, colorSchemeSeed: Colors.indigo),
darkTheme: ThemeData.dark(useMaterial3: true),
home: const DemoScreen(),
);
}
}
class DemoScreen extends StatefulWidget {
const DemoScreen({super.key});
@override
State<DemoScreen> createState() => _DemoScreenState();
}
class _DemoScreenState extends State<DemoScreen> {
List<Product> _products = const [];
int _localCount = 0;
@override
void initState() {
super.initState();
final api = context.read<ApiService>();
_products = api.fetchProducts();
}
@override
Widget build(BuildContext context) {
print('DemoScreen built');
final providerCount = context.watch<CounterModel>().count;
return Scaffold(
body: SafeArea(
child: ListView(
padding: const EdgeInsets.all(12),
children: [
Card(
child: ListTile(
title: const Text('setState Counter'),
subtitle: Text('count: $_localCount'),
trailing: ElevatedButton.icon(
icon: const Icon(Icons.add),
label: const Text('Increment'),
onPressed: () {
setState(() {
_localCount++;
});
},
),
),
),
Card(
child: ListTile(
title: const Text('Provider Counter'),
subtitle: Text('count: $providerCount'),
trailing: ElevatedButton.icon(
icon: const Icon(Icons.add),
label: const Text('Increment'),
onPressed: () => context.read<CounterModel>().increment(),
),
),
),
const SizedBox(height: 8),
const SizedBox(height: 8),
Card(
child: Column(
children: [
const ListTile(
title: Text('Products (Provider + Selector)'),
subtitle: Text('Add to cart and watch rebuilds'),
),
..._products.map((p) => ProductTile(product: p)),
const SizedBox(height: 8),
Consumer<CartModel>(
builder: (context, cart, _) => Padding(
padding: const EdgeInsets.all(12.0),
child: Row(
children: [
Text('Items in cart: ${cart.totalItems}'),
const Spacer(),
OutlinedButton(
onPressed: () => context.read<CartModel>().clear(),
child: const Text('Clear cart'),
),
],
),
),
),
],
),
),
],
),
),
);
}
}
class ProductTile extends StatelessWidget {
const ProductTile({super.key, required this.product});
final Product product;
@override
Widget build(BuildContext context) {
return Selector<CartModel, int>(
selector: (context, cart) => cart.lines[product.id] ?? 0,
builder: (context, qty, _) => ListTile(
title: Text(product.name),
subtitle: Text('€${product.price.toStringAsFixed(2)}'),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
if (qty > 0)
Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: Colors.green.withValues(alpha: 0.15),
borderRadius: BorderRadius.circular(12),
),
child: Text('x$qty'),
),
const SizedBox(width: 8),
ElevatedButton(
onPressed: () => context.read<CartModel>().add(product.id),
child: const Text('Add'),
),
],
),
),
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment