Add random sort option

This commit is contained in:
Jack Hamilton 2024-10-10 23:50:23 -05:00
parent c8bb78d91a
commit 0ab795bfa3
5 changed files with 78 additions and 25 deletions

View File

@ -6,6 +6,8 @@ import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Refresh
import androidx.compose.material3.FilterChip import androidx.compose.material3.FilterChip
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@ -29,6 +31,7 @@ import tachiyomi.domain.library.service.LibraryPreferences
import tachiyomi.i18n.MR import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.CheckboxItem import tachiyomi.presentation.core.components.CheckboxItem
import tachiyomi.presentation.core.components.HeadingItem import tachiyomi.presentation.core.components.HeadingItem
import tachiyomi.presentation.core.components.NondirectionalSortItem
import tachiyomi.presentation.core.components.SettingsChipRow import tachiyomi.presentation.core.components.SettingsChipRow
import tachiyomi.presentation.core.components.SliderItem import tachiyomi.presentation.core.components.SliderItem
import tachiyomi.presentation.core.components.SortItem import tachiyomi.presentation.core.components.SortItem
@ -178,27 +181,42 @@ private fun ColumnScope.SortPage(
MR.strings.action_sort_latest_chapter to LibrarySort.Type.LatestChapter, MR.strings.action_sort_latest_chapter to LibrarySort.Type.LatestChapter,
MR.strings.action_sort_chapter_fetch_date to LibrarySort.Type.ChapterFetchDate, MR.strings.action_sort_chapter_fetch_date to LibrarySort.Type.ChapterFetchDate,
MR.strings.action_sort_date_added to LibrarySort.Type.DateAdded, MR.strings.action_sort_date_added to LibrarySort.Type.DateAdded,
MR.strings.action_sort_random to LibrarySort.Type.Random,
).plus(trackerSortOption).map { (titleRes, mode) -> ).plus(trackerSortOption).map { (titleRes, mode) ->
SortItem( when(mode) {
label = stringResource(titleRes), LibrarySort.Type.Random -> {
sortDescending = sortDescending.takeIf { sortingMode == mode }, NondirectionalSortItem(
onClick = { label = stringResource(titleRes),
val isTogglingDirection = sortingMode == mode enabled = sortingMode == LibrarySort.Type.Random,
val direction = when { enabledIcon = Icons.Default.Refresh,
isTogglingDirection -> if (sortDescending) { onClick = {
LibrarySort.Direction.Ascending screenModel.setSort(category, mode, LibrarySort.Direction.Ascending)
} else { },
LibrarySort.Direction.Descending )
} }
else -> if (sortDescending) { else -> {
LibrarySort.Direction.Descending SortItem(
} else { label = stringResource(titleRes),
LibrarySort.Direction.Ascending sortDescending = sortDescending.takeIf { sortingMode == mode },
} onClick = {
} val isTogglingDirection = sortingMode == mode
screenModel.setSort(category, mode, direction) val direction = when {
}, isTogglingDirection -> if (sortDescending) {
) LibrarySort.Direction.Ascending
} else {
LibrarySort.Direction.Descending
}
else -> if (sortDescending) {
LibrarySort.Direction.Descending
} else {
LibrarySort.Direction.Ascending
}
}
screenModel.setSort(category, mode, direction)
},
)
}
}
} }
} }

View File

@ -267,7 +267,7 @@ class LibraryScreenModel(
fun LibrarySort.comparator(): Comparator<LibraryItem> = Comparator { i1, i2 -> fun LibrarySort.comparator(): Comparator<LibraryItem> = Comparator { i1, i2 ->
when (this.type) { when (this.type) {
LibrarySort.Type.Alphabetical -> { LibrarySort.Type.Alphabetical, LibrarySort.Type.Random -> {
sortAlphabetically(i1, i2) sortAlphabetically(i1, i2)
} }
LibrarySort.Type.LastRead -> { LibrarySort.Type.LastRead -> {
@ -304,11 +304,16 @@ class LibraryScreenModel(
} }
return mapValues { (key, value) -> return mapValues { (key, value) ->
val comparator = key.sort.comparator() when (key.sort.type) {
.let { if (key.sort.isAscending) it else it.reversed() } LibrarySort.Type.Random -> value.shuffled()
.thenComparator(sortAlphabetically) else -> {
val comparator = key.sort.comparator()
.let { if (key.sort.isAscending) it else it.reversed() }
.thenComparator(sortAlphabetically)
value.sortedWith(comparator) value.sortedWith(comparator)
}
}
} }
} }

View File

@ -31,6 +31,7 @@ data class LibrarySort(
data object ChapterFetchDate : Type(0b00011000) data object ChapterFetchDate : Type(0b00011000)
data object DateAdded : Type(0b00011100) data object DateAdded : Type(0b00011100)
data object TrackerMean : Type(0b000100000) data object TrackerMean : Type(0b000100000)
data object Random : Type(0b000100100)
companion object { companion object {
fun valueOf(flag: Long): Type { fun valueOf(flag: Long): Type {
@ -77,6 +78,7 @@ data class LibrarySort(
Type.ChapterFetchDate, Type.ChapterFetchDate,
Type.DateAdded, Type.DateAdded,
Type.TrackerMean, Type.TrackerMean,
Type.Random
) )
} }
val directions by lazy { setOf(Direction.Ascending, Direction.Descending) } val directions by lazy { setOf(Direction.Ascending, Direction.Descending) }
@ -104,6 +106,7 @@ data class LibrarySort(
"CHAPTER_FETCH_DATE" -> Type.ChapterFetchDate "CHAPTER_FETCH_DATE" -> Type.ChapterFetchDate
"DATE_ADDED" -> Type.DateAdded "DATE_ADDED" -> Type.DateAdded
"TRACKER_MEAN" -> Type.TrackerMean "TRACKER_MEAN" -> Type.TrackerMean
"RANDOM" -> Type.Random
else -> Type.Alphabetical else -> Type.Alphabetical
} }
val ascending = if (values[1] == "ASCENDING") Direction.Ascending else Direction.Descending val ascending = if (values[1] == "ASCENDING") Direction.Ascending else Direction.Descending
@ -125,6 +128,7 @@ data class LibrarySort(
Type.ChapterFetchDate -> "CHAPTER_FETCH_DATE" Type.ChapterFetchDate -> "CHAPTER_FETCH_DATE"
Type.DateAdded -> "DATE_ADDED" Type.DateAdded -> "DATE_ADDED"
Type.TrackerMean -> "TRACKER_MEAN" Type.TrackerMean -> "TRACKER_MEAN"
Type.Random -> "RANDOM"
} }
val direction = if (direction == Direction.Ascending) "ASCENDING" else "DESCENDING" val direction = if (direction == Direction.Ascending) "ASCENDING" else "DESCENDING"
return "$type,$direction" return "$type,$direction"

View File

@ -69,6 +69,7 @@
<string name="action_sort_chapter_fetch_date">Chapter fetch date</string> <string name="action_sort_chapter_fetch_date">Chapter fetch date</string>
<string name="action_sort_date_added">Date added</string> <string name="action_sort_date_added">Date added</string>
<string name="action_sort_tracker_score">Tracker score</string> <string name="action_sort_tracker_score">Tracker score</string>
<string name="action_sort_random">Random</string>
<string name="action_search">Search</string> <string name="action_search">Search</string>
<string name="action_search_hint">Search…</string> <string name="action_search_hint">Search…</string>
<string name="action_search_settings">Search settings</string> <string name="action_search_settings">Search settings</string>

View File

@ -17,6 +17,7 @@ import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowDownward import androidx.compose.material.icons.filled.ArrowDownward
import androidx.compose.material.icons.filled.ArrowUpward import androidx.compose.material.icons.filled.ArrowUpward
import androidx.compose.material.icons.filled.Refresh
import androidx.compose.material.icons.rounded.CheckBox import androidx.compose.material.icons.rounded.CheckBox
import androidx.compose.material.icons.rounded.CheckBoxOutlineBlank import androidx.compose.material.icons.rounded.CheckBoxOutlineBlank
import androidx.compose.material.icons.rounded.DisabledByDefault import androidx.compose.material.icons.rounded.DisabledByDefault
@ -115,6 +116,30 @@ fun SortItem(label: String, sortDescending: Boolean?, onClick: () -> Unit) {
) )
} }
@Composable
fun NondirectionalSortItem(label: String, enabled: Boolean, enabledIcon: ImageVector, onClick: () -> Unit) {
val icon = when(enabled) {
true -> enabledIcon
false -> null
}
BaseSettingsItem(
label = label,
widget = {
if (icon != null) {
Icon(
imageVector = icon,
contentDescription = null,
tint = MaterialTheme.colorScheme.primary,
)
} else {
Spacer(modifier = Modifier.size(24.dp))
}
},
onClick = onClick,
)
}
@Composable @Composable
fun CheckboxItem(label: String, pref: Preference<Boolean>) { fun CheckboxItem(label: String, pref: Preference<Boolean>) {
val checked by pref.collectAsState() val checked by pref.collectAsState()