mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-10-31 14:27:57 +01:00 
			
		
		
		
	| @@ -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) | ||||
|   | ||||
| @@ -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, | ||||
|   | ||||
| @@ -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, | ||||
|   | ||||
| @@ -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, | ||||
|   | ||||
| @@ -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 }, | ||||
|                 ) | ||||
|   | ||||
| @@ -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) | ||||
|         } | ||||
|   | ||||
| @@ -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(), | ||||
|     ) | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -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 | ||||
|  | ||||
|   | ||||
| @@ -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]) }, | ||||
|             ) | ||||
|         }, | ||||
|   | ||||
| @@ -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> { | ||||
|  | ||||
|   | ||||
| @@ -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) | ||||
|         } | ||||
|  | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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") | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -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() | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -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 = "" | ||||
|  | ||||
|   | ||||
| @@ -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 { | ||||
|   | ||||
| @@ -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 = "" | ||||
|  | ||||
|   | ||||
| @@ -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() | ||||
|  | ||||
|   | ||||
| @@ -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() | ||||
|   | ||||
| @@ -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() | ||||
|   | ||||
| @@ -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 = "" | ||||
|  | ||||
|   | ||||
| @@ -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()) | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										81
									
								
								app/src/main/java/eu/kanade/tachiyomi/di/PreferenceModule.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								app/src/main/java/eu/kanade/tachiyomi/di/PreferenceModule.kt
									
									
									
									
									
										Normal 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()) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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() | ||||
|   | ||||
| @@ -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 | ||||
| } | ||||
| @@ -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) | ||||
|     } | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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, | ||||
|     ) { | ||||
|   | ||||
| @@ -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() | ||||
|     } | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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 { | ||||
|  | ||||
|   | ||||
| @@ -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, | ||||
|   | ||||
| @@ -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, | ||||
|   | ||||
| @@ -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() | ||||
|         } | ||||
|  | ||||
|   | ||||
| @@ -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 } | ||||
|   | ||||
| @@ -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 | ||||
| 
 | ||||
| @@ -80,7 +80,7 @@ class EpubFile(file: File) : Closeable { | ||||
|     /** | ||||
|      * 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") | ||||
|             .filter { node -> "application/xhtml+xml" == node.attr("media-type") } | ||||
|             .associateBy { it.attr("id") } | ||||
| @@ -102,10 +102,9 @@ class EpubFile(file: File) : Closeable { | ||||
|             val imageBasePath = getParentDirectory(entryPath) | ||||
|  | ||||
|             document.allElements.forEach { | ||||
|                 if (it.tagName() == "img") { | ||||
|                     result.add(resolveZipPath(imageBasePath, it.attr("src"))) | ||||
|                 } else if (it.tagName() == "image") { | ||||
|                     result.add(resolveZipPath(imageBasePath, it.attr("xlink:href"))) | ||||
|                 when (it.tagName()) { | ||||
|                     "img" -> result.add(resolveZipPath(imageBasePath, it.attr("src"))) | ||||
|                     "image" -> result.add(resolveZipPath(imageBasePath, it.attr("xlink:href"))) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|   | ||||
| @@ -23,6 +23,12 @@ class StubSource( | ||||
|  | ||||
|     override fun toString(): String = | ||||
|         if (isInvalid.not()) "$name (${lang.uppercase()})" else id.toString() | ||||
|  | ||||
|     companion object { | ||||
|         fun from(source: Source): StubSource { | ||||
|             return StubSource(id = source.id, lang = source.lang, name = source.name) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| class SourceNotInstalledException : Exception() | ||||
|   | ||||
| @@ -14,7 +14,6 @@ corektx = "androidx.core:core-ktx:1.12.0" | ||||
| splashscreen = "androidx.core:core-splashscreen:1.0.1" | ||||
| recyclerview = "androidx.recyclerview:recyclerview:1.3.2" | ||||
| viewpager = "androidx.viewpager:viewpager:1.1.0-alpha01" | ||||
| glance = "androidx.glance:glance-appwidget:1.0.0" | ||||
| profileinstaller = "androidx.profileinstaller:profileinstaller:1.3.1" | ||||
|  | ||||
| lifecycle-common = { module = "androidx.lifecycle:lifecycle-common", version.ref = "lifecycle_version" } | ||||
|   | ||||
| @@ -19,7 +19,11 @@ material-icons = { module = "androidx.compose.material:material-icons-extended" | ||||
| # Some components aren't available in Material3 | ||||
| material-core = { module = "androidx.compose.material:material" } | ||||
|  | ||||
| glance = "androidx.glance:glance-appwidget:1.0.0" | ||||
|  | ||||
| accompanist-webview = { module = "com.google.accompanist:accompanist-webview", version.ref = "accompanist" } | ||||
| accompanist-permissions = { module = "com.google.accompanist:accompanist-permissions", version.ref = "accompanist" } | ||||
| accompanist-themeadapter = { module = "com.google.accompanist:accompanist-themeadapter-material3", version.ref = "accompanist" } | ||||
| accompanist-systemuicontroller = { module = "com.google.accompanist:accompanist-systemuicontroller", version.ref = "accompanist" } | ||||
|  | ||||
| lintchecks = { module = "com.slack.lint.compose:compose-lint-checks", version = "1.2.0" } | ||||
| @@ -7,6 +7,8 @@ xml_serialization_version = "0.86.2" | ||||
| reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin_version" } | ||||
| gradle = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin_version" } | ||||
|  | ||||
| immutables = { module = "org.jetbrains.kotlinx:kotlinx-collections-immutable", version = "0.3.6" } | ||||
|  | ||||
| coroutines-bom = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-bom", version = "1.7.3" } | ||||
| coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core" } | ||||
| coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android" } | ||||
|   | ||||
| @@ -5,7 +5,7 @@ shizuku_version = "12.2.0" | ||||
| sqlite = "2.4.0" | ||||
| sqldelight = "2.0.0" | ||||
| leakcanary = "2.12" | ||||
| voyager = "1.0.0-rc09" | ||||
| voyager = "1.0.0-rc10" | ||||
| richtext = "0.17.0" | ||||
|  | ||||
| [libraries] | ||||
|   | ||||
| @@ -566,8 +566,8 @@ | ||||
|     <string name="rotation_portrait">رأسي</string> | ||||
|     <string name="rotation_type">التدوير</string> | ||||
|     <string name="automatic_background">تلقائيًّا</string> | ||||
|     <string name="pref_create_folder_per_manga_summary">إنشاء مجلدات وفقا لعنوان الإدخالات</string> | ||||
|     <string name="pref_create_folder_per_manga">حفظ الصفحات في مجلدات منفصلة</string> | ||||
|     <string name="pref_create_folder_per_manga_summary">يُنشِئ مجلدات وفقًا لعناوين المدخلات</string> | ||||
|     <string name="pref_create_folder_per_manga">احفظ الصفحات في مجلدات منفصلة</string> | ||||
|     <string name="pref_reader_actions">الإجراءات</string> | ||||
|     <string name="pref_grayscale">تدرج رمادي</string> | ||||
|     <string name="exclude">إستثناء: %s</string> | ||||
| @@ -882,11 +882,18 @@ | ||||
|     <string name="sort_category_confirmation">أتريد ترتيب الفئات حسب الحروف؟</string> | ||||
|     <string name="source_settings">إعدادات المصادر</string> | ||||
|     <string name="app_settings">إعدادات التطبيق</string> | ||||
|     <string name="file_null_uri_error">ما استطاع محدِّد الملفات من إدخال الملف في التطبيق</string> | ||||
|     <string name="file_null_uri_error">لا ملفات حُدِّدت</string> | ||||
|     <string name="label_data_storage">البيانات والتخزين</string> | ||||
|     <string name="relative_time_span_never">أبدًا</string> | ||||
|     <string name="pref_flash_page_summ">يخفِّف الحرق في شاشات الحبر</string> | ||||
|     <string name="last_auto_backup_info">آخر احتياط تلقائي: %s</string> | ||||
|     <string name="pref_flash_page">أشرق الشاشة بِيضًا إذا تغيرت الصفحة</string> | ||||
|     <string name="pref_storage_usage">التخزين</string> | ||||
|     <string name="action_sort_tracker_score">نقاط المتتبع</string> | ||||
|     <string name="action_create">أنشئ</string> | ||||
|     <string name="action_apply">نفِّذ</string> | ||||
|     <string name="action_revert_to_default">صفِّر</string> | ||||
|     <string name="no_scanlators_found">لم يُعثَر على مترجمين</string> | ||||
|     <string name="scanlator">المترجم</string> | ||||
|     <string name="exclude_scanlators">احجب بعض المترجمين</string> | ||||
| </resources> | ||||
| @@ -271,7 +271,7 @@ | ||||
|     <string name="action_start">Iniciar</string> | ||||
|     <string name="action_retry">Reintentar</string> | ||||
|     <string name="pref_clear_cookies">Borrar cookies</string> | ||||
|     <string name="label_network">Red</string> | ||||
|     <string name="label_network">Redes</string> | ||||
|     <string name="restoring_backup_canceled">Se canceló la restauración</string> | ||||
|     <string name="restoring_backup_error">La restauración de la copia de seguridad falló</string> | ||||
|     <string name="restoring_backup">Restaurando copia de seguridad</string> | ||||
| @@ -291,8 +291,8 @@ | ||||
|     <string name="invalid_backup_file_missing_manga">La copia de seguridad no contiene ningún manga.</string> | ||||
|     <string name="invalid_backup_file">Archivo de copia de seguridad invalido</string> | ||||
|     <string name="backup_created">Copia de seguridad creada</string> | ||||
|     <string name="pref_backup_slots">Máximo de copias de seguridad</string> | ||||
|     <string name="pref_backup_interval">Frecuencia de respaldo</string> | ||||
|     <string name="pref_backup_slots">Máximo de copias de seguridad automáticas</string> | ||||
|     <string name="pref_backup_interval">Frecuencia de respaldo automático</string> | ||||
|     <string name="pref_backup_directory">Directorio de copia de seguridad</string> | ||||
|     <string name="pref_restore_backup_summ">Restaurar biblioteca desde archivo de copia de seguridad</string> | ||||
|     <string name="cache_deleted">Caché borrada. %1$d archivos se han eliminado</string> | ||||
| @@ -523,7 +523,7 @@ | ||||
|     <string name="rotation_type">Rotación</string> | ||||
|     <string name="nav_zone_right">Derecha</string> | ||||
|     <string name="nav_zone_left">Izquierda</string> | ||||
|     <string name="pref_create_folder_per_manga_summary">Crea carpetas según el título del manga</string> | ||||
|     <string name="pref_create_folder_per_manga_summary">Crear carpetas según el título del manga</string> | ||||
|     <string name="pref_grayscale">Escala de grises</string> | ||||
|     <string name="update_check_eol">Está versión de Android ya no está soportada</string> | ||||
|     <string name="clipboard_copy_error">Falló al copiar en el portapapeles</string> | ||||
| @@ -708,7 +708,7 @@ | ||||
|     <string name="pref_reader_summary">Modo lectura, apariencia, navegación</string> | ||||
|     <string name="pref_downloads_summary">Descargas automáticas y por adelantado</string> | ||||
|     <string name="pref_browse_summary">Fuentes, extensiones, búsqueda global</string> | ||||
|     <string name="pref_backup_summary">Respaldo manual y automático</string> | ||||
|     <string name="pref_backup_summary">Respaldo manual y automático, espacio de almacenamiento</string> | ||||
|     <string name="pref_security_summary">Bloqueo de aplicación, pantalla de seguridad</string> | ||||
|     <string name="pref_advanced_summary">Guardar registros de fallo, optimizaciones de bateria</string> | ||||
|     <string name="pref_tracking_summary">Sincronización de progreso unidireccional, sincronización mejorada</string> | ||||
| @@ -747,7 +747,7 @@ | ||||
|     <string name="unknown_title">Título desconocido</string> | ||||
|     <string name="download_notifier_cache_renewal">Comprobando descargas</string> | ||||
|     <string name="invalid_location">Ubicación incorrecta: %s</string> | ||||
|     <string name="pref_reset_user_agent_string">Reestablecer el nombre del navegador</string> | ||||
|     <string name="pref_reset_user_agent_string">Restablecer el nombre del navegador</string> | ||||
|     <string name="update_already_running">Una actualización está actualmente en curso</string> | ||||
|     <string name="are_you_sure">¿Estás seguro\?</string> | ||||
|     <string name="label_titles_section">Manga</string> | ||||
| @@ -834,5 +834,18 @@ | ||||
|     <string name="sort_category_confirmation">¿Quieres ordenar las categorías de forma alfabética\?</string> | ||||
|     <string name="source_settings">Configuraciónes de fuente</string> | ||||
|     <string name="app_settings">Configuraciones</string> | ||||
|     <string name="file_null_uri_error">El selector de archivos no pudo devolver el archivo a la aplicación</string> | ||||
|     <string name="file_null_uri_error">Ningún archivo seleccionado</string> | ||||
|     <string name="action_create">Crear</string> | ||||
|     <string name="relative_time_span_never">Nunca</string> | ||||
|     <string name="pref_flash_page_summ">Reducir el ghosting en pantallas de tinta electrónica</string> | ||||
|     <string name="action_apply">Aplicar</string> | ||||
|     <string name="action_revert_to_default">Restablecer configuración predeterminada</string> | ||||
|     <string name="last_auto_backup_info">Última copia de seguridad automática: %s</string> | ||||
|     <string name="no_scanlators_found">No se encontraron scanlators</string> | ||||
|     <string name="scanlator">Scanlator</string> | ||||
|     <string name="pref_flash_page">Destello blanco al cambiar de página</string> | ||||
|     <string name="pref_storage_usage">Uso de almacenamiento</string> | ||||
|     <string name="action_sort_tracker_score">Puntuación del rastreador</string> | ||||
|     <string name="label_data_storage">Datos y almacenamiento</string> | ||||
|     <string name="exclude_scanlators">Excluir scanlators</string> | ||||
| </resources> | ||||
| @@ -162,8 +162,8 @@ | ||||
|     <string name="pref_restore_backup">Restaura una còpia de seguretat</string> | ||||
|     <string name="pref_restore_backup_summ">Restaura la biblioteca del fitxer de còpia de seguretat</string> | ||||
|     <string name="pref_backup_directory">Ubicació de la còpia de seguretat</string> | ||||
|     <string name="pref_backup_interval">Freqüència de la còpia de seguretat</string> | ||||
|     <string name="pref_backup_slots">Màxim de còpies de seguretat</string> | ||||
|     <string name="pref_backup_interval">Freqüència de la còpia de seguretat automàtica</string> | ||||
|     <string name="pref_backup_slots">Màxim de còpies de seguretat automàtiques</string> | ||||
|     <string name="backup_created">S’ha creat la còpia de seguretat</string> | ||||
|     <string name="restore_completed">S’ha completat la restauració</string> | ||||
|     <string name="backup_choice">De què voleu fer una còpia de seguretat\?</string> | ||||
| @@ -317,6 +317,7 @@ | ||||
|     <string name="lock_never">Mai</string> | ||||
|     <plurals name="lock_after_mins"> | ||||
|         <item quantity="one">Després d’%1$s minut</item> | ||||
|         <item quantity="many">Després de %1$s minuts</item> | ||||
|         <item quantity="other">Després de %1$s minuts</item> | ||||
|     </plurals> | ||||
|     <string name="secure_screen">Mode discret</string> | ||||
| @@ -329,6 +330,7 @@ | ||||
|     <string name="pref_category_display">Visualització</string> | ||||
|     <plurals name="notification_chapters_generic"> | ||||
|         <item quantity="one">%1$d capítol nou</item> | ||||
|         <item quantity="many">%1$d capítols nous</item> | ||||
|         <item quantity="other">%1$d capítols nous</item> | ||||
|     </plurals> | ||||
|     <string name="notification_chapters_single">Capítol %1$s</string> | ||||
| @@ -336,6 +338,7 @@ | ||||
|     <string name="notification_chapters_multiple">Capítols %1$s</string> | ||||
|     <plurals name="notification_chapters_multiple_and_more"> | ||||
|         <item quantity="one">Capítols %1$s i 1 més</item> | ||||
|         <item quantity="many">Capítols %1$s i %2$d més</item> | ||||
|         <item quantity="other">Capítols %1$s i %2$d més</item> | ||||
|     </plurals> | ||||
|     <string name="hide_notification_content">Amaga el contingut de les notificacions</string> | ||||
| @@ -347,6 +350,7 @@ | ||||
|     <string name="pref_always_show_chapter_transition">Mostra sempre la transició de capítol</string> | ||||
|     <plurals name="notification_new_chapters_summary"> | ||||
|         <item quantity="one">Per a %d element</item> | ||||
|         <item quantity="many">Per a %d elements</item> | ||||
|         <item quantity="other">Per a %d elements</item> | ||||
|     </plurals> | ||||
|     <string name="action_menu">Menú</string> | ||||
| @@ -356,6 +360,7 @@ | ||||
|     <string name="action_move_to_bottom">Mou a sota de tot</string> | ||||
|     <plurals name="update_check_notification_ext_updates"> | ||||
|         <item quantity="one">Hi ha una actualització d’una extensió</item> | ||||
|         <item quantity="many">Hi ha actualitzacions de %d extensions</item> | ||||
|         <item quantity="other">Hi ha actualitzacions de %d extensions</item> | ||||
|     </plurals> | ||||
|     <string name="channel_ext_updates">Actualitzacions d’extensions</string> | ||||
| @@ -391,6 +396,7 @@ | ||||
|     <string name="downloaded_only_summary">Filtra tots els elements de la vostra biblioteca</string> | ||||
|     <plurals name="download_queue_summary"> | ||||
|         <item quantity="one">En resta %1$s</item> | ||||
|         <item quantity="many">En resten %1$s</item> | ||||
|         <item quantity="other">En resten %1$s</item> | ||||
|     </plurals> | ||||
|     <string name="gray_background">Gris</string> | ||||
| @@ -399,11 +405,13 @@ | ||||
|     <string name="battery_optimization_setting_activity_not_found">No s’ha pogut obrir la configuració del dispositiu</string> | ||||
|     <plurals name="restore_completed_message"> | ||||
|         <item quantity="one">Fet en %1$s amb %2$s error</item> | ||||
|         <item quantity="many">Fet en %1$s amb %2$s errors</item> | ||||
|         <item quantity="other">Fet en %1$s amb %2$s errors</item> | ||||
|     </plurals> | ||||
|     <string name="pref_true_color_summary">Redueix les bandes de colors, però pot afectar el rendiment</string> | ||||
|     <plurals name="num_categories"> | ||||
|         <item quantity="one">%d categoria</item> | ||||
|         <item quantity="many">%d categories</item> | ||||
|         <item quantity="other">%d categories</item> | ||||
|     </plurals> | ||||
|     <string name="tracking_info">La sincronització és unidireccional per a actualitzar el progrés dels capítols als serveis de seguiment externs. Configureu el seguiment d’elements individuals al seu botó de seguiment.</string> | ||||
| @@ -433,6 +441,7 @@ | ||||
|     <string name="loader_not_implemented_error">No s’ha trobat la font</string> | ||||
|     <plurals name="manga_num_chapters"> | ||||
|         <item quantity="one">%1$s capítol</item> | ||||
|         <item quantity="many">%1$s capítols</item> | ||||
|         <item quantity="other">%1$s capítols</item> | ||||
|     </plurals> | ||||
|     <string name="unknown_status">Estat desconegut</string> | ||||
| @@ -451,6 +460,7 @@ | ||||
|     <string name="action_sort_date_added">Data d’incorporació</string> | ||||
|     <plurals name="num_trackers"> | ||||
|         <item quantity="one">%d servei de seguiment</item> | ||||
|         <item quantity="many">%d serveis de seguiment</item> | ||||
|         <item quantity="other">%d serveis de seguiment</item> | ||||
|     </plurals> | ||||
|     <string name="no_pinned_sources">No teniu cap origen fixat</string> | ||||
| @@ -465,6 +475,7 @@ | ||||
|     <string name="parental_controls_info">Això no evita que les extensions no oficials o possiblement mal etiquetades puguin mostrar contingut NSFW (+18) a l’aplicació.</string> | ||||
|     <plurals name="missing_chapters_warning"> | ||||
|         <item quantity="one">S’ha omès %d capítol. És possible que manqui a la font o que hagi estat filtrat</item> | ||||
|         <item quantity="many">S’han omès %d capítols. És possible que manquin a la font o que hagin estat filtrats</item> | ||||
|         <item quantity="other">S’han omès %d capítols. És possible que manquin a la font o que hagin estat filtrats</item> | ||||
|     </plurals> | ||||
|     <string name="no_chapters_error">No s’ha trobat cap capítol</string> | ||||
| @@ -563,6 +574,7 @@ | ||||
|     <string name="enhanced_services">Serveis de seguiment millorats</string> | ||||
|     <plurals name="relative_time"> | ||||
|         <item quantity="one">Ahir</item> | ||||
|         <item quantity="many">Fa %1$d dies</item> | ||||
|         <item quantity="other">Fa %1$d dies</item> | ||||
|     </plurals> | ||||
|     <string name="relative_time_today">Avui</string> | ||||
| @@ -692,11 +704,12 @@ | ||||
|     <string name="crash_screen_description">S’ha produït un error inesperat al %s. Us suggerim que compartiu el registre d’errors al nostre canal d’assistència al Discord.</string> | ||||
|     <plurals name="next_unread_chapters"> | ||||
|         <item quantity="one">El següent capítol no llegit</item> | ||||
|         <item quantity="many">Els següents %d capítols no llegits</item> | ||||
|         <item quantity="other">Els següents %d capítols no llegits</item> | ||||
|     </plurals> | ||||
|     <string name="missing_storage_permission">No s’han concedit permisos d’emmagatzematge</string> | ||||
|     <string name="popular">Populars</string> | ||||
|     <string name="pref_backup_summary">Còpies de seguretat automàtiques i manuals</string> | ||||
|     <string name="pref_backup_summary">Còpies de seguretat automàtiques i manuals i espai d’emmagatzematge</string> | ||||
|     <string name="pref_reader_summary">Mode de lectura, visualització i navegació</string> | ||||
|     <string name="pref_downloads_summary">Baixades automàtiques i per avançat</string> | ||||
|     <string name="multi_lang">Múltiples</string> | ||||
| @@ -750,6 +763,7 @@ | ||||
|     <string name="information_required_plain">*obligatori</string> | ||||
|     <plurals name="download_amount"> | ||||
|         <item quantity="one">El següent capítol</item> | ||||
|         <item quantity="many">Els següents %d capítols</item> | ||||
|         <item quantity="other">Els següents %d capítols</item> | ||||
|     </plurals> | ||||
|     <string name="information_no_manga_category">La categoria és buida</string> | ||||
| @@ -773,6 +787,7 @@ | ||||
|     <string name="pref_page_rotate">Rota les pàgines amples perquè s’ajustin a la pantalla</string> | ||||
|     <plurals name="missing_chapters"> | ||||
|         <item quantity="one">Manca %1$s capítol</item> | ||||
|         <item quantity="many">Manquen %1$s capítols</item> | ||||
|         <item quantity="other">Manquen %1$s capítols</item> | ||||
|     </plurals> | ||||
|     <string name="pref_debug_info">Informació de depuració</string> | ||||
| @@ -781,6 +796,7 @@ | ||||
|     <string name="action_sort_next_updated">Pròxima actualització prevista</string> | ||||
|     <plurals name="day"> | ||||
|         <item quantity="one">1 dia</item> | ||||
|         <item quantity="many">%d dies</item> | ||||
|         <item quantity="other">%d dies</item> | ||||
|     </plurals> | ||||
|     <string name="action_filter_interval_long">Obtén mensualment (28 dies)</string> | ||||
| @@ -818,5 +834,18 @@ | ||||
|     <string name="sort_category_confirmation">Voleu ordenar les categories alfabèticament\?</string> | ||||
|     <string name="source_settings">Configuració de la font</string> | ||||
|     <string name="app_settings">Configuració de l’aplicació</string> | ||||
|     <string name="file_null_uri_error">El selector de fitxers no ha retornat cap fitxer a l’aplicació</string> | ||||
|     <string name="file_null_uri_error">No s’ha seleccionat cap fitxer</string> | ||||
|     <string name="action_create">Crea</string> | ||||
|     <string name="relative_time_span_never">Mai</string> | ||||
|     <string name="pref_flash_page_summ">Redueix l’efecte fantasma en pantalles de tinta electrònica</string> | ||||
|     <string name="action_apply">Aplica</string> | ||||
|     <string name="action_revert_to_default">Torna a la configuració per defecte</string> | ||||
|     <string name="last_auto_backup_info">Darrera còpia de seguretat automàtica: %s</string> | ||||
|     <string name="no_scanlators_found">No s’ha trobat cap scanlator</string> | ||||
|     <string name="scanlator">Scanlator</string> | ||||
|     <string name="pref_flash_page">Centelleig blanc en canviar de pàgina</string> | ||||
|     <string name="pref_storage_usage">Ús de l’emmagatzematge</string> | ||||
|     <string name="action_sort_tracker_score">Puntuació del servei de seguiment</string> | ||||
|     <string name="label_data_storage">Dades i emmagatzematge</string> | ||||
|     <string name="exclude_scanlators">Exclou scanlators</string> | ||||
| </resources> | ||||
| @@ -162,8 +162,8 @@ | ||||
|     <string name="pref_restore_backup">Επαναφορά αντιγράφου ασφαλείας</string> | ||||
|     <string name="pref_restore_backup_summ">Επαναφορά βιβλιοθήκης από αρχείο αντιγράφου ασφαλείας</string> | ||||
|     <string name="pref_backup_directory">Τοποθεσία αντιγράφων ασφαλείας</string> | ||||
|     <string name="pref_backup_interval">Συχνότητα αντίγραφου ασφάλειας</string> | ||||
|     <string name="pref_backup_slots">Μέγιστα αντίγραφα ασφαλείας</string> | ||||
|     <string name="pref_backup_interval">Συχνότητα αυτόματων αντιγράφων ασφαλείας</string> | ||||
|     <string name="pref_backup_slots">Μέγιστα αυτόματα αντίγραφα ασφαλείας</string> | ||||
|     <string name="backup_created">Δημιουργήθηκε αντίγραφο ασφαλείας</string> | ||||
|     <string name="restore_completed">Η επαναφορά ολοκληρώθηκε</string> | ||||
|     <string name="backup_choice">Τι αντίγραφο ασφαλείας θέλετε να δημιουργήσετε;</string> | ||||
| @@ -703,7 +703,7 @@ | ||||
|     <string name="pref_library_summary">Κατηγορίες, καθολική ενημέρωση, σύρσιμο κεφαλαίου</string> | ||||
|     <string name="pref_reader_summary">Λειτουργία ανάγνωσης, οθόνη, πλοήγηση</string> | ||||
|     <string name="pref_tracking_summary">Μονόδρομος συγχρονισμός προόδου, ενισχυμένος συγχρονισμός</string> | ||||
|     <string name="pref_backup_summary">Χειροκίνητα & αυτόματα αντίγραφα ασφαλείας</string> | ||||
|     <string name="pref_backup_summary">Χειροκίνητα & αυτόματα αντίγραφα ασφαλείας, χώρος αποθήκευσης</string> | ||||
|     <string name="pref_security_summary">Κλείδωμα εφαρμογής, ασφαλής οθόνη</string> | ||||
|     <string name="crash_screen_restart_application">Επανεκκίνηση της εφαρμογής</string> | ||||
|     <string name="pref_downloads_summary">Αυτόματη λήψη, λήψη εκ των προτέρων</string> | ||||
| @@ -818,5 +818,18 @@ | ||||
|     <string name="notification_updating_progress">Ενημέρωση βιβλιοθήκης… (%s)</string> | ||||
|     <string name="sort_category_confirmation">Θέλετε να ταξινομήσετε τις κατηγορίες αλφαβητικά;</string> | ||||
|     <string name="source_settings">Ρυθμίσεις πηγών</string> | ||||
|     <string name="file_null_uri_error">Το πρόγραμμα επιλογής αρχείων απέτυχε να επιστρέψει το αρχείο στην εφαρμογή</string> | ||||
|     <string name="file_null_uri_error">Δεν έχει επιλεγεί αρχείο</string> | ||||
|     <string name="relative_time_span_never">Ποτέ</string> | ||||
|     <string name="pref_flash_page_summ">Μειώνει το ghosting σε οθόνες e-ink</string> | ||||
|     <string name="last_auto_backup_info">Τελευταία αυτόματη δημιουργία αντιγράφων ασφαλείας: %s</string> | ||||
|     <string name="pref_flash_page">Λευκό φλας κατά την αλλαγή σελίδας</string> | ||||
|     <string name="pref_storage_usage">Χρήση αποθηκευτικού χώρου</string> | ||||
|     <string name="action_sort_tracker_score">Σκορ tracker</string> | ||||
|     <string name="label_data_storage">Δεδομένα και χώρος αποθήκευσης</string> | ||||
|     <string name="action_create">Δημιουργία</string> | ||||
|     <string name="action_apply">Υποβολή</string> | ||||
|     <string name="action_revert_to_default">Επαναφορά προεπιλογής</string> | ||||
|     <string name="no_scanlators_found">Δε βρέθηκαν scanlators</string> | ||||
|     <string name="scanlator">Scanlator</string> | ||||
|     <string name="exclude_scanlators">Εξαίρεση scanlator</string> | ||||
| </resources> | ||||
| @@ -572,8 +572,8 @@ | ||||
|     <string name="action_display_show_number_of_items">Mostrar el número de elementos</string> | ||||
|     <string name="action_sort_chapter_fetch_date">Fecha de obtención del capítulo</string> | ||||
|     <string name="rotation_type">Tipo de rotación</string> | ||||
|     <string name="pref_create_folder_per_manga_summary">Crea carpetas según el título de los elementos</string> | ||||
|     <string name="pref_create_folder_per_manga">Guardar páginas en carpetas separadas</string> | ||||
|     <string name="pref_create_folder_per_manga_summary">Crea carpetas según el título de las entradas</string> | ||||
|     <string name="pref_create_folder_per_manga">Guardar las páginas en carpetas independientes</string> | ||||
|     <string name="pref_reader_actions">Acciones</string> | ||||
|     <string name="pref_grayscale">Escala de grises</string> | ||||
|     <string name="restore_miui_warning">Es posible que las funciones de copia de respaldo y restauración no funcionen correctamente si la opción «Optimización de MIUI» está desactivada.</string> | ||||
| @@ -865,11 +865,18 @@ | ||||
|     <string name="app_settings">Ajustes de la aplicación</string> | ||||
|     <string name="action_sort_category">Ordenar categorías</string> | ||||
|     <string name="sort_category_confirmation">¿Quieres ordenar las categorías de forma alfabética\?</string> | ||||
|     <string name="file_null_uri_error">La pantalla de selección de archivos no ha devuelto ningún archivo</string> | ||||
|     <string name="file_null_uri_error">Ningún archivo seleccionado</string> | ||||
|     <string name="relative_time_span_never">Nunca</string> | ||||
|     <string name="pref_flash_page_summ">Reducir el ghosting en las pantallas de tinta electrónica</string> | ||||
|     <string name="last_auto_backup_info">Última copia de seguridad automática: %s</string> | ||||
|     <string name="pref_flash_page">Parpadeo en blanco al cambiar de página</string> | ||||
|     <string name="label_data_storage">Datos y almacenamiento</string> | ||||
|     <string name="pref_storage_usage">Almacenamiento utilizado</string> | ||||
|     <string name="action_sort_tracker_score">Puntuación del rastreador</string> | ||||
|     <string name="action_apply">Aplicar</string> | ||||
|     <string name="action_revert_to_default">Volver a la configuración predeterminada</string> | ||||
|     <string name="action_create">Crear</string> | ||||
|     <string name="no_scanlators_found">Sin ningún scanlators</string> | ||||
|     <string name="scanlator">Scanlator</string> | ||||
|     <string name="exclude_scanlators">Omitir a los scanlators</string> | ||||
| </resources> | ||||
| @@ -15,8 +15,8 @@ | ||||
|     <string name="action_oldest">Pinakaluma</string> | ||||
|     <string name="action_newest">Pinakabago</string> | ||||
|     <string name="action_sort">Ayusin</string> | ||||
|     <string name="action_cancel_all">Ikansela lahat</string> | ||||
|     <string name="action_cancel">Ikansela</string> | ||||
|     <string name="action_cancel_all">Kanselahin lahat</string> | ||||
|     <string name="action_cancel">Kanselahin</string> | ||||
|     <string name="action_unpin">I-unpin</string> | ||||
|     <string name="action_pin">I-pin</string> | ||||
|     <string name="action_disable">Isara</string> | ||||
| @@ -380,7 +380,7 @@ | ||||
|     <string name="unknown_author">Di alam ang may-akda</string> | ||||
|     <string name="unknown">Di alam</string> | ||||
|     <string name="ongoing">Patuloy</string> | ||||
|     <string name="local_source_help_guide">Gabay sa Lokal na Source</string> | ||||
|     <string name="local_source_help_guide">Gabay sa Lokal na source</string> | ||||
|     <string name="browse">Maghanap</string> | ||||
|     <string name="latest">Pinakabago</string> | ||||
|     <string name="action_global_search_query">Hinanap ang \"%1$s\" sa lahat</string> | ||||
| @@ -388,7 +388,7 @@ | ||||
|     <string name="pinned_sources">Naka-pin</string> | ||||
|     <string name="last_used_source">Huling ginamit</string> | ||||
|     <string name="other_source">Iba pa</string> | ||||
|     <string name="local_source">Lokal na Source</string> | ||||
|     <string name="local_source">Lokal na source</string> | ||||
|     <string name="no_results_found">Walang nakitang resulta</string> | ||||
|     <string name="no_more_results">Wala na\'ng resulta</string> | ||||
|     <string name="tabs_header">Mga Tab</string> | ||||
| @@ -453,7 +453,7 @@ | ||||
|         <item quantity="one">%d tracker</item> | ||||
|         <item quantity="other">%d na mga tracker</item> | ||||
|     </plurals> | ||||
|     <string name="no_pinned_sources">Wala kang naka-pin na pinagkukunan</string> | ||||
|     <string name="no_pinned_sources">Wala kang naka-pin na source</string> | ||||
|     <string name="channel_complete">Tapos na</string> | ||||
|     <string name="channel_errors">Mga error</string> | ||||
|     <string name="channel_progress">Takbo</string> | ||||
| @@ -482,11 +482,11 @@ | ||||
|     <string name="pref_clear_history">Linisin ang nakaraan</string> | ||||
|     <string name="clear_history_completed">Nalinis na ang nakaraan</string> | ||||
|     <string name="clear_history_confirmation">Sigurado ka ba talaga\? Mawawala ang buong nakaraan.</string> | ||||
|     <string name="migration_help_guide">Gabay sa Paglipat ng Source</string> | ||||
|     <string name="migration_help_guide">Gabay sa Paglipat ng source</string> | ||||
|     <string name="spen_next_page">Abante</string> | ||||
|     <string name="spen_previous_page">Balik</string> | ||||
|     <string name="file_picker_error">Walang nakitang app para makapili</string> | ||||
|     <string name="pref_show_nsfw_source">Ipakita sa mga source at extension</string> | ||||
|     <string name="pref_show_nsfw_source">Ipakita sa mga listahan ng source at extension</string> | ||||
|     <string name="pref_category_nsfw_content">Mga source na NSFW (18+)</string> | ||||
|     <string name="myanimelist_relogin">Mag-login muli po sa MAL</string> | ||||
|     <string name="track_finished_reading_date">Natapos basahin</string> | ||||
| @@ -504,7 +504,7 @@ | ||||
|     <string name="action_filter_tracked">Sinundan</string> | ||||
|     <string name="right_and_left_nav">Kaliwa at Kanan</string> | ||||
|     <string name="pref_dual_page_split">Hatiin ang mga malalapad na pahina</string> | ||||
|     <string name="action_display_show_number_of_items">Ipakita ang dami</string> | ||||
|     <string name="action_display_show_number_of_items">Ipakita ang bilang ng mga item</string> | ||||
|     <string name="pref_dual_page_invert_summary">Kung sakaling hindi sumasakto sa direksyon ng pagbabasa ang paghahati sa malalapad na pahina</string> | ||||
|     <string name="pref_dual_page_invert">Baligtarin ang paghahati sa pahina</string> | ||||
|     <string name="backup_restore_content_full">Ire-restore ang mga datos mula sa backup file. | ||||
| @@ -535,8 +535,8 @@ | ||||
|     <string name="rotation_type">Pag-ikot</string> | ||||
|     <string name="pref_grayscale">Maabo</string> | ||||
|     <string name="notification_incognito_text">Isara ang incognito</string> | ||||
|     <string name="automatic_background">Kusa</string> | ||||
|     <string name="cancel_all_for_series">Ikansela lahat para sa seryeng ito</string> | ||||
|     <string name="automatic_background">Awto</string> | ||||
|     <string name="cancel_all_for_series">Kanselahin lahat para sa seryeng ito</string> | ||||
|     <string name="local_filter_order_by">Ayusin ayon sa</string> | ||||
|     <string name="restrictions">Restriksyon: %s</string> | ||||
|     <string name="error_no_match">Walang nahanap na kapares</string> | ||||
| @@ -608,7 +608,7 @@ | ||||
|     <string name="download_queue_size_warning">Babala: maaaring humantong sa pagbagal at/o pagharang ng mga source sa Tachiyomi ang mga malalaking maramihang pag-download. I-tap para matuto pa.</string> | ||||
|     <string name="channel_app_updates">Mga update sa app</string> | ||||
|     <string name="ext_update_all">I-update lahat</string> | ||||
|     <string name="clear_database_source_item_count">%1$d na entry sa database na wala sa Aklatan</string> | ||||
|     <string name="clear_database_source_item_count">%1$d na entry sa database na wala sa aklatan</string> | ||||
|     <string name="pref_auto_clear_chapter_cache">Linisin ang cache ng kabanata sa paglulunsad ng app</string> | ||||
|     <string name="database_clean">Walang malilinis</string> | ||||
|     <string name="extension_api_error">Bigong makuha ang listahan ng mga extension</string> | ||||
| @@ -780,7 +780,7 @@ | ||||
|     <string name="action_filter_interval_custom">Ipasadya ang fetch interval</string> | ||||
|     <string name="action_filter_interval_late">Huling 10+ pagsusuri</string> | ||||
|     <string name="action_sort_next_updated">Susunod na inaasahang update</string> | ||||
|     <string name="action_filter_interval_dropped">Nawala\? or Nahulog\? (depending on the context, \"Nahulog\" means dropped or dropped something, and \"Nawala\" means Gone/Vanished) Nahuling 20+ at 2 buwan</string> | ||||
|     <string name="action_filter_interval_dropped">Itinigil\? Huli ng 20+ at 2 buwan</string> | ||||
|     <string name="action_filter_interval_passed">Lumipas ang check period</string> | ||||
|     <string name="action_filter_interval_long">Kunin kada buwan (kada ika-28 na araw)</string> | ||||
|     <plurals name="day"> | ||||
| @@ -816,7 +816,7 @@ | ||||
|     <string name="action_sort_category">Mag-ayos ng kategorya</string> | ||||
|     <string name="notification_updating_progress">Nag-a-update ang aklatan... (%s)</string> | ||||
|     <string name="sort_category_confirmation">Gusto mo bang mag-ayos ng kategorya ayon sa alpabeto\?</string> | ||||
|     <string name="source_settings">Mga setting ng pinagmula</string> | ||||
|     <string name="source_settings">Mga setting ng source</string> | ||||
|     <string name="app_settings">Mga setting ng app</string> | ||||
|     <string name="file_null_uri_error">Ang file picker ay nabigo na ibalik ang file sa app</string> | ||||
|     <string name="label_data_storage">Data at storage</string> | ||||
| @@ -825,4 +825,11 @@ | ||||
|     <string name="relative_time_span_never">Hindi kailanman</string> | ||||
|     <string name="last_auto_backup_info">Huling awtomatikong na-back up: %s</string> | ||||
|     <string name="pref_storage_usage">Paggamit ng storage</string> | ||||
|     <string name="action_sort_tracker_score">Iskor sa tracker</string> | ||||
|     <string name="action_apply">Gamitin</string> | ||||
|     <string name="action_revert_to_default">Ibalik sa default</string> | ||||
|     <string name="no_scanlators_found">Walang scanlator ang nahanap</string> | ||||
|     <string name="scanlator">Scanlator</string> | ||||
|     <string name="exclude_scanlators">Ibukod ang mga scanlator</string> | ||||
|     <string name="action_create">Lumikha</string> | ||||
| </resources> | ||||
| @@ -544,7 +544,7 @@ | ||||
|     <string name="notification_incognito_text">Deaktiviraj anonimni modus</string> | ||||
|     <string name="rotation_type">Okretanje</string> | ||||
|     <string name="automatic_background">Automatski</string> | ||||
|     <string name="pref_create_folder_per_manga_summary">Stvara mape prema naslovu unosa</string> | ||||
|     <string name="pref_create_folder_per_manga_summary">Stvara mape na osnovi naslova unosa</string> | ||||
|     <string name="pref_create_folder_per_manga">Spremi stranice u zasebne mape</string> | ||||
|     <string name="pref_reader_actions">Radnje</string> | ||||
|     <string name="cancel_all_for_series">Prekini sve za ovu seriju</string> | ||||
| @@ -832,7 +832,7 @@ | ||||
|     <string name="action_sort_category">Razvrstaj kategorije</string> | ||||
|     <string name="notification_updating_progress">Aktualiziranje biblioteke … (%s)</string> | ||||
|     <string name="sort_category_confirmation">Želiš li razvrstati kategorije po abecedi\?</string> | ||||
|     <string name="file_null_uri_error">Program za biranje datoteka nije uspio vratiti datoteku u aplikaciju</string> | ||||
|     <string name="file_null_uri_error">Nije odabrana nijedna datoteka</string> | ||||
|     <string name="source_settings">Postavke izvora</string> | ||||
|     <string name="app_settings">Postavke aplikacije</string> | ||||
|     <string name="label_data_storage">Podaci i spremište</string> | ||||
| @@ -840,4 +840,12 @@ | ||||
|     <string name="pref_flash_page_summ">Smanjuje artefakte na ekranima s e-tintom</string> | ||||
|     <string name="last_auto_backup_info">Zadnja automatska sigurnosna kopija: %s</string> | ||||
|     <string name="pref_flash_page">Zabljesni prilikom mijenjanja stranice</string> | ||||
|     <string name="action_create">Stvori</string> | ||||
|     <string name="action_apply">Primijeni</string> | ||||
|     <string name="action_revert_to_default">Obnovi standardne vrijednosti</string> | ||||
|     <string name="no_scanlators_found">Nije pronađen nijedan amaterski prevoditelj</string> | ||||
|     <string name="scanlator">Amaterski prevoditelj</string> | ||||
|     <string name="pref_storage_usage">Korištenje memorije</string> | ||||
|     <string name="action_sort_tracker_score">Rezultat tragača</string> | ||||
|     <string name="exclude_scanlators">Isključi amaterske prevoditelje</string> | ||||
| </resources> | ||||
| @@ -135,8 +135,8 @@ | ||||
|     <string name="pref_restore_backup">Pulihkan cadangan</string> | ||||
|     <string name="pref_restore_backup_summ">Pulihkan isi pustaka dari berkas cadangan</string> | ||||
|     <string name="pref_backup_directory">Tempat pencadangan</string> | ||||
|     <string name="pref_backup_interval">Frekuensi cadangan dibuat</string> | ||||
|     <string name="pref_backup_slots">Jumlah maksimum cadangan</string> | ||||
|     <string name="pref_backup_interval">Frekuensi pencadangan otomatis</string> | ||||
|     <string name="pref_backup_slots">Jumlah maksimum pencadangan otomatis</string> | ||||
|     <string name="backup_created">Cadangan dibuat</string> | ||||
|     <string name="restore_completed">Pemulihan selesai</string> | ||||
|     <string name="backup_choice">Apa saja yang ingin Anda cadangkan\?</string> | ||||
| @@ -499,8 +499,8 @@ | ||||
|     <string name="nav_zone_next">Lanjut</string> | ||||
|     <string name="nav_zone_prev">Sblm</string> | ||||
|     <string name="automatic_background">Otomatis</string> | ||||
|     <string name="pref_create_folder_per_manga">Simpan halaman di folder terpisah</string> | ||||
|     <string name="pref_create_folder_per_manga_summary">Membuat folder sesuai dengan judul entri</string> | ||||
|     <string name="pref_create_folder_per_manga">Menyimpan halaman ke dalam folder terpisah</string> | ||||
|     <string name="pref_create_folder_per_manga_summary">Membuat folder menurut judul entri</string> | ||||
|     <string name="exclude">Kecuali: %s</string> | ||||
|     <string name="include">Termasuk: %s</string> | ||||
|     <string name="pref_dual_page_split">Membagi halaman lebar</string> | ||||
| @@ -692,7 +692,7 @@ | ||||
|     <string name="pref_security_summary">Kunci aplikasi, layar aman</string> | ||||
|     <string name="pref_appearance_summary">Tema, format tanggal & waktu</string> | ||||
|     <string name="pref_library_summary">Kategori, pembaruan global, geser chapter</string> | ||||
|     <string name="pref_backup_summary">Pencadangan manual & otomatis</string> | ||||
|     <string name="pref_backup_summary">Pencadangan manual & otomatis, ruang penyimpanan</string> | ||||
|     <string name="pref_advanced_summary">Buat log kerusakan, pengoptimalan baterai</string> | ||||
|     <string name="crash_screen_title">Aduh!</string> | ||||
|     <string name="crash_screen_restart_application">Mulai ulang aplikasi</string> | ||||
| @@ -800,7 +800,20 @@ | ||||
|     <string name="action_sort_category">Mengurutkan kategori</string> | ||||
|     <string name="notification_updating_progress">Memperbarui pustaka... (%s)</string> | ||||
|     <string name="sort_category_confirmation">Apakah Anda ingin mengurutkan kategori menurut abjad\?</string> | ||||
|     <string name="file_null_uri_error">Pemilih file gagal mengembalikan file ke aplikasi</string> | ||||
|     <string name="file_null_uri_error">Tidak ada file yang dipilih</string> | ||||
|     <string name="source_settings">Pengaturan sumber</string> | ||||
|     <string name="app_settings">Pengaturan aplikasi</string> | ||||
|     <string name="action_create">Buat</string> | ||||
|     <string name="relative_time_span_never">Tidak pernah</string> | ||||
|     <string name="pref_flash_page_summ">Mengurangi ghosting pada tampilan e-ink</string> | ||||
|     <string name="action_apply">Terapkan</string> | ||||
|     <string name="action_revert_to_default">Kembalikan ke default</string> | ||||
|     <string name="last_auto_backup_info">Terakhir dicadangkan secara otomatis: %s</string> | ||||
|     <string name="no_scanlators_found">Tidak ditemukan pemindai</string> | ||||
|     <string name="scanlator">Pemindai</string> | ||||
|     <string name="pref_flash_page">Berkedip putih pada perubahan halaman</string> | ||||
|     <string name="pref_storage_usage">Penggunaan penyimpanan</string> | ||||
|     <string name="action_sort_tracker_score">Skor pelacak</string> | ||||
|     <string name="label_data_storage">Data dan penyimpanan</string> | ||||
|     <string name="exclude_scanlators">Kecualikan pemindai</string> | ||||
| </resources> | ||||
| @@ -802,11 +802,18 @@ | ||||
|     <string name="sort_category_confirmation">カテゴリをアルファベット順で並べ替えますか?</string> | ||||
|     <string name="source_settings">ソース設定</string> | ||||
|     <string name="app_settings">アプリ設定</string> | ||||
|     <string name="file_null_uri_error">ファイルピッカーはアプリにファイルを返せませんでした</string> | ||||
|     <string name="file_null_uri_error">選択したファイルがありません</string> | ||||
|     <string name="relative_time_span_never">なし</string> | ||||
|     <string name="pref_flash_page_summ">Eインク画面の焼き付きを軽減</string> | ||||
|     <string name="last_auto_backup_info">前回の自動バックアップ: %s</string> | ||||
|     <string name="pref_flash_page">ページめくりの時、画面を点滅させる</string> | ||||
|     <string name="pref_storage_usage">使用中のストレージ領域</string> | ||||
|     <string name="label_data_storage">データとストレージ</string> | ||||
|     <string name="action_sort_tracker_score">トラッカーの評価点数</string> | ||||
|     <string name="action_create">作成</string> | ||||
|     <string name="action_apply">適用</string> | ||||
|     <string name="action_revert_to_default">デフォルトに戻す</string> | ||||
|     <string name="no_scanlators_found">スキャンレーターが見つかりませんでした</string> | ||||
|     <string name="scanlator">スキャンレーター</string> | ||||
|     <string name="exclude_scanlators">スキャンレーターを除外</string> | ||||
| </resources> | ||||
| @@ -834,8 +834,18 @@ | ||||
|     <string name="source_settings">Configurações das fontes</string> | ||||
|     <string name="action_sort_category">Ordenar as categorias</string> | ||||
|     <string name="sort_category_confirmation">Você deseja ordenar as categorias alfabeticamente\?</string> | ||||
|     <string name="file_null_uri_error">O seletor de arquivos não retornou o arquivo para o aplicativo</string> | ||||
|     <string name="file_null_uri_error">Nenhum arquivo selecionado</string> | ||||
|     <string name="label_data_storage">Dados e armazenamento</string> | ||||
|     <string name="pref_flash_page_summ">Reduz o efeito fantasma em telas e-ink</string> | ||||
|     <string name="pref_flash_page">Flash branco ao mudar de página</string> | ||||
|     <string name="action_sort_tracker_score">Avaliação no monitorador</string> | ||||
|     <string name="relative_time_span_never">Nunca</string> | ||||
|     <string name="last_auto_backup_info">Último backup automático feito em: %s</string> | ||||
|     <string name="pref_storage_usage">Uso de armazenamento</string> | ||||
|     <string name="action_apply">Aplicar</string> | ||||
|     <string name="action_revert_to_default">Reverter para o padrão</string> | ||||
|     <string name="no_scanlators_found">Nenhum scanlator encontrado</string> | ||||
|     <string name="scanlator">Scanlator</string> | ||||
|     <string name="exclude_scanlators">Excluir scanlators</string> | ||||
|     <string name="action_create">Criar</string> | ||||
| </resources> | ||||
| @@ -850,11 +850,18 @@ | ||||
|     <string name="notification_updating_progress">Обновление библиотеки... (%s)</string> | ||||
|     <string name="action_sort_category">Сортировать категории</string> | ||||
|     <string name="sort_category_confirmation">Хотите ли вы сортировать категории по алфавиту\?</string> | ||||
|     <string name="file_null_uri_error">Приложению для выбора файлов не удалось вернуть путь файла в Tachiyomi</string> | ||||
|     <string name="file_null_uri_error">Файл не выбран</string> | ||||
|     <string name="label_data_storage">Данные и хранение</string> | ||||
|     <string name="relative_time_span_never">Никогда</string> | ||||
|     <string name="pref_flash_page_summ">Уменьшает артефакты у экранов e-ink</string> | ||||
|     <string name="last_auto_backup_info">Последнее автоматическое резервное копирование: %s</string> | ||||
|     <string name="pref_flash_page">Мигать экраном при смене страницы</string> | ||||
|     <string name="pref_storage_usage">Использование хранилища</string> | ||||
|     <string name="action_sort_tracker_score">Оценка сервиса отслеживания</string> | ||||
|     <string name="action_create">Создать</string> | ||||
|     <string name="action_apply">Применить</string> | ||||
|     <string name="action_revert_to_default">Сбросить настройки</string> | ||||
|     <string name="no_scanlators_found">Переводчики не найдены</string> | ||||
|     <string name="scanlator">Переводчик</string> | ||||
|     <string name="exclude_scanlators">Исключить переводчиков</string> | ||||
| </resources> | ||||
| @@ -301,8 +301,8 @@ | ||||
|     <string name="l_nav">รูปตัว L</string> | ||||
|     <string name="automatic_background">อัตโนมัติ</string> | ||||
|     <string name="gray_background">เทา</string> | ||||
|     <string name="pref_create_folder_per_manga_summary">สร้างโฟลเดอร์ตามชื่อเรื่อง</string> | ||||
|     <string name="pref_create_folder_per_manga">บันทึกหน้าลงในโฟลเดอร์ที่แยกต่างหาก</string> | ||||
|     <string name="pref_create_folder_per_manga_summary">สร้างโฟลเดอร์ตามชื่อเรื่องของรายการ</string> | ||||
|     <string name="pref_create_folder_per_manga">บันทึกแต่ละหน้าลงในโฟลเดอร์ที่แยกต่างหาก</string> | ||||
|     <string name="pref_reader_actions">การกระทำ</string> | ||||
|     <string name="tapping_inverted_both">ทั้งสอง</string> | ||||
|     <string name="tapping_inverted_vertical">แนวตั้ง</string> | ||||
| @@ -564,7 +564,7 @@ | ||||
|     <string name="enhanced_services">ตัวติดตามขั้นสูง</string> | ||||
|     <string name="backup_info">ควรเก็บสำเนาของข้อมูลสำรองไว้ที่อื่นด้วยเช่นกัน การสำรองข้อมูลอาจมีข้อมูลที่ละเอียดอ่อนรวมถึงรหัสผ่านที่เก็บไว้ ควรระวังหากแบ่งปันสำเนา</string> | ||||
|     <string name="pref_verbose_logging_summary">บันทึกบันทึกอย่างละเอียดไปยังบันทึกของระบบ (ลดประสิทธิภาพของแอป)</string> | ||||
|     <string name="help_translate">ช่วยแปล</string> | ||||
|     <string name="help_translate">แปลเป็นภาษาไทยโดย altqx</string> | ||||
|     <string name="local_invalid_format">รูปแบบตอนไม่ถูกต้อง</string> | ||||
|     <string name="manga_cover">ปก</string> | ||||
|     <string name="unread">ยังไม่ได้อ่าน</string> | ||||
| @@ -802,11 +802,18 @@ | ||||
|     <string name="sort_category_confirmation">ต้องการจัดเรียงหมวดหมู่ตามตัวอักษรหรือไม่\?</string> | ||||
|     <string name="source_settings">การตั้งค่าแหล่งที่มา</string> | ||||
|     <string name="app_settings">การตั้งค่าแอป</string> | ||||
|     <string name="file_null_uri_error">เครื่องมือเลือกไฟล์ไม่สามารถส่งต่อไฟล์ไปยังแอปได้</string> | ||||
|     <string name="file_null_uri_error">ไม่มีไฟล์ถูกเลือกไว้</string> | ||||
|     <string name="relative_time_span_never">ไม่เลย</string> | ||||
|     <string name="pref_flash_page_summ">ลดภาพซ้อนบนจอแสดงผล E-Ink</string> | ||||
|     <string name="last_auto_backup_info">สำรองข้อมูลอัตโนมัติครั้งล่าสุด: %s</string> | ||||
|     <string name="pref_flash_page">แฟลชสีขาวเมื่อเปลี่ยนหน้า</string> | ||||
|     <string name="pref_storage_usage">การใช้พื้นที่เก็บข้อมูล</string> | ||||
|     <string name="label_data_storage">ข้อมูลและการจัดเก็บข้อมูล</string> | ||||
|     <string name="action_create">สร้าง</string> | ||||
|     <string name="action_apply">นำไปใช้</string> | ||||
|     <string name="action_revert_to_default">ย้อนกลับไปเป็นค่าเริ่มต้น</string> | ||||
|     <string name="no_scanlators_found">ไม่พบผู้แปล</string> | ||||
|     <string name="scanlator">ผู้แปล</string> | ||||
|     <string name="action_sort_tracker_score">คะแนนจากตัวติดตาม</string> | ||||
|     <string name="exclude_scanlators">ผู้แปลที่เว้นไว้</string> | ||||
| </resources> | ||||
| @@ -162,8 +162,8 @@ | ||||
|     <string name="pref_restore_backup">Yedeği geri yükle</string> | ||||
|     <string name="pref_restore_backup_summ">Kitaplığı yedek dosyasından geri yükle</string> | ||||
|     <string name="pref_backup_directory">Yedekleme konumu</string> | ||||
|     <string name="pref_backup_interval">Yedekleme sıklığı</string> | ||||
|     <string name="pref_backup_slots">Maksimum yedek</string> | ||||
|     <string name="pref_backup_interval">Kendiliğinden yedekleme sıklığı</string> | ||||
|     <string name="pref_backup_slots">En fazla kendiliğinden yedek</string> | ||||
|     <string name="backup_created">Yedek oluşturuldu</string> | ||||
|     <string name="restore_completed">Geri yükleme tamamlandı</string> | ||||
|     <string name="backup_choice">Neyi yedeklemek istiyorsunuz?</string> | ||||
| @@ -375,7 +375,7 @@ | ||||
|     <string name="manga_info_collapse">Daha az</string> | ||||
|     <string name="manga_info_expand">Daha fazla</string> | ||||
|     <string name="website">Web sitesi</string> | ||||
|     <string name="information_webview_required">Web Görünümü, uygulamanın işlevselliği için gereklidir</string> | ||||
|     <string name="information_webview_required">WebView, uygulamanın işlevselliği için gereklidir</string> | ||||
|     <string name="licenses">Açık kaynak lisansları</string> | ||||
|     <string name="label_downloaded_only">Yalnızca indirilen</string> | ||||
|     <string name="recent_manga_time">Böl. %1$s - %2$s</string> | ||||
| @@ -434,7 +434,7 @@ | ||||
|         <item quantity="other">%1$s bölüm</item> | ||||
|     </plurals> | ||||
|     <string name="requires_app_restart">Etkili olması için uygulamanın yeniden başlatılmasını gerektirir</string> | ||||
|     <string name="label_network">Ağ</string> | ||||
|     <string name="label_network">Ağ oluşturma</string> | ||||
|     <string name="tapping_inverted_none">Yok</string> | ||||
|     <string name="pref_read_with_tapping_inverted">Dokunma bölgelerini ters çevir</string> | ||||
|     <string name="tapping_inverted_both">İkisi de</string> | ||||
| @@ -697,7 +697,7 @@ | ||||
|     <string name="missing_storage_permission">Depolama izinleri verilmedi</string> | ||||
|     <string name="skipped_reason_not_always_update">Dizi güncelleme gerektirmediği için atlandı</string> | ||||
|     <string name="action_search_hint">Ara…</string> | ||||
|     <string name="pref_backup_summary">Elle ve kendiliğinden yedeklemeler</string> | ||||
|     <string name="pref_backup_summary">Elle ve kendiliğinden yedeklemeler, depolama alanı</string> | ||||
|     <string name="pref_security_summary">Uygulama kilidi, güvenli ekran</string> | ||||
|     <string name="pref_advanced_summary">Çökme günlükleri dökümü, pil iyileştirmeleri</string> | ||||
|     <string name="pref_library_summary">Kategoriler, genel güncelleme, bölüm kaydırma</string> | ||||
| @@ -806,7 +806,7 @@ | ||||
|     <string name="exception_unknown_host">%s verisine erişilemedi</string> | ||||
|     <string name="track_activity_name">İzleyici girişi</string> | ||||
|     <string name="library_sync_complete">Kitaplık eşleşmesi tamamlandı</string> | ||||
|     <string name="exception_http">HTTP %d, siteyi Web Görünümünde denetle</string> | ||||
|     <string name="exception_http">HTTP %d, siteyi WebView\'de denetle</string> | ||||
|     <string name="exception_offline">Genel ağ bağlantısı yok</string> | ||||
|     <string name="syncing_library">Kitaplık eşleştiriliyor</string> | ||||
|     <string name="unlock_app_title">Aç: %s</string> | ||||
| @@ -819,4 +819,16 @@ | ||||
|     <string name="app_settings">Uygulama ayarları</string> | ||||
|     <string name="pref_relative_format">Göreli zaman damgaları</string> | ||||
|     <string name="pref_relative_format_summary">\"%1$s\" yerine \"%2$s</string> | ||||
|     <string name="relative_time_span_never">Asla</string> | ||||
|     <string name="pref_flash_page_summ">E-ink görüntülerinde gölgelenmeyi azaltır</string> | ||||
|     <string name="action_apply">Uygula</string> | ||||
|     <string name="action_revert_to_default">Varsayılana dön</string> | ||||
|     <string name="last_auto_backup_info">En son şu tarihte kendi yedekledi: %s</string> | ||||
|     <string name="no_scanlators_found">Tareviriler bulunamadı</string> | ||||
|     <string name="scanlator">Tareviri</string> | ||||
|     <string name="pref_flash_page">Sayfa değişiminde beyaz ışık çak</string> | ||||
|     <string name="pref_storage_usage">Depolama kullanımı</string> | ||||
|     <string name="action_sort_tracker_score">İzleyici notu</string> | ||||
|     <string name="label_data_storage">Veri ve depolama</string> | ||||
|     <string name="exclude_scanlators">Tarevirileri hariç tut</string> | ||||
| </resources> | ||||
| @@ -846,4 +846,11 @@ | ||||
|     <string name="pref_relative_format_summary">\"%1$s\" замість \"%2$s\"</string> | ||||
|     <string name="source_settings">Налаштування джерела</string> | ||||
|     <string name="app_settings">Налаштування застосунку</string> | ||||
|     <string name="action_apply">Застосувати</string> | ||||
|     <string name="action_revert_to_default">Повернути за замовчуванням</string> | ||||
|     <string name="action_sort_category">Сортувати категорії</string> | ||||
|     <string name="scanlator">Сканлейтор</string> | ||||
|     <string name="action_sort_tracker_score">Оцінка трекера</string> | ||||
|     <string name="label_data_storage">Дані та сховище</string> | ||||
|     <string name="sort_category_confirmation">Ви хочете сортувати категорії алфавітно?</string> | ||||
| </resources> | ||||
| @@ -156,14 +156,14 @@ | ||||
|     <string name="fourth_to_last">倒数第四已读章节</string> | ||||
|     <string name="fifth_to_last">倒数第五已读章节</string> | ||||
|     <string name="pref_download_new">自动下载新章节</string> | ||||
|     <string name="services">平台</string> | ||||
|     <string name="services">记录平台</string> | ||||
|     <string name="pref_create_backup">创建备份</string> | ||||
|     <string name="pref_create_backup_summ">可用于还原当前书架数据</string> | ||||
|     <string name="pref_restore_backup">还原备份</string> | ||||
|     <string name="pref_restore_backup_summ">从备份文件中还原</string> | ||||
|     <string name="pref_backup_directory">备份路径</string> | ||||
|     <string name="pref_backup_interval">备份频率</string> | ||||
|     <string name="pref_backup_slots">最大备份数</string> | ||||
|     <string name="pref_backup_interval">自动备份频率</string> | ||||
|     <string name="pref_backup_slots">最大自动备份数</string> | ||||
|     <string name="backup_created">已创建备份</string> | ||||
|     <string name="restore_completed">还原完毕</string> | ||||
|     <string name="backup_choice">需要备份什么?</string> | ||||
| @@ -365,7 +365,7 @@ | ||||
|     <string name="vertical_plus_viewer">条漫(页间有空隙)</string> | ||||
|     <string name="action_select_inverse">反选</string> | ||||
|     <string name="add_tracking">添加进度记录</string> | ||||
|     <string name="information_webview_required">Tachiyomi 依赖于 WebView</string> | ||||
|     <string name="information_webview_required">app依赖WebView实现其功能</string> | ||||
|     <string name="manga_info_collapse">收起</string> | ||||
|     <string name="manga_info_expand">展开</string> | ||||
|     <string name="licenses">开源许可证</string> | ||||
| @@ -556,7 +556,7 @@ | ||||
|     <string name="theme_greenapple">青苹果</string> | ||||
|     <string name="pref_app_theme">应用主题</string> | ||||
|     <string name="enhanced_tracking_info">为特定图源提供增强功能。作品在添加到书架时会自动同步进度。</string> | ||||
|     <string name="enhanced_services">增强平台</string> | ||||
|     <string name="enhanced_services">增强型记录平台</string> | ||||
|     <string name="theme_monet">动态</string> | ||||
|     <string name="label_background_activity">后台活动</string> | ||||
|     <string name="pref_lowest">最低</string> | ||||
| @@ -589,7 +589,7 @@ | ||||
|     <string name="pref_verbose_logging">详细日志记录</string> | ||||
|     <string name="label_warning">警告</string> | ||||
|     <string name="action_display_language_badge">语言</string> | ||||
|     <string name="backup_info">你应该将备份数据保存到多个地方。</string> | ||||
|     <string name="backup_info">你应该将备份数据保存到多个地方。备份可能存有包括所有已存储密码在内的敏感数据;请谨慎分享。</string> | ||||
|     <string name="notification_size_warning">大量更新会损害图源,并可能导致更新变慢、耗电增加。点击了解详情。</string> | ||||
|     <string name="connected_to_wifi">仅连接至 Wi-Fi 时</string> | ||||
|     <string name="update_72hour">每 3 天</string> | ||||
| @@ -769,7 +769,7 @@ | ||||
|     <string name="delete_downloaded">删除已下载章节</string> | ||||
|     <string name="action_filter_interval_custom">自定义更新间隔</string> | ||||
|     <string name="action_set_interval">设定间隔</string> | ||||
|     <string name="action_filter_interval_dropped">放弃\? 延迟 20+ 和 2个月</string> | ||||
|     <string name="action_filter_interval_dropped">放弃?延迟 20+ 和 2个月</string> | ||||
|     <string name="action_filter_interval_passed">通过检查期</string> | ||||
|     <string name="action_sort_next_updated">下次预期更新</string> | ||||
|     <string name="action_filter_interval_long">每月更新(28天)</string> | ||||
| @@ -781,7 +781,7 @@ | ||||
|     <string name="manga_display_interval_title">估计每个</string> | ||||
|     <string name="manga_display_modified_interval_title">设定更新为每</string> | ||||
|     <string name="manga_modify_calculated_interval_title">自定义间隔</string> | ||||
|     <string name="skipped_reason_not_in_release_period">跳过、今天预期没有新发布</string> | ||||
|     <string name="skipped_reason_not_in_release_period">跳过,因为预计今天没有新发布</string> | ||||
|     <string name="has_results">有结果</string> | ||||
|     <string name="syncing_library">正在同步书架</string> | ||||
|     <string name="library_sync_complete">书架同步完成</string> | ||||
| @@ -800,7 +800,7 @@ | ||||
|     <string name="action_move_to_bottom_all_for_series">将作品移到底部</string> | ||||
|     <string name="notification_updating_progress">书架更新中…(%s)</string> | ||||
|     <string name="sort_category_confirmation">是否按字母顺序对分类进行排序?</string> | ||||
|     <string name="file_null_uri_error">文件选择器无法将文件恢复至应用</string> | ||||
|     <string name="file_null_uri_error">没有文件被选中</string> | ||||
|     <string name="pref_relative_format">相对时间戳</string> | ||||
|     <string name="pref_relative_format_summary">以\"%1$s\" 表示 \"%2$s\"</string> | ||||
|     <string name="relative_time_span_never">从不</string> | ||||
| @@ -809,4 +809,11 @@ | ||||
|     <string name="pref_flash_page">切页时闪烁白屏</string> | ||||
|     <string name="label_data_storage">数据与存储</string> | ||||
|     <string name="pref_storage_usage">存储占用</string> | ||||
|     <string name="action_create">创建</string> | ||||
|     <string name="action_apply">应用</string> | ||||
|     <string name="action_revert_to_default">恢复默认</string> | ||||
|     <string name="no_scanlators_found">未找到扫译者</string> | ||||
|     <string name="scanlator">扫译者</string> | ||||
|     <string name="action_sort_tracker_score">记录平台评分</string> | ||||
|     <string name="exclude_scanlators">排除的扫译者</string> | ||||
| </resources> | ||||
| @@ -400,7 +400,7 @@ | ||||
|         <item quantity="other">%d 個類別</item> | ||||
|     </plurals> | ||||
|     <string name="requires_app_restart">需要重新啟動應用程式以套用</string> | ||||
|     <string name="label_network">網路設定</string> | ||||
|     <string name="label_network">網路</string> | ||||
|     <string name="tapping_inverted_both">全部</string> | ||||
|     <string name="tapping_inverted_vertical">垂直</string> | ||||
|     <string name="tapping_inverted_horizontal">水平</string> | ||||
| @@ -639,7 +639,7 @@ | ||||
|     <string name="split_tall_images_summary">用以改善閱讀器效能</string> | ||||
|     <string name="download_notifier_split_page_path_not_found">找不到第 %d 頁的檔案路徑</string> | ||||
|     <string name="pref_reset_viewer_flags">重設個別閱讀器設定</string> | ||||
|     <string name="pref_reset_viewer_flags_summary">將所有作品的閱讀模式和螢幕方向恢復為預設值</string> | ||||
|     <string name="pref_reset_viewer_flags_summary">將所有作品的閱讀模式和螢幕方向還原為預設值</string> | ||||
|     <string name="pref_reset_viewer_flags_success">已重設所有閱讀器設定</string> | ||||
|     <string name="pref_reset_viewer_flags_error">無法重設閱讀器設定</string> | ||||
|     <string name="empty_screen">呃…尷尬了</string> | ||||
| @@ -802,11 +802,18 @@ | ||||
|     <string name="notification_updating_progress">正在更新書櫃… (%s)</string> | ||||
|     <string name="sort_category_confirmation">欲依照字母順序排列類別嗎?</string> | ||||
|     <string name="source_settings">來源設定</string> | ||||
|     <string name="file_null_uri_error">無法將選定的檔案傳回給應用程式</string> | ||||
|     <string name="file_null_uri_error">未選擇檔案</string> | ||||
|     <string name="relative_time_span_never">永不</string> | ||||
|     <string name="pref_flash_page_summ">減少電子墨水螢幕上的殘影</string> | ||||
|     <string name="last_auto_backup_info">最後一次自動備份:%s</string> | ||||
|     <string name="pref_flash_page">頁面轉換時閃白</string> | ||||
|     <string name="label_data_storage">資料與儲存空間</string> | ||||
|     <string name="pref_storage_usage">儲存空間佔用</string> | ||||
|     <string name="pref_storage_usage">儲存空間使用情形</string> | ||||
|     <string name="action_sort_tracker_score">歷程平台評分</string> | ||||
|     <string name="action_apply">套用</string> | ||||
|     <string name="action_revert_to_default">還原為預設值</string> | ||||
|     <string name="no_scanlators_found">沒有掃譯者</string> | ||||
|     <string name="scanlator">掃譯者</string> | ||||
|     <string name="exclude_scanlators">排除掃譯者</string> | ||||
|     <string name="action_create">建立</string> | ||||
| </resources> | ||||
| @@ -35,6 +35,9 @@ dependencies { | ||||
|     debugImplementation(compose.ui.tooling) | ||||
|     implementation(compose.ui.tooling.preview) | ||||
|     implementation(compose.ui.util) | ||||
|     lintChecks(compose.lintchecks) | ||||
|  | ||||
|     implementation(kotlinx.immutables) | ||||
| } | ||||
|  | ||||
| tasks { | ||||
|   | ||||
| @@ -14,10 +14,10 @@ import androidx.compose.ui.unit.dp | ||||
|  | ||||
| @Composable | ||||
| fun ActionButton( | ||||
|     modifier: Modifier = Modifier, | ||||
|     title: String, | ||||
|     icon: ImageVector, | ||||
|     onClick: () -> Unit, | ||||
|     modifier: Modifier = Modifier, | ||||
| ) { | ||||
|     TextButton( | ||||
|         modifier = modifier, | ||||
|   | ||||
| @@ -56,11 +56,11 @@ private val sheetAnimationSpec = tween<Float>(durationMillis = 350) | ||||
|  | ||||
| @Composable | ||||
| fun AdaptiveSheet( | ||||
|     modifier: Modifier = Modifier, | ||||
|     isTabletUi: Boolean, | ||||
|     tonalElevation: Dp, | ||||
|     enableSwipeDismiss: Boolean, | ||||
|     onDismissRequest: () -> Unit, | ||||
|     modifier: Modifier = Modifier, | ||||
|     content: @Composable () -> Unit, | ||||
| ) { | ||||
|     val density = LocalDensity.current | ||||
|   | ||||
| @@ -36,13 +36,14 @@ fun BadgeGroup( | ||||
| @Composable | ||||
| fun Badge( | ||||
|     text: String, | ||||
|     modifier: Modifier = Modifier, | ||||
|     color: Color = MaterialTheme.colorScheme.secondary, | ||||
|     textColor: Color = MaterialTheme.colorScheme.onSecondary, | ||||
|     shape: Shape = RectangleShape, | ||||
| ) { | ||||
|     Text( | ||||
|         text = text, | ||||
|         modifier = Modifier | ||||
|         modifier = modifier | ||||
|             .clip(shape) | ||||
|             .background(color) | ||||
|             .padding(horizontal = 3.dp, vertical = 1.dp), | ||||
| @@ -56,6 +57,7 @@ fun Badge( | ||||
| @Composable | ||||
| fun Badge( | ||||
|     imageVector: ImageVector, | ||||
|     modifier: Modifier = Modifier, | ||||
|     color: Color = MaterialTheme.colorScheme.secondary, | ||||
|     iconColor: Color = MaterialTheme.colorScheme.onSecondary, | ||||
|     shape: Shape = RectangleShape, | ||||
| @@ -86,7 +88,7 @@ fun Badge( | ||||
|     Text( | ||||
|         text = text, | ||||
|         inlineContent = inlineContent, | ||||
|         modifier = Modifier | ||||
|         modifier = modifier | ||||
|             .clip(shape) | ||||
|             .background(color) | ||||
|             .padding(horizontal = 3.dp, vertical = 1.dp), | ||||
|   | ||||
| @@ -23,7 +23,10 @@ import androidx.compose.ui.unit.dp | ||||
| import tachiyomi.presentation.core.theme.header | ||||
|  | ||||
| @Composable | ||||
| fun CollapsibleBox(heading: String, content: @Composable () -> Unit) { | ||||
| fun CollapsibleBox( | ||||
|     heading: String, | ||||
|     content: @Composable () -> Unit, | ||||
| ) { | ||||
|     var expanded by remember { mutableStateOf(false) } | ||||
|  | ||||
|     Column { | ||||
|   | ||||
| @@ -17,10 +17,10 @@ import androidx.compose.ui.unit.dp | ||||
|  | ||||
| @Composable | ||||
| fun LabeledCheckbox( | ||||
|     modifier: Modifier = Modifier, | ||||
|     label: String, | ||||
|     checked: Boolean, | ||||
|     onCheckedChange: (Boolean) -> Unit, | ||||
|     modifier: Modifier = Modifier, | ||||
|     enabled: Boolean = true, | ||||
| ) { | ||||
|     Row( | ||||
|   | ||||
| @@ -11,7 +11,12 @@ import androidx.compose.ui.platform.LocalUriHandler | ||||
| import androidx.compose.ui.unit.dp | ||||
|  | ||||
| @Composable | ||||
| fun LinkIcon(modifier: Modifier = Modifier, label: String, icon: ImageVector, url: String) { | ||||
| fun LinkIcon( | ||||
|     label: String, | ||||
|     icon: ImageVector, | ||||
|     url: String, | ||||
|     modifier: Modifier = Modifier, | ||||
| ) { | ||||
|     val uriHandler = LocalUriHandler.current | ||||
|     IconButton( | ||||
|         modifier = modifier.padding(4.dp), | ||||
|   | ||||
| @@ -9,7 +9,10 @@ import androidx.compose.ui.text.font.FontWeight | ||||
| import tachiyomi.presentation.core.components.material.padding | ||||
|  | ||||
| @Composable | ||||
| fun ListGroupHeader(modifier: Modifier = Modifier, text: String) { | ||||
| fun ListGroupHeader( | ||||
|     text: String, | ||||
|     modifier: Modifier = Modifier, | ||||
| ) { | ||||
|     Text( | ||||
|         text = text, | ||||
|         modifier = modifier | ||||
|   | ||||
| @@ -156,11 +156,11 @@ fun RadioItem(label: String, selected: Boolean, onClick: () -> Unit) { | ||||
| @Composable | ||||
| fun SliderItem( | ||||
|     label: String, | ||||
|     min: Int = 0, | ||||
|     max: Int, | ||||
|     value: Int, | ||||
|     valueText: String, | ||||
|     onChange: (Int) -> Unit, | ||||
|     max: Int, | ||||
|     min: Int = 0, | ||||
| ) { | ||||
|     val haptic = LocalHapticFeedback.current | ||||
|  | ||||
|   | ||||
| @@ -17,10 +17,10 @@ import androidx.compose.ui.unit.dp | ||||
|  | ||||
| @Composable | ||||
| fun TwoPanelBox( | ||||
|     modifier: Modifier = Modifier, | ||||
|     contentWindowInsets: WindowInsets = WindowInsets(0), | ||||
|     startContent: @Composable BoxScope.() -> Unit, | ||||
|     endContent: @Composable BoxScope.() -> Unit, | ||||
|     modifier: Modifier = Modifier, | ||||
|     contentWindowInsets: WindowInsets = WindowInsets(0), | ||||
| ) { | ||||
|     val direction = LocalLayoutDirection.current | ||||
|     val padding = contentWindowInsets.asPaddingValues() | ||||
|   | ||||
| @@ -41,6 +41,7 @@ import androidx.compose.ui.text.input.TextFieldValue | ||||
| import androidx.compose.ui.text.style.TextAlign | ||||
| import androidx.compose.ui.unit.DpSize | ||||
| import androidx.compose.ui.unit.dp | ||||
| import kotlinx.collections.immutable.ImmutableList | ||||
| import kotlinx.coroutines.flow.collectLatest | ||||
| import kotlinx.coroutines.flow.distinctUntilChanged | ||||
| import kotlinx.coroutines.flow.drop | ||||
| @@ -54,9 +55,9 @@ import kotlin.math.absoluteValue | ||||
|  | ||||
| @Composable | ||||
| fun WheelNumberPicker( | ||||
|     items: ImmutableList<Number>, | ||||
|     modifier: Modifier = Modifier, | ||||
|     startIndex: Int = 0, | ||||
|     items: List<Number>, | ||||
|     size: DpSize = DpSize(128.dp, 128.dp), | ||||
|     onSelectionChanged: (index: Int) -> Unit = {}, | ||||
|     backgroundContent: (@Composable (size: DpSize) -> Unit)? = { | ||||
| @@ -78,9 +79,9 @@ fun WheelNumberPicker( | ||||
|  | ||||
| @Composable | ||||
| fun WheelTextPicker( | ||||
|     items: ImmutableList<String>, | ||||
|     modifier: Modifier = Modifier, | ||||
|     startIndex: Int = 0, | ||||
|     items: List<String>, | ||||
|     size: DpSize = DpSize(128.dp, 128.dp), | ||||
|     onSelectionChanged: (index: Int) -> Unit = {}, | ||||
|     backgroundContent: (@Composable (size: DpSize) -> Unit)? = { | ||||
| @@ -101,9 +102,9 @@ fun WheelTextPicker( | ||||
|  | ||||
| @Composable | ||||
| private fun <T> WheelPicker( | ||||
|     items: ImmutableList<T>, | ||||
|     modifier: Modifier = Modifier, | ||||
|     startIndex: Int = 0, | ||||
|     items: List<T>, | ||||
|     size: DpSize = DpSize(128.dp, 128.dp), | ||||
|     onSelectionChanged: (index: Int) -> Unit = {}, | ||||
|     manualInputType: KeyboardType? = null, | ||||
|   | ||||
| @@ -46,7 +46,10 @@ fun ExtendedFloatingActionButton( | ||||
|     contentColor: Color = contentColorFor(containerColor), | ||||
|     elevation: FloatingActionButtonElevation = FloatingActionButtonDefaults.elevation(), | ||||
| ) { | ||||
|     val minWidth by animateDpAsState(if (expanded) ExtendedFabMinimumWidth else FabContainerWidth) | ||||
|     val minWidth by animateDpAsState( | ||||
|         targetValue = if (expanded) ExtendedFabMinimumWidth else FabContainerWidth, | ||||
|         label = "minWidth", | ||||
|     ) | ||||
|     FloatingActionButton( | ||||
|         modifier = modifier.sizeIn(minWidth = minWidth), | ||||
|         onClick = onClick, | ||||
| @@ -56,8 +59,14 @@ fun ExtendedFloatingActionButton( | ||||
|         contentColor = contentColor, | ||||
|         elevation = elevation, | ||||
|     ) { | ||||
|         val startPadding by animateDpAsState(if (expanded) ExtendedFabIconSize / 2 else 0.dp) | ||||
|         val endPadding by animateDpAsState(if (expanded) ExtendedFabTextPadding else 0.dp) | ||||
|         val startPadding by animateDpAsState( | ||||
|             targetValue = if (expanded) ExtendedFabIconSize / 2 else 0.dp, | ||||
|             label = "startPadding", | ||||
|         ) | ||||
|         val endPadding by animateDpAsState( | ||||
|             targetValue = if (expanded) ExtendedFabTextPadding else 0.dp, | ||||
|             label = "endPadding", | ||||
|         ) | ||||
|  | ||||
|         Row( | ||||
|             modifier = Modifier.padding(start = startPadding, end = endPadding), | ||||
|   | ||||
| @@ -20,9 +20,9 @@ import androidx.compose.ui.unit.dp | ||||
| fun IconToggleButton( | ||||
|     checked: Boolean, | ||||
|     onCheckedChange: (Boolean) -> Unit, | ||||
|     modifier: Modifier = Modifier, | ||||
|     imageVector: ImageVector, | ||||
|     title: String, | ||||
|     modifier: Modifier = Modifier, | ||||
| ) { | ||||
|     FilledIconToggleButton( | ||||
|         checked = checked, | ||||
|   | ||||
| @@ -36,10 +36,12 @@ private fun Modifier.tabIndicatorOffset( | ||||
|         val currentTabWidth by animateDpAsState( | ||||
|             targetValue = currentTabPosition.width, | ||||
|             animationSpec = spring(stiffness = Spring.StiffnessMediumLow), | ||||
|             label = "currentTabWidth", | ||||
|         ) | ||||
|         val offset by animateDpAsState( | ||||
|             targetValue = currentTabPosition.left + (currentTabWidth * currentPageOffsetFraction), | ||||
|             animationSpec = spring(stiffness = Spring.StiffnessMediumLow), | ||||
|             label = "offset", | ||||
|         ) | ||||
|         Modifier | ||||
|             .offset { IntOffset(x = offset.roundToPx(), y = 0) } | ||||
|   | ||||
| @@ -23,6 +23,7 @@ import androidx.compose.ui.text.style.TextAlign | ||||
| import androidx.compose.ui.unit.LayoutDirection | ||||
| import androidx.compose.ui.unit.dp | ||||
| import androidx.compose.ui.util.fastForEach | ||||
| import kotlinx.collections.immutable.ImmutableList | ||||
| import tachiyomi.presentation.core.components.ActionButton | ||||
| import tachiyomi.presentation.core.components.material.padding | ||||
| import tachiyomi.presentation.core.util.secondaryItemAlpha | ||||
| @@ -38,7 +39,7 @@ data class EmptyScreenAction( | ||||
| fun EmptyScreen( | ||||
|     @StringRes textResource: Int, | ||||
|     modifier: Modifier = Modifier, | ||||
|     actions: List<EmptyScreenAction>? = null, | ||||
|     actions: ImmutableList<EmptyScreenAction>? = null, | ||||
| ) { | ||||
|     EmptyScreen( | ||||
|         message = stringResource(textResource), | ||||
| @@ -51,7 +52,7 @@ fun EmptyScreen( | ||||
| fun EmptyScreen( | ||||
|     message: String, | ||||
|     modifier: Modifier = Modifier, | ||||
|     actions: List<EmptyScreenAction>? = null, | ||||
|     actions: ImmutableList<EmptyScreenAction>? = null, | ||||
| ) { | ||||
|     val face = remember { getRandomErrorFace() } | ||||
|     Column( | ||||
| @@ -98,7 +99,7 @@ fun EmptyScreen( | ||||
|     } | ||||
| } | ||||
|  | ||||
| private val ERROR_FACES = listOf( | ||||
| private val ErrorFaces = listOf( | ||||
|     "(・o・;)", | ||||
|     "Σ(ಠ_ಠ)", | ||||
|     "ಥ_ಥ", | ||||
| @@ -108,5 +109,5 @@ private val ERROR_FACES = listOf( | ||||
| ) | ||||
|  | ||||
| private fun getRandomErrorFace(): String { | ||||
|     return ERROR_FACES[Random.nextInt(ERROR_FACES.size)] | ||||
|     return ErrorFaces[Random.nextInt(ErrorFaces.size)] | ||||
| } | ||||
|   | ||||
| @@ -25,7 +25,10 @@ dependencies { | ||||
|     implementation(project(":domain")) | ||||
|     implementation(project(":presentation-core")) | ||||
|  | ||||
|     implementation(androidx.glance) | ||||
|     implementation(compose.glance) | ||||
|     lintChecks(compose.lintchecks) | ||||
|  | ||||
|     implementation(kotlinx.immutables) | ||||
|  | ||||
|     implementation(platform(libs.coil.bom)) | ||||
|     implementation(libs.coil.core) | ||||
|   | ||||
| @@ -30,6 +30,8 @@ import coil.size.Scale | ||||
| import coil.transform.RoundedCornersTransformation | ||||
| import eu.kanade.tachiyomi.core.security.SecurityPreferences | ||||
| import eu.kanade.tachiyomi.util.system.dpToPx | ||||
| import kotlinx.collections.immutable.ImmutableList | ||||
| import kotlinx.collections.immutable.toImmutableList | ||||
| import kotlinx.coroutines.flow.map | ||||
| import tachiyomi.core.util.lang.withIOContext | ||||
| import tachiyomi.domain.manga.model.MangaCover | ||||
| @@ -95,10 +97,10 @@ abstract class BaseUpdatesGridGlanceWidget( | ||||
|             val data by flow.collectAsState(initial = null) | ||||
|             UpdatesWidget( | ||||
|                 data = data, | ||||
|                 modifier = containerModifier, | ||||
|                 contentColor = foreground, | ||||
|                 topPadding = topPadding, | ||||
|                 bottomPadding = bottomPadding, | ||||
|                 modifier = containerModifier, | ||||
|             ) | ||||
|         } | ||||
|     } | ||||
| @@ -106,7 +108,7 @@ abstract class BaseUpdatesGridGlanceWidget( | ||||
|     private suspend fun List<UpdatesWithRelations>.prepareData( | ||||
|         rowCount: Int, | ||||
|         columnCount: Int, | ||||
|     ): List<Pair<Long, Bitmap?>> { | ||||
|     ): ImmutableList<Pair<Long, Bitmap?>> { | ||||
|         // Resize to cover size | ||||
|         val widthPx = CoverWidth.value.toInt().dpToPx | ||||
|         val heightPx = CoverHeight.value.toInt().dpToPx | ||||
| @@ -140,6 +142,7 @@ abstract class BaseUpdatesGridGlanceWidget( | ||||
|                         .build() | ||||
|                     Pair(updatesView.mangaId, context.imageLoader.executeBlocking(request).drawable?.toBitmap()) | ||||
|                 } | ||||
|                 .toImmutableList() | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -12,7 +12,7 @@ import logcat.LogPriority | ||||
| import tachiyomi.core.util.system.logcat | ||||
| import tachiyomi.domain.updates.interactor.GetUpdates | ||||
| 
 | ||||
| class TachiyomiWidgetManager( | ||||
| class WidgetManager( | ||||
|     private val getUpdates: GetUpdates, | ||||
|     private val securityPreferences: SecurityPreferences, | ||||
| ) { | ||||
| @@ -17,7 +17,10 @@ val CoverWidth = 58.dp | ||||
| val CoverHeight = 87.dp | ||||
|  | ||||
| @Composable | ||||
| fun UpdatesMangaCover(modifier: GlanceModifier = GlanceModifier, cover: Bitmap?) { | ||||
| fun UpdatesMangaCover( | ||||
|     cover: Bitmap?, | ||||
|     modifier: GlanceModifier = GlanceModifier, | ||||
| ) { | ||||
|     Box( | ||||
|         modifier = modifier | ||||
|             .size(width = CoverWidth, height = CoverHeight) | ||||
|   | ||||
| @@ -21,6 +21,7 @@ import androidx.glance.layout.padding | ||||
| import androidx.glance.text.Text | ||||
| import androidx.glance.text.TextStyle | ||||
| import androidx.glance.unit.ColorProvider | ||||
| import kotlinx.collections.immutable.ImmutableList | ||||
| import tachiyomi.core.Constants | ||||
| import tachiyomi.presentation.widget.R | ||||
| import tachiyomi.presentation.widget.util.calculateRowAndColumnCount | ||||
| @@ -28,11 +29,11 @@ import tachiyomi.presentation.widget.util.stringResource | ||||
|  | ||||
| @Composable | ||||
| fun UpdatesWidget( | ||||
|     data: List<Pair<Long, Bitmap?>>?, | ||||
|     modifier: GlanceModifier = GlanceModifier, | ||||
|     data: ImmutableList<Pair<Long, Bitmap?>>?, | ||||
|     contentColor: ColorProvider, | ||||
|     topPadding: Dp, | ||||
|     bottomPadding: Dp, | ||||
|     modifier: GlanceModifier = GlanceModifier, | ||||
| ) { | ||||
|     Box( | ||||
|         contentAlignment = Alignment.Center, | ||||
| @@ -83,8 +84,8 @@ fun UpdatesWidget( | ||||
|                                         addCategory(mangaId.toString()) | ||||
|                                     } | ||||
|                                     UpdatesMangaCover( | ||||
|                                         modifier = GlanceModifier.clickable(actionStartActivity(intent)), | ||||
|                                         cover = cover, | ||||
|                                         modifier = GlanceModifier.clickable(actionStartActivity(intent)), | ||||
|                                     ) | ||||
|                                 } | ||||
|                             } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user