diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 800e667cbb..18884b4184 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -52,19 +52,22 @@ jobs: - name: Check code format run: ./gradlew spotlessCheck - - name: Build app - run: ./gradlew assembleRelease -Penable-updater - - name: Run unit tests id: unit_tests - run: ./gradlew testReleaseUnitTest + run: ./gradlew testDebugUnitTest + + - name: Verify SQLDelight migrations + run: ./gradlew verifySqlDelightMigration - name: Upload test report if: steps.unit_tests.outcome == 'failure' uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 with: name: test-report-${{ github.sha }} - path: app/build/reports/tests/testReleaseUnitTest + path: app/build/reports/tests/testDebugUnitTest + + - name: Build app + run: ./gradlew assembleRelease -Penable-updater - name: Upload APK uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 22049ed60e..a009f885c5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -59,7 +59,7 @@ jobs: run: ./gradlew assembleRelease -Penable-updater - name: Sign APK - uses: r0adkll/sign-android-release@f30bdd30588842ac76044ecdbd4b6d0e3e813478 + uses: r0adkll/sign-android-release@a391126403df92c6a0a3988a829dd47f79b89ed7 with: releaseDirectory: app/build/outputs/apk/release signingKeyBase64: ${{ secrets.SIGNING_KEY }} @@ -110,7 +110,7 @@ jobs: Animiru - name: Create GitHub Release - uses: softprops/action-gh-release@153bb8e04406b158c6c84fc1615b65b24149a1fe # v2.6.1 + uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2.6.2 with: tag_name: ${{ needs.get_tag.outputs.tag }} name: Animiru ${{ needs.get_tag.outputs.tag }} diff --git a/CHANGELOG.md b/CHANGELOG.md index c3ac2e9a5d..bbfe0bc66e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,9 @@ The format is a modified version of [Keep a Changelog](https://keepachangelog.co ### Added - Added system font fallback ([@Secozzi](https://github.com/Secozzi)) ([#156](https://github.com/quickdesh/Animiru/pull/156)) +### Other +- Merge from Mihon ([@Secozzi](https://github.com/Secozzi)) ([#155](https://github.com/quickdesh/Animiru/pull/155)) + ## [v0.19.7.3] - 2026-04-17 ### Improved - Allow options in mpv.conf to override options set by `AniyomiMPVView` ([@Secozzi](https://github.com/Secozzi)) ([#151](https://github.com/quickdesh/Animiru/pull/151)) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 13e8a7bb16..1aac9df567 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,18 +1,18 @@ -import mihon.buildlogic.Config -import mihon.buildlogic.getBuildTime -import mihon.buildlogic.getCommitCount -import mihon.buildlogic.getGitSha +import mihon.gradle.Config +import mihon.gradle.getBuildTime +import mihon.gradle.getLatestCommitCount +import mihon.gradle.getLatestCommitSha +import mihon.gradle.tasks.ReplaceShortcutsPlaceholderTask plugins { - id("mihon.android.application") - id("mihon.android.application.compose") - id("com.github.zellius.shortcut-helper") - kotlin("plugin.serialization") + alias(mihonx.plugins.android.application) + alias(mihonx.plugins.compose) + alias(mihonx.plugins.spotless) + alias(libs.plugins.aboutLibraries) + alias(libs.plugins.kotlin.serialization) } -shortcutHelper.setFilePath("./shortcuts.xml") - android { namespace = "eu.kanade.tachiyomi" @@ -22,9 +22,9 @@ android { versionCode = 140 versionName = "0.19.7.3" - buildConfigField("String", "COMMIT_COUNT", "\"${getCommitCount()}\"") - buildConfigField("String", "COMMIT_SHA", "\"${getGitSha()}\"") - buildConfigField("String", "BUILD_TIME", "\"${getBuildTime(useLastCommitTime = false)}\"") + buildConfigField("String", "COMMIT_COUNT", "\"${getLatestCommitCount()}\"") + buildConfigField("String", "COMMIT_SHA", "\"${getLatestCommitSha()}\"") + buildConfigField("String", "BUILD_TIME", "\"${getBuildTime(useLatestCommitTime = false)}\"") buildConfigField("boolean", "UPDATER_ENABLED", "${Config.enableUpdater}") testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" @@ -33,7 +33,7 @@ android { buildTypes { val debug by getting { applicationIdSuffix = ".dev" - versionNameSuffix = "-${getCommitCount()}" + versionNameSuffix = "-${getLatestCommitCount()}" isPseudoLocalesEnabled = true } val release by getting { @@ -42,7 +42,7 @@ android { proguardFiles("proguard-android-optimize.txt", "proguard-rules.pro") - buildConfigField("String", "BUILD_TIME", "\"${getBuildTime(useLastCommitTime = true)}\"") + buildConfigField("String", "BUILD_TIME", "\"${getBuildTime(useLatestCommitTime = true)}\"") } val commonMatchingFallbacks = listOf(release.name) @@ -57,7 +57,7 @@ android { matchingFallbacks.addAll(commonMatchingFallbacks) - buildConfigField("String", "BUILD_TIME", "\"${getBuildTime(useLastCommitTime = false)}\"") + buildConfigField("String", "BUILD_TIME", "\"${getBuildTime(useLatestCommitTime = false)}\"") } create("benchmark") { initWith(release) @@ -74,8 +74,8 @@ android { } sourceSets { - getByName("preview").res.srcDirs("src/debug/res") - getByName("benchmark").res.srcDirs("src/debug/res") + getByName("preview").res.directories.add("src/debug/res") + getByName("benchmark").res.directories.add("src/debug/res") } splits { @@ -138,10 +138,6 @@ android { viewBinding = true buildConfig = true aidl = true - - // Disable some unused things - renderScript = false - shaders = false } lint { @@ -189,81 +185,81 @@ dependencies { implementation(projects.presentationWidget) // Compose - implementation(compose.activity) - implementation(compose.foundation) - implementation(compose.material3.core) - implementation(compose.material.icons) - implementation(compose.animation) - implementation(compose.animation.graphics) - debugImplementation(compose.ui.tooling) - implementation(compose.ui.tooling.preview) - implementation(compose.ui.util) + implementation(libs.androidx.activity.compose) + implementation(libs.androidx.compose.foundation) + implementation(libs.androidx.compose.material3) + implementation(libs.androidx.compose.materialIcons) + implementation(libs.androidx.compose.animation) + implementation(libs.androidx.compose.animationGraphics) + debugImplementation(libs.androidx.compose.uiTooling) + implementation(libs.androidx.compose.uiToolingPreview) + implementation(libs.androidx.compose.uiUtil) - implementation(androidx.interpolator) + implementation(libs.androidx.interpolator) - implementation(androidx.paging.runtime) - implementation(androidx.paging.compose) + implementation(libs.androidx.paging.runtime) + implementation(libs.androidx.paging.compose) - implementation(androidx.sqlite.bundled) + implementation(libs.androidx.sqlite.bundled) - implementation(kotlinx.reflect) - implementation(kotlinx.immutables) + implementation(libs.kotlin.reflect) + implementation(libs.kotlinx.collections.immutable) - implementation(platform(kotlinx.coroutines.bom)) - implementation(kotlinx.bundles.coroutines) + implementation(libs.bundles.kotlinx.coroutines) + + implementation(libs.sqldelight.async) // AndroidX libraries - implementation(androidx.annotation) - implementation(androidx.appcompat) - implementation(androidx.biometricktx) - implementation(androidx.constraintlayout) + implementation(libs.androidx.annotation) + implementation(libs.androidx.appCompat) + implementation(libs.androidx.biometric) + implementation(libs.androidx.constraintLayout) // AY --> implementation(aniyomilibs.compose.constraintlayout) // <-- AY - implementation(androidx.corektx) - implementation(androidx.splashscreen) - implementation(androidx.recyclerview) + implementation(libs.androidx.core) + implementation(libs.androidx.coreSplashScreen) + implementation(libs.androidx.recyclerView) // AM (REMOVE_LIBRARIES) --> - // implementation(androidx.viewpager) + // implementation(libs.androidx.viewPager) // <-- AM (REMOVE_LIBRARIES) - implementation(androidx.profileinstaller) + implementation(libs.androidx.profileInstaller) // AY --> implementation(aniyomilibs.mediasession) // <-- AY - implementation(androidx.bundles.lifecycle) + implementation(libs.bundles.androidx.lifecycle) // Job scheduling - implementation(androidx.workmanager) + implementation(libs.androidx.work) // RxJava - implementation(libs.rxjava) + implementation(libs.rxJava) // Networking implementation(libs.bundles.okhttp) implementation(libs.okio) - implementation(libs.conscrypt.android) // TLS 1.3 support for Android < 10 + implementation(libs.conscrypt) // TLS 1.3 support for Android < 10 // Data serialization (JSON, protobuf, xml) - implementation(kotlinx.bundles.serialization) + implementation(libs.bundles.serialization) // HTML parser implementation(libs.jsoup) // Disk - implementation(libs.disklrucache) + implementation(libs.diskLruCache) implementation(libs.unifile) // Preferences - implementation(libs.preferencektx) + implementation(libs.androidx.preference) // Dependency injection implementation(libs.injekt) // Image loading - implementation(platform(libs.coil.bom)) implementation(libs.bundles.coil) - implementation(libs.subsamplingscaleimageview) { + implementation(libs.subsamplingScaleImageView) { exclude(module = "image-decoder") } // AM (REMOVE_LIBRARIES) --> @@ -272,20 +268,20 @@ dependencies { // UI libraries implementation(libs.material) - implementation(libs.flexible.adapter.core) + implementation(libs.flexibleAdapter) // AM (REMOVE_LIBRARIES) --> - // implementation(libs.photoview) - // implementation(libs.directionalviewpager) { + // implementation(libs.photoView) + // implementation(libs.directionalViewPager) { // exclude(group = "androidx.viewpager", module = "viewpager") // } // <-- AM (REMOVE_LIBRARIES) - implementation(libs.richeditor.compose) + implementation(libs.composeRichEditor) implementation(libs.aboutLibraries.compose) implementation(libs.bundles.voyager) - implementation(libs.compose.materialmotion) + implementation(libs.composeMaterialMotion) implementation(libs.swipe) - implementation(libs.compose.webview) - implementation(libs.compose.grid) + implementation(libs.composeWebview) + implementation(libs.composeGrid) implementation(libs.reorderable) implementation(libs.bundles.markdown) implementation(libs.materialKolor) @@ -304,9 +300,9 @@ dependencies { testRuntimeOnly(libs.junit.platform.launcher) // For detecting memory leaks; see https://square.github.io/leakcanary/ - // debugImplementation(libs.leakcanary.android) + // debugImplementation(libs.leakCanary.android) // AM (REMOVE_LIBRARIES) --> - // implementation(libs.leakcanary.plumber) + // implementation(libs.leakCanary.plumber) // <-- AM (REMOVE_LIBRARIES) // AY --> @@ -329,19 +325,26 @@ dependencies { implementation(aniyomilibs.google.api.client.oauth) // <-- AM (SYNC_DRIVE) - testImplementation(kotlinx.coroutines.test) + testImplementation(libs.kotlinx.coroutines.test) } androidComponents { + onVariants { variant -> + val resSource = variant.sources.res ?: return@onVariants + + val variantName = variant.name.replaceFirstChar { it.uppercase() } + val replaceShortcutsPlaceholderTask = tasks.register( + "replace${variantName}ShortcutPlaceholder", + ) { + applicationId.set(variant.applicationId) + shortcutsFile.set(projectDir.resolve("src/main/shortcuts.xml")) + } + resSource.addGeneratedSourceDirectory(replaceShortcutsPlaceholderTask) { it.outputDir } + } + onVariants(selector().withFlavor("default" to "standard")) { // Only excluding in standard flavor because this breaks // Layout Inspector's Compose tree it.packaging.resources.excludes.add("META-INF/*.version") } } - -buildscript { - dependencies { - classpath(kotlinx.gradle) - } -} diff --git a/app/src/main/java/eu/kanade/domain/anime/interactor/GetExcludedScanlators.kt b/app/src/main/java/eu/kanade/domain/anime/interactor/GetExcludedScanlators.kt index 0b25aa693a..215e018ac6 100644 --- a/app/src/main/java/eu/kanade/domain/anime/interactor/GetExcludedScanlators.kt +++ b/app/src/main/java/eu/kanade/domain/anime/interactor/GetExcludedScanlators.kt @@ -1,24 +1,24 @@ package eu.kanade.domain.anime.interactor +import app.cash.sqldelight.async.coroutines.awaitAsList import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map -import tachiyomi.data.DatabaseHandler +import tachiyomi.data.Database +import tachiyomi.data.subscribeToList class GetExcludedScanlators( - private val handler: DatabaseHandler, + private val database: Database, ) { suspend fun await(animeId: Long): Set { - return handler.awaitList { - excluded_scanlatorsQueries.getExcludedScanlatorsByAnimeId(animeId) - } + return database.excluded_scanlatorsQueries.getExcludedScanlatorsByAnimeId(animeId) + .awaitAsList() .toSet() } fun subscribe(animeId: Long): Flow> { - return handler.subscribeToList { - excluded_scanlatorsQueries.getExcludedScanlatorsByAnimeId(animeId) - } + return database.excluded_scanlatorsQueries.getExcludedScanlatorsByAnimeId(animeId) + .subscribeToList() .map { it.toSet() } } } diff --git a/app/src/main/java/eu/kanade/domain/anime/interactor/SetExcludedScanlators.kt b/app/src/main/java/eu/kanade/domain/anime/interactor/SetExcludedScanlators.kt index 0b7cc4c5e8..f4b64b4789 100644 --- a/app/src/main/java/eu/kanade/domain/anime/interactor/SetExcludedScanlators.kt +++ b/app/src/main/java/eu/kanade/domain/anime/interactor/SetExcludedScanlators.kt @@ -1,22 +1,22 @@ package eu.kanade.domain.anime.interactor -import tachiyomi.data.DatabaseHandler +import app.cash.sqldelight.async.coroutines.awaitAsList +import tachiyomi.data.Database class SetExcludedScanlators( - private val handler: DatabaseHandler, + private val database: Database, ) { suspend fun await(animeId: Long, excludedScanlators: Set) { - handler.await(inTransaction = true) { - val currentExcluded = handler.awaitList { - excluded_scanlatorsQueries.getExcludedScanlatorsByAnimeId(animeId) - }.toSet() + database.transaction { + val currentExcluded = database.excluded_scanlatorsQueries.getExcludedScanlatorsByAnimeId(animeId) + .awaitAsList().toSet() val toAdd = excludedScanlators.minus(currentExcluded) for (scanlator in toAdd) { - excluded_scanlatorsQueries.insert(animeId, scanlator) + database.excluded_scanlatorsQueries.insert(animeId, scanlator) } val toRemove = currentExcluded.minus(excludedScanlators) - excluded_scanlatorsQueries.remove(animeId, toRemove) + database.excluded_scanlatorsQueries.remove(animeId, toRemove) } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/AnimeBackupCreator.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/AnimeBackupCreator.kt index 5d19b86de6..b50333da9b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/AnimeBackupCreator.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/AnimeBackupCreator.kt @@ -1,12 +1,14 @@ package eu.kanade.tachiyomi.data.backup.create.creators +import app.cash.sqldelight.async.coroutines.awaitAsList +import app.cash.sqldelight.async.coroutines.awaitAsOne import eu.kanade.tachiyomi.data.backup.create.BackupOptions import eu.kanade.tachiyomi.data.backup.models.BackupAnime import eu.kanade.tachiyomi.data.backup.models.BackupEpisode import eu.kanade.tachiyomi.data.backup.models.BackupHistory import eu.kanade.tachiyomi.data.backup.models.backupEpisodeMapper import eu.kanade.tachiyomi.data.backup.models.backupTrackMapper -import tachiyomi.data.DatabaseHandler +import tachiyomi.data.Database import tachiyomi.domain.anime.interactor.GetCustomAnimeInfo import tachiyomi.domain.anime.model.Anime import tachiyomi.domain.anime.model.CustomAnimeInfo @@ -16,7 +18,7 @@ import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get class AnimeBackupCreator( - private val handler: DatabaseHandler = Injekt.get(), + private val database: Database = Injekt.get(), private val getCategories: GetCategories = Injekt.get(), private val getHistory: GetHistory = Injekt.get(), // AM (CUSTOM_INFORMATION) --> @@ -38,19 +40,17 @@ class AnimeBackupCreator( // <-- AM (CUSTOM_INFORMATION) ) - animeObject.excludedScanlators = handler.awaitList { - excluded_scanlatorsQueries.getExcludedScanlatorsByAnimeId(anime.id) - } + animeObject.excludedScanlators = database.excluded_scanlatorsQueries.getExcludedScanlatorsByAnimeId(anime.id) + .awaitAsList() if (options.episodes) { // Backup all the episodes - handler.awaitList { - episodesQueries.getEpisodesByAnimeId( - animeId = anime.id, - applyScanlatorFilter = 0, // false - mapper = backupEpisodeMapper, - ) - } + database.episodesQueries.getEpisodesByAnimeId( + animeId = anime.id, + applyScanlatorFilter = 0, // false + mapper = backupEpisodeMapper, + ) + .awaitAsList() .takeUnless(List::isEmpty) ?.let { animeObject.episodes = it } } @@ -64,7 +64,7 @@ class AnimeBackupCreator( } if (options.tracking) { - val tracks = handler.awaitList { anime_syncQueries.getTracksByAnimeId(anime.id, backupTrackMapper) } + val tracks = database.anime_syncQueries.getTracksByAnimeId(anime.id, backupTrackMapper).awaitAsList() if (tracks.isNotEmpty()) { animeObject.tracking = tracks } @@ -74,7 +74,7 @@ class AnimeBackupCreator( val historyByAnimeId = getHistory.await(anime.id) if (historyByAnimeId.isNotEmpty()) { val history = historyByAnimeId.map { history -> - val episode = handler.awaitOne { episodesQueries.getEpisodeById(history.episodeId) } + val episode = database.episodesQueries.getEpisodeById(history.episodeId).awaitAsOne() BackupHistory(episode.url, history.seenAt?.time ?: 0L) } if (history.isNotEmpty()) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/AnimeRestorer.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/AnimeRestorer.kt index df1cd984ef..a03fdc598a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/AnimeRestorer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/AnimeRestorer.kt @@ -1,12 +1,15 @@ package eu.kanade.tachiyomi.data.backup.restore.restorers +import app.cash.sqldelight.async.coroutines.awaitAsList +import app.cash.sqldelight.async.coroutines.awaitAsOne +import app.cash.sqldelight.async.coroutines.awaitAsOneOrNull import eu.kanade.domain.anime.interactor.UpdateAnime import eu.kanade.tachiyomi.data.backup.models.BackupAnime import eu.kanade.tachiyomi.data.backup.models.BackupCategory import eu.kanade.tachiyomi.data.backup.models.BackupEpisode import eu.kanade.tachiyomi.data.backup.models.BackupHistory import eu.kanade.tachiyomi.data.backup.models.BackupTracking -import tachiyomi.data.DatabaseHandler +import tachiyomi.data.Database import tachiyomi.data.FetchTypeColumnAdapter import tachiyomi.data.UpdateStrategyColumnAdapter import tachiyomi.domain.anime.interactor.FetchInterval @@ -27,7 +30,7 @@ import java.util.Date import kotlin.math.max class AnimeRestorer( - private val handler: DatabaseHandler = Injekt.get(), + private val database: Database = Injekt.get(), private val getCategories: GetCategories = Injekt.get(), private val getAnimeByUrlAndSourceId: GetAnimeByUrlAndSourceId = Injekt.get(), private val getEpisodesByAnimeId: GetEpisodesByAnimeId = Injekt.get(), @@ -49,7 +52,8 @@ class AnimeRestorer( } suspend fun sortByNew(backupAnimes: List): List { - val urlsBySource = handler.awaitList { animesQueries.getAllAnimeSourceAndUrl() } + val urlsBySource = database.animesQueries.getAllAnimeSourceAndUrl() + .awaitAsList() .groupBy({ it.source }, { it.url }) return backupAnimes @@ -69,7 +73,7 @@ class AnimeRestorer( backupSeasons: List, // <-- AY ) { - handler.await(inTransaction = true) { + database.transaction { val dbAnime = findExistingAnime(backupAnime) val anime = backupAnime.getAnimeImpl() val restoredAnime = if (dbAnime == null) { @@ -144,42 +148,40 @@ class AnimeRestorer( } internal suspend fun updateAnime(anime: Anime): Anime { - handler.await(true) { - animesQueries.update( - source = anime.source, - url = anime.url, - artist = anime.artist, - author = anime.author, - description = anime.description, - genre = anime.genre?.joinToString(separator = ", "), - title = anime.title, - status = anime.status, - thumbnailUrl = anime.thumbnailUrl, - favorite = anime.favorite, - lastUpdate = anime.lastUpdate, - nextUpdate = null, - calculateInterval = null, - initialized = anime.initialized, - viewer = anime.viewerFlags, - episodeFlags = anime.episodeFlags, - coverLastModified = anime.coverLastModified, - dateAdded = anime.dateAdded, - animeId = anime.id, - updateStrategy = anime.updateStrategy.let(UpdateStrategyColumnAdapter::encode), - version = anime.version, - isSyncing = 1, - notes = anime.notes, - // AY --> - fetchType = anime.fetchType.let(FetchTypeColumnAdapter::encode), - parentId = anime.parentId, - seasonFlags = anime.seasonFlags, - seasonNumber = anime.seasonNumber, - seasonSourceOrder = anime.seasonSourceOrder, - backgroundUrl = anime.backgroundUrl, - backgroundLastModified = anime.backgroundLastModified, - // <-- AY - ) - } + database.animesQueries.update( + source = anime.source, + url = anime.url, + artist = anime.artist, + author = anime.author, + description = anime.description, + genre = anime.genre?.joinToString(separator = ", "), + title = anime.title, + status = anime.status, + thumbnailUrl = anime.thumbnailUrl, + favorite = anime.favorite, + lastUpdate = anime.lastUpdate, + nextUpdate = null, + calculateInterval = null, + initialized = anime.initialized, + viewer = anime.viewerFlags, + episodeFlags = anime.episodeFlags, + coverLastModified = anime.coverLastModified, + dateAdded = anime.dateAdded, + animeId = anime.id, + updateStrategy = anime.updateStrategy.let(UpdateStrategyColumnAdapter::encode), + version = anime.version, + isSyncing = 1, + notes = anime.notes, + // AY --> + fetchType = anime.fetchType.let(FetchTypeColumnAdapter::encode), + parentId = anime.parentId, + seasonFlags = anime.seasonFlags, + seasonNumber = anime.seasonNumber, + seasonSourceOrder = anime.seasonSourceOrder, + backgroundUrl = anime.backgroundUrl, + backgroundLastModified = anime.backgroundLastModified, + // <-- AY + ) return anime } @@ -240,9 +242,9 @@ class AnimeRestorer( this.copy(id = 0L, animeId = 0L, dateFetch = 0L, dateUpload = 0L, lastModifiedAt = 0L, version = 0L) private suspend fun insertNewEpisodes(episodes: List) { - handler.await(true) { + database.transaction { episodes.forEach { episode -> - episodesQueries.insert( + database.episodesQueries.insert( episode.animeId, episode.url, episode.name, @@ -271,9 +273,9 @@ class AnimeRestorer( } private suspend fun updateExistingEpisodes(episodes: List) { - handler.await(true) { + database.transaction { episodes.forEach { episode -> - episodesQueries.update( + database.episodesQueries.update( animeId = null, url = null, name = null, @@ -309,41 +311,39 @@ class AnimeRestorer( * @return id of [Anime], null if not found */ private suspend fun insertAnime(anime: Anime): Long { - return handler.awaitOneExecutable(true) { - animesQueries.insert( - source = anime.source, - url = anime.url, - artist = anime.artist, - author = anime.author, - description = anime.description, - genre = anime.genre, - title = anime.title, - status = anime.status, - thumbnailUrl = anime.thumbnailUrl, - favorite = anime.favorite, - lastUpdate = anime.lastUpdate, - nextUpdate = 0L, - calculateInterval = 0L, - initialized = anime.initialized, - viewerFlags = anime.viewerFlags, - episodeFlags = anime.episodeFlags, - coverLastModified = anime.coverLastModified, - dateAdded = anime.dateAdded, - updateStrategy = anime.updateStrategy, - version = anime.version, - notes = anime.notes, - // AY --> - fetchType = anime.fetchType, - parentId = anime.parentId, - seasonFlags = anime.seasonFlags, - seasonNumber = anime.seasonNumber, - seasonSourceOrder = anime.seasonSourceOrder, - backgroundUrl = anime.backgroundUrl, - backgroundLastModified = anime.backgroundLastModified, - // <-- AY - ) - animesQueries.selectLastInsertedRowId() - } + return database.animesQueries.insertReturningId( + source = anime.source, + url = anime.url, + artist = anime.artist, + author = anime.author, + description = anime.description, + genre = anime.genre, + title = anime.title, + status = anime.status, + thumbnailUrl = anime.thumbnailUrl, + favorite = anime.favorite, + lastUpdate = anime.lastUpdate, + nextUpdate = 0L, + calculateInterval = 0L, + initialized = anime.initialized, + viewerFlags = anime.viewerFlags, + episodeFlags = anime.episodeFlags, + coverLastModified = anime.coverLastModified, + dateAdded = anime.dateAdded, + updateStrategy = anime.updateStrategy, + version = anime.version, + notes = anime.notes, + // AY --> + fetchType = anime.fetchType, + parentId = anime.parentId, + seasonFlags = anime.seasonFlags, + seasonNumber = anime.seasonNumber, + seasonSourceOrder = anime.seasonSourceOrder, + backgroundUrl = anime.backgroundUrl, + backgroundLastModified = anime.backgroundLastModified, + // <-- AY + ) + .awaitAsOne() } private suspend fun restoreAnimeDetails( @@ -395,10 +395,10 @@ class AnimeRestorer( } if (animeCategoriesToUpdate.isNotEmpty()) { - handler.await(true) { - animes_categoriesQueries.deleteAnimeCategoryByAnimeId(anime.id) + database.transaction { + database.animes_categoriesQueries.deleteAnimeCategoryByAnimeId(anime.id) animeCategoriesToUpdate.forEach { (animeId, categoryId) -> - animes_categoriesQueries.insert(animeId, categoryId) + database.animes_categoriesQueries.insert(animeId, categoryId) } } } @@ -406,11 +406,11 @@ class AnimeRestorer( private suspend fun restoreHistory(backupHistory: List) { val toUpdate = backupHistory.mapNotNull { history -> - val dbHistory = handler.awaitOneOrNull { historyQueries.getHistoryByEpisodeUrl(history.url) } + val dbHistory = database.historyQueries.getHistoryByEpisodeUrl(history.url).awaitAsOneOrNull() val item = history.getHistoryImpl() if (dbHistory == null) { - val episode = handler.awaitOneOrNull { episodesQueries.getEpisodeByUrl(history.url) } + val episode = database.episodesQueries.getEpisodeByUrl(history.url).awaitAsOneOrNull() return@mapNotNull if (episode == null) { // Episode doesn't exist; skip null @@ -430,14 +430,13 @@ class AnimeRestorer( ) } - if (toUpdate.isNotEmpty()) { - handler.await(true) { - toUpdate.forEach { - historyQueries.upsert( - it.episodeId, - it.seenAt, - ) - } + if (toUpdate.isEmpty()) return + database.transaction { + toUpdate.forEach { + database.historyQueries.upsert( + it.episodeId, + it.seenAt, + ) } } } @@ -472,26 +471,25 @@ class AnimeRestorer( if (newTracks.isNotEmpty()) { insertTrack.awaitAll(newTracks) } - if (existingTracks.isNotEmpty()) { - handler.await(true) { - existingTracks.forEach { track -> - anime_syncQueries.update( - track.animeId, - track.trackerId, - track.remoteId, - track.libraryId, - track.title, - track.lastEpisodeSeen, - track.totalEpisodes, - track.status, - track.score, - track.remoteUrl, - track.startDate, - track.finishDate, - track.private, - track.id, - ) - } + if (existingTracks.isEmpty()) return + database.transaction { + existingTracks.forEach { track -> + database.anime_syncQueries.update( + track.animeId, + track.trackerId, + track.remoteId, + track.libraryId, + track.title, + track.lastEpisodeSeen, + track.totalEpisodes, + track.status, + track.score, + track.remoteUrl, + track.startDate, + track.finishDate, + track.private, + track.id, + ) } } } @@ -506,16 +504,12 @@ class AnimeRestorer( */ private suspend fun restoreExcludedScanlators(anime: Anime, excludedScanlators: List) { if (excludedScanlators.isEmpty()) return - val existingExcludedScanlators = handler.awaitList { - excluded_scanlatorsQueries.getExcludedScanlatorsByAnimeId(anime.id) - } + val existingExcludedScanlators = database.excluded_scanlatorsQueries.getExcludedScanlatorsByAnimeId(anime.id) + .awaitAsList() val toInsert = excludedScanlators.filter { it !in existingExcludedScanlators } - if (toInsert.isNotEmpty()) { - handler.await { - toInsert.forEach { - excluded_scanlatorsQueries.insert(anime.id, it) - } - } + if (toInsert.isEmpty()) return + toInsert.forEach { + database.excluded_scanlatorsQueries.insert(anime.id, it) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/CategoriesRestorer.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/CategoriesRestorer.kt index 3d73cfefc1..9c6cb7307c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/CategoriesRestorer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/CategoriesRestorer.kt @@ -1,14 +1,15 @@ package eu.kanade.tachiyomi.data.backup.restore.restorers +import app.cash.sqldelight.async.coroutines.awaitAsOne import eu.kanade.tachiyomi.data.backup.models.BackupCategory -import tachiyomi.data.DatabaseHandler +import tachiyomi.data.Database import tachiyomi.domain.category.interactor.GetCategories import tachiyomi.domain.library.service.LibraryPreferences import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get class CategoriesRestorer( - private val handler: DatabaseHandler = Injekt.get(), + private val database: Database = Injekt.get(), private val getCategories: GetCategories = Injekt.get(), private val libraryPreferences: LibraryPreferences = Injekt.get(), ) { @@ -25,10 +26,7 @@ class CategoriesRestorer( val dbCategory = dbCategoriesByName[it.name] if (dbCategory != null) return@map dbCategory val order = nextOrder++ - handler.awaitOneExecutable { - categoriesQueries.insert(it.name, order, it.flags) - categoriesQueries.selectLastInsertedRowId() - } + database.categoriesQueries.insert(it.name, order, it.flags) .let { id -> it.toCategory(id).copy(order = order) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/CustomButtonRestorer.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/CustomButtonRestorer.kt index af50f6918b..e16221d030 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/CustomButtonRestorer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/CustomButtonRestorer.kt @@ -1,14 +1,15 @@ // AY --> package eu.kanade.tachiyomi.data.backup.restore.restorers +import app.cash.sqldelight.async.coroutines.awaitAsOne import eu.kanade.tachiyomi.data.backup.models.BackupCustomButtons -import tachiyomi.data.DatabaseHandler +import tachiyomi.data.Database import tachiyomi.domain.custombutton.interactor.GetCustomButtons import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get class CustomButtonRestorer( - private val handler: DatabaseHandler = Injekt.get(), + private val database: Database = Injekt.get(), private val getCustomButtons: GetCustomButtons = Injekt.get(), ) { suspend operator fun invoke( @@ -26,18 +27,16 @@ class CustomButtonRestorer( val dbCustomButton = dbCustomButtonsByName[it.name] if (dbCustomButton != null) return@map dbCustomButton val sortIndex = nextSortIndex++ - handler.awaitOneExecutable { - val isFavorite = it.isFavorite && !dbHasFavorite - custom_buttonsQueries.insert( - it.name, - isFavorite, - sortIndex, - it.content, - it.longPressContent, - it.onStartup, - ) - custom_buttonsQueries.selectLastInsertedRowId() - } + val isFavorite = it.isFavorite && !dbHasFavorite + database.custom_buttonsQueries.insert( + it.name, + isFavorite, + sortIndex, + it.content, + it.longPressContent, + it.onStartup, + ) + .awaitAsOne() } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/ExtensionRepoRestorer.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/ExtensionRepoRestorer.kt index 006e48df16..7dbc0631f2 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/ExtensionRepoRestorer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/ExtensionRepoRestorer.kt @@ -2,12 +2,12 @@ package eu.kanade.tachiyomi.data.backup.restore.restorers import eu.kanade.tachiyomi.data.backup.models.BackupExtensionRepos import mihon.domain.extensionrepo.interactor.GetExtensionRepo -import tachiyomi.data.DatabaseHandler +import tachiyomi.data.Database import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get class ExtensionRepoRestorer( - private val handler: DatabaseHandler = Injekt.get(), + private val database: Database = Injekt.get(), private val getExtensionRepos: GetExtensionRepo = Injekt.get(), ) { @@ -26,15 +26,13 @@ class ExtensionRepoRestorer( } else if (shaExists != null) { error("${shaExists.name} has the same signing key fingerprint") } else { - handler.await { - extension_reposQueries.insert( - backupRepo.baseUrl, - backupRepo.name, - backupRepo.shortName, - backupRepo.website, - backupRepo.signingKeyFingerprint, - ) - } + database.extension_reposQueries.insert( + backupRepo.baseUrl, + backupRepo.name, + backupRepo.shortName, + backupRepo.website, + backupRepo.signingKeyFingerprint, + ) } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/connection/syncmiru/SyncManager.kt b/app/src/main/java/eu/kanade/tachiyomi/data/connection/syncmiru/SyncManager.kt index 4b241b8d50..1e219ddae6 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/connection/syncmiru/SyncManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/connection/syncmiru/SyncManager.kt @@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.data.connection.syncmiru import android.content.Context import android.net.Uri +import app.cash.sqldelight.async.coroutines.awaitAsList import eu.kanade.domain.connection.SyncPreferences import eu.kanade.tachiyomi.data.backup.create.BackupCreator import eu.kanade.tachiyomi.data.backup.create.BackupOptions @@ -19,7 +20,7 @@ import kotlinx.serialization.json.Json import kotlinx.serialization.protobuf.ProtoBuf import logcat.LogPriority import tachiyomi.core.common.util.system.logcat -import tachiyomi.data.DatabaseHandler +import tachiyomi.data.Database import tachiyomi.data.Episodes import tachiyomi.data.anime.AnimeMapper.mapAnime import tachiyomi.domain.anime.model.Anime @@ -40,7 +41,7 @@ import logcat.logcat as log */ class SyncManager( private val context: Context, - private val handler: DatabaseHandler = Injekt.get(), + private val database: Database = Injekt.get(), private val syncPreferences: SyncPreferences = Injekt.get(), private var json: Json = Json { encodeDefaults = true @@ -61,9 +62,9 @@ class SyncManager( suspend fun syncData() { // Reset isSyncing in case it was left over or failed syncing during restore. - handler.await(inTransaction = true) { - animesQueries.resetIsSyncing() - episodesQueries.resetIsSyncing() + database.transaction { + database.animesQueries.resetIsSyncing() + database.episodesQueries.resetIsSyncing() } val syncOptions = syncPreferences.getSyncSettings() @@ -208,15 +209,15 @@ class SyncManager( * @return a list of all anime stored in the database */ private suspend fun getAllAnimeFromDB(): List { - return handler.awaitList { animesQueries.getAllAnime(::mapAnime) } + return database.animesQueries.getAllAnime(::mapAnime).awaitAsList() } private suspend fun getAllAnimeThatNeedsSync(): List { - return handler.awaitList { animesQueries.getAnimesWithFavoriteTimestamp(::mapAnime) } + return database.animesQueries.getAnimesWithFavoriteTimestamp(::mapAnime).awaitAsList() } private suspend fun isAnimeDifferent(localAnime: Anime, remoteAnime: BackupAnime): Boolean { - val localEpisodes = handler.await { episodesQueries.getEpisodesByAnimeId(localAnime.id, 0).executeAsList() } + val localEpisodes = database.episodesQueries.getEpisodesByAnimeId(localAnime.id, 0).awaitAsList() val localCategories = getCategories.await(localAnime.id).map { it.order } if (areEpisodesDifferent(localEpisodes, remoteAnime.episodes)) { 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 d2b980ea02..1b3386305d 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 @@ -155,7 +155,7 @@ class LibraryUpdateNotifier( Notifications.ID_LIBRARY_ERROR, Notifications.CHANNEL_LIBRARY_ERROR, ) { - setContentTitle(context.stringResource(MR.strings.notification_update_error, failed)) + setContentTitle(context.pluralStringResource(MR.plurals.notification_update_error, failed, failed)) setContentText(context.stringResource(MR.strings.action_show_errors)) setSmallIcon(R.drawable.ic_ani) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListApi.kt index 0f1b19fe3f..3806e806cb 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListApi.kt @@ -12,7 +12,9 @@ import eu.kanade.tachiyomi.data.track.myanimelist.dto.MALSearchResult import eu.kanade.tachiyomi.data.track.myanimelist.dto.MALUser import eu.kanade.tachiyomi.network.DELETE import eu.kanade.tachiyomi.network.GET +import eu.kanade.tachiyomi.network.HttpException import eu.kanade.tachiyomi.network.POST +import eu.kanade.tachiyomi.network.await import eu.kanade.tachiyomi.network.awaitSuccess import eu.kanade.tachiyomi.network.parseAs import eu.kanade.tachiyomi.util.PkceUtil @@ -121,8 +123,23 @@ class MyAnimeListApi( .put(formBodyBuilder.build()) .build() with(json) { - authClient.newCall(request) - .awaitSuccess() + val response = authClient + .newCall(request) + .await() + + if (!response.isSuccessful) { + if (response.body.string().contains("invalid_content")) { + // MAL returns unapproved titles in search but does not allow adding them to the list + // returns 400 with this body: {"message":"Invalid content","error":"invalid_content"} + // These unapproved titles cannot be filtered out in search and are also returned by the + // endpoint we use for id prefix search + throw MALTitleNotApproved() + } else { + throw HttpException(response.code) + } + } + + response .parseAs() .let { parseAnimeItem(it, track) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListInterceptor.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListInterceptor.kt index 84eed73021..3a3644c481 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListInterceptor.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListInterceptor.kt @@ -80,5 +80,6 @@ class MyAnimeListInterceptor(private val myanimelist: MyAnimeList) : Interceptor } } +class MALTitleNotApproved : IOException("MAL: This title can't be added because it is waiting for approval.") class MALTokenRefreshFailed : IOException("MAL: Failed to refresh account token") class MALTokenExpired : IOException("MAL: Login has expired") diff --git a/app/src/main/java/eu/kanade/tachiyomi/di/AppModule.kt b/app/src/main/java/eu/kanade/tachiyomi/di/AppModule.kt index b879ff6150..a8de838fce 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/di/AppModule.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/di/AppModule.kt @@ -32,10 +32,8 @@ import nl.adaptivity.xmlutil.XmlDeclMode import nl.adaptivity.xmlutil.core.XmlVersion import nl.adaptivity.xmlutil.serialization.XML import tachiyomi.core.common.storage.AndroidStorageFolderProvider -import tachiyomi.data.AndroidDatabaseHandler import tachiyomi.data.Animes import tachiyomi.data.Database -import tachiyomi.data.DatabaseHandler import tachiyomi.data.DateColumnAdapter import tachiyomi.data.FetchTypeColumnAdapter import tachiyomi.data.History @@ -95,7 +93,6 @@ class AppModule(val app: Application) : InjektModule { ), ) } - addSingletonFactory { AndroidDatabaseHandler(get(), get()) } addSingletonFactory { Json { diff --git a/app/shortcuts.xml b/app/src/main/shortcuts.xml similarity index 88% rename from app/shortcuts.xml rename to app/src/main/shortcuts.xml index 48936aafe6..cf3c196aec 100644 --- a/app/shortcuts.xml +++ b/app/src/main/shortcuts.xml @@ -8,7 +8,8 @@ android:shortcutShortLabel="@string/label_library"> + android:targetClass="eu.kanade.tachiyomi.ui.main.MainActivity" + android:targetPackage="${applicationId}" /> + android:targetClass="eu.kanade.tachiyomi.ui.main.MainActivity" + android:targetPackage="${applicationId}" /> + android:targetClass="eu.kanade.tachiyomi.ui.main.MainActivity" + android:targetPackage="${applicationId}" /> + android:targetClass="eu.kanade.tachiyomi.ui.main.MainActivity" + android:targetPackage="${applicationId}" /> diff --git a/build.gradle.kts b/build.gradle.kts index a13d3fb00d..253ff367fd 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,16 +1,28 @@ buildscript { dependencies { - classpath(libs.android.shortcut.gradle) + classpath(libs.kotlin.gradle) } } plugins { - alias(kotlinx.plugins.serialization) apply false alias(libs.plugins.aboutLibraries) apply false - alias(libs.plugins.moko) apply false + alias(libs.plugins.android.application) apply false + alias(libs.plugins.android.kmp.library) apply false + alias(libs.plugins.android.library) apply false + alias(libs.plugins.android.test) apply false + alias(libs.plugins.kotlin.compose.compiler) apply false + alias(libs.plugins.kotlin.serialization) apply false + alias(libs.plugins.moko.resources) apply false alias(libs.plugins.sqldelight) apply false + + alias(mihonx.plugins.spotless) } -tasks.register("clean") { - delete(rootProject.layout.buildDirectory) +val buildLogic: IncludedBuild = gradle.includedBuild("build-logic") +tasks { + listOf("clean", "spotlessApply", "spotlessCheck").forEach { task -> + named(task) { + dependsOn(buildLogic.task(":$task")) + } + } } diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts deleted file mode 100644 index 5ed94c26ba..0000000000 --- a/buildSrc/build.gradle.kts +++ /dev/null @@ -1,22 +0,0 @@ -plugins { - `kotlin-dsl` -} - -dependencies { - implementation(androidx.gradle) - implementation(kotlinx.gradle) - implementation(kotlinx.compose.compiler.gradle) - implementation(libs.spotless.gradle) - implementation(gradleApi()) - - implementation(files(libs.javaClass.superclass.protectionDomain.codeSource.location)) - implementation(files(androidx.javaClass.superclass.protectionDomain.codeSource.location)) - implementation(files(compose.javaClass.superclass.protectionDomain.codeSource.location)) - implementation(files(kotlinx.javaClass.superclass.protectionDomain.codeSource.location)) -} - -repositories { - gradlePluginPortal() - mavenCentral() - google() -} diff --git a/buildSrc/settings.gradle.kts b/buildSrc/settings.gradle.kts deleted file mode 100644 index 0e494efad9..0000000000 --- a/buildSrc/settings.gradle.kts +++ /dev/null @@ -1,23 +0,0 @@ -dependencyResolutionManagement { - versionCatalogs { - create("libs") { - from(files("../gradle/libs.versions.toml")) - } - create("androidx") { - from(files("../gradle/androidx.versions.toml")) - } - create("compose") { - from(files("../gradle/compose.versions.toml")) - } - create("kotlinx") { - from(files("../gradle/kotlinx.versions.toml")) - } - // AY --> - create("aniyomilibs") { - from(files("../gradle/aniyomi.versions.toml")) - } - // <-- AY - } -} - -rootProject.name = "mihon-buildSrc" diff --git a/buildSrc/src/main/kotlin/mihon.android.application.compose.gradle.kts b/buildSrc/src/main/kotlin/mihon.android.application.compose.gradle.kts deleted file mode 100644 index 767f758cbe..0000000000 --- a/buildSrc/src/main/kotlin/mihon.android.application.compose.gradle.kts +++ /dev/null @@ -1,12 +0,0 @@ -import mihon.buildlogic.configureCompose - -plugins { - id("com.android.application") - kotlin("android") - - id("mihon.code.lint") -} - -android { - configureCompose(this) -} diff --git a/buildSrc/src/main/kotlin/mihon.android.application.gradle.kts b/buildSrc/src/main/kotlin/mihon.android.application.gradle.kts deleted file mode 100644 index 080f9ca643..0000000000 --- a/buildSrc/src/main/kotlin/mihon.android.application.gradle.kts +++ /dev/null @@ -1,18 +0,0 @@ -import mihon.buildlogic.AndroidConfig -import mihon.buildlogic.configureAndroid -import mihon.buildlogic.configureTest - -plugins { - id("com.android.application") - kotlin("android") - - id("mihon.code.lint") -} - -android { - defaultConfig { - targetSdk = AndroidConfig.TARGET_SDK - } - configureAndroid(this) - configureTest() -} diff --git a/buildSrc/src/main/kotlin/mihon.benchmark.gradle.kts b/buildSrc/src/main/kotlin/mihon.benchmark.gradle.kts deleted file mode 100644 index 50c47f2801..0000000000 --- a/buildSrc/src/main/kotlin/mihon.benchmark.gradle.kts +++ /dev/null @@ -1,14 +0,0 @@ -import mihon.buildlogic.configureAndroid -import mihon.buildlogic.configureTest - -plugins { - id("com.android.test") - kotlin("android") - - id("mihon.code.lint") -} - -android { - configureAndroid(this) - configureTest() -} diff --git a/buildSrc/src/main/kotlin/mihon.code.lint.gradle.kts b/buildSrc/src/main/kotlin/mihon.code.lint.gradle.kts deleted file mode 100644 index 99c3e99a16..0000000000 --- a/buildSrc/src/main/kotlin/mihon.code.lint.gradle.kts +++ /dev/null @@ -1,35 +0,0 @@ -import org.gradle.accessors.dm.LibrariesForLibs - -plugins { - id("com.diffplug.spotless") -} - -val libs = the() - -val xmlFormatExclude = buildList(2) { - add("**/build/**/*.xml") - - projectDir - .resolve("src/commonMain/moko-resources") - .takeIf { it.isDirectory } - ?.let(::fileTree) - ?.matching { exclude("/base/**") } - ?.let(::add) -} - .toTypedArray() - -spotless { - kotlin { - target("**/*.kt", "**/*.kts") - targetExclude("**/build/**/*.kt") - ktlint(libs.ktlint.core.get().version) - trimTrailingWhitespace() - endWithNewline() - } - format("xml") { - target("**/*.xml") - targetExclude(*xmlFormatExclude) - trimTrailingWhitespace() - endWithNewline() - } -} diff --git a/buildSrc/src/main/kotlin/mihon.library.compose.gradle.kts b/buildSrc/src/main/kotlin/mihon.library.compose.gradle.kts deleted file mode 100644 index 7b377ce4ce..0000000000 --- a/buildSrc/src/main/kotlin/mihon.library.compose.gradle.kts +++ /dev/null @@ -1,11 +0,0 @@ -import mihon.buildlogic.configureCompose - -plugins { - id("com.android.library") - - id("mihon.code.lint") -} - -android { - configureCompose(this) -} diff --git a/buildSrc/src/main/kotlin/mihon.library.gradle.kts b/buildSrc/src/main/kotlin/mihon.library.gradle.kts deleted file mode 100644 index 4cf5f6efc7..0000000000 --- a/buildSrc/src/main/kotlin/mihon.library.gradle.kts +++ /dev/null @@ -1,13 +0,0 @@ -import mihon.buildlogic.configureAndroid -import mihon.buildlogic.configureTest - -plugins { - id("com.android.library") - - id("mihon.code.lint") -} - -android { - configureAndroid(this) - configureTest() -} diff --git a/buildSrc/src/main/kotlin/mihon/buildlogic/AndroidConfig.kt b/buildSrc/src/main/kotlin/mihon/buildlogic/AndroidConfig.kt deleted file mode 100644 index f97970c4c8..0000000000 --- a/buildSrc/src/main/kotlin/mihon/buildlogic/AndroidConfig.kt +++ /dev/null @@ -1,14 +0,0 @@ -package mihon.buildlogic - -import org.gradle.api.JavaVersion as GradleJavaVersion -import org.jetbrains.kotlin.gradle.dsl.JvmTarget as KotlinJvmTarget - -object AndroidConfig { - const val COMPILE_SDK = 36 - const val TARGET_SDK = 36 - const val MIN_SDK = 26 - - // https://youtrack.jetbrains.com/issue/KT-66995/JvmTarget-and-JavaVersion-compatibility-for-easier-JVM-version-setup - val JavaVersion = GradleJavaVersion.VERSION_17 - val JvmTarget = KotlinJvmTarget.JVM_17 -} diff --git a/buildSrc/src/main/kotlin/mihon/buildlogic/ProjectExtensions.kt b/buildSrc/src/main/kotlin/mihon/buildlogic/ProjectExtensions.kt deleted file mode 100644 index 7df0c772a7..0000000000 --- a/buildSrc/src/main/kotlin/mihon/buildlogic/ProjectExtensions.kt +++ /dev/null @@ -1,104 +0,0 @@ -package mihon.buildlogic - -import com.android.build.api.dsl.CommonExtension -import org.gradle.accessors.dm.LibrariesForAndroidx -import org.gradle.accessors.dm.LibrariesForCompose -import org.gradle.accessors.dm.LibrariesForKotlinx -import org.gradle.accessors.dm.LibrariesForLibs -import org.gradle.api.Project -import org.gradle.api.tasks.testing.Test -import org.gradle.api.tasks.testing.logging.TestLogEvent -import org.gradle.kotlin.dsl.configure -import org.gradle.kotlin.dsl.dependencies -import org.gradle.kotlin.dsl.provideDelegate -import org.gradle.kotlin.dsl.the -import org.gradle.kotlin.dsl.withType -import org.jetbrains.kotlin.compose.compiler.gradle.ComposeCompilerGradlePluginExtension -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile -import java.io.File - -val Project.androidx get() = the() -val Project.compose get() = the() -val Project.kotlinx get() = the() -val Project.libs get() = the() - -internal fun Project.configureAndroid(commonExtension: CommonExtension<*, *, *, *, *, *>) { - commonExtension.apply { - compileSdk = AndroidConfig.COMPILE_SDK - - defaultConfig { - minSdk = AndroidConfig.MIN_SDK - } - - compileOptions { - sourceCompatibility = AndroidConfig.JavaVersion - targetCompatibility = AndroidConfig.JavaVersion - isCoreLibraryDesugaringEnabled = true - } - } - - tasks.withType().configureEach { - compilerOptions { - jvmTarget.set(AndroidConfig.JvmTarget) - freeCompilerArgs.addAll( - // AM --> - "-Xwhen-guards", - // <-- AM - "-Xcontext-parameters", - "-opt-in=kotlin.RequiresOptIn", - ) - - // Treat all Kotlin warnings as errors (disabled by default) - // Override by setting warningsAsErrors=true in your ~/.gradle/gradle.properties - val warningsAsErrors: String? by project - allWarningsAsErrors.set(warningsAsErrors.toBoolean()) - - } - } - - dependencies { - "coreLibraryDesugaring"(libs.desugar) - } -} - -internal fun Project.configureCompose(commonExtension: CommonExtension<*, *, *, *, *, *>) { - pluginManager.apply(kotlinx.plugins.compose.compiler.get().pluginId) - - commonExtension.apply { - buildFeatures { - compose = true - } - - dependencies { - "implementation"(platform(compose.bom)) - } - } - - extensions.configure { - val enableMetrics = project.providers.gradleProperty("enableComposeCompilerMetrics").orNull.toBoolean() - val enableReports = project.providers.gradleProperty("enableComposeCompilerReports").orNull.toBoolean() - - val rootBuildDir = rootProject.layout.buildDirectory.asFile.get() - val relativePath = projectDir.relativeTo(rootDir) - - if (enableMetrics) { - rootBuildDir.resolve("compose-metrics").resolve(relativePath).let(metricsDestination::set) - } - - if (enableReports) { - rootBuildDir.resolve("compose-reports").resolve(relativePath).let(reportsDestination::set) - } - } - -} - -internal fun Project.configureTest() { - tasks.withType { - useJUnitPlatform() - testLogging { - events(TestLogEvent.PASSED, TestLogEvent.SKIPPED, TestLogEvent.FAILED) - } - } -} - -val Project.generatedBuildDir: File get() = project.layout.buildDirectory.asFile.get().resolve("generated/mihon") diff --git a/buildSrc/src/main/kotlin/mihon/buildlogic/tasks/LocalesConfigTask.kt b/buildSrc/src/main/kotlin/mihon/buildlogic/tasks/LocalesConfigTask.kt deleted file mode 100644 index 329e4a769d..0000000000 --- a/buildSrc/src/main/kotlin/mihon/buildlogic/tasks/LocalesConfigTask.kt +++ /dev/null @@ -1,36 +0,0 @@ -package mihon.buildlogic.tasks - -import org.gradle.api.Project -import org.gradle.api.Task -import org.gradle.api.tasks.TaskProvider -import java.io.File - -private val emptyResourcesElement = "\\s*|".toRegex() - -fun Project.getLocalesConfigTask(outputResourceDir: File): TaskProvider { - return tasks.register("generateLocalesConfig") { - val locales = fileTree("$projectDir/src/commonMain/moko-resources/") - .matching { include("**/strings.xml") } - .filterNot { it.readText().contains(emptyResourcesElement) } - .map { - it.parentFile.name - .replace("base", "en") - .replace("-r", "-") - .replace("+", "-") - } - .sorted() - .joinToString("\n") { "| " } - - val content = """ - | - | - $locales - | - """.trimMargin() - - outputResourceDir.resolve("xml/locales_config.xml").apply { - parentFile.mkdirs() - writeText(content) - } - } -} diff --git a/core-metadata/build.gradle.kts b/core-metadata/build.gradle.kts index dfb3c1943f..2c528e5a5e 100644 --- a/core-metadata/build.gradle.kts +++ b/core-metadata/build.gradle.kts @@ -1,20 +1,16 @@ plugins { - id("mihon.library") - kotlin("android") - kotlin("plugin.serialization") + alias(mihonx.plugins.android.library) + alias(mihonx.plugins.spotless) + + alias(libs.plugins.kotlin.serialization) } android { namespace = "tachiyomi.core.metadata" - - defaultConfig { - testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" - consumerProguardFiles("consumer-rules.pro") - } } dependencies { implementation(projects.sourceApi) - implementation(kotlinx.bundles.serialization) + implementation(libs.bundles.serialization) } diff --git a/core-metadata/consumer-rules.pro b/core-metadata/consumer-rules.pro deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/core-metadata/proguard-rules.pro b/core-metadata/proguard-rules.pro deleted file mode 100644 index 481bb43481..0000000000 --- a/core-metadata/proguard-rules.pro +++ /dev/null @@ -1,21 +0,0 @@ -# Add project specific ProGuard rules here. -# You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Uncomment this to preserve the line number information for -# debugging stack traces. -#-keepattributes SourceFile,LineNumberTable - -# If you keep the line number information, uncomment this to -# hide the original source file name. -#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/core/archive/build.gradle.kts b/core/archive/build.gradle.kts index c2208a695a..64f1ff7961 100644 --- a/core/archive/build.gradle.kts +++ b/core/archive/build.gradle.kts @@ -1,7 +1,8 @@ plugins { - id("mihon.library") - kotlin("android") - kotlin("plugin.serialization") + alias(mihonx.plugins.android.library) + alias(mihonx.plugins.spotless) + + alias(libs.plugins.kotlin.serialization) } android { diff --git a/core/common/build.gradle.kts b/core/common/build.gradle.kts index e99c841740..42a3f9df51 100644 --- a/core/common/build.gradle.kts +++ b/core/common/build.gradle.kts @@ -1,7 +1,8 @@ plugins { - id("mihon.library") - kotlin("android") - kotlin("plugin.serialization") + alias(mihonx.plugins.android.library) + alias(mihonx.plugins.spotless) + + alias(libs.plugins.kotlin.serialization) } android { @@ -22,12 +23,12 @@ dependencies { api(libs.logcat) - api(libs.rxjava) + api(libs.rxJava) api(libs.okhttp.core) api(libs.okhttp.logging) api(libs.okhttp.brotli) - api(libs.okhttp.dnsoverhttps) + api(libs.okhttp.dnsOverHttps) api(libs.okio) // AM (REMOVE_LIBRARIES) --> @@ -35,13 +36,13 @@ dependencies { // <-- AM (REMOVE_LIBRARIES) implementation(libs.unifile) - implementation(libs.libarchive) + implementation(libs.archive) - api(kotlinx.coroutines.core) - api(kotlinx.serialization.json) - api(kotlinx.serialization.json.okio) + api(libs.kotlinx.coroutines.core) + api(libs.kotlinx.serialization.json) + api(libs.kotlinx.serialization.jsonOkio) - api(libs.preferencektx) + api(libs.androidx.preference) implementation(libs.jsoup) @@ -49,7 +50,7 @@ dependencies { implementation(libs.natural.comparator) // JavaScript engine - implementation(libs.bundles.js.engine) + implementation(libs.quickJs) // AY --> // FFmpeg-kit diff --git a/core/common/src/main/kotlin/eu/kanade/tachiyomi/network/OkHttpExtensions.kt b/core/common/src/main/kotlin/eu/kanade/tachiyomi/network/OkHttpExtensions.kt index 0a860d0697..072c50c81e 100644 --- a/core/common/src/main/kotlin/eu/kanade/tachiyomi/network/OkHttpExtensions.kt +++ b/core/common/src/main/kotlin/eu/kanade/tachiyomi/network/OkHttpExtensions.kt @@ -77,7 +77,7 @@ private suspend fun Call.await(callStack: Array): Response { val callback = object : Callback { override fun onResponse(call: Call, response: Response) { - continuation.resume(response) { + continuation.resume(response) { _, _, _ -> response.body.close() } } diff --git a/data/build.gradle.kts b/data/build.gradle.kts index 552bae9b3a..002c1a0b3c 100644 --- a/data/build.gradle.kts +++ b/data/build.gradle.kts @@ -1,23 +1,21 @@ plugins { - id("mihon.library") - kotlin("android") - kotlin("plugin.serialization") + alias(mihonx.plugins.android.library) + alias(mihonx.plugins.spotless) + + alias(libs.plugins.kotlin.serialization) alias(libs.plugins.sqldelight) } android { namespace = "tachiyomi.data" - defaultConfig { - consumerProguardFiles("consumer-rules.pro") - } - sqldelight { databases { create("Database") { packageName.set("tachiyomi.data") - dialect(libs.sqldelight.dialects.sql) + dialect(libs.sqldelight.sqliteDialect338) schemaOutputDirectory.set(project.file("./src/main/sqldelight")) + generateAsync.set(true) } } } diff --git a/data/consumer-rules.pro b/data/consumer-rules.pro deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/data/proguard-rules.pro b/data/proguard-rules.pro deleted file mode 100644 index 481bb43481..0000000000 --- a/data/proguard-rules.pro +++ /dev/null @@ -1,21 +0,0 @@ -# Add project specific ProGuard rules here. -# You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Uncomment this to preserve the line number information for -# debugging stack traces. -#-keepattributes SourceFile,LineNumberTable - -# If you keep the line number information, uncomment this to -# hide the original source file name. -#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/data/src/main/java/mihon/data/repository/ExtensionRepoRepositoryImpl.kt b/data/src/main/java/mihon/data/repository/ExtensionRepoRepositoryImpl.kt index 61c279630a..0b7bfbf3f9 100644 --- a/data/src/main/java/mihon/data/repository/ExtensionRepoRepositoryImpl.kt +++ b/data/src/main/java/mihon/data/repository/ExtensionRepoRepositoryImpl.kt @@ -1,36 +1,49 @@ package mihon.data.repository import android.database.SQLException +import app.cash.sqldelight.async.coroutines.awaitAsList +import app.cash.sqldelight.async.coroutines.awaitAsOneOrNull import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map import mihon.domain.extensionrepo.exception.SaveExtensionRepoException import mihon.domain.extensionrepo.model.ExtensionRepo import mihon.domain.extensionrepo.repository.ExtensionRepoRepository -import tachiyomi.data.DatabaseHandler +import tachiyomi.data.Database +import tachiyomi.data.subscribeToList +import tachiyomi.data.subscribeToOne class ExtensionRepoRepositoryImpl( - private val handler: DatabaseHandler, + private val database: Database, ) : ExtensionRepoRepository { override fun subscribeAll(): Flow> { - return handler.subscribeToList { extension_reposQueries.findAll(::mapExtensionRepo) } + return database.extension_reposQueries + .findAll(::mapExtensionRepo) + .subscribeToList() } override suspend fun getAll(): List { - return handler.awaitList { extension_reposQueries.findAll(::mapExtensionRepo) } + return database.extension_reposQueries + .findAll(::mapExtensionRepo) + .awaitAsList() } override suspend fun getRepo(baseUrl: String): ExtensionRepo? { - return handler.awaitOneOrNull { extension_reposQueries.findOne(baseUrl, ::mapExtensionRepo) } + return database.extension_reposQueries + .findOne(baseUrl, ::mapExtensionRepo) + .awaitAsOneOrNull() } override suspend fun getRepoBySigningKeyFingerprint(fingerprint: String): ExtensionRepo? { - return handler.awaitOneOrNull { - extension_reposQueries.findOneBySigningKeyFingerprint(fingerprint, ::mapExtensionRepo) - } + return database.extension_reposQueries + .findOneBySigningKeyFingerprint(fingerprint, ::mapExtensionRepo) + .awaitAsOneOrNull() } override fun getCount(): Flow { - return handler.subscribeToOne { extension_reposQueries.count() }.map { it.toInt() } + return database.extension_reposQueries + .count() + .subscribeToOne() + .map { it.toInt() } } override suspend fun insertRepo( @@ -41,7 +54,7 @@ class ExtensionRepoRepositoryImpl( signingKeyFingerprint: String, ) { try { - handler.await { extension_reposQueries.insert(baseUrl, name, shortName, website, signingKeyFingerprint) } + database.extension_reposQueries.insert(baseUrl, name, shortName, website, signingKeyFingerprint) } catch (ex: SQLException) { throw SaveExtensionRepoException(ex) } @@ -55,26 +68,24 @@ class ExtensionRepoRepositoryImpl( signingKeyFingerprint: String, ) { try { - handler.await { extension_reposQueries.upsert(baseUrl, name, shortName, website, signingKeyFingerprint) } + database.extension_reposQueries.upsert(baseUrl, name, shortName, website, signingKeyFingerprint) } catch (ex: SQLException) { throw SaveExtensionRepoException(ex) } } override suspend fun replaceRepo(newRepo: ExtensionRepo) { - handler.await { - extension_reposQueries.replace( - newRepo.baseUrl, - newRepo.name, - newRepo.shortName, - newRepo.website, - newRepo.signingKeyFingerprint, - ) - } + database.extension_reposQueries.replace( + newRepo.baseUrl, + newRepo.name, + newRepo.shortName, + newRepo.website, + newRepo.signingKeyFingerprint, + ) } override suspend fun deleteRepo(baseUrl: String) { - return handler.await { extension_reposQueries.delete(baseUrl) } + database.extension_reposQueries.delete(baseUrl) } private fun mapExtensionRepo( diff --git a/data/src/main/java/tachiyomi/data/AndroidDatabaseHandler.kt b/data/src/main/java/tachiyomi/data/AndroidDatabaseHandler.kt deleted file mode 100644 index be74a1102a..0000000000 --- a/data/src/main/java/tachiyomi/data/AndroidDatabaseHandler.kt +++ /dev/null @@ -1,104 +0,0 @@ -package tachiyomi.data - -import androidx.paging.PagingSource -import app.cash.sqldelight.ExecutableQuery -import app.cash.sqldelight.Query -import app.cash.sqldelight.coroutines.asFlow -import app.cash.sqldelight.coroutines.mapToList -import app.cash.sqldelight.coroutines.mapToOne -import app.cash.sqldelight.coroutines.mapToOneOrNull -import app.cash.sqldelight.db.SqlDriver -import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.withContext - -class AndroidDatabaseHandler( - val db: Database, - private val driver: SqlDriver, - val queryDispatcher: CoroutineDispatcher = Dispatchers.IO, - val transactionDispatcher: CoroutineDispatcher = queryDispatcher, -) : DatabaseHandler { - - val suspendingTransactionId = ThreadLocal() - - override suspend fun await(inTransaction: Boolean, block: suspend Database.() -> T): T { - return dispatch(inTransaction, block) - } - - override suspend fun awaitList( - inTransaction: Boolean, - block: suspend Database.() -> Query, - ): List { - return dispatch(inTransaction) { block(db).executeAsList() } - } - - override suspend fun awaitOne( - inTransaction: Boolean, - block: suspend Database.() -> Query, - ): T { - return dispatch(inTransaction) { block(db).executeAsOne() } - } - - override suspend fun awaitOneExecutable( - inTransaction: Boolean, - block: suspend Database.() -> ExecutableQuery, - ): T { - return dispatch(inTransaction) { block(db).executeAsOne() } - } - - override suspend fun awaitOneOrNull( - inTransaction: Boolean, - block: suspend Database.() -> Query, - ): T? { - return dispatch(inTransaction) { block(db).executeAsOneOrNull() } - } - - override suspend fun awaitOneOrNullExecutable( - inTransaction: Boolean, - block: suspend Database.() -> ExecutableQuery, - ): T? { - return dispatch(inTransaction) { block(db).executeAsOneOrNull() } - } - - override fun subscribeToList(block: Database.() -> Query): Flow> { - return block(db).asFlow().mapToList(queryDispatcher) - } - - override fun subscribeToOne(block: Database.() -> Query): Flow { - return block(db).asFlow().mapToOne(queryDispatcher) - } - - override fun subscribeToOneOrNull(block: Database.() -> Query): Flow { - return block(db).asFlow().mapToOneOrNull(queryDispatcher) - } - - override fun subscribeToPagingSource( - countQuery: Database.() -> Query, - queryProvider: Database.(Long, Long) -> Query, - ): PagingSource { - return QueryPagingSource( - handler = this, - countQuery = countQuery, - queryProvider = { limit, offset -> - queryProvider.invoke(db, limit, offset) - }, - ) - } - - private suspend fun dispatch(inTransaction: Boolean, block: suspend Database.() -> T): T { - // Create a transaction if needed and run the calling block inside it. - if (inTransaction) { - return withTransaction { block(db) } - } - - // If we're currently in the transaction thread, there's no need to dispatch our query. - if (driver.currentTransaction() != null) { - return block(db) - } - - // Get the current database context and run the calling block. - val context = getCurrentDatabaseContext() - return withContext(context) { block(db) } - } -} diff --git a/data/src/main/java/tachiyomi/data/DatabaseHandler.kt b/data/src/main/java/tachiyomi/data/DatabaseHandler.kt deleted file mode 100644 index 57f58f7909..0000000000 --- a/data/src/main/java/tachiyomi/data/DatabaseHandler.kt +++ /dev/null @@ -1,47 +0,0 @@ -package tachiyomi.data - -import androidx.paging.PagingSource -import app.cash.sqldelight.ExecutableQuery -import app.cash.sqldelight.Query -import kotlinx.coroutines.flow.Flow - -interface DatabaseHandler { - - suspend fun await(inTransaction: Boolean = false, block: suspend Database.() -> T): T - - suspend fun awaitList( - inTransaction: Boolean = false, - block: suspend Database.() -> Query, - ): List - - suspend fun awaitOne( - inTransaction: Boolean = false, - block: suspend Database.() -> Query, - ): T - - suspend fun awaitOneExecutable( - inTransaction: Boolean = false, - block: suspend Database.() -> ExecutableQuery, - ): T - - suspend fun awaitOneOrNull( - inTransaction: Boolean = false, - block: suspend Database.() -> Query, - ): T? - - suspend fun awaitOneOrNullExecutable( - inTransaction: Boolean = false, - block: suspend Database.() -> ExecutableQuery, - ): T? - - fun subscribeToList(block: Database.() -> Query): Flow> - - fun subscribeToOne(block: Database.() -> Query): Flow - - fun subscribeToOneOrNull(block: Database.() -> Query): Flow - - fun subscribeToPagingSource( - countQuery: Database.() -> Query, - queryProvider: Database.(Long, Long) -> Query, - ): PagingSource -} diff --git a/data/src/main/java/tachiyomi/data/QueryExtension.kt b/data/src/main/java/tachiyomi/data/QueryExtension.kt new file mode 100644 index 0000000000..45c90b3e70 --- /dev/null +++ b/data/src/main/java/tachiyomi/data/QueryExtension.kt @@ -0,0 +1,36 @@ +package tachiyomi.data + +import app.cash.sqldelight.Query +import app.cash.sqldelight.async.coroutines.awaitAsList +import app.cash.sqldelight.async.coroutines.awaitAsOne +import app.cash.sqldelight.async.coroutines.awaitAsOneOrNull +import app.cash.sqldelight.coroutines.asFlow +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.withContext +import kotlin.coroutines.CoroutineContext +import kotlin.coroutines.EmptyCoroutineContext + +fun Query.subscribeToList( + context: CoroutineContext = EmptyCoroutineContext, +): Flow> = asFlow().map { + withContext(context) { + it.awaitAsList() + } +} + +fun Query.subscribeToOne( + context: CoroutineContext = EmptyCoroutineContext, +): Flow = asFlow().map { + withContext(context) { + it.awaitAsOne() + } +} + +fun Query.subscribeToOneOrNull( + context: CoroutineContext = EmptyCoroutineContext, +): Flow = asFlow().map { + withContext(context) { + it.awaitAsOneOrNull() + } +} diff --git a/data/src/main/java/tachiyomi/data/QueryPagingSource.kt b/data/src/main/java/tachiyomi/data/QueryPagingSource.kt index 16974e368c..5b963ff6b1 100644 --- a/data/src/main/java/tachiyomi/data/QueryPagingSource.kt +++ b/data/src/main/java/tachiyomi/data/QueryPagingSource.kt @@ -3,12 +3,14 @@ package tachiyomi.data import androidx.paging.PagingSource import androidx.paging.PagingState import app.cash.sqldelight.Query +import app.cash.sqldelight.async.coroutines.awaitAsList +import app.cash.sqldelight.async.coroutines.awaitAsOne import kotlin.properties.Delegates +@Suppress("unused") class QueryPagingSource( - val handler: DatabaseHandler, - val countQuery: Database.() -> Query, - val queryProvider: Database.(Long, Long) -> Query, + val countQuery: () -> Query, + val queryProvider: (Long, Long) -> Query, ) : PagingSource(), Query.Listener { override val jumpingSupported: Boolean = true @@ -29,17 +31,16 @@ class QueryPagingSource( try { val key = params.key ?: 0L val loadSize = params.loadSize - val count = handler.awaitOne { countQuery() } + val count = countQuery().awaitAsOne() val (offset, limit) = when (params) { is LoadParams.Prepend -> key - loadSize to loadSize.toLong() else -> key to loadSize.toLong() } - val data = handler.awaitList { - queryProvider(limit, offset) - .also { currentQuery = it } - } + val data = queryProvider(limit, offset) + .also { currentQuery = it } + .awaitAsList() val (prevKey, nextKey) = when (params) { is LoadParams.Append -> (offset - loadSize to offset + loadSize) diff --git a/data/src/main/java/tachiyomi/data/TransactionContext.kt b/data/src/main/java/tachiyomi/data/TransactionContext.kt deleted file mode 100644 index f804a0b8e2..0000000000 --- a/data/src/main/java/tachiyomi/data/TransactionContext.kt +++ /dev/null @@ -1,165 +0,0 @@ -package tachiyomi.data - -import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.Job -import kotlinx.coroutines.asContextElement -import kotlinx.coroutines.runBlocking -import kotlinx.coroutines.suspendCancellableCoroutine -import kotlinx.coroutines.withContext -import java.util.concurrent.RejectedExecutionException -import kotlin.concurrent.atomics.AtomicInt -import kotlin.concurrent.atomics.ExperimentalAtomicApi -import kotlin.concurrent.atomics.decrementAndFetch -import kotlin.concurrent.atomics.incrementAndFetch -import kotlin.coroutines.ContinuationInterceptor -import kotlin.coroutines.CoroutineContext -import kotlin.coroutines.EmptyCoroutineContext -import kotlin.coroutines.coroutineContext -import kotlin.coroutines.resume - -/** - * Returns the transaction dispatcher if we are on a transaction, or the database dispatchers. - */ -internal suspend fun AndroidDatabaseHandler.getCurrentDatabaseContext(): CoroutineContext { - return coroutineContext[TransactionElement]?.transactionDispatcher ?: queryDispatcher -} - -/** - * Calls the specified suspending [block] in a database transaction. The transaction will be - * marked as successful unless an exception is thrown in the suspending [block] or the coroutine - * is cancelled. - * - * SQLDelight will only perform at most one transaction at a time, additional transactions are queued - * and executed on a first come, first serve order. - * - * Performing blocking database operations is not permitted in a coroutine scope other than the - * one received by the suspending block. It is recommended that all [Dao] function invoked within - * the [block] be suspending functions. - * - * The dispatcher used to execute the given [block] will utilize threads from SQLDelight's query executor. - */ -internal suspend fun AndroidDatabaseHandler.withTransaction(block: suspend () -> T): T { - // Use inherited transaction context if available, this allows nested suspending transactions. - val transactionContext = - coroutineContext[TransactionElement]?.transactionDispatcher ?: createTransactionContext() - return withContext(transactionContext) { - val transactionElement = coroutineContext[TransactionElement]!! - transactionElement.acquire() - try { - db.transactionWithResult { - runBlocking(transactionContext) { - block() - } - } - } finally { - transactionElement.release() - } - } -} - -/** - * Creates a [CoroutineContext] for performing database operations within a coroutine transaction. - * - * The context is a combination of a dispatcher, a [TransactionElement] and a thread local element. - * - * * The dispatcher will dispatch coroutines to a single thread that is taken over from the SQLDelight - * query executor. If the coroutine context is switched, suspending DAO functions will be able to - * dispatch to the transaction thread. - * - * * The [TransactionElement] serves as an indicator for inherited context, meaning, if there is a - * switch of context, suspending DAO methods will be able to use the indicator to dispatch the - * database operation to the transaction thread. - * - * * The thread local element serves as a second indicator and marks threads that are used to - * execute coroutines within the coroutine transaction, more specifically it allows us to identify - * if a blocking DAO method is invoked within the transaction coroutine. Never assign meaning to - * this value, for now all we care is if its present or not. - */ -private suspend fun AndroidDatabaseHandler.createTransactionContext(): CoroutineContext { - val controlJob = Job() - // make sure to tie the control job to this context to avoid blocking the transaction if - // context get cancelled before we can even start using this job. Otherwise, the acquired - // transaction thread will forever wait for the controlJob to be cancelled. - // see b/148181325 - coroutineContext[Job]?.invokeOnCompletion { - controlJob.cancel() - } - - val dispatcher = transactionDispatcher.acquireTransactionThread(controlJob) - val transactionElement = TransactionElement(controlJob, dispatcher) - val threadLocalElement = - suspendingTransactionId.asContextElement(System.identityHashCode(controlJob)) - return dispatcher + transactionElement + threadLocalElement -} - -/** - * Acquires a thread from the executor and returns a [ContinuationInterceptor] to dispatch - * coroutines to the acquired thread. The [controlJob] is used to control the release of the - * thread by cancelling the job. - */ -private suspend fun CoroutineDispatcher.acquireTransactionThread( - controlJob: Job, -): ContinuationInterceptor { - return suspendCancellableCoroutine { continuation -> - continuation.invokeOnCancellation { - // We got cancelled while waiting to acquire a thread, we can't stop our attempt to - // acquire a thread, but we can cancel the controlling job so once it gets acquired it - // is quickly released. - controlJob.cancel() - } - try { - dispatch(EmptyCoroutineContext) { - runBlocking { - // Thread acquired, resume coroutine - continuation.resume(coroutineContext[ContinuationInterceptor]!!) - controlJob.join() - } - } - } catch (ex: RejectedExecutionException) { - // Couldn't acquire a thread, cancel coroutine - continuation.cancel( - IllegalStateException( - "Unable to acquire a thread to perform the database transaction", - ex, - ), - ) - } - } -} - -/** - * A [CoroutineContext.Element] that indicates there is an on-going database transaction. - */ -@OptIn(ExperimentalAtomicApi::class) -private class TransactionElement( - private val transactionThreadControlJob: Job, - val transactionDispatcher: ContinuationInterceptor, -) : CoroutineContext.Element { - - companion object Key : CoroutineContext.Key - - override val key: CoroutineContext.Key - get() = TransactionElement - - /** - * Number of transactions (including nested ones) started with this element. - * Call [acquire] to increase the count and [release] to decrease it. If the count reaches zero - * when [release] is invoked then the transaction job is cancelled and the transaction thread - * is released. - */ - private val referenceCount = AtomicInt(0) - - fun acquire() { - referenceCount.incrementAndFetch() - } - - fun release() { - val count = referenceCount.decrementAndFetch() - if (count < 0) { - throw IllegalStateException("Transaction was never started or was already released") - } else if (count == 0) { - // Cancel the job that controls the transaction thread, causing it to be released. - transactionThreadControlJob.cancel() - } - } -} diff --git a/data/src/main/java/tachiyomi/data/anime/AnimeMapper.kt b/data/src/main/java/tachiyomi/data/anime/AnimeMapper.kt index 0c0186cc5e..3bba4abf86 100644 --- a/data/src/main/java/tachiyomi/data/anime/AnimeMapper.kt +++ b/data/src/main/java/tachiyomi/data/anime/AnimeMapper.kt @@ -9,6 +9,7 @@ import tachiyomi.domain.library.model.LibraryAnime import tachiyomi.domain.source.model.DeletableAnime object AnimeMapper { + @Suppress("UNUSED_PARAMETER") fun mapAnime( id: Long, source: Long, @@ -33,7 +34,6 @@ object AnimeMapper { lastModifiedAt: Long, favoriteModifiedAt: Long?, version: Long, - @Suppress("UNUSED_PARAMETER") isSyncing: Long, notes: String, // AY --> diff --git a/data/src/main/java/tachiyomi/data/anime/AnimeRepositoryImpl.kt b/data/src/main/java/tachiyomi/data/anime/AnimeRepositoryImpl.kt index 441c259ef5..543964d352 100644 --- a/data/src/main/java/tachiyomi/data/anime/AnimeRepositoryImpl.kt +++ b/data/src/main/java/tachiyomi/data/anime/AnimeRepositoryImpl.kt @@ -1,13 +1,19 @@ package tachiyomi.data.anime import aniyomi.domain.anime.SeasonAnime +import app.cash.sqldelight.async.coroutines.awaitAsList +import app.cash.sqldelight.async.coroutines.awaitAsOne +import app.cash.sqldelight.async.coroutines.awaitAsOneOrNull import kotlinx.coroutines.flow.Flow import logcat.LogPriority import tachiyomi.core.common.util.system.logcat -import tachiyomi.data.DatabaseHandler +import tachiyomi.data.Database import tachiyomi.data.FetchTypeColumnAdapter import tachiyomi.data.StringListColumnAdapter import tachiyomi.data.UpdateStrategyColumnAdapter +import tachiyomi.data.subscribeToList +import tachiyomi.data.subscribeToOne +import tachiyomi.data.subscribeToOneOrNull import tachiyomi.domain.anime.model.Anime import tachiyomi.domain.anime.model.AnimeUpdate import tachiyomi.domain.anime.model.AnimeWithEpisodeCount @@ -18,73 +24,70 @@ import java.time.LocalDate import java.time.ZoneId class AnimeRepositoryImpl( - private val handler: DatabaseHandler, + private val database: Database, ) : AnimeRepository { override suspend fun getAnimeById(id: Long): Anime { - return handler.awaitOne { animesQueries.getAnimeById(id, AnimeMapper::mapAnime) } + return database.animesQueries.getAnimeById(id, AnimeMapper::mapAnime).awaitAsOne() } override suspend fun getAnimeByIdAsFlow(id: Long): Flow { - return handler.subscribeToOne { animesQueries.getAnimeById(id, AnimeMapper::mapAnime) } + return database.animesQueries.getAnimeById(id, AnimeMapper::mapAnime).subscribeToOne() } override suspend fun getAnimeByUrlAndSourceId(url: String, sourceId: Long): Anime? { - return handler.awaitOneOrNull { - animesQueries.getAnimeByUrlAndSource( - url, - sourceId, - AnimeMapper::mapAnime, - ) - } + return database.animesQueries.getAnimeByUrlAndSource( + url, + sourceId, + AnimeMapper::mapAnime, + ).awaitAsOneOrNull() } override fun getAnimeByUrlAndSourceIdAsFlow(url: String, sourceId: Long): Flow { - return handler.subscribeToOneOrNull { - animesQueries.getAnimeByUrlAndSource( - url, - sourceId, - AnimeMapper::mapAnime, - ) - } + return database.animesQueries.getAnimeByUrlAndSource( + url, + sourceId, + AnimeMapper::mapAnime, + ).subscribeToOneOrNull() } override suspend fun getFavorites(): List { - return handler.awaitList { animesQueries.getFavorites(AnimeMapper::mapAnime) } + return database.animesQueries.getFavorites(AnimeMapper::mapAnime).awaitAsList() } override suspend fun getSeenAnimeNotInLibrary(): List { - return handler.awaitList { animesQueries.getSeenAnimeNotInLibrary(AnimeMapper::mapAnime) } + return database.animesQueries.getSeenAnimeNotInLibrary(AnimeMapper::mapAnime).awaitAsList() } override suspend fun getLibraryAnime(): List { - return handler.awaitList { libraryViewQueries.library(AnimeMapper::mapLibraryAnime) } + return database.libraryViewQueries.library(AnimeMapper::mapLibraryAnime).awaitAsList() } override fun getLibraryAnimeAsFlow(): Flow> { - return handler.subscribeToList { libraryViewQueries.library(AnimeMapper::mapLibraryAnime) } + return database.libraryViewQueries.library(AnimeMapper::mapLibraryAnime).subscribeToList() } override fun getFavoritesBySourceId(sourceId: Long): Flow> { - return handler.subscribeToList { animesQueries.getFavoriteBySourceId(sourceId, AnimeMapper::mapAnime) } + return database.animesQueries.getFavoriteBySourceId(sourceId, AnimeMapper::mapAnime).subscribeToList() } override suspend fun getDuplicateLibraryAnime(id: Long, title: String): List { - return handler.awaitList { - animesQueries.getDuplicateLibraryAnime(id, title, AnimeMapper::mapAnimeWithEpisodeCount) - } + return database.animesQueries.getDuplicateLibraryAnime( + id, + title, + AnimeMapper::mapAnimeWithEpisodeCount, + ).awaitAsList() } override suspend fun getUpcomingAnime(statuses: Set): Flow> { val epochMillis = LocalDate.now().atStartOfDay(ZoneId.systemDefault()).toEpochSecond() * 1000 - return handler.subscribeToList { - animesQueries.getUpcomingAnime(epochMillis, statuses, AnimeMapper::mapAnime) - } + return database.animesQueries.getUpcomingAnime(epochMillis, statuses, AnimeMapper::mapAnime) + .subscribeToList() } override suspend fun resetViewerFlags(): Boolean { return try { - handler.await { animesQueries.resetViewerFlags() } + database.animesQueries.resetViewerFlags() true } catch (e: Exception) { logcat(LogPriority.ERROR, e) @@ -93,10 +96,10 @@ class AnimeRepositoryImpl( } override suspend fun setAnimeCategories(animeId: Long, categoryIds: List) { - handler.await(inTransaction = true) { - animes_categoriesQueries.deleteAnimeCategoryByAnimeId(animeId) - categoryIds.map { categoryId -> - animes_categoriesQueries.insert(animeId, categoryId) + database.transaction { + database.animes_categoriesQueries.deleteAnimeCategoryByAnimeId(animeId) + categoryIds.forEach { categoryId -> + database.animes_categoriesQueries.insert(animeId, categoryId) } } } @@ -122,9 +125,9 @@ class AnimeRepositoryImpl( } override suspend fun insertNetworkAnime(anime: List): List { - return handler.await(inTransaction = true) { + return database.transactionWithResult { anime.map { - animesQueries.insertNetworkAnime( + database.animesQueries.insertNetworkAnime( source = it.source, url = it.url, artist = it.artist, @@ -163,45 +166,45 @@ class AnimeRepositoryImpl( updateDetails = it.initialized, mapper = AnimeMapper::mapAnime, ) - .executeAsOne() + .awaitAsOne() } } } // AY --> override suspend fun getAnimeSeasonsById(parentId: Long): List { - return handler.awaitList { animeseasonsViewQueries.getAnimeSeasonsById(parentId, AnimeMapper::mapSeasonAnime) } + return database.animeseasonsViewQueries.getAnimeSeasonsById(parentId, AnimeMapper::mapSeasonAnime).awaitAsList() } override fun getAnimeSeasonsByIdAsFlow(parentId: Long): Flow> { - return handler.subscribeToList { - animeseasonsViewQueries.getAnimeSeasonsById(parentId, AnimeMapper::mapSeasonAnime) - } + return database.animeseasonsViewQueries.getAnimeSeasonsById( + parentId, + AnimeMapper::mapSeasonAnime, + ).subscribeToList() } override suspend fun removeParentIdByIds(animeIds: List) { try { - handler.await { animesQueries.removeParentIdByIds(animeIds) } + database.animesQueries.removeParentIdByIds(animeIds) } catch (e: Exception) { logcat(LogPriority.ERROR, e) } } override fun getDeletableParentAnime(): Flow> { - return handler.subscribeToList { - animedeletableViewQueries.getDeletableParentAnime(AnimeMapper::mapDeletableAnime) - } + return database.animedeletableViewQueries.getDeletableParentAnime(AnimeMapper::mapDeletableAnime) + .subscribeToList() } override suspend fun getChildrenByParentId(parentId: Long): List { - return handler.awaitList { animesQueries.getChildrenByParentId(parentId, AnimeMapper::mapAnime) } + return database.animesQueries.getChildrenByParentId(parentId, AnimeMapper::mapAnime).awaitAsList() } // <-- AY private suspend fun partialUpdate(vararg animeUpdates: AnimeUpdate) { - handler.await(inTransaction = true) { + database.transaction { animeUpdates.forEach { value -> - animesQueries.update( + database.animesQueries.update( source = value.source, url = value.url, artist = value.artist, diff --git a/data/src/main/java/tachiyomi/data/category/CategoryRepositoryImpl.kt b/data/src/main/java/tachiyomi/data/category/CategoryRepositoryImpl.kt index 6c5dcf7b40..9a9ff278b2 100644 --- a/data/src/main/java/tachiyomi/data/category/CategoryRepositoryImpl.kt +++ b/data/src/main/java/tachiyomi/data/category/CategoryRepositoryImpl.kt @@ -1,88 +1,66 @@ package tachiyomi.data.category +import app.cash.sqldelight.async.coroutines.awaitAsList +import app.cash.sqldelight.async.coroutines.awaitAsOneOrNull import kotlinx.coroutines.flow.Flow import tachiyomi.data.Database -import tachiyomi.data.DatabaseHandler +import tachiyomi.data.subscribeToList import tachiyomi.domain.category.model.Category import tachiyomi.domain.category.model.CategoryUpdate import tachiyomi.domain.category.repository.CategoryRepository class CategoryRepositoryImpl( - private val handler: DatabaseHandler, + private val database: Database, ) : CategoryRepository { override suspend fun get(id: Long): Category? { - return handler.awaitOneOrNull { categoriesQueries.getCategory(id, ::mapCategory) } + return database.categoriesQueries.getCategory(id, ::mapCategory).awaitAsOneOrNull() } override suspend fun getAll(): List { - return handler.awaitList { categoriesQueries.getCategories(::mapCategory) } + return database.categoriesQueries.getCategories(::mapCategory).awaitAsList() } override fun getAllAsFlow(): Flow> { - return handler.subscribeToList { categoriesQueries.getCategories(::mapCategory) } + return database.categoriesQueries.getCategories(::mapCategory).subscribeToList() } override suspend fun getCategoriesByAnimeId(animeId: Long): List { - return handler.awaitList { - categoriesQueries.getCategoriesByAnimeId(animeId, ::mapCategory) - } + return database.categoriesQueries.getCategoriesByAnimeId(animeId, ::mapCategory).awaitAsList() } override fun getCategoriesByAnimeIdAsFlow(animeId: Long): Flow> { - return handler.subscribeToList { - categoriesQueries.getCategoriesByAnimeId(animeId, ::mapCategory) - } + return database.categoriesQueries.getCategoriesByAnimeId(animeId, ::mapCategory).subscribeToList() } // AY --> override suspend fun getAllVisible(): List { - return handler.awaitList { categoriesQueries.getVisibleCategories(::mapCategory) } + return database.categoriesQueries.getVisibleCategories(::mapCategory).awaitAsList() } override fun getAllVisibleAsFlow(): Flow> { - return handler.subscribeToList { categoriesQueries.getVisibleCategories(::mapCategory) } + return database.categoriesQueries.getVisibleCategories(::mapCategory).subscribeToList() } override suspend fun getVisibleCategoriesByAnimeId(animeId: Long): List { - return handler.awaitList { - categoriesQueries.getVisibleCategoriesByAnimeId(animeId, ::mapCategory) - } + return database.categoriesQueries.getVisibleCategoriesByAnimeId(animeId, ::mapCategory).awaitAsList() } override fun getVisibleCategoriesByAnimeIdAsFlow(animeId: Long): Flow> { - return handler.subscribeToList { - categoriesQueries.getVisibleCategoriesByAnimeId(animeId, ::mapCategory) - } + return database.categoriesQueries.getVisibleCategoriesByAnimeId(animeId, ::mapCategory).subscribeToList() } // <-- AY override suspend fun insert(category: Category) { - handler.await { - categoriesQueries.insert( - name = category.name, - order = category.order, - flags = category.flags, - ) - } + database.categoriesQueries.insert( + name = category.name, + order = category.order, + flags = category.flags, + ) } override suspend fun updatePartial(update: CategoryUpdate) { - handler.await { - updatePartialBlocking(update) - } - } - - override suspend fun updatePartial(updates: List) { - handler.await(inTransaction = true) { - for (update in updates) { - updatePartialBlocking(update) - } - } - } - - private fun Database.updatePartialBlocking(update: CategoryUpdate) { - categoriesQueries.update( + database.categoriesQueries.update( name = update.name, order = update.order, flags = update.flags, @@ -93,18 +71,18 @@ class CategoryRepositoryImpl( ) } - override suspend fun updateAllFlags(flags: Long?) { - handler.await { - categoriesQueries.updateAllFlags(flags) + override suspend fun updatePartial(updates: List) { + database.transaction { + updates.forEach { updatePartial(it) } } } + override suspend fun updateAllFlags(flags: Long?) { + database.categoriesQueries.updateAllFlags(flags) + } + override suspend fun delete(categoryId: Long) { - handler.await { - categoriesQueries.delete( - categoryId = categoryId, - ) - } + database.categoriesQueries.delete(categoryId = categoryId) } private fun mapCategory( diff --git a/data/src/main/java/tachiyomi/data/custombutton/CustomButtonRepositoryImpl.kt b/data/src/main/java/tachiyomi/data/custombutton/CustomButtonRepositoryImpl.kt index 270b0baae4..fb763eb7f7 100644 --- a/data/src/main/java/tachiyomi/data/custombutton/CustomButtonRepositoryImpl.kt +++ b/data/src/main/java/tachiyomi/data/custombutton/CustomButtonRepositoryImpl.kt @@ -2,23 +2,24 @@ package tachiyomi.data.custombutton import android.database.sqlite.SQLiteException +import app.cash.sqldelight.async.coroutines.awaitAsList import kotlinx.coroutines.flow.Flow import tachiyomi.data.Database -import tachiyomi.data.DatabaseHandler +import tachiyomi.data.subscribeToList import tachiyomi.domain.custombutton.exception.SaveCustomButtonException import tachiyomi.domain.custombutton.model.CustomButton import tachiyomi.domain.custombutton.model.CustomButtonUpdate import tachiyomi.domain.custombutton.repository.CustomButtonRepository class CustomButtonRepositoryImpl( - private val handler: DatabaseHandler, + private val database: Database, ) : CustomButtonRepository { override fun subscribeAll(): Flow> { - return handler.subscribeToList { custom_buttonsQueries.findAll(::mapCustomButton) } + return database.custom_buttonsQueries.findAll(::mapCustomButton).subscribeToList() } override suspend fun getAll(): List { - return handler.awaitList { custom_buttonsQueries.findAll(::mapCustomButton) } + return database.custom_buttonsQueries.findAll(::mapCustomButton).awaitAsList() } override suspend fun insertCustomButton( @@ -29,32 +30,14 @@ class CustomButtonRepositoryImpl( onStartup: String, ) { try { - handler.await { custom_buttonsQueries.insert(name, false, sortIndex, content, longPressContent, onStartup) } + database.custom_buttonsQueries.insert(name, false, sortIndex, content, longPressContent, onStartup) } catch (ex: SQLiteException) { throw SaveCustomButtonException(ex) } } override suspend fun updatePartialCustomButton(update: CustomButtonUpdate) { - handler.await { - updatePartialBlocking(update) - } - } - - override suspend fun updatePartialCustomButtons(updates: List) { - handler.await(inTransaction = true) { - for (update in updates) { - updatePartialBlocking(update) - } - } - } - - override suspend fun deleteCustomButton(customButtonId: Long) { - return handler.await { custom_buttonsQueries.delete(customButtonId) } - } - - private fun Database.updatePartialBlocking(update: CustomButtonUpdate) { - custom_buttonsQueries.update( + database.custom_buttonsQueries.update( name = update.name, isFavorite = update.isFavorite, sortIndex = update.sortIndex, @@ -65,6 +48,16 @@ class CustomButtonRepositoryImpl( ) } + override suspend fun updatePartialCustomButtons(updates: List) { + database.transaction { + updates.forEach { updatePartialCustomButton(it) } + } + } + + override suspend fun deleteCustomButton(customButtonId: Long) { + database.custom_buttonsQueries.delete(customButtonId) + } + private fun mapCustomButton( id: Long, name: String, diff --git a/data/src/main/java/tachiyomi/data/episode/EpisodeRepositoryImpl.kt b/data/src/main/java/tachiyomi/data/episode/EpisodeRepositoryImpl.kt index f9e76889ba..2c34373c14 100644 --- a/data/src/main/java/tachiyomi/data/episode/EpisodeRepositoryImpl.kt +++ b/data/src/main/java/tachiyomi/data/episode/EpisodeRepositoryImpl.kt @@ -1,23 +1,27 @@ package tachiyomi.data.episode +import app.cash.sqldelight.async.coroutines.awaitAsList +import app.cash.sqldelight.async.coroutines.awaitAsOne +import app.cash.sqldelight.async.coroutines.awaitAsOneOrNull import kotlinx.coroutines.flow.Flow import logcat.LogPriority import tachiyomi.core.common.util.lang.toLong import tachiyomi.core.common.util.system.logcat -import tachiyomi.data.DatabaseHandler +import tachiyomi.data.Database +import tachiyomi.data.subscribeToList import tachiyomi.domain.episode.model.Episode import tachiyomi.domain.episode.model.EpisodeUpdate import tachiyomi.domain.episode.repository.EpisodeRepository class EpisodeRepositoryImpl( - private val handler: DatabaseHandler, + private val database: Database, ) : EpisodeRepository { override suspend fun addAll(episodes: List): List { return try { - handler.await(inTransaction = true) { + database.transactionWithResult { episodes.map { episode -> - episodesQueries.insert( + val episodeId = database.episodesQueries.insertReturningId( episode.animeId, episode.url, episode.name, @@ -41,8 +45,8 @@ class EpisodeRepositoryImpl( episode.previewUrl, // <-- AY ) - val lastInsertId = episodesQueries.selectLastInsertedRowId().executeAsOne() - episode.copy(id = lastInsertId) + .awaitAsOne() + episode.copy(id = episodeId) } } } catch (e: Exception) { @@ -60,9 +64,9 @@ class EpisodeRepositoryImpl( } private suspend fun partialUpdate(vararg episodeUpdates: EpisodeUpdate) { - handler.await(inTransaction = true) { + database.transaction { episodeUpdates.forEach { episodeUpdate -> - episodesQueries.update( + database.episodesQueries.update( animeId = episodeUpdate.animeId, url = episodeUpdate.url, name = episodeUpdate.name, @@ -94,59 +98,56 @@ class EpisodeRepositoryImpl( override suspend fun removeEpisodesWithIds(episodeIds: List) { try { - handler.await { episodesQueries.removeEpisodesWithIds(episodeIds) } + database.episodesQueries.removeEpisodesWithIds(episodeIds) } catch (e: Exception) { logcat(LogPriority.ERROR, e) } } override suspend fun getEpisodeByAnimeId(animeId: Long, applyScanlatorFilter: Boolean): List { - return handler.awaitList { - episodesQueries.getEpisodesByAnimeId(animeId, applyScanlatorFilter.toLong(), ::mapEpisode) - } + return database.episodesQueries.getEpisodesByAnimeId( + animeId, + applyScanlatorFilter.toLong(), + ::mapEpisode, + ).awaitAsList() } override suspend fun getScanlatorsByAnimeId(animeId: Long): List { - return handler.awaitList { - episodesQueries.getScanlatorsByAnimeId(animeId) { it.orEmpty() } - } + return database.episodesQueries.getScanlatorsByAnimeId(animeId) { it.orEmpty() }.awaitAsList() } override fun getScanlatorsByAnimeIdAsFlow(animeId: Long): Flow> { - return handler.subscribeToList { - episodesQueries.getScanlatorsByAnimeId(animeId) { it.orEmpty() } - } + return database.episodesQueries.getScanlatorsByAnimeId(animeId) { it.orEmpty() }.subscribeToList() } override suspend fun getBookmarkedEpisodesByAnimeId(animeId: Long): List { - return handler.awaitList { - episodesQueries.getBookmarkedEpisodesByAnimeId( - animeId, - ::mapEpisode, - ) - } + return database.episodesQueries.getBookmarkedEpisodesByAnimeId( + animeId, + ::mapEpisode, + ).awaitAsList() } override suspend fun getEpisodeById(id: Long): Episode? { - return handler.awaitOneOrNull { episodesQueries.getEpisodeById(id, ::mapEpisode) } + return database.episodesQueries.getEpisodeById(id, ::mapEpisode).awaitAsOneOrNull() } override suspend fun getEpisodeByAnimeIdAsFlow(animeId: Long, applyScanlatorFilter: Boolean): Flow> { - return handler.subscribeToList { - episodesQueries.getEpisodesByAnimeId(animeId, applyScanlatorFilter.toLong(), ::mapEpisode) - } + return database.episodesQueries.getEpisodesByAnimeId( + animeId, + applyScanlatorFilter.toLong(), + ::mapEpisode, + ).subscribeToList() } override suspend fun getEpisodeByUrlAndAnimeId(url: String, animeId: Long): Episode? { - return handler.awaitOneOrNull { - episodesQueries.getEpisodeByUrlAndAnimeId( - url, - animeId, - ::mapEpisode, - ) - } + return database.episodesQueries.getEpisodeByUrlAndAnimeId( + url, + animeId, + ::mapEpisode, + ).awaitAsOneOrNull() } + @Suppress("UNUSED_PARAMETER") private fun mapEpisode( id: Long, animeId: Long, @@ -168,7 +169,6 @@ class EpisodeRepositoryImpl( dateUpload: Long, lastModifiedAt: Long, version: Long, - @Suppress("UNUSED_PARAMETER") isSyncing: Long, // AY --> summary: String?, diff --git a/data/src/main/java/tachiyomi/data/history/HistoryRepositoryImpl.kt b/data/src/main/java/tachiyomi/data/history/HistoryRepositoryImpl.kt index 17622f4784..7b82437297 100644 --- a/data/src/main/java/tachiyomi/data/history/HistoryRepositoryImpl.kt +++ b/data/src/main/java/tachiyomi/data/history/HistoryRepositoryImpl.kt @@ -1,37 +1,37 @@ package tachiyomi.data.history +import app.cash.sqldelight.async.coroutines.awaitAsList +import app.cash.sqldelight.async.coroutines.awaitAsOneOrNull import kotlinx.coroutines.flow.Flow import logcat.LogPriority import tachiyomi.core.common.util.system.logcat -import tachiyomi.data.DatabaseHandler +import tachiyomi.data.Database +import tachiyomi.data.subscribeToList import tachiyomi.domain.history.model.History import tachiyomi.domain.history.model.HistoryUpdate import tachiyomi.domain.history.model.HistoryWithRelations import tachiyomi.domain.history.repository.HistoryRepository class HistoryRepositoryImpl( - private val handler: DatabaseHandler, + private val database: Database, ) : HistoryRepository { override fun getHistory(query: String): Flow> { - return handler.subscribeToList { - historyViewQueries.history(query, HistoryMapper::mapHistoryWithRelations) - } + return database.historyViewQueries.history(query, HistoryMapper::mapHistoryWithRelations).subscribeToList() } override suspend fun getLastHistory(): HistoryWithRelations? { - return handler.awaitOneOrNull { - historyViewQueries.getLatestHistory(HistoryMapper::mapHistoryWithRelations) - } + return database.historyViewQueries.getLatestHistory(HistoryMapper::mapHistoryWithRelations) + .awaitAsOneOrNull() } override suspend fun getHistoryByAnimeId(animeId: Long): List { - return handler.awaitList { historyQueries.getHistoryByAnimeId(animeId, HistoryMapper::mapHistory) } + return database.historyQueries.getHistoryByAnimeId(animeId, HistoryMapper::mapHistory).awaitAsList() } override suspend fun resetHistory(historyId: Long) { try { - handler.await { historyQueries.resetHistoryById(historyId) } + database.historyQueries.resetHistoryById(historyId) } catch (e: Exception) { logcat(LogPriority.ERROR, throwable = e) } @@ -39,7 +39,7 @@ class HistoryRepositoryImpl( override suspend fun resetHistoryByAnimeId(animeId: Long) { try { - handler.await { historyQueries.resetHistoryByAnimeId(animeId) } + database.historyQueries.resetHistoryByAnimeId(animeId) } catch (e: Exception) { logcat(LogPriority.ERROR, throwable = e) } @@ -47,7 +47,7 @@ class HistoryRepositoryImpl( override suspend fun deleteAllHistory(): Boolean { return try { - handler.await { historyQueries.removeAllHistory() } + database.historyQueries.removeAllHistory() true } catch (e: Exception) { logcat(LogPriority.ERROR, throwable = e) @@ -57,12 +57,10 @@ class HistoryRepositoryImpl( override suspend fun upsertHistory(historyUpdate: HistoryUpdate) { try { - handler.await { - historyQueries.upsert( - historyUpdate.episodeId, - historyUpdate.seenAt, - ) - } + database.historyQueries.upsert( + historyUpdate.episodeId, + historyUpdate.seenAt, + ) } catch (e: Exception) { logcat(LogPriority.ERROR, throwable = e) } diff --git a/data/src/main/java/tachiyomi/data/source/SourceRepositoryImpl.kt b/data/src/main/java/tachiyomi/data/source/SourceRepositoryImpl.kt index b1f7119de3..90c7a4aea3 100644 --- a/data/src/main/java/tachiyomi/data/source/SourceRepositoryImpl.kt +++ b/data/src/main/java/tachiyomi/data/source/SourceRepositoryImpl.kt @@ -7,7 +7,8 @@ import eu.kanade.tachiyomi.animesource.online.AnimeHttpSource import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.map -import tachiyomi.data.DatabaseHandler +import tachiyomi.data.Database +import tachiyomi.data.subscribeToList import tachiyomi.domain.source.model.StubSource import tachiyomi.domain.source.repository.SourcePagingSource import tachiyomi.domain.source.repository.SourceRepository @@ -16,7 +17,7 @@ import tachiyomi.domain.source.model.Source as DomainSource class SourceRepositoryImpl( private val sourceManager: SourceManager, - private val handler: DatabaseHandler, + private val database: Database, ) : SourceRepository { override fun getSources(): Flow> { @@ -38,10 +39,13 @@ class SourceRepositoryImpl( } override fun getSourcesWithFavoriteCount(): Flow>> { - return combine( - handler.subscribeToList { animesQueries.getSourceIdWithFavoriteCount() }, - sourceManager.catalogueSources, - ) { sourceIdWithFavoriteCount, _ -> sourceIdWithFavoriteCount } + val sourceIdWithFavoriteCountFlow = database.animesQueries + .getSourceIdWithFavoriteCount() + .subscribeToList() + + return combine(sourceIdWithFavoriteCountFlow, sourceManager.catalogueSources) { sourceIdWithFavoriteCount, _ -> + sourceIdWithFavoriteCount + } .map { it.map { (sourceId, count) -> val source = sourceManager.getOrStub(sourceId) diff --git a/data/src/main/java/tachiyomi/data/source/StubSourceRepositoryImpl.kt b/data/src/main/java/tachiyomi/data/source/StubSourceRepositoryImpl.kt index 157e1eb2f1..2c49573dfb 100644 --- a/data/src/main/java/tachiyomi/data/source/StubSourceRepositoryImpl.kt +++ b/data/src/main/java/tachiyomi/data/source/StubSourceRepositoryImpl.kt @@ -1,24 +1,26 @@ package tachiyomi.data.source +import app.cash.sqldelight.async.coroutines.awaitAsOneOrNull import kotlinx.coroutines.flow.Flow -import tachiyomi.data.DatabaseHandler +import tachiyomi.data.Database +import tachiyomi.data.subscribeToList import tachiyomi.domain.source.model.StubSource import tachiyomi.domain.source.repository.StubSourceRepository class StubSourceRepositoryImpl( - private val handler: DatabaseHandler, + private val database: Database, ) : StubSourceRepository { override fun subscribeAll(): Flow> { - return handler.subscribeToList { sourcesQueries.findAll(::mapStubSource) } + return database.sourcesQueries.findAll(::mapStubSource).subscribeToList() } override suspend fun getStubSource(id: Long): StubSource? { - return handler.awaitOneOrNull { sourcesQueries.findOne(id, ::mapStubSource) } + return database.sourcesQueries.findOne(id, ::mapStubSource).awaitAsOneOrNull() } override suspend fun upsertStubSource(id: Long, lang: String, name: String) { - handler.await { sourcesQueries.upsert(id, lang, name) } + database.sourcesQueries.upsert(id, lang, name) } private fun mapStubSource( diff --git a/data/src/main/java/tachiyomi/data/track/TrackRepositoryImpl.kt b/data/src/main/java/tachiyomi/data/track/TrackRepositoryImpl.kt index 81bdd5dc47..5726a8a951 100644 --- a/data/src/main/java/tachiyomi/data/track/TrackRepositoryImpl.kt +++ b/data/src/main/java/tachiyomi/data/track/TrackRepositoryImpl.kt @@ -1,44 +1,41 @@ package tachiyomi.data.track +import app.cash.sqldelight.async.coroutines.awaitAsList +import app.cash.sqldelight.async.coroutines.awaitAsOneOrNull import kotlinx.coroutines.flow.Flow -import tachiyomi.data.DatabaseHandler +import tachiyomi.data.Database +import tachiyomi.data.subscribeToList import tachiyomi.data.track.TrackMapper.mapTrack import tachiyomi.domain.track.model.Track import tachiyomi.domain.track.repository.TrackRepository class TrackRepositoryImpl( - private val handler: DatabaseHandler, + private val database: Database, ) : TrackRepository { override suspend fun getTrackById(id: Long): Track? { - return handler.awaitOneOrNull { anime_syncQueries.getTrackById(id, TrackMapper::mapTrack) } + return database.anime_syncQueries.getTrackById(id, TrackMapper::mapTrack).awaitAsOneOrNull() } override suspend fun getTracksByAnimeId(animeId: Long): List { - return handler.awaitList { - anime_syncQueries.getTracksByAnimeId(animeId, TrackMapper::mapTrack) - } + return database.anime_syncQueries.getTracksByAnimeId(animeId, TrackMapper::mapTrack).awaitAsList() } override fun getTracksAsFlow(): Flow> { - return handler.subscribeToList { - anime_syncQueries.getTracks(TrackMapper::mapTrack) - } + return database.anime_syncQueries.getTracks(TrackMapper::mapTrack) + .subscribeToList() } override fun getTracksByAnimeIdAsFlow(animeId: Long): Flow> { - return handler.subscribeToList { - anime_syncQueries.getTracksByAnimeId(animeId, TrackMapper::mapTrack) - } + return database.anime_syncQueries.getTracksByAnimeId(animeId, TrackMapper::mapTrack) + .subscribeToList() } override suspend fun delete(animeId: Long, trackerId: Long) { - handler.await { - anime_syncQueries.delete( - animeId = animeId, - syncId = trackerId, - ) - } + database.anime_syncQueries.delete( + animeId = animeId, + syncId = trackerId, + ) } override suspend fun insert(track: Track) { @@ -50,9 +47,9 @@ class TrackRepositoryImpl( } private suspend fun insertValues(vararg tracks: Track) { - handler.await(inTransaction = true) { + database.transaction { tracks.forEach { animeTrack -> - anime_syncQueries.insert( + database.anime_syncQueries.insert( animeId = animeTrack.animeId, syncId = animeTrack.trackerId, remoteId = animeTrack.remoteId, @@ -73,9 +70,8 @@ class TrackRepositoryImpl( // AM (GROUPING) --> override suspend fun getTracks(): List { - return handler.awaitList { - anime_syncQueries.getTracks(::mapTrack) - } + return database.anime_syncQueries.getTracks(::mapTrack) + .awaitAsList() } // <-- AM (GROUPING) } diff --git a/data/src/main/java/tachiyomi/data/updates/UpdatesRepositoryImpl.kt b/data/src/main/java/tachiyomi/data/updates/UpdatesRepositoryImpl.kt index 9c5eaabe88..258c5393bd 100644 --- a/data/src/main/java/tachiyomi/data/updates/UpdatesRepositoryImpl.kt +++ b/data/src/main/java/tachiyomi/data/updates/UpdatesRepositoryImpl.kt @@ -1,14 +1,16 @@ package tachiyomi.data.updates +import app.cash.sqldelight.async.coroutines.awaitAsList import kotlinx.coroutines.flow.Flow import tachiyomi.core.common.util.lang.toLong -import tachiyomi.data.DatabaseHandler +import tachiyomi.data.Database +import tachiyomi.data.subscribeToList import tachiyomi.domain.anime.model.AnimeCover import tachiyomi.domain.updates.model.UpdatesWithRelations import tachiyomi.domain.updates.repository.UpdatesRepository class UpdatesRepositoryImpl( - private val databaseHandler: DatabaseHandler, + private val database: Database, ) : UpdatesRepository { override suspend fun awaitWithSeen( @@ -16,14 +18,12 @@ class UpdatesRepositoryImpl( after: Long, limit: Long, ): List { - return databaseHandler.awaitList { - updatesViewQueries.getUpdatesBySeenStatus( - seen = seen, - after = after, - limit = limit, - mapper = ::mapUpdatesWithRelations, - ) - } + return database.updatesViewQueries.getUpdatesBySeenStatus( + seen = seen, + after = after, + limit = limit, + mapper = ::mapUpdatesWithRelations, + ).awaitAsList() } override fun subscribeAll( @@ -35,19 +35,17 @@ class UpdatesRepositoryImpl( fillermarked: Boolean?, hideExcludedScanlators: Boolean, ): Flow> { - return databaseHandler.subscribeToList { - updatesViewQueries.getRecentUpdatesWithFilters( - after = after, - limit = limit, - // invert because unseen in Kotlin -> seen column in SQL - seen = unseen?.let { !it }, - started = started?.toLong(), - bookmarked = bookmarked, - fillermarked = fillermarked, - hideExcludedScanlators = hideExcludedScanlators.toLong(), - mapper = ::mapUpdatesWithRelations, - ) - } + return database.updatesViewQueries.getRecentUpdatesWithFilters( + after = after, + limit = limit, + // invert because unseen in Kotlin -> seen column in SQL + seen = unseen?.let { !it }, + started = started?.toLong(), + bookmarked = bookmarked, + fillermarked = fillermarked, + hideExcludedScanlators = hideExcludedScanlators.toLong(), + mapper = ::mapUpdatesWithRelations, + ).subscribeToList() } override fun subscribeWithSeen( @@ -55,16 +53,16 @@ class UpdatesRepositoryImpl( after: Long, limit: Long, ): Flow> { - return databaseHandler.subscribeToList { - updatesViewQueries.getUpdatesBySeenStatus( - seen = seen, - after = after, - limit = limit, - mapper = ::mapUpdatesWithRelations, - ) - } + return database.updatesViewQueries.getUpdatesBySeenStatus( + seen = seen, + after = after, + limit = limit, + mapper = ::mapUpdatesWithRelations, + ) + .subscribeToList() } + @Suppress("UNUSED_PARAMETER") private fun mapUpdatesWithRelations( animeId: Long, animeTitle: String, diff --git a/data/src/main/sqldelight/tachiyomi/data/animes.sq b/data/src/main/sqldelight/tachiyomi/data/animes.sq index 403ed1595a..c911e2e151 100644 --- a/data/src/main/sqldelight/tachiyomi/data/animes.sq +++ b/data/src/main/sqldelight/tachiyomi/data/animes.sq @@ -213,9 +213,10 @@ AND ( ) ); -insert: +insertReturningId: INSERT INTO animes(source, url, artist, author, description, genre, title, status, thumbnail_url, favorite, last_update, next_update, initialized, viewer, episode_flags, cover_last_modified, date_added, update_strategy, calculate_interval, last_modified_at, version, notes, fetch_type, parent_id, season_flags, season_number, season_source_order, background_url, background_last_modified) -VALUES (:source, :url, :artist, :author, :description, :genre, :title, :status, :thumbnailUrl, :favorite, :lastUpdate, :nextUpdate, :initialized, :viewerFlags, :episodeFlags, :coverLastModified, :dateAdded, :updateStrategy, :calculateInterval, 0, :version, :notes, :fetchType, :parentId, :seasonFlags, :seasonNumber, :seasonSourceOrder, :backgroundUrl, :backgroundLastModified); +VALUES (:source, :url, :artist, :author, :description, :genre, :title, :status, :thumbnailUrl, :favorite, :lastUpdate, :nextUpdate, :initialized, :viewerFlags, :episodeFlags, :coverLastModified, :dateAdded, :updateStrategy, :calculateInterval, 0, :version, :notes, :fetchType, :parentId, :seasonFlags, :seasonNumber, :seasonSourceOrder, :backgroundUrl, :backgroundLastModified) +RETURNING _id; update: UPDATE animes SET @@ -252,9 +253,6 @@ UPDATE animes SET -- <-- AY WHERE _id = :animeId; -selectLastInsertedRowId: -SELECT last_insert_rowid(); - insertNetworkAnime { -- Insert the anime if it doesn't exist already INSERT INTO animes( diff --git a/data/src/main/sqldelight/tachiyomi/data/categories.sq b/data/src/main/sqldelight/tachiyomi/data/categories.sq index 733905e7dc..f65d78fea6 100644 --- a/data/src/main/sqldelight/tachiyomi/data/categories.sq +++ b/data/src/main/sqldelight/tachiyomi/data/categories.sq @@ -99,6 +99,3 @@ WHERE _id = :categoryId; updateAllFlags: UPDATE categories SET flags = coalesce(?, flags); - -selectLastInsertedRowId: -SELECT last_insert_rowid(); diff --git a/data/src/main/sqldelight/tachiyomi/data/custom_buttons.sq b/data/src/main/sqldelight/tachiyomi/data/custom_buttons.sq index 63b7212098..42bc236b5b 100644 --- a/data/src/main/sqldelight/tachiyomi/data/custom_buttons.sq +++ b/data/src/main/sqldelight/tachiyomi/data/custom_buttons.sq @@ -35,9 +35,12 @@ SELECT * FROM custom_buttons ORDER BY sortIndex; -insert: -INSERT INTO custom_buttons(name, isFavorite, sortIndex, content, longPressContent, onStartup) -VALUES (:name, :isFavorite, :sortIndex, :content, :longPressContent, :onStartup); +insert { + INSERT INTO custom_buttons(name, isFavorite, sortIndex, content, longPressContent, onStartup) + VALUES (:name, :isFavorite, :sortIndex, :content, :longPressContent, :onStartup); + + SELECT last_insert_rowid(); +} delete: DELETE FROM custom_buttons @@ -52,7 +55,4 @@ SET name = coalesce(:name, name), longPressContent = coalesce(:longPressContent, longPressContent), onStartup = coalesce(:onStartup, onStartup) WHERE _id = :customButtonId; - -selectLastInsertedRowId: -SELECT last_insert_rowid(); -- <-- AY diff --git a/data/src/main/sqldelight/tachiyomi/data/episodes.sq b/data/src/main/sqldelight/tachiyomi/data/episodes.sq index c2dd9e23ca..c3d374c6ce 100644 --- a/data/src/main/sqldelight/tachiyomi/data/episodes.sq +++ b/data/src/main/sqldelight/tachiyomi/data/episodes.sq @@ -111,6 +111,11 @@ insert: INSERT INTO episodes(anime_id, url, name, scanlator, seen, bookmark, fillermark, last_second_seen, total_seconds, episode_number, source_order, date_fetch, date_upload, last_modified_at, version, is_syncing, summary, preview_url) VALUES (:animeId, :url, :name, :scanlator, :seen, :bookmark, :fillermark, :lastSecondSeen, :totalSeconds, :episodeNumber, :sourceOrder, :dateFetch, :dateUpload, 0, :version, 0, :summary, :previewUrl); +insertReturningId: +INSERT INTO episodes(anime_id, url, name, scanlator, seen, bookmark, fillermark, last_second_seen, total_seconds, episode_number, source_order, date_fetch, date_upload, last_modified_at, version, is_syncing, summary, preview_url) +VALUES (:animeId, :url, :name, :scanlator, :seen, :bookmark, :fillermark, :lastSecondSeen, :totalSeconds, :episodeNumber, :sourceOrder, :dateFetch, :dateUpload, 0, :version, 0, :summary, :previewUrl) +RETURNING _id; + update: UPDATE episodes SET anime_id = coalesce(:animeId, anime_id), @@ -137,6 +142,3 @@ SET anime_id = coalesce(:animeId, anime_id), preview_url = coalesce(:previewUrl, preview_url) -- <-- AY WHERE _id = :episodeId; - -selectLastInsertedRowId: -SELECT last_insert_rowid(); diff --git a/domain/build.gradle.kts b/domain/build.gradle.kts index 89bf001213..467dccef44 100644 --- a/domain/build.gradle.kts +++ b/domain/build.gradle.kts @@ -1,16 +1,12 @@ plugins { - id("mihon.library") - kotlin("android") - kotlin("plugin.serialization") + alias(mihonx.plugins.android.library) + alias(mihonx.plugins.spotless) + + alias(libs.plugins.kotlin.serialization) } android { namespace = "tachiyomi.domain" - - defaultConfig { - testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" - consumerProguardFiles("consumer-rules.pro") - } } kotlin { @@ -27,17 +23,17 @@ dependencies { implementation(projects.i18nAnimiru) // <-- AM (GROUPING) - implementation(platform(kotlinx.coroutines.bom)) - implementation(kotlinx.bundles.coroutines) - implementation(kotlinx.bundles.serialization) + implementation(libs.bundles.kotlinx.coroutines) + implementation(libs.bundles.serialization) implementation(libs.unifile) - api(libs.sqldelight.android.paging) + api(libs.sqldelight.androidxPaging) - compileOnly(compose.runtime.annotation) + compileOnly(platform(libs.androidx.compose.bom)) + compileOnly(libs.androidx.compose.runtimeAnnotation) testImplementation(libs.bundles.test) - testImplementation(kotlinx.coroutines.test) + testImplementation(libs.kotlinx.coroutines.test) testRuntimeOnly(libs.junit.platform.launcher) } diff --git a/domain/consumer-rules.pro b/domain/consumer-rules.pro deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/domain/proguard-rules.pro b/domain/proguard-rules.pro deleted file mode 100644 index 481bb43481..0000000000 --- a/domain/proguard-rules.pro +++ /dev/null @@ -1,21 +0,0 @@ -# Add project specific ProGuard rules here. -# You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Uncomment this to preserve the line number information for -# debugging stack traces. -#-keepattributes SourceFile,LineNumberTable - -# If you keep the line number information, uncomment this to -# hide the original source file name. -#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 22e7dfed58..03ae0ec0a2 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,9 +1,8 @@ android.nonTransitiveRClass=false -android.useAndroidX=true kotlin.code.style=official -kotlin.mpp.androidSourceSetLayoutVersion=2 +# Configuration should be synced with [/gradle/build-logic/gradle.properties] org.gradle.caching=true org.gradle.configureondemand=true org.gradle.jvmargs=-Xmx4g -Dfile.encoding=UTF-8 diff --git a/gradle/androidx.versions.toml b/gradle/androidx.versions.toml deleted file mode 100644 index 43296b6476..0000000000 --- a/gradle/androidx.versions.toml +++ /dev/null @@ -1,40 +0,0 @@ -[versions] -agp_version = "8.13.2" -lifecycle_version = "2.10.0" -paging_version = "3.4.2" -interpolator_version = "1.0.0" -sqlite = "2.6.2" - -[libraries] -gradle = { module = "com.android.tools.build:gradle", version.ref = "agp_version" } - -annotation = "androidx.annotation:annotation:1.9.1" -appcompat = "androidx.appcompat:appcompat:1.7.1" -biometricktx = "androidx.biometric:biometric-ktx:1.2.0-alpha05" -constraintlayout = "androidx.constraintlayout:constraintlayout:2.2.1" -corektx = "androidx.core:core-ktx:1.18.0" -splashscreen = "androidx.core:core-splashscreen:1.2.0" -recyclerview = "androidx.recyclerview:recyclerview:1.4.0" -viewpager = "androidx.viewpager:viewpager:1.1.0" -profileinstaller = "androidx.profileinstaller:profileinstaller:1.4.1" - -lifecycle-common = { module = "androidx.lifecycle:lifecycle-common", version.ref = "lifecycle_version" } -lifecycle-process = { module = "androidx.lifecycle:lifecycle-process", version.ref = "lifecycle_version" } -lifecycle-runtimektx = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "lifecycle_version" } - -workmanager = "androidx.work:work-runtime:2.11.1" - -paging-runtime = { module = "androidx.paging:paging-runtime", version.ref = "paging_version" } -paging-compose = { module = "androidx.paging:paging-compose", version.ref = "paging_version" } - -interpolator = { group = "androidx.interpolator", name = "interpolator", version.ref = "interpolator_version" } - -benchmark-macro = "androidx.benchmark:benchmark-macro-junit4:1.4.1" -test-ext = "androidx.test.ext:junit-ktx:1.3.0" -test-espresso-core = "androidx.test.espresso:espresso-core:3.7.0" -test-uiautomator = "androidx.test.uiautomator:uiautomator:2.3.0" - -sqlite-bundled = { module = "androidx.sqlite:sqlite-bundled", version.ref = "sqlite" } - -[bundles] -lifecycle = ["lifecycle-common", "lifecycle-process", "lifecycle-runtimektx"] diff --git a/gradle/build-logic/build.gradle.kts b/gradle/build-logic/build.gradle.kts new file mode 100644 index 0000000000..cb4968fdee --- /dev/null +++ b/gradle/build-logic/build.gradle.kts @@ -0,0 +1,78 @@ +plugins { + alias(libs.plugins.kotlin.jvm) + alias(libs.plugins.kotlin.samWithReceiver) + alias(libs.plugins.spotless) + `java-gradle-plugin` +} + +// Configuration should be synced with [/gradle/build-logic/src/main/kotlin/PluginSpotless.kt] +val ktlintVersion = libs.ktlint.bom.get().version +val editorConfigFile = rootProject.file("../../.editorconfig") +spotless { + kotlin { + target("src/**/*.kt") + ktlint(ktlintVersion).setEditorConfigPath(editorConfigFile) + trimTrailingWhitespace() + endWithNewline() + } + + kotlinGradle { + target("*.kts") + ktlint(ktlintVersion).setEditorConfigPath(editorConfigFile) + trimTrailingWhitespace() + endWithNewline() + } +} + +dependencies { + compileOnly(gradleKotlinDsl()) + compileOnly(libs.android.gradle) + compileOnly(libs.kotlin.compose.compiler.gradle) + compileOnly(libs.kotlin.gradle) + implementation(libs.spotless.gradle) + implementation(libs.tapmoc.gradle) + + // These allow us to reference the dependency catalog inside our compiled plugins + compileOnly(files(libs::class.java.superclass.protectionDomain.codeSource.location)) + compileOnly(files(mihonx::class.java.superclass.protectionDomain.codeSource.location)) + // AM --> + compileOnly(files(aniyomilibs::class.java.superclass.protectionDomain.codeSource.location)) + // <-- AM +} + +samWithReceiver { + annotation("org.gradle.api.HasImplicitReceiver") +} + +gradlePlugin { + plugins { + register("android-application") { + id = mihonx.plugins.android.application.get().pluginId + implementationClass = "PluginAndroidApplication" + } + register("android-base") { + id = mihonx.plugins.android.base.get().pluginId + implementationClass = "PluginAndroidBase" + } + register("android-library") { + id = mihonx.plugins.android.library.get().pluginId + implementationClass = "PluginAndroidLibrary" + } + register("android-test") { + id = mihonx.plugins.android.test.get().pluginId + implementationClass = "PluginAndroidTest" + } + register("compose-android") { + id = mihonx.plugins.compose.get().pluginId + implementationClass = "PluginComposeAndroid" + } + register("kotlin-multiplatform") { + id = mihonx.plugins.kotlin.multiplatform.get().pluginId + implementationClass = "PluginKotlinMultiplatform" + } + register("spotless") { + id = mihonx.plugins.spotless.get().pluginId + implementationClass = "PluginSpotless" + } + } +} diff --git a/gradle/build-logic/gradle.properties b/gradle/build-logic/gradle.properties new file mode 100644 index 0000000000..ed607fa33c --- /dev/null +++ b/gradle/build-logic/gradle.properties @@ -0,0 +1,8 @@ +# Configuration should be synced with [/gradle.properties] +# +# Gradle properties are not passed to included builds +# https://github.com/gradle/gradle/issues/2534 +org.gradle.caching=true +org.gradle.configureondemand=true +org.gradle.jvmargs=-Xmx4g -Dfile.encoding=UTF-8 +org.gradle.parallel=true diff --git a/gradle/build-logic/settings.gradle.kts b/gradle/build-logic/settings.gradle.kts new file mode 100644 index 0000000000..fc1cffc513 --- /dev/null +++ b/gradle/build-logic/settings.gradle.kts @@ -0,0 +1,23 @@ +dependencyResolutionManagement { + @Suppress("UnstableApiUsage") + repositories { + google() + mavenCentral() + gradlePluginPortal() + } + versionCatalogs { + create("libs") { + from(files("../libs.versions.toml")) + } + create("mihonx") { + from(files("../mihon.versions.toml")) + } + // AM --> + create("aniyomilibs") { + from(files("../aniyomi.versions.toml")) + } + // <-- AM + } +} + +rootProject.name = "build-logic" diff --git a/gradle/build-logic/src/main/kotlin/PluginAndroidApplication.kt b/gradle/build-logic/src/main/kotlin/PluginAndroidApplication.kt new file mode 100644 index 0000000000..1348f92cc1 --- /dev/null +++ b/gradle/build-logic/src/main/kotlin/PluginAndroidApplication.kt @@ -0,0 +1,16 @@ +import mihon.gradle.extensions.alias +import mihon.gradle.extensions.libs +import mihon.gradle.extensions.mihonx +import mihon.gradle.extensions.plugins +import org.gradle.api.Plugin +import org.gradle.api.Project + +@Suppress("UNUSED") +class PluginAndroidApplication : Plugin { + override fun apply(target: Project): Unit = with(target) { + plugins { + alias(libs.plugins.android.application) + alias(mihonx.plugins.android.base) + } + } +} diff --git a/gradle/build-logic/src/main/kotlin/PluginAndroidBase.kt b/gradle/build-logic/src/main/kotlin/PluginAndroidBase.kt new file mode 100644 index 0000000000..70e553ea32 --- /dev/null +++ b/gradle/build-logic/src/main/kotlin/PluginAndroidBase.kt @@ -0,0 +1,50 @@ +import com.android.build.api.dsl.ApplicationDefaultConfig +import com.android.build.api.dsl.CommonExtension +import com.android.build.api.dsl.CompileOptions +import com.android.build.api.dsl.DefaultConfig +import mihon.gradle.configurations.configureKotlin +import mihon.gradle.extensions.android +import mihon.gradle.extensions.configureTest +import mihon.gradle.extensions.coreLibraryDesugaring +import mihon.gradle.extensions.libs +import mihon.gradle.extensions.mihonx +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.kotlin.dsl.dependencies + +@Suppress("UNUSED") +class PluginAndroidBase : Plugin { + override fun apply(target: Project): Unit = with(target) { + configureKotlin() + configureTest() + + android { + defaultConfig { + minSdk = mihonx.versions.android.sdk.min.get().toInt() + if (this is ApplicationDefaultConfig) { + targetSdk = mihonx.versions.android.sdk.target.get().toInt() + } + + ndkVersion = mihonx.versions.android.ndk.get() + } + + compileSdk = mihonx.versions.android.sdk.compile.get().toInt() + + compileOptions { + isCoreLibraryDesugaringEnabled = true + } + } + + dependencies { + coreLibraryDesugaring(libs.android.desugar) + } + } +} + +private fun CommonExtension.defaultConfig(block: DefaultConfig.() -> Unit) { + defaultConfig.apply(block) +} + +private fun CommonExtension.compileOptions(block: CompileOptions.() -> Unit) { + compileOptions.apply(block) +} diff --git a/gradle/build-logic/src/main/kotlin/PluginAndroidLibrary.kt b/gradle/build-logic/src/main/kotlin/PluginAndroidLibrary.kt new file mode 100644 index 0000000000..044301f4e6 --- /dev/null +++ b/gradle/build-logic/src/main/kotlin/PluginAndroidLibrary.kt @@ -0,0 +1,16 @@ +import mihon.gradle.extensions.alias +import mihon.gradle.extensions.libs +import mihon.gradle.extensions.mihonx +import mihon.gradle.extensions.plugins +import org.gradle.api.Plugin +import org.gradle.api.Project + +@Suppress("UNUSED") +class PluginAndroidLibrary : Plugin { + override fun apply(target: Project): Unit = with(target) { + plugins { + alias(libs.plugins.android.library) + alias(mihonx.plugins.android.base) + } + } +} diff --git a/gradle/build-logic/src/main/kotlin/PluginAndroidTest.kt b/gradle/build-logic/src/main/kotlin/PluginAndroidTest.kt new file mode 100644 index 0000000000..91c2027fc1 --- /dev/null +++ b/gradle/build-logic/src/main/kotlin/PluginAndroidTest.kt @@ -0,0 +1,16 @@ +import mihon.gradle.extensions.alias +import mihon.gradle.extensions.libs +import mihon.gradle.extensions.mihonx +import mihon.gradle.extensions.plugins +import org.gradle.api.Plugin +import org.gradle.api.Project + +@Suppress("UNUSED") +class PluginAndroidTest : Plugin { + override fun apply(target: Project): Unit = with(target) { + plugins { + alias(libs.plugins.android.test) + alias(mihonx.plugins.android.base) + } + } +} diff --git a/gradle/build-logic/src/main/kotlin/PluginComposeAndroid.kt b/gradle/build-logic/src/main/kotlin/PluginComposeAndroid.kt new file mode 100644 index 0000000000..8f961e06f3 --- /dev/null +++ b/gradle/build-logic/src/main/kotlin/PluginComposeAndroid.kt @@ -0,0 +1,39 @@ +import com.android.build.api.dsl.BuildFeatures +import com.android.build.api.dsl.CommonExtension +import mihon.gradle.extensions.alias +import mihon.gradle.extensions.android +import mihon.gradle.extensions.api +import mihon.gradle.extensions.debugApi +import mihon.gradle.extensions.implementation +import mihon.gradle.extensions.libs +import mihon.gradle.extensions.plugins +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.kotlin.dsl.dependencies + +@Suppress("UNUSED") +class PluginComposeAndroid : Plugin { + override fun apply(target: Project): Unit = with(target) { + plugins { + alias(libs.plugins.kotlin.compose.compiler) + } + + android { + buildFeatures { + compose = true + } + } + + dependencies { + implementation(platform(libs.androidx.compose.bom)) + + // Compose @Preview tooling + api(libs.androidx.compose.uiToolingPreview) + debugApi(libs.androidx.compose.uiTooling) + } + } +} + +private fun CommonExtension.buildFeatures(block: BuildFeatures.() -> Unit) { + buildFeatures.apply(block) +} diff --git a/gradle/build-logic/src/main/kotlin/PluginKotlinMultiplatform.kt b/gradle/build-logic/src/main/kotlin/PluginKotlinMultiplatform.kt new file mode 100644 index 0000000000..5839156449 --- /dev/null +++ b/gradle/build-logic/src/main/kotlin/PluginKotlinMultiplatform.kt @@ -0,0 +1,52 @@ +import com.android.build.api.dsl.KotlinMultiplatformAndroidLibraryTarget +import mihon.gradle.configurations.configureKotlin +import mihon.gradle.extensions.alias +import mihon.gradle.extensions.configureTest +import mihon.gradle.extensions.coreLibraryDesugaring +import mihon.gradle.extensions.libs +import mihon.gradle.extensions.mihonx +import mihon.gradle.extensions.plugins +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.kotlin.dsl.configure +import org.gradle.kotlin.dsl.dependencies +import org.gradle.kotlin.dsl.withType +import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi +import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension +import kotlin.text.toInt + +@Suppress("UNUSED") +class PluginKotlinMultiplatform : Plugin { + override fun apply(target: Project): Unit = with(target) { + plugins { + alias(libs.plugins.android.kmp.library) + alias(libs.plugins.kotlin.multiplatform) + } + + configureKotlin() + configureTest() + + kotlin { + @OptIn(ExperimentalKotlinGradlePluginApi::class) + applyDefaultHierarchyTemplate() + + android { + minSdk = mihonx.versions.android.sdk.min.get().toInt() + compileSdk = mihonx.versions.android.sdk.compile.get().toInt() + enableCoreLibraryDesugaring = true + } + } + + dependencies { + coreLibraryDesugaring(libs.android.desugar) + } + } +} + +private fun Project.kotlin(block: KotlinMultiplatformExtension.() -> Unit) { + extensions.configure(block) +} + +private fun KotlinMultiplatformExtension.android(block: KotlinMultiplatformAndroidLibraryTarget.() -> Unit) { + targets.withType().configureEach(block) +} diff --git a/gradle/build-logic/src/main/kotlin/PluginSpotless.kt b/gradle/build-logic/src/main/kotlin/PluginSpotless.kt new file mode 100644 index 0000000000..6584c9f86d --- /dev/null +++ b/gradle/build-logic/src/main/kotlin/PluginSpotless.kt @@ -0,0 +1,44 @@ +import com.diffplug.gradle.spotless.SpotlessExtension +import mihon.gradle.extensions.alias +import mihon.gradle.extensions.libs +import mihon.gradle.extensions.plugins +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.kotlin.dsl.configure + +@Suppress("UNUSED") +class PluginSpotless : Plugin { + override fun apply(target: Project): Unit = with(target) { + plugins { + alias(libs.plugins.spotless) + } + + // Configuration should be synced with [/gradle/build-logic/build.gradle.kts] + val ktlintVersion = libs.ktlint.bom.get().version + spotless { + kotlin { + target("src/**/*.kt") + ktlint(ktlintVersion) + trimTrailingWhitespace() + endWithNewline() + } + + kotlinGradle { + target("*.kts") + ktlint(ktlintVersion) + trimTrailingWhitespace() + endWithNewline() + } + + format("xml") { + target("src/**/*.xml") + trimTrailingWhitespace() + endWithNewline() + } + } + } +} + +private fun Project.spotless(block: SpotlessExtension.() -> Unit) { + extensions.configure(block) +} diff --git a/buildSrc/src/main/kotlin/mihon/buildlogic/BuildConfig.kt b/gradle/build-logic/src/main/kotlin/mihon/gradle/BuildConfig.kt similarity index 95% rename from buildSrc/src/main/kotlin/mihon/buildlogic/BuildConfig.kt rename to gradle/build-logic/src/main/kotlin/mihon/gradle/BuildConfig.kt index c838003bf2..e150dfe2de 100644 --- a/buildSrc/src/main/kotlin/mihon/buildlogic/BuildConfig.kt +++ b/gradle/build-logic/src/main/kotlin/mihon/gradle/BuildConfig.kt @@ -1,4 +1,4 @@ -package mihon.buildlogic +package mihon.gradle import org.gradle.api.Project diff --git a/buildSrc/src/main/kotlin/mihon/buildlogic/Commands.kt b/gradle/build-logic/src/main/kotlin/mihon/gradle/Commands.kt similarity index 64% rename from buildSrc/src/main/kotlin/mihon/buildlogic/Commands.kt rename to gradle/build-logic/src/main/kotlin/mihon/gradle/Commands.kt index f3470f957e..c56a3e2693 100644 --- a/buildSrc/src/main/kotlin/mihon/buildlogic/Commands.kt +++ b/gradle/build-logic/src/main/kotlin/mihon/gradle/Commands.kt @@ -1,4 +1,4 @@ -package mihon.buildlogic +package mihon.gradle import org.gradle.api.Project import java.time.Instant @@ -8,33 +8,33 @@ import java.time.format.DateTimeFormatter // Git is needed in your system PATH for these commands to work. // If it's not installed, you can return a random value as a workaround -fun Project.getCommitCount(): String { - return runCommand("git rev-list --count HEAD") +fun Project.getLatestCommitCount(): String { + return exec("git rev-list --count HEAD") // return "1" } -fun Project.getGitSha(): String { - return runCommand("git rev-parse --short HEAD") +fun Project.getLatestCommitSha(): String { + return exec("git rev-parse --short HEAD") // return "1" } private val BUILD_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'") /** - * @param useLastCommitTime If `true`, the build time is based on the timestamp of the last Git commit; + * @param useLatestCommitTime If `true`, the build time is based on the timestamp of the last Git commit; * otherwise, the current time is used. Both are in UTC. * @return A formatted string representing the build time. The format used is defined by [BUILD_TIME_FORMATTER]. */ -fun Project.getBuildTime(useLastCommitTime: Boolean): String { - return if (useLastCommitTime) { - val epoch = runCommand("git log -1 --format=%ct").toLong() +fun Project.getBuildTime(useLatestCommitTime: Boolean): String { + return if (useLatestCommitTime) { + val epoch = exec("git log -1 --format=%ct").toLong() Instant.ofEpochSecond(epoch).atOffset(ZoneOffset.UTC).format(BUILD_TIME_FORMATTER) } else { LocalDateTime.now(ZoneOffset.UTC).format(BUILD_TIME_FORMATTER) } } -private fun Project.runCommand(command: String): String { +fun Project.exec(command: String): String { return providers.exec { commandLine = command.split(" ") } diff --git a/gradle/build-logic/src/main/kotlin/mihon/gradle/configurations/Kotlin.kt b/gradle/build-logic/src/main/kotlin/mihon/gradle/configurations/Kotlin.kt new file mode 100644 index 0000000000..aea762db69 --- /dev/null +++ b/gradle/build-logic/src/main/kotlin/mihon/gradle/configurations/Kotlin.kt @@ -0,0 +1,27 @@ +package mihon.gradle.configurations + +import mihon.gradle.extensions.mihonx +import org.gradle.api.Project +import org.gradle.kotlin.dsl.configure +import org.jetbrains.kotlin.gradle.dsl.HasConfigurableKotlinCompilerOptions +import org.jetbrains.kotlin.gradle.dsl.KotlinBaseExtension +import org.jetbrains.kotlin.gradle.dsl.KotlinCommonCompilerOptions +import tapmoc.configureJavaCompatibility + +fun Project.configureKotlin() { + configureJavaCompatibility(mihonx.versions.java.get().toInt()) + + kotlin { + compilerOptions { + freeCompilerArgs.add("-Xcontext-parameters") + } + } +} + +private fun Project.kotlin(block: KotlinBaseExtension.() -> Unit) { + extensions.configure(block) +} + +private fun KotlinBaseExtension.compilerOptions(block: KotlinCommonCompilerOptions.() -> Unit) { + if (this is HasConfigurableKotlinCompilerOptions<*>) compilerOptions(block) +} diff --git a/gradle/build-logic/src/main/kotlin/mihon/gradle/extensions/DependencyHandlerScope.kt b/gradle/build-logic/src/main/kotlin/mihon/gradle/extensions/DependencyHandlerScope.kt new file mode 100644 index 0000000000..9627b2145a --- /dev/null +++ b/gradle/build-logic/src/main/kotlin/mihon/gradle/extensions/DependencyHandlerScope.kt @@ -0,0 +1,32 @@ +package mihon.gradle.extensions + +import org.gradle.api.Project +import org.gradle.api.artifacts.ExternalModuleDependencyBundle +import org.gradle.api.artifacts.MinimalExternalModuleDependency +import org.gradle.api.provider.Provider +import org.gradle.kotlin.dsl.DependencyHandlerScope + +fun DependencyHandlerScope.api(dependencyNotation: Provider) { + add("api", dependencyNotation) +} + +fun DependencyHandlerScope.coreLibraryDesugaring(dependencyNotation: Provider) { + add("coreLibraryDesugaring", dependencyNotation) +} + +fun DependencyHandlerScope.debugApi(dependencyNotation: Provider) { + add("debugApi", dependencyNotation) +} + +@JvmName("implementationBundle") +fun DependencyHandlerScope.implementation(dependencyNotation: Provider) { + add("implementation", dependencyNotation) +} + +fun DependencyHandlerScope.implementation(dependencyNotation: Provider) { + add("implementation", dependencyNotation) +} + +fun DependencyHandlerScope.implementation(dependencyNotation: Project) { + add("implementation", dependencyNotation) +} diff --git a/gradle/build-logic/src/main/kotlin/mihon/gradle/extensions/PluginManager.kt b/gradle/build-logic/src/main/kotlin/mihon/gradle/extensions/PluginManager.kt new file mode 100644 index 0000000000..5ffc17134d --- /dev/null +++ b/gradle/build-logic/src/main/kotlin/mihon/gradle/extensions/PluginManager.kt @@ -0,0 +1,9 @@ +package mihon.gradle.extensions + +import org.gradle.api.plugins.PluginManager +import org.gradle.api.provider.Provider +import org.gradle.plugin.use.PluginDependency + +fun PluginManager.alias(notation: Provider) { + apply(notation.get().pluginId) +} diff --git a/gradle/build-logic/src/main/kotlin/mihon/gradle/extensions/Project.kt b/gradle/build-logic/src/main/kotlin/mihon/gradle/extensions/Project.kt new file mode 100644 index 0000000000..86cb5ebd92 --- /dev/null +++ b/gradle/build-logic/src/main/kotlin/mihon/gradle/extensions/Project.kt @@ -0,0 +1,37 @@ +package mihon.gradle.extensions + +import com.android.build.api.dsl.CommonExtension +import org.gradle.accessors.dm.LibrariesForAniyomilibs +import org.gradle.accessors.dm.LibrariesForLibs +import org.gradle.accessors.dm.LibrariesForMihonx +import org.gradle.api.Project +import org.gradle.api.plugins.PluginManager +import org.gradle.api.tasks.testing.Test +import org.gradle.api.tasks.testing.logging.TestLogEvent +import org.gradle.kotlin.dsl.configure +import org.gradle.kotlin.dsl.the +import org.gradle.kotlin.dsl.withType + +internal val Project.libs get() = the() +internal val Project.mihonx get() = the() + +// AM --> +internal val Project.aniyomilibs get() = the() +// <-- AM + +internal fun Project.plugins(block: PluginManager.() -> Unit) { + pluginManager.apply(block) +} + +internal fun Project.android(block: CommonExtension.() -> Unit) { + extensions.configure(block) +} + +fun Project.configureTest() { + tasks.withType { + useJUnitPlatform() + testLogging { + events(TestLogEvent.PASSED, TestLogEvent.SKIPPED, TestLogEvent.FAILED) + } + } +} diff --git a/gradle/build-logic/src/main/kotlin/mihon/gradle/tasks/GenerateLocalesConfigTask.kt b/gradle/build-logic/src/main/kotlin/mihon/gradle/tasks/GenerateLocalesConfigTask.kt new file mode 100644 index 0000000000..736cb7f91c --- /dev/null +++ b/gradle/build-logic/src/main/kotlin/mihon/gradle/tasks/GenerateLocalesConfigTask.kt @@ -0,0 +1,51 @@ +package mihon.gradle.tasks + +import org.gradle.api.DefaultTask +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.model.ObjectFactory +import org.gradle.api.tasks.OutputDirectory +import org.gradle.api.tasks.TaskAction +import javax.inject.Inject + +abstract class GenerateLocalesConfigTask : DefaultTask() { + + @get:Inject + abstract val objectFactory: ObjectFactory + + @get:OutputDirectory + abstract val outputDir: DirectoryProperty + + @TaskAction + fun action() { + val locales = objectFactory.fileTree() + .from("src/commonMain/moko-resources") + .matching { include("**/strings.xml") } + .asSequence() + .filterNot { it.readText().contains(emptyResourcesElement) } + .map { + it.parentFile.name + .replace("base", "en") + .replace("-r", "-") + .replace("+", "-") + } + .distinct() + .sorted() + .joinToString("\n") { "| " } + + val content = """ + | + | + $locales + | + """.trimMargin() + + outputDir.get().file("xml/locales_config.xml").asFile.apply { + parentFile.mkdirs() + writeText(content) + } + } + + companion object { + private val emptyResourcesElement = "\\s*|".toRegex() + } +} diff --git a/gradle/build-logic/src/main/kotlin/mihon/gradle/tasks/ReplaceShortcutsPlaceholderTask.kt b/gradle/build-logic/src/main/kotlin/mihon/gradle/tasks/ReplaceShortcutsPlaceholderTask.kt new file mode 100644 index 0000000000..1cde0423c6 --- /dev/null +++ b/gradle/build-logic/src/main/kotlin/mihon/gradle/tasks/ReplaceShortcutsPlaceholderTask.kt @@ -0,0 +1,34 @@ +package mihon.gradle.tasks + +import org.gradle.api.DefaultTask +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.file.RegularFileProperty +import org.gradle.api.provider.Property +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.InputFile +import org.gradle.api.tasks.OutputDirectory +import org.gradle.api.tasks.TaskAction + +abstract class ReplaceShortcutsPlaceholderTask : DefaultTask() { + + @get:Input + abstract val applicationId: Property + + @get:InputFile + abstract val shortcutsFile: RegularFileProperty + + @get:OutputDirectory + abstract val outputDir: DirectoryProperty + + @TaskAction + fun action() { + val content = shortcutsFile.asFile.get() + .readText() + .replace($$"${applicationId}", applicationId.get()) + + outputDir.get().file("xml/shortcuts.xml").asFile.apply { + parentFile.mkdirs() + writeText(content) + } + } +} diff --git a/gradle/compose.versions.toml b/gradle/compose.versions.toml deleted file mode 100644 index 03f7285aa9..0000000000 --- a/gradle/compose.versions.toml +++ /dev/null @@ -1,19 +0,0 @@ -[versions] -compose-bom = "2026.03.00" - -[libraries] -activity = "androidx.activity:activity-compose:1.13.0" -bom = { group = "androidx.compose", name = "compose-bom", version.ref = "compose-bom" } -foundation = { module = "androidx.compose.foundation:foundation" } -animation = { module = "androidx.compose.animation:animation" } -animation-graphics = { module = "androidx.compose.animation:animation-graphics" } -runtime = { module = "androidx.compose.runtime:runtime" } -runtime-annotation = { module = "androidx.compose.runtime:runtime-annotation" } -ui-tooling = { module = "androidx.compose.ui:ui-tooling" } -ui-tooling-preview = { module = "androidx.compose.ui:ui-tooling-preview" } -ui-util = { module = "androidx.compose.ui:ui-util" } - -material3-core = { module = "androidx.compose.material3:material3" } -material-icons = { module = "androidx.compose.material:material-icons-extended" } - -glance = "androidx.glance:glance-appwidget:1.1.1" diff --git a/gradle/kotlinx.versions.toml b/gradle/kotlinx.versions.toml deleted file mode 100644 index 83ea539e84..0000000000 --- a/gradle/kotlinx.versions.toml +++ /dev/null @@ -1,33 +0,0 @@ -[versions] -kotlin_version = "2.3.20" -serialization_version = "1.10.0" -xml_serialization_version = "0.91.3" - -[libraries] -reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin_version" } -gradle = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin_version" } -compose-compiler-gradle = { module = "org.jetbrains.kotlin:compose-compiler-gradle-plugin", version.ref = "kotlin_version" } - -immutables = { module = "org.jetbrains.kotlinx:kotlinx-collections-immutable", version = "0.4.0" } - -coroutines-bom = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-bom", version = "1.10.2" } -coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core" } -coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android" } -coroutines-guava = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-guava" } -coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test" } - -serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "serialization_version" } -serialization-json-okio = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json-okio", version.ref = "serialization_version" } -serialization-protobuf = { module = "org.jetbrains.kotlinx:kotlinx-serialization-protobuf", version.ref = "serialization_version" } - -serialization-xml-core = { module = "io.github.pdvrieze.xmlutil:core-android", version.ref = "xml_serialization_version" } -serialization-xml = { module = "io.github.pdvrieze.xmlutil:serialization", version.ref = "xml_serialization_version" } - -[bundles] -coroutines = ["coroutines-core", "coroutines-android", "coroutines-guava"] -serialization = ["serialization-json", "serialization-json-okio", "serialization-protobuf", "serialization-xml-core", "serialization-xml"] - -[plugins] -android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin_version" } -compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin_version" } -serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin_version" } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c85d8d87b5..0d7089631d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,122 +1,214 @@ [versions] -aboutlib_version = "13.2.1" -leakcanary = "2.14" -moko = "0.26.1" -okhttp_version = "5.3.2" -shizuku_version = "13.1.5" -sqldelight = "2.3.2" -voyager = "1.1.0-beta03" -spotless = "8.4.0" -ktlint-core = "1.8.0" -firebase-bom = "34.11.0" +aboutLibraries = "14.2.1" +android-desugar = "2.1.5" +android-gradle = "9.2.1" +androidx-activity-compose = "1.13.0" +androidx-annotation = "1.10.0" +androidx-appCompat = "1.7.1" +androidx-benchmark = "1.4.1" +androidx-biometric = "1.2.0-alpha05" +androidx-compose-bom = "2026.05.01" +androidx-constraintLayout = "2.2.1" +androidx-core = "1.18.0" +androidx-coreSplashScreen = "1.2.0" +androidx-glance = "1.1.1" +androidx-interpolator = "1.0.0" +androidx-lifecycle = "2.10.0" +androidx-paging = "3.4.2" +androidx-preference = "1.2.1" +androidx-profileInstaller = "1.4.1" +androidx-recyclerView = "1.4.0" +androidx-sqlite = "2.6.2" +androidx-test-espresso = "3.7.0" +androidx-test-junit = "1.3.0" +androidx-test-uiautomator = "2.3.0" +androidx-viewPager = "1.1.0" +androidx-work = "2.11.2" +archive = "1.1.6" +coil = "3.4.0" +composeGrid = "1.2.2" +composeMaterialMotion = "2.0.1" +composeRichEditor = "1.0.0-rc14" +composeWebview = "0.33.6" +conscrypt = "2.5.3" +directionalViewPager = "1.0.0" +diskLruCache = "2.0.2" +firebase-bom = "34.13.0" +firebase-crashlytics = "3.0.7" +flexibleAdapter = "c8013533" +google-services = "4.4.4" +image-decoder = "e03b81e18a" +injekt = "91edab2317" +jsoup = "1.22.2" +junit = "6.1.0" +kotest-assertions = "6.1.11" +kotlin-gradle = "2.3.21" +kotlinx-collections-immutable = "0.4.0" +kotlinx-coroutines = "1.11.0" +kotlinx-serialization = "1.11.0" +ktlint = "1.8.0" +leakCanary = "2.14" +logcat = "0.4" markdown = "0.39.2" -junit = "6.0.3" +material = "1.12.0" materialKolor = "5.0.0-alpha07" +mockk = "1.14.9" +moko-resources = "0.26.4" +okhttp = "5.3.2" +okio = "3.17.0" +photoView = "2.3.0" +quickJs = "547f5b1597" +reorderable = "3.1.0" +rxJava = "1.3.8" +shizuku = "13.1.5" +spotless = "8.5.1" +sqldelight = "2.3.2" +sqldelight-androidx-driver = "0.2.0" +stringSimilarity = "0.1.0" +subsamplingScaleImageView = "66e0db195d" +swipe = "1.3.0" +tapmoc = "0.4.2" +unifile = "e0def6b3dc" +voyager = "1.1.0-beta03" +xmlutil = "0.91.3" [libraries] -desugar = "com.android.tools:desugar_jdk_libs:2.1.5" -android-shortcut-gradle = "com.github.zellius:android-shortcut-gradle-plugin:0.1.2" - -rxjava = "io.reactivex:rxjava:1.3.8" - -okhttp-core = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp_version" } -okhttp-logging = { module = "com.squareup.okhttp3:logging-interceptor", version.ref = "okhttp_version" } -okhttp-brotli = { module = "com.squareup.okhttp3:okhttp-brotli", version.ref = "okhttp_version" } -okhttp-dnsoverhttps = { module = "com.squareup.okhttp3:okhttp-dnsoverhttps", version.ref = "okhttp_version" } -okio = "com.squareup.okio:okio:3.17.0" - -conscrypt-android = "org.conscrypt:conscrypt-android:2.5.3" - -quickjs-android = { group = "com.github.zhanghai.quickjs-java", name = "quickjs-android", version = "547f5b1597" } - -jsoup = "org.jsoup:jsoup:1.22.1" - -disklrucache = "com.jakewharton:disklrucache:2.0.2" -unifile = "com.github.tachiyomiorg:unifile:e0def6b3dc" -libarchive = "me.zhanghai.android.libarchive:library:1.1.6" - -preferencektx = "androidx.preference:preference-ktx:1.2.1" - -injekt = "com.github.mihonapp:injekt:91edab2317" - -coil-bom = { module = "io.coil-kt.coil3:coil-bom", version = "3.4.0" } -coil-core = { module = "io.coil-kt.coil3:coil" } -coil-gif = { module = "io.coil-kt.coil3:coil-gif" } -coil-compose = { module = "io.coil-kt.coil3:coil-compose" } -coil-network-okhttp = { module = "io.coil-kt.coil3:coil-network-okhttp" } - -subsamplingscaleimageview = "com.github.tachiyomiorg:subsampling-scale-image-view:66e0db195d" -image-decoder = "com.github.tachiyomiorg:image-decoder:41c059e540" - -natural-comparator = "com.github.gpanther:java-nat-sort:natural-comparator-1.1" - -richeditor-compose = "com.mohamedrejeb.richeditor:richeditor-compose:1.0.0-rc13" - -material = "com.google.android.material:material:1.12.0" -flexible-adapter-core = "com.github.arkon.FlexibleAdapter:flexible-adapter:c8013533" -photoview = "com.github.chrisbanes:PhotoView:2.3.0" -directionalviewpager = "com.github.tachiyomiorg:DirectionalViewPager:1.0.0" -compose-materialmotion = "io.github.fornewid:material-motion-compose-core:2.0.1" -compose-webview = "io.github.kevinnzou:compose-webview:0.33.6" -compose-grid = "io.woong.compose.grid:grid:1.2.2" -reorderable = { module = "sh.calvin.reorderable:reorderable", version = "3.0.0" } - -swipe = "me.saket.swipe:swipe:1.3.0" - -moko-core = { module = "dev.icerock.moko:resources", version.ref = "moko" } - -logcat = "com.squareup.logcat:logcat:0.4" - -firebase-bom = { module = "com.google.firebase:firebase-bom", version.ref = "firebase-bom" } +aboutLibraries-compose = { module = "com.mikepenz:aboutlibraries-compose-m3", version.ref = "aboutLibraries" } +android-desugar = { module = "com.android.tools:desugar_jdk_libs", version.ref = "android-desugar" } +android-gradle = { module = "com.android.tools.build:gradle", version.ref = "android-gradle" } +androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "androidx-activity-compose" } +androidx-annotation = { module = "androidx.annotation:annotation", version.ref = "androidx-annotation" } +androidx-appCompat = { module = "androidx.appcompat:appcompat", version.ref = "androidx-appCompat" } +androidx-benchmark-macroJunit4 = { module = "androidx.benchmark:benchmark-macro-junit4", version.ref = "androidx-benchmark" } +androidx-biometric = { module = "androidx.biometric:biometric-ktx", version.ref = "androidx-biometric" } +androidx-compose-animation = { module = "androidx.compose.animation:animation" } +androidx-compose-animationGraphics = { module = "androidx.compose.animation:animation-graphics" } +androidx-compose-bom = { module = "androidx.compose:compose-bom-alpha", version.ref = "androidx-compose-bom" } +androidx-compose-foundation = { module = "androidx.compose.foundation:foundation" } +androidx-compose-material3 = { module = "androidx.compose.material3:material3" } +androidx-compose-materialIcons = { module = "androidx.compose.material:material-icons-extended" } +androidx-compose-runtime = { module = "androidx.compose.runtime:runtime" } +androidx-compose-runtimeAnnotation = { module = "androidx.compose.runtime:runtime-annotation" } +androidx-compose-uiTooling = { module = "androidx.compose.ui:ui-tooling" } +androidx-compose-uiToolingPreview = { module = "androidx.compose.ui:ui-tooling-preview" } +androidx-compose-uiUtil = { module = "androidx.compose.ui:ui-util" } +androidx-constraintLayout = { module = "androidx.constraintlayout:constraintlayout", version.ref = "androidx-constraintLayout" } +androidx-core = { module = "androidx.core:core-ktx", version.ref = "androidx-core" } +androidx-coreSplashScreen = { module = "androidx.core:core-splashscreen", version.ref = "androidx-coreSplashScreen" } +androidx-glance-appWidget = { module = "androidx.glance:glance-appwidget", version.ref = "androidx-glance" } +androidx-interpolator = { module = "androidx.interpolator:interpolator", version.ref = "androidx-interpolator" } +androidx-lifecycle-common = { module = "androidx.lifecycle:lifecycle-common", version.ref = "androidx-lifecycle" } +androidx-lifecycle-process = { module = "androidx.lifecycle:lifecycle-process", version.ref = "androidx-lifecycle" } +androidx-lifecycle-runtime = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "androidx-lifecycle" } +androidx-paging-compose = { module = "androidx.paging:paging-compose", version.ref = "androidx-paging" } +androidx-paging-runtime = { module = "androidx.paging:paging-runtime", version.ref = "androidx-paging" } +androidx-preference = { module = "androidx.preference:preference-ktx", version.ref = "androidx-preference" } +androidx-profileInstaller = { module = "androidx.profileinstaller:profileinstaller", version.ref = "androidx-profileInstaller" } +androidx-recyclerView = { module = "androidx.recyclerview:recyclerview", version.ref = "androidx-recyclerView" } +androidx-sqlite-bundled = { module = "androidx.sqlite:sqlite-bundled", version.ref = "androidx-sqlite" } +androidx-test-espresso-core = { module = "androidx.test.espresso:espresso-core", version.ref = "androidx-test-espresso" } +androidx-test-junit = { module = "androidx.test.ext:junit-ktx", version.ref = "androidx-test-junit" } +androidx-test-uiautomator = { module = "androidx.test.uiautomator:uiautomator", version.ref = "androidx-test-uiautomator" } +androidx-viewPager = { module = "androidx.viewpager:viewpager", version.ref = "androidx-viewPager" } +androidx-work = { module = "androidx.work:work-runtime", version.ref = "androidx-work" } +archive = { module = "me.zhanghai.android.libarchive:library", version.ref = "archive" } +coil-compose = { module = "io.coil-kt.coil3:coil-compose", version.ref = "coil" } +coil-core = { module = "io.coil-kt.coil3:coil", version.ref = "coil" } +coil-gif = { module = "io.coil-kt.coil3:coil-gif", version.ref = "coil" } +coil-network-okhttp = { module = "io.coil-kt.coil3:coil-network-okhttp", version.ref = "coil" } +composeGrid = { module = "io.woong.compose.grid:grid", version.ref = "composeGrid" } +composeMaterialMotion = { module = "io.github.fornewid:material-motion-compose-core", version.ref = "composeMaterialMotion" } +composeRichEditor = { module = "com.mohamedrejeb.richeditor:richeditor-compose", version.ref = "composeRichEditor" } +composeWebview = { module = "io.github.kevinnzou:compose-webview", version.ref = "composeWebview" } +conscrypt = { module = "org.conscrypt:conscrypt-android", version.ref = "conscrypt" } +directionalViewPager = { module = "com.github.tachiyomiorg:DirectionalViewPager", version.ref = "directionalViewPager" } +diskLruCache = { module = "com.jakewharton:disklrucache", version.ref = "diskLruCache" } firebase-analytics = { module = "com.google.firebase:firebase-analytics" } +firebase-bom = { module = "com.google.firebase:firebase-bom", version.ref = "firebase-bom" } firebase-crashlytics = { module = "com.google.firebase:firebase-crashlytics" } - -aboutLibraries-compose = { module = "com.mikepenz:aboutlibraries-compose-m3", version.ref = "aboutlib_version" } - -shizuku-api = { module = "dev.rikka.shizuku:api", version.ref = "shizuku_version" } -shizuku-provider = { module = "dev.rikka.shizuku:provider", version.ref = "shizuku_version" } - -leakcanary-android = { module = "com.squareup.leakcanary:leakcanary-android", version.ref = "leakcanary" } -leakcanary-plumber = { module = "com.squareup.leakcanary:plumber-android", version.ref = "leakcanary" } - -sqldelight-androidx-driver = { module = "com.eygraber:sqldelight-androidx-driver", version = "0.0.17" } -sqldelight-coroutines = { module = "app.cash.sqldelight:coroutines-extensions-jvm", version.ref = "sqldelight" } -sqldelight-android-paging = { module = "app.cash.sqldelight:androidx-paging3-extensions", version.ref = "sqldelight" } -sqldelight-dialects-sql = { module = "app.cash.sqldelight:sqlite-3-38-dialect", version.ref = "sqldelight" } - +flexibleAdapter = { module = "com.github.arkon.FlexibleAdapter:flexible-adapter", version.ref = "flexibleAdapter" } +image-decoder = { module = "com.github.mihonapp:image-decoder", version.ref = "image-decoder" } +injekt = { module = "com.github.mihonapp:injekt", version.ref = "injekt" } +jsoup = { module = "org.jsoup:jsoup", version.ref = "jsoup" } junit-jupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junit" } junit-platform-launcher = { module = "org.junit.platform:junit-platform-launcher" } -kotest-assertions = "io.kotest:kotest-assertions-core:6.1.7" -mockk = "io.mockk:mockk:1.14.9" - -voyager-navigator = { module = "cafe.adriel.voyager:voyager-navigator", version.ref = "voyager" } -voyager-screenmodel = { module = "cafe.adriel.voyager:voyager-screenmodel", 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" } - -spotless-gradle = { group = "com.diffplug.spotless", name = "spotless-plugin-gradle", version.ref = "spotless" } -ktlint-core = { module = "com.pinterest.ktlint:ktlint-cli", version.ref = "ktlint-core" } - -markdown-core = { module = "com.mikepenz:multiplatform-markdown-renderer", version.ref = "markdown" } +kotest-assertions = { module = "io.kotest:kotest-assertions-core", version.ref = "kotest-assertions" } +kotlin-compose-compiler-gradle = { module = "org.jetbrains.kotlin:compose-compiler-gradle-plugin", version.ref = "kotlin-gradle" } +kotlin-gradle = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin-gradle" } +kotlin-reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin-gradle" } +kotlinx-collections-immutable = { module = "org.jetbrains.kotlinx:kotlinx-collections-immutable", version.ref = "kotlinx-collections-immutable" } +kotlinx-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "kotlinx-coroutines" } +kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" } +kotlinx-coroutines-guava = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-guava", version.ref = "kotlinx-coroutines" } +kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlinx-coroutines" } +kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinx-serialization" } +kotlinx-serialization-jsonOkio = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json-okio", version.ref = "kotlinx-serialization" } +kotlinx-serialization-protobuf = { module = "org.jetbrains.kotlinx:kotlinx-serialization-protobuf", version.ref = "kotlinx-serialization" } +ktlint-bom = { module = "com.pinterest.ktlint:ktlint-bom", version.ref = "ktlint" } +leakCanary-core = { module = "com.squareup.leakcanary:leakcanary-android", version.ref = "leakCanary" } +leakCanary-plumber = { module = "com.squareup.leakcanary:plumber-android", version.ref = "leakCanary" } +logcat = { module = "com.squareup.logcat:logcat", version.ref = "logcat" } markdown-coil = { module = "com.mikepenz:multiplatform-markdown-renderer-coil3", version.ref = "markdown" } - -stringSimilarity = { module = "com.aallam.similarity:string-similarity-kotlin", version = "0.1.0" } - +markdown-core = { module = "com.mikepenz:multiplatform-markdown-renderer", version.ref = "markdown" } +material = { module = "com.google.android.material:material", version.ref = "material" } materialKolor = { module = "com.materialkolor:material-kolor", version.ref = "materialKolor" } +mockk = { module = "io.mockk:mockk", version.ref = "mockk" } +moko-resources = { module = "dev.icerock.moko:resources", version.ref = "moko-resources" } +natural-comparator = { module = "com.github.gpanther:java-nat-sort", version = "natural-comparator-1.1" } +okhttp-brotli = { module = "com.squareup.okhttp3:okhttp-brotli", version.ref = "okhttp" } +okhttp-core = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" } +okhttp-dnsOverHttps = { module = "com.squareup.okhttp3:okhttp-dnsoverhttps", version.ref = "okhttp" } +okhttp-logging = { module = "com.squareup.okhttp3:logging-interceptor", version.ref = "okhttp" } +okio = { module = "com.squareup.okio:okio", version.ref = "okio" } +photoView = { module = "com.github.chrisbanes:PhotoView", version.ref = "photoView" } +quickJs = { module = "com.github.zhanghai.quickjs-java:quickjs-android", version.ref = "quickJs" } +reorderable = { module = "sh.calvin.reorderable:reorderable", version.ref = "reorderable" } +rxJava = { module = "io.reactivex:rxjava", version.ref = "rxJava" } +shizuku-api = { module = "dev.rikka.shizuku:api", version.ref = "shizuku" } +shizuku-provider = { module = "dev.rikka.shizuku:provider", version.ref = "shizuku" } +spotless-gradle = { module = "com.diffplug.spotless:spotless-plugin-gradle", version.ref = "spotless" } +sqldelight-androidxDriver = { module = "com.eygraber:sqldelight-androidx-driver", version.ref = "sqldelight-androidx-driver" } +sqldelight-androidxPaging = { module = "app.cash.sqldelight:androidx-paging3-extensions", version.ref = "sqldelight" } +sqldelight-async = { module = "app.cash.sqldelight:async-extensions", version.ref = "sqldelight" } +sqldelight-coroutines = { module = "app.cash.sqldelight:coroutines-extensions", version.ref = "sqldelight" } +sqldelight-sqliteDialect338 = { module = "app.cash.sqldelight:sqlite-3-38-dialect", version.ref = "sqldelight" } +stringSimilarity = { module = "com.aallam.similarity:string-similarity-kotlin", version.ref = "stringSimilarity" } +subsamplingScaleImageView = { module = "com.github.tachiyomiorg:subsampling-scale-image-view", version.ref = "subsamplingScaleImageView" } +swipe = { module = "me.saket.swipe:swipe", version.ref = "swipe" } +tapmoc-gradle = { module = "com.gradleup.tapmoc:tapmoc-gradle-plugin", version.ref = "tapmoc" } +unifile = { module = "com.github.tachiyomiorg:unifile", version.ref = "unifile" } +voyager-navigator = { module = "cafe.adriel.voyager:voyager-navigator", version.ref = "voyager" } +voyager-screenModel = { module = "cafe.adriel.voyager:voyager-screenmodel", version.ref = "voyager" } +voyager-tabNavigator = { module = "cafe.adriel.voyager:voyager-tab-navigator", version.ref = "voyager" } +voyager-transitions = { module = "cafe.adriel.voyager:voyager-transitions", version.ref = "voyager" } +xmlutil-core = { module = "io.github.pdvrieze.xmlutil:core-android", version.ref = "xmlutil" } +xmlutil-serialization = { module = "io.github.pdvrieze.xmlutil:serialization", version.ref = "xmlutil" } [plugins] -google-services = { id = "com.google.gms.google-services", version = "4.4.4" } -aboutLibraries = { id = "com.mikepenz.aboutlibraries.plugin.android", version.ref = "aboutlib_version" } +aboutLibraries = { id = "com.mikepenz.aboutlibraries.plugin.android", version.ref = "aboutLibraries" } +android-application = { id = "com.android.application", version.ref = "android-gradle" } +android-test = { id = "com.android.test", version.ref = "android-gradle" } +android-kmp-library = { id = "com.android.kotlin.multiplatform.library", version.ref = "android-gradle" } +android-library = { id = "com.android.library", version.ref = "android-gradle" } +firebase-crashlytics = { id = "com.google.firebase.crashlytics", version.ref = "firebase-crashlytics" } +google-services = { id = "com.google.gms.google-services", version.ref = "google-services" } +kotlin-compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin-gradle" } +kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin-gradle" } +kotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin-gradle" } +kotlin-samWithReceiver = { id = "org.jetbrains.kotlin.plugin.sam.with.receiver", version.ref = "kotlin-gradle" } +kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin-gradle" } +moko-resources = { id = "dev.icerock.mobile.multiplatform-resources", version.ref = "moko-resources" } +spotless = { id = "com.diffplug.spotless", version.ref = "spotless" } sqldelight = { id = "app.cash.sqldelight", version.ref = "sqldelight" } -moko = { id = "dev.icerock.mobile.multiplatform-resources", version.ref = "moko" } -firebase-crashlytics = { id = "com.google.firebase.crashlytics", version = "3.0.6" } [bundles] -okhttp = ["okhttp-core", "okhttp-logging", "okhttp-brotli", "okhttp-dnsoverhttps"] -js-engine = ["quickjs-android"] +androidx-lifecycle = ["androidx-lifecycle-common", "androidx-lifecycle-process", "androidx-lifecycle-runtime"] coil = ["coil-core", "coil-gif", "coil-compose", "coil-network-okhttp"] +kotlinx-coroutines = ["kotlinx-coroutines-core", "kotlinx-coroutines-android", "kotlinx-coroutines-guava"] +markdown = ["markdown-core", "markdown-coil"] +okhttp = ["okhttp-core", "okhttp-logging", "okhttp-brotli", "okhttp-dnsOverHttps"] +serialization = ["kotlinx-serialization-json", "kotlinx-serialization-jsonOkio", "kotlinx-serialization-protobuf", "xmlutil-core", "xmlutil-serialization"] shizuku = ["shizuku-api", "shizuku-provider"] -sqldelight = ["sqldelight-androidx-driver", "sqldelight-coroutines", "sqldelight-android-paging"] -voyager = ["voyager-navigator", "voyager-screenmodel", "voyager-tab-navigator", "voyager-transitions"] +sqldelight = ["sqldelight-androidxDriver", "sqldelight-async", "sqldelight-coroutines", "sqldelight-androidxPaging"] test = ["junit-jupiter", "kotest-assertions", "mockk"] -markdown = ["markdown-core", "markdown-coil"] +voyager = ["voyager-navigator", "voyager-screenModel", "voyager-tabNavigator", "voyager-transitions"] diff --git a/gradle/mihon.versions.toml b/gradle/mihon.versions.toml new file mode 100644 index 0000000000..b7b4e396bd --- /dev/null +++ b/gradle/mihon.versions.toml @@ -0,0 +1,16 @@ +[versions] +# Used in [/gradle/build-config/src/main/kotlin/PluginKotlinMultiplatform.kt] +android-sdk-min = "26" +android-sdk-compile = "37" +android-sdk-target = "36" +android-ndk = "29.0.14206865" +java = "17" + +[plugins] +android-application = { id = "mihon.plugins.android.application" } +android-base = { id = "mihon.plugins.android.base" } +android-library = { id = "mihon.plugins.android.library" } +android-test = { id = "mihon.plugins.android.test" } +compose = { id = "mihon.plugins.compose.android" } +kotlin-multiplatform = { id = "mihon.plugins.kotlin.multiplatform" } +spotless = { id = "mihon.plugins.spotless" } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 1b33c55baa..b1b8ef56b4 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index aaaabb3cb9..df6a6ad763 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,9 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.4-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.1-bin.zip networkTimeout=10000 +retries=0 +retryBackOffMs=500 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 23d15a9367..b9bb139f79 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright © 2015-2021 the original authors. +# Copyright © 2015 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -57,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/3d91ce3b8caaf77ad09f381f43615b715b53f72c/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -114,7 +114,6 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH="\\\"\\\"" # Determine the Java command to use to start the JVM. @@ -172,7 +171,6 @@ fi # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) @@ -212,7 +210,6 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ "$@" diff --git a/gradlew.bat b/gradlew.bat index db3a6ac207..24c62d56f2 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -23,8 +23,8 @@ @rem @rem ########################################################################## -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal +@rem Set local scope for the variables, and ensure extensions are enabled +setlocal EnableExtensions set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @@ -51,7 +51,7 @@ echo. 1>&2 echo Please set the JAVA_HOME variable in your environment to match the 1>&2 echo location of your Java installation. 1>&2 -goto fail +"%COMSPEC%" /c exit 1 :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% @@ -65,30 +65,18 @@ echo. 1>&2 echo Please set the JAVA_HOME variable in your environment to match the 1>&2 echo location of your Java installation. 1>&2 -goto fail +"%COMSPEC%" /c exit 1 :execute @rem Setup the command line -set CLASSPATH= @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* +@rem endlocal doesn't take effect until after the line is parsed and variables are expanded +@rem which allows us to clear the local environment before executing the java command +endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +:exitWithErrorLevel +@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts +"%COMSPEC%" /c exit %ERRORLEVEL% diff --git a/i18n-animiru/build.gradle.kts b/i18n-animiru/build.gradle.kts index 298b3cb909..843000d2a3 100644 --- a/i18n-animiru/build.gradle.kts +++ b/i18n-animiru/build.gradle.kts @@ -1,24 +1,24 @@ -import mihon.buildlogic.generatedBuildDir -import mihon.buildlogic.tasks.getLocalesConfigTask +import mihon.gradle.tasks.GenerateLocalesConfigTask import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi plugins { - id("mihon.library") - kotlin("multiplatform") - alias(libs.plugins.moko) + alias(mihonx.plugins.kotlin.multiplatform) + alias(mihonx.plugins.spotless) + + alias(libs.plugins.moko.resources) } kotlin { - androidTarget() + android { + namespace = "tachiyomi.i18n.animiru" - applyDefaultHierarchyTemplate() + // TODO(antsy): Remove when https://youtrack.jetbrains.com/issue/KT-83319 is resolved + withHostTest { } + } - sourceSets { - commonMain { - dependencies { - api(libs.moko.core) - } - } + @OptIn(ExperimentalKotlinGradlePluginApi::class) + dependencies { + api(libs.moko.resources) } @OptIn(ExperimentalKotlinGradlePluginApi::class) @@ -27,21 +27,13 @@ kotlin { } } -val generatedAndroidResourceDir = generatedBuildDir.resolve("android/res") +androidComponents { + onVariants { variant -> + val resSource = variant.sources.res ?: return@onVariants -android { - namespace = "tachiyomi.i18n.animiru" - - sourceSets { - val main by getting - main.res.srcDirs( - "src/commonMain/resources", - generatedAndroidResourceDir, - ) - } - - lint { - disable.addAll(listOf("MissingTranslation", "ExtraTranslation")) + val variantName = variant.name.replaceFirstChar { it.uppercase() } + val task = tasks.register("generate${variantName}LocalesConfig") + resSource.addGeneratedSourceDirectory(task) { it.outputDir } } } @@ -49,10 +41,3 @@ multiplatformResources { resourcesClassName.set("AMMR") resourcesPackage.set("tachiyomi.i18n.animiru") } - -tasks { - val localesConfigTask = project.getLocalesConfigTask(generatedAndroidResourceDir) - preBuild { - dependsOn(localesConfigTask) - } -} diff --git a/i18n-aniyomi/build.gradle.kts b/i18n-aniyomi/build.gradle.kts index 56736f6a12..762bafe7c7 100644 --- a/i18n-aniyomi/build.gradle.kts +++ b/i18n-aniyomi/build.gradle.kts @@ -1,24 +1,24 @@ -import mihon.buildlogic.generatedBuildDir -import mihon.buildlogic.tasks.getLocalesConfigTask +import mihon.gradle.tasks.GenerateLocalesConfigTask import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi plugins { - id("mihon.library") - kotlin("multiplatform") - alias(libs.plugins.moko) + alias(mihonx.plugins.kotlin.multiplatform) + alias(mihonx.plugins.spotless) + + alias(libs.plugins.moko.resources) } kotlin { - androidTarget() + android { + namespace = "tachiyomi.i18n.aniyomi" - applyDefaultHierarchyTemplate() + // TODO(antsy): Remove when https://youtrack.jetbrains.com/issue/KT-83319 is resolved + withHostTest { } + } - sourceSets { - commonMain { - dependencies { - api(libs.moko.core) - } - } + @OptIn(ExperimentalKotlinGradlePluginApi::class) + dependencies { + api(libs.moko.resources) } @OptIn(ExperimentalKotlinGradlePluginApi::class) @@ -27,21 +27,13 @@ kotlin { } } -val generatedAndroidResourceDir = generatedBuildDir.resolve("android/res") +androidComponents { + onVariants { variant -> + val resSource = variant.sources.res ?: return@onVariants -android { - namespace = "tachiyomi.i18n.aniyomi" - - sourceSets { - val main by getting - main.res.srcDirs( - "src/commonMain/resources", - generatedAndroidResourceDir, - ) - } - - lint { - disable.addAll(listOf("MissingTranslation", "ExtraTranslation")) + val variantName = variant.name.replaceFirstChar { it.uppercase() } + val task = tasks.register("generate${variantName}LocalesConfig") + resSource.addGeneratedSourceDirectory(task) { it.outputDir } } } @@ -49,10 +41,3 @@ multiplatformResources { resourcesClassName.set("AYMR") resourcesPackage.set("tachiyomi.i18n.aniyomi") } - -tasks { - val localesConfigTask = project.getLocalesConfigTask(generatedAndroidResourceDir) - preBuild { - dependsOn(localesConfigTask) - } -} diff --git a/i18n-aniyomi/src/commonMain/moko-resources/am/strings.xml b/i18n-aniyomi/src/commonMain/moko-resources/am/strings.xml index 1febe1df6c..0e5329cae3 100644 --- a/i18n-aniyomi/src/commonMain/moko-resources/am/strings.xml +++ b/i18n-aniyomi/src/commonMain/moko-resources/am/strings.xml @@ -30,4 +30,4 @@ ነባሪ ምድብ ማውረድ ለአፍታ ቆሟል የምዕራፍ ዝመናዎች - \ No newline at end of file + diff --git a/i18n-aniyomi/src/commonMain/moko-resources/ar/plurals.xml b/i18n-aniyomi/src/commonMain/moko-resources/ar/plurals.xml index 1108b04d95..bdbc88ca9c 100644 --- a/i18n-aniyomi/src/commonMain/moko-resources/ar/plurals.xml +++ b/i18n-aniyomi/src/commonMain/moko-resources/ar/plurals.xml @@ -56,4 +56,4 @@ الحلقات %1$s و %2$d أخرى الحلقات %1$s و %2$d أخرى - \ No newline at end of file + diff --git a/i18n-aniyomi/src/commonMain/moko-resources/be/strings.xml b/i18n-aniyomi/src/commonMain/moko-resources/be/strings.xml index 18ee625206..469bcd2803 100644 --- a/i18n-aniyomi/src/commonMain/moko-resources/be/strings.xml +++ b/i18n-aniyomi/src/commonMain/moko-resources/be/strings.xml @@ -5,4 +5,4 @@ Значкі лакальных Катэгорыя па змаўчанні Манга ў выключаных катэгорыях не будзе абнаўляцца, нават калі яны таксама знаходзяцца ў уключаных катэгорыях. - \ No newline at end of file + diff --git a/i18n-aniyomi/src/commonMain/moko-resources/bg/strings.xml b/i18n-aniyomi/src/commonMain/moko-resources/bg/strings.xml index b415e10371..bcaa58dc69 100644 --- a/i18n-aniyomi/src/commonMain/moko-resources/bg/strings.xml +++ b/i18n-aniyomi/src/commonMain/moko-resources/bg/strings.xml @@ -14,4 +14,4 @@ На пауза Изтеглянето спряно Нови глави - \ No newline at end of file + diff --git a/i18n-aniyomi/src/commonMain/moko-resources/ca/plurals.xml b/i18n-aniyomi/src/commonMain/moko-resources/ca/plurals.xml index d9dc187b8a..56e9393ad4 100644 --- a/i18n-aniyomi/src/commonMain/moko-resources/ca/plurals.xml +++ b/i18n-aniyomi/src/commonMain/moko-resources/ca/plurals.xml @@ -24,4 +24,4 @@ Episodis %1$s i 1 més Episodis %1$s i %2$d més - \ No newline at end of file + diff --git a/i18n-aniyomi/src/commonMain/moko-resources/ceb/strings.xml b/i18n-aniyomi/src/commonMain/moko-resources/ceb/strings.xml index b077e8ee81..25db126cbf 100644 --- a/i18n-aniyomi/src/commonMain/moko-resources/ceb/strings.xml +++ b/i18n-aniyomi/src/commonMain/moko-resources/ceb/strings.xml @@ -7,4 +7,4 @@ Wala iapil nga mga kategorya Klaro nga database I-delete ang history para sa manga nga wala ma-save sa imong library - \ No newline at end of file + diff --git a/i18n-aniyomi/src/commonMain/moko-resources/cs/plurals.xml b/i18n-aniyomi/src/commonMain/moko-resources/cs/plurals.xml index cb27314463..7ab5b8bc75 100644 --- a/i18n-aniyomi/src/commonMain/moko-resources/cs/plurals.xml +++ b/i18n-aniyomi/src/commonMain/moko-resources/cs/plurals.xml @@ -30,4 +30,4 @@ Epizody %1$s a další %2$d Epizody %1$s a dalších %2$d - \ No newline at end of file + diff --git a/i18n-aniyomi/src/commonMain/moko-resources/cv/strings.xml b/i18n-aniyomi/src/commonMain/moko-resources/cv/strings.xml index bdb8da5906..3e45e79173 100644 --- a/i18n-aniyomi/src/commonMain/moko-resources/cv/strings.xml +++ b/i18n-aniyomi/src/commonMain/moko-resources/cv/strings.xml @@ -11,4 +11,4 @@ Вӑхӑтлӑха чарнӑ Тиеве вӑхӑтлӑха чарнӑ Сыпӑксен ҫӗнетӗвӗсем - \ No newline at end of file + diff --git a/i18n-aniyomi/src/commonMain/moko-resources/da/strings.xml b/i18n-aniyomi/src/commonMain/moko-resources/da/strings.xml index a071022186..aad446c887 100644 --- a/i18n-aniyomi/src/commonMain/moko-resources/da/strings.xml +++ b/i18n-aniyomi/src/commonMain/moko-resources/da/strings.xml @@ -4,4 +4,4 @@ Lokale manga Standard kategori Manga i ekskluderede kategorier vil ikke blive opdateret selv hvis de også er i inkluderede kategorier. - \ No newline at end of file + diff --git a/i18n-aniyomi/src/commonMain/moko-resources/de/plurals.xml b/i18n-aniyomi/src/commonMain/moko-resources/de/plurals.xml index 3f46e2c45e..12bffd0305 100644 --- a/i18n-aniyomi/src/commonMain/moko-resources/de/plurals.xml +++ b/i18n-aniyomi/src/commonMain/moko-resources/de/plurals.xml @@ -28,4 +28,4 @@ Folgen %1$s und 1 mehr Folgen %1$s und %2$d mehr - \ No newline at end of file + diff --git a/i18n-aniyomi/src/commonMain/moko-resources/el/strings.xml b/i18n-aniyomi/src/commonMain/moko-resources/el/strings.xml index 4f197a7abf..91bf454d7e 100644 --- a/i18n-aniyomi/src/commonMain/moko-resources/el/strings.xml +++ b/i18n-aniyomi/src/commonMain/moko-resources/el/strings.xml @@ -14,4 +14,4 @@ Παύση Λήψη σε παύση Ενημερώσεις κεφαλαίων - \ No newline at end of file + diff --git a/i18n-aniyomi/src/commonMain/moko-resources/eo/strings.xml b/i18n-aniyomi/src/commonMain/moko-resources/eo/strings.xml index 3658e3c37f..058f1ea7fd 100644 --- a/i18n-aniyomi/src/commonMain/moko-resources/eo/strings.xml +++ b/i18n-aniyomi/src/commonMain/moko-resources/eo/strings.xml @@ -9,4 +9,4 @@ Paŭzigita Elŝutito paŭzigita Ĉapitraj ĝisdatigoj - \ No newline at end of file + diff --git a/i18n-aniyomi/src/commonMain/moko-resources/es/plurals.xml b/i18n-aniyomi/src/commonMain/moko-resources/es/plurals.xml index 9b71f4070b..78d349f490 100644 --- a/i18n-aniyomi/src/commonMain/moko-resources/es/plurals.xml +++ b/i18n-aniyomi/src/commonMain/moko-resources/es/plurals.xml @@ -35,4 +35,4 @@ Episodios %1$s y %2$d más Episodios %1$s y %2$d más - \ No newline at end of file + diff --git a/i18n-aniyomi/src/commonMain/moko-resources/eu/strings.xml b/i18n-aniyomi/src/commonMain/moko-resources/eu/strings.xml index 14312a142d..a229f23791 100644 --- a/i18n-aniyomi/src/commonMain/moko-resources/eu/strings.xml +++ b/i18n-aniyomi/src/commonMain/moko-resources/eu/strings.xml @@ -13,4 +13,4 @@ Gelditurik Deskarga pausatu da Kapituluaren eguneraketak - \ No newline at end of file + diff --git a/i18n-aniyomi/src/commonMain/moko-resources/fa/plurals.xml b/i18n-aniyomi/src/commonMain/moko-resources/fa/plurals.xml index 5e98c904e4..4c71e067a2 100644 --- a/i18n-aniyomi/src/commonMain/moko-resources/fa/plurals.xml +++ b/i18n-aniyomi/src/commonMain/moko-resources/fa/plurals.xml @@ -28,4 +28,4 @@ قسمت‌های %1$s و 1 قسمت دیگر قسمت‌های %1$s و %2$d قسمت دیگر - \ No newline at end of file + diff --git a/i18n-aniyomi/src/commonMain/moko-resources/fi/plurals.xml b/i18n-aniyomi/src/commonMain/moko-resources/fi/plurals.xml index 5f3010623c..7dfbf3f4c3 100644 --- a/i18n-aniyomi/src/commonMain/moko-resources/fi/plurals.xml +++ b/i18n-aniyomi/src/commonMain/moko-resources/fi/plurals.xml @@ -12,4 +12,4 @@ %d sekunti %d sekuntia - \ No newline at end of file + diff --git a/i18n-aniyomi/src/commonMain/moko-resources/fil/plurals.xml b/i18n-aniyomi/src/commonMain/moko-resources/fil/plurals.xml index e3da54fba4..de40f5ca2a 100644 --- a/i18n-aniyomi/src/commonMain/moko-resources/fil/plurals.xml +++ b/i18n-aniyomi/src/commonMain/moko-resources/fil/plurals.xml @@ -28,4 +28,4 @@ Mga Episode %1$s at 1 pa Mga Episode %1$s at %2$d pa - \ No newline at end of file + diff --git a/i18n-aniyomi/src/commonMain/moko-resources/fr/plurals.xml b/i18n-aniyomi/src/commonMain/moko-resources/fr/plurals.xml index 0728ce4ebf..e1563ba26d 100644 --- a/i18n-aniyomi/src/commonMain/moko-resources/fr/plurals.xml +++ b/i18n-aniyomi/src/commonMain/moko-resources/fr/plurals.xml @@ -30,4 +30,4 @@ Épisodes %1$s et %2$d autres Épisodes %1$s et %2$d autres - \ No newline at end of file + diff --git a/i18n-aniyomi/src/commonMain/moko-resources/gl/strings.xml b/i18n-aniyomi/src/commonMain/moko-resources/gl/strings.xml index c05b3c81f9..d9405dd43b 100644 --- a/i18n-aniyomi/src/commonMain/moko-resources/gl/strings.xml +++ b/i18n-aniyomi/src/commonMain/moko-resources/gl/strings.xml @@ -3,4 +3,4 @@ Categorías, actualización global, accións ao arrastrar Categorías Categoría por defecto - \ No newline at end of file + diff --git a/i18n-aniyomi/src/commonMain/moko-resources/he/plurals.xml b/i18n-aniyomi/src/commonMain/moko-resources/he/plurals.xml index e477b49508..788497193a 100644 --- a/i18n-aniyomi/src/commonMain/moko-resources/he/plurals.xml +++ b/i18n-aniyomi/src/commonMain/moko-resources/he/plurals.xml @@ -42,4 +42,4 @@ פרקים %1$s ו-%2$d נוספים - \ No newline at end of file + diff --git a/i18n-aniyomi/src/commonMain/moko-resources/hr/plurals.xml b/i18n-aniyomi/src/commonMain/moko-resources/hr/plurals.xml index a0cf6d3a7b..80579d14e2 100644 --- a/i18n-aniyomi/src/commonMain/moko-resources/hr/plurals.xml +++ b/i18n-aniyomi/src/commonMain/moko-resources/hr/plurals.xml @@ -35,4 +35,4 @@ Epizode %1$s i još %2$d Epizode %1$s i još %2$d - \ No newline at end of file + diff --git a/i18n-aniyomi/src/commonMain/moko-resources/hu/strings.xml b/i18n-aniyomi/src/commonMain/moko-resources/hu/strings.xml index 6bc326fee9..e9b4522656 100644 --- a/i18n-aniyomi/src/commonMain/moko-resources/hu/strings.xml +++ b/i18n-aniyomi/src/commonMain/moko-resources/hu/strings.xml @@ -14,4 +14,4 @@ Szünetel Letöltés szüneteltetve Fejezetfrissítések - \ No newline at end of file + diff --git a/i18n-aniyomi/src/commonMain/moko-resources/in/plurals.xml b/i18n-aniyomi/src/commonMain/moko-resources/in/plurals.xml index 291ce0553d..94358e041c 100644 --- a/i18n-aniyomi/src/commonMain/moko-resources/in/plurals.xml +++ b/i18n-aniyomi/src/commonMain/moko-resources/in/plurals.xml @@ -21,4 +21,4 @@ Episode %1$s dan %2$d lainnya - \ No newline at end of file + diff --git a/i18n-aniyomi/src/commonMain/moko-resources/it/plurals.xml b/i18n-aniyomi/src/commonMain/moko-resources/it/plurals.xml index c57a4e20e6..c301b7d9e0 100644 --- a/i18n-aniyomi/src/commonMain/moko-resources/it/plurals.xml +++ b/i18n-aniyomi/src/commonMain/moko-resources/it/plurals.xml @@ -35,4 +35,4 @@ Episodi %1$s e altri %2$d Episodi %1$s e altri %2$d - \ No newline at end of file + diff --git a/i18n-aniyomi/src/commonMain/moko-resources/jv/strings.xml b/i18n-aniyomi/src/commonMain/moko-resources/jv/strings.xml index 05c62a6879..9ccf48e27f 100644 --- a/i18n-aniyomi/src/commonMain/moko-resources/jv/strings.xml +++ b/i18n-aniyomi/src/commonMain/moko-resources/jv/strings.xml @@ -8,4 +8,4 @@ kategori gawan Manga ing kategori sing ora kalebu ora bakal dianyari sanajan uga ana ing kategori sing kalebu. Donlotan mandheg - \ No newline at end of file + diff --git a/i18n-aniyomi/src/commonMain/moko-resources/ka-rGE/strings.xml b/i18n-aniyomi/src/commonMain/moko-resources/ka-rGE/strings.xml index b03487442d..ff3737ad9e 100644 --- a/i18n-aniyomi/src/commonMain/moko-resources/ka-rGE/strings.xml +++ b/i18n-aniyomi/src/commonMain/moko-resources/ka-rGE/strings.xml @@ -9,4 +9,4 @@ დაპაუზებულია გადმოწერა დაპაუზებულია თავების განახლებები - \ No newline at end of file + diff --git a/i18n-aniyomi/src/commonMain/moko-resources/km/strings.xml b/i18n-aniyomi/src/commonMain/moko-resources/km/strings.xml index 364f8b0abb..3039d8111f 100644 --- a/i18n-aniyomi/src/commonMain/moko-resources/km/strings.xml +++ b/i18n-aniyomi/src/commonMain/moko-resources/km/strings.xml @@ -3,4 +3,4 @@ ការតម្រៀបថ្នាក់ ម៊េងហ្គាដែលមានស្រាប់ក្នុងឧបករណ៍ ថ្នាក់ធម្មតា - \ No newline at end of file + diff --git a/i18n-aniyomi/src/commonMain/moko-resources/kn/strings.xml b/i18n-aniyomi/src/commonMain/moko-resources/kn/strings.xml index 80d49685dc..c108db7f89 100644 --- a/i18n-aniyomi/src/commonMain/moko-resources/kn/strings.xml +++ b/i18n-aniyomi/src/commonMain/moko-resources/kn/strings.xml @@ -11,4 +11,4 @@ ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ ಡೌನ್‌ಲೋಡ್ ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ ಅಧ್ಯಾಯ ನವೀಕರಣಗಳು - \ No newline at end of file + diff --git a/i18n-aniyomi/src/commonMain/moko-resources/ko/plurals.xml b/i18n-aniyomi/src/commonMain/moko-resources/ko/plurals.xml index fe09ef8cc3..2cb28d2e51 100644 --- a/i18n-aniyomi/src/commonMain/moko-resources/ko/plurals.xml +++ b/i18n-aniyomi/src/commonMain/moko-resources/ko/plurals.xml @@ -21,4 +21,4 @@ 에피소드 %1$s와 그 외 %2$d - \ No newline at end of file + diff --git a/i18n-aniyomi/src/commonMain/moko-resources/lv/strings.xml b/i18n-aniyomi/src/commonMain/moko-resources/lv/strings.xml index aa1a1f05d6..2fe2bd7d4c 100644 --- a/i18n-aniyomi/src/commonMain/moko-resources/lv/strings.xml +++ b/i18n-aniyomi/src/commonMain/moko-resources/lv/strings.xml @@ -18,4 +18,4 @@ Pievienot manga bibliotēkai? Lejuplāde pauzēta Nodaļu atjauninājumi - \ No newline at end of file + diff --git a/i18n-aniyomi/src/commonMain/moko-resources/mr/strings.xml b/i18n-aniyomi/src/commonMain/moko-resources/mr/strings.xml index 82ee3fe101..4e6b295044 100644 --- a/i18n-aniyomi/src/commonMain/moko-resources/mr/strings.xml +++ b/i18n-aniyomi/src/commonMain/moko-resources/mr/strings.xml @@ -3,4 +3,4 @@ चालु केले श्रेण्या मूलभूत श्रेणी - \ No newline at end of file + diff --git a/i18n-aniyomi/src/commonMain/moko-resources/my/strings.xml b/i18n-aniyomi/src/commonMain/moko-resources/my/strings.xml index 326a328ce6..c20d1f28db 100644 --- a/i18n-aniyomi/src/commonMain/moko-resources/my/strings.xml +++ b/i18n-aniyomi/src/commonMain/moko-resources/my/strings.xml @@ -2,4 +2,4 @@ စာကြည့်တိုက်အနှစ်ချုပ် အိုင်ကွန်ပေါ်တွင် မဖတ်ရသေးတဲ့ အရေအတွက်ကို ပြသပါ - \ No newline at end of file + diff --git a/i18n-aniyomi/src/commonMain/moko-resources/nb-rNO/strings.xml b/i18n-aniyomi/src/commonMain/moko-resources/nb-rNO/strings.xml index 04764cf06d..0e2b64f44f 100644 --- a/i18n-aniyomi/src/commonMain/moko-resources/nb-rNO/strings.xml +++ b/i18n-aniyomi/src/commonMain/moko-resources/nb-rNO/strings.xml @@ -14,4 +14,4 @@ Pauset Nedlasting pauset Kapitteloppdateringer - \ No newline at end of file + diff --git a/i18n-aniyomi/src/commonMain/moko-resources/ne/strings.xml b/i18n-aniyomi/src/commonMain/moko-resources/ne/strings.xml index a98fffd8ac..2224a34d31 100644 --- a/i18n-aniyomi/src/commonMain/moko-resources/ne/strings.xml +++ b/i18n-aniyomi/src/commonMain/moko-resources/ne/strings.xml @@ -14,4 +14,4 @@ रोकिएको डाउनलोडहरु रोकियो अध्याय अपडेटहरू - \ No newline at end of file + diff --git a/i18n-aniyomi/src/commonMain/moko-resources/pl/plurals.xml b/i18n-aniyomi/src/commonMain/moko-resources/pl/plurals.xml index 82fce5858c..3f058c1364 100644 --- a/i18n-aniyomi/src/commonMain/moko-resources/pl/plurals.xml +++ b/i18n-aniyomi/src/commonMain/moko-resources/pl/plurals.xml @@ -42,4 +42,4 @@ Odcinki %1$s i %2$d więcej Odcinki %1$s i %2$d więcej - \ No newline at end of file + diff --git a/i18n-aniyomi/src/commonMain/moko-resources/pt-rBR/plurals.xml b/i18n-aniyomi/src/commonMain/moko-resources/pt-rBR/plurals.xml index 3ddd82f513..a42a1c9dd5 100644 --- a/i18n-aniyomi/src/commonMain/moko-resources/pt-rBR/plurals.xml +++ b/i18n-aniyomi/src/commonMain/moko-resources/pt-rBR/plurals.xml @@ -35,4 +35,4 @@ Episódios %1$s e %2$d mais Episódios %1$s e %2$d mais - \ No newline at end of file + diff --git a/i18n-aniyomi/src/commonMain/moko-resources/pt/plurals.xml b/i18n-aniyomi/src/commonMain/moko-resources/pt/plurals.xml index 9ed43cd31c..b41222c75c 100644 --- a/i18n-aniyomi/src/commonMain/moko-resources/pt/plurals.xml +++ b/i18n-aniyomi/src/commonMain/moko-resources/pt/plurals.xml @@ -35,4 +35,4 @@ Episódios %1$s e %2$d mais Episódios %1$s e %2$d mais - \ No newline at end of file + diff --git a/i18n-aniyomi/src/commonMain/moko-resources/ro/strings.xml b/i18n-aniyomi/src/commonMain/moko-resources/ro/strings.xml index f6ee4b2cf5..82dc38aff0 100644 --- a/i18n-aniyomi/src/commonMain/moko-resources/ro/strings.xml +++ b/i18n-aniyomi/src/commonMain/moko-resources/ro/strings.xml @@ -14,4 +14,4 @@ Întrerupt Descărcare întreruptă Actualizări de capitole - \ No newline at end of file + diff --git a/i18n-aniyomi/src/commonMain/moko-resources/sa/strings.xml b/i18n-aniyomi/src/commonMain/moko-resources/sa/strings.xml index 81b98f87d6..ed2e641f48 100644 --- a/i18n-aniyomi/src/commonMain/moko-resources/sa/strings.xml +++ b/i18n-aniyomi/src/commonMain/moko-resources/sa/strings.xml @@ -13,4 +13,4 @@ विरमितम् अवारोपणं विरमितम् अध्यायनवीकरणानि - \ No newline at end of file + diff --git a/i18n-aniyomi/src/commonMain/moko-resources/sah/strings.xml b/i18n-aniyomi/src/commonMain/moko-resources/sah/strings.xml index c5b2883276..9bb556dad5 100644 --- a/i18n-aniyomi/src/commonMain/moko-resources/sah/strings.xml +++ b/i18n-aniyomi/src/commonMain/moko-resources/sah/strings.xml @@ -8,4 +8,4 @@ Маанганы Бэбэлэтиэкэҕэ киллэрэбит дуу? Сыыһааһын Тохтотулунна - \ No newline at end of file + diff --git a/i18n-aniyomi/src/commonMain/moko-resources/sc/strings.xml b/i18n-aniyomi/src/commonMain/moko-resources/sc/strings.xml index 684bc385fd..01faf015a4 100644 --- a/i18n-aniyomi/src/commonMain/moko-resources/sc/strings.xml +++ b/i18n-aniyomi/src/commonMain/moko-resources/sc/strings.xml @@ -55,4 +55,4 @@ In pàusa Iscarrigamentu in pàusa Agiornamentos de sos capìtulos - \ No newline at end of file + diff --git a/i18n-aniyomi/src/commonMain/moko-resources/sdh/strings.xml b/i18n-aniyomi/src/commonMain/moko-resources/sdh/strings.xml index d3d86b3319..152730f33d 100644 --- a/i18n-aniyomi/src/commonMain/moko-resources/sdh/strings.xml +++ b/i18n-aniyomi/src/commonMain/moko-resources/sdh/strings.xml @@ -3,4 +3,4 @@ کاتیگۆرییەکان مانگای ناوخۆیی زیادکردنی مانگا بۆ کۆکراوەکان؟ - \ No newline at end of file + diff --git a/i18n-aniyomi/src/commonMain/moko-resources/sq/strings.xml b/i18n-aniyomi/src/commonMain/moko-resources/sq/strings.xml index 0bfdc588ae..f2467881dd 100644 --- a/i18n-aniyomi/src/commonMain/moko-resources/sq/strings.xml +++ b/i18n-aniyomi/src/commonMain/moko-resources/sq/strings.xml @@ -1,4 +1,4 @@ Kategoritë, përditësimi global - \ No newline at end of file + diff --git a/i18n-aniyomi/src/commonMain/moko-resources/te/strings.xml b/i18n-aniyomi/src/commonMain/moko-resources/te/strings.xml index 66f3c1a08f..3e3f97e323 100644 --- a/i18n-aniyomi/src/commonMain/moko-resources/te/strings.xml +++ b/i18n-aniyomi/src/commonMain/moko-resources/te/strings.xml @@ -1,4 +1,4 @@ విభాగములు - \ No newline at end of file + diff --git a/i18n-aniyomi/src/commonMain/moko-resources/th/strings.xml b/i18n-aniyomi/src/commonMain/moko-resources/th/strings.xml index 2a0f5e049a..b351a27bd7 100644 --- a/i18n-aniyomi/src/commonMain/moko-resources/th/strings.xml +++ b/i18n-aniyomi/src/commonMain/moko-resources/th/strings.xml @@ -14,4 +14,4 @@ หยุดชั่วคราว การดาวน์โหลดหยุดชั่วคราว อัปเดตตอน - \ No newline at end of file + diff --git a/i18n-aniyomi/src/commonMain/moko-resources/tr/plurals.xml b/i18n-aniyomi/src/commonMain/moko-resources/tr/plurals.xml index d9b31be478..5cfa767b16 100644 --- a/i18n-aniyomi/src/commonMain/moko-resources/tr/plurals.xml +++ b/i18n-aniyomi/src/commonMain/moko-resources/tr/plurals.xml @@ -28,4 +28,4 @@ %1$s bölüm ve 1 tane daha %1$s bölüm ve %2$d tane daha - \ No newline at end of file + diff --git a/i18n-aniyomi/src/commonMain/moko-resources/uk/plurals.xml b/i18n-aniyomi/src/commonMain/moko-resources/uk/plurals.xml index b35608e7f5..08475baf06 100644 --- a/i18n-aniyomi/src/commonMain/moko-resources/uk/plurals.xml +++ b/i18n-aniyomi/src/commonMain/moko-resources/uk/plurals.xml @@ -42,4 +42,4 @@ Епізоди %1$s та інші %2$d Епізоди %1$s та інші %2$d - \ No newline at end of file + diff --git a/i18n-aniyomi/src/commonMain/moko-resources/ur/strings.xml b/i18n-aniyomi/src/commonMain/moko-resources/ur/strings.xml index 55344e5192..045e125f3d 100644 --- a/i18n-aniyomi/src/commonMain/moko-resources/ur/strings.xml +++ b/i18n-aniyomi/src/commonMain/moko-resources/ur/strings.xml @@ -1,3 +1,3 @@ - \ No newline at end of file + diff --git a/i18n-aniyomi/src/commonMain/moko-resources/uz/strings.xml b/i18n-aniyomi/src/commonMain/moko-resources/uz/strings.xml index e4fc68ea81..5da3c9f336 100644 --- a/i18n-aniyomi/src/commonMain/moko-resources/uz/strings.xml +++ b/i18n-aniyomi/src/commonMain/moko-resources/uz/strings.xml @@ -2,4 +2,4 @@ Toifalar, global yangilanish Kategoriyalar - \ No newline at end of file + diff --git a/i18n-aniyomi/src/commonMain/moko-resources/zh-rCN/plurals.xml b/i18n-aniyomi/src/commonMain/moko-resources/zh-rCN/plurals.xml index 7f2ac66c62..08ab10fb67 100644 --- a/i18n-aniyomi/src/commonMain/moko-resources/zh-rCN/plurals.xml +++ b/i18n-aniyomi/src/commonMain/moko-resources/zh-rCN/plurals.xml @@ -9,4 +9,4 @@ %d秒 - \ No newline at end of file + diff --git a/i18n/build.gradle.kts b/i18n/build.gradle.kts index 7259e46fdb..808068734d 100644 --- a/i18n/build.gradle.kts +++ b/i18n/build.gradle.kts @@ -1,24 +1,24 @@ -import mihon.buildlogic.generatedBuildDir -import mihon.buildlogic.tasks.getLocalesConfigTask +import mihon.gradle.tasks.GenerateLocalesConfigTask import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi plugins { - id("mihon.library") - kotlin("multiplatform") - alias(libs.plugins.moko) + alias(mihonx.plugins.kotlin.multiplatform) + alias(mihonx.plugins.spotless) + + alias(libs.plugins.moko.resources) } kotlin { - androidTarget() + android { + namespace = "tachiyomi.i18n" - applyDefaultHierarchyTemplate() + // TODO(antsy): Remove when https://youtrack.jetbrains.com/issue/KT-83319 is resolved + withHostTest { } + } - sourceSets { - commonMain { - dependencies { - api(libs.moko.core) - } - } + @OptIn(ExperimentalKotlinGradlePluginApi::class) + dependencies { + api(libs.moko.resources) } @OptIn(ExperimentalKotlinGradlePluginApi::class) @@ -27,31 +27,16 @@ kotlin { } } -val generatedAndroidResourceDir = generatedBuildDir.resolve("android/res") +androidComponents { + onVariants { variant -> + val resSource = variant.sources.res ?: return@onVariants -android { - namespace = "tachiyomi.i18n" - - sourceSets { - val main by getting - main.res.srcDirs( - "src/commonMain/resources", - generatedAndroidResourceDir, - ) - } - - lint { - disable.addAll(listOf("MissingTranslation", "ExtraTranslation")) + val variantName = variant.name.replaceFirstChar { it.uppercase() } + val task = tasks.register("generate${variantName}LocalesConfig") + resSource.addGeneratedSourceDirectory(task) { it.outputDir } } } multiplatformResources { resourcesPackage.set("tachiyomi.i18n") } - -tasks { - val localesConfigTask = project.getLocalesConfigTask(generatedAndroidResourceDir) - preBuild { - dependsOn(localesConfigTask) - } -} diff --git a/i18n/src/commonMain/moko-resources/ar/strings.xml b/i18n/src/commonMain/moko-resources/ar/strings.xml index 00ad13fe44..81d8ac57b2 100644 --- a/i18n/src/commonMain/moko-resources/ar/strings.xml +++ b/i18n/src/commonMain/moko-resources/ar/strings.xml @@ -409,7 +409,6 @@ مؤلّف غير معروف لا تمتلك أيّة مصادر مثبّتة إبحث عن \"%1$s\" بشكلٍ شامل - حُدِّث إلى الإصدار v%1$s لم يُعثر على فصول %1$s: %2$s, صفحة %3$d إعدادات الفصل الإفتراضية المُحدثة @@ -567,7 +566,6 @@ خطأ أثناء حفظ الصورة معطل رأسي بالعكس - فشل %1$d تحديث أو تحديثات اضغط لمعرفة المزيد نقل سلسلة الفصول للأعلى لا توجد مدخلات في المكتبة لإجراء نسخة احتياطي‮‮ة @@ -852,7 +850,6 @@ التكرارات المحتملة تحديث المتابعات إلى الفصل %d؟ إيقاف قراءة التاريخ مؤقتًا للتمديد - تبرع كاتبوتشين ­تقديم الصور في أوصاف المانجا إخفاء مؤشرات الفصل المفقودة diff --git a/i18n/src/commonMain/moko-resources/as/strings.xml b/i18n/src/commonMain/moko-resources/as/strings.xml index 53d4ee14ab..96df539ea4 100644 --- a/i18n/src/commonMain/moko-resources/as/strings.xml +++ b/i18n/src/commonMain/moko-resources/as/strings.xml @@ -551,7 +551,6 @@ খুলা উৎস লাইচেন্স গোপনীয়তা নীতি আপডেট চাওক - v%1$s ত আপডেট কৰা হৈছে ক্রাশ ৰিপ\'ৰ্ট পঠিয়াব যিকোনো বাগ মেলাবলৈ সহায় কৰে। কোনো সংবেদনশীল তথ্য পঠিয়াব নোৱাৰি F-Droid নিৰ্মাণসমূহৰ আনুষ্ঠানিক সমৰ্থন নাই। @@ -755,7 +754,6 @@ অধ্যায় %1$s অধ্যায় %1$s আৰু %2$d অধিক অধ্যায়সমূহ %1$s - %1$d আপডেট(s) ব্যৰ্থ অধিক জানিবলৈ টেপ কৰক কভাৰ আপডেট কৰিবলৈ ব্যৰ্থ এইটো কৰিবলৈ আগত অনুগ্ৰহ কৰি ৰেকৰ্ডটো আপোনাৰ লাইব্রেৰীত যোগ কৰক diff --git a/i18n/src/commonMain/moko-resources/base/plurals.xml b/i18n/src/commonMain/moko-resources/base/plurals.xml index c257f67648..1f1cb182fe 100644 --- a/i18n/src/commonMain/moko-resources/base/plurals.xml +++ b/i18n/src/commonMain/moko-resources/base/plurals.xml @@ -109,4 +109,9 @@ An entry was skipped %1$d entries were skipped + + + %1$d update failed + %1$d updates failed + diff --git a/i18n/src/commonMain/moko-resources/base/strings.xml b/i18n/src/commonMain/moko-resources/base/strings.xml index bd7005e8be..6ab3463c1b 100644 --- a/i18n/src/commonMain/moko-resources/base/strings.xml +++ b/i18n/src/commonMain/moko-resources/base/strings.xml @@ -919,7 +919,6 @@ Chapter %1$s Chapter %1$s and %2$d more Chapters %1$s - %1$d update(s) failed Tap to learn more Failed to update cover Please add the entry to your library before doing this diff --git a/i18n/src/commonMain/moko-resources/be/plurals.xml b/i18n/src/commonMain/moko-resources/be/plurals.xml index f326e86dcd..93afb4ca11 100644 --- a/i18n/src/commonMain/moko-resources/be/plurals.xml +++ b/i18n/src/commonMain/moko-resources/be/plurals.xml @@ -7,10 +7,10 @@ %d катэгорый - Пасля %1$s хвіліны - Пасля %1$s хвілін - Пасля %1$s хвілін - Пасля %1$s хвілін + Праз %1$s хвіліну + Праз %1$s хвіліны + Праз %1$s хвілін + Праз %1$s хвілін Учора @@ -19,9 +19,117 @@ %1$d дзён таму - Наступная непрачытаная глава - Наступныя %d непрачытаныя главы - Наступныя %d непрачытаных глав - Наступныя %d непрачытаных глав + Наступны непрачытаная раздзел + Наступныя %d непрачытаныя раздзелы + Наступныя %d непрачытаных раздзелаў + Наступныя %d непрачытаных раздзелаў + + + Заўтра + Праз %1$d дні + Праз %1$d дзён + Праз %1$d дзён + + + Выканана за %1$s з %2$s памылкай + Выканана за %1$s з %2$s памылкамі + Выканана за %1$s з %2$s памылкамі + Выканана за %1$s з %2$s памылкамі + + + Застаўся %1$s + Засталося %1$s + Засталося %1$s + Засталося %1$s + + + %d дзень + %d дні + %d дзён + %d дзён + + + %1$s старонка + %1$s старонкі + %1$s старонак + %1$s старонак + + + Адсутнічае %1$s раздзел + Адсутнічаюць %1$s раздзелы + Адсутнічаюць %1$s раздзелаў + Адсутнічаюць %1$s раздзелаў + + + %1$s раздзел + %1$s раздзелы + %1$s раздзелаў + %1$s раздзелаў + + + Наступны раздзел + Наступныя %d раздзелы + Наступныя %d раздзелаў + Наступныя %d раздзелаў + + + %d трэкер + %d трэкеры + %d трэкераў + %d трэкераў + + + Прапускаецца %d раздзел: адсутнічае ў крыніцы або адфільтраваны + Прапускаюцца %d раздзелы: адсутнічаюць у крыніцы або адфільтраваныя + Прапускаецца %d раздзелаў: адсутнічаюць у крыніцы або адфільтраваныя + Прапускаецца %d раздзелаў: адсутнічаюць у крыніцы або адфільтраваныя + + + Для %d твора + Для %d твораў + Для %d твораў + Для %d твораў + + + %1$d новы раздзел + %1$d новыя раздзелы + %1$d новых раздзелаў + %1$d новых раздзелаў + + + %1$d твор быў прапушчаны + %1$d творы былі прапушчаны + %1$d твораў было прапушчана + %1$d твораў было прапушчана + + + Раздзелы %1$s і яшчэ адзін + Раздзелы %1$s і яшчэ %2$d + Раздзелы %1$s і яшчэ %2$d + Раздзелы %1$s і яшчэ %2$d + + + Даступна абнаўленне пашырэння + Даступна %d абнаўленні пашырэнняў + Даступна %d абнаўленняў пашырэнняў + Даступна %d абнаўленняў пашырэнняў + + + %d рэпазіторый + %d рэпазіторыі + %d рэпазіторыяў + %d рэпазіторыяў + + + Перанесці %1$d твор? + Перанесці %1$d творы? + Перанесці %1$d твораў? + Перанесці %1$d твораў? + + + Скапіяваць %1$d твор? + Скапіяваць %1$d творы? + Скапіяваць %1$d твораў? + Скапіяваць %1$d твораў? diff --git a/i18n/src/commonMain/moko-resources/be/strings.xml b/i18n/src/commonMain/moko-resources/be/strings.xml index be98fcffac..435402f332 100644 --- a/i18n/src/commonMain/moko-resources/be/strings.xml +++ b/i18n/src/commonMain/moko-resources/be/strings.xml @@ -1,355 +1,902 @@ - Перайсці да пачатку - Сыходны - Узыходзячы + Да пачатку + Па спаданні + Па ўзрастанні Найстарэйшы Найноўшы - Па нумару часткi - Па даце загрузкі + Па нумары раздзела + Па даце запампоўкі Сартаваць - Адмяніце ўсе для гэтай серыі - Адмяніць усе - Адмена + Скасаваць усе для гэтай серыі + Скасаваць усе + Скасаваць Адмацаваць Замацаваць Адключыць - Паказаць колькасць прадметаў - Паказаць укладкі катэгорый - Значкі лакальных - Значкі загружаных + Паказаць колькасць элементаў + Паказваць укладкі катэгорый + Лакальная крыніца + Спампаваныя раздзелы Спіс Зручная сетка Кампактная сетка - Выгляд + Адлюстраванне Рэжым адлюстравання Міграваць Адкрыць у WebView Адкрыць у браўзэры - Прадоўжыць + Узнавіць Пачаць - Выдаляць + Прыбраць Паўтарыць - Наступная частка - Папярэдняя частка + Наступны раздзел + Папярэдні раздзел Паўза - Прагляд частак - Рэдагаваць вокладку - Дадаць у катэгорыі + Праглядзець раздзелы + Змяніць вокладку + Змяніць катэгорыі Перайменаваць катэгорыю Рэдагаваць катэгорыі Дадаць катэгорыю Дадаць Рэдагаваць Адключыць усе - Ўключыць усе + Уключыць усе Абнавіць бібліятэку Выдаліць - Зняць закладку з часткi - Закладка часткi - Скачаць + Зняць закладку + Дадаць у закладкі + Спампаваць Пазначыць папярэдняе як прачытанае Пазначыць як непрачытанае - Адзначыць як прачытанае - Выбраць наадварот + Пазначыць як прачытанае + Інвертаваць выбар Выбраць усе Глабальны пошук Пошук налад Пошук Дата дадання Дата атрымання - Апошняя частка - Апошняе чытанне - Усяго частак - У алфавітным парадку + Апошні раздзел + Апошняе прачытанае + Усяго раздзелаў + Па алфавіту Зняць фільтр - Непрачытаны + Непрачытана Адсочваецца - Паведамленні ў закладкі + У закладках Фільтр Меню Налады Дапамога - Інфармацыя аб пашырэнні + Зведкі пра пашырэнні Назва - Пашырэння - перанесці дадзеныя - Рэзервовае капіяванне і аднаўленне + Пашырэнні + Міграваць + Рэзерваванне і аднаўленне Крыніцы Гісторыя Абнаўленні Бібліятэка - Чарга загрузак + Чарга спамповак Налады Яшчэ Гісторыя Адсочванне - Часткi - Манга + Раздзелы + Творы бібліятэкі Катэгорыі - Выдаліць - Ненадзейны - Надзейны - Усталяваны - Устаноўка - Загрузка - Чаканне + Дэінсталяваць + Ненадзейнае + Надзейнае + Усталявана + Усталёўваецца + Пампуецца + Чакаецца Усталяваць - Састарэла - Абнаўленне + Састарэлае + Абнавіць Даступны абнаўлення - Выключыць: %s + Выключаць: %s Уключаць: %s - Ніхто + Няма Усе - Манга ў выключаных катэгорыях не будзе абнаўляцца, нават калі яны таксама знаходзяцца ў уключаных катэгорыях. - Налады для кожнай катэгорыі для сартавання і адлюстравання - Заўсёды пытацца + Творы ў выключаных катэгорыях не будуць абнаўляцца, нават калі яны таксама знаходзяцца ва ўключаных. + Асобныя налады сартавання для кожнай катэгорыі + Запытваць Катэгорыя па змаўчанні Правераць наяўнасць новай вокладкі і дэталяў пры абнаўленні бібліятэкі - Аўтаматычнае абнаўленне метададзеных - Абнаўляць толькі незавершаную мангу + Аўтаабнаўленне метададзеных + Прапускаць завершаныя творы Абмежаванні: %s - Зарадка - Абмежаванні на абнаўленне + Падчас зарадкі + Абмежаванні аўтаабнаўленняў Штотыдзень Кожныя 2 дні Штодня Кожныя 12 гадзін Кожныя 6 гадзін - Уручную - Частата абнаўлення + Выключаны + Аўтаабнаўленні Глабальнае абнаўленне - Гарызантальная - Партрэтная - Элементы ў радку + Альбомная + Кніжная + Элементаў у радку Адлюстраванне - Гэта не перашкаджае таму, каб неафіцыйныя або патэнцыйна няправільна пазначаныя пашырэння адлюстроўвалі змесціва NSFW (18+) у дадатку. - Паказаць у спісе крыніц - Крыніцы NSFW (18+) + Гэта не перашкаджае неафіцыйным або патэнцыйна няправільна пазначаным пашырэнням паказваць кантэнт 18+ (NSFW) у праграме. + Паказваць у спісе крыніц і пашырэнняў + Крыніцы 18+ (NSFW) Схаваць змесціва апавяшчэнняў - Схаваць змесціва прыкладання пры пераключэнні на іншыя прыкладання і блакаваць скрыншоты + Абарона экрана хавае змесціва праграмы пры пераключэнні паміж праграмамі і стварэнні скрыншотаў Абарона экрана Ніколі Заўсёды Блакаванне пры бяздзейнасці Патрабаваць разблакоўку - Бяспека + Бяспека і прыватнасць Кіраванне апавяшчэннямі Фармат даты - Чысты чорны цёмны рэжым - Ёцуба + Чорная + Yotsuba Інь і Ян - Тако + Tako Клубнічны дайкiры Паўночнае змярканне Зялёны яблык Дынамічная - Тэма прыкладання - Уключаны - Выключаны - У адпаведнасці з сістэмнай тэмай + Тэма праграмы + Цёмная + Светлая + Сістэмная Тэма - Інфармацыя + Пра праграму Дадаткова Адсочванне - Загрузкi - Чыталка + Пампоўкі + Чытанка Бібліятэка Агульныя - Дадатак недаступны - Пагрузка… - Пачаць загрузку прама зараз - Асвяжыць + Праграма недаступная + Загрузка… + Пачаць спампоўку зараз + Абнавіць Наперад Назад Аднавіць - Паказваць памылкі - Адкрыць часопіс + Націсніце для падрабязнасцей + Адкрыць журнал Адмяніць - Скід + Скінуць Захаваць Падзяліцца Усталяваць - Перайсцi на дно - Ніякіх апошніх абнаўленняў - Няма загрузак - Анімацыя пераходаў паміж старонкамі - Паказваць змесціва ў галіне выраза - Калі размяшчэнне падзелу на дзве старонкі не адпавядае кірунку чытання - Інвертаваць размяшчэнне з падзелам на дзве старонкі - Падзел на дзве старонкі - Паказваць зоны дотыку калі чыталка адкрыта - Паказваць накладанне схемы навігацыі - Поўнаэкранны рэжым - Можа ўтрымліваць кантэнт NSFW (18+) + У канец + Няма нядаўніх абнаўленняў + Няма спамповак + Аніміраваць пераходы старонак + Паказваць змесціва ў вобласці выраза + Калі размяшчэнне палоў падзеленай старонкі не адпавядае напрамку чытання + Інвертаваць размяшчэнне палоў падзеленай старонкі + Падзяляць шырокія старонкі напалову + Кароткачасова паказваць пры адкрыцці чытанкі + Паказваць накладанне зон дотыку + На ўвесь экран + Крыніцы з гэтага пашырэння могуць утрымліваць 18+ кантэнт (NSFW) 18+ - Гэта пашырэнне больш недаступна. - Гэта пашырэнне было падпісана ненадзейным сертыфікатам і не было актывавана. -\n -\nШкоднаснае пашырэнне можа счытваць любыя ўліковыя дадзеныя для ўваходу, якія захоўваюцца ў Mihon, або выконваць адвольны код. -\n -\nДавяраючы гэтаму сертыфікату, вы прымаеце на сябе гэтыя рызыкі. + Гэта пашырэнне больш недаступнае. Яно можа працаваць некарэктна і выклікаць праблемы ў праграме. Рэкамендуецца яго дэінсталяваць. + Шкодныя пашырэнні могуць счытваць любыя захаваныя ўліковыя даныя або выконваць адвольны код.\n\nДавяраючы гэтаму пашырэнню, вы прымаеце гэтыя рызыкі. Ненадзейнае пашырэнне - Схема навігацыі + Зоны дотыку Пастаронкава - Бесперапынна вертыкальна - Вэб-комікс - Вертыкальна - Справа налева - Злева направа + Рулон з прамежкамі + Рулон + Пастаронкава (вертыкальна) + Пастаронкава (справа налева) + Пастаронкава (злева направа) Справа Злева Наступная Папярэдняя Справа і злева - Край - Kindle-падобная - L-вобразная форма - Рэжым чытання па змаўчанні - Аўтаматычна + Краі + Kindle-падобны + L-падобны + Прадвызначаны рэжым чытання + Аўта Чорны Шэры Белы Колер фону - Ствараць тэчкі ў адпаведнасці з назвай мангі + Ствараць тэчкі ў адпаведнасці з назвай твора Захоўваць старонкі ў асобныя тэчкі - Паказаць пры доўгім націску - Дзеяння - Абодва + Паказваць дзеянні пры доўгім дотыку + Дзеянні + Па абедзвум Вертыкальна Гарызантальна - Не - Націск наадварот - Інвертаваць клавішы рэгулявання гучнасці - Клавішы рэгулявання гучнасці + Няма + Інвертаваць зоны дотыку + Інвертаваць клавішы гучнасці + Клавішы гучнасці Навігацыя - Прапусціць адфільтраваныя часткi - Прапусціць часткi, адзначаныя як прачытаныя - Трымаць экран уключаным - Зацямненьне + Пропускаць адфільтраваныя раздзелы + Пропускаць прачытаныя раздзелы + Не выключаць экран + Зацямненне Асвятленне Экран Множанне - Перакрыцце - Рэжым накладання каляровага фільтра - Карыстацкі каляровы фільтр + Накладанне + Рэжым змешвання колернага фільтра + Уласны колерны фільтр Адценні шэрага - Карыстацкая яркасць - Выключаны - Уключаны - Абрэзаць поля - Ненадоўга адлюстраваць бягучы рэжым пры адкрыцці чыталкі - Паказаць рэжым чытання - Паказаць нумар старонкі - Хуткасць анімацыі падвойнага націску + Уласная яркасць + Выключана + Уключана + Абразаць палі + Ненадоўга паказваць бягучы рэжым пры адкрыцці чытанкі + Паказваць рэжым чытання + Паказваць нумар старонкі + Хуткасць анімацыі пры падвойным дотыку Хуткая Звычайная - Ніякай анімацыі - Цэнтральная + Без анімацыі + Па цэнтры Справа Злева - Аўтаматычная - Стартавая пазіцыя павелічэння - Разумны - Зыходны памер + Аўтаматычна + Пачатковая пазіцыя павелічэння + Разумнае ўпісванне + Арыгінальны памер Па вышыні Па шырыні Расцягнуць - Змясціць у экран + Упісаць у экран Маштабаванне - Колеры наадварот + Інвертаваныя Сёння - Бірузовы - Знешнасць - Аўтэнтыфікацыя для пацверджання змяненняў + Бірузовая + Выгляд + Аўтэнтыфікуйцеся, каб падтвердзіць змену Па змаўчанні - У вас няма катэгорый. Націсніце кнопку \"Плюс\", каб стварыць яе для арганізацыі вашай бібліятэкі. + У вас няма катэгорый. Націсніце «плюс», каб стварыць іх і ўпарадкаваць бібліятэку. Ваша бібліятэка пустая - У апошні час нічога не прачытана + Нядаўна прачытанага няма Адсочваць - Службы, якія прадстаўляюць пашыраныя функцыі для пэўных крыніц. Манга аўтаматычна адсочваецца пры даданні ў вашу бібліятэку. - Пашыраныя паслугі - Аднабаковая сінхранізацыя для абнаўлення прагрэсу частак у службах адсочвання. Наладзьце адсочванне асобных запісаў мангі з дапамогай кнопкі адсочвання. - Паслугi + Дае пашыраныя магчымасці для пэўных крыніц. Творы будуць аўтаматычна адсочвацца пры даданні ў бібліятэку. + Пашыраныя трэкеры + Аднабаковая сінхранізацыя прагрэсу з вонкавымі трэкерамі. Наладзьце адсочванне твораў з дапамогай кнопкі «Адсочванне». + Трэкеры Абнаўляць прагрэс пасля чытання - Кіраўніцтва па адсочванні - Манга ў выключаных катэгорыях не будзе загружана, нават калі яны таксама знаходзяцца ў уключаных катэгорыях. - Спампаваць новыя часткi - Аўтаматычная загрузка - Пятая ад прачытанай часткi - Чацвёртая ад прачытанай часткi - Трэцяя ад прачытанай часткі - Перадапошняя частка - Апошняя прачытаная частка + Дапаможнік па адсочванні + Творы з выключаных катэгорый не будуць спампоўвацца, нават калі яны ёсць у іншых катэгорыях. + Спампоўваць новыя раздзелы + Аўтаспампоўка + 5 ад канца прачытаны раздзел + 4 ад канца прачытаны раздзел + 3 ад канца прачытаны раздзел + Перадапошні прачытаны раздзел + Апошні прачытаны раздзел Адключана - Дазволіць выдаленне частак з закладкамі - Аўтаматычна пасля чытання - Пасля таго, як пазначана як \"Прачытанае\" - Выдаліць часткі - Найнізкая + Дазволіць выдаленне раздзелаў з закладкамі + Аўтавыдаленне пасля чытання + Пасля ручнога пазначэння прачытаным + Выдаліць раздзелы + Найніжэйшая Нізкая Высокая Найвышэйшая - Аўтаматычнае утойванне меню пры адчувальнасці да прагортцы - Бакавой водступ - Чытаньне + Адчувальнасць хавання меню пры пракрутцы + Бакавы водступ + Чытанне Рэжым чытання - Заўсёды паказваць пераход паміж часткамі - A - B - G - R + Заўсёды паказваць пераход раздзелаў + Празрыстасць + Сіні + Зялёны + Чырвоны Заблакаваная альбомная Свабодная - Партрэтная + Кніжная Альбомная - Заблакаваная партрэтная - Тып арыентацыі - Тып арыентацыі па змаўчанні - папярэджанне + Заблакаваная кніжная + Арыентацыя + Прадвызначаная арыентацыя + Папярэджанне Выдаліць катэгорыю - Вы хочаце выдаліць катэгорыю \"%s\"? - InternalError: Праверце журнал збояў для атрымання дадатковай інфармацыі + Вы хочаце выдаліць катэгорыю «%s»? + InternalError: Праверце журнал збояў для дадатковых зведак Абнавіць усё - Узроставае абмежаванне - Не пачата - Паказаць мангу + Узроставы цэнз + Прапускаць непачатыя творы + Паказаць твор Версія - Апошняе абнаўленне мангі + Апошняя праверка абнаўлення Колькасць непрачытаных - Не ўдалося атрымаць спіс пашырэнняў - Сетка без назвы - Аб дадатку - Колькасць мангі + Не ўдалося атрымаць даступныя пашырэнні + Сетка вокладак + Звесткі пра праграму + Усяго твораў Мова - Толькі ў безлемітнай сетцы + Толькі ў безлімітнай сетцы Мова Лаванда - Мова дадатку - Ёсць непрачытаныя главы - Shizuku не працуе + Мова праграмы + Прапускаць з непрачытаным(і) раздзелам(і) + Shizuku не запушчаны Закрыць - Устаноўка пашырэнняў… - Перамясціць у пачатак спісу + Усталёўка пашырэння… + Перамясціць серыю ў пачатак Усталёўнік - па змаўчанні - Выдаліць усё + Састарэлы + Прыбраць усё Кожныя 3 дні - Толькі па Wi-Fi + Толькі праз Wi-Fi Не выбрана Перайсці ўверх - Разблакіраваць %s - Пачата + Разблакаваць %s + Пачатае Выбрана - Другія опцыі - Выдаліць загружанае - Даныя і хаванне + Дадатковыя параметры + Выдаліць спампаванае + Даныя і сховішча Статыстыка - На ўстройстве + Лакальна Задаць інтэрвал - Наладжвальная частата абнаўлення + Наладжваемая частата абнаўлення Наступнае - Перакладчык - Загружана + Сканлейтар + Спампована + Аўта + Наступнае чаканае абнаўленне + Ацэнка трэкера + Выпадкова + Шукаць… + Абнавіць катэгорыю + Адкрыць выпадковы твор + Скапіяваць у буфер абмену + Скапіяваць спасылку + Непрачытаныя раздзелы + Кнопка «Працягнуць чытанне» + Ужыць + ОК + Нататкі + Перамясціць серыю ў канец + Рэдагаваць нататкі + Скінуць налады + Закрыць укладку + Не зараз + Усё адно дадаць + Першыя крокі + Вітаем! + Давайце спачатку ўсё наладзім. Вы заўсёды зможаце змяніць гэта пазней у наладах. + Далей + Пачнем + Прапусціць + Абярыце тэчку, дзе %1$s будзе захоўваць спампаваныя раздзелы, рэзервовыя копіі ды іншае.\n\nРэкамендуецца абраць асобную тэчку.\n\nВыбраная тэчка: %2$s + Абраць тэчку + Неабходна абраць тэчку + Абнаўляецеся са старой версіі і не ведаеце, што выбраць? Звярніцеся да дапаможніка па сховішчы для дадатковых зведак. + Дапаможнік па сховішчы + Дазвол на ўсталёўку праграм + Для ўсталёўкі пашырэнняў крыніц. + Дазвол на апавяшчэнні + Атрымліваць апавяшчэнні пра абнаўленні бібліятэкі ды іншае. + Выкарыстанне батарэі ў фоне + Дазволіць пазбегнуць абрываў доўгатэрміновых абнаўленняў бібліятэкі, памповак ды аднаўленняў рэзервоўкі. + Даслаць журнал збояў + Ананімна даслаць журнал збояў распрацоўнікам. + Дазволіць аналітыку + Ананімна дасылаць даныя выкарыстання праграмы для паляпшэння яе функцый. + Надаць + Упершыню ў %s? Рэкамендуем азнаёміцца з дапаможнікам пачаткоўца. + Пераўсталёўваеце %s? + Тэма, фармат даты і часу + Катэгорыі, глабальнае абнаўленне, гартанне раздзелаў + Рэжым чытання, адлюстраванне, навігацыя + Аўтаматычнае спампоўванне, спампоўванне наперад + Аднабаковая сінхранізацыя прагрэсу, пашыраная сінхранізацыя + Крыніцы, пашырэнні, глабальны пошук + Ручныя і аўтаматычныя рэзервоўкі, сховішча + Блакіроўка праграмы, абарона экрана + Выгрузка журнала збояў, аптымізацыя батарэі + Catppuccin + Манахром + Nord + Tidal Wave + Адносныя пазнакі часу + «%1$s» замест « %2$s» + Адлюстроўваць выявы ў апісаннях твораў + Бяспека + Аналітыка і журналы збояў + Адпраўка журналаў збояў і аналітыкі дазволіць нам выяўляць і выпраўляць памылкі, паляпшаць прадукцыйнасць і развіваць праграму з улікам вашых патрэб + Разумнае абнаўленне + Прадказваць выхад новых раздзелаў + Паказваць колькасць непрачытаных на значку «Абнаўленні» + Паводзіны + Раздзел пры змахванні ўправа + Раздзел пры змахванні ўлева + Пазначаць прачытаны дублікат раздзела як «прачытаны» + Пасля прачытання раздзела + Пасля атрымання новага раздзела + Схаваць індыкатары адсутных раздзелаў + Забараніць не-ASCII назвы файлаў + Забяспечвае сумяшчальнасць з носьбітамі без падтрымкі Unicode. Патрабуе ручнога перайменавання тэчак крыніц і серый: замяніце не-ASCII сімвалы на іх шаснаццатковыя коды UTF-8 (ніжні рэгістр). Файлы раздзелаў пераймяноўваць не трэба. + Шматмоўныя + Прыбраць + Прыбраць пашырэнне? + Вы сапраўды хочаце прыбраць пашырэнне «%s»? + Для ўсталёўкі пашырэнняў патрабуюцца дазволы. Націсніце сюды, каб даць іх. + Усталюйце і запусціце Shizuku, каб выкарыстоўваць яго як усталёўнік пашырэнняў. + Адклікаць давер да ненадзейных пашырэнняў + Рэпазітар пашырэнняў + У вас няма рэпазітароў. + Дадаць рэпазітар + URL-адрас рэпазітара + Дадайце дадатковыя рэпазітары у %s. Іхнія URL-адрасы павінны заканчвацца на «index.min.json». + Гэты рэпазітар ужо дададзены! + Выдаліць рэпазітар + Недапушчальны URL рэпазітара + Вы сапраўды хочаце выдаліць рэпазітар «%s»? + Ці хочаце дадаць рэпазітар «%s»? + Адкрыць рэпазітар крыніцы + Замяніць + Адбітак ключа подпісу ўжо існуе + Рэпазітар %1$s мае такі ж самы адбітак ключа подпісу, як і %2$s.\nКалі гэта чакана, %2$s будзе заменены, у адваротным выпадку звяжыцеся з суправаджальнікам вашага рэпазітара. + Паварочваць шырокія старонкі пад памер экрана + Адлюстроўваць арыентацыю павернутых шырокіх старонак + Падвойны дотык для павелічэння + Мігаць пры змене старонкі + Змяншае дваенне выявы на экранах e-ink + Час мігацення + %1$s мс + Мігаць кожную + Мігаць з + Чорным + Белым + Белым і чорным + Уласная мяжа апаратнага растравання + Па змаўчанні (%d) + Калі чытанка загружае пустую выяву, паступова змяншаць парог.\nВыбрана: %s + Выкарыстоўваць састарэлы дэкодэр у чытанцы рулонаў + Уплывае на прадукцыйнасць. Уключайце толькі калі памяншэнне парога растра не вырашае праблему з пустымі выявамі + Уласны профіль адлюстравання + Пропускаць дубляваныя раздзелы + Адключана + Панарамаванне шырокіх выяў + Аўтаматычна павялічваць шырокія выявы + Зваротная кніжная + Адключыць памяншэнне маштабу + Выключаныя катэгорыі + Не вызначана месца сховішча + Недапушчальнае месца: %s + Не ўдалося стварыць тэчку спамповак + Не ўдалося стварыць тэчку: %s + Прапускаць спампоўку дублікатаў прачытаных раздзелаў + Спампоўваць наперад + Аўтаспампоўка падчас чытання + Працуе, толькі калі бягучы і наступны раздзелы ўжо спампаваны. + Захаваць як CBZ-архіў + Раздзяляць доўгія выявы + Паляпшае прадукцыйнасць чытанкі + Паралельныя спампоўкі з крыніц + Паралельныя спампоўкі старонак + Адначасовых спамповак старонак на крыніцу + Абнаўляць прагрэс пасля пазначэння прачытаным + Даступна, але крыніца не ўсталявана: %s + Уваход у трэкер + Хаваць творы, якія ўжо ёсць у бібліятэцы + Месца сховішча + Для аўтаматычных рэзервовак, спампоўвання раздзелаў і лакальных крыніц. + Зарэзерваваць + можна выкарыстаць каб аднавіць бягучую бібліятэку + Аднавіць з рэзервоўкі + Аднавіць бібліятэку з файла рэзервоўкі + Частата аўтаматычнага рэзервавання + Стварыць + Рэзервоўка створана + Няправільны файл рэзервоўкі: + Поўная памылка: + Рэзервоўка не ўтрымлівае твораў. + JSON-фармат рэзервовак не падтрымліваецца + Файл рэзервоўкі пашкоджаны + Адсутныя крыніцы: + Трэкеры без аўтарызацыі: + Вам можа спатрэбіцца ўсталяваць адсутныя пашырэнні і ўвайсці ў трэкеры для іх выкарыстання. + Аднаўленне завершана + %1$02d хв %2$02d сек + Рэзерваванне ўжо выконваецца + Што вы хочаце зарэзерваваць? + Налады праграмы + Налады крыніцы + Рэпазітар пашырэнняў + Уключаць прыватныя налады (напр., токены трэкераў) + Усе прачытаныя творы + Зарэзерваванне + Памылка рэзервавання + Не нададзены дазволы на захаванне даных + У бібліятэцы няма твораў для рэзервавання + Не ўдалося стварыць файл рэзервоўкі + Рэзервоўка і аднаўленне могуць працаваць неналежным чынам, калі адключана «Аптымізацыя MIUI». + Аднаўленне ўжо выконваецца + Аднаўленне з рэзервоўкі + Памылка аднаўлення з рэзервоўкі + Аднаўленне адменена + Варта захоўваць копіі рэзервовак таксама і ў іншых месцах. Рэзервоўкі могуць утрымліваць канфідэнцыйныя даныя, у тым ліку захаваныя паролі; будзьце асцярожныя, калі дзеліцеся імі. + Апошняе аўтаматычнае рэзерваванне: %s + Даныя + Выкарыстанне сховішча + Даступна: %1$s / Усяго: %2$s + Ачысціць кэш раздзелаў + Выкарыстана %1$s + Кэш ачышчаны, выдалена файлаў: %1$d + Адбылася памылка падчас ачысткі + Ачышчаць кэш раздзелаў пры запуску праграмы + Экспартаваць + Спіс бібліятэкі + Бібліятэка экспартавана + Сінхранізацыя бібліятэкі + Сінхранізацыя бібліятэкі завершана + Сетка + Ачысціць кукі + DNS праз HTTPS (DoH) + Прадвызначаны user agent + User agent не можа быць пустым + Недапушчальны user agent + Аднавіць user agent па змаўчанні + Патрабуецца перазапуск праграмы, каб змены ўступілі ў сілу + Кукі ачышчаны + Пераіндэксаваць спампоўкі + Прымусова пераправерыць спампаваныя раздзелы + Перастварэнне індэкса спамповак + Ачысціць базу даных + Выдаліць гісторыю для твораў, якія не захаваны ў вашай бібліятэцы + У базе даных %1$d пазабібліятэчных твораў + Вы збіраецеся прыбраць творы з базы даных + Прачытаныя раздзелы і прагрэс пазабібліятэчных твораў будуць страчаны + Пакідаць творы з прачытанымі раздзеламі + Творы выдалены + Няма чаго ачышчаць + Ачысціць даныя WebView + Даныя WebView ачышчаны + Абнавіць вокладкі бібліятэкі + Скінуць налады чытанкі для кожнай серыі + Скідае рэжым чытання і арыентацыю ўсіх серый + Усе налады чытанкі скінуты + Не ўдалося скінуць параметры чытанкі + Падзяліцца журналам збояў + Захоўвае журналы збояў у файл для адпраўкі распрацоўнікам + Фонавая актыўнасць + Адключыць аптымізацыю батарэі + Дапамагае з абнаўленнем бібліятэкі і рэзерваваннем ў фоне + Аптымізацыя батарэі ўжо адключана + Не ўдалося адкрыць налады прылады + Некаторыя вытворцы маюць дадатковыя абмежаванні для праграм, якія забіваюць фонавыя службы. Тут ёсць зведкі, як гэта выправіць. + Планшэтны інтэрфейс + Падрабязнае журналяванне + Запісваць падрабязнасці у сістэмны журнал (зніжае прадукцыйнасць праграмы) + Зведкі адладкі + Абнаўляць назвы твораў бібліятэцы пры неадпаведнасці крыніцы + Увага: калі твор быў перайменаваны, ён будзе выдалены з чаргі спампоўкі (калі там быў). + Сайт + Версія + Што новага + Дапамагчы з перакладам + Ліцэнзіі адкрытага кода + Палітыка прыватнасці + Праверыць абнаўленні + Адпраўляць справаздачы пра збоі + Дапамагае выпраўляць памылкі. Ніякія асабістыя даныя не будуць адпраўлены + Зборкі F-Droid афіцыйна не падтрымліваюцца.\nНацісніце, каб даведацца больш. + Толькі спампаваныя + Рэжым інкогніта + Прыпыняе гісторыю чытання + Прыпыніць гісторыю чытання для пашырэння + Адключыць рэжым інкогніта + Фільтруе ўсе творы ў вашай бібліятэцы + Увайсці ў %1$s + Імя карыстальніка + Адрас эл. пошты + Пароль + Логін + Уваход… + Увайшлі + Выйсці з %1$s? + Выйсці + Вы паспешна выйшлі + Невядомая памылка + Абнаўленне катэгорыі + З бібліятэкі + Спампаваныя раздзелы + Інтэрвалы + Накладанне + Укладкі + Больш няма вынікаў + Нічога не знойдзена + Лакальная крыніца + Іншае + Апошнія выкарыстаныя + Замацавана + Глабальны пошук… + Шукаць «%1$s» глабальна + Апошнія + Папулярнае + Агляд + Ёсць вынікі + Дапаможнік па лакальнай крыніцы + У вас няма замацаваных крыніц + Раздзел не знойдзены + Недапушчальны фармат раздзела + Сартаваць па + Дата + Выходзіць + Невядома + Невядомы аўтар + Аўтар + Мастак + Невядомы статус + Ліцэнзавана + Публікацыя завершана + Адменена + Замарожана + Дадаць у бібліятэку + У бібліятэцы + Прыбраць з бібліятэкі + Невядомая назва + Магчымыя дублікаты + У вашай бібліятэцы ёсць творы з падобнай назвай.\n\nАбярыце твор для пераносу або проста дадайце яго. + Дададзена ў бібліятэку + Прыбрана з бібліятэкі + Больш + Менш + Выдаліць спампаваныя раздзелы? + Скапіявана ў буфер абмену + Скапіявана ў буфер абмену:\n%1$s + Не ўдалося скапіяваць у буфер абмену + Крыніца не ўсталявана: %1$s + Дадаць у бібліятэку? + Няма апісання + Раздзел %1$s + Ацэньваць кожныя + Абнаўляць кожныя + Выхад новых раздзелаў прагназуецца прыкладна праз %1$s, праверка кожныя %2$s. + Гэты твор альбо завершаны, альбо дата яго выхаду невядомая. + Хутка + Наладжаная частата абнаўлення: + Спампоўваецца (%1$d/%2$d) + Памылка + Прыпынена + Назва крыніцы + Нумар раздзела + Па крыніцы + Па нумары раздзела + Па даце запампоўкі + Спампаваць + Непрачытаныя + У закладках + Уласная вокладка + Вокладка + Вокладка захавана + Памылка пры захаванні вокладкі + Памылка адпраўлення вокладкі + Дакладна выдаліць выбраныя раздзелы? + Налады раздзела + Дакладна захаваць гэтыя налады як прадвызначаныя? + Таксама ўжыць для ўсёй маёй бібліятэкі + Як па змаўчанні + Раздзелы не знойдзены + Вы ўпэўнены? + Выключыць сканлэйтараў + Сканлэйтары не знойдзены + Аднавіць трэкеры да раздзела %d? + Трэкеры адноўлены да раздзела %d + Адсочванне + Дадаць адсочванне + Непрачытанае + Чытаю + Скончана + Пакінута + Адкладзена + Прыпынена + Запланавана + Перачытваю + Спіс чытання + Спіс пажаданняў + Спіс завершаных + Спіс адкладзеных + Спіс незакончаных + Ацэнка + Загаловак + Статус + Статус + Дата пачатку + Дата заканчэння + Адсочваецца прыватна + Адсочваць прыватна + Адсочваць публічна + Тып + Калі ласка, увайдзіце ў MAL зноў + Крыніца не падтрымліваецца + Супадзенняў не знойдзена + %1$s памылка: %2$s + Прыбраць дату? + Гэта прыбярэ выбраную раней дату пачатку з %s + Гэта прыбярэ абраную раней дату заканчэння з %s + Прыбраць адсочванне %s? + Гэта прыбярэ адсочванне лакальна. + Таксама прыбраць з %s + Катэгoрыя з такой назвай ужо існуе! + Катэгорыі выдалены + Гэта прыбярэ дату прачытання раздзела. Вы ўпэўнены? + Скінуць усе раздзелы для гэтага твора + Выява захавана + Памылка захавання выявы + Уласны фільтр + Усталяваць як вокладку + Вокладка адноўлена + %1$s: %2$s, старонка %3$d + Старонка: %1$d + Наступны раздзел не знойдзены + Не ўдалося загрузіць выяву + Выкарыстаць як вокладку? + Для гэтай серыі + Рэжым чытання + Скончана: + Бягучая: + Наступная: + Папярэдняя: + Наступнага раздзела няма + Папярэдняга раздзела няма + Загрузка старонак… + Не ўдалося загрузіць старонкі: %1$s + Старонкі не знойдзены + Крыніца не знойдзена + Абнаўленне бібліятэкі + Абнаўленне ўжо запушчана + Не ўдалося адкрыць апошні прачытаны раздзел + Апошняе абноўленне: %s + Толькі што + Ніколі + Прагляд будучых абнаўленняў + Фільтраваць выключаных сканлэйтараў + Будучы дапаможнік + Наступны месяц + Папярэдні месяц + Раздз. %1$s ‐ %2$s + Ачысціць гісторыю + Гісторыя выдалена + Вы ўпэўнены? Уся гісторыя будзе выдалена. + Крыніц не знойдзена + Усталяваных крыніц не знойдзена + Дапаможнік па пераносе крыніц + Абярыце даныя для ўключэння + Скасаваць + Скасаваць + Скасаваць + Дапаможнік пачаткоўца + Абярыце мігруючую крыніцу + Міграваць + Скапіяваць + Вой, нейкая няўвязка + Не ўсталявана + Вой! + У %s адбылася непрадбачаная памылка. Мы рэкамендуем падзяліцца журналам збояў у нашым канале падтрымкі ў Discord. + Перазапусціць праграму + Агляд + Завершаныя творы + Працягласць чытання + Творы + У глабальным абнаўленні + Усяго + Прачытана + Адсочванне + Адсочваемыя творы + Сярэдняя ацэнка + Выкарыстана + Н/Д + %dд + %dг + %dхв + %dс + Не ўдалося спампаваць раздзелы. Паспрабуйце яшчэ раз у раздзеле спамповак + Не ўдалося спампаваць праз недахоп месца ў сховішчы + Папярэджанне: вялікая колькасць спамповак можа прывесці да запавольвання працы крыніц і/або блакіроўкі %s. Націсніце, каб даведацца больш. + Абнаўленне бібліятэкі… (%s) + Вялікія абнаўленні шкодзяць крыніцам і могуць прывесці да іх запавольвання і павялічанага расходу батарэі. Націсніце, каб даведацца больш. + Знойдзены новыя раздзелы + Раздзел %1$s + Раздзел %1$s ды яшчэ %2$d + Раздзелы %1$s + Націсніце, каб даведацца больш + Не ўдалося абнавіць вокладку + Калі ласка, дадайце твор у бібліятэку перад гэтым дзеяннем + Для дапамогі ў выпраўленні памылак абнаўлення бібліятэкі глядзіце %1$s + Прапушчана, бо серыя завершана + Прапушчана, бо ёсць непрачытаныя раздзелы + Прапушчана, бо няма прачытаных раздзелаў + Прапушчана, бо твор не патрабуе абнаўленняў + Прапушчана, бо сёння не чакаецца выхаду раздзелаў + Абраць вокладку + Абраць файл рэзервоўкі + Праграма для выбару файлаў не знойдзена + Не ўдалося атрымаць пастаянны доступ да тэчкі. Праграма можа паводзіць сябе непрадбачана. + Файл не выбраны + Спампаваць + Адкрыць на GitHub + Гэтая версія Android больш не падтрымліваецца + Няма новых абнаўленняў + Спампоўванне… + Націсніце, каб усталяваць абнаўленне + Памылка спампоўвання + Даступная новая версія! + Катэгорыя пустая + У гэтай катэгорыі твораў не знойдзена + У вас яшчэ няма катэгорый. + Не ўдалося прайсці Cloudflare + Націсніце тут, каб атрымаць дапамогу з Cloudflare + *абавязкова + WebView неабходны для працы праграмы + Калі ласка, абнавіце WebView для лепшай сумяшчальнасці + Стандартныя параметры раздзелаў абноўлены + Пампоўшчык + Памылка + Не ўдалося спампаваць раздзел праз непрадбачаную памылку + Няма Wi-Fi злучэння + Няма злучэння з сеткай + Спампоўванне прыпынена + Старонка %d не знойдзена падчас падзелу + Шлях да файлу старонкі %d не знойдзены + Праверка спамповак + Агульнае + Прагрэс + Завершэнні + Памылкі + Абнаўленні раздзелаў + Абнаўленні праграмы + Абнаўленні пашырэнняў + Папярэдняя старонка + Наступная старонка + Праглядзець нядаўна абноўленыя ў бібліятэцы + Віджэт недаступны, калі ўключана блакіроўка праграмы + Вы збіраецеся прыбраць «%s» са сваёй бібліятэкі + HTTP %d: праверце сайт у WebView + Няма інтэрнэт-злучэння + Не ўдалося далучыцца да %s + Спадабалася частка, дзе… + Выбрана + Даступна + Выбраць усё + Нічога не выбіраць + Выбраць уключаныя крыніцы + Выбраць замацаваныя крыніцы + Працягнуць + Даныя для мігравання + Выдаліць спампоўкі бягучага твора пасля міграцыі + Дадатковыя ключавыя словы (неабавязкова) + Дапамагае звузіць пошук праз дадатковыя ключавыя словы + Хаваць творы без супадзенняў + Хаваць творы без новых раздзелаў + Паказваць толькі пры наяўнасці дадатковых раздзелаў + Гэтыя параметры марудныя, небяспечныя і могуць прывесці да блакіровак + Пашыраны глыбокі пошук + Разбівае назву на ключавыя словы для пашырэння пошуку + Супадзенне па колькасці раздзелаў + Выбірае супадзенне з найбольшай колькасцю раздзелаў. Інакш — па прыярытэце крыніцы. + Міграцыя + Міграцыя (%1$d/%2$d) + Скапіяваць + Міграваць + Альтэрнаціў не знойдзена + Апошні: %1$s + Невядома + Шукаць уручную + Не міграваць + Міграваць зараз + Скапіяваць зараз + Спыніць міграванне? + Спыніць + Скапіяваць + Міграваць + Няма раздзелаў, твор не падыходзіць для міграцыі diff --git a/i18n/src/commonMain/moko-resources/bg/strings.xml b/i18n/src/commonMain/moko-resources/bg/strings.xml index 3208bc2350..6b23be1222 100644 --- a/i18n/src/commonMain/moko-resources/bg/strings.xml +++ b/i18n/src/commonMain/moko-resources/bg/strings.xml @@ -400,7 +400,6 @@ Неизвестен автор Нямате отметнати източници Търси „%1$s“ глобално - Обновена до v%1$s Какво е новото Не сте влезли като потребител в: Позволи изтриване на отметнати глави @@ -618,7 +617,6 @@ Версия В хиатус Корица по избор - %1$d провалени обновление/я Търсене… Деактивирано Натисни, за да научиш повече diff --git a/i18n/src/commonMain/moko-resources/bn/strings.xml b/i18n/src/commonMain/moko-resources/bn/strings.xml index a297619430..1b1ef81184 100644 --- a/i18n/src/commonMain/moko-resources/bn/strings.xml +++ b/i18n/src/commonMain/moko-resources/bn/strings.xml @@ -410,7 +410,6 @@ পড়ার ইতিহাসে বিরতি দেয় ছদ্মবেশী মোড শুধু ডাউনলোড - v%1$s এ আপডেট হয়েছে সংস্করণ যাচাই ওপেন সোর্স লাইসেন্স নতুন কি @@ -551,7 +550,6 @@ এড়িয়ে যাওয়া হয়েছে কারণ সিরিজটি সম্পূর্ণ বাতিল করা হয়েছে বিরতিতে রয়েছে - %1$d আপডেট(গুলি) ব্যর্থ হয়েছে সম্পূর্ণ প্রকাশিত সর্বশেষ হালনাগাদ চেক আপনি কি “%s” ক্যাটাগরিটি মুছে ফেলতে চান? @@ -687,7 +685,6 @@ সাদা আর কালো যদি রিডার একটি ফাঁকা ছবি লোড করে, ধাপে ধাপে থ্রেশহোল্ড কমিয়ে দিন।\nসিলেক্টেড %s পারফরম্যান্স অ্যাফেক্ট করবে। ফাঁকা ইমেজ সমস্যা থ্রেশহোল্ড কমিয়ে ঠিক না হলে কেবল এনেবল করবে - ডোনেট অটোমেটিক ডাউনলোড, আগাম ডাউনলোড ওয়ান-ওয়ে প্রগ্রেস সিঙ্ক, এনহ্যান্সড সিঙ্ক সোর্স, এক্সটেনশন, গ্লোবাল সার্চ diff --git a/i18n/src/commonMain/moko-resources/ca/strings.xml b/i18n/src/commonMain/moko-resources/ca/strings.xml index a0e4c37bf5..9c903a3251 100644 --- a/i18n/src/commonMain/moko-resources/ca/strings.xml +++ b/i18n/src/commonMain/moko-resources/ca/strings.xml @@ -386,7 +386,6 @@ Estat desconegut Autor desconegut Cerca «%1$s» globalment - S’ha actualitzat a la v%1$s Novetats Cal reiniciar l’aplicació perquè tingui efecte Xarxa @@ -562,7 +561,6 @@ S’ha omès perquè no hi ha cap capítol llegit S’ha omès perquè hi ha capítols no llegits Premeu per a obtenir més informació - Han fallat %1$d actualitzacions Vertical inversa Mou la sèrie a dalt de tot Desactivat @@ -833,7 +831,6 @@ Monocrom Llista de la biblioteca Segueix de manera privada - Dóna Capítols no llegits Notes Edita les notes diff --git a/i18n/src/commonMain/moko-resources/ceb/strings.xml b/i18n/src/commonMain/moko-resources/ceb/strings.xml index 05e96a8894..108386501a 100644 --- a/i18n/src/commonMain/moko-resources/ceb/strings.xml +++ b/i18n/src/commonMain/moko-resources/ceb/strings.xml @@ -419,7 +419,6 @@ Incognito mode Bersyon Susiha ang mga update - Mga update sa v%1$s Ipadala ang mga taho sa pagkahagsa Naka-log out ka na karon Password diff --git a/i18n/src/commonMain/moko-resources/cs/strings.xml b/i18n/src/commonMain/moko-resources/cs/strings.xml index b16b0e822a..9dfe09b97a 100644 --- a/i18n/src/commonMain/moko-resources/cs/strings.xml +++ b/i18n/src/commonMain/moko-resources/cs/strings.xml @@ -332,7 +332,6 @@ Pozastaví historii čtení Anonymní režim Pouze staženo - Aktualizováno na verzi v%1$s Zkontrolovat aktualizace Open Source licence Co je nového @@ -558,7 +557,6 @@ Zobrazit položku Mřížka jen s přebaly Přeskočit nerozečtené položky - %1$d aktualizace(í) selhalo Má pauzu Přeskočeno, protože obsahuje nepřečtené kapitoly Přesunout sérii na začátek @@ -860,7 +858,6 @@ Nepodařilo se vytvořit adresář: %s Chystáte se odstranit položky z databáze Ponechat položky s přečtenými kapitolami - Přispěj Catppuccin Skrýt indikátory chybějících kapitol Nepovolovat soubory s non-ASCII znaky @@ -868,7 +865,6 @@ Souběžné stahování zdrojů Souběžné stahování stránek Zavřít okno - Vypočítávání… Souběžně stahované stránky na zdroj Vybrat vše Vybrat žádné diff --git a/i18n/src/commonMain/moko-resources/cv/strings.xml b/i18n/src/commonMain/moko-resources/cv/strings.xml index 20caa2115c..17a4bc4a3d 100644 --- a/i18n/src/commonMain/moko-resources/cv/strings.xml +++ b/i18n/src/commonMain/moko-resources/cv/strings.xml @@ -391,7 +391,6 @@ Вулавӑша йантӑлавран тавӑр Йантӑлав тавӑр Йантӑлав ту - v%1$s верссиччен ҫӗнетнӗ Мӗн ҫӗнни Темӗ Хушни вӑхӑчӗпе diff --git a/i18n/src/commonMain/moko-resources/de/plurals.xml b/i18n/src/commonMain/moko-resources/de/plurals.xml index 619f1feb02..80586f0c58 100644 --- a/i18n/src/commonMain/moko-resources/de/plurals.xml +++ b/i18n/src/commonMain/moko-resources/de/plurals.xml @@ -88,4 +88,8 @@ Ein Eintrag wurde übersprungen %1$d Einträge wurden übersprungen + + %1$d Aktualisierung ist fehlgeschlagen + %1$d Aktualisierungen sind fehlgeschlagen + diff --git a/i18n/src/commonMain/moko-resources/de/strings.xml b/i18n/src/commonMain/moko-resources/de/strings.xml index 36b77d18be..aa1d309fd2 100644 --- a/i18n/src/commonMain/moko-resources/de/strings.xml +++ b/i18n/src/commonMain/moko-resources/de/strings.xml @@ -393,7 +393,6 @@ Unbekannter Status Unbekannter Autor - Auf v%1$s aktualisiert Was ist neu Herunterladen von Kapiteln aufgrund von zu wenig Speicherplatz nicht möglich Überall nach „%1$s“ suchen @@ -564,7 +563,6 @@ Übersprungen, da die Serie abgeschlossen ist Übersprungen, weil es ungelesene Kapitel gibt Übersprungen, weil keine Kapitel gelesen wurden - %1$d Aktualisierung(en) fehlgeschlagen Antippen, um mehr zu erfahren Umgekehrtes Hochformat Serie nach oben verschieben @@ -901,7 +899,6 @@ Abbrechen Abbrechen Keine Kapitel gefunden, dieser Eintrag konnte nicht für eine Migration verwendet werden - Spenden Bilder in Mangabeschreibungen anzeigen Nicht-ASCII-Dateinamen nicht zulassen Versichert Kompatibilität mit bestimmten Speichermedien, die Unicode nicht unterstützen. Ist diese Option aktiviert, müssen Quellen- und Manga-Ordner manuell umbenannt werden, indem Nicht-ASCII-Zeichen durch ihre UTF-8-Hexadezimaldarstellungen in Kleinbuchstaben ersetzt werden. Kapiteldateien müssen nicht umbenannt werden. @@ -910,6 +907,18 @@ Pro Quelle gleichzeitig heruntergeladene Seiten Tab schließen Ausgeschlossene Scanlationgruppen herausfiltern - Wird berechnet… Mit Lesezeichen versehen + Unterstütze Uns + Unterstützende erhalten Zugang zu exklusiven Kanälen. Weitere Vorteile folgen. + Patreon (bevorzugt) + OpenCollective + Mihon wird aktuell von %d+ Personen unterstützt. Wir bedanken uns bei euch allen. Lasst uns Mihon gemeinsam noch besser machen. + Trete unserem Discord-Server für alternative Optionen oder bei weiteren Fragen bei. + Discord + Gefällt dir die App? + Hi! Ich bin der Hauptentwickler von Mihon und möchte darum bitten, die Entwicklung finanziell zu unterstützen. Mit genügend Unterstützung werde ich in der Lage sein, in Vollzeit an Mihon zu arbeiten und sowohl langjährige Probleme zu beheben als auch häufig gewünschte Features zu implementieren. + Du kannst entweder mittels Patreon (bevorzugt) oder OpenCollective spenden. Wenn du Fragen hast oder auf anderem Wege die Entwicklung unterstützen möchstest, dann kannst du mich gerne über Mihons Discord-Server erreichen. + Unabhängig davon wird Mihon weiterhin von mir und anderen Freiwilligen entwickelt werden und bleibt Open-Source-Software. + Discord + Verwerfen diff --git a/i18n/src/commonMain/moko-resources/el/plurals.xml b/i18n/src/commonMain/moko-resources/el/plurals.xml index 3debd74758..c627de2897 100644 --- a/i18n/src/commonMain/moko-resources/el/plurals.xml +++ b/i18n/src/commonMain/moko-resources/el/plurals.xml @@ -88,4 +88,8 @@ Μια καταχώρηση παραλείφθηκε %1$d καταχωρήσεις παραλείφθηκαν + + %1$d ενημέρωση απέτυχε + %1$d ενημερώσεις απέτυχαν + diff --git a/i18n/src/commonMain/moko-resources/el/strings.xml b/i18n/src/commonMain/moko-resources/el/strings.xml index 5860a3eb9b..5d0b2decc3 100644 --- a/i18n/src/commonMain/moko-resources/el/strings.xml +++ b/i18n/src/commonMain/moko-resources/el/strings.xml @@ -393,7 +393,6 @@ Αντιστροφή ζωνών πατήματος Άγνωστη κατάσταση Άγνωστος συγγραφέας - Ενημερώθηκε σε v%1$s Τι νέο υπάρχει Δεν ήταν δυνατή η λήψη κεφαλαίων λόγω χαμηλού αποθηκευτικού χώρου Αναζήτηση του \"%1$s\" καθολικά @@ -564,7 +563,6 @@ Παραλείφθηκε επειδή η σειρά ολοκληρώθηκε Παραβλέφθηκε επειδή υπάρχουν μη αναγνωσμένα κεφάλαια Παραλείπεται επειδή δεν έχουν διαβαστεί κεφάλαια - %1$d ενημέρωση(ες) απέτυχε(-αν) Πατήστε για να μάθετε περισσότερα Αντίστροφο πορτρέτο Μετακίνηση σειράς προς τα πάνω @@ -901,7 +899,6 @@ Κρατήστε καταχωρήσεις με αναγνωσμένα κεφάλαια Αποτυχία δημιουργίας καταλόγου λήψης Αποτυχία δημιουργίας καταλόγου: %s - Δωρεά Αναπαράσταση εικόνων σε περιγραφές manga Απαγόρευση μη ASCII ονομάτων αρχείων Εξασφαλίζει συμβατότητα με ορισμένα μέσα αποθήκευσης που δεν υποστηρίζουν Unicode. Όταν αυτή η επιλογή είναι ενεργοποιημένη, θα πρέπει να μετονομάσετε χειροκίνητα τους φακέλους πηγής και manga, αντικαθιστώντας τους χαρακτήρες που δεν είναι ASCII με τις μικρές κεφαλαίες δεκαεξαδικές αναπαραστάσεις UTF-8. Τα αρχεία κεφαλαίων δε χρειάζεται να μετονομάζονται. @@ -909,7 +906,7 @@ Ταυτόχρονες λήψεις πηγών Ταυτόχρονες λήψεις σελίδων Σελίδες που λήφθηκαν ταυτόχρονα ανά πηγή - Υπολογισμός… Προστέθηκε στους σελιδοδείκτες Φιλτράρισμα εξαιρούμενων scanlator + Υποστηρίξτε μας diff --git a/i18n/src/commonMain/moko-resources/eo/strings.xml b/i18n/src/commonMain/moko-resources/eo/strings.xml index 0fe38264c8..53a5659a14 100644 --- a/i18n/src/commonMain/moko-resources/eo/strings.xml +++ b/i18n/src/commonMain/moko-resources/eo/strings.xml @@ -297,7 +297,6 @@ Ensaluti Ensaluti al %1$s Nur elŝutitaj - Ĝisdatigita al v%1$s Malfermitkodaj permesiloj Kio novas Versio @@ -815,7 +814,6 @@ Averto: grandaj amasaj elŝutoj povas igi fontojn fariĝi pli malrapidaj kaj/aŭ bloki %s. Tuŝetu por ekscii pli. Ĝisdatigado de biblioteko… (%s) Grandaj ĝisdatigoj povas damaĝi fontojn kaj konduki al pli malrapidaj ĝisdatigoj kaj pliigan baterian uzadon. Tuŝetu por ekscii pli. - %1$d ĝisdatigo(j) fiaskis Tuŝetu por ekscii pli Bonvolu aldoni la elementon al via biblioteko antaŭ ol fari tion Por helpo pri kiel ripari erarojn de bibliotekaj ĝisdatigoj, vidu %1$s @@ -889,7 +887,6 @@ Nuligi Nuligi Neniu ĉapitro trovita, ĉi tiu elemento ne povas esti uzota por migri - Donacu Katpuĉino Montri bildojn en mangaaj priskriboj Kaŝi mankantajn ĉapitrajn indikilojn @@ -901,6 +898,5 @@ Kunrulaj elŝutoj de paĝoj Paĝoj elŝutitaj sammomente por fonto Filtri ekskluzivitajn skantradukistojn - Kalkulado… Legosignita diff --git a/i18n/src/commonMain/moko-resources/es/plurals.xml b/i18n/src/commonMain/moko-resources/es/plurals.xml index 3ea0549b14..2ebe657577 100644 --- a/i18n/src/commonMain/moko-resources/es/plurals.xml +++ b/i18n/src/commonMain/moko-resources/es/plurals.xml @@ -110,4 +110,9 @@ ¿Migrar estos %1$d elementos? ¿Migrar estos %1$d elementos? + + No se ha podido actualizar %1$d elemento + No se han podido actualizar %1$d elementos + No se han podido actualizar %1$d elementos + diff --git a/i18n/src/commonMain/moko-resources/es/strings.xml b/i18n/src/commonMain/moko-resources/es/strings.xml index 76a50fc2c4..ce3c986190 100644 --- a/i18n/src/commonMain/moko-resources/es/strings.xml +++ b/i18n/src/commonMain/moko-resources/es/strings.xml @@ -391,7 +391,6 @@ No invertir Invertir zonas de toque Autor desconocido - Actualizado a v%1$s Novedades No se pudo descargar ningún capítulo, queda muy poco espacio Buscar por «%1$s» en todas las fuentes @@ -563,7 +562,6 @@ Omitido porque todavía hay capítulos sin leer Omitido porque no hay capítulos leídos Ver más detalles - Actualizaciones fallidas: %1$d En vertical, al revés Mover al primer puesto Desactivado @@ -894,7 +892,6 @@ Migrando (%1$d/%2$d) Migrar ahora Ocultar los indicadores de capítulos que falten - Donar Ver imágenes en las descripciones de manga Prohibir los nombres de archivo que no sean ASCII Permite guardar tus datos en ciertos tipos de almacenamiento que no admitan Unicode. Al activarlo tendrás que renombrar las carpetas de tus fuentes y manga, pasándolas a representaciones UTF-8 en hexadecimal en minúscula. No tienes que hacer lo mismo con las carpetas de capítulos. @@ -903,6 +900,18 @@ Cantidad de páginas a descargar simultáneamente desde cada fuente remota Cerrar pestaña Ocultar equipos de traducción excluidos - Calculando… Favoritos + Apóyanos + Los patrocinadores obtienen acceso a canales exclusivos, con más beneficios por venir. + Patreon (preferido) + OpenCollective + Mihon cuenta actualmente con el apoyo de %d+ patrocinadores. Queremos agradecerles a cada uno de ustedes. Hagamos Mihon aún mejor juntos. + Para opciones alternativas o cualquier pregunta relacionada, únete a nuestro servidor de Discord. + Discord + ¿Disfrutando la aplicación? + ¡Hola! Soy el desarrollador principal de Mihon, y me gustaría pedirte que consideres apoyar su desarrollo económicamente. Con suficiente apoyo, podré trabajar en Mihon a tiempo completo y centrarme en problemas antiguos, así como en funciones muy solicitadas. + Puedes donar a través de Patreon (preferido) o OpenCollective. Si tienes preguntas o prefieres apoyar usando otros métodos, no dudes en contactarme a través del servidor de Discord de Mihon. + De todas formas, Mihon seguirá siendo mantenido por mí y los voluntarios, y se mantendrá como código abierto. + Descartar + Discord diff --git a/i18n/src/commonMain/moko-resources/eu/plurals.xml b/i18n/src/commonMain/moko-resources/eu/plurals.xml index 55139ec509..2e4dd708e6 100644 --- a/i18n/src/commonMain/moko-resources/eu/plurals.xml +++ b/i18n/src/commonMain/moko-resources/eu/plurals.xml @@ -48,4 +48,24 @@ %1$s kapituluak eta bat gehiago %1$s kapituluak eta %2$d gehiago + + Bihar + %1$d egunetan + + + Irakurri gabeko hurrengo kapitulua + Irakurri gabeko hurrengo %d kapituluak + + + Egun 1 + %d egun + + + Orri 1 + %1$s orri + + + Hurrengo kapitulua + Hurrengo %d kapituluak + diff --git a/i18n/src/commonMain/moko-resources/eu/strings.xml b/i18n/src/commonMain/moko-resources/eu/strings.xml index 9951193e9a..53a1b246cc 100644 --- a/i18n/src/commonMain/moko-resources/eu/strings.xml +++ b/i18n/src/commonMain/moko-resources/eu/strings.xml @@ -169,7 +169,6 @@ Itzali Nabigazioa U - v%1$s-ra eguneratua Saioa hasia Itxi saioa %1$s-n? Liburutegira gehitua @@ -223,11 +222,7 @@ Ez da aurkitu fitxategiak hautatzeko aplikaziorik Denak Fabrikatzaile batzuek aplikazioen murrizketa gehigarriak dituzte, atzeko planoko zerbitzuak akabatzen dituztenak. Webgune honek informazio gehiago du nola konpondu jakiteko. - Luzapen hau fidagarria ez den ziurtagiri batekin sinatu zen eta ez zen aktibatu. -\n -\nLuzapen maltzur batek Mihon-n gordetako saio-hasierako kredentzialak irakur ditzake edo kode arbitrarioa exekutatu. -\n -\nZiurtagiri honetaz fidatzean, arrisku hauek onartzen dituzu. + Luzapen maltzurrek gordetako edozein saio kredentzialak irakur ditzake edota kode arbitrarioa exekutatu.\n\nLuzapen honetaz fidatzen bazara, arrisku horiek onartzen dituzu. Fidatu gabekoa Atzeko planoaren kolorea Eguneratu @@ -601,4 +596,23 @@ Ezarri denbora-bitartea Datu eta memoria Azkenengo egunearatze egiaztapena + Inoiz ez + Ausaz + Artista + Aplikazioa gustoko duzu? + Kaixo! Mihonen atzean dagoen garatzaile nagusia naiz, eta haren garapena ekonomikoki babestea aztertzeko eskatu nahi nizuke. Laguntza nahikoarekin, Mihonen denbora osoz lan egin ahal izango dut eta arazo zaharretan zein oso eskatutako funtzioetan zentratu ahal izango naiz. + Patreon (hobetsia) edo OpenCollective bitartez dirua eman dezakezu. Galderarik baduzu edo beste metodo batzuk erabiliz lagundu nahi baduzu, jar zaitez nirekin harremanetan Mihonen Discord zerbitzariaren bitartez. + Nolanahi ere, Mihon boluntarioek eta nik mantentzen jarraituko dugu, eta kode irekikoa izaten jarraituko du. + Discord + Baztertu + Mezenasek kanal esklusiboetarako sarbidea lortzen dute, abantaila gehiagorekin etorkizunean. + Patreon (hobetsia) + OpenCollective + Gaur egun %d+ mezenasek babesten dute Mihon. Eskerrak eman nahi dizkizuegu guztioi. Mihon are hobea egin dezagun elkarrekin. + Aukera alternatiboak edo lotutako edozein zalantza argitzeko, gure Discord zerbitzarian sartu. + Discord + Lagun iezaguzu + Etorkizunean + %s desblokeatu + Esteka kopiatu diff --git a/i18n/src/commonMain/moko-resources/fa/strings.xml b/i18n/src/commonMain/moko-resources/fa/strings.xml index 9baa5b38ba..6b50df251d 100644 --- a/i18n/src/commonMain/moko-resources/fa/strings.xml +++ b/i18n/src/commonMain/moko-resources/fa/strings.xml @@ -399,7 +399,6 @@ تم غیرفعال کردن تاریخ اضافه شدن - به نسخه v%1$s آپدیت شد جست و جوی تنضیمات قسمت های دانلود شده مانگاهای کتابخانه @@ -602,7 +601,6 @@ به دلیل این که این مجموعه نیازی به به روز رسانی نداشت رد شد به دلیل وجود چپتر های خوانده نشده رد شد به دلیل این که هیچ چپتری خوانده نشده بود رد شد - %1$d بروز رسانی ناموفق \"%1$s\" به جای \"%2$s\" صفحات عریض را بچرخان تا جا شوند محبوب diff --git a/i18n/src/commonMain/moko-resources/fi/plurals.xml b/i18n/src/commonMain/moko-resources/fi/plurals.xml index 7fa9a44aea..93467b5042 100644 --- a/i18n/src/commonMain/moko-resources/fi/plurals.xml +++ b/i18n/src/commonMain/moko-resources/fi/plurals.xml @@ -52,4 +52,16 @@ Seuraava lukematon luku Seuraavat %d lukematonta lukua + + Huomenna + %1$d:n päivän päästä + + + 1 päivä + %d päivää + + + 1 sivu + %1$s sivua + diff --git a/i18n/src/commonMain/moko-resources/fi/strings.xml b/i18n/src/commonMain/moko-resources/fi/strings.xml index 1e6e4acd60..f1a738991e 100644 --- a/i18n/src/commonMain/moko-resources/fi/strings.xml +++ b/i18n/src/commonMain/moko-resources/fi/strings.xml @@ -393,7 +393,6 @@ Käännä näpäyttäminen Tuntematon tila Tuntematon tekijä - Päivitetty versioon v%1$s Mitä uutta Lukuja ei voitu ladata vähäisen tallennustilan vuoksi Etsi \"%1$s\" globaalisesti @@ -571,7 +570,6 @@ Virhe tallentaessa kuvaa Kirjastoa ollaan jo päivitämässä Kirjasto päivitetty viimeksi: %s - %1$d päivitys(tä) epäonnistui Ohitettu, koska sarja on päättynyt Sinulla ei vielä ole kategorioita. Tauolla @@ -668,4 +666,5 @@ Automaattinen lataus, ennakkolataus Yksisuuntainen synkronointi, paranneltu synkronointi Kategoriat, globaalit päivitykset, luvun pyyhkäisy + Navigoi ylös diff --git a/i18n/src/commonMain/moko-resources/fil/plurals.xml b/i18n/src/commonMain/moko-resources/fil/plurals.xml index 5cf2086a3f..a727a509a0 100644 --- a/i18n/src/commonMain/moko-resources/fil/plurals.xml +++ b/i18n/src/commonMain/moko-resources/fil/plurals.xml @@ -88,4 +88,8 @@ Isang entry ang nilaktawan %1$d (na) entry ang nilaktawan + + %1$d na update ay nabigo + %1$d na mga update ay nabigo + diff --git a/i18n/src/commonMain/moko-resources/fil/strings.xml b/i18n/src/commonMain/moko-resources/fil/strings.xml index c0b0b4249e..5d07554a95 100644 --- a/i18n/src/commonMain/moko-resources/fil/strings.xml +++ b/i18n/src/commonMain/moko-resources/fil/strings.xml @@ -225,7 +225,7 @@ I-restore ang backup Magagamit para ma-restore ang kasalukuyang aklatan Gumawa ng backup - Isahang pag-sync para mai-update ang progress sa mga kabanata sa mga external na tracking service. Ayusin ang pagta-track para sa mga indibidwal na entry gamit ang button na Pagta-track. + Isahang pag-sync para mai-update ang progress ng kabanata sa mga external na tracking service. Ayusin ang pagta-track para sa mga indibidwal na entry gamit ang button na Pagta-track. Mga Tracker I-update ang progress pagkatapos basahin I-download ang mga bagong kabanata @@ -367,7 +367,6 @@ Mga na-download lang Nakatutulong sa pag-ayos sa mga bug. Walang sensitibong data ang ipapadala Ipadala ang mga ulat ng pag-crash - Na-update sa v%1$s Maghanap ng update Mga lisensiyang open-source Anong bago @@ -565,7 +564,6 @@ Awtomatikong mag-zoom sa mga malalawak na larawan I-pan ang mga malalapad na larawan Matuto pa - Nabigo ang %1$d (na) update Baligtad na patayo Ilagay sa taas ang serye Nakasara @@ -650,7 +648,7 @@ Tatanggalin nito ang huling petsa na napili mo mula sa %s Aalisin nito ang dati mong napiling petsa ng pagtatapos mula sa %s Muling i-index ang mga download - Pilitin ang app na tingnan kung may naka-download + Pilitin ang app na tingnan kung may naka-download na kabanata Mga natapos na entry Nasimulan Lokal @@ -857,10 +855,10 @@ Panatilihin ang mga entry na may mga nabasang kabanata Mga nabasang kabanata at ang progress ng mga entry na wala sa aklatan ay mawawala Nagla-log in… - Nabigong lumikha ng direktory para sa pag-download - Nabigong lumikha ng direktory: %s - I-update ang mga pamagat ng manga ng aklatan upang tumugma sa source - Babala: kung ang isang manga ay pinalitan ng pangalan, ito ay aalisin sa pila ng mga download (kung mayroon). + Nabigong lumikha ng directory para sa pag-download + Nabigong lumikha ng directory: %s + I-update ang mga pamagat ng manga upang tumugma sa source + Babala: kung ang manga ay pinalitan ng pangalan, ito ay aalisin sa pila ng mga download (kung mayroon). Napili Piliin lahat Pumili ng wala @@ -900,7 +898,6 @@ Ihinto Itago ang mga indikasyon ng nawawalang kabanata I-render ang mga imahe sa mga paglalarawan ng manga - Mag-donate Di-payagan ang mga non-ASCII na filename Tinitiyak ang pagiging tugma sa ilang partikular na storage media na hindi sumusuporta sa Unicode. Kapag napagana ito, kakailanganin mong manu-manong palitan ang pangalan ng source at manga folder sa pamamagitan ng pagpapalit ng mga hindi ASCII na character ng kanilang lowercase na UTF-8 hexadecimal na representasyon. Hindi kailangang palitan ng pangalan ang mga file ng kabanata. Kasabay na pag-download ng source @@ -910,5 +907,18 @@ Catppuccin Maaaring Magamit I-filter ang na-ibukod na mga scanlator - Kinakalkula… + Na-bookmark + Suportahan Kami + Ang mga patron ay may access sa exclusive channels, at marami pang perks ang darating. + Patreon (mas mainam) + OpenCollective + Ang Mihon ay kasalukuyang sinusuportahan ng %d+ na patron. Nais naming pasalamatan ang bawat isa sa inyo. Sama-sama nating pagandahin pa lalo ang Mihon. + Para sa iba pang alternatibong opsyon o anumang mga katanungan, sumali sa aming Discord server. + Discord + Nasisiyahan ka ba sa paggamit ng app? + Kumusta! Ako ang main developer ng Mihon. Nais ko sanang humiling ng inyong suportang pinansyal para sa development nito. Sa sapat na suporta, magagawa kong pagtuunan ng panahon ang Mihon full-time at mabigyang-pansin ang mga dati pang isyu pati na ang mga feature na madalas ninyong hinihiling. + Maaari kang mag-donate sa pamamagitan ng Patreon (mas mainam) o OpenCollective. Kung mayroon kang mga katanungan o nais tumulong gamit ang ibang paraan, huwag mag-atubiling makipag-ugnayan sa akin sa Discord server ng Mihon. + Anuman ang mangyari, patuloy na itataguyod ang Mihon ko at ng mga volunteer, at mananatili itong open source. + Discord + Alisin diff --git a/i18n/src/commonMain/moko-resources/fr/strings.xml b/i18n/src/commonMain/moko-resources/fr/strings.xml index ba5a8f33cb..2d6bfa376c 100644 --- a/i18n/src/commonMain/moko-resources/fr/strings.xml +++ b/i18n/src/commonMain/moko-resources/fr/strings.xml @@ -394,7 +394,6 @@ Statut inconnu Auteur inconnu Quoi de neuf - Mise à jour de v%1$s Impossible de télécharger les chapitres, l\'espace de stockage est insuffisant Rechercher « %1$s » partout Date ajoutée @@ -565,7 +564,6 @@ Sauté car aucun chapitre n\'est lu Sauté car il y a des chapitres non lus Appuyez pour en savoir plus - Échec de %1$d mise(s) à jour Portrait inversé Déplacer la série vers le haut Désactivé @@ -901,7 +899,6 @@ Migrer Annuler Annuler - Donation Rendre les images dans les descriptions de mangas Fermer l\'onglet Interdire les noms de fichiers non ASCII diff --git a/i18n/src/commonMain/moko-resources/gl/strings.xml b/i18n/src/commonMain/moko-resources/gl/strings.xml index b8ba879553..cd5ab1b9c8 100644 --- a/i18n/src/commonMain/moko-resources/gl/strings.xml +++ b/i18n/src/commonMain/moko-resources/gl/strings.xml @@ -272,7 +272,6 @@ Procurar actualizacións Licenzas de código aberto Política de privacidade - Actualizado a v%1$s Axuda a corrixir os erros. Non se enviará ningunha información sensíbel Desactivar o modo incógnito Iniciar sesión @@ -606,7 +605,6 @@ Rematado: Páxina: %1$d Produciuse un erro ao gardar a imaxe - Actualizacións erradas: %1$d Descargar Actualizacións da aplicación Preme para saber máis diff --git a/i18n/src/commonMain/moko-resources/he/plurals.xml b/i18n/src/commonMain/moko-resources/he/plurals.xml index 03bd26a33d..ce9d6f171b 100644 --- a/i18n/src/commonMain/moko-resources/he/plurals.xml +++ b/i18n/src/commonMain/moko-resources/he/plurals.xml @@ -101,4 +101,4 @@ מחרותיים בעוד %1$d ימים - \ No newline at end of file + diff --git a/i18n/src/commonMain/moko-resources/he/strings.xml b/i18n/src/commonMain/moko-resources/he/strings.xml index c46b983903..1fdbe1fd50 100644 --- a/i18n/src/commonMain/moko-resources/he/strings.xml +++ b/i18n/src/commonMain/moko-resources/he/strings.xml @@ -524,7 +524,6 @@ WebView נצרך ל-Mihon רשת רק של הכריכות פתח את יומן האירועים - %1$d עדכונים נכשלו בצע קירוב לתמונות אופקיות באופן אוטומטי משפר את ביצועי מצב הקריאה דולג בגלל שהסדרה נגמרה @@ -682,7 +681,6 @@ לא מסוגל לפתוח את הפרק שנקרא לאחרונה פרק בהחלקה שמאלה לחיצה כפולה לקירוב (זום) - עודכן לגרסה %1$s בסך הכל שגיאה %1$s: %2$s עובד רק אם הפרק הנוכחי והפרק הבא כבר הורדו. diff --git a/i18n/src/commonMain/moko-resources/hi/strings.xml b/i18n/src/commonMain/moko-resources/hi/strings.xml index c7d5fe38e7..6d8937a4b1 100644 --- a/i18n/src/commonMain/moko-resources/hi/strings.xml +++ b/i18n/src/commonMain/moko-resources/hi/strings.xml @@ -398,7 +398,6 @@ नया क्या है कम संग्रहण स्थान के कारण अध्याय डाउनलोड नहीं कर सके विश्व स्तर पर \"%1$s\" के लिए खोजें - v%1$s तक अद्यतन पढ़न मोड थीम तारीख को जोड़ा गया @@ -567,7 +566,6 @@ केवल कवर ग्रिड अक्षम रिवर्स पोर्ट्रेट - %1$d अपडेट विफल चौड़ी छवियां पैन करें ज़ूम लैंडस्केप इमेज श्रृंखला को शीर्ष पर ले जाएं @@ -700,7 +698,6 @@ आपकी पुस्तकालय में एक समान नाम वाली प्रविष्टियाँ हैं।\n\nस्थानांतरित करने के लिए एक प्रविष्टि चुनें या फिर भी जोड़ें। %1$s अध्याय डाउनलोड, बैकअप और अन्य चीज़ों को संग्रहित करने के लिए एक फ़ोल्डर चुनें।\n\nएक समर्पित फ़ोल्डर उपयुक्त रहेगा।\n\nचयनित फ़ोल्डर: %2$s एक्सटेंशन स्थापित करने के लिए अनुमतियाँ आवश्यक हैं। अनुमति देने के लिए यहाँ टैप करें। - दान करें अनुप्रयोग संस्थापित करने की अनुमति स्रोत विस्तार संस्थापित करने हेतु। अधिसूचना अनुमति diff --git a/i18n/src/commonMain/moko-resources/hr/strings.xml b/i18n/src/commonMain/moko-resources/hr/strings.xml index b43baa934e..9d711d1a00 100644 --- a/i18n/src/commonMain/moko-resources/hr/strings.xml +++ b/i18n/src/commonMain/moko-resources/hr/strings.xml @@ -393,7 +393,6 @@ Preokreni područja za dodirivanje Nepoznato stanje Nepoznat autor - Aktualizirano na v%1$s Što je novo Neuspjelo preuzimanje poglavlja zbog nedovoljne memorije Traži „%1$s” globalno @@ -564,7 +563,6 @@ Preskočeno, jer je serija kompletna Preskočeno, jer nijedno poglavlje nije pročitano Preskočeno, jer postoje nepročitana poglavlja - Nauspjela aktualiziranja: %1$d Dodirni za daljnje informacije Preokreni uspravni format Premjesti seriju na vrh @@ -901,7 +899,6 @@ Najnovije: %1$s Nepoznato Nije pronađeno nijedno poglavlje. Ovaj se unos ne može koristiti za premještanje - Doniraj Iscrtaj slike u opisima manga Zabrani imena datoteka koji nisu u ASCII formatu Osigurava kompatibilnost s određenim medijima za spremanje podataka koji ne podržavaju Unicode. Kada je ova opcija aktivirana, morat ćeš ručno preimenovati izvor i mape s mangama zamjenjivanjem znakova koji nisu ASCII s njihovim UTF-8 heksadecimalnim vrijednostima (u malim slovima). Datoteke poglavlja se ne moraju preimenovati. @@ -909,7 +906,6 @@ Istovremena preuzimanja stranica Istovremeno preuzete stranice po izvoru Zatvori karticu - Izračunavanje … Filtriraj isključene amaterske prevoditelje Zabilježeno diff --git a/i18n/src/commonMain/moko-resources/hu/strings.xml b/i18n/src/commonMain/moko-resources/hu/strings.xml index 0f1f823e9d..22d061306b 100644 --- a/i18n/src/commonMain/moko-resources/hu/strings.xml +++ b/i18n/src/commonMain/moko-resources/hu/strings.xml @@ -510,7 +510,6 @@ Ez az Android verzió már nem támogatott Alkalmazás frissítések Nem sikerült megnyitni az utoljára olvasott fejezetet - Frissítve erre: v%1$s Széles képek pásztázása Mentés CBZ archívumkén Levendula @@ -538,7 +537,6 @@ Jelenlegi: Hát, ez kínos A nagy frissítések kárt okoznak a forrásoknak, és lassabb frissítésekhez, valamint megnövekedett akkumulátorhasználathoz vezethetnek. Koppintson további információért. - %1$d frissítés sikertelen Javítja az olvasó teljesítményét Nem bejelentkezett nyilvántartó: Inkognitó mód diff --git a/i18n/src/commonMain/moko-resources/in/strings.xml b/i18n/src/commonMain/moko-resources/in/strings.xml index b1651faafb..790da8cc24 100644 --- a/i18n/src/commonMain/moko-resources/in/strings.xml +++ b/i18n/src/commonMain/moko-resources/in/strings.xml @@ -391,7 +391,6 @@ Balikkan zona ketuk Status tidak diketahui Penulis tidak diketahui - Diperbarui ke v%1$s Apa yang baru Tidak dapat mengunduh bab karena ruang penyimpanan rendah Pencarian untuk \"%1$s\" secara global @@ -566,7 +565,6 @@ Geser gambar lebar Pelajari lebih lanjut Layar tegak terbalik - %1$d pembaruan gagal Pindahkan seri ke atas Dinonaktifkan Gagal menyimpan gambar @@ -853,7 +851,6 @@ Setelah mengambil bab baru Sembunyikan indikator bab yang hilang Gagal membuat direktori unduhan - Donasi Render gambar dalam deskripsi manga Gagal membuat direktori: %s Anda akan menghapus entri dari database diff --git a/i18n/src/commonMain/moko-resources/it/strings.xml b/i18n/src/commonMain/moko-resources/it/strings.xml index 8c0e44ee9f..f5b45adaef 100644 --- a/i18n/src/commonMain/moko-resources/it/strings.xml +++ b/i18n/src/commonMain/moko-resources/it/strings.xml @@ -387,7 +387,6 @@ Fonte non trovata Stato sconosciuto Autore sconosciuto - Aggiornato alla v%1$s Le novità Richiesto riavvio dell\'app per applicare le modifiche Rete @@ -564,7 +563,6 @@ Saltato perché la serie è completa Saltato perché ci sono capitoli non letti Saltato perché non ci sono capitoli letti - %1$d aggiornamento(i) fallito(i) Tocca per approfondire Verticale inverso Sposta la serie in cima @@ -707,7 +705,7 @@ Sincronizzazione libreria completata Sincronizzazione libreria Tocca qua per assistenza con Cloudflare - Indice dei download invalidato + Ricreando l\'indice dei download Login del trakcer Non è stato possibile creare un file di backup HTTP %d, controlla il sito nella WebView @@ -733,7 +731,7 @@ Altre opzioni Selezionato Non selezionato - Scanlator + Traduttore Salta Prossimo Uso della batteria in secondo piano @@ -850,7 +848,7 @@ Lista libreria Libreria esportata Metti in pausa la cronologia di lettura per l\'estensione - Aggiorna i titoli della libreria perchè coincidano con la fonte + Aggiorna i titoli della libreria perché coincidano con la fonte Attenzione: se un manga viene rinominato, sarà rimosso dalla coda download (se presente). Autenticazione in corso… Possibili duplicati @@ -869,7 +867,6 @@ Creazione della cartella download fallita Creazione della cartella %s fallita Mi è piaciuta la parte dove… - Dona Chiudi scheda Renderizza immagini nella descrizioni dei manga Nascondi gli indicatori dei capitoli mancanti @@ -909,4 +906,6 @@ Annulla Annulla Nessun capitolo trovato, questa voce non può essere utilizzata per la migrazione + Segnato + Filtrare i scanlator esclusi diff --git a/i18n/src/commonMain/moko-resources/ja/strings.xml b/i18n/src/commonMain/moko-resources/ja/strings.xml index ec568159ed..bdb5c4e199 100644 --- a/i18n/src/commonMain/moko-resources/ja/strings.xml +++ b/i18n/src/commonMain/moko-resources/ja/strings.xml @@ -13,7 +13,7 @@ バックアップと復元 設定 絞り込む - お気に入り + ブックマーク済み 未読 フィルタを削除 アルファベット順 @@ -393,7 +393,6 @@ 変更を適用するには再起動してください ネットワーク タップでのページめくりを反転 - v%1$sに更新しました 更新情報 読み方 完了 @@ -565,7 +564,6 @@ 読了した章がない為スキップしました 幅広い画像を左右に移動 タップでもっと詳しく - %1$d件の更新に失敗しました 縦向き (反転) シリーズをトップに移動 無効 @@ -852,8 +850,7 @@ 非図書館エントリの章の読み取りと進捗は失われます 読み終えた章を含むエントリーを保持する 重複の可能性 - 寄付する - 自動車 + 自動 キャットプッチン モノクロ マンガの描写で画像をレンダリングする @@ -875,4 +872,5 @@ 有効なソースを選択 固定されたソースを選択 移行するデータ + ブックマーク済み diff --git a/i18n/src/commonMain/moko-resources/jv/strings.xml b/i18n/src/commonMain/moko-resources/jv/strings.xml index 8bb0d7e209..d602994fd6 100644 --- a/i18n/src/commonMain/moko-resources/jv/strings.xml +++ b/i18n/src/commonMain/moko-resources/jv/strings.xml @@ -308,7 +308,6 @@ Bakal muncul navigasi mendhuwur Diluru - Sumbangan Otomatis Bikak kunci %s Trapake jeda wayah diff --git a/i18n/src/commonMain/moko-resources/ka-rGE/strings.xml b/i18n/src/commonMain/moko-resources/ka-rGE/strings.xml index a0a451f620..20520817da 100644 --- a/i18n/src/commonMain/moko-resources/ka-rGE/strings.xml +++ b/i18n/src/commonMain/moko-resources/ka-rGE/strings.xml @@ -393,7 +393,6 @@ უცნობი სტატუსი უცნობი ავტორი მოიძებნოს \"%1$s\"-თვის გლობალურად - განახლებულია v%1$s-მდე რა არის ახალი ასამოქმედებლად საჭიროა აპლიკაციის გადატვირთვა ქსელი diff --git a/i18n/src/commonMain/moko-resources/kk/plurals.xml b/i18n/src/commonMain/moko-resources/kk/plurals.xml index 88f5ca8073..926ab35fbc 100644 --- a/i18n/src/commonMain/moko-resources/kk/plurals.xml +++ b/i18n/src/commonMain/moko-resources/kk/plurals.xml @@ -64,4 +64,4 @@ Ертең %1$d күнде - \ No newline at end of file + diff --git a/i18n/src/commonMain/moko-resources/kk/strings.xml b/i18n/src/commonMain/moko-resources/kk/strings.xml index 0b9f99e821..165a0d11cd 100644 --- a/i18n/src/commonMain/moko-resources/kk/strings.xml +++ b/i18n/src/commonMain/moko-resources/kk/strings.xml @@ -403,7 +403,6 @@ Сұрыптау Нұсқа Open source лицензасы - %1$s дейін жаңартылды Жарамсыз тарау пішіні Күн Шығып жатыр @@ -509,7 +508,6 @@ Келесі: Сенімдісіз бе? Бар тарих жоғалады. Дереккөз табылмады - %1$d жаңарту сәтсіз өтті Мұқаба жаңартылмады Жаңа нұсқа қолжетімді! %d бет табылмады, бөлінгенде diff --git a/i18n/src/commonMain/moko-resources/kn/strings.xml b/i18n/src/commonMain/moko-resources/kn/strings.xml index 2527addc2a..a431e69d12 100644 --- a/i18n/src/commonMain/moko-resources/kn/strings.xml +++ b/i18n/src/commonMain/moko-resources/kn/strings.xml @@ -395,7 +395,6 @@ ಅಜ್ಞಾತ ಸ್ಥಿತಿ ಅಜ್ಞಾತ ಲೇಖಕ \"%1$s\" ಅನ್ನು ಗ್ಲೋಬಲ್ ಸರ್ಚ್ ಮಾಡಿ - v%1$s ಗೆ ಅಪ್ಡೇಟ್ ಆಗಿದೆ ಹೊಸತೇನಿದೆ ಅನ್ವಯಿಸಲು ಅಪ್ಲಿಕೇಶನ್ ಮರುಪ್ರಾರಂಭದ ಅಗತ್ಯವಿದೆ ಅಡ್ವಾನ್ಸ್ಡ್ ಸೆಕ್ಷನ್ diff --git a/i18n/src/commonMain/moko-resources/ko/plurals.xml b/i18n/src/commonMain/moko-resources/ko/plurals.xml index 0d1c7d0bef..31f6cae264 100644 --- a/i18n/src/commonMain/moko-resources/ko/plurals.xml +++ b/i18n/src/commonMain/moko-resources/ko/plurals.xml @@ -66,4 +66,7 @@ %1$d개 항목이 생략되었습니다 + + %1$d개 업데이트 실패 + diff --git a/i18n/src/commonMain/moko-resources/ko/strings.xml b/i18n/src/commonMain/moko-resources/ko/strings.xml index 11e84cf8ea..d3ebb3fd9c 100644 --- a/i18n/src/commonMain/moko-resources/ko/strings.xml +++ b/i18n/src/commonMain/moko-resources/ko/strings.xml @@ -298,7 +298,6 @@ 시크릿 모드 끄기 다운로드가 완료된 항목만 표시 시크릿 모드 - v%1$s 으로 업데이트 됨 업데이트 확인 오픈 소스 라이선스 디바이스 설정을 열 수 없습니다 @@ -465,7 +464,6 @@ 경고: 대량 다운로드는 원본 속도에 영향을 미치거나 %s을 차단할 수 있습니다. 탭하여 자세히 알아보기. 대규모 업데이트는 소스에 피해를 입히고 업데이트가 느려지고 배터리 사용량이 증가할 수 있습니다. 탭하여 자세히 알아보기. %1$s화 - %1$d개의 업데이트가 실패했습니다 서재 업데이트 오류를 해결하려면 %1$s를 참조하세요 완결된 만화를 건너 뛰었습니다 읽지 않은 만화를 건너 뛰었습니다 @@ -786,7 +784,6 @@ 사용가능: %1$s / 전체: %2$s Nord 곧 공개 - 기부 자동 무작위 링크 복사 @@ -909,5 +906,6 @@ 취소 챕터를 찾을 수 없어 이 항목은 마이그레이션에 사용할 수 없습니다 스캔레이터를 제외한 필터 - 계산 중… + 북마크됨 + 저희를 지원해 주세요 diff --git a/i18n/src/commonMain/moko-resources/lt/strings.xml b/i18n/src/commonMain/moko-resources/lt/strings.xml index 99bd76dd9c..f64dad45af 100644 --- a/i18n/src/commonMain/moko-resources/lt/strings.xml +++ b/i18n/src/commonMain/moko-resources/lt/strings.xml @@ -347,7 +347,6 @@ Priskirti šiai serijai Baigta: Dabartinis: - Nepavyko atnaujinti %1$d Prieš atlikdami šį veiksmą, pridėkite įrašą į savo biblioteką Praleista, nes nėra perskaitytų skyrių Nepavyko apeiti \"Cloudflare\" @@ -536,7 +535,6 @@ Atsisiųsti Data Kategorijos atnaujinimas - Atnaujinta į v%1$s Prisijunkite prie %1$s Rezultatų nerasta Vykdoma diff --git a/i18n/src/commonMain/moko-resources/lv/strings.xml b/i18n/src/commonMain/moko-resources/lv/strings.xml index 3af102ee96..20b508d4bd 100644 --- a/i18n/src/commonMain/moko-resources/lv/strings.xml +++ b/i18n/src/commonMain/moko-resources/lv/strings.xml @@ -6,7 +6,7 @@ Izsekošana Vēsture Iestatījumi - Lejupieladēšanas rinda + Lejupielādes rinda Bibliotēka Vēsture Atjauninājumi @@ -402,7 +402,6 @@ Tīmekļa vietne Versija Jaunumi - Atjaunināts uz v%1$s Atvērtā avota licences Pārbaudīt, vai nav atjauninājumu Notīrīt WebView datus @@ -556,7 +555,6 @@ Nodaļa %1$s Sadalīšanas laikā netika atrasta lapa %d Izlaists, jo ir nelasītas nodaļas - %1$d atjauninājums(-i) neizdevās Pieskarieties, lai uzzinātu vairāk Lietotnes atjauninājumi Ir pieejama jauna versija! diff --git a/i18n/src/commonMain/moko-resources/ml/strings.xml b/i18n/src/commonMain/moko-resources/ml/strings.xml index 944334eba3..0428034d0a 100644 --- a/i18n/src/commonMain/moko-resources/ml/strings.xml +++ b/i18n/src/commonMain/moko-resources/ml/strings.xml @@ -207,4 +207,17 @@ ലൈബ്രറി അപ്‌ഡേറ്റുകൾക്കും മറ്റും അറിയിപ്പ് നേടുക. പശ്ചാത്തല ബാറ്ററി ഉപയോഗം ദീർഘകാല ലൈബ്രറി അപ്‌ഡേറ്റുകൾ, ഡൗൺലോഡ്, ബാക്കപ്പ് പുനഃസ്ഥാപിക്കൽ എന്നിവയ്ക്കുള്ള തടസ്സങ്ങൾ ഒഴിവാക്കുക. + നിരസിക്കുക + നിരസിക്കുക + സ്ഥലാന്തരീകരിക്കുക + പകർത്തുക + നിരസിക്കുക + നിർത്തുക + സ്ഥലാന്തരീകരണം നിർത്തണോ? + അജ്ഞാതം + സ്ഥലാന്തരീകരിക്കുക + പകർത്തുക + സ്ഥലാന്തരീകരണം + തുടരുക + ലഭ്യം diff --git a/i18n/src/commonMain/moko-resources/ms/strings.xml b/i18n/src/commonMain/moko-resources/ms/strings.xml index 7d0e328dff..b8abb91efa 100644 --- a/i18n/src/commonMain/moko-resources/ms/strings.xml +++ b/i18n/src/commonMain/moko-resources/ms/strings.xml @@ -393,7 +393,6 @@ Songsangkan zon ketik Status tidak diketahui Pengarang tidak diketahui - Dikemas kini ke v%1$s Apa yang terbaharu Tarikh ditambah Memuat turun tidak berjaya kerana kekurangan ruang storan @@ -564,7 +563,6 @@ Dilangkau kerana tiada bab yang dibaca Zum secara automatik pada imej lebar Panorama imej lebar - %1$d kemas kini gagal Ketik untuk ketahui selebihnya Potret terbalik Alih siri ke atas @@ -792,7 +790,6 @@ Panduan yang akan datang Bulan depan Bulan sebelumnya - Menderma Otomatis Rawak Pautan salin diff --git a/i18n/src/commonMain/moko-resources/my/strings.xml b/i18n/src/commonMain/moko-resources/my/strings.xml index 6b57f782a5..b023054a81 100644 --- a/i18n/src/commonMain/moko-resources/my/strings.xml +++ b/i18n/src/commonMain/moko-resources/my/strings.xml @@ -292,6 +292,5 @@ ကန့်သက်မထားသော ကွန်ရက်ပေါ်တွင်သာ သင့်ဖုန်းမှ ဖယ်ရှားရန် Dynamic - လှူဒါန်း အလိုအလျောက် diff --git a/i18n/src/commonMain/moko-resources/nb-rNO/strings.xml b/i18n/src/commonMain/moko-resources/nb-rNO/strings.xml index a0525b959e..b898840975 100644 --- a/i18n/src/commonMain/moko-resources/nb-rNO/strings.xml +++ b/i18n/src/commonMain/moko-resources/nb-rNO/strings.xml @@ -409,7 +409,6 @@ Ikke nok lagringsplass til å laste ned kapitler Anvend også for allle oppføringer i biblioteket Søk etter \"%1$s\" globalt - Oppdatert til v%1$s Friprog-lisenser Hva er nytt Hjelper med oppdatering og sikkerhetskopiering av biblioteket @@ -565,7 +564,6 @@ Klarte ikke å hente tilgjengelige utvidelser Omvendt portrett Tøm kapittel hurtigbufferen ved oppstart av appen - %1$d oppdatering(er) mislyktes Trykk for å finne ut mer Hoppet over fordi ingen kapitler er lest Deaktivert diff --git a/i18n/src/commonMain/moko-resources/ne/strings.xml b/i18n/src/commonMain/moko-resources/ne/strings.xml index cf7d967df7..492897f6c0 100644 --- a/i18n/src/commonMain/moko-resources/ne/strings.xml +++ b/i18n/src/commonMain/moko-resources/ne/strings.xml @@ -169,7 +169,6 @@ डाउनलोड गरिएको मात्र कुनै पनि बगहरू ठीक गर्न मद्दत गर्दछ। कुनै संवेदनशील डेटा पठाइने छैन Crash रिपोर्ट पठाउनुहोस् - v%1$s मा अपडेट गरियो अपडेटका लागि जाँच गर्नुहोस् छवि लोड गर्न सकिएन अध्यायहरू डाउनलोड गर्न सकिएन। तपाईं डाउनलोड सूचीमा फेरि प्रयास गर्न सक्नुहुन्छ @@ -564,7 +563,6 @@ सुरु गर्ने गाइड चौडा छविहरू प्यान गर्नुहोस् फराकिलो छविहरूमा स्वचालित रूपमा जूम गर्नुहोस् - %1$d अपडेट(हरू) असफल भयो असक्षम पुस्तकालय अपडेट त्रुटिहरू कसरी समाधान गर्ने भन्ने बारे मद्दतको लागि, %1$s हेर्नुहोस् नपढिएको संख्या @@ -859,7 +857,6 @@ तपाईंको पुस्तकालयमा उस्तै नामका इन्ट्रीहरू छन्।\n\nस्थानान्तरण गर्न वा जे भए पनि थप्नको लागि इन्ट्री चयन गर्नुहोस्। तपाईं डाटाबेसबाट इन्ट्रीहरू हटाउन लाग्दै हुनुहुन्छ डाउनलोड directory सिर्जना गर्न असफल भयो - दान कात्पुचिन mangaको विवरणहरूमा तस्वीर देखाउनुहोस नभएको अध्यायहरु लुकौनुहोस diff --git a/i18n/src/commonMain/moko-resources/nl/plurals.xml b/i18n/src/commonMain/moko-resources/nl/plurals.xml index 44805cca4c..fcadb40b10 100644 --- a/i18n/src/commonMain/moko-resources/nl/plurals.xml +++ b/i18n/src/commonMain/moko-resources/nl/plurals.xml @@ -88,4 +88,8 @@ Een item werd overgeslagen %1$d items werden overgeslagen + + %1$d update mislukt + %1$d updates mislukt + diff --git a/i18n/src/commonMain/moko-resources/nl/strings.xml b/i18n/src/commonMain/moko-resources/nl/strings.xml index 05639387a0..5e1ee508ad 100644 --- a/i18n/src/commonMain/moko-resources/nl/strings.xml +++ b/i18n/src/commonMain/moko-resources/nl/strings.xml @@ -163,7 +163,7 @@ Selecteer back-upbestand Download Geen nieuwe updates beschikbaar - Download voltooid + Tik om update te installeren Nieuwe versie beschikbaar! Geen downloads Geen recente updates @@ -393,7 +393,6 @@ Onbekende auteur Kon hoofdstukken niet downloaden omdat er te weinig opslagruimte is Overal zoeken naar \"%1$s\" - Bijgewerkt naar v%1$s Wat is er nieuw Leesmodus Thema @@ -430,7 +429,7 @@ Geen bestandskiezer-app gevonden Log alstublieft opnieuw in op MAL Weergeven in bronnen- en extensielijst - Navigatie-indeling + Tikzones Rand Kindle-achtig L-vormig @@ -463,7 +462,7 @@ Items in uitgesloten categorieën worden niet bijgewerkt, zelfs niet als ze onder opgenomen categorieën vallen. Datum opgehaald Geen - Klik om details te weergeven + Tik om details weer te geven Deze Android versie wordt niet meer ondersteund Mislukt om naar het klemboord te kopiëren Incognitomodus uitschakelen @@ -554,8 +553,7 @@ Uitgave voltooid Geannuleerd Gepauzeerd - %1$d update(s) mislukt - Kom meer te weten + Tik om meer te leren Overgeslagen want er zijn geen ongelezen hoofdstukken Overgeslagen want er zijn geen gelezen hoofdstukken Zoom liggende afbeelding @@ -594,7 +592,7 @@ Werkt alleen als het huidige hoofdstuk en het volgende alreeds gedownload zijn. Standaard \'user-agent-string\' Zoek… - Opslag bevoegdheden niet verleent + Opslagrechten niet verleend Knop om lezen te hervatten weergeven Statistieken Gestart @@ -613,8 +611,7 @@ Kon leesinstellingen niet terugzetten naar standaardwaarden Populair Downloads worden gecontroleerd - F-Droid versies worden niet officieel ondersteund. -\nTik hier voor meer informatie. + F-Droid versies worden niet officieel ondersteund. \nTik om meer te leren. Dubbele hoofdstukken overslaan Weet je het zeker? Leeslijst @@ -676,7 +673,7 @@ Leesduur Schat elke Herstart de applicatie - Download Index geïnvalideerd + Downloadindex hermaken Herindexeer downloads OK Hoofdstuk bij links vegen @@ -720,7 +717,7 @@ Opslaggebruik Bibliotheek bijwerken... (%s) Data en opslag - Bestandskiezer gaf geen bestand terug aan de app + Geen bestand geselecteerd Bron-instellingen App-instellingen Relatieve tijdstempels @@ -732,7 +729,7 @@ Scanlator Toepassen Naar standaard terugkeren - Onboarding gids + Onboardinggids Welkom! Link kopiëren Vertrouwde onbekende extensies intrekken @@ -819,7 +816,6 @@ Duplicaat gelezen hoofdstuk als gelezen markeren Ongelezen hoofdstukken Monochroom - Doneer Geef afbeeldingen weer in mangabeschrijvingen Verberg ontbrekende hoofdstukindicatoren Verbied niet-ASCII-bestandsnamen @@ -887,4 +883,21 @@ Annuleer Annuleer Geen hoofdstukken gevonden. Dit item kan niet worden gebruikt voor migratie + Tabblad sluiten + Gelijktijdige brondownloads + Gelijktijdige paginadownloads + Gelijktijdig gedownloade pagina\'s per bron + Met bladwijzer + Filter uitgesloten scanlators + Catppuccin + Selecteer een map waarin %1$s hoofdstukdownloads, back-ups en meer zal opslaan.\n\nEen specifiek hiervoor bestemde map is aangeraden.\n\nGeselecteerde map: %2$s + App-installatierecht + Meldingsrecht + Achtergrondbatterijgebruik + Het verzenden van crashlogs en analytics zal ons toestaan om problemen te identificeren en op te lossen, performance te verbeteren en om toekomstige updates relevanter te maken voor jouw noden + Ondertekeningssleutelvingerafdruk bestaat al + Repo %1$s heeft dezelfde ondertekeningssleutelvingerafdruk als %2$s.\nAls dit verwacht is zal %2$s vervangen worden. Zo niet, neem dan contact op met de beheerder van uw repo. + Toekomstige Updatesgids + Kon geen permanente toegang tot map vergijken. De app kan zich onverwacht gedragen. + Beginnen diff --git a/i18n/src/commonMain/moko-resources/nn/strings.xml b/i18n/src/commonMain/moko-resources/nn/strings.xml index 32ec8d2242..c669f7343e 100644 --- a/i18n/src/commonMain/moko-resources/nn/strings.xml +++ b/i18n/src/commonMain/moko-resources/nn/strings.xml @@ -205,7 +205,6 @@ Hjelp med å omsetje Personvernerklæring Sjå etter oppdateringar - Oppdatert til v%1$s Inkognitomodus Brukarnamn E-postadresse diff --git a/i18n/src/commonMain/moko-resources/pl/plurals.xml b/i18n/src/commonMain/moko-resources/pl/plurals.xml index 2a86f3d90e..8ff20f65ae 100644 --- a/i18n/src/commonMain/moko-resources/pl/plurals.xml +++ b/i18n/src/commonMain/moko-resources/pl/plurals.xml @@ -114,4 +114,10 @@ %1$s stron %1$s stron - \ No newline at end of file + + %1$d aktualizacja się nie powiodła + %1$d aktualizacje się nie powiodły + %1$d aktualizacji się nie powiodły + %1$d aktualizacji się nie powiodły + + diff --git a/i18n/src/commonMain/moko-resources/pl/strings.xml b/i18n/src/commonMain/moko-resources/pl/strings.xml index c7307186ef..e2f1f04deb 100644 --- a/i18n/src/commonMain/moko-resources/pl/strings.xml +++ b/i18n/src/commonMain/moko-resources/pl/strings.xml @@ -397,7 +397,6 @@ Nieznany status Nieznany autor Szukaj \"%1$s\" globalnie - Zaktualizowano do v%1$s Co nowego Tryb czytania Motyw @@ -568,7 +567,6 @@ Pominięto, ponieważ brak przeczytanych rozdziałów Pominięto, ponieważ seria została ukończona Pominięto, ponieważ istnieją nieprzeczytane rozdziały - %1$d aktualizacja (aktualizacje) nie powiodła się Zamknij Przenieś serię na górę Ilość nieprzeczytanych @@ -843,4 +841,8 @@ Nie udało się utworzyć folderu pobierania Nie udało się utworzyć folderu: %s Eksportuj + Auto + Nieprzeczytane rozdziały + Catppucin + Zachowanie diff --git a/i18n/src/commonMain/moko-resources/pt-rBR/plurals.xml b/i18n/src/commonMain/moko-resources/pt-rBR/plurals.xml index e55abba583..b9b311fd63 100644 --- a/i18n/src/commonMain/moko-resources/pt-rBR/plurals.xml +++ b/i18n/src/commonMain/moko-resources/pt-rBR/plurals.xml @@ -3,7 +3,7 @@ Após %1$s minuto Após %1$s minutos - Após %1$s minuto + Após %1$s minutos %1$d capítulo novo @@ -108,6 +108,11 @@ 1 página %1$s páginas - + + + + %1$d atualização falhou + %1$d atualizações falharam + %1$d atualizações falharam diff --git a/i18n/src/commonMain/moko-resources/pt-rBR/strings.xml b/i18n/src/commonMain/moko-resources/pt-rBR/strings.xml index 9bb51d4df3..573bda8f92 100644 --- a/i18n/src/commonMain/moko-resources/pt-rBR/strings.xml +++ b/i18n/src/commonMain/moko-resources/pt-rBR/strings.xml @@ -116,10 +116,10 @@ Automática Retrato bloqueado Paisagem bloqueado - R - G - B - A + Vermelho + Verde + Azul + Alfa Após marcado como lido manualmente Excluir automaticamente após a leitura Desativado @@ -393,7 +393,6 @@ Inverter as zonas de toque Estado desconhecido Autor desconhecido - Atualizado para v%1$s O que há de novo Não foi possível fazer o download dos capítulos devido ao pouco espaço de armazenamento Data de inclusão @@ -564,7 +563,6 @@ Pulado porque a série está finalizada Pulado porque há capítulos não lidos Pulado porque nenhum capítulo foi lido - %1$d atualização(ões) falhou(aram) Toque para saber mais Retrato invertido Mover série para o começo @@ -578,7 +576,7 @@ Nenhuma fonte instalada foi encontrada Nenhuma fonte encontrada Contagem de não lidos - Ultima checagem de atualização + Última checagem de atualização Melhora o desempenho do leitor Página %d não encontrada durante a divisão Não foi possível encontrar o caminho do arquivo da página %d @@ -649,7 +647,7 @@ Remover data? Isto irá remover sua data de início selecionada anteriormente no %s Isto irá remover sua data de término selecionada anteriormente no %s - Invalidar o índice de downloads + Reindexar downloads Força o aplicativo a checar novamente por capítulos disponíveis offline Local Disponíveis offline @@ -687,7 +685,7 @@ Rotacionar páginas largas para caber Inverter a orientação das páginas largas rotacionadas Informações de depuração - Capitulo ao deslizar para a direita + Capítulo ao deslizar para a direita Ação de deslizar para a esquerda Toque duplo para dar zoom Próxima atualização esperada @@ -901,7 +899,12 @@ Editar anotações Anotações Catppuccin - Doar Fechar aba Renderizar imagens em descrições de mangá + Não permitir nomes de arquivos não ASCII + Garante a compatibilidade com determinadas mídias de armazenamento que não suportam Unicode. Quando esta opção estiver ativada, você precisará renomear manualmente as pastas de origem e de mangá, substituindo os caracteres não ASCII por suas representações hexadecimais UTF-8 em minúsculas. Os arquivos de capítulos não precisam ser renomeados. + Favoritos + Download simultâneo de páginas + Páginas baixadas simultâneamente por fonte + Filtrar grupo de traduções excluidos diff --git a/i18n/src/commonMain/moko-resources/pt/strings.xml b/i18n/src/commonMain/moko-resources/pt/strings.xml index 50034e17d4..d180f232df 100644 --- a/i18n/src/commonMain/moko-resources/pt/strings.xml +++ b/i18n/src/commonMain/moko-resources/pt/strings.xml @@ -391,7 +391,6 @@ Autor desconhecido Requer reinício da app para ter efeito Rede - Atualizado para v%1$s Novidades Não foi possível transferir capítulos devido a falta de espaço de armazenamento Procurar por \"%1$s\" globalmente @@ -568,7 +567,6 @@ Dados do WebView limpos Vertical invertido Nenhuma fonte instalada encontrada - %1$d actualização(ões) falhada(s) Toque para saber mais Imagens panorâmicas Ampliar imagem horizontal @@ -828,6 +826,5 @@ Artista Autor Equipa de tradução - Doar Capítulos não lidos diff --git a/i18n/src/commonMain/moko-resources/ro/strings.xml b/i18n/src/commonMain/moko-resources/ro/strings.xml index d85b623df9..c1f4d5d4be 100644 --- a/i18n/src/commonMain/moko-resources/ro/strings.xml +++ b/i18n/src/commonMain/moko-resources/ro/strings.xml @@ -393,7 +393,6 @@ Inversați zonele de atingere Stare necunoscută Autor necunoscut - Actualizat la v%1$s Ce este nou Nu s-au putut descărca capitole din cauza spațiului de stocare redus Căutați „%1$s” la nivel global @@ -500,7 +499,6 @@ Format de capitol invalid Atenție : actualizarile mari în masă vor face sursele mai incete și/sau vor bloca %s. Apăsați pentru mai multe informatii. Ghidul de inceput - %1$d actualizari esuate Ignorata deoarece sunt capitole necitite Nu există intrări în bibliotecă pentru a face backupuri Ștergeți categoria @@ -833,7 +831,6 @@ Afectează performanța. Activați numai dacă reducerea pragului bitmap nu rezolvă problemele legate de imaginile goale Automatic Întrerupeți istoricul de lectură pentru extensie - Donează Capitole necitite Notițe Editează notițe diff --git a/i18n/src/commonMain/moko-resources/ru/plurals.xml b/i18n/src/commonMain/moko-resources/ru/plurals.xml index d9ff94cf45..95a9556551 100644 --- a/i18n/src/commonMain/moko-resources/ru/plurals.xml +++ b/i18n/src/commonMain/moko-resources/ru/plurals.xml @@ -61,10 +61,10 @@ %d сервисов отслеживания - Отсутствует %d глава в источнике или была отфильтрована - Отсутствуют %d главы в источнике или были отфильтрованы - Отсутствуют %d глав в источнике или были отфильтрованы - Отсутствуют %d глав в источнике или были отфильтрованы + Была пропущена %d глава, поскольку она отсутствует в источнике или была отфильтрована + Были пропущены %d главы, поскольку они отсутствуют в источнике или были отфильтрованы + Было пропущено %d глав, поскольку они отсутствуют в источнике или были отфильтрованы + Было пропущено %d глав, поскольку они отсутствуют в источнике или были отфильтрованы Вчера @@ -132,4 +132,10 @@ Копировать %1$d серий? Копировать %1$d серий? + + %1$d ошибка обновления + %1$d ошибки обновлений + %1$d ошибок обновлений + %1$d ошибок обновлений + diff --git a/i18n/src/commonMain/moko-resources/ru/strings.xml b/i18n/src/commonMain/moko-resources/ru/strings.xml index 3e5e7427de..cd8aaffac2 100644 --- a/i18n/src/commonMain/moko-resources/ru/strings.xml +++ b/i18n/src/commonMain/moko-resources/ru/strings.xml @@ -393,7 +393,6 @@ Зоны касания наоборот Неизвестный статус Неизвестный автор - Обновлено до %1$s Что нового Не удалось загрузить главы из-за малого объема хранилища Искать \"%1$s\" глобально @@ -565,7 +564,6 @@ Пропущено, т.к есть непрочитанные главы Пропущено, т.к серия не начата Нажать для подробностей - %1$d обновление(ий) не удалось Портретная наоборот Переместить серию в начало Отключено @@ -902,7 +900,6 @@ Отменить Скрывать индикаторы отсутствующих глав Отрисововать изображения в описаниях серий - Спонсорство Не позволять наименования файлов в виде non-ASCII Обеспечивает совместимость с некоторыми носителями информации, которые не поддерживают Unicode. Когда этот функция включена, вам нужно будет вручную переименовать папки серий и источников, заменив non-ASCII символы на шестнадцатеричные UTF-8 в нижнем регистре. Файлы глав можно не переименовать. Параллельные загрузки с источников @@ -910,6 +907,18 @@ Параллельные загрузки страниц Число одновременных загрузок страниц с источника Фильтровать исключенных переводчиков - Вычисление… В закладках + Поддержите нас + Patreon (Предпочтительно) + OpenCollective + Mihon сейчас поддерживается %d+ Patreon-спонсорами. Мы хотим поблагодарить каждого из вас. Давайте сделаем Mihon лучше. + Discord + Patreon-спонсоры получать доступ к эксклюзивным каналам с будущими привилегиями и возможностями. + Discord + Нравится приложение? + Приветствую! Я главный разработчик Mihon и хотел бы попросить вас об финансовой поддержке проекта. При достаточной поддержке я смогу работать над Mihon в полную силу и сосредоточиться как на давно существующих проблемах, так и на функциях, которые пользователи уже давно просят добавить. + Вы можете поддержать проект через Patreon (Предпочтительно) или OpenCollective. Если у вас есть вопросы или хотите поддержать, используя другие способы, вы можете связаться со мной через Discord-сервер нашего приложения. + Независимо от поддержки, проект останется с открытым исходным кодом, и я с волонтёрами будем и дальше поддерживать это приложение. + Отклонить + Если у вас есть другие способы поддержки или вопросы по этому поводу, можете присоединиться к нашему Discord-серверу. diff --git a/i18n/src/commonMain/moko-resources/sa/plurals.xml b/i18n/src/commonMain/moko-resources/sa/plurals.xml index 4c1eec2956..1cddee9120 100644 --- a/i18n/src/commonMain/moko-resources/sa/plurals.xml +++ b/i18n/src/commonMain/moko-resources/sa/plurals.xml @@ -76,4 +76,4 @@ %1$s अध्यायः नास्ति %1$s अध्यायाः न सन्ति - \ No newline at end of file + diff --git a/i18n/src/commonMain/moko-resources/sa/strings.xml b/i18n/src/commonMain/moko-resources/sa/strings.xml index df87bd6384..eecbd02f05 100644 --- a/i18n/src/commonMain/moko-resources/sa/strings.xml +++ b/i18n/src/commonMain/moko-resources/sa/strings.xml @@ -428,7 +428,6 @@ उपयुक्तम् - %1$s निवेशाः नाशिताः नवीकरणेभ्यः मार्गतु - सं%1$s प्रति नवीकृतम् ईपत्रसङ्केतः अन्तर्गतम् बहिर्गच्छतु @@ -558,7 +557,6 @@ अध्यायानाम् अवारोपणं न अशक्नोत्। त्वया अवारोपितानि नाम्नः विभागे पुनः यतितुं शक्यते यस्मात् स्थानान्तरगमनं करणीयं तत् चिनोतु पूर्वसूचना -- मूलेभ्यः महद्नवीकरणानि हानिकारकाणि भवन्ति तस्मात् नवीकरणानि मन्दानि भवेयुः अपि च विद्युत्कोषोपयोगः अधिकं भवेत् - %1$d नवीकरणानि अनुत्तीर्णानि अधिकं जानातु धारावाहिकम् अग्रस्थानं चालयतु विपरीतं लम्बदर्शनम् diff --git a/i18n/src/commonMain/moko-resources/sah/strings.xml b/i18n/src/commonMain/moko-resources/sah/strings.xml index b6135d89d4..025e598ab2 100644 --- a/i18n/src/commonMain/moko-resources/sah/strings.xml +++ b/i18n/src/commonMain/moko-resources/sah/strings.xml @@ -269,7 +269,6 @@ Биэрсия Үөп сир Аһаҕас төрүттээх лицензиялар - v%1$s дылы саҥарданна Саҥардыы баар буолуутун бэрэбиэркэлээһин Толору көрдөөһүн… Иҥиннэриллибит diff --git a/i18n/src/commonMain/moko-resources/sc/plurals.xml b/i18n/src/commonMain/moko-resources/sc/plurals.xml index dfe3faee05..903973414a 100644 --- a/i18n/src/commonMain/moko-resources/sc/plurals.xml +++ b/i18n/src/commonMain/moko-resources/sc/plurals.xml @@ -76,4 +76,4 @@ 1 pàgina %1$s pàginas - \ No newline at end of file + diff --git a/i18n/src/commonMain/moko-resources/sc/strings.xml b/i18n/src/commonMain/moko-resources/sc/strings.xml index f16505b2e7..f2b1a5609a 100644 --- a/i18n/src/commonMain/moko-resources/sc/strings.xml +++ b/i18n/src/commonMain/moko-resources/sc/strings.xml @@ -391,7 +391,6 @@ Fùrria sas zonas de tocu Istadu disconnotu Autore disconnotu - Agiornadu a v%1$s Ite b\'at de nou Iscarrigamentu de sos capìtulos fallidu pro neghe de su pagu ispàtziu lìberu in su discu Chirca \"%1$s\" globalmente @@ -563,7 +562,6 @@ Brincadu ca bi sunt capìtulos non lèghidos Brincadu ca non bi sunt capìtulos lèghidos Toca pro àteras informatziones - %1$d agiornamentu(os) fallidu(os) Verticale a s\'imbesse Move sa sèrie cara a pitzos Disabilitadu diff --git a/i18n/src/commonMain/moko-resources/sk/strings.xml b/i18n/src/commonMain/moko-resources/sk/strings.xml index c5719f8aff..9f00838818 100644 --- a/i18n/src/commonMain/moko-resources/sk/strings.xml +++ b/i18n/src/commonMain/moko-resources/sk/strings.xml @@ -535,7 +535,6 @@ Horizontálne Zakázané Vylúčené kategórie - Aktualizované na v%1$s Iba stiahnuté Zoznam prianí Chystáte sa odstrániť \"%s\" zo svojej knižnice @@ -603,7 +602,6 @@ Viac Upozornenie: Veľké hromadné sťahovanie môže viesť k spomaleniu zdrojov a/alebo blokovaniu %s. Klepnutím sa dozviete viac. Veľké aktualizácie poškodzujú zdroje a môžu viesť k pomalším aktualizáciám a tiež k zvýšeniu spotreby batérie. Klepnutím sa dozviete viac. - Zlyhané aktualizácie: %1$d Zálohovanie zlyhalo Sledovať Webová stránka @@ -663,7 +661,6 @@ Nadchádzajúce Nahradiť Navigovať hore - Prispieť finančne Auto Vlastná frekvencia aktualizácie Skóre na sledovači @@ -675,7 +672,6 @@ Zatvoriť kartu Nie teraz Ajtak pridať - Vypočítavam… Príručka na úvod Poďme najprv nastaviť nejaké veci. Vždy ich môžete neskôr zmeniť. Vyberte priečinok, kde %1$s bude ukladať stiahnuté kapitoly, zálohy a ďalšie.\n\nOdporúčame použiť samostatný priečinok špecificky pre túto aplikáciu.\n\nVybraný priečinok: %2$s diff --git a/i18n/src/commonMain/moko-resources/sq/strings.xml b/i18n/src/commonMain/moko-resources/sq/strings.xml index 3f8ab926d8..06dd02f223 100644 --- a/i18n/src/commonMain/moko-resources/sq/strings.xml +++ b/i18n/src/commonMain/moko-resources/sq/strings.xml @@ -420,7 +420,6 @@ Mënyra e leximit Tjetra: Pastro historinë - %1$d përditësim(e) dështoi U anashkalua sepse seria ka përfunduar Zgjidhni imazhin e kopertinës Hapni në GitHub @@ -524,7 +523,6 @@ Optimizimi i baterisë është tashmë i çaktivizuar Cilësimet e pajisjes nuk mund të hapeshin Kontrolloni për përditësime - Përditësuar në v%1$s Dërgoni raporte përplasjesh Ndihmon në rregullimin e çdo defekti. Nuk do të dërgohen të dhëna sensitive Ndërtimet e F-Droid nuk mbështeten zyrtarisht. diff --git a/i18n/src/commonMain/moko-resources/sr/strings.xml b/i18n/src/commonMain/moko-resources/sr/strings.xml index 783dee64db..ccc31fa0be 100644 --- a/i18n/src/commonMain/moko-resources/sr/strings.xml +++ b/i18n/src/commonMain/moko-resources/sr/strings.xml @@ -481,7 +481,6 @@ Датум завршетка Аутоматски Лиценце отвореног кода - Ажурирано на v%1$s Ништа није пронађено Раздели широке странице Ништа @@ -561,7 +560,6 @@ Прескочи уносе који нису започети Прикажи наслов Помакни наслов на врх - %1$d ажурирање није успело Додирните да сазнате више За помоћ о томе како да поправите грешке у ажурирању колекције, погледајте %1$s Прескочено јер ниједно поглавље није прочитано diff --git a/i18n/src/commonMain/moko-resources/sv/strings.xml b/i18n/src/commonMain/moko-resources/sv/strings.xml index 3922722e8e..14089b0fd3 100644 --- a/i18n/src/commonMain/moko-resources/sv/strings.xml +++ b/i18n/src/commonMain/moko-resources/sv/strings.xml @@ -395,7 +395,6 @@ Inaktivera Det gick inte att ladda ner kapitelt på grund av lågt lagringsutrymme Sök efter \"%1$s\" globalt - Uppdaterad till v%1$s Vad är nytt Läsläge Tema @@ -565,7 +564,6 @@ Hoppade över eftersom det finns olästa kapitel Hoppade över eftersom inga kapitel läses Tryck på för att få veta mer - %1$d uppdatering(ar) misslyckades Omvänt porträtt Flytta serien till toppen Inaktiverad diff --git a/i18n/src/commonMain/moko-resources/ta/strings.xml b/i18n/src/commonMain/moko-resources/ta/strings.xml index b4ae4cdc2c..342cdb5009 100644 --- a/i18n/src/commonMain/moko-resources/ta/strings.xml +++ b/i18n/src/commonMain/moko-resources/ta/strings.xml @@ -348,7 +348,7 @@ ரெப்போ சேர்க்கவும் முகவரி களஞ்சி தீங்கிழைக்கும் நீட்டிப்புகள் சேமிக்கப்பட்ட உள்நுழைவு நற்சான்றிதழ்களைப் படிக்கலாம் அல்லது தன்னிச்சையான குறியீட்டை இயக்கலாம்.\n\n இந்த நீட்டிப்பை நம்புவதன் மூலம், இந்த அபாயங்களை நீங்கள் ஏற்றுக்கொள்கிறீர்கள். - மிஓனில் கூடுதல் களஞ்சியங்களைச் சேர்க்கவும். இது \"index.min.json\" உடன் முடிவடையும் முகவரி ஆக இருக்க வேண்டும். + %s இல் கூடுதல் களஞ்சியங்களைச் சேர்க்கவும். இது \"index.min.json\" என்று முடிவடையும் முகவரி ஆக இருக்க வேண்டும். இந்த ரெப்போ ஏற்கனவே உள்ளது! ரெப்போவை நீக்கு தவறான ரெப்போ முகவரி @@ -372,7 +372,7 @@ முழு திரை குழாய் மண்டலங்கள் மேலடுக்கைக் காட்டு வாசகர் திறக்கப்படும்போது சுருக்கமாகக் காட்டுங்கள் - %1$s MS + %1$s மிநொ ஒவ்வொரு ஃபிளாச் உடன் ஃபிளாச் செயல்திறனை பாதிக்கிறது. பிட்மேப் வாசலைக் குறைப்பது வெற்று பட சிக்கல்களை சரிசெய்யவில்லை என்றால் மட்டுமே இயக்கவும் @@ -547,9 +547,9 @@ நூலகம் ஒத்திசைத்தல் நூலக ஒத்திசைவு முடிந்தது நெட்வொர்க்கிங் - REINDEX பதிவிறக்கங்கள் + மறுகுறியீடு பதிவிறக்கங்கள் பதிவிறக்கம் செய்யப்பட்ட அத்தியாயங்களை மறுபரிசீலனை செய்ய பயன்பாடு - பதிவிறக்கங்கள் அட்டவணை செல்லாதது + பதிவிறக்க அட்டவணையை மீண்டும் உருவாக்குகிறது தரவுத்தளத்தை அழிக்கவும் உங்கள் நூலகத்தில் சேமிக்கப்படாத உள்ளீடுகளுக்கான வரலாற்றை நீக்கவும் தரவுத்தளத்தில் %1$d நூலகமற்ற உள்ளீடுகள் @@ -575,7 +575,6 @@ கணினி பதிவுக்கு வாய்மொழி பதிவுகளை அச்சிடுக (பயன்பாட்டு செயல்திறனைக் குறைக்கிறது) தனியுரிமைக் கொள்கை புதுப்பிப்புகளை சரிபார்க்கவும் - V%1$s க்கு புதுப்பிக்கப்பட்டது செயலிழப்பு அறிக்கைகளை அனுப்பவும் எந்த பிழைகளையும் சரிசெய்ய உதவுகிறது. முக்கியமான தரவு எதுவும் அனுப்பப்படாது எஃப்-டிராய்டு கட்டடங்கள் அதிகாரப்பூர்வமாக ஆதரிக்கப்படவில்லை.\n மேலும் அறிய தட்டவும். @@ -753,7 +752,7 @@ சராசரி மதிப்பெண் பயன்படுத்தப்பட்டது குறைந்த சேமிப்பு இடம் காரணமாக அத்தியாயங்களை பதிவிறக்கம் செய்ய முடியவில்லை - எச்சரிக்கை: பெரிய மொத்த பதிவிறக்கங்கள் ஆதாரங்கள் மெதுவாகவும்/அல்லது மிஓனைத் தடுக்கவும் வழிவகுக்கும். மேலும் அறிய தட்டவும். + எச்சரிக்கை: பெரிய மொத்தப் பதிவிறக்கங்கள் மூலங்கள் மெதுவாக மாறுவதற்கும்/அல்லது %sஐத் தடுப்பதற்கும் வழிவகுக்கும். மேலும் அறிய தட்டவும். இதற்கில்லை %d.டி. நூலகத்தைப் புதுப்பித்தல்… (%s) @@ -766,7 +765,6 @@ அத்தியாயம் %1$s அத்தியாயம் %1$s மற்றும் %2$d மேலும் அத்தியாயங்கள் %1$s - %1$d புதுப்பிப்பு (கள்) தோல்வியடைந்தது மேலும் அறிய தட்டவும் அட்டையைப் புதுப்பிக்கத் தவறிவிட்டது இதைச் செய்வதற்கு முன் உங்கள் நூலகத்தில் உள்ளீட்டைச் சேர்க்கவும் @@ -892,4 +890,13 @@ நூலாசிரியர் கோப்பகத்தை உருவாக்குவதில் தோல்வி: %s பதிவிறக்க கோப்பகத்தை உருவாக்குவதில் தோல்வி + தாவலை மூடு + மங்கா விளக்கங்களில் படங்களை வழங்கவும் + ASCII அல்லாத கோப்பு பெயர்களை அனுமதிக்க வேண்டாம் + யூனிகோடை ஆதரிக்காத சில சேமிப்பக மீடியாவுடன் இணக்கத்தன்மையை உறுதி செய்கிறது. இது இயக்கப்பட்டால், ASCII அல்லாத எழுத்துக்களை அவற்றின் சிறிய UTF-8 எக்சாடெசிமல் பிரதிநிதித்துவங்களுடன் மாற்றுவதன் மூலம், நீங்கள் மூல மற்றும் மங்கா கோப்புறைகளை கைமுறையாக மறுபெயரிட வேண்டும். அத்தியாய கோப்புகளை மறுபெயரிட தேவையில்லை. + ஒரே நேரத்தில் மூல பதிவிறக்கங்கள் + ஒரே நேரத்தில் பக்க பதிவிறக்கங்கள் + ஒவ்வொரு மூலத்திற்கும் ஒரே நேரத்தில் பதிவிறக்கம் செய்யப்பட்ட பக்கங்கள் + புத்தகக்குறி செய்யப்பட்டது + நீக்கப்பட்ட ச்கேலேட்டர்களை வடிகட்டி diff --git a/i18n/src/commonMain/moko-resources/th/strings.xml b/i18n/src/commonMain/moko-resources/th/strings.xml index 98f166ff3c..7c845aea2c 100644 --- a/i18n/src/commonMain/moko-resources/th/strings.xml +++ b/i18n/src/commonMain/moko-resources/th/strings.xml @@ -431,7 +431,6 @@ หยุดประวัติการอ่านชั่วคราว โหมดไม่ระบุตัวตน ดาวน์โหลดแล้วเท่านั้น - อัปเดตเป็น v%1$s แล้ว ตรวจสอบการอัปเดต ใบอนุญาตโอเพ่นซอร์ส มีอะไรใหม่ @@ -565,7 +564,6 @@ ข้ามรายการที่ยังไม่ได้เริ่มอ่าน ถูกข้ามเนื่องจากเรื่องนี้จบแล้ว แตะเพื่อเรียนรู้เพิ่มเติม - อัปเดตผิดพลาด %1$d รายการ แนวตั้งแบบกลับด้าน ย้ายเรื่องไปด้านบน ปิดใช้งาน @@ -848,7 +846,6 @@ รายการคลัง ส่งออกคลังแล้ว คุณกำลังจะลบรายการออกจากฐานข้อมูล - บริจาค เรนเดอร์รูปภาพในคำอธิบายเรื่อง ไม่อนุญาตชื่อไฟล์ที่ไม่ใช่ ASCII diff --git a/i18n/src/commonMain/moko-resources/tr/plurals.xml b/i18n/src/commonMain/moko-resources/tr/plurals.xml index e4222dc4ce..60971a185b 100644 --- a/i18n/src/commonMain/moko-resources/tr/plurals.xml +++ b/i18n/src/commonMain/moko-resources/tr/plurals.xml @@ -41,8 +41,8 @@ %d izleyici - %d bölüm atlandı, kaynak mevcut değil veya filtrelendi - %d bölüm atlandı, kaynak mevcut değil veya filtrelendi + %d bölüm atlandı, kaynak mevcut değil ya da filtrelendi + %d bölüm atlandı, kaynak mevcut değil ya da filtrelendi Dün @@ -88,4 +88,8 @@ Bir girdi atlandı %1$d girdi atlandı + + %1$d güncelleme başarısız + %1$d güncelleme başarısız + diff --git a/i18n/src/commonMain/moko-resources/tr/strings.xml b/i18n/src/commonMain/moko-resources/tr/strings.xml index 6c264329b1..e30880326c 100644 --- a/i18n/src/commonMain/moko-resources/tr/strings.xml +++ b/i18n/src/commonMain/moko-resources/tr/strings.xml @@ -393,7 +393,6 @@ Yatay Bilinmeyen durum Bilinmeyen yazar - v%1$s sürümüne güncellendi Yenilikler Depolama alanı az olduğu için bölümler indirilemedi Eklendiği tarih @@ -564,7 +563,6 @@ Hiçbir bölüm okunmadığı için atlandı Geniş görselleri kaydır Geniş görsellere otomatik yakınlaştır - %1$d güncelleme başarısız oldu Daha fazla bilgi için dokunun Ters portre Seriyi en üste taşı @@ -902,7 +900,6 @@ Durdur Eksik bölüm göstergelerini gizle Manga açıklamalarında bulunan görselleri göster - Bağış ASCII olmayan dosya isimlerine izin verme Unicode desteklemeyen bazı depolama sistemleri için uyumluluk sağlar. Etkinleştirildiğinde kaynak ve manga klasörlerini manuel olarak yeniden adlandırıp ASCII olmayan karakterleri küçük UTF-8 heksadesimal karşılıklarıyla değiştirmeniz gerekir. Bölüm dosyalarının yeniden adlandırılması gerekli değildir. Tek seferde indirilen sayfa sayısı @@ -910,6 +907,18 @@ Tek seferde indirilen kaynak sayısı Sekmeyi kapat Hariç tutulan Çevirenleri filtrele - Hesaplanıyor… Yer imli + Bizi Destekleyin + Patronlar, özel kanallara ve gelecekte daha fazlasına erişim elde eder. + Patreon (tercih edilen) + OpenCollective + Mihon, şu anda %d+ patron tarafından desteklenmektedir. Her birinize ayrı olarak teşekkür etmek istiyoruz. Hadi Mihon\'u birlikte daha iyi yapalım. + Başka seçenekler ve sorularınız için Discord sunucumuza katılın. + Discord + Uygulamayı beğendiniz mi? + Merhaba! Ben, Mihon\'un ana geliştiricisiyim ve geliştirme sürecine maddi olarak destek olmayı düşünmenizi isterim. Yeterli destek olursa Mihon üzerinde tam zamanlı olarak çalışabilirim ve uzun zamandır olan sorunlara ve çok istenen özelliklere odaklanabilirim. + Patreon (tercih edilen) veya OpenCollective üzerinden bağışta bulunabilirsiniz. Sorularınız varsa veya başka bir yolla destek olmak isterseniz Mihon\'un Discord sunucusu üzerinden bana ulaşmaktan çekinmeyin. + Ancak ne olursa olsun Mihon, ben ve gönüllü insanlar tarafından geliştirilmeye devam edecek ve açık kaynak kodlu olarak kalacaktır. + Discord + Kapat diff --git a/i18n/src/commonMain/moko-resources/tt/strings.xml b/i18n/src/commonMain/moko-resources/tt/strings.xml index 55344e5192..045e125f3d 100644 --- a/i18n/src/commonMain/moko-resources/tt/strings.xml +++ b/i18n/src/commonMain/moko-resources/tt/strings.xml @@ -1,3 +1,3 @@ - \ No newline at end of file + diff --git a/i18n/src/commonMain/moko-resources/uk/strings.xml b/i18n/src/commonMain/moko-resources/uk/strings.xml index a0e392c346..9dd46af28b 100644 --- a/i18n/src/commonMain/moko-resources/uk/strings.xml +++ b/i18n/src/commonMain/moko-resources/uk/strings.xml @@ -393,7 +393,6 @@ Невідомий автор Потрібен перезапуск застосунку, щоб зміни вступили в дію Мережа - Оновлено до v%1$s Що новенького Не вдалось завантажити розділи через нестачу місця в сховищі Шукати \"%1$s\" глобально @@ -561,7 +560,6 @@ Пропустити непочаті глави Перемістити серію на початок Портретна навпаки - %1$d оновлення(нь) не вдалось Пропущено, оскільки серія завершена Пропущено через те, що є непрочитані розділи Пропущено, оскільки серія не почата diff --git a/i18n/src/commonMain/moko-resources/vi/strings.xml b/i18n/src/commonMain/moko-resources/vi/strings.xml index a9c96b430b..93ea0a1c7d 100644 --- a/i18n/src/commonMain/moko-resources/vi/strings.xml +++ b/i18n/src/commonMain/moko-resources/vi/strings.xml @@ -418,7 +418,6 @@ Mục Lọc tất cả truyện trong thư viện Tắt chế độ ẩn danh - Được cập nhật đến phiên bản v%1$s Kiểm tra cập nhật Mở giấy phép nguồn mở Có gì mới @@ -563,7 +562,6 @@ Xoay ảnh rộng Lưới chỉ mỗi bìa Đảo ngược chân dung - %1$d cập nhật thất bại Đã bỏ qua vì bộ truyện đã hoàn thành Đã bỏ qua vì vẫn còn chương chưa đọc Đã bỏ qua vì chưa chương được đọc @@ -901,7 +899,6 @@ Hủy bỏ Hủy bỏ Không tìm thấy chương nào, mục này không thể được sử dụng để di chuyển - Quyên góp Hiển thị hình ảnh trong mô tả manga Không cho phép tên tệp không phải định dạng ASCII Đảm bảo khả năng tương thích với một số phương tiện lưu trữ nhất định không hỗ trợ Unicode. Khi tính năng này được bật, bạn sẽ cần đổi tên thủ công các thư mục nguồn và manga bằng cách thay thế các ký tự không phải ASCII bằng cách biểu diễn thập lục phân UTF-8 chữ thường của chúng. Các tập tin chương không cần phải đổi tên. @@ -910,6 +907,5 @@ Các trang được tải xuống đồng thời theo từng nguồn Đóng thẻ Lọc nhóm dịch bị loại trừ - Đang tính… Đã đánh dấu diff --git a/i18n/src/commonMain/moko-resources/zh-rCN/plurals.xml b/i18n/src/commonMain/moko-resources/zh-rCN/plurals.xml index d436da2789..52a68127e2 100644 --- a/i18n/src/commonMain/moko-resources/zh-rCN/plurals.xml +++ b/i18n/src/commonMain/moko-resources/zh-rCN/plurals.xml @@ -66,4 +66,7 @@ %1$d 个作品已跳过 + + %1$d 更新失败 + diff --git a/i18n/src/commonMain/moko-resources/zh-rCN/strings.xml b/i18n/src/commonMain/moko-resources/zh-rCN/strings.xml index 8fd311a76c..b50b4441ee 100644 --- a/i18n/src/commonMain/moko-resources/zh-rCN/strings.xml +++ b/i18n/src/commonMain/moko-resources/zh-rCN/strings.xml @@ -392,7 +392,6 @@ 未知状态 未知作者 - 已更新至 v%1$s 更新日志 存储空间不足,无法下载章节 全局搜索 \"%1$s\" @@ -565,7 +564,6 @@ 已跳过,因为有未读章节 已跳过,因为尚未开始阅读 点击了解详情 - %1$d 个更新失败了 反向竖屏 将作品移到顶部 关闭 @@ -902,7 +900,6 @@ 迁移 隐藏缺失章节提示符 在漫画注释中显示图片 - 捐赠 禁用非ASCII文件名 确保与某些不支持 Unicode 的存储介质相兼容。启用此功能后,你需要手动重命名图源和漫画文件夹,将非 ASCII 字符改为对应的 UTF-8 小写十六进制表示形式。章节文件无需重命名。 同时下载的图源数量 @@ -910,6 +907,18 @@ 每个图源同时下载的页数 关闭标签 筛选排除翻译组 - 计算中… 已添加书签 + 支持我们 + 赞助者可访问专属频道,更多福利即将推出。 + Patreon(首选) + OpenCollective + 目前 Mihon 已获得 %d+ 位赞助者的支持。我们衷心感谢大家。让我们携手把 Mihon 办得更出色。 + 如需替代方案或有任何相关问题,请加入我们的 Discord 服务器。 + Discord + 喜欢本应用吗? + 你好!我是 Mihon 的首席开发者,恳请你考虑为 Mihon 的开发工作给予资金方面的支持。有了足够的资金支持,我就能全职投入 Mihon 的开发,专注于解决长期存在的问题以及用户呼声很高的功能。 + 您可以通过 Patreon(首选)或 OpenCollective 进行捐赠。如果您有任何疑问,或者希望使用其他方式提供支持,欢迎通过 Mihon 的 Discord 服务器联系我。 + 无论如何,Mihon 仍将由我和志愿者们继续维护,并且会保持开源。 + Discord + 放弃 diff --git a/i18n/src/commonMain/moko-resources/zh-rTW/plurals.xml b/i18n/src/commonMain/moko-resources/zh-rTW/plurals.xml index e27b864d35..4b63924663 100644 --- a/i18n/src/commonMain/moko-resources/zh-rTW/plurals.xml +++ b/i18n/src/commonMain/moko-resources/zh-rTW/plurals.xml @@ -66,4 +66,7 @@ 已跳過 %1$d 個項目 + + %1$d 更新失敗 + diff --git a/i18n/src/commonMain/moko-resources/zh-rTW/strings.xml b/i18n/src/commonMain/moko-resources/zh-rTW/strings.xml index 028c2e7a09..93c4ddb23f 100644 --- a/i18n/src/commonMain/moko-resources/zh-rTW/strings.xml +++ b/i18n/src/commonMain/moko-resources/zh-rTW/strings.xml @@ -389,7 +389,6 @@ 佚名 在所有範圍內搜尋「%1$s」 由於儲存空間不足,無法下載章節 - 已更新至 v%1$s 閱讀模式 主題 收藏日期 @@ -563,7 +562,6 @@ 由於無已讀章節,因此略過 顛倒直向 瞭解詳情 - %1$d 項更新失敗 置頂此作品 停用 書櫃中尚無作品可供備份 @@ -893,7 +891,6 @@ 遷移 找不到章節,此項目無法用於遷移 在漫畫描述中顯示圖片 - 捐贈 禁止使用非 ASCII 檔名 確保與不支援 Unicode 的某些儲存媒體相容,啟用此選項後,你需要手動將來源與漫畫資料夾中的非 ASCII 字元改成對應的小寫 UTF-8 十六進位表示方式,章節檔案則不需要重新命名。 同時下載的來源數目 @@ -901,6 +898,6 @@ 每個來源同時下載的頁數 關閉頁籤 篩選排除掃譯者 - 計算中… 已新增書籤 + 支持我們 diff --git a/macrobenchmark/build.gradle.kts b/macrobenchmark/build.gradle.kts index ec2d049a5d..c7b006979b 100644 --- a/macrobenchmark/build.gradle.kts +++ b/macrobenchmark/build.gradle.kts @@ -1,5 +1,5 @@ plugins { - id("mihon.benchmark") + alias(mihonx.plugins.android.test) } android { @@ -26,10 +26,10 @@ android { } dependencies { - implementation(androidx.test.ext) - implementation(androidx.test.espresso.core) - implementation(androidx.test.uiautomator) - implementation(androidx.benchmark.macro) + implementation(libs.androidx.test.junit) + implementation(libs.androidx.test.espresso.core) + implementation(libs.androidx.test.uiautomator) + implementation(libs.androidx.benchmark.macroJunit4) } androidComponents { diff --git a/presentation-core/build.gradle.kts b/presentation-core/build.gradle.kts index 332c1fffea..79fd1b4ef6 100644 --- a/presentation-core/build.gradle.kts +++ b/presentation-core/build.gradle.kts @@ -1,16 +1,12 @@ plugins { - id("mihon.library") - id("mihon.library.compose") - kotlin("android") + alias(mihonx.plugins.android.library) + alias(mihonx.plugins.compose) + + alias(mihonx.plugins.spotless) } android { namespace = "tachiyomi.presentation.core" - - defaultConfig { - testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" - consumerProguardFiles("consumer-rules.pro") - } } kotlin { @@ -32,17 +28,17 @@ dependencies { api(projects.i18n) // Compose - implementation(compose.activity) - implementation(compose.foundation) - implementation(compose.material3.core) - implementation(compose.material.icons) - implementation(compose.animation) - implementation(compose.animation.graphics) - debugImplementation(compose.ui.tooling) - implementation(compose.ui.tooling.preview) - implementation(compose.ui.util) + implementation(libs.androidx.activity.compose) + implementation(libs.androidx.compose.foundation) + implementation(libs.androidx.compose.material3) + implementation(libs.androidx.compose.materialIcons) + implementation(libs.androidx.compose.animation) + implementation(libs.androidx.compose.animationGraphics) + debugImplementation(libs.androidx.compose.uiTooling) + implementation(libs.androidx.compose.uiToolingPreview) + implementation(libs.androidx.compose.uiUtil) - implementation(androidx.paging.runtime) - implementation(androidx.paging.compose) - implementation(kotlinx.immutables) + implementation(libs.androidx.paging.runtime) + implementation(libs.androidx.paging.compose) + implementation(libs.kotlinx.collections.immutable) } diff --git a/presentation-core/consumer-rules.pro b/presentation-core/consumer-rules.pro deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/presentation-core/proguard-rules.pro b/presentation-core/proguard-rules.pro deleted file mode 100644 index 481bb43481..0000000000 --- a/presentation-core/proguard-rules.pro +++ /dev/null @@ -1,21 +0,0 @@ -# Add project specific ProGuard rules here. -# You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Uncomment this to preserve the line number information for -# debugging stack traces. -#-keepattributes SourceFile,LineNumberTable - -# If you keep the line number information, uncomment this to -# hide the original source file name. -#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/presentation-widget/build.gradle.kts b/presentation-widget/build.gradle.kts index 09faa96394..1018b54e16 100644 --- a/presentation-widget/build.gradle.kts +++ b/presentation-widget/build.gradle.kts @@ -1,16 +1,12 @@ plugins { - id("mihon.library") - id("mihon.library.compose") - kotlin("android") + alias(mihonx.plugins.android.library) + alias(mihonx.plugins.compose) + + alias(mihonx.plugins.spotless) } android { namespace = "tachiyomi.presentation.widget" - - defaultConfig { - testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" - consumerProguardFiles("consumer-rules.pro") - } } dependencies { @@ -19,12 +15,11 @@ dependencies { implementation(projects.presentationCore) api(projects.i18n) - implementation(compose.glance) + implementation(libs.androidx.glance.appWidget) implementation(libs.material) - implementation(kotlinx.immutables) + implementation(libs.kotlinx.collections.immutable) - implementation(platform(libs.coil.bom)) implementation(libs.coil.core) api(libs.injekt) diff --git a/presentation-widget/consumer-rules.pro b/presentation-widget/consumer-rules.pro deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/presentation-widget/proguard-rules.pro b/presentation-widget/proguard-rules.pro deleted file mode 100644 index 481bb43481..0000000000 --- a/presentation-widget/proguard-rules.pro +++ /dev/null @@ -1,21 +0,0 @@ -# Add project specific ProGuard rules here. -# You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Uncomment this to preserve the line number information for -# debugging stack traces. -#-keepattributes SourceFile,LineNumberTable - -# If you keep the line number information, uncomment this to -# hide the original source file name. -#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 39f414650b..2ae6920ad7 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,30 +1,17 @@ pluginManagement { - resolutionStrategy { - eachPlugin { - val regex = "com.android.(library|application)".toRegex() - if (regex matches requested.id.id) { - useModule("com.android.tools.build:gradle:${requested.version}") - } - } - } + includeBuild("gradle/build-logic") repositories { - gradlePluginPortal() google() mavenCentral() + gradlePluginPortal() maven(url = "https://www.jitpack.io") } } dependencyResolutionManagement { versionCatalogs { - create("kotlinx") { - from(files("gradle/kotlinx.versions.toml")) - } - create("androidx") { - from(files("gradle/androidx.versions.toml")) - } - create("compose") { - from(files("gradle/compose.versions.toml")) + create("mihonx") { + from(files("gradle/mihon.versions.toml")) } // AY --> create("aniyomilibs") { @@ -34,8 +21,8 @@ dependencyResolutionManagement { } repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { - mavenCentral() google() + mavenCentral() maven(url = "https://www.jitpack.io") } } diff --git a/source-api/build.gradle.kts b/source-api/build.gradle.kts index 330e5f29d5..9683dbf047 100644 --- a/source-api/build.gradle.kts +++ b/source-api/build.gradle.kts @@ -1,33 +1,44 @@ import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi plugins { - id("mihon.library") - kotlin("multiplatform") - kotlin("plugin.serialization") + alias(mihonx.plugins.kotlin.multiplatform) + alias(mihonx.plugins.spotless) + + alias(libs.plugins.kotlin.serialization) } kotlin { - androidTarget() - sourceSets { - val commonMain by getting { - dependencies { - api(kotlinx.serialization.json) - api(libs.injekt) - api(libs.rxjava) - api(libs.jsoup) + @Suppress("UnstableApiUsage") + android { + namespace = "eu.kanade.tachiyomi.source" - implementation(project.dependencies.platform(compose.bom)) - implementation(compose.runtime) + optimization { + consumerKeepRules.apply { + publish = true + file("consumer-proguard.pro") } } - val androidMain by getting { + + // TODO(antsy): Remove when https://youtrack.jetbrains.com/issue/KT-83319 is resolved + withHostTest { } + } + + @OptIn(ExperimentalKotlinGradlePluginApi::class) + dependencies { + api(libs.kotlinx.serialization.json) + api(libs.injekt) + api(libs.rxJava) + api(libs.jsoup) + + implementation(platform(libs.androidx.compose.bom)) + implementation(libs.androidx.compose.runtime) + } + + sourceSets { + androidMain { dependencies { implementation(projects.core.common) - api(libs.preferencektx) - - // Workaround for https://youtrack.jetbrains.com/issue/KT-57605 - implementation(kotlinx.coroutines.android) - implementation(project.dependencies.platform(kotlinx.coroutines.bom)) + api(libs.androidx.preference) } } } @@ -37,11 +48,3 @@ kotlin { freeCompilerArgs.add("-Xexpect-actual-classes") } } - -android { - namespace = "eu.kanade.tachiyomi.source" - - defaultConfig { - consumerProguardFile("consumer-proguard.pro") - } -} diff --git a/source-local/build.gradle.kts b/source-local/build.gradle.kts index 48cddc95f3..998771d03a 100644 --- a/source-local/build.gradle.kts +++ b/source-local/build.gradle.kts @@ -1,22 +1,28 @@ import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi plugins { - id("mihon.library") - kotlin("multiplatform") + alias(mihonx.plugins.kotlin.multiplatform) + alias(mihonx.plugins.spotless) } kotlin { - androidTarget() - sourceSets { - val commonMain by getting { - dependencies { - implementation(projects.sourceApi) - api(projects.i18n) + android { + namespace = "tachiyomi.source.local" - implementation(libs.unifile) - } - } - val androidMain by getting { + // TODO(antsy): Remove when https://youtrack.jetbrains.com/issue/KT-83319 is resolved + withHostTest { } + } + + @OptIn(ExperimentalKotlinGradlePluginApi::class) + dependencies { + implementation(projects.sourceApi) + api(projects.i18n) + + implementation(libs.unifile) + } + + sourceSets { + androidMain { dependencies { implementation(projects.core.archive) implementation(projects.core.common) @@ -25,7 +31,12 @@ kotlin { // Move ChapterRecognition to separate module? implementation(projects.domain) - implementation(kotlinx.bundles.serialization) + implementation(libs.bundles.serialization) + + // AM --> + // FFmpeg-kit + implementation(aniyomilibs.ffmpeg.kit) + // <-- AM } } } @@ -38,19 +49,3 @@ kotlin { ) } } - -android { - namespace = "tachiyomi.source.local" - - defaultConfig { - testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" - consumerProguardFiles("consumer-rules.pro") - } - - // AY --> - dependencies { - // FFmpeg-kit - implementation(aniyomilibs.ffmpeg.kit) - } - // <-- AY -} diff --git a/source-local/consumer-rules.pro b/source-local/consumer-rules.pro deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/source-local/proguard-rules.pro b/source-local/proguard-rules.pro deleted file mode 100644 index 481bb43481..0000000000 --- a/source-local/proguard-rules.pro +++ /dev/null @@ -1,21 +0,0 @@ -# Add project specific ProGuard rules here. -# You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Uncomment this to preserve the line number information for -# debugging stack traces. -#-keepattributes SourceFile,LineNumberTable - -# If you keep the line number information, uncomment this to -# hide the original source file name. -#-renamesourcefileattribute SourceFile \ No newline at end of file