├── .gitignore ├── .idea ├── compiler.xml ├── gradle.xml ├── kotlinScripting.xml ├── misc.xml └── vcs.xml ├── README.md ├── android-common-build.gradle ├── android-core-build.gradle ├── android-feature-build.gradle ├── app ├── .gitignore ├── build.gradle.kts ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── emamagic │ │ └── android_multi_module │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── emamagic │ │ │ └── android_multi_module │ │ │ ├── App.kt │ │ │ ├── MainActivity.kt │ │ │ ├── NoInternetAvailableDialog.kt │ │ │ ├── OnAppVisibilityListener.kt │ │ │ └── di │ │ │ ├── AppComponent.kt │ │ │ ├── AppComponentProvider.kt │ │ │ ├── SubComponents.kt │ │ │ └── SubComponentsModule.kt │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ ├── ic_launcher_background.xml │ │ ├── ic_splash.xml │ │ ├── rounded_btn_blue.xml │ │ └── splash_screen.xml │ │ ├── layout │ │ ├── activity_main.xml │ │ └── fragment_no_internet_available.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── raw │ │ └── no_internet_available.json │ │ ├── values-night │ │ └── themes.xml │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── themes.xml │ └── test │ └── java │ └── com │ └── emamagic │ └── android_multi_module │ └── ExampleUnitTest.kt ├── application ├── .gitignore ├── build.gradle.kts ├── consumer-rules.pro ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── emamagic │ │ └── core │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── emamagic │ │ │ └── core │ │ │ ├── base │ │ │ ├── Action.kt │ │ │ ├── BaseEffect.kt │ │ │ ├── BaseFragment.kt │ │ │ ├── BaseFragmentRedux.kt │ │ │ ├── BaseStore.kt │ │ │ ├── BaseViewModel.kt │ │ │ ├── BaseViewModelRedux.kt │ │ │ ├── Event.kt │ │ │ ├── Middleware.kt │ │ │ ├── Reducer.kt │ │ │ ├── State.kt │ │ │ ├── Store.kt │ │ │ ├── ViewModelDelegation.kt │ │ │ ├── ViewModelFactory.kt │ │ │ └── ViewModelFactoryBinderModule.kt │ │ │ ├── extension │ │ │ ├── BindingAdapter.kt │ │ │ ├── ComponentExt.kt │ │ │ └── ViewExt.kt │ │ │ ├── interactor │ │ │ ├── HomeUseCase.kt │ │ │ ├── MovieUseCase.kt │ │ │ └── MoviesUseCase.kt │ │ │ ├── interfaces │ │ │ ├── InitialVisibleFragmentFun.kt │ │ │ └── OnAppVisibility.kt │ │ │ └── utils │ │ │ ├── AlertType.java │ │ │ ├── Logger.kt │ │ │ ├── ToastyMode.java │ │ │ ├── ViewExt.kt │ │ │ ├── ViewModelKey.kt │ │ │ ├── ViewModelScope.java │ │ │ └── keyboard │ │ │ ├── KeyboardEventListener.kt │ │ │ └── keyboardExt.kt │ └── res │ │ ├── drawable │ │ ├── bg_corroct_toast.xml │ │ ├── bg_error_toast.xml │ │ ├── bg_rank.xml │ │ ├── bg_warning_toast.xml │ │ ├── hover_oval.xml │ │ ├── hover_oval_drawable.xml │ │ ├── ic_access_time.xml │ │ ├── ic_corroct_toast.xml │ │ ├── ic_cross.xml │ │ ├── ic_error_blue_24dp.xml │ │ ├── ic_error_red_24dp.xml │ │ ├── ic_error_toast.xml │ │ ├── ic_error_yellow_24dp.xml │ │ ├── ic_favorite_empty.xml │ │ ├── ic_favorite_fill.xml │ │ ├── ic_folder_special.xml │ │ ├── ic_warning_toast.xml │ │ ├── rounded_btn_grey.xml │ │ ├── rounded_btn_red.xml │ │ ├── rounded_iw.xml │ │ └── simple_round_transparent.xml │ │ ├── layout │ │ ├── dialog_alert.xml │ │ └── layout_toast.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── themes.xml │ │ └── values-night │ │ └── themes.xml │ └── test │ └── java │ └── com │ └── emamagic │ └── core │ └── ExampleUnitTest.kt ├── build.gradle.kts ├── buildSrc ├── build.gradle.kts ├── build │ ├── classes │ │ └── kotlin │ │ │ └── main │ │ │ ├── Android.class │ │ │ ├── Build.class │ │ │ ├── Libs.class │ │ │ ├── META-INF │ │ │ └── buildSrc.kotlin_module │ │ │ ├── Modules.class │ │ │ ├── Releases.class │ │ │ ├── Tests.class │ │ │ └── Versions.class │ ├── kotlin │ │ ├── buildSrcjar-classes.txt │ │ └── compileKotlin │ │ │ ├── build-history.bin │ │ │ ├── caches-jvm │ │ │ ├── inputs │ │ │ │ ├── source-to-output.tab │ │ │ │ ├── source-to-output.tab.keystream │ │ │ │ ├── source-to-output.tab.keystream.len │ │ │ │ ├── source-to-output.tab.len │ │ │ │ ├── source-to-output.tab.values.at │ │ │ │ ├── source-to-output.tab_i │ │ │ │ └── source-to-output.tab_i.len │ │ │ ├── jvm │ │ │ │ └── kotlin │ │ │ │ │ ├── class-attributes.tab │ │ │ │ │ ├── class-attributes.tab.keystream │ │ │ │ │ ├── class-attributes.tab.keystream.len │ │ │ │ │ ├── class-attributes.tab.len │ │ │ │ │ ├── class-attributes.tab.values.at │ │ │ │ │ ├── class-attributes.tab_i │ │ │ │ │ ├── class-attributes.tab_i.len │ │ │ │ │ ├── class-fq-name-to-source.tab │ │ │ │ │ ├── class-fq-name-to-source.tab.keystream │ │ │ │ │ ├── class-fq-name-to-source.tab.keystream.len │ │ │ │ │ ├── class-fq-name-to-source.tab.len │ │ │ │ │ ├── class-fq-name-to-source.tab.values.at │ │ │ │ │ ├── class-fq-name-to-source.tab_i │ │ │ │ │ ├── class-fq-name-to-source.tab_i.len │ │ │ │ │ ├── constants.tab │ │ │ │ │ ├── constants.tab.keystream │ │ │ │ │ ├── constants.tab.keystream.len │ │ │ │ │ ├── constants.tab.len │ │ │ │ │ ├── constants.tab.values.at │ │ │ │ │ ├── constants.tab_i │ │ │ │ │ ├── constants.tab_i.len │ │ │ │ │ ├── internal-name-to-source.tab │ │ │ │ │ ├── internal-name-to-source.tab.keystream │ │ │ │ │ ├── internal-name-to-source.tab.keystream.len │ │ │ │ │ ├── internal-name-to-source.tab.len │ │ │ │ │ ├── internal-name-to-source.tab.values.at │ │ │ │ │ ├── internal-name-to-source.tab_i │ │ │ │ │ ├── internal-name-to-source.tab_i.len │ │ │ │ │ ├── proto.tab │ │ │ │ │ ├── proto.tab.keystream │ │ │ │ │ ├── proto.tab.keystream.len │ │ │ │ │ ├── proto.tab.len │ │ │ │ │ ├── proto.tab.values.at │ │ │ │ │ ├── proto.tab_i │ │ │ │ │ ├── proto.tab_i.len │ │ │ │ │ ├── source-to-classes.tab │ │ │ │ │ ├── source-to-classes.tab.keystream │ │ │ │ │ ├── source-to-classes.tab.keystream.len │ │ │ │ │ ├── source-to-classes.tab.len │ │ │ │ │ ├── source-to-classes.tab.values.at │ │ │ │ │ ├── source-to-classes.tab_i │ │ │ │ │ └── source-to-classes.tab_i.len │ │ │ └── lookups │ │ │ │ ├── counters.tab │ │ │ │ ├── file-to-id.tab │ │ │ │ ├── file-to-id.tab.keystream │ │ │ │ ├── file-to-id.tab.keystream.len │ │ │ │ ├── file-to-id.tab.len │ │ │ │ ├── file-to-id.tab.values.at │ │ │ │ ├── file-to-id.tab_i │ │ │ │ ├── file-to-id.tab_i.len │ │ │ │ ├── id-to-file.tab │ │ │ │ ├── id-to-file.tab.keystream │ │ │ │ ├── id-to-file.tab.keystream.len │ │ │ │ ├── id-to-file.tab.len │ │ │ │ ├── id-to-file.tab.values.at │ │ │ │ ├── id-to-file.tab_i │ │ │ │ ├── id-to-file.tab_i.len │ │ │ │ ├── lookups.tab │ │ │ │ ├── lookups.tab.keystream │ │ │ │ ├── lookups.tab.keystream.len │ │ │ │ ├── lookups.tab.len │ │ │ │ ├── lookups.tab.values.at │ │ │ │ ├── lookups.tab_i │ │ │ │ └── lookups.tab_i.len │ │ │ └── last-build.bin │ ├── libs │ │ └── buildSrc.jar │ ├── pluginUnderTestMetadata │ │ └── plugin-under-test-metadata.properties │ ├── reports │ │ └── plugin-development │ │ │ └── validation-report.txt │ ├── source-roots │ │ └── buildSrc │ │ │ └── source-roots.txt │ └── tmp │ │ └── jar │ │ └── MANIFEST.MF └── src │ └── main │ └── kotlin │ ├── Android.kt │ ├── Build.kt │ ├── Libs.kt │ ├── Modules.kt │ ├── Releases.kt │ ├── Tests.kt │ └── Versions.kt ├── data ├── cache │ ├── .gitignore │ ├── build.gradle.kts │ ├── consumer-rules.pro │ ├── proguard-rules.pro │ └── src │ │ ├── androidTest │ │ └── java │ │ │ └── com │ │ │ └── emamagic │ │ │ └── cache │ │ │ └── ExampleInstrumentedTest.kt │ │ ├── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ │ └── com │ │ │ └── emamagic │ │ │ └── cache │ │ │ ├── BaseDao.kt │ │ │ ├── MoviesDB.kt │ │ │ ├── PreferenceManager.kt │ │ │ ├── dao │ │ │ ├── GenreDao.kt │ │ │ ├── MovieDao.kt │ │ │ └── SliderDao.kt │ │ │ └── entity │ │ │ ├── GenreEntity.kt │ │ │ ├── MovieEntity.kt │ │ │ └── SliderEntity.kt │ │ └── test │ │ └── java │ │ └── com │ │ └── emamagic │ │ └── cache │ │ └── ExampleUnitTest.kt ├── network │ ├── .gitignore │ ├── build.gradle.kts │ ├── consumer-rules.pro │ ├── proguard-rules.pro │ └── src │ │ ├── androidTest │ │ └── java │ │ │ └── com │ │ │ └── emamagic │ │ │ └── network │ │ │ └── ExampleInstrumentedTest.kt │ │ ├── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ │ └── com │ │ │ └── emamagic │ │ │ └── network │ │ │ ├── di │ │ │ └── RetrofitModule.kt │ │ │ ├── dto │ │ │ ├── CastDto.kt │ │ │ ├── EpisodeDto.kt │ │ │ ├── GenreDto.kt │ │ │ ├── MovieDetailDto.kt │ │ │ ├── MovieDto.kt │ │ │ ├── SeasonDto.kt │ │ │ └── SliderDto.kt │ │ │ ├── interceptor │ │ │ ├── ClientInterceptor.kt │ │ │ ├── NetworkInterceptor.kt │ │ │ └── ServerConnection.kt │ │ │ ├── response │ │ │ ├── CastResponse.kt │ │ │ ├── EpisodeResponse.kt │ │ │ ├── GenreListResponse.kt │ │ │ ├── MovieDetailResponse.kt │ │ │ ├── MovieListResponse.kt │ │ │ ├── SeasonResponse.kt │ │ │ └── SliderListResponse.kt │ │ │ ├── service │ │ │ ├── GenreService.kt │ │ │ ├── MovieDetailsService.kt │ │ │ └── MovieService.kt │ │ │ └── util │ │ │ └── Const.kt │ │ └── test │ │ └── java │ │ └── com │ │ └── emamagic │ │ └── network │ │ └── ExampleUnitTest.kt └── repository-impl │ ├── .gitignore │ ├── build.gradle.kts │ ├── consumer-rules.pro │ ├── proguard-rules.pro │ └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── emamagic │ │ └── repository │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ └── java │ │ └── com │ │ └── emamagic │ │ └── repository │ │ ├── di │ │ └── RepositoryBinderModule.kt │ │ ├── mapper │ │ ├── DataClassMapper.kt │ │ └── EntityMapper.kt │ │ └── repository │ │ ├── GenreRepositoryImpl.kt │ │ ├── MovieDetailRepositoryImpl.kt │ │ └── MovieRepositoryImpl.kt │ └── test │ └── java │ └── com │ └── emamagic │ └── repository │ └── ExampleUnitTest.kt ├── domain ├── common-entity │ ├── .gitignore │ ├── build.gradle │ └── src │ │ └── main │ │ └── java │ │ └── com │ │ └── emamagic │ │ └── common_entity │ │ ├── Cast.kt │ │ ├── Episode.kt │ │ ├── Genre.kt │ │ ├── Movie.kt │ │ ├── MovieDetail.kt │ │ ├── Season.kt │ │ └── Slider.kt ├── common-jvm │ ├── .gitignore │ ├── build.gradle │ └── src │ │ └── main │ │ └── java │ │ └── com │ │ └── emamagic │ │ └── common_jvm │ │ ├── ErrorEntity.kt │ │ ├── Exceptions.kt │ │ ├── GenreCategory.java │ │ ├── MovieCategory.java │ │ └── ResultWrapper.kt └── repository │ ├── .gitignore │ ├── build.gradle │ └── src │ └── main │ └── java │ └── com │ └── emamagic │ └── domain │ ├── GenreRepository.kt │ ├── MovieDetailRepository.kt │ └── MovieRepository.kt ├── features ├── home │ ├── .gitignore │ ├── build.gradle │ ├── consumer-rules.pro │ ├── proguard-rules.pro │ └── src │ │ ├── androidTest │ │ └── java │ │ │ └── com │ │ │ └── emamagic │ │ │ └── home │ │ │ └── ExampleInstrumentedTest.kt │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ │ └── com │ │ │ │ └── emamagic │ │ │ │ └── home │ │ │ │ ├── HomeFragment.kt │ │ │ │ ├── HomeViewModel.kt │ │ │ │ ├── contract │ │ │ │ ├── HomeAction.kt │ │ │ │ ├── HomeState.kt │ │ │ │ └── redux │ │ │ │ │ ├── HomeMiddleware.kt │ │ │ │ │ ├── HomeReducer.kt │ │ │ │ │ └── HomeStore.kt │ │ │ │ ├── di │ │ │ │ ├── HomeComponent.kt │ │ │ │ ├── HomeComponentProvider.kt │ │ │ │ └── ViewModelModule.kt │ │ │ │ └── util │ │ │ │ └── EpoxyDataBindingConfig.java │ │ └── res │ │ │ ├── drawable │ │ │ ├── ic_apps.xml │ │ │ ├── ic_home.xml │ │ │ ├── ic_menu.xml │ │ │ ├── ic_payment.xml │ │ │ └── ic_search.xml │ │ │ ├── layout │ │ │ ├── fragment_home.xml │ │ │ ├── shimmer_genre_layout.xml │ │ │ ├── shimmer_movie_h_layout.xml │ │ │ ├── shimmer_movie_v_layout.xml │ │ │ ├── view_holder_genre.xml │ │ │ ├── view_holder_movie_h.xml │ │ │ └── view_holder_movie_v.xml │ │ │ ├── menu │ │ │ └── home_menu.xml │ │ │ └── values │ │ │ ├── colors.xml │ │ │ ├── themes.xml │ │ │ └── values-night │ │ │ └── themes.xml │ │ └── test │ │ └── java │ │ └── com │ │ └── emamagic │ │ └── home │ │ └── ExampleUnitTest.kt ├── movie │ ├── .gitignore │ ├── build.gradle │ ├── consumer-rules.pro │ ├── proguard-rules.pro │ └── src │ │ ├── androidTest │ │ └── java │ │ │ └── com │ │ │ └── emamagic │ │ │ └── movie │ │ │ └── ExampleInstrumentedTest.kt │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ │ └── com │ │ │ │ └── emamagic │ │ │ │ └── movie │ │ │ │ ├── MovieFragment.kt │ │ │ │ ├── MovieViewModel.kt │ │ │ │ ├── contract │ │ │ │ ├── MovieAction.kt │ │ │ │ ├── MovieState.kt │ │ │ │ └── redux │ │ │ │ │ ├── MovieMiddleware.kt │ │ │ │ │ ├── MovieReducer.kt │ │ │ │ │ └── MovieStore.kt │ │ │ │ ├── di │ │ │ │ ├── MovieComponent.kt │ │ │ │ ├── MovieComponentProvider.kt │ │ │ │ └── ViewModelModule.kt │ │ │ │ └── util │ │ │ │ └── EpoxyDataBindingConfig.java │ │ └── res │ │ │ ├── drawable │ │ │ ├── bg_detail.xml │ │ │ ├── bg_genre.xml │ │ │ ├── bg_rate_imdb.xml │ │ │ ├── ic_comment.xml │ │ │ ├── ic_get_app.xml │ │ │ └── play_arrow.xml │ │ │ └── layout │ │ │ ├── fragment_movie.xml │ │ │ └── view_holder_cast.xml │ │ └── test │ │ └── java │ │ └── com │ │ └── emamagic │ │ └── movie │ │ └── ExampleUnitTest.kt └── movies │ ├── .gitignore │ ├── build.gradle │ ├── consumer-rules.pro │ ├── proguard-rules.pro │ └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── emamagic │ │ └── movies │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── emamagic │ │ │ └── movies │ │ │ ├── MoviesFragment.kt │ │ │ ├── MoviesViewModel.kt │ │ │ ├── contract │ │ │ ├── MoviesEvent.kt │ │ │ └── MoviesState.kt │ │ │ ├── di │ │ │ ├── MoviesComponent.kt │ │ │ ├── MoviesComponentProvider.kt │ │ │ └── ViewModelModule.kt │ │ │ └── util │ │ │ └── EpoxyDataBindingConfig.java │ └── res │ │ ├── drawable │ │ ├── bg_rate_imdb.xml │ │ ├── ic_arrow_back.xml │ │ └── ic_favorite_border.xml │ │ └── layout │ │ ├── fragment_movies.xml │ │ ├── view_holder_movie.xml │ │ └── view_holder_season.xml │ └── test │ └── java │ └── com │ └── emamagic │ └── movies │ └── ExampleUnitTest.kt ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── navigator ├── .gitignore ├── build.gradle.kts ├── consumer-rules.pro ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── emamagic │ │ └── navigator │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ └── res │ │ └── navigation │ │ └── nav_graph.xml │ └── test │ └── java │ └── com │ └── emamagic │ └── navigator │ └── ExampleUnitTest.kt ├── photo ├── multi_module_diagram.png ├── screen_1.jpg └── screen_2.jpg ├── safe ├── .gitignore ├── build.gradle ├── consumer-rules.pro ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── emamagic │ │ └── safe │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ └── java │ │ └── com │ │ └── emamagic │ │ └── safe │ │ ├── General.kt │ │ ├── SafeApi.kt │ │ ├── connectivity │ │ ├── ConnectionLiveData.kt │ │ ├── Connectivity.kt │ │ ├── ConnectivityPublisher.kt │ │ ├── ConnectivityPublisherDelegate.kt │ │ ├── ConnectivityReceiver.kt │ │ ├── ConnectivityStatus.kt │ │ └── DoesNetworkHaveInternet.kt │ │ ├── error │ │ ├── ErrorHandler.kt │ │ └── GeneralErrorHandlerImpl.kt │ │ ├── policy │ │ ├── CachePolicy.kt │ │ └── RetryPolicy.kt │ │ └── store │ │ ├── ITimeLimitedResource.kt │ │ ├── RefreshControl.kt │ │ ├── Resource.kt │ │ └── ResourceGroup.kt │ └── test │ └── java │ └── com │ └── emamagic │ └── safe │ └── ExampleUnitTest.kt └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | local.properties 16 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 35 | 36 | -------------------------------------------------------------------------------- /.idea/kotlinScripting.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 2147483647 6 | true 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [Android-Multi-Module-App](https://github.com/emamagic/Android-Multi-Module) 2 | 3 | **NOTE** 4 | this is a sample template for android multi module application, I do my best for extending this app, 5 | if you have any idea to improve the project, It is open for contribution 6 | 7 | **TODO** 8 | complete modules functionality and writing test 9 | 10 | **Dependencies** 11 | 1. MVI (UDF) 12 | 2. SSOT 13 | 3. coroutines 14 | 4. clean architecture 15 | 5. navigation components 16 | 6. dagger 2 17 | 7. kotlin dsl 18 | 8. epoxy 19 | 9. room 20 | 10. retrofit 21 | 11. data binding 22 | 12. .... 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /android-common-build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'kotlin-android' 2 | apply plugin: 'kotlin-kapt' 3 | apply from: "$rootDir/android-core-build.gradle" 4 | 5 | android { 6 | compileSdk Android.compileSdk 7 | 8 | defaultConfig { 9 | minSdk Android.minSdk 10 | targetSdk Android.targetSdk 11 | versionCode Releases.versionCode 12 | versionName Releases.versionName 13 | 14 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 15 | consumerProguardFiles "consumer-rules.pro" 16 | } 17 | 18 | buildTypes { 19 | release { 20 | minifyEnabled false 21 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 22 | } 23 | } 24 | lint { 25 | abortOnError false 26 | } 27 | compileOptions { 28 | sourceCompatibility JavaVersion.VERSION_1_8 29 | targetCompatibility JavaVersion.VERSION_1_8 30 | } 31 | kotlinOptions { 32 | jvmTarget = "1.8" 33 | } 34 | } -------------------------------------------------------------------------------- /android-core-build.gradle: -------------------------------------------------------------------------------- 1 | dependencies { 2 | 3 | implementation Libs.androidx_core 4 | implementation Libs.androidx_compat 5 | implementation Libs.material 6 | implementation Libs.constraint_layout 7 | testImplementation Tests.junit_4 8 | androidTestImplementation Tests.androidx_junit 9 | androidTestImplementation Tests.androidx_espresso 10 | 11 | } -------------------------------------------------------------------------------- /android-feature-build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply from: "$rootDir/android-common-build.gradle" 3 | apply plugin: "androidx.navigation.safeargs.kotlin" 4 | 5 | android { 6 | buildFeatures { 7 | dataBinding true 8 | } 9 | } 10 | 11 | kapt { 12 | correctErrorTypes = true 13 | } 14 | 15 | dependencies { 16 | 17 | implementation project(Modules.application) 18 | implementation project(Modules.navigator) 19 | implementation project(Modules.commonEntity) 20 | implementation project(Modules.commonJvm) 21 | implementation Libs.kotlin_coroutines 22 | implementation Libs.dagger 23 | kapt Libs.dagger_kapt 24 | implementation (Libs.navigation_component_fragment) 25 | implementation (Libs.navigation_component_ui) 26 | 27 | implementation Libs.view_model_scope 28 | 29 | implementation Libs.epoxy 30 | implementation Libs.epoxy_data_binding 31 | kapt Libs.epoxy_kapt 32 | } -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle.kts.kts.kts.kts.kts.kts.kts.kts. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /app/src/androidTest/java/com/emamagic/android_multi_module/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.emamagic.android_multi_module 2 | 3 | import androidx.test.platform.app.InstrumentationRegistry 4 | import androidx.test.ext.junit.runners.AndroidJUnit4 5 | 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | import org.junit.Assert.* 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * See [testing documentation](http://d.android.com/tools/testing). 15 | */ 16 | @RunWith(AndroidJUnit4::class) 17 | class ExampleInstrumentedTest { 18 | @Test 19 | fun useAppContext() { 20 | // Context of the app under test. 21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 22 | assertEquals("com.emamagic.limonad_android", appContext.packageName) 23 | } 24 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 15 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/emamagic/android_multi_module/App.kt: -------------------------------------------------------------------------------- 1 | package com.emamagic.android_multi_module 2 | 3 | import androidx.lifecycle.Lifecycle 4 | import androidx.lifecycle.LifecycleEventObserver 5 | import androidx.lifecycle.LifecycleOwner 6 | import androidx.lifecycle.ProcessLifecycleOwner 7 | import androidx.multidex.MultiDexApplication 8 | import com.emamagic.android_multi_module.di.AppComponentProvider 9 | import com.emamagic.android_multi_module.di.SubComponents 10 | import com.emamagic.core.interfaces.OnAppVisibility 11 | 12 | class App: MultiDexApplication(), SubComponents, LifecycleEventObserver, OnAppVisibility { 13 | 14 | private var isInBackground = false 15 | var appVisibilityListener: OnAppVisibilityListener? = null 16 | 17 | override fun onCreate() { 18 | super.onCreate() 19 | AppComponentProvider.provideAppComponent(this) 20 | ProcessLifecycleOwner.get().lifecycle.addObserver(this) 21 | } 22 | 23 | override fun appIsInBackground(): Boolean = isInBackground 24 | 25 | override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) { 26 | isInBackground = 27 | !(event == Lifecycle.Event.ON_CREATE || event == Lifecycle.Event.ON_RESUME || event == Lifecycle.Event.ON_START) 28 | appVisibilityListener?.appVisibility(isInBackground) 29 | } 30 | 31 | 32 | } -------------------------------------------------------------------------------- /app/src/main/java/com/emamagic/android_multi_module/NoInternetAvailableDialog.kt: -------------------------------------------------------------------------------- 1 | package com.emamagic.android_multi_module 2 | 3 | import android.os.Bundle 4 | import android.util.Log 5 | import android.view.* 6 | import androidx.databinding.DataBindingUtil 7 | import androidx.fragment.app.DialogFragment 8 | import androidx.navigation.fragment.findNavController 9 | import com.emamagic.android_multi_module.R 10 | import com.emamagic.android_multi_module.databinding.FragmentNoInternetAvailableBinding 11 | 12 | class NoInternetAvailableDialog: DialogFragment() { 13 | 14 | private var _binding: FragmentNoInternetAvailableBinding? = null 15 | private val binding: FragmentNoInternetAvailableBinding get() = _binding!! 16 | 17 | override fun onCreate(savedInstanceState: Bundle?) { 18 | setStyle(STYLE_NORMAL, R.style.AppTheme_FullScreenDialog) 19 | super.onCreate(savedInstanceState) 20 | } 21 | 22 | override fun onCreateView( 23 | inflater: LayoutInflater, 24 | container: ViewGroup?, 25 | savedInstanceState: Bundle? 26 | ): View { 27 | _binding = DataBindingUtil.inflate(inflater, 28 | R.layout.fragment_no_internet_available, container, false) 29 | binding.lifecycleOwner = viewLifecycleOwner 30 | return binding.root 31 | } 32 | 33 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 34 | super.onViewCreated(view, savedInstanceState) 35 | binding.btnOk.setOnClickListener { findNavController().navigateUp() } 36 | } 37 | 38 | 39 | override fun onDestroyView() { 40 | _binding = null 41 | super.onDestroyView() 42 | } 43 | 44 | } -------------------------------------------------------------------------------- /app/src/main/java/com/emamagic/android_multi_module/OnAppVisibilityListener.kt: -------------------------------------------------------------------------------- 1 | package com.emamagic.android_multi_module 2 | 3 | interface OnAppVisibilityListener { 4 | fun appVisibility(isInBackground: Boolean) 5 | } -------------------------------------------------------------------------------- /app/src/main/java/com/emamagic/android_multi_module/di/AppComponent.kt: -------------------------------------------------------------------------------- 1 | package com.emamagic.android_multi_module.di 2 | 3 | import android.app.Application 4 | import com.emamagic.core.base.ViewModelFactoryBinderModule 5 | import com.emamagic.home.di.HomeComponent 6 | import com.emamagic.movie.di.MovieComponent 7 | import com.emamagic.movies.di.MoviesComponent 8 | import com.emamagic.network.di.RetrofitModule 9 | import com.emamagic.repository.di.RepositoryBinderModule 10 | import dagger.BindsInstance 11 | import dagger.Component 12 | import javax.inject.Singleton 13 | 14 | @Singleton 15 | @Component( 16 | modules = [ 17 | RetrofitModule::class, 18 | RepositoryBinderModule::class, 19 | SubComponentsModule::class, 20 | ViewModelFactoryBinderModule::class 21 | ] 22 | ) 23 | interface AppComponent { 24 | 25 | // Save the reference of factories in the app component for creating sub components 26 | fun homeComponent(): HomeComponent.Factory 27 | fun moviesComponent(): MoviesComponent.Factory 28 | fun movieComponent(): MovieComponent.Factory 29 | 30 | @Component.Factory 31 | interface Factory { 32 | fun create(@BindsInstance application: Application): AppComponent 33 | } 34 | 35 | } -------------------------------------------------------------------------------- /app/src/main/java/com/emamagic/android_multi_module/di/AppComponentProvider.kt: -------------------------------------------------------------------------------- 1 | package com.emamagic.android_multi_module.di 2 | 3 | import android.app.Application 4 | 5 | object AppComponentProvider { 6 | private lateinit var appComponent: AppComponent 7 | 8 | @JvmStatic 9 | fun appComponent() = appComponent 10 | 11 | fun provideAppComponent(application: Application) { 12 | appComponent = DaggerAppComponent.factory().create(application) 13 | } 14 | } -------------------------------------------------------------------------------- /app/src/main/java/com/emamagic/android_multi_module/di/SubComponents.kt: -------------------------------------------------------------------------------- 1 | package com.emamagic.android_multi_module.di 2 | 3 | import com.emamagic.home.di.HomeComponent 4 | import com.emamagic.home.di.HomeComponentProvider 5 | import com.emamagic.movie.di.MovieComponent 6 | import com.emamagic.movie.di.MovieComponentProvider 7 | import com.emamagic.movies.di.MoviesComponent 8 | import com.emamagic.movies.di.MoviesComponentProvider 9 | 10 | interface SubComponents: HomeComponentProvider, MoviesComponentProvider, MovieComponentProvider { 11 | 12 | override fun provideHomeComponent(): HomeComponent = 13 | AppComponentProvider.appComponent().homeComponent().create() 14 | 15 | override fun provideMoviesComponent(): MoviesComponent = 16 | AppComponentProvider.appComponent().moviesComponent().create() 17 | 18 | override fun provideMovieComponent(): MovieComponent = 19 | AppComponentProvider.appComponent().movieComponent().create() 20 | 21 | } -------------------------------------------------------------------------------- /app/src/main/java/com/emamagic/android_multi_module/di/SubComponentsModule.kt: -------------------------------------------------------------------------------- 1 | package com.emamagic.android_multi_module.di 2 | 3 | import com.emamagic.home.di.HomeComponent 4 | import com.emamagic.movie.di.MovieComponent 5 | import com.emamagic.movies.di.MoviesComponent 6 | import dagger.Module 7 | 8 | @Module( 9 | subcomponents = [ 10 | HomeComponent::class, 11 | MoviesComponent::class, 12 | MovieComponent::class 13 | ] 14 | ) 15 | class SubComponentsModule -------------------------------------------------------------------------------- /app/src/main/res/drawable/rounded_btn_blue.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/splash_screen.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_no_internet_available.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 14 | 27 | 28 |