The purpose of this repository to share the idea of how to structuring the application in a nice way. In my opinion, flutter_redux and redux_epics is a great combination to setup base for flutter application.
Nihad Delic also wrote a small application to understand how to use flutter_redux
with redux_epics in the following
URL Redux and epics for better-organized code in Flutter apps.
This structure already listed on Flutter's official State management list page.
By utilizing Flutter Redux as a global application state management tool and Redux Epics for stream handling, you can recycle your Dart code.
When starting a new project, it's common to consider which architecture and structure to follow. With so many state management options available, it’s a bit challenging to pick one and you may be seeking a solution that is not only reusable but can also accommodate future product expansion.
 I’m going to explain the structure I have been following and how it helped me to manage the state of the application
in a better way.
I’m going to explain the structure I have been following and how it helped me to manage the state of the application
in a better way.
The directory structure with their responsibilities are mentioned below:

- The API is synonymous with the repository, and we will use the interface to retrieve data from either the network or local storage.
- You have the flexibility to relocate this layer within the package to suit your specific needs.
- The objects of your data type will be included in the repository.
- During the App's initState(){}method, inject the completegraphor modules, and then pass the Store to theStoreProvider. There is no need for any external injections in this step.
- Within the application's build(BuildContext context){}method, the modules will be transmitted to all the app's widgets using aStoreProvider().
- Throughout the application's life cycle, the App module will monitor all the modules.
- This is the primary way to create any type of exception. It functions as a decorator on the Exceptionand will provide an example ofLowPriorityExceptionfor now.
- All the helper extensionswill be part of this directory. You can enhance as per your requirement, but you can find a number of extensions methods.
- You have the option to define your page's name and then execute the build runnercommand to automatically generate the corresponding route.
- Once the route has been generated, it can be utilized for navigation purposes.
Note: I opted for Auto_router because it can tackle complicated navigation scenarios. However, you can substitute it with any other navigation tool of your choice.
- 
This is where all the features, pages, screens, and so on, will be located. 
- 
Every feature will have a corresponding UI and Redux folder that contains its action,epics,reducer, andState.- To begin, generate a State class for the corresponding feature. In the current instance, LaunchesStatewill contain two objects: the first will record the status of the launches obtained from the API, while the second will contain the actual list of launches.
- Establish an Actionclass in a distinct file and define your actions by expanding from the core Action class ( outlined in Redux). Actions serve as the events that will be triggered, such asFetchLaunchesAction,FetchLaunchesSucceededAction,FetchLaunchesFailureAction.
- You can create a new file for the epicsand read/catch your action/event in it. Access the repository and apply your business logic. Then,emit/yieldthe nextaction/event(either success or failure). Finally, combine your epics in a list and pass them back to the Middleware, which is connected with redux/core.
 To clarify, the middleware in this context is essentially a list of all the epics for each feature, which functions as a middleware. - In a new file, create a reducerto update the state of the feature based on the Action/Event.
- Great, now you're all set and can display the data in the user interface!
 NOTE: In this example, you will see the other classes. Those are decorators to manage the data layer by layer. 
- To begin, generate a State class for the corresponding feature. In the current instance, 
- 
To receive data via ViewModelin the UI, you can useStoreConnector.
- An abstract class named Actionshould be created, which will serve as the base class for all child actions/events. Additionally, anExceptionActionshould be declared as a child of Action, which will serve as the parentexceptionaction.
- Next, create an AppStateclass that includes the initial values. This class should contain a factory method that maintains the initial state for all features. To update the state, include acopyWith()method.
- The app's core must be constructed, which involves creating a Storeand injecting theinitialState()of the app. The Store also needs to receive theMiddlewareof the app in the form of epics, as well as a reducer to identify the actions/events.Hint: Here, you can establish your logout process without any boilerplate code. 
- Create a reducerto manage the actions that are related to the system's core.
- Define a DataStateclass which can indicate the status of an object, such asloaded,loading,failure, etc. This DataState will be utilized in the application to track the state of the corresponding object.
- Create app life cycle actions and their corresponding observers, along with business logic to handle object changes during the life cycle.
- The module initializerneeds to be set up in this architecture. It involves a list of modules that includes the initialization ofDio,Repository,Environment,Local Storage, and so on.
- To build the values for the list of modules, create a Graphof the Module objects, which can be accomplished using the built_value package. Additionally, in this example, an abstract class has been included with adispose()method that can be used to close all connections of the initialized objects.
- In a separate initializer file, create a method named initialize()to set up thegraphby providing the necessary values.
- You can use the FutureBuilder()in the main file toasynchronouslyreceive the initialized graph. This allows you to display a splash page while the app/graph is being prepared.
- To make high level values accessible throughout the app, use InheritedWidgetto create anInjectorWidgetfordependency injectionvia the context.
- This directory will contain utility functions and classes that can be useful in organizing the app.
- You can put your commonly used widgets in this directory, which can be accessed and utilized throughout the app. If needed, you can also move them to a separate layer or package for more organization.
- Set up your router's initialization here.
- Build a graphwhile initializing the modules list.
- During initializing, make sure to show your splash page.
- At this point, you don’t have the MaterialApp()access, and you can useDirectionalitywidget to present the SplashScreen
- Once Graphis ready, switch the UI with yourFutureBuilder()'s builder method.
- You may find this structure easy to test
- Test your API/Repositories in a separate layer
- Your Redux layer is testable in a separate directory and easy to test
- UI layer behaves as independently and easy to test
- Business logic epic/reducerwill be managed separately to test
- Moduleby module testing can make sure the app is bug free
- In future if you need to change anything, you will be sure where to make changes and scalable
- You can add more feature without touching its architecture layer
- Easy to maintain the code and architecture
- Easy for learning for new people from web development (who have experience in Redux)
- Unit tests covers
- API
- redux
- system
- Common widgets
 
Note: Tests(Unit, Widget, and e2e_integration) are under development, and will try my best to cover 99%.
