Skip to content

Commit

Permalink
fix: use new user settings for search (#1024)
Browse files Browse the repository at this point in the history
* feat: use the new settings for search as well

Show the user chosen image quality, and user chosen titles for the search results.

* test: update tests

* test: fix search object creation in tests

* test: fix another failure model creation in tests

* style: ktlint fixes
  • Loading branch information
Chesire committed Jun 24, 2023
1 parent 2485530 commit 8308f60
Show file tree
Hide file tree
Showing 15 changed files with 200 additions and 98 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.chesire.nekome.helpers.creation
import com.chesire.nekome.core.flags.SeriesType
import com.chesire.nekome.core.flags.Subtype
import com.chesire.nekome.core.models.ImageModel
import com.chesire.nekome.core.preferences.flags.TitleLanguage
import com.chesire.nekome.datasource.search.SearchDomain

/**
Expand All @@ -14,13 +15,18 @@ fun createSearchDomain(
type: SeriesType = SeriesType.Anime,
synopsis: String = "synopsis",
canonicalTitle: String = "canonicalTitle",
titles: Map<String, String> = mapOf(
TitleLanguage.English.key to "enTitle",
TitleLanguage.Japanese.key to "japaneseTitle"
),
subtype: Subtype = Subtype.TV,
posterImage: ImageModel = ImageModel.empty
) = SearchDomain(
id,
type,
synopsis,
canonicalTitle,
titles,
subtype,
posterImage
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package com.chesire.nekome.app.search.host.ui

import com.chesire.nekome.core.models.ImageModel
import com.chesire.nekome.core.preferences.SeriesPreferences
import com.chesire.nekome.core.preferences.flags.ImageQuality
import com.chesire.nekome.core.preferences.flags.TitleLanguage
import com.chesire.nekome.datasource.search.SearchDomain
import javax.inject.Inject
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking

class DomainMapper @Inject constructor(
private val seriesPreferences: SeriesPreferences
) {

fun toResultModels(models: List<SearchDomain>, currentSeriesIds: List<Int>): List<ResultModel> {
return models.map { model ->
ResultModel(
id = model.id,
type = model.type,
synopsis = model.synopsis,
title = chooseTitle(model),
subtype = model.subtype.name,
posterImage = choosePosterImageUrl(model.posterImage),
canTrack = !currentSeriesIds.contains(model.id),
isTracking = false
)
}
}

private fun chooseTitle(series: SearchDomain): String {
val titleLanguage = runBlocking {
seriesPreferences.titleLanguage.first()
}

return when (titleLanguage) {
TitleLanguage.Canonical -> series.canonicalTitle
else -> series.otherTitles[titleLanguage.key]
.takeIf { !it.isNullOrBlank() }
?: series.canonicalTitle
}
}

private fun choosePosterImageUrl(imageModel: ImageModel): String {
val imageQuality = runBlocking {
seriesPreferences.imageQuality.first()
}

return when (imageQuality) {
ImageQuality.Low -> imageModel.smallest?.url
ImageQuality.Medium -> imageModel.middlest?.url
ImageQuality.High -> imageModel.largest?.url
} ?: ""
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ import com.chesire.nekome.app.search.R
import com.chesire.nekome.app.search.host.core.model.SearchGroup
import com.chesire.nekome.core.compose.theme.NekomeTheme
import com.chesire.nekome.core.flags.SeriesType
import com.chesire.nekome.core.models.ImageModel

@Composable
fun HostScreen(viewModel: HostViewModel = hiltViewModel()) {
Expand Down Expand Up @@ -254,7 +253,7 @@ private fun ResultItem(model: ResultModel, onSeriesTrack: (ResultModel) -> Unit)
}
Row(modifier = Modifier.fillMaxSize()) {
AsyncImage(
model = model.posterImage.smallest?.url,
model = model.posterImage,
placeholder = rememberVectorPainter(image = Icons.Default.InsertPhoto),
error = rememberVectorPainter(image = Icons.Default.BrokenImage),
contentDescription = null,
Expand All @@ -269,7 +268,7 @@ private fun ResultItem(model: ResultModel, onSeriesTrack: (ResultModel) -> Unit)
.fillMaxHeight()
) {
Text(
text = model.canonicalTitle,
text = model.title,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
style = MaterialTheme.typography.bodyLarge,
Expand Down Expand Up @@ -346,61 +345,19 @@ private fun PopulatedPreview() {
id = 0,
type = SeriesType.Anime,
synopsis = "This is a synopsis",
canonicalTitle = "This is the title",
title = "This is the title",
subtype = "Oneshot",
posterImage = ImageModel(
tiny = ImageModel.ImageData(
url = "",
width = 0,
height = 0
),
small = ImageModel.ImageData(
url = "",
width = 0,
height = 0
),
medium = ImageModel.ImageData(
url = "",
width = 0,
height = 0
),
large = ImageModel.ImageData(
url = "",
width = 0,
height = 0
)
),
posterImage = "",
canTrack = true,
isTracking = false
),
ResultModel(
id = 1,
type = SeriesType.Anime,
synopsis = "This is another synopsis",
canonicalTitle = "This is the title again",
title = "This is the title again",
subtype = "Oneshot",
posterImage = ImageModel(
tiny = ImageModel.ImageData(
url = "",
width = 0,
height = 0
),
small = ImageModel.ImageData(
url = "",
width = 0,
height = 0
),
medium = ImageModel.ImageData(
url = "",
width = 0,
height = 0
),
large = ImageModel.ImageData(
url = "",
width = 0,
height = 0
)
),
posterImage = "",
canTrack = false,
isTracking = true
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import com.chesire.nekome.app.search.host.core.SearchFailureReason
import com.chesire.nekome.app.search.host.core.SearchSeriesUseCase
import com.chesire.nekome.app.search.host.core.TrackSeriesUseCase
import com.chesire.nekome.app.search.host.core.model.SearchGroup
import com.chesire.nekome.datasource.search.SearchDomain
import com.github.michaelbull.result.onFailure
import com.github.michaelbull.result.onSuccess
import dagger.hilt.android.lifecycle.HiltViewModel
Expand All @@ -28,7 +27,8 @@ class HostViewModel @Inject constructor(
private val retrieveUserSeriesIds: RetrieveUserSeriesIdsUseCase,
private val rememberSearchGroup: RememberSearchGroupUseCase,
private val searchSeries: SearchSeriesUseCase,
private val trackSeries: TrackSeriesUseCase
private val trackSeries: TrackSeriesUseCase,
private val mapper: DomainMapper
) : ViewModel() {

private val _uiState = MutableStateFlow(UIState.Default)
Expand Down Expand Up @@ -86,7 +86,7 @@ class HostViewModel @Inject constructor(
.onSuccess {
state = state.copy(
isSearching = false,
resultModels = it.toResultModels(retrieveUserSeriesIds().first())
resultModels = mapper.toResultModels(it, retrieveUserSeriesIds().first())
)
}
.onFailure(::handleSearchFailure)
Expand All @@ -100,10 +100,12 @@ class HostViewModel @Inject constructor(
isSearchTextError = true,
errorSnackbar = SnackbarData(R.string.search_error_no_text)
)

SearchFailureReason.NetworkError -> state.copy(
isSearching = false,
errorSnackbar = SnackbarData(R.string.error_generic)
)

SearchFailureReason.NoSeriesFound -> state.copy(
isSearching = false,
errorSnackbar = SnackbarData(R.string.search_error_no_series_found)
Expand Down Expand Up @@ -138,7 +140,7 @@ class HostViewModel @Inject constructor(
),
errorSnackbar = SnackbarData(
R.string.results_failure,
model.canonicalTitle
model.title
)
)
}
Expand All @@ -165,19 +167,4 @@ class HostViewModel @Inject constructor(
private fun handleErrorSnackbarObserved() {
state = state.copy(errorSnackbar = null)
}

private fun List<SearchDomain>.toResultModels(currentSeriesIds: List<Int>): List<ResultModel> {
return map {
ResultModel(
id = it.id,
type = it.type,
synopsis = it.synopsis,
canonicalTitle = it.canonicalTitle,
subtype = it.subtype.name,
posterImage = it.posterImage,
canTrack = !currentSeriesIds.contains(it.id),
isTracking = false
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package com.chesire.nekome.app.search.host.ui
import androidx.annotation.StringRes
import com.chesire.nekome.app.search.host.core.model.SearchGroup
import com.chesire.nekome.core.flags.SeriesType
import com.chesire.nekome.core.models.ImageModel

data class UIState(
val searchText: String,
Expand All @@ -30,9 +29,9 @@ data class ResultModel(
val id: Int,
val type: SeriesType,
val synopsis: String,
val canonicalTitle: String,
val title: String,
val subtype: String,
val posterImage: ImageModel,
val posterImage: String,
val canTrack: Boolean,
val isTracking: Boolean
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ class SearchSeriesUseCaseTest {
type = SeriesType.Manga,
synopsis = "",
canonicalTitle = "",
otherTitles = mapOf("en" to "en"),
subtype = Subtype.Manga,
posterImage = ImageModel(
tiny = ImageModel.ImageData(
Expand Down Expand Up @@ -122,6 +123,7 @@ class SearchSeriesUseCaseTest {
type = SeriesType.Manga,
synopsis = "",
canonicalTitle = "",
otherTitles = mapOf("en" to "en"),
subtype = Subtype.Manga,
posterImage = ImageModel(
tiny = ImageModel.ImageData(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package com.chesire.nekome.app.search.host.ui

import com.chesire.nekome.core.flags.SeriesType
import com.chesire.nekome.core.flags.Subtype
import com.chesire.nekome.core.models.ImageModel
import com.chesire.nekome.core.preferences.SeriesPreferences
import com.chesire.nekome.core.preferences.flags.ImageQuality
import com.chesire.nekome.core.preferences.flags.TitleLanguage
import com.chesire.nekome.datasource.search.SearchDomain
import io.mockk.clearAllMocks
import io.mockk.every
import io.mockk.mockk
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Test

class DomainMapperTest {

private val seriesPreferences = mockk<SeriesPreferences>()
private lateinit var mapper: DomainMapper
private val initialDomain = SearchDomain(
id = 0,
type = SeriesType.Anime,
synopsis = "Synopsis",
canonicalTitle = "canonicalTitle",
otherTitles = mapOf(
TitleLanguage.English.key to "en",
TitleLanguage.Japanese.key to "jp"
),
subtype = Subtype.Movie,
posterImage = ImageModel(
tiny = ImageModel.ImageData(
url = "tiny",
width = 0,
height = 0
),
small = ImageModel.ImageData(
url = "small",
width = 0,
height = 0
),
medium = ImageModel.ImageData(
url = "medium",
width = 0,
height = 0
),
large = ImageModel.ImageData(
url = "large",
width = 0,
height = 0
)
)
)

@Before
fun setup() {
clearAllMocks()

every { seriesPreferences.imageQuality } returns flowOf(ImageQuality.Medium)
every { seriesPreferences.titleLanguage } returns flowOf(TitleLanguage.Canonical)
mapper = DomainMapper(seriesPreferences)
}

@Test
fun `When toResultModels, Then list of ResultModel item is returned`() = runTest {
val input = listOf(initialDomain)
val expected = listOf(
ResultModel(
id = 0,
type = SeriesType.Anime,
synopsis = "Synopsis",
title = "canonicalTitle",
subtype = Subtype.Movie.name,
posterImage = "medium",
canTrack = true,
isTracking = false
)
)

val result = mapper.toResultModels(input, emptyList())

assertEquals(expected, result)
}

@Test
fun `Given user already tracks ID, When toResultModels, Then canTrack is false`() = runTest {
val input = listOf(initialDomain)
val expected = listOf(
ResultModel(
id = 0,
type = SeriesType.Anime,
synopsis = "Synopsis",
title = "canonicalTitle",
subtype = Subtype.Movie.name,
posterImage = "medium",
canTrack = false,
isTracking = false
)
)

val result = mapper.toResultModels(input, listOf(0))

assertEquals(expected, result)
}
}
Loading

0 comments on commit 8308f60

Please sign in to comment.