diff --git a/.editorconfig b/.editorconfig index bbef1d752..d1f195728 100644 --- a/.editorconfig +++ b/.editorconfig @@ -3,5 +3,5 @@ indent_size=4 insert_final_newline=true ij_kotlin_allow_trailing_comma=true ij_kotlin_allow_trailing_comma_on_call_site=true -ij_kotlin_name_count_to_use_star_import = 2147483647 -ij_kotlin_name_count_to_use_star_import_for_members = 2147483647 \ No newline at end of file +ij_kotlin_name_count_to_use_star_import=2147483647 +ij_kotlin_name_count_to_use_star_import_for_members=2147483647 diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 0d9d67163..3e311f12f 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -5,7 +5,7 @@ I acknowledge that: - I have updated: - To the latest version of the app (stable is v0.14.6) - All extensions -- I have gone through the FAQ (https://tachiyomi.org/help/faq/) and troubleshooting guide (https://tachiyomi.org/help/guides/troubleshooting/) +- I have gone through the FAQ (https://tachiyomi.org/docs/faq/general) and troubleshooting guide (https://tachiyomi.org/docs/guides/troubleshooting/) - If this is an issue with an extension, that I should be opening an issue in https://github.com/tachiyomiorg/tachiyomi-extensions - I have searched the existing issues and this is new ticket **NOT** a duplicate or related to another open or closed issue - I will fill out the title and the information in this template diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 0922c459d..dddf1e374 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -4,8 +4,8 @@ contact_links: url: https://github.com/tachiyomiorg/tachiyomi-extensions/issues/new/choose about: Issues and requests for extensions and sources should be opened in the tachiyomi-extensions repository instead - name: 📦 Tachiyomi extensions - url: https://tachiyomi.org/extensions + url: https://tachiyomi.org/extensions/ about: List of all available extensions with download links - name: 🖥️ Tachiyomi website - url: https://tachiyomi.org/help/ + url: https://tachiyomi.org/ about: Guides, troubleshooting, and answers to common questions diff --git a/.github/ISSUE_TEMPLATE/report_issue.yml b/.github/ISSUE_TEMPLATE/report_issue.yml index 460e43d82..e80993914 100644 --- a/.github/ISSUE_TEMPLATE/report_issue.yml +++ b/.github/ISSUE_TEMPLATE/report_issue.yml @@ -96,7 +96,7 @@ body: required: true - label: If this is an issue with an extension, I should be opening an issue in the [extensions repository](https://github.com/tachiyomiorg/tachiyomi-extensions/issues/new/choose). required: true - - label: I have gone through the [FAQ](https://tachiyomi.org/help/faq/) and [troubleshooting guide](https://tachiyomi.org/help/guides/troubleshooting/). + - label: I have gone through the [FAQ](https://tachiyomi.org/docs/faq/general) and [troubleshooting guide](https://tachiyomi.org/docs/guides/troubleshooting/). required: true - label: I have updated the app to version **[0.14.6](https://github.com/tachiyomiorg/tachiyomi/releases/latest)**. required: true diff --git a/.github/workflows/build_pull_request.yml b/.github/workflows/build_pull_request.yml index a9af6d308..da79440dc 100644 --- a/.github/workflows/build_pull_request.yml +++ b/.github/workflows/build_pull_request.yml @@ -19,7 +19,7 @@ jobs: steps: - name: Clone repo - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Validate Gradle Wrapper uses: gradle/wrapper-validation-action@v1 @@ -36,4 +36,4 @@ jobs: - name: Build app and run unit tests uses: gradle/gradle-command-action@v2 with: - arguments: lintKotlin assembleStandardRelease testReleaseUnitTest \ No newline at end of file + arguments: ktlintCheck assembleStandardRelease testReleaseUnitTest \ No newline at end of file diff --git a/.github/workflows/build_push.yml b/.github/workflows/build_push.yml index e49ef19cb..e43c229a0 100644 --- a/.github/workflows/build_push.yml +++ b/.github/workflows/build_push.yml @@ -17,7 +17,7 @@ jobs: steps: - name: Clone repo - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Validate Gradle Wrapper uses: gradle/wrapper-validation-action@v1 @@ -31,7 +31,7 @@ jobs: - name: Build app and run unit tests uses: gradle/gradle-command-action@v2 with: - arguments: lintKotlin assembleStandardRelease testReleaseUnitTest + arguments: ktlintCheck assembleStandardRelease testReleaseUnitTest # Sign APK and create release for tags @@ -104,3 +104,13 @@ jobs: prerelease: false env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + update-website: + needs: [build] + runs-on: ubuntu-latest + if: startsWith(github.ref, 'refs/tags/') && github.repository == 'tachiyomiorg/tachiyomi' + steps: + - name: Trigger Netlify build hook + run: curl -s -X POST -d {} "https://api.netlify.com/build_hooks/${TOKEN}" + env: + TOKEN: ${{ secrets.NETLIFY_HOOK_RELEASE }} diff --git a/.github/workflows/issue_moderator.yml b/.github/workflows/issue_moderator.yml index 8c88132d0..8e937956c 100644 --- a/.github/workflows/issue_moderator.yml +++ b/.github/workflows/issue_moderator.yml @@ -39,7 +39,7 @@ jobs: "regex": ".*(?:fail(?:ed|ure|s)?|can\\s*(?:no|')?t|(?:not|un).*able|(?Issues -1. **Before reporting a new issue, take a look at the [FAQ](https://tachiyomi.org/help/faq/), the [changelog](https://github.com/tachiyomiorg/tachiyomi/releases) and the already opened [issues](https://github.com/tachiyomiorg/tachiyomi/issues).** +1. **Before reporting a new issue, take a look at the [FAQ](https://tachiyomi.org/docs/faq/general), the [changelog](https://tachiyomi.org/changelogs/) and the already opened [issues](https://github.com/tachiyomiorg/tachiyomi/issues).** 2. If you are unsure, ask here: [![Discord](https://img.shields.io/discord/349436576037732353.svg)](https://discord.gg/tachiyomi) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index a7d394f99..23ec3c59f 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,5 +1,4 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile -import org.jmailen.gradle.kotlinter.tasks.LintTask plugins { id("com.android.application") @@ -104,15 +103,17 @@ android { } packaging { - resources.excludes.addAll(listOf( - "META-INF/DEPENDENCIES", - "LICENSE.txt", - "META-INF/LICENSE", - "META-INF/LICENSE.txt", - "META-INF/README.md", - "META-INF/NOTICE", - "META-INF/*.kotlin_module", - )) + resources.excludes.addAll( + listOf( + "META-INF/DEPENDENCIES", + "LICENSE.txt", + "META-INF/LICENSE", + "META-INF/LICENSE.txt", + "META-INF/README.md", + "META-INF/NOTICE", + "META-INF/*.kotlin_module", + ), + ) } dependenciesInfo { @@ -267,7 +268,9 @@ androidComponents { beforeVariants { variantBuilder -> // Disables standardBenchmark if (variantBuilder.buildType == "benchmark") { - variantBuilder.enable = variantBuilder.productFlavors.containsAll(listOf("default" to "dev")) + variantBuilder.enable = variantBuilder.productFlavors.containsAll( + listOf("default" to "dev"), + ) } } onVariants(selector().withFlavor("default" to "standard")) { @@ -278,10 +281,6 @@ androidComponents { } tasks { - withType().configureEach { - exclude { it.file.path.contains("generated[\\\\/]".toRegex()) } - } - // See https://kotlinlang.org/docs/reference/experimental.html#experimental-status-of-experimental-api(-markers) withType { kotlinOptions.freeCompilerArgs += listOf( @@ -306,12 +305,12 @@ tasks { kotlinOptions.freeCompilerArgs += listOf( "-P", "plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=" + - project.buildDir.absolutePath + "/compose_metrics" + project.buildDir.absolutePath + "/compose_metrics", ) kotlinOptions.freeCompilerArgs += listOf( "-P", "plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=" + - project.buildDir.absolutePath + "/compose_metrics" + project.buildDir.absolutePath + "/compose_metrics", ) } } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index f75bf4b8c..424952c7d 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -155,20 +155,6 @@ android:name=".data.notification.NotificationReceiver" android:exported="false" /> - - - - - - - - diff --git a/app/src/main/java/eu/kanade/domain/DomainModule.kt b/app/src/main/java/eu/kanade/domain/DomainModule.kt index 494033c87..f5e428e8a 100644 --- a/app/src/main/java/eu/kanade/domain/DomainModule.kt +++ b/app/src/main/java/eu/kanade/domain/DomainModule.kt @@ -50,6 +50,7 @@ import tachiyomi.domain.history.interactor.GetTotalReadDuration import tachiyomi.domain.history.interactor.RemoveHistory import tachiyomi.domain.history.interactor.UpsertHistory import tachiyomi.domain.history.repository.HistoryRepository +import tachiyomi.domain.manga.interactor.FetchInterval import tachiyomi.domain.manga.interactor.GetDuplicateLibraryManga import tachiyomi.domain.manga.interactor.GetFavorites import tachiyomi.domain.manga.interactor.GetLibraryManga @@ -57,7 +58,6 @@ import tachiyomi.domain.manga.interactor.GetManga import tachiyomi.domain.manga.interactor.GetMangaWithChapters import tachiyomi.domain.manga.interactor.NetworkToLocalManga import tachiyomi.domain.manga.interactor.ResetViewerFlags -import tachiyomi.domain.manga.interactor.SetFetchInterval import tachiyomi.domain.manga.interactor.SetMangaChapterFlags import tachiyomi.domain.manga.repository.MangaRepository import tachiyomi.domain.release.interactor.GetApplicationRelease @@ -102,7 +102,7 @@ class DomainModule : InjektModule { addFactory { GetNextChapters(get(), get(), get()) } addFactory { ResetViewerFlags(get()) } addFactory { SetMangaChapterFlags(get()) } - addFactory { SetFetchInterval(get()) } + addFactory { FetchInterval(get()) } addFactory { SetMangaDefaultChapterFlags(get(), get(), get()) } addFactory { SetMangaViewerFlags(get()) } addFactory { NetworkToLocalManga(get()) } diff --git a/app/src/main/java/eu/kanade/domain/manga/interactor/UpdateManga.kt b/app/src/main/java/eu/kanade/domain/manga/interactor/UpdateManga.kt index 38d6083ff..468ea2389 100644 --- a/app/src/main/java/eu/kanade/domain/manga/interactor/UpdateManga.kt +++ b/app/src/main/java/eu/kanade/domain/manga/interactor/UpdateManga.kt @@ -3,7 +3,7 @@ package eu.kanade.domain.manga.interactor import eu.kanade.domain.manga.model.hasCustomCover import eu.kanade.tachiyomi.data.cache.CoverCache import eu.kanade.tachiyomi.source.model.SManga -import tachiyomi.domain.manga.interactor.SetFetchInterval +import tachiyomi.domain.manga.interactor.FetchInterval import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.manga.model.MangaUpdate import tachiyomi.domain.manga.repository.MangaRepository @@ -15,7 +15,7 @@ import java.util.Date class UpdateManga( private val mangaRepository: MangaRepository, - private val setFetchInterval: SetFetchInterval, + private val fetchInterval: FetchInterval, ) { suspend fun await(mangaUpdate: MangaUpdate): Boolean { @@ -79,9 +79,9 @@ class UpdateManga( suspend fun awaitUpdateFetchInterval( manga: Manga, dateTime: ZonedDateTime = ZonedDateTime.now(), - window: Pair = setFetchInterval.getWindow(dateTime), + window: Pair = fetchInterval.getWindow(dateTime), ): Boolean { - return setFetchInterval.toMangaUpdateOrNull(manga, dateTime, window) + return fetchInterval.toMangaUpdateOrNull(manga, dateTime, window) ?.let { mangaRepository.update(it) } ?: false } diff --git a/app/src/main/java/eu/kanade/presentation/category/components/CategoryDialogs.kt b/app/src/main/java/eu/kanade/presentation/category/components/CategoryDialogs.kt index ce0f59a7e..0e99d26c1 100644 --- a/app/src/main/java/eu/kanade/presentation/category/components/CategoryDialogs.kt +++ b/app/src/main/java/eu/kanade/presentation/category/components/CategoryDialogs.kt @@ -162,7 +162,7 @@ fun CategoryDeleteDialog( TextButton(onClick = { onDelete() onDismissRequest() - },) { + }) { Text(text = stringResource(R.string.action_ok)) } }, @@ -217,7 +217,7 @@ fun ChangeCategoryDialog( tachiyomi.presentation.core.components.material.TextButton(onClick = { onDismissRequest() onEditCategories() - },) { + }) { Text(text = stringResource(R.string.action_edit)) } Spacer(modifier = Modifier.weight(1f)) diff --git a/app/src/main/java/eu/kanade/presentation/components/RelativeDateHeader.kt b/app/src/main/java/eu/kanade/presentation/components/RelativeDateHeader.kt index 89bb61b4f..598bad83e 100644 --- a/app/src/main/java/eu/kanade/presentation/components/RelativeDateHeader.kt +++ b/app/src/main/java/eu/kanade/presentation/components/RelativeDateHeader.kt @@ -3,8 +3,6 @@ package eu.kanade.presentation.components import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext -import eu.kanade.tachiyomi.util.lang.toRelativeString import tachiyomi.presentation.core.components.ListGroupHeader import java.text.DateFormat import java.util.Date @@ -15,11 +13,10 @@ fun RelativeDateHeader( date: Date, dateFormat: DateFormat, ) { - val context = LocalContext.current ListGroupHeader( modifier = modifier, text = remember { - date.toRelativeString(context, dateFormat) + dateFormat.format(date) }, ) } diff --git a/app/src/main/java/eu/kanade/presentation/history/components/HistoryDialogs.kt b/app/src/main/java/eu/kanade/presentation/history/components/HistoryDialogs.kt index 55cd0aac4..12db68602 100644 --- a/app/src/main/java/eu/kanade/presentation/history/components/HistoryDialogs.kt +++ b/app/src/main/java/eu/kanade/presentation/history/components/HistoryDialogs.kt @@ -61,7 +61,7 @@ fun HistoryDeleteDialog( TextButton(onClick = { onDelete(removeEverything) onDismissRequest() - },) { + }) { Text(text = stringResource(R.string.action_remove)) } }, @@ -90,7 +90,7 @@ fun HistoryDeleteAllDialog( TextButton(onClick = { onDelete() onDismissRequest() - },) { + }) { Text(text = stringResource(R.string.action_ok)) } }, diff --git a/app/src/main/java/eu/kanade/presentation/manga/MangaScreen.kt b/app/src/main/java/eu/kanade/presentation/manga/MangaScreen.kt index 740ece4a2..352e6aedb 100644 --- a/app/src/main/java/eu/kanade/presentation/manga/MangaScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/manga/MangaScreen.kt @@ -63,7 +63,6 @@ import eu.kanade.tachiyomi.data.download.model.Download import eu.kanade.tachiyomi.source.getNameForMangaInfo import eu.kanade.tachiyomi.ui.manga.ChapterItem import eu.kanade.tachiyomi.ui.manga.MangaScreenModel -import eu.kanade.tachiyomi.util.lang.toRelativeString import eu.kanade.tachiyomi.util.system.copyToClipboard import tachiyomi.domain.chapter.model.Chapter import tachiyomi.domain.chapter.service.missingChaptersCount @@ -740,7 +739,7 @@ private fun LazyListScope.sharedChapterItems( date = chapterItem.chapter.dateUpload .takeIf { it > 0L } ?.let { - Date(it).toRelativeString(context, dateFormat) + dateFormat.format(Date(it)) }, readProgress = chapterItem.chapter.lastPageRead .takeIf { !chapterItem.chapter.read && it > 0L } diff --git a/app/src/main/java/eu/kanade/presentation/manga/components/MangaBottomActionMenu.kt b/app/src/main/java/eu/kanade/presentation/manga/components/MangaBottomActionMenu.kt index eac2228f1..fa98e176b 100644 --- a/app/src/main/java/eu/kanade/presentation/manga/components/MangaBottomActionMenu.kt +++ b/app/src/main/java/eu/kanade/presentation/manga/components/MangaBottomActionMenu.kt @@ -143,7 +143,7 @@ fun MangaBottomActionMenu( if (onMarkPreviousAsReadClicked != null) { Button( title = stringResource(R.string.action_mark_previous_as_read), - icon = ImageVector.vectorResource(id = R.drawable.ic_done_prev_24dp), + icon = ImageVector.vectorResource(R.drawable.ic_done_prev_24dp), toConfirm = confirm[4], onLongClick = { onLongClickItem(4) }, onClick = onMarkPreviousAsReadClicked, diff --git a/app/src/main/java/eu/kanade/presentation/manga/components/MangaDialogs.kt b/app/src/main/java/eu/kanade/presentation/manga/components/MangaDialogs.kt index 84d969247..94f34eec2 100644 --- a/app/src/main/java/eu/kanade/presentation/manga/components/MangaDialogs.kt +++ b/app/src/main/java/eu/kanade/presentation/manga/components/MangaDialogs.kt @@ -16,7 +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 tachiyomi.domain.manga.interactor.MAX_FETCH_INTERVAL +import tachiyomi.domain.manga.interactor.FetchInterval import tachiyomi.presentation.core.components.WheelTextPicker @Composable @@ -67,7 +67,7 @@ fun SetIntervalDialog( contentAlignment = Alignment.Center, ) { val size = DpSize(width = maxWidth / 2, height = 128.dp) - val items = (0..MAX_FETCH_INTERVAL).map { + val items = (0..FetchInterval.MAX_INTERVAL).map { if (it == 0) { stringResource(R.string.label_default) } else { @@ -91,7 +91,7 @@ fun SetIntervalDialog( TextButton(onClick = { onValueChanged(selectedInterval) onDismissRequest() - },) { + }) { Text(text = stringResource(R.string.action_ok)) } }, diff --git a/app/src/main/java/eu/kanade/presentation/more/MoreScreen.kt b/app/src/main/java/eu/kanade/presentation/more/MoreScreen.kt index 702d42396..c12ac59e8 100644 --- a/app/src/main/java/eu/kanade/presentation/more/MoreScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/MoreScreen.kt @@ -62,7 +62,7 @@ fun MoreScreen( WarningBanner( textRes = R.string.fdroid_warning, modifier = Modifier.clickable { - uriHandler.openUri("https://tachiyomi.org/help/faq/#how-do-i-migrate-from-the-f-droid-version") + uriHandler.openUri("https://tachiyomi.org/docs/faq/general#how-do-i-update-from-the-f-droid-builds") }, ) } @@ -108,11 +108,11 @@ fun MoreScreen( stringResource(R.string.paused) } else { "${stringResource(R.string.paused)} • ${ - pluralStringResource( - id = R.plurals.download_queue_summary, - count = pending, - pending, - ) + pluralStringResource( + id = R.plurals.download_queue_summary, + count = pending, + pending, + ) }" } } diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/PreferenceModel.kt b/app/src/main/java/eu/kanade/presentation/more/settings/Preference.kt similarity index 99% rename from app/src/main/java/eu/kanade/presentation/more/settings/PreferenceModel.kt rename to app/src/main/java/eu/kanade/presentation/more/settings/Preference.kt index 5e8973626..fa25ff184 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/PreferenceModel.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/Preference.kt @@ -4,7 +4,6 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.res.stringResource -import eu.kanade.presentation.more.settings.Preference.PreferenceItem import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.track.TrackService import tachiyomi.core.preference.Preference as PreferenceData diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBackupAndSyncScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBackupAndSyncScreen.kt index f4ad14532..c46375164 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBackupAndSyncScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBackupAndSyncScreen.kt @@ -211,7 +211,7 @@ object SettingsBackupAndSyncScreen : SearchableSettings { showCreateDialog = false flag = it try { - chooseBackupDir.launch(Backup.getBackupFilename()) + chooseBackupDir.launch(Backup.getFilename()) } catch (e: ActivityNotFoundException) { flag = 0 context.toast(R.string.file_picker_error) diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsTrackingScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsTrackingScreen.kt index 3b4df1e0b..d57034536 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsTrackingScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsTrackingScreen.kt @@ -70,7 +70,7 @@ object SettingsTrackingScreen : SearchableSettings { @Composable override fun RowScope.AppBarAction() { val uriHandler = LocalUriHandler.current - IconButton(onClick = { uriHandler.openUri("https://tachiyomi.org/help/guides/tracking/") }) { + IconButton(onClick = { uriHandler.openUri("https://tachiyomi.org/docs/guides/tracking") }) { Icon( imageVector = Icons.Outlined.HelpOutline, contentDescription = stringResource(R.string.tracking_guide), diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/about/AboutScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/about/AboutScreen.kt index 6f42edb7a..af3835987 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/about/AboutScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/about/AboutScreen.kt @@ -149,7 +149,7 @@ object AboutScreen : Screen() { item { TextPreferenceWidget( title = stringResource(R.string.help_translate), - onPreferenceClick = { uriHandler.openUri("https://tachiyomi.org/help/contribution/#translation") }, + onPreferenceClick = { uriHandler.openUri("https://tachiyomi.org/docs/contribute#translation") }, ) } @@ -163,7 +163,7 @@ object AboutScreen : Screen() { item { TextPreferenceWidget( title = stringResource(R.string.privacy_policy), - onPreferenceClick = { uriHandler.openUri("https://tachiyomi.org/privacy") }, + onPreferenceClick = { uriHandler.openUri("https://tachiyomi.org/privacy/") }, ) } diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/about/OpenSourceLicensesScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/about/OpenSourceLicensesScreen.kt index e5b94adb8..f1a8ae47c 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/about/OpenSourceLicensesScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/about/OpenSourceLicensesScreen.kt @@ -41,9 +41,9 @@ class OpenSourceLicensesScreen : Screen() { ), onLibraryClick = { val libraryLicenseScreen = OpenSourceLibraryLicenseScreen( - name = it.name, - website = it.website, - license = it.licenses.firstOrNull()?.htmlReadyLicenseContent.orEmpty(), + name = it.library.name, + website = it.library.website, + license = it.library.licenses.firstOrNull()?.htmlReadyLicenseContent.orEmpty(), ) navigator.push(libraryLicenseScreen) }, diff --git a/app/src/main/java/eu/kanade/presentation/reader/OrientationModeSelectDialog.kt b/app/src/main/java/eu/kanade/presentation/reader/OrientationModeSelectDialog.kt index 9e277b757..0fbe079a9 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/OrientationModeSelectDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/OrientationModeSelectDialog.kt @@ -1,25 +1,25 @@ package eu.kanade.presentation.reader -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding -import androidx.compose.material3.FilterChip -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text +import androidx.compose.foundation.lazy.grid.items import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.res.stringResource +import androidx.compose.ui.res.vectorResource import androidx.compose.ui.unit.dp import eu.kanade.domain.manga.model.orientationType import eu.kanade.presentation.components.AdaptiveSheet import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.ui.reader.setting.OrientationType import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsScreenModel -import tachiyomi.presentation.core.components.SettingsChipRow -import tachiyomi.presentation.core.components.material.padding +import tachiyomi.presentation.core.components.SettingsIconGrid +import tachiyomi.presentation.core.components.material.IconToggleButton private val orientationTypeOptions = OrientationType.entries.map { it.stringRes to it } @@ -32,22 +32,20 @@ fun OrientationModeSelectDialog( val manga by screenModel.mangaFlow.collectAsState() val orientationType = remember(manga) { OrientationType.fromPreference(manga?.orientationType?.toInt()) } - AdaptiveSheet( - onDismissRequest = onDismissRequest, - ) { - Row( - modifier = Modifier.padding(vertical = 16.dp), - horizontalArrangement = Arrangement.spacedBy(MaterialTheme.padding.small), - ) { - SettingsChipRow(R.string.rotation_type) { - orientationTypeOptions.map { (stringRes, it) -> - FilterChip( - selected = it == orientationType, - onClick = { - screenModel.onChangeOrientation(it) + AdaptiveSheet(onDismissRequest = onDismissRequest) { + Box(modifier = Modifier.padding(vertical = 16.dp)) { + SettingsIconGrid(R.string.rotation_type) { + items(orientationTypeOptions) { (stringRes, mode) -> + IconToggleButton( + checked = mode == orientationType, + onCheckedChange = { + screenModel.onChangeOrientation(mode) onChange(stringRes) + onDismissRequest() }, - label = { Text(stringResource(stringRes)) }, + modifier = Modifier.fillMaxWidth(), + imageVector = ImageVector.vectorResource(mode.iconRes), + title = stringResource(stringRes), ) } } diff --git a/app/src/main/java/eu/kanade/presentation/reader/ReadingModeSelectDialog.kt b/app/src/main/java/eu/kanade/presentation/reader/ReadingModeSelectDialog.kt index 91920d2ec..cb11d9950 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/ReadingModeSelectDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/ReadingModeSelectDialog.kt @@ -1,24 +1,25 @@ package eu.kanade.presentation.reader -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding -import androidx.compose.material3.FilterChip +import androidx.compose.foundation.lazy.grid.items import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.res.stringResource -import androidx.compose.ui.unit.dp +import androidx.compose.ui.res.vectorResource import eu.kanade.domain.manga.model.readingModeType import eu.kanade.presentation.components.AdaptiveSheet import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsScreenModel import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType -import tachiyomi.presentation.core.components.SettingsChipRow +import tachiyomi.presentation.core.components.SettingsIconGrid +import tachiyomi.presentation.core.components.material.IconToggleButton import tachiyomi.presentation.core.components.material.padding private val readingModeOptions = ReadingModeType.entries.map { it.stringRes to it } @@ -32,22 +33,20 @@ fun ReadingModeSelectDialog( val manga by screenModel.mangaFlow.collectAsState() val readingMode = remember(manga) { ReadingModeType.fromPreference(manga?.readingModeType?.toInt()) } - AdaptiveSheet( - onDismissRequest = onDismissRequest, - ) { - Row( - modifier = Modifier.padding(vertical = 16.dp), - horizontalArrangement = Arrangement.spacedBy(MaterialTheme.padding.small), - ) { - SettingsChipRow(R.string.pref_category_reading_mode) { - readingModeOptions.map { (stringRes, it) -> - FilterChip( - selected = it == readingMode, - onClick = { - screenModel.onChangeReadingMode(it) + AdaptiveSheet(onDismissRequest = onDismissRequest) { + Box(modifier = Modifier.padding(vertical = MaterialTheme.padding.medium)) { + SettingsIconGrid(R.string.pref_category_reading_mode) { + items(readingModeOptions) { (stringRes, mode) -> + IconToggleButton( + checked = mode == readingMode, + onCheckedChange = { + screenModel.onChangeReadingMode(mode) onChange(stringRes) + onDismissRequest() }, - label = { Text(stringResource(stringRes)) }, + modifier = Modifier.fillMaxWidth(), + imageVector = ImageVector.vectorResource(mode.iconRes), + title = stringResource(stringRes), ) } } diff --git a/app/src/main/java/eu/kanade/presentation/track/TrackServiceSearch.kt b/app/src/main/java/eu/kanade/presentation/track/TrackServiceSearch.kt index 201f87607..1ac38ecf0 100644 --- a/app/src/main/java/eu/kanade/presentation/track/TrackServiceSearch.kt +++ b/app/src/main/java/eu/kanade/presentation/track/TrackServiceSearch.kt @@ -223,6 +223,7 @@ private fun SearchResultItem( val borderColor = if (selected) MaterialTheme.colorScheme.outline else Color.Transparent Box( modifier = Modifier + .fillMaxWidth() .padding(horizontal = 12.dp) .clip(shape) .background(MaterialTheme.colorScheme.surface) diff --git a/app/src/main/java/eu/kanade/presentation/updates/UpdatesDialog.kt b/app/src/main/java/eu/kanade/presentation/updates/UpdatesDialog.kt index 45e28127e..b5210916e 100644 --- a/app/src/main/java/eu/kanade/presentation/updates/UpdatesDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/updates/UpdatesDialog.kt @@ -21,7 +21,7 @@ fun UpdatesDeleteConfirmationDialog( TextButton(onClick = { onConfirm() onDismissRequest() - },) { + }) { Text(text = stringResource(R.string.action_ok)) } }, diff --git a/app/src/main/java/eu/kanade/presentation/webview/WebViewScreenContent.kt b/app/src/main/java/eu/kanade/presentation/webview/WebViewScreenContent.kt index 3a97d57ec..5f88a4fe3 100644 --- a/app/src/main/java/eu/kanade/presentation/webview/WebViewScreenContent.kt +++ b/app/src/main/java/eu/kanade/presentation/webview/WebViewScreenContent.kt @@ -175,7 +175,7 @@ fun WebViewScreenContent( WarningBanner( textRes = R.string.information_cloudflare_help, modifier = Modifier.clickable { - uriHandler.openUri("https://tachiyomi.org/help/guides/troubleshooting/#solving-cloudflare-issues") + uriHandler.openUri("https://tachiyomi.org/docs/guides/troubleshooting/#cloudflare") }, ) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt index 817988c31..034cc0320 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt @@ -93,15 +93,14 @@ class BackupManager( // Delete older backups val numberOfBackups = backupPreferences.numberOfBackups().get() - val backupRegex = Regex("""tachiyomi_\d+-\d+-\d+_\d+-\d+.proto.gz""") - dir.listFiles { _, filename -> backupRegex.matches(filename) } + dir.listFiles { _, filename -> Backup.filenameRegex.matches(filename) } .orEmpty() .sortedByDescending { it.name } .drop(numberOfBackups - 1) .forEach { it.delete() } // Create new file to place backup - dir.createFile(Backup.getBackupFilename()) + dir.createFile(Backup.getFilename()) } else { UniFile.fromUri(context, uri) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestorer.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestorer.kt index 544c5c18d..765a700c1 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestorer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestorer.kt @@ -14,7 +14,7 @@ import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.isActive import tachiyomi.domain.chapter.model.Chapter import tachiyomi.domain.chapter.repository.ChapterRepository -import tachiyomi.domain.manga.interactor.SetFetchInterval +import tachiyomi.domain.manga.interactor.FetchInterval import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.track.model.Track import uy.kohesive.injekt.Injekt @@ -31,10 +31,10 @@ class BackupRestorer( ) { private val updateManga: UpdateManga = Injekt.get() private val chapterRepository: ChapterRepository = Injekt.get() - private val setFetchInterval: SetFetchInterval = Injekt.get() + private val fetchInterval: FetchInterval = Injekt.get() private var now = ZonedDateTime.now() - private var currentFetchWindow = setFetchInterval.getWindow(now) + private var currentFetchWindow = fetchInterval.getWindow(now) private var backupManager = BackupManager(context) @@ -103,7 +103,7 @@ class BackupRestorer( val backupMaps = backup.backupBrokenSources.map { BackupSource(it.name, it.sourceId) } + backup.backupSources sourceMapping = backupMaps.associate { it.sourceId to it.name } now = ZonedDateTime.now() - currentFetchWindow = setFetchInterval.getWindow(now) + currentFetchWindow = fetchInterval.getWindow(now) return coroutineScope { // Restore individual manga diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/Backup.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/Backup.kt index 8a9de244d..14d4dd0ae 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/Backup.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/Backup.kt @@ -1,5 +1,6 @@ package eu.kanade.tachiyomi.data.backup.models +import eu.kanade.tachiyomi.BuildConfig import kotlinx.serialization.Serializable import kotlinx.serialization.protobuf.ProtoNumber import java.text.SimpleDateFormat @@ -16,9 +17,11 @@ data class Backup( ) { companion object { - fun getBackupFilename(): String { + val filenameRegex = """${BuildConfig.APPLICATION_ID}_\d+-\d+-\d+_\d+-\d+.tachibk""".toRegex() + + fun getFilename(): String { val date = SimpleDateFormat("yyyy-MM-dd_HH-mm", Locale.getDefault()).format(Date()) - return "tachiyomi_$date.proto.gz" + return "${BuildConfig.APPLICATION_ID}_$date.tachibk" } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/cache/ChapterCache.kt b/app/src/main/java/eu/kanade/tachiyomi/data/cache/ChapterCache.kt index 38583ee64..3f155e7f5 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/cache/ChapterCache.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/cache/ChapterCache.kt @@ -8,9 +8,11 @@ import eu.kanade.tachiyomi.util.storage.DiskUtil import eu.kanade.tachiyomi.util.storage.saveTo import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json +import logcat.LogPriority import okhttp3.Response import okio.buffer import okio.sink +import tachiyomi.core.util.system.logcat import tachiyomi.domain.chapter.model.Chapter import uy.kohesive.injekt.injectLazy import java.io.File @@ -97,6 +99,7 @@ class ChapterCache(private val context: Context) { editor.commit() editor.abortUnlessCommitted() } catch (e: Exception) { + logcat(LogPriority.WARN, e) { "Failed to put page list to cache" } // Ignore. } finally { editor?.abortUnlessCommitted() @@ -174,7 +177,7 @@ class ChapterCache(private val context: Context) { * @return status of deletion for the file. */ private fun removeFileFromCache(file: String): Boolean { - // Make sure we don't delete the journal file (keeps track of cache). + // Make sure we don't delete the journal file (keeps track of cache) if (file == "journal" || file.startsWith("journal.")) { return false } @@ -182,9 +185,10 @@ class ChapterCache(private val context: Context) { return try { // Remove the extension from the file to get the key of the cache val key = file.substringBeforeLast(".") - // Remove file from cache. + // Remove file from cache diskCache.remove(key) } catch (e: Exception) { + logcat(LogPriority.WARN, e) { "Failed to remove file from cache" } false } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt b/app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt index 4ae5cfade..9a15967f4 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt @@ -43,7 +43,6 @@ import nl.adaptivity.xmlutil.serialization.XML import okhttp3.Response import tachiyomi.core.metadata.comicinfo.COMIC_INFO_FILE import tachiyomi.core.metadata.comicinfo.ComicInfo -import tachiyomi.core.util.lang.awaitSingle import tachiyomi.core.util.lang.launchIO import tachiyomi.core.util.lang.launchNow import tachiyomi.core.util.lang.withIOContext @@ -363,7 +362,7 @@ class Downloader( if (page.imageUrl.isNullOrEmpty()) { page.status = Page.State.LOAD_PAGE try { - page.imageUrl = download.source.fetchImageUrl(page).awaitSingle() + page.imageUrl = download.source.getImageUrl(page) } catch (e: Throwable) { page.status = Page.State.ERROR } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateJob.kt b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateJob.kt index cdca75770..734b5180c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateJob.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateJob.kt @@ -59,9 +59,9 @@ import tachiyomi.domain.library.service.LibraryPreferences.Companion.MANGA_HAS_U import tachiyomi.domain.library.service.LibraryPreferences.Companion.MANGA_NON_COMPLETED import tachiyomi.domain.library.service.LibraryPreferences.Companion.MANGA_NON_READ import tachiyomi.domain.library.service.LibraryPreferences.Companion.MANGA_OUTSIDE_RELEASE_PERIOD +import tachiyomi.domain.manga.interactor.FetchInterval import tachiyomi.domain.manga.interactor.GetLibraryManga import tachiyomi.domain.manga.interactor.GetManga -import tachiyomi.domain.manga.interactor.SetFetchInterval import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.manga.model.toMangaUpdate import tachiyomi.domain.source.model.SourceNotInstalledException @@ -90,7 +90,7 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet private val getCategories: GetCategories = Injekt.get() private val syncChaptersWithSource: SyncChaptersWithSource = Injekt.get() private val refreshTracks: RefreshTracks = Injekt.get() - private val setFetchInterval: SetFetchInterval = Injekt.get() + private val fetchInterval: FetchInterval = Injekt.get() private val notifier = LibraryUpdateNotifier(context) @@ -216,7 +216,7 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet val failedUpdates = CopyOnWriteArrayList>() val hasDownloads = AtomicBoolean(false) val restrictions = libraryPreferences.autoUpdateMangaRestrictions().get() - val fetchWindow = setFetchInterval.getWindow(ZonedDateTime.now()) + val fetchWindow = fetchInterval.getWindow(ZonedDateTime.now()) coroutineScope { mangaToUpdate.groupBy { it.manga.source }.values @@ -497,7 +497,7 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet private const val WORK_NAME_AUTO = "LibraryUpdate-auto" private const val WORK_NAME_MANUAL = "LibraryUpdate-manual" - private const val ERROR_LOG_HELP_URL = "https://tachiyomi.org/help/guides/troubleshooting" + private const val ERROR_LOG_HELP_URL = "https://tachiyomi.org/docs/guides/troubleshooting/" private const val MANGA_PER_SOURCE_QUEUE_WARNING_THRESHOLD = 60 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateNotifier.kt b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateNotifier.kt index 0c4606a4d..299889b8c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateNotifier.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateNotifier.kt @@ -329,11 +329,11 @@ class LibraryUpdateNotifier(private val context: Context) { } companion object { - const val HELP_WARNING_URL = "https://tachiyomi.org/help/faq/#why-does-the-app-warn-about-large-bulk-updates-and-downloads" + const val HELP_WARNING_URL = "https://tachiyomi.org/docs/faq/library#why-am-i-warned-about-large-bulk-updates-and-downloads" } } private const val NOTIF_MAX_CHAPTERS = 5 private const val NOTIF_TITLE_MAX_LEN = 45 private const val NOTIF_ICON_SIZE = 192 -private const val HELP_SKIPPED_URL = "https://tachiyomi.org/help/faq/#why-does-global-update-skip-some-entries" +private const val HELP_SKIPPED_URL = "https://tachiyomi.org/docs/faq/library#why-is-global-update-skipping-entries" diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/saver/ImageSaver.kt b/app/src/main/java/eu/kanade/tachiyomi/data/saver/ImageSaver.kt index 9656c0fd9..7086f1023 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/saver/ImageSaver.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/saver/ImageSaver.kt @@ -1,6 +1,5 @@ package eu.kanade.tachiyomi.data.saver -import android.annotation.SuppressLint import android.content.ContentUris import android.content.Context import android.graphics.Bitmap @@ -28,30 +27,59 @@ class ImageSaver( val context: Context, ) { - @SuppressLint("InlinedApi") fun save(image: Image): Uri { val data = image.data - val type = ImageUtil.findImageType(data) ?: throw Exception("Not an image") + val type = ImageUtil.findImageType(data) ?: throw IllegalArgumentException("Not an image") val filename = DiskUtil.buildValidFilename("${image.name}.${type.extension}") if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q || image.location !is Location.Pictures) { return save(data(), image.location.directory(context), filename) } + return saveApi29(image, type, filename, data) + } + + private fun save(inputStream: InputStream, directory: File, filename: String): Uri { + directory.mkdirs() + + val destFile = File(directory, filename) + + inputStream.use { input -> + destFile.outputStream().use { output -> + input.copyTo(output) + } + } + + DiskUtil.scanMedia(context, destFile.toUri()) + + return destFile.getUriCompat(context) + } + + @RequiresApi(Build.VERSION_CODES.Q) + private fun saveApi29( + image: Image, + type: ImageUtil.ImageType, + filename: String, + data: () -> InputStream, + ): Uri { val pictureDir = MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY) - val folderRelativePath = "${Environment.DIRECTORY_PICTURES}/${context.getString(R.string.app_name)}/" val imageLocation = (image.location as Location.Pictures).relativePath + val relativePath = listOf( + Environment.DIRECTORY_PICTURES, + context.getString(R.string.app_name), + imageLocation, + ).joinToString(File.separator) val contentValues = contentValuesOf( + MediaStore.Images.Media.RELATIVE_PATH to relativePath, MediaStore.Images.Media.DISPLAY_NAME to image.name, MediaStore.Images.Media.MIME_TYPE to type.mime, - MediaStore.Images.Media.RELATIVE_PATH to folderRelativePath + imageLocation, ) - val picture = findUriOrDefault(folderRelativePath, "$imageLocation$filename") { + val picture = findUriOrDefault(relativePath, filename) { context.contentResolver.insert( pictureDir, contentValues, @@ -74,49 +102,34 @@ class ImageSaver( return picture } - private fun save(inputStream: InputStream, directory: File, filename: String): Uri { - directory.mkdirs() - - val destFile = File(directory, filename) - - inputStream.use { input -> - destFile.outputStream().use { output -> - input.copyTo(output) - } - } - - DiskUtil.scanMedia(context, destFile.toUri()) - - return destFile.getUriCompat(context) - } - @RequiresApi(Build.VERSION_CODES.Q) - private fun findUriOrDefault(relativePath: String, imagePath: String, default: () -> Uri): Uri { + private fun findUriOrDefault(path: String, filename: String, default: () -> Uri): Uri { val projection = arrayOf( MediaStore.MediaColumns._ID, MediaStore.MediaColumns.DISPLAY_NAME, - MediaStore.Images.Media.MIME_TYPE, MediaStore.MediaColumns.RELATIVE_PATH, - MediaStore.MediaColumns.DATE_MODIFIED, ) val selection = "${MediaStore.MediaColumns.RELATIVE_PATH}=? AND ${MediaStore.MediaColumns.DISPLAY_NAME}=?" + // Need to make sure it ends with the separator + val normalizedPath = "${path.removeSuffix(File.separator)}${File.separator}" + context.contentResolver.query( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection, selection, - arrayOf(relativePath, imagePath), + arrayOf(normalizedPath, filename), null, ).use { cursor -> if (cursor != null && cursor.count >= 1) { - cursor.moveToFirst().let { + if (cursor.moveToFirst()) { val id = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns._ID)) - return ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id) } } } + return default() } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/kavita/Kavita.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/kavita/Kavita.kt index 0a45187a3..c11730754 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/kavita/Kavita.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/kavita/Kavita.kt @@ -119,7 +119,7 @@ class Kavita(private val context: Context, id: Long) : TrackService(id, "Kavita" .reduce(Long::or) and Long.MAX_VALUE } val preferences: SharedPreferences by lazy { - context.getSharedPreferences("source_$sourceSuffixID", 0x0000) + context.getSharedPreferences("source_$sourceSuffixID", Context.MODE_PRIVATE) } val prefApiUrl = preferences.getString("APIURL", "")!! if (prefApiUrl.isEmpty()) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/suwayomi/TachideskApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/suwayomi/TachideskApi.kt index 24127c63a..86227095d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/suwayomi/TachideskApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/suwayomi/TachideskApi.kt @@ -1,6 +1,7 @@ package eu.kanade.tachiyomi.data.track.suwayomi import android.app.Application +import android.content.Context import android.content.SharedPreferences import eu.kanade.tachiyomi.data.database.models.Track import eu.kanade.tachiyomi.data.track.TrackManager @@ -107,7 +108,7 @@ class TachideskApi { } private val preferences: SharedPreferences by lazy { - Injekt.get().getSharedPreferences("source_$tachideskExtensionId", 0x0000) + Injekt.get().getSharedPreferences("source_$tachideskExtensionId", Context.MODE_PRIVATE) } private fun getPrefBaseUrl(): String = preferences.getString(ADDRESS_TITLE, ADDRESS_DEFAULT)!! diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateNotifier.kt b/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateNotifier.kt index 7c0794bc7..728967654 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateNotifier.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateNotifier.kt @@ -143,7 +143,7 @@ internal class AppUpdateNotifier(private val context: Context) { setContentTitle(context.getString(R.string.update_check_notification_update_available)) setContentText(context.getString(R.string.update_check_fdroid_migration_info)) setSmallIcon(R.drawable.ic_tachi) - setContentIntent(NotificationHandler.openUrl(context, "https://tachiyomi.org/help/faq/#how-do-i-migrate-from-the-f-droid-version")) + setContentIntent(NotificationHandler.openUrl(context, "https://tachiyomi.org/docs/faq/general#how-do-i-update-from-the-f-droid-builds")) } notificationBuilder.show(Notifications.ID_APP_UPDATE_PROMPT) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/details/ExtensionDetailsScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/details/ExtensionDetailsScreenModel.kt index 1ad0faec4..c88ea5b42 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/details/ExtensionDetailsScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/details/ExtensionDetailsScreenModel.kt @@ -102,7 +102,7 @@ class ExtensionDetailsScreenModel( val extension = state.value.extension ?: return "" if (!extension.hasReadme) { - return "https://tachiyomi.org/help/faq/#extensions" + return "https://tachiyomi.org/docs/faq/browse/extensions" } val pkgName = extension.pkgName.substringAfter("eu.kanade.tachiyomi.extension.") diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/sources/MigrateSourceTab.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/sources/MigrateSourceTab.kt index 14dcd9756..fe53ccfad 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/sources/MigrateSourceTab.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/sources/MigrateSourceTab.kt @@ -31,7 +31,7 @@ fun Screen.migrateSourceTab(): TabContent { title = stringResource(R.string.migration_help_guide), icon = Icons.Outlined.HelpOutline, onClick = { - uriHandler.openUri("https://tachiyomi.org/help/guides/source-migration/") + uriHandler.openUri("https://tachiyomi.org/docs/guides/source-migration") }, ), ), diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt index ff6ad995b..188b148eb 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt @@ -9,6 +9,7 @@ import androidx.compose.ui.unit.dp import androidx.paging.Pager import androidx.paging.PagingConfig import androidx.paging.cachedIn +import androidx.paging.filter import androidx.paging.map import cafe.adriel.voyager.core.model.StateScreenModel import cafe.adriel.voyager.core.model.coroutineScope @@ -30,7 +31,6 @@ import eu.kanade.tachiyomi.util.removeCovers import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.emptyFlow -import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.flow.map @@ -113,25 +113,20 @@ class BrowseSourceScreenModel( /** * Flow of Pager flow tied to [State.listing] */ + private val hideInLibraryItems = sourcePreferences.hideInLibraryItems().get() val mangaPagerFlowFlow = state.map { it.listing } .distinctUntilChanged() .map { listing -> - Pager( - PagingConfig(pageSize = 25), - ) { + Pager(PagingConfig(pageSize = 25)) { getRemoteManga.subscribe(sourceId, listing.query ?: "", listing.filters) }.flow.map { pagingData -> pagingData.map { networkToLocalManga.await(it.toDomainManga(sourceId)) - .let { localManga -> - getManga.subscribe(localManga.url, localManga.source) - } + .let { localManga -> getManga.subscribe(localManga.url, localManga.source) } .filterNotNull() - .filter { localManga -> - !sourcePreferences.hideInLibraryItems().get() || !localManga.favorite - } .stateIn(ioCoroutineScope) } + .filter { !hideInLibraryItems || !it.value.favorite } } .cachedIn(ioCoroutineScope) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/SourceFilterDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/SourceFilterDialog.kt index f82f800ae..5ec0769dc 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/SourceFilterDialog.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/SourceFilterDialog.kt @@ -64,7 +64,7 @@ fun SourceFilterDialog( Button(onClick = { onFilter() onDismissRequest() - },) { + }) { Text(stringResource(R.string.action_filter)) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/SearchScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/SearchScreenModel.kt index 55c2e151b..276af54ee 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/SearchScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/SearchScreenModel.kt @@ -19,7 +19,6 @@ import kotlinx.coroutines.flow.update import kotlinx.coroutines.isActive import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import tachiyomi.core.util.lang.awaitSingle import tachiyomi.domain.manga.interactor.GetManga import tachiyomi.domain.manga.interactor.NetworkToLocalManga import tachiyomi.domain.manga.model.Manga @@ -140,7 +139,7 @@ abstract class SearchScreenModel( try { val page = withContext(coroutineDispatcher) { - source.fetchSearchManga(1, query, source.getFilterList()).awaitSingle() + source.getSearchManga(1, query, source.getFilterList()) } val titles = page.mangas.map { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadQueueScreen.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadQueueScreen.kt index 143185634..dcbb4536f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadQueueScreen.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadQueueScreen.kt @@ -1,13 +1,13 @@ package eu.kanade.tachiyomi.ui.download import android.view.LayoutInflater -import android.view.ViewGroup import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.PlayArrow @@ -42,7 +42,6 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.compose.ui.viewinterop.AndroidView import androidx.core.view.ViewCompat -import androidx.core.view.updateLayoutParams import androidx.core.view.updatePadding import androidx.recyclerview.widget.LinearLayoutManager import cafe.adriel.voyager.core.model.rememberScreenModel @@ -243,6 +242,7 @@ object DownloadQueueScreen : Screen() { ) return@Scaffold } + val density = LocalDensity.current val layoutDirection = LocalLayoutDirection.current val left = with(density) { contentPadding.calculateLeftPadding(layoutDirection).toPx().roundToInt() } @@ -252,13 +252,13 @@ object DownloadQueueScreen : Screen() { Box(modifier = Modifier.nestedScroll(nestedScrollConnection)) { AndroidView( + modifier = Modifier.fillMaxWidth(), factory = { context -> screenModel.controllerBinding = DownloadListBinding.inflate(LayoutInflater.from(context)) screenModel.adapter = DownloadAdapter(screenModel.listener) - screenModel.controllerBinding.recycler.adapter = screenModel.adapter + screenModel.controllerBinding.root.adapter = screenModel.adapter screenModel.adapter?.isHandleDragEnabled = true - screenModel.adapter?.fastScroller = screenModel.controllerBinding.fastScroller - screenModel.controllerBinding.recycler.layoutManager = LinearLayoutManager(context) + screenModel.controllerBinding.root.layoutManager = LinearLayoutManager(context) ViewCompat.setNestedScrollingEnabled(screenModel.controllerBinding.root, true) @@ -274,7 +274,7 @@ object DownloadQueueScreen : Screen() { screenModel.controllerBinding.root }, update = { - screenModel.controllerBinding.recycler + screenModel.controllerBinding.root .updatePadding( left = left, top = top, @@ -282,14 +282,6 @@ object DownloadQueueScreen : Screen() { bottom = bottom, ) - screenModel.controllerBinding.fastScroller - .updateLayoutParams { - leftMargin = left - topMargin = top - rightMargin = right - bottomMargin = bottom - } - screenModel.adapter?.updateDataSet(downloadList) }, ) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadQueueScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadQueueScreenModel.kt index 711985887..18ab4c36b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadQueueScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadQueueScreenModel.kt @@ -84,13 +84,17 @@ class DownloadQueueScreenModel( } reorder(newDownloads) } - R.id.move_to_top_series -> { + R.id.move_to_top_series, R.id.move_to_bottom_series -> { val (selectedSeries, otherSeries) = adapter?.currentItems ?.filterIsInstance() ?.map(DownloadItem::download) ?.partition { item.download.manga.id == it.manga.id } ?: Pair(emptyList(), emptyList()) - reorder(selectedSeries + otherSeries) + if (menuItem.itemId == R.id.move_to_top_series) { + reorder(selectedSeries + otherSeries) + } else { + reorder(otherSeries + selectedSeries) + } } R.id.cancel_download -> { cancel(listOf(item.download)) @@ -258,6 +262,6 @@ class DownloadQueueScreenModel( * @return the holder of the download or null if it's not bound. */ private fun getHolder(download: Download): DownloadHolder? { - return controllerBinding.recycler.findViewHolderForItemId(download.chapter.id) as? DownloadHolder + return controllerBinding.root.findViewHolderForItemId(download.chapter.id) as? DownloadHolder } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryTab.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryTab.kt index cde9762d5..5469a11a8 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryTab.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryTab.kt @@ -158,7 +158,7 @@ object LibraryTab : Tab { EmptyScreenAction( stringResId = R.string.getting_started_guide, icon = Icons.Outlined.HelpOutline, - onClick = { handler.openUri("https://tachiyomi.org/help/guides/getting-started") }, + onClick = { handler.openUri("https://tachiyomi.org/docs/guides/getting-started") }, ), ), ) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackInfoDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackInfoDialog.kt index 47d7c5132..f92374b2a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackInfoDialog.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackInfoDialog.kt @@ -271,7 +271,10 @@ private data class TrackStatusSelectorScreen( selection = state.selection, onSelectionChange = sm::setSelection, selections = remember { sm.getSelections() }, - onConfirm = { sm.setStatus(); navigator.pop() }, + onConfirm = { + sm.setStatus() + navigator.pop() + }, onDismissRequest = navigator::pop, ) } @@ -322,7 +325,10 @@ private data class TrackChapterSelectorScreen( selection = state.selection, onSelectionChange = sm::setSelection, range = remember { sm.getRange() }, - onConfirm = { sm.setChapter(); navigator.pop() }, + onConfirm = { + sm.setChapter() + navigator.pop() + }, onDismissRequest = navigator::pop, ) } @@ -378,7 +384,10 @@ private data class TrackScoreSelectorScreen( selection = state.selection, onSelectionChange = sm::setSelection, selections = remember { sm.getSelections() }, - onConfirm = { sm.setScore(); navigator.pop() }, + onConfirm = { + sm.setScore() + navigator.pop() + }, onDismissRequest = navigator::pop, ) } @@ -495,7 +504,10 @@ private data class TrackDateSelectorScreen( }, initialSelectedDateMillis = sm.initialSelection, selectableDates = selectableDates, - onConfirm = { sm.setDate(it); navigator.pop() }, + onConfirm = { + sm.setDate(it) + navigator.pop() + }, onRemove = { sm.confirmRemoveDate(navigator) }.takeIf { canRemove }, onDismissRequest = navigator::pop, ) @@ -584,7 +596,10 @@ private data class TrackDateRemoverScreen( Text(text = stringResource(android.R.string.cancel)) } FilledTonalButton( - onClick = { sm.removeDate(); navigator.popUntil { it is TrackInfoDialogHomeScreen } }, + onClick = { + sm.removeDate() + navigator.popUntil { it is TrackInfoDialogHomeScreen } + }, colors = ButtonDefaults.filledTonalButtonColors( containerColor = MaterialTheme.colorScheme.errorContainer, contentColor = MaterialTheme.colorScheme.onErrorContainer, @@ -646,7 +661,10 @@ data class TrackServiceSearchScreen( queryResult = state.queryResult, selected = state.selected, onSelectedChange = sm::updateSelection, - onConfirmSelection = { sm.registerTracking(state.selected!!); navigator.pop() }, + onConfirmSelection = { + sm.registerTracking(state.selected!!) + navigator.pop() + }, onDismissRequest = navigator::pop, ) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/HttpPageLoader.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/HttpPageLoader.kt index 38ec9361d..4802708a6 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/HttpPageLoader.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/HttpPageLoader.kt @@ -15,7 +15,6 @@ import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.flow import kotlinx.coroutines.runInterruptible import kotlinx.coroutines.suspendCancellableCoroutine -import tachiyomi.core.util.lang.awaitSingle import tachiyomi.core.util.lang.launchIO import tachiyomi.core.util.lang.withIOContext import uy.kohesive.injekt.Injekt @@ -170,7 +169,7 @@ internal class HttpPageLoader( try { if (page.imageUrl.isNullOrEmpty()) { page.status = Page.State.LOAD_PAGE - page.imageUrl = source.fetchImageUrl(page).awaitSingle() + page.imageUrl = source.getImageUrl(page) } val imageUrl = page.imageUrl!! diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/security/UnlockActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/security/UnlockActivity.kt index b697a98d1..09ec00169 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/security/UnlockActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/security/UnlockActivity.kt @@ -19,7 +19,7 @@ class UnlockActivity : BaseActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) startAuthentication( - getString(R.string.unlock_app), + getString(R.string.unlock_app_title, getString(R.string.app_name)), confirmationRequired = false, callback = object : AuthenticatorUtil.AuthenticationCallback() { override fun onAuthenticationError( diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/updates/UpdatesScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/updates/UpdatesScreenModel.kt index 6459d6525..6e0c1c474 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/updates/UpdatesScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/updates/UpdatesScreenModel.kt @@ -20,7 +20,6 @@ import eu.kanade.tachiyomi.data.download.DownloadManager 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.coroutines.channels.Channel import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.catch @@ -384,7 +383,7 @@ class UpdatesScreenModel( val afterDate = after?.item?.update?.dateFetch?.toDateKey() ?: Date(0) when { beforeDate.time != afterDate.time && afterDate.time != 0L -> { - val text = afterDate.toRelativeString(context, dateFormat) + val text = dateFormat.format(afterDate) UpdatesUiModel.Header(text) } // Return null to avoid adding a separator between two items. diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/CrashLogUtil.kt b/app/src/main/java/eu/kanade/tachiyomi/util/CrashLogUtil.kt index aa9830de8..c495c7008 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/CrashLogUtil.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/CrashLogUtil.kt @@ -4,6 +4,7 @@ import android.content.Context import android.os.Build import eu.kanade.tachiyomi.BuildConfig import eu.kanade.tachiyomi.util.storage.getUriCompat +import eu.kanade.tachiyomi.util.system.WebViewUtil import eu.kanade.tachiyomi.util.system.createFileInCacheDir import eu.kanade.tachiyomi.util.system.toShareIntent import eu.kanade.tachiyomi.util.system.toast @@ -35,6 +36,7 @@ class CrashLogUtil(private val context: Context) { Device name: ${Build.DEVICE} Device model: ${Build.MODEL} Device product name: ${Build.PRODUCT} + WebView user agent: ${WebViewUtil.getInferredUserAgent(context)} """.trimIndent() } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/lang/DateExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/lang/DateExtensions.kt index 9efcaaa9f..88477e8d5 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/lang/DateExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/lang/DateExtensions.kt @@ -1,14 +1,11 @@ package eu.kanade.tachiyomi.util.lang -import android.content.Context -import eu.kanade.tachiyomi.R import java.text.DateFormat import java.time.Instant import java.time.LocalDateTime import java.time.ZoneId import java.util.Calendar import java.util.Date -import java.util.TimeZone fun Date.toDateTimestampString(dateFormatter: DateFormat): String { val date = dateFormatter.format(this) @@ -45,101 +42,3 @@ fun Long.toDateKey(): Date { cal[Calendar.MILLISECOND] = 0 return cal.time } - -/** - * Convert epoch long to Calendar instance - * - * @return Calendar instance at supplied epoch time. Null if epoch was 0. - */ -fun Long.toCalendar(): Calendar? { - if (this == 0L) { - return null - } - val cal = Calendar.getInstance() - cal.timeInMillis = this - return cal -} - -/** - * Convert local time millisecond value to Calendar instance in UTC - * - * @return UTC Calendar instance at supplied time. Null if time is 0. - */ -fun Long.toUtcCalendar(): Calendar? { - if (this == 0L) { - return null - } - val rawCalendar = Calendar.getInstance().apply { - timeInMillis = this@toUtcCalendar - } - return Calendar.getInstance(TimeZone.getTimeZone("UTC")).apply { - clear() - set( - rawCalendar.get(Calendar.YEAR), - rawCalendar.get(Calendar.MONTH), - rawCalendar.get(Calendar.DAY_OF_MONTH), - rawCalendar.get(Calendar.HOUR_OF_DAY), - rawCalendar.get(Calendar.MINUTE), - rawCalendar.get(Calendar.SECOND), - ) - } -} - -/** - * Convert UTC time millisecond to Calendar instance in local time zone - * - * @return local Calendar instance at supplied UTC time. Null if time is 0. - */ -fun Long.toLocalCalendar(): Calendar? { - if (this == 0L) { - return null - } - val rawCalendar = Calendar.getInstance(TimeZone.getTimeZone("UTC")).apply { - timeInMillis = this@toLocalCalendar - } - return Calendar.getInstance().apply { - clear() - set( - rawCalendar.get(Calendar.YEAR), - rawCalendar.get(Calendar.MONTH), - rawCalendar.get(Calendar.DAY_OF_MONTH), - rawCalendar.get(Calendar.HOUR_OF_DAY), - rawCalendar.get(Calendar.MINUTE), - rawCalendar.get(Calendar.SECOND), - ) - } -} - -private const val MILLISECONDS_IN_DAY = 86_400_000L - -fun Date.toRelativeString( - context: Context, - dateFormat: DateFormat = DateFormat.getDateInstance(DateFormat.SHORT), -): String { - val now = Date() - val difference = now.timeWithOffset.floorNearest(MILLISECONDS_IN_DAY) - this.timeWithOffset.floorNearest(MILLISECONDS_IN_DAY) - val days = difference.floorDiv(MILLISECONDS_IN_DAY).toInt() - return when { - difference < 0 -> dateFormat.format(this) - difference < MILLISECONDS_IN_DAY -> context.getString(R.string.relative_time_today) - difference < MILLISECONDS_IN_DAY.times(7) -> context.resources.getQuantityString( - R.plurals.relative_time, - days, - days, - ) - else -> dateFormat.format(this) - } -} - -private val Date.timeWithOffset: Long - get() { - return Calendar.getInstance().run { - time = this@timeWithOffset - val dstOffset = get(Calendar.DST_OFFSET) - this@timeWithOffset.time + timeZone.rawOffset + dstOffset - } - } - -fun Long.floorNearest(to: Long): Long { - return this.floorDiv(to) * to -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/system/DisplayExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/system/DisplayExtensions.kt index 50f45ae85..3e2834fd2 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/system/DisplayExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/system/DisplayExtensions.kt @@ -3,9 +3,7 @@ package eu.kanade.tachiyomi.util.system import android.app.Activity import android.content.Context import android.content.res.Configuration -import android.content.res.Resources import android.os.Build -import android.view.View import eu.kanade.domain.ui.UiPreferences import eu.kanade.domain.ui.model.TabletUiMode import uy.kohesive.injekt.Injekt @@ -64,18 +62,6 @@ fun Context.isNightMode(): Boolean { return resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES } -val Resources.isLTR - get() = configuration.layoutDirection == View.LAYOUT_DIRECTION_LTR - -/** - * Converts to px and takes into account LTR/RTL layout. - */ -val Float.dpToPxEnd: Float - get() = ( - this * Resources.getSystem().displayMetrics.density * - if (Resources.getSystem().isLTR) 1 else -1 - ) - /** * Checks whether if the device has a display cutout (i.e. notch, camera cutout, etc.). * diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/MaterialFastScroll.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/MaterialFastScroll.kt deleted file mode 100644 index 29e9e43e3..000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/MaterialFastScroll.kt +++ /dev/null @@ -1,92 +0,0 @@ -package eu.kanade.tachiyomi.widget - -import android.annotation.SuppressLint -import android.content.Context -import android.util.AttributeSet -import android.view.MotionEvent -import androidx.core.view.ViewCompat -import dev.chrisbanes.insetter.applyInsetter -import eu.davidea.fastscroller.FastScroller -import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.util.system.dpToPxEnd -import eu.kanade.tachiyomi.util.system.isLTR - -class MaterialFastScroll @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : - FastScroller(context, attrs) { - - init { - setViewsToUse( - R.layout.material_fastscroll, - R.id.fast_scroller_bubble, - R.id.fast_scroller_handle, - ) - autoHideEnabled = true - ignoreTouchesOutsideHandle = true - - applyInsetter { - type(navigationBars = true) { - margin() - } - } - } - - // Overridden to handle RTL - @SuppressLint("ClickableViewAccessibility") - override fun onTouchEvent(event: MotionEvent): Boolean { - if (recyclerView.computeVerticalScrollRange() <= recyclerView.computeVerticalScrollExtent()) { - return super.onTouchEvent(event) - } - - when (event.action) { - MotionEvent.ACTION_DOWN -> { - // start: handle RTL differently - if ( - if (context.resources.isLTR) { - event.x < handle.x - ViewCompat.getPaddingStart(handle) - } else { - event.x > handle.width + ViewCompat.getPaddingStart(handle) - } - ) { - return false - } - // end - - if (ignoreTouchesOutsideHandle && - (event.y < handle.y || event.y > handle.y + handle.height) - ) { - return false - } - handle.isSelected = true - notifyScrollStateChange(true) - showBubble() - showScrollbar() - val y = event.y - setBubbleAndHandlePosition(y) - setRecyclerViewPosition(y) - return true - } - MotionEvent.ACTION_MOVE -> { - val y = event.y - setBubbleAndHandlePosition(y) - setRecyclerViewPosition(y) - return true - } - MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> { - handle.isSelected = false - notifyScrollStateChange(false) - hideBubble() - if (autoHideEnabled) hideScrollbar() - return true - } - } - return super.onTouchEvent(event) - } - - override fun setBubbleAndHandlePosition(y: Float) { - super.setBubbleAndHandlePosition(y) - if (bubbleEnabled) { - bubble.y = handle.y - bubble.height / 2f + handle.height / 2f - bubble.translationX = (-45f).dpToPxEnd - } - } -} diff --git a/app/src/main/res/drawable/material_thumb_drawable.xml b/app/src/main/res/drawable/material_thumb_drawable.xml deleted file mode 100644 index 2e550c0df..000000000 --- a/app/src/main/res/drawable/material_thumb_drawable.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/download_list.xml b/app/src/main/res/layout/download_list.xml index e2c96ff12..ec3e3bab9 100644 --- a/app/src/main/res/layout/download_list.xml +++ b/app/src/main/res/layout/download_list.xml @@ -1,24 +1,7 @@ - - - - - - - + android:layout_height="match_parent" + android:clipToPadding="false" + tools:listitem="@layout/download_item" /> diff --git a/app/src/main/res/layout/material_fastscroll.xml b/app/src/main/res/layout/material_fastscroll.xml deleted file mode 100644 index 56b16a1b8..000000000 --- a/app/src/main/res/layout/material_fastscroll.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/menu/download_single.xml b/app/src/main/res/menu/download_single.xml index 34ec33a4d..1cf14ff0c 100644 --- a/app/src/main/res/menu/download_single.xml +++ b/app/src/main/res/menu/download_single.xml @@ -13,6 +13,10 @@ android:id="@+id/move_to_bottom" android:title="@string/action_move_to_bottom" /> + + diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 14dc1a13a..22313ff42 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -56,21 +56,6 @@ - - - - - diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index b5854fcb5..2c76035b7 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -5,7 +5,7 @@ plugins { dependencies { implementation(androidxLibs.gradle) implementation(kotlinLibs.gradle) - implementation(libs.kotlinter) + implementation(libs.ktlint) implementation(gradleApi()) } diff --git a/buildSrc/src/main/kotlin/tachiyomi.lint.gradle.kts b/buildSrc/src/main/kotlin/tachiyomi.lint.gradle.kts index 12b7b2295..a89d88592 100644 --- a/buildSrc/src/main/kotlin/tachiyomi.lint.gradle.kts +++ b/buildSrc/src/main/kotlin/tachiyomi.lint.gradle.kts @@ -1,20 +1,14 @@ -import org.jmailen.gradle.kotlinter.KotlinterExtension -import org.jmailen.gradle.kotlinter.KotlinterPlugin +import org.jlleitschuh.gradle.ktlint.KtlintExtension +import org.jlleitschuh.gradle.ktlint.KtlintPlugin -apply() +apply() -extensions.configure("kotlinter") { - experimentalRules = true +extensions.configure("ktlint") { + version.set("0.50.0") + android.set(true) + enableExperimentalRules.set(true) - disabledRules = arrayOf( - "experimental:argument-list-wrapping", // Doesn't play well with Android Studio - "filename", // Often broken to give a more general name - ) -} - -tasks { - named("preBuild").configure { - if (!System.getenv("CI").toBoolean()) - dependsOn("formatKotlin") + filter { + exclude("**/generated/**") } } diff --git a/core-metadata/build.gradle.kts b/core-metadata/build.gradle.kts index 51db46b91..43b8846ab 100644 --- a/core-metadata/build.gradle.kts +++ b/core-metadata/build.gradle.kts @@ -11,7 +11,6 @@ android { testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" consumerProguardFiles("consumer-rules.pro") } - } dependencies { diff --git a/core/src/main/java/eu/kanade/tachiyomi/network/NetworkHelper.kt b/core/src/main/java/eu/kanade/tachiyomi/network/NetworkHelper.kt index 38ba749d2..6893a0495 100644 --- a/core/src/main/java/eu/kanade/tachiyomi/network/NetworkHelper.kt +++ b/core/src/main/java/eu/kanade/tachiyomi/network/NetworkHelper.kt @@ -39,7 +39,9 @@ class NetworkHelper( builder.addNetworkInterceptor(httpLoggingInterceptor) } - builder.addInterceptor(CloudflareInterceptor(context, cookieJar, ::defaultUserAgentProvider)) + builder.addInterceptor( + CloudflareInterceptor(context, cookieJar, ::defaultUserAgentProvider), + ) when (preferences.dohProvider().get()) { PREF_DOH_CLOUDFLARE -> builder.dohCloudflare() diff --git a/core/src/main/java/eu/kanade/tachiyomi/network/NetworkPreferences.kt b/core/src/main/java/eu/kanade/tachiyomi/network/NetworkPreferences.kt index 5e14d0342..cba50e99c 100644 --- a/core/src/main/java/eu/kanade/tachiyomi/network/NetworkPreferences.kt +++ b/core/src/main/java/eu/kanade/tachiyomi/network/NetworkPreferences.kt @@ -17,6 +17,9 @@ class NetworkPreferences( } fun defaultUserAgent(): Preference { - return preferenceStore.getString("default_user_agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/114.0") + return preferenceStore.getString( + "default_user_agent", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/114.0", + ) } } diff --git a/core/src/main/java/eu/kanade/tachiyomi/network/OkHttpExtensions.kt b/core/src/main/java/eu/kanade/tachiyomi/network/OkHttpExtensions.kt index 4cbb34812..e6eec02f4 100644 --- a/core/src/main/java/eu/kanade/tachiyomi/network/OkHttpExtensions.kt +++ b/core/src/main/java/eu/kanade/tachiyomi/network/OkHttpExtensions.kt @@ -58,6 +58,15 @@ fun Call.asObservable(): Observable { } } +fun Call.asObservableSuccess(): Observable { + return asObservable().doOnNext { response -> + if (!response.isSuccessful) { + response.close() + throw HttpException(response.code) + } + } +} + // Based on https://github.com/gildor/kotlin-coroutines-okhttp @OptIn(ExperimentalCoroutinesApi::class) private suspend fun Call.await(callStack: Array): Response { @@ -95,6 +104,9 @@ suspend fun Call.await(): Response { return await(callStack) } +/** + * @since extensions-lib 1.5 + */ suspend fun Call.awaitSuccess(): Response { val callStack = Exception().stackTrace.run { copyOfRange(1, size) } val response = await(callStack) @@ -105,15 +117,6 @@ suspend fun Call.awaitSuccess(): Response { return response } -fun Call.asObservableSuccess(): Observable { - return asObservable().doOnNext { response -> - if (!response.isSuccessful) { - response.close() - throw HttpException(response.code) - } - } -} - fun OkHttpClient.newCachelessCallWithProgress(request: Request, listener: ProgressListener): Call { val progressClient = newBuilder() .cache(null) diff --git a/core/src/main/java/eu/kanade/tachiyomi/network/ProgressResponseBody.kt b/core/src/main/java/eu/kanade/tachiyomi/network/ProgressResponseBody.kt index 72248f17b..6ba53b197 100644 --- a/core/src/main/java/eu/kanade/tachiyomi/network/ProgressResponseBody.kt +++ b/core/src/main/java/eu/kanade/tachiyomi/network/ProgressResponseBody.kt @@ -9,7 +9,10 @@ import okio.Source import okio.buffer import java.io.IOException -class ProgressResponseBody(private val responseBody: ResponseBody, private val progressListener: ProgressListener) : ResponseBody() { +class ProgressResponseBody( + private val responseBody: ResponseBody, + private val progressListener: ProgressListener, +) : ResponseBody() { private val bufferedSource: BufferedSource by lazy { source(responseBody.source()).buffer() @@ -36,7 +39,11 @@ class ProgressResponseBody(private val responseBody: ResponseBody, private val p val bytesRead = super.read(sink, byteCount) // read() returns the number of bytes read, or -1 if this source is exhausted. totalBytesRead += if (bytesRead != -1L) bytesRead else 0 - progressListener.update(totalBytesRead, responseBody.contentLength(), bytesRead == -1L) + progressListener.update( + totalBytesRead, + responseBody.contentLength(), + bytesRead == -1L, + ) return bytesRead } } diff --git a/core/src/main/java/eu/kanade/tachiyomi/network/interceptor/CloudflareInterceptor.kt b/core/src/main/java/eu/kanade/tachiyomi/network/interceptor/CloudflareInterceptor.kt index 25b5a140a..d5893bb05 100644 --- a/core/src/main/java/eu/kanade/tachiyomi/network/interceptor/CloudflareInterceptor.kt +++ b/core/src/main/java/eu/kanade/tachiyomi/network/interceptor/CloudflareInterceptor.kt @@ -31,7 +31,11 @@ class CloudflareInterceptor( return response.code in ERROR_CODES && response.header("Server") in SERVER_CHECK } - override fun intercept(chain: Interceptor.Chain, request: Request, response: Response): Response { + override fun intercept( + chain: Interceptor.Chain, + request: Request, + response: Response, + ): Response { try { response.close() cookieManager.remove(request.url, COOKIE_NAMES, 0) diff --git a/core/src/main/java/eu/kanade/tachiyomi/network/interceptor/SpecificHostRateLimitInterceptor.kt b/core/src/main/java/eu/kanade/tachiyomi/network/interceptor/SpecificHostRateLimitInterceptor.kt index b364db743..c86f780d9 100644 --- a/core/src/main/java/eu/kanade/tachiyomi/network/interceptor/SpecificHostRateLimitInterceptor.kt +++ b/core/src/main/java/eu/kanade/tachiyomi/network/interceptor/SpecificHostRateLimitInterceptor.kt @@ -33,7 +33,9 @@ fun OkHttpClient.Builder.rateLimitHost( permits: Int, period: Long = 1, unit: TimeUnit = TimeUnit.SECONDS, -) = addInterceptor(RateLimitInterceptor(httpUrl.host, permits, period.toDuration(unit.toDurationUnit()))) +) = addInterceptor( + RateLimitInterceptor(httpUrl.host, permits, period.toDuration(unit.toDurationUnit())), +) /** * An OkHttp interceptor that handles given url host's rate limiting. @@ -69,8 +71,5 @@ fun OkHttpClient.Builder.rateLimitHost( * @param permits [Int] Number of requests allowed within a period of units. * @param period [Duration] The limiting duration. Defaults to 1.seconds. */ -fun OkHttpClient.Builder.rateLimitHost( - url: String, - permits: Int, - period: Duration = 1.seconds, -) = addInterceptor(RateLimitInterceptor(url.toHttpUrlOrNull()?.host, permits, period)) +fun OkHttpClient.Builder.rateLimitHost(url: String, permits: Int, period: Duration = 1.seconds) = + addInterceptor(RateLimitInterceptor(url.toHttpUrlOrNull()?.host, permits, period)) diff --git a/core/src/main/java/eu/kanade/tachiyomi/util/system/ToastExtensions.kt b/core/src/main/java/eu/kanade/tachiyomi/util/system/ToastExtensions.kt index 4901e7463..9e4554cb4 100644 --- a/core/src/main/java/eu/kanade/tachiyomi/util/system/ToastExtensions.kt +++ b/core/src/main/java/eu/kanade/tachiyomi/util/system/ToastExtensions.kt @@ -10,7 +10,11 @@ import androidx.annotation.StringRes * @param resource the text resource. * @param duration the duration of the toast. Defaults to short. */ -fun Context.toast(@StringRes resource: Int, duration: Int = Toast.LENGTH_SHORT, block: (Toast) -> Unit = {}): Toast { +fun Context.toast( + @StringRes resource: Int, + duration: Int = Toast.LENGTH_SHORT, + block: (Toast) -> Unit = {}, +): Toast { return toast(getString(resource), duration, block) } @@ -20,7 +24,11 @@ fun Context.toast(@StringRes resource: Int, duration: Int = Toast.LENGTH_SHORT, * @param text the text to display. * @param duration the duration of the toast. Defaults to short. */ -fun Context.toast(text: String?, duration: Int = Toast.LENGTH_SHORT, block: (Toast) -> Unit = {}): Toast { +fun Context.toast( + text: String?, + duration: Int = Toast.LENGTH_SHORT, + block: (Toast) -> Unit = {}, +): Toast { return Toast.makeText(applicationContext, text.orEmpty(), duration).also { block(it) it.show() diff --git a/core/src/main/java/eu/kanade/tachiyomi/util/system/WebViewClientCompat.kt b/core/src/main/java/eu/kanade/tachiyomi/util/system/WebViewClientCompat.kt index 6c6fba4ff..93ce0337d 100644 --- a/core/src/main/java/eu/kanade/tachiyomi/util/system/WebViewClientCompat.kt +++ b/core/src/main/java/eu/kanade/tachiyomi/util/system/WebViewClientCompat.kt @@ -47,10 +47,7 @@ abstract class WebViewClientCompat : WebViewClient() { return shouldInterceptRequestCompat(view, request.url.toString()) } - final override fun shouldInterceptRequest( - view: WebView, - url: String, - ): WebResourceResponse? { + final override fun shouldInterceptRequest(view: WebView, url: String): WebResourceResponse? { return shouldInterceptRequestCompat(view, url) } diff --git a/core/src/main/java/eu/kanade/tachiyomi/util/system/WebViewUtil.kt b/core/src/main/java/eu/kanade/tachiyomi/util/system/WebViewUtil.kt index 4fcaaceed..eb1ad9617 100644 --- a/core/src/main/java/eu/kanade/tachiyomi/util/system/WebViewUtil.kt +++ b/core/src/main/java/eu/kanade/tachiyomi/util/system/WebViewUtil.kt @@ -14,7 +14,24 @@ import kotlin.coroutines.resume object WebViewUtil { const val SPOOF_PACKAGE_NAME = "org.chromium.chrome" - const val MINIMUM_WEBVIEW_VERSION = 111 + const val MINIMUM_WEBVIEW_VERSION = 114 + + /** + * Uses the WebView's user agent string to create something similar to what Chrome on Android + * would return. + * + * Example of WebView user agent string: + * Mozilla/5.0 (Linux; Android 13; Pixel 7 Build/TQ3A.230901.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/116.0.0.0 Mobile Safari/537.36 + * + * Example of Chrome on Android: + * Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Mobile Safari/537.3 + */ + fun getInferredUserAgent(context: Context): String { + return WebView(context) + .getDefaultUserAgentString() + .replace("; Android .*?\\)".toRegex(), "; Android 10; K)") + .replace("Version/.* Chrome/".toRegex(), "Chrome/") + } fun supportsWebView(context: Context): Boolean { try { diff --git a/core/src/main/java/tachiyomi/core/Constants.kt b/core/src/main/java/tachiyomi/core/Constants.kt index 156ed6101..c5631535f 100644 --- a/core/src/main/java/tachiyomi/core/Constants.kt +++ b/core/src/main/java/tachiyomi/core/Constants.kt @@ -1,7 +1,7 @@ package tachiyomi.core object Constants { - const val URL_HELP = "https://tachiyomi.org/help/" + const val URL_HELP = "https://tachiyomi.org/docs/guides/troubleshooting/" const val MANGA_EXTRA = "manga" diff --git a/core/src/main/java/tachiyomi/core/preference/AndroidPreference.kt b/core/src/main/java/tachiyomi/core/preference/AndroidPreference.kt index 00f3701d0..a0f2f335c 100644 --- a/core/src/main/java/tachiyomi/core/preference/AndroidPreference.kt +++ b/core/src/main/java/tachiyomi/core/preference/AndroidPreference.kt @@ -68,7 +68,11 @@ sealed class AndroidPreference( key: String, defaultValue: String, ) : AndroidPreference(preferences, keyFlow, key, defaultValue) { - override fun read(preferences: SharedPreferences, key: String, defaultValue: String): String { + override fun read( + preferences: SharedPreferences, + key: String, + defaultValue: String, + ): String { return preferences.getString(key, defaultValue) ?: defaultValue } @@ -128,7 +132,11 @@ sealed class AndroidPreference( key: String, defaultValue: Boolean, ) : AndroidPreference(preferences, keyFlow, key, defaultValue) { - override fun read(preferences: SharedPreferences, key: String, defaultValue: Boolean): Boolean { + override fun read( + preferences: SharedPreferences, + key: String, + defaultValue: Boolean, + ): Boolean { return preferences.getBoolean(key, defaultValue) } @@ -143,7 +151,11 @@ sealed class AndroidPreference( key: String, defaultValue: Set, ) : AndroidPreference>(preferences, keyFlow, key, defaultValue) { - override fun read(preferences: SharedPreferences, key: String, defaultValue: Set): Set { + override fun read( + preferences: SharedPreferences, + key: String, + defaultValue: Set, + ): Set { return preferences.getStringSet(key, defaultValue) ?: defaultValue } diff --git a/core/src/main/java/tachiyomi/core/preference/AndroidPreferenceStore.kt b/core/src/main/java/tachiyomi/core/preference/AndroidPreferenceStore.kt index 74c2872d8..c59652da5 100644 --- a/core/src/main/java/tachiyomi/core/preference/AndroidPreferenceStore.kt +++ b/core/src/main/java/tachiyomi/core/preference/AndroidPreferenceStore.kt @@ -64,7 +64,11 @@ class AndroidPreferenceStore( private val SharedPreferences.keyFlow get() = callbackFlow { - val listener = SharedPreferences.OnSharedPreferenceChangeListener { _, key: String? -> trySend(key) } + val listener = SharedPreferences.OnSharedPreferenceChangeListener { _, key: String? -> + trySend( + key, + ) + } registerOnSharedPreferenceChangeListener(listener) awaitClose { unregisterOnSharedPreferenceChangeListener(listener) diff --git a/core/src/main/java/tachiyomi/core/preference/Preference.kt b/core/src/main/java/tachiyomi/core/preference/Preference.kt index 67b7a44f4..e76ea23d4 100644 --- a/core/src/main/java/tachiyomi/core/preference/Preference.kt +++ b/core/src/main/java/tachiyomi/core/preference/Preference.kt @@ -23,7 +23,9 @@ interface Preference { fun stateIn(scope: CoroutineScope): StateFlow } -inline fun Preference.getAndSet(crossinline block: (T) -> R) = set(block(get())) +inline fun Preference.getAndSet(crossinline block: (T) -> R) = set( + block(get()), +) operator fun Preference>.plusAssign(item: T) { set(get() + item) diff --git a/core/src/main/java/tachiyomi/core/util/lang/CoroutinesExtensions.kt b/core/src/main/java/tachiyomi/core/util/lang/CoroutinesExtensions.kt index 4573b2d85..829207a9b 100644 --- a/core/src/main/java/tachiyomi/core/util/lang/CoroutinesExtensions.kt +++ b/core/src/main/java/tachiyomi/core/util/lang/CoroutinesExtensions.kt @@ -52,9 +52,15 @@ fun CoroutineScope.launchIO(block: suspend CoroutineScope.() -> Unit): Job = fun CoroutineScope.launchNonCancellable(block: suspend CoroutineScope.() -> Unit): Job = launchIO { withContext(NonCancellable, block) } -suspend fun withUIContext(block: suspend CoroutineScope.() -> T) = withContext(Dispatchers.Main, block) +suspend fun withUIContext(block: suspend CoroutineScope.() -> T) = withContext( + Dispatchers.Main, + block, +) -suspend fun withIOContext(block: suspend CoroutineScope.() -> T) = withContext(Dispatchers.IO, block) +suspend fun withIOContext(block: suspend CoroutineScope.() -> T) = withContext( + Dispatchers.IO, + block, +) suspend fun withNonCancellableContext(block: suspend CoroutineScope.() -> T) = withContext(NonCancellable, block) diff --git a/data/src/main/java/tachiyomi/data/DatabaseAdapter.kt b/data/src/main/java/tachiyomi/data/DatabaseAdapter.kt index 4a3475b4f..596a31286 100644 --- a/data/src/main/java/tachiyomi/data/DatabaseAdapter.kt +++ b/data/src/main/java/tachiyomi/data/DatabaseAdapter.kt @@ -11,13 +11,14 @@ object DateColumnAdapter : ColumnAdapter { private const val LIST_OF_STRINGS_SEPARATOR = ", " object StringListColumnAdapter : ColumnAdapter, String> { - override fun decode(databaseValue: String) = - if (databaseValue.isEmpty()) { - emptyList() - } else { - databaseValue.split(LIST_OF_STRINGS_SEPARATOR) - } - override fun encode(value: List) = value.joinToString(separator = LIST_OF_STRINGS_SEPARATOR) + override fun decode(databaseValue: String) = if (databaseValue.isEmpty()) { + emptyList() + } else { + databaseValue.split(LIST_OF_STRINGS_SEPARATOR) + } + override fun encode(value: List) = value.joinToString( + separator = LIST_OF_STRINGS_SEPARATOR, + ) } object UpdateStrategyColumnAdapter : ColumnAdapter { diff --git a/data/src/main/java/tachiyomi/data/chapter/ChapterMapper.kt b/data/src/main/java/tachiyomi/data/chapter/ChapterMapper.kt index 71ae1720e..c8243682f 100644 --- a/data/src/main/java/tachiyomi/data/chapter/ChapterMapper.kt +++ b/data/src/main/java/tachiyomi/data/chapter/ChapterMapper.kt @@ -2,7 +2,21 @@ package tachiyomi.data.chapter import tachiyomi.domain.chapter.model.Chapter -val chapterMapper: (Long, Long, String, String, String?, Boolean, Boolean, Long, Double, Long, Long, Long, Long) -> Chapter = +val chapterMapper: ( + Long, + Long, + String, + String, + String?, + Boolean, + Boolean, + Long, + Double, + Long, + Long, + Long, + Long, +) -> Chapter = { id, mangaId, url, name, scanlator, read, bookmark, lastPageRead, chapterNumber, sourceOrder, dateFetch, dateUpload, lastModifiedAt -> Chapter( id = id, diff --git a/data/src/main/java/tachiyomi/data/chapter/ChapterRepositoryImpl.kt b/data/src/main/java/tachiyomi/data/chapter/ChapterRepositoryImpl.kt index 45a61e363..594a592ac 100644 --- a/data/src/main/java/tachiyomi/data/chapter/ChapterRepositoryImpl.kt +++ b/data/src/main/java/tachiyomi/data/chapter/ChapterRepositoryImpl.kt @@ -81,7 +81,12 @@ class ChapterRepositoryImpl( } override suspend fun getBookmarkedChaptersByMangaId(mangaId: Long): List { - return handler.awaitList { chaptersQueries.getBookmarkedChaptersByMangaId(mangaId, chapterMapper) } + return handler.awaitList { + chaptersQueries.getBookmarkedChaptersByMangaId( + mangaId, + chapterMapper, + ) + } } override suspend fun getChapterById(id: Long): Chapter? { @@ -89,10 +94,21 @@ class ChapterRepositoryImpl( } override suspend fun getChapterByMangaIdAsFlow(mangaId: Long): Flow> { - return handler.subscribeToList { chaptersQueries.getChaptersByMangaId(mangaId, chapterMapper) } + return handler.subscribeToList { + chaptersQueries.getChaptersByMangaId( + mangaId, + chapterMapper, + ) + } } override suspend fun getChapterByUrlAndMangaId(url: String, mangaId: Long): Chapter? { - return handler.awaitOneOrNull { chaptersQueries.getChapterByUrlAndMangaId(url, mangaId, chapterMapper) } + return handler.awaitOneOrNull { + chaptersQueries.getChapterByUrlAndMangaId( + url, + mangaId, + chapterMapper, + ) + } } } diff --git a/data/src/main/java/tachiyomi/data/history/HistoryMapper.kt b/data/src/main/java/tachiyomi/data/history/HistoryMapper.kt index c2d110f74..134a1c91c 100644 --- a/data/src/main/java/tachiyomi/data/history/HistoryMapper.kt +++ b/data/src/main/java/tachiyomi/data/history/HistoryMapper.kt @@ -14,7 +14,19 @@ val historyMapper: (Long, Long, Date?, Long) -> History = { id, chapterId, readA ) } -val historyWithRelationsMapper: (Long, Long, Long, String, String?, Long, Boolean, Long, Double, Date?, Long) -> HistoryWithRelations = { +val historyWithRelationsMapper: ( + Long, + Long, + Long, + String, + String?, + Long, + Boolean, + Long, + Double, + Date?, + Long, +) -> HistoryWithRelations = { historyId, mangaId, chapterId, title, thumbnailUrl, sourceId, isFavorite, coverLastModified, chapterNumber, readAt, readDuration -> HistoryWithRelations( id = historyId, diff --git a/data/src/main/java/tachiyomi/data/manga/MangaMapper.kt b/data/src/main/java/tachiyomi/data/manga/MangaMapper.kt index 3cc46aa5c..43bb1ed0c 100644 --- a/data/src/main/java/tachiyomi/data/manga/MangaMapper.kt +++ b/data/src/main/java/tachiyomi/data/manga/MangaMapper.kt @@ -4,7 +4,30 @@ import eu.kanade.tachiyomi.source.model.UpdateStrategy import tachiyomi.domain.library.model.LibraryManga import tachiyomi.domain.manga.model.Manga -val mangaMapper: (Long, Long, String, String?, String?, String?, List?, String, Long, String?, Boolean, Long?, Long?, Boolean, Long, Long, Long, Long, UpdateStrategy, Long, Long, Long?) -> Manga = +val mangaMapper: ( + Long, + Long, + String, + String?, + String?, + String?, + List?, + String, + Long, + String?, + Boolean, + Long?, + Long?, + Boolean, + Long, + Long, + Long, + Long, + UpdateStrategy, + Long, + Long, + Long?, +) -> Manga = { id, source, url, artist, author, description, genre, title, status, thumbnailUrl, favorite, lastUpdate, nextUpdate, initialized, viewerFlags, chapterFlags, coverLastModified, dateAdded, updateStrategy, calculateInterval, lastModifiedAt, favoriteModifiedAt -> Manga( id = id, @@ -32,7 +55,37 @@ val mangaMapper: (Long, Long, String, String?, String?, String?, List?, ) } -val libraryManga: (Long, Long, String, String?, String?, String?, List?, String, Long, String?, Boolean, Long?, Long?, Boolean, Long, Long, Long, Long, UpdateStrategy, Long, Long, Long?, Long, Double, Long, Long, Long, Double, Long) -> LibraryManga = +val libraryManga: ( + Long, + Long, + String, + String?, + String?, + String?, + List?, + String, + Long, + String?, + Boolean, + Long?, + Long?, + Boolean, + Long, + Long, + Long, + Long, + UpdateStrategy, + Long, + Long, + Long?, + Long, + Double, + Long, + Long, + Long, + Double, + Long, +) -> LibraryManga = { id, source, url, artist, author, description, genre, title, status, thumbnailUrl, favorite, lastUpdate, nextUpdate, initialized, viewerFlags, chapterFlags, coverLastModified, dateAdded, updateStrategy, calculateInterval, lastModifiedAt, favoriteModifiedAt, totalCount, readCount, latestUpload, chapterFetchedAt, lastRead, bookmarkCount, category -> LibraryManga( manga = mangaMapper( diff --git a/data/src/main/java/tachiyomi/data/manga/MangaRepositoryImpl.kt b/data/src/main/java/tachiyomi/data/manga/MangaRepositoryImpl.kt index 49f3160a6..39bbcb99f 100644 --- a/data/src/main/java/tachiyomi/data/manga/MangaRepositoryImpl.kt +++ b/data/src/main/java/tachiyomi/data/manga/MangaRepositoryImpl.kt @@ -24,11 +24,23 @@ class MangaRepositoryImpl( } override suspend fun getMangaByUrlAndSourceId(url: String, sourceId: Long): Manga? { - return handler.awaitOneOrNull(inTransaction = true) { mangasQueries.getMangaByUrlAndSource(url, sourceId, mangaMapper) } + return handler.awaitOneOrNull(inTransaction = true) { + mangasQueries.getMangaByUrlAndSource( + url, + sourceId, + mangaMapper, + ) + } } override fun getMangaByUrlAndSourceIdAsFlow(url: String, sourceId: Long): Flow { - return handler.subscribeToOneOrNull { mangasQueries.getMangaByUrlAndSource(url, sourceId, mangaMapper) } + return handler.subscribeToOneOrNull { + mangasQueries.getMangaByUrlAndSource( + url, + sourceId, + mangaMapper, + ) + } } override suspend fun getFavorites(): List { diff --git a/data/src/main/java/tachiyomi/data/release/GithubRelease.kt b/data/src/main/java/tachiyomi/data/release/GithubRelease.kt index 94394cef0..f7fa16923 100644 --- a/data/src/main/java/tachiyomi/data/release/GithubRelease.kt +++ b/data/src/main/java/tachiyomi/data/release/GithubRelease.kt @@ -32,7 +32,9 @@ data class GitHubAssets(@SerialName("browser_download_url") val downloadLink: St * Reference: https://stackoverflow.com/a/30281147 */ val gitHubUsernameMentionRegex = - """\B@([a-z0-9](?:-(?=[a-z0-9])|[a-z0-9]){0,38}(?<=[a-z0-9]))""".toRegex(RegexOption.IGNORE_CASE) + """\B@([a-z0-9](?:-(?=[a-z0-9])|[a-z0-9]){0,38}(?<=[a-z0-9]))""".toRegex( + RegexOption.IGNORE_CASE, + ) val releaseMapper: (GithubRelease) -> Release = { Release( diff --git a/data/src/main/java/tachiyomi/data/source/SourcePagingSource.kt b/data/src/main/java/tachiyomi/data/source/SourcePagingSource.kt index 032ae0ab5..c87ec5cff 100644 --- a/data/src/main/java/tachiyomi/data/source/SourcePagingSource.kt +++ b/data/src/main/java/tachiyomi/data/source/SourcePagingSource.kt @@ -5,25 +5,26 @@ import eu.kanade.tachiyomi.source.CatalogueSource import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.MangasPage import eu.kanade.tachiyomi.source.model.SManga -import tachiyomi.core.util.lang.awaitSingle import tachiyomi.core.util.lang.withIOContext import tachiyomi.domain.source.repository.SourcePagingSourceType -class SourceSearchPagingSource(source: CatalogueSource, val query: String, val filters: FilterList) : SourcePagingSource(source) { +class SourceSearchPagingSource(source: CatalogueSource, val query: String, val filters: FilterList) : SourcePagingSource( + source, +) { override suspend fun requestNextPage(currentPage: Int): MangasPage { - return source.fetchSearchManga(currentPage, query, filters).awaitSingle() + return source.getSearchManga(currentPage, query, filters) } } class SourcePopularPagingSource(source: CatalogueSource) : SourcePagingSource(source) { override suspend fun requestNextPage(currentPage: Int): MangasPage { - return source.fetchPopularManga(currentPage).awaitSingle() + return source.getPopularManga(currentPage) } } class SourceLatestPagingSource(source: CatalogueSource) : SourcePagingSource(source) { override suspend fun requestNextPage(currentPage: Int): MangasPage { - return source.fetchLatestUpdates(currentPage).awaitSingle() + return source.getLatestUpdates(currentPage) } } diff --git a/data/src/main/java/tachiyomi/data/track/TrackMapper.kt b/data/src/main/java/tachiyomi/data/track/TrackMapper.kt index e8978e25b..a4a9714f6 100644 --- a/data/src/main/java/tachiyomi/data/track/TrackMapper.kt +++ b/data/src/main/java/tachiyomi/data/track/TrackMapper.kt @@ -2,7 +2,21 @@ package tachiyomi.data.track import tachiyomi.domain.track.model.Track -val trackMapper: (Long, Long, Long, Long, Long?, String, Double, Long, Long, Double, String, Long, Long) -> Track = +val trackMapper: ( + Long, + Long, + Long, + Long, + Long?, + String, + Double, + Long, + Long, + Double, + String, + Long, + Long, +) -> Track = { id, mangaId, syncId, remoteId, libraryId, title, lastChapterRead, totalChapters, status, score, remoteUrl, startDate, finishDate -> Track( id = id, diff --git a/data/src/main/java/tachiyomi/data/updates/UpdatesMapper.kt b/data/src/main/java/tachiyomi/data/updates/UpdatesMapper.kt index efbc55410..56e9743a9 100644 --- a/data/src/main/java/tachiyomi/data/updates/UpdatesMapper.kt +++ b/data/src/main/java/tachiyomi/data/updates/UpdatesMapper.kt @@ -3,7 +3,22 @@ package tachiyomi.data.updates import tachiyomi.domain.manga.model.MangaCover import tachiyomi.domain.updates.model.UpdatesWithRelations -val updateWithRelationMapper: (Long, String, Long, String, String?, Boolean, Boolean, Long, Long, Boolean, String?, Long, Long, Long) -> UpdatesWithRelations = { +val updateWithRelationMapper: ( + Long, + String, + Long, + String, + String?, + Boolean, + Boolean, + Long, + Long, + Boolean, + String?, + Long, + Long, + Long, +) -> UpdatesWithRelations = { mangaId, mangaTitle, chapterId, chapterName, scanlator, read, bookmark, lastPageRead, sourceId, favorite, thumbnailUrl, coverLastModified, _, dateFetch -> UpdatesWithRelations( mangaId = mangaId, diff --git a/data/src/main/java/tachiyomi/data/updates/UpdatesRepositoryImpl.kt b/data/src/main/java/tachiyomi/data/updates/UpdatesRepositoryImpl.kt index 99ec74415..b50aee4be 100644 --- a/data/src/main/java/tachiyomi/data/updates/UpdatesRepositoryImpl.kt +++ b/data/src/main/java/tachiyomi/data/updates/UpdatesRepositoryImpl.kt @@ -9,7 +9,11 @@ class UpdatesRepositoryImpl( private val databaseHandler: DatabaseHandler, ) : UpdatesRepository { - override suspend fun awaitWithRead(read: Boolean, after: Long, limit: Long): List { + override suspend fun awaitWithRead( + read: Boolean, + after: Long, + limit: Long, + ): List { return databaseHandler.awaitList { updatesViewQueries.getUpdatesByReadStatus( read = read, @@ -26,7 +30,11 @@ class UpdatesRepositoryImpl( } } - override fun subscribeWithRead(read: Boolean, after: Long, limit: Long): Flow> { + override fun subscribeWithRead( + read: Boolean, + after: Long, + limit: Long, + ): Flow> { return databaseHandler.subscribeToList { updatesViewQueries.getUpdatesByReadStatus( read = read, diff --git a/domain/src/main/java/tachiyomi/domain/category/interactor/ReorderCategory.kt b/domain/src/main/java/tachiyomi/domain/category/interactor/ReorderCategory.kt index af61400ab..b29cfd093 100644 --- a/domain/src/main/java/tachiyomi/domain/category/interactor/ReorderCategory.kt +++ b/domain/src/main/java/tachiyomi/domain/category/interactor/ReorderCategory.kt @@ -16,11 +16,9 @@ class ReorderCategory( private val mutex = Mutex() - suspend fun moveUp(category: Category): Result = - await(category, MoveTo.UP) + suspend fun moveUp(category: Category): Result = await(category, MoveTo.UP) - suspend fun moveDown(category: Category): Result = - await(category, MoveTo.DOWN) + suspend fun moveDown(category: Category): Result = await(category, MoveTo.DOWN) private suspend fun await(category: Category, moveTo: MoveTo) = withNonCancellableContext { mutex.withLock { diff --git a/domain/src/main/java/tachiyomi/domain/category/interactor/SetSortModeForCategory.kt b/domain/src/main/java/tachiyomi/domain/category/interactor/SetSortModeForCategory.kt index 28c999e9f..e514e0898 100644 --- a/domain/src/main/java/tachiyomi/domain/category/interactor/SetSortModeForCategory.kt +++ b/domain/src/main/java/tachiyomi/domain/category/interactor/SetSortModeForCategory.kt @@ -28,7 +28,11 @@ class SetSortModeForCategory( } } - suspend fun await(category: Category?, type: LibrarySort.Type, direction: LibrarySort.Direction) { + suspend fun await( + category: Category?, + type: LibrarySort.Type, + direction: LibrarySort.Direction, + ) { await(category?.id, type, direction) } } diff --git a/domain/src/main/java/tachiyomi/domain/chapter/interactor/SetDefaultChapterSettings.kt b/domain/src/main/java/tachiyomi/domain/chapter/interactor/SetMangaDefaultChapterFlags.kt similarity index 100% rename from domain/src/main/java/tachiyomi/domain/chapter/interactor/SetDefaultChapterSettings.kt rename to domain/src/main/java/tachiyomi/domain/chapter/interactor/SetMangaDefaultChapterFlags.kt diff --git a/domain/src/main/java/tachiyomi/domain/chapter/service/ChapterRecognition.kt b/domain/src/main/java/tachiyomi/domain/chapter/service/ChapterRecognition.kt index d41eb1484..b2c3f6b44 100644 --- a/domain/src/main/java/tachiyomi/domain/chapter/service/ChapterRecognition.kt +++ b/domain/src/main/java/tachiyomi/domain/chapter/service/ChapterRecognition.kt @@ -30,7 +30,11 @@ object ChapterRecognition { */ private val unwantedWhiteSpace = Regex("""\s(?=extra|special|omake)""") - fun parseChapterNumber(mangaTitle: String, chapterName: String, chapterNumber: Double? = null): Double { + fun parseChapterNumber( + mangaTitle: String, + chapterName: String, + chapterNumber: Double? = null, + ): Double { // If chapter number is known return. if (chapterNumber != null && (chapterNumber == -2.0 || chapterNumber > -1.0)) { return chapterNumber diff --git a/domain/src/main/java/tachiyomi/domain/chapter/service/ChapterSort.kt b/domain/src/main/java/tachiyomi/domain/chapter/service/ChapterSort.kt index e7f5648cb..45f302455 100644 --- a/domain/src/main/java/tachiyomi/domain/chapter/service/ChapterSort.kt +++ b/domain/src/main/java/tachiyomi/domain/chapter/service/ChapterSort.kt @@ -3,7 +3,13 @@ package tachiyomi.domain.chapter.service import tachiyomi.domain.chapter.model.Chapter import tachiyomi.domain.manga.model.Manga -fun getChapterSort(manga: Manga, sortDescending: Boolean = manga.sortDescending()): (Chapter, Chapter) -> Int { +fun getChapterSort( + manga: Manga, + sortDescending: Boolean = manga.sortDescending(), +): ( + Chapter, + Chapter, +) -> Int { return when (manga.sorting) { Manga.CHAPTER_SORTING_SOURCE -> when (sortDescending) { true -> { c1, c2 -> c1.sourceOrder.compareTo(c2.sourceOrder) } diff --git a/domain/src/main/java/tachiyomi/domain/download/service/DownloadPreferences.kt b/domain/src/main/java/tachiyomi/domain/download/service/DownloadPreferences.kt index cc930cf51..51a07dc8e 100644 --- a/domain/src/main/java/tachiyomi/domain/download/service/DownloadPreferences.kt +++ b/domain/src/main/java/tachiyomi/domain/download/service/DownloadPreferences.kt @@ -8,9 +8,15 @@ class DownloadPreferences( private val preferenceStore: PreferenceStore, ) { - fun downloadsDirectory() = preferenceStore.getString("download_directory", folderProvider.path()) + fun downloadsDirectory() = preferenceStore.getString( + "download_directory", + folderProvider.path(), + ) - fun downloadOnlyOverWifi() = preferenceStore.getBoolean("pref_download_only_over_wifi_key", true) + fun downloadOnlyOverWifi() = preferenceStore.getBoolean( + "pref_download_only_over_wifi_key", + true, + ) fun saveChaptersAsCBZ() = preferenceStore.getBoolean("save_chapter_as_cbz", true) @@ -20,15 +26,27 @@ class DownloadPreferences( fun removeAfterReadSlots() = preferenceStore.getInt("remove_after_read_slots", -1) - fun removeAfterMarkedAsRead() = preferenceStore.getBoolean("pref_remove_after_marked_as_read_key", false) + fun removeAfterMarkedAsRead() = preferenceStore.getBoolean( + "pref_remove_after_marked_as_read_key", + false, + ) fun removeBookmarkedChapters() = preferenceStore.getBoolean("pref_remove_bookmarked", false) - fun removeExcludeCategories() = preferenceStore.getStringSet("remove_exclude_categories", emptySet()) + fun removeExcludeCategories() = preferenceStore.getStringSet( + "remove_exclude_categories", + emptySet(), + ) fun downloadNewChapters() = preferenceStore.getBoolean("download_new", false) - fun downloadNewChapterCategories() = preferenceStore.getStringSet("download_new_categories", emptySet()) + fun downloadNewChapterCategories() = preferenceStore.getStringSet( + "download_new_categories", + emptySet(), + ) - fun downloadNewChapterCategoriesExclude() = preferenceStore.getStringSet("download_new_categories_exclude", emptySet()) + fun downloadNewChapterCategoriesExclude() = preferenceStore.getStringSet( + "download_new_categories_exclude", + emptySet(), + ) } diff --git a/domain/src/main/java/tachiyomi/domain/history/interactor/GetNextChapters.kt b/domain/src/main/java/tachiyomi/domain/history/interactor/GetNextChapters.kt index ebe6fa83e..6e9526158 100644 --- a/domain/src/main/java/tachiyomi/domain/history/interactor/GetNextChapters.kt +++ b/domain/src/main/java/tachiyomi/domain/history/interactor/GetNextChapters.kt @@ -30,7 +30,11 @@ class GetNextChapters( } } - suspend fun await(mangaId: Long, fromChapterId: Long, onlyUnread: Boolean = true): List { + suspend fun await( + mangaId: Long, + fromChapterId: Long, + onlyUnread: Boolean = true, + ): List { val chapters = await(mangaId, onlyUnread) val currChapterIndex = chapters.indexOfFirst { it.id == fromChapterId } val nextChapters = chapters.subList(max(0, currChapterIndex), chapters.size) diff --git a/domain/src/main/java/tachiyomi/domain/library/model/LibrarySortMode.kt b/domain/src/main/java/tachiyomi/domain/library/model/LibrarySortMode.kt index 40acc5b5a..7f525eb57 100644 --- a/domain/src/main/java/tachiyomi/domain/library/model/LibrarySortMode.kt +++ b/domain/src/main/java/tachiyomi/domain/library/model/LibrarySortMode.kt @@ -65,7 +65,18 @@ data class LibrarySort( } companion object { - val types by lazy { setOf(Type.Alphabetical, Type.LastRead, Type.LastUpdate, Type.UnreadCount, Type.TotalChapters, Type.LatestChapter, Type.ChapterFetchDate, Type.DateAdded) } + val types by lazy { + setOf( + Type.Alphabetical, + Type.LastRead, + Type.LastUpdate, + Type.UnreadCount, + Type.TotalChapters, + Type.LatestChapter, + Type.ChapterFetchDate, + Type.DateAdded, + ) + } val directions by lazy { setOf(Direction.Ascending, Direction.Descending) } val default = LibrarySort(Type.Alphabetical, Direction.Ascending) diff --git a/domain/src/main/java/tachiyomi/domain/library/service/LibraryPreferences.kt b/domain/src/main/java/tachiyomi/domain/library/service/LibraryPreferences.kt index e66c705d9..8c853c759 100644 --- a/domain/src/main/java/tachiyomi/domain/library/service/LibraryPreferences.kt +++ b/domain/src/main/java/tachiyomi/domain/library/service/LibraryPreferences.kt @@ -11,9 +11,19 @@ class LibraryPreferences( private val preferenceStore: PreferenceStore, ) { - fun displayMode() = preferenceStore.getObject("pref_display_mode_library", LibraryDisplayMode.default, LibraryDisplayMode.Serializer::serialize, LibraryDisplayMode.Serializer::deserialize) + fun displayMode() = preferenceStore.getObject( + "pref_display_mode_library", + LibraryDisplayMode.default, + LibraryDisplayMode.Serializer::serialize, + LibraryDisplayMode.Serializer::deserialize, + ) - fun sortingMode() = preferenceStore.getObject("library_sorting_mode", LibrarySort.default, LibrarySort.Serializer::serialize, LibrarySort.Serializer::deserialize) + fun sortingMode() = preferenceStore.getObject( + "library_sorting_mode", + LibrarySort.default, + LibrarySort.Serializer::serialize, + LibrarySort.Serializer::deserialize, + ) fun portraitColumns() = preferenceStore.getInt("pref_library_columns_portrait_key", 0) @@ -42,31 +52,64 @@ class LibraryPreferences( fun autoUpdateTrackers() = preferenceStore.getBoolean("auto_update_trackers", false) - fun showContinueReadingButton() = preferenceStore.getBoolean("display_continue_reading_button", false) + fun showContinueReadingButton() = preferenceStore.getBoolean( + "display_continue_reading_button", + false, + ) // region Filter - fun filterDownloaded() = preferenceStore.getEnum("pref_filter_library_downloaded_v2", TriState.DISABLED) + fun filterDownloaded() = preferenceStore.getEnum( + "pref_filter_library_downloaded_v2", + TriState.DISABLED, + ) fun filterUnread() = preferenceStore.getEnum("pref_filter_library_unread_v2", TriState.DISABLED) - fun filterStarted() = preferenceStore.getEnum("pref_filter_library_started_v2", TriState.DISABLED) + fun filterStarted() = preferenceStore.getEnum( + "pref_filter_library_started_v2", + TriState.DISABLED, + ) - fun filterBookmarked() = preferenceStore.getEnum("pref_filter_library_bookmarked_v2", TriState.DISABLED) + fun filterBookmarked() = preferenceStore.getEnum( + "pref_filter_library_bookmarked_v2", + TriState.DISABLED, + ) - fun filterCompleted() = preferenceStore.getEnum("pref_filter_library_completed_v2", TriState.DISABLED) + fun filterCompleted() = preferenceStore.getEnum( + "pref_filter_library_completed_v2", + TriState.DISABLED, + ) - fun filterIntervalCustom() = preferenceStore.getEnum("pref_filter_library_interval_custom", TriState.DISABLED) + fun filterIntervalCustom() = preferenceStore.getEnum( + "pref_filter_library_interval_custom", + TriState.DISABLED, + ) - fun filterIntervalLong() = preferenceStore.getEnum("pref_filter_library_interval_long", TriState.DISABLED) + fun filterIntervalLong() = preferenceStore.getEnum( + "pref_filter_library_interval_long", + TriState.DISABLED, + ) - fun filterIntervalLate() = preferenceStore.getEnum("pref_filter_library_interval_late", TriState.DISABLED) + fun filterIntervalLate() = preferenceStore.getEnum( + "pref_filter_library_interval_late", + TriState.DISABLED, + ) - fun filterIntervalDropped() = preferenceStore.getEnum("pref_filter_library_interval_dropped", TriState.DISABLED) + fun filterIntervalDropped() = preferenceStore.getEnum( + "pref_filter_library_interval_dropped", + TriState.DISABLED, + ) - fun filterIntervalPassed() = preferenceStore.getEnum("pref_filter_library_interval_passed", TriState.DISABLED) + fun filterIntervalPassed() = preferenceStore.getEnum( + "pref_filter_library_interval_passed", + TriState.DISABLED, + ) - fun filterTracking(id: Int) = preferenceStore.getEnum("pref_filter_library_tracked_${id}_v2", TriState.DISABLED) + fun filterTracking(id: Int) = preferenceStore.getEnum( + "pref_filter_library_tracked_${id}_v2", + TriState.DISABLED, + ) // endregion @@ -97,24 +140,45 @@ class LibraryPreferences( fun updateCategories() = preferenceStore.getStringSet("library_update_categories", emptySet()) - fun updateCategoriesExclude() = preferenceStore.getStringSet("library_update_categories_exclude", emptySet()) + fun updateCategoriesExclude() = preferenceStore.getStringSet( + "library_update_categories_exclude", + emptySet(), + ) // endregion // region Chapter - fun filterChapterByRead() = preferenceStore.getLong("default_chapter_filter_by_read", Manga.SHOW_ALL) + fun filterChapterByRead() = preferenceStore.getLong( + "default_chapter_filter_by_read", + Manga.SHOW_ALL, + ) - fun filterChapterByDownloaded() = preferenceStore.getLong("default_chapter_filter_by_downloaded", Manga.SHOW_ALL) + fun filterChapterByDownloaded() = preferenceStore.getLong( + "default_chapter_filter_by_downloaded", + Manga.SHOW_ALL, + ) - fun filterChapterByBookmarked() = preferenceStore.getLong("default_chapter_filter_by_bookmarked", Manga.SHOW_ALL) + fun filterChapterByBookmarked() = preferenceStore.getLong( + "default_chapter_filter_by_bookmarked", + Manga.SHOW_ALL, + ) // and upload date - fun sortChapterBySourceOrNumber() = preferenceStore.getLong("default_chapter_sort_by_source_or_number", Manga.CHAPTER_SORTING_SOURCE) + fun sortChapterBySourceOrNumber() = preferenceStore.getLong( + "default_chapter_sort_by_source_or_number", + Manga.CHAPTER_SORTING_SOURCE, + ) - fun displayChapterByNameOrNumber() = preferenceStore.getLong("default_chapter_display_by_name_or_number", Manga.CHAPTER_DISPLAY_NAME) + fun displayChapterByNameOrNumber() = preferenceStore.getLong( + "default_chapter_display_by_name_or_number", + Manga.CHAPTER_DISPLAY_NAME, + ) - fun sortChapterByAscendingOrDescending() = preferenceStore.getLong("default_chapter_sort_by_ascending_or_descending", Manga.CHAPTER_SORT_DESC) + fun sortChapterByAscendingOrDescending() = preferenceStore.getLong( + "default_chapter_sort_by_ascending_or_descending", + Manga.CHAPTER_SORT_DESC, + ) fun setChapterSettingsDefault(manga: Manga) { filterChapterByRead().set(manga.unreadFilterRaw) @@ -122,7 +186,9 @@ class LibraryPreferences( filterChapterByBookmarked().set(manga.bookmarkedFilterRaw) sortChapterBySourceOrNumber().set(manga.sorting) displayChapterByNameOrNumber().set(manga.displayMode) - sortChapterByAscendingOrDescending().set(if (manga.sortDescending()) Manga.CHAPTER_SORT_DESC else Manga.CHAPTER_SORT_ASC) + sortChapterByAscendingOrDescending().set( + if (manga.sortDescending()) Manga.CHAPTER_SORT_DESC else Manga.CHAPTER_SORT_ASC, + ) } fun autoClearChapterCache() = preferenceStore.getBoolean("auto_clear_chapter_cache", false) @@ -131,9 +197,15 @@ class LibraryPreferences( // region Swipe Actions - fun swipeToStartAction() = preferenceStore.getEnum("pref_chapter_swipe_end_action", ChapterSwipeAction.ToggleBookmark) + fun swipeToStartAction() = preferenceStore.getEnum( + "pref_chapter_swipe_end_action", + ChapterSwipeAction.ToggleBookmark, + ) - fun swipeToEndAction() = preferenceStore.getEnum("pref_chapter_swipe_start_action", ChapterSwipeAction.ToggleRead) + fun swipeToEndAction() = preferenceStore.getEnum( + "pref_chapter_swipe_start_action", + ChapterSwipeAction.ToggleRead, + ) // endregion diff --git a/domain/src/main/java/tachiyomi/domain/manga/interactor/SetFetchInterval.kt b/domain/src/main/java/tachiyomi/domain/manga/interactor/FetchInterval.kt similarity index 80% rename from domain/src/main/java/tachiyomi/domain/manga/interactor/SetFetchInterval.kt rename to domain/src/main/java/tachiyomi/domain/manga/interactor/FetchInterval.kt index 6dc77819e..740c0a150 100644 --- a/domain/src/main/java/tachiyomi/domain/manga/interactor/SetFetchInterval.kt +++ b/domain/src/main/java/tachiyomi/domain/manga/interactor/FetchInterval.kt @@ -5,14 +5,12 @@ import tachiyomi.domain.chapter.model.Chapter import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.manga.model.MangaUpdate import java.time.Instant +import java.time.ZoneId import java.time.ZonedDateTime import java.time.temporal.ChronoUnit import kotlin.math.absoluteValue -const val MAX_FETCH_INTERVAL = 28 -private const val FETCH_INTERVAL_GRACE_PERIOD = 1 - -class SetFetchInterval( +class FetchInterval( private val getChapterByMangaId: GetChapterByMangaId, ) { @@ -27,7 +25,10 @@ class SetFetchInterval( window } val chapters = getChapterByMangaId.await(manga.id) - val interval = manga.fetchInterval.takeIf { it < 0 } ?: calculateInterval(chapters, dateTime) + val interval = manga.fetchInterval.takeIf { it < 0 } ?: calculateInterval( + chapters, + dateTime.zone, + ) val nextUpdate = calculateNextUpdate(manga, interval, dateTime, currentWindow) return if (manga.nextUpdate == nextUpdate && manga.fetchInterval == interval) { @@ -39,31 +40,34 @@ class SetFetchInterval( fun getWindow(dateTime: ZonedDateTime): Pair { val today = dateTime.toLocalDate().atStartOfDay(dateTime.zone) - val lowerBound = today.minusDays(FETCH_INTERVAL_GRACE_PERIOD.toLong()) - val upperBound = today.plusDays(FETCH_INTERVAL_GRACE_PERIOD.toLong()) + val lowerBound = today.minusDays(GRACE_PERIOD) + val upperBound = today.plusDays(GRACE_PERIOD) return Pair(lowerBound.toEpochSecond() * 1000, upperBound.toEpochSecond() * 1000 - 1) } - internal fun calculateInterval(chapters: List, zonedDateTime: ZonedDateTime): Int { - val sortedChapters = chapters - .sortedWith(compareByDescending { it.dateUpload }.thenByDescending { it.dateFetch }) - .take(50) - - val uploadDates = sortedChapters + internal fun calculateInterval(chapters: List, zone: ZoneId): Int { + val uploadDates = chapters.asSequence() .filter { it.dateUpload > 0L } + .sortedByDescending { it.dateUpload } .map { - ZonedDateTime.ofInstant(Instant.ofEpochMilli(it.dateUpload), zonedDateTime.zone) + ZonedDateTime.ofInstant(Instant.ofEpochMilli(it.dateUpload), zone) .toLocalDate() .atStartOfDay() } .distinct() - val fetchDates = sortedChapters + .take(10) + .toList() + + val fetchDates = chapters.asSequence() + .sortedByDescending { it.dateFetch } .map { - ZonedDateTime.ofInstant(Instant.ofEpochMilli(it.dateFetch), zonedDateTime.zone) + ZonedDateTime.ofInstant(Instant.ofEpochMilli(it.dateFetch), zone) .toLocalDate() .atStartOfDay() } .distinct() + .take(10) + .toList() val interval = when { // Enough upload date from source @@ -82,7 +86,7 @@ class SetFetchInterval( else -> 7 } - return interval.coerceIn(1, MAX_FETCH_INTERVAL) + return interval.coerceIn(1, MAX_INTERVAL) } private fun calculateNextUpdate( @@ -95,7 +99,10 @@ class SetFetchInterval( manga.nextUpdate !in window.first.rangeTo(window.second + 1) || manga.fetchInterval == 0 ) { - val latestDate = ZonedDateTime.ofInstant(Instant.ofEpochMilli(manga.lastUpdate), dateTime.zone) + val latestDate = ZonedDateTime.ofInstant( + Instant.ofEpochMilli(manga.lastUpdate), + dateTime.zone, + ) .toLocalDate() .atStartOfDay() val timeSinceLatest = ChronoUnit.DAYS.between(latestDate, dateTime).toInt() @@ -110,7 +117,7 @@ class SetFetchInterval( } private fun doubleInterval(delta: Int, timeSinceLatest: Int, doubleWhenOver: Int): Int { - if (delta >= MAX_FETCH_INTERVAL) return MAX_FETCH_INTERVAL + if (delta >= MAX_INTERVAL) return MAX_INTERVAL // double delta again if missed more than 9 check in new delta val cycle = timeSinceLatest.floorDiv(delta) + 1 @@ -120,4 +127,10 @@ class SetFetchInterval( delta } } + + companion object { + const val MAX_INTERVAL = 28 + + private const val GRACE_PERIOD = 1L + } } diff --git a/domain/src/main/java/tachiyomi/domain/release/interactor/GetApplicationRelease.kt b/domain/src/main/java/tachiyomi/domain/release/interactor/GetApplicationRelease.kt index 735782fd2..1a0ff4e4b 100644 --- a/domain/src/main/java/tachiyomi/domain/release/interactor/GetApplicationRelease.kt +++ b/domain/src/main/java/tachiyomi/domain/release/interactor/GetApplicationRelease.kt @@ -20,7 +20,10 @@ class GetApplicationRelease( val now = Instant.now() // Limit checks to once every 3 days at most - if (arguments.forceCheck.not() && now.isBefore(Instant.ofEpochMilli(lastChecked.get()).plus(3, ChronoUnit.DAYS))) { + if (arguments.forceCheck.not() && now.isBefore( + Instant.ofEpochMilli(lastChecked.get()).plus(3, ChronoUnit.DAYS), + ) + ) { return Result.NoNewUpdate } @@ -29,7 +32,12 @@ class GetApplicationRelease( lastChecked.set(now.toEpochMilli()) // Check if latest version is different from current version - val isNewVersion = isNewVersion(arguments.isPreview, arguments.commitCount, arguments.versionName, release.version) + val isNewVersion = isNewVersion( + arguments.isPreview, + arguments.commitCount, + arguments.versionName, + release.version, + ) return when { isNewVersion && arguments.isThirdParty -> Result.ThirdPartyInstallation isNewVersion -> Result.NewUpdate(release) @@ -37,7 +45,12 @@ class GetApplicationRelease( } } - private fun isNewVersion(isPreview: Boolean, commitCount: Int, versionName: String, versionTag: String): Boolean { + private fun isNewVersion( + isPreview: Boolean, + commitCount: Int, + versionName: String, + versionTag: String, + ): Boolean { // Removes prefixes like "r" or "v" val newVersion = versionTag.replace("[^\\d.]".toRegex(), "") return if (isPreview) { diff --git a/domain/src/main/java/tachiyomi/domain/source/model/StubSource.kt b/domain/src/main/java/tachiyomi/domain/source/model/StubSource.kt index 38d38ef57..8b5f67ef5 100644 --- a/domain/src/main/java/tachiyomi/domain/source/model/StubSource.kt +++ b/domain/src/main/java/tachiyomi/domain/source/model/StubSource.kt @@ -4,7 +4,6 @@ import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.model.Page import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SManga -import rx.Observable class StubSource( override val id: Long, @@ -14,36 +13,16 @@ class StubSource( private val isInvalid: Boolean = name.isBlank() || lang.isBlank() - override suspend fun getMangaDetails(manga: SManga): SManga { + override suspend fun getMangaDetails(manga: SManga): SManga = throw SourceNotInstalledException() - } - @Deprecated("Use the non-RxJava API instead", replaceWith = ReplaceWith("getMangaDetails")) - override fun fetchMangaDetails(manga: SManga): Observable { - return Observable.error(SourceNotInstalledException()) - } - - override suspend fun getChapterList(manga: SManga): List { + override suspend fun getChapterList(manga: SManga): List = throw SourceNotInstalledException() - } - - @Deprecated("Use the non-RxJava API instead", replaceWith = ReplaceWith("getChapterList")) - override fun fetchChapterList(manga: SManga): Observable> { - return Observable.error(SourceNotInstalledException()) - } - - override suspend fun getPageList(chapter: SChapter): List { + override suspend fun getPageList(chapter: SChapter): List = throw SourceNotInstalledException() - } - @Deprecated("Use the non-RxJava API instead", replaceWith = ReplaceWith("getPageList")) - override fun fetchPageList(chapter: SChapter): Observable> { - return Observable.error(SourceNotInstalledException()) - } - - override fun toString(): String { - return if (isInvalid.not()) "$name (${lang.uppercase()})" else id.toString() - } + override fun toString(): String = + if (isInvalid.not()) "$name (${lang.uppercase()})" else id.toString() } class SourceNotInstalledException : Exception() diff --git a/domain/src/test/java/tachiyomi/domain/library/model/LibraryFlagsTest.kt b/domain/src/test/java/tachiyomi/domain/library/model/LibraryFlagsTest.kt index 633ba250e..408dee18a 100644 --- a/domain/src/test/java/tachiyomi/domain/library/model/LibraryFlagsTest.kt +++ b/domain/src/test/java/tachiyomi/domain/library/model/LibraryFlagsTest.kt @@ -34,7 +34,10 @@ class LibraryFlagsTest { @Test fun `Test Flag plus operator with old flag as base`() { - val currentSort = LibrarySort(LibrarySort.Type.UnreadCount, LibrarySort.Direction.Descending) + val currentSort = LibrarySort( + LibrarySort.Type.UnreadCount, + LibrarySort.Direction.Descending, + ) currentSort.flag shouldBe 0b00001100 val sort = LibrarySort(LibrarySort.Type.DateAdded, LibrarySort.Direction.Ascending) diff --git a/domain/src/test/java/tachiyomi/domain/manga/interactor/FetchIntervalTest.kt b/domain/src/test/java/tachiyomi/domain/manga/interactor/FetchIntervalTest.kt new file mode 100644 index 000000000..468d7eb2d --- /dev/null +++ b/domain/src/test/java/tachiyomi/domain/manga/interactor/FetchIntervalTest.kt @@ -0,0 +1,127 @@ +package tachiyomi.domain.manga.interactor + +import io.kotest.matchers.shouldBe +import io.mockk.mockk +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.parallel.Execution +import org.junit.jupiter.api.parallel.ExecutionMode +import tachiyomi.domain.chapter.model.Chapter +import java.time.ZoneOffset +import java.time.ZonedDateTime +import kotlin.time.Duration +import kotlin.time.Duration.Companion.days +import kotlin.time.Duration.Companion.hours +import kotlin.time.DurationUnit +import kotlin.time.toDuration +import kotlin.time.toJavaDuration + +@Execution(ExecutionMode.CONCURRENT) +class FetchIntervalTest { + + private val testTime = ZonedDateTime.parse("2020-01-01T00:00:00Z") + private val testZoneId = ZoneOffset.UTC + private var chapter = Chapter.create().copy( + dateFetch = testTime.toEpochSecond() * 1000, + dateUpload = testTime.toEpochSecond() * 1000, + ) + + private val fetchInterval = FetchInterval(mockk()) + + @Test + fun `returns default interval of 7 days when not enough distinct days`() { + val chaptersWithUploadDate = (1..50).map { + chapterWithTime(chapter, 1.days) + } + fetchInterval.calculateInterval(chaptersWithUploadDate, testZoneId) shouldBe 7 + + val chaptersWithoutUploadDate = chaptersWithUploadDate.map { + it.copy(dateUpload = 0L) + } + fetchInterval.calculateInterval(chaptersWithoutUploadDate, testZoneId) shouldBe 7 + } + + @Test + fun `returns interval based on more recent chapters`() { + val oldChapters = (1..5).map { + chapterWithTime(chapter, (it * 7).days) // Would have interval of 7 days + } + val newChapters = (1..10).map { + chapterWithTime(chapter, oldChapters.lastUploadDate() + it.days) + } + + val chapters = oldChapters + newChapters + + fetchInterval.calculateInterval(chapters, testZoneId) shouldBe 1 + } + + @Test + fun `returns interval of 7 days when multiple chapters in 1 day`() { + val chapters = (1..10).map { + chapterWithTime(chapter, 10.hours) + } + fetchInterval.calculateInterval(chapters, testZoneId) shouldBe 7 + } + + @Test + fun `returns interval of 7 days when multiple chapters in 2 days`() { + val chapters = (1..2).map { + chapterWithTime(chapter, 1.days) + } + (1..5).map { + chapterWithTime(chapter, 2.days) + } + fetchInterval.calculateInterval(chapters, testZoneId) shouldBe 7 + } + + @Test + fun `returns interval of 1 day when chapters are released every 1 day`() { + val chapters = (1..20).map { + chapterWithTime(chapter, it.days) + } + fetchInterval.calculateInterval(chapters, testZoneId) shouldBe 1 + } + + @Test + fun `returns interval of 1 day when delta is less than 1 day`() { + val chapters = (1..20).map { + chapterWithTime(chapter, (15 * it).hours) + } + fetchInterval.calculateInterval(chapters, testZoneId) shouldBe 1 + } + + @Test + fun `returns interval of 2 days when chapters are released every 2 days`() { + val chapters = (1..20).map { + chapterWithTime(chapter, (2 * it).days) + } + fetchInterval.calculateInterval(chapters, testZoneId) shouldBe 2 + } + + @Test + fun `returns interval with floored value when interval is decimal`() { + val chaptersWithUploadDate = (1..5).map { + chapterWithTime(chapter, (25 * it).hours) + } + fetchInterval.calculateInterval(chaptersWithUploadDate, testZoneId) shouldBe 1 + + val chaptersWithoutUploadDate = chaptersWithUploadDate.map { + it.copy(dateUpload = 0L) + } + fetchInterval.calculateInterval(chaptersWithoutUploadDate, testZoneId) shouldBe 1 + } + + @Test + fun `returns interval of 1 day when chapters are released just below every 2 days`() { + val chapters = (1..20).map { + chapterWithTime(chapter, (43 * it).hours) + } + fetchInterval.calculateInterval(chapters, testZoneId) shouldBe 1 + } + + private fun chapterWithTime(chapter: Chapter, duration: Duration): Chapter { + val newTime = testTime.plus(duration.toJavaDuration()).toEpochSecond() * 1000 + return chapter.copy(dateFetch = newTime, dateUpload = newTime) + } + + private fun List.lastUploadDate() = + last().dateUpload.toDuration(DurationUnit.MILLISECONDS) +} diff --git a/domain/src/test/java/tachiyomi/domain/manga/interactor/SetFetchIntervalTest.kt b/domain/src/test/java/tachiyomi/domain/manga/interactor/SetFetchIntervalTest.kt deleted file mode 100644 index 8c329ca22..000000000 --- a/domain/src/test/java/tachiyomi/domain/manga/interactor/SetFetchIntervalTest.kt +++ /dev/null @@ -1,104 +0,0 @@ -package tachiyomi.domain.manga.interactor - -import io.kotest.matchers.shouldBe -import io.mockk.mockk -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.parallel.Execution -import org.junit.jupiter.api.parallel.ExecutionMode -import tachiyomi.domain.chapter.model.Chapter -import java.time.ZonedDateTime -import kotlin.time.Duration -import kotlin.time.Duration.Companion.hours -import kotlin.time.toJavaDuration - -@Execution(ExecutionMode.CONCURRENT) -class SetFetchIntervalTest { - - private val testTime = ZonedDateTime.parse("2020-01-01T00:00:00Z") - private var chapter = Chapter.create().copy( - dateFetch = testTime.toEpochSecond() * 1000, - dateUpload = testTime.toEpochSecond() * 1000, - ) - - private val setFetchInterval = SetFetchInterval(mockk()) - - @Test - fun `calculateInterval returns default of 7 days when less than 3 distinct days`() { - val chapters = (1..2).map { - chapterWithTime(chapter, 10.hours) - } - setFetchInterval.calculateInterval(chapters, testTime) shouldBe 7 - } - - @Test - fun `calculateInterval returns 7 when 5 chapters in 1 day`() { - val chapters = (1..5).map { - chapterWithTime(chapter, 10.hours) - } - setFetchInterval.calculateInterval(chapters, testTime) shouldBe 7 - } - - @Test - fun `calculateInterval returns 7 when 7 chapters in 48 hours, 2 day`() { - val chapters = (1..2).map { - chapterWithTime(chapter, 24.hours) - } + (1..5).map { - chapterWithTime(chapter, 48.hours) - } - setFetchInterval.calculateInterval(chapters, testTime) shouldBe 7 - } - - @Test - fun `calculateInterval returns default of 1 day when interval less than 1`() { - val chapters = (1..5).map { - chapterWithTime(chapter, (15 * it).hours) - } - setFetchInterval.calculateInterval(chapters, testTime) shouldBe 1 - } - - // Normal interval calculation - @Test - fun `calculateInterval returns 1 when 5 chapters in 120 hours, 5 days`() { - val chapters = (1..5).map { - chapterWithTime(chapter, (24 * it).hours) - } - setFetchInterval.calculateInterval(chapters, testTime) shouldBe 1 - } - - @Test - fun `calculateInterval returns 2 when 5 chapters in 240 hours, 10 days`() { - val chapters = (1..5).map { - chapterWithTime(chapter, (48 * it).hours) - } - setFetchInterval.calculateInterval(chapters, testTime) shouldBe 2 - } - - @Test - fun `calculateInterval returns floored value when interval is decimal`() { - val chapters = (1..5).map { - chapterWithTime(chapter, (25 * it).hours) - } - setFetchInterval.calculateInterval(chapters, testTime) shouldBe 1 - } - - @Test - fun `calculateInterval returns 1 when 5 chapters in 215 hours, 5 days`() { - val chapters = (1..5).map { - chapterWithTime(chapter, (43 * it).hours) - } - setFetchInterval.calculateInterval(chapters, testTime) shouldBe 1 - } - - @Test - fun `calculateInterval returns interval based on fetch time if upload time not available`() { - val chapters = (1..5).map { - chapterWithTime(chapter, (25 * it).hours).copy(dateUpload = 0L) - } - setFetchInterval.calculateInterval(chapters, testTime) shouldBe 1 - } - - private fun chapterWithTime(chapter: Chapter, duration: Duration): Chapter { - val newTime = testTime.plus(duration.toJavaDuration()).toEpochSecond() * 1000 - return chapter.copy(dateFetch = newTime, dateUpload = newTime) - } -} diff --git a/domain/src/test/java/tachiyomi/domain/release/interactor/GetApplicationReleaseTest.kt b/domain/src/test/java/tachiyomi/domain/release/interactor/GetApplicationReleaseTest.kt index 41df15221..f813094fe 100644 --- a/domain/src/test/java/tachiyomi/domain/release/interactor/GetApplicationReleaseTest.kt +++ b/domain/src/test/java/tachiyomi/domain/release/interactor/GetApplicationReleaseTest.kt @@ -79,7 +79,9 @@ class GetApplicationReleaseTest { ), ) - (result as GetApplicationRelease.Result.NewUpdate).release shouldBe GetApplicationRelease.Result.NewUpdate(release).release + (result as GetApplicationRelease.Result.NewUpdate).release shouldBe GetApplicationRelease.Result.NewUpdate( + release, + ).release } @Test @@ -106,7 +108,9 @@ class GetApplicationReleaseTest { ), ) - (result as GetApplicationRelease.Result.NewUpdate).release shouldBe GetApplicationRelease.Result.NewUpdate(release).release + (result as GetApplicationRelease.Result.NewUpdate).release shouldBe GetApplicationRelease.Result.NewUpdate( + release, + ).release } @Test diff --git a/gradle/androidx.versions.toml b/gradle/androidx.versions.toml index 9fe6455c3..ec3244800 100644 --- a/gradle/androidx.versions.toml +++ b/gradle/androidx.versions.toml @@ -1,20 +1,20 @@ [versions] agp_version = "8.1.1" -lifecycle_version = "2.6.1" -paging_version = "3.2.0" +lifecycle_version = "2.6.2" +paging_version = "3.2.1" [libraries] gradle = { module = "com.android.tools.build:gradle", version.ref = "agp_version" } -annotation = "androidx.annotation:annotation:1.7.0-rc01" +annotation = "androidx.annotation:annotation:1.7.0" appcompat = "androidx.appcompat:appcompat:1.6.1" biometricktx = "androidx.biometric:biometric-ktx:1.2.0-alpha05" constraintlayout = "androidx.constraintlayout:constraintlayout:2.1.4" -corektx = "androidx.core:core-ktx:1.12.0-rc01" +corektx = "androidx.core:core-ktx:1.12.0" splashscreen = "androidx.core:core-splashscreen:1.0.1" recyclerview = "androidx.recyclerview:recyclerview:1.3.1" viewpager = "androidx.viewpager:viewpager:1.1.0-alpha01" -glance = "androidx.glance:glance-appwidget:1.0.0-rc01" +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" } @@ -27,7 +27,7 @@ guava = "com.google.guava:guava:32.1.2-android" paging-runtime = { module = "androidx.paging:paging-runtime", version.ref = "paging_version" } paging-compose = { module = "androidx.paging:paging-compose", version.ref = "paging_version" } -benchmark-macro = "androidx.benchmark:benchmark-macro-junit4:1.2.0-beta04" +benchmark-macro = "androidx.benchmark:benchmark-macro-junit4:1.2.0-rc01" test-ext = "androidx.test.ext:junit-ktx:1.2.0-alpha01" test-espresso-core = "androidx.test.espresso:espresso-core:3.6.0-alpha01" test-uiautomator = "androidx.test.uiautomator:uiautomator:2.3.0-alpha04" diff --git a/gradle/compose.versions.toml b/gradle/compose.versions.toml index e21536263..dc18de785 100644 --- a/gradle/compose.versions.toml +++ b/gradle/compose.versions.toml @@ -1,5 +1,5 @@ [versions] -compiler = "1.5.2" +compiler = "1.5.3" compose-bom = "2023.09.00-alpha02" accompanist = "0.33.1-alpha" diff --git a/gradle/kotlinx.versions.toml b/gradle/kotlinx.versions.toml index 61d4968c4..1f7a93033 100644 --- a/gradle/kotlinx.versions.toml +++ b/gradle/kotlinx.versions.toml @@ -1,7 +1,7 @@ [versions] -kotlin_version = "1.9.0" +kotlin_version = "1.9.10" serialization_version = "1.6.0" -xml_serialization_version = "0.86.1" +xml_serialization_version = "0.86.2" [libraries] reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin_version" } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 0cd15c4fa..2411d35b9 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,17 +1,17 @@ [versions] -aboutlib_version = "10.8.3" +aboutlib_version = "10.9.0" okhttp_version = "5.0.0-alpha.11" shizuku_version = "12.2.0" sqlite = "2.3.1" sqldelight = "2.0.0" leakcanary = "2.12" -voyager = "1.0.0-rc06" +voyager = "1.0.0-rc07" richtext = "0.17.0" [libraries] desugar = "com.android.tools:desugar_jdk_libs:2.0.3" android-shortcut-gradle = "com.github.zellius:android-shortcut-gradle-plugin:0.1.2" -google-services-gradle = "com.google.gms:google-services:4.3.15" +google-services-gradle = "com.google.gms:google-services:4.4.0" rxjava = "io.reactivex:rxjava:1.3.8" flowreactivenetwork = "ru.beryukhov:flowreactivenetwork:1.0.4" @@ -33,7 +33,7 @@ junrar = "com.github.junrar:junrar:7.5.5" sqlite-framework = { module = "androidx.sqlite:sqlite-framework", version.ref = "sqlite" } sqlite-ktx = { module = "androidx.sqlite:sqlite-ktx", version.ref = "sqlite" } -sqlite-android = "com.github.requery:sqlite-android:3.42.0" +sqlite-android = "com.github.requery:sqlite-android:3.43.0" preferencektx = "androidx.preference:preference-ktx:1.2.1" @@ -57,14 +57,14 @@ flexible-adapter-core = "com.github.arkon.FlexibleAdapter:flexible-adapter:c8013 photoview = "com.github.chrisbanes:PhotoView:2.3.0" directionalviewpager = "com.github.tachiyomiorg:DirectionalViewPager:1.0.0" insetter = "dev.chrisbanes.insetter:insetter:0.6.1" -compose-materialmotion = "io.github.fornewid:material-motion-compose-core:1.0.6" +compose-materialmotion = "io.github.fornewid:material-motion-compose-core:1.1.0" compose-simpleicons = "br.com.devsrsouza.compose.icons.android:simple-icons:1.0.0" swipe = "me.saket.swipe:swipe:1.2.0" logcat = "com.squareup.logcat:logcat:0.1" -acra-http = "ch.acra:acra-http:5.11.1" +acra-http = "ch.acra:acra-http:5.11.2" firebase-analytics = "com.google.firebase:firebase-analytics-ktx:21.3.0" aboutLibraries-gradle = { module = "com.mikepenz.aboutlibraries.plugin:aboutlibraries-plugin", version.ref = "aboutlib_version" } @@ -83,18 +83,17 @@ sqldelight-dialects-sql = { module = "app.cash.sqldelight:sqlite-3-38-dialect", sqldelight-gradle = { module = "app.cash.sqldelight:gradle-plugin", version.ref = "sqldelight" } junit = "org.junit.jupiter:junit-jupiter:5.10.0" -kotest-assertions = "io.kotest:kotest-assertions-core:5.6.2" -mockk = "io.mockk:mockk:1.13.7" +kotest-assertions = "io.kotest:kotest-assertions-core:5.7.2" +mockk = "io.mockk:mockk:1.13.8" voyager-navigator = { module = "cafe.adriel.voyager:voyager-navigator", version.ref = "voyager" } voyager-tab-navigator = { module = "cafe.adriel.voyager:voyager-tab-navigator", version.ref = "voyager" } voyager-transitions = { module = "cafe.adriel.voyager:voyager-transitions", version.ref = "voyager" } +ktlint = "org.jlleitschuh.gradle:ktlint-gradle:11.6.0" google-api-services-drive = "com.google.apis:google-api-services-drive:v3-rev197-1.25.0" google-api-client-oauth = "com.google.oauth-client:google-oauth-client:1.34.1" -kotlinter = "org.jmailen.gradle:kotlinter-gradle:3.13.0" - [bundles] okhttp = ["okhttp-core", "okhttp-logging", "okhttp-dnsoverhttps"] js-engine = ["quickjs-android"] diff --git a/i18n/src/main/res/values-am/strings.xml b/i18n/src/main/res/values-am/strings.xml index 566ebf712..60b800dd0 100644 --- a/i18n/src/main/res/values-am/strings.xml +++ b/i18n/src/main/res/values-am/strings.xml @@ -143,8 +143,6 @@ ማጣሪያ ምናሌ ማስተካከያዎች - ለመውጣት እንደገና ተመልሰው ይጫኑ - ታቺዮሚን ይክፈቱ ኢክስቴንሽኖች ታሪክ መከታተል diff --git a/i18n/src/main/res/values-ar/strings.xml b/i18n/src/main/res/values-ar/strings.xml index 6489e8a5e..b6a544028 100644 --- a/i18n/src/main/res/values-ar/strings.xml +++ b/i18n/src/main/res/values-ar/strings.xml @@ -251,7 +251,7 @@ إضافة ذات ريبة هذه اﻹضافة موقَّعة بشهادة ذات ريبة ولم تفعَّل. \n -\nيمكن لأي إضافة خبيثة قراءة بيانات اعتماد تسجيل الدخول المخزَّنة في Tachiyomi أو تنفيذ تعليمات برمجية عشوائية. +\nيمكن لأي إضافة خبيثة قراءة بيانات اعتماد تسجيل الدخول المخزَّنة أو تنفيذ تعليمات برمجية عشوائية. \n \nأنت تقبل هذه المخاطر إن وثقت بالشهادة. سرعة مؤثر النقر المزدوج @@ -297,7 +297,6 @@ تحديث المكتبة المزيد - افتح Tachiyomi نقل إلى الأعلى الأقدم الأَحدثْ @@ -346,11 +345,10 @@ إلغاء التثبيت تثبيت عكس التحديد - اضغط رجوع مرة أخرى للخروج تحديثات اﻹضافات تحديثات الفصول يرجى تحديث تطبيق WebView لتوافق أفضل - يتطلب Tachiyomi وجود WebView + إن وجود WebView لازم ليعمل التطبيق فشل في تجاوز Cloudflare لايوجد تحديث للإضافة @@ -401,7 +399,6 @@ دليل استخدام المصادر المحلية المثبتة آخر مصدر مُستخدم - التحقق من الموقع الإلكتروني في WebView تم تسجيل الخروج تسجيل الخروج تسجيل الخروج من %1$s؟ @@ -442,7 +439,7 @@ النسخة الإحتياطية لا تحتوي على أيّة إدخالات المكتبة. ملفُّ النسخ الاحتياطيِّ غير صالح مزامنة أحاديّة لتحديث تقدم الفصول في خدمات التتبع. قم بإعداد التتبع الخاص للإدخالات محدّدة من زر التتبع الخاص بها. - هذه الإضافة ليست من قائمة إضافات Tachiyomi الرسمية. + ليست هذه الإضافة من القائمة الرسمية. غير رسمي تحقق من وجود غلاف جديد وتفاصيل جديدة عند تحديث المكتبة تحديث البيانات الوصفية تلقائياً @@ -700,7 +697,6 @@ فتح في GitHub احذف بيانات WebView حُذفت بيانات WebView - عند ارتفاع نسبة الشحن‌ لا يوجد مصادر مثبته لا يوجد مصدر المانجا الغير مقروءة @@ -881,4 +877,8 @@ ولوج التتبع أُفسد فهرس التنزيلات اضغط هنا تتحرَّ كلاودفلير + لا اتصال بالإنترنت + خطأ HTTP %d، انظر في WebView + لم نصل %s + افتح %s \ No newline at end of file diff --git a/i18n/src/main/res/values-b+es+419/strings.xml b/i18n/src/main/res/values-b+es+419/strings.xml index 5f1020736..ede476a22 100644 --- a/i18n/src/main/res/values-b+es+419/strings.xml +++ b/i18n/src/main/res/values-b+es+419/strings.xml @@ -5,7 +5,6 @@ Capítulo más reciente Total de capítulos Información de la extensión - Pulse Atrás de nuevo para salir Copia de seguridad y restauración Historial Historial @@ -23,7 +22,7 @@ Agregar categoría Agregar Editar - Actualizar Biblioteca + Actualizar biblioteca Borrar Descargar Marcar anteriores como leído @@ -38,7 +37,6 @@ Filtrar Menú Configuración - Desbloquear Tachiyomi Capítulos Manga Categorías @@ -320,7 +318,6 @@ Última usada Otro Fuente local - Abrir sitio en WebView No se han encontrado resultados No hay más resultados Pestañas @@ -398,8 +395,8 @@ En curso No hay nuevas actualizaciones disponibles Descargar - Seleccione el archivo de copia de seguridad - Seleccione la imagen de portada + Seleccionar archivo de copia de seguridad + Seleccionar imagen de portada Por favor agregue el manga a la biblioteca antes de hacer esto Error al actualizar la portada @@ -663,7 +660,6 @@ Una nueva versión esta disponible desde los lanzamientos oficiales, Toca para aprender a emigrar de lanzamientos F-droid no oficiales. Error al guardar imagen Cerrar - Cuando la batería no está baja Abrir en GitHub Ninguna fuente encontrada No se encontró ninguna fuente instalada @@ -826,4 +822,14 @@ %d días Con resultados + Licenciado - No hay capítulos para mostrar + HTTP %d, comprueba la página web en WebView + Sin conexión a Internet + Índice de descargas invalidado + No se pudo crear un archivo de respaldo + Sincronizando biblioteca + Se completó la sincronización de la biblioteca + Toque aquí para obtener ayuda con Cloudflare + Inicio de sesión para seguimiento + No se pudo acceder a %s \ No newline at end of file diff --git a/i18n/src/main/res/values-be/strings.xml b/i18n/src/main/res/values-be/strings.xml index 8aeeb5dfe..1cefa0e7b 100644 --- a/i18n/src/main/res/values-be/strings.xml +++ b/i18n/src/main/res/values-be/strings.xml @@ -69,8 +69,6 @@ Фільтр Меню Налады - Націсніце назад яшчэ раз, каб выйсці - Разблакіраваць Tachiyomi Дапамога Інфармацыя аб пашырэнні Назва @@ -361,7 +359,6 @@ Ёсць непрачытаныя главы Shizuku не працуе Закрыць - калі батарэя зараджана Устаноўка пашырэнняў… Перамясціць у пачатак спісу Усталёўнік diff --git a/i18n/src/main/res/values-bg/strings.xml b/i18n/src/main/res/values-bg/strings.xml index 9e95b4aff..097115845 100644 --- a/i18n/src/main/res/values-bg/strings.xml +++ b/i18n/src/main/res/values-bg/strings.xml @@ -374,7 +374,6 @@ Помощ за локални източници Закачени Последно използвани - Виж уебсайта в WebView Имейл адрес 1 оставаща @@ -429,8 +428,6 @@ Избери обратно Последна глава Меню - Натиснете назад още веднъж, за да излезете - Отключете Тачийоми Източници Още Режим на четене @@ -668,7 +665,6 @@ Не е инсталиран Пропуснати Обърнат портрет - Когато батерията не е паднала Език Случи се неочаквана грешка Автоматично изтегляне при четене diff --git a/i18n/src/main/res/values-bn/strings.xml b/i18n/src/main/res/values-bn/strings.xml index b44956d03..7f3dc3ef9 100644 --- a/i18n/src/main/res/values-bn/strings.xml +++ b/i18n/src/main/res/values-bn/strings.xml @@ -307,8 +307,6 @@ তারিখে যোগকৃত সর্বশেষ অধ্যায় তালিকা - প্রস্থান করতে আবার ব্যাক চাপুন - তাচিওমি খুলুন উৎস সমূহ আরও প্রদর্শন @@ -460,7 +458,6 @@ স্থানীয় উৎস নির্দেশিকা \"%1$s\" সার্বজনীনভাবে খুঁজুন সর্বশেষ ব্যবহৃত - ওয়েবসাইটটি ওয়েবভিউতে পরীক্ষা করুন ট্যাব গুলি ডাউনলোড করা অধ্যায় লাইব্রেরীর মাঙ্গা diff --git a/i18n/src/main/res/values-ca/strings.xml b/i18n/src/main/res/values-ca/strings.xml index 97f260013..033783918 100644 --- a/i18n/src/main/res/values-ca/strings.xml +++ b/i18n/src/main/res/values-ca/strings.xml @@ -99,7 +99,7 @@ Extensió no fiable Aquesta extensió s’ha signat amb un certificat que no és de confiança i no s’ha activat. \n -\nUna extensió maliciosa podria llegir qualsevol credencial desada al Tachiyomi o executar codi arbitrari. +\nUna extensió maliciosa podria llegir qualsevol credencial d’inici de sessió desada o executar codi arbitrari. \n \nSi confieu en aquest certificat, accepteu aquests riscos. Pantalla completa @@ -326,9 +326,8 @@ Actualitzacions pendents Mostra el contingut a l’àrea de retall No s’ha pogut evitar el Cloudflare - Actualitzeu l’aplicació de WebView per a tenir més bona compatibilitat + Actualitzeu l’aplicació WebView per a tenir més bona compatibilitat Novetats de capítols - Desbloca el Tachiyomi El mode discret amaga el contingut de l’aplicació en canviar entre aplicacions i bloca les captures de pantalla Visualització @@ -363,7 +362,6 @@ Hi ha actualitzacions de %d extensions Actualitzacions d’extensions - Comproveu el lloc web en una WebView S’està actualitzant la biblioteca Lectura Omet els capítols filtrats @@ -377,12 +375,11 @@ Desfixa A la biblioteca Afegeix a la biblioteca - El Tachiyomi requereix el WebView + La WebView és necessària per al funcionament de l’aplicació Menys Més Llicències de codi obert Lloc web - Torneu a prémer Endarrere per a sortir Només els baixats Cap. %1$s - %2$s Ha fallat la restauració de la còpia de seguretat @@ -414,7 +411,7 @@ La sincronització és unidireccional per a actualitzar el progrés dels capítols als serveis de seguiment. Configureu el seguiment d’elements individuals al seu botó de seguiment. Refresca les portades de la biblioteca - Aquesta extensió no pertany a la llista d’extensions oficials del Tachiyomi. + Aquesta extensió no pertany a la llista d’extensions oficials. No oficial Per data de pujada Dades @@ -649,10 +646,9 @@ S’ha produït un error en desar la imatge No hi ha cap element a la biblioteca del qual fer còpia de seguretat Hi ha una nova versió disponible als llançaments oficials. Premeu per a obtenir informació de com migrar a partir dels llançaments no oficials d’F-Droid. - Neteja les dades del WebView - S’han netejat les dades del WebView + Neteja les dades de la WebView + S’han netejat les dades de la WebView Tanca - Quan la bateria no sigui baixa No s’ha trobat cap font instal·lada No s’ha trobat cap font Nombre de no llegits @@ -817,4 +813,8 @@ Inici de sessió al seguiment S’ha invalidat l\'índex de baixades Premeu aquí per a obtenir ajuda amb el Cloudflare + Desbloca %s + No hi ha connexió a Internet + HTTP %d, comproveu el lloc web en una WebView + No s’ha pogut accedir a %s \ No newline at end of file diff --git a/i18n/src/main/res/values-ceb/strings.xml b/i18n/src/main/res/values-ceb/strings.xml index 43f8e0fb7..81529b94c 100644 --- a/i18n/src/main/res/values-ceb/strings.xml +++ b/i18n/src/main/res/values-ceb/strings.xml @@ -2,9 +2,7 @@ Kasaysayan Mga update - I-unlock ang Tachiyomi Panghimatuod aron makumpirma ang pagbag-o - Pindota balik pag-usab aron makagawas Mga setting Menu Gi-bookmark @@ -150,7 +148,6 @@ Kada 2 ka adlaw Kada semana Sa dihang nag-charge - Dili ubos ang baterya Mga pagdili: %s Laktawan ang pag-update sa mga titulo Uban sa wala pa mabasa nga (mga) kapitulo diff --git a/i18n/src/main/res/values-cs/strings.xml b/i18n/src/main/res/values-cs/strings.xml index c8b7b05ce..49b800e0f 100644 --- a/i18n/src/main/res/values-cs/strings.xml +++ b/i18n/src/main/res/values-cs/strings.xml @@ -63,7 +63,7 @@ Nedůvěryhodné rozšíření Toto rozšíření bylo podepsané nedůvěryhodným certifikátem a nebylo aktivované. \n -\nŠkodlivé rozšíření může přečíst přihlašovací údaje uložené v Tachiyomi nebo spustit libovolný kód. +\nŠkodlivé rozšíření může přečíst jakékoliv uložené přihlašovací údaje nebo spustit libovolný kód. \n \nDůvěřováním tomuto certifikátu přijímáte tato rizika. Celá obrazovka @@ -324,7 +324,6 @@ Nejnovější Zobrazit kapitoly Poslední kapitola - Odemknout Tachiyomi Přidat sledování Nebyly nalezeny žádné kapitoly Nastavit jako výchozí @@ -347,7 +346,6 @@ Hledat \"%1$s\" globálně Připnuté Naposledy použitý - Zobrazit stránku ve WebView Karty Stažené kapitoly Z knihovny @@ -409,7 +407,7 @@ Žádné Zdroje z tohoto rozšíření mohou obsahovat NSFW (18+) obsah 18+ - Toto rozšíření není z oficiálního seznamu rozšíření pro Tachiyomi. + Toto rozšíření není z oficiálního seznamu rozšíření. Neoficiální %d kategorie @@ -445,7 +443,7 @@ Postup Výchozí nastavení kapitol aktualizováno Prosím aktualizujte aplikaci WebView pro lepší kompatibilitu - Je nutné mít nainstalovanou aplikaci WebView + Je nutné mít nainstalovanou aplikaci WebView pro správné fungování aplikace Nastala chyba při obcházení služby Cloudflare Je dostupná aktualizace rozšíření @@ -499,7 +497,6 @@ Nastavení vyhledávání Datum přidání Sledováno - Opětovným stisknutím tlačítka aplikaci opustíte Režim čtení Ukazovat režim čtení Pro tuto sérii @@ -685,7 +682,6 @@ Posunutí širokých snímků Počet nepřečtených Poslední kontrola aktualizace - Když baterie není vybitá Nelze otevřít poslední přečtenou kapitolu Vlastní obal Nenainstalováno @@ -833,4 +829,8 @@ Index stažených zneplatněn Nelze vytvořit soubor zálohy Licencováno - Žádné kapitoly k zobrazení + Bez připojení k internetu + Nelze dosáhnout %s + HTTP %d, zkontrolovat web v WebView + Odemknout %s \ No newline at end of file diff --git a/i18n/src/main/res/values-cv/strings.xml b/i18n/src/main/res/values-cv/strings.xml index bc9e4d457..4e43a567a 100644 --- a/i18n/src/main/res/values-cv/strings.xml +++ b/i18n/src/main/res/values-cv/strings.xml @@ -11,7 +11,7 @@ Юлашки вуланӑ сыпăк Сӳнтернӗ Вуланӑ хыҫҫӑн - Тиев вырӑнӗ + Тийев вырӑнӗ Вулани Кӑвак Симӗс @@ -27,7 +27,7 @@ Хура Шурӑ Ӳкерчĕк хыҫӑн тӗсӗ - Экран + Екран Хутлани Катерт Лартнӑ @@ -100,7 +100,6 @@ Пухмӑш хуш Хуш Умӗнхине вуланӑ пек паллӑ ту - Тухма тепӗр хут пус Улӑштар Пурне те сӳнтер Пурне те ҫут @@ -135,7 +134,7 @@ Wi-Fi ҫыхӑну ҫук Йӑнӑш Ҫӗнӗ версси пур! - Тиев йӑнӑшӗ + Тийев йӑнӑшӗ Тиенсе пӗтрӗ %1$s-мӗш сыпӑк Ҫӗнӗ сыпӑксем тупӑнман @@ -154,7 +153,6 @@ Меллӗ сетке Ҫӑтӑ сетке Тепӗр майлӑ суйла - Tachiyomi уҫ Сӳнтернӗ Сетке пысӑкӑшӗ Урлӑ @@ -220,11 +218,11 @@ Ҫаклатнӑ урлӑскер Ирӗклӗ Яланхилле урлӑ-тӑрӑх - Энимсӗр + Енимсӗр Пысӑклатни пуҫламӑш тӑрӑмӗ Тӑнлӑ Тӑс - Экранпа + Екранпа Сарӑмлани Вӗҫӗмсӗрех урлӑ Вӑрӑм елсем @@ -238,7 +236,7 @@ Куҫӑм Аланӑ сыпӑксене сиктермелле Вуланӑ сыпӑксене сиктермелле - Экрана ҫутӑ тыт + Екрана ҫутӑ тыт Тӗттӗмлетӳ Ҫутату Витӗм @@ -279,15 +277,15 @@ Хушмасен ҫӗнетӗвӗсем Сыпӑксен ҫӗнетӗвӗсем Яланхи - Тиеве вӑхӑтлӑха чарнӑ + Тийеве вӑхӑтлӑха чарнӑ Кӗтмен йӑнӑша пула сыпӑксене тиесе илеймест - Тиевҫӗ + Тийевҫӗ Tachiyomi валли WebView кирлӗ Хушма валли ҫӗнетӳ пур %d хушма валли ҫӗнетӳ пур - Тиев… + Тийев… Ҫӗнетӳсем тупӑнман Тиесе ил Хуплашка суйла @@ -308,7 +306,7 @@ Ҫӗнӗ сыпӑксем %d хайлав валли тупӑннӑ Ҫӗнӗ сыпӑксен пуррине тӗрӗслени - Сыпӑксене тиесе илес ҫук. Тиевсем пайӗнче ҫӗнӗрен хӑтланса пӑхма пултаратӑн + Сыпӑксене тиесе илес ҫук. Тийевсем пайӗнче ҫӗнӗрен хӑтланса пӑхма пултаратӑн Ӑтавла Куҫар Куҫарма ҫӑл куҫ суйла @@ -349,7 +347,7 @@ Пӑрахнӑ Вӗҫленӗ Вулатӑп - Эсӗ суйланӑ сыпӑксене катертесшӗнех-и\? + Есӗ суйланӑ сыпӑксене катертесшӗнех-и\? Вуламанине Тиесе ил Тиенӗ вӑхӑчӗпе @@ -389,14 +387,13 @@ Юлашки усӑ курни Ыттисем Вырӑнти ҫӑл куҫ - Эле WebView-ра тӗрӗсле Пӗр тупсӑм та тупӑнман Урӑх тупсӑмсем ҫук Кантӑксем Тӗрӗс мар янтӑв файлӗ Пухмӑша ҫӗнетни Паллӑ мар йӑнӑш - Эсӗ тухрӑн + Есӗ тухрӑн Тух “%1$s тухмалла-и\? Ӑнӑҫлӑ кӗни @@ -567,7 +564,6 @@ Wi-Fi урлӑ ҫеҫ «Малалла вула» пускӑч Апа ҫаклатни, ыкран хӳтӗлевӗ - Петтерей тулли чух Чарусем: %s Вуламан сыпӑк(сем) пур Пуҫланӑ diff --git a/i18n/src/main/res/values-da/strings.xml b/i18n/src/main/res/values-da/strings.xml index 1aae251a9..ccd1e3144 100644 --- a/i18n/src/main/res/values-da/strings.xml +++ b/i18n/src/main/res/values-da/strings.xml @@ -7,7 +7,6 @@ Migerering Standard Advarsel - Lås op for Tachiyomi Bogmærket Fjern filter Inverter valg @@ -46,7 +45,6 @@ Intet læst for nyligt Ingen downloads Dato hentet - Tryk tilbage igen for at afslutte Indstillinger Ulæst Manga ialt @@ -180,7 +178,6 @@ Hver tredje dag Ugentligt Kun under opladning - Når batteriet ikke et lavt Begrænsninger: %s Spring over opdatering af titler Med ulæst kapitler diff --git a/i18n/src/main/res/values-de/strings.xml b/i18n/src/main/res/values-de/strings.xml index d054f8437..44b84fdc5 100644 --- a/i18n/src/main/res/values-de/strings.xml +++ b/i18n/src/main/res/values-de/strings.xml @@ -249,7 +249,7 @@ Deinstallieren Diese Erweiterung ist mit einem nicht vertrauenswürdigen Zertifikat unterschrieben und wurde nicht aktiviert. \n -\nEine bösartige Erweiterung könnte in Tachiyomi gespeicherte Anmeldedaten auslesen oder einen schädlichen Code ausführen. +\nEine bösartige Erweiterung könnte gespeicherte Anmeldedaten auslesen oder einen schädlichen Code ausführen. \n \nDurch das Vertrauen dieses Zertifikats akzeptierst du diese Risiken. Keine Animation @@ -328,7 +328,6 @@ Fehler beim Umgehen von Cloudflare Bitte aktualisiere die WebView-App für eine bessere Kompatibilität Kapitelaktualisierungen - Tachiyomi entsperren Sicherer Bildschirm verbirgt App-Inhalte beim Wechseln von Apps und blockiert Screenshots Anzeige @@ -363,7 +362,6 @@ %d Erweiterungsaktualisierungen verfügbar Erweiterungsaktualisierungen - Webseite in WebView prüfen Bibliothek wird aktualisiert Gefilterte Kapitel überspringen Beim Lesen @@ -379,8 +377,7 @@ Mehr In der Bibliothek Zur Bibliothek hinzufügen - Zum Beenden nochmal die Zurück-Taste drücken - WebView ist für Tachiyomi erforderlich + WebView ist für das Funktionieren der App erforderlich Open-Source-Lizenzen Webseite Nur Heruntergeladenes @@ -414,7 +411,7 @@ Einweg-Synchronisation zum Aktualisieren der Kapitelfortschritte in den Trackingdiensten. Richte Tracking für einzelne Einträge über deren jeweiligen Tracking-Button ein. Bibliothekscover aktualisieren - Diese Erweiterung stammt nicht von der offiziellen Tachiyomi-Erweiterungsliste. + Diese Erweiterung stammt nicht aus der offiziellen Liste. Inoffiziell Nach Uploaddatum Daten @@ -652,7 +649,6 @@ WebView-Daten löschen WebView-Daten gelöscht Schließen - Wenn der Akkustand nicht niedrig ist Keine installierte Quelle gefunden Keine Quelle gefunden Anzahl an Ungelesenem @@ -817,4 +813,8 @@ Tracking-Login Sicherungsdatei konnte nicht erstellt werden Lizenziert - Keine Kapitel zu zeigen + HTTP %d, überprüfe die Webseite in WebView + Keine Internetverbindung + %s konnte nicht erreicht werden + %s entsperren \ No newline at end of file diff --git a/i18n/src/main/res/values-el/strings.xml b/i18n/src/main/res/values-el/strings.xml index 995b310b2..5a8f8939c 100644 --- a/i18n/src/main/res/values-el/strings.xml +++ b/i18n/src/main/res/values-el/strings.xml @@ -97,9 +97,9 @@ Μη αξιόπιστο Απεγκατάσταση Μη αξιόπιστη επέκταση - Αυτή η επέκταση υπογράφηκε με μη αξιόπιστο πιστοποιητικό και δεν ενεργοποιήθηκε. + Αυτή η επέκταση υπογράφηκε με αναξιόπιστο πιστοποιητικό και δεν ενεργοποιήθηκε. \n -\nΜια κακόβουλη επέκταση θα μπορούσε να διαβάσει τα διαπιστευτήρια σύνδεσης που είναι αποθηκευμένα στο Tachiyomi ή να εκτελέσει αυθαίρετο κώδικα. +\nΜια κακόβουλη επέκταση θα μπορούσε να διαβάσει τυχόν αποθηκευμένα διαπιστευτήρια σύνδεσης ή να εκτελέσει αυθαίρετο κώδικα. \n \nΕμπιστεύοντας αυτό το πιστοποιητικό αποδέχεστε αυτούς τους κινδύνους. Πλήρης οθόνη @@ -302,13 +302,12 @@ Χρησιμοποιήθηκε τελευταία Προσθήκη tracking Καρφιτσωμένα - Πατήστε ξανά για έξοδο %02d λεπτά, %02d δευτερόλεπτα Επιλογή αντίστροφου Ενημερώσεις επεκτάσεων Ενημερώσεις κεφαλαίων Παρακαλώ ενημερώστε την εφαρμογή WebView για καλύτερη συμβατότητα - Το WebView απαιτείται για το Tachiyomi + Το WebView απαιτείται για τη λειτουργία της εφαρμογής Κεφάλαιο %1$s και %2$d ακόμη Κεφάλαια %1$s Κεφάλαιο %1$s @@ -334,7 +333,6 @@ Διαθέσιμη ενημέρωση επέκτασης %d διαθέσιμες ενημερώσεις επεκτάσεων - Ελέγξτε τον ιστότοπο στο WebView Έχετε αποσυνδεθεί Αποσύνδεση Αποσύνδεση από %1$s; @@ -385,7 +383,6 @@ Προβολή κεφαλαίων Νεότερο κεφάλαιο Μενού - Ξεκλειδώστε το Tachiyomi Ληφθέντα μόνο Πηγές Παλαιότερο @@ -414,7 +411,7 @@ Μονόδρομος συγχρονισμός για ενημέρωση των υπηρεσιών παρακολούθησης προόδου κεφαλαίων. Ρυθμίστε την παρακολούθηση για μεμονωμένες καταχωρήσεις από το κουμπί παρακολούθησης τους. Ανανέωση εξώφυλλων βιβλιοθήκης - Αυτή η επέκταση δεν προέρχεται από την επίσημη λίστα επεκτάσεων Tachiyomi. + Αυτή η επέκταση δεν προέρχεται από την επίσημη λίστα. Ανεπίσημη Από ημερομηνία μεταφόρτωσης Δεδομένα @@ -652,7 +649,6 @@ Τα δεδομένα WebView διαγράφηκαν Διαγραφή δεδομένων WebView Κλείσιμο - Όταν η μπαταρία δεν είναι χαμηλή Δε βρέθηκε εγκατεστημένη πηγή Αριθμός μη αναγνωσμένων Τελευταίος έλεγχος ενημέρωσης @@ -817,4 +813,8 @@ Σύνδεση παρακολούθησης Δεν ήταν δυνατή η δημιουργία αντιγράφου ασφαλείας Αδειοδοτημένο - Δεν υπάρχουν κεφάλαια προς εμφάνιση + Δεν μπορούσε να φτάσει το %s + HTTP %d, ελέγξτε την ιστοσελίδα στο WebView + Δεν υπάρχει σύνδεση στο διαδίκτυο + Ξεκλείδωμα %s \ No newline at end of file diff --git a/i18n/src/main/res/values-eo/strings.xml b/i18n/src/main/res/values-eo/strings.xml index 0d91f2c8a..857703896 100644 --- a/i18n/src/main/res/values-eo/strings.xml +++ b/i18n/src/main/res/values-eo/strings.xml @@ -47,7 +47,6 @@ Filtrilo Menuo Agordoj - Malŝlosi Tachiyomi-n Historio Ĉapitroj Biblioteka kontribuoj @@ -427,7 +426,6 @@ Nevalida ĉapitra formato Ĉapitro netrovita Loka fonta - Kontroli retejon en WebView Ĝisdatigi kategorion Kontroli por trovi ĝisdatigojn Helpu traduki @@ -449,7 +447,6 @@ Meznokta Vesperiĝo Ŝargas… Nuligi ĉiujn por ĉi tiu serio - Premi «reen» denove por eliri Aŭtentigi por konfirmi ŝanĝon Rezignita restaŭro Restaŭro fiaskis diff --git a/i18n/src/main/res/values-es/strings.xml b/i18n/src/main/res/values-es/strings.xml index 4c762aeb7..eda92c287 100644 --- a/i18n/src/main/res/values-es/strings.xml +++ b/i18n/src/main/res/values-es/strings.xml @@ -60,7 +60,7 @@ Cada 2 días Restricciones de actualización automática del dispositivo Mientras se carga la batería - Series completadas + Marcadas como completadas Actualizar progreso al terminar un capítulo Pantalla completa @@ -292,7 +292,7 @@ Copiar Esta extensión está firmada por una fuente sin certificar y por lo tanto no se ha activado. \n -\nUna extensión maliciosa puede leer credenciales de inicio guardadas en Tachiyomi o ejecutar cualquier tipo de código en tu dispositivo. +\nUna extensión maliciosa puede leer credenciales de inicio guardadas o ejecutar cualquier tipo de código en tu dispositivo. \n \nAl confiar en este certificado aceptas estos riesgos. Sin animación @@ -361,7 +361,6 @@ Fallo al evitar Cloudflare Actualiza la aplicación WebView para mejorar la compatibilidad Nuevos capítulos - Desbloquear Tachiyomi Pantalla segura oculta el contenido al cambiar de aplicación y bloquea las capturas de pantalla Visualización @@ -400,7 +399,6 @@ %d actualizaciones de extensiones disponibles Actualizando biblioteca - Abrir sitio en WebView Actualizaciones de extensiones Saltar capítulos excluidos por filtros Lectura @@ -414,12 +412,11 @@ Añadir seguimiento En biblioteca Añadir a biblioteca - Tachiyomi necesita WebView + Primero instala WebView para poder ver contenido de la aplicación Menos Más Licencias de código abierto Página web - Pulsa atrás de nuevo para salir Sólo ya descargados Caps. %1$s-%2$s Se ha cancelado la restauración @@ -454,7 +451,7 @@ Completada en %1$s con %2$s errores La sincronización de estos servicios solo funciona en un solo sentido. Cada elemento en tu biblioteca tiene un botón de seguimiento y tendrás que configurarlo a mano, uno a uno. - Esta extensión no es de la lista oficial de extensiones de Tachiyomi. + Esta extensión no es de la lista oficial de extensiones. No oficial Datos Fuentes que faltan: @@ -677,8 +674,8 @@ Desplazarse por el resto de la página antes de cambiar Cuadrícula sólo de portadas Acercar la vista en horizontal - Series sin empezar - Omitido porque la serie está completa + Sin empezar + Omitido, ya que su publicación ha terminado Omitido porque hay capítulos sin leer Omitido porque no hay capítulos leídos Ver más detalles @@ -695,7 +692,6 @@ Se han limpiado los datos del WebView Limpiar datos del WebView Cerrar - Cuando la batería tenga suficiente carga Todavía no se ha instalado ninguna fuente No se ha encontrado ninguna fuente Última comprobación de actualizaciones @@ -750,7 +746,7 @@ Populares Varios idiomas No se han concedido los permisos de almacenamiento - Saltando, porque este manga no necesita actualizarse + Omitido, ya que no es necesario actualizarse Buscar… Sincroniza tu progreso de lectura; unidireccional o mejorada Descargas automáticas y por adelantado @@ -864,4 +860,9 @@ Inicio de sesión de seguimiento No se ha podido crear un archivo de respaldo Con licencia oficial, sin capítulos que mostrar + No se ha podido acceder a %s + HTTP %d, comprueba la página web en WebView + Sin conexión a Internet + Desbloquear %s + Mover al último puesto \ No newline at end of file diff --git a/i18n/src/main/res/values-eu/strings.xml b/i18n/src/main/res/values-eu/strings.xml index 70776f91c..77162b700 100644 --- a/i18n/src/main/res/values-eu/strings.xml +++ b/i18n/src/main/res/values-eu/strings.xml @@ -443,7 +443,6 @@ Irakurri gabeko kapituluak ditu Sartu: %s G - Ikusi webgunea WebView-n Besteak Bilaketa globala… Historia ezabatu da @@ -483,9 +482,7 @@ Gehienezko babeskopiak Alfabetikoki Oharra - Desblokeatu Tachiyomi Autentifikatu aldaketa berresteko - Sakatu atzera berriro irteteko Ezarpenak Menua Iragazi @@ -640,7 +637,6 @@ Ezabatu kategoria Itxi App hizkuntza - Bateria baxu ez dagoenean Hizkuntza Bilatu… \"%s\" kategoria ezabatu nahi duzu\? diff --git a/i18n/src/main/res/values-fa/strings.xml b/i18n/src/main/res/values-fa/strings.xml index 3606fbea1..cb38c0439 100644 --- a/i18n/src/main/res/values-fa/strings.xml +++ b/i18n/src/main/res/values-fa/strings.xml @@ -97,7 +97,6 @@ Dodge / Lighten هر ۱۲ ساعت یکبار انتخاب دسته بندی - بازکردن تاچی یومی هیچ دسته بندی وجود ندارد. با زدن دکمه به علاوه دسته بندی جدیدی بسازید. کتابخانه شما خالی است هیچ چیز مانگاای به تازگی خوانده شده @@ -128,7 +127,6 @@ آخرین استفاده دیگر منبع محلی - وب سایت را در WebView بررسی کنید هیچ نتیجه ای یافت نشد نتیجه بیشتری یافت نشد تب ها @@ -428,7 +426,6 @@ فیلتر منو تنضیمات - برای بستن دکمه بازگشت را یک بار دیگر بزنید تاریخچه قسمت ها کتابخانه ورودی‌ها @@ -559,7 +556,6 @@ با قسمت‌(های) خوانده‌نشده ردیاب‌ها را به طور خودکار تازه کن - هنگامی که باتری کم نیست از به‌روزرسانی ورودی‌ها صرف‌نظر کنید امروز هر 3 روز diff --git a/i18n/src/main/res/values-fi/strings.xml b/i18n/src/main/res/values-fi/strings.xml index bd4a39a51..c97467e5f 100644 --- a/i18n/src/main/res/values-fi/strings.xml +++ b/i18n/src/main/res/values-fi/strings.xml @@ -323,7 +323,6 @@ Cloudflaren ohittaminen epäonnistui Lukujen päivitykset - Avaa Tachiyomi Näyttö Päivitettävät Päivitä WebView-sovellus yhteensopivuuden parantamiseksi @@ -367,7 +366,6 @@ Varmuuskopion palautus epäonnistui Varmuuskopiointi epäonnistui Ohita suodatetut luvut - Paina takaisin uudestaan poistuaksesi Ladatut Lähteet Päivittää kirjastoa @@ -388,7 +386,6 @@ Vähemmän Enemmän Kiinnitetyt - Katso sivu WebViewissä Luettavana Tarkista päivitykset Viimeksi käytetty @@ -621,7 +618,6 @@ Korkein Kieli Haku… - Kun akku ei ole vähissä Laventeli Sovelluksen kieli Versio diff --git a/i18n/src/main/res/values-fil/strings.xml b/i18n/src/main/res/values-fil/strings.xml index e9698d55e..e1292a666 100644 --- a/i18n/src/main/res/values-fil/strings.xml +++ b/i18n/src/main/res/values-fil/strings.xml @@ -69,8 +69,6 @@ Pansala Menu Mga setting - Pindutin muli para umalis - Buksan ang Tachiyomi Nakaraan Tina-track Mga Kabanata @@ -124,7 +122,7 @@ Pinili kong lugar Pagkamarkahang nabasa na Pagkatapos basahin, kusang burahin - Lugar ng paglalagyan + Lokasyon sa pag-download Kapal ng gilid Pagbabasa Ipakita palagi ang paglipat-kabanata @@ -187,11 +185,11 @@ I-animate ang paglipat-pahina Ipakita ang laman sa cutout area Naka-fullscreen - Wala sa opisyal na listahan ng mga extension ng Tachiyomi ang extension na ito. + Wala sa opisyal na listahan ang extension na ito. Hindi na available ang extension na ito. Maaaring hindi ito gumana nang maayos at maaaring magdulot ng mga isyu sa app. Inirerekomenda ang pag-uninstall nito. Pinirmahan ang extension na ito gamit ang isang kaduda-dudang certificate at hindi muna pinagana. \n -\nMaaaring mabasa ng isang kaduda-dudang extension ang kahit anong credentials sa pag-login na nakatago sa Tachiyomi o di kaya nama\'y magsimula ng delikadong code. +\nMaaaring mabasa ng isang kaduda-dudang extension ang kahit anong nakatagong credentials sa pag-login o di kaya nama\'y magsimula ng delikadong code. \n \nTinatanggap mo ang mga bantang ito sa pagtiwala sa certificate na ito. Kaduda-dudang extension @@ -271,7 +269,7 @@ Nagka-error Taga-download Paki-update po ang WebView app para sa mas maayos na paggana - Kailangan ng Tachiyomi ang WebView + Kinakailangan ng app ang WebView upang gumana ito Bigong ma-bypass ang Cloudflare Ang extension ay available upang i-update @@ -392,7 +390,6 @@ Huling ginamit Iba pa Lokal na Source - Bisitahin ang site sa WebView Walang nakitang resulta Wala na\'ng resulta Mga Tab @@ -652,7 +649,6 @@ Nalinis na ang WebView data Linisin ang WebView data Isara - Kapag di lowbat Walang nakitang naka-install na source Walang nakitang source Huling pag-update @@ -698,7 +694,7 @@ Sigurado ka ba\? Susunod na hindi pa nababasa na kabanata - Susunod na ang %d na hindi pa nababasa na kabanata + Susunod na %d di pa nababasa na kabanata Marami Tatanggalin mo na ang \"%s\" mula sa aklatan mo @@ -802,7 +798,7 @@ Itakdang i-update bawat Sa labas ng inaasahang release period Mga pagitan - I-customize ang Interval + Ayusin ang interval Nilaktawan dahil walang inaasahang release ngayong araw May mga resulta Tanggalin ang na-download @@ -817,4 +813,8 @@ Hindi makalikha ng backup file Pag-login sa tracking Lisensyado - Walang mapakitang kabanata + I-unlock ang %s + Walang koneksyon sa Internet + HTTP %d, tignan ang website sa WebView + Hindi maabot ang %s \ No newline at end of file diff --git a/i18n/src/main/res/values-fr/strings.xml b/i18n/src/main/res/values-fr/strings.xml index ccc7c76da..6f1d9e714 100644 --- a/i18n/src/main/res/values-fr/strings.xml +++ b/i18n/src/main/res/values-fr/strings.xml @@ -282,7 +282,7 @@ Extension non reconnue Cette extension a été signée avec un certificat non fiable et n\'a pas été activée. \n -\nUne extension malveillante pourrait lire n\'importe quel identifiant de connexion stocké dans Tachiyomi ou exécuter un code arbitraire. +\nUne extension malveillante pourrait lire n\'importe quel identifiant de connexion stocké ou exécuter un code arbitraire. \n \nEn faisant confiance à ce certificat, vous acceptez ces risques. Vitesse d\'animation du double-clic @@ -313,7 +313,7 @@ Échec du chargement des pages : %1$s Déplacer Copier - Afficher en cas d\'appui long + Afficher les actions en appuyant longuement Ouvrir dans WebView Couleurs à 32 bits Passer les chapitres marqués comme lus @@ -363,7 +363,6 @@ Impossible de contourner Cloudflare Veuillez mettre à jour l\'application WebView pour une meilleure compatibilité Mises à jour des chapitres - Débloquer Tachiyomi L\'écran sécurisé cache le contenu lors du changement d\'application et bloque les captures d\'écran Affichage @@ -402,7 +401,6 @@ %d mises à jour d\'extensions disponibles %d mises à jour d\'extensions disponibles - Consultez le site Web de WebView Mise à jour de la bibliothèque Sources En cours @@ -427,11 +425,10 @@ Site web Ch. %1$s – %2$s Licences à code source ouvert - Appuyer à nouveau pour quitter Dernière utilisée Rechercher des mises à jour %02d min, %02d s - WebView est requis par Tachiyomi + WebView est requis pour le fonctionnement l\'application Guide des sources locales %1$s restant @@ -456,7 +453,7 @@ Impossible d\'ouvrir les paramètres de l\'appareil Actualiser les couvertures de la bibliothèque Synchronisation à sens unique pour mettre à jour la progression du chapitre dans les services de suivi. Configurez le suivi des entrées individuelles à partir de leur bouton de suivi. - Cette extension ne fait pas partie de la liste des extensions officielles de Tachiyomi. + Cette extension ne fait pas partie de la liste officielle. Non officiel Vérifier s\'il y a une nouvelle couverture ou synopsis lors des mises à jour de la bibliothèque Par date de téléversement @@ -593,7 +590,7 @@ Format de chapitre invalide Chapitre non trouvé Mode de rotation - Automatique + Auto Mettre à jour les services de suivi lors de la mise à jour de la bibliothèque Actualiser automatiquement les services de suivi Restrictions : %s @@ -606,7 +603,7 @@ Manuel de suivi Désactivé Activé - Rendre les réglages de tri et d\'affichage propres à chaque catégorie + Rendre les réglages de tri propres à chaque catégorie Vous n\'avez pas encore de catégories. Commencer à télécharger Mise à jour de la bibliothèque… (%1$d/%2$d) @@ -663,7 +660,7 @@ Attention : les téléchargements massifs peuvent entraîner un ralentissement des sources ou le blocage de Tachiyomi. Appuyez pour en savoir plus. Tout mettre à jour Mises à jour de l\'application - Effacer le cache du chapitre à la fermeture de l\'application + Vider le cache de chapitre au lancement de l\'application %1$d entrées qui ne sont pas dans la bibliothèque dans la base de données Rien à effacer Échec de la récupération de la liste des extensions @@ -679,7 +676,7 @@ Afficher le titre Grille avec seulement la couverture Panoramique des images larges - Agrandir les images en paysage + Zoom automatique dans les images larges Qui n\'ont pas encore commencé Sauté car la série est terminée Sauté car aucun chapitre n\'est lu @@ -698,7 +695,6 @@ Effacer les données WebView Données WebView effacées Fermer - Quand la batterie n\'est pas faible Aucune source installée trouvée Dernière verification de mise à jour Nombre de non-lus @@ -745,7 +741,7 @@ Les %d suivants non lus Les %d suivants non lus - Fonctionne seulement sur les entrées de la bibliothèque et si le chapitre actuel et le suivant sont déjà téléchargés + Fonctionne seulement si le chapitre actuel et le suivant sont déjà téléchargés. Êtes-vous sûr(e) \? Populaire Diviser les grandes images (BETA) @@ -838,11 +834,28 @@ Appuyez deux fois pour zoomer Recherche mensuelle (28 jours) Vérification tardive 10+ - Abandonné \? Fin 20+ et 2 mois + Abandonné \? En retard de 20+ et 2 mois Période de contrôle réussie Prochaine mise à jour prévue Période de diffusion prévue Définir l\'intervalle Valider Intervalle de recherche personnalisé + Appuyez ici pour de l\'aide sur Cloudflare + Débloquer %s + Synchronisation de la bibliothèque + Intervals + Synchronisation de la bibliothèque complété + Licenciés - Aucun chapitres à montrer + Aucune connexion internet + Indice de téléchargement invalidé + Ignoré car aucune sortie n\'était attendue aujourd\'hui + A des résultats + Estimer chaque + HTTP %d, consulter le site Web dans WebView + + 1 jour + %d jours + %d jours + \ No newline at end of file diff --git a/i18n/src/main/res/values-gl/strings.xml b/i18n/src/main/res/values-gl/strings.xml index 5aa5f65b2..1b58a9ac9 100644 --- a/i18n/src/main/res/values-gl/strings.xml +++ b/i18n/src/main/res/values-gl/strings.xml @@ -230,8 +230,6 @@ Filtro Menú Axustes - Preme atrás novamente para saír - Desbloquea Tachiyomi Historial Seguimento Capítulos @@ -368,7 +366,6 @@ Baixados Idioma da aplicación ErroInterno: Revisa o rexistro de erros para máis información - Cando a batería non estea baixa Información da aplicación Shizuku non se está executando Instala e inicia Shizuku para utilizalo como instalador de extensións. @@ -720,7 +717,6 @@ Páxina anterior Lista de lectura Estás seguro\? - Abrir o sitio web no WebView Outros Estado descoñecido Fonte non instalada: %1$s diff --git a/i18n/src/main/res/values-he/strings.xml b/i18n/src/main/res/values-he/strings.xml index 0c255f305..d419e9157 100644 --- a/i18n/src/main/res/values-he/strings.xml +++ b/i18n/src/main/res/values-he/strings.xml @@ -3,7 +3,7 @@ עדכונים לתוסף עדכונים לפרק נפוץ - ההורדה מושהית + ההורדות מושהות אין חיבור רשת זמין אין חיבור Wi-Fi זמין לא ניתן להוריד את הפרק בגלל שגיאה בלתי צפויה @@ -21,13 +21,13 @@ גרסה חדשה זמינה! שגיאה בהורדה - לחץ כדי להתקין + לחץ כדי להתקין עדכון מוריד… אין עדכונים חדשים זמינים הורדה בחר קובץ גיבוי בחר תמונת כריכה - אנא הוסף את המנגה לספרייה שלך לפני שתעשה זאת + אנא הוסף את הפריט לספרייה שלך לפני שתעשה זאת עדכון הכריכה נכשל פרקים %1$s ואחד נוסף @@ -74,7 +74,7 @@ הכריכה עודכנה סנן מותאם אישית התמונה נשמרה - אפס את כל הפרקים למאנגה זו + אפס את כל הפרקים לפריט זה פעולה זו תסיר את התאריך הקריאה של פרק זה. האם אתה בטוח\? הקטגוריות נמחקו קטגוריה עם שם זה כבר קיימת! @@ -99,7 +99,7 @@ שגיאה מוריד (%1$d/%2$d) פרקים %1$s - להוסיף מאנגה לספרייה\? + להוסיף לספרייה\? המקור לא הותקן: %1$s למחוק פרקים שירדו\? נוסף לספרייה @@ -111,7 +111,6 @@ חיפוש גלובלי… אחר מאנגה מקומית - בדוק אתר ב-WebView לא נמצאו תוצאות אין תוצאות נוספות מעדכן קטגוריה @@ -167,8 +166,8 @@ לעולם לא תמיד נעילה כאשר אינו פעיל - דורש ביטול נעילה - אבטחה + ביטול נעילה דרוש + אבטחה ופרטיות ניהול התראות תבנית תאריך פעיל @@ -224,8 +223,8 @@ השבתת האופטימיזציה של הסוללה עדכן סטטוס, ציון ופרק אחרון שנקרא משירותי המעקב הרשומות נמחקו - האם אתה בטוח\? פרקים שנקראו וההתקדמות של מנגה שאינה בספרייה יאבדו - מחק את היסטוריית המנגה שאינם שמורים בספריה שלך + האם אתה בטוח\? פרקים שנקראו וההתקדמות של פריטים שאינם בספרייה יאבדו + מחק את היסטוריית הפריטים שאינם שמורים בספריה שלך נקה את מסד הנתונים עוגיות נוקו נקה עוגיות @@ -282,10 +281,10 @@ למתוח התאם לגודל מסך סוג קנה מידה - Webtoon - אנכי - ימין לשמאל - שמאל לימין + רצועה מוארכת + סידור עמודים (אנכי) + סידור עמודים (ימין לשמאל) + סידור עמודים (שמאל לימין) ברירת המחדל של מצב הקריאה שחור לבן @@ -307,7 +306,7 @@ הנפשת מעברי דפים הצג תוכן באזור החתוך תוסף לא מאומת - תוסף זה אינו זמין עוד. + תוסף זה אינו זמין עוד. ייתכן שאינו פועל כצפוי ויכול לגרום לבעיות באפליקציה. מומלץ להסיר את התקנת התוסף. מסך מלא הוסף ערוך @@ -344,12 +343,10 @@ הגדרות היסטוריה פרקים - מנגה + פריטים בספריה קטגוריות שם - לחץ אחורה שוב כדי לסגור - שחרר את Tachiyomi - שום דבר נקרא לאחרונה + שום דבר לא נקרא לאחרונה אין עידכונים אחרונים סומן רענון עוקבים אוטומטית @@ -358,7 +355,7 @@ התחל להוריד עכשיו נעץ מסך מאובטח - פריטים לשורה + גודל רשת עקוב אחר המערכת בדוק אם יש כריכה ופרטים חדשים בעת עדכון הספרייה סה\"כ פריטים @@ -406,7 +403,7 @@ תאריך הוספה תאריך האחזור של הפרקים דינמי - מנגה הנמצאת בקטגוריית מנועי העדכונים לא תעודכן גם אם היא נכללת בקטגורייה אחרת שכן מתעדכנת. + פריט הנמצא בקטגוריית מנועי העדכונים לא יעודכן גם אם הוא נכלל בקטגורייה אחרת שכן מתעדכנת. הראה פריט עם פרק(ים) שלא נקרא(ו) העבר סדרה לראש @@ -428,7 +425,7 @@ הראה מצב קריאה בלתי רשמי פרטי האפליקצייה - דלג על עדכוני כותרות + דלג על עדכוני פריטים נכשל בקבלת רשימת ההרחבות שו\"ת ומדריכים @@ -462,7 +459,7 @@ הכי נמוך מחק פרקים קטגוריות מוחרגות - מנגה הנמצאת בקטגוריית מנועי ההורדות לא תעודכן גם אם היא נכללת בקטגוריה אחרת שכן נכללת (בהורדות). + פריט הנמצא בקטגוריית מנועי ההורדות לא יעודכן גם אם הוא נכלל בקטגוריה אחרת שכן נכללת (בהורדות). שמור כארכיון CBZ שירותים משופרים גבול @@ -473,25 +470,25 @@ מצב קריאה הורדה אוטומטית אפור - אנכי מתמשך - עמודים + רצועה מוארכת עם רווחים + סידור עמודים מאונך הפוך שמור דפים בתיקיות נפרדות אנכי שניהם פעולות - הראה בלחיצה ארוכה + הצג פעולות בלחיצה ארוכה אוטומטי אפשר מחיקת פרקים שסומנו מנוע - צור תיקיות בהתאם לכותרת המנגה - שירותים המספקים שירותים משופרים למקורות ספציפיים. מנגות יהיו במעקב אוטומטי אחרי הוספה לספרייה שלך. + צור תיקיות בהתאם לכותרת הפריטים + שירותים המספקים שירותים משופרים למקורות ספציפיים. פריטים יהיו במעקב אוטומטי אחרי הוספה לספרייה שלך. מקורות חסרים: קובץ גיבוי לא תקין - הגיבוי לא מכיל שום מנגה. + הגיבוי לא מכיל שום פריטים. מעקב - נקה את זיכרון המטמון של הפרקים כשהאפליקציה נסגרת - יש %1$d מנגה שנמצאות במסד הנתונים אבל לא בספרייה + נקה את זיכרון המטמון של הפרקים כשהאפליקציה עולה + יש %1$d פריטים שנמצאים במסד הנתונים אבל לא בספרייה לשוניות חפש את \"%1$s\" גלובלית מצב לא ידוע @@ -510,7 +507,7 @@ שגיאה בשיתוף הכריכה קבע כברירת המחדל מצב קריאה - מנגה מתוך הספרייה + מהספרייה פרקים שירדו כריכה יותר @@ -544,20 +541,20 @@ 1 נשאר 2 נשארו %1$s נשארו - %1$s נשארו + התחברות נעוץ %02d דקות, %02d שניות השחזור בוטל - עדכונים אוטומטיים מאוד מומלצים. רצוי לשמור עותקים נוספים במקומות אחרים. - מסד הנתונים נקי + רצוי לשמור עותקים נוספים של גיבויים במקומות אחרים בנוסף. + אין מה לנקות בדוק עדכונים סדר ע\"י תאריך מחבר לא ידוע מצב פרטי - סינון כל המנגה בספרייה שלך + סינון כל הפריטים בספרייה שלך אתר מידע שגיאה בשמירת התמונה @@ -569,7 +566,7 @@ הושלם ב %1$s עם שגיאה אחת הושלם ב %1$s עם שתי שגיאות הושלם ב %1$s עם %2$s שגיאות - הושלם ב %1$s עם %2$s שגיאות + רשת בוטל/ה @@ -598,8 +595,7 @@ נכשל איפוס הגדרות מצב הקריאה עדכון אחרון לא נקראו - אין קצת סוללה - הגדרות מיון ותצוגה לכל קטגוריה בנפרד + הגדרות מיון לכל קטגוריה בנפרד מקור לא נמצא %1$d עדכונים דולגו גרסת האנדרואיד הזאת כבר לא נתמכת @@ -607,8 +603,8 @@ רשת רק של הכריכות פתח את יומן האירועים %1$d עדכונים נכשלו - הגדל תמונה אופקית - משפר את ביצועי מצב הקריאה ע\"י חיתוך תמונות גבוהות שירדו. + בצע קירוב לתמונות אופקיות באופן אוטומטי + משפר את ביצועי מצב הקריאה דולג בגלל שהסדרה נגמרה דולג בגלל שיש פרקים שלא נקראו דולג בגלל שאין פרקים שנקראו @@ -618,7 +614,7 @@ דולג פרק אחד, המקור חסר או שהוא סונן החוצה דולגו שני פרקים, המקור חסר או שהם סוננו החוצה דולגו %d פרקים, המקור חסר או שהם סוננו החוצה - דולגו %d פרקים, המקור חסר או שהם סוננו החוצה + מפחית פסים, אך עשוי להשפיע על הביצועים שגיאות @@ -634,7 +630,7 @@ פורמט פרק לא תקין בהפסקה האם תרצה למחוק את הקטגוריה %s\? - פיצול לשני עמודים + פצל עמודים רחבים כמו ספר אלקטרוני גרסה כיסוי @@ -646,10 +642,10 @@ הגבלה מורשת שפת אפליקציה - היפוך שני העמודים + הפוך מיקום של עמודים מפוצלים מדריך מעקב מחק הכל - אם המקום של הפיצול עמוד לא תואם לכיוון הקריאה + אם המקום של העמוד המפוצל לא תואם לכיוון הקריאה כלום איזורי נגיעה הפורמט RARv5 לא נתמך @@ -658,4 +654,198 @@ מדריך למתחיל סטטיסטיקות מקומי + *דרוש + שגיאה פנימית: בדוק ביומני קריסה למידע נוסף + נעילת אפליקציה, מסך מוגן + אתה עומד למחוק את \"%s\" מהספריה שלך + הותחלו + הורדו + גלים + קבע מרווח זמן + קבע מרווח זמן מותאם מראש לטעינה + טען חודשית (28 ימים) + כותרת לא מוכרת + בחר מרווח זמן מותאם אישית + מנהל ההורדות + HTTP %d, בדוק באתר ב-WebView + אין חיבור אינטרנט + קטגוריה ריקה + קטגוריית עדכון + כפתור המשך קריאה + מקורות, הרחבות, חיפוש כללי + מצב קריאה, תצוגה, ניווט + העתק ללוח הכתיבה + הגדרות פרק דיפולטי עודכנו + לא עכשיו + בודק הורדות + מחק הורדות + בדוק 10+ באיחור + נפל\? באיחור 20+ וחודשיים + תקופת בדיקה עברה + העדכון הצפוי הבא + הורד קבצי קריסה, אופטימיזציה לסוללה + לבנדר + %d בכל שורה + + הפרק הבא + שני הפרקים הבאים + %d הפרקים הבאים + + + לחץ כאן לעזרה עם Cloudflare + עמוד %d לא נמצא בעת פיצול + צפה בפריטי הספריה העדכניים ביותר + נכשל במציאת כתובת עמוד %d + כבר קיים פריט בספריה בעל אותו שם. +\n +\nלהמשיך בכל זאת\? + הורדה אוטומטית, הורד את הבאים + נושא, פורמט תאריך וזמן + קטגוריות, עדכון כללי, החלקת פרק + סנכרון חד צדדי, סנכרון משופר + מדריך וגיבויים אוטומטיים + לא נמצאו פריטים בקטגוריה זו + בסדר + + מעקב אחד + שני מעקבים + %d מעקבים + + + ספריה עודכנה לאחרונה ב: %s + פצל תמונות מוארכות (בטא) + שטח תמונה רחבה + הסתר פריטים שכבר בספרייה + הרשאות אחסון לא ניתנו + אין פרטי ספרייה לגיבוי + נכשל ביצירת קובץ גיבוי + מחרוזת משתמש לא תקינה + איפוס מחרוזת משתמש דיפולטית + לא הצליח לפתוח הגדרות מכשיר + לוג מפורט + הדפס דוחות שגיאה מפורטים ליומן המערכת (מוריד ביצועים לאפליקציה) + שכבת על + %d ימים + פתח ב-GitHub + פעולה בהחלקה ימינה + בטל תוקף של אינדקס ההורדות + זמין אבל המקור לא מותקן: %s + סנכרון חד צדדי לעדכון ההתקדמות בפרקים בשיקות המעקב. קבע מעקב עבור פריטים ספציפיים מכפתור המעקב שלהם. + הצג כמות פרקים שלא נקראו בסמל העדכונים + פצל תמונה מוארכת + שומר דוח שגיאות לקובץ עבור שיתוף עם המפתחים + כריכה מותאמת אישית + להסיר תאריך\? + הורד הלאה + פעילות רקע + פריטים במעקב + מחרוזת משתמש דיפולטית + מעבר פרק + בעל רישיון - אין פרקים להראות + הועתק ללוח כתיבה + האם אתה בטוח\? + המקור לא נתמך + לא נמצאה התאמה + לא מותקן + משך קריאה + בעדכון כללי + N/A + לזערה לגבי איך לתקן בעיות בעדכוני ספריה, ראה %1$s + לא יכל להשיג את %s + מחוץ לתקופת הפרסום הצפויה + סובב עמודים רחבים להתאמה + ממש עכשיו + הורד אוטומטית בזמן קריאה + פרטי התחברות למעקב + מיקום לא תקין: %s + מסנכרן ספריה + מחרזות משתמש לא יכולה להיות ריקה + שומש לאחרונה + בבקשה התחבר ל-MAL שוב + פריטים שהושלמו + %s נתקל בשגיאה בלתי צפויה. אנו ממליצים שתשתף את דוחות השגיאה שלך בערוץ התמיכה שלנו בדיסקורד. + נקראו + פריטים + %d שניות + רשימת פריטים בעצירה זמנית + רשימת פריטים שלא הושלמו + פעולת עדכון כבר פועלת + מעקבים + החלף אוריינטציה של עמודים רחבים מסובבים + מעקבים שדורשים התחברות: + רשימת פריטים שהושלמו + ממשק משתמש טאבלט + F-Droid builds לא נתמכים באופן רשמי. +\nלחץ כדי ללמוד עוד. + להסיר את %s ממעקב\? + פעולה זו תסיר את המעקב שלך מקומית. + הסר גם מ-%s + קבע גם עבור כל הפריטים בספריה + רק ברשת בלתי מוגבלת + שתף יומני קריסה + רענן מעקבים + פעולה זו תסיר את תאריך ההתחלה הקודם שלך מ-%s + רשימת קריאה + רשימת תכנונים + רבים + להתחמק / להאיר + רפד בצדדים + סנכרון ספריה הושלם + מרווחי זמן + לא מסוגל לפתוח את הפרק שנקרא לאחרונה + פעולה בהחלקה שמאלה + לחיצה כפולה לקירוב (זום) + עודכן לגרסה %1$s + בסך הכל + שגיאה %1$s: %2$s + עובד רק אם הפרק הנוכחי והפרק הבא כבר הורדו. + דלג על פרקים כפולים + DNS over HTTPS (DoH) + תוקף אינדקס ההורדות בוטל + מידע של WebView נוקה בהצלחה + אפס מצב קריאה ואוריינטציה לכל הסדרות + + הפרק הבא שלא נקרא + שני הפרקים הבאים שלא נקראו + %d הפרקים הבאים שלא נקראו + + + מידע דיבוג + רישיונות מקורות פתוחים + פופולרי + + יום אחד + יומיים + %d ימים + + + + חסר פרק אחד + חסרים שני פרקים + חסרים %1$s פרקים + + + הוסף מעקב + לחלק מהיצרנים יש הגבלות אפליקציה שהורגות תהליכים ברקע. באתר הזה יש עוד מידע לגבי איך לתקן את זה. + פעולה זו תסיר את תאריך הסיום הקודם שלך מ-%s + אופס! + אתחל את האפליקציה + %d שעות + דולג בגלל שהספריה לא דורשת עדכונים + דולג בגלל שלא צפוי פרסום היום + לא נמצאה אפליקציה לאסוף קבצים + במעקב + אין תיאור + בצע אומדן בכל + קבע לעדכון בכל + פרקים %1$s-%2$s + סקירה + יישומון לא זמין כשנעילת האפליקציה מופעלת + הכרח את האפליקציה לבדוק מחדש פרקים שהורדו + נקה מידע של WebView + רענן כריכות ספרייה + בעל תוצאות + ציון ממוצע + בשימוש + %d דקות \ No newline at end of file diff --git a/i18n/src/main/res/values-hi/strings.xml b/i18n/src/main/res/values-hi/strings.xml index c8e28abc6..d4cff453b 100644 --- a/i18n/src/main/res/values-hi/strings.xml +++ b/i18n/src/main/res/values-hi/strings.xml @@ -328,7 +328,6 @@ Cloudflare को बायपास करने में विफल बेहतर संगतता के लिए कृपया WebView ऐप को अपडेट करें अध्याय अद्यतन - अनलॉक Tachiyomi सुरक्षित स्क्रीन एप्लिकेशन स्विच करते समय एप्लिकेशन सामग्री छिपाता हैं और स्क्रीनशॉट ब्लॉक करता हैं प्रदर्शन @@ -363,7 +362,6 @@ %d एक्सटेंशन अपडेट उपलब्ध एक्सटेंशन अपडेट - WebView में वेबसाइट देखें अद्यतन पुस्तकालय पठन फ़िल्टर किए गए अध्यायों को छोड़ें @@ -382,7 +380,6 @@ ताचियोमी के लिए WebView आवश्यक है ओपन सोर्स लाइसेंस वेबसाइट - बाहर निकलने के लिए फिर से वापस दबाएं केवल डाउनलोड किए गए अध्याय %1$s – %2$s बैकअप बहाल करने में विफल रहा @@ -649,7 +646,6 @@ कोई स्थापित स्रोत नहीं मिला आखिरी आइटम अद्यतन अपठित गिनती - जब बैटरी कम नहीं WebView डेटा साफ हो गया गिटहब में खोलें चित्र सहेजने में त्रुटि diff --git a/i18n/src/main/res/values-hr/strings.xml b/i18n/src/main/res/values-hr/strings.xml index 1dc7fa125..227cdcc33 100644 --- a/i18n/src/main/res/values-hr/strings.xml +++ b/i18n/src/main/res/values-hr/strings.xml @@ -11,7 +11,7 @@ Ovo proširenje više nije dostupno. Možda neće ispravno funkcionirati i može uzrokovati probleme s aplikacijom. Preporučuje se deinstalacija. Ovo proširenje potpisano je nepovjerljivim certifikatom i nije aktivirano. \n -\nZlonamjerno proširenje može pročitati sve podatke za prijavu koji su spremljeni u programu Tachiyomi ili izvršiti proizvoljni kod. +\nZlonamjerno proširenje može pročitati sve spremljene podatke za prijavu ili izvršiti proizvoljni kod. \n \nVjerujući ovom certifikatu, prihvaćaš te rizike. Nepovjerljivo proširenje @@ -152,8 +152,6 @@ Filtar Izbornik Postavke - Za zatvaranje programa ponovo pritisni natrag - Otključaj Tachiyomi Povijest Praćenje Unosi u biblioteci @@ -342,7 +340,6 @@ Zadnji korišteni Drugi Lokalni izvor - Provjeri web-stranice pomoću WebView Nema rezultata Nema daljnjih rezultata Ažuriranje kategorije @@ -399,7 +396,7 @@ Dostupne su %d nove verzije proširenja Dostupno je %d novih verzija proširenja - Za Tachiyomi je potreban WebView + Za funkcioniranje programa je potreban WebView %1$d novo poglavlje %1$d nova poglavlja @@ -427,7 +424,7 @@ Sigurnosna kopija ne sadrži unose u biblioteci. Neispravna datoteka sigurnosne kopije Jednosmjerna sinkronizacija za aktualiziranje napretka poglavlja u usluzi praćenja. Postavi praćenje pojedinačnih unosa manga putem gumba za praćenje. - Ovo proširenje nije sa službenog popisa Tachiyomi proširenja. + Ovo proširenje nije iz službenog popisa. Neslužbeno Provjeri nove naslovnice i pojedinosti prilikom aktualiziranja biblioteke Automatski osvježi metapodatke @@ -677,7 +674,6 @@ Zadnja provjera aktualiziranja Rastavi visoke slike (BETA) Samo na mrežom bez ograničenja - Kad se baterija nije slaba Broj nepročitanih Izbriši kategoriju Želiš li izbrisati kategoriju „%s”\? @@ -833,4 +829,8 @@ Indeks preuzimanja poništen Nije bilo moguće stvoriti datoteku sigurnosne kopije Licencirano – Nema poglavlja za prikaz + Otključaj %s + Ne postoji veza s internetom + HTTP %d, provjeri web stranicu u WebView + Nije bilo moguće povezati se s računalom %s \ No newline at end of file diff --git a/i18n/src/main/res/values-hu/strings.xml b/i18n/src/main/res/values-hu/strings.xml index 071bdd1d5..9df1cbc82 100644 --- a/i18n/src/main/res/values-hu/strings.xml +++ b/i18n/src/main/res/values-hu/strings.xml @@ -148,8 +148,6 @@ Összes engedélyezése Kiválasztás megfordítása Menü - A befejezéshez nyomd meg újfent a Vissza gombot - Tachiyomi feloldása A könyvtárad üres Nincs új frissítés Nincs letöltés folyamatban @@ -460,7 +458,6 @@ Beállítás alapértelmezettként Tablet mód Lista elejére - Nézze meg a web oldalt WebView-ban Globális keresés \"%1$s\"-ra/re Nincs több találat Nincs találat @@ -614,7 +611,6 @@ Szűri a könyvtár összes tartalmát Hiba a fedlap megosztása közben Bezár - Ha nem alacsony az akkumulátor tözöttség Fordított álló Megállítva Olvasási lista diff --git a/i18n/src/main/res/values-in/strings.xml b/i18n/src/main/res/values-in/strings.xml index e4c7a8520..1f4824c66 100644 --- a/i18n/src/main/res/values-in/strings.xml +++ b/i18n/src/main/res/values-in/strings.xml @@ -248,11 +248,11 @@ Tidak terpercaya Lepas Ekstensi tidak terpercaya - Ekstensi ini ditanda tangani dengan sertifikat yang tidak terpercaya dan belum diaktifkan. + Ekstensi ini ditandatangani dengan sertifikat tidak tepercaya dan tidak diaktifkan. \n -\nSebuah ekstensi berbahaya dapat membaca kredensial login Anda yang tersimpan pada Tachiyomi atau mengeksekusi kode berbahaya. +\nEkstensi berbahaya dapat membaca kredensial login apa pun yang disimpan atau mengeksekusi kode arbitrer. \n -\nDengan mempercayai sertifikat ini Anda menyetujui resiko tersebut. +\nDengan mempercayai sertifikat ini, Anda menerima risiko ini. Kecepatan animasi ketukan dua kali Tanpa animasi Normal @@ -306,7 +306,6 @@ Ikuti sistem Kelola notifikasi Keamanan dan privasi - Buka Tachiyomi Menu Terbaru Terlama @@ -355,7 +354,7 @@ Sumber Pembaruan ekstensi Membaca - WebView dibutuhkan untuk Tachiyomi + WebView diperlukan agar aplikasi dapat berfungsi Terdapat %d perbaruan ekstensi @@ -366,7 +365,6 @@ Selengkapnya Di pustaka Tambahkan ke pustaka - Cek dalam WebView Lisensi terbuka Gagal memulihkan data dari cadangan Pencadangan data gagal @@ -375,7 +373,6 @@ Hilangkan tanda Tandai Pilih kebalikan - Tekan lagi untuk keluar Hanya yang sudah diunduh Tersemat Situs web @@ -404,7 +401,7 @@ Selesai dalam %1$s dengan %2$s kesalahan Sinkronisasi satu arah untuk memperbarui kemajuan bab dalam layanan pelacakan. Siapkan pelacakan untuk entri individu dari tombol pelacakan mereka. - Ekstensi ini bukan dari daftar ekstensi resmi Tachiyomi. + Ekstensi ini bukan dari daftar resmi. Tidak resmi Periksa sampul dan detail baru saat memperbarui pustaka Segarkan metadata secara otomatis @@ -640,7 +637,6 @@ Membersihkan data WebView Data WebView telah dibersihkan Tutup - Saat baterai tidak lemah Sumber yang diinstal tidak ditemukan Tidak ada sumber yang ditemukan Pembaruan terakhir @@ -801,4 +797,8 @@ Pelacak login Tidak dapat membuat file cadangan Lisensi - Tidak ada chapter untuk ditampilkan + Buka kunci %s + Tidak ada koneksi Internet + HTTP %d, periksa situs web di WebView + Tidak dapat mencapai %s \ No newline at end of file diff --git a/i18n/src/main/res/values-it/strings.xml b/i18n/src/main/res/values-it/strings.xml index a987815e5..76403f394 100644 --- a/i18n/src/main/res/values-it/strings.xml +++ b/i18n/src/main/res/values-it/strings.xml @@ -278,7 +278,7 @@ Estensione non attendibile Questa estensione è stata firmata con un certificato non attendibile e non è stata attivata. \n -\nUn\'estensione maliziosa potrebbe leggere credenziali di accesso all\'interno di Tachiyomi, o eseguire codice dannoso. +\nUn\'estensione maliziosa potrebbe leggere credenziali di accesso salvate o eseguire codice dannoso. \n \nFidandoti di questo certificato accetti questi rischi. Velocità animazioni doppio tocco @@ -362,7 +362,6 @@ Impossibile bypassare Cloudflare Per favore aggiorna l\'app WebView per una migliore compatibilità Aggiornamenti capitoli - Sblocca Tachiyomi Schermo sicuro nasconde i contenuti dell\'app quando cambi applicazione e blocca gli screenshot Visualizzazione Aggiornamenti estensione @@ -390,7 +389,6 @@ Per %d voci Cercando nuovi capitoli - Controlla il sito in WebView Indirizzo e-mail Ottimizzazione batteria già disattivata Facilita gli aggiornamenti e i backup in secondo piano @@ -425,9 +423,8 @@ Ripristino già in corso Backup fallito Il backup è già in corso - Premi indietro nuovamente per uscire Solo scaricati - È necessaria l\'app WebView per Tachiyomi + WebView è necessaria per il funzionamento dell\'app Modalità di lettura Per questa serie Guida alle fonti locali @@ -462,7 +459,7 @@ Fonti mancanti: Il backup non contiene alcuna voce di libreria. File di backup invalido - Questa estensione non è presente nella lista ufficiale delle estensioni di Tachiyomi. + Questa estensione non è dalla lista ufficiale. Non ufficiale Controlla nuove copertine e descrizioni durante l\'aggiornamento della libreria Ricarica metadati automaticamente @@ -697,7 +694,6 @@ Cancella dati WebView Dati WebView cancellati Chiudi - Quando la batteria non è scarica Nessuna fonte installata trovata Nessuna fonte trovata Conteggio non letti @@ -866,4 +862,8 @@ Login del tracking Non è stato possibile creare un file di backup Licenziato - Nessun capitolo da mostrare + HTTP %d, controlla il sito nella WebView + Nessuna connessione ad internet + %s non raggiungibile + Sblocca %s \ No newline at end of file diff --git a/i18n/src/main/res/values-ja/strings.xml b/i18n/src/main/res/values-ja/strings.xml index 32156f9e3..6041abf98 100644 --- a/i18n/src/main/res/values-ja/strings.xml +++ b/i18n/src/main/res/values-ja/strings.xml @@ -165,7 +165,7 @@ 同期 この拡張機能は信頼できない証明書でサインされているため、有効にされていません。 \n -\n悪意のある拡張機能はTachiyomiに保存されているすべてのログイン情報を読み取ることや、任意コード実行をすることができます。 +\n悪意のある拡張機能は保存されているすべてのログイン情報を読み取ることや、任意コード実行をすることができます。 \n \nこれらのリスクを受け入れ、この証明書を信頼しますか? ページ数を表示 @@ -317,7 +317,6 @@ %1$s分後 セキュア画面 - Tachiyomiのロックを解除する %1$d新しい章 @@ -325,7 +324,6 @@ 最新 ソース ローカルソース - WebViewでサイトを開く タブ メールアドレス @@ -366,7 +364,7 @@ 乗算 バンディングを軽減しますが、パフォーマンスを影響するかもしれません 画面の切り抜きエリアにも内容を表示 - この拡張機能はTachiyomiの公式拡張機能リストに含まれていません。 + この拡張機能は公式リストに含まれていません。 非公式 更新あり @@ -390,10 +388,9 @@ 全て有効にする 選択を反転 メニュー - もう一度押して終了します 章の更新 WebViewアプリを更新して互換性を向上させてください - TachiyomiはWebViewを必要としています + WebViewが必要です %d件の拡張機能の更新が利用可能 @@ -640,7 +637,6 @@ 閉じる WebViewデータを消去 WebViewデータを消去しました - バッテリー残量が十分な場合 ソースが見つかりません インストール済みのソースが見つかりません 前回の更新確認 @@ -783,7 +779,7 @@ 今日、連載更新が予想されていないためスキップしました 間隔を設定 - 実績あり + 結果あり %s の追跡を削除しますか\? 毎に評価 ごとに更新するように設定する @@ -798,4 +794,11 @@ ライブラリを同期しました Cloudflareに関するヘルプ情報はこちら ダウンロード インデックスを消去しました + バックアップ ファイルを作成できませんでした + トラッキング サービスにログイン + ライセンス制限あり—章を表示できません + HTTP %d、WebViewでこのWebサイトを確認してください + インターネット接続がありません + %sにアクセスできませんでした + %sをアンロック \ No newline at end of file diff --git a/i18n/src/main/res/values-jv/strings.xml b/i18n/src/main/res/values-jv/strings.xml index 2b4894dbc..14b9636aa 100644 --- a/i18n/src/main/res/values-jv/strings.xml +++ b/i18n/src/main/res/values-jv/strings.xml @@ -81,7 +81,6 @@ Durung kewoco Saringan Pengaturan - Mbukak Tachiyomi Sejarah Kategori Ora ono updetan anyar @@ -120,7 +119,6 @@ Kelacak Diwenehi tandha Menu - Pencet bali maneh kanggo metu Ngelacak Bab Sampeyan ora duwe kategori. Dhemok tombol tambah kanggo nggawe siji kategori kanggo ngatur perpustakaane sampeyan. @@ -260,7 +258,6 @@ Nganyari metadata otomatis Jaringan gak kebates tok Lewati updatean judul - Pas baterai ora titik Bohoso aplikasi Ekstensi iki ditandatangani nganggo sertifikat sing ora dipercaya lan ora diaktifake. \n diff --git a/i18n/src/main/res/values-ka-rGE/strings.xml b/i18n/src/main/res/values-ka-rGE/strings.xml index 0c733f0c9..11a537fe1 100644 --- a/i18n/src/main/res/values-ka-rGE/strings.xml +++ b/i18n/src/main/res/values-ka-rGE/strings.xml @@ -244,7 +244,6 @@ ჩანართები შედეგების სიის დასასრული შედეგი ვერ მოიძებნა - ვებსაიტის ნახვა WebView-ში ლოცალური წყარო სხვა ბოლოს გამოყენებული @@ -347,8 +346,6 @@ რეზერვი გავრცობები გავრცობის შესახებ - Tachiyomi-ს განბლოკვა - გასასვლელად დააჭირეთ ისევ უკან გლობალური ძებნა კატეგორიების მინიჭება ყდის რედაქტირება diff --git a/i18n/src/main/res/values-kk/strings.xml b/i18n/src/main/res/values-kk/strings.xml index 6fbad6634..58d841434 100644 --- a/i18n/src/main/res/values-kk/strings.xml +++ b/i18n/src/main/res/values-kk/strings.xml @@ -16,9 +16,7 @@ Көшу Әдепкі Ескерту - Tachiyomi-ді бұғаттан босату Өзгертуді растау үшін аутентификация өтіңіз - Шығу үшін қайтадан басыңыз Мәзір Сүзгі Бетбелгіленген @@ -50,7 +48,6 @@ Тізім Жүктелген тараулар Қолданба экранын қорғау - Батарея қуаты аз емес кезінде Қолданба кейпі Динамикалық Жасыл Алма @@ -419,7 +416,6 @@ Электрондық пошта мекенжайы Шығу Белгісіз қателік - Сайтты WebView-де тексеріңіз Дерекқорды тазалау Қателіктер туралы есептерді жіберу Сізде бекітілген дереккөздер жоқ diff --git a/i18n/src/main/res/values-km/strings.xml b/i18n/src/main/res/values-km/strings.xml index 5c3f7e44a..85cbee0ce 100644 --- a/i18n/src/main/res/values-km/strings.xml +++ b/i18n/src/main/res/values-km/strings.xml @@ -22,7 +22,6 @@ ប្រភពម៊េងហ្គា ជំនួយ លំនាំដើម - បើកតាឈិយ៉ូមិ ហ្វីលធឺ បានបញ្ចូលទៅក្នុងបណ្ណាល័យ បានដាក់ការតាមដានការអាន @@ -76,7 +75,6 @@ អ្នកពុំមានការទម្រៀបម៊េងហ្គាឡើយ។ ចុចប៊ូតុងសញ្ញាបូកដើម្បីទម្រៀបម៊េងហ្គាសម្រាប់បណ្ណាល័យរបស់អ្នក។ ម៊េងហ្គា Authenticateដើម្បីបញ្ចាក់ពីការកែប្រែ - ចុចថយម្ដងទៀតដើម្បីចេញ ការកំណត់ កន្លែងកំណត់ បញ្ចាក់ភាគមុនថាបានអាន diff --git a/i18n/src/main/res/values-kn/strings.xml b/i18n/src/main/res/values-kn/strings.xml index b6857e6d7..ed01f878f 100644 --- a/i18n/src/main/res/values-kn/strings.xml +++ b/i18n/src/main/res/values-kn/strings.xml @@ -93,8 +93,6 @@ ಸೋಸು ಸಲಹಾಕಾರ ಸಂಯೋಜನೆಗಳು - ನಿರ್ಗಮಿಸಲು ಮತ್ತೊಮ್ಮೆ ಒತ್ತಿರಿ - ತಚಿಯೋಮಿಯನ್ನು ಅನ್ಲಾಕ್ ಮಾಡಿ ಇತಿಹಾಸ ಟ್ರ್ಯಾಕಿಂಗ್ ಅಧ್ಯಾಯಗಳು @@ -363,7 +361,6 @@ ಕೊನೆಯದಾಗಿ ಉಪಯೋಗಿಸಿದ ಇತರೆ ಲೋಕಲ್ ಮೂಲ - ವೆಬ್‌ವೀಕ್ಷಣೆಯಲ್ಲಿ ವೆಬ್‌ಸೈಟ್ ಪರಿಶೀಲಿಸಿ ಯಾವುದೇ ಫಲಿತಾಂಶಗಳು ಕಂಡುಬರಲಿಲ್ಲ ಹೆಚ್ಚಿನ ಫಲಿತಾಂಶಗಳಿಲ್ಲ ವರ್ಗವನ್ನು ನವೀಕರಿಸಲಾಗುತ್ತಿದೆ diff --git a/i18n/src/main/res/values-ko/strings.xml b/i18n/src/main/res/values-ko/strings.xml index 9aa1f7d3f..f6c3e5560 100644 --- a/i18n/src/main/res/values-ko/strings.xml +++ b/i18n/src/main/res/values-ko/strings.xml @@ -292,8 +292,6 @@ 도움말 이메일 주소 웹사이트 - Tachiyomi 잠금 해제 - 뒤로 가기를 한 번 더 누르면 앱을 종료합니다 메뉴 더 보기 소스 @@ -482,7 +480,6 @@ 일부 제조사는 백그라운드 서비스를 종료하는 추가적인 제한 사항이 있습니다. 자세한 사항은 웹사이트를 참조하세요. 태블릿 UI - WebView에서 사이트 열기 핀 설정됨 \"%1$s\"를 전체 검색합니다 로컬 저장소 사용법 @@ -642,7 +639,6 @@ 마지막으로 업데이트한 날짜순 읽지 않은 항목 개수순 닫기 - 배터리가 부족하지 않을 때만 WebView 데이터 지우기 WebView 데이터 삭제됨 리더 성능 향상 diff --git a/i18n/src/main/res/values-lt/strings.xml b/i18n/src/main/res/values-lt/strings.xml index 142dfc7f1..820fc3087 100644 --- a/i18n/src/main/res/values-lt/strings.xml +++ b/i18n/src/main/res/values-lt/strings.xml @@ -3,8 +3,6 @@ Filtras Meniu Nustatymai - Paspauskite atgal, kad išeitumėte - Atrakinkite Tachiyomi Istorija Sekimas Skyriai @@ -458,7 +456,6 @@ Ištrinti viską InternalError: Patikrinkite klaidų žurnalus, kad gautumėte daugiau informacijos Kai duomenys neapmokestinami - Kai baterija nėra išsikrovusi Perkelti seriją į viršų Sekimo priemonės, neprijungtos prie: Pagerina skaitytuvo našumą @@ -609,7 +606,6 @@ Viršelis Prisegtas El. pašto adresas - Patikrinkite svetainę \"WebView\" aplinkoje Pasaulinė paieška… Naujausia Vietos šaltinių vadovas diff --git a/i18n/src/main/res/values-lv/strings.xml b/i18n/src/main/res/values-lv/strings.xml index c71d8f0dd..899565ddf 100644 --- a/i18n/src/main/res/values-lv/strings.xml +++ b/i18n/src/main/res/values-lv/strings.xml @@ -71,7 +71,7 @@ Kļūda Lejupielādētājs Lai uzlabotu saderību, lūdzu, atjauniniet WebView lietotni - Tachiyomi ir nepieciešams WebView + Lai aplikācija strādātu ir nepieciešams WebView Dublējuma atjaunošana neizdevās Dublējuma atjaunošana Atjaunošana jau notiek @@ -90,7 +90,6 @@ Dublējumā nav neviena bibliotēkas ieraksta. Paplašinājumu informācija Paplašinājumi - Atslēgt Tachijomi Abi Vertikāls Horizontāls @@ -116,7 +115,6 @@ Pievienošanas datums Jaunākā nodaļa Izvēlne - Vēlreiz nospiediet atpakaļ, lai izietu Jums nav nevienas kategorijas. Pieskarieties plus pogai, lai izveidotu kategoriju savas bibliotēkas organizēšanai. Jūsu bibliotēka ir tukša Nekas nesen lasīts @@ -131,7 +129,7 @@ Lejuplādēt Ainava Portrets - Vienumi rindā + Režģa izmērs Displejs Slēpt paziņojumu saturu Drošs ekrāns paslēpj saturu mainot lietotnes, un bloķē ekrānuzņēmumus @@ -247,7 +245,7 @@ Neuzticams paplašinājums Šis paplašinājums tika parakstīts ar neuzticamu sertifikātu, un tas netika aktivizēts. \n -\nĻaunprātīgs paplašinājums var nolasīt visus pieteikšanās akreditācijas datus, kas saglabāti Tachiyomi, vai izpildīt patvaļīgu kodu. +\nĻaunprātīgs paplašinājums var nolasīt visus saglabātos pieteikšanās akreditācijas datus vai izpildīt patvaļīgu kodu. \n \nUzticoties šim sertifikātam, jūs piekrītat šiem riskiem. Mantots @@ -280,11 +278,10 @@ Yotsuba Pilnīgi melns tumšais režīms Aplikācijas valoda - Ja akumalators nav zems Ar nelasītu(ām) nodaļu(ām) Kas nav sāktas Vienmēr jautāt - Kategorijas iestatījumi kārtošanai un rādīšanai + Kategorijas iestatījumi kārtošanai Izslēgto kategoriju ieraksti netiks atjaunināti, pat ja tie ir iekļautajās kategorijās. Neviens Iekļaut: %s @@ -295,7 +292,7 @@ Neoficiāls Neuzticams Šis paplašinājums vairs nav pieejams. Tas var nedarboties pareizi un var radīt problēmas ar lietotni. Ieteicams to atinstalēt. - Šis paplašinājums nav no oficiālo Tachiyomi paplašinājumu saraksta. + Šis paplašinājums nav no oficiālā saraksta. Sadalīt platas lapas Apvērst dalītās lapas izvietojumu Rādīt saturu izgriezuma apgabalā @@ -308,7 +305,7 @@ Ik pēc 2 dienam Ik pēc 3 dienām Tikai uz Wi-Fi - Automātisks + Auto Turēt ekrānu ieslēgtu Centrs Rotācijas tips @@ -341,7 +338,7 @@ Pelēks Atspējots Balts - Nepārtraukta vertikāle + Garā strīpā ar pārtraukumu Sānu platums Izslēgtās kategorijas Lokālais avots @@ -353,8 +350,8 @@ Mala Pa labi un pa kreisi Pa labi - No kreisās puses uz labo - Webtoon + Lapaspuses (no kreisās puses uz labo) + Garā strīpā Skāriena zonas Izstiept Ietilpt platumā @@ -364,8 +361,8 @@ Portrets Aizslēgts portreta režīmā Lasīšanas režīms - No labās puses uz kreiso - Vertikāls + Lapaspuses (no labās puses uz kreiso) + Lapaspuses (vertikāli) Bibliotēkas ieraksti Ātrs Noklusējuma rotācijas tips @@ -380,7 +377,7 @@ Izlaist filtrētās nodaļas Navigācija Invertēt skaļuma regulēšanas taustiņus - Rādīt ar ilgu pieskārienu + Rādīt darbīūbas ar ilgu pieskārienu Izveido mapes atbilstoši ieraksta nosaukumam Fona krāsa Mēroga tips @@ -409,7 +406,7 @@ Drukāt verbose žurnālus sistēmas žurnālā (samazina programmas veiktspēju) Atjaunot progresu pēc lasīšanas Izsekošanas rokasgrāmata - Saglabā avārijas žurnālu + Dalīties ar avārijas žurnālu Saglabā kļūdu žurnālus failā priekš koplietošanas ar izstrādātājiem Notīrīt nodaļas kešatmiņu Atsvaidzināt bibliotēkas vākus @@ -417,7 +414,7 @@ Nav bibliotēkas ierakstu, ko dublēt Atjaunošana atcelta Dublēšana/atjaunošana var nedarboties pareizi, ja ir atspējota MIUI Optimization. - Notīriet nodaļu kešatmiņu, aizverot lietotni + Notīriet nodaļu kešatmiņu, atverot lietotni %1$d ierakstu, kas nav bibliotēkas, ir datu bāzē Tīkls Dati @@ -482,7 +479,6 @@ Lapaspušu skats Izrakstīties Piesprausts - Pārbaudīt tīmekļa vietni šeit: WebView Citi Tagad jūs esat izrakstījies Cilnes @@ -632,9 +628,9 @@ Lietotnes atjauninājumi Ir pieejama jauna versija! Atjaunināti noklusējuma nodaļu iestatījumi - Palielināt ainavas attēlu + Automātiski tuvināt ainavas attēlus Nākošā lapa - Pieskaroties izplest platus attēlus + Izplest platus attēlus Nevar atvērt pēdējo lasīto nodaļu Pārlasīšana Vai dzēst lejupielādētās nodaļas\? @@ -703,7 +699,7 @@ Paisuma vilnis Vairāku Lejupielādēt uz priekšu - Darbojas tikai ar ierakstiem bibliotēkā un tad, ja pašreizējā un nākamā nodaļa jau ir lejupielādēta + Darbojas tikai ja pašreizējā nodaļa + nākošā nodaļa ir jau lejupielādēta. Jūsu bibliotēkā ir ieraksts ar tādu pašu nosaukumu. \n \nVai joprojām vēlaties turpināt\? @@ -745,7 +741,7 @@ Vienvirziena progresa sinhronizācija, uzlabota sinhronizācija Avoti, paplašinājumi, globālā meklēšana Tēma, datuma un laika formāti - Kategorijas, globāli atjauninājumi + Kategorijas, globāli atjauninājumi, nodaļu vilkšana Rādīt nelasīto skaitu uz atjauninājumu ikonas Logrīks nav pieejams, ja ir iespējota lietotņu bloķēšana RARv5 formāts netiek atbalstīts @@ -764,7 +760,7 @@ %1$s kļūda: %2$s Atjauninājums jau darbojas - %s radās neparedzēta kļūda. Mēs iesakām izveidot šo ziņojumu ekrānuzņēmumu, atrast avārijas žurnālu un pēc tam kopīgot to mūsu atbalsta kanālā Discord lietotnē. + %s radās neparedzēta kļūda. Mēs iesakām dalīties ar avārijas žurnālu mūsu atbalsta kanālā Discord lietotnē. Pagrieziet platas lapas, lai tās ietilptu Apvērst orientācija pagrieztām platām lapām Sadalīt augstus attēlus @@ -796,4 +792,45 @@ Globālajā atjauninājumā Kopā *obligāti + Nevarēja izveidot dublējuma failu + Lejupielādes indeks ir nederīgs + Licencēts - Nav nevienu nodaļu ko parādīt + Izlaists, jo šodien nebija gaidīta jauna nodaļa + Vilkt uz labās puses darbību + Atkļūdošanas informācija + Pieskarieties šeit, lai iegūtu palīdzību ar Cloudflare + Ir rezultāti + Noņemt arī no %s + Vilkt uz kreisās puses darbību + Novērtēt katru + Iestatīt intervālu + Pielāgots datu iegūšanas intervāls + Iegūt katru mēnesi (28 dienas) + Nokārtots pārbaudes periods + Nākamais gaidāmais atjauninājums + Pieteikšanās izsekošana + Sinhronizē bibliotēku + Bibliotēkas sinhronizācija ir pabeigta + Intervāli + + %d dienas + %d diena + %d dienas + + Šis noņems locālo izsekošanu. + Izdzēst lejupielādētos + Vai noņemt %s izsekošanu\? + OK + Ārpus paredzamā izlaišanas perioda + Dubult-pieskarieties, lai tuvinātu + %d katrā rindā + Atbloķēt %s + Par vēlu +10 pārbaudes + Pametāt\? Par vēlu +20 un 2 mēnešus + Vilkt nodaļas + Atjaunināt katru + Pielāgot intervālu + HTTP %d, pārbaudiet vietni iekš WebView + Nav interneta savienojuma + Nevarēja sasniegt %s \ No newline at end of file diff --git a/i18n/src/main/res/values-mr/strings.xml b/i18n/src/main/res/values-mr/strings.xml index a5974e747..9ae0f9de6 100644 --- a/i18n/src/main/res/values-mr/strings.xml +++ b/i18n/src/main/res/values-mr/strings.xml @@ -27,8 +27,6 @@ सामान्य मेनू बुकमार्क आहे - अॅप बंद करण्यासाठी बॅक पुन्हा दाबा - तचीयोमी उघडा ट्रॅकिंग लायब्ररी इंत्रिज श्रेण्या diff --git a/i18n/src/main/res/values-ms/strings.xml b/i18n/src/main/res/values-ms/strings.xml index 708306722..45fda159a 100644 --- a/i18n/src/main/res/values-ms/strings.xml +++ b/i18n/src/main/res/values-ms/strings.xml @@ -252,7 +252,7 @@ Sambungan tak dipercayai Sambungan ini telah ditandatangani dengan sijil tidak dipercayai dan ia tidak diaktifkan. \n -\nSambungan yang berniat jahat kemungkinan membaca sebarang kelayakan log masuk yang di simpan dalam Tachiyomi atau melaksanakan kod sesuka hati. +\nSambungan yang berniat jahat kemungkinan membaca sebarang kelayakan log masuk yang di simpan atau melaksanakan kod sesuka hati. \n \nDengan mempercayai sijil ini, anda menerima risiko tersebut. Kelajuan animasi ketik dua kali @@ -327,7 +327,6 @@ Gagal untuk memintas Cloudflare Sila kemas kini aplikasi WebView untuk keserasian yang lebih baik Pengemaskinian bab - Buka kunci Tachiyomi Skrin keselamatan menyembunyikan kandungan aplikasi apabila menukar aplikasi dan sekat tangkapan skrin Paparan @@ -358,7 +357,6 @@ %d kemas kini sambungan tersedia Kemas kini sambungan - Semak laman web dalam WebView Mengemas kini pustaka Membaca Sebaris panjang dengan sela @@ -366,7 +364,7 @@ Pilih songsang Sumber Tambahan sisi - WebView diperlukan untuk Tachiyomi + WebView diperlukan untuk aplikasi berfungsi Bab %1$s - %2$s Tambah penjejakan Tutup @@ -383,7 +381,6 @@ Sandaran sedang dijalankan Buang sematkan Sematkan - Tekan kembali sekali lagi untuk keluar Dimuat turun sahaja Terakhir digunakan Semak untuk kemas kini @@ -404,14 +401,14 @@ Selesai dalam %1$s dengan %2$s ralat - Sinkron satu hala untuk kemas kini bab kemajuan dalam sistem penjejakan. Sediakan penjejakan untuk entri individu daripada butang penjejakan mereka. + Menyelaras satu hala untuk kemas kini bab kemajuan dalam sistem penjejakan. Sediakan penjejakan untuk entri individu daripada butang penjejakan mereka. Segar semula muka hadapan pustaka Mengikut tarikh muat naik Data Tiada sumber: Sandaran tidak mengandungi apa-apa entri pustaka. Fail sandaran tidak sah - Sambungan ini bukan daripada senarai sambungan Tachiyomi yang rasmi. + Sambungan ini bukan daripada senarai yang rasmi. Tidak rasmi Semak muka hadapan dan tentang baharu bila mengemaskini pustaka Segar semula metadata secara automatik @@ -640,7 +637,6 @@ Hapus data WebView Data WebView dihapuskan Tutup - Apabila bateri tidak lemah Tiada sumber dipasang ditemui Tiada sumber ditemui Bilangan belum dibaca @@ -699,7 +695,7 @@ Kategori, Kemas kini keseluruhan, leret bab Mod membaca, paparan, navigasi Muat turun automatik, muat turun maju - Sinkron kemajuan satu hala, pertingkat sinkron + Menyelaras kemajuan satu hala, pertingkat menyelaras Manual & sandaran automatik Kumpulan log kerosakan, pengoptimuman bateri Kekunci aplikasi, skrin keselamatan @@ -784,7 +780,7 @@ %d hari - Tersuai Jarak Masa + Tersuai jarak masa Diluar jangkaan masa keluaran Anggaran setiap Melepasi tempoh semak @@ -794,4 +790,15 @@ Juga buang daripada %s Padam dimuat turun Mempunyai hasil + Tidak boleh menghasilkan fail sandaran + Berlesen - Tiada bab untuk ditayangkan + Tidak dapat mencapai %s + Menyelaraskan pustaka + Pustaka selesai diselaraskan + Tiada sambungan Internet + Log masuk penjejakan + Indeks muat turun tidak sah + Ketik di sini untuk bantuan berkenaan Cloudflare + HTTP %d, semak laman web dalam WebView + Buka kunci %s \ No newline at end of file diff --git a/i18n/src/main/res/values-nb-rNO/strings.xml b/i18n/src/main/res/values-nb-rNO/strings.xml index ff8522816..ce9561b16 100644 --- a/i18n/src/main/res/values-nb-rNO/strings.xml +++ b/i18n/src/main/res/values-nb-rNO/strings.xml @@ -323,7 +323,6 @@ Sikker skjerm Kapitteloppdateringer - Lås opp Tachiyomi Kapittel %1$s E-postadresse I biblioteket @@ -351,7 +350,6 @@ Hopp over filtrerte kapitler Skjul merknadsinnhold Sikker skjerm skjuler programinnhold ved bytting av programmer og blokker skjermavbildninger - Trykk \"Tilbake\" igjen for å avslutte Kun nedlastet Uoffisiell Lesemodus @@ -394,7 +392,6 @@ Ukjent status Ukjent forfatter Lokal kildeguide - Sjekk nettsted i WebView %1$s gjenstående %1$s gjenstående @@ -652,7 +649,6 @@ Lukk Slett WebView data WebView data slettet - Batteri er ikke lavt Vel, dette er pinlig Enveis fremdriftssynkronisering, forbedret synkronisering Kilder, utvidelser, globalt søk @@ -779,7 +775,7 @@ Mangler %1$s kapittel Mangler %1$s kapitler - Skift retning på roterte brede sider + Vend orienteringen av roterte brede sider Roter brede sider slik at de passer Debug info %d per rad @@ -814,4 +810,7 @@ Biblioteksynkronisering fullført Trykk her for å få hjelp med Cloudflare Nedlastingsindeksen er ugyldiggjort + Kunne ikke opprette en backup-fil + Lisensiert - Ingen kapitler å vise + Sporingsinnlogging \ No newline at end of file diff --git a/i18n/src/main/res/values-ne/strings.xml b/i18n/src/main/res/values-ne/strings.xml index 9c479844f..edec1498a 100644 --- a/i18n/src/main/res/values-ne/strings.xml +++ b/i18n/src/main/res/values-ne/strings.xml @@ -94,8 +94,6 @@ हालै केहि पढेको छैन हालैका कुनै अपडेट छैन डाउनलोड लाम - बाहिर निस्किन फेरि फिर्ता थिच्नुहोस् - ताचियोमी अनलक गर्नुहोस् कुनै डाउनलोडहरू छैन मद्दत एक्सटेन्शनको जानकारी @@ -473,7 +471,6 @@ कुनै परिणाम फेला परेन पिन गरिएको ग्लोबल रूपमा \"%1$s\" खोज्नुहोस् - WebView मा वेबसाइट जाँच गर्नुहोस् अज्ञात लेखक %1$s बाँकी @@ -661,7 +658,6 @@ पढ्दा स्वत: डाउनलोड गर्नुहोस् म्यानुअल र स्वचालित ब्याकअप एप लक, सुरक्षित स्क्रिन - जब ब्याट्री कम छैन अग्लो छविहरू विभाजित गर्नुहोस् (BETA) थुप्रै अपडेटहरू आइकनमा नपढिएको गणना देखाउनुहोस् @@ -817,4 +813,7 @@ ट्र्याकिङ लगइन ब्याकअप फाइल सिर्जना गर्न असफल भयो लाइसेन्स प्राप्त - देखाउन को लागि कुनै अध्याय छैन + इन्टरनेट जडान छैन + %s मा पुग्न सकिएन + HTTP %d, WebView मा वेबसाइट जाँच गर्नुहोस् \ No newline at end of file diff --git a/i18n/src/main/res/values-nl/strings.xml b/i18n/src/main/res/values-nl/strings.xml index fbde722b2..06ea1cc29 100644 --- a/i18n/src/main/res/values-nl/strings.xml +++ b/i18n/src/main/res/values-nl/strings.xml @@ -327,7 +327,6 @@ Kon Cloudflare niet omzeilen Gelieve de WebView-app bij te werken voor betere compatibiliteit Hoofdstukupdates - Ontgrendel Tachiyomi Veilig scherm modus verbergt de inhoud van de app bij het wisselen en blokkeert schermafbeeldingen Weergave Verplaats naar beneden @@ -337,7 +336,6 @@ Vastpinnen Bronnen Selectie omkeren - Druk nogmaals op terug om te verlaten Herstellen geannuleerd Herstellen mislukt Er wordt al een back-up hersteld @@ -373,7 +371,6 @@ Hulp bij lokale bronnen Vastgepind Laatst gebruikt - Bekijk website in WebView E-mailadres %1$s resterend @@ -668,7 +665,6 @@ Classificatie per leeftijd Grote afbeeldingen splitsen (BETA) Versie - Wanneer de batterij niet leeg is Taal van de applicatie Geen bibliotheek inzendingen om te backuppen Ongelezen aantal @@ -747,4 +743,78 @@ Dit gaat je eerder geselcteerde startdatum %s verwijderen Download verwijderen Overgeslagen omdat serie geen updates vereist. + %s is een onverwachte fout tegengekomen. We raden u aan de crashlogboeken te delen in ons ondersteuningskanaal op Discord. + Foutopsporingsinformatie + Voltooide titels + Buiten verwachte vrijgave periode + Interval instellen + Aangepast ophaalinterval + Maandelijks ophalen (28 dagen) + Controleperiode overschreden + Volgende verwachte update + Splits hoge afbeeldingen + Gelicenseerd - Geen hoofdstukken te laten zien + Draairichting van geroteerde brede pagina\'s omdraaien + Dubbeltik om te zoomen + Log-in volgen + Bibliotheek synchroniseren + Heeft resultaten + Dit zal jouw eerder geselecteerde einddatum weg halen van %s + Dit zal de tracking lokaal verwijderen. + Haal ook weg van %s + Overlay + Overzicht + Leesduur + Schat elke + Herstart de applicatie + Interval aanpassen + Download Index geïnvalideerd + + + + + Maak de downloadindex ongeldig + + + + + OK + Swipe naar de linker actie + Intervallen + Haal %s tracking weg\? + Ontgrendel %s + Swipe naar de juiste actie + %d per rij + Hoofdstuk veeg + Roteer brede pagina\'s zodat ze passen + Kon een backup-bestand niet creëren + Bibliotheeksynchronisatie beëindigd + Trackers + Overgeslagen omdat geen uitgave is verwacht vandaag + *vereist + Totaal + Late 10+ controle + Gevallen\? Late 20+ en 2 maanden + Lees + Gevolgde titels + Gemiddelde score + %du + U staat op het punt om \"%s\" te verwijderen uit uw bibliotheek + %ds + Kon bestandspad van pagina %d niet vinden + Titels + Open op GitHub + Geen titels gevonden in deze categorie + Geen internet verbinding + Kon niet %s bereiken + Gebruikt + N.v.t + Stel in om te updaten iedere + Tik hier voor hulp met Cloudflare + %dd + Category is leeg + %dm + Er is een nieuwe versie beschikbaar van de officiële uitgavens. Tik om te leren hoe u kunt migreren vanuit niet-officiële F-Droid-releases. + HTTP %d, check website in WebView + In globale update \ No newline at end of file diff --git a/i18n/src/main/res/values-nn/strings.xml b/i18n/src/main/res/values-nn/strings.xml index 56824eeff..ece30340f 100644 --- a/i18n/src/main/res/values-nn/strings.xml +++ b/i18n/src/main/res/values-nn/strings.xml @@ -12,7 +12,6 @@ Historikk Standard Åtvaring - Lås opp Tachiyomi Autentiser for å stadfesta endring Filter Bokmerket @@ -87,7 +86,6 @@ Ingen nylege oppdateringar Bibliotek Kjelder - Trykk tilbake igjen for å avslutta Innstillingar Meny Sett kategoriar @@ -267,7 +265,6 @@ Manglande kjelder: Sporingstenester ikkje logga inn i: Nokre produsentar har ytterlegare appavgrensingar som drep bakgrunnstenester. Denne nettstaden har meir info om korleis det kan fiksast. - Sjekk nettstad i WebView Nettstaden Sorter etter Dato diff --git a/i18n/src/main/res/values-pl/strings.xml b/i18n/src/main/res/values-pl/strings.xml index c0b03e021..e208a925c 100644 --- a/i18n/src/main/res/values-pl/strings.xml +++ b/i18n/src/main/res/values-pl/strings.xml @@ -8,7 +8,7 @@ Kolejka pobierania Historia Ustawienia - Filtrowanie + Filtry Nieprzeczytane Szukaj Zaznacz wszystko @@ -16,7 +16,7 @@ Aktualizacje Kopia zapasowa i przywracanie Zakładki - Usuń filtrowanie + Usuń filtr Ostatnio czytane Oznacz jako przeczytane Oznacz jako nieprzeczytane @@ -138,7 +138,7 @@ Od lewej do prawej Od prawej do lewej Pionowy - Web-komiks + Długi pasek Domyślny styl czytania Dopasuj do ekranu Rozciągnij @@ -261,7 +261,7 @@ Niezaufane rozszerzenie To rozszerzenie było podpisane niezaufanym certyfikatem i nie zostało aktywowane. \n -\nZłośliwe rozszerzenie może odczytać dane logowania przechowywane w Tachiyomi albo uruchomić złośliwy kod. +\nZłośliwe rozszerzenie może odczytać dane logowania albo uruchomić złośliwy kod. \n \nUfając temu rozszerzeniu akceptujesz to zagrożenie. Zaznacz dane do zawarcia @@ -282,7 +282,7 @@ Otwórz używając WebView Kolor 32-bitowy Pomiń rozdziały ozn. jako przeczytane - Pokaż po przytrzymaniu + Pokaż akcje po przytrzymaniu Tryb mieszania kolorów Nakładka Pomnożenie @@ -338,14 +338,12 @@ Odwróć zaznaczenie Ostatni rozdział Menu - Odblokuj Tachiyomi Źródła Rozdział %1$s Aktualizowanie biblioteki Dla tej serii Mniej Dodaj do biblioteki - Sprawdź stronę w WebView Adres e-mail Filtruje wszystkie pozycje w twojej bibliotece Tylko pobrane @@ -372,7 +370,6 @@ Ukryj ekran Odepnij Przypnij - Wciśnij wstecz ponownie, aby wyjść Więcej Rozdz. %1$s - %2$s W bibliotece @@ -380,7 +377,7 @@ Ostatnio używane Przesyłanie postępu czytania do zewnętrznego serwisu. Ustaw śledzenie guzikiem \"Śledzenie\" w wybranych tytułach. Aktualizacje rozszerzeń - WebView jest wymagany do poprawnego działania Tachiyomi + WebView jest wymagany do poprawnego działania aplikacji Dostępna aktualizacja rozszerzenia Dostępne %d aktualizacje rozszerzeń @@ -430,7 +427,7 @@ Wykonano w %1$s z %2$s błędami Czytane - Te rozszerzenie nie jest na liście oficjalnych rozszerzeń Tachiyomi. + Te rozszerzenie nie jest na liście oficjalnych rozszerzeń. Nieoficjalne Po dacie dodania Dane @@ -562,7 +559,7 @@ Źródło nie jest wspierane Nieprzeczytane Orientacja ekranu - Automatyczne + Automatycznie Utwórz foldery względem tytułu Zapisz strony do osobnych folderów Akcje @@ -655,7 +652,7 @@ Posiada nieprzeczytane rozdziały FAQ i poradniki Brak przeczytanych rozdziałów - Przybliżaj poziome obrazy + Automatycznie przybliżaj poziome obrazy Pokaż Przesuń szeroki obraz Siatka z samych okładek @@ -691,7 +688,6 @@ Nie znaleziono źródła Nie znaleziono zainstalowanego źródła Cóż, to troszkę niezręczne - Kiedy poziom baterii nie jest niski Język Lista czytanych Nowa wersja jest dostępna z oficjalnych wydań. Naciśnij, by dowiedzieć się jak przeprowadzić migrację z nieoficjalnych wydań F-Droid. @@ -827,4 +823,20 @@ %d dni Synchronizowanie biblioteki + Nie można wykonać kopi zapasowej + Interwały + Usuń też z %s + HTTP %d, otwórz w WebView + Brak połączenia z internetem + Nie można połączyć się z %s + Przestań śledzić %s\? + Usuń pobrane + Synchronizacja biblioteki zakończona + Indeksy pobrań unieważnione + Naciśnij tutaj aby uzyskać pomoc dotyczącą Cloudflare + Odblokuj %s + Dostosowany interwał aktualizacji + W miesiącu (28 dni) + OK + To usunie śledzenie lokalne. \ No newline at end of file diff --git a/i18n/src/main/res/values-pt-rBR/strings.xml b/i18n/src/main/res/values-pt-rBR/strings.xml index 51217f683..3b7f69478 100644 --- a/i18n/src/main/res/values-pt-rBR/strings.xml +++ b/i18n/src/main/res/values-pt-rBR/strings.xml @@ -252,7 +252,7 @@ Extensão não confiável Esta extensão foi assinada com um certificado não confiável e não foi ativada. \n -\nUma extensão maliciosa poderia ler quaisquer credenciais de login armazenadas no Tachiyomi ou executar códigos arbitrários. +\nUma extensão maliciosa poderia ler quaisquer credenciais de login armazenadas ou executar códigos arbitrários. \n \nAo confiar neste certificado, você estará aceitando estes riscos. Velocidade da animação do toque duplo @@ -329,7 +329,6 @@ Falha ao contornar o Cloudflare Por favor, atualize o aplicativo de WebView para uma melhor compatibilidade Atualizações de capítulos - Desbloquear o Tachiyomi A tela segura oculta os conteúdos do aplicativo durante a troca de aplicativos e impede capturas de tela Visualização @@ -360,7 +359,7 @@ Menu Mais novos Mais antigos - Mover para o topo + Mover para o começo Mover para o final Atualização de extensão disponível @@ -368,7 +367,6 @@ %d atualizações de extensão disponíveis Atualizações de extensões - Verifique o site na WebView Atualizando a biblioteca Leitura Pular os capítulos filtrados @@ -384,8 +382,7 @@ Na biblioteca Menos Mais - Pressione voltar novamente para sair - A WebView é necessária para o Tachiyomi + A WebView é necessária para o funcionamento do app Licenças de código aberto Site Somente disponíveis offline @@ -422,7 +419,7 @@ Sincronização unidirecional para atualizar o progresso dos capítulos nos serviços de monitoramento. Configure o monitoramento para itens individuais a partir de seus botões de monitoramento. Atualizar as capas da biblioteca - Esta extensão não é da lista oficial de extensões do Tachiyomi. + Esta extensão não é da lista oficial. Não oficial Pela data de envio Dados @@ -655,7 +652,7 @@ %1$d atualização(ões) falhou(aram) Toque para saber mais Retrato invertido - Mover série para o topo + Mover série para o começo Desativado Uma nova versão está disponível nos releases oficiais. Toque para saber como migrar dos releases não oficiais do F-Droid. Erro ao salvar a imagem @@ -664,7 +661,6 @@ Limpar os dados da WebView Dados da WebView limpos Fechar - Quando a bateria não está fraca Nenhuma fonte instalada foi encontrada Nenhuma fonte encontrada Contagem de não lidos @@ -833,4 +829,9 @@ Login do monitoramento Não foi possível criar o arquivo do backup Licenciado - Nenhum capítulo para mostrar + HTTP %d, verifique o site na WebView + Sem conexão de internet + Não foi possível resolver %s + Desbloquear o %s + Mover série para o final \ No newline at end of file diff --git a/i18n/src/main/res/values-pt/strings.xml b/i18n/src/main/res/values-pt/strings.xml index 8ef841c58..f0a0dd8e5 100644 --- a/i18n/src/main/res/values-pt/strings.xml +++ b/i18n/src/main/res/values-pt/strings.xml @@ -359,7 +359,6 @@ Falha ao contornar o Cloudflare Por favor, atualize a app de WebView para melhor compatibilidade Atualizações de capítulos - Desbloquear o Tachiyomi Ecrã seguro esconde os conteúdos da app durante a troca de apps e impedir capturas de ecrã Visualização Capítulo %1$s e %2$d mais @@ -400,7 +399,6 @@ Atualizando biblioteca Fixado - Verifique o sítio web no WebView Preenchimento lateral Lendo Página longa com espaços @@ -415,7 +413,6 @@ Restauro já em progresso Cópia de segurança falhou Cópia de segurança já em progresso - Pressione novamente para sair Apenas transferidos WebView é necessária para Tachiyomi Cap. %1$s - %2$s @@ -676,7 +673,6 @@ Desativado Grelha apenas de capas Fechar - Quando a bateria não está fraca Mover séries para o topo Ignorado porque a séria está completa Ignorado porque nenhum capítulo foi lido @@ -847,4 +843,5 @@ Próxima atualização esperada Definido para atualizar a cada Pulado, pois nenhum lançamento é esperado para hoje + Deletar dowloand \ No newline at end of file diff --git a/i18n/src/main/res/values-ro/strings.xml b/i18n/src/main/res/values-ro/strings.xml index d004233c4..1fa29539a 100644 --- a/i18n/src/main/res/values-ro/strings.xml +++ b/i18n/src/main/res/values-ro/strings.xml @@ -314,7 +314,6 @@ Gestionați notificările Securitate Necesită deblocare - Deblochează Tachiyomi Ultimul capitol Blocați când este inactiv Întotdeauna @@ -368,7 +367,6 @@ %d actualizări de extensii sunt disponibile %d actualizări de extensii sunt disponibile - Verificați site-ul în WebView Se actualizează biblioteca Citind Săriți peste capitolele filtrate @@ -390,7 +388,6 @@ Pagină web Restaurarea copiei de rezervă a eșuat Crearea copiei de rezervă a eșuat - Apăsați din nou pentru a ieși Doar descărcate Restaurare anulată Restaurarea este deja în curs de desfășurare @@ -605,7 +602,6 @@ Ar trebui să păstrați copii ale backupurilor și în alte locuri. Îmbunătățește performanța cititorului Închide - Când bateria nu este scăzută Azi Listă de citit Lista de dorințe diff --git a/i18n/src/main/res/values-ru/strings.xml b/i18n/src/main/res/values-ru/strings.xml index 749bcea86..e8c850ca3 100644 --- a/i18n/src/main/res/values-ru/strings.xml +++ b/i18n/src/main/res/values-ru/strings.xml @@ -251,7 +251,7 @@ Ненадёжное расширение Это расширение было подписано ненадёжным сертификатом и не было активировано. \n -\nВредоносное расширение может считывать любые учетные данные для входа, хранящиеся в Tachiyomi, или выполнять произвольный код. +\nВредоносное расширение может считывать и хранить любые учётные данные для входа или выполнять произвольный код. \n \nДоверяя этому сертификату, вы принимаете эти риски. Скорость анимации при двойном нажатии @@ -354,7 +354,6 @@ Проверка наличия новых глав Обновление библиотеки - Проверить сайт в WebView Оптимизация батареи уже выключена Помогает с обновлением библиотеки и резервной копией в фоне Отключить оптимизацию батареи @@ -373,7 +372,6 @@ В начало В конец Обновления расширений - Разблокировать Tachiyomi Меню Источники Чтение @@ -385,9 +383,8 @@ Открепить Закрепить Добавить отслеживание - Нажмите ещё раз, чтобы выйти Только загруженные главы - Для Tachiyomi необходим WebView + Для работы приложения необходимо WebView Меньше Больше В библиотеке @@ -430,7 +427,7 @@ Выполнено за %1$s с %2$s ошибками Односторонняя синхронизация для обновления прогресса в сервисах отслеживания. Настройте отслеживание при помощи кнопки «Отслеживание». - Это расширение не входит в официальный список расширений Tachiyomi. + Это расширение не входит в официальный список расширений. Неофициальное Дата добавления Данные @@ -676,7 +673,6 @@ Данные WebView очищены Очистить данные WebView Закрыть - Когда батарея заряжена Не найдено установленных источников Не найдено источников Последняя проверка обновления @@ -825,7 +821,7 @@ Настроить интервал Задать интервал Проверка поздних 10+ дней - Прошедшая проверка периода + Срок проверки истёк Следующее ожидамое обновление За пределами ожидаемого периода выпуска Задать обновления каждые @@ -837,7 +833,7 @@ Пропущено, т.к сегодня не ожидается выпуска Удалить отслеживание %s\? - Это удалит отслеживание локально. + Это удалит отслеживание в приложении. Также удалить из %s ОК Удалить загруженное @@ -847,6 +843,10 @@ Нажмите здесь, чтобы получить помощь с Cloudflare Индекс загрузок недействителен Не удалось создать файл резервной копии - Лицензировано - Нет глав для показа + Лицензировано - Нет глав Вход в сервис отслеживания + HTTP %d, проверьте сайт в WebView + Нет подключения к интернету + Не удалось достичь %s + Разблокировать %s \ No newline at end of file diff --git a/i18n/src/main/res/values-sa/strings.xml b/i18n/src/main/res/values-sa/strings.xml index f38bd56e4..25834e3e2 100644 --- a/i18n/src/main/res/values-sa/strings.xml +++ b/i18n/src/main/res/values-sa/strings.xml @@ -17,12 +17,10 @@ चरित्रम् मूलानि प्राथमिकम् - ताचियोमिम् उद्घाटयतु ग्रन्थालयः प्रतिलेखनं प्रतिसंस्कारं च पूर्वसूचना परिवर्तनं दृढीकर्तुं प्रमाणीकरोतु - निष्क्रमितुं पृष्ठगण्डं पुनः नोदयतु सूचिः शोधकम् पुटचिह्नं कृतानि @@ -555,7 +553,6 @@ \"%1$s\" कृते सार्वत्रिकेण अवेक्षताम् %1$s प्रति अन्तर्गच्छतु %1$s इतः बहिर्गच्छानि किम् - जालस्थानं वेबव्यू-तन्त्रांशे मार्गतु मूलं न प्रतिष्ठापितम् - %1$s माङ्गां ग्रन्थालये योजयानि किम् मुखचित्रनवीकरणम् अनुत्तीर्णम् diff --git a/i18n/src/main/res/values-sah/strings.xml b/i18n/src/main/res/values-sah/strings.xml index f1494aa88..486d9d40e 100644 --- a/i18n/src/main/res/values-sah/strings.xml +++ b/i18n/src/main/res/values-sah/strings.xml @@ -27,8 +27,6 @@ Биилтирэ Талба Түстэл - Өссө биирдэ төттөрүнү баттаан, тахсар курдук - Тachiyomi арыйыыта История Кэтээһин Түһүмэхтэр @@ -300,7 +298,6 @@ Бүтэһигинэн туттуллубут Атыттар Локальнай төрүт - Үөп сири WebView\'га көрүн Түмүк суох Эбии түмүк суох Кыбытыктар diff --git a/i18n/src/main/res/values-sc/strings.xml b/i18n/src/main/res/values-sc/strings.xml index 2391ca825..8d4b42c45 100644 --- a/i18n/src/main/res/values-sc/strings.xml +++ b/i18n/src/main/res/values-sc/strings.xml @@ -328,7 +328,6 @@ Isfrancamentu de Cloudflare fallidu Agiorna s\'aplicatzione de WebView pro otènnere una cumpatibilidade prus manna Agiornamentos de sos capìtulos - Isbloca Tachiyomi S\'ischermu seguru cuat sos cuntenutos de s\'aplicatzione cando mudas de aplicatzione e blocat sas ischermadas Visualizatzione @@ -363,7 +362,6 @@ B\'ant agiornamentos disponìbiles pro %d estensiones Agiornamentos de sas estensiones - Verìfica su situ web cun WebView Agiornende sa biblioteca Leghende Brinca sos capìtulos filtrados @@ -382,7 +380,6 @@ Pro Tachiyomi b\'at bisòngiu de WebView Litzèntzias a còdighe abertu Situ web - Incarca in segus torra pro essire Iscarrigados ebbia Cap. %1$s - %2$s Ùrtima impreada @@ -652,7 +649,6 @@ Isbòida sos datos de WebView Datos de WebView isboidados Serra - Cando sa bateria no est bassa Ùrtimu agiornamentu Contu de non lèghidos Peruna fonte agatada diff --git a/i18n/src/main/res/values-sdh/strings.xml b/i18n/src/main/res/values-sdh/strings.xml index 5bc6ac7ee..65edfe421 100644 --- a/i18n/src/main/res/values-sdh/strings.xml +++ b/i18n/src/main/res/values-sdh/strings.xml @@ -7,7 +7,6 @@ سازکارییەکان لیستی داونلۆد تۆماری ڕابردوو - بکەرەوەTachiyomi دڵنیابوونەوە تا گۆڕانکاری بکرێت ئاماژەکردنی پێشوو وەک خوێندراو نیشانکردنی چاپتەر @@ -51,7 +50,6 @@ داونلۆد هیچ کاتیگۆرییەکت نییە. دەست بنێ بە دوگمەی زیادە تا کاتیگۆرییەک بۆ ڕێکخستنی تۆماری ڕابردووت درووست بکەیت. سڕینەوە - دووبارە گەڕانەوە بکە بۆ چوونە دەرەوە هێج نوێکارییەک نییە لەم دواییانەدا سەرچاوەکان هیچ مانگایەکت لەم دواییانە نەخوێندووەتەوە diff --git a/i18n/src/main/res/values-sk/strings.xml b/i18n/src/main/res/values-sk/strings.xml index 95a4fd998..699246092 100644 --- a/i18n/src/main/res/values-sk/strings.xml +++ b/i18n/src/main/res/values-sk/strings.xml @@ -301,7 +301,6 @@ Najnovšia kapitola Zobraziť kapitoly Zrušiť všetky - Odomknúť Tachiyomi Menu Najnovšie Najstaršie @@ -323,7 +322,6 @@ Hľadať v nastaveniach Dátum pridaný Dátum načítania kapitoly - Stlačte tlačidlo späť znova pre ukončenie Prihlásiť sa pre potvrdenie zmien Predvolené Zdroje @@ -453,7 +451,6 @@ Čo je nové Pomôžte s prekladom Licencia Open Source - Skontrolujte webovú stránku vo WebView Chyba pri zdieľaní obalu %d sledovač @@ -612,7 +609,6 @@ Kapitoly %1$s a %2$d ďalšie Kapitoly %1$s a %2$d ďalších - Keď batéria nie je vybitá Typ rotácie Zatvoriť Záznamy vo vylúčených kategóriách nebudú aktualizované, aj keď sú tiež v zahrnutých kategóriách. diff --git a/i18n/src/main/res/values-sq/strings.xml b/i18n/src/main/res/values-sq/strings.xml index 6476ad2ca..f992c611b 100644 --- a/i18n/src/main/res/values-sq/strings.xml +++ b/i18n/src/main/res/values-sq/strings.xml @@ -116,11 +116,9 @@ Sipas alfabetit Totali i kapitujve Paralajmërim - Zhblloko Tachiyomi Totali i hyrjeve Leximi i fundit Vërtetoni për të konfirmuar ndryshimin - Shtypni përsëri për të dalë Menuja Filtro Sipas numrit të kapitullit @@ -184,7 +182,6 @@ Ekrani i sigurt fsheh përmbajtjen e aplikacionit kur ndërron aplikacionet dhe bllokon screenshots Kjo nuk parandalon shtesat jozyrtare ose potencialisht të shënuara gabimisht që të shfaqin përmbajtjen NSFW (18+) brenda aplikacionit. Portret - Kur bateria nuk është e ulët Kufizimet: %s Përditësimet automatike Çdo 6 orë @@ -595,7 +592,6 @@ Kapitujt e shkarkuar Skedat Nuk ka më rezultate - Kontrolloni faqen e internetit në WebView Burimi lokal Tjetër Fiksuar diff --git a/i18n/src/main/res/values-sr/strings.xml b/i18n/src/main/res/values-sr/strings.xml index ec19957dd..0a66772ff 100644 --- a/i18n/src/main/res/values-sr/strings.xml +++ b/i18n/src/main/res/values-sr/strings.xml @@ -97,11 +97,11 @@ Неповерљиво Обриши Неповерљив додатак - Овај додатак је потписан са неповерљивим сертификатом и није активиран. + Овај додатак је потписан са непоузданим сертификатом и није активиран. \n -\nЗлонамерни додатак може прочитати све податке за пријаву који су спремљени у програму Тachiyomi или извршити произвољни код. +\nЗлонамерни додатак може прочитати све податке за пријаву или извршити произвољни код. \n -\nВерујући овом сертификату, прихваташ те ризике. +\nВерујући овом сертификату прихватате ове ризике. Цео екран Анимације при промени странице Брзина анимације двоклика @@ -257,7 +257,6 @@ Безбедносни екран Ажурирања на чекању - Откључај Tachiyomi Прикажи Сакриј обавештења Искључи оптимизацију коришћења батерије @@ -279,7 +278,6 @@ Закачи Изабери обрнуто Мени - Притисните поново назад да бисте изашли Само преузето Немате категорија. Додирните дугме плус да бисте направили нову категорију за организовање колекције. Поглавља %1$s @@ -344,7 +342,6 @@ Водич за локалне изворе Закачено Последње коришћено - Провери вебсајт у WebView Филтрира све наслове у колекцији Провери ажурирања Sajt @@ -365,7 +362,7 @@ Грешка Преузимања Ажурирајте WebView за бољу компатибилност - За Tachiyomi је потребан WebView + WebView је потребан како би апликација функционисала Неуспешно заобилажење Cloudflare-а Доступно је %d ново ажурирање додатака @@ -395,7 +392,7 @@ Прикажи начин читања Може садржати садржај за одрасле (18+) 18+ - Овај додатак није из званичне листе Таchiyomi додатака. + Овај додатак није из званичне листе. Незванично %d категорија @@ -662,7 +659,6 @@ Отвори на GitHub-у Грешка при чувању слике Затвори - Батерија није празна Обриши податке WebView-a Подаци WebView-a су обрисани Категорије, глобално ажурирање, листање поглавља @@ -833,4 +829,8 @@ Следеће очекивано ажурирање Синхронизовање колекције Месечно преузимање (28 дана) + Откључај %s + Нема везе са интернетом + HTTP %d, погледај веб сајт у WebView + %s је недоступан \ No newline at end of file diff --git a/i18n/src/main/res/values-sv/strings.xml b/i18n/src/main/res/values-sv/strings.xml index 4e37b056e..509b508f9 100644 --- a/i18n/src/main/res/values-sv/strings.xml +++ b/i18n/src/main/res/values-sv/strings.xml @@ -99,7 +99,7 @@ Opålitlig extension Detta tillägg tecknades med ett otillförlitligt certifikat och var inte aktiverat. \n -\nEtt skadligt tillägg kan läsa inloggningsuppgifter som är lagrade i Tachiyomi eller utföra godtycklig kod. +\nEtt skadligt tillägg kan läsa lagrade inloggningsuppgifter eller utföra godtycklig kod. \n \nGenom att lita på detta certifikat accepterar du dessa risker. Fullskärm @@ -328,7 +328,6 @@ Det gick inte att kringgå Cloudflare Uppdatera WebView-appen för bättre kompatibilitet Kapiteluppdateringar - Lås upp Tachiyomi Säker skärm döljer appinnehållet när du byter app och blockerar skärmdumpar Skärmvisning @@ -364,7 +363,6 @@ %d tilläggsuppdateringar tillgängliga Uppdaterar biblioteket - Kontrollera webbplatsen i WebView Läser Hoppa över filtrerade kapitel Källor @@ -379,8 +377,7 @@ Välj omvänd Mindre Mer - Tryck tillbaka igen för att gå ur - WebView krävs för Tachiyomi + WebView krävs för att appen ska fungera Kapitel %1$s - %2$s Lokal källa guide Senast använd @@ -419,7 +416,7 @@ Saknade källor: Säkerhetskopian innehåller inga biblioteksposter. Ogiltig säkerhetskopia - Detta tillägg kommer inte från den officiella Tachiyomi-tilläggslistan. + Detta tillägg är inte från den officiella listan. Inofficiell Sök efter nytt omslag och detaljer när du uppdaterar biblioteket Uppdatera metadata automatiskt @@ -649,7 +646,6 @@ En ny version finns tillgänglig i de officiella utgåvorna. Tryck på för att lära dig hur du flyttar från inofficiella F-Droid-versioner. Inga biblioteksposter att säkerhetskopiera Öppna på GitHub - När batteriet inte är lågt Rensa data från WebView WebView-data rensas Stäng @@ -817,4 +813,8 @@ Kunde inte skapa en backup-fil Licensierad - Inga kapitel att visa Spårning av inloggning + Ingen internet anslutning + HTTP %d, kolla på webbsida i WebView + Kunde inte nå %s + Lås upp %s \ No newline at end of file diff --git a/i18n/src/main/res/values-te/strings.xml b/i18n/src/main/res/values-te/strings.xml index 633a47469..1ee8a80af 100644 --- a/i18n/src/main/res/values-te/strings.xml +++ b/i18n/src/main/res/values-te/strings.xml @@ -45,8 +45,6 @@ శోధకము వివరాలపట్టిక అమరికలు - నిష్క్రమించడానికి బ్యాక్ చిహ్నాన్ని మళ్ళీ నొక్కండి - టచియోమిని తెరవండి చరిత్ర కంట కనిపెట్టుట అధ్యాయాలు diff --git a/i18n/src/main/res/values-th/strings.xml b/i18n/src/main/res/values-th/strings.xml index 511635a60..c6550e937 100644 --- a/i18n/src/main/res/values-th/strings.xml +++ b/i18n/src/main/res/values-th/strings.xml @@ -104,7 +104,7 @@ ส่วนขยายที่ไม่น่าเชื่อถือ ส่วนขยายนี้ลงนามด้วยใบรับรองที่ไม่น่าเชื่อถือและจะไม่ถูกเปิดใช้งาน \n -\nส่วนขยายที่เป็นอันตรายสามารถอ่านข้อมูลการเข้าสู่ระบบที่จัดเก็บไว้ใน Tachiyomi หรือเรียกใช้โค้ดโดยอำเภอใจ +\nส่วนขยายที่เป็นอันตรายสามารถอ่านข้อมูลการเข้าสู่ระบบที่จัดเก็บไว้ หรือเรียกใช้โค้ดโดยอำเภอใจ \n \nการเชื่อถือใบรับรองนี้แสดงว่าคุณยอมรับความเสี่ยงเหล่านี้ เต็มหน้าจอ @@ -325,7 +325,7 @@ แสดงตำแหน่งโซนการแตะ แหล่งที่มาจากส่วนขยายนี้อาจมีเนื้อหา NSFW (18+) 18+ - ส่วนขยายนี้ไม่ได้มาจากรายการส่วนขยายทางการของ Tachiyomi + ส่วนขยายนี้ไม่ได้มาจากรายการทางการ ส่วนขยายนี้ไม่สามารถใช้ได้อีกต่อไป แอปอาจทำงานไม่ถูกต้องและอาจทำให้เกิดปัญหากับแอปได้ ขอแนะนำให้ถอนการติดตั้งออก ไม่เป็นทางการ ล้าสมัย @@ -395,8 +395,6 @@ ตอนล่าสุด ติดตามแล้ว เมนู - กดกลับอีกครั้งเพื่อออก - ปลดล็อก Tachiyomi แหล่งที่มา เพิ่มเติม ช่องว่างด้านข้าง @@ -451,7 +449,6 @@ ค้นหา \"%1$s\" ในทั้งหมด ที่ตรึงไว้ ใช้ล่าสุด - ตรวจสอบเว็บไซต์ใน WebView แท็บ ตอนที่ดาวน์โหลดแล้ว จากคลัง @@ -526,7 +523,7 @@ ความคืบหน้า อัปเดตการตั้งค่าตอนเริ่มต้นแล้ว โปรดอัปเดตแอพ WebView เพื่อความเข้ากันได้ที่ดีขึ้น - Tachiyomi จำเป็นต้องใช้ WebView + แอปจำเป็นต้องใช้ WebView เพื่อให้ทำงานได้ ไม่สามารถเลี่ยงผ่าน Cloudflare ได้ มีการอัปเดตส่วนขยาย %d รายการพร้อมใช้งาน @@ -640,7 +637,6 @@ ปิด ล้างข้อมูล WebView ล้างข้อมูล WebView แล้ว - ขณะแบตเตอรี่ยังไม่ต่ำ ไม่พบแหล่งที่มาที่ติดตั้งแล้ว ไม่พบแหล่งที่มาใด ๆ จำนวนตอนที่ยังไม่ได้อ่าน @@ -801,4 +797,8 @@ ไม่สามารถสร้างไฟล์สำรองข้อมูล มีลิขสิทธิ์แล้ว - ไม่มีตอนให้แสดง เข้าสู่ระบบการติดตาม + ปลดล็อก %s + ไม่มีการเชื่อมต่ออินเทอร์เน็ต + HTTP %d, ดูเว็บไซต์ใน WebView + ไม่สามารถเข้าถึง %s ได้ \ No newline at end of file diff --git a/i18n/src/main/res/values-tr/strings.xml b/i18n/src/main/res/values-tr/strings.xml index 4739c4b25..e2cfd0824 100644 --- a/i18n/src/main/res/values-tr/strings.xml +++ b/i18n/src/main/res/values-tr/strings.xml @@ -99,7 +99,7 @@ Güvenilmeyen uzantı Bu uzantı güvenilmeyen bir sertifika ile imzalanmış ve etkinleştirilmedi. \n -\nKötü niyetli bir uzantı, Tachiyomi\'de saklanan her giriş kimlik bilgisini okuyabilir veya rastgele kod yürütebilir. +\nKötü niyetli bir uzantı, saklanan her giriş kimlik bilgisini okuyabilir veya rastgele kod yürütebilir. \n \nBu sertifikaya güvenerek bu riskleri kabul etmiş oluyorsunuz. Tam Ekran @@ -328,7 +328,6 @@ Cloudflare baypas edilemedi Daha iyi uyumluluk için lütfen WebView\'i güncelleyin Bölüm güncellemeleri - Tachiyomi\'nin kilidi aç Güvenli ekran, uygulamalar arasında geçiş yaparken uygulama içeriğini gizler ve ekran görüntüsü alınmasını engeller Ekran @@ -362,7 +361,6 @@ Uzantı güncellemesi var %d uzantı güncellemesi var - Web sitesini WebView\'de görüntüle Uzantı güncellemeleri Kitaplık güncelleniyor Okunan @@ -380,9 +378,8 @@ Daha az Daha fazla Web sitesi - WebView, Tachiyomi için gereklidir + Web Görünümü, uygulamanın işlevselliği için gereklidir Açık kaynak lisansları - Çıkmak için yeniden geriye basın Yalnızca indirilen Böl. %1$s - %2$s Yedek geri yüklenemedi @@ -414,7 +411,7 @@ Bölüm ilerlemesini, izleme hizmetlerinde güncellemek için tek yönlü eşitleme. Her girdinin izleme düğmesinden, izlemeyi ayarlayın. Kitaplıktakilerin kapaklarını yenile - Bu uzantı resmi Tachiyomi uzantıları dizelgesinden değil. + Bu uzantı resmi dizelgeden değil. Resmi olmayan Yükleme tarihine göre Veri @@ -652,7 +649,6 @@ WebView verileri temizlendi WebView verilerini temizle Kapat - Pil düşük olmadığında Kurulu kaynak bulunamadı Kaynak bulunamadı Son güncelleme denetimi @@ -810,4 +806,15 @@ Güncelleme aralığını ayarla Sonuç var İndirilenleri sil + Yedekleme dosyası oluşturulamadı + Lisanslı - Gösterilecek bölüm yok + İndirilenler dizini geçersiz kılındı + Cloudflare\'le ilgili yardım için tıklayın + %s verisine erişilemedi + İzleme girişi + Kitaplık eşleşmesi tamamlandı + HTTP %d, siteyi Web Görünümünde denetle + Genel ağ bağlantısı yok + Kitaplık eşleştiriliyor + Aç: %s \ No newline at end of file diff --git a/i18n/src/main/res/values-uk/strings.xml b/i18n/src/main/res/values-uk/strings.xml index bf43f2527..33976dc75 100644 --- a/i18n/src/main/res/values-uk/strings.xml +++ b/i18n/src/main/res/values-uk/strings.xml @@ -330,7 +330,6 @@ Не вдалось обійти Cloudflare Будь ласка, оновіть WebView для кращої сумісності Оновлення розділів - Розблокувати Tachiyomi Ховати вміст застосунку при перемиканні застосунків та блокувати скріншоти Відображення @@ -372,7 +371,6 @@ %d наявних оновлень розширень Оновлення розширень - Відкрити сайт у WebView Читання Джерела Оновлення бібліотеки @@ -391,7 +389,6 @@ WebView необхідний для Tachiyomi Ліцензії з відкритим кодом Сторінка - Натисніть ще раз, щоб вийти Тільки завантажені Сірий Зменшує смугастість, але може вплинути на продуктивність @@ -693,7 +690,6 @@ Тицьніть задля подробиць Не вдається відкрити останній прочитаний розділ Мова застосунку - Коли батарею заряджено Версія Мова Вікові обмеження diff --git a/i18n/src/main/res/values-uz/strings.xml b/i18n/src/main/res/values-uz/strings.xml index 49cf51aef..9b2703dbe 100644 --- a/i18n/src/main/res/values-uz/strings.xml +++ b/i18n/src/main/res/values-uz/strings.xml @@ -35,8 +35,6 @@ Filtr Menyu Sozlamalar - Chiqish uchun orqaga tugmasini bosing - Tachiyomini ochish Tarix Kuzatish Boblar @@ -271,7 +269,6 @@ Til Portret Har kun - Quvvat past bo\'lmaganda Avtomatik yangilanish O\'chiq Kulrang diff --git a/i18n/src/main/res/values-vi/strings.xml b/i18n/src/main/res/values-vi/strings.xml index 8a904f98d..e37aebf1b 100644 --- a/i18n/src/main/res/values-vi/strings.xml +++ b/i18n/src/main/res/values-vi/strings.xml @@ -313,7 +313,7 @@ Sao chép Không có danh mục. Nhấn vào dấu cộng để tạo một nhóm từ thư viện. Thường gặp - Nhấn giữ để mở hộp thoại + Nhấn giữ để mở mục hành động Mở bằng WebView Màu 32-bit Bỏ qua chap đã đọc @@ -339,7 +339,6 @@ Kiểm tra các chương cập nhật mới Đang cập nhật thư viện Đã tạm ngưng - Kiểm tra trang web bằng WebView Bạn đã đăng xuất Đăng xuất tài khoản Đăng xuất khỏi %1$s\? @@ -387,7 +386,6 @@ Đảo ngược lựa chọn Chương mới nhất Mục chính - Mở Khoá Tachiyomi Nguồn Thêm Đồng bộ một chiều để cập nhật tiến trình chương trong các dịch vụ theo dõi. Thiết lập theo dõi cho các truyện riêng lẻ từ nút theo dõi. @@ -412,7 +410,6 @@ Tắt tất cả Bật tất cả Ngày thêm - Nhấn trở lại lần nữa để thoát Bản sao lưu không chứa truyện nào. Tệp sao lưu không hợp lệ Thêm vào thư viện @@ -509,7 +506,7 @@ Dữ liệu DNS qua HTTPS (DoH) Mạng - Quá trình phục hồi bị huỷ bỏ + Quá trình khôi phục đã bị ngắt Khôi phục thất bại Đang trong quá trình phục hồi Lưu trữ thất bại @@ -596,7 +593,7 @@ Chủ đề: Âm & Dương Chủ đề: Yotsuba Chế độ đen tuyền - Tùy chỉnh mỗi danh mục cho sắp xếp và hiện thị + Tùy chỉnh mỗi danh mục cho sắp xếp Hướng dẫn theo dõi Dịch vụ nâng cao Dịch vụ cung cấp các tính năng nâng cao cho các nguồn cụ thể. Truyện sẽ tự động theo dõi khi được thêm vào thư viện của bạn. @@ -655,7 +652,7 @@ Chưa bắt đầu đọc %1$d cập nhật được bỏ qua Nhấn để tìm hiểu thêm - Phóng ảnh phong cảnh + Phóng ảnh phong cảnh tự động Hiển thị truyện Xoay ảnh rộng Lưới chỉ mỗi bìa @@ -670,7 +667,6 @@ Một phiên bản mới sẵn sàng từ mục phát hành chính thức. Nhấn để học cách kết hợp các mục phát hành không chính thức từ F-Droid. Lỗi khi lưu ảnh Đóng - Khi pin không quá ít Không có nguồn đã cài tìm thấy Không có nguồn nào được tìm thấy Mở trên GitHub @@ -820,4 +816,5 @@ Cập nhật dự kiến tiếp theo Nhấn vào đây để được trợ giúp về Cloudflare Chưa công bố + Mở khoá %s \ No newline at end of file diff --git a/i18n/src/main/res/values-zh-rCN/strings.xml b/i18n/src/main/res/values-zh-rCN/strings.xml index 654ecf2b4..2a32f659f 100644 --- a/i18n/src/main/res/values-zh-rCN/strings.xml +++ b/i18n/src/main/res/values-zh-rCN/strings.xml @@ -324,7 +324,6 @@ 待更新 无法绕过 Cloudflare 请更新 WebView 应用以获得更好的兼容性 - 解锁 Tachiyomi 阻止截屏,并在切换后台时隐藏预览图 显示 章节更新 @@ -358,7 +357,6 @@ %d 个插件可更新 插件更新 - 在 WebView 中检查网站 图源 正在更新书架 阅读 @@ -375,7 +373,6 @@ 展开 开源许可证 官网 - 再按一次退出 添加到书架 在书架中 仅限已下载内容 @@ -639,7 +636,6 @@ 打开 GitHub 页面 已清除 WebView 数据 清除 WebView 数据 - 非低电量时 关闭 未找到已安装的图源 未找到图源 @@ -800,4 +796,8 @@ 已清除下载索引 登录进度记录平台 无法创建备份文件 + 已有正版,没有章节可供显示 + 未连接网络 + HTTP %d,请在 WebView 中检查网站 + 无法连接到 %s \ No newline at end of file diff --git a/i18n/src/main/res/values-zh-rTW/strings.xml b/i18n/src/main/res/values-zh-rTW/strings.xml index 3736b238a..6fdde8a91 100644 --- a/i18n/src/main/res/values-zh-rTW/strings.xml +++ b/i18n/src/main/res/values-zh-rTW/strings.xml @@ -262,11 +262,11 @@ 信任 不信任 不信任的擴充套件 - 這個擴充套件的憑證並不可靠,且尚未被啟用。 + 此擴充功能使用未受信任的憑證簽署,並未啟用。 \n -\n惡意的擴充套件可能存取任何儲存於 Tachiyomi 中的登錄憑證,或執行任意的程式碼。 +\n惡意擴充功能可能會讀取任何已儲存的登入憑證或執行任意程式碼。 \n -\n信任這個憑證,即表示你願意承擔上述風險。 +\n通過信任此憑證,您接受這些風險。 最後閱畢的章節 最大備份保留數 不在書櫃中的作品閱讀進度將被清除,你確定嗎? @@ -303,7 +303,6 @@ 深色模式 開啟 日期格式 - 再按一次以離開 將套用至你書櫃中的作品 僅限下載內容 開放原始碼授權 @@ -317,7 +316,6 @@ 永不 立即 閒置時鎖定 - 解除鎖定 Tachiyomi 上鎖應用程式 在切換應用程式時隱藏預覽,並禁止擷取螢幕畫面。 防窺畫面 @@ -347,7 +345,7 @@ 最近使用 本機來源入門指南 請更新 WebView 以獲得更佳的相容性 - WebView 為 Tachiyomi 的必要元件 + 應用程式運作需要 WebView 反向選擇 自動重新整理中繼資料 更新書櫃時一併檢查封面與簡介是否有更動 @@ -417,7 +415,7 @@ 歷時 %1$s,出現 %2$s 個錯誤 %02d 分 %02d 秒 - 這個擴充套件不是由 Tachiyomi 所提供。 + 此擴充功能不在官方清單中。 非官方 第 %1$s 章 - %2$s @@ -470,7 +468,6 @@ 清除閱讀記錄 暫停閱讀記錄 無痕模式 - 在 WebView 中檢查網站 找不到檔案選擇器 《%1$s》:%2$s,第 %3$d 頁 來源遷移說明 @@ -640,7 +637,6 @@ 清除 WebView 資料 已清除 WebView 資料 關閉 - 電量充足時 找不到來源 找不到已安裝的來源 上次檢查更新日期 @@ -801,4 +797,8 @@ 登入歷程平台 無法建立備份檔 已有正版,沒有章節可供顯示 + HTTP %d,請在 WebView 中檢查網站 + 沒有網際網路連線 + 無法連上 %s + 解鎖 %s \ No newline at end of file diff --git a/i18n/src/main/res/values/strings.xml b/i18n/src/main/res/values/strings.xml index 634051417..629d720c3 100644 --- a/i18n/src/main/res/values/strings.xml +++ b/i18n/src/main/res/values/strings.xml @@ -39,9 +39,8 @@ Local Downloaded - Unlock Tachiyomi + Unlock %s Authenticate to confirm change - Press back again to exit Settings @@ -140,6 +139,7 @@ Move to top Move series to top Move to bottom + Move series to bottom Install Share Save @@ -225,12 +225,6 @@ Show in sources and extensions lists This does not prevent unofficial or potentially incorrectly flagged extensions from surfacing NSFW (18+) content within the app. - Today - - Yesterday - %1$d days ago - - Display Grid size @@ -304,9 +298,9 @@ Uninstall App info Untrusted extension - This extension was signed with an untrusted certificate and wasn\'t activated.\n\nA malicious extension could read any login credentials stored in Tachiyomi or execute arbitrary code.\n\nBy trusting this certificate you accept these risks. + This extension was signed with an untrusted certificate and wasn\'t activated.\n\nA malicious extension could read any stored login credentials or execute arbitrary code.\n\nBy trusting this certificate you accept these risks. This extension is no longer available. It may not function properly and can cause issues with the app. Uninstalling it is recommended. - This extension is not from the official Tachiyomi extensions list. + This extension is not from the official list. Failed to get extensions list Version Language @@ -407,8 +401,8 @@ No animation Normal Fast - Default rotation type - Rotation type + Default rotation + Rotation Free Portrait Reverse portrait @@ -941,7 +935,7 @@ Tap here for help with Cloudflare *required - WebView is required for Tachiyomi + WebView is required for the app to function Please update the WebView app for better compatibility Updated default chapter settings diff --git a/macrobenchmark/src/main/java/tachiyomi/macrobenchmark/StartupBenchmark.kt b/macrobenchmark/src/main/java/tachiyomi/macrobenchmark/StartupBenchmark.kt index cd1002770..87c1d33c1 100644 --- a/macrobenchmark/src/main/java/tachiyomi/macrobenchmark/StartupBenchmark.kt +++ b/macrobenchmark/src/main/java/tachiyomi/macrobenchmark/StartupBenchmark.kt @@ -60,11 +60,16 @@ abstract class AbstractStartupBenchmark(private val startupMode: StartupMode) { @Test fun startupBaselineProfileDisabled() = startup( - CompilationMode.Partial(baselineProfileMode = BaselineProfileMode.Disable, warmupIterations = 1), + CompilationMode.Partial( + baselineProfileMode = BaselineProfileMode.Disable, + warmupIterations = 1, + ), ) @Test - fun startupBaselineProfile() = startup(CompilationMode.Partial(baselineProfileMode = BaselineProfileMode.Require)) + fun startupBaselineProfile() = startup( + CompilationMode.Partial(baselineProfileMode = BaselineProfileMode.Require), + ) @Test fun startupFullCompilation() = startup(CompilationMode.Full()) diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/AdaptiveSheet.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/AdaptiveSheet.kt index 87e17416a..eea05b4ca 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/AdaptiveSheet.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/AdaptiveSheet.kt @@ -182,7 +182,10 @@ fun AdaptiveSheet( shape = MaterialTheme.shapes.extraLarge, tonalElevation = tonalElevation, content = { - BackHandler(enabled = anchoredDraggableState.targetValue == 0, onBack = internalOnDismissRequest) + BackHandler( + enabled = anchoredDraggableState.targetValue == 0, + onBack = internalOnDismissRequest, + ) content() }, ) @@ -200,49 +203,50 @@ fun AdaptiveSheet( } } -private fun AnchoredDraggableState.preUpPostDownNestedScrollConnection() = object : NestedScrollConnection { - override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset { - val delta = available.toFloat() - return if (delta < 0 && source == NestedScrollSource.Drag) { - dispatchRawDelta(delta).toOffset() - } else { - Offset.Zero +private fun AnchoredDraggableState.preUpPostDownNestedScrollConnection() = + object : NestedScrollConnection { + override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset { + val delta = available.toFloat() + return if (delta < 0 && source == NestedScrollSource.Drag) { + dispatchRawDelta(delta).toOffset() + } else { + Offset.Zero + } } - } - override fun onPostScroll( - consumed: Offset, - available: Offset, - source: NestedScrollSource, - ): Offset { - return if (source == NestedScrollSource.Drag) { - dispatchRawDelta(available.toFloat()).toOffset() - } else { - Offset.Zero + override fun onPostScroll( + consumed: Offset, + available: Offset, + source: NestedScrollSource, + ): Offset { + return if (source == NestedScrollSource.Drag) { + dispatchRawDelta(available.toFloat()).toOffset() + } else { + Offset.Zero + } } - } - override suspend fun onPreFling(available: Velocity): Velocity { - val toFling = available.toFloat() - return if (toFling < 0 && offset > anchors.minAnchor()) { - settle(toFling) - // since we go to the anchor with tween settling, consume all for the best UX - available - } else { - Velocity.Zero + override suspend fun onPreFling(available: Velocity): Velocity { + val toFling = available.toFloat() + return if (toFling < 0 && offset > anchors.minAnchor()) { + settle(toFling) + // since we go to the anchor with tween settling, consume all for the best UX + available + } else { + Velocity.Zero + } } + + override suspend fun onPostFling(consumed: Velocity, available: Velocity): Velocity { + settle(velocity = available.toFloat()) + return available + } + + private fun Float.toOffset(): Offset = Offset(0f, this) + + @JvmName("velocityToFloat") + private fun Velocity.toFloat() = this.y + + @JvmName("offsetToFloat") + private fun Offset.toFloat(): Float = this.y } - - override suspend fun onPostFling(consumed: Velocity, available: Velocity): Velocity { - settle(velocity = available.toFloat()) - return available - } - - private fun Float.toOffset(): Offset = Offset(0f, this) - - @JvmName("velocityToFloat") - private fun Velocity.toFloat() = this.y - - @JvmName("offsetToFloat") - private fun Offset.toFloat(): Float = this.y -} diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/CircularProgressIndicator.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/CircularProgressIndicator.kt index dafe3237d..bda305890 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/CircularProgressIndicator.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/CircularProgressIndicator.kt @@ -37,9 +37,7 @@ import androidx.compose.ui.tooling.preview.Preview * By always rotating we give the feedback to the user that the application isn't 'stuck'. */ @Composable -fun CombinedCircularProgressIndicator( - progress: Float, -) { +fun CombinedCircularProgressIndicator(progress: Float) { val animatedProgress by animateFloatAsState( targetValue = progress, animationSpec = ProgressIndicatorDefaults.ProgressAnimationSpec, diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/CollapsibleBox.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/CollapsibleBox.kt index b70cb2705..ffd4b84e9 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/CollapsibleBox.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/CollapsibleBox.kt @@ -23,10 +23,7 @@ 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 { diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/LinkIcon.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/LinkIcon.kt index 17dc818ca..86d1225b5 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/LinkIcon.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/LinkIcon.kt @@ -11,12 +11,7 @@ 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(modifier: Modifier = Modifier, label: String, icon: ImageVector, url: String) { val uriHandler = LocalUriHandler.current IconButton( modifier = modifier.padding(4.dp), diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/ListGroupHeader.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/ListGroupHeader.kt index c0ffb35d4..2fe128746 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/ListGroupHeader.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/ListGroupHeader.kt @@ -9,10 +9,7 @@ import androidx.compose.ui.text.font.FontWeight import tachiyomi.presentation.core.components.material.padding @Composable -fun ListGroupHeader( - modifier: Modifier = Modifier, - text: String, -) { +fun ListGroupHeader(modifier: Modifier = Modifier, text: String) { Text( text = text, modifier = modifier diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/SettingsItems.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/SettingsItems.kt index f1d544db7..08bf2d567 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/SettingsItems.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/SettingsItems.kt @@ -12,6 +12,9 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.foundation.lazy.grid.GridCells +import androidx.compose.foundation.lazy.grid.LazyGridScope +import androidx.compose.foundation.lazy.grid.LazyVerticalGrid import androidx.compose.material.ContentAlpha import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ArrowDownward @@ -42,6 +45,7 @@ import androidx.compose.ui.unit.dp import tachiyomi.core.preference.Preference import tachiyomi.core.preference.TriState import tachiyomi.core.preference.toggle +import tachiyomi.presentation.core.components.material.padding import tachiyomi.presentation.core.theme.header import tachiyomi.presentation.core.util.collectAsState @@ -51,16 +55,12 @@ object SettingsItemsPaddings { } @Composable -fun HeadingItem( - @StringRes labelRes: Int, -) { +fun HeadingItem(@StringRes labelRes: Int) { HeadingItem(stringResource(labelRes)) } @Composable -fun HeadingItem( - text: String, -) { +fun HeadingItem(text: String) { Text( text = text, style = MaterialTheme.typography.header, @@ -74,11 +74,7 @@ fun HeadingItem( } @Composable -fun IconItem( - label: String, - icon: ImageVector, - onClick: () -> Unit, -) { +fun IconItem(label: String, icon: ImageVector, onClick: () -> Unit) { BaseSettingsItem( label = label, widget = { @@ -93,11 +89,7 @@ fun IconItem( } @Composable -fun SortItem( - label: String, - sortDescending: Boolean?, - onClick: () -> Unit, -) { +fun SortItem(label: String, sortDescending: Boolean?, onClick: () -> Unit) { val arrowIcon = when (sortDescending) { true -> Icons.Default.ArrowDownward false -> Icons.Default.ArrowUpward @@ -122,10 +114,7 @@ fun SortItem( } @Composable -fun CheckboxItem( - label: String, - pref: Preference, -) { +fun CheckboxItem(label: String, pref: Preference) { val checked by pref.collectAsState() CheckboxItem( label = label, @@ -135,11 +124,7 @@ fun CheckboxItem( } @Composable -fun CheckboxItem( - label: String, - checked: Boolean, - onClick: () -> Unit, -) { +fun CheckboxItem(label: String, checked: Boolean, onClick: () -> Unit) { BaseSettingsItem( label = label, widget = { @@ -153,11 +138,7 @@ fun CheckboxItem( } @Composable -fun RadioItem( - label: String, - selected: Boolean, - onClick: () -> Unit, -) { +fun RadioItem(label: String, selected: Boolean, onClick: () -> Unit) { BaseSettingsItem( label = label, widget = { @@ -285,7 +266,7 @@ fun TriStateItem( vertical = SettingsItemsPaddings.Vertical, ), verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(24.dp), + horizontalArrangement = Arrangement.spacedBy(MaterialTheme.padding.large), ) { val stateAlpha = if (enabled && onClick != null) 1f else ContentAlpha.disabled @@ -314,11 +295,7 @@ fun TriStateItem( } @Composable -fun TextItem( - label: String, - value: String, - onChange: (String) -> Unit, -) { +fun TextItem(label: String, value: String, onChange: (String) -> Unit) { OutlinedTextField( modifier = Modifier .fillMaxWidth() @@ -331,10 +308,7 @@ fun TextItem( } @Composable -fun SettingsChipRow( - @StringRes labelRes: Int, - content: @Composable FlowRowScope.() -> Unit, -) { +fun SettingsChipRow(@StringRes labelRes: Int, content: @Composable FlowRowScope.() -> Unit) { Column { HeadingItem(labelRes) FlowRow( @@ -344,7 +318,25 @@ fun SettingsChipRow( end = SettingsItemsPaddings.Horizontal, bottom = SettingsItemsPaddings.Vertical, ), - horizontalArrangement = Arrangement.spacedBy(8.dp), + horizontalArrangement = Arrangement.spacedBy(MaterialTheme.padding.small), + content = content, + ) + } +} + +@Composable +fun SettingsIconGrid(@StringRes labelRes: Int, content: LazyGridScope.() -> Unit) { + Column { + HeadingItem(labelRes) + LazyVerticalGrid( + columns = GridCells.Adaptive(128.dp), + modifier = Modifier.padding( + start = SettingsItemsPaddings.Horizontal, + end = SettingsItemsPaddings.Horizontal, + bottom = SettingsItemsPaddings.Vertical, + ), + verticalArrangement = Arrangement.spacedBy(MaterialTheme.padding.tiny), + horizontalArrangement = Arrangement.spacedBy(MaterialTheme.padding.small), content = content, ) } diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/VerticalFastScroller.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/VerticalFastScroller.kt index c65aa9606..4f44f60e2 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/VerticalFastScroller.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/VerticalFastScroller.kt @@ -197,7 +197,8 @@ private fun rememberColumnWidthSums( horizontalArrangement, contentPadding, ) { - { constraints -> + { + constraints -> require(constraints.maxWidth != Constraints.Infinity) { "LazyVerticalGrid's width should be bound by parent" } diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/AlertDialog.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/AlertDialog.kt index 9bbce88bf..3db94c018 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/AlertDialog.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/AlertDialog.kt @@ -30,7 +30,9 @@ fun AlertDialogContent( title = title, content = { Column { - CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onSurfaceVariant) { + CompositionLocalProvider( + LocalContentColor provides MaterialTheme.colorScheme.onSurfaceVariant, + ) { val textStyle = MaterialTheme.typography.bodyMedium ProvideTextStyle(textStyle) { Box( @@ -54,7 +56,9 @@ fun AlertDialogContent( ) .align(Alignment.End), ) { - CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.primary) { + CompositionLocalProvider( + LocalContentColor provides MaterialTheme.colorScheme.primary, + ) { val textStyle = MaterialTheme.typography.labelLarge ProvideTextStyle(value = textStyle, content = buttons) } @@ -86,7 +90,9 @@ fun AlertDialogContent( .fillMaxWidth(), ) { icon?.let { - CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.secondary) { + CompositionLocalProvider( + LocalContentColor provides MaterialTheme.colorScheme.secondary, + ) { Box( Modifier .padding(IconPadding) @@ -97,7 +103,9 @@ fun AlertDialogContent( } } title?.let { - CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onSurface) { + CompositionLocalProvider( + LocalContentColor provides MaterialTheme.colorScheme.onSurface, + ) { val textStyle = MaterialTheme.typography.headlineSmall ProvideTextStyle(textStyle) { Box( diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Button.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Button.kt index 3a5de0275..6a645ed6a 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Button.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Button.kt @@ -64,20 +64,19 @@ fun TextButton( ), contentPadding: PaddingValues = M3ButtonDefaults.TextButtonContentPadding, content: @Composable RowScope.() -> Unit, -) = - Button( - onClick = onClick, - modifier = modifier, - onLongClick = onLongClick, - enabled = enabled, - interactionSource = interactionSource, - elevation = elevation, - shape = shape, - border = border, - colors = colors, - contentPadding = contentPadding, - content = content, - ) +) = Button( + onClick = onClick, + modifier = modifier, + onLongClick = onLongClick, + enabled = enabled, + interactionSource = interactionSource, + elevation = elevation, + shape = shape, + border = border, + colors = colors, + contentPadding = contentPadding, + content = content, +) /** * Button with additional onLongClick functionality. diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/IconButton.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/IconButtonTokens.kt similarity index 100% rename from presentation-core/src/main/java/tachiyomi/presentation/core/components/material/IconButton.kt rename to presentation-core/src/main/java/tachiyomi/presentation/core/components/material/IconButtonTokens.kt diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/IconToggleButton.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/IconToggleButton.kt new file mode 100644 index 000000000..2abcc4b39 --- /dev/null +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/IconToggleButton.kt @@ -0,0 +1,52 @@ +package tachiyomi.presentation.core.components.material + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.FilledIconToggleButton +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.dp + +@Composable +fun IconToggleButton( + checked: Boolean, + onCheckedChange: (Boolean) -> Unit, + modifier: Modifier = Modifier, + imageVector: ImageVector, + title: String, +) { + FilledIconToggleButton( + checked = checked, + onCheckedChange = onCheckedChange, + modifier = modifier + .height(48.dp), + ) { + Row( + horizontalArrangement = Arrangement.spacedBy(MaterialTheme.padding.small), + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .fillMaxWidth() + .padding(MaterialTheme.padding.small), + ) { + Icon( + imageVector = imageVector, + contentDescription = null, + ) + + Text( + text = title, + maxLines = 2, + overflow = TextOverflow.Ellipsis, + ) + } + } +} diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/NavigationRail.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/NavigationRail.kt index 02e670ca7..39c00895b 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/NavigationRail.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/NavigationRail.kt @@ -48,7 +48,10 @@ fun NavigationRail( .padding(vertical = MaterialTheme.padding.tiny) .selectableGroup(), horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.spacedBy(MaterialTheme.padding.tiny, alignment = Alignment.CenterVertically), + verticalArrangement = Arrangement.spacedBy( + MaterialTheme.padding.tiny, + alignment = Alignment.CenterVertically, + ), ) { if (header != null) { header() diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Scaffold.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Scaffold.kt index 7ecd5964c..cd14e2c0e 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Scaffold.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Scaffold.kt @@ -99,7 +99,9 @@ import kotlin.math.max @Composable fun Scaffold( modifier: Modifier = Modifier, - topBarScrollBehavior: TopAppBarScrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState()), + topBarScrollBehavior: TopAppBarScrollBehavior = TopAppBarDefaults.pinnedScrollBehavior( + rememberTopAppBarState(), + ), topBar: @Composable (TopAppBarScrollBehavior) -> Unit = {}, bottomBar: @Composable () -> Unit = {}, startBar: @Composable () -> Unit = {}, @@ -116,7 +118,11 @@ fun Scaffold( androidx.compose.material3.Surface( modifier = Modifier .nestedScroll(topBarScrollBehavior.nestedScrollConnection) - .onConsumedWindowInsetsChanged { remainingWindowInsets.insets = contentWindowInsets.exclude(it) } + .onConsumedWindowInsetsChanged { + remainingWindowInsets.insets = contentWindowInsets.exclude( + it, + ) + } .then(modifier), color = containerColor, contentColor = contentColor, @@ -271,7 +277,10 @@ private fun ScaffoldLayout( } else { max(bottomBarHeightPx.toDp(), fabOffsetDp) }, - start = max(insets.calculateStartPadding((this@SubcomposeLayout).layoutDirection), startBarWidth.toDp()), + start = max( + insets.calculateStartPadding((this@SubcomposeLayout).layoutDirection), + startBarWidth.toDp(), + ), end = insets.calculateEndPadding((this@SubcomposeLayout).layoutDirection), ) content(innerPadding) diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Surface.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Surface.kt index eda45695f..71866b61d 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Surface.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Surface.kt @@ -104,9 +104,7 @@ private fun surfaceColorAtElevation(color: Color, elevation: Dp): Color { } } -private fun ColorScheme.surfaceColorAtElevation( - elevation: Dp, -): Color { +private fun ColorScheme.surfaceColorAtElevation(elevation: Dp): Color { if (elevation == 0.dp) return surface val alpha = ((4.5f * ln(elevation.value + 1)) + 2f) / 100f return surfaceTint.copy(alpha = alpha).compositeOver(surface) diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Tabs.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Tabs.kt index d547ad8d0..66e44ca24 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Tabs.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Tabs.kt @@ -46,10 +46,7 @@ private fun Modifier.tabIndicatorOffset( } @Composable -fun TabIndicator( - currentTabPosition: TabPosition, - currentPageOffsetFraction: Float, -) { +fun TabIndicator(currentTabPosition: TabPosition, currentPageOffsetFraction: Float) { SecondaryIndicator( modifier = Modifier .tabIndicatorOffset(currentTabPosition, currentPageOffsetFraction) @@ -59,10 +56,7 @@ fun TabIndicator( } @Composable -fun TabText( - text: String, - badgeCount: Int? = null, -) { +fun TabText(text: String, badgeCount: Int? = null) { val pillAlpha = if (isSystemInDarkTheme()) 0.12f else 0.08f Row( diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/util/Preview.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/util/ThemePreviews.kt similarity index 100% rename from presentation-core/src/main/java/tachiyomi/presentation/core/util/Preview.kt rename to presentation-core/src/main/java/tachiyomi/presentation/core/util/ThemePreviews.kt diff --git a/presentation-widget/src/main/AndroidManifest.xml b/presentation-widget/src/main/AndroidManifest.xml index 568741e54..38943f13e 100644 --- a/presentation-widget/src/main/AndroidManifest.xml +++ b/presentation-widget/src/main/AndroidManifest.xml @@ -1,2 +1,39 @@ - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/presentation-widget/src/main/java/tachiyomi/presentation/widget/BaseUpdatesGridGlanceWidget.kt b/presentation-widget/src/main/java/tachiyomi/presentation/widget/BaseUpdatesGridGlanceWidget.kt new file mode 100644 index 000000000..26e1cd918 --- /dev/null +++ b/presentation-widget/src/main/java/tachiyomi/presentation/widget/BaseUpdatesGridGlanceWidget.kt @@ -0,0 +1,153 @@ +package tachiyomi.presentation.widget + +import android.app.Application +import android.content.Context +import android.graphics.Bitmap +import android.os.Build +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.compose.ui.unit.Dp +import androidx.core.graphics.drawable.toBitmap +import androidx.glance.GlanceId +import androidx.glance.GlanceModifier +import androidx.glance.ImageProvider +import androidx.glance.appwidget.GlanceAppWidget +import androidx.glance.appwidget.GlanceAppWidgetManager +import androidx.glance.appwidget.SizeMode +import androidx.glance.appwidget.appWidgetBackground +import androidx.glance.appwidget.provideContent +import androidx.glance.background +import androidx.glance.layout.fillMaxSize +import androidx.glance.layout.padding +import androidx.glance.unit.ColorProvider +import coil.executeBlocking +import coil.imageLoader +import coil.request.CachePolicy +import coil.request.ImageRequest +import coil.size.Precision +import coil.size.Scale +import coil.transform.RoundedCornersTransformation +import eu.kanade.tachiyomi.core.security.SecurityPreferences +import eu.kanade.tachiyomi.util.system.dpToPx +import kotlinx.coroutines.flow.map +import tachiyomi.core.util.lang.withIOContext +import tachiyomi.domain.manga.model.MangaCover +import tachiyomi.domain.updates.interactor.GetUpdates +import tachiyomi.domain.updates.model.UpdatesWithRelations +import tachiyomi.presentation.widget.components.CoverHeight +import tachiyomi.presentation.widget.components.CoverWidth +import tachiyomi.presentation.widget.components.LockedWidget +import tachiyomi.presentation.widget.components.UpdatesWidget +import tachiyomi.presentation.widget.util.appWidgetBackgroundRadius +import tachiyomi.presentation.widget.util.calculateRowAndColumnCount +import uy.kohesive.injekt.Injekt +import uy.kohesive.injekt.api.get +import java.util.Calendar +import java.util.Date + +abstract class BaseUpdatesGridGlanceWidget( + private val context: Context = Injekt.get(), + private val getUpdates: GetUpdates = Injekt.get(), + private val preferences: SecurityPreferences = Injekt.get(), +) : GlanceAppWidget() { + + override val sizeMode = SizeMode.Exact + + abstract val foreground: ColorProvider + abstract val background: ImageProvider + abstract val topPadding: Dp + abstract val bottomPadding: Dp + + override suspend fun provideGlance(context: Context, id: GlanceId) { + val locked = preferences.useAuthenticator().get() + val containerModifier = GlanceModifier + .fillMaxSize() + .background(background) + .appWidgetBackground() + .padding(top = topPadding, bottom = bottomPadding) + .appWidgetBackgroundRadius() + + val manager = GlanceAppWidgetManager(context) + val ids = manager.getGlanceIds(javaClass) + val (rowCount, columnCount) = ids + .flatMap { manager.getAppWidgetSizes(it) } + .maxBy { it.height.value * it.width.value } + .calculateRowAndColumnCount(topPadding, bottomPadding) + + provideContent { + // If app lock enabled, don't do anything + if (locked) { + LockedWidget( + foreground = foreground, + modifier = containerModifier, + ) + return@provideContent + } + + val flow = remember { + getUpdates + .subscribe(false, DateLimit.timeInMillis) + .map { rawData -> + rawData.prepareData(rowCount, columnCount) + } + } + val data by flow.collectAsState(initial = null) + UpdatesWidget( + data = data, + modifier = containerModifier, + contentColor = foreground, + topPadding = topPadding, + bottomPadding = bottomPadding, + ) + } + } + + private suspend fun List.prepareData( + rowCount: Int, + columnCount: Int, + ): List> { + // Resize to cover size + val widthPx = CoverWidth.value.toInt().dpToPx + val heightPx = CoverHeight.value.toInt().dpToPx + val roundPx = context.resources.getDimension(R.dimen.appwidget_inner_radius) + return withIOContext { + this@prepareData + .distinctBy { it.mangaId } + .take(rowCount * columnCount) + .map { updatesView -> + val request = ImageRequest.Builder(context) + .data( + MangaCover( + mangaId = updatesView.mangaId, + sourceId = updatesView.sourceId, + isMangaFavorite = true, + url = updatesView.coverData.url, + lastModified = updatesView.coverData.lastModified, + ), + ) + .memoryCachePolicy(CachePolicy.DISABLED) + .precision(Precision.EXACT) + .size(widthPx, heightPx) + .scale(Scale.FILL) + .let { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) { + it.transformations(RoundedCornersTransformation(roundPx)) + } else { + it // Handled by system + } + } + .build() + Pair(updatesView.mangaId, context.imageLoader.executeBlocking(request).drawable?.toBitmap()) + } + } + } + + companion object { + val DateLimit: Calendar + get() = Calendar.getInstance().apply { + time = Date() + add(Calendar.MONTH, -3) + } + } +} diff --git a/presentation-widget/src/main/java/tachiyomi/presentation/widget/TachiyomiWidgetManager.kt b/presentation-widget/src/main/java/tachiyomi/presentation/widget/TachiyomiWidgetManager.kt index e51b0337d..8227c6c51 100644 --- a/presentation-widget/src/main/java/tachiyomi/presentation/widget/TachiyomiWidgetManager.kt +++ b/presentation-widget/src/main/java/tachiyomi/presentation/widget/TachiyomiWidgetManager.kt @@ -19,7 +19,7 @@ class TachiyomiWidgetManager( fun Context.init(scope: LifecycleCoroutineScope) { combine( - getUpdates.subscribe(read = false, after = UpdatesGridGlanceWidget.DateLimit.timeInMillis), + getUpdates.subscribe(read = false, after = BaseUpdatesGridGlanceWidget.DateLimit.timeInMillis), securityPreferences.useAuthenticator().changes(), transform = { a, _ -> a }, ) @@ -27,6 +27,7 @@ class TachiyomiWidgetManager( .onEach { try { UpdatesGridGlanceWidget().updateAll(this) + UpdatesGridCoverScreenGlanceWidget().updateAll(this) } catch (e: Exception) { logcat(LogPriority.ERROR, e) { "Failed to update widget" } } diff --git a/presentation-widget/src/main/java/tachiyomi/presentation/widget/UpdatesGridCoverScreenGlanceReceiver.kt b/presentation-widget/src/main/java/tachiyomi/presentation/widget/UpdatesGridCoverScreenGlanceReceiver.kt new file mode 100644 index 000000000..721c6a3ac --- /dev/null +++ b/presentation-widget/src/main/java/tachiyomi/presentation/widget/UpdatesGridCoverScreenGlanceReceiver.kt @@ -0,0 +1,9 @@ +package tachiyomi.presentation.widget + +import androidx.glance.appwidget.GlanceAppWidget +import androidx.glance.appwidget.GlanceAppWidgetReceiver + +class UpdatesGridCoverScreenGlanceReceiver : GlanceAppWidgetReceiver() { + override val glanceAppWidget: GlanceAppWidget + get() = UpdatesGridCoverScreenGlanceWidget() +} diff --git a/presentation-widget/src/main/java/tachiyomi/presentation/widget/UpdatesGridCoverScreenGlanceWidget.kt b/presentation-widget/src/main/java/tachiyomi/presentation/widget/UpdatesGridCoverScreenGlanceWidget.kt new file mode 100644 index 000000000..efb67f1c3 --- /dev/null +++ b/presentation-widget/src/main/java/tachiyomi/presentation/widget/UpdatesGridCoverScreenGlanceWidget.kt @@ -0,0 +1,13 @@ +package tachiyomi.presentation.widget + +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import androidx.glance.ImageProvider +import androidx.glance.unit.ColorProvider + +class UpdatesGridCoverScreenGlanceWidget : BaseUpdatesGridGlanceWidget() { + override val foreground = ColorProvider(Color.White) + override val background = ImageProvider(R.drawable.appwidget_coverscreen_background) + override val topPadding = 0.dp + override val bottomPadding = 24.dp +} diff --git a/presentation-widget/src/main/java/tachiyomi/presentation/widget/UpdatesGridGlanceReceiver.kt b/presentation-widget/src/main/java/tachiyomi/presentation/widget/UpdatesGridGlanceReceiver.kt index 93a4cf735..3ee232781 100644 --- a/presentation-widget/src/main/java/tachiyomi/presentation/widget/UpdatesGridGlanceReceiver.kt +++ b/presentation-widget/src/main/java/tachiyomi/presentation/widget/UpdatesGridGlanceReceiver.kt @@ -4,5 +4,6 @@ import androidx.glance.appwidget.GlanceAppWidget import androidx.glance.appwidget.GlanceAppWidgetReceiver class UpdatesGridGlanceReceiver : GlanceAppWidgetReceiver() { - override val glanceAppWidget: GlanceAppWidget = UpdatesGridGlanceWidget() + override val glanceAppWidget: GlanceAppWidget + get() = UpdatesGridGlanceWidget() } diff --git a/presentation-widget/src/main/java/tachiyomi/presentation/widget/UpdatesGridGlanceWidget.kt b/presentation-widget/src/main/java/tachiyomi/presentation/widget/UpdatesGridGlanceWidget.kt index 4275d08f0..2de89ecce 100644 --- a/presentation-widget/src/main/java/tachiyomi/presentation/widget/UpdatesGridGlanceWidget.kt +++ b/presentation-widget/src/main/java/tachiyomi/presentation/widget/UpdatesGridGlanceWidget.kt @@ -1,133 +1,12 @@ package tachiyomi.presentation.widget -import android.app.Application -import android.content.Context -import android.graphics.Bitmap -import android.os.Build -import androidx.core.graphics.drawable.toBitmap -import androidx.glance.GlanceId -import androidx.glance.GlanceModifier +import androidx.compose.ui.unit.dp import androidx.glance.ImageProvider -import androidx.glance.appwidget.GlanceAppWidget -import androidx.glance.appwidget.GlanceAppWidgetManager -import androidx.glance.appwidget.SizeMode -import androidx.glance.appwidget.appWidgetBackground -import androidx.glance.appwidget.provideContent -import androidx.glance.background -import androidx.glance.layout.fillMaxSize -import coil.executeBlocking -import coil.imageLoader -import coil.request.CachePolicy -import coil.request.ImageRequest -import coil.size.Precision -import coil.size.Scale -import coil.transform.RoundedCornersTransformation -import eu.kanade.tachiyomi.core.security.SecurityPreferences -import eu.kanade.tachiyomi.util.system.dpToPx -import tachiyomi.core.util.lang.withIOContext -import tachiyomi.domain.manga.model.MangaCover -import tachiyomi.domain.updates.interactor.GetUpdates -import tachiyomi.domain.updates.model.UpdatesWithRelations -import tachiyomi.presentation.widget.components.CoverHeight -import tachiyomi.presentation.widget.components.CoverWidth -import tachiyomi.presentation.widget.components.LockedWidget -import tachiyomi.presentation.widget.components.UpdatesWidget -import tachiyomi.presentation.widget.util.appWidgetBackgroundRadius -import tachiyomi.presentation.widget.util.calculateRowAndColumnCount -import uy.kohesive.injekt.Injekt -import uy.kohesive.injekt.api.get -import java.util.Calendar -import java.util.Date +import androidx.glance.unit.ColorProvider -class UpdatesGridGlanceWidget( - private val context: Context = Injekt.get(), - private val getUpdates: GetUpdates = Injekt.get(), - private val preferences: SecurityPreferences = Injekt.get(), -) : GlanceAppWidget() { - - private var data: List>? = null - - override val sizeMode = SizeMode.Exact - - override suspend fun provideGlance(context: Context, id: GlanceId) { - val locked = preferences.useAuthenticator().get() - if (!locked) loadData() - - provideContent { - // If app lock enabled, don't do anything - if (locked) { - LockedWidget() - return@provideContent - } - UpdatesWidget(data) - } - } - - private suspend fun loadData() { - val manager = GlanceAppWidgetManager(context) - val ids = manager.getGlanceIds(this@UpdatesGridGlanceWidget::class.java) - if (ids.isEmpty()) return - - withIOContext { - val updates = getUpdates.await( - read = false, - after = DateLimit.timeInMillis, - ) - val (rowCount, columnCount) = ids - .flatMap { manager.getAppWidgetSizes(it) } - .maxBy { it.height.value * it.width.value } - .calculateRowAndColumnCount() - - data = prepareList(updates, rowCount * columnCount) - } - } - - private fun prepareList(processList: List, take: Int): List> { - // Resize to cover size - val widthPx = CoverWidth.value.toInt().dpToPx - val heightPx = CoverHeight.value.toInt().dpToPx - val roundPx = context.resources.getDimension(R.dimen.appwidget_inner_radius) - return processList - .distinctBy { it.mangaId } - .take(take) - .map { updatesView -> - val request = ImageRequest.Builder(context) - .data( - MangaCover( - mangaId = updatesView.mangaId, - sourceId = updatesView.sourceId, - isMangaFavorite = true, - url = updatesView.coverData.url, - lastModified = updatesView.coverData.lastModified, - ), - ) - .memoryCachePolicy(CachePolicy.DISABLED) - .precision(Precision.EXACT) - .size(widthPx, heightPx) - .scale(Scale.FILL) - .let { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) { - it.transformations(RoundedCornersTransformation(roundPx)) - } else { - it // Handled by system - } - } - .build() - Pair(updatesView.mangaId, context.imageLoader.executeBlocking(request).drawable?.toBitmap()) - } - } - - companion object { - val DateLimit: Calendar - get() = Calendar.getInstance().apply { - time = Date() - add(Calendar.MONTH, -3) - } - } +class UpdatesGridGlanceWidget : BaseUpdatesGridGlanceWidget() { + override val foreground = ColorProvider(R.color.appwidget_on_secondary_container) + override val background = ImageProvider(R.drawable.appwidget_background) + override val topPadding = 0.dp + override val bottomPadding = 0.dp } - -val ContainerModifier = GlanceModifier - .fillMaxSize() - .background(ImageProvider(R.drawable.appwidget_background)) - .appWidgetBackground() - .appWidgetBackgroundRadius() diff --git a/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/LockedWidget.kt b/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/LockedWidget.kt index 730ab0670..6acb8d7ec 100644 --- a/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/LockedWidget.kt +++ b/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/LockedWidget.kt @@ -16,26 +16,27 @@ import androidx.glance.text.TextAlign import androidx.glance.text.TextStyle import androidx.glance.unit.ColorProvider import tachiyomi.core.Constants -import tachiyomi.presentation.widget.ContainerModifier import tachiyomi.presentation.widget.R import tachiyomi.presentation.widget.util.stringResource @Composable -fun LockedWidget() { +fun LockedWidget( + foreground: ColorProvider, + modifier: GlanceModifier = GlanceModifier, +) { val intent = Intent(LocalContext.current, Class.forName(Constants.MAIN_ACTIVITY)).apply { addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) } Box( - modifier = GlanceModifier + modifier = modifier .clickable(actionStartActivity(intent)) - .then(ContainerModifier) .padding(8.dp), contentAlignment = Alignment.Center, ) { Text( text = stringResource(R.string.appwidget_unavailable_locked), style = TextStyle( - color = ColorProvider(R.color.appwidget_on_secondary_container), + color = foreground, fontSize = 12.sp, textAlign = TextAlign.Center, ), diff --git a/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/UpdatesMangaCover.kt b/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/UpdatesMangaCover.kt index 888acec88..5b537f45d 100644 --- a/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/UpdatesMangaCover.kt +++ b/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/UpdatesMangaCover.kt @@ -17,10 +17,7 @@ val CoverWidth = 58.dp val CoverHeight = 87.dp @Composable -fun UpdatesMangaCover( - modifier: GlanceModifier = GlanceModifier, - cover: Bitmap?, -) { +fun UpdatesMangaCover(modifier: GlanceModifier = GlanceModifier, cover: Bitmap?) { Box( modifier = modifier .size(width = CoverWidth, height = CoverHeight) diff --git a/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/UpdatesWidget.kt b/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/UpdatesWidget.kt index f7ecd2e71..63a3b329d 100644 --- a/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/UpdatesWidget.kt +++ b/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/UpdatesWidget.kt @@ -3,6 +3,7 @@ package tachiyomi.presentation.widget.components import android.content.Intent import android.graphics.Bitmap import androidx.compose.runtime.Composable +import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.glance.GlanceModifier import androidx.glance.LocalContext @@ -14,59 +15,75 @@ import androidx.glance.layout.Alignment import androidx.glance.layout.Box import androidx.glance.layout.Column import androidx.glance.layout.Row +import androidx.glance.layout.fillMaxHeight import androidx.glance.layout.fillMaxWidth import androidx.glance.layout.padding import androidx.glance.text.Text +import androidx.glance.text.TextStyle +import androidx.glance.unit.ColorProvider import tachiyomi.core.Constants -import tachiyomi.presentation.widget.ContainerModifier import tachiyomi.presentation.widget.R import tachiyomi.presentation.widget.util.calculateRowAndColumnCount import tachiyomi.presentation.widget.util.stringResource @Composable -fun UpdatesWidget(data: List>?) { - val (rowCount, columnCount) = LocalSize.current.calculateRowAndColumnCount() - Column( - modifier = ContainerModifier, - verticalAlignment = Alignment.CenterVertically, - horizontalAlignment = Alignment.CenterHorizontally, +fun UpdatesWidget( + data: List>?, + modifier: GlanceModifier = GlanceModifier, + contentColor: ColorProvider, + topPadding: Dp, + bottomPadding: Dp, +) { + Box( + contentAlignment = Alignment.Center, + modifier = modifier, ) { if (data == null) { - CircularProgressIndicator() + CircularProgressIndicator(color = contentColor) } else if (data.isEmpty()) { - Text(text = stringResource(R.string.information_no_recent)) + Text( + text = stringResource(R.string.information_no_recent), + style = TextStyle(color = contentColor), + ) } else { - (0.. - val coverRow = (0.. - data.getOrNull(j + (i * columnCount)) - } - if (coverRow.isNotEmpty()) { - Row( - modifier = GlanceModifier - .padding(vertical = 4.dp) - .fillMaxWidth(), - horizontalAlignment = Alignment.CenterHorizontally, - verticalAlignment = Alignment.CenterVertically, - ) { - coverRow.forEach { (mangaId, cover) -> - Box( - modifier = GlanceModifier - .padding(horizontal = 3.dp), - contentAlignment = Alignment.Center, - ) { - val intent = Intent(LocalContext.current, Class.forName(Constants.MAIN_ACTIVITY)).apply { - action = Constants.SHORTCUT_MANGA - putExtra(Constants.MANGA_EXTRA, mangaId) - addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) + val (rowCount, columnCount) = LocalSize.current.calculateRowAndColumnCount(topPadding, bottomPadding) + Column( + modifier = GlanceModifier.fillMaxHeight(), + verticalAlignment = Alignment.CenterVertically, + horizontalAlignment = Alignment.CenterHorizontally, + ) { + (0.. + val coverRow = (0.. + data.getOrNull(j + (i * columnCount)) + } + if (coverRow.isNotEmpty()) { + Row( + modifier = GlanceModifier + .padding(vertical = 4.dp) + .fillMaxWidth(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalAlignment = Alignment.CenterVertically, + ) { + coverRow.forEach { (mangaId, cover) -> + Box( + modifier = GlanceModifier + .padding(horizontal = 3.dp), + contentAlignment = Alignment.Center, + ) { + val intent = Intent(LocalContext.current, Class.forName(Constants.MAIN_ACTIVITY)).apply { + action = Constants.SHORTCUT_MANGA + putExtra(Constants.MANGA_EXTRA, mangaId) + addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) - // https://issuetracker.google.com/issues/238793260 - addCategory(mangaId.toString()) + // https://issuetracker.google.com/issues/238793260 + addCategory(mangaId.toString()) + } + UpdatesMangaCover( + modifier = GlanceModifier.clickable(actionStartActivity(intent)), + cover = cover, + ) } - UpdatesMangaCover( - modifier = GlanceModifier.clickable(actionStartActivity(intent)), - cover = cover, - ) } } } diff --git a/presentation-widget/src/main/java/tachiyomi/presentation/widget/util/GlanceUtils.kt b/presentation-widget/src/main/java/tachiyomi/presentation/widget/util/GlanceUtils.kt index fe8360a0e..51710a1be 100644 --- a/presentation-widget/src/main/java/tachiyomi/presentation/widget/util/GlanceUtils.kt +++ b/presentation-widget/src/main/java/tachiyomi/presentation/widget/util/GlanceUtils.kt @@ -2,6 +2,7 @@ package tachiyomi.presentation.widget.util import androidx.annotation.StringRes import androidx.compose.runtime.Composable +import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.DpSize import androidx.glance.GlanceModifier import androidx.glance.LocalContext @@ -34,9 +35,13 @@ fun stringResource(@StringRes id: Int): String { * * @return pair of row and column count */ -fun DpSize.calculateRowAndColumnCount(): Pair { +fun DpSize.calculateRowAndColumnCount( + topPadding: Dp, + bottomPadding: Dp, +): Pair { // Hack: Size provided by Glance manager is not reliable so take at least 1 row and 1 column // Set max to 10 children each direction because of Glance limitation + val height = this.height - topPadding - bottomPadding val rowCount = (height.value / 95).toInt().coerceIn(1, 10) val columnCount = (width.value / 64).toInt().coerceIn(1, 10) return Pair(rowCount, columnCount) diff --git a/presentation-widget/src/main/res/drawable-nodpi/updates_grid_coverscreen_widget_preview.webp b/presentation-widget/src/main/res/drawable-nodpi/updates_grid_coverscreen_widget_preview.webp new file mode 100644 index 000000000..b28fb91b9 Binary files /dev/null and b/presentation-widget/src/main/res/drawable-nodpi/updates_grid_coverscreen_widget_preview.webp differ diff --git a/app/src/main/res/drawable-nodpi/updates_grid_widget_preview.webp b/presentation-widget/src/main/res/drawable-nodpi/updates_grid_widget_preview.webp similarity index 100% rename from app/src/main/res/drawable-nodpi/updates_grid_widget_preview.webp rename to presentation-widget/src/main/res/drawable-nodpi/updates_grid_widget_preview.webp diff --git a/presentation-widget/src/main/res/drawable/appwidget_coverscreen_background.xml b/presentation-widget/src/main/res/drawable/appwidget_coverscreen_background.xml new file mode 100644 index 000000000..066a95b17 --- /dev/null +++ b/presentation-widget/src/main/res/drawable/appwidget_coverscreen_background.xml @@ -0,0 +1,5 @@ + + + + diff --git a/presentation-widget/src/main/res/layout/appwidget_coverscreen_loading.xml b/presentation-widget/src/main/res/layout/appwidget_coverscreen_loading.xml new file mode 100644 index 000000000..057df58f8 --- /dev/null +++ b/presentation-widget/src/main/res/layout/appwidget_coverscreen_loading.xml @@ -0,0 +1,14 @@ + + + + + + diff --git a/presentation-widget/src/main/res/values/colors_appwidget.xml b/presentation-widget/src/main/res/values/colors_appwidget.xml index 7d07ea1f8..a5526c94c 100644 --- a/presentation-widget/src/main/res/values/colors_appwidget.xml +++ b/presentation-widget/src/main/res/values/colors_appwidget.xml @@ -1,6 +1,7 @@ @color/tachiyomi_surface + #00000000 @color/tachiyomi_onSurface @color/tachiyomi_surfaceVariant @color/tachiyomi_onSurfaceVariant diff --git a/app/src/main/res/xml/updates_grid_glance_widget_info.xml b/presentation-widget/src/main/res/xml/updates_grid_homescreen_widget_info.xml similarity index 100% rename from app/src/main/res/xml/updates_grid_glance_widget_info.xml rename to presentation-widget/src/main/res/xml/updates_grid_homescreen_widget_info.xml diff --git a/presentation-widget/src/main/res/xml/updates_grid_lockscreen_widget_info.xml b/presentation-widget/src/main/res/xml/updates_grid_lockscreen_widget_info.xml new file mode 100644 index 000000000..62a91467c --- /dev/null +++ b/presentation-widget/src/main/res/xml/updates_grid_lockscreen_widget_info.xml @@ -0,0 +1,7 @@ + + diff --git a/presentation-widget/src/main/res/xml/updates_grid_samsung_cover_widget_info.xml b/presentation-widget/src/main/res/xml/updates_grid_samsung_cover_widget_info.xml new file mode 100644 index 000000000..5f20ff228 --- /dev/null +++ b/presentation-widget/src/main/res/xml/updates_grid_samsung_cover_widget_info.xml @@ -0,0 +1,4 @@ + + diff --git a/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/CatalogueSource.kt b/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/CatalogueSource.kt index f9e416def..937fa28a9 100644 --- a/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/CatalogueSource.kt +++ b/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/CatalogueSource.kt @@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.source import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.MangasPage import rx.Observable +import tachiyomi.core.util.lang.awaitSingle interface CatalogueSource : Source { @@ -17,30 +18,63 @@ interface CatalogueSource : Source { val supportsLatest: Boolean /** - * Returns an observable containing a page with a list of manga. + * Get a page with a list of manga. * + * @since extensions-lib 1.5 * @param page the page number to retrieve. */ - fun fetchPopularManga(page: Int): Observable + @Suppress("DEPRECATION") + suspend fun getPopularManga(page: Int): MangasPage { + return fetchPopularManga(page).awaitSingle() + } /** - * Returns an observable containing a page with a list of manga. + * Get a page with a list of manga. * + * @since extensions-lib 1.5 * @param page the page number to retrieve. * @param query the search query. * @param filters the list of filters to apply. */ - fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable + @Suppress("DEPRECATION") + suspend fun getSearchManga(page: Int, query: String, filters: FilterList): MangasPage { + return fetchSearchManga(page, query, filters).awaitSingle() + } /** - * Returns an observable containing a page with a list of latest manga updates. + * Get a page with a list of latest manga updates. * + * @since extensions-lib 1.5 * @param page the page number to retrieve. */ - fun fetchLatestUpdates(page: Int): Observable + @Suppress("DEPRECATION") + suspend fun getLatestUpdates(page: Int): MangasPage { + return fetchLatestUpdates(page).awaitSingle() + } /** * Returns the list of filters for the source. */ fun getFilterList(): FilterList + + @Deprecated( + "Use the non-RxJava API instead", + ReplaceWith("getPopularManga"), + ) + fun fetchPopularManga(page: Int): Observable = + throw IllegalStateException("Not used") + + @Deprecated( + "Use the non-RxJava API instead", + ReplaceWith("getSearchManga"), + ) + fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable = + throw IllegalStateException("Not used") + + @Deprecated( + "Use the non-RxJava API instead", + ReplaceWith("getLatestUpdates"), + ) + fun fetchLatestUpdates(page: Int): Observable = + throw IllegalStateException("Not used") } diff --git a/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/ConfigurableSource.kt b/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/ConfigurableSource.kt index d42885f80..4be411e3b 100644 --- a/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/ConfigurableSource.kt +++ b/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/ConfigurableSource.kt @@ -1,6 +1,20 @@ package eu.kanade.tachiyomi.source +import android.app.Application +import android.content.Context +import android.content.SharedPreferences +import uy.kohesive.injekt.Injekt +import uy.kohesive.injekt.api.get + interface ConfigurableSource : Source { + /** + * Gets instance of [SharedPreferences] scoped to the specific source. + * + * @since extensions-lib 1.5 + */ + fun getPreferences(): SharedPreferences = + Injekt.get().getSharedPreferences("source_$id", Context.MODE_PRIVATE) + fun setupPreferenceScreen(screen: PreferenceScreen) } diff --git a/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/Source.kt b/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/Source.kt index 15747af98..83fcd7962 100644 --- a/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/Source.kt +++ b/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/Source.kt @@ -27,7 +27,9 @@ interface Source { /** * Get the updated details for a manga. * + * @since extensions-lib 1.5 * @param manga the manga to update. + * @return the updated manga. */ @Suppress("DEPRECATION") suspend fun getMangaDetails(manga: SManga): SManga { @@ -37,7 +39,9 @@ interface Source { /** * Get all the available chapters for a manga. * + * @since extensions-lib 1.5 * @param manga the manga to update. + * @return the chapters for the manga. */ @Suppress("DEPRECATION") suspend fun getChapterList(manga: SManga): List { @@ -48,44 +52,33 @@ interface Source { * Get the list of pages a chapter has. Pages should be returned * in the expected order; the index is ignored. * + * @since extensions-lib 1.5 * @param chapter the chapter. + * @return the pages for the chapter. */ @Suppress("DEPRECATION") suspend fun getPageList(chapter: SChapter): List { return fetchPageList(chapter).awaitSingle() } - /** - * Returns an observable with the updated details for a manga. - * - * @param manga the manga to update. - */ @Deprecated( "Use the non-RxJava API instead", ReplaceWith("getMangaDetails"), ) - fun fetchMangaDetails(manga: SManga): Observable = throw IllegalStateException("Not used") + fun fetchMangaDetails(manga: SManga): Observable = + throw IllegalStateException("Not used") - /** - * Returns an observable with all the available chapters for a manga. - * - * @param manga the manga to update. - */ @Deprecated( "Use the non-RxJava API instead", ReplaceWith("getChapterList"), ) - fun fetchChapterList(manga: SManga): Observable> = throw IllegalStateException("Not used") + fun fetchChapterList(manga: SManga): Observable> = + throw IllegalStateException("Not used") - /** - * Returns an observable with the list of pages a chapter has. Pages should be returned - * in the expected order; the index is ignored. - * - * @param chapter the chapter. - */ @Deprecated( "Use the non-RxJava API instead", ReplaceWith("getPageList"), ) - fun fetchPageList(chapter: SChapter): Observable> = Observable.empty() + fun fetchPageList(chapter: SChapter): Observable> = + throw IllegalStateException("Not used") } diff --git a/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/model/Filter.kt b/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/model/Filter.kt index f30b2f52d..99c72e58e 100644 --- a/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/model/Filter.kt +++ b/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/model/Filter.kt @@ -3,7 +3,10 @@ package eu.kanade.tachiyomi.source.model sealed class Filter(val name: String, var state: T) { open class Header(name: String) : Filter(name, 0) open class Separator(name: String = "") : Filter(name, 0) - abstract class Select(name: String, val values: Array, state: Int = 0) : Filter(name, state) + abstract class Select(name: String, val values: Array, state: Int = 0) : Filter( + name, + state, + ) abstract class Text(name: String, state: String = "") : Filter(name, state) abstract class CheckBox(name: String, state: Boolean = false) : Filter(name, state) abstract class TriState(name: String, state: Int = STATE_IGNORE) : Filter(name, state) { diff --git a/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/online/HttpSource.kt b/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/online/HttpSource.kt index 7378f43a8..957febceb 100644 --- a/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/online/HttpSource.kt +++ b/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/online/HttpSource.kt @@ -16,6 +16,7 @@ import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.Response import rx.Observable +import tachiyomi.core.util.lang.awaitSingle import uy.kohesive.injekt.injectLazy import java.net.URI import java.net.URISyntaxException @@ -24,6 +25,7 @@ import java.security.MessageDigest /** * A simple implementation for sources from a website. */ +@Suppress("unused") abstract class HttpSource : CatalogueSource { /** @@ -81,6 +83,7 @@ abstract class HttpSource : CatalogueSource { * @param versionId [Int] the version ID of the source * @return a unique ID for the source */ + @Suppress("MemberVisibilityCanBePrivate") protected fun generateId(name: String, lang: String, versionId: Int): Long { val key = "${name.lowercase()}/$lang/$versionId" val bytes = MessageDigest.getInstance("MD5").digest(key.toByteArray()) @@ -135,7 +138,11 @@ abstract class HttpSource : CatalogueSource { * @param query the search query. * @param filters the list of filters to apply. */ - override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable { + override fun fetchSearchManga( + page: Int, + query: String, + filters: FilterList, + ): Observable { return Observable.defer { try { client.newCall(searchMangaRequest(page, query, filters)).asObservableSuccess() @@ -157,7 +164,11 @@ abstract class HttpSource : CatalogueSource { * @param query the search query. * @param filters the list of filters to apply. */ - protected abstract fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request + protected abstract fun searchMangaRequest( + page: Int, + query: String, + filters: FilterList, + ): Request /** * Parses the response from the site and returns a [MangasPage] object. @@ -194,11 +205,18 @@ abstract class HttpSource : CatalogueSource { protected abstract fun latestUpdatesParse(response: Response): MangasPage /** - * Returns an observable with the updated details for a manga. Normally it's not needed to - * override this method. + * Get the updated details for a manga. + * Normally it's not needed to override this method. * - * @param manga the manga to be updated. + * @param manga the manga to update. + * @return the updated manga. */ + @Suppress("DEPRECATION") + override suspend fun getMangaDetails(manga: SManga): SManga { + return fetchMangaDetails(manga).awaitSingle() + } + + @Deprecated("Use the non-RxJava API instead", replaceWith = ReplaceWith("getMangaDetails")) override fun fetchMangaDetails(manga: SManga): Observable { return client.newCall(mangaDetailsRequest(manga)) .asObservableSuccess() @@ -225,11 +243,23 @@ abstract class HttpSource : CatalogueSource { protected abstract fun mangaDetailsParse(response: Response): SManga /** - * Returns an observable with the updated chapter list for a manga. Normally it's not needed to - * override this method. If a manga is licensed an empty chapter list observable is returned + * Get all the available chapters for a manga. + * Normally it's not needed to override this method. * - * @param manga the manga to look for chapters. + * @param manga the manga to update. + * @return the chapters for the manga. + * @throws LicensedMangaChaptersException if a manga is licensed and therefore no chapters are available. */ + @Suppress("DEPRECATION") + override suspend fun getChapterList(manga: SManga): List { + if (manga.status == SManga.LICENSED) { + throw LicensedMangaChaptersException() + } + + return fetchChapterList(manga).awaitSingle() + } + + @Deprecated("Use the non-RxJava API instead", replaceWith = ReplaceWith("getChapterList")) override fun fetchChapterList(manga: SManga): Observable> { return if (manga.status != SManga.LICENSED) { client.newCall(chapterListRequest(manga)) @@ -260,10 +290,18 @@ abstract class HttpSource : CatalogueSource { protected abstract fun chapterListParse(response: Response): List /** - * Returns an observable with the page list for a chapter. + * Get the list of pages a chapter has. Pages should be returned + * in the expected order; the index is ignored. * - * @param chapter the chapter whose page list has to be fetched. + * @param chapter the chapter. + * @return the pages for the chapter. */ + @Suppress("DEPRECATION") + override suspend fun getPageList(chapter: SChapter): List { + return fetchPageList(chapter).awaitSingle() + } + + @Deprecated("Use the non-RxJava API instead", replaceWith = ReplaceWith("getPageList")) override fun fetchPageList(chapter: SChapter): Observable> { return client.newCall(pageListRequest(chapter)) .asObservableSuccess() @@ -293,8 +331,15 @@ abstract class HttpSource : CatalogueSource { * Returns an observable with the page containing the source url of the image. If there's any * error, it will return null instead of throwing an exception. * + * @since extensions-lib 1.5 * @param page the page whose source image has to be fetched. */ + @Suppress("DEPRECATION") + open suspend fun getImageUrl(page: Page): String { + return fetchImageUrl(page).awaitSingle() + } + + @Deprecated("Use the non-RxJava API instead", replaceWith = ReplaceWith("getImageUrl")) open fun fetchImageUrl(page: Page): Observable { return client.newCall(imageUrlRequest(page)) .asObservableSuccess() @@ -318,24 +363,14 @@ abstract class HttpSource : CatalogueSource { */ protected abstract fun imageUrlParse(response: Response): String - /** - * Returns an observable with the response of the source image. - * - * @param page the page whose source image has to be downloaded. - */ - fun fetchImage(page: Page): Observable { - // images will be cached or saved manually, so don't take up network cache - return client.newCachelessCallWithProgress(imageRequest(page), page) - .asObservableSuccess() - } - /** * Returns the response of the source image. + * Typically does not need to be overridden. * + * @since extensions-lib 1.5 * @param page the page whose source image has to be downloaded. */ - suspend fun getImage(page: Page): Response { - // images will be cached or saved manually, so don't take up network cache + open suspend fun getImage(page: Page): Response { return client.newCachelessCallWithProgress(imageRequest(page), page) .awaitSuccess() } diff --git a/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/online/HttpSourceFetcher.kt b/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/online/HttpSourceFetcher.kt deleted file mode 100644 index 76c68e882..000000000 --- a/source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/online/HttpSourceFetcher.kt +++ /dev/null @@ -1,25 +0,0 @@ -package eu.kanade.tachiyomi.source.online - -import eu.kanade.tachiyomi.source.model.Page -import rx.Observable - -fun HttpSource.fetchAllImageUrlsFromPageList(pages: List): Observable { - return Observable.from(pages) - .filter { !it.imageUrl.isNullOrEmpty() } - .mergeWith(fetchRemainingImageUrlsFromPageList(pages)) -} - -private fun HttpSource.fetchRemainingImageUrlsFromPageList(pages: List): Observable { - return Observable.from(pages) - .filter { it.imageUrl.isNullOrEmpty() } - .concatMap { getImageUrl(it) } -} - -private fun HttpSource.getImageUrl(page: Page): Observable { - page.status = Page.State.LOAD_PAGE - return fetchImageUrl(page) - .doOnError { page.status = Page.State.ERROR } - .onErrorReturn { null } - .doOnNext { page.imageUrl = it } - .map { page } -} diff --git a/source-local/src/androidMain/kotlin/tachiyomi/source/local/LocalSource.kt b/source-local/src/androidMain/kotlin/tachiyomi/source/local/LocalSource.kt index 403419df2..b74dcbb2d 100644 --- a/source-local/src/androidMain/kotlin/tachiyomi/source/local/LocalSource.kt +++ b/source-local/src/androidMain/kotlin/tachiyomi/source/local/LocalSource.kt @@ -16,7 +16,6 @@ import kotlinx.serialization.json.decodeFromStream import logcat.LogPriority import nl.adaptivity.xmlutil.AndroidXmlReader import nl.adaptivity.xmlutil.serialization.XML -import rx.Observable import tachiyomi.core.metadata.comicinfo.COMIC_INFO_FILE import tachiyomi.core.metadata.comicinfo.ComicInfo import tachiyomi.core.metadata.comicinfo.copyFromComicInfo @@ -66,11 +65,11 @@ actual class LocalSource( override val supportsLatest: Boolean = true // Browse related - override fun fetchPopularManga(page: Int) = fetchSearchManga(page, "", POPULAR_FILTERS) + override suspend fun getPopularManga(page: Int) = getSearchManga(page, "", POPULAR_FILTERS) - override fun fetchLatestUpdates(page: Int) = fetchSearchManga(page, "", LATEST_FILTERS) + override suspend fun getLatestUpdates(page: Int) = getSearchManga(page, "", LATEST_FILTERS) - override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable { + override suspend fun getSearchManga(page: Int, query: String, filters: FilterList): MangasPage { val baseDirsFiles = fileSystem.getFilesInBaseDirectories() val lastModifiedLimit by lazy { if (filters === LATEST_FILTERS) System.currentTimeMillis() - LATEST_THRESHOLD else 0L } var mangaDirs = baseDirsFiles @@ -143,7 +142,7 @@ actual class LocalSource( } } - return Observable.just(MangasPage(mangas.toList(), false)) + return MangasPage(mangas.toList(), false) } // Manga details related @@ -349,7 +348,7 @@ actual class LocalSource( companion object { const val ID = 0L - const val HELP_URL = "https://tachiyomi.org/help/guides/local-manga/" + const val HELP_URL = "https://tachiyomi.org/docs/guides/local-source/" private val LATEST_THRESHOLD = 7.days.inWholeMilliseconds }