Grimoire (pronounced gruhm · waar) is a hobby app that employs several Android modern technologies and best practices.
It is currently a work in progress being slowly improved weekend by weekend, for usage on my not-so-regular tabletop RPG gaming sessions.
Built 100% with Kotlin, it has a single-activity and performs navigation actions
with Jetpack's Navigation Component. Fragments and ViewModels interact with one another
through the usage of LiveDatas, employing a unidirectional data flow on our presentation layer.
All (or at least the majority) of this project's library dependencies were declared using Gradle's Kotlin DSL, which are located in a module (:buildSrc
) of its own.
The focus is to display a modern multi-module design paired with a tidy architecture.
In search of achieving a Clean Architecture, the common monolithic Android structure was dismembered into multiple modules.
I chose to have a separation by layer here. In doing so, :domain
module will contain all UseCase classes of our app, no matter which presentation module it serves.
Same goes for the :data
module, which will contain all Dao, Repository Implementation and Room-related classes
The only difference arises on the :presentation
module, where each screen (and it's Fragments/States) were put into separate folders.
Our :app
module dependes on everything else in order to take the role of provider of every other module's dependencies
Using this layout, our Domain layer (which encompasses both Application + Enterprise business rules) is completely unaware of any other module - as intended. The Data layer needs only to depend on the Domain to provide concrete implementations of the Domain's components (Repository, Entity, etc).
The Presentation layer depends on both of the aforementioned layers, since it is the third layer of our architecture, and thus our state-handling Presenters must be able to dispatch and call for state-changing Interactors.
Finally, we have an "extra" layer - the App - that knows of everything else. There we have our app's entry-point, as well as the configuration and components of the chosen Dependency Injection library.