### Installing States_rebuilder with Flutter CLI Source: https://github.com/gifatahth/states_rebuilder/blob/master/states_rebuilder_package/README.md This command line instruction demonstrates how to add the `states_rebuilder` package to a Flutter project using the `flutter pub add` command, which automatically updates the `pubspec.yaml` file. ```yaml flutter pub add states_rebuilder ``` -------------------------------- ### Basic States_rebuilder Counter Application Source: https://github.com/gifatahth/states_rebuilder/blob/master/states_rebuilder_package/README.md This comprehensive Dart code example illustrates a basic counter application using `states_rebuilder`. It defines a plain data class (`Counter`), a business logic class (`ViewModel`) with injected reactive states (primitive and non-primitive), and UI components (`CounterApp`, `Counter1View`, `Counter2View`) that react to state changes. It demonstrates state injection, mutation, and UI updates. ```dart /* ------------- 🗄️ Plain Data Class ------------- */ class Counter { final int value; Counter(this.value); @override String toString() => 'Counter($value)'; } /* -------------- 🤔 Business Logic -------------- */ //🚀 These states are immutable @immutable class ViewModel { // Inject a reactive state of type int. // Works for all primitives, List, Map and Set final counter1 = 0.inj(); // For non primitives and for more options final counter2 = RM.inject( () => Counter(0), // State will be redone and undone undoStackLength: 8, // Build-in logger debugPrintWhenNotifiedPreMessage: 'counter2', ); //A getter that uses the state of the injected counters int get sum => counter1.state + counter2.state.value; incrementCounter1() { counter1.state++; } incrementCounter2() { counter2.state = Counter(counter2.state.value + 1); } } /* ------------------- 👍 Setup ------------------- */ /// 🚀 As [ViewModel] is immutable and final, it is safe to globally instantiate it. // The state of counter1 and counter2 will be auto-disposed when no longer in use. // NOTE: They are testable and mockable. // States inject like this have global scope and can be reached from anywhere. final viewModel = ViewModel(); // To create many independent instances of viewModel and inject them into the widget // tree using the concept of InheritedWidget, see the section on global and local // state below. /* -------------------- 👀 UI -------------------- */ ///🚀 Just use [ReactiveStatelessWidget] widget instead of StatelessWidget. // CounterApp will automatically register in any state consumed in its widget child // branch, regardless of its depth, provided the widget is not lazily loaded as // in the builder method of the ListView.builder widget. // BTW, if you're looking for optimization for rebuild by target widget, // check out [OnReactive] or [OnBuilder]. class CounterApp extends ReactiveStatelessWidget { const CounterApp(); @override Widget build(BuildContext context) { return Scaffold( body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ Counter1View(), // Not const to make it rebuildable const Counter2View(), // Notice the use of const modifier (good approach) Text('🏁 Result: ${viewModel.sum}'), // Will be updated when sum changes ], ), ), ); } } // Child 1 - Plain StatelessWidget class Counter1View extends StatelessWidget { const Counter1View({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Column( children: [ ElevatedButton( child: const Text('🏎️ Counter1 ++'), onPressed: () => viewModel.incrementCounter1(), ), // Listen to the state from parent Text('Counter1 value: ${viewModel.counter1.state}'), ], ); } } // Child 2 - User ReactiveStatelessWidget because Counter2View // is instantiated with const modifier class Counter2View extends ReactiveStatelessWidget { const Counter2View({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Column( children: [ ElevatedButton( child: const Text('🏎️ Counter2 ++'), onPressed: () => viewModel.incrementCounter2(), ), ElevatedButton( child: const Text('⏱️ Undo'), onPressed: () => viewModel.counter2.undoState(), ), Text('Counter2 value: ${viewModel.counter2.state.value}'), ], ); } } ``` -------------------------------- ### Initializing Authentication with States Rebuilder (Dart) Source: https://github.com/gifatahth/states_rebuilder/blob/master/states_rebuilder_package/README.md This snippet shows how to set up user authentication and authorization using `RM.injectAuth`. It requires an `IAuth` implementation for the repository and can configure automatic token refresh or sign-out based on token expiry. ```Dart final user = RM.injectAuth( ()=> MyAuthRepository(),// Implements IAuth autoRefreshTokenOrSignOut: (user)=> Duration(seconds: user.tokenExpiryDate) ); ``` -------------------------------- ### Initializing CRUD Operations with States Rebuilder (Dart) Source: https://github.com/gifatahth/states_rebuilder/blob/master/states_rebuilder_package/README.md This snippet demonstrates how to initialize a CRUD (Create, Read, Update, Delete) service using `RM.injectCRUD`. It requires a repository that implements `ICRUD` and can optionally read data on initialization. ```Dart final products = RM.injectCRUD( ()=> MyProductRepository(), // Implements ICRUD readOnInitialization: true, // Optional (Default is false) ); ``` -------------------------------- ### Initializing Tab/Page View Controller with States_Rebuilder Source: https://github.com/gifatahth/states_rebuilder/blob/master/states_rebuilder_package/README.md This snippet illustrates how to initialize a tab and page view controller using `RM.injectTabPageView`. It allows setting an initial index and the total length of the tabs/pages. ```Dart final injectedTab = RM.injectTabPageView( initialIndex: 2, length: 5, ); ``` -------------------------------- ### Performing Imperative Navigation with InjectedNavigator in Dart Source: https://github.com/gifatahth/states_rebuilder/blob/master/states_rebuilder_package/README.md This snippet illustrates various imperative navigation methods available through the `InjectedNavigator` instance, such as `to`, `toDeeply`, `toReplacement`, `toAndRemoveUntil`, `back`, and `backUntil`. These methods allow programmatic control over the navigation stack. ```dart myNavigator.to('/page1'); myNavigator.toDeeply('/page1'); myNavigator.toReplacement('/page1', argument: 'myArgument'); myNavigator.toAndRemoveUntil('/page1', queryParam: {'id':'1'}); myNavigator.back(); myNavigator.backUntil('/page1'); ``` -------------------------------- ### Initializing Dynamic Theme Switching with States Rebuilder (Dart) Source: https://github.com/gifatahth/states_rebuilder/blob/master/states_rebuilder_package/README.md This snippet illustrates how to configure dynamic theme switching using `RM.injectTheme`. It allows defining multiple light and dark themes, setting an initial theme mode (e.g., system), and persisting the chosen theme using a key. ```Dart final theme = RM.injectTheme( lightThemes : { 'simple': ThemeData.light( ... ), 'solarized': ThemeData.light( ...), }, darkThemes: { 'simple': ThemeData.dark( ... ), 'solarized': ThemeData.dark( ...), }; themeMode: ThemeMode.system; persistKey: '__theme__', ); ``` -------------------------------- ### Initializing Scroll Controller with States_Rebuilder Source: https://github.com/gifatahth/states_rebuilder/blob/master/states_rebuilder_package/README.md This snippet demonstrates how to initialize a scroll controller using `RM.injectScrolling`. It allows configuration of initial offset, scroll offset persistence, end scroll delay, and provides callbacks for scroll events like reaching min/max extent or starting to scroll. ```Dart final scroll = RM.injectScrolling( initialScrollOffset: 0.0, keepScrollOffset: true, endScrollDelay: 300, onScrolling: (scroll){ if (scroll.hasReachedMinExtent) { print('Scrolling vertical list is in its top position'); } if (scroll.hasReachedMaxExtent) { print('Scrolling vertical list is in its bottom position'); } if (scroll.hasStartedScrolling) { // Called only one time. print('User has just start scrolling'); } } ); ``` -------------------------------- ### Manually Adding States_rebuilder Dependency Source: https://github.com/gifatahth/states_rebuilder/blob/master/states_rebuilder_package/README.md This YAML snippet shows how to manually add the `states_rebuilder` package as a dependency in the `pubspec.yaml` file, allowing for explicit version control. ```yaml dependencies: states_rebuilder: ... ``` -------------------------------- ### Configuring Navigator 2.0 with RM.injectNavigator in Dart Source: https://github.com/gifatahth/states_rebuilder/blob/master/states_rebuilder_package/README.md This snippet demonstrates how to initialize `RM.injectNavigator` to define application routes, handle path and query parameters, implement sub-routes, and set up global navigation guards using `onNavigate` and `onNavigateBack` callbacks. It's crucial for declarative route management. ```dart final InjectedNavigator myNavigator = RM.injectNavigator( // Define your routes map routes: { '/': (RouteData data) => Home(), // redirect all paths that starts with '/home' to '/' path '/home/*': (RouteData data) => data.redirectTo('/'), '/page1': (RouteData data) => Page1(), '/page1/page11': (RouteData data) => Page11(), '/page2/:id': (RouteData data) { // Extract path parameters from dynamic links final id = data.pathParams['id']; // OR inside Page2 you can use `context.routeData.pathParams['id']` return Page2(id: id); }, '/page3/:kind(all|popular|favorite)': (RouteData data) { // Use custom regular expression final kind = data.pathParams['kind']; return Page3(kind: kind); }, '/page4': (RouteData data) { // Extract query parameters from links // Ex link is `/page4?age=4` final age = data.queryParams['age']; // OR inside Page4 you can use `context.routeData.queryParams['age']` return Page4(age: age); }, // Using sub routes '/page5': (RouteData data) => RouteWidget( builder: (Widget routerOutlet) { return MyParentWidget( child: routerOutlet; // OR inside MyParentWidget you can use `context.routerOutlet` ) }, routes: { '/': (RouteData data) => Page5(), '/page51': (RouteData data) => Page51(), }, ), }, // // Called after a location is resolved and just before navigation. // It is used for route guarding and global redirection. onNavigate: (RouteData data) { final toLocation = data.location; if (toLocation == '/homePage' && userIsNotSigned) { return data.redirectTo('/signInPage'); } if (toLocation == '/signInPage' && userIsSigned) { return data.redirectTo('/homePage'); } //You can also check query or path parameters if (data.queryParams['userId'] == '1') { return data.redirectTo('/superUserPage'); } }, // // Called when route is going back. // It is used to prevent leaving pages before date is validated onNavigateBack: (RouteData data) { if(data== null){ // data is null when the back Button of Android device is hit and the route // stack is empty. // returning true we will exit the app. // returning false we will stay on the app. return false; } final backFrom = data.location; if (backFrom == '/SingInFormPage' && formIsNotSaved) { RM.navigate.toDialog( AlertDialog( content: Text('The form is not saved yet! Do you want to exit?'), actions: [ ElevatedButton( onPressed: () => RM.navigate.forceBack(), child: Text('Yes'), ), ElevatedButton( onPressed: () => RM.navigate.back(), child: Text('No'), ), ], ), ); return false; } }, ); ``` -------------------------------- ### Adding Parameterized String Translations (ARB) Source: https://github.com/gifatahth/states_rebuilder/blob/master/examples/ex008_00_app_i18n_i10n/lib/ex_002_i18n_using_arb/README.md These ARB snippets show how to define strings with arguments, such as 'welcome {name}'. The English example includes a `"@welcome"` metadata entry with `"placeholders"` to explicitly define the `name` argument, while the Arabic and Spanish examples demonstrate the direct usage of the placeholder. ```ARB { "welcome": "Welcome {name}", "@welcome": { "placeholders": { "name": {} } } } ``` ```ARB { "welcome": "مرحبا {name}" } ``` ```ARB { "welcome": "Hola {name}" } ``` -------------------------------- ### Handling Authentication UI and Actions with States Rebuilder (Dart) Source: https://github.com/gifatahth/states_rebuilder/blob/master/states_rebuilder_package/README.md This snippet demonstrates how to use `OnAuthBuilder` in the widget tree to conditionally render UI based on the user's authentication status (signed in or out). It also shows how to programmatically trigger sign-up, sign-in, and sign-out actions using the injected `user.auth` instance. ```Dart // in the widget tree OnAuthBuilder( listenTo: user, onUnsigned: ()=> LoginPage(), onSigned: ()=> UserHomePage(), ) // later on: // Sign up user.auth.signUp((param)=> Param()); // Sign in user.auth.signIn((param)=> Param()); // Sign out user.auth.signOut(); ``` -------------------------------- ### Listening to Multiple States with OnBuilder.all in States Rebuilder (Dart) Source: https://github.com/gifatahth/states_rebuilder/blob/master/states_rebuilder_package/README.md This example shows `OnBuilder.all`, which listens to multiple injected states (`myState1`, `myState2`) simultaneously. It provides specific callbacks (`onWaiting`, `onError`, `onData`) that are invoked based on the combined status of all listened states, allowing for unified handling of loading, error, and data states. ```Dart OnBuilder.all( listenToMany: [myState1, myState2], onWaiting: () => Text('onWaiting'), // Will be invoked if at least one state is waiting onError: (err, refreshError) => Text('onError'), // Will be invoked if at least on state has error onData: (data) => Text(myState.state.toString()), // Will be invoked if all states have data. ), ``` -------------------------------- ### Listening to Injected States with OnReactive Widget - Dart Source: https://github.com/gifatahth/states_rebuilder/blob/master/states_rebuilder_package/README.md Demonstrates how to use the `OnReactive` widget to listen to changes in `RM.inject` states (`counter1`, `counter2`) and automatically rebuild specific parts of the widget tree. It shows how to listen to individual states or a computed sum of multiple states. ```Dart final counter1 = RM.inject(()=> 0) // Equivalent to 0.inj(); final counter2 = 0.inj(); // Or: using extension style int get sum => counter1.state + counter2.state; // In the widget tree: Column( children: [ OnReactive( // Will listen to counter1 ()=> Text('${counter1.state}'); ), OnReactive( // Will listen to counter2 ()=> Text('${counter2.state}'); ), OnReactive( // Will listen to both counter1 and counter2 ()=> Text('$sum'); ) ] ) ``` -------------------------------- ### Defining NameRepository for Asynchronous Data Fetching (Dart) Source: https://github.com/gifatahth/states_rebuilder/blob/master/examples/others/ex_000_hello_world/README.md This class simulates an asynchronous operation to fetch name information, introducing a random chance of failure to demonstrate error handling. It serves as a data source for the state management examples. ```Dart class NameRepository { Future getNameInfo(String name) async { await Future.delayed(Duration(seconds: 1)); if (Random().nextInt(10) > 6) { // Async task are error prone process and exceptions // must be handled for a good user experience. throw Exception('Server Error'); } return 'This is the info of $name'; } } ``` -------------------------------- ### Performing Declarative Navigation with InjectedNavigator in Dart Source: https://github.com/gifatahth/states_rebuilder/blob/master/states_rebuilder_package/README.md This snippet demonstrates how to use `myNavigator.setRouteStack` for declarative navigation, allowing direct manipulation of the route stack by providing a new list of pages. This approach offers fine-grained control over the navigation history. ```dart myNavigator.setRouteStack( (pages){ // exposes a copy of the current route stack return [...newPagesList]; } ) ``` -------------------------------- ### Performing CRUD Operations with States Rebuilder (Dart) Source: https://github.com/gifatahth/states_rebuilder/blob/master/states_rebuilder_package/README.md This snippet illustrates how to perform common CRUD operations (Read, Create, Update, Delete) on the `products` instance injected via `RM.injectCRUD`. It shows methods for reading data with parameters, creating new products, updating existing products based on a condition, and deleting products, with an option for optimistic updates. ```Dart // READ products.crud.read(param: (param)=> NewParam()); // CREATE products.crud.create(NewProduct()); // UPDATE products.crud.update( where: (product) => product.id == 1, set: (product)=> product.copyWith(...), ); // DELETE products.crud.delete( where: (product) => product.id == 1, isOptimistic: false, // Optional (Default is true) ); ``` -------------------------------- ### Importing States_rebuilder in Dart Source: https://github.com/gifatahth/states_rebuilder/blob/master/states_rebuilder_package/README.md This Dart import statement is required to access the functionalities and classes provided by the `states_rebuilder` package within any Dart file. ```dart import 'package:states_rebuilder/states_rebuilder.dart'; ``` -------------------------------- ### Navigating to Pageless Routes and Showing UI Elements without BuildContext in Dart Source: https://github.com/gifatahth/states_rebuilder/blob/master/states_rebuilder_package/README.md This snippet shows how to navigate to pageless routes and display UI elements like dialogs and snackbars without requiring a `BuildContext`. It leverages `myNavigator.toPageless`, `RM.navigate.toDialog`, and `RM.scaffoldShow.snackbar` for context-independent UI interactions. ```dart myNavigator.toPageless(HomePage()); RM.navigate.toDialog(AlertDialog( ... )); RM.scaffoldShow.snackbar(SnackBar( ... )); ``` -------------------------------- ### Initializing Internationalization with States Rebuilder (Dart) Source: https://github.com/gifatahth/states_rebuilder/blob/master/states_rebuilder_package/README.md This snippet shows how to initialize internationalization using `RM.injectI18N`. It maps `Locale` objects to functions that return language-specific classes (e.g., `EnUS`, `EsES`), allowing for asynchronous loading. It also configures a persistence key for storing the chosen language locally. ```Dart final i18n = RM.injectI18N( { Local('en', 'US'): ()=> EnUS(); // Can be async Local('es', 'ES'): ()=> EsES(); }; persistKey: '__lang__', // Local persistance of language ); ``` -------------------------------- ### Initializing State Persistence with States_Rebuilder (Dart) Source: https://github.com/gifatahth/states_rebuilder/blob/master/states_rebuilder_package/README.md This snippet demonstrates how to initialize state persistence for a model using `RM.inject` in States_Rebuilder. It configures a `PersistState` object with a unique key, `toJson` and `fromJson` methods for serialization/deserialization, and an optional `throttleDelay` to control persistence frequency. ```Dart final model = RM.inject( ()=>MyModel(), persist:() => PersistState( key: 'modelKey', toJson: (MyModel s) => s.toJson(), fromJson: (String json) => MyModel.fromJson(json), // Optionally, throttle the state persistance throttleDelay: 1000, ), ); ``` -------------------------------- ### Creating Reactive Widgets with ReactiveStatelessWidget - Dart Source: https://github.com/gifatahth/states_rebuilder/blob/master/states_rebuilder_package/README.md Shows how to use `ReactiveStatelessWidget` as an alternative to `StatelessWidget` to make an entire widget reactive. When extending `ReactiveStatelessWidget`, the widget implicitly tracks listeners for injected states within its `build` method, triggering rebuilds automatically. ```Dart class MyWidget extends ReactiveStatelessWidget { @override Widget build(BuildContext context) { return Column( children: [ Text('${counter1.state}'), Text('${counter2.state}'), Text('$sum'), ] ); } } ``` -------------------------------- ### Initializing Form Fields and Form Controller with States Rebuilder (Dart) Source: https://github.com/gifatahth/states_rebuilder/blob/master/states_rebuilder_package/README.md This snippet initializes reactive form fields (`email`, `password`, `acceptLicence`) using `RM.injectTextEditing` and `RM.injectedFormField`, including client-side validators. It also sets up a main form controller (`form`) with `RM.injectForm`, defining submission logic, auto-validation mode, and callbacks for submission states, enabling robust form management. ```Dart final email = RM.injectTextEditing(): final password = RM.injectTextEditing( validators: [ (String? value) { if (value!.length < 6) { return "Password must have at least 6 characters"; } return null; }, ], ); final acceptLicence = RM.injectedFormField( validators: [ (bool? value) { if (bool != true) { return "You have to accept the licence"; } return null; }, ], ); final form = RM.injectForm( autovalidateMode: AutovalidateMode.disable, autoFocusOnFirstError: true, submit: () async { // This is the default submission logic: // 1. it may be override when calling form.submit( () async { }); // 2. it may contains server validation. await serverError = authRepository.signInWithEmailAndPassword( email: email.text, password: password.text, ); // After server validation if(serverError == 'Invalid-Email'){ email.error = 'Invalid email'; } if(serverError == 'Weak-Password'){ email.error = 'Password must have more the 6 characters'; } }, onSubmitting: () { // Called while waiting for form submission, }, onSubmitted: () { // Called after form is successfully submitted // for example: navigation to user page } ); ``` -------------------------------- ### Defining a Simple Business Logic Class in Dart Source: https://github.com/gifatahth/states_rebuilder/blob/master/states_rebuilder_package/README.md This Dart class `Foo` demonstrates a typical business logic structure in `states_rebuilder`. It can contain both mutable and immutable states and methods that return `Future` or `Stream`, which `states_rebuilder` handles automatically without requiring manual asynchronous state tracking or notification logic. ```Dart class Foo { // Don't extend any other library specific class int mutableState = 0; // The state can be mutable final int immutableState; // Or it can be immutable (no difference) Foo(this.immutableState); Future fetchSomeThing async(){ // No need for any kind of async state tracking variables return repository.fetchSomeThing(); // No need for any kind of notification } Stream streamSomeThing async*(){ // Methods can return stream, future, or simple sync objects, // states_rebuilder treats them equally } } ``` -------------------------------- ### Initializing Animation Controller with States Rebuilder (Dart) Source: https://github.com/gifatahth/states_rebuilder/blob/master/states_rebuilder_package/README.md This snippet initializes an animation controller using `RM.injectAnimation` from the `states_rebuilder` library. It sets the animation duration to 1 second and uses a linear curve, providing a reactive animation instance for UI components. ```Dart final animation = RM.injectAnimation( duration: const Duration(seconds: 1), curve: Curves.linear, ); ``` -------------------------------- ### Initializing Plugins with TopStatelessWidget - Dart Source: https://github.com/gifatahth/states_rebuilder/blob/master/states_rebuilder_package/changelog/v-5.0.0.md This example shows how to use States Rebuilder's TopStatelessWidget to manage plugin initialization. It provides methods to define a list of initialization futures, display a splash screen during initialization, and present an error screen with a retry option if initialization fails. ```Dart class MyApp extends TopStatelessWidget { const MyApp({Key? key}) : super(key: key); @override List>? ensureInitialization() { return [ initializeFirstPlugin(), initializeSecondPlugin(), ]; } @override Widget? splashScreen() { return Material( child: Scaffold( body: Center( child: CircularProgressIndicator(), ), ), ); } @override Widget? errorScreen(error, void Function() refresh) { return ElevatedButton.icon( onPressed: () => refresh(), icon: Icon(Icons.refresh), label: Text('Retry again'), ); } @override Widget build(BuildContext context) { return MyHomePage(); } } ``` -------------------------------- ### Initializing RM.injectNavigator for Flutter Navigation 2.0 (Dart) Source: https://github.com/gifatahth/states_rebuilder/blob/master/examples/ex004_00_navigation/README.md This snippet initializes the `RM.injectNavigator` instance, which is central to managing Flutter Navigation 2.0 routes with states_rebuilder. It defines a map of routes, associating specific URL paths (e.g., '/' and '/selection-screen') with their corresponding screen widgets (`HomeScreen` and `SelectionScreen`), simplifying navigation setup. ```Dart final navigator = RM.injectNavigator( routes: { '/': (data) => const HomeScreen(), '/selection-screen': (data) => const SelectionScreen(), }, ); ``` -------------------------------- ### Handling State Status with OnReactive Widget - Dart Source: https://github.com/gifatahth/states_rebuilder/blob/master/states_rebuilder_package/README.md Illustrates different approaches to handle various state statuses (waiting, error, data) within an `OnReactive` widget. It presents three options: manual conditional rendering, using the `onAll` method for comprehensive status handling, and using `onOrElse` for expected data or a fallback. ```Dart // Option 1: I do it by myself! 😤 OnReactive( ()=> { if(myModel.isWaiting){ return WaitingWidget(); } if(myModel.hasError){ return ErrorWidget(); } return DataWidget(); } ) // Option 2: use onAll method: (defined all status) OnReactive( ()=> myModel.onAll( onWaiting: ()=> WaitingWidget(), onError: (err, refreshErr)=> ErrorWidget(), onData: (data)=> DataWidget(), ); ) // Option 3: use onOrElse method: (expected or undefined status) OnReactive( ()=> myModel.onOrElse( onData: (data)=> DataWidget(), orElse: ()=> IndicatorWidget(), ); ) ``` -------------------------------- ### Defining Language Classes for Internationalization (Dart) Source: https://github.com/gifatahth/states_rebuilder/blob/master/states_rebuilder_package/README.md This snippet demonstrates how to define simple Dart classes to hold localized strings for different languages. `EnUS` serves as the base class for U.S. English, and `EsEs` implements `EnUs` to provide Spanish translations, illustrating a basic structure for internationalization. ```Dart // U.S. English class EnUS { final helloWorld = 'Hello world'; } // Spanish class EsEs implements EnUs{ final helloWorld = 'Hola Mondo'; } ``` -------------------------------- ### Example of Asynchronous Dependency Injection with Plugging, Repository, and Service in states_rebuilder (Dart) Source: https://github.com/gifatahth/states_rebuilder/blob/master/states_rebuilder_package/changelog/v-2.0.0.md This comprehensive example demonstrates a real-world scenario of asynchronous dependency injection involving a `Plugging` (simulating an initialized plugin), a `Repository` that depends on the `Plugging`, and a `SecretService` that depends on the `Repository`. It illustrates how `states_rebuilder` can manage the initialization and availability of these interdependent asynchronous components within a Flutter application. ```Dart void main() { runApp(MaterialApp(home: App())); } class Plugging { Plugging _instance; final String message = 'Hi I am Plugging'; Future init() { return Future.delayed( Duration(seconds: 2), () { if (Random().nextBool()) { throw Exception('ERROR'); } _instance = Plugging(); return _instance; }, ); } Future getSecretNumber() { return Future.delayed(Duration(seconds: 1), () => 700007); } } class Repository { Repository(this.plugging); final Plugging plugging; final String message = 'Repository'; Future fetchSecretNumber() async { await Future.delayed(Duration(seconds: 1)); final secret = await plugging.getSecretNumber(); return 'The Secret Number is $secret'; } } class SecretService { SecretService(this.repository); final Repository repository; ``` -------------------------------- ### Injecting NameRepository with states_rebuilder (Dart) Source: https://github.com/gifatahth/states_rebuilder/blob/master/examples/others/ex_000_hello_world/README.md This snippet demonstrates how to inject the `NameRepository` instance into the states_rebuilder system using `RM.inject`. This makes the repository globally accessible and its state manageable by the framework. ```Dart final repository = RM.inject(() => NameRepository()); ``` -------------------------------- ### Integrating Navigator with MaterialApp.router in Dart Source: https://github.com/gifatahth/states_rebuilder/blob/master/states_rebuilder_package/README.md This code shows how to integrate the `InjectedNavigator` instance with `MaterialApp.router` by providing its `routeInformationParser` and `routerDelegate`. This setup is essential for enabling Navigator 2.0 functionality in a Flutter application. ```dart class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp.router( routeInformationParser: myNavigator.routeInformationParser, routerDelegate: myNavigator.routerDelegate, ); } } ``` -------------------------------- ### Mocking Injected States for Testing in States_Rebuilder Source: https://github.com/gifatahth/states_rebuilder/blob/master/states_rebuilder_package/README.md This snippet provides examples of how to mock different types of injected states (`injectMock`, `injectFutureMock`, `injectCRUDMock`, `injectAuthMock`) for testing purposes within the States_Rebuilder framework, allowing isolation of components during tests. ```Dart model.injectMock(()=> MyMockModel()); model.injectFutureMock(()=> MyMockModel()); products.injectCRUDMock(()=> MockRepository()) user.injectAuthMock(()=> MockAuthRepository()) ``` -------------------------------- ### Full API of OnReactive Widget in Dart Source: https://github.com/gifatahth/states_rebuilder/blob/master/states_rebuilder_package/changelog/v-4.4.0.md This snippet provides a comprehensive overview of the OnReactive widget's API, detailing its various lifecycle callbacks and properties. It explains initState for initial setup, dispose for cleanup, onSetState for reactions to state notifications, and shouldRebuild for controlling rebuild behavior. ```Dart OnReactive( (){ //Widget to rebuild }, initState: (){ // Side effect to call when the widget is first inserted into the widget tree }, dispose: (){ // Side effect to call when the widget is removed from the widget tree }, onSetState: (snapState){ // Side effect to call when is notified to rebuild //if the OnReactive listens to many states, the exposed snapState is that of the state that emits the notification }, shouldRebuild: (oldSnap, newSnap){ // return bool to whether rebuild the widget or not. //if the OnReactive listens to many states, the exposed snapState is that of the state that emits the notification }, ); ``` -------------------------------- ### Changing Application Language with States Rebuilder (Dart) Source: https://github.com/gifatahth/states_rebuilder/blob/master/states_rebuilder_package/README.md This snippet illustrates how to dynamically change the application's language by setting the `i18n.locale` property. It shows examples of setting a specific locale (e.g., Spanish) or automatically adopting the system's preferred locale. ```Dart // Choose the language i18n.locale = Local('es', 'Es'); // Or: choose the system language i18n.locale = SystemLocale(); ``` -------------------------------- ### Intercepting State Changes with `stateInterceptor` in States_Rebuilder (Dart) Source: https://github.com/gifatahth/states_rebuilder/blob/master/states_rebuilder_package/README.md This example illustrates how to use the `stateInterceptor` parameter within the `setState` method to control state transitions. The `stateInterceptor` is invoked after new state calculation but before mutation, allowing inspection of `currentSnap` and `nextSnap` to conditionally prevent or modify state updates, such as skipping the `isWaiting` stage. ```Dart // For more options foo.setState( (s) => s.fetchSomeThing(), // stateInterceptor is called after new state calculation and just // before state mutation. It exposes the current and the next snapState. stateInterceptor: (currentSnap, nextSnap){ // Ignoring the waiting stage. if(nextSnap.isWaiting) return currentSnap; } ); ``` -------------------------------- ### Encapsulating Global State in a BLOC with States Rebuilder (Dart) Source: https://github.com/gifatahth/states_rebuilder/blob/master/states_rebuilder_package/README.md This example demonstrates encapsulating multiple injected states (`_myState1`, `_myState2`) within an immutable `MyBloc` class. Instantiating `MyBloc` globally makes its internal states and logic accessible throughout the application, promoting better organization and maintainability for complex global state management. ```Dart //For the sake of best practice, one strives to make the class immutable @immutable class MyBloc { // or MyViewModel, or MyController final _myState1 = RM.inject(() => MyState1()) final _myState2 = RM.inject(() => MyState2()) //Other logic that mutate _myState1 and _myState2 } //As MyBloc is immutable, it is safe to instantiate it globally final myBloc = MyBloc(); ``` -------------------------------- ### Injecting Local (Scoped) BLOC with inherited in States Rebuilder (Dart) Source: https://github.com/gifatahth/states_rebuilder/blob/master/states_rebuilder_package/README.md This example demonstrates injecting a local (scoped) `MyBloc` instance using `RM.inject` and `inherited`. Similar to local state, the `MyBloc` is initialized with specific parameters (`parm1`, `param2`) within the widget tree, ensuring each widget instance has its own independent BLOC, accessible via `myBloc.of(context)`. ```Dart final myBloc = RM.inject(() => throw UnimplementedError()) //In the widget tree myState.inherited( stateOverride: () { return MyBloc(parm1, param2); }, builder: (context) { final _myBloc = myBloc.of(context); } ) ``` -------------------------------- ### Initializing Flutter Project Files (CLI) Source: https://github.com/gifatahth/states_rebuilder/blob/master/examples/others/ex_007_2_clean_architecture_dane_mackier_app_with_fi/README.md This command is essential for setting up a new Flutter project or regenerating platform-specific files (e.g., Android, iOS, web) after cloning a repository. It ensures the project is ready for development and compilation across different platforms. ```Shell flutter create . ``` -------------------------------- ### Implementing Widget-Wise State with inherited in States Rebuilder (Dart) Source: https://github.com/gifatahth/states_rebuilder/blob/master/states_rebuilder_package/README.md This example demonstrates how to create widget-wise state using `RM.inject` and the `inherited` method. Each item in a `ListView.builder` overrides the `item` state with its specific data (`items[index]`), allowing `ItemWidget` to access the correct state for its branch using `item.of(context)` or `item(context)`, effectively scoping the state to individual widgets. ```Dart final items = [1,2,3]; final item = RM.inject(()=>null); class App extends StatelessWidget{ build (context){ return ListView.builder( itemCount: items.length, itemBuilder: (BuildContext context, int index) { return item.inherited( // Inherited uses the `InheritedWidget` concept stateOverride: () => items[index], builder: () { return const ItemWidget(); // Inside ItemWidget you can use the buildContext to get // the right state for each widget branch using: // This Element owner of context is registered to item model. // item.of(context); // Or: this Element owner of context is not registered to item model. // item(context); } ); }, ); } } ``` -------------------------------- ### Managing Dependent States and Side Effects with states_rebuilder (Dart) Source: https://github.com/gifatahth/states_rebuilder/blob/master/examples/others/ex_000_hello_world/README.md This code defines two injected states: `name` (a simple string) and `helloName` (which depends on `name`). It showcases how `helloName` automatically recalculates when `name` changes, and how `onSetState` is used with `On.or` to display `SnackBar` messages for waiting, error, and default (hide) states, providing immediate user feedback. ```Dart // create a name state and inject it. final name = RM.inject(() => ''); final helloName = RM.inject( () => 'Hello, ${name.state}', // helloName depends on the name injected model. // Whenever the name state changes the helloName will recalculate its // creation function and notify its listeners. // // helloName state status is a combination of its own state and the state // of the injected models that it depends on. // ex: if name is waiting => helloName is waiting, // if name has error => helloName has error, // if name has data => helloName state will be recalculated // dependsOn: DependsOn( {name}, // Do not recalculate until 400 ms has been passed without any // further notification from name injected model. debounceDelay: 400, ), // Execute side effects while notify the state // // It take on On objects, it has many named constructor: On.data, On.error, // On.waiting, On.all and On.or onSetState: On.or( onWaiting: () => RM.scaffold.showSnackBar( SnackBar( content: Row( children: [ Text('Waiting ...'), Spacer(), CircularProgressIndicator(), ], ), ), ), onError: (err) => RM.scaffold.showSnackBar( SnackBar(content: Text('${err.message}')), ), //the default case. hide the snackbar or: () => RM.scaffold.hideCurrentSnackBar(), ), ); ``` -------------------------------- ### Integrating Scroll Controller with ListView in Flutter Source: https://github.com/gifatahth/states_rebuilder/blob/master/states_rebuilder_package/README.md This snippet shows how to integrate the `scroll.controller` obtained from `RM.injectScrolling` with a `ListView` widget in Flutter, enabling the `ListView` to be managed by the injected scroll state. ```Dart ListView( controller: scroll.controller, // Ready to go 🏃‍♀️ 🏃 children: [], ); ``` -------------------------------- ### Initializing Flutter App with States Rebuilder Navigation (Dart) Source: https://github.com/gifatahth/states_rebuilder/blob/master/examples/others/ex_007_2_clean_architecture_dane_mackier_app_with_fi/README.old.md This snippet initializes a Flutter application using `runApp` and defines the root `App` widget. It configures `MaterialApp` to use `states_rebuilder`'s navigation key (`RM.navigate.navigatorKey`) for integrated navigation management, demonstrating basic UI setup with the framework. ```Dart void main() => runApp(App()); class App extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData(), onGenerateRoute: route.Router.generateRoute, //As we will use states_rebuilder navigator //we assign its key to the navigator key navigatorKey: RM.navigate.navigatorKey, ); } } ``` -------------------------------- ### Controlling Theme State with States Rebuilder (Dart) Source: https://github.com/gifatahth/states_rebuilder/blob/master/states_rebuilder_package/README.md This snippet shows how to programmatically change the active theme by setting the `theme.state` to a specific theme identifier. It also demonstrates how to toggle between the dark and light modes of the currently selected theme. ```Dart // Choose the theme theme.state = 'solarized' // Toggle between dark and light mode of the chosen them theme.toggle(); ``` -------------------------------- ### Implementing Undo/Redo UI with States Rebuilder (Dart) Source: https://github.com/gifatahth/states_rebuilder/blob/master/examples/others/ex_000_hello_world/README.md This UI snippet demonstrates how to create buttons for undoing and redoing state changes. It uses `helloName.canUndoState` and `helloName.canRedoState` to enable/disable the buttons and calls `helloName.undoState()` or `helloName.redoState()` to perform the respective actions. `On.all` is used to display different UI states (idle, waiting, error, data). ```Dart Row( children: [ On.data( () => IconButton( icon: Icon(Icons.arrow_left_rounded, //check if we can undo the state to enable the //button onPressed: helloName.canUndoState ? () => helloName.undoState()//undo the state : null, ), ).listenTo(helloName), Spacer(), Center( child: On.all( onIdle: () => Text('Enter your name'), onWaiting: () => CircularProgressIndicator(), onError: (err) => Text('${err.message}'), onData: () => Text(helloName.state), ).listenTo(helloName), ), Spacer(), On.data( () => IconButton( icon: Icon(Icons.arrow_right_rounded), //check if we can undo the state to enable the //button onPressed: helloName.canRedoState ? () => helloName.redoState()//redo the state : null, ), ).listenTo(helloName), ], ), ``` -------------------------------- ### Building Posts List UI in Flutter (Dart) Source: https://github.com/gifatahth/states_rebuilder/blob/master/examples/others/ex_007_2_clean_architecture_dane_mackier_app_with_fi/README.old.md This snippet defines a portion of a Flutter UI that displays a welcome message, a header, and an expandable list of user posts. It utilizes `UIHelper` for spacing and `postsInj` (from `states_rebuilder`) to listen for and react to changes in the posts data, rendering them via the `getPostsUi` helper function. ```Dart 'Welcome ${user.name}', style: headerStyle, ), ), Padding( padding: const EdgeInsets.only(left: 20.0), child: Text('Here are all your posts', style: subHeaderStyle), ), UIHelper.verticalSpaceSmall(), Expanded(child: getPostsUi(postsInj.state)), ], ); }, ).listenTo(postsInj),//Listen to postsInj ); } Widget getPostsUi(List posts) => ListView.builder( itemCount: posts.length, itemBuilder: (context, index) => _PostListItem( post: posts[index], ), ); ``` -------------------------------- ### Injecting ProductsState with Initial State in States Rebuilder Source: https://github.com/gifatahth/states_rebuilder/blob/master/states_rebuilder_package/changelog/v-1.15.0.md This snippet demonstrates how to inject the `ProductsState` object into the States Rebuilder's dependency injection system. It initializes `ProductsState` with an empty list, serving as the initial state for product management. ```Dart //inject ProductsState with empty list of product (this is the initial state) inject: [Inject(() => ProductsState([]))], ``` -------------------------------- ### Manually Persisting and Deleting State with States_Rebuilder (Dart) Source: https://github.com/gifatahth/states_rebuilder/blob/master/states_rebuilder_package/README.md This snippet shows how to manually trigger state persistence or delete the persisted state for a model. The `persistState()` method saves the current state, while `deletePersistState()` removes the stored state from persistence. ```Dart model.persistState(); model.deletePersistState(); ``` -------------------------------- ### Clean Architecture Directory Structure Source: https://github.com/gifatahth/states_rebuilder/blob/master/examples/others/ex_007_2_clean_architecture_dane_mackier_app_with_fi/README.old.md This snippet illustrates the recommended directory structure for a clean architecture application. It organizes the codebase into distinct layers: `domain` (core business logic), `service` (interfaces for external services), `data_source` (data fetching/persistence), `infrastructure` (third-party integrations), and `UI` (user interface). Dependencies flow strictly inwards, ensuring modularity and maintainability. ```Text **lib -** | **- domain** | | **- entities :** (mutable or immutable objects with unique IDs. | | They are the in-memory representation of | | the data that was retrieved from the persistence | | store (data_source)) | | | | **- value objects :** (immutable objects which have value equality | | and self-validation but no IDs) | | | | **- exceptions :** (all custom exceptions classes that can be | | thrown from the domain) | | | | **- common :** (common utilities shared inside the domain) | | **- service** | | **- interfaces :** (interfaces that should any external service implements) | | | | **- exceptions :** (all custom exceptions classes that can be thrown | | from the service, infrastructure and data_source) | | | | **- common :**(common utilities shared inside the service) | | | | **- use case classes | | **-data_source** : (implements interfaces and throws exception defined in | | the service layer. It is used to fetch and persist data | | and instantiate entities and value objects) | | **-infrastructure** : (implements interfaces and throws exception defined in | | the service layer. It is used to call third party libraries | | to communicate with the underplaying infrastructure framework for | | example making a call or sending a message or email, using GPS.... ) | | **UI** | | **- pages** :(collection of pages the UI has). | | | | **- widgets**: (small and reusable widgets that should be app independent. | | If you use a widget from external libraries, put it in this folder | | and adapt its interface, | | | | **- exceptions :** (Handle exceptions) | | | | **- common :**(common utilities shared inside the ui) ``` -------------------------------- ### Injecting Global State in States Rebuilder (Dart) Source: https://github.com/gifatahth/states_rebuilder/blob/master/states_rebuilder_package/README.md This snippet shows how to inject a global state using `RM.inject`. By declaring `myState` in the global scope, it becomes accessible throughout the application, providing a single, shared instance of `MyState`. ```Dart //In the global scope final myState = RM.inject(() => MyState()) ``` -------------------------------- ### Posts Page Structure and Data Display - Dart Source: https://github.com/gifatahth/states_rebuilder/blob/master/examples/others/ex_007_2_clean_architecture_dane_mackier_app_with_fi/README.old.md This snippet defines the `PostsPage` widget, which displays posts. It accesses the signed-in user via `userInj.state`. The `body` uses `On.or` to show a `CircularProgressIndicator` while `postsInj` is waiting for data, or displays the main content column once data is available. It includes vertical spacing and padding for a text element, indicating the start of the post list display, demonstrating reactive UI based on data loading state. ```Dart part 'posts_injected.dart'; part 'postlist_item.dart'; class PostsPage extends StatelessWidget { //the signed user final user = userInj.state; @override Widget build(BuildContext context) { return Scaffold( backgroundColor: backgroundColor, //User On.or body: On.or( onWaiting: () => Center(child: CircularProgressIndicator()), or: () { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ UIHelper.verticalSpaceLarge(), Padding( padding: const EdgeInsets.only(left: 20.0), child: Text( ```