├── .gitignore ├── .gradle └── vcs-1 │ └── gc.properties ├── .idea ├── codeStyles │ └── codeStyleConfig.xml ├── jarRepositories.xml ├── libraries │ └── Gradle__javax_annotation_jsr250_api_1_0_jar.xml ├── runConfigurations.xml └── vcs.xml ├── CONTRIBUTING.md ├── LICENSE.md ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── lyhoangvinh │ │ └── simple │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── lyhoangvinh │ │ │ └── simple │ │ │ ├── Constants.kt │ │ │ ├── MyApplication.kt │ │ │ ├── data │ │ │ ├── DataBaseManager.kt │ │ │ ├── SharedPrefs.kt │ │ │ ├── dao │ │ │ │ ├── BaseDao.kt │ │ │ │ ├── CategoriesDao.kt │ │ │ │ ├── CollectionDao.kt │ │ │ │ ├── IssuesDao.kt │ │ │ │ ├── SearchHistoryDao.kt │ │ │ │ └── VideosDao.kt │ │ │ ├── entities │ │ │ │ ├── BitmapWithQuality.kt │ │ │ │ ├── Connection.kt │ │ │ │ ├── DataEmpty.kt │ │ │ │ ├── EntinyDiff.kt │ │ │ │ ├── Entities.kt │ │ │ │ ├── ErrorEntity.kt │ │ │ │ ├── OptionEntity.kt │ │ │ │ ├── State.kt │ │ │ │ ├── Status.kt │ │ │ │ ├── VisibilityView.kt │ │ │ │ ├── avgle │ │ │ │ │ ├── Category.kt │ │ │ │ │ ├── Collection.kt │ │ │ │ │ ├── MergedData.kt │ │ │ │ │ ├── SearchHistory.kt │ │ │ │ │ └── Video.kt │ │ │ │ └── comic │ │ │ │ │ ├── Comics.kt │ │ │ │ │ ├── ImageAll.kt │ │ │ │ │ ├── Issues.kt │ │ │ │ │ └── Volume.kt │ │ │ ├── itemviewmodel │ │ │ │ ├── CategoryItem.kt │ │ │ │ ├── CollectionBannerItem.kt │ │ │ │ ├── CollectionBottomItem.kt │ │ │ │ ├── DividerItem.kt │ │ │ │ ├── SearchDataItem.kt │ │ │ │ ├── SearchHistoryItem.kt │ │ │ │ ├── SearchItem.kt │ │ │ │ ├── TitleSeeAllItem.kt │ │ │ │ └── VideoItem.kt │ │ │ ├── repo │ │ │ │ ├── BaseRepo.kt │ │ │ │ ├── CollectionsRepo.kt │ │ │ │ ├── HomeRepo.kt │ │ │ │ ├── ImageRepo.kt │ │ │ │ ├── IssuesRepo.kt │ │ │ │ ├── SearchPagedRepo.kt │ │ │ │ ├── SearchRepo.kt │ │ │ │ ├── VideoRepo.kt │ │ │ │ └── impl │ │ │ │ │ ├── CollectionsRepoImpl.kt │ │ │ │ │ ├── HomeRepoImpl.kt │ │ │ │ │ ├── ImageRepoImpl.kt │ │ │ │ │ ├── IssuesRepoImpl.kt │ │ │ │ │ ├── SearchPagedRepoImpl.kt │ │ │ │ │ ├── SearchRepoImpl.kt │ │ │ │ │ └── VideoRepoImpl.kt │ │ │ ├── response │ │ │ │ ├── BaseResponseAvgle.kt │ │ │ │ ├── BaseResponseComic.kt │ │ │ │ ├── CategoriesResponse.kt │ │ │ │ ├── CollectionsResponseAvgle.kt │ │ │ │ ├── ResponseBiZip.kt │ │ │ │ ├── ResponseFourZip.kt │ │ │ │ ├── ResponseTriper.kt │ │ │ │ └── VideosResponseAvgle.kt │ │ │ ├── services │ │ │ │ ├── AvgleService.kt │ │ │ │ └── ComicVineService.kt │ │ │ ├── source │ │ │ │ ├── avg │ │ │ │ │ ├── CollectionDataSource.kt │ │ │ │ │ ├── CollectionRxDataSource.kt │ │ │ │ │ ├── SearchDataSource.kt │ │ │ │ │ └── VideoDataSource.kt │ │ │ │ ├── base │ │ │ │ │ ├── BasePositionalDataSource.kt │ │ │ │ │ ├── PlainResponseBiConsumer.kt │ │ │ │ │ ├── PlainResponseFourConsumer.kt │ │ │ │ │ ├── PlainResponseTriperConsumer.kt │ │ │ │ │ ├── RequestState.kt │ │ │ │ │ ├── Resource.kt │ │ │ │ │ ├── SimpleNetworkBoundSource.kt │ │ │ │ │ ├── SimpleNetworkBoundSourceBiRemote.kt │ │ │ │ │ ├── SimpleNetworkBoundSourceFourRemote.kt │ │ │ │ │ ├── local │ │ │ │ │ │ └── BaseLocalPageKeyedDataSource.kt │ │ │ │ │ └── service │ │ │ │ │ │ ├── BaseItemKeyedDataComicSource.kt │ │ │ │ │ │ ├── BasePageKeyedDataComicSource.kt │ │ │ │ │ │ ├── BasePageKeyedDataSource.kt │ │ │ │ │ │ └── BaseRxPageKeyedDataSource.kt │ │ │ │ └── comic │ │ │ │ │ ├── ComicLocalPagingDataSource.kt │ │ │ │ │ └── ComicPagingDataSource.kt │ │ │ └── typecoverter │ │ │ │ ├── ImageTypeConverter.kt │ │ │ │ └── VolumeTypeConverter.kt │ │ │ ├── di │ │ │ ├── ViewModelFactory.kt │ │ │ ├── component │ │ │ │ └── AppComponent.kt │ │ │ ├── module │ │ │ │ ├── AppModule.kt │ │ │ │ ├── BaseActivityModule.kt │ │ │ │ ├── BaseFragmentModule.kt │ │ │ │ ├── BuildersModule.kt │ │ │ │ ├── DataModule.kt │ │ │ │ ├── NetworkModule.kt │ │ │ │ ├── RepositoryModule.kt │ │ │ │ └── ViewModelModule.kt │ │ │ └── qualifier │ │ │ │ ├── ActivityContext.kt │ │ │ │ ├── ActivityFragmentManager.kt │ │ │ │ ├── ApplicationContext.kt │ │ │ │ ├── ChildFragmentManager.kt │ │ │ │ ├── OkHttpAuth.kt │ │ │ │ ├── OkHttpNoAuth.kt │ │ │ │ └── ViewModelKey.kt │ │ │ ├── receiver │ │ │ └── NetworkReceiver.kt │ │ │ ├── ui │ │ │ ├── base │ │ │ │ ├── activity │ │ │ │ │ ├── BaseActivity.kt │ │ │ │ │ ├── BaseSingleFragmentActivity.kt │ │ │ │ │ ├── BaseViewModelActivity.kt │ │ │ │ │ ├── BaseViewModelPagingActivity.kt │ │ │ │ │ └── BaseViewModelRecyclerViewActivity.kt │ │ │ │ ├── adapter │ │ │ │ │ ├── BaseItemPagerAdapter.kt │ │ │ │ │ ├── BaseItemSimpleAdapter.kt │ │ │ │ │ ├── BaseItemSimpleViewHolder.kt │ │ │ │ │ ├── BaseItemViewHolder.kt │ │ │ │ │ ├── BasePagedAdapter.kt │ │ │ │ │ ├── BaseSimpleAdapter.kt │ │ │ │ │ ├── BaseViewHolder.kt │ │ │ │ │ └── ItemViewModel.kt │ │ │ │ ├── fragment │ │ │ │ │ ├── BaseFragment.kt │ │ │ │ │ ├── BaseViewModelFragment.kt │ │ │ │ │ ├── BaseViewModelPagingFragment.kt │ │ │ │ │ └── BaseViewModelRecyclerViewFragment.kt │ │ │ │ ├── interfaces │ │ │ │ │ ├── LoadMoreable.kt │ │ │ │ │ ├── OnClickable.kt │ │ │ │ │ ├── PlainConsumer.kt │ │ │ │ │ ├── PlainEntitiesPagingConsumer.kt │ │ │ │ │ ├── PlainPagingConsumer.kt │ │ │ │ │ ├── Refreshable.kt │ │ │ │ │ └── UiRefreshable.kt │ │ │ │ └── viewmodel │ │ │ │ │ ├── BaseListDataViewModel.kt │ │ │ │ │ ├── BasePagingViewModel.kt │ │ │ │ │ └── BaseViewModel.kt │ │ │ ├── features │ │ │ │ ├── avg │ │ │ │ │ ├── detail │ │ │ │ │ │ ├── DetailActivity.kt │ │ │ │ │ │ ├── DetailModule.kt │ │ │ │ │ │ └── DetailViewModel.kt │ │ │ │ │ ├── main │ │ │ │ │ │ ├── AvgActivity.kt │ │ │ │ │ │ ├── AvgActivityModule.kt │ │ │ │ │ │ ├── collection │ │ │ │ │ │ │ ├── CollectionFragment.kt │ │ │ │ │ │ │ ├── CollectionModule.kt │ │ │ │ │ │ │ ├── CollectionViewModel.kt │ │ │ │ │ │ │ └── CollectionsAdapter.kt │ │ │ │ │ │ ├── home │ │ │ │ │ │ │ ├── HomeFragment.kt │ │ │ │ │ │ │ ├── HomeFragmentModule.kt │ │ │ │ │ │ │ ├── HomeViewModel.kt │ │ │ │ │ │ │ └── adapter │ │ │ │ │ │ │ │ ├── inside │ │ │ │ │ │ │ │ ├── BannerImagesFragment.kt │ │ │ │ │ │ │ │ ├── BannerImagesModule.kt │ │ │ │ │ │ │ │ ├── CategoriesAdapter.kt │ │ │ │ │ │ │ │ ├── CollectionHomeAdapter.kt │ │ │ │ │ │ │ │ ├── ImageBannerAdapter.kt │ │ │ │ │ │ │ │ └── VideosHomeAdapter.kt │ │ │ │ │ │ │ │ ├── paging │ │ │ │ │ │ │ │ └── HomeAdapter.kt │ │ │ │ │ │ │ │ └── simple │ │ │ │ │ │ │ │ └── HomeSimpleAdapter.kt │ │ │ │ │ │ └── video │ │ │ │ │ │ │ ├── VideoAdapter.kt │ │ │ │ │ │ │ ├── VideoFragment.kt │ │ │ │ │ │ │ ├── VideoFragmentModule.kt │ │ │ │ │ │ │ └── VideoViewModel.kt │ │ │ │ │ └── search │ │ │ │ │ │ ├── local │ │ │ │ │ │ ├── SearchActivity.kt │ │ │ │ │ │ ├── SearchAdapter.kt │ │ │ │ │ │ ├── SearchModule.kt │ │ │ │ │ │ └── SearchViewModel.kt │ │ │ │ │ │ └── paging │ │ │ │ │ │ ├── SearchPagedActivity.kt │ │ │ │ │ │ ├── SearchPagedAdapter.kt │ │ │ │ │ │ ├── SearchPagedModule.kt │ │ │ │ │ │ ├── SearchPagedViewModel.kt │ │ │ │ │ │ └── suggestion │ │ │ │ │ │ └── SearchSuggestionsAdapter.kt │ │ │ │ ├── comic │ │ │ │ │ ├── detail │ │ │ │ │ │ ├── ImageDetailActivity.kt │ │ │ │ │ │ ├── ImageDetailModule.kt │ │ │ │ │ │ └── ImageDetailViewModel.kt │ │ │ │ │ ├── testactivity │ │ │ │ │ │ ├── ComicActivity.kt │ │ │ │ │ │ ├── ComicActivityModule.kt │ │ │ │ │ │ ├── ComicAdapter.kt │ │ │ │ │ │ └── ComicViewModel.kt │ │ │ │ │ ├── testfragment │ │ │ │ │ │ ├── ComicFragment.kt │ │ │ │ │ │ ├── ComicFragmentModule.kt │ │ │ │ │ │ ├── ComicSingleActivity.kt │ │ │ │ │ │ ├── ComicSingleActivityModule.kt │ │ │ │ │ │ └── ComicSingleViewModel.kt │ │ │ │ │ └── testpaging │ │ │ │ │ │ ├── ComicPagingActivity.kt │ │ │ │ │ │ ├── ComicPagingActivityModule.kt │ │ │ │ │ │ └── ComicPagingViewModel.kt │ │ │ │ ├── comicavg │ │ │ │ │ ├── ComicAvgActivity.kt │ │ │ │ │ ├── ComicAvgModule.kt │ │ │ │ │ ├── ComicAvgPagerAdapter.kt │ │ │ │ │ ├── ComicAvgViewModel.kt │ │ │ │ │ └── portal │ │ │ │ │ │ ├── PortalAdapter.kt │ │ │ │ │ │ ├── PortalFragment.kt │ │ │ │ │ │ ├── PortalModule.kt │ │ │ │ │ │ └── PortalViewModel.kt │ │ │ │ ├── setting │ │ │ │ │ ├── SettingActivity.kt │ │ │ │ │ ├── SettingAdapter.kt │ │ │ │ │ ├── SettingModule.kt │ │ │ │ │ └── SettingViewModel.kt │ │ │ │ └── splash │ │ │ │ │ ├── SplashActivity.kt │ │ │ │ │ ├── SplashModule.kt │ │ │ │ │ └── SplashViewModel.kt │ │ │ ├── observableUi │ │ │ │ ├── ConnectionObservable.kt │ │ │ │ └── StateObservable.kt │ │ │ └── widget │ │ │ │ ├── AspectConerImageView.java │ │ │ │ ├── MyRecycleView.java │ │ │ │ ├── RotateLoading.java │ │ │ │ ├── newton │ │ │ │ ├── CradleBall.java │ │ │ │ └── NewtonCradleLoading.java │ │ │ │ └── recycleview │ │ │ │ ├── CONST_SNAP.java │ │ │ │ ├── EndlessRecyclerOnScrollListener.java │ │ │ │ ├── GravitySnapHelper.java │ │ │ │ ├── HorizontalSpaceItemDecoration.java │ │ │ │ ├── MyLinearHelper.java │ │ │ │ ├── MyOrientationHelper.java │ │ │ │ ├── MySnapHelper.java │ │ │ │ ├── RecyclerTabLayout.java │ │ │ │ └── VerticalSpaceItemDecoration.java │ │ │ └── utils │ │ │ ├── AutoClearedValue.kt │ │ │ ├── BaseSharedPreferenceLiveData.kt │ │ │ ├── BindingUtils.kt │ │ │ ├── ConnectionLiveData.kt │ │ │ ├── CustomImageLoadTarget.kt │ │ │ ├── Extensions.kt │ │ │ ├── ImageFetcherSingleSubscribe.kt │ │ │ ├── NavigatorHelper.kt │ │ │ ├── NetworkUtils.kt │ │ │ ├── OptionSharedPreferenceLiveData.kt │ │ │ ├── PicassoRxExtensions.kt │ │ │ ├── SafeMutableLiveData.kt │ │ │ ├── ServiceExtensions.kt │ │ │ ├── SingletonHolder.kt │ │ │ ├── TransitionUtil.kt │ │ │ └── rx │ │ │ ├── RxBus.kt │ │ │ └── rxlifecycle │ │ │ ├── AndroidLifecycle.java │ │ │ ├── Functions.java │ │ │ ├── LifecycleProvider.java │ │ │ ├── LifecycleTransformer.java │ │ │ ├── OutsideLifecycleException.java │ │ │ ├── Preconditions.java │ │ │ ├── RxLifecycle.java │ │ │ └── RxLifecycleAndroidLifecycle.java │ └── res │ │ ├── anim │ │ ├── fade_in.xml │ │ ├── fade_out.xml │ │ ├── item_animation_fall_down.xml │ │ └── layout_animation_fall_down.xml │ │ ├── drawable-hdpi │ │ ├── ic_placeholder_rectangle_200px.png │ │ └── kotlin_logo.png │ │ ├── drawable-mdpi │ │ ├── ic_placeholder_rectangle_200px.png │ │ └── kotlin_logo.png │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable-xhdpi │ │ ├── ic_placeholder_rectangle_200px.png │ │ └── kotlin_logo.png │ │ ├── drawable-xxhdpi │ │ ├── ic_placeholder_rectangle_200px.png │ │ └── kotlin_logo.png │ │ ├── drawable-xxxhdpi │ │ ├── ic_placeholder_rectangle_200px.png │ │ └── kotlin_logo.png │ │ ├── drawable │ │ ├── bg_corner.xml │ │ ├── bg_corner_gray_thin.xml │ │ ├── bg_corner_normal.xml │ │ ├── bg_corner_search.xml │ │ ├── bg_corner_selected.xml │ │ ├── bg_empty_corner.xml │ │ ├── bg_gradient_evening_sunshine.xml │ │ ├── bg_oval.xml │ │ ├── bg_oval_shadow.xml │ │ ├── bg_red_status.xml │ │ ├── ic_access_time_black_24dp.xml │ │ ├── ic_arrow_back_black_24dp.xml │ │ ├── ic_cancel_button.xml │ │ ├── ic_check_black_24dp.xml │ │ ├── ic_content_copy_24dp.xml │ │ ├── ic_do_not_disturb_black_24dp.xml │ │ ├── ic_home_black_24dp.xml │ │ ├── ic_launcher_background.xml │ │ ├── ic_not_found.xml │ │ ├── ic_refresh_24dp.xml │ │ ├── ic_search_black_24dp.xml │ │ ├── ic_settings_black_24dp.xml │ │ ├── ic_state_network_offline.xml │ │ ├── ic_toc_black_24dp.xml │ │ ├── ic_up_rcv.xml │ │ ├── ic_wifi.xml │ │ ├── linear_gradient.xml │ │ ├── poster_show_not_available.png │ │ └── tags_blue_rounded_corners.xml │ │ ├── layout │ │ ├── activity_comic.xml │ │ ├── activity_comic_avg.xml │ │ ├── activity_detail.xml │ │ ├── activity_image_detail.xml │ │ ├── activity_paging_test.xml │ │ ├── activity_search.xml │ │ ├── activity_setting.xml │ │ ├── activity_splash.xml │ │ ├── container.xml │ │ ├── empty_layout.xml │ │ ├── fragment_banner_images.xml │ │ ├── fragment_collection.xml │ │ ├── fragment_home.xml │ │ ├── fragment_portal.xml │ │ ├── fragment_test.xml │ │ ├── fragment_video.xml │ │ ├── item_categories.xml │ │ ├── item_collection.xml │ │ ├── item_collection_home.xml │ │ ├── item_comics.xml │ │ ├── item_data_search.xml │ │ ├── item_history.xml │ │ ├── item_loading.xml │ │ ├── item_portal.xml │ │ ├── item_search.xml │ │ ├── item_setting.xml │ │ ├── item_title_see_all.xml │ │ ├── item_video.xml │ │ ├── item_video_home.xml │ │ ├── layout_state_network_off.xml │ │ ├── newton_cradle_loading.xml │ │ ├── progress_dialog.xml │ │ ├── tab_text_view.xml │ │ ├── toolbar_back.xml │ │ ├── view_banner.xml │ │ ├── view_divider.xml │ │ ├── view_error_connection.xml │ │ ├── view_no_data.xml │ │ ├── view_rcy_horizontal.xml │ │ ├── view_recyclerview.xml │ │ └── view_scroll_top.xml │ │ ├── menu │ │ ├── menu_comic_avg.xml │ │ ├── menu_home.xml │ │ └── menu_setting.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── transition │ │ └── changebounds_with_arcmotion.xml │ │ └── values │ │ ├── attrs.xml │ │ ├── colors.xml │ │ ├── dimen.xml │ │ ├── dimen_image_ratio.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── lyhoangvinh │ └── simple │ └── ExampleUnitTest.kt ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew.bat └── settings.gradle /.gradle/vcs-1/gc.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lyhoangvinh/kotlin-mvvm-architecture/cd0abec00c623e88e950f5812454f37d07074b93/.gradle/vcs-1/gc.properties -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | 29 | 30 | -------------------------------------------------------------------------------- /.idea/libraries/Gradle__javax_annotation_jsr250_api_1_0_jar.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | 1. Fork it! 4 | 2. Checkout the development branch: `git checkout development` 5 | 3. Create your feature branch: `git checkout -b my-new-feature` 6 | 4. Add your changes to the index: `git add .` 7 | 5. Commit your changes: `git commit -m 'Add some feature'` 8 | 6. Push to the branch: `git push origin my-new-feature` 9 | 7. Submit a pull request against the `development` branch 10 | 11 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /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. 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 22 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/lyhoangvinh/simple/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.lyhoangvinh.simple 2 | 3 | import androidx.test.InstrumentationRegistry 4 | import androidx.test.runner.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.getTargetContext() 22 | assertEquals("com.lyhoangvinh.simple", appContext.packageName) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/com/lyhoangvinh/simple/Constants.kt: -------------------------------------------------------------------------------- 1 | package com.lyhoangvinh.simple 2 | 3 | class Constants { 4 | companion object { 5 | const val COMIC_ENDPOINT = BuildConfig.COMIC_ENDPOINT 6 | const val AVGLE_ENDPOINT = BuildConfig.AVGLE_ENDPOINT 7 | const val KEY = BuildConfig.API_KEY 8 | const val EXTRA_DATA = "EXTRA_DATA" 9 | const val PORTAL = "KEYWORD_PORTAL" 10 | 11 | //video 12 | const val TYPE_ALL = 0 13 | const val TYPE_HOME = 1 14 | const val TYPE_SEARCH = 2 15 | 16 | //collection 17 | const val TYPE_HOME_BANNER = 1 18 | const val TYPE_HOME_BOTTOM = 2 19 | 20 | //options 21 | const val OPTIONS = "option_open" 22 | const val OPTIONS_1 = 0 23 | const val OPTIONS_2 = 1 24 | const val OPTIONS_3 = 2 25 | 26 | //quality 27 | const val THUMB = 0 28 | const val MEDIUM = 1 29 | const val SUPPER = 2 30 | } 31 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lyhoangvinh/simple/MyApplication.kt: -------------------------------------------------------------------------------- 1 | package com.lyhoangvinh.simple 2 | import android.content.Context 3 | import android.util.DisplayMetrics 4 | import android.view.WindowManager 5 | import com.lyhoangvinh.simple.di.component.DaggerAppComponent 6 | import dagger.android.AndroidInjector 7 | import dagger.android.support.DaggerApplication 8 | 9 | class MyApplication : DaggerApplication() { 10 | override fun applicationInjector(): AndroidInjector = 11 | DaggerAppComponent.builder().create(this) 12 | 13 | private var mDeviceWidth = 0 14 | 15 | companion object { 16 | private lateinit var instance: MyApplication 17 | 18 | fun getInstance() = instance 19 | } 20 | 21 | override fun onCreate() { 22 | super.onCreate() 23 | instance = this 24 | 25 | val displayMetrics = DisplayMetrics() 26 | val windowManager = applicationContext.getSystemService(Context.WINDOW_SERVICE) as WindowManager 27 | windowManager.defaultDisplay?.getMetrics(displayMetrics) 28 | mDeviceWidth = displayMetrics.widthPixels 29 | } 30 | 31 | fun getDeviceWidth(): Int { 32 | return mDeviceWidth 33 | } 34 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lyhoangvinh/simple/data/DataBaseManager.kt: -------------------------------------------------------------------------------- 1 | package com.lyhoangvinh.simple.data 2 | 3 | import androidx.room.Database 4 | import androidx.room.RoomDatabase 5 | import androidx.room.TypeConverters 6 | import com.lyhoangvinh.simple.data.dao.* 7 | import com.lyhoangvinh.simple.data.entities.avgle.Category 8 | import com.lyhoangvinh.simple.data.entities.avgle.Collection 9 | import com.lyhoangvinh.simple.data.entities.avgle.SearchHistory 10 | import com.lyhoangvinh.simple.data.entities.avgle.Video 11 | import com.lyhoangvinh.simple.data.entities.comic.Comics 12 | import com.lyhoangvinh.simple.data.entities.comic.Issues 13 | import com.lyhoangvinh.simple.data.typecoverter.ImageTypeConverter 14 | import com.lyhoangvinh.simple.data.typecoverter.VolumeTypeConverter 15 | 16 | @Database( 17 | entities = [Comics::class, Issues::class, Category::class, Collection::class, Video::class, SearchHistory::class], 18 | version = 2, 19 | exportSchema = false 20 | ) 21 | @TypeConverters(ImageTypeConverter::class, VolumeTypeConverter::class) 22 | abstract class DatabaseManager : RoomDatabase() { 23 | 24 | abstract fun issuesDao(): IssuesDao 25 | 26 | abstract fun categoriesDao(): CategoriesDao 27 | 28 | abstract fun collectionDao(): CollectionDao 29 | 30 | abstract fun videosDao(): VideosDao 31 | 32 | abstract fun searchHistoryDao(): SearchHistoryDao 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/com/lyhoangvinh/simple/data/dao/BaseDao.kt: -------------------------------------------------------------------------------- 1 | package com.lyhoangvinh.simple.data.dao 2 | 3 | import androidx.room.* 4 | 5 | interface BaseDao { 6 | 7 | @Insert(onConflict = OnConflictStrategy.REPLACE) 8 | fun insert(t: T) 9 | 10 | @Insert(onConflict = OnConflictStrategy.REPLACE) 11 | fun insertList(list: List) 12 | 13 | @Update(onConflict = OnConflictStrategy.REPLACE) 14 | fun update(t: T) 15 | 16 | @Delete 17 | fun delete(t: T) 18 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lyhoangvinh/simple/data/dao/CategoriesDao.kt: -------------------------------------------------------------------------------- 1 | package com.lyhoangvinh.simple.data.dao 2 | 3 | import androidx.lifecycle.LiveData 4 | import androidx.paging.DataSource 5 | import androidx.room.* 6 | import com.lyhoangvinh.simple.data.entities.avgle.Category 7 | 8 | @Dao 9 | interface CategoriesDao : BaseDao { 10 | 11 | @Insert(onConflict = OnConflictStrategy.IGNORE) 12 | fun insertIgnore(entities: List) 13 | 14 | @Update(onConflict = OnConflictStrategy.IGNORE) 15 | fun updateIgnore(entities: List) 16 | 17 | @Query("DELETE FROM CATEGORY") 18 | fun deleteAll() 19 | 20 | @Query("SELECT * FROM CATEGORY") 21 | fun liveData(): LiveData> 22 | 23 | @Query("SELECT * FROM CATEGORY") 24 | fun getData() : List 25 | 26 | @Query("SELECT * FROM CATEGORY") 27 | fun liveDataFactory(): DataSource.Factory 28 | 29 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lyhoangvinh/simple/data/dao/CollectionDao.kt: -------------------------------------------------------------------------------- 1 | package com.lyhoangvinh.simple.data.dao 2 | 3 | import androidx.lifecycle.LiveData 4 | import androidx.paging.DataSource 5 | import androidx.room.* 6 | import com.lyhoangvinh.simple.data.entities.avgle.Collection 7 | 8 | @Dao 9 | interface CollectionDao : BaseDao { 10 | 11 | @Insert(onConflict = OnConflictStrategy.IGNORE) 12 | fun insertIgnore(entities: List) 13 | 14 | @Update(onConflict = OnConflictStrategy.IGNORE) 15 | fun updateIgnore(entities: List) 16 | 17 | @Query("DELETE FROM COLLECTION") 18 | fun deleteAll() 19 | 20 | @Query("SELECT * FROM COLLECTION") 21 | fun liveData(): LiveData> 22 | 23 | @Query("SELECT * FROM COLLECTION WHERE type=:type") 24 | fun liveDataFromType(type: Int): LiveData> 25 | 26 | @Query("DELETE FROM COLLECTION WHERE type=:value") 27 | fun deleteType(value: Int) 28 | 29 | @Query("SELECT * FROM COLLECTION WHERE type=:type") 30 | fun liveDataFactoryFromType(type: Int): DataSource.Factory 31 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lyhoangvinh/simple/data/dao/IssuesDao.kt: -------------------------------------------------------------------------------- 1 | package com.lyhoangvinh.simple.data.dao 2 | 3 | import androidx.lifecycle.LiveData 4 | import androidx.paging.DataSource 5 | import androidx.room.* 6 | import com.lyhoangvinh.simple.data.entities.comic.Issues 7 | 8 | 9 | @Dao 10 | interface IssuesDao : BaseDao { 11 | @Query("SELECT * FROM Issues") 12 | fun liveData(): LiveData> 13 | 14 | @Query("SELECT * FROM Issues") 15 | fun getAll(): List 16 | 17 | @Query("SELECT * FROM Issues") 18 | fun getAllPaged(): DataSource.Factory 19 | 20 | @Insert 21 | fun inserts(list: List) 22 | 23 | @Insert(onConflict = OnConflictStrategy.IGNORE) 24 | fun insertIgnore(entities: List) 25 | 26 | @Update(onConflict = OnConflictStrategy.IGNORE) 27 | fun updateIgnore(entities: List) 28 | 29 | @Query("DELETE FROM Issues") 30 | fun removeAll() 31 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lyhoangvinh/simple/data/dao/SearchHistoryDao.kt: -------------------------------------------------------------------------------- 1 | package com.lyhoangvinh.simple.data.dao 2 | 3 | import androidx.paging.DataSource 4 | import androidx.room.Dao 5 | import androidx.room.Query 6 | import com.lyhoangvinh.simple.data.entities.avgle.SearchHistory 7 | import io.reactivex.Single 8 | 9 | @Dao 10 | interface SearchHistoryDao : BaseDao { 11 | @Query("SELECT * FROM SearchHistory") 12 | fun liveDataFactory(): DataSource.Factory 13 | 14 | @Query("SELECT * FROM SearchHistory WHERE keyword LIKE :query ") 15 | fun search(query: String) : Single> 16 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lyhoangvinh/simple/data/dao/VideosDao.kt: -------------------------------------------------------------------------------- 1 | package com.lyhoangvinh.simple.data.dao 2 | 3 | import androidx.lifecycle.LiveData 4 | import androidx.paging.DataSource 5 | import androidx.room.* 6 | import com.lyhoangvinh.simple.data.entities.avgle.Video 7 | 8 | @Dao 9 | interface VideosDao : BaseDao