Divide and Conquer: Navigation Component in a Multi-Module Project

In this article, you will learn how you can organize graphs of individual modules / features / user story, centralize them, build direct navigation between them and sprinkle Safe Args with a plugin on top.





You are now in the third part of a large article about Navigation Component in a multi-module project . If you do not understand a single word above, then I urge you to first familiarize yourself with that:





  • What a beast this Navigation Component is .





  • How Safe Args plugin works and what it does .





Well, if you are already familiar with this library, then there is a nice bonus for you in the next article - an approach to organizing iOS-like multistack navigation .





First, let's see how the division of the project into modules looks like in our company in which I work ( magora-systems.com ):





  1. : app is the main module and entry point to the application. He needs to know about all the modules participating in the application.





  2. : core-module contains all the basic things: base classes, models, entity, DTO, extensions, etc. 





  3. Utility modules are used to encapsulate the functionality of the main application components. For example, working with a network, a database or the same navigation.





  4. Feature-modules include the work of a specific feature / user story, be it a flow or a screen.





, Safe Args .





, :





. , :





  1. feature-.





  2. Top-level .





  3. .





  4. , Top-level .





.





feature-

destination- , feature- . , Safe Args , , .





Top-level

— , , .





, .





, , global action.





, Top-level  

, :





  1. (:core)





, . , . , Lint-a, .





, , .





  1. (:app)





+ .





.





Safe args global action- feature- , .





, :app-, Top-level . …





:





: (:navigation), , - .





id action-. generated- , , id .





<item name="actionglobalnavsignin" type="id"/>
<item name="actionglobalnavsignup" type="id"/>
<item name="actionglobalnavhome" type="id"/>
<item name="actionglobalnavuserslist" type="id"/>
<item name="actionglobalnavuserdetails" type="id"/>
<item name="actionglobalnavon¨C11Cglobal¨C12Csettings" type="id"/>
<item name="action¨C13Cto_faq" type="id"/>
      
      



: Directions Args :app  





Safe args global action- feature- , .





: generated-. -. Generated- build- , ( :app), :navigation- . : generateSafeArgs, , Args- Directions- R :app, .





ext {
   navigationArgsPath = '/build/generated/source/navigation-args'
   appNavigation = "${project(':app).projectDir.path}$navigationArgsPath"
   navigationPath = "${project(':navigation').projectDir.path}$navigationArgsPath"
   navigationPackage = “com.example.navigation”
}

tasks.whenTaskAdded { task ->
   if (task.name.contains('generateSafeArgs')) {
       task.doLast {
           fileTree(appNavigation)
                   .filter { it.isFile() && it.name.contains("Directions") }
                   .forEach { file ->
                       if (file.exists()) {
                           def lines = file.readLines()
                           lines = lines.plus(2, "import $navigationPackage.R")
                           file.text = lines.join("\n")
                       }
                   }
       }
       move(file("$appNavigation"), file("$navigationPath"))
   }
}
      
      



, , . - , , , . 





— , sourceSet-s .





I didn’t stop at this victory and decided to see what else could be done about it. For this, a project in which the customer wanted an application with a bottom menu and that each tab retains its state when leaving it came in handy as never before. It is about this decision that the final part of my story about iOS-like multistack-navigation is about .








All Articles