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:
Melihcan Aksoy
2019-07-26 13:38:51 +02:00
committed by Melih Aksoy
parent 11889446cb
commit 625776609d
103 changed files with 4367 additions and 716 deletions

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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)
}
}

View File

@@ -0,0 +1,7 @@
package com.melih.list.di.scopes
import javax.inject.Scope
@Scope
@Retention(AnnotationRetention.BINARY)
annotation class DetailFragmentScope

View File

@@ -0,0 +1,7 @@
package com.melih.list.di.scopes
import javax.inject.Scope
@Scope
@Retention(AnnotationRetention.BINARY)
annotation class DetailScope

View File

@@ -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

View File

@@ -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) {

View File

@@ -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

View File

@@ -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()

View File

@@ -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