diff --git a/app/build.gradle b/app/build.gradle index a2507e0c..bc7e1498 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -66,17 +66,6 @@ android { targetCompatibility 1.8 } - bundle { - density { - enableSplit true - } - abi { - enableSplit true - } - language { - enableSplit false - } - } } dependencies { @@ -110,9 +99,6 @@ dependencies { implementation appDependencies.recyclerviewAnimations //Memory leaks - implementation 'androidx.legacy:legacy-support-v4:1.0.0' - implementation 'androidx.appcompat:appcompat:1.1.0' - implementation 'androidx.constraintlayout:constraintlayout:1.1.3' debugImplementation appDependencies.leakCanary //About Libraries diff --git a/app/src/androidTest/kotlin/com/k0d4black/theforce/CharacterDetailActivityIntegrationTest.kt b/app/src/androidTest/kotlin/com/k0d4black/theforce/CharacterDetailActivityIntegrationTest.kt index b6f74a56..80ecf493 100644 --- a/app/src/androidTest/kotlin/com/k0d4black/theforce/CharacterDetailActivityIntegrationTest.kt +++ b/app/src/androidTest/kotlin/com/k0d4black/theforce/CharacterDetailActivityIntegrationTest.kt @@ -8,7 +8,7 @@ import androidx.test.espresso.matcher.ViewMatchers.* import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.rule.ActivityTestRule import com.k0d4black.theforce.features.character_details.CharacterDetailActivity -import com.k0d4black.theforce.models.StarWarsCharacterUiModel +import com.k0d4black.theforce.models.CharacterPresentation import com.k0d4black.theforce.commons.CHARACTER_PARCEL_KEY import org.junit.After import org.junit.Rule @@ -36,12 +36,12 @@ internal class CharacterDetailActivityIntegrationTest : BaseTest() { fun shouldLoadDataOnLaunchWithValidCharacterId() { val intent = Intent().putExtra( CHARACTER_PARCEL_KEY, - StarWarsCharacterUiModel( + CharacterPresentation( name = "Luke", birthYear = "12BBY", heightInCm = "234", heightInInches = "544", - url = "1" + url = "https://swapi.py4e.com/api/people/1/" ) ) activityRule.launchActivity(intent) diff --git a/app/src/androidTest/kotlin/com/k0d4black/theforce/SearchActivityIntegrationTest.kt b/app/src/androidTest/kotlin/com/k0d4black/theforce/SearchActivityIntegrationTest.kt index 18046522..82dcc445 100644 --- a/app/src/androidTest/kotlin/com/k0d4black/theforce/SearchActivityIntegrationTest.kt +++ b/app/src/androidTest/kotlin/com/k0d4black/theforce/SearchActivityIntegrationTest.kt @@ -28,6 +28,7 @@ import org.junit.runner.RunWith @RunWith(AndroidJUnit4::class) internal class SearchActivityIntegrationTest : BaseTest() { + //TODO Use idling resource @get:Rule var activityRule: ActivityTestRule = @@ -52,7 +53,6 @@ internal class SearchActivityIntegrationTest : BaseTest() { fun shouldDisplayDataOnSearch() { onView(withId(R.id.action_search)).perform(click()) onView(isAssignableFrom(EditText::class.java)).perform(typeText(EXISTING_SEARCH_PARAMS)) - SystemClock.sleep(2000) onView(withId(R.id.search_results_recycler_view)).check(matches(isDisplayed())) } @@ -68,13 +68,13 @@ internal class SearchActivityIntegrationTest : BaseTest() { fun shouldNavigateToCharacterDetailOnItemClick() { onView(withId(R.id.action_search)).perform(click()) onView(isAssignableFrom(EditText::class.java)).perform(typeText(EXISTING_SEARCH_PARAMS)) - SystemClock.sleep(2000) + SystemClock.sleep(1500) onView(withId(R.id.search_results_recycler_view)).perform( RecyclerViewActions.actionOnItemAtPosition( 0, ViewAction.clickChildViewWithId(R.id.more_info_arrow_image_button) ) ) - SystemClock.sleep(2000) + SystemClock.sleep(1500) intended(hasComponent("com.k0d4black.theforce.features.character_details.CharacterDetailActivity")) } diff --git a/app/src/main/kotlin/com/k0d4black/theforce/di/modules/details/CharacterDetailsBindingModule.kt b/app/src/main/kotlin/com/k0d4black/theforce/di/modules/details/CharacterDetailsBindingModule.kt index 7bb7a94f..662a1241 100644 --- a/app/src/main/kotlin/com/k0d4black/theforce/di/modules/details/CharacterDetailsBindingModule.kt +++ b/app/src/main/kotlin/com/k0d4black/theforce/di/modules/details/CharacterDetailsBindingModule.kt @@ -1,6 +1,6 @@ package com.k0d4black.theforce.di.modules.details -import com.k0d4black.theforce.data.repository.StarWarsCharacterDetailsRepository +import com.k0d4black.theforce.data.repository.CharacterDetailsRepository import com.k0d4black.theforce.domain.repository.ICharacterDetailsRepository import dagger.Binds import dagger.Module @@ -11,7 +11,7 @@ abstract class CharacterDetailsBindingModule { @Singleton @Binds abstract fun bindCharacterDetailsRepository( - starWarsCharacterDetailsRepository: StarWarsCharacterDetailsRepository + characterDetailsRepository: CharacterDetailsRepository ): ICharacterDetailsRepository } \ No newline at end of file diff --git a/app/src/main/kotlin/com/k0d4black/theforce/di/modules/details/CharacterDetailsModule.kt b/app/src/main/kotlin/com/k0d4black/theforce/di/modules/details/CharacterDetailsModule.kt index baa22ac1..f9c5fd38 100644 --- a/app/src/main/kotlin/com/k0d4black/theforce/di/modules/details/CharacterDetailsModule.kt +++ b/app/src/main/kotlin/com/k0d4black/theforce/di/modules/details/CharacterDetailsModule.kt @@ -2,11 +2,11 @@ package com.k0d4black.theforce.di.modules.details import com.k0d4black.theforce.data.api.StarWarsApiService -import com.k0d4black.theforce.data.repository.StarWarsCharacterDetailsRepository -import com.k0d4black.theforce.data.source.StarWarsCharacterDetailsDataSource -import com.k0d4black.theforce.domain.usecases.GetStarWarsCharacterFilmsUseCase -import com.k0d4black.theforce.domain.usecases.GetStarWarsCharacterPlanetUseCase -import com.k0d4black.theforce.domain.usecases.GetStarWarsCharacterSpeciesUseCase +import com.k0d4black.theforce.data.repository.CharacterDetailsRepository +import com.k0d4black.theforce.data.source.CharacterDetailsDataSource +import com.k0d4black.theforce.domain.usecases.GetFilmsUseCase +import com.k0d4black.theforce.domain.usecases.GetPlanetUseCase +import com.k0d4black.theforce.domain.usecases.GetSpeciesUseCase import dagger.Module import dagger.Provides @@ -15,21 +15,21 @@ class CharacterDetailsModule { @Provides fun provideCharacterFilmsUseCase( - starWarsCharacterDetailsRepository: StarWarsCharacterDetailsRepository - ): GetStarWarsCharacterFilmsUseCase = GetStarWarsCharacterFilmsUseCase(starWarsCharacterDetailsRepository) + characterDetailsRepository: CharacterDetailsRepository + ): GetFilmsUseCase = GetFilmsUseCase(characterDetailsRepository) @Provides fun provideCharacterPlanetUseCase( - starWarsCharacterDetailsRepository: StarWarsCharacterDetailsRepository - ): GetStarWarsCharacterPlanetUseCase = GetStarWarsCharacterPlanetUseCase(starWarsCharacterDetailsRepository) + characterDetailsRepository: CharacterDetailsRepository + ): GetPlanetUseCase = GetPlanetUseCase(characterDetailsRepository) @Provides fun provideCharacterSpeciesUseCase( - starWarsCharacterDetailsRepository: StarWarsCharacterDetailsRepository - ): GetStarWarsCharacterSpeciesUseCase = GetStarWarsCharacterSpeciesUseCase(starWarsCharacterDetailsRepository) + characterDetailsRepository: CharacterDetailsRepository + ): GetSpeciesUseCase = GetSpeciesUseCase(characterDetailsRepository) @Provides - fun provideCharacterDetailsDataSource(apiService: StarWarsApiService): StarWarsCharacterDetailsDataSource = - StarWarsCharacterDetailsDataSource(apiService) + fun provideCharacterDetailsDataSource(apiService: StarWarsApiService): CharacterDetailsDataSource = + CharacterDetailsDataSource(apiService) } \ No newline at end of file diff --git a/app/src/main/kotlin/com/k0d4black/theforce/di/modules/search/CharacterSearchBindingModule.kt b/app/src/main/kotlin/com/k0d4black/theforce/di/modules/search/CharacterSearchBindingModule.kt index bb73f90f..9b87bd60 100644 --- a/app/src/main/kotlin/com/k0d4black/theforce/di/modules/search/CharacterSearchBindingModule.kt +++ b/app/src/main/kotlin/com/k0d4black/theforce/di/modules/search/CharacterSearchBindingModule.kt @@ -1,6 +1,6 @@ package com.k0d4black.theforce.di.modules.search -import com.k0d4black.theforce.data.repository.StarWarsCharacterSearchRepository +import com.k0d4black.theforce.data.repository.CharacterSearchRepository import com.k0d4black.theforce.domain.repository.ICharacterSearchRepository import dagger.Binds import dagger.Module @@ -12,7 +12,7 @@ abstract class CharacterSearchBindingModule { @Singleton @Binds abstract fun bindCharacterSearchRepository( - starWarsCharacterSearchRepository: StarWarsCharacterSearchRepository + characterSearchRepository: CharacterSearchRepository ): ICharacterSearchRepository } \ No newline at end of file diff --git a/app/src/main/kotlin/com/k0d4black/theforce/di/modules/search/CharacterSearchModule.kt b/app/src/main/kotlin/com/k0d4black/theforce/di/modules/search/CharacterSearchModule.kt index 58750b17..8d8ff6b0 100644 --- a/app/src/main/kotlin/com/k0d4black/theforce/di/modules/search/CharacterSearchModule.kt +++ b/app/src/main/kotlin/com/k0d4black/theforce/di/modules/search/CharacterSearchModule.kt @@ -1,9 +1,9 @@ package com.k0d4black.theforce.di.modules.search import com.k0d4black.theforce.data.api.StarWarsApiService -import com.k0d4black.theforce.data.repository.StarWarsCharacterSearchRepository -import com.k0d4black.theforce.data.source.StarWarsCharacterSearchDataSource -import com.k0d4black.theforce.domain.usecases.SearchStarWarsCharacterUseCase +import com.k0d4black.theforce.data.repository.CharacterSearchRepository +import com.k0d4black.theforce.data.source.CharacterSearchDataSource +import com.k0d4black.theforce.domain.usecases.SearchCharactersUseCase import com.k0d4black.theforce.features.character_search.CharacterSearchViewModel import com.k0d4black.theforce.features.character_search.SearchQueryListener import dagger.Module @@ -19,12 +19,12 @@ class CharacterSearchModule { @Provides fun provideCharacterSearchUseCase( - starWarsCharacterSearchRepository: StarWarsCharacterSearchRepository - ): SearchStarWarsCharacterUseCase = SearchStarWarsCharacterUseCase(starWarsCharacterSearchRepository) + characterSearchRepository: CharacterSearchRepository + ): SearchCharactersUseCase = SearchCharactersUseCase(characterSearchRepository) @Provides - fun provideCharacterSearchDataSource(apiService: StarWarsApiService): StarWarsCharacterSearchDataSource = - StarWarsCharacterSearchDataSource(apiService) + fun provideCharacterSearchDataSource(apiService: StarWarsApiService): CharacterSearchDataSource = + CharacterSearchDataSource(apiService) } diff --git a/app/src/main/kotlin/com/k0d4black/theforce/features/character_details/CharacterDetailActivity.kt b/app/src/main/kotlin/com/k0d4black/theforce/features/character_details/CharacterDetailActivity.kt index 499783f4..92ebbf9b 100644 --- a/app/src/main/kotlin/com/k0d4black/theforce/features/character_details/CharacterDetailActivity.kt +++ b/app/src/main/kotlin/com/k0d4black/theforce/features/character_details/CharacterDetailActivity.kt @@ -12,7 +12,7 @@ import androidx.recyclerview.widget.LinearLayoutManager import com.k0d4black.theforce.R import com.k0d4black.theforce.commons.* import com.k0d4black.theforce.databinding.ActivityCharacterDetailBinding -import com.k0d4black.theforce.models.StarWarsCharacterUiModel +import com.k0d4black.theforce.models.CharacterPresentation import dagger.android.AndroidInjection import kotlinx.android.synthetic.main.activity_character_detail.* import javax.inject.Inject @@ -36,7 +36,7 @@ class CharacterDetailActivity : AppCompatActivity() { binding = DataBindingUtil.setContentView(this, R.layout.activity_character_detail) - val character = intent.getParcelableExtra(CHARACTER_PARCEL_KEY) + val character = intent.getParcelableExtra(CHARACTER_PARCEL_KEY) character?.run { characterDetailViewModel.getCharacterDetails(this.url) @@ -50,19 +50,21 @@ class CharacterDetailActivity : AppCompatActivity() { } private fun observeCharacterSpecies() { - characterDetailViewModel.characterStarWarsCharacterSpecies.observe( + characterDetailViewModel.species.observe( this, Observer { species -> - binding.characterDetailsSpeciesRecyclerView.apply { - adapter = speciesAdapter.apply { submitList(species) } - initRecyclerViewWithLineDecoration(this@CharacterDetailActivity) + if (species.isNotEmpty()) { + binding.characterDetailsSpeciesRecyclerView.apply { + adapter = speciesAdapter.apply { submitList(species) } + initRecyclerViewWithLineDecoration(this@CharacterDetailActivity) + } + enableGroup(R.id.character_species_group) } - enableGroup(R.id.character_species_group) }) } private fun observeCharacterFilms() { - characterDetailViewModel.starWarsCharacterFilms.observe(this, Observer { films -> + characterDetailViewModel.films.observe(this, Observer { films -> binding.characterDetailsFilmsRecyclerView.apply { adapter = filmsAdapter.apply { submitList(films) } layoutManager = @@ -77,13 +79,13 @@ class CharacterDetailActivity : AppCompatActivity() { } private fun observeCharacterPlanet() { - characterDetailViewModel.characterStarWarsCharacterPlanet.observe(this, Observer { planet -> + characterDetailViewModel.planet.observe(this, Observer { planet -> binding.planet = planet enableGroup(R.id.character_planet_group) }) } - private fun displayCharacterDetails(character: StarWarsCharacterUiModel) { + private fun displayCharacterDetails(character: CharacterPresentation) { supportActionBar?.title = character.name binding.character = character enableGroup(R.id.character_details_group) diff --git a/app/src/main/kotlin/com/k0d4black/theforce/features/character_details/CharacterDetailViewModel.kt b/app/src/main/kotlin/com/k0d4black/theforce/features/character_details/CharacterDetailViewModel.kt index b5aa698e..333e15b1 100644 --- a/app/src/main/kotlin/com/k0d4black/theforce/features/character_details/CharacterDetailViewModel.kt +++ b/app/src/main/kotlin/com/k0d4black/theforce/features/character_details/CharacterDetailViewModel.kt @@ -7,57 +7,69 @@ import com.k0d4black.theforce.commons.Error import com.k0d4black.theforce.commons.Loading import com.k0d4black.theforce.commons.Success import com.k0d4black.theforce.commons.UiStateViewModel -import com.k0d4black.theforce.domain.usecases.GetStarWarsCharacterFilmsUseCase -import com.k0d4black.theforce.domain.usecases.GetStarWarsCharacterPlanetUseCase -import com.k0d4black.theforce.domain.usecases.GetStarWarsCharacterSpeciesUseCase +import com.k0d4black.theforce.domain.usecases.GetFilmsUseCase +import com.k0d4black.theforce.domain.usecases.GetPlanetUseCase +import com.k0d4black.theforce.domain.usecases.GetSpeciesUseCase import com.k0d4black.theforce.mappers.toPresentation -import com.k0d4black.theforce.models.StarWarsCharacterFilmsUiModel -import com.k0d4black.theforce.models.StarWarsCharacterPlanetUiModel -import com.k0d4black.theforce.models.StarWarsCharacterSpeciesUiModel +import com.k0d4black.theforce.models.FilmPresentation +import com.k0d4black.theforce.models.PlanetPresentation +import com.k0d4black.theforce.models.SpeciePresentation import kotlinx.coroutines.flow.collect import kotlinx.coroutines.launch import javax.inject.Inject class CharacterDetailViewModel @Inject constructor( - private val getStarWarsCharacterSpeciesUseCase: GetStarWarsCharacterSpeciesUseCase, - private val getStarWarsCharacterPlanetUseCase: GetStarWarsCharacterPlanetUseCase, - private val getStarWarsCharacterFilmsUseCase: GetStarWarsCharacterFilmsUseCase + private val getSpeciesUseCase: GetSpeciesUseCase, + private val getPlanetUseCase: GetPlanetUseCase, + private val getFilmsUseCase: GetFilmsUseCase ) : UiStateViewModel() { - val characterStarWarsCharacterPlanet: LiveData - get() = _characterPlanet + val planet: LiveData + get() = _planet - private var _characterPlanet = - MutableLiveData() + private var _planet = MutableLiveData() - val starWarsCharacterFilms: LiveData> - get() = _characterFilms + val films: LiveData> + get() = _films - private var _characterFilms = - MutableLiveData>() + private var _films = MutableLiveData>() - val characterStarWarsCharacterSpecies: LiveData> - get() = _characterSpecies + val species: LiveData> + get() = _species - private var _characterSpecies = - MutableLiveData>() + private var _species = MutableLiveData>() fun getCharacterDetails(characterUrl: String) { - _uiState.value = Loading viewModelScope.launch(handler) { - getStarWarsCharacterPlanetUseCase(characterUrl).collect { - _characterPlanet.value = it.toPresentation() - } - getStarWarsCharacterFilmsUseCase(characterUrl).collect { - _characterFilms.value = it.map { film -> film.toPresentation() } - } - getStarWarsCharacterSpeciesUseCase(characterUrl).collect { - _characterSpecies.value = it.map { species -> species.toPresentation() } - } + _uiState.value = Loading + loadPlanet(characterUrl) + loadFilms(characterUrl) + loadSpecies(characterUrl) _uiState.value = Success(Unit) } } + private suspend fun loadPlanet(characterUrl: String) { + getPlanetUseCase(characterUrl).collect { planet -> + val planetPresentation = planet.toPresentation() + _planet.value = planetPresentation + } + } + + private suspend fun loadFilms(characterUrl: String) { + getFilmsUseCase(characterUrl).collect { films -> + val filmsPresentation = films.map { eachFilm -> eachFilm.toPresentation() } + _films.value = filmsPresentation + } + } + + private suspend fun loadSpecies(characterUrl: String) { + getSpeciesUseCase(characterUrl).collect { species -> + val speciesPresentation = species.map { eachSpecie -> eachSpecie.toPresentation() } + _species.value = speciesPresentation + } + } + fun displayCharacterError() { _uiState.value = Error(Exception("Error Loading Character")) } diff --git a/app/src/main/kotlin/com/k0d4black/theforce/features/character_details/FilmsAdapter.kt b/app/src/main/kotlin/com/k0d4black/theforce/features/character_details/FilmsAdapter.kt index 6dfe485f..6f5582f7 100644 --- a/app/src/main/kotlin/com/k0d4black/theforce/features/character_details/FilmsAdapter.kt +++ b/app/src/main/kotlin/com/k0d4black/theforce/features/character_details/FilmsAdapter.kt @@ -5,26 +5,26 @@ import android.view.ViewGroup import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView -import com.k0d4black.theforce.databinding.FilmItemLayoutBinding -import com.k0d4black.theforce.models.StarWarsCharacterFilmsUiModel +import com.k0d4black.theforce.databinding.ItemFilmBinding +import com.k0d4black.theforce.models.FilmPresentation -class FilmsAdapter : ListAdapter( +class FilmsAdapter : ListAdapter( SearchedCharacterDiffUtil ) { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FilmViewHolder { val context = parent.context val inflater = LayoutInflater.from(context) - return FilmViewHolder(FilmItemLayoutBinding.inflate(inflater)) + return FilmViewHolder(ItemFilmBinding.inflate(inflater)) } override fun onBindViewHolder(holder: FilmViewHolder, position: Int): Unit = getItem(position).let { holder.bind(it) } - inner class FilmViewHolder(private val binding: FilmItemLayoutBinding) : + inner class FilmViewHolder(private val binding: ItemFilmBinding) : RecyclerView.ViewHolder(binding.root) { - fun bind(modelStarWarsCharacter: StarWarsCharacterFilmsUiModel) { + fun bind(modelStarWarsCharacter: FilmPresentation) { binding.film = modelStarWarsCharacter binding.executePendingBindings() } @@ -32,17 +32,17 @@ class FilmsAdapter : ListAdapter() { + object : DiffUtil.ItemCallback() { override fun areItemsTheSame( - oldItem: StarWarsCharacterFilmsUiModel, - newItem: StarWarsCharacterFilmsUiModel - ): Boolean = oldItem.title == newItem.title + oldItem: FilmPresentation, + newItem: FilmPresentation + ): Boolean = oldItem == newItem override fun areContentsTheSame( - oldItem: StarWarsCharacterFilmsUiModel, - newItem: StarWarsCharacterFilmsUiModel - ): Boolean = oldItem == newItem + oldItem: FilmPresentation, + newItem: FilmPresentation + ): Boolean = oldItem.title == newItem.title } } } \ No newline at end of file diff --git a/app/src/main/kotlin/com/k0d4black/theforce/features/character_details/SpeciesAdapter.kt b/app/src/main/kotlin/com/k0d4black/theforce/features/character_details/SpeciesAdapter.kt index 1b450437..e68a3bc8 100644 --- a/app/src/main/kotlin/com/k0d4black/theforce/features/character_details/SpeciesAdapter.kt +++ b/app/src/main/kotlin/com/k0d4black/theforce/features/character_details/SpeciesAdapter.kt @@ -5,26 +5,26 @@ import android.view.ViewGroup import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView -import com.k0d4black.theforce.databinding.SpecieItemLayoutBinding -import com.k0d4black.theforce.models.StarWarsCharacterSpeciesUiModel +import com.k0d4black.theforce.databinding.ItemSpecieBinding +import com.k0d4black.theforce.models.SpeciePresentation -class SpeciesAdapter : ListAdapter( +class SpeciesAdapter : ListAdapter( SearchedCharacterDiffUtil ) { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SpecieViewHolder { val context = parent.context val inflater = LayoutInflater.from(context) - return SpecieViewHolder(SpecieItemLayoutBinding.inflate(inflater)) + return SpecieViewHolder(ItemSpecieBinding.inflate(inflater)) } override fun onBindViewHolder(holder: SpecieViewHolder, position: Int): Unit = getItem(position).let { holder.bind(it) } - inner class SpecieViewHolder(private val binding: SpecieItemLayoutBinding) : + inner class SpecieViewHolder(private val binding: ItemSpecieBinding) : RecyclerView.ViewHolder(binding.root) { - fun bind(modelStarWarsCharacter: StarWarsCharacterSpeciesUiModel) { + fun bind(modelStarWarsCharacter: SpeciePresentation) { binding.species = modelStarWarsCharacter binding.executePendingBindings() } @@ -32,17 +32,17 @@ class SpeciesAdapter : ListAdapter() { + object : DiffUtil.ItemCallback() { override fun areItemsTheSame( - oldItem: StarWarsCharacterSpeciesUiModel, - newItem: StarWarsCharacterSpeciesUiModel - ): Boolean = oldItem.name == newItem.name + oldItem: SpeciePresentation, + newItem: SpeciePresentation + ): Boolean = oldItem == newItem override fun areContentsTheSame( - oldItem: StarWarsCharacterSpeciesUiModel, - newItem: StarWarsCharacterSpeciesUiModel - ): Boolean = oldItem == newItem + oldItem: SpeciePresentation, + newItem: SpeciePresentation + ): Boolean = oldItem.name == newItem.name } } } \ No newline at end of file diff --git a/app/src/main/kotlin/com/k0d4black/theforce/features/character_search/CharacterSearchViewModel.kt b/app/src/main/kotlin/com/k0d4black/theforce/features/character_search/CharacterSearchViewModel.kt index 33936711..2826543a 100644 --- a/app/src/main/kotlin/com/k0d4black/theforce/features/character_search/CharacterSearchViewModel.kt +++ b/app/src/main/kotlin/com/k0d4black/theforce/features/character_search/CharacterSearchViewModel.kt @@ -4,30 +4,25 @@ import androidx.lifecycle.viewModelScope import com.k0d4black.theforce.commons.Loading import com.k0d4black.theforce.commons.Success import com.k0d4black.theforce.commons.UiStateViewModel -import com.k0d4black.theforce.domain.usecases.SearchStarWarsCharacterUseCase +import com.k0d4black.theforce.domain.usecases.SearchCharactersUseCase import com.k0d4black.theforce.mappers.toPresentation +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.collect import kotlinx.coroutines.launch import javax.inject.Inject class CharacterSearchViewModel @Inject constructor( - private val searchStarWarsCharacterUseCase: SearchStarWarsCharacterUseCase + private val searchCharactersUseCase: SearchCharactersUseCase ) : UiStateViewModel() { -// val searchResultsStarWars: LiveData> -// get() = _searchResultsStarWars -// -// private var _searchResultsStarWars: MutableLiveData> = -// MutableLiveData() - - fun executeCharacterSearch(params: String) { - _uiState.value = Loading + fun executeCharacterSearch(characterName: String) { viewModelScope.launch(handler) { - searchStarWarsCharacterUseCase(params).collect { results -> - _uiState.value = Success(results.map { it.toPresentation() }) + _uiState.value = Loading + searchCharactersUseCase(characterName).collect { results -> + val characters = results.map { character -> character.toPresentation() } + _uiState.value = Success(characters) } } - } } diff --git a/app/src/main/kotlin/com/k0d4black/theforce/features/character_search/SearchActivity.kt b/app/src/main/kotlin/com/k0d4black/theforce/features/character_search/SearchActivity.kt index 24e1fedd..287a0fb9 100644 --- a/app/src/main/kotlin/com/k0d4black/theforce/features/character_search/SearchActivity.kt +++ b/app/src/main/kotlin/com/k0d4black/theforce/features/character_search/SearchActivity.kt @@ -14,7 +14,7 @@ import com.k0d4black.theforce.R import com.k0d4black.theforce.commons.* import com.k0d4black.theforce.features.character_details.CharacterDetailActivity import com.k0d4black.theforce.features.settings.SettingsActivity -import com.k0d4black.theforce.models.StarWarsCharacterUiModel +import com.k0d4black.theforce.models.CharacterPresentation import dagger.android.AndroidInjection import jp.wasabeef.recyclerview.adapters.ScaleInAnimationAdapter import kotlinx.android.synthetic.main.activity_search.* @@ -49,7 +49,7 @@ class SearchActivity : AppCompatActivity() { characterSearchViewModel.uiState.observe(this, Observer { when (it) { is Success<*> -> { - val data = it.data as List + val data = it.data as List showSnackbar(search_results_recycler_view, getString(R.string.info_search_done)) displaySearchResults(data) } @@ -68,7 +68,7 @@ class SearchActivity : AppCompatActivity() { })) } - private fun displaySearchResults(searchResultStarWars: List) { + private fun displaySearchResults(searchResultStarWars: List) { loading_search_results_progress_bar.animate() .alpha(0f) .setListener(AnimatorListener(onEnd = { loading_search_results_progress_bar.hide() })) diff --git a/app/src/main/kotlin/com/k0d4black/theforce/features/character_search/SearchResultAdapter.kt b/app/src/main/kotlin/com/k0d4black/theforce/features/character_search/SearchResultAdapter.kt index 9ed7955a..e6a1bd2f 100644 --- a/app/src/main/kotlin/com/k0d4black/theforce/features/character_search/SearchResultAdapter.kt +++ b/app/src/main/kotlin/com/k0d4black/theforce/features/character_search/SearchResultAdapter.kt @@ -5,51 +5,51 @@ import android.view.ViewGroup import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView -import com.k0d4black.theforce.databinding.SearchResultLayoutItemBinding -import com.k0d4black.theforce.models.StarWarsCharacterUiModel -import kotlinx.android.synthetic.main.search_result_layout_item.view.* +import com.k0d4black.theforce.databinding.ItemSearchBinding +import com.k0d4black.theforce.models.CharacterPresentation +import kotlinx.android.synthetic.main.item_search.view.* -class SearchResultAdapter(val onClick: (StarWarsCharacterUiModel) -> Unit) : - ListAdapter( +class SearchResultAdapter(val onClick: (CharacterPresentation) -> Unit) : + ListAdapter( SearchedCharacterDiffUtil ) { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SearchedCharacterViewHolder { val context = parent.context val inflater = LayoutInflater.from(context) - return SearchedCharacterViewHolder(SearchResultLayoutItemBinding.inflate(inflater,parent,false)) + return SearchedCharacterViewHolder(ItemSearchBinding.inflate(inflater,parent,false)) } override fun onBindViewHolder(holder: SearchedCharacterViewHolder, position: Int): Unit = getItem(position).let { holder.bind(it) } - inner class SearchedCharacterViewHolder(private val binding: SearchResultLayoutItemBinding) : + inner class SearchedCharacterViewHolder(private val binding: ItemSearchBinding) : RecyclerView.ViewHolder(binding.root) { - fun bind(modelSearchStarWars: StarWarsCharacterUiModel) { - binding.searchedCharacter = modelSearchStarWars + fun bind(modelSearch: CharacterPresentation) { + binding.searchedCharacter = modelSearch binding.executePendingBindings() binding.root.more_info_arrow_image_button.setOnClickListener { - onClick(modelSearchStarWars) + onClick(modelSearch) } } } companion object { val SearchedCharacterDiffUtil = - object : DiffUtil.ItemCallback() { + object : DiffUtil.ItemCallback() { override fun areItemsTheSame( - oldItem: StarWarsCharacterUiModel, - newItem: StarWarsCharacterUiModel - ): Boolean = oldItem.url == newItem.url + oldItem: CharacterPresentation, + newItem: CharacterPresentation + ): Boolean = oldItem == newItem override fun areContentsTheSame( - oldItem: StarWarsCharacterUiModel, - newItem: StarWarsCharacterUiModel - ): Boolean = oldItem == newItem + oldItem: CharacterPresentation, + newItem: CharacterPresentation + ): Boolean = oldItem.url == newItem.url } } diff --git a/app/src/main/kotlin/com/k0d4black/theforce/mappers/DomainToPresentation.kt b/app/src/main/kotlin/com/k0d4black/theforce/mappers/DomainToPresentation.kt new file mode 100644 index 00000000..b75bd45e --- /dev/null +++ b/app/src/main/kotlin/com/k0d4black/theforce/mappers/DomainToPresentation.kt @@ -0,0 +1,34 @@ +package com.k0d4black.theforce.mappers + +import com.k0d4black.theforce.domain.models.Character +import com.k0d4black.theforce.domain.models.Film +import com.k0d4black.theforce.domain.models.Planet +import com.k0d4black.theforce.domain.models.Specie +import com.k0d4black.theforce.models.FilmPresentation +import com.k0d4black.theforce.models.PlanetPresentation +import com.k0d4black.theforce.models.SpeciePresentation +import com.k0d4black.theforce.models.CharacterPresentation +import com.k0d4black.theforce.commons.convertToInches + + +fun Character.toPresentation(): CharacterPresentation { + return CharacterPresentation( + this.name, + this.birthYear, + this.height, + convertToInches(this.height), + this.url + ) +} + +fun Planet.toPresentation(): PlanetPresentation { + return PlanetPresentation(this.name, this.population) +} + +fun Film.toPresentation(): FilmPresentation { + return FilmPresentation(this.title, this.openingCrawl) +} + +fun Specie.toPresentation(): SpeciePresentation { + return SpeciePresentation(this.name, this.language) +} \ No newline at end of file diff --git a/app/src/main/kotlin/com/k0d4black/theforce/mappers/DomainToPresentationMapper.kt b/app/src/main/kotlin/com/k0d4black/theforce/mappers/DomainToPresentationMapper.kt deleted file mode 100644 index f0f11793..00000000 --- a/app/src/main/kotlin/com/k0d4black/theforce/mappers/DomainToPresentationMapper.kt +++ /dev/null @@ -1,34 +0,0 @@ -package com.k0d4black.theforce.mappers - -import com.k0d4black.theforce.domain.models.StarWarsCharacter -import com.k0d4black.theforce.domain.models.StarWarsCharacterFilm -import com.k0d4black.theforce.domain.models.StarWarsCharacterPlanet -import com.k0d4black.theforce.domain.models.StarWarsCharacterSpecies -import com.k0d4black.theforce.models.StarWarsCharacterFilmsUiModel -import com.k0d4black.theforce.models.StarWarsCharacterPlanetUiModel -import com.k0d4black.theforce.models.StarWarsCharacterSpeciesUiModel -import com.k0d4black.theforce.models.StarWarsCharacterUiModel -import com.k0d4black.theforce.commons.convertToInches - - -fun StarWarsCharacter.toPresentation(): StarWarsCharacterUiModel { - return StarWarsCharacterUiModel( - this.name, - this.birthYear, - this.height, - convertToInches(this.height), - this.url - ) -} - -fun StarWarsCharacterPlanet.toPresentation(): StarWarsCharacterPlanetUiModel { - return StarWarsCharacterPlanetUiModel(this.name, this.population) -} - -fun StarWarsCharacterFilm.toPresentation(): StarWarsCharacterFilmsUiModel { - return StarWarsCharacterFilmsUiModel(this.title, this.openingCrawl) -} - -fun StarWarsCharacterSpecies.toPresentation(): StarWarsCharacterSpeciesUiModel { - return StarWarsCharacterSpeciesUiModel(this.name, this.language) -} \ No newline at end of file diff --git a/app/src/main/kotlin/com/k0d4black/theforce/models/StarWarsCharacterUiModel.kt b/app/src/main/kotlin/com/k0d4black/theforce/models/CharacterPresentation.kt similarity index 87% rename from app/src/main/kotlin/com/k0d4black/theforce/models/StarWarsCharacterUiModel.kt rename to app/src/main/kotlin/com/k0d4black/theforce/models/CharacterPresentation.kt index 4ea2cd3a..fecb5048 100644 --- a/app/src/main/kotlin/com/k0d4black/theforce/models/StarWarsCharacterUiModel.kt +++ b/app/src/main/kotlin/com/k0d4black/theforce/models/CharacterPresentation.kt @@ -4,7 +4,7 @@ import android.os.Parcelable import kotlinx.android.parcel.Parcelize @Parcelize -data class StarWarsCharacterUiModel( +data class CharacterPresentation( val name: String, val birthYear: String, val heightInCm: String, diff --git a/app/src/main/kotlin/com/k0d4black/theforce/models/FilmPresentation.kt b/app/src/main/kotlin/com/k0d4black/theforce/models/FilmPresentation.kt new file mode 100644 index 00000000..913052d2 --- /dev/null +++ b/app/src/main/kotlin/com/k0d4black/theforce/models/FilmPresentation.kt @@ -0,0 +1,3 @@ +package com.k0d4black.theforce.models + +data class FilmPresentation(val title: String, val openingCrawl: String) diff --git a/app/src/main/kotlin/com/k0d4black/theforce/models/PlanetPresentation.kt b/app/src/main/kotlin/com/k0d4black/theforce/models/PlanetPresentation.kt new file mode 100644 index 00000000..e0887ef0 --- /dev/null +++ b/app/src/main/kotlin/com/k0d4black/theforce/models/PlanetPresentation.kt @@ -0,0 +1,3 @@ +package com.k0d4black.theforce.models + +data class PlanetPresentation(val name: String, val population: String) \ No newline at end of file diff --git a/app/src/main/kotlin/com/k0d4black/theforce/models/SpeciePresentation.kt b/app/src/main/kotlin/com/k0d4black/theforce/models/SpeciePresentation.kt new file mode 100644 index 00000000..453bcc9c --- /dev/null +++ b/app/src/main/kotlin/com/k0d4black/theforce/models/SpeciePresentation.kt @@ -0,0 +1,3 @@ +package com.k0d4black.theforce.models + +data class SpeciePresentation(val name: String, val language: String) diff --git a/app/src/main/kotlin/com/k0d4black/theforce/models/StarWarsCharacterFilmsUiModel.kt b/app/src/main/kotlin/com/k0d4black/theforce/models/StarWarsCharacterFilmsUiModel.kt deleted file mode 100644 index c241fd8b..00000000 --- a/app/src/main/kotlin/com/k0d4black/theforce/models/StarWarsCharacterFilmsUiModel.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.k0d4black.theforce.models - -data class StarWarsCharacterFilmsUiModel(val title: String, val openingCrawl: String) diff --git a/app/src/main/kotlin/com/k0d4black/theforce/models/StarWarsCharacterPlanetUiModel.kt b/app/src/main/kotlin/com/k0d4black/theforce/models/StarWarsCharacterPlanetUiModel.kt deleted file mode 100644 index 23faad5f..00000000 --- a/app/src/main/kotlin/com/k0d4black/theforce/models/StarWarsCharacterPlanetUiModel.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.k0d4black.theforce.models - -data class StarWarsCharacterPlanetUiModel(val name: String, val population: String) \ No newline at end of file diff --git a/app/src/main/kotlin/com/k0d4black/theforce/models/StarWarsCharacterSpeciesUiModel.kt b/app/src/main/kotlin/com/k0d4black/theforce/models/StarWarsCharacterSpeciesUiModel.kt deleted file mode 100644 index ff3caea7..00000000 --- a/app/src/main/kotlin/com/k0d4black/theforce/models/StarWarsCharacterSpeciesUiModel.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.k0d4black.theforce.models - -data class StarWarsCharacterSpeciesUiModel(val name: String, val language: String) diff --git a/app/src/main/res/layout/activity_character_detail.xml b/app/src/main/res/layout/activity_character_detail.xml index 4570ade6..c01b1dd1 100644 --- a/app/src/main/res/layout/activity_character_detail.xml +++ b/app/src/main/res/layout/activity_character_detail.xml @@ -7,11 +7,11 @@ + type="com.k0d4black.theforce.models.CharacterPresentation" /> + type="com.k0d4black.theforce.models.PlanetPresentation" /> - + android:elevation="@dimen/cardview_elevation" + app:cardCornerRadius="@dimen/cardview_radius" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintBottom_toTopOf="@id/character_details_species_title_text_view" + app:layout_constraintTop_toBottomOf="@id/character_details_films_title_text_view"> + + + + + + app:layout_constraintTop_toBottomOf="@id/films_card_container" /> + tools:listitem="@layout/item_specie" /> + app:constraint_referenced_ids="character_details_films_title_text_view,films_card_container" /> + tools:listitem="@layout/item_search" /> - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/item_film.xml b/app/src/main/res/layout/item_film.xml new file mode 100644 index 00000000..fbc2c59f --- /dev/null +++ b/app/src/main/res/layout/item_film.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/search_result_layout_item.xml b/app/src/main/res/layout/item_search.xml similarity index 96% rename from app/src/main/res/layout/search_result_layout_item.xml rename to app/src/main/res/layout/item_search.xml index 94bb1357..03f6baca 100644 --- a/app/src/main/res/layout/search_result_layout_item.xml +++ b/app/src/main/res/layout/item_search.xml @@ -6,7 +6,7 @@ + type="com.k0d4black.theforce.models.CharacterPresentation" /> diff --git a/app/src/main/res/layout/specie_item_layout.xml b/app/src/main/res/layout/item_specie.xml similarity index 92% rename from app/src/main/res/layout/specie_item_layout.xml rename to app/src/main/res/layout/item_specie.xml index 54acd332..f78f3f8d 100644 --- a/app/src/main/res/layout/specie_item_layout.xml +++ b/app/src/main/res/layout/item_specie.xml @@ -5,7 +5,7 @@ + type="com.k0d4black.theforce.models.SpeciePresentation" /> 16dp 16dp + 8dp + 4dp \ No newline at end of file diff --git a/app/src/test/kotlin/com/k0d4black/theforce/utils/SampleData.kt b/app/src/test/kotlin/com/k0d4black/theforce/utils/SampleData.kt index 89424d8d..f9cd5248 100644 --- a/app/src/test/kotlin/com/k0d4black/theforce/utils/SampleData.kt +++ b/app/src/test/kotlin/com/k0d4black/theforce/utils/SampleData.kt @@ -1,30 +1,30 @@ package com.k0d4black.theforce.utils -import com.k0d4black.theforce.domain.models.StarWarsCharacter -import com.k0d4black.theforce.domain.models.StarWarsCharacterFilm -import com.k0d4black.theforce.domain.models.StarWarsCharacterPlanet -import com.k0d4black.theforce.domain.models.StarWarsCharacterSpecies +import com.k0d4black.theforce.domain.models.Character +import com.k0d4black.theforce.domain.models.Film +import com.k0d4black.theforce.domain.models.Planet +import com.k0d4black.theforce.domain.models.Specie object SampleData { - val speciesDomainModel = listOf( - StarWarsCharacterSpecies( + val species = listOf( + Specie( name = "name", language = "language" ) ) - val characterFilms = listOf( - StarWarsCharacterFilm( + val films = listOf( + Film( title = "title", openingCrawl = "opening crawl" ) ) - val planetDomainModel = - StarWarsCharacterPlanet( + val planet = + Planet( name = "name", population = "100000" ) val searchResults = listOf( - StarWarsCharacter( + Character( "Darth Vader", "12BBY", "123", diff --git a/app/src/test/kotlin/com/k0d4black/theforce/viewmodels/CharacterDetailViewModelTest.kt b/app/src/test/kotlin/com/k0d4black/theforce/viewmodels/CharacterDetailViewModelTest.kt new file mode 100644 index 00000000..81bd7500 --- /dev/null +++ b/app/src/test/kotlin/com/k0d4black/theforce/viewmodels/CharacterDetailViewModelTest.kt @@ -0,0 +1,65 @@ +package com.k0d4black.theforce.viewmodels + +import com.google.common.truth.Truth +import com.k0d4black.theforce.BaseViewModelTest +import com.k0d4black.theforce.domain.usecases.GetFilmsUseCase +import com.k0d4black.theforce.domain.usecases.GetPlanetUseCase +import com.k0d4black.theforce.domain.usecases.GetSpeciesUseCase +import com.k0d4black.theforce.features.character_details.CharacterDetailViewModel +import com.k0d4black.theforce.mappers.toPresentation +import com.k0d4black.theforce.utils.SampleData +import com.k0d4black.theforce.utils.observeOnce +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runBlockingTest +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.junit.MockitoJUnitRunner + +@RunWith(MockitoJUnitRunner::class) +internal class CharacterDetailViewModelTest : BaseViewModelTest() { + + @Mock + lateinit var getFilmsUseCase: GetFilmsUseCase + + @Mock + lateinit var getPlanetUseCase: GetPlanetUseCase + + @Mock + lateinit var getSpeciesUseCase: GetSpeciesUseCase + + private lateinit var characterDetailViewModel: CharacterDetailViewModel + + private val characterUrl = "https://swapi.py4e.com/api/people/1/" + + @Before + fun setup() { + characterDetailViewModel = CharacterDetailViewModel( + getSpeciesUseCase, + getPlanetUseCase, + getFilmsUseCase + ) + } + + @ExperimentalCoroutinesApi + @Test + fun shouldGetCharacterDetails() { + runBlockingTest { + characterDetailViewModel.getCharacterDetails(characterUrl) + + characterDetailViewModel.species.observeOnce { speciesPresentation-> + Truth.assertThat(speciesPresentation) + .isEqualTo(SampleData.species.map { it.toPresentation() }) + } + characterDetailViewModel.films.observeOnce { filmPresentation-> + Truth.assertThat(filmPresentation) + .isEqualTo(SampleData.films.map { it.toPresentation() }) + } + characterDetailViewModel.planet.observeOnce { planetPresentation-> + Truth.assertThat(planetPresentation).isEqualTo(SampleData.planet.toPresentation()) + } + } + } + +} \ No newline at end of file diff --git a/app/src/test/kotlin/com/k0d4black/theforce/viewmodels/StarWarsCharacterSearchViewModelTest.kt b/app/src/test/kotlin/com/k0d4black/theforce/viewmodels/CharacterSearchViewModelTest.kt similarity index 80% rename from app/src/test/kotlin/com/k0d4black/theforce/viewmodels/StarWarsCharacterSearchViewModelTest.kt rename to app/src/test/kotlin/com/k0d4black/theforce/viewmodels/CharacterSearchViewModelTest.kt index 84992734..75195ff8 100644 --- a/app/src/test/kotlin/com/k0d4black/theforce/viewmodels/StarWarsCharacterSearchViewModelTest.kt +++ b/app/src/test/kotlin/com/k0d4black/theforce/viewmodels/CharacterSearchViewModelTest.kt @@ -3,7 +3,7 @@ package com.k0d4black.theforce.viewmodels import com.google.common.truth.Truth import com.k0d4black.theforce.BaseViewModelTest import com.k0d4black.theforce.commons.Success -import com.k0d4black.theforce.domain.usecases.SearchStarWarsCharacterUseCase +import com.k0d4black.theforce.domain.usecases.SearchCharactersUseCase import com.k0d4black.theforce.features.character_search.CharacterSearchViewModel import com.k0d4black.theforce.utils.SampleData import com.k0d4black.theforce.utils.observeOnce @@ -18,10 +18,10 @@ import org.mockito.Mock import org.mockito.junit.MockitoJUnitRunner @RunWith(MockitoJUnitRunner::class) -internal class StarWarsCharacterSearchViewModelTest : BaseViewModelTest() { +internal class CharacterSearchViewModelTest : BaseViewModelTest() { @Mock - lateinit var searchStarWarsCharacterUseCase: SearchStarWarsCharacterUseCase + lateinit var searchCharactersUseCase: SearchCharactersUseCase private lateinit var characterSearchViewModel: CharacterSearchViewModel @@ -29,7 +29,7 @@ internal class StarWarsCharacterSearchViewModelTest : BaseViewModelTest() { @Before fun setup() { - characterSearchViewModel = CharacterSearchViewModel(searchStarWarsCharacterUseCase) + characterSearchViewModel = CharacterSearchViewModel(searchCharactersUseCase) } @ExperimentalCoroutinesApi @@ -45,7 +45,7 @@ internal class StarWarsCharacterSearchViewModelTest : BaseViewModelTest() { } private suspend fun setMockAnswer() { - given(searchStarWarsCharacterUseCase(searchParams)).willReturn(flow { + given(searchCharactersUseCase(searchParams)).willReturn(flow { emit(SampleData.searchResults) }) } diff --git a/app/src/test/kotlin/com/k0d4black/theforce/viewmodels/StarWarsCharacterDetailViewModelTest.kt b/app/src/test/kotlin/com/k0d4black/theforce/viewmodels/StarWarsCharacterDetailViewModelTest.kt deleted file mode 100644 index a1f12cfd..00000000 --- a/app/src/test/kotlin/com/k0d4black/theforce/viewmodels/StarWarsCharacterDetailViewModelTest.kt +++ /dev/null @@ -1,79 +0,0 @@ -package com.k0d4black.theforce.viewmodels - -import com.google.common.truth.Truth -import com.k0d4black.theforce.BaseViewModelTest -import com.k0d4black.theforce.domain.usecases.GetStarWarsCharacterFilmsUseCase -import com.k0d4black.theforce.domain.usecases.GetStarWarsCharacterPlanetUseCase -import com.k0d4black.theforce.domain.usecases.GetStarWarsCharacterSpeciesUseCase -import com.k0d4black.theforce.features.character_details.CharacterDetailViewModel -import com.k0d4black.theforce.mappers.toPresentation -import com.k0d4black.theforce.utils.SampleData -import com.k0d4black.theforce.utils.observeOnce -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.flow.flow -import kotlinx.coroutines.test.runBlockingTest -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.BDDMockito.given -import org.mockito.Mock -import org.mockito.junit.MockitoJUnitRunner - -@RunWith(MockitoJUnitRunner::class) -internal class StarWarsCharacterDetailViewModelTest : BaseViewModelTest() { - - @Mock - lateinit var getStarWarsCharacterFilmsUseCase: GetStarWarsCharacterFilmsUseCase - @Mock - lateinit var getStarWarsCharacterPlanetUseCase: GetStarWarsCharacterPlanetUseCase - @Mock - lateinit var getStarWarsCharacterSpeciesUseCase: GetStarWarsCharacterSpeciesUseCase - - private lateinit var characterDetailViewModel: CharacterDetailViewModel - - private val characterUrl = "https://swapi.py4e.com/api/people/1/" - - @Before - fun setup() { - characterDetailViewModel = CharacterDetailViewModel( - getStarWarsCharacterSpeciesUseCase, - getStarWarsCharacterPlanetUseCase, - getStarWarsCharacterFilmsUseCase - ) - } - - @ExperimentalCoroutinesApi - @Test - fun shouldGetCharacterDetails() { - runBlockingTest { - setMockAnswers() - - characterDetailViewModel.getCharacterDetails(characterUrl) - - characterDetailViewModel.characterStarWarsCharacterSpecies.observeOnce { - Truth.assertThat(it) - .isEqualTo(SampleData.speciesDomainModel.map { it.toPresentation() }) - } - characterDetailViewModel.starWarsCharacterFilms.observeOnce { - Truth.assertThat(it) - .isEqualTo(SampleData.characterFilms.map { it.toPresentation() }) - } - characterDetailViewModel.characterStarWarsCharacterPlanet.observeOnce { - Truth.assertThat(it).isEqualTo(SampleData.planetDomainModel.toPresentation()) - } - } - } - - private suspend fun setMockAnswers() { - given(getStarWarsCharacterSpeciesUseCase(characterUrl)).willReturn(flow { - emit(SampleData.speciesDomainModel) - }) - given(getStarWarsCharacterFilmsUseCase(characterUrl)).willReturn(flow { - emit(SampleData.characterFilms) - }) - given(getStarWarsCharacterPlanetUseCase(characterUrl)).willReturn(flow { - emit(SampleData.planetDomainModel) - }) - } - -} \ No newline at end of file diff --git a/data/src/main/kotlin/com/k0d4black/theforce/data/api/StarWarsApiService.kt b/data/src/main/kotlin/com/k0d4black/theforce/data/api/StarWarsApiService.kt index 906472a5..f129ec72 100644 --- a/data/src/main/kotlin/com/k0d4black/theforce/data/api/StarWarsApiService.kt +++ b/data/src/main/kotlin/com/k0d4black/theforce/data/api/StarWarsApiService.kt @@ -1,7 +1,7 @@ package com.k0d4black.theforce.data.api -import com.k0d4black.theforce.data.models.response.details.* -import com.k0d4black.theforce.data.models.response.search.CharacterSearchResponse +import com.k0d4black.theforce.data.models.response.* +import com.k0d4black.theforce.data.models.response.SearchResponse import retrofit2.http.GET import retrofit2.http.Query import retrofit2.http.Url @@ -9,23 +9,23 @@ import retrofit2.http.Url interface StarWarsApiService { @GET("people") - suspend fun searchCharacters(@Query("search") params: String): CharacterSearchResponse + suspend fun searchCharacters(@Query("search") params: String): SearchResponse @GET - suspend fun getSpeciesDetails(@Url speciesUrl: String): SpeciesResponse + suspend fun getSpecieDetails(@Url speciesUrl: String): SpecieDetailResponse @GET - suspend fun getFilmDetails(@Url filmsUrl: String): FilmResponse + suspend fun getFilmDetails(@Url filmsUrl: String): FilmDetailResponse @GET - suspend fun getPlanetDetails(@Url planetUrl: String): PlanetResponse + suspend fun getPlanetDetails(@Url planetUrl: String): PlanetDetailsResponse @GET - suspend fun getCharacterFilms(@Url characterUrl: String): CharacterDetailsFilmsResponse + suspend fun getFilms(@Url characterUrl: String): FilmsResponse @GET - suspend fun getCharacterSpecies(@Url characterUrl: String): CharacterDetailsSpeciesResponse + suspend fun getSpecies(@Url characterUrl: String): SpeciesResponse @GET - suspend fun getCharacterHomeworld(@Url characterUrl: String): CharacterDetailsHomeWorldResponse + suspend fun getPlanet(@Url characterUrl: String): PlanetResponse } \ No newline at end of file diff --git a/data/src/main/kotlin/com/k0d4black/theforce/data/mappers/EntityToDomain.kt b/data/src/main/kotlin/com/k0d4black/theforce/data/mappers/EntityToDomain.kt index 7a46a3d2..bc041b18 100644 --- a/data/src/main/kotlin/com/k0d4black/theforce/data/mappers/EntityToDomain.kt +++ b/data/src/main/kotlin/com/k0d4black/theforce/data/mappers/EntityToDomain.kt @@ -1,40 +1,40 @@ package com.k0d4black.theforce.data.mappers -import com.k0d4black.theforce.data.models.entity.StarWarsCharacterFilmEntity -import com.k0d4black.theforce.data.models.entity.StarWarsCharacterPlanetEntity -import com.k0d4black.theforce.data.models.entity.StarWarsCharacterSpeciesEntity -import com.k0d4black.theforce.data.models.entity.StarWarsCharacterEntity -import com.k0d4black.theforce.domain.models.StarWarsCharacter -import com.k0d4black.theforce.domain.models.StarWarsCharacterFilm -import com.k0d4black.theforce.domain.models.StarWarsCharacterPlanet -import com.k0d4black.theforce.domain.models.StarWarsCharacterSpecies - - -internal fun StarWarsCharacterEntity.toDomain(): StarWarsCharacter { - return StarWarsCharacter( - this.name, - this.birthYear, - this.height, - this.url +import com.k0d4black.theforce.data.models.entity.FilmEntity +import com.k0d4black.theforce.data.models.entity.PlanetEntity +import com.k0d4black.theforce.data.models.entity.SpecieEntity +import com.k0d4black.theforce.data.models.entity.CharacterEntity +import com.k0d4black.theforce.domain.models.Character +import com.k0d4black.theforce.domain.models.Film +import com.k0d4black.theforce.domain.models.Planet +import com.k0d4black.theforce.domain.models.Specie + + +internal fun CharacterEntity.toDomain(): Character { + return Character( + name, + birthYear, + height, + url ) } -internal fun StarWarsCharacterFilmEntity.toDomain(): StarWarsCharacterFilm = - StarWarsCharacterFilm( +internal fun FilmEntity.toDomain(): Film = + Film( this.title, this.openingCrawl ) -internal fun StarWarsCharacterPlanetEntity.toDomain(): StarWarsCharacterPlanet = - StarWarsCharacterPlanet( +internal fun PlanetEntity.toDomain(): Planet = + Planet( this.name, this.population ) -internal fun StarWarsCharacterSpeciesEntity.toDomain(): StarWarsCharacterSpecies = - StarWarsCharacterSpecies( +internal fun SpecieEntity.toDomain(): Specie = + Specie( this.name, this.language ) diff --git a/data/src/main/kotlin/com/k0d4black/theforce/data/mappers/JsonResponseToEntity.kt b/data/src/main/kotlin/com/k0d4black/theforce/data/mappers/JsonResponseToEntity.kt new file mode 100644 index 00000000..649a8166 --- /dev/null +++ b/data/src/main/kotlin/com/k0d4black/theforce/data/mappers/JsonResponseToEntity.kt @@ -0,0 +1,26 @@ +package com.k0d4black.theforce.data.mappers + +import com.k0d4black.theforce.data.models.entity.CharacterEntity +import com.k0d4black.theforce.data.models.entity.FilmEntity +import com.k0d4black.theforce.data.models.entity.PlanetEntity +import com.k0d4black.theforce.data.models.entity.SpecieEntity +import com.k0d4black.theforce.data.models.response.CharacterResponse +import com.k0d4black.theforce.data.models.response.FilmDetailResponse +import com.k0d4black.theforce.data.models.response.PlanetDetailsResponse +import com.k0d4black.theforce.data.models.response.SpecieDetailResponse + +internal fun CharacterResponse.toEntity(): CharacterEntity { + return CharacterEntity(this.name, this.birthYear, this.height, this.url) +} + +internal fun PlanetDetailsResponse.toEntity(): PlanetEntity { + return PlanetEntity(this.name, this.population) +} + +internal fun SpecieDetailResponse.toEntity(): SpecieEntity { + return SpecieEntity(this.name, this.language) +} + +internal fun FilmDetailResponse.toEntity(): FilmEntity { + return FilmEntity(this.title, this.openingCrawl) +} \ No newline at end of file diff --git a/data/src/main/kotlin/com/k0d4black/theforce/data/mappers/JsonToEntity.kt b/data/src/main/kotlin/com/k0d4black/theforce/data/mappers/JsonToEntity.kt deleted file mode 100644 index ebbe76e1..00000000 --- a/data/src/main/kotlin/com/k0d4black/theforce/data/mappers/JsonToEntity.kt +++ /dev/null @@ -1,26 +0,0 @@ -package com.k0d4black.theforce.data.mappers - -import com.k0d4black.theforce.data.models.entity.StarWarsCharacterEntity -import com.k0d4black.theforce.data.models.entity.StarWarsCharacterFilmEntity -import com.k0d4black.theforce.data.models.entity.StarWarsCharacterPlanetEntity -import com.k0d4black.theforce.data.models.entity.StarWarsCharacterSpeciesEntity -import com.k0d4black.theforce.data.models.response.CharacterResponse -import com.k0d4black.theforce.data.models.response.details.FilmResponse -import com.k0d4black.theforce.data.models.response.details.PlanetResponse -import com.k0d4black.theforce.data.models.response.details.SpeciesResponse - -internal fun CharacterResponse.toEntity(): StarWarsCharacterEntity { - return StarWarsCharacterEntity(this.name, this.birthYear, this.height, this.url) -} - -internal fun PlanetResponse.toEntity(): StarWarsCharacterPlanetEntity { - return StarWarsCharacterPlanetEntity(this.name, this.population) -} - -internal fun SpeciesResponse.toEntity(): StarWarsCharacterSpeciesEntity { - return StarWarsCharacterSpeciesEntity(this.name, this.language) -} - -internal fun FilmResponse.toEntity(): StarWarsCharacterFilmEntity { - return StarWarsCharacterFilmEntity(this.title, this.openingCrawl) -} \ No newline at end of file diff --git a/data/src/main/kotlin/com/k0d4black/theforce/data/models/entity/StarWarsCharacterEntity.kt b/data/src/main/kotlin/com/k0d4black/theforce/data/models/entity/CharacterEntity.kt similarity index 85% rename from data/src/main/kotlin/com/k0d4black/theforce/data/models/entity/StarWarsCharacterEntity.kt rename to data/src/main/kotlin/com/k0d4black/theforce/data/models/entity/CharacterEntity.kt index be1ec2b0..6610b774 100644 --- a/data/src/main/kotlin/com/k0d4black/theforce/data/models/entity/StarWarsCharacterEntity.kt +++ b/data/src/main/kotlin/com/k0d4black/theforce/data/models/entity/CharacterEntity.kt @@ -3,7 +3,7 @@ package com.k0d4black.theforce.data.models.entity /** * Provides a shallow character model with minimal data */ -data class StarWarsCharacterEntity( +data class CharacterEntity( var name: String, var birthYear: String, var height: String, diff --git a/data/src/main/kotlin/com/k0d4black/theforce/data/models/entity/FilmEntity.kt b/data/src/main/kotlin/com/k0d4black/theforce/data/models/entity/FilmEntity.kt new file mode 100644 index 00000000..9c9c48b9 --- /dev/null +++ b/data/src/main/kotlin/com/k0d4black/theforce/data/models/entity/FilmEntity.kt @@ -0,0 +1,4 @@ +package com.k0d4black.theforce.data.models.entity + + +data class FilmEntity(val title: String, val openingCrawl: String) \ No newline at end of file diff --git a/data/src/main/kotlin/com/k0d4black/theforce/data/models/entity/StarWarsCharacterPlanetEntity.kt b/data/src/main/kotlin/com/k0d4black/theforce/data/models/entity/PlanetEntity.kt similarity index 70% rename from data/src/main/kotlin/com/k0d4black/theforce/data/models/entity/StarWarsCharacterPlanetEntity.kt rename to data/src/main/kotlin/com/k0d4black/theforce/data/models/entity/PlanetEntity.kt index e6f59056..5f4e57ea 100644 --- a/data/src/main/kotlin/com/k0d4black/theforce/data/models/entity/StarWarsCharacterPlanetEntity.kt +++ b/data/src/main/kotlin/com/k0d4black/theforce/data/models/entity/PlanetEntity.kt @@ -1,7 +1,7 @@ package com.k0d4black.theforce.data.models.entity -data class StarWarsCharacterPlanetEntity( +data class PlanetEntity( val name: String, val population: String ) \ No newline at end of file diff --git a/data/src/main/kotlin/com/k0d4black/theforce/data/models/entity/SpecieEntity.kt b/data/src/main/kotlin/com/k0d4black/theforce/data/models/entity/SpecieEntity.kt new file mode 100644 index 00000000..9a1ce33b --- /dev/null +++ b/data/src/main/kotlin/com/k0d4black/theforce/data/models/entity/SpecieEntity.kt @@ -0,0 +1,4 @@ +package com.k0d4black.theforce.data.models.entity + + +data class SpecieEntity(val name: String, val language: String) \ No newline at end of file diff --git a/data/src/main/kotlin/com/k0d4black/theforce/data/models/entity/StarWarsCharacterFilmEntity.kt b/data/src/main/kotlin/com/k0d4black/theforce/data/models/entity/StarWarsCharacterFilmEntity.kt deleted file mode 100644 index a7cca749..00000000 --- a/data/src/main/kotlin/com/k0d4black/theforce/data/models/entity/StarWarsCharacterFilmEntity.kt +++ /dev/null @@ -1,4 +0,0 @@ -package com.k0d4black.theforce.data.models.entity - - -data class StarWarsCharacterFilmEntity(val title: String, val openingCrawl: String) \ No newline at end of file diff --git a/data/src/main/kotlin/com/k0d4black/theforce/data/models/entity/StarWarsCharacterSpeciesEntity.kt b/data/src/main/kotlin/com/k0d4black/theforce/data/models/entity/StarWarsCharacterSpeciesEntity.kt deleted file mode 100644 index ec3232ce..00000000 --- a/data/src/main/kotlin/com/k0d4black/theforce/data/models/entity/StarWarsCharacterSpeciesEntity.kt +++ /dev/null @@ -1,4 +0,0 @@ -package com.k0d4black.theforce.data.models.entity - - -data class StarWarsCharacterSpeciesEntity(val name: String, val language: String) \ No newline at end of file diff --git a/data/src/main/kotlin/com/k0d4black/theforce/data/models/response/FilmsResponse.kt b/data/src/main/kotlin/com/k0d4black/theforce/data/models/response/FilmsResponse.kt new file mode 100644 index 00000000..6ef0813f --- /dev/null +++ b/data/src/main/kotlin/com/k0d4black/theforce/data/models/response/FilmsResponse.kt @@ -0,0 +1,10 @@ +package com.k0d4black.theforce.data.models.response + +import com.squareup.moshi.Json + +data class FilmsResponse(@field:Json(name = "films")val filmUrls: List) + +data class FilmDetailResponse( + val title:String, + @field:Json(name = "opening_crawl") val openingCrawl: String +) \ No newline at end of file diff --git a/data/src/main/kotlin/com/k0d4black/theforce/data/models/response/PlanetResponse.kt b/data/src/main/kotlin/com/k0d4black/theforce/data/models/response/PlanetResponse.kt new file mode 100644 index 00000000..19217604 --- /dev/null +++ b/data/src/main/kotlin/com/k0d4black/theforce/data/models/response/PlanetResponse.kt @@ -0,0 +1,7 @@ +package com.k0d4black.theforce.data.models.response + +import com.squareup.moshi.Json + +data class PlanetResponse(@field:Json(name = "homeworld") val homeworldUrl: String) + +data class PlanetDetailsResponse(val name: String, val population: String) \ No newline at end of file diff --git a/data/src/main/kotlin/com/k0d4black/theforce/data/models/response/SearchResponse.kt b/data/src/main/kotlin/com/k0d4black/theforce/data/models/response/SearchResponse.kt new file mode 100644 index 00000000..75999d24 --- /dev/null +++ b/data/src/main/kotlin/com/k0d4black/theforce/data/models/response/SearchResponse.kt @@ -0,0 +1,10 @@ +package com.k0d4black.theforce.data.models.response + + +data class SearchResponse( + val count: Int, + val next: Any, + val previous: Any, + val results: List +) + diff --git a/data/src/main/kotlin/com/k0d4black/theforce/data/models/response/SpeciesResponse.kt b/data/src/main/kotlin/com/k0d4black/theforce/data/models/response/SpeciesResponse.kt new file mode 100644 index 00000000..20722b3f --- /dev/null +++ b/data/src/main/kotlin/com/k0d4black/theforce/data/models/response/SpeciesResponse.kt @@ -0,0 +1,7 @@ +package com.k0d4black.theforce.data.models.response + +import com.squareup.moshi.Json + +data class SpeciesResponse(@field:Json(name = "species") val specieUrls: List) + +data class SpecieDetailResponse(val name: String, val language: String) \ No newline at end of file diff --git a/data/src/main/kotlin/com/k0d4black/theforce/data/models/response/details/CharacterDetailsFilmsResponse.kt b/data/src/main/kotlin/com/k0d4black/theforce/data/models/response/details/CharacterDetailsFilmsResponse.kt deleted file mode 100644 index 6aaea7b5..00000000 --- a/data/src/main/kotlin/com/k0d4black/theforce/data/models/response/details/CharacterDetailsFilmsResponse.kt +++ /dev/null @@ -1,14 +0,0 @@ -package com.k0d4black.theforce.data.models.response.details - -import com.squareup.moshi.Json - - -data class CharacterDetailsFilmsResponse(val films: List) - -/** - * Object Representation of string response - */ -data class FilmResponse( - val title:String, - @field:Json(name = "opening_crawl") val openingCrawl: String -) \ No newline at end of file diff --git a/data/src/main/kotlin/com/k0d4black/theforce/data/models/response/details/CharacterDetailsHomeWorldResponse.kt b/data/src/main/kotlin/com/k0d4black/theforce/data/models/response/details/CharacterDetailsHomeWorldResponse.kt deleted file mode 100644 index 5a4dd3f1..00000000 --- a/data/src/main/kotlin/com/k0d4black/theforce/data/models/response/details/CharacterDetailsHomeWorldResponse.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.k0d4black.theforce.data.models.response.details - -import com.squareup.moshi.Json - -data class CharacterDetailsHomeWorldResponse(@field:Json(name = "homeworld") val homeWorld: String) - -/** - * Object Representation of string response - */ -data class PlanetResponse(val name: String, val population: String) \ No newline at end of file diff --git a/data/src/main/kotlin/com/k0d4black/theforce/data/models/response/details/CharacterDetailsSpeciesResponse.kt b/data/src/main/kotlin/com/k0d4black/theforce/data/models/response/details/CharacterDetailsSpeciesResponse.kt deleted file mode 100644 index 865ba879..00000000 --- a/data/src/main/kotlin/com/k0d4black/theforce/data/models/response/details/CharacterDetailsSpeciesResponse.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.k0d4black.theforce.data.models.response.details - -data class CharacterDetailsSpeciesResponse(val species: List) - -/** - * Object Representation of string response - */ -data class SpeciesResponse( - val name: String, - val language: String -) \ No newline at end of file diff --git a/data/src/main/kotlin/com/k0d4black/theforce/data/models/response/search/CharacterSearchResponse.kt b/data/src/main/kotlin/com/k0d4black/theforce/data/models/response/search/CharacterSearchResponse.kt deleted file mode 100644 index 7c7276f9..00000000 --- a/data/src/main/kotlin/com/k0d4black/theforce/data/models/response/search/CharacterSearchResponse.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.k0d4black.theforce.data.models.response.search - -import com.k0d4black.theforce.data.models.response.CharacterResponse - - -data class CharacterSearchResponse( - val count: Int, - val next: Any, - val previous: Any, - val results: List -) - diff --git a/data/src/main/kotlin/com/k0d4black/theforce/data/repository/CharacterDetailsRepository.kt b/data/src/main/kotlin/com/k0d4black/theforce/data/repository/CharacterDetailsRepository.kt new file mode 100644 index 00000000..47bc5807 --- /dev/null +++ b/data/src/main/kotlin/com/k0d4black/theforce/data/repository/CharacterDetailsRepository.kt @@ -0,0 +1,35 @@ +package com.k0d4black.theforce.data.repository + +import com.k0d4black.theforce.data.mappers.toDomain +import com.k0d4black.theforce.data.source.CharacterDetailsDataSource +import com.k0d4black.theforce.domain.models.Film +import com.k0d4black.theforce.domain.models.Planet +import com.k0d4black.theforce.domain.models.Specie +import com.k0d4black.theforce.domain.repository.ICharacterDetailsRepository +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import javax.inject.Inject + +/** + * Co-ordinates data sources exposing character details + */ +class CharacterDetailsRepository @Inject constructor( + private val characterDetailsDataSource: CharacterDetailsDataSource +) : ICharacterDetailsRepository { + + override suspend fun getCharacterPlanet(characterUrl: String): Flow { + return characterDetailsDataSource.getCharacterPlanet(characterUrl) + .map { planet -> planet.toDomain() } + } + + override suspend fun getCharacterSpecies(characterUrl: String): Flow> { + return characterDetailsDataSource.getCharacterSpecies(characterUrl) + .map { species -> species.map { eachSpecie -> eachSpecie.toDomain() } } + } + + override suspend fun getCharacterFilms(characterUrl: String): Flow> { + return characterDetailsDataSource.getCharacterFilms(characterUrl) + .map { films -> films.map { eachFilm -> eachFilm.toDomain() } } + } + +} \ No newline at end of file diff --git a/data/src/main/kotlin/com/k0d4black/theforce/data/repository/CharacterSearchRepository.kt b/data/src/main/kotlin/com/k0d4black/theforce/data/repository/CharacterSearchRepository.kt new file mode 100644 index 00000000..5463bf6e --- /dev/null +++ b/data/src/main/kotlin/com/k0d4black/theforce/data/repository/CharacterSearchRepository.kt @@ -0,0 +1,23 @@ +package com.k0d4black.theforce.data.repository + +import com.k0d4black.theforce.data.mappers.toDomain +import com.k0d4black.theforce.data.source.CharacterSearchDataSource +import com.k0d4black.theforce.domain.models.Character +import com.k0d4black.theforce.domain.repository.ICharacterSearchRepository +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import javax.inject.Inject + +/** + * Co-ordinates data sources exposing search results + */ +class CharacterSearchRepository @Inject constructor( + private val characterSearchDataSource: CharacterSearchDataSource +) : ICharacterSearchRepository { + + override suspend fun searchCharacters(characterName: String): Flow> { + return characterSearchDataSource.query(characterName) + .map { characters -> characters.map { eachCharacter -> eachCharacter.toDomain() } } + } + +} \ No newline at end of file diff --git a/data/src/main/kotlin/com/k0d4black/theforce/data/repository/StarWarsCharacterDetailsRepository.kt b/data/src/main/kotlin/com/k0d4black/theforce/data/repository/StarWarsCharacterDetailsRepository.kt deleted file mode 100644 index a867955a..00000000 --- a/data/src/main/kotlin/com/k0d4black/theforce/data/repository/StarWarsCharacterDetailsRepository.kt +++ /dev/null @@ -1,35 +0,0 @@ -package com.k0d4black.theforce.data.repository - -import com.k0d4black.theforce.data.mappers.toDomain -import com.k0d4black.theforce.data.source.StarWarsCharacterDetailsDataSource -import com.k0d4black.theforce.domain.models.StarWarsCharacterFilm -import com.k0d4black.theforce.domain.models.StarWarsCharacterPlanet -import com.k0d4black.theforce.domain.models.StarWarsCharacterSpecies -import com.k0d4black.theforce.domain.repository.ICharacterDetailsRepository -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.map -import javax.inject.Inject - -/** - * Co-ordinates data sources exposing character details - */ -class StarWarsCharacterDetailsRepository @Inject constructor( - private val starWarsCharacterDetailsDataSource: StarWarsCharacterDetailsDataSource -) : ICharacterDetailsRepository { - - override suspend fun getCharacterPlanet(characterUrl: String): Flow { - return starWarsCharacterDetailsDataSource.getCharacterPlanet(characterUrl) - .map { it.toDomain() } - } - - override suspend fun getCharacterSpecies(characterUrl: String): Flow> { - return starWarsCharacterDetailsDataSource.getCharacterSpecies(characterUrl) - .map { it.map { specie -> specie.toDomain() } } - } - - override suspend fun getCharacterFilms(characterUrl: String): Flow> { - return starWarsCharacterDetailsDataSource.getCharacterFilms(characterUrl) - .map { it.map { film -> film.toDomain() } } - } - -} \ No newline at end of file diff --git a/data/src/main/kotlin/com/k0d4black/theforce/data/repository/StarWarsCharacterSearchRepository.kt b/data/src/main/kotlin/com/k0d4black/theforce/data/repository/StarWarsCharacterSearchRepository.kt deleted file mode 100644 index b7efb073..00000000 --- a/data/src/main/kotlin/com/k0d4black/theforce/data/repository/StarWarsCharacterSearchRepository.kt +++ /dev/null @@ -1,22 +0,0 @@ -package com.k0d4black.theforce.data.repository - -import com.k0d4black.theforce.data.mappers.toDomain -import com.k0d4black.theforce.data.source.StarWarsCharacterSearchDataSource -import com.k0d4black.theforce.domain.models.StarWarsCharacter -import com.k0d4black.theforce.domain.repository.ICharacterSearchRepository -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.map -import javax.inject.Inject - -/** - * Co-ordinates data sources exposing search results - */ -class StarWarsCharacterSearchRepository @Inject constructor( - private val starWarsCharacterSearchDataSource: StarWarsCharacterSearchDataSource -) : ICharacterSearchRepository { - - override suspend fun searchCharacters(params: String): Flow> { - return starWarsCharacterSearchDataSource.query(params).map { it.map { results->results.toDomain() } } - } - -} \ No newline at end of file diff --git a/data/src/main/kotlin/com/k0d4black/theforce/data/source/CharacterDetailsDataSource.kt b/data/src/main/kotlin/com/k0d4black/theforce/data/source/CharacterDetailsDataSource.kt new file mode 100644 index 00000000..00a06e62 --- /dev/null +++ b/data/src/main/kotlin/com/k0d4black/theforce/data/source/CharacterDetailsDataSource.kt @@ -0,0 +1,59 @@ +package com.k0d4black.theforce.data.source + +import com.k0d4black.theforce.data.api.StarWarsApiService +import com.k0d4black.theforce.data.mappers.toEntity +import com.k0d4black.theforce.data.models.entity.FilmEntity +import com.k0d4black.theforce.data.models.entity.PlanetEntity +import com.k0d4black.theforce.data.models.entity.SpecieEntity +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow +import javax.inject.Inject + +/** + * Gets character details data from network resource + */ +class CharacterDetailsDataSource @Inject constructor(private val apiService: StarWarsApiService) { + + /** + * @param characterUrl an absolute url to the character information + * + * @return [Flow] of planet entity that can be used in the data layer + */ + suspend fun getCharacterPlanet(characterUrl: String): Flow { + val planetResponse = apiService.getPlanet(characterUrl) + return flow { + emit(apiService.getPlanetDetails(planetResponse.homeworldUrl).toEntity()) + } + } + + /** + * @param characterUrl an absolute url to the character information + * + * @return [Flow] of a list of specie entities that can be used in the data layer + */ + suspend fun getCharacterSpecies(characterUrl: String): Flow> { + val speciesResponse = apiService.getSpecies(characterUrl) + val species = mutableListOf() + for (specieUrl in speciesResponse.specieUrls) { + val specie = apiService.getSpecieDetails(specieUrl) + species.add(specie.toEntity()) + } + return flow { emit(species) } + } + + /** + * @param characterUrl an absolute url to the character information + * + * @return [Flow] of a list of film entities that can be used in the data layer + */ + suspend fun getCharacterFilms(characterUrl: String): Flow> { + val filmsResponse = apiService.getFilms(characterUrl) + val films = mutableListOf() + for (filmUrl in filmsResponse.filmUrls) { + val film = apiService.getFilmDetails(filmUrl) + films.add(film.toEntity()) + } + return flow { emit(films) } + } + +} \ No newline at end of file diff --git a/data/src/main/kotlin/com/k0d4black/theforce/data/source/CharacterSearchDataSource.kt b/data/src/main/kotlin/com/k0d4black/theforce/data/source/CharacterSearchDataSource.kt new file mode 100644 index 00000000..aecb731b --- /dev/null +++ b/data/src/main/kotlin/com/k0d4black/theforce/data/source/CharacterSearchDataSource.kt @@ -0,0 +1,27 @@ +package com.k0d4black.theforce.data.source + +import com.k0d4black.theforce.data.api.StarWarsApiService +import com.k0d4black.theforce.data.mappers.toEntity +import com.k0d4black.theforce.data.models.entity.CharacterEntity +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow +import javax.inject.Inject + +class CharacterSearchDataSource @Inject constructor(private val apiService: StarWarsApiService) { + + /** + * Takes in a [characterName] to be used for the search + * + * @return [Flow] of starwars characters transformed to entities that can be used in the + * data layer. + */ + suspend fun query(characterName: String): Flow> { + val searchResponse = apiService.searchCharacters(characterName) + val starWarsCharacters = mutableListOf() + for (starWarsCharacter in searchResponse.results) { + starWarsCharacters.add(starWarsCharacter.toEntity()) + } + return flow { emit(starWarsCharacters) } + } + +} \ No newline at end of file diff --git a/data/src/main/kotlin/com/k0d4black/theforce/data/source/StarWarsCharacterDetailsDataSource.kt b/data/src/main/kotlin/com/k0d4black/theforce/data/source/StarWarsCharacterDetailsDataSource.kt deleted file mode 100644 index 32336141..00000000 --- a/data/src/main/kotlin/com/k0d4black/theforce/data/source/StarWarsCharacterDetailsDataSource.kt +++ /dev/null @@ -1,49 +0,0 @@ -package com.k0d4black.theforce.data.source - -import com.k0d4black.theforce.data.api.StarWarsApiService -import com.k0d4black.theforce.data.mappers.toEntity -import com.k0d4black.theforce.data.models.entity.StarWarsCharacterFilmEntity -import com.k0d4black.theforce.data.models.entity.StarWarsCharacterPlanetEntity -import com.k0d4black.theforce.data.models.entity.StarWarsCharacterSpeciesEntity -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.flow -import javax.inject.Inject - -/** - * Gets character details data from network resource - */ -class StarWarsCharacterDetailsDataSource @Inject constructor(private val apiService: StarWarsApiService) { - - suspend fun getCharacterPlanet(characterUrl: String): Flow { - val characterDetailsHomeWorldResponse = apiService.getCharacterHomeworld(characterUrl) - return flow { - emit( - apiService.getPlanetDetails(characterDetailsHomeWorldResponse.homeWorld) - .toEntity() - ) - } - } - - - suspend fun getCharacterSpecies(characterUrl: String): Flow> { - val characterDetailsResponse = apiService.getCharacterSpecies(characterUrl) - val characterSpecies = mutableListOf() - for (specie in characterDetailsResponse.species) { - val specieResponse = apiService.getSpeciesDetails(specie) - characterSpecies.add(specieResponse.toEntity()) - } - return flow { emit(characterSpecies) } - } - - - suspend fun getCharacterFilms(characterUrl: String): Flow> { - val characterDetailsResponse = apiService.getCharacterFilms(characterUrl) - val characterFilms = mutableListOf() - for (film in characterDetailsResponse.films) { - val filmResponse = apiService.getFilmDetails(film) - characterFilms.add(filmResponse.toEntity()) - } - return flow { emit(characterFilms) } - } - -} \ No newline at end of file diff --git a/data/src/main/kotlin/com/k0d4black/theforce/data/source/StarWarsCharacterSearchDataSource.kt b/data/src/main/kotlin/com/k0d4black/theforce/data/source/StarWarsCharacterSearchDataSource.kt deleted file mode 100644 index e1c1d4a4..00000000 --- a/data/src/main/kotlin/com/k0d4black/theforce/data/source/StarWarsCharacterSearchDataSource.kt +++ /dev/null @@ -1,25 +0,0 @@ -package com.k0d4black.theforce.data.source - -import com.k0d4black.theforce.data.api.StarWarsApiService -import com.k0d4black.theforce.data.mappers.toEntity -import com.k0d4black.theforce.data.models.entity.StarWarsCharacterEntity -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.flow -import javax.inject.Inject - -class StarWarsCharacterSearchDataSource @Inject constructor(private val apiService: StarWarsApiService) { - - /** - * Takes in [params] to be used for the search - * @return list of search results - */ - suspend fun query(params: String): Flow> { - val searchResponse = apiService.searchCharacters(params) - val searchDataModels = mutableListOf() - for (searchResult in searchResponse.results) { - searchDataModels.add(searchResult.toEntity()) - } - return flow { emit(searchDataModels) } - } - -} \ No newline at end of file diff --git a/data/src/test/kotlin/com/k0d4black/theforce/data/helpers/Utils.kt b/data/src/test/kotlin/com/k0d4black/theforce/data/helpers/Utils.kt index d99db925..c3ea1f6b 100644 --- a/data/src/test/kotlin/com/k0d4black/theforce/data/helpers/Utils.kt +++ b/data/src/test/kotlin/com/k0d4black/theforce/data/helpers/Utils.kt @@ -1,6 +1,7 @@ package com.k0d4black.theforce.data.helpers +import com.google.common.annotations.Beta import com.google.common.io.Resources.getResource import java.io.File @@ -11,6 +12,7 @@ import java.io.File * @param path : Path of JSON file * @return json : JSON from file at given path */ + fun getJson(path: String): String { val uri = getResource(path) val file = File(uri.path) diff --git a/data/src/test/kotlin/com/k0d4black/theforce/data/repository/StarWarsCharacterDetailsRepositoryTest.kt b/data/src/test/kotlin/com/k0d4black/theforce/data/repository/CharacterDetailsRepositoryTest.kt similarity index 81% rename from data/src/test/kotlin/com/k0d4black/theforce/data/repository/StarWarsCharacterDetailsRepositoryTest.kt rename to data/src/test/kotlin/com/k0d4black/theforce/data/repository/CharacterDetailsRepositoryTest.kt index a5c105f0..b1965807 100644 --- a/data/src/test/kotlin/com/k0d4black/theforce/data/repository/StarWarsCharacterDetailsRepositoryTest.kt +++ b/data/src/test/kotlin/com/k0d4black/theforce/data/repository/CharacterDetailsRepositoryTest.kt @@ -3,23 +3,23 @@ package com.k0d4black.theforce.data.repository import com.google.common.truth.Truth import com.k0d4black.theforce.data.BaseTest import com.k0d4black.theforce.data.helpers.EXISTING_CHARACTER_URL -import com.k0d4black.theforce.data.source.StarWarsCharacterDetailsDataSource +import com.k0d4black.theforce.data.source.CharacterDetailsDataSource import com.k0d4black.theforce.domain.repository.ICharacterDetailsRepository import kotlinx.coroutines.flow.collect import kotlinx.coroutines.runBlocking import org.junit.Before import org.junit.Test -internal class StarWarsCharacterDetailsRepositoryTest : BaseTest() { +internal class CharacterDetailsRepositoryTest : BaseTest() { private lateinit var characterDetailsRepository: ICharacterDetailsRepository @Before override fun setup() { super.setup() - val characterDetailsDataSourceMock = StarWarsCharacterDetailsDataSource(starWarsApiService) + val characterDetailsDataSourceMock = CharacterDetailsDataSource(starWarsApiService) characterDetailsRepository = - StarWarsCharacterDetailsRepository(characterDetailsDataSourceMock) + CharacterDetailsRepository(characterDetailsDataSourceMock) } @Test diff --git a/data/src/test/kotlin/com/k0d4black/theforce/data/repository/StarWarsCharacterSearchRepositoryTest.kt b/data/src/test/kotlin/com/k0d4black/theforce/data/repository/CharacterSearchRepositoryTest.kt similarity index 77% rename from data/src/test/kotlin/com/k0d4black/theforce/data/repository/StarWarsCharacterSearchRepositoryTest.kt rename to data/src/test/kotlin/com/k0d4black/theforce/data/repository/CharacterSearchRepositoryTest.kt index 17d57c4b..6723bd43 100644 --- a/data/src/test/kotlin/com/k0d4black/theforce/data/repository/StarWarsCharacterSearchRepositoryTest.kt +++ b/data/src/test/kotlin/com/k0d4black/theforce/data/repository/CharacterSearchRepositoryTest.kt @@ -4,22 +4,22 @@ import com.google.common.truth.Truth import com.k0d4black.theforce.data.BaseTest import com.k0d4black.theforce.data.helpers.EXISTING_SEARCH_PARAMS import com.k0d4black.theforce.data.helpers.NON_EXISTENT_SEARCH_PARAMS -import com.k0d4black.theforce.data.source.StarWarsCharacterSearchDataSource +import com.k0d4black.theforce.data.source.CharacterSearchDataSource import com.k0d4black.theforce.domain.repository.ICharacterSearchRepository import kotlinx.coroutines.flow.collect import kotlinx.coroutines.runBlocking import org.junit.Before import org.junit.Test -internal class StarWarsCharacterSearchRepositoryTest : BaseTest() { +internal class CharacterSearchRepositoryTest : BaseTest() { private lateinit var characterSearchRepository: ICharacterSearchRepository @Before override fun setup() { super.setup() - val characterSearchDataSourceMock = StarWarsCharacterSearchDataSource(starWarsApiService) - characterSearchRepository = StarWarsCharacterSearchRepository(characterSearchDataSourceMock) + val characterSearchDataSourceMock = CharacterSearchDataSource(starWarsApiService) + characterSearchRepository = CharacterSearchRepository(characterSearchDataSourceMock) } @Test diff --git a/data/src/test/kotlin/com/k0d4black/theforce/data/source/StarWarsCharacterDetailsDataSourceTest.kt b/data/src/test/kotlin/com/k0d4black/theforce/data/source/CharacterDetailsDataSourceTest.kt similarity index 64% rename from data/src/test/kotlin/com/k0d4black/theforce/data/source/StarWarsCharacterDetailsDataSourceTest.kt rename to data/src/test/kotlin/com/k0d4black/theforce/data/source/CharacterDetailsDataSourceTest.kt index 6665669f..141db361 100644 --- a/data/src/test/kotlin/com/k0d4black/theforce/data/source/StarWarsCharacterDetailsDataSourceTest.kt +++ b/data/src/test/kotlin/com/k0d4black/theforce/data/source/CharacterDetailsDataSourceTest.kt @@ -8,25 +8,25 @@ import kotlinx.coroutines.runBlocking import org.junit.Before import org.junit.Test -internal class StarWarsCharacterDetailsDataSourceTest : BaseTest() { +internal class CharacterDetailsDataSourceTest : BaseTest() { - private lateinit var starWarsCharacterDetailsDataSource: StarWarsCharacterDetailsDataSource + private lateinit var characterDetailsDataSource: CharacterDetailsDataSource @Before override fun setup() { super.setup() - starWarsCharacterDetailsDataSource = StarWarsCharacterDetailsDataSource(starWarsApiService) + characterDetailsDataSource = CharacterDetailsDataSource(starWarsApiService) } @Test fun `given a valid character id when executed then return character details`() { runBlocking { val characterFilmsFlow = - starWarsCharacterDetailsDataSource.getCharacterFilms(EXISTING_CHARACTER_URL) + characterDetailsDataSource.getCharacterFilms(EXISTING_CHARACTER_URL) val characterSpeciesFlow = - starWarsCharacterDetailsDataSource.getCharacterSpecies(EXISTING_CHARACTER_URL) + characterDetailsDataSource.getCharacterSpecies(EXISTING_CHARACTER_URL) val characterPlanetFlow = - starWarsCharacterDetailsDataSource.getCharacterPlanet(EXISTING_CHARACTER_URL) + characterDetailsDataSource.getCharacterPlanet(EXISTING_CHARACTER_URL) characterFilmsFlow.collect { Truth.assertThat(it.size).isAtLeast(1) diff --git a/data/src/test/kotlin/com/k0d4black/theforce/data/source/StarWarsCharacterSearchDataSourceTest.kt b/data/src/test/kotlin/com/k0d4black/theforce/data/source/CharacterSearchDataSourceTest.kt similarity index 66% rename from data/src/test/kotlin/com/k0d4black/theforce/data/source/StarWarsCharacterSearchDataSourceTest.kt rename to data/src/test/kotlin/com/k0d4black/theforce/data/source/CharacterSearchDataSourceTest.kt index 601cbb50..d921a3aa 100644 --- a/data/src/test/kotlin/com/k0d4black/theforce/data/source/StarWarsCharacterSearchDataSourceTest.kt +++ b/data/src/test/kotlin/com/k0d4black/theforce/data/source/CharacterSearchDataSourceTest.kt @@ -10,20 +10,20 @@ import org.junit.Before import org.junit.Test -class StarWarsCharacterSearchDataSourceTest : BaseTest() { +class CharacterSearchDataSourceTest : BaseTest() { - private lateinit var starWarsCharacterSearchDataSource: StarWarsCharacterSearchDataSource + private lateinit var characterSearchDataSource: CharacterSearchDataSource @Before override fun setup() { super.setup() - starWarsCharacterSearchDataSource = StarWarsCharacterSearchDataSource(starWarsApiService) + characterSearchDataSource = CharacterSearchDataSource(starWarsApiService) } @Test fun `given search parameters when parameters exist then get available matching characters`() { runBlocking { - val response = starWarsCharacterSearchDataSource.query(EXISTING_SEARCH_PARAMS) + val response = characterSearchDataSource.query(EXISTING_SEARCH_PARAMS) response.collect { Truth.assertThat(it).isNotEmpty() } } } @@ -31,7 +31,7 @@ class StarWarsCharacterSearchDataSourceTest : BaseTest() { @Test fun `given search parameters when parameters dont exist then get no matching characters`() { runBlocking { - val response = starWarsCharacterSearchDataSource.query(NON_EXISTENT_SEARCH_PARAMS) + val response = characterSearchDataSource.query(NON_EXISTENT_SEARCH_PARAMS) response.collect { Truth.assertThat(it).isEmpty() } } } diff --git a/dependencies.gradle b/dependencies.gradle index c20ee976..174ef881 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -8,7 +8,7 @@ ext { //App Versioning versionCodeMajor = 1 versionCodeMinor = 0 - versionCodePatch = 2 + versionCodePatch = 3 versionName = "$versionCodeMajor.$versionCodeMinor.$versionCodePatch" //Dependencies Version - Presentation diff --git a/domain/src/main/kotlin/com/k0d4black/theforce/domain/models/StarWarsCharacter.kt b/domain/src/main/kotlin/com/k0d4black/theforce/domain/models/Character.kt similarity index 82% rename from domain/src/main/kotlin/com/k0d4black/theforce/domain/models/StarWarsCharacter.kt rename to domain/src/main/kotlin/com/k0d4black/theforce/domain/models/Character.kt index ac3eb7b5..523e77fb 100644 --- a/domain/src/main/kotlin/com/k0d4black/theforce/domain/models/StarWarsCharacter.kt +++ b/domain/src/main/kotlin/com/k0d4black/theforce/domain/models/Character.kt @@ -1,7 +1,7 @@ package com.k0d4black.theforce.domain.models -data class StarWarsCharacter( +data class Character( val name: String, val birthYear: String, val height: String, diff --git a/domain/src/main/kotlin/com/k0d4black/theforce/domain/models/Film.kt b/domain/src/main/kotlin/com/k0d4black/theforce/domain/models/Film.kt new file mode 100644 index 00000000..99c0ad59 --- /dev/null +++ b/domain/src/main/kotlin/com/k0d4black/theforce/domain/models/Film.kt @@ -0,0 +1,4 @@ +package com.k0d4black.theforce.domain.models + + +data class Film(val title: String, val openingCrawl: String) \ No newline at end of file diff --git a/domain/src/main/kotlin/com/k0d4black/theforce/domain/models/StarWarsCharacterPlanet.kt b/domain/src/main/kotlin/com/k0d4black/theforce/domain/models/Planet.kt similarity index 72% rename from domain/src/main/kotlin/com/k0d4black/theforce/domain/models/StarWarsCharacterPlanet.kt rename to domain/src/main/kotlin/com/k0d4black/theforce/domain/models/Planet.kt index a8c333b3..4b33d4f5 100644 --- a/domain/src/main/kotlin/com/k0d4black/theforce/domain/models/StarWarsCharacterPlanet.kt +++ b/domain/src/main/kotlin/com/k0d4black/theforce/domain/models/Planet.kt @@ -1,7 +1,7 @@ package com.k0d4black.theforce.domain.models -data class StarWarsCharacterPlanet( +data class Planet( val name: String, val population: String ) \ No newline at end of file diff --git a/domain/src/main/kotlin/com/k0d4black/theforce/domain/models/Specie.kt b/domain/src/main/kotlin/com/k0d4black/theforce/domain/models/Specie.kt new file mode 100644 index 00000000..fffcb0de --- /dev/null +++ b/domain/src/main/kotlin/com/k0d4black/theforce/domain/models/Specie.kt @@ -0,0 +1,3 @@ +package com.k0d4black.theforce.domain.models + +data class Specie(val name: String, val language: String) \ No newline at end of file diff --git a/domain/src/main/kotlin/com/k0d4black/theforce/domain/models/StarWarsCharacterFilm.kt b/domain/src/main/kotlin/com/k0d4black/theforce/domain/models/StarWarsCharacterFilm.kt deleted file mode 100644 index a16de0cc..00000000 --- a/domain/src/main/kotlin/com/k0d4black/theforce/domain/models/StarWarsCharacterFilm.kt +++ /dev/null @@ -1,4 +0,0 @@ -package com.k0d4black.theforce.domain.models - - -data class StarWarsCharacterFilm(val title: String, val openingCrawl: String) \ No newline at end of file diff --git a/domain/src/main/kotlin/com/k0d4black/theforce/domain/models/StarWarsCharacterSpecies.kt b/domain/src/main/kotlin/com/k0d4black/theforce/domain/models/StarWarsCharacterSpecies.kt deleted file mode 100644 index 237d0fc7..00000000 --- a/domain/src/main/kotlin/com/k0d4black/theforce/domain/models/StarWarsCharacterSpecies.kt +++ /dev/null @@ -1,4 +0,0 @@ -package com.k0d4black.theforce.domain.models - - -data class StarWarsCharacterSpecies(val name: String, val language: String) \ No newline at end of file diff --git a/domain/src/main/kotlin/com/k0d4black/theforce/domain/repository/ICharacterDetailsRepository.kt b/domain/src/main/kotlin/com/k0d4black/theforce/domain/repository/ICharacterDetailsRepository.kt index df660320..f730918e 100644 --- a/domain/src/main/kotlin/com/k0d4black/theforce/domain/repository/ICharacterDetailsRepository.kt +++ b/domain/src/main/kotlin/com/k0d4black/theforce/domain/repository/ICharacterDetailsRepository.kt @@ -1,17 +1,17 @@ package com.k0d4black.theforce.domain.repository -import com.k0d4black.theforce.domain.models.StarWarsCharacterFilm -import com.k0d4black.theforce.domain.models.StarWarsCharacterPlanet -import com.k0d4black.theforce.domain.models.StarWarsCharacterSpecies +import com.k0d4black.theforce.domain.models.Film +import com.k0d4black.theforce.domain.models.Planet +import com.k0d4black.theforce.domain.models.Specie import kotlinx.coroutines.flow.Flow interface ICharacterDetailsRepository { - suspend fun getCharacterPlanet(characterUrl: String): Flow + suspend fun getCharacterPlanet(characterUrl: String): Flow - suspend fun getCharacterSpecies(characterUrl: String): Flow> + suspend fun getCharacterSpecies(characterUrl: String): Flow> - suspend fun getCharacterFilms(characterUrl: String): Flow> + suspend fun getCharacterFilms(characterUrl: String): Flow> } \ No newline at end of file diff --git a/domain/src/main/kotlin/com/k0d4black/theforce/domain/repository/ICharacterSearchRepository.kt b/domain/src/main/kotlin/com/k0d4black/theforce/domain/repository/ICharacterSearchRepository.kt index 31c85f56..0861d54a 100644 --- a/domain/src/main/kotlin/com/k0d4black/theforce/domain/repository/ICharacterSearchRepository.kt +++ b/domain/src/main/kotlin/com/k0d4black/theforce/domain/repository/ICharacterSearchRepository.kt @@ -1,8 +1,8 @@ package com.k0d4black.theforce.domain.repository -import com.k0d4black.theforce.domain.models.StarWarsCharacter +import com.k0d4black.theforce.domain.models.Character import kotlinx.coroutines.flow.Flow interface ICharacterSearchRepository { - suspend fun searchCharacters(params: String): Flow> + suspend fun searchCharacters(characterName: String): Flow> } \ No newline at end of file diff --git a/domain/src/main/kotlin/com/k0d4black/theforce/domain/usecases/GetStarWarsCharacterFilmsUseCase.kt b/domain/src/main/kotlin/com/k0d4black/theforce/domain/usecases/GetFilmsUseCase.kt similarity index 85% rename from domain/src/main/kotlin/com/k0d4black/theforce/domain/usecases/GetStarWarsCharacterFilmsUseCase.kt rename to domain/src/main/kotlin/com/k0d4black/theforce/domain/usecases/GetFilmsUseCase.kt index 65a06758..029f39ff 100644 --- a/domain/src/main/kotlin/com/k0d4black/theforce/domain/usecases/GetStarWarsCharacterFilmsUseCase.kt +++ b/domain/src/main/kotlin/com/k0d4black/theforce/domain/usecases/GetFilmsUseCase.kt @@ -5,7 +5,7 @@ import com.k0d4black.theforce.domain.repository.ICharacterDetailsRepository import javax.inject.Inject -class GetStarWarsCharacterFilmsUseCase @Inject constructor( +class GetFilmsUseCase @Inject constructor( private val characterDetailsRepository: ICharacterDetailsRepository ) { diff --git a/domain/src/main/kotlin/com/k0d4black/theforce/domain/usecases/GetStarWarsCharacterPlanetUseCase.kt b/domain/src/main/kotlin/com/k0d4black/theforce/domain/usecases/GetPlanetUseCase.kt similarity index 85% rename from domain/src/main/kotlin/com/k0d4black/theforce/domain/usecases/GetStarWarsCharacterPlanetUseCase.kt rename to domain/src/main/kotlin/com/k0d4black/theforce/domain/usecases/GetPlanetUseCase.kt index a8477279..0ecfe7ff 100644 --- a/domain/src/main/kotlin/com/k0d4black/theforce/domain/usecases/GetStarWarsCharacterPlanetUseCase.kt +++ b/domain/src/main/kotlin/com/k0d4black/theforce/domain/usecases/GetPlanetUseCase.kt @@ -5,7 +5,7 @@ import com.k0d4black.theforce.domain.repository.ICharacterDetailsRepository import javax.inject.Inject -class GetStarWarsCharacterPlanetUseCase @Inject constructor( +class GetPlanetUseCase @Inject constructor( private val characterDetailsRepository: ICharacterDetailsRepository ) { diff --git a/domain/src/main/kotlin/com/k0d4black/theforce/domain/usecases/GetStarWarsCharacterSpeciesUseCase.kt b/domain/src/main/kotlin/com/k0d4black/theforce/domain/usecases/GetSpeciesUseCase.kt similarity index 85% rename from domain/src/main/kotlin/com/k0d4black/theforce/domain/usecases/GetStarWarsCharacterSpeciesUseCase.kt rename to domain/src/main/kotlin/com/k0d4black/theforce/domain/usecases/GetSpeciesUseCase.kt index f2df3e9e..adf0d61f 100644 --- a/domain/src/main/kotlin/com/k0d4black/theforce/domain/usecases/GetStarWarsCharacterSpeciesUseCase.kt +++ b/domain/src/main/kotlin/com/k0d4black/theforce/domain/usecases/GetSpeciesUseCase.kt @@ -4,7 +4,7 @@ package com.k0d4black.theforce.domain.usecases import com.k0d4black.theforce.domain.repository.ICharacterDetailsRepository import javax.inject.Inject -class GetStarWarsCharacterSpeciesUseCase @Inject constructor( +class GetSpeciesUseCase @Inject constructor( private val characterDetailsRepository: ICharacterDetailsRepository ) { diff --git a/domain/src/main/kotlin/com/k0d4black/theforce/domain/usecases/SearchStarWarsCharacterUseCase.kt b/domain/src/main/kotlin/com/k0d4black/theforce/domain/usecases/SearchCharactersUseCase.kt similarity index 58% rename from domain/src/main/kotlin/com/k0d4black/theforce/domain/usecases/SearchStarWarsCharacterUseCase.kt rename to domain/src/main/kotlin/com/k0d4black/theforce/domain/usecases/SearchCharactersUseCase.kt index 89d53fc6..c3bf17de 100644 --- a/domain/src/main/kotlin/com/k0d4black/theforce/domain/usecases/SearchStarWarsCharacterUseCase.kt +++ b/domain/src/main/kotlin/com/k0d4black/theforce/domain/usecases/SearchCharactersUseCase.kt @@ -3,10 +3,10 @@ package com.k0d4black.theforce.domain.usecases import com.k0d4black.theforce.domain.repository.ICharacterSearchRepository import javax.inject.Inject -class SearchStarWarsCharacterUseCase @Inject constructor( +class SearchCharactersUseCase @Inject constructor( private val searchRepository: ICharacterSearchRepository ) { - suspend operator fun invoke(params: String) = searchRepository.searchCharacters(params) + suspend operator fun invoke(characterName: String) = searchRepository.searchCharacters(characterName) } \ No newline at end of file diff --git a/domain/src/test/kotlin/com/k0d4black/theforce/domain/models/StarWarsCharacterTest.kt b/domain/src/test/kotlin/com/k0d4black/theforce/domain/models/CharacterTest.kt similarity index 61% rename from domain/src/test/kotlin/com/k0d4black/theforce/domain/models/StarWarsCharacterTest.kt rename to domain/src/test/kotlin/com/k0d4black/theforce/domain/models/CharacterTest.kt index bf91cc89..c7da2834 100644 --- a/domain/src/test/kotlin/com/k0d4black/theforce/domain/models/StarWarsCharacterTest.kt +++ b/domain/src/test/kotlin/com/k0d4black/theforce/domain/models/CharacterTest.kt @@ -4,15 +4,15 @@ import com.google.common.truth.Truth import org.junit.Test -internal class StarWarsCharacterTest { +internal class CharacterTest { - lateinit var expectedModel: StarWarsCharacter + lateinit var expectedModel: Character @Test fun `instantiate character basic info domain model`() { //Given expectedModel = - StarWarsCharacter( + Character( name = "Luke Skywalker", birthYear = "19 BBY", height = "172", @@ -20,7 +20,7 @@ internal class StarWarsCharacterTest { ) val actualModel = expectedModel.copy() //Then - Truth.assertThat(actualModel).isInstanceOf(StarWarsCharacter::class.java) - Truth.assertThat(expectedModel).isInstanceOf(StarWarsCharacter::class.java) + Truth.assertThat(actualModel).isInstanceOf(Character::class.java) + Truth.assertThat(expectedModel).isInstanceOf(Character::class.java) } } diff --git a/domain/src/test/kotlin/com/k0d4black/theforce/domain/models/StarWarsCharacterFilmTest.kt b/domain/src/test/kotlin/com/k0d4black/theforce/domain/models/FilmTest.kt similarity index 69% rename from domain/src/test/kotlin/com/k0d4black/theforce/domain/models/StarWarsCharacterFilmTest.kt rename to domain/src/test/kotlin/com/k0d4black/theforce/domain/models/FilmTest.kt index 0a1f4735..2a0951a7 100644 --- a/domain/src/test/kotlin/com/k0d4black/theforce/domain/models/StarWarsCharacterFilmTest.kt +++ b/domain/src/test/kotlin/com/k0d4black/theforce/domain/models/FilmTest.kt @@ -3,21 +3,21 @@ package com.k0d4black.theforce.domain.models import com.google.common.truth.Truth import org.junit.Test -internal class StarWarsCharacterFilmTest { +internal class FilmTest { - lateinit var expectedModelStarWars: StarWarsCharacterFilm + lateinit var expectedModelStarWars: Film @Test fun `instantiate character film domain model`() { //Given expectedModelStarWars = - StarWarsCharacterFilm( + Film( title = "Film Title", openingCrawl = "Mwaha ha this is the opening crawl for this film mwa ha ha." ) val actualModel = expectedModelStarWars.copy() //Then - Truth.assertThat(actualModel).isInstanceOf(StarWarsCharacterFilm::class.java) + Truth.assertThat(actualModel).isInstanceOf(Film::class.java) Truth.assertThat(actualModel).isEqualTo(expectedModelStarWars) } } \ No newline at end of file diff --git a/domain/src/test/kotlin/com/k0d4black/theforce/domain/models/StarWarsStarWarsCharacterPlanetTest.kt b/domain/src/test/kotlin/com/k0d4black/theforce/domain/models/PlanetTest.kt similarity index 65% rename from domain/src/test/kotlin/com/k0d4black/theforce/domain/models/StarWarsStarWarsCharacterPlanetTest.kt rename to domain/src/test/kotlin/com/k0d4black/theforce/domain/models/PlanetTest.kt index 7356d53c..cec622ae 100644 --- a/domain/src/test/kotlin/com/k0d4black/theforce/domain/models/StarWarsStarWarsCharacterPlanetTest.kt +++ b/domain/src/test/kotlin/com/k0d4black/theforce/domain/models/PlanetTest.kt @@ -3,21 +3,21 @@ package com.k0d4black.theforce.domain.models import com.google.common.truth.Truth import org.junit.Test -internal class StarWarsStarWarsCharacterPlanetTest { +internal class PlanetTest { - lateinit var expectedModelStarWars: StarWarsCharacterPlanet + lateinit var expectedModelStarWars: Planet @Test fun `instantiate character planet domain model`() { //Given expectedModelStarWars = - StarWarsCharacterPlanet( + Planet( name = "Tatooine", population = "23444499" ) val actualModel = expectedModelStarWars.copy() //Then - Truth.assertThat(actualModel).isInstanceOf(StarWarsCharacterPlanet::class.java) + Truth.assertThat(actualModel).isInstanceOf(Planet::class.java) Truth.assertThat(actualModel).isEqualTo(expectedModelStarWars) } } \ No newline at end of file diff --git a/domain/src/test/kotlin/com/k0d4black/theforce/domain/models/StarWarsStarWarsCharacterSpeciesTest.kt b/domain/src/test/kotlin/com/k0d4black/theforce/domain/models/SpecieTest.kt similarity index 65% rename from domain/src/test/kotlin/com/k0d4black/theforce/domain/models/StarWarsStarWarsCharacterSpeciesTest.kt rename to domain/src/test/kotlin/com/k0d4black/theforce/domain/models/SpecieTest.kt index 621d20e4..bfe75e5a 100644 --- a/domain/src/test/kotlin/com/k0d4black/theforce/domain/models/StarWarsStarWarsCharacterSpeciesTest.kt +++ b/domain/src/test/kotlin/com/k0d4black/theforce/domain/models/SpecieTest.kt @@ -4,21 +4,21 @@ package com.k0d4black.theforce.domain.models import com.google.common.truth.Truth import org.junit.Test -internal class StarWarsStarWarsCharacterSpeciesTest { +internal class SpecieTest { - lateinit var expectedModelStarWars: StarWarsCharacterSpecies + lateinit var expectedModelStarWars: Specie @Test fun `instantiate character species domain model`() { //Given expectedModelStarWars = - StarWarsCharacterSpecies( + Specie( language = "Shyriiwook", name = "Human" ) val actualModel = expectedModelStarWars.copy() //Then - Truth.assertThat(actualModel).isInstanceOf(StarWarsCharacterSpecies::class.java) + Truth.assertThat(actualModel).isInstanceOf(Specie::class.java) Truth.assertThat(actualModel).isEqualTo(expectedModelStarWars) } } \ No newline at end of file diff --git a/domain/src/test/kotlin/com/k0d4black/theforce/domain/usecase/GetStarWarsCharacterFilmsUseCaseTest.kt b/domain/src/test/kotlin/com/k0d4black/theforce/domain/usecase/GetFilmsUseCaseTest.kt similarity index 67% rename from domain/src/test/kotlin/com/k0d4black/theforce/domain/usecase/GetStarWarsCharacterFilmsUseCaseTest.kt rename to domain/src/test/kotlin/com/k0d4black/theforce/domain/usecase/GetFilmsUseCaseTest.kt index 10d3a337..b8f8585a 100644 --- a/domain/src/test/kotlin/com/k0d4black/theforce/domain/usecase/GetStarWarsCharacterFilmsUseCaseTest.kt +++ b/domain/src/test/kotlin/com/k0d4black/theforce/domain/usecase/GetFilmsUseCaseTest.kt @@ -1,7 +1,7 @@ package com.k0d4black.theforce.domain.usecase import com.k0d4black.theforce.domain.repository.ICharacterDetailsRepository -import com.k0d4black.theforce.domain.usecases.GetStarWarsCharacterFilmsUseCase +import com.k0d4black.theforce.domain.usecases.GetFilmsUseCase import kotlinx.coroutines.runBlocking import org.junit.Before import org.junit.Test @@ -11,16 +11,16 @@ import org.mockito.Mockito.verify import org.mockito.junit.MockitoJUnitRunner @RunWith(MockitoJUnitRunner::class) -internal class GetStarWarsCharacterFilmsUseCaseTest { +internal class GetFilmsUseCaseTest { @Mock private lateinit var characterDetailsRepositoryMock: ICharacterDetailsRepository - private lateinit var getStarWarsCharacterFilmsUseCase: GetStarWarsCharacterFilmsUseCase + private lateinit var getFilmsUseCase: GetFilmsUseCase @Before fun setup() { - getStarWarsCharacterFilmsUseCase = - GetStarWarsCharacterFilmsUseCase(characterDetailsRepositoryMock) + getFilmsUseCase = + GetFilmsUseCase(characterDetailsRepositoryMock) } @Test @@ -30,7 +30,7 @@ internal class GetStarWarsCharacterFilmsUseCaseTest { val characterId = "https://swapi.py4e.com/api/people/3/" //When - getStarWarsCharacterFilmsUseCase(characterId) + getFilmsUseCase(characterId) //Then verify(characterDetailsRepositoryMock).getCharacterFilms(characterId) diff --git a/domain/src/test/kotlin/com/k0d4black/theforce/domain/usecase/GetStarWarsCharacterPlanetUseCaseTest.kt b/domain/src/test/kotlin/com/k0d4black/theforce/domain/usecase/GetPlanetUseCaseTest.kt similarity index 67% rename from domain/src/test/kotlin/com/k0d4black/theforce/domain/usecase/GetStarWarsCharacterPlanetUseCaseTest.kt rename to domain/src/test/kotlin/com/k0d4black/theforce/domain/usecase/GetPlanetUseCaseTest.kt index 8fb2b8a8..8c607ae5 100644 --- a/domain/src/test/kotlin/com/k0d4black/theforce/domain/usecase/GetStarWarsCharacterPlanetUseCaseTest.kt +++ b/domain/src/test/kotlin/com/k0d4black/theforce/domain/usecase/GetPlanetUseCaseTest.kt @@ -1,7 +1,7 @@ package com.k0d4black.theforce.domain.usecase import com.k0d4black.theforce.domain.repository.ICharacterDetailsRepository -import com.k0d4black.theforce.domain.usecases.GetStarWarsCharacterPlanetUseCase +import com.k0d4black.theforce.domain.usecases.GetPlanetUseCase import kotlinx.coroutines.runBlocking import org.junit.Before @@ -12,15 +12,15 @@ import org.mockito.Mockito.verify import org.mockito.junit.MockitoJUnitRunner @RunWith(MockitoJUnitRunner::class) -internal class GetStarWarsCharacterPlanetUseCaseTest { +internal class GetPlanetUseCaseTest { @Mock private lateinit var characterDetailsRepositoryMock: ICharacterDetailsRepository - private lateinit var getStarWarsCharacterPlanetUseCase: GetStarWarsCharacterPlanetUseCase + private lateinit var getPlanetUseCase: GetPlanetUseCase @Before fun setup() { - getStarWarsCharacterPlanetUseCase = GetStarWarsCharacterPlanetUseCase(characterDetailsRepositoryMock) + getPlanetUseCase = GetPlanetUseCase(characterDetailsRepositoryMock) } @Test @@ -30,7 +30,7 @@ internal class GetStarWarsCharacterPlanetUseCaseTest { val characterId = "https://swapi.py4e.com/api/people/3/" //When - getStarWarsCharacterPlanetUseCase(characterId) + getPlanetUseCase(characterId) //Then verify(characterDetailsRepositoryMock).getCharacterPlanet(characterId) diff --git a/domain/src/test/kotlin/com/k0d4black/theforce/domain/usecase/GetStarWarsCharacterSpeciesUseCaseTest.kt b/domain/src/test/kotlin/com/k0d4black/theforce/domain/usecase/GetSpecieUseCaseTest.kt similarity index 67% rename from domain/src/test/kotlin/com/k0d4black/theforce/domain/usecase/GetStarWarsCharacterSpeciesUseCaseTest.kt rename to domain/src/test/kotlin/com/k0d4black/theforce/domain/usecase/GetSpecieUseCaseTest.kt index b0970b83..35da1baa 100644 --- a/domain/src/test/kotlin/com/k0d4black/theforce/domain/usecase/GetStarWarsCharacterSpeciesUseCaseTest.kt +++ b/domain/src/test/kotlin/com/k0d4black/theforce/domain/usecase/GetSpecieUseCaseTest.kt @@ -1,7 +1,7 @@ package com.k0d4black.theforce.domain.usecase import com.k0d4black.theforce.domain.repository.ICharacterDetailsRepository -import com.k0d4black.theforce.domain.usecases.GetStarWarsCharacterSpeciesUseCase +import com.k0d4black.theforce.domain.usecases.GetSpeciesUseCase import kotlinx.coroutines.runBlocking import org.junit.Before import org.junit.Test @@ -11,15 +11,15 @@ import org.mockito.Mockito.verify import org.mockito.junit.MockitoJUnitRunner @RunWith(MockitoJUnitRunner::class) -internal class GetStarWarsCharacterSpeciesUseCaseTest { +internal class GetSpecieUseCaseTest { @Mock private lateinit var characterDetailsRepositoryMock: ICharacterDetailsRepository - private lateinit var getStarWarsCharacterSpeciesUseCase: GetStarWarsCharacterSpeciesUseCase + private lateinit var getSpeciesUseCase: GetSpeciesUseCase @Before fun setup() { - getStarWarsCharacterSpeciesUseCase = GetStarWarsCharacterSpeciesUseCase(characterDetailsRepositoryMock) + getSpeciesUseCase = GetSpeciesUseCase(characterDetailsRepositoryMock) } @Test @@ -29,7 +29,7 @@ internal class GetStarWarsCharacterSpeciesUseCaseTest { val characterId = "https://swapi.py4e.com/api/people/3/" //When - getStarWarsCharacterSpeciesUseCase(characterId) + getSpeciesUseCase(characterId) //Then verify(characterDetailsRepositoryMock).getCharacterSpecies(characterId) diff --git a/domain/src/test/kotlin/com/k0d4black/theforce/domain/usecase/SearchStarWarsCharacterUseCaseTest.kt b/domain/src/test/kotlin/com/k0d4black/theforce/domain/usecase/SearchCharactersUseCaseTest.kt similarity index 67% rename from domain/src/test/kotlin/com/k0d4black/theforce/domain/usecase/SearchStarWarsCharacterUseCaseTest.kt rename to domain/src/test/kotlin/com/k0d4black/theforce/domain/usecase/SearchCharactersUseCaseTest.kt index e04a234a..87904ab0 100644 --- a/domain/src/test/kotlin/com/k0d4black/theforce/domain/usecase/SearchStarWarsCharacterUseCaseTest.kt +++ b/domain/src/test/kotlin/com/k0d4black/theforce/domain/usecase/SearchCharactersUseCaseTest.kt @@ -2,7 +2,7 @@ package com.k0d4black.theforce.domain.usecase import com.k0d4black.theforce.domain.repository.ICharacterSearchRepository -import com.k0d4black.theforce.domain.usecases.SearchStarWarsCharacterUseCase +import com.k0d4black.theforce.domain.usecases.SearchCharactersUseCase import kotlinx.coroutines.runBlocking import org.junit.Before import org.junit.Test @@ -12,16 +12,16 @@ import org.mockito.Mockito.verify import org.mockito.junit.MockitoJUnitRunner @RunWith(MockitoJUnitRunner::class) -internal class SearchStarWarsCharacterUseCaseTest { +internal class SearchCharactersUseCaseTest { @Mock private lateinit var searchRepositoryMock: ICharacterSearchRepository - private lateinit var searchStarWarsCharacterUseCase: SearchStarWarsCharacterUseCase + private lateinit var searchCharactersUseCase: SearchCharactersUseCase @Before fun setup() { - searchStarWarsCharacterUseCase = SearchStarWarsCharacterUseCase(searchRepositoryMock) + searchCharactersUseCase = SearchCharactersUseCase(searchRepositoryMock) } @Test @@ -31,7 +31,7 @@ internal class SearchStarWarsCharacterUseCaseTest { val searchParameter = "Luke" //When - searchStarWarsCharacterUseCase(searchParameter) + searchCharactersUseCase(searchParameter) //Then verify(searchRepositoryMock).searchCharacters(searchParameter)