Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ interface NovelApi {
suspend fun getFilteredNovelResult(
@Query("genres") genres: List<String>?,
@Query("isCompleted") isCompleted: Boolean?,
@Query("novelRating") novelRating: Float?,
@Query("novelRatingStart") novelRatingStart: Float,
@Query("novelRatingEnd") novelRatingEnd: Float,
@Query("keywordIds") keywordIds: List<Int>?,
@Query("page") page: Int,
@Query("size") size: Int,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,15 +77,17 @@ class NovelRepository
suspend fun fetchFilteredNovelResult(
genres: List<String>?,
isCompleted: Boolean?,
novelRating: Float?,
novelRatingStart: Float,
novelRatingEnd: Float,
keywordIds: List<Int>?,
page: Int,
size: Int,
): ExploreResultEntity {
val result = novelApi.getFilteredNovelResult(
genres = genres,
isCompleted = isCompleted,
novelRating = novelRating,
novelRatingStart = novelRatingStart,
novelRatingEnd = novelRatingEnd,
keywordIds = keywordIds,
page = page,
size = size,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,20 @@ class GetDetailExploreResultUseCase
) {
private var previousGenres: List<String>? = null
private var previousIsCompleted: Boolean? = null
private var previousNovelRating: Float? = null
private var previousNovelRatingStart: Float = RATING_MIN_DEFAULT
private var previousNovelRatingEnd: Float = RATING_MAX_DEFAULT
private var previousKeywordIds: List<Int>? = null
private var previousPage: Int = INITIAL_PAGE

suspend operator fun invoke(
genres: List<String>?,
isCompleted: Boolean?,
novelRating: Float?,
novelRatingStart: Float,
novelRatingEnd: Float,
keywordIds: List<Int>?,
isSearchButtonClick: Boolean,
): ExploreResult {
if (isSearchButtonClick && isCacheValid(genres, isCompleted, novelRating, keywordIds)) {
if (isSearchButtonClick && isCacheValid(genres, isCompleted, novelRatingStart, novelRatingEnd, keywordIds)) {
return ExploreResultEntity(
resultCount = novelRepository.cachedNormalExploreResult.size.toLong(),
isLoadable = novelRepository.cachedDetailExploreIsLoadable,
Expand All @@ -45,33 +47,39 @@ class GetDetailExploreResultUseCase
.fetchFilteredNovelResult(
genres = genres,
isCompleted = isCompleted,
novelRating = novelRating,
novelRatingStart = novelRatingStart,
novelRatingEnd = novelRatingEnd,
keywordIds = keywordIds,
page = previousPage,
size = REQUEST_SIZE,
).toDomain()
.also {
previousGenres = genres
previousIsCompleted = isCompleted
previousNovelRating = novelRating
previousNovelRatingStart = novelRatingStart
previousNovelRatingEnd = novelRatingEnd
previousKeywordIds = keywordIds
}
}

private fun isCacheValid(
genres: List<String>?,
isCompleted: Boolean?,
novelRating: Float?,
novelRatingStart: Float,
novelRatingEnd: Float,
keywordIds: List<Int>?,
): Boolean =
genres?.equals(previousGenres) == true &&
isCompleted == previousIsCompleted &&
novelRating == previousNovelRating &&
novelRatingStart == previousNovelRatingStart &&
novelRatingEnd == previousNovelRatingEnd &&
keywordIds?.equals(previousKeywordIds) == true

companion object {
private const val INITIAL_PAGE = 0
private const val ADDITIONAL_PAGE_SIZE = 1
private const val REQUEST_SIZE = 30
private const val RATING_MIN_DEFAULT = 0.0f
private const val RATING_MAX_DEFAULT = 5.0f
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,10 @@ class DetailExploreActivity : AppCompatActivity() {
private fun navigateToSearchResult() {
val selectedGenres = detailExploreViewModel.selectedGenres.value ?: emptyList()
val isCompleted = detailExploreViewModel.selectedStatus.value?.isCompleted
val novelRating = detailExploreViewModel.selectedRating.value
val novelRatingStart = detailExploreViewModel.selectedRatingMin.value
?: DetailExploreViewModel.RATING_MIN
val novelRatingEnd = detailExploreViewModel.selectedRatingMax.value
?: DetailExploreViewModel.RATING_MAX

val keywordIds = detailExploreViewModel.uiState.value
?.categories
Expand All @@ -54,7 +57,8 @@ class DetailExploreActivity : AppCompatActivity() {
detailExploreFilteredModel = DetailExploreFilteredModel(
genres = selectedGenres,
isCompleted = isCompleted,
novelRating = novelRating,
novelRatingStart = novelRatingStart,
novelRatingEnd = novelRatingEnd,
keywordIds = keywordIds,
),
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,10 @@ class DetailExploreViewModel
private val _selectedStatus: MutableLiveData<SeriesStatus?> = MutableLiveData()
val selectedStatus: LiveData<SeriesStatus?> get() = _selectedStatus

private val _selectedRatingMin: MutableLiveData<Float> = MutableLiveData(RATING_MIN)
val selectedRatingMin: LiveData<Float> get() = _selectedRatingMin

private val _selectedRatingMax: MutableLiveData<Float> = MutableLiveData(RATING_MAX)
val selectedRatingMax: LiveData<Float> get() = _selectedRatingMax

val selectedRating: LiveData<Float?> = _selectedRatingMin.map { min ->
if (min > RATING_MIN) min else null
}
private val selectedRatingRange: MutableLiveData<RatingRange> =
MutableLiveData(RatingRange(RATING_MIN, RATING_MAX))
val selectedRatingMin: LiveData<Float> = selectedRatingRange.map { it.min }
val selectedRatingMax: LiveData<Float> = selectedRatingRange.map { it.max }

private val _isInfoChipSelected: MediatorLiveData<Boolean> = MediatorLiveData(false)
val isInfoChipSelected: LiveData<Boolean> get() = _isInfoChipSelected
Expand All @@ -56,10 +51,7 @@ class DetailExploreViewModel
_isInfoChipSelected.addSource(_selectedStatus) {
_isInfoChipSelected.value = isInfoChipSelectedEnabled()
}
_isInfoChipSelected.addSource(_selectedRatingMin) {
_isInfoChipSelected.value = isInfoChipSelectedEnabled()
}
_isInfoChipSelected.addSource(_selectedRatingMax) {
_isInfoChipSelected.addSource(selectedRatingRange) {
_isInfoChipSelected.value = isInfoChipSelectedEnabled()
}

Expand All @@ -69,18 +61,16 @@ class DetailExploreViewModel
private fun isInfoChipSelectedEnabled(): Boolean {
val isGenreChipSelected: Boolean = _selectedGenres.value?.isNotEmpty() == true
val isStatusChipSelected: Boolean = _selectedStatus.value != null
val isRatingRangeNarrowed: Boolean =
(_selectedRatingMin.value ?: RATING_MIN) > RATING_MIN ||
(_selectedRatingMax.value ?: RATING_MAX) < RATING_MAX
val range = selectedRatingRange.value ?: RatingRange(RATING_MIN, RATING_MAX)
val isRatingRangeNarrowed: Boolean = range.min > RATING_MIN || range.max < RATING_MAX

return isGenreChipSelected || isStatusChipSelected || isRatingRangeNarrowed
}

fun updateSelectedInfoValueClear() {
_selectedGenres.value = mutableListOf()
_selectedStatus.value = null
_selectedRatingMin.value = RATING_MIN
_selectedRatingMax.value = RATING_MAX
selectedRatingRange.value = RatingRange(RATING_MIN, RATING_MAX)
}

fun updateSelectedGenres(genre: Genre) {
Expand All @@ -107,8 +97,7 @@ class DetailExploreViewModel
min: Float,
max: Float,
) {
_selectedRatingMin.value = min
_selectedRatingMax.value = max
selectedRatingRange.value = RatingRange(min, max)
}

fun updateKeyword(searchWord: String?) {
Expand Down Expand Up @@ -204,6 +193,11 @@ class DetailExploreViewModel
}
}

private data class RatingRange(
val min: Float,
val max: Float,
)

companion object {
const val RATING_MIN = 0.0f
const val RATING_MAX = 5.0f
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
Expand Down Expand Up @@ -78,7 +78,6 @@ fun DetailExploreInfoTab(
max = ratingMax,
onRangeChange = viewModel::updateSelectedRatingRange,
)
Spacer(modifier = Modifier.height(8.dp))
}
}

Expand Down Expand Up @@ -117,6 +116,10 @@ private fun GenreSection(
label = genre.titleKr,
isSelected = selectedGenres.contains(genre),
onClick = { onGenreClick(genre) },
modifier = Modifier.size(
width = genre.figmaWidthDp.dp,
height = 37.dp,
),
)
}
}
Expand Down Expand Up @@ -166,17 +169,19 @@ private fun StatusChipCell(
label = label,
isSelected = selectedStatus == status,
onClick = { onClick(status) },
modifier = modifier.wrapContentHeight(),
modifier = modifier.aspectRatio(STATUS_CHIP_ASPECT_RATIO),
)
}

private const val STATUS_CHIP_ASPECT_RATIO = 155f / 43f

@Composable
private fun RatingSection(
min: Float,
max: Float,
onRangeChange: (Float, Float) -> Unit,
) {
Column {
Column(verticalArrangement = Arrangement.spacedBy(6.dp)) {
Row(
modifier = Modifier
.fillMaxWidth()
Expand All @@ -196,7 +201,6 @@ private fun RatingSection(
color = Primary100,
)
}
Spacer(modifier = Modifier.height(6.dp))
Row(
modifier = Modifier
.fillMaxWidth()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,17 @@ package com.into.websoso.ui.detailExplore.info.model
enum class Genre(
val titleKr: String,
val titleEn: String,
val figmaWidthDp: Int,
) {
ROMANCE("둜맨슀", "romance"),
ROMANCE_FANTASY("둜판", "romanceFantasy"),
FANTASY("νŒνƒ€μ§€", "fantasy"),
MODERN_FANTASY("ν˜„νŒ", "modernFantasy"),
WUXIA("λ¬΄ν˜‘", "wuxia"),
MYSTERY("λ―ΈμŠ€ν„°λ¦¬", "mystery"),
DRAMA("λ“œλΌλ§ˆ", "drama"),
LIGHT_NOVEL("라노벨", "lightNovel"),
BOYS_LOVE("BL", "bl"),
ROMANCE("둜맨슀", "romance", 64),
ROMANCE_FANTASY("둜판", "romanceFantasy", 52),
FANTASY("νŒνƒ€μ§€", "fantasy", 64),
MODERN_FANTASY("ν˜„νŒ", "modernFantasy", 52),
WUXIA("λ¬΄ν˜‘", "wuxia", 52),
MYSTERY("λ―ΈμŠ€ν„°λ¦¬", "mystery", 77),
DRAMA("λ“œλΌλ§ˆ", "drama", 64),
LIGHT_NOVEL("라노벨", "lightNovel", 64),
BOYS_LOVE("BL", "bl", 43),
;

companion object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ class DetailExploreResultViewModel

private val filterGenres: MutableLiveData<List<Genre>?> = MutableLiveData(emptyList())
private val filterIsNovelCompleted: MutableLiveData<Boolean?> = MutableLiveData()
private val filterRating: MutableLiveData<Float?> = MutableLiveData()
private val filterRatingStart: MutableLiveData<Float> = MutableLiveData(DetailExploreFilteredModel.RATING_MIN_DEFAULT)
private val filterRatingEnd: MutableLiveData<Float> = MutableLiveData(DetailExploreFilteredModel.RATING_MAX_DEFAULT)
private val filterKeywordIds: MutableLiveData<List<Int>?> = MutableLiveData(emptyList())

private val _appliedFiltersMessage: MediatorLiveData<String?> = MediatorLiveData()
Expand All @@ -39,7 +40,8 @@ class DetailExploreResultViewModel
_appliedFiltersMessage.apply {
addSource(filterGenres) { updateMessage() }
addSource(filterIsNovelCompleted) { updateMessage() }
addSource(filterRating) { updateMessage() }
addSource(filterRatingStart) { updateMessage() }
addSource(filterRatingEnd) { updateMessage() }
addSource(filterKeywordIds) { updateMessage() }
}
}
Expand All @@ -49,7 +51,7 @@ class DetailExploreResultViewModel

if (filterGenres.value?.isNotEmpty() == true) appliedFilters.add(GENRES_LABEL)
if (filterIsNovelCompleted.value != null) appliedFilters.add(NOVEL_COMPLETED_LABEL)
if (filterRating.value != null) appliedFilters.add(RATING_LABEL)
appliedFilters.add(RATING_LABEL)
if (filterKeywordIds.value?.isNotEmpty() == true) appliedFilters.add(KEYWORDS_LABEL)

_appliedFiltersMessage.value = appliedFilters.joinToString(FILTER_SEPARATOR)
Expand All @@ -58,7 +60,8 @@ class DetailExploreResultViewModel
fun updatePreviousSearchFilteredValue(detailExploreFilteredModel: DetailExploreFilteredModel) {
filterGenres.value = detailExploreFilteredModel.genres
filterIsNovelCompleted.value = detailExploreFilteredModel.isCompleted
filterRating.value = detailExploreFilteredModel.novelRating
filterRatingStart.value = detailExploreFilteredModel.novelRatingStart
filterRatingEnd.value = detailExploreFilteredModel.novelRatingEnd
filterKeywordIds.value = detailExploreFilteredModel.keywordIds

updateSearchResult(true)
Expand All @@ -72,7 +75,8 @@ class DetailExploreResultViewModel
getDetailExploreResultUseCase(
genres = filterGenres.value?.map { it.titleEn },
isCompleted = filterIsNovelCompleted.value,
novelRating = filterRating.value,
novelRatingStart = filterRatingStart.value ?: DetailExploreFilteredModel.RATING_MIN_DEFAULT,
novelRatingEnd = filterRatingEnd.value ?: DetailExploreFilteredModel.RATING_MAX_DEFAULT,
keywordIds = filterKeywordIds.value,
isSearchButtonClick = isSearchButtonClick,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ import kotlinx.parcelize.Parcelize
data class DetailExploreFilteredModel(
val genres: List<Genre>? = null,
val isCompleted: Boolean? = null,
val novelRating: Float? = null,
val novelRatingStart: Float = RATING_MIN_DEFAULT,
val novelRatingEnd: Float = RATING_MAX_DEFAULT,
val keywordIds: List<Int>? = null,
) : Parcelable
) : Parcelable {
companion object {
const val RATING_MIN_DEFAULT = 0.0f
const val RATING_MAX_DEFAULT = 5.0f
}
}
26 changes: 12 additions & 14 deletions app/src/main/res/layout/fragment_home.xml
Original file line number Diff line number Diff line change
Expand Up @@ -100,23 +100,10 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/cl_home_normal_search">

<ImageView
android:layout_width="82dp"
android:layout_height="82dp"
android:layout_marginTop="14dp"
android:alpha="0.08"
android:contentDescription="@null"
android:rotation="12"
android:src="@drawable/ic_explore_genre_first"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.59"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<ImageView
android:layout_width="132dp"
android:layout_height="88dp"
android:layout_marginTop="8dp"
android:layout_marginTop="28dp"
android:contentDescription="@null"
android:src="@drawable/img_home_detail_search"
app:layout_constraintEnd_toEndOf="parent"
Expand All @@ -134,6 +121,17 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<ImageView
android:id="@+id/iv_home_detail_search_navigate"
android:layout_width="24dp"
android:layout_height="24dp"
android:contentDescription="@null"
android:src="@drawable/ic_navigate_right"
app:layout_constraintBottom_toBottomOf="@id/tv_home_detail_search_title"
app:layout_constraintStart_toEndOf="@id/tv_home_detail_search_title"
app:layout_constraintTop_toTopOf="@id/tv_home_detail_search_title"
app:tint="@color/black" />

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
Expand Down
Loading
Loading