jio_provider 1.0.2
jio_provider: ^1.0.2 copied to clipboard
Simple light weight provider inherited widget, basic, multi, eager and lazy jio providers.
import 'package:flutter/material.dart';
import 'package:jio_provider/jio_provider.dart';
void main() {
debugPrintRebuildDirtyWidgets = false; // π enables rebuild logging
// runApp(BasicJioProvider(notifier: ExpenseViewModel(), child: const MyApp()));
runApp(
MultiJioProvider(
providers: [
// β
Lazy β created only when used <-- created only when first used (with LAZY loading)
// β
App startup is faster π β
Memory usage is lower πΎ
//----------------New version-------------------
// LazyJioUniversalProvider<ExpenseViewModel>(() async {
// await Future.delayed(const Duration(seconds: 2));
// return ExpenseViewModel();
// }),
// LazyJioUniversalProvider<CounterViewModel>(() async {
// await Future.delayed(const Duration(seconds: 2));
// return CounterViewModel();
// }),
//----------------Old version-------------------
LazyJioProvider<ExpenseViewModel>(
() => ExpenseViewModel(),
autoDispose: false,
),
// π Keeps state alive even after screen pop
LazyJioProvider<CounterViewModel>(() => CounterViewModel()),
//-----------------------------------------------
// β
Eager β created immediately
EagerJioProvider<TodoViewModel>(notifier: TodoViewModel()),
],
child: const MyApp(),
),
);
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
home: DashboardView(),
);
}
}
//=====================COUNTER==================
class CounterViewModel extends JioNotifier {
bool _option = false;
int _count = 0;
// Private constructor
CounterViewModel._();
// Public accessor
// Factory constructor
factory CounterViewModel() => _instance;
// Single static instance
static final CounterViewModel _instance = CounterViewModel._();
bool get option => _option;
int get count => _count;
void changeOption() {
_option = !_option;
notifyListeners();
}
void increment() {
_count++;
notifyListeners();
}
@override
void dispose() {
debugPrint('ποΈ CounterViewModel disposed');
super.dispose();
}
}
class CounterView extends StatelessWidget {
static int _buildCount = 0;
const CounterView({super.key});
@override
Widget build(BuildContext context) {
_buildCount++;
debugPrint('π Counter built $_buildCount times');
// final counter = JioProvider.of<CounterViewModel>(context); // OK | OK for small app
// rebuilds on change : use it in separate widget
final counter = context.watch<CounterViewModel>();
return Scaffold(
appBar: AppBar(title: Text(counter.option ? 'OPTION1' : 'OPTION2')),
body: Column(
children: [
Center(
child: Row(
children: [
ElevatedButton(
onPressed: () =>
context.read<CounterViewModel>().changeOption(),
child: Text('OPTIONS'),
),
],
),
),
Center(
child: Text(
'Count: ${counter.count}',
style: const TextStyle(fontSize: 28),
),
),
],
),
floatingActionButton: FloatingActionButton(
onPressed: context.read<CounterViewModel>().increment, // no rebuild
child: const Icon(Icons.add),
),
);
}
}
//=====================TO DO==================
class TodoViewModel extends JioNotifier {
final List<String> _todos = [];
List<String> get todos => List.unmodifiable(_todos);
void addTodo() {
_todos.add("Task ${_todos.length + 1}");
notifyListeners(); // π₯ Triggers rebuild for watchers
}
int get count => _todos.length;
}
class TodoView extends StatelessWidget {
static int _buildCount = 0;
const TodoView({super.key});
@override
Widget build(BuildContext context) {
_buildCount++;
debugPrint('π TodoList built $_buildCount times');
// β
This part WATCHES the ViewModel β rebuilds when todos change
final todos = context.watch<TodoViewModel>().todos;
return Scaffold(
appBar: AppBar(
title: const Text('Todo Demo'),
actions: [
// β This part READS only β does NOT rebuild when state changes
Padding(
padding: const EdgeInsets.all(16),
child: Center(
child: Text(
"Total: ${context.read<TodoViewModel>().count}",
style: const TextStyle(fontSize: 16),
),
),
),
],
),
body: ListView.builder(
itemCount: todos.length,
itemBuilder: (context, index) => ListTile(title: Text(todos[index])),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
// β
Use READ because we don't want to rebuild this FAB widget
context.read<TodoViewModel>().addTodo();
},
child: const Icon(Icons.add),
),
);
}
}
//=====================EXPENSE==================
class ExpenseViewModel extends JioNotifier {
final List<String> _txn = [];
List<String> get txs => _txn;
int get total => _txn.length;
void addTxn(int limit) {
for (var i = 0; i < limit; i++) {
_txn.add('Txn: $i | Balance: βΉ${total + i}');
}
notifyListeners();
}
}
class DashboardView extends StatelessWidget {
const DashboardView({super.key});
@override
Widget build(BuildContext context) {
debugPrint("π§± Dashboard rebuilt");
// final expense = context.jioWatch<ExpenseViewModel>(); // π BIG MISTAKE!
return Scaffold(
appBar: AppBar(title: Text("Dashboard")),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: [
_HeaderSection(userName: "Jiocoders"), // β Static β no watch
Divider(),
_BalanceCard(), // β
Dynamic β watch
Divider(),
_RecentTransactions(), // β
Dynamic β watch
Divider(),
_FooterSection(), // β Static β no watch
],
),
floatingActionButton: FloatingActionButton(
onPressed: () {
context.read<ExpenseViewModel>().addTxn(10);
},
child: Icon(Icons.add),
),
);
}
}
class _HeaderSection extends StatelessWidget {
const _HeaderSection({required this.userName});
final String userName;
@override
Widget build(BuildContext context) {
return RebuildLogger(label: 'Header', child: Text("Welcome $userName"));
}
}
class _BalanceCard extends StatelessWidget {
const _BalanceCard();
@override
Widget build(BuildContext context) {
final total = context.watch<ExpenseViewModel>().total;
return RebuildLogger(
label: 'Balance',
child: Text("Total Balance: βΉ$total"),
);
}
}
class _RecentTransactions extends StatelessWidget {
const _RecentTransactions();
@override
Widget build(BuildContext context) {
final txs = context.watch<ExpenseViewModel>().txs;
return RebuildLogger(
label: 'Txn',
child: Expanded(
child: ListView.builder(
itemCount: txs.length,
itemBuilder: (context, index) => Center(child: Text(txs[index])),
),
),
);
}
}
class _FooterSection extends StatelessWidget {
const _FooterSection();
@override
Widget build(BuildContext context) {
return RebuildLogger(label: 'Footer', child: Text("All rights reserved"));
}
}
/// =====================REBUILD LOGGER==================
/// A debug-only widget to track rebuilds of any widget.
///
/// Usage:
/// ```dart
/// RebuildLogger(
/// label: "BalanceCard",
/// child: BalanceCard(),
/// )
/// ```
class RebuildLogger extends StatelessWidget {
final String label;
final Widget child;
const RebuildLogger({super.key, required this.label, required this.child});
@override
Widget build(BuildContext context) {
// π This print runs every time the widget rebuilds
debugPrint("π Widget Rebuilt: $label");
return child;
}
}
/// =====================REBUILD LOGGER END==================