Navigation and UI elements which fit with Osam library

Osam Flutter based on osam.

Why should I use it?

If you want to control navigation outside of widgets and persist UIState and Domain State, you probably found a solution.


To start to restore all data from your app, you should be familiar with hive. Firstly, create two classes AppState and UIState for store domain and UI data. UIState can contain everything you want to store for widgets (textController values, scroll positions, navigation, and other things). To get states you can use Persist (look at example). AppState and UIState save automatically by PersistLifecycleWrapper witch works with Persist. Don't forget to start your app in the runApp with OsamProvider.

Core elements in navigation are OsamRoute, Navigation,TabNavigation.

Navigation works with OsamRoute's stack to push, pop, and others.

To use it, you should determine some class with routes. Example:

class UIState {
  var appNavigation = Navigation(PropertyNotifier([OsamRoute(appRoutes.first)]));


Osam Flutter contains Presenter and Navigation mixins for it. Presenter should be provided for widgets by PresenterProvider.

From osam recommendations Presenters should return IProperty's.

What Presenter can do? It can be useful to call usecases by getting it from usecaseContainer, contains init and dispose methods outside of the widgets and have access to AppState and UIState.

By mixing Presenter with NavigationPresenter you able to navigate in your app without context , and widgets.


class ScreenPresenter extends Presenter<UIState, AppState> with NavigationPresenter {
  Navigation get navigation => uiState.appNavigation;

  void setResult() => setRouteResult(result: 123, route: appRoutes.second);

  Future<String> showDialog() => push(OsamRoute(appRoutes.dialog, argument: currentRoute.value));

  void pushOther() => push(OsamRoute(appRoutes.second, argument: 'arg from other screen'));


By using this widget you should have provided NavigationPresenter above.

OsamNavigator is a wrapper of default Navigator and decide what should be called by getting new routes stack from NavigationPresenter.

Notice: OsamNavigator able to push dialogs. To use this feature, MaterialApp must be determined with globally defined GlobalKey. You will not have problems with navigation if dialogs you use is Futures.

final navKey = GlobalKey<NavigatorState>();
final currentContext = navKey.currentState.overlay.context;

OsamNavigator is not able to found exact NavigationPresenter and that's why you should determinate generic type.


      routes: {
        appRoutes.first: (ctx) => PresenterProvider(
              child: Screen(),
              presenter: ScreenPresenter(appRoutes.first),
        appRoutes.second: (ctx) => PresenterProvider(
              child: Screen(),
              presenter: ScreenPresenter(appRoutes.second),
        appRoutes.dialog: () async => showDialog(
            context: currentContext,
            child: Column(
              children: [
                  presenter: DialogPresenter(),
                  child: Builder(
                    builder: (ctx) {
                      return Material(
                        child: Column(
                          children: <Widget>[
                              onPressed: () {


To get some argument from the previous screen you can provide it by OsamRoute. The result of push, pushReplacement and other methods is storing in OsamRoute and returning by it 's result completer. To set the result of the current route you able to call setResult in Presenter.


Everything above is not easy to understand immediately. I recommend to look at the example and try write your own routes with different screens and dialogs.