fix: merge conflict.

Signed-off-by: KaiserBh <kaiserbh@proton.me>
This commit is contained in:
KaiserBh
2023-11-14 14:09:17 +11:00
81 changed files with 648 additions and 391 deletions

View File

@ -167,6 +167,7 @@ dependencies {
implementation(compose.accompanist.permissions)
implementation(compose.accompanist.themeadapter)
implementation(compose.accompanist.systemuicontroller)
lintChecks(compose.lintchecks)
implementation(androidx.paging.runtime)
implementation(androidx.paging.compose)
@ -174,6 +175,7 @@ dependencies {
implementation(libs.bundles.sqlite)
implementation(kotlinx.reflect)
implementation(kotlinx.immutables)
implementation(platform(kotlinx.coroutines.bom))
implementation(kotlinx.bundles.coroutines)

View File

@ -24,6 +24,7 @@ import eu.kanade.presentation.components.AppBar
import eu.kanade.presentation.util.formattedMessage
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.source.Source
import kotlinx.collections.immutable.persistentListOf
import kotlinx.coroutines.flow.StateFlow
import tachiyomi.domain.library.model.LibraryDisplayMode
import tachiyomi.domain.manga.model.Manga
@ -76,7 +77,7 @@ fun BrowseSourceContent(
modifier = Modifier.padding(contentPadding),
message = getErrorMessage(errorState),
actions = if (source is LocalSource) {
listOf(
persistentListOf(
EmptyScreenAction(
stringResId = R.string.local_source_help_guide,
icon = Icons.Outlined.HelpOutline,
@ -84,7 +85,7 @@ fun BrowseSourceContent(
),
)
} else {
listOf(
persistentListOf(
EmptyScreenAction(
stringResId = R.string.action_retry,
icon = Icons.Outlined.Refresh,

View File

@ -94,8 +94,8 @@ fun SourcesScreen(
@Composable
private fun SourceHeader(
modifier: Modifier = Modifier,
language: String,
modifier: Modifier = Modifier,
) {
val context = LocalContext.current
Text(
@ -108,11 +108,11 @@ private fun SourceHeader(
@Composable
private fun SourceItem(
modifier: Modifier = Modifier,
source: Source,
onClickItem: (Source, Listing) -> Unit,
onLongClickItem: (Source) -> Unit,
onClickPin: (Source) -> Unit,
modifier: Modifier = Modifier,
) {
BaseSourceItem(
modifier = modifier,

View File

@ -8,6 +8,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.PreviewLightDark
import eu.kanade.presentation.theme.TachiyomiTheme
import eu.kanade.tachiyomi.R
import kotlinx.collections.immutable.persistentListOf
import tachiyomi.presentation.core.screens.EmptyScreen
import tachiyomi.presentation.core.screens.EmptyScreenAction
@ -30,7 +31,7 @@ private fun WithActionPreview() {
Surface {
EmptyScreen(
textResource = R.string.empty_screen,
actions = listOf(
actions = persistentListOf(
EmptyScreenAction(
stringResId = R.string.action_retry,
icon = Icons.Outlined.Refresh,

View File

@ -16,6 +16,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
import eu.kanade.tachiyomi.R
import kotlinx.collections.immutable.toImmutableList
import tachiyomi.domain.manga.interactor.FetchInterval
import tachiyomi.presentation.core.components.WheelTextPicker
@ -67,16 +68,18 @@ fun SetIntervalDialog(
contentAlignment = Alignment.Center,
) {
val size = DpSize(width = maxWidth / 2, height = 128.dp)
val items = (0..FetchInterval.MAX_INTERVAL).map {
if (it == 0) {
stringResource(R.string.label_default)
} else {
it.toString()
val items = (0..FetchInterval.MAX_INTERVAL)
.map {
if (it == 0) {
stringResource(R.string.label_default)
} else {
it.toString()
}
}
}
.toImmutableList()
WheelTextPicker(
size = size,
items = items,
size = size,
startIndex = selectedInterval,
onSelectionChanged = { selectedInterval = it },
)

View File

@ -85,12 +85,11 @@ fun PreferenceScreen(
private fun List<Preference>.findHighlightedIndex(highlightKey: String): Int {
return flatMap {
if (it is Preference.PreferenceGroup) {
mutableListOf<String?>()
.apply {
add(null) // Header
addAll(it.preferenceItems.map { groupItem -> groupItem.title })
add(null) // Spacer
}
buildList<String?> {
add(null) // Header
addAll(it.preferenceItems.map { groupItem -> groupItem.title })
add(null) // Spacer
}
} else {
listOf(it.title)
}

View File

@ -36,6 +36,10 @@ import eu.kanade.tachiyomi.data.backup.BackupCreateJob
import eu.kanade.tachiyomi.data.backup.models.Backup
import eu.kanade.tachiyomi.util.system.DeviceUtil
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 tachiyomi.presentation.core.components.LabeledCheckbox
import tachiyomi.presentation.core.components.material.Scaffold
@ -154,7 +158,7 @@ private class CreateBackupScreenModel : StateScreenModel<CreateBackupScreenModel
@Immutable
data class State(
val flags: Set<Int> = BackupChoices.keys,
val flags: PersistentSet<Int> = BackupChoices.keys.toPersistentSet(),
)
}

View File

@ -2,8 +2,8 @@ package eu.kanade.presentation.track
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import eu.kanade.tachiyomi.dev.preview.DummyTracker
import eu.kanade.tachiyomi.ui.manga.track.TrackItem
import eu.kanade.test.DummyTracker
import tachiyomi.domain.track.model.Track
import java.text.DateFormat

View File

@ -34,6 +34,8 @@ import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
import eu.kanade.presentation.theme.TachiyomiTheme
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.WheelNumberPicker
import tachiyomi.presentation.core.components.WheelTextPicker
@ -102,9 +104,9 @@ fun TrackChapterSelector(
title = stringResource(R.string.chapters),
content = {
WheelNumberPicker(
items = range.toImmutableList(),
modifier = Modifier.align(Alignment.Center),
startIndex = selection,
items = range.toList(),
onSelectionChanged = { onSelectionChange(it) },
)
},
@ -117,7 +119,7 @@ fun TrackChapterSelector(
fun TrackScoreSelector(
selection: String,
onSelectionChange: (String) -> Unit,
selections: List<String>,
selections: ImmutableList<String>,
onConfirm: () -> Unit,
onDismissRequest: () -> Unit,
) {
@ -125,9 +127,9 @@ fun TrackScoreSelector(
title = stringResource(R.string.score),
content = {
WheelTextPicker(
items = selections,
modifier = Modifier.align(Alignment.Center),
startIndex = selections.indexOf(selection).takeIf { it > 0 } ?: (selections.size / 2),
items = selections,
onSelectionChanged = { onSelectionChange(selections[it]) },
)
},

View File

@ -4,7 +4,7 @@ import android.graphics.Color
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.track.Tracker
import eu.kanade.tachiyomi.dev.preview.DummyTracker
import eu.kanade.test.DummyTracker
internal class TrackLogoIconPreviewProvider : PreviewParameterProvider<Tracker> {

View File

@ -34,6 +34,8 @@ import eu.kanade.tachiyomi.data.coil.MangaCoverKeyer
import eu.kanade.tachiyomi.data.coil.MangaKeyer
import eu.kanade.tachiyomi.data.coil.TachiyomiImageDecoder
import eu.kanade.tachiyomi.data.notification.Notifications
import eu.kanade.tachiyomi.di.AppModule
import eu.kanade.tachiyomi.di.PreferenceModule
import eu.kanade.tachiyomi.network.NetworkHelper
import eu.kanade.tachiyomi.network.NetworkPreferences
import eu.kanade.tachiyomi.ui.base.delegate.SecureActivityDelegate
@ -54,7 +56,7 @@ import org.acra.ktx.initAcra
import org.acra.sender.HttpSender
import org.conscrypt.Conscrypt
import tachiyomi.core.util.system.logcat
import tachiyomi.presentation.widget.TachiyomiWidgetManager
import tachiyomi.presentation.widget.WidgetManager
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy
@ -125,7 +127,7 @@ class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory {
setAppCompatDelegateThemeMode(Injekt.get<UiPreferences>().themeMode().get())
// Updates widget update
with(TachiyomiWidgetManager(Injekt.get(), Injekt.get())) {
with(WidgetManager(Injekt.get(), Injekt.get())) {
init(ProcessLifecycleOwner.get().lifecycleScope)
}

View File

@ -6,6 +6,7 @@ import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import eu.kanade.tachiyomi.data.database.models.Track
import eu.kanade.tachiyomi.data.track.model.TrackSearch
import kotlinx.collections.immutable.ImmutableList
import okhttp3.OkHttpClient
interface Tracker {
@ -36,7 +37,7 @@ interface Tracker {
fun getCompletionStatus(): Int
fun getScoreList(): List<String>
fun getScoreList(): ImmutableList<String>
// TODO: Store all scores as 10 point in the future maybe?
fun get10PointScore(track: tachiyomi.domain.track.model.Track): Double

View File

@ -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.DeletableTracker
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.json.Json
import uy.kohesive.injekt.injectLazy
@ -74,18 +77,18 @@ class Anilist(id: Long) : BaseTracker(id, "AniList"), DeletableTracker {
override fun getCompletionStatus(): Int = COMPLETED
override fun getScoreList(): List<String> {
override fun getScoreList(): ImmutableList<String> {
return when (scorePreference.get()) {
// 10 point
POINT_10 -> IntRange(0, 10).map(Int::toString)
POINT_10 -> IntRange(0, 10).map(Int::toString).toImmutableList()
// 100 point
POINT_100 -> IntRange(0, 100).map(Int::toString)
POINT_100 -> IntRange(0, 100).map(Int::toString).toImmutableList()
// 5 stars
POINT_5 -> IntRange(0, 5).map { "$it" }
POINT_5 -> IntRange(0, 5).map { "$it" }.toImmutableList()
// Smiley
POINT_3 -> listOf("-", "😦", "😐", "😊")
POINT_3 -> persistentListOf("-", "😦", "😐", "😊")
// 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")
}
}

View File

@ -6,6 +6,8 @@ import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.models.Track
import eu.kanade.tachiyomi.data.track.BaseTracker
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.json.Json
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) }
override fun getScoreList(): List<String> {
return IntRange(0, 10).map(Int::toString)
}
override fun getScoreList(): ImmutableList<String> = SCORE_LIST
override fun displayScore(track: Track): String {
return track.score.toInt().toString()
@ -141,5 +141,9 @@ class Bangumi(id: Long) : BaseTracker(id, "Bangumi") {
const val ON_HOLD = 4
const val DROPPED = 5
const val PLAN_TO_READ = 1
private val SCORE_LIST = IntRange(0, 10)
.map(Int::toString)
.toImmutableList()
}
}

View File

@ -10,6 +10,8 @@ import eu.kanade.tachiyomi.data.track.model.TrackSearch
import eu.kanade.tachiyomi.source.ConfigurableSource
import eu.kanade.tachiyomi.source.Source
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.source.service.SourceManager
import uy.kohesive.injekt.injectLazy
@ -51,7 +53,7 @@ class Kavita(id: Long) : BaseTracker(id, "Kavita"), EnhancedTracker {
override fun getCompletionStatus(): Int = COMPLETED
override fun getScoreList(): List<String> = emptyList()
override fun getScoreList(): ImmutableList<String> = persistentListOf()
override fun displayScore(track: Track): String = ""

View File

@ -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.DeletableTracker
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.json.Json
import uy.kohesive.injekt.injectLazy
@ -54,9 +56,9 @@ class Kitsu(id: Long) : BaseTracker(id, "Kitsu"), DeletableTracker {
override fun getCompletionStatus(): Int = COMPLETED
override fun getScoreList(): List<String> {
override fun getScoreList(): ImmutableList<String> {
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 {

View File

@ -8,6 +8,8 @@ import eu.kanade.tachiyomi.data.track.BaseTracker
import eu.kanade.tachiyomi.data.track.EnhancedTracker
import eu.kanade.tachiyomi.data.track.model.TrackSearch
import eu.kanade.tachiyomi.source.Source
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import okhttp3.Dns
import okhttp3.OkHttpClient
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 getScoreList(): List<String> = emptyList()
override fun getScoreList(): ImmutableList<String> = persistentListOf()
override fun displayScore(track: Track): String = ""

View File

@ -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.toTrackSearch
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 {
@ -18,6 +20,12 @@ class MangaUpdates(id: Long) : BaseTracker(id, "MangaUpdates"), DeletableTracker
const val COMPLETE_LIST = 2
const val UNFINISHED_LIST = 3
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) }
@ -48,11 +56,9 @@ class MangaUpdates(id: Long) : BaseTracker(id, "MangaUpdates"), DeletableTracker
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 = _scoreList[index].toFloat()
override fun indexToScore(index: Int): Float = SCORE_LIST[index].toFloat()
override fun displayScore(track: Track): String = track.score.toString()

View File

@ -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.DeletableTracker
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.json.Json
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_LIST_PREFIX = "my:"
private val SCORE_LIST = IntRange(0, 10)
.map(Int::toString)
.toImmutableList()
}
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 getScoreList(): List<String> {
return IntRange(0, 10).map(Int::toString)
}
override fun getScoreList(): ImmutableList<String> = SCORE_LIST
override fun displayScore(track: Track): String {
return track.score.toInt().toString()

View File

@ -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.DeletableTracker
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.json.Json
import uy.kohesive.injekt.injectLazy
@ -20,6 +22,10 @@ class Shikimori(id: Long) : BaseTracker(id, "Shikimori"), DeletableTracker {
const val DROPPED = 4
const val PLAN_TO_READ = 5
const val REREADING = 6
private val SCORE_LIST = IntRange(0, 10)
.map(Int::toString)
.toImmutableList()
}
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) }
override fun getScoreList(): List<String> {
return IntRange(0, 10).map(Int::toString)
}
override fun getScoreList(): ImmutableList<String> = SCORE_LIST
override fun displayScore(track: Track): String {
return track.score.toInt().toString()

View File

@ -8,6 +8,8 @@ import eu.kanade.tachiyomi.data.track.BaseTracker
import eu.kanade.tachiyomi.data.track.EnhancedTracker
import eu.kanade.tachiyomi.data.track.model.TrackSearch
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.track.model.Track as DomainTrack
@ -41,7 +43,7 @@ class Suwayomi(id: Long) : BaseTracker(id, "Suwayomi"), EnhancedTracker {
override fun getCompletionStatus(): Int = COMPLETED
override fun getScoreList(): List<String> = emptyList()
override fun getScoreList(): ImmutableList<String> = persistentListOf()
override fun displayScore(track: Track): String = ""

View File

@ -1,4 +1,4 @@
package eu.kanade.tachiyomi
package eu.kanade.tachiyomi.di
import android.app.Application
import android.os.Build
@ -7,12 +7,8 @@ import androidx.sqlite.db.SupportSQLiteDatabase
import androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory
import app.cash.sqldelight.db.SqlDriver
import app.cash.sqldelight.driver.android.AndroidSqliteDriver
import eu.kanade.domain.base.BasePreferences
import eu.kanade.domain.source.service.SourcePreferences
import eu.kanade.domain.track.service.TrackPreferences
import eu.kanade.domain.track.store.DelayedTrackingStore
import eu.kanade.domain.ui.UiPreferences
import eu.kanade.tachiyomi.core.security.SecurityPreferences
import eu.kanade.tachiyomi.BuildConfig
import eu.kanade.tachiyomi.data.cache.ChapterCache
import eu.kanade.tachiyomi.data.cache.CoverCache
import eu.kanade.tachiyomi.data.download.DownloadCache
@ -24,19 +20,12 @@ import eu.kanade.tachiyomi.data.track.TrackerManager
import eu.kanade.tachiyomi.extension.ExtensionManager
import eu.kanade.tachiyomi.network.JavaScriptEngine
import eu.kanade.tachiyomi.network.NetworkHelper
import eu.kanade.tachiyomi.network.NetworkPreferences
import eu.kanade.tachiyomi.source.AndroidSourceManager
import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences
import eu.kanade.tachiyomi.util.system.isDevFlavor
import io.requery.android.database.sqlite.RequerySQLiteOpenHelperFactory
import kotlinx.serialization.json.Json
import nl.adaptivity.xmlutil.XmlDeclMode
import nl.adaptivity.xmlutil.core.XmlVersion
import nl.adaptivity.xmlutil.serialization.XML
import tachiyomi.core.preference.AndroidPreferenceStore
import tachiyomi.core.preference.PreferenceStore
import tachiyomi.core.provider.AndroidBackupFolderProvider
import tachiyomi.core.provider.AndroidDownloadFolderProvider
import tachiyomi.data.AndroidDatabaseHandler
import tachiyomi.data.Database
import tachiyomi.data.DatabaseHandler
@ -45,11 +34,7 @@ import tachiyomi.data.History
import tachiyomi.data.Mangas
import tachiyomi.data.StringListColumnAdapter
import tachiyomi.data.UpdateStrategyColumnAdapter
import tachiyomi.domain.backup.service.BackupPreferences
import tachiyomi.domain.download.service.DownloadPreferences
import tachiyomi.domain.library.service.LibraryPreferences
import tachiyomi.domain.source.service.SourceManager
import tachiyomi.domain.sync.SyncPreferences
import tachiyomi.source.local.image.LocalCoverManager
import tachiyomi.source.local.io.LocalSourceFileSystem
import uy.kohesive.injekt.api.InjektModule
@ -156,59 +141,3 @@ class AppModule(val app: Application) : InjektModule {
addSingletonFactory { GoogleDriveService(app) }
}
}
class PreferenceModule(val application: Application) : InjektModule {
override fun InjektRegistrar.registerInjectables() {
addSingletonFactory<PreferenceStore> {
AndroidPreferenceStore(application)
}
addSingletonFactory {
NetworkPreferences(
preferenceStore = get(),
verboseLogging = isDevFlavor,
)
}
addSingletonFactory {
SourcePreferences(get())
}
addSingletonFactory {
SecurityPreferences(get())
}
addSingletonFactory {
LibraryPreferences(get())
}
addSingletonFactory {
ReaderPreferences(get())
}
addSingletonFactory {
TrackPreferences(get())
}
addSingletonFactory {
AndroidDownloadFolderProvider(application)
}
addSingletonFactory {
DownloadPreferences(
folderProvider = get<AndroidDownloadFolderProvider>(),
preferenceStore = get(),
)
}
addSingletonFactory {
AndroidBackupFolderProvider(application)
}
addSingletonFactory {
BackupPreferences(
folderProvider = get<AndroidBackupFolderProvider>(),
preferenceStore = get(),
)
}
addSingletonFactory {
SyncPreferences(get())
}
addSingletonFactory {
UiPreferences(get())
}
addSingletonFactory {
BasePreferences(application, get())
}
}
}

View File

@ -0,0 +1,81 @@
package eu.kanade.tachiyomi.di
import android.app.Application
import eu.kanade.domain.base.BasePreferences
import eu.kanade.domain.source.service.SourcePreferences
import eu.kanade.domain.track.service.TrackPreferences
import eu.kanade.domain.ui.UiPreferences
import eu.kanade.tachiyomi.core.security.SecurityPreferences
import eu.kanade.tachiyomi.network.NetworkPreferences
import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences
import eu.kanade.tachiyomi.util.system.isDevFlavor
import tachiyomi.core.preference.AndroidPreferenceStore
import tachiyomi.core.preference.PreferenceStore
import tachiyomi.core.provider.AndroidBackupFolderProvider
import tachiyomi.core.provider.AndroidDownloadFolderProvider
import tachiyomi.domain.backup.service.BackupPreferences
import tachiyomi.domain.download.service.DownloadPreferences
import tachiyomi.domain.library.service.LibraryPreferences
import tachiyomi.domain.sync.SyncPreferences
import uy.kohesive.injekt.api.InjektModule
import uy.kohesive.injekt.api.InjektRegistrar
import uy.kohesive.injekt.api.addSingletonFactory
import uy.kohesive.injekt.api.get
class PreferenceModule(val app: Application) : InjektModule {
override fun InjektRegistrar.registerInjectables() {
addSingletonFactory<PreferenceStore> {
AndroidPreferenceStore(app)
}
addSingletonFactory {
NetworkPreferences(
preferenceStore = get(),
verboseLogging = isDevFlavor,
)
}
addSingletonFactory {
SourcePreferences(get())
}
addSingletonFactory {
SecurityPreferences(get())
}
addSingletonFactory {
LibraryPreferences(get())
}
addSingletonFactory {
ReaderPreferences(get())
}
addSingletonFactory {
TrackPreferences(get())
}
addSingletonFactory {
AndroidDownloadFolderProvider(app)
}
addSingletonFactory {
DownloadPreferences(
folderProvider = get<AndroidDownloadFolderProvider>(),
preferenceStore = get(),
)
}
addSingletonFactory {
AndroidBackupFolderProvider(app)
}
addSingletonFactory {
BackupPreferences(
folderProvider = get<AndroidBackupFolderProvider>(),
preferenceStore = get(),
)
}
addSingletonFactory {
UiPreferences(get())
}
addSingletonFactory {
BasePreferences(app, get())
}
addSingletonFactory {
SyncPreferences(get())
}
}
}

View File

@ -56,7 +56,7 @@ class AndroidSourceManager(
extensions.forEach { extension ->
extension.sources.forEach {
mutableMap[it.id] = it
registerStubSource(it.toStubSource())
registerStubSource(StubSource.from(it))
}
}
sourcesMapFlow.value = mutableMap

View File

@ -1,17 +1,11 @@
package eu.kanade.tachiyomi.source
import android.graphics.drawable.Drawable
import eu.kanade.domain.source.service.SourcePreferences
import eu.kanade.tachiyomi.extension.ExtensionManager
import tachiyomi.domain.source.model.StubSource
import tachiyomi.source.local.isLocal
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
fun Source.icon(): Drawable? = Injekt.get<ExtensionManager>().getAppIconForSource(this.id)
fun Source.toStubSource(): StubSource = StubSource(id = id, lang = lang, name = name)
fun Source.getNameForMangaInfo(): String {
val preferences = Injekt.get<SourcePreferences>()
val enabledLanguages = preferences.enabledLanguages().get()

View File

@ -1,11 +0,0 @@
package eu.kanade.tachiyomi.source.model
import tachiyomi.data.Chapters
fun SChapter.copyFrom(other: Chapters) {
name = other.name
url = other.url
date_upload = other.date_upload
chapter_number = other.chapter_number.toFloat()
scanlator = other.scanlator
}

View File

@ -3,58 +3,14 @@ package eu.kanade.tachiyomi.source.model
import tachiyomi.data.Mangas
import tachiyomi.domain.manga.model.Manga
fun SManga.copyFrom(other: Mangas) {
if (other.author != null) {
author = other.author
}
if (other.artist != null) {
artist = other.artist
}
if (other.description != null) {
description = other.description
}
if (other.genre != null) {
genre = other.genre!!.joinToString(separator = ", ")
}
if (other.thumbnail_url != null) {
thumbnail_url = other.thumbnail_url
}
status = other.status.toInt()
if (!initialized) {
initialized = other.initialized
}
}
fun Manga.copyFrom(other: Mangas): Manga {
var manga = this
if (other.author != null) {
manga = manga.copy(author = other.author)
}
if (other.artist != null) {
manga = manga.copy(artist = other.artist)
}
if (other.description != null) {
manga = manga.copy(description = other.description)
}
if (other.genre != null) {
manga = manga.copy(genre = other.genre)
}
if (other.thumbnail_url != null) {
manga = manga.copy(thumbnailUrl = other.thumbnail_url)
}
other.author?.let { manga = manga.copy(author = it) }
other.artist?.let { manga = manga.copy(artist = it) }
other.description?.let { manga = manga.copy(description = it) }
other.genre?.let { manga = manga.copy(genre = it) }
other.thumbnail_url?.let { manga = manga.copy(thumbnailUrl = it) }
manga = manga.copy(status = other.status)
if (!initialized) {
manga = manga.copy(initialized = other.initialized)
}

View File

@ -6,6 +6,11 @@ import cafe.adriel.voyager.core.model.screenModelScope
import eu.kanade.domain.extension.interactor.GetExtensionLanguages
import eu.kanade.domain.source.interactor.ToggleLanguage
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.flow.Flow
import kotlinx.coroutines.flow.catch
@ -41,8 +46,8 @@ class ExtensionFilterScreenModel(
.collectLatest { (extensionLanguages, enabledLanguages) ->
mutableState.update {
ExtensionFilterState.Success(
languages = extensionLanguages,
enabledLanguages = enabledLanguages,
languages = extensionLanguages.toImmutableList(),
enabledLanguages = enabledLanguages.toImmutableSet(),
)
}
}
@ -65,8 +70,8 @@ sealed interface ExtensionFilterState {
@Immutable
data class Success(
val languages: List<String>,
val enabledLanguages: Set<String> = emptySet(),
val languages: ImmutableList<String>,
val enabledLanguages: ImmutableSet<String> = persistentSetOf(),
) : ExtensionFilterState {
val isEmpty: Boolean

View File

@ -12,6 +12,9 @@ import eu.kanade.tachiyomi.extension.model.Extension
import eu.kanade.tachiyomi.network.NetworkHelper
import eu.kanade.tachiyomi.source.online.HttpSource
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.flow.Flow
import kotlinx.coroutines.flow.catch
@ -75,10 +78,10 @@ class ExtensionDetailsScreenModel(
}
.catch { throwable ->
logcat(LogPriority.ERROR, throwable)
mutableState.update { it.copy(_sources = emptyList()) }
mutableState.update { it.copy(_sources = persistentListOf()) }
}
.collectLatest { sources ->
mutableState.update { it.copy(_sources = sources) }
mutableState.update { it.copy(_sources = sources.toImmutableList()) }
}
}
}
@ -164,11 +167,11 @@ class ExtensionDetailsScreenModel(
@Immutable
data class State(
val extension: Extension.Installed? = null,
private val _sources: List<ExtensionSourceItem>? = null,
private val _sources: ImmutableList<ExtensionSourceItem>? = null,
) {
val sources: List<ExtensionSourceItem>
get() = _sources.orEmpty()
val sources: ImmutableList<ExtensionSourceItem>
get() = _sources ?: persistentListOf()
val isLoading: Boolean
get() = extension == null || _sources == null

View File

@ -4,6 +4,9 @@ import androidx.compose.runtime.Immutable
import cafe.adriel.voyager.core.model.StateScreenModel
import cafe.adriel.voyager.core.model.screenModelScope
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.flow.Flow
import kotlinx.coroutines.flow.catch
@ -40,11 +43,13 @@ class MigrateMangaScreenModel(
logcat(LogPriority.ERROR, it)
_events.send(MigrationMangaEvent.FailedFetchingFavorites)
mutableState.update { state ->
state.copy(titleList = emptyList())
state.copy(titleList = persistentListOf())
}
}
.map { manga ->
manga.sortedWith(compareBy(String.CASE_INSENSITIVE_ORDER) { it.title })
manga
.sortedWith(compareBy(String.CASE_INSENSITIVE_ORDER) { it.title })
.toImmutableList()
}
.collectLatest { list ->
mutableState.update { it.copy(titleList = list) }
@ -55,11 +60,11 @@ class MigrateMangaScreenModel(
@Immutable
data class State(
val source: Source? = null,
private val titleList: List<Manga>? = null,
private val titleList: ImmutableList<Manga>? = null,
) {
val titles: List<Manga>
get() = titleList.orEmpty()
val titles: ImmutableList<Manga>
get() = titleList ?: persistentListOf()
val isLoading: Boolean
get() = source == null || titleList == null

View File

@ -6,6 +6,9 @@ import cafe.adriel.voyager.core.model.screenModelScope
import eu.kanade.domain.source.interactor.GetSourcesWithFavoriteCount
import eu.kanade.domain.source.interactor.SetMigrateSorting
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.flow.catch
import kotlinx.coroutines.flow.collectLatest
@ -40,7 +43,7 @@ class MigrateSourceScreenModel(
mutableState.update {
it.copy(
isLoading = false,
items = sources,
items = sources.toImmutableList(),
)
}
}
@ -80,7 +83,7 @@ class MigrateSourceScreenModel(
@Immutable
data class State(
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 sortingDirection: SetMigrateSorting.Direction = SetMigrateSorting.Direction.ASCENDING,
) {

View File

@ -7,6 +7,9 @@ import eu.kanade.domain.source.interactor.GetEnabledSources
import eu.kanade.domain.source.interactor.ToggleSource
import eu.kanade.domain.source.interactor.ToggleSourcePin
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.flow.catch
import kotlinx.coroutines.flow.collectLatest
@ -65,14 +68,16 @@ class SourcesScreenModel(
state.copy(
isLoading = false,
items = byLang.flatMap {
listOf(
SourceUiModel.Header(it.key),
*it.value.map { source ->
SourceUiModel.Item(source)
}.toTypedArray(),
)
},
items = byLang
.flatMap {
listOf(
SourceUiModel.Header(it.key),
*it.value.map { source ->
SourceUiModel.Item(source)
}.toTypedArray(),
)
}
.toImmutableList(),
)
}
}
@ -103,7 +108,7 @@ class SourcesScreenModel(
data class State(
val dialog: Dialog? = null,
val isLoading: Boolean = true,
val items: List<SourceUiModel> = emptyList(),
val items: ImmutableList<SourceUiModel> = persistentListOf(),
) {
val isEmpty = items.isEmpty()
}

View File

@ -9,6 +9,10 @@ import eu.kanade.domain.source.service.SourcePreferences
import eu.kanade.presentation.util.ioCoroutineScope
import eu.kanade.tachiyomi.extension.ExtensionManager
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.asCoroutineDispatcher
import kotlinx.coroutines.async
@ -125,9 +129,17 @@ abstract class SearchScreenModel(
// Reuse previous results if possible
if (sameQuery) {
val existingResults = state.value.items
updateItems(sources.associateWith { existingResults[it] ?: SearchItemResult.Loading })
updateItems(
sources
.associateWith { existingResults[it] ?: SearchItemResult.Loading }
.toPersistentMap(),
)
} else {
updateItems(sources.associateWith { SearchItemResult.Loading })
updateItems(
sources
.associateWith { SearchItemResult.Loading }
.toPersistentMap(),
)
}
searchJob = ioCoroutineScope.launch {
@ -160,14 +172,21 @@ abstract class SearchScreenModel(
}
}
private fun updateItems(items: Map<CatalogueSource, SearchItemResult>) {
mutableState.update { it.copy(items = items.toSortedMap(sortComparator(items))) }
private fun updateItems(items: PersistentMap<CatalogueSource, SearchItemResult>) {
mutableState.update {
it.copy(
items = items
.toSortedMap(sortComparator(items))
.toPersistentMap(),
)
}
}
private fun updateItem(source: CatalogueSource, result: SearchItemResult) {
val mutableItems = state.value.items.toMutableMap()
mutableItems[source] = result
updateItems(mutableItems)
val newItems = state.value.items.mutate {
it[source] = result
}
updateItems(newItems)
}
@Immutable
@ -176,7 +195,7 @@ abstract class SearchScreenModel(
val searchQuery: String? = null,
val sourceFilter: SourceFilter = SourceFilter.PinnedOnly,
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 total: Int = items.size

View File

@ -5,6 +5,8 @@ import androidx.compose.runtime.Immutable
import cafe.adriel.voyager.core.model.StateScreenModel
import cafe.adriel.voyager.core.model.screenModelScope
import eu.kanade.tachiyomi.R
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.receiveAsFlow
@ -36,7 +38,9 @@ class CategoryScreenModel(
.collectLatest { categories ->
mutableState.update {
CategoryScreenState.Success(
categories = categories.filterNot(Category::isSystemCategory),
categories = categories
.filterNot(Category::isSystemCategory)
.toImmutableList(),
)
}
}
@ -135,7 +139,7 @@ sealed interface CategoryScreenState {
@Immutable
data class Success(
val categories: List<Category>,
val categories: ImmutableList<Category>,
val dialog: CategoryDialog? = null,
) : CategoryScreenState {

View File

@ -28,6 +28,9 @@ import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.HttpSource
import eu.kanade.tachiyomi.util.chapter.getNextUnread
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.collectLatest
import kotlinx.coroutines.flow.combine
@ -562,16 +565,16 @@ class LibraryScreenModel(
}
fun clearSelection() {
mutableState.update { it.copy(selection = emptyList()) }
mutableState.update { it.copy(selection = persistentListOf()) }
}
fun toggleSelection(manga: LibraryManga) {
mutableState.update { state ->
val newSelection = state.selection.toMutableList().apply {
if (fastAny { it.id == manga.id }) {
removeAll { it.id == manga.id }
val newSelection = state.selection.mutate { list ->
if (list.fastAny { it.id == manga.id }) {
list.removeAll { it.id == manga.id }
} else {
add(manga)
list.add(manga)
}
}
state.copy(selection = newSelection)
@ -584,11 +587,11 @@ class LibraryScreenModel(
*/
fun toggleRangeSelection(manga: LibraryManga) {
mutableState.update { state ->
val newSelection = state.selection.toMutableList().apply {
val lastSelected = lastOrNull()
val newSelection = state.selection.mutate { list ->
val lastSelected = list.lastOrNull()
if (lastSelected?.category != manga.category) {
add(manga)
return@apply
list.add(manga)
return@mutate
}
val items = state.getLibraryItemsByCategoryId(manga.category)
@ -596,17 +599,17 @@ class LibraryScreenModel(
val lastMangaIndex = items.indexOf(lastSelected)
val curMangaIndex = items.indexOf(manga)
val selectedIds = fastMap { it.id }
val selectedIds = list.fastMap { it.id }
val selectionRange = when {
lastMangaIndex < curMangaIndex -> IntRange(lastMangaIndex, curMangaIndex)
curMangaIndex < lastMangaIndex -> IntRange(curMangaIndex, lastMangaIndex)
// We shouldn't reach this point
else -> return@apply
else -> return@mutate
}
val newSelections = selectionRange.mapNotNull { index ->
items[index].takeUnless { it.id in selectedIds }
}
addAll(newSelections)
list.addAll(newSelections)
}
state.copy(selection = newSelection)
}
@ -614,14 +617,14 @@ class LibraryScreenModel(
fun selectAll(index: Int) {
mutableState.update { state ->
val newSelection = state.selection.toMutableList().apply {
val newSelection = state.selection.mutate { list ->
val categoryId = state.categories.getOrNull(index)?.id ?: -1
val selectedIds = fastMap { it.id }
val selectedIds = list.fastMap { it.id }
state.getLibraryItemsByCategoryId(categoryId)
?.fastMapNotNull { item ->
item.libraryManga.takeUnless { it.id in selectedIds }
}
?.let { addAll(it) }
?.let { list.addAll(it) }
}
state.copy(selection = newSelection)
}
@ -629,14 +632,14 @@ class LibraryScreenModel(
fun invertSelection(index: Int) {
mutableState.update { state ->
val newSelection = state.selection.toMutableList().apply {
val newSelection = state.selection.mutate { list ->
val categoryId = state.categories[index].id
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 toRemoveIds = toRemove.fastMap { it.id }
removeAll { it.id in toRemoveIds }
addAll(toAdd)
list.removeAll { it.id in toRemoveIds }
list.addAll(toAdd)
}
state.copy(selection = newSelection)
}
@ -703,7 +706,7 @@ class LibraryScreenModel(
val isLoading: Boolean = true,
val library: LibraryMap = emptyMap(),
val searchQuery: String? = null,
val selection: List<LibraryManga> = emptyList(),
val selection: PersistentList<LibraryManga> = persistentListOf(),
val hasActiveFilters: Boolean = false,
val showCategoryTabs: Boolean = false,
val showMangaCount: Boolean = false,

View File

@ -43,6 +43,7 @@ import eu.kanade.tachiyomi.ui.home.HomeScreen
import eu.kanade.tachiyomi.ui.main.MainActivity
import eu.kanade.tachiyomi.ui.manga.MangaScreen
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
import kotlinx.collections.immutable.persistentListOf
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.receiveAsFlow
@ -154,7 +155,7 @@ object LibraryTab : Tab {
EmptyScreen(
textResource = R.string.information_empty_library,
modifier = Modifier.padding(contentPadding),
actions = listOf(
actions = persistentListOf(
EmptyScreenAction(
stringResId = R.string.getting_started_guide,
icon = Icons.Outlined.HelpOutline,

View File

@ -58,6 +58,7 @@ import eu.kanade.tachiyomi.data.track.model.TrackSearch
import eu.kanade.tachiyomi.util.lang.convertEpochMillisZone
import eu.kanade.tachiyomi.util.system.openInBrowser
import eu.kanade.tachiyomi.util.system.toast
import kotlinx.collections.immutable.ImmutableList
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.distinctUntilChanged
@ -398,7 +399,7 @@ private data class TrackScoreSelectorScreen(
private val tracker: Tracker,
) : StateScreenModel<Model.State>(State(tracker.displayScore(track.toDbTrack()))) {
fun getSelections(): List<String> {
fun getSelections(): ImmutableList<String> {
return tracker.getScoreList()
}

View File

@ -21,6 +21,10 @@ import eu.kanade.tachiyomi.data.download.model.Download
import eu.kanade.tachiyomi.data.library.LibraryUpdateJob
import eu.kanade.tachiyomi.util.lang.toDateKey
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.flow.Flow
import kotlinx.coroutines.flow.catch
@ -106,27 +110,29 @@ class UpdatesScreenModel(
}
}
private fun List<UpdatesWithRelations>.toUpdateItems(): List<UpdatesItem> {
return this.map { update ->
val activeDownload = downloadManager.getQueuedDownloadOrNull(update.chapterId)
val downloaded = downloadManager.isChapterDownloaded(
update.chapterName,
update.scanlator,
update.mangaTitle,
update.sourceId,
)
val downloadState = when {
activeDownload != null -> activeDownload.status
downloaded -> Download.State.DOWNLOADED
else -> Download.State.NOT_DOWNLOADED
private fun List<UpdatesWithRelations>.toUpdateItems(): PersistentList<UpdatesItem> {
return this
.map { update ->
val activeDownload = downloadManager.getQueuedDownloadOrNull(update.chapterId)
val downloaded = downloadManager.isChapterDownloaded(
update.chapterName,
update.scanlator,
update.mangaTitle,
update.sourceId,
)
val downloadState = when {
activeDownload != null -> activeDownload.status
downloaded -> Download.State.DOWNLOADED
else -> Download.State.NOT_DOWNLOADED
}
UpdatesItem(
update = update,
downloadStateProvider = { downloadState },
downloadProgressProvider = { activeDownload?.progress ?: 0 },
selected = update.chapterId in selectedChapterIds,
)
}
UpdatesItem(
update = update,
downloadStateProvider = { downloadState },
downloadProgressProvider = { activeDownload?.progress ?: 0 },
selected = update.chapterId in selectedChapterIds,
)
}
.toPersistentList()
}
fun updateLibrary(): Boolean {
@ -144,17 +150,14 @@ class UpdatesScreenModel(
*/
private fun updateDownloadState(download: Download) {
mutableState.update { state ->
val newItems = state.items.toMutableList().apply {
val modifiedIndex = indexOfFirst { it.update.chapterId == download.chapter.id }
if (modifiedIndex < 0) return@apply
val newItems = state.items.mutate { list ->
val modifiedIndex = list.indexOfFirst { it.update.chapterId == download.chapter.id }
if (modifiedIndex < 0) return@mutate
val item = get(modifiedIndex)
set(
modifiedIndex,
item.copy(
downloadStateProvider = { download.status },
downloadProgressProvider = { download.progress },
),
val item = list[modifiedIndex]
list[modifiedIndex] = item.copy(
downloadStateProvider = { download.status },
downloadProgressProvider = { download.progress },
)
}
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)
it.copy(selected = selected)
}
state.copy(items = newItems)
state.copy(items = newItems.toPersistentList())
}
selectedPositions[0] = -1
@ -353,7 +356,7 @@ class UpdatesScreenModel(
selectedChapterIds.addOrRemove(it.update.chapterId, !it.selected)
it.copy(selected = !it.selected)
}
state.copy(items = newItems)
state.copy(items = newItems.toPersistentList())
}
selectedPositions[0] = -1
selectedPositions[1] = -1
@ -370,7 +373,7 @@ class UpdatesScreenModel(
@Immutable
data class State(
val isLoading: Boolean = true,
val items: List<UpdatesItem> = emptyList(),
val items: PersistentList<UpdatesItem> = persistentListOf(),
val dialog: Dialog? = null,
) {
val selected = items.filter { it.selected }

View File

@ -1,9 +1,11 @@
package eu.kanade.tachiyomi.dev.preview
package eu.kanade.test
import android.graphics.Color
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.track.Tracker
import eu.kanade.tachiyomi.data.track.model.TrackSearch
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList
import okhttp3.OkHttpClient
import tachiyomi.domain.track.model.Track
@ -18,7 +20,7 @@ data class DummyTracker(
val valReadingStatus: Int = 1,
val valRereadingStatus: Int = 1,
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 valSearchResults: List<TrackSearch> = listOf(),
) : Tracker {
@ -48,7 +50,7 @@ data class DummyTracker(
override fun getCompletionStatus(): Int = valCompletionStatus
override fun getScoreList(): List<String> = valScoreList
override fun getScoreList(): ImmutableList<String> = valScoreList
override fun get10PointScore(track: Track): Double = val10PointScore