Use immutable collections in more places
This commit is contained in:
parent
dd998be1e7
commit
336221a972
@ -175,6 +175,7 @@ dependencies {
|
|||||||
implementation(libs.bundles.sqlite)
|
implementation(libs.bundles.sqlite)
|
||||||
|
|
||||||
implementation(kotlinx.reflect)
|
implementation(kotlinx.reflect)
|
||||||
|
implementation(kotlinx.immutables)
|
||||||
|
|
||||||
implementation(platform(kotlinx.coroutines.bom))
|
implementation(platform(kotlinx.coroutines.bom))
|
||||||
implementation(kotlinx.bundles.coroutines)
|
implementation(kotlinx.bundles.coroutines)
|
||||||
|
@ -24,6 +24,7 @@ import eu.kanade.presentation.components.AppBar
|
|||||||
import eu.kanade.presentation.util.formattedMessage
|
import eu.kanade.presentation.util.formattedMessage
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.source.Source
|
import eu.kanade.tachiyomi.source.Source
|
||||||
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import tachiyomi.domain.library.model.LibraryDisplayMode
|
import tachiyomi.domain.library.model.LibraryDisplayMode
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
@ -76,7 +77,7 @@ fun BrowseSourceContent(
|
|||||||
modifier = Modifier.padding(contentPadding),
|
modifier = Modifier.padding(contentPadding),
|
||||||
message = getErrorMessage(errorState),
|
message = getErrorMessage(errorState),
|
||||||
actions = if (source is LocalSource) {
|
actions = if (source is LocalSource) {
|
||||||
listOf(
|
persistentListOf(
|
||||||
EmptyScreenAction(
|
EmptyScreenAction(
|
||||||
stringResId = R.string.local_source_help_guide,
|
stringResId = R.string.local_source_help_guide,
|
||||||
icon = Icons.Outlined.HelpOutline,
|
icon = Icons.Outlined.HelpOutline,
|
||||||
@ -84,7 +85,7 @@ fun BrowseSourceContent(
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
listOf(
|
persistentListOf(
|
||||||
EmptyScreenAction(
|
EmptyScreenAction(
|
||||||
stringResId = R.string.action_retry,
|
stringResId = R.string.action_retry,
|
||||||
icon = Icons.Outlined.Refresh,
|
icon = Icons.Outlined.Refresh,
|
||||||
|
@ -94,8 +94,8 @@ fun SourcesScreen(
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun SourceHeader(
|
private fun SourceHeader(
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
language: String,
|
language: String,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
Text(
|
Text(
|
||||||
@ -108,11 +108,11 @@ private fun SourceHeader(
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun SourceItem(
|
private fun SourceItem(
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
source: Source,
|
source: Source,
|
||||||
onClickItem: (Source, Listing) -> Unit,
|
onClickItem: (Source, Listing) -> Unit,
|
||||||
onLongClickItem: (Source) -> Unit,
|
onLongClickItem: (Source) -> Unit,
|
||||||
onClickPin: (Source) -> Unit,
|
onClickPin: (Source) -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
BaseSourceItem(
|
BaseSourceItem(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
|
@ -8,6 +8,7 @@ import androidx.compose.runtime.Composable
|
|||||||
import androidx.compose.ui.tooling.preview.PreviewLightDark
|
import androidx.compose.ui.tooling.preview.PreviewLightDark
|
||||||
import eu.kanade.presentation.theme.TachiyomiTheme
|
import eu.kanade.presentation.theme.TachiyomiTheme
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
import tachiyomi.presentation.core.screens.EmptyScreen
|
import tachiyomi.presentation.core.screens.EmptyScreen
|
||||||
import tachiyomi.presentation.core.screens.EmptyScreenAction
|
import tachiyomi.presentation.core.screens.EmptyScreenAction
|
||||||
|
|
||||||
@ -30,7 +31,7 @@ private fun WithActionPreview() {
|
|||||||
Surface {
|
Surface {
|
||||||
EmptyScreen(
|
EmptyScreen(
|
||||||
textResource = R.string.empty_screen,
|
textResource = R.string.empty_screen,
|
||||||
actions = listOf(
|
actions = persistentListOf(
|
||||||
EmptyScreenAction(
|
EmptyScreenAction(
|
||||||
stringResId = R.string.action_retry,
|
stringResId = R.string.action_retry,
|
||||||
icon = Icons.Outlined.Refresh,
|
icon = Icons.Outlined.Refresh,
|
||||||
|
@ -16,6 +16,7 @@ import androidx.compose.ui.res.stringResource
|
|||||||
import androidx.compose.ui.unit.DpSize
|
import androidx.compose.ui.unit.DpSize
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
import tachiyomi.domain.manga.interactor.FetchInterval
|
import tachiyomi.domain.manga.interactor.FetchInterval
|
||||||
import tachiyomi.presentation.core.components.WheelTextPicker
|
import tachiyomi.presentation.core.components.WheelTextPicker
|
||||||
|
|
||||||
@ -67,13 +68,15 @@ fun SetIntervalDialog(
|
|||||||
contentAlignment = Alignment.Center,
|
contentAlignment = Alignment.Center,
|
||||||
) {
|
) {
|
||||||
val size = DpSize(width = maxWidth / 2, height = 128.dp)
|
val size = DpSize(width = maxWidth / 2, height = 128.dp)
|
||||||
val items = (0..FetchInterval.MAX_INTERVAL).map {
|
val items = (0..FetchInterval.MAX_INTERVAL)
|
||||||
if (it == 0) {
|
.map {
|
||||||
stringResource(R.string.label_default)
|
if (it == 0) {
|
||||||
} else {
|
stringResource(R.string.label_default)
|
||||||
it.toString()
|
} else {
|
||||||
|
it.toString()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
.toImmutableList()
|
||||||
WheelTextPicker(
|
WheelTextPicker(
|
||||||
items = items,
|
items = items,
|
||||||
size = size,
|
size = size,
|
||||||
|
@ -85,12 +85,11 @@ fun PreferenceScreen(
|
|||||||
private fun List<Preference>.findHighlightedIndex(highlightKey: String): Int {
|
private fun List<Preference>.findHighlightedIndex(highlightKey: String): Int {
|
||||||
return flatMap {
|
return flatMap {
|
||||||
if (it is Preference.PreferenceGroup) {
|
if (it is Preference.PreferenceGroup) {
|
||||||
mutableListOf<String?>()
|
buildList<String?> {
|
||||||
.apply {
|
add(null) // Header
|
||||||
add(null) // Header
|
addAll(it.preferenceItems.map { groupItem -> groupItem.title })
|
||||||
addAll(it.preferenceItems.map { groupItem -> groupItem.title })
|
add(null) // Spacer
|
||||||
add(null) // Spacer
|
}
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
listOf(it.title)
|
listOf(it.title)
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,10 @@ import eu.kanade.tachiyomi.data.backup.BackupCreateJob
|
|||||||
import eu.kanade.tachiyomi.data.backup.models.Backup
|
import eu.kanade.tachiyomi.data.backup.models.Backup
|
||||||
import eu.kanade.tachiyomi.util.system.DeviceUtil
|
import eu.kanade.tachiyomi.util.system.DeviceUtil
|
||||||
import eu.kanade.tachiyomi.util.system.toast
|
import eu.kanade.tachiyomi.util.system.toast
|
||||||
|
import kotlinx.collections.immutable.PersistentSet
|
||||||
|
import kotlinx.collections.immutable.minus
|
||||||
|
import kotlinx.collections.immutable.plus
|
||||||
|
import kotlinx.collections.immutable.toPersistentSet
|
||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
import tachiyomi.presentation.core.components.LabeledCheckbox
|
import tachiyomi.presentation.core.components.LabeledCheckbox
|
||||||
import tachiyomi.presentation.core.components.material.Scaffold
|
import tachiyomi.presentation.core.components.material.Scaffold
|
||||||
@ -154,7 +158,7 @@ private class CreateBackupScreenModel : StateScreenModel<CreateBackupScreenModel
|
|||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
data class State(
|
data class State(
|
||||||
val flags: Set<Int> = BackupChoices.keys,
|
val flags: PersistentSet<Int> = BackupChoices.keys.toPersistentSet(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,6 +34,8 @@ import androidx.compose.ui.tooling.preview.PreviewLightDark
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import eu.kanade.presentation.theme.TachiyomiTheme
|
import eu.kanade.presentation.theme.TachiyomiTheme
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
import tachiyomi.presentation.core.components.ScrollbarLazyColumn
|
import tachiyomi.presentation.core.components.ScrollbarLazyColumn
|
||||||
import tachiyomi.presentation.core.components.WheelNumberPicker
|
import tachiyomi.presentation.core.components.WheelNumberPicker
|
||||||
import tachiyomi.presentation.core.components.WheelTextPicker
|
import tachiyomi.presentation.core.components.WheelTextPicker
|
||||||
@ -102,7 +104,7 @@ fun TrackChapterSelector(
|
|||||||
title = stringResource(R.string.chapters),
|
title = stringResource(R.string.chapters),
|
||||||
content = {
|
content = {
|
||||||
WheelNumberPicker(
|
WheelNumberPicker(
|
||||||
items = range.toList(),
|
items = range.toImmutableList(),
|
||||||
modifier = Modifier.align(Alignment.Center),
|
modifier = Modifier.align(Alignment.Center),
|
||||||
startIndex = selection,
|
startIndex = selection,
|
||||||
onSelectionChanged = { onSelectionChange(it) },
|
onSelectionChanged = { onSelectionChange(it) },
|
||||||
@ -117,7 +119,7 @@ fun TrackChapterSelector(
|
|||||||
fun TrackScoreSelector(
|
fun TrackScoreSelector(
|
||||||
selection: String,
|
selection: String,
|
||||||
onSelectionChange: (String) -> Unit,
|
onSelectionChange: (String) -> Unit,
|
||||||
selections: List<String>,
|
selections: ImmutableList<String>,
|
||||||
onConfirm: () -> Unit,
|
onConfirm: () -> Unit,
|
||||||
onDismissRequest: () -> Unit,
|
onDismissRequest: () -> Unit,
|
||||||
) {
|
) {
|
||||||
|
@ -6,6 +6,7 @@ import androidx.annotation.DrawableRes
|
|||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import eu.kanade.tachiyomi.data.database.models.Track
|
import eu.kanade.tachiyomi.data.database.models.Track
|
||||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||||
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
|
|
||||||
interface Tracker {
|
interface Tracker {
|
||||||
@ -36,7 +37,7 @@ interface Tracker {
|
|||||||
|
|
||||||
fun getCompletionStatus(): Int
|
fun getCompletionStatus(): Int
|
||||||
|
|
||||||
fun getScoreList(): List<String>
|
fun getScoreList(): ImmutableList<String>
|
||||||
|
|
||||||
// TODO: Store all scores as 10 point in the future maybe?
|
// TODO: Store all scores as 10 point in the future maybe?
|
||||||
fun get10PointScore(track: tachiyomi.domain.track.model.Track): Double
|
fun get10PointScore(track: tachiyomi.domain.track.model.Track): Double
|
||||||
|
@ -7,6 +7,9 @@ import eu.kanade.tachiyomi.data.database.models.Track
|
|||||||
import eu.kanade.tachiyomi.data.track.BaseTracker
|
import eu.kanade.tachiyomi.data.track.BaseTracker
|
||||||
import eu.kanade.tachiyomi.data.track.DeletableTracker
|
import eu.kanade.tachiyomi.data.track.DeletableTracker
|
||||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||||
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
@ -74,18 +77,18 @@ class Anilist(id: Long) : BaseTracker(id, "AniList"), DeletableTracker {
|
|||||||
|
|
||||||
override fun getCompletionStatus(): Int = COMPLETED
|
override fun getCompletionStatus(): Int = COMPLETED
|
||||||
|
|
||||||
override fun getScoreList(): List<String> {
|
override fun getScoreList(): ImmutableList<String> {
|
||||||
return when (scorePreference.get()) {
|
return when (scorePreference.get()) {
|
||||||
// 10 point
|
// 10 point
|
||||||
POINT_10 -> IntRange(0, 10).map(Int::toString)
|
POINT_10 -> IntRange(0, 10).map(Int::toString).toImmutableList()
|
||||||
// 100 point
|
// 100 point
|
||||||
POINT_100 -> IntRange(0, 100).map(Int::toString)
|
POINT_100 -> IntRange(0, 100).map(Int::toString).toImmutableList()
|
||||||
// 5 stars
|
// 5 stars
|
||||||
POINT_5 -> IntRange(0, 5).map { "$it ★" }
|
POINT_5 -> IntRange(0, 5).map { "$it ★" }.toImmutableList()
|
||||||
// Smiley
|
// Smiley
|
||||||
POINT_3 -> listOf("-", "😦", "😐", "😊")
|
POINT_3 -> persistentListOf("-", "😦", "😐", "😊")
|
||||||
// 10 point decimal
|
// 10 point decimal
|
||||||
POINT_10_DECIMAL -> IntRange(0, 100).map { (it / 10f).toString() }
|
POINT_10_DECIMAL -> IntRange(0, 100).map { (it / 10f).toString() }.toImmutableList()
|
||||||
else -> throw Exception("Unknown score type")
|
else -> throw Exception("Unknown score type")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,8 @@ import eu.kanade.tachiyomi.R
|
|||||||
import eu.kanade.tachiyomi.data.database.models.Track
|
import eu.kanade.tachiyomi.data.database.models.Track
|
||||||
import eu.kanade.tachiyomi.data.track.BaseTracker
|
import eu.kanade.tachiyomi.data.track.BaseTracker
|
||||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||||
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
@ -18,9 +20,7 @@ class Bangumi(id: Long) : BaseTracker(id, "Bangumi") {
|
|||||||
|
|
||||||
private val api by lazy { BangumiApi(id, client, interceptor) }
|
private val api by lazy { BangumiApi(id, client, interceptor) }
|
||||||
|
|
||||||
override fun getScoreList(): List<String> {
|
override fun getScoreList(): ImmutableList<String> = SCORE_LIST
|
||||||
return IntRange(0, 10).map(Int::toString)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun displayScore(track: Track): String {
|
override fun displayScore(track: Track): String {
|
||||||
return track.score.toInt().toString()
|
return track.score.toInt().toString()
|
||||||
@ -141,5 +141,9 @@ class Bangumi(id: Long) : BaseTracker(id, "Bangumi") {
|
|||||||
const val ON_HOLD = 4
|
const val ON_HOLD = 4
|
||||||
const val DROPPED = 5
|
const val DROPPED = 5
|
||||||
const val PLAN_TO_READ = 1
|
const val PLAN_TO_READ = 1
|
||||||
|
|
||||||
|
private val SCORE_LIST = IntRange(0, 10)
|
||||||
|
.map(Int::toString)
|
||||||
|
.toImmutableList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,8 @@ import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
|||||||
import eu.kanade.tachiyomi.source.ConfigurableSource
|
import eu.kanade.tachiyomi.source.ConfigurableSource
|
||||||
import eu.kanade.tachiyomi.source.Source
|
import eu.kanade.tachiyomi.source.Source
|
||||||
import eu.kanade.tachiyomi.source.sourcePreferences
|
import eu.kanade.tachiyomi.source.sourcePreferences
|
||||||
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
import tachiyomi.domain.source.service.SourceManager
|
import tachiyomi.domain.source.service.SourceManager
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
@ -51,7 +53,7 @@ class Kavita(id: Long) : BaseTracker(id, "Kavita"), EnhancedTracker {
|
|||||||
|
|
||||||
override fun getCompletionStatus(): Int = COMPLETED
|
override fun getCompletionStatus(): Int = COMPLETED
|
||||||
|
|
||||||
override fun getScoreList(): List<String> = emptyList()
|
override fun getScoreList(): ImmutableList<String> = persistentListOf()
|
||||||
|
|
||||||
override fun displayScore(track: Track): String = ""
|
override fun displayScore(track: Track): String = ""
|
||||||
|
|
||||||
|
@ -7,6 +7,8 @@ import eu.kanade.tachiyomi.data.database.models.Track
|
|||||||
import eu.kanade.tachiyomi.data.track.BaseTracker
|
import eu.kanade.tachiyomi.data.track.BaseTracker
|
||||||
import eu.kanade.tachiyomi.data.track.DeletableTracker
|
import eu.kanade.tachiyomi.data.track.DeletableTracker
|
||||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||||
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
@ -54,9 +56,9 @@ class Kitsu(id: Long) : BaseTracker(id, "Kitsu"), DeletableTracker {
|
|||||||
|
|
||||||
override fun getCompletionStatus(): Int = COMPLETED
|
override fun getCompletionStatus(): Int = COMPLETED
|
||||||
|
|
||||||
override fun getScoreList(): List<String> {
|
override fun getScoreList(): ImmutableList<String> {
|
||||||
val df = DecimalFormat("0.#")
|
val df = DecimalFormat("0.#")
|
||||||
return listOf("0") + IntRange(2, 20).map { df.format(it / 2f) }
|
return (listOf("0") + IntRange(2, 20).map { df.format(it / 2f) }).toImmutableList()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun indexToScore(index: Int): Float {
|
override fun indexToScore(index: Int): Float {
|
||||||
|
@ -8,6 +8,8 @@ import eu.kanade.tachiyomi.data.track.BaseTracker
|
|||||||
import eu.kanade.tachiyomi.data.track.EnhancedTracker
|
import eu.kanade.tachiyomi.data.track.EnhancedTracker
|
||||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||||
import eu.kanade.tachiyomi.source.Source
|
import eu.kanade.tachiyomi.source.Source
|
||||||
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
import okhttp3.Dns
|
import okhttp3.Dns
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
@ -48,7 +50,7 @@ class Komga(id: Long) : BaseTracker(id, "Komga"), EnhancedTracker {
|
|||||||
|
|
||||||
override fun getCompletionStatus(): Int = COMPLETED
|
override fun getCompletionStatus(): Int = COMPLETED
|
||||||
|
|
||||||
override fun getScoreList(): List<String> = emptyList()
|
override fun getScoreList(): ImmutableList<String> = persistentListOf()
|
||||||
|
|
||||||
override fun displayScore(track: Track): String = ""
|
override fun displayScore(track: Track): String = ""
|
||||||
|
|
||||||
|
@ -9,6 +9,8 @@ import eu.kanade.tachiyomi.data.track.DeletableTracker
|
|||||||
import eu.kanade.tachiyomi.data.track.mangaupdates.dto.copyTo
|
import eu.kanade.tachiyomi.data.track.mangaupdates.dto.copyTo
|
||||||
import eu.kanade.tachiyomi.data.track.mangaupdates.dto.toTrackSearch
|
import eu.kanade.tachiyomi.data.track.mangaupdates.dto.toTrackSearch
|
||||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||||
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
|
|
||||||
class MangaUpdates(id: Long) : BaseTracker(id, "MangaUpdates"), DeletableTracker {
|
class MangaUpdates(id: Long) : BaseTracker(id, "MangaUpdates"), DeletableTracker {
|
||||||
|
|
||||||
@ -18,6 +20,12 @@ class MangaUpdates(id: Long) : BaseTracker(id, "MangaUpdates"), DeletableTracker
|
|||||||
const val COMPLETE_LIST = 2
|
const val COMPLETE_LIST = 2
|
||||||
const val UNFINISHED_LIST = 3
|
const val UNFINISHED_LIST = 3
|
||||||
const val ON_HOLD_LIST = 4
|
const val ON_HOLD_LIST = 4
|
||||||
|
|
||||||
|
private val SCORE_LIST = (
|
||||||
|
(0..9)
|
||||||
|
.flatMap { i -> (0..9).map { j -> "$i.$j" } } + listOf("10.0")
|
||||||
|
)
|
||||||
|
.toImmutableList()
|
||||||
}
|
}
|
||||||
|
|
||||||
private val interceptor by lazy { MangaUpdatesInterceptor(this) }
|
private val interceptor by lazy { MangaUpdatesInterceptor(this) }
|
||||||
@ -48,11 +56,9 @@ class MangaUpdates(id: Long) : BaseTracker(id, "MangaUpdates"), DeletableTracker
|
|||||||
|
|
||||||
override fun getCompletionStatus(): Int = COMPLETE_LIST
|
override fun getCompletionStatus(): Int = COMPLETE_LIST
|
||||||
|
|
||||||
private val _scoreList = (0..9).flatMap { i -> (0..9).map { j -> "$i.$j" } } + listOf("10.0")
|
override fun getScoreList(): ImmutableList<String> = SCORE_LIST
|
||||||
|
|
||||||
override fun getScoreList(): List<String> = _scoreList
|
override fun indexToScore(index: Int): Float = SCORE_LIST[index].toFloat()
|
||||||
|
|
||||||
override fun indexToScore(index: Int): Float = _scoreList[index].toFloat()
|
|
||||||
|
|
||||||
override fun displayScore(track: Track): String = track.score.toString()
|
override fun displayScore(track: Track): String = track.score.toString()
|
||||||
|
|
||||||
|
@ -7,6 +7,8 @@ import eu.kanade.tachiyomi.data.database.models.Track
|
|||||||
import eu.kanade.tachiyomi.data.track.BaseTracker
|
import eu.kanade.tachiyomi.data.track.BaseTracker
|
||||||
import eu.kanade.tachiyomi.data.track.DeletableTracker
|
import eu.kanade.tachiyomi.data.track.DeletableTracker
|
||||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||||
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
@ -23,6 +25,10 @@ class MyAnimeList(id: Long) : BaseTracker(id, "MyAnimeList"), DeletableTracker {
|
|||||||
|
|
||||||
private const val SEARCH_ID_PREFIX = "id:"
|
private const val SEARCH_ID_PREFIX = "id:"
|
||||||
private const val SEARCH_LIST_PREFIX = "my:"
|
private const val SEARCH_LIST_PREFIX = "my:"
|
||||||
|
|
||||||
|
private val SCORE_LIST = IntRange(0, 10)
|
||||||
|
.map(Int::toString)
|
||||||
|
.toImmutableList()
|
||||||
}
|
}
|
||||||
|
|
||||||
private val json: Json by injectLazy()
|
private val json: Json by injectLazy()
|
||||||
@ -57,9 +63,7 @@ class MyAnimeList(id: Long) : BaseTracker(id, "MyAnimeList"), DeletableTracker {
|
|||||||
|
|
||||||
override fun getCompletionStatus(): Int = COMPLETED
|
override fun getCompletionStatus(): Int = COMPLETED
|
||||||
|
|
||||||
override fun getScoreList(): List<String> {
|
override fun getScoreList(): ImmutableList<String> = SCORE_LIST
|
||||||
return IntRange(0, 10).map(Int::toString)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun displayScore(track: Track): String {
|
override fun displayScore(track: Track): String {
|
||||||
return track.score.toInt().toString()
|
return track.score.toInt().toString()
|
||||||
|
@ -7,6 +7,8 @@ import eu.kanade.tachiyomi.data.database.models.Track
|
|||||||
import eu.kanade.tachiyomi.data.track.BaseTracker
|
import eu.kanade.tachiyomi.data.track.BaseTracker
|
||||||
import eu.kanade.tachiyomi.data.track.DeletableTracker
|
import eu.kanade.tachiyomi.data.track.DeletableTracker
|
||||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||||
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
@ -20,6 +22,10 @@ class Shikimori(id: Long) : BaseTracker(id, "Shikimori"), DeletableTracker {
|
|||||||
const val DROPPED = 4
|
const val DROPPED = 4
|
||||||
const val PLAN_TO_READ = 5
|
const val PLAN_TO_READ = 5
|
||||||
const val REREADING = 6
|
const val REREADING = 6
|
||||||
|
|
||||||
|
private val SCORE_LIST = IntRange(0, 10)
|
||||||
|
.map(Int::toString)
|
||||||
|
.toImmutableList()
|
||||||
}
|
}
|
||||||
|
|
||||||
private val json: Json by injectLazy()
|
private val json: Json by injectLazy()
|
||||||
@ -28,9 +34,7 @@ class Shikimori(id: Long) : BaseTracker(id, "Shikimori"), DeletableTracker {
|
|||||||
|
|
||||||
private val api by lazy { ShikimoriApi(id, client, interceptor) }
|
private val api by lazy { ShikimoriApi(id, client, interceptor) }
|
||||||
|
|
||||||
override fun getScoreList(): List<String> {
|
override fun getScoreList(): ImmutableList<String> = SCORE_LIST
|
||||||
return IntRange(0, 10).map(Int::toString)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun displayScore(track: Track): String {
|
override fun displayScore(track: Track): String {
|
||||||
return track.score.toInt().toString()
|
return track.score.toInt().toString()
|
||||||
|
@ -8,6 +8,8 @@ import eu.kanade.tachiyomi.data.track.BaseTracker
|
|||||||
import eu.kanade.tachiyomi.data.track.EnhancedTracker
|
import eu.kanade.tachiyomi.data.track.EnhancedTracker
|
||||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||||
import eu.kanade.tachiyomi.source.Source
|
import eu.kanade.tachiyomi.source.Source
|
||||||
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
import tachiyomi.domain.manga.model.Manga as DomainManga
|
import tachiyomi.domain.manga.model.Manga as DomainManga
|
||||||
import tachiyomi.domain.track.model.Track as DomainTrack
|
import tachiyomi.domain.track.model.Track as DomainTrack
|
||||||
|
|
||||||
@ -41,7 +43,7 @@ class Suwayomi(id: Long) : BaseTracker(id, "Suwayomi"), EnhancedTracker {
|
|||||||
|
|
||||||
override fun getCompletionStatus(): Int = COMPLETED
|
override fun getCompletionStatus(): Int = COMPLETED
|
||||||
|
|
||||||
override fun getScoreList(): List<String> = emptyList()
|
override fun getScoreList(): ImmutableList<String> = persistentListOf()
|
||||||
|
|
||||||
override fun displayScore(track: Track): String = ""
|
override fun displayScore(track: Track): String = ""
|
||||||
|
|
||||||
|
@ -6,6 +6,11 @@ import cafe.adriel.voyager.core.model.screenModelScope
|
|||||||
import eu.kanade.domain.extension.interactor.GetExtensionLanguages
|
import eu.kanade.domain.extension.interactor.GetExtensionLanguages
|
||||||
import eu.kanade.domain.source.interactor.ToggleLanguage
|
import eu.kanade.domain.source.interactor.ToggleLanguage
|
||||||
import eu.kanade.domain.source.service.SourcePreferences
|
import eu.kanade.domain.source.service.SourcePreferences
|
||||||
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
import kotlinx.collections.immutable.ImmutableSet
|
||||||
|
import kotlinx.collections.immutable.persistentSetOf
|
||||||
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
|
import kotlinx.collections.immutable.toImmutableSet
|
||||||
import kotlinx.coroutines.channels.Channel
|
import kotlinx.coroutines.channels.Channel
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.catch
|
import kotlinx.coroutines.flow.catch
|
||||||
@ -41,8 +46,8 @@ class ExtensionFilterScreenModel(
|
|||||||
.collectLatest { (extensionLanguages, enabledLanguages) ->
|
.collectLatest { (extensionLanguages, enabledLanguages) ->
|
||||||
mutableState.update {
|
mutableState.update {
|
||||||
ExtensionFilterState.Success(
|
ExtensionFilterState.Success(
|
||||||
languages = extensionLanguages,
|
languages = extensionLanguages.toImmutableList(),
|
||||||
enabledLanguages = enabledLanguages,
|
enabledLanguages = enabledLanguages.toImmutableSet(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -65,8 +70,8 @@ sealed interface ExtensionFilterState {
|
|||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
data class Success(
|
data class Success(
|
||||||
val languages: List<String>,
|
val languages: ImmutableList<String>,
|
||||||
val enabledLanguages: Set<String> = emptySet(),
|
val enabledLanguages: ImmutableSet<String> = persistentSetOf(),
|
||||||
) : ExtensionFilterState {
|
) : ExtensionFilterState {
|
||||||
|
|
||||||
val isEmpty: Boolean
|
val isEmpty: Boolean
|
||||||
|
@ -12,6 +12,9 @@ import eu.kanade.tachiyomi.extension.model.Extension
|
|||||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||||
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
||||||
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
import kotlinx.coroutines.channels.Channel
|
import kotlinx.coroutines.channels.Channel
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.catch
|
import kotlinx.coroutines.flow.catch
|
||||||
@ -75,10 +78,10 @@ class ExtensionDetailsScreenModel(
|
|||||||
}
|
}
|
||||||
.catch { throwable ->
|
.catch { throwable ->
|
||||||
logcat(LogPriority.ERROR, throwable)
|
logcat(LogPriority.ERROR, throwable)
|
||||||
mutableState.update { it.copy(_sources = emptyList()) }
|
mutableState.update { it.copy(_sources = persistentListOf()) }
|
||||||
}
|
}
|
||||||
.collectLatest { sources ->
|
.collectLatest { sources ->
|
||||||
mutableState.update { it.copy(_sources = sources) }
|
mutableState.update { it.copy(_sources = sources.toImmutableList()) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -164,11 +167,11 @@ class ExtensionDetailsScreenModel(
|
|||||||
@Immutable
|
@Immutable
|
||||||
data class State(
|
data class State(
|
||||||
val extension: Extension.Installed? = null,
|
val extension: Extension.Installed? = null,
|
||||||
private val _sources: List<ExtensionSourceItem>? = null,
|
private val _sources: ImmutableList<ExtensionSourceItem>? = null,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
val sources: List<ExtensionSourceItem>
|
val sources: ImmutableList<ExtensionSourceItem>
|
||||||
get() = _sources.orEmpty()
|
get() = _sources ?: persistentListOf()
|
||||||
|
|
||||||
val isLoading: Boolean
|
val isLoading: Boolean
|
||||||
get() = extension == null || _sources == null
|
get() = extension == null || _sources == null
|
||||||
|
@ -4,6 +4,9 @@ import androidx.compose.runtime.Immutable
|
|||||||
import cafe.adriel.voyager.core.model.StateScreenModel
|
import cafe.adriel.voyager.core.model.StateScreenModel
|
||||||
import cafe.adriel.voyager.core.model.screenModelScope
|
import cafe.adriel.voyager.core.model.screenModelScope
|
||||||
import eu.kanade.tachiyomi.source.Source
|
import eu.kanade.tachiyomi.source.Source
|
||||||
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
import kotlinx.coroutines.channels.Channel
|
import kotlinx.coroutines.channels.Channel
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.catch
|
import kotlinx.coroutines.flow.catch
|
||||||
@ -40,11 +43,13 @@ class MigrateMangaScreenModel(
|
|||||||
logcat(LogPriority.ERROR, it)
|
logcat(LogPriority.ERROR, it)
|
||||||
_events.send(MigrationMangaEvent.FailedFetchingFavorites)
|
_events.send(MigrationMangaEvent.FailedFetchingFavorites)
|
||||||
mutableState.update { state ->
|
mutableState.update { state ->
|
||||||
state.copy(titleList = emptyList())
|
state.copy(titleList = persistentListOf())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.map { manga ->
|
.map { manga ->
|
||||||
manga.sortedWith(compareBy(String.CASE_INSENSITIVE_ORDER) { it.title })
|
manga
|
||||||
|
.sortedWith(compareBy(String.CASE_INSENSITIVE_ORDER) { it.title })
|
||||||
|
.toImmutableList()
|
||||||
}
|
}
|
||||||
.collectLatest { list ->
|
.collectLatest { list ->
|
||||||
mutableState.update { it.copy(titleList = list) }
|
mutableState.update { it.copy(titleList = list) }
|
||||||
@ -55,11 +60,11 @@ class MigrateMangaScreenModel(
|
|||||||
@Immutable
|
@Immutable
|
||||||
data class State(
|
data class State(
|
||||||
val source: Source? = null,
|
val source: Source? = null,
|
||||||
private val titleList: List<Manga>? = null,
|
private val titleList: ImmutableList<Manga>? = null,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
val titles: List<Manga>
|
val titles: ImmutableList<Manga>
|
||||||
get() = titleList.orEmpty()
|
get() = titleList ?: persistentListOf()
|
||||||
|
|
||||||
val isLoading: Boolean
|
val isLoading: Boolean
|
||||||
get() = source == null || titleList == null
|
get() = source == null || titleList == null
|
||||||
|
@ -6,6 +6,9 @@ import cafe.adriel.voyager.core.model.screenModelScope
|
|||||||
import eu.kanade.domain.source.interactor.GetSourcesWithFavoriteCount
|
import eu.kanade.domain.source.interactor.GetSourcesWithFavoriteCount
|
||||||
import eu.kanade.domain.source.interactor.SetMigrateSorting
|
import eu.kanade.domain.source.interactor.SetMigrateSorting
|
||||||
import eu.kanade.domain.source.service.SourcePreferences
|
import eu.kanade.domain.source.service.SourcePreferences
|
||||||
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
import kotlinx.coroutines.channels.Channel
|
import kotlinx.coroutines.channels.Channel
|
||||||
import kotlinx.coroutines.flow.catch
|
import kotlinx.coroutines.flow.catch
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
@ -40,7 +43,7 @@ class MigrateSourceScreenModel(
|
|||||||
mutableState.update {
|
mutableState.update {
|
||||||
it.copy(
|
it.copy(
|
||||||
isLoading = false,
|
isLoading = false,
|
||||||
items = sources,
|
items = sources.toImmutableList(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -80,7 +83,7 @@ class MigrateSourceScreenModel(
|
|||||||
@Immutable
|
@Immutable
|
||||||
data class State(
|
data class State(
|
||||||
val isLoading: Boolean = true,
|
val isLoading: Boolean = true,
|
||||||
val items: List<Pair<Source, Long>> = emptyList(),
|
val items: ImmutableList<Pair<Source, Long>> = persistentListOf(),
|
||||||
val sortingMode: SetMigrateSorting.Mode = SetMigrateSorting.Mode.ALPHABETICAL,
|
val sortingMode: SetMigrateSorting.Mode = SetMigrateSorting.Mode.ALPHABETICAL,
|
||||||
val sortingDirection: SetMigrateSorting.Direction = SetMigrateSorting.Direction.ASCENDING,
|
val sortingDirection: SetMigrateSorting.Direction = SetMigrateSorting.Direction.ASCENDING,
|
||||||
) {
|
) {
|
||||||
|
@ -7,6 +7,9 @@ import eu.kanade.domain.source.interactor.GetEnabledSources
|
|||||||
import eu.kanade.domain.source.interactor.ToggleSource
|
import eu.kanade.domain.source.interactor.ToggleSource
|
||||||
import eu.kanade.domain.source.interactor.ToggleSourcePin
|
import eu.kanade.domain.source.interactor.ToggleSourcePin
|
||||||
import eu.kanade.presentation.browse.SourceUiModel
|
import eu.kanade.presentation.browse.SourceUiModel
|
||||||
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
import kotlinx.coroutines.channels.Channel
|
import kotlinx.coroutines.channels.Channel
|
||||||
import kotlinx.coroutines.flow.catch
|
import kotlinx.coroutines.flow.catch
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
@ -65,14 +68,16 @@ class SourcesScreenModel(
|
|||||||
|
|
||||||
state.copy(
|
state.copy(
|
||||||
isLoading = false,
|
isLoading = false,
|
||||||
items = byLang.flatMap {
|
items = byLang
|
||||||
listOf(
|
.flatMap {
|
||||||
SourceUiModel.Header(it.key),
|
listOf(
|
||||||
*it.value.map { source ->
|
SourceUiModel.Header(it.key),
|
||||||
SourceUiModel.Item(source)
|
*it.value.map { source ->
|
||||||
}.toTypedArray(),
|
SourceUiModel.Item(source)
|
||||||
)
|
}.toTypedArray(),
|
||||||
},
|
)
|
||||||
|
}
|
||||||
|
.toImmutableList(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -103,7 +108,7 @@ class SourcesScreenModel(
|
|||||||
data class State(
|
data class State(
|
||||||
val dialog: Dialog? = null,
|
val dialog: Dialog? = null,
|
||||||
val isLoading: Boolean = true,
|
val isLoading: Boolean = true,
|
||||||
val items: List<SourceUiModel> = emptyList(),
|
val items: ImmutableList<SourceUiModel> = persistentListOf(),
|
||||||
) {
|
) {
|
||||||
val isEmpty = items.isEmpty()
|
val isEmpty = items.isEmpty()
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,10 @@ import eu.kanade.domain.source.service.SourcePreferences
|
|||||||
import eu.kanade.presentation.util.ioCoroutineScope
|
import eu.kanade.presentation.util.ioCoroutineScope
|
||||||
import eu.kanade.tachiyomi.extension.ExtensionManager
|
import eu.kanade.tachiyomi.extension.ExtensionManager
|
||||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||||
|
import kotlinx.collections.immutable.PersistentMap
|
||||||
|
import kotlinx.collections.immutable.mutate
|
||||||
|
import kotlinx.collections.immutable.persistentMapOf
|
||||||
|
import kotlinx.collections.immutable.toPersistentMap
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.asCoroutineDispatcher
|
import kotlinx.coroutines.asCoroutineDispatcher
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
@ -125,9 +129,17 @@ abstract class SearchScreenModel(
|
|||||||
// Reuse previous results if possible
|
// Reuse previous results if possible
|
||||||
if (sameQuery) {
|
if (sameQuery) {
|
||||||
val existingResults = state.value.items
|
val existingResults = state.value.items
|
||||||
updateItems(sources.associateWith { existingResults[it] ?: SearchItemResult.Loading })
|
updateItems(
|
||||||
|
sources
|
||||||
|
.associateWith { existingResults[it] ?: SearchItemResult.Loading }
|
||||||
|
.toPersistentMap(),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
updateItems(sources.associateWith { SearchItemResult.Loading })
|
updateItems(
|
||||||
|
sources
|
||||||
|
.associateWith { SearchItemResult.Loading }
|
||||||
|
.toPersistentMap(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
searchJob = ioCoroutineScope.launch {
|
searchJob = ioCoroutineScope.launch {
|
||||||
@ -160,14 +172,21 @@ abstract class SearchScreenModel(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateItems(items: Map<CatalogueSource, SearchItemResult>) {
|
private fun updateItems(items: PersistentMap<CatalogueSource, SearchItemResult>) {
|
||||||
mutableState.update { it.copy(items = items.toSortedMap(sortComparator(items))) }
|
mutableState.update {
|
||||||
|
it.copy(
|
||||||
|
items = items
|
||||||
|
.toSortedMap(sortComparator(items))
|
||||||
|
.toPersistentMap(),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateItem(source: CatalogueSource, result: SearchItemResult) {
|
private fun updateItem(source: CatalogueSource, result: SearchItemResult) {
|
||||||
val mutableItems = state.value.items.toMutableMap()
|
val newItems = state.value.items.mutate {
|
||||||
mutableItems[source] = result
|
it[source] = result
|
||||||
updateItems(mutableItems)
|
}
|
||||||
|
updateItems(newItems)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
@ -176,7 +195,7 @@ abstract class SearchScreenModel(
|
|||||||
val searchQuery: String? = null,
|
val searchQuery: String? = null,
|
||||||
val sourceFilter: SourceFilter = SourceFilter.PinnedOnly,
|
val sourceFilter: SourceFilter = SourceFilter.PinnedOnly,
|
||||||
val onlyShowHasResults: Boolean = false,
|
val onlyShowHasResults: Boolean = false,
|
||||||
val items: Map<CatalogueSource, SearchItemResult> = emptyMap(),
|
val items: PersistentMap<CatalogueSource, SearchItemResult> = persistentMapOf(),
|
||||||
) {
|
) {
|
||||||
val progress: Int = items.count { it.value !is SearchItemResult.Loading }
|
val progress: Int = items.count { it.value !is SearchItemResult.Loading }
|
||||||
val total: Int = items.size
|
val total: Int = items.size
|
||||||
|
@ -5,6 +5,8 @@ import androidx.compose.runtime.Immutable
|
|||||||
import cafe.adriel.voyager.core.model.StateScreenModel
|
import cafe.adriel.voyager.core.model.StateScreenModel
|
||||||
import cafe.adriel.voyager.core.model.screenModelScope
|
import cafe.adriel.voyager.core.model.screenModelScope
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
import kotlinx.coroutines.channels.Channel
|
import kotlinx.coroutines.channels.Channel
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.flow.receiveAsFlow
|
import kotlinx.coroutines.flow.receiveAsFlow
|
||||||
@ -36,7 +38,9 @@ class CategoryScreenModel(
|
|||||||
.collectLatest { categories ->
|
.collectLatest { categories ->
|
||||||
mutableState.update {
|
mutableState.update {
|
||||||
CategoryScreenState.Success(
|
CategoryScreenState.Success(
|
||||||
categories = categories.filterNot(Category::isSystemCategory),
|
categories = categories
|
||||||
|
.filterNot(Category::isSystemCategory)
|
||||||
|
.toImmutableList(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -135,7 +139,7 @@ sealed interface CategoryScreenState {
|
|||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
data class Success(
|
data class Success(
|
||||||
val categories: List<Category>,
|
val categories: ImmutableList<Category>,
|
||||||
val dialog: CategoryDialog? = null,
|
val dialog: CategoryDialog? = null,
|
||||||
) : CategoryScreenState {
|
) : CategoryScreenState {
|
||||||
|
|
||||||
|
@ -28,6 +28,9 @@ import eu.kanade.tachiyomi.source.model.SManga
|
|||||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||||
import eu.kanade.tachiyomi.util.chapter.getNextUnread
|
import eu.kanade.tachiyomi.util.chapter.getNextUnread
|
||||||
import eu.kanade.tachiyomi.util.removeCovers
|
import eu.kanade.tachiyomi.util.removeCovers
|
||||||
|
import kotlinx.collections.immutable.PersistentList
|
||||||
|
import kotlinx.collections.immutable.mutate
|
||||||
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
@ -562,16 +565,16 @@ class LibraryScreenModel(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun clearSelection() {
|
fun clearSelection() {
|
||||||
mutableState.update { it.copy(selection = emptyList()) }
|
mutableState.update { it.copy(selection = persistentListOf()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun toggleSelection(manga: LibraryManga) {
|
fun toggleSelection(manga: LibraryManga) {
|
||||||
mutableState.update { state ->
|
mutableState.update { state ->
|
||||||
val newSelection = state.selection.toMutableList().apply {
|
val newSelection = state.selection.mutate { list ->
|
||||||
if (fastAny { it.id == manga.id }) {
|
if (list.fastAny { it.id == manga.id }) {
|
||||||
removeAll { it.id == manga.id }
|
list.removeAll { it.id == manga.id }
|
||||||
} else {
|
} else {
|
||||||
add(manga)
|
list.add(manga)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
state.copy(selection = newSelection)
|
state.copy(selection = newSelection)
|
||||||
@ -584,11 +587,11 @@ class LibraryScreenModel(
|
|||||||
*/
|
*/
|
||||||
fun toggleRangeSelection(manga: LibraryManga) {
|
fun toggleRangeSelection(manga: LibraryManga) {
|
||||||
mutableState.update { state ->
|
mutableState.update { state ->
|
||||||
val newSelection = state.selection.toMutableList().apply {
|
val newSelection = state.selection.mutate { list ->
|
||||||
val lastSelected = lastOrNull()
|
val lastSelected = list.lastOrNull()
|
||||||
if (lastSelected?.category != manga.category) {
|
if (lastSelected?.category != manga.category) {
|
||||||
add(manga)
|
list.add(manga)
|
||||||
return@apply
|
return@mutate
|
||||||
}
|
}
|
||||||
|
|
||||||
val items = state.getLibraryItemsByCategoryId(manga.category)
|
val items = state.getLibraryItemsByCategoryId(manga.category)
|
||||||
@ -596,17 +599,17 @@ class LibraryScreenModel(
|
|||||||
val lastMangaIndex = items.indexOf(lastSelected)
|
val lastMangaIndex = items.indexOf(lastSelected)
|
||||||
val curMangaIndex = items.indexOf(manga)
|
val curMangaIndex = items.indexOf(manga)
|
||||||
|
|
||||||
val selectedIds = fastMap { it.id }
|
val selectedIds = list.fastMap { it.id }
|
||||||
val selectionRange = when {
|
val selectionRange = when {
|
||||||
lastMangaIndex < curMangaIndex -> IntRange(lastMangaIndex, curMangaIndex)
|
lastMangaIndex < curMangaIndex -> IntRange(lastMangaIndex, curMangaIndex)
|
||||||
curMangaIndex < lastMangaIndex -> IntRange(curMangaIndex, lastMangaIndex)
|
curMangaIndex < lastMangaIndex -> IntRange(curMangaIndex, lastMangaIndex)
|
||||||
// We shouldn't reach this point
|
// We shouldn't reach this point
|
||||||
else -> return@apply
|
else -> return@mutate
|
||||||
}
|
}
|
||||||
val newSelections = selectionRange.mapNotNull { index ->
|
val newSelections = selectionRange.mapNotNull { index ->
|
||||||
items[index].takeUnless { it.id in selectedIds }
|
items[index].takeUnless { it.id in selectedIds }
|
||||||
}
|
}
|
||||||
addAll(newSelections)
|
list.addAll(newSelections)
|
||||||
}
|
}
|
||||||
state.copy(selection = newSelection)
|
state.copy(selection = newSelection)
|
||||||
}
|
}
|
||||||
@ -614,14 +617,14 @@ class LibraryScreenModel(
|
|||||||
|
|
||||||
fun selectAll(index: Int) {
|
fun selectAll(index: Int) {
|
||||||
mutableState.update { state ->
|
mutableState.update { state ->
|
||||||
val newSelection = state.selection.toMutableList().apply {
|
val newSelection = state.selection.mutate { list ->
|
||||||
val categoryId = state.categories.getOrNull(index)?.id ?: -1
|
val categoryId = state.categories.getOrNull(index)?.id ?: -1
|
||||||
val selectedIds = fastMap { it.id }
|
val selectedIds = list.fastMap { it.id }
|
||||||
state.getLibraryItemsByCategoryId(categoryId)
|
state.getLibraryItemsByCategoryId(categoryId)
|
||||||
?.fastMapNotNull { item ->
|
?.fastMapNotNull { item ->
|
||||||
item.libraryManga.takeUnless { it.id in selectedIds }
|
item.libraryManga.takeUnless { it.id in selectedIds }
|
||||||
}
|
}
|
||||||
?.let { addAll(it) }
|
?.let { list.addAll(it) }
|
||||||
}
|
}
|
||||||
state.copy(selection = newSelection)
|
state.copy(selection = newSelection)
|
||||||
}
|
}
|
||||||
@ -629,14 +632,14 @@ class LibraryScreenModel(
|
|||||||
|
|
||||||
fun invertSelection(index: Int) {
|
fun invertSelection(index: Int) {
|
||||||
mutableState.update { state ->
|
mutableState.update { state ->
|
||||||
val newSelection = state.selection.toMutableList().apply {
|
val newSelection = state.selection.mutate { list ->
|
||||||
val categoryId = state.categories[index].id
|
val categoryId = state.categories[index].id
|
||||||
val items = state.getLibraryItemsByCategoryId(categoryId)?.fastMap { it.libraryManga }.orEmpty()
|
val items = state.getLibraryItemsByCategoryId(categoryId)?.fastMap { it.libraryManga }.orEmpty()
|
||||||
val selectedIds = fastMap { it.id }
|
val selectedIds = list.fastMap { it.id }
|
||||||
val (toRemove, toAdd) = items.fastPartition { it.id in selectedIds }
|
val (toRemove, toAdd) = items.fastPartition { it.id in selectedIds }
|
||||||
val toRemoveIds = toRemove.fastMap { it.id }
|
val toRemoveIds = toRemove.fastMap { it.id }
|
||||||
removeAll { it.id in toRemoveIds }
|
list.removeAll { it.id in toRemoveIds }
|
||||||
addAll(toAdd)
|
list.addAll(toAdd)
|
||||||
}
|
}
|
||||||
state.copy(selection = newSelection)
|
state.copy(selection = newSelection)
|
||||||
}
|
}
|
||||||
@ -703,7 +706,7 @@ class LibraryScreenModel(
|
|||||||
val isLoading: Boolean = true,
|
val isLoading: Boolean = true,
|
||||||
val library: LibraryMap = emptyMap(),
|
val library: LibraryMap = emptyMap(),
|
||||||
val searchQuery: String? = null,
|
val searchQuery: String? = null,
|
||||||
val selection: List<LibraryManga> = emptyList(),
|
val selection: PersistentList<LibraryManga> = persistentListOf(),
|
||||||
val hasActiveFilters: Boolean = false,
|
val hasActiveFilters: Boolean = false,
|
||||||
val showCategoryTabs: Boolean = false,
|
val showCategoryTabs: Boolean = false,
|
||||||
val showMangaCount: Boolean = false,
|
val showMangaCount: Boolean = false,
|
||||||
|
@ -43,6 +43,7 @@ import eu.kanade.tachiyomi.ui.home.HomeScreen
|
|||||||
import eu.kanade.tachiyomi.ui.main.MainActivity
|
import eu.kanade.tachiyomi.ui.main.MainActivity
|
||||||
import eu.kanade.tachiyomi.ui.manga.MangaScreen
|
import eu.kanade.tachiyomi.ui.manga.MangaScreen
|
||||||
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
||||||
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
import kotlinx.coroutines.channels.Channel
|
import kotlinx.coroutines.channels.Channel
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.flow.receiveAsFlow
|
import kotlinx.coroutines.flow.receiveAsFlow
|
||||||
@ -154,7 +155,7 @@ object LibraryTab : Tab {
|
|||||||
EmptyScreen(
|
EmptyScreen(
|
||||||
textResource = R.string.information_empty_library,
|
textResource = R.string.information_empty_library,
|
||||||
modifier = Modifier.padding(contentPadding),
|
modifier = Modifier.padding(contentPadding),
|
||||||
actions = listOf(
|
actions = persistentListOf(
|
||||||
EmptyScreenAction(
|
EmptyScreenAction(
|
||||||
stringResId = R.string.getting_started_guide,
|
stringResId = R.string.getting_started_guide,
|
||||||
icon = Icons.Outlined.HelpOutline,
|
icon = Icons.Outlined.HelpOutline,
|
||||||
|
@ -58,6 +58,7 @@ import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
|||||||
import eu.kanade.tachiyomi.util.lang.convertEpochMillisZone
|
import eu.kanade.tachiyomi.util.lang.convertEpochMillisZone
|
||||||
import eu.kanade.tachiyomi.util.system.openInBrowser
|
import eu.kanade.tachiyomi.util.system.openInBrowser
|
||||||
import eu.kanade.tachiyomi.util.system.toast
|
import eu.kanade.tachiyomi.util.system.toast
|
||||||
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
import kotlinx.coroutines.flow.catch
|
import kotlinx.coroutines.flow.catch
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
@ -398,7 +399,7 @@ private data class TrackScoreSelectorScreen(
|
|||||||
private val tracker: Tracker,
|
private val tracker: Tracker,
|
||||||
) : StateScreenModel<Model.State>(State(tracker.displayScore(track.toDbTrack()))) {
|
) : StateScreenModel<Model.State>(State(tracker.displayScore(track.toDbTrack()))) {
|
||||||
|
|
||||||
fun getSelections(): List<String> {
|
fun getSelections(): ImmutableList<String> {
|
||||||
return tracker.getScoreList()
|
return tracker.getScoreList()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,10 @@ import eu.kanade.tachiyomi.data.download.model.Download
|
|||||||
import eu.kanade.tachiyomi.data.library.LibraryUpdateJob
|
import eu.kanade.tachiyomi.data.library.LibraryUpdateJob
|
||||||
import eu.kanade.tachiyomi.util.lang.toDateKey
|
import eu.kanade.tachiyomi.util.lang.toDateKey
|
||||||
import eu.kanade.tachiyomi.util.lang.toRelativeString
|
import eu.kanade.tachiyomi.util.lang.toRelativeString
|
||||||
|
import kotlinx.collections.immutable.PersistentList
|
||||||
|
import kotlinx.collections.immutable.mutate
|
||||||
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
|
import kotlinx.collections.immutable.toPersistentList
|
||||||
import kotlinx.coroutines.channels.Channel
|
import kotlinx.coroutines.channels.Channel
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.catch
|
import kotlinx.coroutines.flow.catch
|
||||||
@ -106,27 +110,29 @@ class UpdatesScreenModel(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun List<UpdatesWithRelations>.toUpdateItems(): List<UpdatesItem> {
|
private fun List<UpdatesWithRelations>.toUpdateItems(): PersistentList<UpdatesItem> {
|
||||||
return this.map { update ->
|
return this
|
||||||
val activeDownload = downloadManager.getQueuedDownloadOrNull(update.chapterId)
|
.map { update ->
|
||||||
val downloaded = downloadManager.isChapterDownloaded(
|
val activeDownload = downloadManager.getQueuedDownloadOrNull(update.chapterId)
|
||||||
update.chapterName,
|
val downloaded = downloadManager.isChapterDownloaded(
|
||||||
update.scanlator,
|
update.chapterName,
|
||||||
update.mangaTitle,
|
update.scanlator,
|
||||||
update.sourceId,
|
update.mangaTitle,
|
||||||
)
|
update.sourceId,
|
||||||
val downloadState = when {
|
)
|
||||||
activeDownload != null -> activeDownload.status
|
val downloadState = when {
|
||||||
downloaded -> Download.State.DOWNLOADED
|
activeDownload != null -> activeDownload.status
|
||||||
else -> Download.State.NOT_DOWNLOADED
|
downloaded -> Download.State.DOWNLOADED
|
||||||
|
else -> Download.State.NOT_DOWNLOADED
|
||||||
|
}
|
||||||
|
UpdatesItem(
|
||||||
|
update = update,
|
||||||
|
downloadStateProvider = { downloadState },
|
||||||
|
downloadProgressProvider = { activeDownload?.progress ?: 0 },
|
||||||
|
selected = update.chapterId in selectedChapterIds,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
UpdatesItem(
|
.toPersistentList()
|
||||||
update = update,
|
|
||||||
downloadStateProvider = { downloadState },
|
|
||||||
downloadProgressProvider = { activeDownload?.progress ?: 0 },
|
|
||||||
selected = update.chapterId in selectedChapterIds,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateLibrary(): Boolean {
|
fun updateLibrary(): Boolean {
|
||||||
@ -144,17 +150,14 @@ class UpdatesScreenModel(
|
|||||||
*/
|
*/
|
||||||
private fun updateDownloadState(download: Download) {
|
private fun updateDownloadState(download: Download) {
|
||||||
mutableState.update { state ->
|
mutableState.update { state ->
|
||||||
val newItems = state.items.toMutableList().apply {
|
val newItems = state.items.mutate { list ->
|
||||||
val modifiedIndex = indexOfFirst { it.update.chapterId == download.chapter.id }
|
val modifiedIndex = list.indexOfFirst { it.update.chapterId == download.chapter.id }
|
||||||
if (modifiedIndex < 0) return@apply
|
if (modifiedIndex < 0) return@mutate
|
||||||
|
|
||||||
val item = get(modifiedIndex)
|
val item = list[modifiedIndex]
|
||||||
set(
|
list[modifiedIndex] = item.copy(
|
||||||
modifiedIndex,
|
downloadStateProvider = { download.status },
|
||||||
item.copy(
|
downloadProgressProvider = { download.progress },
|
||||||
downloadStateProvider = { download.status },
|
|
||||||
downloadProgressProvider = { download.progress },
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
state.copy(items = newItems)
|
state.copy(items = newItems)
|
||||||
@ -330,7 +333,7 @@ class UpdatesScreenModel(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
state.copy(items = newItems)
|
state.copy(items = newItems.toPersistentList())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -340,7 +343,7 @@ class UpdatesScreenModel(
|
|||||||
selectedChapterIds.addOrRemove(it.update.chapterId, selected)
|
selectedChapterIds.addOrRemove(it.update.chapterId, selected)
|
||||||
it.copy(selected = selected)
|
it.copy(selected = selected)
|
||||||
}
|
}
|
||||||
state.copy(items = newItems)
|
state.copy(items = newItems.toPersistentList())
|
||||||
}
|
}
|
||||||
|
|
||||||
selectedPositions[0] = -1
|
selectedPositions[0] = -1
|
||||||
@ -353,7 +356,7 @@ class UpdatesScreenModel(
|
|||||||
selectedChapterIds.addOrRemove(it.update.chapterId, !it.selected)
|
selectedChapterIds.addOrRemove(it.update.chapterId, !it.selected)
|
||||||
it.copy(selected = !it.selected)
|
it.copy(selected = !it.selected)
|
||||||
}
|
}
|
||||||
state.copy(items = newItems)
|
state.copy(items = newItems.toPersistentList())
|
||||||
}
|
}
|
||||||
selectedPositions[0] = -1
|
selectedPositions[0] = -1
|
||||||
selectedPositions[1] = -1
|
selectedPositions[1] = -1
|
||||||
@ -370,7 +373,7 @@ class UpdatesScreenModel(
|
|||||||
@Immutable
|
@Immutable
|
||||||
data class State(
|
data class State(
|
||||||
val isLoading: Boolean = true,
|
val isLoading: Boolean = true,
|
||||||
val items: List<UpdatesItem> = emptyList(),
|
val items: PersistentList<UpdatesItem> = persistentListOf(),
|
||||||
val dialog: Dialog? = null,
|
val dialog: Dialog? = null,
|
||||||
) {
|
) {
|
||||||
val selected = items.filter { it.selected }
|
val selected = items.filter { it.selected }
|
||||||
|
@ -4,6 +4,8 @@ import android.graphics.Color
|
|||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.track.Tracker
|
import eu.kanade.tachiyomi.data.track.Tracker
|
||||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||||
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import tachiyomi.domain.track.model.Track
|
import tachiyomi.domain.track.model.Track
|
||||||
|
|
||||||
@ -18,7 +20,7 @@ data class DummyTracker(
|
|||||||
val valReadingStatus: Int = 1,
|
val valReadingStatus: Int = 1,
|
||||||
val valRereadingStatus: Int = 1,
|
val valRereadingStatus: Int = 1,
|
||||||
val valCompletionStatus: Int = 2,
|
val valCompletionStatus: Int = 2,
|
||||||
val valScoreList: List<String> = (0..10).map(Int::toString),
|
val valScoreList: ImmutableList<String> = (0..10).map(Int::toString).toImmutableList(),
|
||||||
val val10PointScore: Double = 5.4,
|
val val10PointScore: Double = 5.4,
|
||||||
val valSearchResults: List<TrackSearch> = listOf(),
|
val valSearchResults: List<TrackSearch> = listOf(),
|
||||||
) : Tracker {
|
) : Tracker {
|
||||||
@ -48,7 +50,7 @@ data class DummyTracker(
|
|||||||
|
|
||||||
override fun getCompletionStatus(): Int = valCompletionStatus
|
override fun getCompletionStatus(): Int = valCompletionStatus
|
||||||
|
|
||||||
override fun getScoreList(): List<String> = valScoreList
|
override fun getScoreList(): ImmutableList<String> = valScoreList
|
||||||
|
|
||||||
override fun get10PointScore(track: Track): Double = val10PointScore
|
override fun get10PointScore(track: Track): Double = val10PointScore
|
||||||
|
|
||||||
|
@ -80,7 +80,7 @@ class EpubFile(file: File) : Closeable {
|
|||||||
/**
|
/**
|
||||||
* Returns all the pages from the epub.
|
* Returns all the pages from the epub.
|
||||||
*/
|
*/
|
||||||
fun getPagesFromDocument(document: Document): List<String> {
|
private fun getPagesFromDocument(document: Document): List<String> {
|
||||||
val pages = document.select("manifest > item")
|
val pages = document.select("manifest > item")
|
||||||
.filter { node -> "application/xhtml+xml" == node.attr("media-type") }
|
.filter { node -> "application/xhtml+xml" == node.attr("media-type") }
|
||||||
.associateBy { it.attr("id") }
|
.associateBy { it.attr("id") }
|
||||||
@ -102,10 +102,9 @@ class EpubFile(file: File) : Closeable {
|
|||||||
val imageBasePath = getParentDirectory(entryPath)
|
val imageBasePath = getParentDirectory(entryPath)
|
||||||
|
|
||||||
document.allElements.forEach {
|
document.allElements.forEach {
|
||||||
if (it.tagName() == "img") {
|
when (it.tagName()) {
|
||||||
result.add(resolveZipPath(imageBasePath, it.attr("src")))
|
"img" -> result.add(resolveZipPath(imageBasePath, it.attr("src")))
|
||||||
} else if (it.tagName() == "image") {
|
"image" -> result.add(resolveZipPath(imageBasePath, it.attr("xlink:href")))
|
||||||
result.add(resolveZipPath(imageBasePath, it.attr("xlink:href")))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,8 @@ dependencies {
|
|||||||
implementation(compose.ui.tooling.preview)
|
implementation(compose.ui.tooling.preview)
|
||||||
implementation(compose.ui.util)
|
implementation(compose.ui.util)
|
||||||
lintChecks(compose.lintchecks)
|
lintChecks(compose.lintchecks)
|
||||||
|
|
||||||
|
implementation(kotlinx.immutables)
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks {
|
tasks {
|
||||||
|
@ -36,13 +36,14 @@ fun BadgeGroup(
|
|||||||
@Composable
|
@Composable
|
||||||
fun Badge(
|
fun Badge(
|
||||||
text: String,
|
text: String,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
color: Color = MaterialTheme.colorScheme.secondary,
|
color: Color = MaterialTheme.colorScheme.secondary,
|
||||||
textColor: Color = MaterialTheme.colorScheme.onSecondary,
|
textColor: Color = MaterialTheme.colorScheme.onSecondary,
|
||||||
shape: Shape = RectangleShape,
|
shape: Shape = RectangleShape,
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = text,
|
text = text,
|
||||||
modifier = Modifier
|
modifier = modifier
|
||||||
.clip(shape)
|
.clip(shape)
|
||||||
.background(color)
|
.background(color)
|
||||||
.padding(horizontal = 3.dp, vertical = 1.dp),
|
.padding(horizontal = 3.dp, vertical = 1.dp),
|
||||||
@ -56,6 +57,7 @@ fun Badge(
|
|||||||
@Composable
|
@Composable
|
||||||
fun Badge(
|
fun Badge(
|
||||||
imageVector: ImageVector,
|
imageVector: ImageVector,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
color: Color = MaterialTheme.colorScheme.secondary,
|
color: Color = MaterialTheme.colorScheme.secondary,
|
||||||
iconColor: Color = MaterialTheme.colorScheme.onSecondary,
|
iconColor: Color = MaterialTheme.colorScheme.onSecondary,
|
||||||
shape: Shape = RectangleShape,
|
shape: Shape = RectangleShape,
|
||||||
@ -86,7 +88,7 @@ fun Badge(
|
|||||||
Text(
|
Text(
|
||||||
text = text,
|
text = text,
|
||||||
inlineContent = inlineContent,
|
inlineContent = inlineContent,
|
||||||
modifier = Modifier
|
modifier = modifier
|
||||||
.clip(shape)
|
.clip(shape)
|
||||||
.background(color)
|
.background(color)
|
||||||
.padding(horizontal = 3.dp, vertical = 1.dp),
|
.padding(horizontal = 3.dp, vertical = 1.dp),
|
||||||
|
@ -41,6 +41,7 @@ import androidx.compose.ui.text.input.TextFieldValue
|
|||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.unit.DpSize
|
import androidx.compose.ui.unit.DpSize
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
import kotlinx.coroutines.flow.drop
|
import kotlinx.coroutines.flow.drop
|
||||||
@ -54,7 +55,7 @@ import kotlin.math.absoluteValue
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun WheelNumberPicker(
|
fun WheelNumberPicker(
|
||||||
items: List<Number>,
|
items: ImmutableList<Number>,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
startIndex: Int = 0,
|
startIndex: Int = 0,
|
||||||
size: DpSize = DpSize(128.dp, 128.dp),
|
size: DpSize = DpSize(128.dp, 128.dp),
|
||||||
@ -78,7 +79,7 @@ fun WheelNumberPicker(
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun WheelTextPicker(
|
fun WheelTextPicker(
|
||||||
items: List<String>,
|
items: ImmutableList<String>,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
startIndex: Int = 0,
|
startIndex: Int = 0,
|
||||||
size: DpSize = DpSize(128.dp, 128.dp),
|
size: DpSize = DpSize(128.dp, 128.dp),
|
||||||
@ -101,7 +102,7 @@ fun WheelTextPicker(
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun <T> WheelPicker(
|
private fun <T> WheelPicker(
|
||||||
items: List<T>,
|
items: ImmutableList<T>,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
startIndex: Int = 0,
|
startIndex: Int = 0,
|
||||||
size: DpSize = DpSize(128.dp, 128.dp),
|
size: DpSize = DpSize(128.dp, 128.dp),
|
||||||
|
@ -23,6 +23,7 @@ import androidx.compose.ui.text.style.TextAlign
|
|||||||
import androidx.compose.ui.unit.LayoutDirection
|
import androidx.compose.ui.unit.LayoutDirection
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.util.fastForEach
|
import androidx.compose.ui.util.fastForEach
|
||||||
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
import tachiyomi.presentation.core.components.ActionButton
|
import tachiyomi.presentation.core.components.ActionButton
|
||||||
import tachiyomi.presentation.core.components.material.padding
|
import tachiyomi.presentation.core.components.material.padding
|
||||||
import tachiyomi.presentation.core.util.secondaryItemAlpha
|
import tachiyomi.presentation.core.util.secondaryItemAlpha
|
||||||
@ -38,7 +39,7 @@ data class EmptyScreenAction(
|
|||||||
fun EmptyScreen(
|
fun EmptyScreen(
|
||||||
@StringRes textResource: Int,
|
@StringRes textResource: Int,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
actions: List<EmptyScreenAction>? = null,
|
actions: ImmutableList<EmptyScreenAction>? = null,
|
||||||
) {
|
) {
|
||||||
EmptyScreen(
|
EmptyScreen(
|
||||||
message = stringResource(textResource),
|
message = stringResource(textResource),
|
||||||
@ -51,7 +52,7 @@ fun EmptyScreen(
|
|||||||
fun EmptyScreen(
|
fun EmptyScreen(
|
||||||
message: String,
|
message: String,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
actions: List<EmptyScreenAction>? = null,
|
actions: ImmutableList<EmptyScreenAction>? = null,
|
||||||
) {
|
) {
|
||||||
val face = remember { getRandomErrorFace() }
|
val face = remember { getRandomErrorFace() }
|
||||||
Column(
|
Column(
|
||||||
@ -98,7 +99,7 @@ fun EmptyScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val ERROR_FACES = listOf(
|
private val ErrorFaces = listOf(
|
||||||
"(・o・;)",
|
"(・o・;)",
|
||||||
"Σ(ಠ_ಠ)",
|
"Σ(ಠ_ಠ)",
|
||||||
"ಥ_ಥ",
|
"ಥ_ಥ",
|
||||||
@ -108,5 +109,5 @@ private val ERROR_FACES = listOf(
|
|||||||
)
|
)
|
||||||
|
|
||||||
private fun getRandomErrorFace(): String {
|
private fun getRandomErrorFace(): String {
|
||||||
return ERROR_FACES[Random.nextInt(ERROR_FACES.size)]
|
return ErrorFaces[Random.nextInt(ErrorFaces.size)]
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user