From 671cbe9c6061d6d635ec81240b892ca17d8f91f9 Mon Sep 17 00:00:00 2001 From: Giuseppe Filograno Date: Fri, 1 May 2020 19:14:09 +0200 Subject: [PATCH 1/9] Add SplashActivity --- app/src/main/AndroidManifest.xml | 10 +++++++--- .../example/android/dagger/splash/SplashActivity.kt | 11 +++++++++++ 2 files changed, 18 insertions(+), 3 deletions(-) create mode 100644 app/src/main/java/com/example/android/dagger/splash/SplashActivity.kt diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 09ae1a34..a966eb7a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -27,14 +27,18 @@ android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> - + + + @@ -46,4 +50,4 @@ android:screenOrientation="portrait" /> - + \ No newline at end of file diff --git a/app/src/main/java/com/example/android/dagger/splash/SplashActivity.kt b/app/src/main/java/com/example/android/dagger/splash/SplashActivity.kt new file mode 100644 index 00000000..8da0d3d0 --- /dev/null +++ b/app/src/main/java/com/example/android/dagger/splash/SplashActivity.kt @@ -0,0 +1,11 @@ +package com.example.android.dagger.splash + +import androidx.appcompat.app.AppCompatActivity +import android.os.Bundle + +class SplashActivity : AppCompatActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + } +} From 5c3d6aac6df1fae529ec2b3da403ddc2fd162d02 Mon Sep 17 00:00:00 2001 From: Giuseppe Filograno Date: Fri, 1 May 2020 19:19:13 +0200 Subject: [PATCH 2/9] Add SplashViewModel --- .../com/example/android/dagger/splash/SplashViewModel.kt | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 app/src/main/java/com/example/android/dagger/splash/SplashViewModel.kt diff --git a/app/src/main/java/com/example/android/dagger/splash/SplashViewModel.kt b/app/src/main/java/com/example/android/dagger/splash/SplashViewModel.kt new file mode 100644 index 00000000..6b010a4c --- /dev/null +++ b/app/src/main/java/com/example/android/dagger/splash/SplashViewModel.kt @@ -0,0 +1,6 @@ +package com.example.android.dagger.splash + +import javax.inject.Inject + +class SplashViewModel @Inject constructor() { +} \ No newline at end of file From b46ec11b05b4a3e3f694dabe59a6216c274b1bee Mon Sep 17 00:00:00 2001 From: Giuseppe Filograno Date: Fri, 1 May 2020 19:26:05 +0200 Subject: [PATCH 3/9] Add SplashComponent --- .../example/android/dagger/di/AppComponent.kt | 2 ++ .../android/dagger/di/AppSubcomponents.kt | 4 +++- .../android/dagger/splash/SplashComponent.kt | 19 +++++++++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/com/example/android/dagger/splash/SplashComponent.kt diff --git a/app/src/main/java/com/example/android/dagger/di/AppComponent.kt b/app/src/main/java/com/example/android/dagger/di/AppComponent.kt index c65c7bac..f1f6c0da 100644 --- a/app/src/main/java/com/example/android/dagger/di/AppComponent.kt +++ b/app/src/main/java/com/example/android/dagger/di/AppComponent.kt @@ -19,6 +19,7 @@ package com.example.android.dagger.di import android.content.Context import com.example.android.dagger.login.LoginComponent import com.example.android.dagger.registration.RegistrationComponent +import com.example.android.dagger.splash.SplashComponent import com.example.android.dagger.user.UserManager import dagger.BindsInstance import dagger.Component @@ -42,4 +43,5 @@ interface AppComponent { fun registrationComponent(): RegistrationComponent.Factory fun loginComponent(): LoginComponent.Factory fun userManager(): UserManager + fun splashComponent(): SplashComponent.Factory } diff --git a/app/src/main/java/com/example/android/dagger/di/AppSubcomponents.kt b/app/src/main/java/com/example/android/dagger/di/AppSubcomponents.kt index fa2335da..d3ed0f27 100644 --- a/app/src/main/java/com/example/android/dagger/di/AppSubcomponents.kt +++ b/app/src/main/java/com/example/android/dagger/di/AppSubcomponents.kt @@ -18,6 +18,7 @@ package com.example.android.dagger.di import com.example.android.dagger.login.LoginComponent import com.example.android.dagger.registration.RegistrationComponent +import com.example.android.dagger.splash.SplashComponent import com.example.android.dagger.user.UserComponent import dagger.Module @@ -26,7 +27,8 @@ import dagger.Module subcomponents = [ RegistrationComponent::class, LoginComponent::class, - UserComponent::class + UserComponent::class, + SplashComponent::class ] ) class AppSubcomponents diff --git a/app/src/main/java/com/example/android/dagger/splash/SplashComponent.kt b/app/src/main/java/com/example/android/dagger/splash/SplashComponent.kt new file mode 100644 index 00000000..797d7e92 --- /dev/null +++ b/app/src/main/java/com/example/android/dagger/splash/SplashComponent.kt @@ -0,0 +1,19 @@ +package com.example.android.dagger.splash + +import com.example.android.dagger.di.ActivityScope +import dagger.Subcomponent + +// Scope annotation that the SplashComponent uses +// Classes annotated with @ActivityScope will have a unique instance in this Component +@ActivityScope +// Definition of a Dagger subcomponent +@Subcomponent +interface SplashComponent { + @Subcomponent.Factory + interface Factory { + fun create(): SplashComponent + } + + // Classes that can be injected by this Component + fun inject(activity: SplashActivity) +} \ No newline at end of file From d54555100feca7eba61a736969b41f1c7c3fe1e8 Mon Sep 17 00:00:00 2001 From: Giuseppe Filograno Date: Fri, 1 May 2020 19:29:31 +0200 Subject: [PATCH 4/9] Add injection for SplashActivity and SplashViewModel --- .../example/android/dagger/splash/SplashActivity.kt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/app/src/main/java/com/example/android/dagger/splash/SplashActivity.kt b/app/src/main/java/com/example/android/dagger/splash/SplashActivity.kt index 8da0d3d0..c53a487e 100644 --- a/app/src/main/java/com/example/android/dagger/splash/SplashActivity.kt +++ b/app/src/main/java/com/example/android/dagger/splash/SplashActivity.kt @@ -2,10 +2,20 @@ package com.example.android.dagger.splash import androidx.appcompat.app.AppCompatActivity import android.os.Bundle +import com.example.android.dagger.MyApplication +import javax.inject.Inject class SplashActivity : AppCompatActivity() { + // @Inject annotated fields will be provided by Dagger + @Inject + lateinit var splashViewModel: SplashViewModel + override fun onCreate(savedInstanceState: Bundle?) { + + // Creates an instance of Splash component by grabbing the factory from the app graph + // and injects this activity to that Component + (application as MyApplication).appComponent.splashComponent().create().inject(this) super.onCreate(savedInstanceState) } } From dc1be6f543a1c80bd3cd8d4f9d0730c298c40939 Mon Sep 17 00:00:00 2001 From: Giuseppe Filograno Date: Fri, 1 May 2020 20:01:21 +0200 Subject: [PATCH 5/9] Add logic to show the right Activity --- .../android/dagger/splash/SplashActivity.kt | 8 +++++ .../android/dagger/splash/SplashViewModel.kt | 30 ++++++++++++++++++- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/example/android/dagger/splash/SplashActivity.kt b/app/src/main/java/com/example/android/dagger/splash/SplashActivity.kt index c53a487e..47b64e44 100644 --- a/app/src/main/java/com/example/android/dagger/splash/SplashActivity.kt +++ b/app/src/main/java/com/example/android/dagger/splash/SplashActivity.kt @@ -1,5 +1,6 @@ package com.example.android.dagger.splash +import android.content.Intent import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import com.example.android.dagger.MyApplication @@ -17,5 +18,12 @@ class SplashActivity : AppCompatActivity() { // and injects this activity to that Component (application as MyApplication).appComponent.splashComponent().create().inject(this) super.onCreate(savedInstanceState) + showActivity() + } + + private fun showActivity() { + val activity = splashViewModel.getActivityClass() + startActivity(Intent(this, activity)) + finish() } } diff --git a/app/src/main/java/com/example/android/dagger/splash/SplashViewModel.kt b/app/src/main/java/com/example/android/dagger/splash/SplashViewModel.kt index 6b010a4c..f6f66366 100644 --- a/app/src/main/java/com/example/android/dagger/splash/SplashViewModel.kt +++ b/app/src/main/java/com/example/android/dagger/splash/SplashViewModel.kt @@ -1,6 +1,34 @@ package com.example.android.dagger.splash +import androidx.appcompat.app.AppCompatActivity +import com.example.android.dagger.login.LoginActivity +import com.example.android.dagger.main.MainActivity +import com.example.android.dagger.registration.RegistrationActivity +import com.example.android.dagger.user.UserManager import javax.inject.Inject -class SplashViewModel @Inject constructor() { +/** + * SplashViewModel is the ViewModel that [SplashActivity] uses to + * obtain information of what Activity to show on the screen. + * + * @Inject tells Dagger how to provide instances of this type. Dagger also knows + * that UserManager is a dependency. + */ +class SplashViewModel @Inject constructor(private val userManager: UserManager) { + + /** + * If the User is not registered, RegistrationActivity will be returned, + * If the User is not logged in, LoginActivity will be returned, + * else MainActivity. + */ + fun getActivityClass(): Class = + if (!userManager.isUserLoggedIn()) { + if (!userManager.isUserRegistered()) { + RegistrationActivity::class.java + } else { + LoginActivity::class.java + } + } else { + MainActivity::class.java + } } \ No newline at end of file From 5915b88ce4f14c1df3daaf62713e38b5f6a15e39 Mon Sep 17 00:00:00 2001 From: Giuseppe Filograno Date: Fri, 1 May 2020 20:01:45 +0200 Subject: [PATCH 6/9] Add ActivityScope to SplashViewModel --- .../java/com/example/android/dagger/splash/SplashViewModel.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/com/example/android/dagger/splash/SplashViewModel.kt b/app/src/main/java/com/example/android/dagger/splash/SplashViewModel.kt index f6f66366..9a957693 100644 --- a/app/src/main/java/com/example/android/dagger/splash/SplashViewModel.kt +++ b/app/src/main/java/com/example/android/dagger/splash/SplashViewModel.kt @@ -1,6 +1,7 @@ package com.example.android.dagger.splash import androidx.appcompat.app.AppCompatActivity +import com.example.android.dagger.di.ActivityScope import com.example.android.dagger.login.LoginActivity import com.example.android.dagger.main.MainActivity import com.example.android.dagger.registration.RegistrationActivity @@ -14,6 +15,7 @@ import javax.inject.Inject * @Inject tells Dagger how to provide instances of this type. Dagger also knows * that UserManager is a dependency. */ +@ActivityScope class SplashViewModel @Inject constructor(private val userManager: UserManager) { /** From f99b4267e1a95344b5f1c388889b603c69e23539 Mon Sep 17 00:00:00 2001 From: Giuseppe Filograno Date: Fri, 1 May 2020 20:03:50 +0200 Subject: [PATCH 7/9] Delete the display logic from the MainActivity --- .../android/dagger/main/MainActivity.kt | 29 +++++-------------- 1 file changed, 7 insertions(+), 22 deletions(-) diff --git a/app/src/main/java/com/example/android/dagger/main/MainActivity.kt b/app/src/main/java/com/example/android/dagger/main/MainActivity.kt index 93be56c8..69e86db5 100644 --- a/app/src/main/java/com/example/android/dagger/main/MainActivity.kt +++ b/app/src/main/java/com/example/android/dagger/main/MainActivity.kt @@ -34,32 +34,17 @@ class MainActivity : AppCompatActivity() { @Inject lateinit var mainViewModel: MainViewModel - /** - * If the User is not registered, RegistrationActivity will be launched, - * If the User is not logged in, LoginActivity will be launched, - * else carry on with MainActivity. - */ override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - // Grabs instance of UserManager from the application graph val userManager = (application as MyApplication).appComponent.userManager() - if (!userManager.isUserLoggedIn()) { - if (!userManager.isUserRegistered()) { - startActivity(Intent(this, RegistrationActivity::class.java)) - finish() - } else { - startActivity(Intent(this, LoginActivity::class.java)) - finish() - } - } else { - setContentView(R.layout.activity_main) + // If the MainActivity needs to be displayed, we get the UserComponent from the + // application graph and gets this Activity injected + userManager.userComponent!!.inject(this) - // If the MainActivity needs to be displayed, we get the UserComponent from the - // application graph and gets this Activity injected - userManager.userComponent!!.inject(this) - setupViews() - } + super.onCreate(savedInstanceState) + + setContentView(R.layout.activity_main) + setupViews() } /** From 118cc968794610636ca45e99d5b70fcab2d996c4 Mon Sep 17 00:00:00 2001 From: Giuseppe Filograno Date: Fri, 1 May 2020 20:19:22 +0200 Subject: [PATCH 8/9] Update instrumentation test --- .../java/com/example/android/dagger/ApplicationTest.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/androidTest/java/com/example/android/dagger/ApplicationTest.kt b/app/src/androidTest/java/com/example/android/dagger/ApplicationTest.kt index 6d58f80b..d3b59d16 100644 --- a/app/src/androidTest/java/com/example/android/dagger/ApplicationTest.kt +++ b/app/src/androidTest/java/com/example/android/dagger/ApplicationTest.kt @@ -21,14 +21,14 @@ import androidx.test.espresso.Espresso.onView import androidx.test.espresso.action.ViewActions.* import androidx.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.matcher.ViewMatchers.* -import com.example.android.dagger.main.MainActivity +import com.example.android.dagger.splash.SplashActivity import org.junit.Test class ApplicationTest { @Test fun runApp() { - ActivityScenario.launch(MainActivity::class.java) + ActivityScenario.launch(SplashActivity::class.java) // Should be in Registration/EnterDetails because the user is not registered onView(withText("Register to Dagger World!")).check(matches(isDisplayed())) From 7f9b88da794fa8528c9c63d19b6e1f622fd49a7b Mon Sep 17 00:00:00 2001 From: Giuseppe Filograno Date: Sat, 2 May 2020 16:50:34 +0200 Subject: [PATCH 9/9] Add unit tests on SplashViewModel --- .../dagger/splash/SplashViewModelTest.kt | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 app/src/test/java/com/example/android/dagger/splash/SplashViewModelTest.kt diff --git a/app/src/test/java/com/example/android/dagger/splash/SplashViewModelTest.kt b/app/src/test/java/com/example/android/dagger/splash/SplashViewModelTest.kt new file mode 100644 index 00000000..543843f9 --- /dev/null +++ b/app/src/test/java/com/example/android/dagger/splash/SplashViewModelTest.kt @@ -0,0 +1,45 @@ +package com.example.android.dagger.splash + +import com.example.android.dagger.login.LoginActivity +import com.example.android.dagger.main.MainActivity +import com.example.android.dagger.registration.RegistrationActivity +import com.example.android.dagger.user.UserManager +import org.junit.Assert.assertEquals +import org.junit.Before +import org.junit.Test +import org.mockito.Mockito.mock +import org.mockito.Mockito.`when` as whenever + +class SplashViewModelTest { + + private lateinit var userManager: UserManager + private lateinit var viewModel: SplashViewModel + + @Before + fun setup() { + userManager = mock(UserManager::class.java) + viewModel = SplashViewModel(userManager) + } + + @Test + fun `If the user is not registered then getActivityClass returns RegistrationActivity`() { + whenever(userManager.isUserRegistered()).thenReturn(false) + + assertEquals(RegistrationActivity::class.java, viewModel.getActivityClass()) + } + + @Test + fun `If the user is registered but not logged in then getActivityClass returns LoginActivity`() { + whenever(userManager.isUserRegistered()).thenReturn(true) + whenever(userManager.isUserLoggedIn()).thenReturn(false) + + assertEquals(LoginActivity::class.java, viewModel.getActivityClass()) + } + + @Test + fun `If the user is logged in then getActivityClass returns MainActivity`() { + whenever(userManager.isUserLoggedIn()).thenReturn(true) + + assertEquals(MainActivity::class.java, viewModel.getActivityClass()) + } +} \ No newline at end of file