diff --git a/app/build.gradle b/app/build.gradle
index a390928..7371495 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -2,6 +2,8 @@ plugins {
id 'com.android.application'
id 'kotlin-android'
id 'kotlin-kapt'
+ // hilt specific
+ id 'dagger.hilt.android.plugin'
}
android {
@@ -25,6 +27,17 @@ android {
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
+ flavorDimensions 'di'
+ productFlavors {
+ hilt {
+ dimension 'di'
+ applicationId "org.fnives.test.showcase.hilt"
+ }
+ koin {
+ dimension 'di'
+ applicationId "org.fnives.test.showcase.koin"
+ }
+ }
buildFeatures {
viewBinding true
@@ -49,10 +62,17 @@ android {
}
}
+hilt {
+ enableAggregatingTask = true
+ enableExperimentalClasspathAggregation = true
+}
+
afterEvaluate {
// making sure the :mockserver is assembled after :clean when running tests
- testDebugUnitTest.dependsOn tasks.getByPath(':mockserver:assemble')
- testReleaseUnitTest.dependsOn tasks.getByPath(':mockserver:assemble')
+ testKoinDebugUnitTest.dependsOn tasks.getByPath(':mockserver:assemble')
+ testKoinReleaseUnitTest.dependsOn tasks.getByPath(':mockserver:assemble')
+ testHiltDebugUnitTest.dependsOn tasks.getByPath(':mockserver:assemble')
+ testHiltReleaseUnitTest.dependsOn tasks.getByPath(':mockserver:assemble')
}
dependencies {
@@ -66,7 +86,14 @@ dependencies {
implementation "androidx.swiperefreshlayout:swiperefreshlayout:$androidx_swiperefreshlayout_version"
// Koin
- implementation "io.insert-koin:koin-android:$koin_version"
+ koinImplementation "io.insert-koin:koin-android:$koin_version"
+
+ // Hilt
+// hiltImplementation "com.google.dagger:hilt-android:$hilt_version"
+ implementation "com.google.dagger:hilt-android:$hilt_version"
+// implementation "com.google.dagger:hilt-core:$hilt_version"
+ kaptHilt "com.google.dagger:hilt-compiler:$hilt_version"
+ hiltImplementation "androidx.activity:activity-ktx:$activity_ktx_version"
implementation "androidx.room:room-runtime:$androidx_room_version"
kapt "androidx.room:room-compiler:$androidx_room_version"
@@ -98,6 +125,8 @@ dependencies {
testImplementation "com.jakewharton.espresso:okhttp3-idling-resource:$testing_okhttp3_idling_resource_version"
testImplementation "androidx.arch.core:core-testing:$testing_androidx_arch_core_version"
testRuntimeOnly "org.junit.vintage:junit-vintage-engine:$testing_junit5_version"
+ testImplementation "com.google.dagger:hilt-android-testing:$hilt_version"
+ kaptTest "com.google.dagger:hilt-compiler:$hilt_version"
androidTestImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines_version"
androidTestImplementation "io.insert-koin:koin-test-junit4:$koin_version"
@@ -111,4 +140,6 @@ dependencies {
androidTestImplementation "com.jakewharton.espresso:okhttp3-idling-resource:$testing_okhttp3_idling_resource_version"
androidTestImplementation "androidx.arch.core:core-testing:$testing_androidx_arch_core_version"
androidTestRuntimeOnly "org.junit.vintage:junit-vintage-engine:$testing_junit5_version"
+ androidTestImplementation "com.google.dagger:hilt-android-testing:$hilt_version"
+ kaptAndroidTest "com.google.dagger:hilt-compiler:$hilt_version"
}
\ No newline at end of file
diff --git a/app/src/hilt/AndroidManifest.xml b/app/src/hilt/AndroidManifest.xml
new file mode 100644
index 0000000..d65911d
--- /dev/null
+++ b/app/src/hilt/AndroidManifest.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/hilt/java/org/fnives/test/showcase/TestShowcaseApplication.kt b/app/src/hilt/java/org/fnives/test/showcase/TestShowcaseApplication.kt
new file mode 100644
index 0000000..a3b36fe
--- /dev/null
+++ b/app/src/hilt/java/org/fnives/test/showcase/TestShowcaseApplication.kt
@@ -0,0 +1,13 @@
+package org.fnives.test.showcase
+
+import android.app.Application
+import dagger.hilt.android.HiltAndroidApp
+
+@HiltAndroidApp
+class TestShowcaseApplication : Application() {
+
+ override fun onCreate() {
+ super.onCreate()
+
+ }
+}
diff --git a/app/src/hilt/java/org/fnives/test/showcase/di/AppModule.kt b/app/src/hilt/java/org/fnives/test/showcase/di/AppModule.kt
new file mode 100644
index 0000000..57fa755
--- /dev/null
+++ b/app/src/hilt/java/org/fnives/test/showcase/di/AppModule.kt
@@ -0,0 +1,53 @@
+package org.fnives.test.showcase.di
+
+import android.content.Context
+import dagger.Module
+import dagger.Provides
+import dagger.hilt.InstallIn
+import dagger.hilt.android.qualifiers.ApplicationContext
+import dagger.hilt.components.SingletonComponent
+import org.fnives.test.showcase.core.session.SessionExpirationListener
+import org.fnives.test.showcase.core.storage.UserDataLocalStorage
+import org.fnives.test.showcase.core.storage.content.FavouriteContentLocalStorage
+import org.fnives.test.showcase.session.SessionExpirationListenerImpl
+import org.fnives.test.showcase.storage.SharedPreferencesManagerImpl
+import org.fnives.test.showcase.storage.database.DatabaseInitialization
+import org.fnives.test.showcase.storage.favourite.FavouriteContentLocalStorageImpl
+import javax.inject.Singleton
+
+@InstallIn(SingletonComponent::class)
+@Module
+object AppModule {
+
+ @Provides
+ fun provideBaseUrl(): String = BaseUrlProvider.get().baseUrl
+
+ @Provides
+ fun enableLogging(): Boolean = true
+
+ @Singleton
+ @Provides
+ fun provideFavouriteDao(@ApplicationContext context: Context) =
+ DatabaseInitialization.create(context).favouriteDao
+
+ @Provides
+ fun provideSharedPreferencesManagerImpl(@ApplicationContext context: Context) =
+ SharedPreferencesManagerImpl.create(context)
+
+ @Singleton
+ @Provides
+ fun provideUserDataLocalStorage(
+ sharedPreferencesManagerImpl: SharedPreferencesManagerImpl
+ ): UserDataLocalStorage = sharedPreferencesManagerImpl
+
+ @Provides
+ fun provideFavouriteContentLocalStorage(
+ favouriteContentLocalStorageImpl: FavouriteContentLocalStorageImpl
+ ): FavouriteContentLocalStorage = favouriteContentLocalStorageImpl
+
+ @Provides
+ internal fun bindSessionExpirationListener(
+ sessionExpirationListenerImpl: SessionExpirationListenerImpl
+ ) : SessionExpirationListener = sessionExpirationListenerImpl
+
+}
\ No newline at end of file
diff --git a/app/src/hilt/java/org/fnives/test/showcase/ui/IntentCoordinator.kt b/app/src/hilt/java/org/fnives/test/showcase/ui/IntentCoordinator.kt
new file mode 100644
index 0000000..a7d3f6e
--- /dev/null
+++ b/app/src/hilt/java/org/fnives/test/showcase/ui/IntentCoordinator.kt
@@ -0,0 +1,14 @@
+package org.fnives.test.showcase.ui
+
+import android.content.Context
+import org.fnives.test.showcase.ui.auth.HiltAuthActivity
+import org.fnives.test.showcase.ui.home.HiltMainActivity
+
+object IntentCoordinator {
+
+ fun mainActivitygetStartIntent(context: Context) =
+ HiltMainActivity.getStartIntent(context)
+
+ fun authActivitygetStartIntent(context: Context) =
+ HiltAuthActivity.getStartIntent(context)
+}
\ No newline at end of file
diff --git a/app/src/hilt/java/org/fnives/test/showcase/ui/ViewModelDelegate.kt b/app/src/hilt/java/org/fnives/test/showcase/ui/ViewModelDelegate.kt
new file mode 100644
index 0000000..2138fa6
--- /dev/null
+++ b/app/src/hilt/java/org/fnives/test/showcase/ui/ViewModelDelegate.kt
@@ -0,0 +1,12 @@
+package org.fnives.test.showcase.ui
+
+import androidx.activity.ComponentActivity
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelStoreOwner
+import androidx.activity.viewModels as androidxViewModel
+
+inline fun ViewModelStoreOwner.viewModels(): Lazy =
+ when (this) {
+ is ComponentActivity -> androidxViewModel()
+ else -> throw IllegalStateException("Only supports activity viewModel for now")
+ }
\ No newline at end of file
diff --git a/app/src/hilt/java/org/fnives/test/showcase/ui/auth/HiltAuthActivity.kt b/app/src/hilt/java/org/fnives/test/showcase/ui/auth/HiltAuthActivity.kt
new file mode 100644
index 0000000..e6df5b0
--- /dev/null
+++ b/app/src/hilt/java/org/fnives/test/showcase/ui/auth/HiltAuthActivity.kt
@@ -0,0 +1,12 @@
+package org.fnives.test.showcase.ui.auth
+
+import android.content.Context
+import android.content.Intent
+import dagger.hilt.android.AndroidEntryPoint
+
+@AndroidEntryPoint
+class HiltAuthActivity : AuthActivity() {
+ companion object {
+ fun getStartIntent(context: Context): Intent = Intent(context, HiltAuthActivity::class.java)
+ }
+}
\ No newline at end of file
diff --git a/app/src/hilt/java/org/fnives/test/showcase/ui/home/HiltMainActivity.kt b/app/src/hilt/java/org/fnives/test/showcase/ui/home/HiltMainActivity.kt
new file mode 100644
index 0000000..f6a7cdc
--- /dev/null
+++ b/app/src/hilt/java/org/fnives/test/showcase/ui/home/HiltMainActivity.kt
@@ -0,0 +1,12 @@
+package org.fnives.test.showcase.ui.home
+
+import android.content.Context
+import android.content.Intent
+import dagger.hilt.android.AndroidEntryPoint
+
+@AndroidEntryPoint
+class HiltMainActivity : MainActivity() {
+ companion object {
+ fun getStartIntent(context: Context): Intent = Intent(context, HiltMainActivity::class.java)
+ }
+}
\ No newline at end of file
diff --git a/app/src/hilt/java/org/fnives/test/showcase/ui/splash/HiltSplashActivity.kt b/app/src/hilt/java/org/fnives/test/showcase/ui/splash/HiltSplashActivity.kt
new file mode 100644
index 0000000..19ba159
--- /dev/null
+++ b/app/src/hilt/java/org/fnives/test/showcase/ui/splash/HiltSplashActivity.kt
@@ -0,0 +1,6 @@
+package org.fnives.test.showcase.ui.splash
+
+import dagger.hilt.android.AndroidEntryPoint
+
+@AndroidEntryPoint
+class HiltSplashActivity : SplashActivity()
\ No newline at end of file
diff --git a/app/src/koin/AndroidManifest.xml b/app/src/koin/AndroidManifest.xml
new file mode 100644
index 0000000..72cf478
--- /dev/null
+++ b/app/src/koin/AndroidManifest.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/org/fnives/test/showcase/TestShowcaseApplication.kt b/app/src/koin/java/org/fnives/test/showcase/TestShowcaseApplication.kt
similarity index 100%
rename from app/src/main/java/org/fnives/test/showcase/TestShowcaseApplication.kt
rename to app/src/koin/java/org/fnives/test/showcase/TestShowcaseApplication.kt
diff --git a/app/src/main/java/org/fnives/test/showcase/di/createAppModules.kt b/app/src/koin/java/org/fnives/test/showcase/di/createAppModules.kt
similarity index 96%
rename from app/src/main/java/org/fnives/test/showcase/di/createAppModules.kt
rename to app/src/koin/java/org/fnives/test/showcase/di/createAppModules.kt
index 8d05715..4c20221 100644
--- a/app/src/main/java/org/fnives/test/showcase/di/createAppModules.kt
+++ b/app/src/koin/java/org/fnives/test/showcase/di/createAppModules.kt
@@ -1,6 +1,6 @@
package org.fnives.test.showcase.di
-import org.fnives.test.showcase.core.di.createCoreModule
+import org.fnives.test.showcase.core.di.koin.createCoreModule
import org.fnives.test.showcase.model.network.BaseUrl
import org.fnives.test.showcase.session.SessionExpirationListenerImpl
import org.fnives.test.showcase.storage.LocalDatabase
diff --git a/app/src/koin/java/org/fnives/test/showcase/ui/IntentCoordinator.kt b/app/src/koin/java/org/fnives/test/showcase/ui/IntentCoordinator.kt
new file mode 100644
index 0000000..4a5170a
--- /dev/null
+++ b/app/src/koin/java/org/fnives/test/showcase/ui/IntentCoordinator.kt
@@ -0,0 +1,14 @@
+package org.fnives.test.showcase.ui
+
+import android.content.Context
+import org.fnives.test.showcase.ui.auth.AuthActivity
+import org.fnives.test.showcase.ui.home.MainActivity
+
+object IntentCoordinator {
+
+ fun mainActivitygetStartIntent(context: Context) =
+ MainActivity.getStartIntent(context)
+
+ fun authActivitygetStartIntent(context: Context) =
+ AuthActivity.getStartIntent(context)
+}
\ No newline at end of file
diff --git a/app/src/koin/java/org/fnives/test/showcase/ui/ViewModelDelegate.kt b/app/src/koin/java/org/fnives/test/showcase/ui/ViewModelDelegate.kt
new file mode 100644
index 0000000..1cca4d6
--- /dev/null
+++ b/app/src/koin/java/org/fnives/test/showcase/ui/ViewModelDelegate.kt
@@ -0,0 +1,8 @@
+package org.fnives.test.showcase.ui
+
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelStoreOwner
+import org.koin.androidx.viewmodel.ext.android.viewModel
+
+inline fun ViewModelStoreOwner.viewModels(): Lazy =
+ viewModel()
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 09b554f..f778c8e 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -6,24 +6,13 @@
-
-
-
-
-
-
-
-
-
-
+ tools:ignore="AllowBackup"/>
\ No newline at end of file
diff --git a/app/src/main/java/org/fnives/test/showcase/session/SessionExpirationListenerImpl.kt b/app/src/main/java/org/fnives/test/showcase/session/SessionExpirationListenerImpl.kt
index 230a521..b0fb00d 100644
--- a/app/src/main/java/org/fnives/test/showcase/session/SessionExpirationListenerImpl.kt
+++ b/app/src/main/java/org/fnives/test/showcase/session/SessionExpirationListenerImpl.kt
@@ -4,15 +4,20 @@ import android.content.Context
import android.content.Intent
import android.os.Handler
import android.os.Looper
+import dagger.hilt.android.qualifiers.ApplicationContext
import org.fnives.test.showcase.core.session.SessionExpirationListener
-import org.fnives.test.showcase.ui.auth.AuthActivity
+import org.fnives.test.showcase.ui.IntentCoordinator
+import javax.inject.Inject
-class SessionExpirationListenerImpl(private val context: Context) : SessionExpirationListener {
+class SessionExpirationListenerImpl @Inject constructor(
+ @ApplicationContext
+ private val context: Context
+) : SessionExpirationListener {
override fun onSessionExpired() {
Handler(Looper.getMainLooper()).post {
context.startActivity(
- AuthActivity.getStartIntent(context)
+ IntentCoordinator.authActivitygetStartIntent(context)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
)
diff --git a/app/src/main/java/org/fnives/test/showcase/storage/SharedPreferencesManagerImpl.kt b/app/src/main/java/org/fnives/test/showcase/storage/SharedPreferencesManagerImpl.kt
index a62af66..aa4265b 100644
--- a/app/src/main/java/org/fnives/test/showcase/storage/SharedPreferencesManagerImpl.kt
+++ b/app/src/main/java/org/fnives/test/showcase/storage/SharedPreferencesManagerImpl.kt
@@ -7,7 +7,7 @@ import org.fnives.test.showcase.model.session.Session
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
-class SharedPreferencesManagerImpl(private val sharedPreferences: SharedPreferences) : UserDataLocalStorage {
+class SharedPreferencesManagerImpl constructor(private val sharedPreferences: SharedPreferences) : UserDataLocalStorage {
override var session: Session? by SessionDelegate(SESSION_KEY)
diff --git a/app/src/main/java/org/fnives/test/showcase/storage/favourite/FavouriteContentLocalStorageImpl.kt b/app/src/main/java/org/fnives/test/showcase/storage/favourite/FavouriteContentLocalStorageImpl.kt
index ac0f9d9..4797f32 100644
--- a/app/src/main/java/org/fnives/test/showcase/storage/favourite/FavouriteContentLocalStorageImpl.kt
+++ b/app/src/main/java/org/fnives/test/showcase/storage/favourite/FavouriteContentLocalStorageImpl.kt
@@ -4,8 +4,9 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import org.fnives.test.showcase.core.storage.content.FavouriteContentLocalStorage
import org.fnives.test.showcase.model.content.ContentId
+import javax.inject.Inject
-class FavouriteContentLocalStorageImpl(private val favouriteDao: FavouriteDao) : FavouriteContentLocalStorage {
+class FavouriteContentLocalStorageImpl @Inject constructor(private val favouriteDao: FavouriteDao) : FavouriteContentLocalStorage {
override fun observeFavourites(): Flow> =
favouriteDao.get().map { it.map(FavouriteEntity::contentId).map(::ContentId) }
diff --git a/app/src/main/java/org/fnives/test/showcase/ui/auth/AuthActivity.kt b/app/src/main/java/org/fnives/test/showcase/ui/auth/AuthActivity.kt
index 3e4157c..9e035bc 100644
--- a/app/src/main/java/org/fnives/test/showcase/ui/auth/AuthActivity.kt
+++ b/app/src/main/java/org/fnives/test/showcase/ui/auth/AuthActivity.kt
@@ -9,12 +9,12 @@ import androidx.core.widget.doAfterTextChanged
import com.google.android.material.snackbar.Snackbar
import org.fnives.test.showcase.R
import org.fnives.test.showcase.databinding.ActivityAuthenticationBinding
-import org.fnives.test.showcase.ui.home.MainActivity
-import org.koin.androidx.viewmodel.ext.android.viewModel
+import org.fnives.test.showcase.ui.IntentCoordinator
+import org.fnives.test.showcase.ui.viewModels
-class AuthActivity : AppCompatActivity() {
+open class AuthActivity : AppCompatActivity() {
- private val viewModel by viewModel()
+ private val viewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -35,7 +35,7 @@ class AuthActivity : AppCompatActivity() {
}
viewModel.navigateToHome.observe(this) {
it.consume() ?: return@observe
- startActivity(MainActivity.getStartIntent(this))
+ startActivity(IntentCoordinator.mainActivitygetStartIntent(this))
finishAffinity()
}
setContentView(binding.root)
diff --git a/app/src/main/java/org/fnives/test/showcase/ui/auth/AuthViewModel.kt b/app/src/main/java/org/fnives/test/showcase/ui/auth/AuthViewModel.kt
index 0221f14..b5fa26f 100644
--- a/app/src/main/java/org/fnives/test/showcase/ui/auth/AuthViewModel.kt
+++ b/app/src/main/java/org/fnives/test/showcase/ui/auth/AuthViewModel.kt
@@ -4,14 +4,17 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
+import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import org.fnives.test.showcase.core.login.LoginUseCase
import org.fnives.test.showcase.model.auth.LoginCredentials
import org.fnives.test.showcase.model.auth.LoginStatus
import org.fnives.test.showcase.model.shared.Answer
import org.fnives.test.showcase.ui.shared.Event
+import javax.inject.Inject
-class AuthViewModel(private val loginUseCase: LoginUseCase) : ViewModel() {
+@HiltViewModel
+class AuthViewModel @Inject constructor(private val loginUseCase: LoginUseCase) : ViewModel() {
private val _username = MutableLiveData()
val username: LiveData = _username
diff --git a/app/src/main/java/org/fnives/test/showcase/ui/home/MainActivity.kt b/app/src/main/java/org/fnives/test/showcase/ui/home/MainActivity.kt
index 187304a..a9bea69 100644
--- a/app/src/main/java/org/fnives/test/showcase/ui/home/MainActivity.kt
+++ b/app/src/main/java/org/fnives/test/showcase/ui/home/MainActivity.kt
@@ -6,17 +6,18 @@ import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.isVisible
import androidx.recyclerview.widget.LinearLayoutManager
+import dagger.hilt.android.AndroidEntryPoint
import org.fnives.test.showcase.R
import org.fnives.test.showcase.databinding.ActivityMainBinding
import org.fnives.test.showcase.model.content.ContentId
-import org.fnives.test.showcase.ui.auth.AuthActivity
+import org.fnives.test.showcase.ui.IntentCoordinator
import org.fnives.test.showcase.ui.shared.VerticalSpaceItemDecoration
import org.fnives.test.showcase.ui.shared.getThemePrimaryColor
-import org.koin.androidx.viewmodel.ext.android.viewModel
+import org.fnives.test.showcase.ui.viewModels
-class MainActivity : AppCompatActivity() {
+open class MainActivity : AppCompatActivity() {
- private val viewModel by viewModel()
+ private val viewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -45,7 +46,7 @@ class MainActivity : AppCompatActivity() {
}
viewModel.navigateToAuth.observe(this) {
it.consume() ?: return@observe
- startActivity(AuthActivity.getStartIntent(this))
+ startActivity(IntentCoordinator.authActivitygetStartIntent(this))
finishAffinity()
}
viewModel.loading.observe(this) {
diff --git a/app/src/main/java/org/fnives/test/showcase/ui/home/MainViewModel.kt b/app/src/main/java/org/fnives/test/showcase/ui/home/MainViewModel.kt
index 326ac01..502d543 100644
--- a/app/src/main/java/org/fnives/test/showcase/ui/home/MainViewModel.kt
+++ b/app/src/main/java/org/fnives/test/showcase/ui/home/MainViewModel.kt
@@ -5,6 +5,7 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.liveData
import androidx.lifecycle.viewModelScope
+import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
import org.fnives.test.showcase.core.content.AddContentToFavouriteUseCase
@@ -16,8 +17,10 @@ import org.fnives.test.showcase.model.content.ContentId
import org.fnives.test.showcase.model.content.FavouriteContent
import org.fnives.test.showcase.model.shared.Resource
import org.fnives.test.showcase.ui.shared.Event
+import javax.inject.Inject
-class MainViewModel(
+@HiltViewModel
+class MainViewModel @Inject constructor(
private val getAllContentUseCase: GetAllContentUseCase,
private val logoutUseCase: LogoutUseCase,
private val fetchContentUseCase: FetchContentUseCase,
diff --git a/app/src/main/java/org/fnives/test/showcase/ui/splash/SplashActivity.kt b/app/src/main/java/org/fnives/test/showcase/ui/splash/SplashActivity.kt
index ab7ee68..48e1ce1 100644
--- a/app/src/main/java/org/fnives/test/showcase/ui/splash/SplashActivity.kt
+++ b/app/src/main/java/org/fnives/test/showcase/ui/splash/SplashActivity.kt
@@ -3,21 +3,20 @@ package org.fnives.test.showcase.ui.splash
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import org.fnives.test.showcase.R
-import org.fnives.test.showcase.ui.auth.AuthActivity
-import org.fnives.test.showcase.ui.home.MainActivity
-import org.koin.androidx.viewmodel.ext.android.viewModel
+import org.fnives.test.showcase.ui.IntentCoordinator
+import org.fnives.test.showcase.ui.viewModels
-class SplashActivity : AppCompatActivity() {
+open class SplashActivity : AppCompatActivity() {
- private val viewModel by viewModel()
+ private val viewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_splash)
viewModel.navigateTo.observe(this) {
val intent = when (it.consume()) {
- SplashViewModel.NavigateTo.HOME -> MainActivity.getStartIntent(this)
- SplashViewModel.NavigateTo.AUTHENTICATION -> AuthActivity.getStartIntent(this)
+ SplashViewModel.NavigateTo.HOME -> IntentCoordinator.mainActivitygetStartIntent(this)
+ SplashViewModel.NavigateTo.AUTHENTICATION -> IntentCoordinator.authActivitygetStartIntent(this)
null -> return@observe
}
startActivity(intent)
diff --git a/app/src/main/java/org/fnives/test/showcase/ui/splash/SplashViewModel.kt b/app/src/main/java/org/fnives/test/showcase/ui/splash/SplashViewModel.kt
index d9bbd43..13a1887 100644
--- a/app/src/main/java/org/fnives/test/showcase/ui/splash/SplashViewModel.kt
+++ b/app/src/main/java/org/fnives/test/showcase/ui/splash/SplashViewModel.kt
@@ -4,12 +4,15 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
+import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.fnives.test.showcase.core.login.IsUserLoggedInUseCase
import org.fnives.test.showcase.ui.shared.Event
+import javax.inject.Inject
-class SplashViewModel(isUserLoggedInUseCase: IsUserLoggedInUseCase) : ViewModel() {
+@HiltViewModel
+class SplashViewModel @Inject constructor(isUserLoggedInUseCase: IsUserLoggedInUseCase) : ViewModel() {
private val _navigateTo = MutableLiveData>()
val navigateTo: LiveData> = _navigateTo
diff --git a/build.gradle b/build.gradle
index c09cd78..c4df286 100644
--- a/build.gradle
+++ b/build.gradle
@@ -2,12 +2,14 @@
buildscript {
ext.kotlin_version = "1.5.30"
ext.detekt_version = "1.18.1"
+ ext.hilt_version = "2.38.1"
repositories {
mavenCentral()
google()
maven { url "https://plugins.gradle.org/m2/" }
}
dependencies {
+ classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version"
classpath 'com.android.tools.build:gradle:7.0.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jlleitschuh.gradle:ktlint-gradle:10.2.0"
@@ -22,6 +24,15 @@ allprojects {
repositories {
mavenCentral()
google()
+ maven {
+ url "https://maven.pkg.github.com/fknives/ReloadableHiltModule"
+ credentials {
+ username = project.findProperty("GITHUB_USERNAME") ?: System.getenv("GITHUB_USERNAME")
+ password = project.findProperty("GITHUB_TOKEN") ?: System.getenv("GITHUB_TOKEN")
+ }
+ // how to get token
+ // https://docs.github.com/en/github/authenticating-to-github/keeping-your-account-and-data-secure/creating-a-personal-access-token
+ }
}
}
@@ -29,7 +40,7 @@ task clean(type: Delete) {
delete rootProject.buildDir
}
-task unitTests(dependsOn: ["app:testDebugUnitTest", "core:test", "network:test"]){
+task unitTests(dependsOn: ["app:testKoinDebugUnitTest", "app:testHiltDebugUnitTest", "core:test", "network:test"]){
group = 'Tests'
description = 'Run all unit tests'
}
diff --git a/core/build.gradle b/core/build.gradle
index 745175d..a66b8fc 100644
--- a/core/build.gradle
+++ b/core/build.gradle
@@ -1,6 +1,7 @@
plugins {
id 'java-library'
id 'kotlin'
+ id 'kotlin-kapt'
}
java {
@@ -14,12 +15,22 @@ compileKotlin {
}
}
+kapt {
+ correctErrorTypes = true
+}
+
dependencies {
api "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version"
api project(":model")
implementation project(":network")
+ // hilt
+ implementation "com.google.dagger:hilt-core:$hilt_version"
+ kapt "com.google.dagger:hilt-compiler:$hilt_version"
+ implementation "org.fnives.library.reloadable.module:annotation:$reloadable_module_version"
+ kapt "org.fnives.library.reloadable.module:annotation-processor:$reloadable_module_version"
+
testImplementation "io.insert-koin:koin-test-junit5:$koin_version"
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines_version"
testImplementation "org.mockito.kotlin:mockito-kotlin:$testing_kotlin_mockito_version"
diff --git a/core/src/main/java/org/fnives/test/showcase/core/content/AddContentToFavouriteUseCase.kt b/core/src/main/java/org/fnives/test/showcase/core/content/AddContentToFavouriteUseCase.kt
index c5ea010..2483d1c 100644
--- a/core/src/main/java/org/fnives/test/showcase/core/content/AddContentToFavouriteUseCase.kt
+++ b/core/src/main/java/org/fnives/test/showcase/core/content/AddContentToFavouriteUseCase.kt
@@ -2,8 +2,9 @@ package org.fnives.test.showcase.core.content
import org.fnives.test.showcase.core.storage.content.FavouriteContentLocalStorage
import org.fnives.test.showcase.model.content.ContentId
+import javax.inject.Inject
-class AddContentToFavouriteUseCase internal constructor(
+class AddContentToFavouriteUseCase @Inject internal constructor(
private val favouriteContentLocalStorage: FavouriteContentLocalStorage
) {
diff --git a/core/src/main/java/org/fnives/test/showcase/core/content/ContentRepository.kt b/core/src/main/java/org/fnives/test/showcase/core/content/ContentRepository.kt
index b243db5..143d2c8 100644
--- a/core/src/main/java/org/fnives/test/showcase/core/content/ContentRepository.kt
+++ b/core/src/main/java/org/fnives/test/showcase/core/content/ContentRepository.kt
@@ -7,6 +7,7 @@ import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOf
+import org.fnives.test.showcase.core.di.hilt.LoggedInModuleInject
import org.fnives.test.showcase.core.shared.Optional
import org.fnives.test.showcase.core.shared.mapIntoResource
import org.fnives.test.showcase.core.shared.wrapIntoAnswer
@@ -14,7 +15,7 @@ import org.fnives.test.showcase.model.content.Content
import org.fnives.test.showcase.model.shared.Resource
import org.fnives.test.showcase.network.content.ContentRemoteSource
-internal class ContentRepository(private val contentRemoteSource: ContentRemoteSource) {
+internal class ContentRepository @LoggedInModuleInject constructor(private val contentRemoteSource: ContentRemoteSource) {
private val mutableContentFlow = MutableStateFlow(Optional>(null))
private val requestFlow: Flow>> = flow {
diff --git a/core/src/main/java/org/fnives/test/showcase/core/content/FetchContentUseCase.kt b/core/src/main/java/org/fnives/test/showcase/core/content/FetchContentUseCase.kt
index 90c7a5b..16944f5 100644
--- a/core/src/main/java/org/fnives/test/showcase/core/content/FetchContentUseCase.kt
+++ b/core/src/main/java/org/fnives/test/showcase/core/content/FetchContentUseCase.kt
@@ -1,6 +1,8 @@
package org.fnives.test.showcase.core.content
-class FetchContentUseCase internal constructor(private val contentRepository: ContentRepository) {
+import javax.inject.Inject
+
+class FetchContentUseCase @Inject internal constructor(private val contentRepository: ContentRepository) {
fun invoke() = contentRepository.fetch()
}
diff --git a/core/src/main/java/org/fnives/test/showcase/core/content/GetAllContentUseCase.kt b/core/src/main/java/org/fnives/test/showcase/core/content/GetAllContentUseCase.kt
index 24a4b63..56b7c72 100644
--- a/core/src/main/java/org/fnives/test/showcase/core/content/GetAllContentUseCase.kt
+++ b/core/src/main/java/org/fnives/test/showcase/core/content/GetAllContentUseCase.kt
@@ -7,8 +7,9 @@ import org.fnives.test.showcase.model.content.Content
import org.fnives.test.showcase.model.content.ContentId
import org.fnives.test.showcase.model.content.FavouriteContent
import org.fnives.test.showcase.model.shared.Resource
+import javax.inject.Inject
-class GetAllContentUseCase internal constructor(
+class GetAllContentUseCase @Inject internal constructor(
private val contentRepository: ContentRepository,
private val favouriteContentLocalStorage: FavouriteContentLocalStorage
) {
diff --git a/core/src/main/java/org/fnives/test/showcase/core/content/RemoveContentFromFavouritesUseCase.kt b/core/src/main/java/org/fnives/test/showcase/core/content/RemoveContentFromFavouritesUseCase.kt
index 494af3e..4c03f90 100644
--- a/core/src/main/java/org/fnives/test/showcase/core/content/RemoveContentFromFavouritesUseCase.kt
+++ b/core/src/main/java/org/fnives/test/showcase/core/content/RemoveContentFromFavouritesUseCase.kt
@@ -2,8 +2,9 @@ package org.fnives.test.showcase.core.content
import org.fnives.test.showcase.core.storage.content.FavouriteContentLocalStorage
import org.fnives.test.showcase.model.content.ContentId
+import javax.inject.Inject
-class RemoveContentFromFavouritesUseCase internal constructor(
+class RemoveContentFromFavouritesUseCase @Inject internal constructor(
private val favouriteContentLocalStorage: FavouriteContentLocalStorage
) {
diff --git a/core/src/main/java/org/fnives/test/showcase/core/di/hilt/CoreModule.kt b/core/src/main/java/org/fnives/test/showcase/core/di/hilt/CoreModule.kt
new file mode 100644
index 0000000..6ca5bdc
--- /dev/null
+++ b/core/src/main/java/org/fnives/test/showcase/core/di/hilt/CoreModule.kt
@@ -0,0 +1,34 @@
+package org.fnives.test.showcase.core.di.hilt
+
+import dagger.Module
+import dagger.Provides
+import dagger.hilt.InstallIn
+import dagger.hilt.components.SingletonComponent
+import org.fnives.test.showcase.core.login.LogoutUseCase
+import org.fnives.test.showcase.core.session.SessionExpirationAdapter
+import org.fnives.test.showcase.core.storage.NetworkSessionLocalStorageAdapter
+import org.fnives.test.showcase.core.storage.UserDataLocalStorage
+import org.fnives.test.showcase.network.session.NetworkSessionExpirationListener
+import org.fnives.test.showcase.network.session.NetworkSessionLocalStorage
+import org.fnives.test.showcase.core.di.hilt.ReloadLoggedInModuleInjectModule
+
+@InstallIn(SingletonComponent::class)
+@Module
+object CoreModule {
+
+ @Provides
+ internal fun bindNetworkSessionLocalStorageAdapter(
+ networkSessionLocalStorageAdapter: NetworkSessionLocalStorageAdapter
+ ): NetworkSessionLocalStorage = networkSessionLocalStorageAdapter
+
+ @Provides
+ internal fun bindNetworkSessionExpirationListener(
+ sessionExpirationAdapter: SessionExpirationAdapter
+ ): NetworkSessionExpirationListener = sessionExpirationAdapter
+
+ @Provides
+ fun provideLogoutUseCase(
+ storage: UserDataLocalStorage,
+ reloadLoggedInModuleInjectModule: ReloadLoggedInModuleInjectModule
+ ) : LogoutUseCase = LogoutUseCase(storage, reloadLoggedInModuleInjectModule)
+}
\ No newline at end of file
diff --git a/core/src/main/java/org/fnives/test/showcase/core/di/hilt/LoggedInModuleInject.kt b/core/src/main/java/org/fnives/test/showcase/core/di/hilt/LoggedInModuleInject.kt
new file mode 100644
index 0000000..3649804
--- /dev/null
+++ b/core/src/main/java/org/fnives/test/showcase/core/di/hilt/LoggedInModuleInject.kt
@@ -0,0 +1,8 @@
+package org.fnives.test.showcase.core.di.hilt
+
+import org.fnives.library.reloadable.module.annotation.ReloadableModule
+
+@ReloadableModule
+@Target(AnnotationTarget.CONSTRUCTOR)
+@Retention(AnnotationRetention.SOURCE)
+annotation class LoggedInModuleInject
\ No newline at end of file
diff --git a/core/src/main/java/org/fnives/test/showcase/core/di/createCoreModule.kt b/core/src/main/java/org/fnives/test/showcase/core/di/koin/createCoreModule.kt
similarity index 94%
rename from core/src/main/java/org/fnives/test/showcase/core/di/createCoreModule.kt
rename to core/src/main/java/org/fnives/test/showcase/core/di/koin/createCoreModule.kt
index d3b6bc5..5f66810 100644
--- a/core/src/main/java/org/fnives/test/showcase/core/di/createCoreModule.kt
+++ b/core/src/main/java/org/fnives/test/showcase/core/di/koin/createCoreModule.kt
@@ -1,4 +1,4 @@
-package org.fnives.test.showcase.core.di
+package org.fnives.test.showcase.core.di.koin
import org.fnives.test.showcase.core.content.AddContentToFavouriteUseCase
import org.fnives.test.showcase.core.content.ContentRepository
@@ -14,7 +14,7 @@ import org.fnives.test.showcase.core.storage.NetworkSessionLocalStorageAdapter
import org.fnives.test.showcase.core.storage.UserDataLocalStorage
import org.fnives.test.showcase.core.storage.content.FavouriteContentLocalStorage
import org.fnives.test.showcase.model.network.BaseUrl
-import org.fnives.test.showcase.network.di.createNetworkModules
+import org.fnives.test.showcase.network.di.koin.createNetworkModules
import org.koin.core.module.Module
import org.koin.core.scope.Scope
import org.koin.dsl.module
@@ -42,7 +42,7 @@ fun repositoryModule() = module {
fun useCaseModule() = module {
factory { LoginUseCase(get(), get()) }
- factory { LogoutUseCase(get()) }
+ factory { LogoutUseCase(get(), null) }
factory { GetAllContentUseCase(get(), get()) }
factory { AddContentToFavouriteUseCase(get()) }
factory { RemoveContentFromFavouritesUseCase(get()) }
diff --git a/core/src/main/java/org/fnives/test/showcase/core/login/IsUserLoggedInUseCase.kt b/core/src/main/java/org/fnives/test/showcase/core/login/IsUserLoggedInUseCase.kt
index fd0539a..1e21dd1 100644
--- a/core/src/main/java/org/fnives/test/showcase/core/login/IsUserLoggedInUseCase.kt
+++ b/core/src/main/java/org/fnives/test/showcase/core/login/IsUserLoggedInUseCase.kt
@@ -1,8 +1,11 @@
package org.fnives.test.showcase.core.login
import org.fnives.test.showcase.core.storage.UserDataLocalStorage
+import javax.inject.Inject
-class IsUserLoggedInUseCase(private val userDataLocalStorage: UserDataLocalStorage) {
+class IsUserLoggedInUseCase @Inject constructor(
+ private val userDataLocalStorage: UserDataLocalStorage
+) {
fun invoke(): Boolean = userDataLocalStorage.session != null
}
diff --git a/core/src/main/java/org/fnives/test/showcase/core/login/LoginUseCase.kt b/core/src/main/java/org/fnives/test/showcase/core/login/LoginUseCase.kt
index 2a91780..cf03c79 100644
--- a/core/src/main/java/org/fnives/test/showcase/core/login/LoginUseCase.kt
+++ b/core/src/main/java/org/fnives/test/showcase/core/login/LoginUseCase.kt
@@ -7,8 +7,9 @@ import org.fnives.test.showcase.model.auth.LoginStatus
import org.fnives.test.showcase.model.shared.Answer
import org.fnives.test.showcase.network.auth.LoginRemoteSource
import org.fnives.test.showcase.network.auth.model.LoginStatusResponses
+import javax.inject.Inject
-class LoginUseCase internal constructor(
+class LoginUseCase @Inject internal constructor(
private val loginRemoteSource: LoginRemoteSource,
private val userDataLocalStorage: UserDataLocalStorage
) {
diff --git a/core/src/main/java/org/fnives/test/showcase/core/login/LogoutUseCase.kt b/core/src/main/java/org/fnives/test/showcase/core/login/LogoutUseCase.kt
index 158e7e0..7e36a78 100644
--- a/core/src/main/java/org/fnives/test/showcase/core/login/LogoutUseCase.kt
+++ b/core/src/main/java/org/fnives/test/showcase/core/login/LogoutUseCase.kt
@@ -1,13 +1,22 @@
package org.fnives.test.showcase.core.login
-import org.fnives.test.showcase.core.di.repositoryModule
+import org.fnives.test.showcase.core.di.koin.repositoryModule
import org.fnives.test.showcase.core.storage.UserDataLocalStorage
import org.koin.core.context.loadKoinModules
+import org.koin.mp.KoinPlatformTools
+import org.fnives.test.showcase.core.di.hilt.ReloadLoggedInModuleInjectModule
-class LogoutUseCase(private val storage: UserDataLocalStorage) {
+class LogoutUseCase(
+ private val storage: UserDataLocalStorage,
+ private val reloadLoggedInModuleInjectModule: ReloadLoggedInModuleInjectModule?
+) {
suspend fun invoke() {
- loadKoinModules(repositoryModule())
+ if (KoinPlatformTools.defaultContext().getOrNull() == null) {
+ reloadLoggedInModuleInjectModule?.reload()
+ } else {
+ loadKoinModules(repositoryModule())
+ }
storage.session = null
}
}
diff --git a/core/src/main/java/org/fnives/test/showcase/core/session/SessionExpirationAdapter.kt b/core/src/main/java/org/fnives/test/showcase/core/session/SessionExpirationAdapter.kt
index 1947635..3571971 100644
--- a/core/src/main/java/org/fnives/test/showcase/core/session/SessionExpirationAdapter.kt
+++ b/core/src/main/java/org/fnives/test/showcase/core/session/SessionExpirationAdapter.kt
@@ -1,11 +1,11 @@
package org.fnives.test.showcase.core.session
import org.fnives.test.showcase.network.session.NetworkSessionExpirationListener
+import javax.inject.Inject
-internal class SessionExpirationAdapter(
+internal class SessionExpirationAdapter @Inject constructor(
private val sessionExpirationListener: SessionExpirationListener
-) :
- NetworkSessionExpirationListener {
+) : NetworkSessionExpirationListener {
override fun onSessionExpired() = sessionExpirationListener.onSessionExpired()
}
diff --git a/core/src/main/java/org/fnives/test/showcase/core/storage/NetworkSessionLocalStorageAdapter.kt b/core/src/main/java/org/fnives/test/showcase/core/storage/NetworkSessionLocalStorageAdapter.kt
index a9d5d77..0d157f6 100644
--- a/core/src/main/java/org/fnives/test/showcase/core/storage/NetworkSessionLocalStorageAdapter.kt
+++ b/core/src/main/java/org/fnives/test/showcase/core/storage/NetworkSessionLocalStorageAdapter.kt
@@ -2,8 +2,9 @@ package org.fnives.test.showcase.core.storage
import org.fnives.test.showcase.model.session.Session
import org.fnives.test.showcase.network.session.NetworkSessionLocalStorage
+import javax.inject.Inject
-internal class NetworkSessionLocalStorageAdapter(
+internal class NetworkSessionLocalStorageAdapter @Inject constructor(
private val userDataLocalStorage: UserDataLocalStorage
) : NetworkSessionLocalStorage {
diff --git a/core/src/test/java/org/fnives/test/showcase/core/login/LogoutUseCaseTest.kt b/core/src/test/java/org/fnives/test/showcase/core/login/LogoutUseCaseTest.kt
index ffb1900..776f1ab 100644
--- a/core/src/test/java/org/fnives/test/showcase/core/login/LogoutUseCaseTest.kt
+++ b/core/src/test/java/org/fnives/test/showcase/core/login/LogoutUseCaseTest.kt
@@ -2,7 +2,7 @@ package org.fnives.test.showcase.core.login
import kotlinx.coroutines.test.runBlockingTest
import org.fnives.test.showcase.core.content.ContentRepository
-import org.fnives.test.showcase.core.di.createCoreModule
+import org.fnives.test.showcase.core.di.koin.createCoreModule
import org.fnives.test.showcase.core.storage.UserDataLocalStorage
import org.fnives.test.showcase.model.network.BaseUrl
import org.junit.jupiter.api.AfterEach
diff --git a/gradlescripts/versions.gradle b/gradlescripts/versions.gradle
index 4f8ed25..0d5a246 100644
--- a/gradlescripts/versions.gradle
+++ b/gradlescripts/versions.gradle
@@ -6,6 +6,7 @@ project.ext {
androidx_livedata_version = "2.3.1"
androidx_swiperefreshlayout_version = "1.1.0"
androidx_room_version = "2.3.0"
+ activity_ktx_version = "1.3.1"
coroutines_version = "1.4.3"
koin_version = "3.1.2"
@@ -13,6 +14,7 @@ project.ext {
retrofit_version = "2.9.0"
okhttp_version = "4.9.1"
moshi_version = "1.12.0"
+ reloadable_module_version = "0.1.0"
testing_androidx_code_version = "1.4.0"
testing_androidx_junit_version = "1.1.3"
diff --git a/network/build.gradle b/network/build.gradle
index fc17ae7..7449ab7 100644
--- a/network/build.gradle
+++ b/network/build.gradle
@@ -18,6 +18,8 @@ dependencies {
kapt "com.squareup.moshi:moshi-kotlin-codegen:$moshi_version"
implementation "com.squareup.okhttp3:logging-interceptor:$okhttp_version"
api "io.insert-koin:koin-core:$koin_version"
+ implementation "com.google.dagger:hilt-core:$hilt_version"
+ kapt "com.google.dagger:hilt-compiler:$hilt_version"
api project(":model")
diff --git a/network/src/main/java/org/fnives/test/showcase/network/auth/LoginErrorConverter.kt b/network/src/main/java/org/fnives/test/showcase/network/auth/LoginErrorConverter.kt
index 49a588b..057064e 100644
--- a/network/src/main/java/org/fnives/test/showcase/network/auth/LoginErrorConverter.kt
+++ b/network/src/main/java/org/fnives/test/showcase/network/auth/LoginErrorConverter.kt
@@ -7,8 +7,9 @@ import org.fnives.test.showcase.network.shared.ExceptionWrapper
import org.fnives.test.showcase.network.shared.exceptions.ParsingException
import retrofit2.HttpException
import retrofit2.Response
+import javax.inject.Inject
-internal class LoginErrorConverter {
+internal class LoginErrorConverter @Inject constructor() {
@Throws(ParsingException::class)
suspend fun invoke(request: suspend () -> Response): LoginStatusResponses =
diff --git a/network/src/main/java/org/fnives/test/showcase/network/auth/LoginRemoteSourceImpl.kt b/network/src/main/java/org/fnives/test/showcase/network/auth/LoginRemoteSourceImpl.kt
index 248ffde..0a5bf85 100644
--- a/network/src/main/java/org/fnives/test/showcase/network/auth/LoginRemoteSourceImpl.kt
+++ b/network/src/main/java/org/fnives/test/showcase/network/auth/LoginRemoteSourceImpl.kt
@@ -7,8 +7,9 @@ import org.fnives.test.showcase.network.auth.model.LoginStatusResponses
import org.fnives.test.showcase.network.shared.ExceptionWrapper
import org.fnives.test.showcase.network.shared.exceptions.NetworkException
import org.fnives.test.showcase.network.shared.exceptions.ParsingException
+import javax.inject.Inject
-internal class LoginRemoteSourceImpl constructor(
+internal class LoginRemoteSourceImpl @Inject constructor(
private val loginService: LoginService,
private val loginErrorConverter: LoginErrorConverter
) : LoginRemoteSource {
diff --git a/network/src/main/java/org/fnives/test/showcase/network/content/ContentRemoteSourceImpl.kt b/network/src/main/java/org/fnives/test/showcase/network/content/ContentRemoteSourceImpl.kt
index d1daac8..4c0da1a 100644
--- a/network/src/main/java/org/fnives/test/showcase/network/content/ContentRemoteSourceImpl.kt
+++ b/network/src/main/java/org/fnives/test/showcase/network/content/ContentRemoteSourceImpl.kt
@@ -4,8 +4,9 @@ import org.fnives.test.showcase.model.content.Content
import org.fnives.test.showcase.model.content.ContentId
import org.fnives.test.showcase.model.content.ImageUrl
import org.fnives.test.showcase.network.shared.ExceptionWrapper
+import javax.inject.Inject
-internal class ContentRemoteSourceImpl(private val contentService: ContentService) : ContentRemoteSource {
+internal class ContentRemoteSourceImpl @Inject constructor(private val contentService: ContentService) : ContentRemoteSource {
override suspend fun get(): List =
ExceptionWrapper.wrap {
diff --git a/network/src/main/java/org/fnives/test/showcase/network/di/hilt/HiltNetworkModule.kt b/network/src/main/java/org/fnives/test/showcase/network/di/hilt/HiltNetworkModule.kt
new file mode 100644
index 0000000..a5a6898
--- /dev/null
+++ b/network/src/main/java/org/fnives/test/showcase/network/di/hilt/HiltNetworkModule.kt
@@ -0,0 +1,96 @@
+package org.fnives.test.showcase.network.di.hilt
+
+import dagger.Module
+import dagger.Provides
+import dagger.hilt.InstallIn
+import dagger.hilt.components.SingletonComponent
+import okhttp3.OkHttpClient
+import org.fnives.test.showcase.network.auth.LoginRemoteSource
+import org.fnives.test.showcase.network.auth.LoginRemoteSourceImpl
+import org.fnives.test.showcase.network.auth.LoginService
+import org.fnives.test.showcase.network.content.ContentRemoteSource
+import org.fnives.test.showcase.network.content.ContentRemoteSourceImpl
+import org.fnives.test.showcase.network.content.ContentService
+import org.fnives.test.showcase.network.di.setupLogging
+import org.fnives.test.showcase.network.session.AuthenticationHeaderInterceptor
+import org.fnives.test.showcase.network.session.AuthenticationHeaderUtils
+import org.fnives.test.showcase.network.session.SessionAuthenticator
+import org.fnives.test.showcase.network.shared.PlatformInterceptor
+import retrofit2.Converter
+import retrofit2.Retrofit
+import retrofit2.converter.moshi.MoshiConverterFactory
+import javax.inject.Singleton
+
+@InstallIn(SingletonComponent::class)
+@Module
+object HiltNetworkModule {
+
+ @Provides
+ @Singleton
+ fun provideConverterFactory(): Converter.Factory = MoshiConverterFactory.create()
+
+ @Provides
+ @Singleton
+ @SessionLessQualifier
+ fun provideSessionLessOkHttpClient(enableLogging: Boolean) =
+ OkHttpClient.Builder()
+ .addInterceptor(PlatformInterceptor())
+ .setupLogging(enableLogging)
+ .build()
+
+ @Provides
+ @Singleton
+ @SessionLessQualifier
+ fun provideSessionLessRetrofit(
+ baseUrl: String,
+ converterFactory: Converter.Factory,
+ @SessionLessQualifier okHttpClient: OkHttpClient
+ ) = Retrofit.Builder()
+ .baseUrl(baseUrl)
+ .addConverterFactory(converterFactory)
+ .client(okHttpClient)
+ .build()
+
+ @Provides
+ @Singleton
+ @SessionQualifier
+ internal fun provideSessionOkHttpClient(
+ @SessionLessQualifier okHttpClient: OkHttpClient,
+ sessionAuthenticator: SessionAuthenticator,
+ authenticationHeaderUtils: AuthenticationHeaderUtils
+ ) =
+ okHttpClient
+ .newBuilder()
+ .authenticator(sessionAuthenticator)
+ .addInterceptor(AuthenticationHeaderInterceptor(authenticationHeaderUtils))
+ .build()
+
+ @Provides
+ @Singleton
+ @SessionQualifier
+ fun provideSessionRetrofit(
+ @SessionLessQualifier retrofit: Retrofit,
+ @SessionQualifier okHttpClient: OkHttpClient
+ ) = retrofit.newBuilder()
+ .client(okHttpClient)
+ .build()
+
+ @Provides
+ internal fun bindContentRemoteSource(
+ contentRemoteSourceImpl: ContentRemoteSourceImpl
+ ): ContentRemoteSource = contentRemoteSourceImpl
+
+ @Provides
+ internal fun bindLoginRemoteSource(
+ loginRemoteSource: LoginRemoteSourceImpl
+ ): LoginRemoteSource = loginRemoteSource
+
+ @Provides
+ internal fun provideLoginService(@SessionLessQualifier retrofit: Retrofit): LoginService =
+ retrofit.create(LoginService::class.java)
+
+ @Provides
+ internal fun provideContentService(@SessionQualifier retrofit: Retrofit): ContentService =
+ retrofit.create(ContentService::class.java)
+
+}
\ No newline at end of file
diff --git a/network/src/main/java/org/fnives/test/showcase/network/di/hilt/SessionLessQualifier.kt b/network/src/main/java/org/fnives/test/showcase/network/di/hilt/SessionLessQualifier.kt
new file mode 100644
index 0000000..46a259d
--- /dev/null
+++ b/network/src/main/java/org/fnives/test/showcase/network/di/hilt/SessionLessQualifier.kt
@@ -0,0 +1,6 @@
+package org.fnives.test.showcase.network.di.hilt
+
+import javax.inject.Qualifier
+
+@Qualifier
+annotation class SessionLessQualifier
\ No newline at end of file
diff --git a/network/src/main/java/org/fnives/test/showcase/network/di/hilt/SessionQualifier.kt b/network/src/main/java/org/fnives/test/showcase/network/di/hilt/SessionQualifier.kt
new file mode 100644
index 0000000..30ad41b
--- /dev/null
+++ b/network/src/main/java/org/fnives/test/showcase/network/di/hilt/SessionQualifier.kt
@@ -0,0 +1,6 @@
+package org.fnives.test.showcase.network.di.hilt
+
+import javax.inject.Qualifier
+
+@Qualifier
+annotation class SessionQualifier
\ No newline at end of file
diff --git a/network/src/main/java/org/fnives/test/showcase/network/di/createNetworkmodules.kt b/network/src/main/java/org/fnives/test/showcase/network/di/koin/createNetworkmodules.kt
similarity index 97%
rename from network/src/main/java/org/fnives/test/showcase/network/di/createNetworkmodules.kt
rename to network/src/main/java/org/fnives/test/showcase/network/di/koin/createNetworkmodules.kt
index b4b0e8b..2c84e77 100644
--- a/network/src/main/java/org/fnives/test/showcase/network/di/createNetworkmodules.kt
+++ b/network/src/main/java/org/fnives/test/showcase/network/di/koin/createNetworkmodules.kt
@@ -1,4 +1,4 @@
-package org.fnives.test.showcase.network.di
+package org.fnives.test.showcase.network.di.koin
import okhttp3.OkHttpClient
import org.fnives.test.showcase.model.network.BaseUrl
@@ -9,6 +9,7 @@ import org.fnives.test.showcase.network.auth.LoginService
import org.fnives.test.showcase.network.content.ContentRemoteSource
import org.fnives.test.showcase.network.content.ContentRemoteSourceImpl
import org.fnives.test.showcase.network.content.ContentService
+import org.fnives.test.showcase.network.di.setupLogging
import org.fnives.test.showcase.network.session.AuthenticationHeaderInterceptor
import org.fnives.test.showcase.network.session.AuthenticationHeaderUtils
import org.fnives.test.showcase.network.session.NetworkSessionExpirationListener
diff --git a/network/src/main/java/org/fnives/test/showcase/network/session/AuthenticationHeaderUtils.kt b/network/src/main/java/org/fnives/test/showcase/network/session/AuthenticationHeaderUtils.kt
index cfb35c6..ae228d5 100644
--- a/network/src/main/java/org/fnives/test/showcase/network/session/AuthenticationHeaderUtils.kt
+++ b/network/src/main/java/org/fnives/test/showcase/network/session/AuthenticationHeaderUtils.kt
@@ -1,8 +1,9 @@
package org.fnives.test.showcase.network.session
import okhttp3.Request
+import javax.inject.Inject
-internal class AuthenticationHeaderUtils(private val networkSessionLocalStorage: NetworkSessionLocalStorage) {
+internal class AuthenticationHeaderUtils @Inject constructor(private val networkSessionLocalStorage: NetworkSessionLocalStorage) {
fun hasToken(okhttpRequest: Request): Boolean =
okhttpRequest.header(KEY) == networkSessionLocalStorage.session?.accessToken
diff --git a/network/src/main/java/org/fnives/test/showcase/network/session/SessionAuthenticator.kt b/network/src/main/java/org/fnives/test/showcase/network/session/SessionAuthenticator.kt
index df1c411..544574c 100644
--- a/network/src/main/java/org/fnives/test/showcase/network/session/SessionAuthenticator.kt
+++ b/network/src/main/java/org/fnives/test/showcase/network/session/SessionAuthenticator.kt
@@ -6,8 +6,9 @@ import okhttp3.Request
import okhttp3.Response
import okhttp3.Route
import org.fnives.test.showcase.network.auth.LoginRemoteSourceImpl
+import javax.inject.Inject
-internal class SessionAuthenticator(
+internal class SessionAuthenticator @Inject constructor(
private val networkSessionLocalStorage: NetworkSessionLocalStorage,
private val loginRemoteSource: LoginRemoteSourceImpl,
private val authenticationHeaderUtils: AuthenticationHeaderUtils,
diff --git a/network/src/test/java/org/fnives/test/showcase/network/auth/LoginRemoteSourceRefreshActionImplTest.kt b/network/src/test/java/org/fnives/test/showcase/network/auth/LoginRemoteSourceRefreshActionImplTest.kt
index fc71d92..418d667 100644
--- a/network/src/test/java/org/fnives/test/showcase/network/auth/LoginRemoteSourceRefreshActionImplTest.kt
+++ b/network/src/test/java/org/fnives/test/showcase/network/auth/LoginRemoteSourceRefreshActionImplTest.kt
@@ -2,7 +2,7 @@ package org.fnives.test.showcase.network.auth
import kotlinx.coroutines.runBlocking
import org.fnives.test.showcase.model.network.BaseUrl
-import org.fnives.test.showcase.network.di.createNetworkModules
+import org.fnives.test.showcase.network.di.koin.createNetworkModules
import org.fnives.test.showcase.network.mockserver.ContentData
import org.fnives.test.showcase.network.mockserver.scenario.refresh.RefreshTokenScenario
import org.fnives.test.showcase.network.session.NetworkSessionLocalStorage
diff --git a/network/src/test/java/org/fnives/test/showcase/network/auth/LoginRemoteSourceTest.kt b/network/src/test/java/org/fnives/test/showcase/network/auth/LoginRemoteSourceTest.kt
index cd586bd..6d74777 100644
--- a/network/src/test/java/org/fnives/test/showcase/network/auth/LoginRemoteSourceTest.kt
+++ b/network/src/test/java/org/fnives/test/showcase/network/auth/LoginRemoteSourceTest.kt
@@ -4,7 +4,7 @@ import kotlinx.coroutines.runBlocking
import org.fnives.test.showcase.model.auth.LoginCredentials
import org.fnives.test.showcase.model.network.BaseUrl
import org.fnives.test.showcase.network.auth.model.LoginStatusResponses
-import org.fnives.test.showcase.network.di.createNetworkModules
+import org.fnives.test.showcase.network.di.koin.createNetworkModules
import org.fnives.test.showcase.network.mockserver.ContentData
import org.fnives.test.showcase.network.mockserver.ContentData.createExpectedLoginRequestJson
import org.fnives.test.showcase.network.mockserver.scenario.auth.AuthScenario
diff --git a/network/src/test/java/org/fnives/test/showcase/network/content/CodeKataSessionExpirationTest.kt b/network/src/test/java/org/fnives/test/showcase/network/content/CodeKataSessionExpirationTest.kt
index eb2f310..625b995 100644
--- a/network/src/test/java/org/fnives/test/showcase/network/content/CodeKataSessionExpirationTest.kt
+++ b/network/src/test/java/org/fnives/test/showcase/network/content/CodeKataSessionExpirationTest.kt
@@ -3,7 +3,7 @@ package org.fnives.test.showcase.network.content
import kotlinx.coroutines.runBlocking
import okhttp3.mockwebserver.MockWebServer
import org.fnives.test.showcase.model.network.BaseUrl
-import org.fnives.test.showcase.network.di.createNetworkModules
+import org.fnives.test.showcase.network.di.koin.createNetworkModules
import org.fnives.test.showcase.network.session.NetworkSessionExpirationListener
import org.fnives.test.showcase.network.session.NetworkSessionLocalStorage
import org.junit.jupiter.api.AfterEach
diff --git a/network/src/test/java/org/fnives/test/showcase/network/content/ContentRemoteSourceImplTest.kt b/network/src/test/java/org/fnives/test/showcase/network/content/ContentRemoteSourceImplTest.kt
index f1996d2..cff87d8 100644
--- a/network/src/test/java/org/fnives/test/showcase/network/content/ContentRemoteSourceImplTest.kt
+++ b/network/src/test/java/org/fnives/test/showcase/network/content/ContentRemoteSourceImplTest.kt
@@ -2,7 +2,7 @@ package org.fnives.test.showcase.network.content
import kotlinx.coroutines.runBlocking
import org.fnives.test.showcase.model.network.BaseUrl
-import org.fnives.test.showcase.network.di.createNetworkModules
+import org.fnives.test.showcase.network.di.koin.createNetworkModules
import org.fnives.test.showcase.network.mockserver.ContentData
import org.fnives.test.showcase.network.mockserver.scenario.content.ContentScenario
import org.fnives.test.showcase.network.session.NetworkSessionLocalStorage
diff --git a/network/src/test/java/org/fnives/test/showcase/network/content/SessionExpirationTest.kt b/network/src/test/java/org/fnives/test/showcase/network/content/SessionExpirationTest.kt
index 0f80d3e..3450b85 100644
--- a/network/src/test/java/org/fnives/test/showcase/network/content/SessionExpirationTest.kt
+++ b/network/src/test/java/org/fnives/test/showcase/network/content/SessionExpirationTest.kt
@@ -3,7 +3,7 @@ package org.fnives.test.showcase.network.content
import kotlinx.coroutines.runBlocking
import org.fnives.test.showcase.model.network.BaseUrl
import org.fnives.test.showcase.model.session.Session
-import org.fnives.test.showcase.network.di.createNetworkModules
+import org.fnives.test.showcase.network.di.koin.createNetworkModules
import org.fnives.test.showcase.network.mockserver.ContentData
import org.fnives.test.showcase.network.mockserver.scenario.content.ContentScenario
import org.fnives.test.showcase.network.mockserver.scenario.refresh.RefreshTokenScenario