jio_provider 1.0.2 copy "jio_provider: ^1.0.2" to clipboard
jio_provider: ^1.0.2 copied to clipboard

Simple light weight provider inherited widget, basic, multi, eager and lazy jio providers.

example/lib/main.dart

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==================
1
likes
160
points
28
downloads
screenshot

Documentation

Documentation
API reference

Publisher

unverified uploader

Weekly Downloads

Simple light weight provider inherited widget, basic, multi, eager and lazy jio providers.

Repository (GitHub)
View/report issues
Contributing

Topics

#state-management #jio-provider #multi-jio-provider #eager-jio-provider #lazy-jio-provider

Funding

Consider supporting this project:

jiocoders.com

License

MIT (license)

Dependencies

flutter

More

Packages that depend on jio_provider