From c6fc8630f3bf53e52cdc490334c1f74fcf8307f4 Mon Sep 17 00:00:00 2001 From: Santiago Andracchi Date: Mon, 20 Sep 2021 18:52:11 -0300 Subject: [PATCH 1/2] Add koin as DI instead of dagger-hilt Use Koin as dependency inyector --- .gitignore | 9 +-- app/build.gradle | 13 ++-- .../android/tests/utils/PrefTests.kt | 2 - .../main/java/com/rootstrap/android/App.kt | 10 +++- .../com/rootstrap/android/di/AppModule.kt | 35 +++++++++++ .../android/network/managers/ManagerModule.kt | 24 -------- .../managers/session/SessionManagerImpl.kt | 3 +- .../network/managers/user/UserManagerImpl.kt | 10 ++-- .../user/UserManagerRetrofitBuilder.kt | 59 +++++++++++++++++++ .../user/UserManagerService.kt} | 4 +- .../providers/ServiceProviderModule.kt | 57 ------------------ .../android/network/services/ApiModule.kt | 17 ------ .../services/AuthenticationInterceptor.kt | 3 +- .../network/services/ResponseInterceptor.kt | 6 +- .../ui/activity/main/ProfileActivity.kt | 13 ++-- .../activity/main/ProfileActivityViewModel.kt | 3 +- .../ui/activity/main/SignInActivity.kt | 8 +-- .../activity/main/SignInActivityViewModel.kt | 3 +- .../ui/activity/main/SignUpActivity.kt | 8 +-- .../activity/main/SignUpActivityViewModel.kt | 3 +- .../rootstrap/android/ui/base/BaseActivity.kt | 4 +- .../java/com/rootstrap/android/util/Prefs.kt | 3 +- 22 files changed, 134 insertions(+), 163 deletions(-) create mode 100644 app/src/main/java/com/rootstrap/android/di/AppModule.kt delete mode 100644 app/src/main/java/com/rootstrap/android/network/managers/ManagerModule.kt create mode 100644 app/src/main/java/com/rootstrap/android/network/managers/user/UserManagerRetrofitBuilder.kt rename app/src/main/java/com/rootstrap/android/network/{services/ApiService.kt => managers/user/UserManagerService.kt} (83%) delete mode 100644 app/src/main/java/com/rootstrap/android/network/providers/ServiceProviderModule.kt delete mode 100644 app/src/main/java/com/rootstrap/android/network/services/ApiModule.kt diff --git a/.gitignore b/.gitignore index 83d8a4c..3cb6086 100644 --- a/.gitignore +++ b/.gitignore @@ -2,14 +2,7 @@ .gradle /local.properties /gradle.properties -/.idea/caches -/.idea/libraries -/.idea/modules.xml -/.idea/workspace.xml -/.idea/navEditor.xml -/.idea/assetWizardSettings.xml -/.idea/gradle.xml -/.idea/* +.idea /app/prod/release/* /fastlane/report.xml .DS_Store diff --git a/app/build.gradle b/app/build.gradle index 4074a58..1477d98 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -6,8 +6,6 @@ apply plugin: 'kotlin-kapt' apply plugin: 'kotlin-android-extensions' -apply plugin: 'dagger.hilt.android.plugin' - apply plugin: 'com.google.gms.google-services' apply plugin: 'com.google.firebase.crashlytics' @@ -188,12 +186,13 @@ dependencies { //---- Linters ---- ktlint "com.pinterest:ktlint:0.35.0" //---- Hilt ---- - implementation "com.google.dagger:hilt-android:2.28-alpha" implementation 'androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha02' - kapt "com.google.dagger:hilt-android-compiler:2.28-alpha" - kapt 'androidx.hilt:hilt-compiler:1.0.0-alpha02' - androidTestImplementation 'com.google.dagger:hilt-android-testing:2.28-alpha' - kaptAndroidTest 'com.google.dagger:hilt-android-compiler:2.28-alpha' + + // Koin + def koin_version = "2.1.3" + implementation "org.koin:koin-android:$koin_version" + implementation "org.koin:koin-androidx-scope:$koin_version" + implementation "org.koin:koin-androidx-viewmodel:$koin_version" //security crypto implementation "androidx.security:security-crypto:1.1.0-alpha03" diff --git a/app/src/androidTest/java/com/rootstrap/android/tests/utils/PrefTests.kt b/app/src/androidTest/java/com/rootstrap/android/tests/utils/PrefTests.kt index fb06073..b5e1be9 100644 --- a/app/src/androidTest/java/com/rootstrap/android/tests/utils/PrefTests.kt +++ b/app/src/androidTest/java/com/rootstrap/android/tests/utils/PrefTests.kt @@ -4,7 +4,6 @@ import android.content.SharedPreferences import androidx.security.crypto.EncryptedSharedPreferences import com.rootstrap.android.util.Prefs import dagger.hilt.android.testing.HiltAndroidRule -import dagger.hilt.android.testing.HiltAndroidTest import org.junit.Assert import org.junit.Before import org.junit.Rule @@ -12,7 +11,6 @@ import org.junit.Test import java.util.* // ktlint-disable no-wildcard-imports import javax.inject.Inject -@HiltAndroidTest class PrefTests { @get:Rule var hiltRule = HiltAndroidRule(this) diff --git a/app/src/main/java/com/rootstrap/android/App.kt b/app/src/main/java/com/rootstrap/android/App.kt index 7ca19b3..205c4aa 100644 --- a/app/src/main/java/com/rootstrap/android/App.kt +++ b/app/src/main/java/com/rootstrap/android/App.kt @@ -1,16 +1,20 @@ package com.rootstrap.android import android.app.Application +import com.rootstrap.android.di.myModule import com.rootstrap.android.metrics.Analytics import com.rootstrap.android.metrics.GoogleAnalytics -import dagger.hilt.android.HiltAndroidApp +import org.koin.android.ext.koin.androidContext +import org.koin.core.context.startKoin -@HiltAndroidApp class App : Application() { override fun onCreate() { super.onCreate() - + startKoin { + androidContext(this@App) + modules(myModule) + } Analytics.addProvider(GoogleAnalytics(this)) // You need the api key in order to use MixPanel // Analytics.addProvider(MixPanelAnalytics(this)) diff --git a/app/src/main/java/com/rootstrap/android/di/AppModule.kt b/app/src/main/java/com/rootstrap/android/di/AppModule.kt new file mode 100644 index 0000000..a181773 --- /dev/null +++ b/app/src/main/java/com/rootstrap/android/di/AppModule.kt @@ -0,0 +1,35 @@ +package com.rootstrap.android.di + +import android.content.Context +import android.content.SharedPreferences +import com.rootstrap.android.network.managers.session.SessionManager +import com.rootstrap.android.network.managers.session.SessionManagerImpl +import com.rootstrap.android.network.managers.user.UserManager +import com.rootstrap.android.network.managers.user.UserManagerImpl +import com.rootstrap.android.network.managers.user.UserManagerRetrofitBuilder +import com.rootstrap.android.network.services.AuthenticationInterceptor +import com.rootstrap.android.network.services.ResponseInterceptor +import com.rootstrap.android.ui.activity.main.ProfileActivityViewModel +import com.rootstrap.android.ui.activity.main.SignInActivityViewModel +import com.rootstrap.android.ui.activity.main.SignUpActivityViewModel +import com.rootstrap.android.util.Prefs +import org.koin.android.ext.koin.androidApplication +import org.koin.core.module.Module +import org.koin.androidx.viewmodel.dsl.viewModel +import org.koin.dsl.module + +val myModule: Module = module { + + single { AuthenticationInterceptor(get()) } + single { ResponseInterceptor(get(), get()) } + single { UserManagerRetrofitBuilder(get(), get()) } + single { UserManagerImpl(get()) } + single { androidApplication().getSharedPreferences("userPreferences", Context.MODE_PRIVATE) } + factory { Prefs(get()) } + single { SessionManagerImpl(get()) } + viewModel { SignInActivityViewModel(get(), get()) } + viewModel { ProfileActivityViewModel(get(), get()) } + viewModel { SignUpActivityViewModel(get(), get()) } + // viewModel { BottomBarViewModel(androidApplication()) } + // single { provideIotDao(androidContext()) } +} diff --git a/app/src/main/java/com/rootstrap/android/network/managers/ManagerModule.kt b/app/src/main/java/com/rootstrap/android/network/managers/ManagerModule.kt deleted file mode 100644 index 6447fec..0000000 --- a/app/src/main/java/com/rootstrap/android/network/managers/ManagerModule.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.rootstrap.android.network.managers - -import com.rootstrap.android.network.managers.session.SessionManager -import com.rootstrap.android.network.managers.session.SessionManagerImpl -import com.rootstrap.android.network.managers.user.UserManager -import com.rootstrap.android.network.managers.user.UserManagerImpl -import dagger.Binds -import dagger.Module -import dagger.hilt.InstallIn -import dagger.hilt.android.components.ApplicationComponent -import javax.inject.Singleton - -@Module -@InstallIn(ApplicationComponent::class) -abstract class ManagerModule { - - @Binds - @Singleton - abstract fun bindSessionManager(sessionManagerImpl: SessionManagerImpl): SessionManager - - @Binds - @Singleton - abstract fun bindUserManager(userManagerImplImpl: UserManagerImpl): UserManager -} diff --git a/app/src/main/java/com/rootstrap/android/network/managers/session/SessionManagerImpl.kt b/app/src/main/java/com/rootstrap/android/network/managers/session/SessionManagerImpl.kt index adb674c..5bbd543 100644 --- a/app/src/main/java/com/rootstrap/android/network/managers/session/SessionManagerImpl.kt +++ b/app/src/main/java/com/rootstrap/android/network/managers/session/SessionManagerImpl.kt @@ -2,9 +2,8 @@ package com.rootstrap.android.network.managers.session import com.rootstrap.android.network.models.User import com.rootstrap.android.util.Prefs -import javax.inject.Inject -class SessionManagerImpl @Inject constructor(private val prefs: Prefs) : SessionManager { +class SessionManagerImpl(private val prefs: Prefs) : SessionManager { override var user: User? = prefs.user set(value) { diff --git a/app/src/main/java/com/rootstrap/android/network/managers/user/UserManagerImpl.kt b/app/src/main/java/com/rootstrap/android/network/managers/user/UserManagerImpl.kt index 6c048d2..238d704 100644 --- a/app/src/main/java/com/rootstrap/android/network/managers/user/UserManagerImpl.kt +++ b/app/src/main/java/com/rootstrap/android/network/managers/user/UserManagerImpl.kt @@ -2,22 +2,20 @@ package com.rootstrap.android.network.managers.user import com.rootstrap.android.network.models.User import com.rootstrap.android.network.models.UserSerializer -import com.rootstrap.android.network.services.ApiService import com.rootstrap.android.util.extensions.ActionCallback import com.rootstrap.android.util.extensions.Data -import javax.inject.Inject /** * Singleton class * */ -class UserManagerImpl @Inject constructor(private val service: ApiService) : UserManager { +class UserManagerImpl(private val apiService: UserManagerRetrofitBuilder) : UserManager { override suspend fun signUp(user: User): Result> = - ActionCallback.call(service.signUp(UserSerializer(user))) + ActionCallback.call(apiService.signUp(UserSerializer(user))) override suspend fun signIn(user: User): Result> = - ActionCallback.call(service.signIn(UserSerializer(user))) + ActionCallback.call(apiService.signIn(UserSerializer(user))) override suspend fun signOut(): Result> = - ActionCallback.call(service.signOut()) + ActionCallback.call(apiService.signOut()) } diff --git a/app/src/main/java/com/rootstrap/android/network/managers/user/UserManagerRetrofitBuilder.kt b/app/src/main/java/com/rootstrap/android/network/managers/user/UserManagerRetrofitBuilder.kt new file mode 100644 index 0000000..c1a4abd --- /dev/null +++ b/app/src/main/java/com/rootstrap/android/network/managers/user/UserManagerRetrofitBuilder.kt @@ -0,0 +1,59 @@ +package com.rootstrap.android.network.managers.user + +import com.rootstrap.android.BuildConfig +import com.rootstrap.android.network.models.UserSerializer +import com.rootstrap.android.network.services.AuthenticationInterceptor +import com.rootstrap.android.network.services.HeadersInterceptor +import com.rootstrap.android.network.services.ResponseInterceptor +import com.squareup.moshi.Moshi +import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory +import okhttp3.OkHttpClient +import okhttp3.logging.HttpLoggingInterceptor +import retrofit2.Call +import retrofit2.Retrofit +import retrofit2.converter.moshi.MoshiConverterFactory +import java.util.concurrent.TimeUnit + +class UserManagerRetrofitBuilder( + authenticationInterceptor: AuthenticationInterceptor, + responseInterceptor: ResponseInterceptor +) { + + private val httpInterceptorLevel = if (BuildConfig.DEBUG) HttpLoggingInterceptor.Level.BODY + else HttpLoggingInterceptor.Level.BASIC + + private val okHttpClient = OkHttpClient() + .newBuilder() + .connectTimeout(30, TimeUnit.SECONDS) + .writeTimeout(30, TimeUnit.SECONDS) + .readTimeout(30, TimeUnit.SECONDS) + .addInterceptor(HeadersInterceptor()) + .addInterceptor(authenticationInterceptor) + .addInterceptor(responseInterceptor) + .addInterceptor(HttpLoggingInterceptor().setLevel(httpInterceptorLevel)) + .build() + + private val moshi = Moshi.Builder() + .add(KotlinJsonAdapterFactory()) + .build() + + private val buildAuthRetrofit = Retrofit.Builder() + .baseUrl(BuildConfig.API_URL) + .addConverterFactory(MoshiConverterFactory.create(moshi).withNullSerialization()) + .client(okHttpClient) + .build() + + private val api = buildAuthRetrofit.create(UserManagerService::class.java) + + fun signIn(user: UserSerializer): Call { + return api.signIn(user) + } + + fun signOut(): Call { + return api.signOut() + } + + fun signUp(user: UserSerializer): Call { + return api.signUp(user) + } +} diff --git a/app/src/main/java/com/rootstrap/android/network/services/ApiService.kt b/app/src/main/java/com/rootstrap/android/network/managers/user/UserManagerService.kt similarity index 83% rename from app/src/main/java/com/rootstrap/android/network/services/ApiService.kt rename to app/src/main/java/com/rootstrap/android/network/managers/user/UserManagerService.kt index 2a832fd..5d5b8b8 100644 --- a/app/src/main/java/com/rootstrap/android/network/services/ApiService.kt +++ b/app/src/main/java/com/rootstrap/android/network/managers/user/UserManagerService.kt @@ -1,4 +1,4 @@ -package com.rootstrap.android.network.services +package com.rootstrap.android.network.managers.user import com.rootstrap.android.network.models.UserSerializer import retrofit2.Call @@ -6,7 +6,7 @@ import retrofit2.http.Body import retrofit2.http.DELETE import retrofit2.http.POST -interface ApiService { +interface UserManagerService { @POST("users/") fun signUp(@Body user: UserSerializer): Call diff --git a/app/src/main/java/com/rootstrap/android/network/providers/ServiceProviderModule.kt b/app/src/main/java/com/rootstrap/android/network/providers/ServiceProviderModule.kt deleted file mode 100644 index 8665732..0000000 --- a/app/src/main/java/com/rootstrap/android/network/providers/ServiceProviderModule.kt +++ /dev/null @@ -1,57 +0,0 @@ -package com.rootstrap.android.network.providers - -import com.rootstrap.android.BuildConfig -import com.rootstrap.android.network.services.AuthenticationInterceptor -import com.rootstrap.android.network.services.HeadersInterceptor -import com.rootstrap.android.network.services.ResponseInterceptor -import com.squareup.moshi.Moshi -import dagger.Module -import dagger.Provides -import dagger.hilt.InstallIn -import dagger.hilt.android.components.ApplicationComponent -import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory -import okhttp3.OkHttpClient -import okhttp3.logging.HttpLoggingInterceptor -import retrofit2.Retrofit -import retrofit2.converter.moshi.MoshiConverterFactory -import javax.inject.Singleton - -@Module -@InstallIn(ApplicationComponent::class) -class ServiceProviderModule { - - @Provides - @Singleton - fun provideOkHttpClient( - authenticationInterceptor: AuthenticationInterceptor, - responseInterceptor: ResponseInterceptor - ): OkHttpClient { - val httpInterceptorLevel = if (BuildConfig.DEBUG) HttpLoggingInterceptor.Level.BODY - else HttpLoggingInterceptor.Level.BASIC - - return OkHttpClient.Builder() - .addInterceptor(HeadersInterceptor()) - .addInterceptor(authenticationInterceptor) - .addInterceptor(responseInterceptor) - .addInterceptor(HttpLoggingInterceptor().setLevel(httpInterceptorLevel)) - .build() - } - - @Provides - @Singleton - fun provideRetrofit(okHttpClient: OkHttpClient): Retrofit { - val url = URL_API ?: BuildConfig.API_URL - val moshi = Moshi.Builder() - .add(KotlinJsonAdapterFactory()) - .build() - return Retrofit.Builder() - .baseUrl(url) - .addConverterFactory(MoshiConverterFactory.create(moshi).withNullSerialization()) - .client(okHttpClient) - .build() - } - - companion object { - var URL_API: String? = null - } -} diff --git a/app/src/main/java/com/rootstrap/android/network/services/ApiModule.kt b/app/src/main/java/com/rootstrap/android/network/services/ApiModule.kt deleted file mode 100644 index 53c844a..0000000 --- a/app/src/main/java/com/rootstrap/android/network/services/ApiModule.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.rootstrap.android.network.services - -import dagger.Module -import dagger.Provides -import dagger.hilt.InstallIn -import dagger.hilt.android.components.ApplicationComponent -import retrofit2.Retrofit - -@Module -@InstallIn(ApplicationComponent::class) -class ApiModule { - - @Provides - fun provideApiService(retrofit: Retrofit): ApiService { - return retrofit.create(ApiService::class.java) - } -} diff --git a/app/src/main/java/com/rootstrap/android/network/services/AuthenticationInterceptor.kt b/app/src/main/java/com/rootstrap/android/network/services/AuthenticationInterceptor.kt index af7666b..4df7a32 100644 --- a/app/src/main/java/com/rootstrap/android/network/services/AuthenticationInterceptor.kt +++ b/app/src/main/java/com/rootstrap/android/network/services/AuthenticationInterceptor.kt @@ -4,9 +4,8 @@ import com.rootstrap.android.util.Prefs import okhttp3.Interceptor import okhttp3.Response import java.io.IOException -import javax.inject.Inject -class AuthenticationInterceptor @Inject constructor(private val prefs: Prefs) : Interceptor { +class AuthenticationInterceptor(private val prefs: Prefs) : Interceptor { @Throws(IOException::class) override fun intercept(chain: Interceptor.Chain): Response { diff --git a/app/src/main/java/com/rootstrap/android/network/services/ResponseInterceptor.kt b/app/src/main/java/com/rootstrap/android/network/services/ResponseInterceptor.kt index 9d7e252..2206b2d 100644 --- a/app/src/main/java/com/rootstrap/android/network/services/ResponseInterceptor.kt +++ b/app/src/main/java/com/rootstrap/android/network/services/ResponseInterceptor.kt @@ -5,12 +5,8 @@ import com.rootstrap.android.util.Prefs import okhttp3.Interceptor import okhttp3.Response import java.io.IOException -import javax.inject.Inject -class ResponseInterceptor @Inject constructor( - private val prefs: Prefs, - private val sessionManager: SessionManager -) : Interceptor { +class ResponseInterceptor(private val prefs: Prefs, private val sessionManager: SessionManager) : Interceptor { @Throws(IOException::class) override fun intercept(chain: Interceptor.Chain): Response { diff --git a/app/src/main/java/com/rootstrap/android/ui/activity/main/ProfileActivity.kt b/app/src/main/java/com/rootstrap/android/ui/activity/main/ProfileActivity.kt index 7c92979..3dca5a1 100644 --- a/app/src/main/java/com/rootstrap/android/ui/activity/main/ProfileActivity.kt +++ b/app/src/main/java/com/rootstrap/android/ui/activity/main/ProfileActivity.kt @@ -1,7 +1,6 @@ package com.rootstrap.android.ui.activity.main import android.os.Bundle -import androidx.activity.viewModels import androidx.lifecycle.Observer import com.rootstrap.android.R import com.rootstrap.android.metrics.Analytics @@ -11,16 +10,14 @@ import com.rootstrap.android.network.managers.session.SessionManager import com.rootstrap.android.ui.base.BaseActivity import com.rootstrap.android.ui.view.ProfileView import com.rootstrap.android.util.NetworkState -import dagger.hilt.android.AndroidEntryPoint import kotlinx.android.synthetic.main.activity_profile.* -import javax.inject.Inject +import org.koin.android.ext.android.inject +import org.koin.androidx.viewmodel.ext.android.viewModel -@AndroidEntryPoint class ProfileActivity : BaseActivity(), ProfileView { - @Inject lateinit var sessionManager: SessionManager - - private val viewModel: ProfileActivityViewModel by viewModels() + private val viewModel by viewModel() + private val sessionManager: SessionManager by inject() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -36,7 +33,7 @@ class ProfileActivity : BaseActivity(), ProfileView { } override fun goToFirstScreen() { - startActivityClearTask(SignUpActivity()) + startActivityClearTask(SignUpActivity::class.java) } private fun setObservers() { diff --git a/app/src/main/java/com/rootstrap/android/ui/activity/main/ProfileActivityViewModel.kt b/app/src/main/java/com/rootstrap/android/ui/activity/main/ProfileActivityViewModel.kt index 7fdf3ec..7a2ee01 100644 --- a/app/src/main/java/com/rootstrap/android/ui/activity/main/ProfileActivityViewModel.kt +++ b/app/src/main/java/com/rootstrap/android/ui/activity/main/ProfileActivityViewModel.kt @@ -1,6 +1,5 @@ package com.rootstrap.android.ui.activity.main -import androidx.hilt.lifecycle.ViewModelInject import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope @@ -12,7 +11,7 @@ import com.rootstrap.android.util.extensions.ApiErrorType import com.rootstrap.android.util.extensions.ApiException import kotlinx.coroutines.launch -open class ProfileActivityViewModel @ViewModelInject constructor( +open class ProfileActivityViewModel( private val sessionManager: SessionManager, private val userManager: UserManager ) : BaseViewModel() { diff --git a/app/src/main/java/com/rootstrap/android/ui/activity/main/SignInActivity.kt b/app/src/main/java/com/rootstrap/android/ui/activity/main/SignInActivity.kt index fdf09a0..6d280c4 100644 --- a/app/src/main/java/com/rootstrap/android/ui/activity/main/SignInActivity.kt +++ b/app/src/main/java/com/rootstrap/android/ui/activity/main/SignInActivity.kt @@ -2,7 +2,6 @@ package com.rootstrap.android.ui.activity.main import android.Manifest import android.os.Bundle -import androidx.activity.viewModels import androidx.lifecycle.Observer import com.rootstrap.android.R import com.rootstrap.android.databinding.ActivitySignInBinding @@ -15,12 +14,11 @@ import com.rootstrap.android.util.NetworkState import com.rootstrap.android.util.extensions.value import com.rootstrap.android.util.permissions.PermissionActivity import com.rootstrap.android.util.permissions.PermissionResponse -import dagger.hilt.android.AndroidEntryPoint +import org.koin.androidx.viewmodel.ext.android.viewModel -@AndroidEntryPoint class SignInActivity : PermissionActivity(), AuthView { - private val viewModel: SignInActivityViewModel by viewModels() + private val viewModel by viewModel() private lateinit var binding: ActivitySignInBinding override fun onCreate(savedInstanceState: Bundle?) { @@ -39,7 +37,7 @@ class SignInActivity : PermissionActivity(), AuthView { } override fun showProfile() { - startActivityClearTask(ProfileActivity()) + startActivityClearTask(ProfileActivity::class.java) } private fun signIn() { diff --git a/app/src/main/java/com/rootstrap/android/ui/activity/main/SignInActivityViewModel.kt b/app/src/main/java/com/rootstrap/android/ui/activity/main/SignInActivityViewModel.kt index c3783ac..d9853ac 100644 --- a/app/src/main/java/com/rootstrap/android/ui/activity/main/SignInActivityViewModel.kt +++ b/app/src/main/java/com/rootstrap/android/ui/activity/main/SignInActivityViewModel.kt @@ -1,6 +1,5 @@ package com.rootstrap.android.ui.activity.main -import androidx.hilt.lifecycle.ViewModelInject import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope @@ -13,7 +12,7 @@ import com.rootstrap.android.util.extensions.ApiErrorType import com.rootstrap.android.util.extensions.ApiException import kotlinx.coroutines.launch -open class SignInActivityViewModel @ViewModelInject constructor( +open class SignInActivityViewModel( private val sessionManager: SessionManager, private val userManager: UserManager ) : BaseViewModel() { diff --git a/app/src/main/java/com/rootstrap/android/ui/activity/main/SignUpActivity.kt b/app/src/main/java/com/rootstrap/android/ui/activity/main/SignUpActivity.kt index 83ef2f4..6dfe02c 100644 --- a/app/src/main/java/com/rootstrap/android/ui/activity/main/SignUpActivity.kt +++ b/app/src/main/java/com/rootstrap/android/ui/activity/main/SignUpActivity.kt @@ -2,7 +2,6 @@ package com.rootstrap.android.ui.activity.main import android.content.Intent import android.os.Bundle -import androidx.activity.viewModels import androidx.lifecycle.Observer import com.rootstrap.android.R import com.rootstrap.android.databinding.ActivitySignUpBinding @@ -14,12 +13,11 @@ import com.rootstrap.android.ui.base.BaseActivity import com.rootstrap.android.ui.view.AuthView import com.rootstrap.android.util.NetworkState import com.rootstrap.android.util.extensions.value -import dagger.hilt.android.AndroidEntryPoint +import org.koin.androidx.viewmodel.ext.android.viewModel -@AndroidEntryPoint class SignUpActivity : BaseActivity(), AuthView { - private val viewModel: SignUpActivityViewModel by viewModels() + private val viewModel by viewModel() private lateinit var binding: ActivitySignUpBinding override fun onCreate(savedInstanceState: Bundle?) { @@ -38,7 +36,7 @@ class SignUpActivity : BaseActivity(), AuthView { } override fun showProfile() { - startActivityClearTask(ProfileActivity()) + startActivityClearTask(ProfileActivity::class.java) } private fun signIn() { diff --git a/app/src/main/java/com/rootstrap/android/ui/activity/main/SignUpActivityViewModel.kt b/app/src/main/java/com/rootstrap/android/ui/activity/main/SignUpActivityViewModel.kt index 47ae75f..a8ab23d 100644 --- a/app/src/main/java/com/rootstrap/android/ui/activity/main/SignUpActivityViewModel.kt +++ b/app/src/main/java/com/rootstrap/android/ui/activity/main/SignUpActivityViewModel.kt @@ -1,6 +1,5 @@ package com.rootstrap.android.ui.activity.main -import androidx.hilt.lifecycle.ViewModelInject import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope @@ -13,7 +12,7 @@ import com.rootstrap.android.util.extensions.ApiErrorType import com.rootstrap.android.util.extensions.ApiException import kotlinx.coroutines.launch -open class SignUpActivityViewModel @ViewModelInject constructor( +open class SignUpActivityViewModel( private val sessionManager: SessionManager, private val userManager: UserManager ) : BaseViewModel() { diff --git a/app/src/main/java/com/rootstrap/android/ui/base/BaseActivity.kt b/app/src/main/java/com/rootstrap/android/ui/base/BaseActivity.kt index 4b3765a..708d684 100644 --- a/app/src/main/java/com/rootstrap/android/ui/base/BaseActivity.kt +++ b/app/src/main/java/com/rootstrap/android/ui/base/BaseActivity.kt @@ -21,8 +21,8 @@ open class BaseActivity : AppCompatActivity(), BaseView { LoadingDialogUtil.showError(message, this) } - protected fun startActivityClearTask(activity: Activity) { - val intent = Intent(this, activity.javaClass) + protected fun startActivityClearTask(activity: Class) { + val intent = Intent(this, activity) intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK) startActivity(intent) diff --git a/app/src/main/java/com/rootstrap/android/util/Prefs.kt b/app/src/main/java/com/rootstrap/android/util/Prefs.kt index 7230177..46b9f55 100644 --- a/app/src/main/java/com/rootstrap/android/util/Prefs.kt +++ b/app/src/main/java/com/rootstrap/android/util/Prefs.kt @@ -4,9 +4,8 @@ import android.content.SharedPreferences import com.google.gson.Gson import com.rootstrap.android.network.models.User import com.rootstrap.android.util.extensions.fromJson -import javax.inject.Inject -class Prefs @Inject constructor(private val prefs: SharedPreferences) { +class Prefs(private val prefs: SharedPreferences) { val ACCESS_TOKEN = "access-token" val CLIENT = "Client" From e7555ec75c1933b2117a4d0c5d142d0e18a07af9 Mon Sep 17 00:00:00 2001 From: Santiago Andracchi Date: Tue, 21 Sep 2021 19:04:58 -0300 Subject: [PATCH 2/2] Use mockk for testing --- .idea/gradle.xml | 3 +- app/build.gradle | 4 +- app/src/androidTest/AndroidManifest.xml | 6 +++ .../com/rootstrap/android/CustomTestRunner.kt | 13 ------- .../android/tests/ProfileActivityTest.kt | 12 +++--- .../android/tests/SignInActivityTest.kt | 6 +-- .../android/tests/SignUpActivityTest.kt | 6 +-- .../android/tests/utils/PrefTests.kt | 37 ------------------- .../android/tests/utils/PrefsTest.kt | 27 ++++++++++++++ .../utils/{BaseTests.kt => BaseTest.kt} | 32 +++++++++------- .../java/com/rootstrap/android/util/Prefs.kt | 24 +++++++----- 11 files changed, 80 insertions(+), 90 deletions(-) create mode 100644 app/src/androidTest/AndroidManifest.xml delete mode 100644 app/src/androidTest/java/com/rootstrap/android/CustomTestRunner.kt delete mode 100644 app/src/androidTest/java/com/rootstrap/android/tests/utils/PrefTests.kt create mode 100644 app/src/androidTest/java/com/rootstrap/android/tests/utils/PrefsTest.kt rename app/src/androidTest/java/com/rootstrap/android/utils/{BaseTests.kt => BaseTest.kt} (85%) diff --git a/.idea/gradle.xml b/.idea/gradle.xml index 41871c2..4404972 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -5,7 +5,7 @@ diff --git a/app/build.gradle b/app/build.gradle index 1477d98..d127ae9 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -19,7 +19,7 @@ android { targetSdkVersion 29 versionCode 42 versionName "1.0" - testInstrumentationRunner 'com.rootstrap.android.CustomTestRunner' + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } viewBinding { @@ -146,6 +146,8 @@ dependencies { implementation 'com.google.android.material:material:1.2.1' testImplementation 'junit:junit:4.13.1' testImplementation 'org.mockito:mockito-core:2.28.2' + androidTestImplementation "io.mockk:mockk-android:1.12.0" + testImplementation "io.mockk:mockk:1.12.0" androidTestImplementation 'androidx.test:runner:1.3.0' androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' androidTestImplementation 'androidx.test.espresso:espresso-intents:3.3.0' diff --git a/app/src/androidTest/AndroidManifest.xml b/app/src/androidTest/AndroidManifest.xml new file mode 100644 index 0000000..53d4de0 --- /dev/null +++ b/app/src/androidTest/AndroidManifest.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/app/src/androidTest/java/com/rootstrap/android/CustomTestRunner.kt b/app/src/androidTest/java/com/rootstrap/android/CustomTestRunner.kt deleted file mode 100644 index 7dfbf3d..0000000 --- a/app/src/androidTest/java/com/rootstrap/android/CustomTestRunner.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.rootstrap.android - -import android.app.Application -import android.content.Context -import androidx.test.runner.AndroidJUnitRunner -import dagger.hilt.android.testing.HiltTestApplication - -class CustomTestRunner : AndroidJUnitRunner() { - - override fun newApplication(cl: ClassLoader?, name: String?, context: Context?): Application { - return super.newApplication(cl, HiltTestApplication::class.java.name, context) - } -} diff --git a/app/src/androidTest/java/com/rootstrap/android/tests/ProfileActivityTest.kt b/app/src/androidTest/java/com/rootstrap/android/tests/ProfileActivityTest.kt index 54c03d4..b97d10b 100644 --- a/app/src/androidTest/java/com/rootstrap/android/tests/ProfileActivityTest.kt +++ b/app/src/androidTest/java/com/rootstrap/android/tests/ProfileActivityTest.kt @@ -4,11 +4,12 @@ import androidx.test.core.app.ActivityScenario import androidx.test.espresso.Espresso.onView import androidx.test.espresso.action.ViewActions.click import androidx.test.espresso.matcher.ViewMatchers.withId +import androidx.test.ext.junit.runners.AndroidJUnit4 import com.rootstrap.android.R import com.rootstrap.android.ui.activity.main.ProfileActivity import com.rootstrap.android.ui.activity.main.SignUpActivity -import com.rootstrap.android.utils.BaseTests -import dagger.hilt.android.testing.HiltAndroidTest +import com.rootstrap.android.utils.BaseTest +import io.mockk.every import okhttp3.mockwebserver.Dispatcher import okhttp3.mockwebserver.MockResponse import okhttp3.mockwebserver.RecordedRequest @@ -16,9 +17,10 @@ import org.junit.After import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Test +import org.junit.runner.RunWith -@HiltAndroidTest -class ProfileActivityTest : BaseTests() { +@RunWith(AndroidJUnit4::class) +class ProfileActivityTest : BaseTest() { private lateinit var activity: ProfileActivity private lateinit var scenario: ActivityScenario @@ -27,7 +29,7 @@ class ProfileActivityTest : BaseTests() { override fun before() { super.before() setServerDispatch(logoutDispatcher()) - sessionManager.user = testUser() + every { sessionManager.user } returns testUser() scenario = ActivityScenario.launch(ProfileActivity::class.java) scenario.onActivity { activity -> this.activity = activity } } diff --git a/app/src/androidTest/java/com/rootstrap/android/tests/SignInActivityTest.kt b/app/src/androidTest/java/com/rootstrap/android/tests/SignInActivityTest.kt index b36cfab..ea6b7c6 100644 --- a/app/src/androidTest/java/com/rootstrap/android/tests/SignInActivityTest.kt +++ b/app/src/androidTest/java/com/rootstrap/android/tests/SignInActivityTest.kt @@ -6,8 +6,7 @@ import com.rootstrap.android.R import com.rootstrap.android.network.models.UserSerializer import com.rootstrap.android.ui.activity.main.ProfileActivity import com.rootstrap.android.ui.activity.main.SignInActivity -import com.rootstrap.android.utils.BaseTests -import dagger.hilt.android.testing.HiltAndroidTest +import com.rootstrap.android.utils.BaseTest import okhttp3.mockwebserver.Dispatcher import okhttp3.mockwebserver.MockResponse import okhttp3.mockwebserver.RecordedRequest @@ -16,8 +15,7 @@ import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Test -@HiltAndroidTest -class SignInActivityTest : BaseTests() { +class SignInActivityTest : BaseTest() { private lateinit var activity: SignInActivity private lateinit var scenario: ActivityScenario diff --git a/app/src/androidTest/java/com/rootstrap/android/tests/SignUpActivityTest.kt b/app/src/androidTest/java/com/rootstrap/android/tests/SignUpActivityTest.kt index 8409a87..1b9abb5 100644 --- a/app/src/androidTest/java/com/rootstrap/android/tests/SignUpActivityTest.kt +++ b/app/src/androidTest/java/com/rootstrap/android/tests/SignUpActivityTest.kt @@ -7,8 +7,7 @@ import com.rootstrap.android.network.models.UserSerializer import com.rootstrap.android.ui.activity.main.ProfileActivity import com.rootstrap.android.ui.activity.main.SignInActivity import com.rootstrap.android.ui.activity.main.SignUpActivity -import com.rootstrap.android.utils.BaseTests -import dagger.hilt.android.testing.HiltAndroidTest +import com.rootstrap.android.utils.BaseTest import okhttp3.mockwebserver.Dispatcher import okhttp3.mockwebserver.MockResponse import okhttp3.mockwebserver.RecordedRequest @@ -17,8 +16,7 @@ import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Test -@HiltAndroidTest -class SignUpActivityTest : BaseTests() { +class SignUpActivityTest : BaseTest() { private lateinit var activity: SignUpActivity private lateinit var scenario: ActivityScenario diff --git a/app/src/androidTest/java/com/rootstrap/android/tests/utils/PrefTests.kt b/app/src/androidTest/java/com/rootstrap/android/tests/utils/PrefTests.kt deleted file mode 100644 index b5e1be9..0000000 --- a/app/src/androidTest/java/com/rootstrap/android/tests/utils/PrefTests.kt +++ /dev/null @@ -1,37 +0,0 @@ -package com.rootstrap.android.tests.utils - -import android.content.SharedPreferences -import androidx.security.crypto.EncryptedSharedPreferences -import com.rootstrap.android.util.Prefs -import dagger.hilt.android.testing.HiltAndroidRule -import org.junit.Assert -import org.junit.Before -import org.junit.Rule -import org.junit.Test -import java.util.* // ktlint-disable no-wildcard-imports -import javax.inject.Inject - -class PrefTests { - @get:Rule - var hiltRule = HiltAndroidRule(this) - - @Inject - lateinit var prefs: Prefs - - @Inject - lateinit var preferences: SharedPreferences - - @Before - fun init() { - hiltRule.inject() - } - - @Test - fun savingSecureDataPrefs() { - val uid = UUID.randomUUID().toString() - prefs.uid = uid - - Assert.assertTrue(preferences is EncryptedSharedPreferences) - Assert.assertEquals(prefs.uid, uid) - } -} diff --git a/app/src/androidTest/java/com/rootstrap/android/tests/utils/PrefsTest.kt b/app/src/androidTest/java/com/rootstrap/android/tests/utils/PrefsTest.kt new file mode 100644 index 0000000..d261d93 --- /dev/null +++ b/app/src/androidTest/java/com/rootstrap/android/tests/utils/PrefsTest.kt @@ -0,0 +1,27 @@ +package com.rootstrap.android.tests.utils + +import android.content.SharedPreferences +import com.rootstrap.android.util.Prefs +import io.mockk.every +import io.mockk.mockk +import io.mockk.spyk +import org.junit.Assert +import org.junit.Test +import java.util.UUID + +class PrefsTest { + + @Test + fun savingSecureDataPrefs() { + val uid = UUID.randomUUID().toString() + val preferences = mockk() + val prefs = spyk(Prefs(preferences), recordPrivateCalls = true) + every { preferences.edit().putString("uid", uid).apply() } returns Unit + every { preferences.getString("uid", "")!! } returns uid + every { prefs ["getPref"]() } returns preferences + + prefs.uid = uid + + Assert.assertEquals(prefs.uid, uid) + } +} diff --git a/app/src/androidTest/java/com/rootstrap/android/utils/BaseTests.kt b/app/src/androidTest/java/com/rootstrap/android/utils/BaseTest.kt similarity index 85% rename from app/src/androidTest/java/com/rootstrap/android/utils/BaseTests.kt rename to app/src/androidTest/java/com/rootstrap/android/utils/BaseTest.kt index 2be338b..fda7139 100644 --- a/app/src/androidTest/java/com/rootstrap/android/utils/BaseTests.kt +++ b/app/src/androidTest/java/com/rootstrap/android/utils/BaseTest.kt @@ -2,11 +2,11 @@ package com.rootstrap.android.utils import android.app.Activity import androidx.test.espresso.Espresso.onView -import androidx.test.espresso.action.ViewActions.typeText +import androidx.test.espresso.action.ViewActions.closeSoftKeyboard import androidx.test.espresso.action.ViewActions.scrollTo -import androidx.test.espresso.action.ViewActions.click import androidx.test.espresso.action.ViewActions.clearText -import androidx.test.espresso.action.ViewActions.closeSoftKeyboard +import androidx.test.espresso.action.ViewActions.click +import androidx.test.espresso.action.ViewActions.typeText import androidx.test.espresso.assertion.ViewAssertions import androidx.test.espresso.matcher.ViewMatchers import androidx.test.espresso.matcher.ViewMatchers.withId @@ -15,31 +15,35 @@ import androidx.test.runner.lifecycle.ActivityLifecycleMonitorRegistry import androidx.test.runner.lifecycle.Stage import com.rootstrap.android.network.managers.session.SessionManager import com.rootstrap.android.network.models.User -import com.rootstrap.android.network.providers.ServiceProviderModule -import dagger.hilt.android.testing.HiltAndroidRule +import io.mockk.every +import io.mockk.spyk import okhttp3.mockwebserver.Dispatcher -import org.junit.Rule import org.junit.runner.RunWith -import javax.inject.Inject @RunWith(AndroidJUnit4ClassRunner::class) -open class BaseTests { +open class BaseTest { - @Inject lateinit var sessionManager: SessionManager + lateinit var sessionManager: SessionManager var mockServer: MockServer = MockServer - @get:Rule - var hiltRule = HiltAndroidRule(this) - open fun setServerDispatch(dispatcher: Dispatcher) { mockServer.server().dispatcher = dispatcher } open fun before() { + sessionManager = spyk() + val user = User( + "9032", + "user123@mail.com", + "Richard", + "Richard", + "99090909", + "asdasdasdasda", + "Richard" + ) + every { sessionManager.user } returns user mockServer.startServer() - ServiceProviderModule.URL_API = mockServer.server().url("/").toString() - hiltRule.inject() } open fun after() { diff --git a/app/src/main/java/com/rootstrap/android/util/Prefs.kt b/app/src/main/java/com/rootstrap/android/util/Prefs.kt index 46b9f55..d7e1c4c 100644 --- a/app/src/main/java/com/rootstrap/android/util/Prefs.kt +++ b/app/src/main/java/com/rootstrap/android/util/Prefs.kt @@ -1,6 +1,7 @@ package com.rootstrap.android.util import android.content.SharedPreferences +import androidx.annotation.VisibleForTesting import com.google.gson.Gson import com.rootstrap.android.network.models.User import com.rootstrap.android.util.extensions.fromJson @@ -16,24 +17,27 @@ class Prefs(private val prefs: SharedPreferences) { private val gson: Gson = Gson() var accessToken: String - get() = prefs.getString(ACCESS_TOKEN, "")!! - set(value) = prefs.edit().putString(ACCESS_TOKEN, value).apply() + get() = getPref().getString(ACCESS_TOKEN, "")!! + set(value) = getPref().edit().putString(ACCESS_TOKEN, value).apply() var client: String - get() = prefs.getString(CLIENT, "")!! - set(value) = prefs.edit().putString(CLIENT, value).apply() + get() = getPref().getString(CLIENT, "")!! + set(value) = getPref().edit().putString(CLIENT, value).apply() var uid: String - get() = prefs.getString(UID, "")!! - set(value) = prefs.edit().putString(UID, value).apply() + get() = getPref().getString(UID, "")!! + set(value) = getPref().edit().putString(UID, value).apply() var user: User? get() = gson.fromJson(prefs.getString(USER, "")!!) - set(value) = prefs.edit().putString(USER, gson.toJson(value)).apply() + set(value) = getPref().edit().putString(USER, gson.toJson(value)).apply() var signedIn: Boolean - get() = prefs.getBoolean(SIGNED_IN, false) - set(value) = prefs.edit().putBoolean(SIGNED_IN, value).apply() + get() = getPref().getBoolean(SIGNED_IN, false) + set(value) = getPref().edit().putBoolean(SIGNED_IN, value).apply() - fun clear() = prefs.edit().clear().apply() + fun clear() = getPref().edit().clear().apply() + + @VisibleForTesting + private fun getPref() = prefs }