Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Navigation. Cicerone

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers. →
Avatar for Dima Dima
March 28, 2018

Navigation. Cicerone

Avatar for Dima

Dima

March 28, 2018

More Decks by Dima

Other Decks in Programming

Transcript

  1. Command public Forward(String screenKey, Object transitionData) {...} public Back() {}

    public BackTo(String screenKey) {...} public Replace(String screenKey, Object transitionData) {...}
  2. Navigator public SupportFragmentNavigator(FragmentManager fragmentManager, int containerId) { this.fragmentManager = fragmentManager;

    this.containerId = containerId; } protected abstract Fragment createFragment(String screenKey, Object data); protected abstract void showSystemMessage(String message); protected abstract void exit();
  3. Navigator public SupportAppNavigator(FragmentActivity activity, int containerId) { super(activity.getSupportFragmentManager(), containerId); this.activity

    = activity; } protected abstract Intent createActivityIntent(Context context, String screenKey, Object data); protected abstract Fragment createFragment(String screenKey, Object data);
  4. Router public class Router extends BaseRouter { ... public void

    newRootScreen(String screenKey, Object data) { executeCommands( new BackTo(null), new Replace(screenKey, data) ); } ... }
  5. Command Buffer class CommandBuffer implements NavigatorHolder { … } public

    interface NavigatorHolder { void setNavigator(Navigator navigator); void removeNavigator(); }
  6. Cicerone @Module class NavigationModule { private val cicerone = Cicerone.create()

    @Singleton @Provides fun provideNavigatorHolder(): NavigatorHolder = cicerone.navigatorHolder @Singleton @Provides fun provideRouter(): Router = cicerone.router }
  7. Activity/Fragment @Inject lateinit var navigatorHolder: NavigatorHolder private val navigator: SupportFragmentNavigator

    = object : SupportFragmentNavigator( this.supportFragmentManager, R.id.activity_main_container ) { override fun exit() { [email protected]() } override fun showSystemMessage(message: String) { … } override fun createFragment(screenKey: String?, data: Any?): Fragment? = when (screenKey) { ScreenKeys.MAIN_SCREEN -> MainFragment() ScreenKeys.BASKET_SCREEN -> BasketFragment() else -> null } }
  8. Presenter/... class MainPresenterImpl @Inject constructor( private val interactor: MainInteractor, private

    val mapper: MainDomainMapper, private val router: Router, private val schedulersProvider: SchedulersProvider, private val resourceManager: ResourceManager ) : MainPresenter { override fun basketClicked() { router.navigateTo(ScreenKeys.BASKET_SCREEN) }
  9. Activity/Fragment @Inject lateinit var navigatorHolder: NavigatorHolder private val navigator: SupportFragmentNavigator

    = object : SupportFragmentNavigator( this.supportFragmentManager, R.id.activity_main_container ) { override fun exit() { [email protected]() } override fun showSystemMessage(message: String) { … } override fun createFragment(screenKey: String?, data: Any?): Fragment? = when (screenKey) { ScreenKeys.MAIN_SCREEN -> MainFragment() ScreenKeys.BASKET_SCREEN -> BasketFragment() else -> null } }
  10. Component manager object ComponentManager { private var appComponent: AppComponent? =

    null private val componentMap: MutableMap <String, BaseComponent<BaseActivity>> = hashMapOf() private val tempComponentMap: MutableMap<String, TempComponent> = hashMapOf() }
  11. Fragment class SearchFragment : BaseFragment() { ... override fun injectModule(context:

    Context) { (ComponentManager.getTempComponent(context, this) as SearchComponent).inject(this) } ... }
  12. Fragment class SearchFragment : BaseFragment() { ... override fun onDestroy()

    { super.onDestroy() searchAdapter.dispose() presenter.disposeRxBinding() if (isRemoving) { presenter.dispose() ComponentManager.releaseTempComponent(this) } } ... }
  13. Fragment override fun onActivityCreated(savedInstanceState: Bundle?) { ... presenter.listenEditTextModel(RxTextView.editorActionEvents( fragment_search_edit_text) .map

    { EditTextBindingModel(it.view().text.toString(), it.actionId()) } ) ... } class EditTextBindingModel(val text: String, val actionId: Int)
  14. Interactor override fun listenActionDone(observable:Observable<EditTextBindingModel>): Observable<String> = observable.filter { it.actionId ==

    ACTION_DONE } .flatMap { Completable.fromCallable { storeSearch(it.text) } .compose(this::setSchedulers) .andThen(Observable.just(it.text)) }
  15. Global navigator class NewsMainNavigatorImpl @Inject constructor(private val router: ExtendedRouter) :

    NewsMainNavigator { ... override fun openSearchContent(textTyped: String) { router.navigateTo(RouterConstants.SEARCH_CHOSEN_SCREEN, ContentChosen( toolbar = ToolbarData.SearchToolbar(title = textTyped), url = SEARCH_URL_PREFIX, query = textTyped ) ) ... }
  16. Activity private val appNavigator = object : ExtendedNavigator( activity =

    this@MainActivity, containerId = R.id.main_activity_fragment_container ) { override fun createFragment(screenKey: String?, data: Any?): Fragment? = when (screenKey) { ... RouterConstants.MAIN_SCREEN -> MainFragment() RouterConstants.SEARCH_CHOSEN_SCREEN -> initTempComponent(SectionChosenFragment(), data) else -> null }
  17. Component Manager @Subcomponent(modules = [SectionChosenModule::class]) interface SectionChosenComponent : TempComponent {

    @Subcomponent.Builder interface Builder { @BindsInstance fun contentChosenModel(model: ContentChosen): Builder fun build(): SectionChosenComponent } fun inject(fragment: SectionChosenFragment) }
  18. Component Manager private val componentMap: MutableMap <String, BaseComponent<BaseActivity>> private val

    tempComponentMap: MutableMap<String, TempComponent> val nextScreenComponent = activityComponent.sectionChosenBuilder() .contentChosenModel(model) .build()
  19. In brief First Screen 1) Perform some logic to receive

    require Data 2) Create DTO 3) Pass DTO to Component Manager Component Manager 1) Bind DTO with a Component for a next screen 2) Create this Component Second Screen 1) Inject this DTO and use Data
  20. Router class OpenInBrowser(val url: String) : Command class ExtendedRouter :

    Router() { fun openInBrowser(url: String) { executeCommands(OpenInBrowser(url)) } }
  21. Router class OpenInBrowser(val url: String) : Command class ExtendedRouter :

    Router() { fun openInBrowser(url: String) { executeCommands(OpenInBrowser(url)) } }
  22. Navigator abstract class ExtendedNavigator(private val activity: FragmentActivity, containerId: Int) :

    SupportAppNavigator(activity, containerId) { override fun applyCommand(command: Command) = when (command) { is OpenInBrowser -> createCustomTabsIntent(command.url) .launchUrl(activity, Uri.parse(command.url)) else -> super.applyCommand(command) } protected abstract fun createCustomTabsIntent(url: String): CustomTabsIntent } class OpenInBrowser(val url: String) : Command
  23. Cicerone @Module class NavigationModule { private val cicerone = Cicerone.create(ExtendedRouter())

    @Singleton @Provides fun provideNavigatorHolder(): NavigatorHolder = cicerone.navigatorHolder @Singleton @Provides fun provideExtendedRouter(): ExtendedRouter = cicerone.router }