mirror of
https://github.com/melihaksoy/Android-Kotlin-Modulerized-CleanArchitecture.git
synced 2026-03-31 06:33:08 +02:00
Milestones/ms1 (#16)
* Closes #11 * Closes #13 * Closes #17 * Closes #18 * Closes #19 * Closes #6 * Closes #3 * Closes #12 * Closes #15
This commit is contained in:
committed by
Melih Aksoy
parent
11889446cb
commit
625776609d
@@ -1,7 +1,9 @@
|
||||
package com.melih.detail.di
|
||||
|
||||
import com.melih.detail.di.modules.DetailBinds
|
||||
import com.melih.detail.di.modules.DetailProvides
|
||||
import com.melih.detail.ui.DetailFragment
|
||||
import com.melih.list.di.scopes.DetailFragmentScope
|
||||
import dagger.Module
|
||||
import dagger.android.ContributesAndroidInjector
|
||||
|
||||
@@ -15,9 +17,11 @@ abstract class DetailContributor {
|
||||
|
||||
@ContributesAndroidInjector(
|
||||
modules = [
|
||||
DetailBinds::class
|
||||
DetailBinds::class,
|
||||
DetailProvides::class
|
||||
]
|
||||
)
|
||||
@DetailFragmentScope
|
||||
abstract fun detailFragment(): DetailFragment
|
||||
// endregion
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.melih.detail.di
|
||||
|
||||
import com.melih.detail.ui.DetailActivity
|
||||
import com.melih.list.di.scopes.DetailScope
|
||||
import dagger.Module
|
||||
import dagger.android.ContributesAndroidInjector
|
||||
|
||||
/**
|
||||
* Contributes fragments & view models in this module
|
||||
*/
|
||||
@Module
|
||||
abstract class DetailModule {
|
||||
|
||||
// region Contributes
|
||||
|
||||
@ContributesAndroidInjector(
|
||||
modules = [
|
||||
DetailContributor::class
|
||||
]
|
||||
)
|
||||
@DetailScope
|
||||
abstract fun detailActivity(): DetailActivity
|
||||
// endregion
|
||||
}
|
||||
@@ -6,7 +6,6 @@ import com.melih.detail.ui.DetailViewModel
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.multibindings.IntoMap
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
|
||||
@Module
|
||||
abstract class DetailBinds {
|
||||
@@ -16,7 +15,6 @@ abstract class DetailBinds {
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ViewModelKey(DetailViewModel::class)
|
||||
@ExperimentalCoroutinesApi
|
||||
abstract fun detailViewModel(detailViewModel: DetailViewModel): ViewModel
|
||||
// endregion
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.melih.detail.di.modules
|
||||
|
||||
import androidx.navigation.fragment.navArgs
|
||||
import com.melih.detail.ui.DetailFragment
|
||||
import com.melih.detail.ui.DetailFragmentArgs
|
||||
import com.melih.repository.interactors.GetLaunchDetails
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
|
||||
@Module
|
||||
class DetailProvides {
|
||||
|
||||
/**
|
||||
* Provides launch detail params
|
||||
*/
|
||||
@Provides
|
||||
fun provideGetLaunchDetailParams(fragment: DetailFragment): GetLaunchDetails.Params {
|
||||
val args: DetailFragmentArgs by fragment.navArgs()
|
||||
return GetLaunchDetails.Params(args.launchId)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.melih.list.di.scopes
|
||||
|
||||
import javax.inject.Scope
|
||||
|
||||
@Scope
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class DetailFragmentScope
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.melih.list.di.scopes
|
||||
|
||||
import javax.inject.Scope
|
||||
|
||||
@Scope
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class DetailScope
|
||||
@@ -6,7 +6,6 @@ import com.melih.core.actions.EXTRA_LAUNCH_ID
|
||||
import com.melih.core.base.lifecycle.BaseActivity
|
||||
import com.melih.detail.R
|
||||
import com.melih.detail.databinding.DetailActivityBinding
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
|
||||
const val INVALID_LAUNCH_ID = -1L
|
||||
|
||||
@@ -14,13 +13,12 @@ class DetailActivity : BaseActivity<DetailActivityBinding>() {
|
||||
|
||||
// region Functions
|
||||
|
||||
@ExperimentalCoroutinesApi
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
setSupportActionBar(binding.toolbar)
|
||||
supportActionBar?.setDisplayHomeAsUpEnabled(true);
|
||||
supportActionBar?.setDisplayShowHomeEnabled(true);
|
||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||
supportActionBar?.setDisplayShowHomeEnabled(true)
|
||||
}
|
||||
|
||||
override fun getLayoutId(): Int = R.layout.activity_detail
|
||||
|
||||
@@ -3,38 +3,28 @@ package com.melih.detail.ui
|
||||
import android.os.Bundle
|
||||
import android.text.method.ScrollingMovementMethod
|
||||
import android.view.View
|
||||
import androidx.navigation.fragment.navArgs
|
||||
import com.melih.core.base.lifecycle.BaseDaggerFragment
|
||||
import com.melih.core.extensions.createFor
|
||||
import com.melih.core.extensions.observe
|
||||
import com.melih.detail.R
|
||||
import com.melih.detail.databinding.DetailBinding
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import timber.log.Timber
|
||||
|
||||
class DetailFragment : BaseDaggerFragment<DetailBinding>() {
|
||||
|
||||
// region Properties
|
||||
|
||||
private val args: DetailFragmentArgs by navArgs()
|
||||
|
||||
@ExperimentalCoroutinesApi
|
||||
private val viewModel: DetailViewModel
|
||||
get() = viewModelFactory.createFor(this)
|
||||
// endregion
|
||||
|
||||
// region Functions
|
||||
|
||||
@ExperimentalCoroutinesApi
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
binding.tvDescription.movementMethod = ScrollingMovementMethod()
|
||||
binding.viewModel = viewModel
|
||||
|
||||
viewModel.createParamsFor(args.launchId)
|
||||
viewModel.loadData()
|
||||
|
||||
// Observing error to show toast with retry action
|
||||
observe(viewModel.errorData) {
|
||||
showSnackbarWithAction(it) {
|
||||
|
||||
@@ -1,24 +1,20 @@
|
||||
package com.melih.detail.ui
|
||||
|
||||
import androidx.lifecycle.Transformations
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.melih.core.base.viewmodel.BaseViewModel
|
||||
import com.melih.repository.entities.LaunchEntity
|
||||
import com.melih.repository.interactors.GetLaunchDetails
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import com.melih.repository.interactors.base.handle
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
@ExperimentalCoroutinesApi
|
||||
class DetailViewModel @Inject constructor(
|
||||
private val getLaunchDetails: GetLaunchDetails
|
||||
private val getLaunchDetails: GetLaunchDetails,
|
||||
private val getLaunchDetailsParams: GetLaunchDetails.Params
|
||||
) : BaseViewModel<LaunchEntity>() {
|
||||
|
||||
// region Properties
|
||||
|
||||
private var params = GetLaunchDetails.Params(INVALID_LAUNCH_ID)
|
||||
|
||||
val rocketName = Transformations.map(successData) {
|
||||
it.rocket.name
|
||||
}
|
||||
@@ -38,18 +34,12 @@ class DetailViewModel @Inject constructor(
|
||||
|
||||
// region Functions
|
||||
|
||||
fun createParamsFor(id: Long) {
|
||||
params = GetLaunchDetails.Params(id)
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggering interactor in view model scope
|
||||
*/
|
||||
override fun loadData() {
|
||||
viewModelScope.launch {
|
||||
getLaunchDetails(params).collect {
|
||||
it.handle(::handleState, ::handleFailure, ::handleSuccess)
|
||||
}
|
||||
override suspend fun loadData() {
|
||||
getLaunchDetails(getLaunchDetailsParams).collect {
|
||||
it.handle(::handleState, ::handleFailure, ::handleSuccess)
|
||||
}
|
||||
}
|
||||
// endregion
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.melih.list
|
||||
package com.melih.detail
|
||||
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
@@ -8,19 +8,17 @@ import kotlinx.coroutines.test.setMain
|
||||
import org.junit.jupiter.api.AfterEach
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
|
||||
@UseExperimental(ExperimentalCoroutinesApi::class)
|
||||
abstract class BaseTestWithMainThread {
|
||||
|
||||
@ExperimentalCoroutinesApi
|
||||
protected val dispatcher = TestCoroutineDispatcher()
|
||||
|
||||
@BeforeEach
|
||||
@ExperimentalCoroutinesApi
|
||||
fun setUp() {
|
||||
Dispatchers.setMain(dispatcher)
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
@ExperimentalCoroutinesApi
|
||||
fun tearDown() {
|
||||
Dispatchers.resetMain()
|
||||
dispatcher.cleanupTestCoroutines()
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.melih.detail
|
||||
|
||||
import com.melih.detail.ui.DetailViewModel
|
||||
import com.melih.list.BaseTestWithMainThread
|
||||
import com.melih.repository.interactors.GetLaunchDetails
|
||||
import io.mockk.mockk
|
||||
import io.mockk.slot
|
||||
@@ -17,21 +16,20 @@ import org.junit.jupiter.api.Test
|
||||
*
|
||||
* See [testing documentation](http://d.android.com/tools/testing).
|
||||
*/
|
||||
@UseExperimental(ExperimentalCoroutinesApi::class)
|
||||
class DetailViewModelTest : BaseTestWithMainThread() {
|
||||
|
||||
private val getLaunchDetails: GetLaunchDetails = mockk(relaxed = true)
|
||||
private val getLaunchDetailsParams = GetLaunchDetails.Params(1013)
|
||||
|
||||
@ExperimentalCoroutinesApi
|
||||
private val viewModel = spyk(DetailViewModel(getLaunchDetails))
|
||||
private val viewModel = spyk(DetailViewModel(getLaunchDetails, getLaunchDetailsParams))
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
fun `loadData should invoke getLauchDetails with provided params`() {
|
||||
dispatcher.runBlockingTest {
|
||||
|
||||
val paramsSlot = slot<GetLaunchDetails.Params>()
|
||||
|
||||
viewModel.createParamsFor(1013)
|
||||
viewModel.loadData()
|
||||
|
||||
// init should have called it already due to creation above
|
||||
|
||||
Reference in New Issue
Block a user