From 2a230b2e4472ff2d60cb358332d0f1be66a1fed7 Mon Sep 17 00:00:00 2001 From: dmersiyanov Date: Wed, 4 Dec 2019 14:30:26 +0300 Subject: [PATCH 1/5] added empty onboarding feature module --- app/build.gradle | 4 +-- features/feature_onboarding/.gitignore | 1 + features/feature_onboarding/build.gradle | 30 +++++++++++++++++++ .../feature_onboarding/consumer-rules.pro | 0 .../feature_onboarding/proguard-rules.pro | 21 +++++++++++++ .../ExampleInstrumentedTest.kt | 22 ++++++++++++++ .../src/main/AndroidManifest.xml | 1 + .../src/main/res/values/strings.xml | 3 ++ .../feature_onboarding/ExampleUnitTest.kt | 16 ++++++++++ settings.gradle | 2 +- 10 files changed, 96 insertions(+), 4 deletions(-) create mode 100644 features/feature_onboarding/.gitignore create mode 100644 features/feature_onboarding/build.gradle create mode 100644 features/feature_onboarding/consumer-rules.pro create mode 100644 features/feature_onboarding/proguard-rules.pro create mode 100644 features/feature_onboarding/src/androidTest/java/com/dmity/androidacademy/feature_onboarding/ExampleInstrumentedTest.kt create mode 100644 features/feature_onboarding/src/main/AndroidManifest.xml create mode 100644 features/feature_onboarding/src/main/res/values/strings.xml create mode 100644 features/feature_onboarding/src/test/java/com/dmity/androidacademy/feature_onboarding/ExampleUnitTest.kt diff --git a/app/build.gradle b/app/build.gradle index 319c2d2..819cbcd 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -80,7 +80,7 @@ dependencies { implementation "androidx.lifecycle:lifecycle-extensions:2.1.0" implementation "androidx.lifecycle:lifecycle-reactivestreams:2.1.0" implementation 'androidx.legacy:legacy-support-v4:1.0.0' - kapt "androidx.lifecycle:lifecycle-compiler:2.1.0" + implementation "androidx.lifecycle:lifecycle-common-java8:2.1.0" // Room implementation "androidx.room:room-runtime:2.2.2" @@ -92,9 +92,7 @@ dependencies { // Dagger 2 implementation dagger2.core -// implementation dagger2.androidSupport kapt dagger2.daggerCompiler -// kapt dagger2.androidCompiler implementation dagger2.jsr330 } diff --git a/features/feature_onboarding/.gitignore b/features/feature_onboarding/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/features/feature_onboarding/.gitignore @@ -0,0 +1 @@ +/build diff --git a/features/feature_onboarding/build.gradle b/features/feature_onboarding/build.gradle new file mode 100644 index 0000000..4c1c7e0 --- /dev/null +++ b/features/feature_onboarding/build.gradle @@ -0,0 +1,30 @@ +apply from: "$rootDir/base/deps_versions.gradle" +apply from: "$rootDir/base/config.gradle" + +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-android-extensions' +apply plugin: 'kotlin-kapt' + +androidExtensions { + experimental = true +} + +android { + compileSdkVersion config.currentSDK + + defaultConfig { + versionCode config.versionCode + versionName config.versionName + minSdkVersion config.minSDK + targetSdkVersion config.currentSDK + } +} + +dependencies { + implementation project(":domain") + + implementation appcompat + implementation coreKtx + +} \ No newline at end of file diff --git a/features/feature_onboarding/consumer-rules.pro b/features/feature_onboarding/consumer-rules.pro new file mode 100644 index 0000000..e69de29 diff --git a/features/feature_onboarding/proguard-rules.pro b/features/feature_onboarding/proguard-rules.pro new file mode 100644 index 0000000..f1b4245 --- /dev/null +++ b/features/feature_onboarding/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/features/feature_onboarding/src/androidTest/java/com/dmity/androidacademy/feature_onboarding/ExampleInstrumentedTest.kt b/features/feature_onboarding/src/androidTest/java/com/dmity/androidacademy/feature_onboarding/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..c911051 --- /dev/null +++ b/features/feature_onboarding/src/androidTest/java/com/dmity/androidacademy/feature_onboarding/ExampleInstrumentedTest.kt @@ -0,0 +1,22 @@ +package com.dmity.androidacademy.feature_onboarding + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.platform.app.InstrumentationRegistry +import org.junit.Assert.assertEquals +import org.junit.Test +import org.junit.runner.RunWith + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.dmity.androidacademy.feature_onboarding.test", appContext.packageName) + } +} diff --git a/features/feature_onboarding/src/main/AndroidManifest.xml b/features/feature_onboarding/src/main/AndroidManifest.xml new file mode 100644 index 0000000..63d0ed8 --- /dev/null +++ b/features/feature_onboarding/src/main/AndroidManifest.xml @@ -0,0 +1 @@ + diff --git a/features/feature_onboarding/src/main/res/values/strings.xml b/features/feature_onboarding/src/main/res/values/strings.xml new file mode 100644 index 0000000..c276601 --- /dev/null +++ b/features/feature_onboarding/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + feature_onboarding + diff --git a/features/feature_onboarding/src/test/java/com/dmity/androidacademy/feature_onboarding/ExampleUnitTest.kt b/features/feature_onboarding/src/test/java/com/dmity/androidacademy/feature_onboarding/ExampleUnitTest.kt new file mode 100644 index 0000000..8d006d0 --- /dev/null +++ b/features/feature_onboarding/src/test/java/com/dmity/androidacademy/feature_onboarding/ExampleUnitTest.kt @@ -0,0 +1,16 @@ +package com.dmity.androidacademy.feature_onboarding + +import org.junit.Assert.assertEquals +import org.junit.Test + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} diff --git a/settings.gradle b/settings.gradle index b33b497..1f1ae7c 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1 @@ -include ':app', ':domain' +include ':app', ':domain', ':features:feature_onboarding' From d066be8363bf94754b2c1e0aa2ff5853074990ed Mon Sep 17 00:00:00 2001 From: dmersiyanov Date: Thu, 5 Dec 2019 10:13:59 +0300 Subject: [PATCH 2/5] added empty core module --- app/build.gradle | 2 + base/core/.gitignore | 1 + base/core/build.gradle | 39 +++++++++++++++++++ base/core/consumer-rules.pro | 0 base/core/proguard-rules.pro | 21 ++++++++++ .../core/ExampleInstrumentedTest.kt | 22 +++++++++++ base/core/src/main/AndroidManifest.xml | 1 + base/core/src/main/res/values/strings.xml | 3 ++ .../androidacademy/core/ExampleUnitTest.kt | 16 ++++++++ features/feature_onboarding/build.gradle | 5 +-- settings.gradle | 2 +- 11 files changed, 107 insertions(+), 5 deletions(-) create mode 100644 base/core/.gitignore create mode 100644 base/core/build.gradle create mode 100644 base/core/consumer-rules.pro create mode 100644 base/core/proguard-rules.pro create mode 100644 base/core/src/androidTest/java/com/dmity/androidacademy/core/ExampleInstrumentedTest.kt create mode 100644 base/core/src/main/AndroidManifest.xml create mode 100644 base/core/src/main/res/values/strings.xml create mode 100644 base/core/src/test/java/com/dmity/androidacademy/core/ExampleUnitTest.kt diff --git a/app/build.gradle b/app/build.gradle index 819cbcd..8bae34c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -48,6 +48,8 @@ dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation project(':domain') + implementation project(':base:core') + implementation project(':features:feature_onboarding') // Google libs diff --git a/base/core/.gitignore b/base/core/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/base/core/.gitignore @@ -0,0 +1 @@ +/build diff --git a/base/core/build.gradle b/base/core/build.gradle new file mode 100644 index 0000000..206ef09 --- /dev/null +++ b/base/core/build.gradle @@ -0,0 +1,39 @@ +apply from: "$rootDir/base/deps_versions.gradle" +apply from: "$rootDir/base/config.gradle" + +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-android-extensions' +apply plugin: 'kotlin-kapt' + +androidExtensions { + experimental = true +} + +android { + compileSdkVersion config.currentSDK + + defaultConfig { + versionCode config.versionCode + versionName config.versionName + minSdkVersion config.minSDK + targetSdkVersion config.currentSDK + } +} + + +dependencies { + + api project(":domain") + api timber + api lifecycleExtensions + + api appcompat + api coreKtx + + // Dagger 2 + api dagger2.core + kapt dagger2.daggerCompiler + api dagger2.jsr330 + +} \ No newline at end of file diff --git a/base/core/consumer-rules.pro b/base/core/consumer-rules.pro new file mode 100644 index 0000000..e69de29 diff --git a/base/core/proguard-rules.pro b/base/core/proguard-rules.pro new file mode 100644 index 0000000..f1b4245 --- /dev/null +++ b/base/core/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/base/core/src/androidTest/java/com/dmity/androidacademy/core/ExampleInstrumentedTest.kt b/base/core/src/androidTest/java/com/dmity/androidacademy/core/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..b7544c7 --- /dev/null +++ b/base/core/src/androidTest/java/com/dmity/androidacademy/core/ExampleInstrumentedTest.kt @@ -0,0 +1,22 @@ +package com.dmity.androidacademy.core + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.platform.app.InstrumentationRegistry +import org.junit.Assert.* +import org.junit.Test +import org.junit.runner.RunWith + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.dmity.androidacademy.core.test", appContext.packageName) + } +} diff --git a/base/core/src/main/AndroidManifest.xml b/base/core/src/main/AndroidManifest.xml new file mode 100644 index 0000000..4de1dcd --- /dev/null +++ b/base/core/src/main/AndroidManifest.xml @@ -0,0 +1 @@ + diff --git a/base/core/src/main/res/values/strings.xml b/base/core/src/main/res/values/strings.xml new file mode 100644 index 0000000..6f8e4f6 --- /dev/null +++ b/base/core/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + core + diff --git a/base/core/src/test/java/com/dmity/androidacademy/core/ExampleUnitTest.kt b/base/core/src/test/java/com/dmity/androidacademy/core/ExampleUnitTest.kt new file mode 100644 index 0000000..1629907 --- /dev/null +++ b/base/core/src/test/java/com/dmity/androidacademy/core/ExampleUnitTest.kt @@ -0,0 +1,16 @@ +package com.dmity.androidacademy.core + +import org.junit.Assert.* +import org.junit.Test + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} diff --git a/features/feature_onboarding/build.gradle b/features/feature_onboarding/build.gradle index 4c1c7e0..246687c 100644 --- a/features/feature_onboarding/build.gradle +++ b/features/feature_onboarding/build.gradle @@ -22,9 +22,6 @@ android { } dependencies { - implementation project(":domain") - - implementation appcompat - implementation coreKtx + implementation project(":base:core") } \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 1f1ae7c..9b526cc 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1 @@ -include ':app', ':domain', ':features:feature_onboarding' +include ':app', ':domain', ':features:feature_onboarding', ':base:core' From 23c488be63f41ab554f4df9bbec5a5640347d630 Mon Sep 17 00:00:00 2001 From: dmersiyanov Date: Thu, 5 Dec 2019 12:41:34 +0300 Subject: [PATCH 3/5] moved sharing code to core module --- app/build.gradle | 3 - .../features/about/AboutActivity.kt | 4 +- .../newsDetail/NewsDetailsFragment.kt | 13 ++-- .../newsDetail/NewsDetailsViewModel.kt | 5 +- .../features/newsList/MainActivity.kt | 6 +- .../features/newsList/NewListFragment.kt | 24 +++---- .../features/newsList/NewsViewModel.kt | 5 +- .../adapter/BaseNewsAdapterDelegate.kt | 6 +- .../features/onboarding/OnBoardingActivity.kt | 4 +- .../onboarding/OnBoardingViewModel.kt | 2 +- .../dmity/androidacademy/utils/Extentions.kt | 67 ------------------- .../androidacademy/views/ImageTextView.kt | 2 +- app/src/main/res/values/dimens.xml | 6 +- app/src/main/res/values/strings.xml | 3 +- base/core/build.gradle | 10 +++ .../androidacademy/core}/BaseActivity.kt | 4 +- .../androidacademy/core}/BaseFragment.kt | 6 +- .../com/dmity/androidacademy/core}/Layout.kt | 2 +- .../core}/SubscriptionsHolder.kt | 2 +- .../core/adapter}/BaseAdapterDelegate.kt | 10 ++- .../core/adapter}/BaseViewHolder.kt | 2 +- .../core/extensions/ActivityExtensions.kt | 12 ++++ .../core/extensions/ContextExtensions.kt | 21 ++++++ .../core/extensions/FragmentExtensions.kt | 25 +++++++ .../core/extensions/ViewExtensions.kt | 36 ++++++++++ .../src/main/res/drawable/btn_outline.xml | 0 .../src/main/res/drawable/ic_placeholder.xml | 0 .../src/main/res/layout/view_error_stub.xml | 0 .../main/res/layout/view_progress_stub.xml | 0 .../src/main/res/layout/view_separator.xml | 0 base/core/src/main/res/values-ru/strings.xml | 5 ++ base/core/src/main/res/values/dimens.xml | 9 +++ base/core/src/main/res/values/strings.xml | 3 +- domain/build.gradle | 3 + 34 files changed, 171 insertions(+), 129 deletions(-) delete mode 100644 app/src/main/java/com/dmity/androidacademy/utils/Extentions.kt rename {app/src/main/java/com/dmity/androidacademy/base => base/core/src/main/java/com/dmity/androidacademy/core}/BaseActivity.kt (94%) rename {app/src/main/java/com/dmity/androidacademy/base => base/core/src/main/java/com/dmity/androidacademy/core}/BaseFragment.kt (78%) rename {app/src/main/java/com/dmity/androidacademy/base => base/core/src/main/java/com/dmity/androidacademy/core}/Layout.kt (74%) rename {app/src/main/java/com/dmity/androidacademy/base => base/core/src/main/java/com/dmity/androidacademy/core}/SubscriptionsHolder.kt (92%) rename {app/src/main/java/com/dmity/androidacademy/base => base/core/src/main/java/com/dmity/androidacademy/core/adapter}/BaseAdapterDelegate.kt (71%) rename {app/src/main/java/com/dmity/androidacademy/base => base/core/src/main/java/com/dmity/androidacademy/core/adapter}/BaseViewHolder.kt (76%) create mode 100644 base/core/src/main/java/com/dmity/androidacademy/core/extensions/ActivityExtensions.kt create mode 100644 base/core/src/main/java/com/dmity/androidacademy/core/extensions/ContextExtensions.kt create mode 100644 base/core/src/main/java/com/dmity/androidacademy/core/extensions/FragmentExtensions.kt create mode 100644 base/core/src/main/java/com/dmity/androidacademy/core/extensions/ViewExtensions.kt rename {app => base/core}/src/main/res/drawable/btn_outline.xml (100%) rename {app => base/core}/src/main/res/drawable/ic_placeholder.xml (100%) rename {app => base/core}/src/main/res/layout/view_error_stub.xml (100%) rename {app => base/core}/src/main/res/layout/view_progress_stub.xml (100%) rename {app => base/core}/src/main/res/layout/view_separator.xml (100%) create mode 100644 base/core/src/main/res/values-ru/strings.xml create mode 100644 base/core/src/main/res/values/dimens.xml diff --git a/app/build.gradle b/app/build.gradle index 8bae34c..64e04ff 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -60,9 +60,6 @@ dependencies { implementation 'androidx.coordinatorlayout:coordinatorlayout:1.0.0' implementation 'androidx.constraintlayout:constraintlayout:1.1.3' - // Glide - implementation 'com.github.bumptech.glide:glide:4.10.0' - // AdapterDelegates implementation 'com.hannesdorfmann:adapterdelegates4:4.0.0' diff --git a/app/src/main/java/com/dmity/androidacademy/features/about/AboutActivity.kt b/app/src/main/java/com/dmity/androidacademy/features/about/AboutActivity.kt index 0add6ab..2b7c2e4 100644 --- a/app/src/main/java/com/dmity/androidacademy/features/about/AboutActivity.kt +++ b/app/src/main/java/com/dmity/androidacademy/features/about/AboutActivity.kt @@ -3,8 +3,8 @@ package com.dmity.androidacademy.features.about import android.content.Context import android.content.Intent import com.dmity.androidacademy.R -import com.dmity.androidacademy.base.BaseActivity -import com.dmity.androidacademy.base.Layout +import com.dmity.androidacademy.core.BaseActivity +import com.dmity.androidacademy.core.Layout import com.dmity.androidacademy.utils.ThirdPartyIntentUtils import com.google.android.material.snackbar.Snackbar import kotlinx.android.synthetic.main.content_activity_about.* diff --git a/app/src/main/java/com/dmity/androidacademy/features/newsDetail/NewsDetailsFragment.kt b/app/src/main/java/com/dmity/androidacademy/features/newsDetail/NewsDetailsFragment.kt index c09db36..aa3ae2a 100644 --- a/app/src/main/java/com/dmity/androidacademy/features/newsDetail/NewsDetailsFragment.kt +++ b/app/src/main/java/com/dmity/androidacademy/features/newsDetail/NewsDetailsFragment.kt @@ -6,11 +6,12 @@ import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProviders import com.bumptech.glide.Glide import com.dmity.androidacademy.R -import com.dmity.androidacademy.base.BaseFragment +import com.dmity.androidacademy.core.BaseFragment +import com.dmity.androidacademy.core.extensions.setRetryListener +import com.dmity.androidacademy.core.extensions.showError +import com.dmity.androidacademy.core.extensions.showProgress import com.dmity.androidacademy.features.newsList.model.NewsEntity -import com.dmity.androidacademy.utils.visible import kotlinx.android.synthetic.main.fragment_news_details.* -import kotlinx.android.synthetic.main.view_error_stub.* class NewsDetailsFragment : BaseFragment() { @@ -26,14 +27,10 @@ class NewsDetailsFragment : BaseFragment() { } override fun initUx() { - btnRetry.setOnClickListener { requireActivity().onBackPressed() } + setRetryListener { requireActivity().onBackPressed() } toolbar?.setNavigationOnClickListener { requireActivity().onBackPressed() } } - fun showError(errorMessage: String, show: Boolean) { - errorStub.visible(show) - } - private fun initObservers() { viewModel.showProgress.observe(this, Observer { showProgress(it) diff --git a/app/src/main/java/com/dmity/androidacademy/features/newsDetail/NewsDetailsViewModel.kt b/app/src/main/java/com/dmity/androidacademy/features/newsDetail/NewsDetailsViewModel.kt index 5e88f0b..dd095d4 100644 --- a/app/src/main/java/com/dmity/androidacademy/features/newsDetail/NewsDetailsViewModel.kt +++ b/app/src/main/java/com/dmity/androidacademy/features/newsDetail/NewsDetailsViewModel.kt @@ -5,7 +5,7 @@ import android.content.Context import android.util.Log import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.MutableLiveData -import com.dmity.androidacademy.base.SubscriptionsHolder +import com.dmity.androidacademy.core.SubscriptionsHolder import com.dmity.androidacademy.database.AppDatabase import com.dmity.androidacademy.features.newsList.NewsRepo import com.dmity.androidacademy.features.newsList.model.NewsEntity @@ -13,7 +13,8 @@ import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.CompositeDisposable import io.reactivex.schedulers.Schedulers -class NewsDetailsViewModel(application: Application) : AndroidViewModel(application), SubscriptionsHolder { +class NewsDetailsViewModel(application: Application) : AndroidViewModel(application), + SubscriptionsHolder { override val disposables: CompositeDisposable = CompositeDisposable() private val newsRepo: NewsRepo diff --git a/app/src/main/java/com/dmity/androidacademy/features/newsList/MainActivity.kt b/app/src/main/java/com/dmity/androidacademy/features/newsList/MainActivity.kt index d24a1a3..d869a2b 100644 --- a/app/src/main/java/com/dmity/androidacademy/features/newsList/MainActivity.kt +++ b/app/src/main/java/com/dmity/androidacademy/features/newsList/MainActivity.kt @@ -6,12 +6,12 @@ import android.os.Bundle import android.widget.ArrayAdapter import androidx.lifecycle.ViewModelProviders import com.dmity.androidacademy.R -import com.dmity.androidacademy.base.BaseActivity -import com.dmity.androidacademy.base.Layout +import com.dmity.androidacademy.core.BaseActivity +import com.dmity.androidacademy.core.Layout +import com.dmity.androidacademy.core.extensions.addOnClickListener import com.dmity.androidacademy.features.newsDetail.NewsDetailsFragment import com.dmity.androidacademy.utils.DisplayMetricsUtils.isPhone import com.dmity.androidacademy.utils.DisplayMetricsUtils.isTablet -import com.dmity.androidacademy.utils.addOnClickListener import kotlinx.android.synthetic.main.activity_main.* import kotlinx.android.synthetic.main.toolbar_main_tablet.* diff --git a/app/src/main/java/com/dmity/androidacademy/features/newsList/NewListFragment.kt b/app/src/main/java/com/dmity/androidacademy/features/newsList/NewListFragment.kt index 5b4a9e1..fa16500 100644 --- a/app/src/main/java/com/dmity/androidacademy/features/newsList/NewListFragment.kt +++ b/app/src/main/java/com/dmity/androidacademy/features/newsList/NewListFragment.kt @@ -12,19 +12,20 @@ import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.dmity.androidacademy.R -import com.dmity.androidacademy.base.BaseFragment +import com.dmity.androidacademy.core.BaseFragment +import com.dmity.androidacademy.core.extensions.addOnClickListener +import com.dmity.androidacademy.core.extensions.setRetryListener +import com.dmity.androidacademy.core.extensions.showError +import com.dmity.androidacademy.core.extensions.showProgress +import com.dmity.androidacademy.core.extensions.showSnack +import com.dmity.androidacademy.core.extensions.visible import com.dmity.androidacademy.features.about.AboutActivity import com.dmity.androidacademy.features.newsList.adapter.NewsAdapter import com.dmity.androidacademy.features.newsList.model.DisplayableItem import com.dmity.androidacademy.features.newsList.model.NewsEntity import com.dmity.androidacademy.utils.DisplayMetricsUtils.isPhone import com.dmity.androidacademy.utils.DisplayMetricsUtils.isPortrait -import com.dmity.androidacademy.utils.addOnClickListener -import com.dmity.androidacademy.utils.showSnack -import com.dmity.androidacademy.utils.visible import kotlinx.android.synthetic.main.fragment_news_list.* -import kotlinx.android.synthetic.main.view_error_stub.* -import kotlinx.android.synthetic.main.view_progress_stub.* class NewListFragment : BaseFragment() { @@ -58,7 +59,7 @@ class NewListFragment : BaseFragment() { viewModel.getNews(retry = true) } - btnRetry.setOnClickListener(clickListener) + setRetryListener(clickListener) fab?.setOnClickListener(clickListener) aboutBtn?.setOnClickListener { AboutActivity.display(requireContext()) @@ -71,20 +72,11 @@ class NewListFragment : BaseFragment() { inflater.inflate(R.menu.menu_list, menu) } - override fun showProgress(show: Boolean) = progress?.visible(show) - override fun onDetach() { clickListener = null super.onDetach() } - private fun showError(errorMessage: String, show: Boolean) { - if(errorMessage.isNotBlank()) { - tvErrorMessage.text = errorMessage - } - errorStub.visible(show) - } - private fun showSnackBar(text: String, show: Boolean) { if (show && text.isNotBlank()) { rvNews.showSnack(text) diff --git a/app/src/main/java/com/dmity/androidacademy/features/newsList/NewsViewModel.kt b/app/src/main/java/com/dmity/androidacademy/features/newsList/NewsViewModel.kt index 42a0ac7..6964318 100644 --- a/app/src/main/java/com/dmity/androidacademy/features/newsList/NewsViewModel.kt +++ b/app/src/main/java/com/dmity/androidacademy/features/newsList/NewsViewModel.kt @@ -6,7 +6,7 @@ import android.util.Log import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.MutableLiveData import com.dmity.androidacademy.R -import com.dmity.androidacademy.base.SubscriptionsHolder +import com.dmity.androidacademy.core.SubscriptionsHolder import com.dmity.androidacademy.database.AppDatabase import com.dmity.androidacademy.features.newsList.model.NewsEntity import com.dmity.androidacademy.features.newsList.model.dto.NewsResponseDTO @@ -16,7 +16,8 @@ import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.CompositeDisposable import io.reactivex.schedulers.Schedulers -class NewsViewModel(application: Application) : AndroidViewModel(application), SubscriptionsHolder { +class NewsViewModel(application: Application) : AndroidViewModel(application), + SubscriptionsHolder { override val disposables: CompositeDisposable = CompositeDisposable() private val mapper: NewsItemMapper = NewsItemMapper() diff --git a/app/src/main/java/com/dmity/androidacademy/features/newsList/adapter/BaseNewsAdapterDelegate.kt b/app/src/main/java/com/dmity/androidacademy/features/newsList/adapter/BaseNewsAdapterDelegate.kt index 4b62a4e..fa1e83d 100644 --- a/app/src/main/java/com/dmity/androidacademy/features/newsList/adapter/BaseNewsAdapterDelegate.kt +++ b/app/src/main/java/com/dmity/androidacademy/features/newsList/adapter/BaseNewsAdapterDelegate.kt @@ -2,11 +2,11 @@ package com.dmity.androidacademy.features.newsList.adapter import android.view.ViewGroup import com.dmity.androidacademy.R -import com.dmity.androidacademy.base.BaseAdapterDelegate -import com.dmity.androidacademy.base.BaseViewHolder +import com.dmity.androidacademy.core.adapter.BaseAdapterDelegate +import com.dmity.androidacademy.core.adapter.BaseViewHolder +import com.dmity.androidacademy.core.extensions.loadImg import com.dmity.androidacademy.features.newsList.model.DisplayableItem import com.dmity.androidacademy.features.newsList.model.NewsEntity -import com.dmity.androidacademy.utils.loadImg import kotlinx.android.synthetic.main.item_news_constrained.view.* class BaseNewsAdapterDelegate(private val clickListener: (DisplayableItem) -> Unit) : BaseAdapterDelegate() { diff --git a/app/src/main/java/com/dmity/androidacademy/features/onboarding/OnBoardingActivity.kt b/app/src/main/java/com/dmity/androidacademy/features/onboarding/OnBoardingActivity.kt index ae44c76..d1e437b 100644 --- a/app/src/main/java/com/dmity/androidacademy/features/onboarding/OnBoardingActivity.kt +++ b/app/src/main/java/com/dmity/androidacademy/features/onboarding/OnBoardingActivity.kt @@ -8,8 +8,8 @@ import androidx.fragment.app.FragmentPagerAdapter import androidx.lifecycle.Observer import com.dmity.androidacademy.NewsApp import com.dmity.androidacademy.R -import com.dmity.androidacademy.base.BaseActivity -import com.dmity.androidacademy.base.Layout +import com.dmity.androidacademy.core.BaseActivity +import com.dmity.androidacademy.core.Layout import com.dmity.androidacademy.features.newsList.MainActivity import kotlinx.android.synthetic.main.activity_onboarding.* diff --git a/app/src/main/java/com/dmity/androidacademy/features/onboarding/OnBoardingViewModel.kt b/app/src/main/java/com/dmity/androidacademy/features/onboarding/OnBoardingViewModel.kt index 981b7b5..d6ff7ba 100644 --- a/app/src/main/java/com/dmity/androidacademy/features/onboarding/OnBoardingViewModel.kt +++ b/app/src/main/java/com/dmity/androidacademy/features/onboarding/OnBoardingViewModel.kt @@ -5,7 +5,7 @@ import android.content.Context import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.MutableLiveData import com.dmity.androidacademy.NewsApp -import com.dmity.androidacademy.base.SubscriptionsHolder +import com.dmity.androidacademy.core.SubscriptionsHolder import com.dmity.androidacademy.domain.interactor.GetOnboardingVisibilityInteractor import com.dmity.androidacademy.features.newsList.MainActivity import io.reactivex.Completable diff --git a/app/src/main/java/com/dmity/androidacademy/utils/Extentions.kt b/app/src/main/java/com/dmity/androidacademy/utils/Extentions.kt deleted file mode 100644 index 1f6082b..0000000 --- a/app/src/main/java/com/dmity/androidacademy/utils/Extentions.kt +++ /dev/null @@ -1,67 +0,0 @@ -package com.dmity.androidacademy.utils - -import android.content.Context -import android.content.res.Configuration -import android.content.res.TypedArray -import android.util.AttributeSet -import android.view.View -import android.widget.AdapterView -import android.widget.ImageView -import android.widget.Spinner -import androidx.annotation.IdRes -import androidx.appcompat.app.ActionBar -import androidx.appcompat.app.AppCompatActivity -import com.bumptech.glide.Glide -import com.dmity.androidacademy.R -import com.google.android.material.snackbar.Snackbar - - -fun Context.extractAttrsWithRecycle(set: AttributeSet, id: IntArray, func: TypedArray.() -> Unit) { - var attributes: TypedArray? = null - try { - attributes = obtainStyledAttributes(set, id) - func(attributes) - } finally { - attributes?.recycle() - } -} - -fun View.visible(visible: Boolean) { - this.visibility = if (visible) View.VISIBLE else View.GONE -} - - -fun Context.isPortrait(): Boolean { - val orientation: Int = resources.configuration.orientation - return orientation == Configuration.ORIENTATION_PORTRAIT -} - -fun ImageView.loadImg(imageUrl: String?) { - if (imageUrl.isNullOrBlank()) { - Glide.with(context).load(R.drawable.ic_placeholder).into(this) - } else { - Glide.with(context).load(imageUrl).into(this) - } -} - -fun View.showSnack(text: String, timeLength: Int = Snackbar.LENGTH_LONG) { - Snackbar.make(this, text, timeLength).show() -} - -fun AppCompatActivity.setupActionBar(@IdRes toolbarId: Int, action: ActionBar.() -> Unit) { - setSupportActionBar(findViewById(toolbarId)) - supportActionBar?.run { - action() - } -} - -fun Spinner?.addOnClickListener(clickListener: (position: Int) -> Unit) { - this?.onItemSelectedListener = object: AdapterView.OnItemSelectedListener { - override fun onNothingSelected(parent: AdapterView<*>?) {} - - override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { - clickListener.invoke(position) - } - } -} - diff --git a/app/src/main/java/com/dmity/androidacademy/views/ImageTextView.kt b/app/src/main/java/com/dmity/androidacademy/views/ImageTextView.kt index f20db0a..f45a442 100644 --- a/app/src/main/java/com/dmity/androidacademy/views/ImageTextView.kt +++ b/app/src/main/java/com/dmity/androidacademy/views/ImageTextView.kt @@ -5,7 +5,7 @@ import android.util.AttributeSet import android.view.View import android.widget.LinearLayout import com.dmity.androidacademy.R -import com.dmity.androidacademy.utils.extractAttrsWithRecycle +import com.dmity.androidacademy.core.extensions.extractAttrsWithRecycle import kotlinx.android.synthetic.main.layout_image_text_view.view.* diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index d60c1fb..dfc6e0b 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -1,18 +1,14 @@ - 32dp - 16dp - 8dp + 13sp 12sp 28dp 12dp 20dp - 1dp 225dp 18sp 5dp - 100dp 300dp 50dp 150dp diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 20f86d7..49bba65 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -13,8 +13,7 @@ About A Danish tourist has admitted he took his life in his hands by sitting on a large crocodile in Australia. + Niels Jensen, 22, was on safari in a wildlife park east of Darwin in northern Australia when he encountered the predator, estimated to be 4.7m (15ft) long and weighing 653kg (1428 lbs). The wildlife management graduate is filmed enticing the large reptile, which had been relocated to the park after it was caught preying on livestock, with a wallaby carcass. After leaving the bait on the ground and waiting for the crocodile to start eating, he astonishingly straddled the reptile\'s back, sitting just behind its rear legs. He touched some of the scales on the animal\'s back, and, after a few moments, rose and walked away. But a man out of shot told him to get back and give a thumbs-up, so he approached the animal for a second time, sat down again, turned towards the camera, smiled and put this thumb in the air. Mr Jensen admitted he took life in his hands by sitting on a live crocodile for the first time. Error while loading - Retry - Error has occurred. \nTry again. + Yesterday, %s %d hr. ago, %s Get latest news from all over the world diff --git a/base/core/build.gradle b/base/core/build.gradle index 206ef09..5c050e9 100644 --- a/base/core/build.gradle +++ b/base/core/build.gradle @@ -30,10 +30,20 @@ dependencies { api appcompat api coreKtx + api material // Dagger 2 api dagger2.core kapt dagger2.daggerCompiler api dagger2.jsr330 + // Rx + api rx.android + + // Glide + api 'com.github.bumptech.glide:glide:4.10.0' + + // AdapterDelegates + implementation 'com.hannesdorfmann:adapterdelegates4:4.0.0' + } \ No newline at end of file diff --git a/app/src/main/java/com/dmity/androidacademy/base/BaseActivity.kt b/base/core/src/main/java/com/dmity/androidacademy/core/BaseActivity.kt similarity index 94% rename from app/src/main/java/com/dmity/androidacademy/base/BaseActivity.kt rename to base/core/src/main/java/com/dmity/androidacademy/core/BaseActivity.kt index 42aad07..19e3083 100644 --- a/app/src/main/java/com/dmity/androidacademy/base/BaseActivity.kt +++ b/base/core/src/main/java/com/dmity/androidacademy/core/BaseActivity.kt @@ -1,10 +1,10 @@ -package com.dmity.androidacademy.base +package com.dmity.androidacademy.core import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import androidx.fragment.app.Fragment import androidx.lifecycle.ViewModelProvider -import com.dmity.androidacademy.utils.visible +import com.dmity.androidacademy.core.extensions.visible import io.reactivex.disposables.CompositeDisposable import kotlinx.android.synthetic.main.view_progress_stub.* import javax.inject.Inject diff --git a/app/src/main/java/com/dmity/androidacademy/base/BaseFragment.kt b/base/core/src/main/java/com/dmity/androidacademy/core/BaseFragment.kt similarity index 78% rename from app/src/main/java/com/dmity/androidacademy/base/BaseFragment.kt rename to base/core/src/main/java/com/dmity/androidacademy/core/BaseFragment.kt index 21ae8ca..73f51bd 100644 --- a/app/src/main/java/com/dmity/androidacademy/base/BaseFragment.kt +++ b/base/core/src/main/java/com/dmity/androidacademy/core/BaseFragment.kt @@ -1,4 +1,4 @@ -package com.dmity.androidacademy.base +package com.dmity.androidacademy.core import android.content.Context import android.os.Bundle @@ -6,8 +6,6 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment -import com.dmity.androidacademy.utils.visible -import kotlinx.android.synthetic.main.view_progress_stub.* abstract class BaseFragment: Fragment() { @@ -29,7 +27,7 @@ abstract class BaseFragment: Fragment() { protected abstract fun initUx() protected abstract fun initUi() - open fun showProgress(show: Boolean) = progress?.visible(show) +// open fun showProgress(show: Boolean) = progress?.visible(show) diff --git a/app/src/main/java/com/dmity/androidacademy/base/Layout.kt b/base/core/src/main/java/com/dmity/androidacademy/core/Layout.kt similarity index 74% rename from app/src/main/java/com/dmity/androidacademy/base/Layout.kt rename to base/core/src/main/java/com/dmity/androidacademy/core/Layout.kt index 89e15b4..2ba336e 100644 --- a/app/src/main/java/com/dmity/androidacademy/base/Layout.kt +++ b/base/core/src/main/java/com/dmity/androidacademy/core/Layout.kt @@ -1,4 +1,4 @@ -package com.dmity.androidacademy.base +package com.dmity.androidacademy.core @Target(AnnotationTarget.CLASS) @Retention(AnnotationRetention.RUNTIME) diff --git a/app/src/main/java/com/dmity/androidacademy/base/SubscriptionsHolder.kt b/base/core/src/main/java/com/dmity/androidacademy/core/SubscriptionsHolder.kt similarity index 92% rename from app/src/main/java/com/dmity/androidacademy/base/SubscriptionsHolder.kt rename to base/core/src/main/java/com/dmity/androidacademy/core/SubscriptionsHolder.kt index a670c0f..f5f110f 100644 --- a/app/src/main/java/com/dmity/androidacademy/base/SubscriptionsHolder.kt +++ b/base/core/src/main/java/com/dmity/androidacademy/core/SubscriptionsHolder.kt @@ -1,4 +1,4 @@ -package com.dmity.androidacademy.base +package com.dmity.androidacademy.core import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.Disposable diff --git a/app/src/main/java/com/dmity/androidacademy/base/BaseAdapterDelegate.kt b/base/core/src/main/java/com/dmity/androidacademy/core/adapter/BaseAdapterDelegate.kt similarity index 71% rename from app/src/main/java/com/dmity/androidacademy/base/BaseAdapterDelegate.kt rename to base/core/src/main/java/com/dmity/androidacademy/core/adapter/BaseAdapterDelegate.kt index b09cd25..e12b435 100644 --- a/app/src/main/java/com/dmity/androidacademy/base/BaseAdapterDelegate.kt +++ b/base/core/src/main/java/com/dmity/androidacademy/core/adapter/BaseAdapterDelegate.kt @@ -1,4 +1,4 @@ -package com.dmity.androidacademy.base +package com.dmity.androidacademy.core.adapter import android.view.LayoutInflater import android.view.ViewGroup @@ -11,7 +11,13 @@ abstract class BaseAdapterDelegate: AbsL protected fun fromLayoutId(layoutId: Int, parent: ViewGroup): BaseViewHolder { inflater = LayoutInflater.from(parent.context) - return BaseViewHolder(inflater.inflate(layoutId, parent, false)) + return BaseViewHolder( + inflater.inflate( + layoutId, + parent, + false + ) + ) } } \ No newline at end of file diff --git a/app/src/main/java/com/dmity/androidacademy/base/BaseViewHolder.kt b/base/core/src/main/java/com/dmity/androidacademy/core/adapter/BaseViewHolder.kt similarity index 76% rename from app/src/main/java/com/dmity/androidacademy/base/BaseViewHolder.kt rename to base/core/src/main/java/com/dmity/androidacademy/core/adapter/BaseViewHolder.kt index 091e822..763aef8 100644 --- a/app/src/main/java/com/dmity/androidacademy/base/BaseViewHolder.kt +++ b/base/core/src/main/java/com/dmity/androidacademy/core/adapter/BaseViewHolder.kt @@ -1,4 +1,4 @@ -package com.dmity.androidacademy.base +package com.dmity.androidacademy.core.adapter import android.view.View import androidx.recyclerview.widget.RecyclerView diff --git a/base/core/src/main/java/com/dmity/androidacademy/core/extensions/ActivityExtensions.kt b/base/core/src/main/java/com/dmity/androidacademy/core/extensions/ActivityExtensions.kt new file mode 100644 index 0000000..1637c19 --- /dev/null +++ b/base/core/src/main/java/com/dmity/androidacademy/core/extensions/ActivityExtensions.kt @@ -0,0 +1,12 @@ +package com.dmity.androidacademy.core.extensions + +import androidx.annotation.IdRes +import androidx.appcompat.app.ActionBar +import androidx.appcompat.app.AppCompatActivity + +fun AppCompatActivity.setupActionBar(@IdRes toolbarId: Int, action: ActionBar.() -> Unit) { + setSupportActionBar(findViewById(toolbarId)) + supportActionBar?.run { + action() + } +} \ No newline at end of file diff --git a/base/core/src/main/java/com/dmity/androidacademy/core/extensions/ContextExtensions.kt b/base/core/src/main/java/com/dmity/androidacademy/core/extensions/ContextExtensions.kt new file mode 100644 index 0000000..bfc11f9 --- /dev/null +++ b/base/core/src/main/java/com/dmity/androidacademy/core/extensions/ContextExtensions.kt @@ -0,0 +1,21 @@ +package com.dmity.androidacademy.core.extensions + +import android.content.Context +import android.content.res.Configuration +import android.content.res.TypedArray +import android.util.AttributeSet + +fun Context.extractAttrsWithRecycle(set: AttributeSet, id: IntArray, func: TypedArray.() -> Unit) { + var attributes: TypedArray? = null + try { + attributes = obtainStyledAttributes(set, id) + func(attributes) + } finally { + attributes?.recycle() + } +} + +fun Context.isPortrait(): Boolean { + val orientation: Int = resources.configuration.orientation + return orientation == Configuration.ORIENTATION_PORTRAIT +} \ No newline at end of file diff --git a/base/core/src/main/java/com/dmity/androidacademy/core/extensions/FragmentExtensions.kt b/base/core/src/main/java/com/dmity/androidacademy/core/extensions/FragmentExtensions.kt new file mode 100644 index 0000000..30a2253 --- /dev/null +++ b/base/core/src/main/java/com/dmity/androidacademy/core/extensions/FragmentExtensions.kt @@ -0,0 +1,25 @@ +package com.dmity.androidacademy.core.extensions + +import android.view.View +import androidx.fragment.app.Fragment +import kotlinx.android.synthetic.main.view_error_stub.* +import kotlinx.android.synthetic.main.view_progress_stub.* + +fun Fragment.showProgress(show: Boolean) = progress?.visible(show) + +fun Fragment.showError(errorMessage: String, show: Boolean) { + if (errorMessage.isNotBlank()) { + tvErrorMessage.text = errorMessage + } + errorStub.visible(show) +} + +fun Fragment.setRetryListener(clickListener: View.OnClickListener) { + btnRetry.setOnClickListener(clickListener) +} + +fun Fragment.setRetryListener(listener: () -> Unit) { + btnRetry.setOnClickListener { + listener.invoke() + } +} diff --git a/base/core/src/main/java/com/dmity/androidacademy/core/extensions/ViewExtensions.kt b/base/core/src/main/java/com/dmity/androidacademy/core/extensions/ViewExtensions.kt new file mode 100644 index 0000000..8c07c88 --- /dev/null +++ b/base/core/src/main/java/com/dmity/androidacademy/core/extensions/ViewExtensions.kt @@ -0,0 +1,36 @@ +package com.dmity.androidacademy.core.extensions + +import android.view.View +import android.widget.AdapterView +import android.widget.ImageView +import android.widget.Spinner +import com.bumptech.glide.Glide +import com.dmity.androidacademy.core.R +import com.google.android.material.snackbar.Snackbar + +fun View.visible(visible: Boolean) { + this.visibility = if (visible) View.VISIBLE else View.GONE +} + +fun Spinner?.addOnClickListener(clickListener: (position: Int) -> Unit) { + this?.onItemSelectedListener = object : + AdapterView.OnItemSelectedListener { + override fun onNothingSelected(parent: AdapterView<*>?) {} + + override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { + clickListener.invoke(position) + } + } +} + +fun View.showSnack(text: String, timeLength: Int = Snackbar.LENGTH_LONG) { + Snackbar.make(this, text, timeLength).show() +} + +fun ImageView.loadImg(imageUrl: String?) { + if (imageUrl.isNullOrBlank()) { + Glide.with(context).load(R.drawable.ic_placeholder).into(this) + } else { + Glide.with(context).load(imageUrl).into(this) + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/btn_outline.xml b/base/core/src/main/res/drawable/btn_outline.xml similarity index 100% rename from app/src/main/res/drawable/btn_outline.xml rename to base/core/src/main/res/drawable/btn_outline.xml diff --git a/app/src/main/res/drawable/ic_placeholder.xml b/base/core/src/main/res/drawable/ic_placeholder.xml similarity index 100% rename from app/src/main/res/drawable/ic_placeholder.xml rename to base/core/src/main/res/drawable/ic_placeholder.xml diff --git a/app/src/main/res/layout/view_error_stub.xml b/base/core/src/main/res/layout/view_error_stub.xml similarity index 100% rename from app/src/main/res/layout/view_error_stub.xml rename to base/core/src/main/res/layout/view_error_stub.xml diff --git a/app/src/main/res/layout/view_progress_stub.xml b/base/core/src/main/res/layout/view_progress_stub.xml similarity index 100% rename from app/src/main/res/layout/view_progress_stub.xml rename to base/core/src/main/res/layout/view_progress_stub.xml diff --git a/app/src/main/res/layout/view_separator.xml b/base/core/src/main/res/layout/view_separator.xml similarity index 100% rename from app/src/main/res/layout/view_separator.xml rename to base/core/src/main/res/layout/view_separator.xml diff --git a/base/core/src/main/res/values-ru/strings.xml b/base/core/src/main/res/values-ru/strings.xml new file mode 100644 index 0000000..078533c --- /dev/null +++ b/base/core/src/main/res/values-ru/strings.xml @@ -0,0 +1,5 @@ + + + Повторить + Произошла ошибка при загрузке. \nПопробуйте еще раз. + \ No newline at end of file diff --git a/base/core/src/main/res/values/dimens.xml b/base/core/src/main/res/values/dimens.xml new file mode 100644 index 0000000..a1359ad --- /dev/null +++ b/base/core/src/main/res/values/dimens.xml @@ -0,0 +1,9 @@ + + + 32dp + 16dp + 8dp + 1dp + 100dp + + \ No newline at end of file diff --git a/base/core/src/main/res/values/strings.xml b/base/core/src/main/res/values/strings.xml index 6f8e4f6..7de1023 100644 --- a/base/core/src/main/res/values/strings.xml +++ b/base/core/src/main/res/values/strings.xml @@ -1,3 +1,4 @@ - core + Retry + Error has occurred. \nTry again. diff --git a/domain/build.gradle b/domain/build.gradle index 911fda2..8b991e9 100644 --- a/domain/build.gradle +++ b/domain/build.gradle @@ -4,6 +4,9 @@ apply plugin: 'kotlin' dependencies { implementation kotlin implementation dagger2.jsr330 + + api rx.java + api rx.kotlin } sourceCompatibility = "8" From 9c830d30cd68553c29a15dfd0b327bca49155409 Mon Sep 17 00:00:00 2001 From: dmersiyanov Date: Thu, 5 Dec 2019 12:55:43 +0300 Subject: [PATCH 4/5] moved onboarding feature layouts to module --- app/src/main/res/values-ru/strings.xml | 3 --- app/src/main/res/values/strings.xml | 4 ---- features/feature_onboarding/build.gradle | 3 +++ .../src/main/res/drawable/color_indicator_black.xml | 0 .../src/main/res/drawable/ic_onboarding.png | Bin .../src/main/res/drawable/ic_onboarding_2.jpg | Bin .../src/main/res/layout/activity_onboarding.xml | 4 ++-- .../src/main/res/layout/fragment_onboarding.xml | 0 .../src/main/res/values-ru/strings.xml | 5 +++++ .../src/main/res/values/dimens.xml | 8 ++++++++ .../src/main/res/values/strings.xml | 4 +++- 11 files changed, 21 insertions(+), 10 deletions(-) rename {app => features/feature_onboarding}/src/main/res/drawable/color_indicator_black.xml (100%) rename {app => features/feature_onboarding}/src/main/res/drawable/ic_onboarding.png (100%) rename {app => features/feature_onboarding}/src/main/res/drawable/ic_onboarding_2.jpg (100%) rename {app => features/feature_onboarding}/src/main/res/layout/activity_onboarding.xml (92%) rename {app => features/feature_onboarding}/src/main/res/layout/fragment_onboarding.xml (100%) create mode 100644 features/feature_onboarding/src/main/res/values-ru/strings.xml create mode 100644 features/feature_onboarding/src/main/res/values/dimens.xml diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index debdd30..1b2fdc0 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -14,9 +14,6 @@ Ошибка загрузки Повторить Произошла ошибка при загрузке. \nПопробуйте еще раз. - Пропустить - Получайте последние новости со всего мира - Будьте в курсе последних новостей Выберите новость \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 49bba65..32cefaf 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -13,12 +13,8 @@ About A Danish tourist has admitted he took his life in his hands by sitting on a large crocodile in Australia. + Niels Jensen, 22, was on safari in a wildlife park east of Darwin in northern Australia when he encountered the predator, estimated to be 4.7m (15ft) long and weighing 653kg (1428 lbs). The wildlife management graduate is filmed enticing the large reptile, which had been relocated to the park after it was caught preying on livestock, with a wallaby carcass. After leaving the bait on the ground and waiting for the crocodile to start eating, he astonishingly straddled the reptile\'s back, sitting just behind its rear legs. He touched some of the scales on the animal\'s back, and, after a few moments, rose and walked away. But a man out of shot told him to get back and give a thumbs-up, so he approached the animal for a second time, sat down again, turned towards the camera, smiled and put this thumb in the air. Mr Jensen admitted he took life in his hands by sitting on a live crocodile for the first time. Error while loading - Yesterday, %s %d hr. ago, %s - Get latest news from all over the world - Stay on top of all the important events - Skip Choose peace of news diff --git a/features/feature_onboarding/build.gradle b/features/feature_onboarding/build.gradle index 246687c..4513b55 100644 --- a/features/feature_onboarding/build.gradle +++ b/features/feature_onboarding/build.gradle @@ -24,4 +24,7 @@ android { dependencies { implementation project(":base:core") + // Other + implementation 'me.relex:circleindicator:2.1.4' + } \ No newline at end of file diff --git a/app/src/main/res/drawable/color_indicator_black.xml b/features/feature_onboarding/src/main/res/drawable/color_indicator_black.xml similarity index 100% rename from app/src/main/res/drawable/color_indicator_black.xml rename to features/feature_onboarding/src/main/res/drawable/color_indicator_black.xml diff --git a/app/src/main/res/drawable/ic_onboarding.png b/features/feature_onboarding/src/main/res/drawable/ic_onboarding.png similarity index 100% rename from app/src/main/res/drawable/ic_onboarding.png rename to features/feature_onboarding/src/main/res/drawable/ic_onboarding.png diff --git a/app/src/main/res/drawable/ic_onboarding_2.jpg b/features/feature_onboarding/src/main/res/drawable/ic_onboarding_2.jpg similarity index 100% rename from app/src/main/res/drawable/ic_onboarding_2.jpg rename to features/feature_onboarding/src/main/res/drawable/ic_onboarding_2.jpg diff --git a/app/src/main/res/layout/activity_onboarding.xml b/features/feature_onboarding/src/main/res/layout/activity_onboarding.xml similarity index 92% rename from app/src/main/res/layout/activity_onboarding.xml rename to features/feature_onboarding/src/main/res/layout/activity_onboarding.xml index 7f663dc..12459fb 100644 --- a/app/src/main/res/layout/activity_onboarding.xml +++ b/features/feature_onboarding/src/main/res/layout/activity_onboarding.xml @@ -8,7 +8,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginTop="@dimen/small_margin" - android:background="@color/white" /> + android:background="@android:color/white" /> + android:textColor="@android:color/black" /> \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_onboarding.xml b/features/feature_onboarding/src/main/res/layout/fragment_onboarding.xml similarity index 100% rename from app/src/main/res/layout/fragment_onboarding.xml rename to features/feature_onboarding/src/main/res/layout/fragment_onboarding.xml diff --git a/features/feature_onboarding/src/main/res/values-ru/strings.xml b/features/feature_onboarding/src/main/res/values-ru/strings.xml new file mode 100644 index 0000000..4e3c458 --- /dev/null +++ b/features/feature_onboarding/src/main/res/values-ru/strings.xml @@ -0,0 +1,5 @@ + + Получайте последние новости со всего мира + Будьте в курсе последних новостей + Пропустить + diff --git a/features/feature_onboarding/src/main/res/values/dimens.xml b/features/feature_onboarding/src/main/res/values/dimens.xml new file mode 100644 index 0000000..0a2413d --- /dev/null +++ b/features/feature_onboarding/src/main/res/values/dimens.xml @@ -0,0 +1,8 @@ + + + + 300dp + 50dp + 48dp + 20dp + \ No newline at end of file diff --git a/features/feature_onboarding/src/main/res/values/strings.xml b/features/feature_onboarding/src/main/res/values/strings.xml index c276601..1e36ff3 100644 --- a/features/feature_onboarding/src/main/res/values/strings.xml +++ b/features/feature_onboarding/src/main/res/values/strings.xml @@ -1,3 +1,5 @@ - feature_onboarding + Get latest news from all over the world + Stay on top of all the important events + Skip From 0fdf9f876535e9c36dedb9af1190feea6964e316 Mon Sep 17 00:00:00 2001 From: Dmitry Mersiyanov Date: Sun, 15 Dec 2019 14:37:23 +0300 Subject: [PATCH 5/5] added feature module, setup dagger for multi-modules --- app/src/main/AndroidManifest.xml | 2 +- .../java/com/dmity/androidacademy/NewsApp.kt | 31 +++---- .../dmity/androidacademy/di/AppComponent.kt | 38 ++++++--- .../com/dmity/androidacademy/di/AppModule.kt | 20 +++++ .../dmity/androidacademy/di/ContextModule.kt | 16 ---- .../androidacademy/di/FacadeComponent.kt | 23 +++++ .../androidacademy/di/ViewModelModule.kt | 14 --- .../di/utils/ViewModelFactory.kt | 17 ---- .../onboarding/di/OnBoardingModule.kt | 36 +++----- base/core/build.gradle | 2 + .../dmity/androidacademy/core/BaseActivity.kt | 24 +++--- .../androidacademy/core/di/AppProvider.kt | 8 ++ .../androidacademy/core/di/AppWithFacade.kt | 7 ++ .../core/di/CoreProvidersFactory.kt | 11 +++ .../androidacademy/core/di/ProvidersFacade.kt | 3 + .../core/di/viewModel/ViewModelComponent.kt | 9 ++ .../di/viewModel/ViewModelFactoryProvider.kt | 20 +++++ .../core/di/viewModel}/ViewModelKey.kt | 2 +- .../core/di/viewModel/ViewModelModule.kt | 25 ++++++ .../core/di/viewModel/ViewModelsProvider.kt | 11 +++ build.gradle | 2 +- features/feature_onboarding/build.gradle | 2 + .../ExampleInstrumentedTest.kt | 14 +-- .../di/OnboardingComponent.kt | 30 +++++++ .../feature_onboarding/di/OnboardingModule.kt | 49 +++++++++++ .../repo/OnBoardingRepoImpl.kt | 34 ++++++++ .../view/OnBoardingActivity.kt | 85 +++++++++++++++++++ .../view}/OnBoardingFragment.kt | 4 +- .../viewModel/OnBoardingViewModel.kt | 68 +++++++++++++++ 29 files changed, 482 insertions(+), 125 deletions(-) create mode 100644 app/src/main/java/com/dmity/androidacademy/di/AppModule.kt delete mode 100644 app/src/main/java/com/dmity/androidacademy/di/ContextModule.kt create mode 100644 app/src/main/java/com/dmity/androidacademy/di/FacadeComponent.kt delete mode 100644 app/src/main/java/com/dmity/androidacademy/di/ViewModelModule.kt delete mode 100644 app/src/main/java/com/dmity/androidacademy/di/utils/ViewModelFactory.kt create mode 100644 base/core/src/main/java/com/dmity/androidacademy/core/di/AppProvider.kt create mode 100644 base/core/src/main/java/com/dmity/androidacademy/core/di/AppWithFacade.kt create mode 100644 base/core/src/main/java/com/dmity/androidacademy/core/di/CoreProvidersFactory.kt create mode 100644 base/core/src/main/java/com/dmity/androidacademy/core/di/ProvidersFacade.kt create mode 100644 base/core/src/main/java/com/dmity/androidacademy/core/di/viewModel/ViewModelComponent.kt create mode 100644 base/core/src/main/java/com/dmity/androidacademy/core/di/viewModel/ViewModelFactoryProvider.kt rename {app/src/main/java/com/dmity/androidacademy/di/utils => base/core/src/main/java/com/dmity/androidacademy/core/di/viewModel}/ViewModelKey.kt (86%) create mode 100644 base/core/src/main/java/com/dmity/androidacademy/core/di/viewModel/ViewModelModule.kt create mode 100644 base/core/src/main/java/com/dmity/androidacademy/core/di/viewModel/ViewModelsProvider.kt create mode 100644 features/feature_onboarding/src/main/java/com/dmity/androidacademy/feature_onboarding/di/OnboardingComponent.kt create mode 100644 features/feature_onboarding/src/main/java/com/dmity/androidacademy/feature_onboarding/di/OnboardingModule.kt create mode 100644 features/feature_onboarding/src/main/java/com/dmity/androidacademy/feature_onboarding/repo/OnBoardingRepoImpl.kt create mode 100644 features/feature_onboarding/src/main/java/com/dmity/androidacademy/feature_onboarding/view/OnBoardingActivity.kt rename {app/src/main/java/com/dmity/androidacademy/features/onboarding => features/feature_onboarding/src/main/java/com/dmity/androidacademy/feature_onboarding/view}/OnBoardingFragment.kt (93%) create mode 100644 features/feature_onboarding/src/main/java/com/dmity/androidacademy/feature_onboarding/viewModel/OnBoardingViewModel.kt diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 1605f1f..717849e 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -24,7 +24,7 @@ diff --git a/app/src/main/java/com/dmity/androidacademy/NewsApp.kt b/app/src/main/java/com/dmity/androidacademy/NewsApp.kt index 6b35d7b..b70f054 100644 --- a/app/src/main/java/com/dmity/androidacademy/NewsApp.kt +++ b/app/src/main/java/com/dmity/androidacademy/NewsApp.kt @@ -3,31 +3,30 @@ package com.dmity.androidacademy import android.annotation.SuppressLint import android.app.Application import android.content.Context -import android.util.Log -import com.dmity.androidacademy.di.AppComponent -import com.dmity.androidacademy.di.ContextModule -import com.dmity.androidacademy.di.DaggerAppComponent +import com.dmity.androidacademy.core.di.AppWithFacade +import com.dmity.androidacademy.core.di.ProvidersFacade +import com.dmity.androidacademy.di.FacadeComponent import io.reactivex.plugins.RxJavaPlugins +import timber.log.Timber -class NewsApp: Application() { - - lateinit var appComponent: AppComponent +class NewsApp : Application(), AppWithFacade { override fun onCreate() { super.onCreate() context = this - - appComponent = DaggerAppComponent - .builder() - .contextModule(ContextModule(this)) - .build() - + (getFacade() as FacadeComponent).inject(this) setGlobalRxJavaErrorHandler() } + override fun getFacade(): ProvidersFacade { + return facadeComponent ?: FacadeComponent.init(this).also { + facadeComponent = it + } + } + @SuppressLint("LongLogTag") private fun setGlobalRxJavaErrorHandler() { RxJavaPlugins.setErrorHandler { e -> @@ -40,15 +39,13 @@ class NewsApp: Application() { Thread.currentThread().uncaughtExceptionHandler.uncaughtException(Thread.currentThread(), e) } - Log.w("Undeliverable exception received", e.message) + Timber.w(e) } } companion object { - - fun getAppComponent() = (context as NewsApp).appComponent - + private var facadeComponent: FacadeComponent? = null @SuppressLint("StaticFieldLeak") lateinit var context: Context diff --git a/app/src/main/java/com/dmity/androidacademy/di/AppComponent.kt b/app/src/main/java/com/dmity/androidacademy/di/AppComponent.kt index c5273f6..a7db8b9 100644 --- a/app/src/main/java/com/dmity/androidacademy/di/AppComponent.kt +++ b/app/src/main/java/com/dmity/androidacademy/di/AppComponent.kt @@ -1,21 +1,39 @@ package com.dmity.androidacademy.di -import com.dmity.androidacademy.features.onboarding.OnBoardingActivity -import com.dmity.androidacademy.features.onboarding.OnBoardingViewModel -import com.dmity.androidacademy.features.onboarding.di.OnBoardingModule +import android.app.Application +import android.content.Context +import com.dmity.androidacademy.core.di.AppProvider + +import dagger.BindsInstance import dagger.Component import javax.inject.Singleton @Singleton @Component( - modules = [ - ContextModule::class, - OnBoardingModule::class, - ViewModelModule::class] + modules = [AppModule::class] ) -interface AppComponent { +interface AppComponent : AppProvider { + + companion object { + + private var appComponent: AppProvider? = null + + fun create(application: Application): AppProvider { + return appComponent ?: DaggerAppComponent + .builder() + .application(application.applicationContext) + .build().also { + appComponent = it + } + } + } + + @Component.Builder + interface Builder { - fun inject(onBoardingViewModel: OnBoardingViewModel) - fun inject(onBoardingActivity: OnBoardingActivity) + @BindsInstance + fun application(context: Context): Builder + fun build(): AppComponent + } } \ No newline at end of file diff --git a/app/src/main/java/com/dmity/androidacademy/di/AppModule.kt b/app/src/main/java/com/dmity/androidacademy/di/AppModule.kt new file mode 100644 index 0000000..a8ed180 --- /dev/null +++ b/app/src/main/java/com/dmity/androidacademy/di/AppModule.kt @@ -0,0 +1,20 @@ +package com.dmity.androidacademy.di + +import dagger.Module + +@Module +abstract class AppModule { + + @Module + companion object { + + // Пока не используется +// private const val PREFS_NAME = "HABITS_SP" +// +// @JvmStatic +// @Provides +// @Singleton +// fun provideSharedPreferences(context: Context): SharedPreferences = +// context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/dmity/androidacademy/di/ContextModule.kt b/app/src/main/java/com/dmity/androidacademy/di/ContextModule.kt deleted file mode 100644 index 5ebb5be..0000000 --- a/app/src/main/java/com/dmity/androidacademy/di/ContextModule.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.dmity.androidacademy.di - -import android.app.Application -import android.content.Context -import dagger.Module -import dagger.Provides - -@Module -class ContextModule(private val appContext: Context) { - - @Provides - fun appContext(): Context = appContext - - @Provides - fun app(): Application = appContext as Application -} \ No newline at end of file diff --git a/app/src/main/java/com/dmity/androidacademy/di/FacadeComponent.kt b/app/src/main/java/com/dmity/androidacademy/di/FacadeComponent.kt new file mode 100644 index 0000000..37c6870 --- /dev/null +++ b/app/src/main/java/com/dmity/androidacademy/di/FacadeComponent.kt @@ -0,0 +1,23 @@ +package com.dmity.androidacademy.di + +import android.app.Application +import com.dmity.androidacademy.NewsApp +import com.dmity.androidacademy.core.di.AppProvider +import com.dmity.androidacademy.core.di.ProvidersFacade +import dagger.Component + +@Component( + dependencies = [AppProvider::class] +) +interface FacadeComponent : ProvidersFacade { + + companion object { + + fun init(application: Application): FacadeComponent = + DaggerFacadeComponent.builder() + .appProvider(AppComponent.create(application)) + .build() + } + + fun inject(app: NewsApp) +} \ No newline at end of file diff --git a/app/src/main/java/com/dmity/androidacademy/di/ViewModelModule.kt b/app/src/main/java/com/dmity/androidacademy/di/ViewModelModule.kt deleted file mode 100644 index 081062f..0000000 --- a/app/src/main/java/com/dmity/androidacademy/di/ViewModelModule.kt +++ /dev/null @@ -1,14 +0,0 @@ -package com.dmity.androidacademy.di - -import androidx.lifecycle.ViewModelProvider -import com.dmity.androidacademy.di.utils.ViewModelFactory -import dagger.Binds -import dagger.Module - -@Module -abstract class ViewModelModule { - - @Binds - abstract fun bindFactory(viewModelFactory: ViewModelFactory): ViewModelProvider.Factory - -} \ No newline at end of file diff --git a/app/src/main/java/com/dmity/androidacademy/di/utils/ViewModelFactory.kt b/app/src/main/java/com/dmity/androidacademy/di/utils/ViewModelFactory.kt deleted file mode 100644 index 3d8d4fe..0000000 --- a/app/src/main/java/com/dmity/androidacademy/di/utils/ViewModelFactory.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.dmity.androidacademy.di.utils - -import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider -import javax.inject.Inject -import javax.inject.Provider -import javax.inject.Singleton - -@Singleton -class ViewModelFactory -@Inject constructor(private val viewModelMap: @JvmSuppressWildcards Map, Provider>) : - ViewModelProvider.Factory { - - @Suppress("UNCHECKED_CAST") - override fun create(modelClass: Class) = - viewModelMap.getValue(modelClass).get() as T -} \ No newline at end of file diff --git a/app/src/main/java/com/dmity/androidacademy/features/onboarding/di/OnBoardingModule.kt b/app/src/main/java/com/dmity/androidacademy/features/onboarding/di/OnBoardingModule.kt index 28b8eee..c725b98 100644 --- a/app/src/main/java/com/dmity/androidacademy/features/onboarding/di/OnBoardingModule.kt +++ b/app/src/main/java/com/dmity/androidacademy/features/onboarding/di/OnBoardingModule.kt @@ -1,25 +1,15 @@ package com.dmity.androidacademy.features.onboarding.di -import androidx.lifecycle.ViewModel -import com.dmity.androidacademy.di.utils.ViewModelKey -import com.dmity.androidacademy.domain.repo.OnBoardingRepo -import com.dmity.androidacademy.features.onboarding.OnBoardingRepoImpl -import com.dmity.androidacademy.features.onboarding.OnBoardingViewModel -import dagger.Binds -import dagger.Module -import dagger.multibindings.IntoMap -import javax.inject.Singleton - -@Module -abstract class OnBoardingModule { - - @Singleton - @Binds - abstract fun getOnBoardingRepo(onBoardingRepoImpl: OnBoardingRepoImpl): OnBoardingRepo - - @IntoMap - @ViewModelKey(OnBoardingViewModel::class) - @Binds - abstract fun bindOnBoardingViewModel(vm: OnBoardingViewModel): ViewModel - -} \ No newline at end of file +//@Module +//abstract class OnBoardingModule { +// +// @Singleton +// @Binds +// abstract fun getOnBoardingRepo(onBoardingRepoImpl: OnBoardingRepoImpl): OnBoardingRepo +// +// @IntoMap +// @ViewModelKey(OnBoardingViewModel::class) +// @Binds +// abstract fun bindOnBoardingViewModel(vm: OnBoardingViewModel): ViewModel +// +//} \ No newline at end of file diff --git a/base/core/build.gradle b/base/core/build.gradle index 5c050e9..cb49def 100644 --- a/base/core/build.gradle +++ b/base/core/build.gradle @@ -28,9 +28,11 @@ dependencies { api timber api lifecycleExtensions + // Google api appcompat api coreKtx api material + api fragmentKtx // Dagger 2 api dagger2.core diff --git a/base/core/src/main/java/com/dmity/androidacademy/core/BaseActivity.kt b/base/core/src/main/java/com/dmity/androidacademy/core/BaseActivity.kt index 19e3083..8448472 100644 --- a/base/core/src/main/java/com/dmity/androidacademy/core/BaseActivity.kt +++ b/base/core/src/main/java/com/dmity/androidacademy/core/BaseActivity.kt @@ -3,16 +3,12 @@ package com.dmity.androidacademy.core import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import androidx.fragment.app.Fragment -import androidx.lifecycle.ViewModelProvider import com.dmity.androidacademy.core.extensions.visible import io.reactivex.disposables.CompositeDisposable import kotlinx.android.synthetic.main.view_progress_stub.* -import javax.inject.Inject -abstract class BaseActivity: AppCompatActivity(), SubscriptionsHolder { - - @Inject - lateinit var viewModelFactory: ViewModelProvider.Factory +abstract class BaseActivity(private val layoutId: Int = 0) : AppCompatActivity(), + SubscriptionsHolder { override val disposables: CompositeDisposable = CompositeDisposable() @@ -20,6 +16,7 @@ abstract class BaseActivity: AppCompatActivity(), SubscriptionsHolder { super.onCreate(savedInstanceState) initLayout() + initLayoutFromConstructor() initUi() initUi(savedInstanceState) initUx() @@ -36,7 +33,7 @@ abstract class BaseActivity: AppCompatActivity(), SubscriptionsHolder { protected open fun showProgress(show: Boolean) = progress?.visible(show) protected open fun showError(errorMessage: String = "", show: Boolean) {} - private fun initLayout(){ + private fun initLayout() { var layoutId = 0 val annotation = javaClass.getAnnotation(Layout::class.java) if (annotation != null) { @@ -48,12 +45,19 @@ abstract class BaseActivity: AppCompatActivity(), SubscriptionsHolder { } } + /** Для использования в feature модулях */ + private fun initLayoutFromConstructor() { + if (layoutId != 0) { + setContentView(layoutId) + } + } + protected fun replaceFragment(container: Int, fragment: Fragment, addToBackStack: Boolean) { val transaction = supportFragmentManager - .beginTransaction() - .replace(container, fragment) + .beginTransaction() + .replace(container, fragment) - if(addToBackStack) { + if (addToBackStack) { transaction.addToBackStack(null) } diff --git a/base/core/src/main/java/com/dmity/androidacademy/core/di/AppProvider.kt b/base/core/src/main/java/com/dmity/androidacademy/core/di/AppProvider.kt new file mode 100644 index 0000000..e567525 --- /dev/null +++ b/base/core/src/main/java/com/dmity/androidacademy/core/di/AppProvider.kt @@ -0,0 +1,8 @@ +package com.dmity.androidacademy.core.di + +import android.content.Context + +interface AppProvider { + + fun provideContext(): Context +} \ No newline at end of file diff --git a/base/core/src/main/java/com/dmity/androidacademy/core/di/AppWithFacade.kt b/base/core/src/main/java/com/dmity/androidacademy/core/di/AppWithFacade.kt new file mode 100644 index 0000000..787409f --- /dev/null +++ b/base/core/src/main/java/com/dmity/androidacademy/core/di/AppWithFacade.kt @@ -0,0 +1,7 @@ +package com.dmity.androidacademy.core.di + +interface AppWithFacade { + + fun getFacade(): ProvidersFacade + +} \ No newline at end of file diff --git a/base/core/src/main/java/com/dmity/androidacademy/core/di/CoreProvidersFactory.kt b/base/core/src/main/java/com/dmity/androidacademy/core/di/CoreProvidersFactory.kt new file mode 100644 index 0000000..b012efa --- /dev/null +++ b/base/core/src/main/java/com/dmity/androidacademy/core/di/CoreProvidersFactory.kt @@ -0,0 +1,11 @@ +package com.dmity.androidacademy.core.di + +import com.dmity.androidacademy.core.di.viewModel.DaggerViewModelComponent +import com.dmity.androidacademy.core.di.viewModel.ViewModelsProvider + +object CoreProvidersFactory { + + fun createViewModelBuilder(): ViewModelsProvider { + return DaggerViewModelComponent.create() + } +} \ No newline at end of file diff --git a/base/core/src/main/java/com/dmity/androidacademy/core/di/ProvidersFacade.kt b/base/core/src/main/java/com/dmity/androidacademy/core/di/ProvidersFacade.kt new file mode 100644 index 0000000..21ea115 --- /dev/null +++ b/base/core/src/main/java/com/dmity/androidacademy/core/di/ProvidersFacade.kt @@ -0,0 +1,3 @@ +package com.dmity.androidacademy.core.di + +interface ProvidersFacade : AppProvider \ No newline at end of file diff --git a/base/core/src/main/java/com/dmity/androidacademy/core/di/viewModel/ViewModelComponent.kt b/base/core/src/main/java/com/dmity/androidacademy/core/di/viewModel/ViewModelComponent.kt new file mode 100644 index 0000000..222efd3 --- /dev/null +++ b/base/core/src/main/java/com/dmity/androidacademy/core/di/viewModel/ViewModelComponent.kt @@ -0,0 +1,9 @@ +package com.dmity.androidacademy.core.di.viewModel + +import dagger.Component +import javax.inject.Singleton + +@Singleton +@Component(modules = [ViewModelModule::class]) +interface ViewModelComponent : + ViewModelsProvider \ No newline at end of file diff --git a/base/core/src/main/java/com/dmity/androidacademy/core/di/viewModel/ViewModelFactoryProvider.kt b/base/core/src/main/java/com/dmity/androidacademy/core/di/viewModel/ViewModelFactoryProvider.kt new file mode 100644 index 0000000..4a66bc9 --- /dev/null +++ b/base/core/src/main/java/com/dmity/androidacademy/core/di/viewModel/ViewModelFactoryProvider.kt @@ -0,0 +1,20 @@ +package com.dmity.androidacademy.core.di.viewModel + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import javax.inject.Inject + +class ViewModelFactoryProvider +@Inject constructor( + private val creators: @JvmSuppressWildcards MutableMap, ViewModel> +) : ViewModelProvider.Factory { + + override fun create(modelClass: Class): T { + val found = creators.entries.find { + modelClass.isAssignableFrom(it.key) + } + val creator = found?.value + ?: throw ClassNotFoundException("no model provided with for ${modelClass.simpleName}") + return creator as T + } +} \ No newline at end of file diff --git a/app/src/main/java/com/dmity/androidacademy/di/utils/ViewModelKey.kt b/base/core/src/main/java/com/dmity/androidacademy/core/di/viewModel/ViewModelKey.kt similarity index 86% rename from app/src/main/java/com/dmity/androidacademy/di/utils/ViewModelKey.kt rename to base/core/src/main/java/com/dmity/androidacademy/core/di/viewModel/ViewModelKey.kt index 6f4d085..ef0c289 100644 --- a/app/src/main/java/com/dmity/androidacademy/di/utils/ViewModelKey.kt +++ b/base/core/src/main/java/com/dmity/androidacademy/core/di/viewModel/ViewModelKey.kt @@ -1,4 +1,4 @@ -package com.dmity.androidacademy.di.utils +package com.dmity.androidacademy.core.di.viewModel import androidx.lifecycle.ViewModel import dagger.MapKey diff --git a/base/core/src/main/java/com/dmity/androidacademy/core/di/viewModel/ViewModelModule.kt b/base/core/src/main/java/com/dmity/androidacademy/core/di/viewModel/ViewModelModule.kt new file mode 100644 index 0000000..7037a75 --- /dev/null +++ b/base/core/src/main/java/com/dmity/androidacademy/core/di/viewModel/ViewModelModule.kt @@ -0,0 +1,25 @@ +package com.dmity.androidacademy.core.di.viewModel + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import dagger.Module +import dagger.Provides +import javax.inject.Singleton + +@Module +class ViewModelModule { + + @Provides + @Singleton + fun viewModelsHolder(): @JvmSuppressWildcards MutableMap, ViewModel> { + return mutableMapOf() + } + + @Provides + @Singleton + fun bindsFactory(map: @JvmSuppressWildcards MutableMap, ViewModel>): ViewModelProvider.Factory { + return ViewModelFactoryProvider( + map + ) + } +} \ No newline at end of file diff --git a/base/core/src/main/java/com/dmity/androidacademy/core/di/viewModel/ViewModelsProvider.kt b/base/core/src/main/java/com/dmity/androidacademy/core/di/viewModel/ViewModelsProvider.kt new file mode 100644 index 0000000..9754101 --- /dev/null +++ b/base/core/src/main/java/com/dmity/androidacademy/core/di/viewModel/ViewModelsProvider.kt @@ -0,0 +1,11 @@ +package com.dmity.androidacademy.core.di.viewModel + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider + +interface ViewModelsProvider { + + fun provideMap(): @JvmSuppressWildcards MutableMap, ViewModel> + + fun provideViewModel(): ViewModelProvider.Factory +} \ No newline at end of file diff --git a/build.gradle b/build.gradle index fbd05d3..d07100d 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.5.2' + classpath 'com.android.tools.build:gradle:3.5.3' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // NOTE: Do not place your application dependencies here; they belong diff --git a/features/feature_onboarding/build.gradle b/features/feature_onboarding/build.gradle index 4513b55..8afabd5 100644 --- a/features/feature_onboarding/build.gradle +++ b/features/feature_onboarding/build.gradle @@ -26,5 +26,7 @@ dependencies { // Other implementation 'me.relex:circleindicator:2.1.4' + kapt dagger2.daggerCompiler + } \ No newline at end of file diff --git a/features/feature_onboarding/src/androidTest/java/com/dmity/androidacademy/feature_onboarding/ExampleInstrumentedTest.kt b/features/feature_onboarding/src/androidTest/java/com/dmity/androidacademy/feature_onboarding/ExampleInstrumentedTest.kt index c911051..a730126 100644 --- a/features/feature_onboarding/src/androidTest/java/com/dmity/androidacademy/feature_onboarding/ExampleInstrumentedTest.kt +++ b/features/feature_onboarding/src/androidTest/java/com/dmity/androidacademy/feature_onboarding/ExampleInstrumentedTest.kt @@ -1,22 +1,10 @@ package com.dmity.androidacademy.feature_onboarding -import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.test.platform.app.InstrumentationRegistry -import org.junit.Assert.assertEquals -import org.junit.Test -import org.junit.runner.RunWith - /** * Instrumented test, which will execute on an Android device. * * See [testing documentation](http://d.android.com/tools/testing). */ -@RunWith(AndroidJUnit4::class) class ExampleInstrumentedTest { - @Test - fun useAppContext() { - // Context of the app under test. - val appContext = InstrumentationRegistry.getInstrumentation().targetContext - assertEquals("com.dmity.androidacademy.feature_onboarding.test", appContext.packageName) - } + } diff --git a/features/feature_onboarding/src/main/java/com/dmity/androidacademy/feature_onboarding/di/OnboardingComponent.kt b/features/feature_onboarding/src/main/java/com/dmity/androidacademy/feature_onboarding/di/OnboardingComponent.kt new file mode 100644 index 0000000..acc5a98 --- /dev/null +++ b/features/feature_onboarding/src/main/java/com/dmity/androidacademy/feature_onboarding/di/OnboardingComponent.kt @@ -0,0 +1,30 @@ +package com.dmity.androidacademy.feature_onboarding.di + +import com.dmity.androidacademy.core.di.CoreProvidersFactory +import com.dmity.androidacademy.core.di.ProvidersFacade +import com.dmity.androidacademy.core.di.viewModel.ViewModelsProvider +import com.dmity.androidacademy.feature_onboarding.view.OnBoardingActivity +import dagger.Component +import javax.inject.Singleton + +@Singleton +@Component( + modules = [OnboardingModule::class], + dependencies = [ProvidersFacade::class, ViewModelsProvider::class] +) +interface OnboardingComponent : + ViewModelsProvider { + + companion object { + + fun create(providersFacade: ProvidersFacade): OnboardingComponent { + return DaggerOnboardingComponent + .builder() + .viewModelsProvider(CoreProvidersFactory.createViewModelBuilder()) + .providersFacade(providersFacade) + .build() + } + } + + fun inject(onBoardingActivity: OnBoardingActivity) +} \ No newline at end of file diff --git a/features/feature_onboarding/src/main/java/com/dmity/androidacademy/feature_onboarding/di/OnboardingModule.kt b/features/feature_onboarding/src/main/java/com/dmity/androidacademy/feature_onboarding/di/OnboardingModule.kt new file mode 100644 index 0000000..495f75c --- /dev/null +++ b/features/feature_onboarding/src/main/java/com/dmity/androidacademy/feature_onboarding/di/OnboardingModule.kt @@ -0,0 +1,49 @@ +package com.dmity.androidacademy.feature_onboarding.di + +import android.app.Application +import android.content.Context +import androidx.lifecycle.ViewModel +import com.dmity.androidacademy.domain.interactor.GetOnboardingVisibilityInteractor +import com.dmity.androidacademy.domain.repo.OnBoardingRepo +import com.dmity.androidacademy.feature_onboarding.repo.OnBoardingRepoImpl +import com.dmity.androidacademy.feature_onboarding.viewModel.OnBoardingViewModel +import dagger.Binds +import dagger.Module +import dagger.Provides +import javax.inject.Singleton + +@Module +abstract class OnboardingModule { + + @Binds + @Singleton + abstract fun bindsBoardingRepo(onBoardingRepo: OnBoardingRepoImpl): OnBoardingRepo + + + @Module + companion object { + + @Provides + @Singleton + @JvmStatic + fun provideOnBoardingViewModel( + map: @JvmSuppressWildcards MutableMap, ViewModel>, + getOnboardingVisibilityInteractor: GetOnboardingVisibilityInteractor, + context: Context, + onBoardingRepo: OnBoardingRepo + ): ViewModel = OnBoardingViewModel( + application = context as Application, + getOnboardingVisibilityInteractor = getOnboardingVisibilityInteractor, + onBoardingRepo = onBoardingRepo + ).also { + map[OnBoardingViewModel::class.java] = it + } + + @Provides + @Singleton + @JvmStatic + fun provideDummy(viewModel: ViewModel) = EagerTrigger() + } +} + +class EagerTrigger \ No newline at end of file diff --git a/features/feature_onboarding/src/main/java/com/dmity/androidacademy/feature_onboarding/repo/OnBoardingRepoImpl.kt b/features/feature_onboarding/src/main/java/com/dmity/androidacademy/feature_onboarding/repo/OnBoardingRepoImpl.kt new file mode 100644 index 0000000..db15c64 --- /dev/null +++ b/features/feature_onboarding/src/main/java/com/dmity/androidacademy/feature_onboarding/repo/OnBoardingRepoImpl.kt @@ -0,0 +1,34 @@ +package com.dmity.androidacademy.feature_onboarding.repo + +import android.content.Context +import android.content.Context.MODE_PRIVATE +import android.content.SharedPreferences +import com.dmity.androidacademy.domain.repo.OnBoardingRepo +import javax.inject.Inject + +class OnBoardingRepoImpl @Inject constructor(context: Context) : OnBoardingRepo { + + private var writer: SharedPreferences.Editor + private val reader: SharedPreferences + + init { + reader = context.getSharedPreferences(ON_BOARD, MODE_PRIVATE) + writer = reader.edit() + } + + override fun incrementCounter() { + val counter = getCounter() + writer.putInt(LAUNCH_COUNTER, counter + 1).apply() + } + + override fun getCounter(): Int { + return reader.getInt(LAUNCH_COUNTER, 0) + } + + companion object { + private const val ON_BOARD = "on_board" + private const val LAUNCH_COUNTER = "launch_counter" + } + + +} \ No newline at end of file diff --git a/features/feature_onboarding/src/main/java/com/dmity/androidacademy/feature_onboarding/view/OnBoardingActivity.kt b/features/feature_onboarding/src/main/java/com/dmity/androidacademy/feature_onboarding/view/OnBoardingActivity.kt new file mode 100644 index 0000000..e49af9f --- /dev/null +++ b/features/feature_onboarding/src/main/java/com/dmity/androidacademy/feature_onboarding/view/OnBoardingActivity.kt @@ -0,0 +1,85 @@ +package com.dmity.androidacademy.feature_onboarding.view + + +import android.os.Bundle +import androidx.activity.viewModels +import androidx.fragment.app.FragmentManager +import androidx.fragment.app.FragmentPagerAdapter +import androidx.lifecycle.Observer +import androidx.lifecycle.ViewModelProvider +import com.dmity.androidacademy.core.BaseActivity +import com.dmity.androidacademy.core.di.AppWithFacade +import com.dmity.androidacademy.feature_onboarding.R +import com.dmity.androidacademy.feature_onboarding.di.EagerTrigger +import com.dmity.androidacademy.feature_onboarding.di.OnboardingComponent +import com.dmity.androidacademy.feature_onboarding.viewModel.OnBoardingViewModel +import kotlinx.android.synthetic.main.activity_onboarding.* +import javax.inject.Inject + +class OnBoardingActivity : BaseActivity(layoutId = R.layout.activity_onboarding) { + + @Inject + lateinit var eagerTrigger: EagerTrigger + + @Inject + lateinit var viewModelFactory: ViewModelProvider.Factory + + private val viewModel: OnBoardingViewModel by viewModels { viewModelFactory } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + OnboardingComponent.create((application as AppWithFacade).getFacade()).inject(this) + initObserver() + } + + override fun onBackPressed() { + if (viewpager.currentItem == 0) { + super.onBackPressed() + } else { + viewpager.currentItem = viewpager.currentItem - 1 + } + } + + private fun initObserver() { + viewModel.showOnBoarding.observe(this, Observer { showOnBoarding -> + if (showOnBoarding) { + setContentView(R.layout.activity_onboarding) + setupTabs() + setSkipBtn() + } + }) + } + + private fun setSkipBtn() { + btnSkip.setOnClickListener { + finish() +// MainActivity.display(this) + } + } + + private fun setupTabs() { + viewpager.adapter = OnBoardingPagerAdapter(supportFragmentManager) + indicator.setViewPager(viewpager) + } + + private inner class OnBoardingPagerAdapter(fm: FragmentManager) : FragmentPagerAdapter(fm) { + + val images = listOf( + R.drawable.ic_onboarding, + R.drawable.ic_onboarding_2 + ) + val titles = listOf( + R.string.onboarding_title_page_1, + R.string.onboarding_title_page_2 + ) + + override fun getItem(position: Int) = + OnBoardingFragment.newInstance( + images[position], + titles[position] + ) + + override fun getCount() = images.size + } + +} diff --git a/app/src/main/java/com/dmity/androidacademy/features/onboarding/OnBoardingFragment.kt b/features/feature_onboarding/src/main/java/com/dmity/androidacademy/feature_onboarding/view/OnBoardingFragment.kt similarity index 93% rename from app/src/main/java/com/dmity/androidacademy/features/onboarding/OnBoardingFragment.kt rename to features/feature_onboarding/src/main/java/com/dmity/androidacademy/feature_onboarding/view/OnBoardingFragment.kt index 973f7ff..6613f62 100644 --- a/app/src/main/java/com/dmity/androidacademy/features/onboarding/OnBoardingFragment.kt +++ b/features/feature_onboarding/src/main/java/com/dmity/androidacademy/feature_onboarding/view/OnBoardingFragment.kt @@ -1,4 +1,4 @@ -package com.dmity.androidacademy.features.onboarding +package com.dmity.androidacademy.feature_onboarding.view import android.os.Bundle @@ -7,7 +7,7 @@ import android.view.View import android.view.ViewGroup import androidx.core.content.ContextCompat import androidx.fragment.app.Fragment -import com.dmity.androidacademy.R +import com.dmity.androidacademy.feature_onboarding.R import kotlinx.android.synthetic.main.fragment_onboarding.* private const val ARG_IMAGE_ID = "image_id" diff --git a/features/feature_onboarding/src/main/java/com/dmity/androidacademy/feature_onboarding/viewModel/OnBoardingViewModel.kt b/features/feature_onboarding/src/main/java/com/dmity/androidacademy/feature_onboarding/viewModel/OnBoardingViewModel.kt new file mode 100644 index 0000000..f78fe4d --- /dev/null +++ b/features/feature_onboarding/src/main/java/com/dmity/androidacademy/feature_onboarding/viewModel/OnBoardingViewModel.kt @@ -0,0 +1,68 @@ +package com.dmity.androidacademy.feature_onboarding.viewModel + +import android.app.Application +import android.content.Context +import android.widget.Toast +import androidx.lifecycle.AndroidViewModel +import androidx.lifecycle.MutableLiveData +import com.dmity.androidacademy.core.SubscriptionsHolder +import com.dmity.androidacademy.domain.interactor.GetOnboardingVisibilityInteractor +import com.dmity.androidacademy.domain.repo.OnBoardingRepo +import io.reactivex.Completable +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.CompositeDisposable +import java.util.concurrent.TimeUnit +import javax.inject.Inject + +class OnBoardingViewModel @Inject constructor( + application: Application, + private val getOnboardingVisibilityInteractor: GetOnboardingVisibilityInteractor, + private val onBoardingRepo: OnBoardingRepo +) : + AndroidViewModel(application), + SubscriptionsHolder { + + override val disposables: CompositeDisposable = CompositeDisposable() + private var context: Context = getApplication() + val showOnBoarding = MutableLiveData() + + init { +// NewsApp.getAppComponent().inject(this) + setupOnBoarding() + } + + override fun onCleared() { + super.onCleared() + resetCompositeDisposable() + } + + private fun setupOnBoarding() { + + if (getOnboardingVisibilityInteractor.execute()) { + + showOnBoarding.value = true + + Completable.complete() + .delay(DELAY_IN_SECONDS, TimeUnit.SECONDS) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe { + Toast.makeText(context, "Навигация на MainActivity", Toast.LENGTH_LONG).show() +// MainActivity.display(context) + } + .bind() + } else { + showOnBoarding.value = false + Toast.makeText(context, "Навигация на MainActivity", Toast.LENGTH_LONG).show() + +// MainActivity.display(context) + } + + onBoardingRepo.incrementCounter() + + } + + companion object { + private const val DELAY_IN_SECONDS = 15L + } + +} \ No newline at end of file