Compare commits

...

407 Commits

Author SHA1 Message Date
Jobobby04 509ace1a38 Revert "Reapply "Fix thread starvation caused by not yielding or using an inappropriate thread pool (#2955)""
This reverts commit 9c01119d24.

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderViewModel.kt
2026-04-08 15:02:37 -04:00
Jobobby04 170358f88e Revert "Reapply "Fix cache invalidation isn't done at startup (#2970)""
This reverts commit c17e9573b7.
2026-04-08 14:52:15 -04:00
Jobobby04 5c14879c12 Fix build 2026-04-06 16:25:25 -04:00
ArthurKun 1682962703 Add gradle.properties to build-logic synced with root gradle.properties (#3159)
Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com>
2026-04-06 16:22:14 -04:00
Mend Renovate a1daf53188 Update dependency com.gradleup.tapmoc:tapmoc-gradle-plugin to v0.4.1 (#3173) 2026-04-06 16:03:22 -04:00
Mend Renovate b0bdee8c72 Update dependency io.kotest:kotest-assertions-core to v6.1.10 (#3172) 2026-04-06 16:03:16 -04:00
MajorTanya 72c091d317 Add informative error for unapproved MAL titles (#3155)
MAL has a concept of "titles waiting for approval". These titles
cannot be added to user lists, but they do show up on the website and
crucially, in search results.

However, trying to add such an "unapproved" title will return a 400
error response with the error "invalid_content".

Previously, the awaitSuccess() call would mean the generic "HTTP 400"
toast would be shown. Now, a dedicated informative error message is
shown instead.
# Conflicts:
#	CHANGELOG.md
2026-04-06 16:02:51 -04:00
Mend Renovate 1cc796a62e Update dependency androidx.compose:compose-bom-beta to v2026.03.01 (#3147) 2026-04-06 16:02:30 -04:00
Mend Renovate cd40c0fb32 Update dependency androidx.work:work-runtime to v2.11.2 (#3146) 2026-04-06 16:02:15 -04:00
Christos 88edd18d02 Use plural forms for update error notification (#3090)
* Use plural forms for update error notification

Replace the hardcoded 'X update(s) failed' string with Android
plural resources so the notification correctly shows '1 update failed'
vs '2 updates failed', enabling proper localization.

Fixes #3051

* Address review: rename plural key and remove comment

Rename plural key to notification_update_errors to avoid potential
conflicts with existing translated string keys. Remove leftover
comment from strings.xml.

* Revert key rename per review
2026-04-06 16:02:10 -04:00
Mend Renovate ba9d010f78 Update dependency io.kotest:kotest-assertions-core to v6.1.9 (#3137) 2026-04-06 16:02:02 -04:00
Mend Renovate 1ed375968e Update dependency io.kotest:kotest-assertions-core to v6.1.8 (#3132) 2026-04-06 16:01:55 -04:00
MajorTanya 9e525515ea Address Gradle warning about Task.project (#3118)
Apparently, this is all that's needed to replace the forbidden
`Task.project` accessor, which would be an error in Gradle v10 (it's
been deprecated for a while)

This will also allow us to use the Configuration Cache if we wanted
to.
2026-04-06 16:01:47 -04:00
AntsyLich bd7201cfb9 Fix app crash on startup on some Android TV
Why do you guys even exist

# Conflicts:
#	CHANGELOG.md
2026-04-06 16:01:40 -04:00
AntsyLich d9ca2b69e8 Fix occasional crash when mass installing/uninstalling extension using PackageManager
# Conflicts:
#	CHANGELOG.md
2026-04-06 16:01:20 -04:00
AntsyLich 925fb118af Potentially fix 'database is locked' crash
# Conflicts:
#	CHANGELOG.md
#	app/src/main/java/eu/kanade/tachiyomi/di/AppModule.kt
2026-04-06 15:59:05 -04:00
AntsyLich 4552221020 Fix wrong exception being caught after 8c480c6355 migration
`android.database.sqlite.SQLiteException` instead of `android.database.SQLException`

# Conflicts:
#	CHANGELOG.md
2026-04-06 15:54:09 -04:00
MajorTanya 24b66b7030 Address CancellableContinuation.resume deprecation (#3115)
According to the source docs, this has been a warning since
kotlinx.coroutines 1.9.0.
2026-04-06 15:52:45 -04:00
Mend Renovate 58decd076c Update Gradle to v9 (#2333) 2026-04-06 15:50:18 -04:00
AntsyLich a7d93ae751 Cleanup and rework build logic (#3113)
# Conflicts:
#	app/build.gradle.kts
#	app/shortcuts.xml
#	app/src/main/res/xml/shortcuts.xml
#	app/src/main/shortcuts.xml
#	build.gradle.kts
#	buildSrc/src/main/kotlin/mihon/buildlogic/AndroidConfig.kt
#	core/archive/build.gradle.kts
#	core/common/build.gradle.kts
#	gradle/build-logic/src/main/kotlin/mihon/gradle/BuildConfig.kt
#	settings.gradle.kts
#	source-api/build.gradle.kts
#	source-local/build.gradle.kts
#	telemetry/build.gradle.kts
2026-04-06 15:50:09 -04:00
Weblate (bot) d225b7c586 Translations update from Hosted Weblate (#3003)
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/be/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/fi/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/tr/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/be/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/fi/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/fil/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ja/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ko/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/lv/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/nl/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ta/
Translation: Mihon/Mihon
Translation: Mihon/Mihon Plurals

Co-authored-by: A <ogloppi@mailbox.org>
Co-authored-by: Infy's Tagalog Translations <ced.paltep10@gmail.com>
Co-authored-by: Kehribar <103407696+dpentx@users.noreply.github.com>
Co-authored-by: Lucas Correia <anicetoclucas@gmail.com>
Co-authored-by: ScratchBuild <foobarbuzz@gmail.com>
Co-authored-by: Siebrenvde <siebren@siebrenvde.dev>
Co-authored-by: lilp <felipegabriel.avila6@gmail.com>
Co-authored-by: nadevko <ormak@protonmail.com>
Co-authored-by: தமிழ்நேரம் <tamilneram247@gmail.com>
Co-authored-by: ℂ𝕠𝕠𝕠𝕝 (𝕘𝕚𝕥𝕙𝕦𝕓.𝕔𝕠𝕞/ℂ𝕠𝕠𝕠𝕝) <coool@mail.lv>
Co-authored-by: 안세훈 <on9686@gmail.com>
# Conflicts:
#	i18n/src/commonMain/moko-resources/be/strings.xml
2026-04-06 15:27:10 -04:00
AntsyLich 4c51d01236 Merge and cleanup version catalogs (#3103)
# Conflicts:
#	app/build.gradle.kts
#	core/archive/build.gradle.kts
#	gradle/libs.versions.toml
#	i18n/build.gradle.kts
#	settings.gradle.kts
#	source-api/build.gradle.kts
2026-04-06 15:26:05 -04:00
Mend Renovate 4d46e84f54 Update dependency com.google.firebase:firebase-bom to v34.11.0 (#3094) 2026-04-06 15:06:15 -04:00
AntsyLich af51607053 Replace preference getter functions with properties (#3091)
# Conflicts:
#	app/src/main/java/eu/kanade/domain/source/interactor/GetEnabledSources.kt
#	app/src/main/java/eu/kanade/domain/source/service/SourcePreferences.kt
#	app/src/main/java/eu/kanade/domain/ui/UiPreferences.kt
#	app/src/main/java/eu/kanade/presentation/library/LibrarySettingsDialog.kt
#	app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAdvancedScreen.kt
#	app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsLibraryScreen.kt
#	app/src/main/java/eu/kanade/presentation/reader/settings/GeneralSettingsPage.kt
#	app/src/main/java/eu/kanade/presentation/reader/settings/ReadingModePage.kt
#	app/src/main/java/eu/kanade/tachiyomi/App.kt
#	app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadProvider.kt
#	app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateJob.kt
#	app/src/main/java/eu/kanade/tachiyomi/di/PreferenceModule.kt
#	app/src/main/java/eu/kanade/tachiyomi/source/SourceExtensions.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/base/delegate/SecureActivityDelegate.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryScreenModel.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderViewModel.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderPreferences.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ViewerConfig.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/stats/StatsScreenModel.kt
#	app/src/main/java/eu/kanade/tachiyomi/util/CrashLogUtil.kt
#	app/src/main/java/mihon/feature/migration/list/MigrationListScreenModel.kt
#	core/common/src/main/kotlin/eu/kanade/tachiyomi/network/NetworkHelper.kt
#	domain/src/main/java/tachiyomi/domain/library/service/LibraryPreferences.kt
2026-04-06 15:06:05 -04:00
Leodyver Semilla 1c8e6dcd6f Fix extension actions disappearing after installing and uninstalling in same session (#3049)
Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com>
# Conflicts:
#	CHANGELOG.md
2026-04-06 14:20:49 -04:00
AntsyLich 7a398dabba Make retry in reader redownload image (#3089)
# Conflicts:
#	CHANGELOG.md
#	app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/HttpPageLoader.kt
2026-04-06 14:18:57 -04:00
Leodyver Semilla b7fcf7ccda Fix WebView JavaScript dialogs popup after screen is closed (#3041)
Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com>
# Conflicts:
#	CHANGELOG.md
2026-04-06 14:13:39 -04:00
Leodyver Semilla acbda604cc MangaUpdates API content-type heade (#3021)
Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com>
# Conflicts:
#	CHANGELOG.md
2026-04-06 14:13:18 -04:00
Leodyver Semilla 97f3dd3b25 Fix tracker-induced duplicate key crash in duplicate detection (#3040)
# Conflicts:
#	CHANGELOG.md
2026-04-06 14:12:59 -04:00
Mend Renovate 60758f89ed Update dependency com.diffplug.spotless:spotless-plugin-gradle to v8.4.0 (#3086) 2026-04-06 14:12:41 -04:00
KaiserBh e96895345e feat(sync): prevent deleted "ghost chapters" from reappearing during sync. (#1575)
* feat(sync): prevent deleted "ghost chapters" from reappearing during sync.

- Pass lastSyncTime down to mergeChapters in SyncService.kt.
- Apply timestamp-based tombstoning logic to chapter merging. When a chapter is missing from either the local or remote backup, its `lastModifiedAt` timestamp is checked against the device's last sync time.
- Ensure that chapters deleted on one device (or removed by a source) are recognized as deletions and dropped from the merged backup, rather than being erroneously restored as "new" chapters on subsequent syncs.

* chore: change timestamp to use duration-based calculations

* chore: spotless
2026-04-06 13:08:30 -04:00
MediocreLegion eec1236b8b fix(delegate): migrate NH to the v2 api (#1581)
* fix(delegate): migrate NH to the v2 api

* remove extra comment

* remove redundant data

* linting

* Code cleanup

---------

Co-authored-by: Jobobby04 <jobobby04@users.noreply.github.com>
2026-04-03 12:59:13 -04:00
Weblate (bot) ee1e783126 Translations update from Hosted Weblate (#1577)
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/ja/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/ko/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/ru/
Translation: Mihon/TachiyomiSY

Co-authored-by: Dexroneum <Rozhenkov69@gmail.com>
Co-authored-by: ScratchBuild <foobarbuzz@gmail.com>
Co-authored-by: ZenVinny <atdenada@gmail.com>
Co-authored-by: 안세훈 <on9686@gmail.com>
2026-04-03 12:50:27 -04:00
renovate[bot] f3ab39cb1f Update dependency net.zetetic:sqlcipher-android to v4.14.1 (#1583)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-03 12:50:00 -04:00
KaiserBh ba75395648 refactor: improve sync merging categories (#1559)
* feat: Add versioning to categories

* feat: use random UID for categories.

For legacy and migration we should assign uid on insert, and modify existing one as well in the migration.

* feat: sync category metadata

Add version, uid and lastModifiedAt fields to Category model to allow syncing.

* chore: fix category merging logic

Improve the category merging logic by matching using UIDs first, with a fallback to matching by name for legacy remote categories.

Previously, categories were only matched by name, which could lead to incorrect merges if names were changed. This change ensures more accurate synchronization by prioritizing the unique identifier. Conflict resolution is now based on the `version` field, and logging has been added for better visibility into the merging process.

* refactor: prioritize UID when restoring categories

If a category with the same UID exists, update it instead of creating a new one. Fallback to matching by name if no UID match is found.

* chore: add isSyncing flag like before.

This make sure the version is consistent, and it's not accidentally appended by the trigger, if it does then one device will always be ahead, than previous, and they need to make multiple changes to increase the version.

* Apply suggestion from @jobobby04

Use SY specific numbers(601, 602 for now)

Co-authored-by: jobobby04 <jobobby04@users.noreply.github.com>

* chore: commit review, re-order.

* chore: surround changes in // SY --> // SY <--

* refactor: fallback to existing category UID if backup UID is 0 during restore.

when dealing with old backups (backups created before we added UIDs). In those old backups, backupCategory.uid defaults to 0.
If a user restored an old backup, it would match by name, and then overwrite the newly generated local UID with 0. This would break the synchronization.

* refactor: change to 6xx

* feat: improve sync reliability for categories and settings

- Refactor `mergeCategoriesLists` to correctly match categories by name when UID matching fails, ensuring better reconciliation across devices.
- Fix a bug in category merging where multiple categories with UID 0 (common for non-synced items) caused data loss.
- Update `SyncManager` to detect changes in categories, sources, preferences, saved searches, and extension repos, ensuring they synchronize even when the library favorites haven't changed.
- Convert `BackupCategory` and `BackupExtensionRepos` to data classes to support robust content-aware comparison during the sync process.
- Fix data loss in `mergeSourcesLists`, `mergePreferencesLists`, and `mergeSavedSearchesLists` by retaining local versions when conflicting with remote data.

* fix(sync): properly sync category deletions across devices

Previously, the sync system could not distinguish between a category that was deleted locally and a new category created on another device, causing deleted categories to be restored from the remote backup.

- Update `SyncService` to use `lastSyncTimestamp` to deduce if a missing local category was deleted (if modified before last sync) or newly created remotely (if modified after).
- Update `SyncManager` to explicitly delete local categories that are absent from the merged remote backup, propagating deletions to other devices.
- Fix `RestoreOptions` in `SyncManager` to respect the user's sync preferences instead of hardcoding `categories = true`.

* chore: change it to 6xx and not 600.

* chore: don't need to change this.

* chore: use kotlin time duration units

---------

Co-authored-by: jobobby04 <jobobby04@users.noreply.github.com>
2026-04-03 12:49:37 -04:00
Weblate (bot) fe0b14ab97 Translations update from Hosted Weblate (#1561)
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy-plurals/be/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy-plurals/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy-plurals/ta/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy-plurals/tr/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/be/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/ko/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/ta/
Translation: Mihon/TachiyomiSY
Translation: Mihon/TachiyomiSY Plurals

Co-authored-by: Kehribar <103407696+dpentx@users.noreply.github.com>
Co-authored-by: Lucas Correia <anicetoclucas@gmail.com>
Co-authored-by: lilp <felipegabriel.avila6@gmail.com>
Co-authored-by: nadevko <ormak@protonmail.com>
Co-authored-by: தமிழ்நேரம் <tamilneram247@gmail.com>
Co-authored-by: 안세훈 <on9686@gmail.com>
2026-03-18 19:55:58 -04:00
renovate[bot] 91d2140288 Update koin to v4.2.0 (#1569)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-18 19:47:20 -04:00
renovate[bot] 0417969dd6 Update dependency net.zetetic:sqlcipher-android to v4.14.0 (#1567)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-18 19:47:08 -04:00
AntsyLich 5d8d2ce48a Switch to AndroidX bundled sqlite driver (#3082)
# Conflicts:
#	app/build.gradle.kts
#	app/src/main/java/eu/kanade/tachiyomi/di/AppModule.kt
2026-03-18 19:45:20 -04:00
Mend Renovate b15277f134 Update paging.version to v3.4.2 (#3063) 2026-03-18 19:21:01 -04:00
Mend Renovate 76ca27f681 Update kotlin monorepo to v2.3.20 (#3074) 2026-03-18 19:20:57 -04:00
Mend Renovate 56923c76d4 Update sqldelight to v2.3.2 (#3077) 2026-03-18 19:20:53 -04:00
MajorTanya 32e19736b9 Address bundleOf deprecation (#3073) 2026-03-18 19:20:48 -04:00
Mend Renovate 11b01b2771 Update sqldelight to v2.3.1 (#3071)
Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com>
2026-03-18 19:20:45 -04:00
Mend Renovate 460ff13e54 Update dependency io.kotest:kotest-assertions-core to v6.1.7 (#3062) 2026-03-18 19:20:42 -04:00
Mend Renovate 57f77c8105 Update moko to v0.26.1 (#3068) 2026-03-18 19:20:39 -04:00
Mend Renovate a2eb22964a Update dependency com.squareup.okio:okio to v3.17.0 (#3070) 2026-03-18 19:20:36 -04:00
Mend Renovate 7158bae26a Update dependency androidx.activity:activity-compose to v1.13.0 (#3065) 2026-03-18 19:20:32 -04:00
Mend Renovate 807ce846d5 Update dependency androidx.core:core-ktx to v1.18.0 (#3067) 2026-03-18 19:20:29 -04:00
Mend Renovate 0b68f2c62a Update dependency androidx.compose:compose-bom to v2026.03.00 (#3066) 2026-03-18 19:20:26 -04:00
AntsyLich b7d6cc8dd0 Add installation id for feature flags (#3052)
# Conflicts:
#	app/build.gradle.kts
#	app/src/main/java/eu/kanade/tachiyomi/util/CrashLogUtil.kt
#	app/src/main/java/mihon/core/migration/migrations/Migrations.kt
2026-03-18 19:20:17 -04:00
Mend Renovate 8b1fd30902 Update dependency androidx.compose:compose-bom to v2026.02.01 (#3009) 2026-03-18 19:09:37 -04:00
Mend Renovate aff43f3aeb Update dependency com.google.firebase:firebase-bom to v34.10.0 (#3006) 2026-03-18 19:09:29 -04:00
Mend Renovate 0047d2e5d8 Update dependency com.diffplug.spotless:spotless-plugin-gradle to v8.3.0 (#3029) 2026-03-18 19:09:22 -04:00
Mend Renovate d87385f5b3 Update dependency com.materialkolor:material-kolor to v5.0.0-alpha07 (#3024) 2026-03-18 19:09:15 -04:00
AntsyLich c17e9573b7 Reapply "Fix cache invalidation isn't done at startup (#2970)"
This reverts commit d219c5e3bbcfb24c40fa69e40bff11b6fd81fd7f.

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadCache.kt
2026-03-18 19:08:43 -04:00
AntsyLich 9c01119d24 Reapply "Fix thread starvation caused by not yielding or using an inappropriate thread pool (#2955)"
This reverts commit 1d7c838ae64e624d9dd0884722f0c6ae5d18e386.

# Conflicts:
#	CHANGELOG.md
#	app/src/main/java/eu/kanade/tachiyomi/data/cache/ChapterCache.kt
#	app/src/main/java/eu/kanade/tachiyomi/extension/ExtensionManager.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderViewModel.kt
2026-03-18 19:06:16 -04:00
Jobobby04 bbc839e234 Lint 2026-02-27 22:44:01 -05:00
Jobobby04 917f20894b Bump version code 2026-02-27 22:08:28 -05:00
Jobobby04 3a3b719b8b Copy last page read in migrate 2026-02-27 22:07:59 -05:00
Jobobby04 1903437ecf Cleanup 2026-02-27 22:07:42 -05:00
Jobobby04 5c26bb3a52 Add recommended proguard rules 2026-02-27 22:07:31 -05:00
Jobobby04 07599ade3a Fix blank page on cloudflare guard 2026-02-27 13:49:26 -05:00
Jobobby04 0a9f36402b Remove migrate button from merged manga 2026-02-27 13:38:28 -05:00
Weblate (bot) d2b325cd02 Translations update from Hosted Weblate (#2997)
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/cs/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/vi/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/zh_Hant/
Translation: Mihon/Mihon

Co-authored-by: Filip Jaruška <filip.jaruska@gmail.com>
Co-authored-by: Nguyễn Trung Đức <vaicato16@gmail.com>
Co-authored-by: ɴᴇᴋᴏ <s99095lkjjim@gmail.com>
(cherry picked from commit cc3f640faa7df9f2a64976d2639e6dfd60ebe213)
2026-02-27 13:33:34 -05:00
AntsyLich cdc64aceb7 Fix extension install/update stuck at pending (#3000)
Co-authored-by: p
(cherry picked from commit 84265febf3ce24d71994ced2b81215f858430d4e)

# Conflicts:
#	CHANGELOG.md
2026-02-27 13:33:28 -05:00
Mend Renovate 4bfd6e4026 Update dependency io.kotest:kotest-assertions-core to v6.1.4 (#2998)
(cherry picked from commit 171a06a8baccae7fb21d2c60150639941747d90c)
2026-02-27 13:33:01 -05:00
Weblate (bot) 50eebdf7d3 Translations update from Hosted Weblate (#2980)
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/de/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/el/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/eo/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/es/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/hr/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ru/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/sk/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/tr/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/zh_Hans/
Translation: Mihon/Mihon

Co-authored-by: Dexroneum <Rozhenkov69@gmail.com>
Co-authored-by: Frosted <frosted@users.noreply.hosted.weblate.org>
Co-authored-by: Jakub Szafranek13 Fabijan <jakubfabijan@tuta.io>
Co-authored-by: KraXen <dpelech1@gmail.com>
Co-authored-by: Lyfja <45209212+lyfja@users.noreply.github.com>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: Pitpe11 <giorgos2550@gmail.com>
Co-authored-by: Swyter <swyterzone@gmail.com>
Co-authored-by: ZerOriSama <godarms2010@live.com>
(cherry picked from commit 565379779f82ee7dfdad45e251d82ff73dc3b7b2)
2026-02-27 13:32:56 -05:00
AntsyLich f843de28d7 Run automatic library updates even when connected to a VPN (#2996)
Co-authored-by: jeremiejig <3978761+jeremiejig@users.noreply.github.com>
(cherry picked from commit 039471427448347a1c12c39a488a1127a3ea1497)

# Conflicts:
#	CHANGELOG.md
#	app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateJob.kt
2026-02-27 13:32:48 -05:00
Cuong-Tran d250a9a680 Going back now first clears search query on browse extension tab (#2906)
Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com>
(cherry picked from commit 75b445fa8fd42b882266e27d9b979b22ca37d42a)

# Conflicts:
#	CHANGELOG.md
2026-02-27 13:30:07 -05:00
AntsyLich 4130db3920 Add all pages of adjacent chapters in the UI instead of only the first or last three (#2995)
(cherry picked from commit 0cc724108b4f29a3d1d33ac4666a14873460a657)

# Conflicts:
#	CHANGELOG.md
2026-02-27 13:29:44 -05:00
Mend Renovate f2cbff04ab Update dependency io.coil-kt.coil3:coil-bom to v3.4.0 (#2992)
(cherry picked from commit 5b85084d0a90b241fdf1d3ad018a27b49db15f12)
2026-02-27 13:29:19 -05:00
AntsyLich 061e9359e8 Fix migration dialog not showing for consecutive prompts from the same screen (#2994)
(cherry picked from commit 8b2d35f3068a3f9c5e1bba77ed825ae51531c91c)

# Conflicts:
#	CHANGELOG.md
2026-02-27 13:29:16 -05:00
AntsyLich 73258e9e05 Fix migration's selected sources order not preserved (#2993)
(cherry picked from commit 47816d4b218e6a62ef9fcd3097b6b0b8f2f95b17)

# Conflicts:
#	CHANGELOG.md
2026-02-27 13:28:55 -05:00
NarwhalHorns 73e4982ffb Utilize tracker for library duplicate detection (#2978)
Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com>
(cherry picked from commit 89bbdb17fb4ed1cbe99c14f389940e0f91093a10)

# Conflicts:
#	CHANGELOG.md
2026-02-27 13:28:38 -05:00
NarwhalHorns 185cd923c0 Add option for bookmarked chapters to download dropdown (#2891)
(cherry picked from commit 3c6f0f1697ccab055ee7af47da84b2161d406f0c)

# Conflicts:
#	CHANGELOG.md
#	app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryScreenModel.kt
2026-02-27 13:28:16 -05:00
NarwhalHorns 3cfc53bf11 Optimize tracked library filter (#2977)
Co-authored-by: NarwhalHorns <onefailedgamer@gamil.com>
Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com>
(cherry picked from commit ab214526c6f24466a0432b5c5c7d254a244cd958)

# Conflicts:
#	CHANGELOG.md
2026-02-27 13:21:29 -05:00
Weblate (bot) 1301acfdb7 Translations update from Hosted Weblate (#2843)
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ar/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ca/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/de/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/eo/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/es/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/fil/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/fr/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/hi/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/hr/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/id/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ja/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ko/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/my/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/pl/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ru/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/tr/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/vi/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/zh_Hant/
Translation: Mihon/Mihon

Co-authored-by: Ai Ai Ecchi <aiaiecchi9og@gmail.com>
Co-authored-by: Alexandre Dhooge <alexandre.dhooge@zaclys.net>
Co-authored-by: Cuong Tran <cuongtran.tm@gmail.com>
Co-authored-by: Dexroneum <Rozhenkov69@gmail.com>
Co-authored-by: Eduard Ereza Martínez <eduard@ereza.cat>
Co-authored-by: Frosted <frosted@users.noreply.hosted.weblate.org>
Co-authored-by: Hualiang <642615676@qq.com>
Co-authored-by: Infy's Tagalog Translations <ced.paltep10@gmail.com>
Co-authored-by: Jakub Szafranek13 Fabijan <jakubfabijan@tuta.io>
Co-authored-by: Lyfja <45209212+lyfja@users.noreply.github.com>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: MuhamadSyabitHidayattulloh <tebepc@gmail.com>
Co-authored-by: Swyter <swyterzone@gmail.com>
Co-authored-by: Throw Away <throwawayacc4gulshan@gmail.com>
Co-authored-by: ZerOriSama <godarms2010@live.com>
Co-authored-by: akir45 <akkn0708@gmail.com>
Co-authored-by: clukki <nguyenhuuminh16911@gmail.com>
Co-authored-by: momoehab <momoehab@gmail.com>
Co-authored-by: yumekon <konrad.nowicki91@gmail.com>
Co-authored-by: ɴᴇᴋᴏ <s99095lkjjim@gmail.com>
Co-authored-by: 안세훈 <on9686@gmail.com>
(cherry picked from commit 7c7d35e2c64d4f85b0db431fbe18408698af9c6e)
2026-02-27 13:21:06 -05:00
Cuong-Tran 9d9dbea48d Remove redundant userSelected from selection methods (#2976)
(cherry picked from commit 9867c160f781b52cd297f7b1202cc6963b375df0)

# Conflicts:
#	app/src/main/java/eu/kanade/presentation/updates/UpdatesUiItem.kt
2026-02-27 13:19:34 -05:00
Cuong-Tran c1df3eb1d0 Don't wrap an intent-chooser inside another intent-chooser (#2921)
(cherry picked from commit 20c899f2cd83fdd37dfc14d58ded6ae7581d3d65)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreen.kt
2026-02-27 13:19:12 -05:00
Jobobby04 3154c97aee Fix some build warnings 2026-02-27 13:17:48 -05:00
Mend Renovate ffe1b160de Update moko to v0.26.0 (#2967)
(cherry picked from commit 27749fc583527ab1360594a69ef586a4311c93f5)
2026-02-27 13:10:37 -05:00
Mend Renovate 23272375b7 Update dependency com.google.firebase:firebase-bom to v34.9.0 (#2964)
(cherry picked from commit 2248bdac546914492b0adf75425915b899749900)
2026-02-27 13:10:30 -05:00
Mend Renovate 863b6ee784 Update dependency org.junit.jupiter:junit-jupiter to v6.0.3 (#2963)
(cherry picked from commit 42c7329a9e17ab15c0dc1c1f33eabf54286f9339)
2026-02-27 13:10:25 -05:00
Mend Renovate c4c8d4b9c3 Update dependency androidx.compose:compose-bom to v2026.02.00 (#2962)
(cherry picked from commit 5be5a4e81978954713da6f7faa24cc9956c823e9)
2026-02-27 13:10:18 -05:00
Mend Renovate b2bbbca585 Update dependency androidx.activity:activity-compose to v1.12.4 (#2959)
(cherry picked from commit b924d582f459835f533fa54badbe129eede4388f)
2026-02-27 13:10:12 -05:00
Mend Renovate df3b879cf6 Update kotlin monorepo to v2.3.10 (#2960)
(cherry picked from commit 6f601a18c5beb78a70a94471abc2960fb37199b4)
2026-02-27 13:10:05 -05:00
Mend Renovate 47c4f2cc8c Update paging.version to v3.4.1 (#2961)
(cherry picked from commit 1ff9a5625c442be1c9504df0f0eabdaf24aa2fda)
2026-02-27 13:10:00 -05:00
Luca Auer 905a1c1230 Add missing indexes to improve database query performance (#2950)
(cherry picked from commit cae9fbf3213987e7d263845431dfac10a2ecb3b0)

# Conflicts:
#	data/src/main/sqldelight/tachiyomi/migrations/10.sqm
2026-02-27 13:09:55 -05:00
Mend Renovate bcaf7f6415 Update dependency io.kotest:kotest-assertions-core to v6.1.3 (#2939)
(cherry picked from commit d17976c91068944be1a5cba9a959c3763f589590)
2026-02-27 13:02:50 -05:00
Mend Renovate 4639b3ecc3 Update dependency com.materialkolor:material-kolor to v5.0.0-alpha06 (#2938)
(cherry picked from commit b609166702e0788160a557fa1470c6dd8e585169)
2026-02-27 13:02:44 -05:00
MajorTanya 2034971cc0 Clean up some build warnings (#2929)
* Replace deprecated rememberPlainTooltipPositionProvider

* Remove superfluous when branch

This when is marked as exhaustive.

* Replace deprecated LibrariesContainer call

AboutLibraries now wants us to produce the libraries ourselves.

* Replace deprecated ClipboardManager with Clipboard

Clipboard uses suspend functions, hence the coroutine scope addition.

* Use multi-dollar strs to simplify GraphQL queries

These have been available since Kotlin 2.1.

* Remove various redundant casts & conversions

- WebViewScreenContent: loadingState is in the LoadingState.Loading
  branch, no need to cast at all
- Bangumi: username is not modified, make val
- Kavita: token is already a String
- PagerViewerAdapter: insertPageLastPage is already null-checked
- PagerViewerAdapter: use reified filterIsInstance
- ReaderViewModel: chapter IDs are already Longs
- CloudflareInterceptor: webview is smart-cast to non-null here

* Replace deprecated MenuAnchorType

Literally just a typealias for ExposedDropdownMenuAnchorType anyway.

* OptimizeNonSkippingGroups is enabled by default

* Suppress shadowing warning

This is explicitly intentional according to the KDocs.

* Migrate Context Receivers to Context Parameters

Requires changing the compiler arg, but that is part of the migration:

https://blog.jetbrains.com/kotlin/2025/04/update-on-context-parameters

Apparently, the only visible change is that names are required now.
"_" can be used for anonymous context parameters.

* Fix expression bodies with explicit return

Naming conflict resolved by aliasing.

From 2.4/2.5 onward, these will only be allowed with explicit return
types, or have to be turned into a block body. I opted for the latter
since the function is reasonably dense already.

see: https://youtrack.jetbrains.com/issue/KTLC-288

* Suppress deprecation of non-AutoMirrored icons

We use these arrows for navigation in the Upcoming screen.
I strongly doubt the AutoMirrored versions would make sense for our
use-case.

* Explicitly opt-in to new annotation default rules

affects the following annotated value-parameters:
- Preference.SliderPreference.steps (`@IntRange`)
- ReaderViewModel.State.brightnessOverlayValue (`@IntRange`)
- ReadingMode.iconRes (`@DrawableRes`)
- MigrationListScreenModel.Dialog.Progress.progress (`@FloatRange`)

see: https://youtrack.jetbrains.com/issue/KT-73255
see: https://github.com/Kotlin/KEEP/blob/change-defaulting-rule/proposals/annotation-target-in-properties.md

Warning message was the following:

    This annotation is currently applied to the value parameter only, but in the future it will also be applied to field.
    - To opt in to applying to both value parameter and field, add '-Xannotation-default-target=param-property' to your compiler arguments.
    - To keep applying to the value parameter only, use the '@param:' annotation target.

(cherry picked from commit b543bc089a442c5e93b0fb6c83bc4037740b1eb5)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerViewerAdapter.kt
#	core/common/src/main/kotlin/eu/kanade/tachiyomi/network/interceptor/CloudflareInterceptor.kt
#	core/common/src/main/kotlin/mihon/core/common/archive/ArchiveInputStream.kt
2026-02-27 13:02:31 -05:00
Mend Renovate bb8698b2a6 Update dependency androidx.compose:compose-bom to v2026.01.01 (#2913)
(cherry picked from commit 100cea0757c930b153e50ca2ba52e4c06f14800d)
2026-02-27 12:52:37 -05:00
Mend Renovate cd69b09dd0 Update dependency androidx.work:work-runtime to v2.11.1 (#2914)
(cherry picked from commit e092b4208a0f8476c81ed58a2b0efd3a7c5996cf)
2026-02-27 12:52:29 -05:00
Mend Renovate 462b2164e8 Update paging.version to v3.4.0 (#2916)
(cherry picked from commit 1bf4eff931781eff11e3c1d59ca3747ffb069203)
2026-02-27 12:52:23 -05:00
Mend Renovate fb1a4ad828 Update dependency androidx.activity:activity-compose to v1.12.3 (#2917)
(cherry picked from commit b70edfac58e8e5722a51be398212ac025b818258)
2026-02-27 12:52:17 -05:00
Mend Renovate 3bd89cee26 Update markdown to v0.39.2 (#2923)
(cherry picked from commit 9c0eebb55ceb6a7edc50e414b4be19faf256bcda)
2026-02-27 12:52:11 -05:00
Mend Renovate 6f43e98fff Update dependency io.kotest:kotest-assertions-core to v6.1.2 (#2908)
(cherry picked from commit f6f1d13addea504ff7ed6ec87276d1cfdfcf2013)
2026-02-27 12:52:06 -05:00
Mend Renovate 6feeb4b1ee Update dependency com.diffplug.spotless:spotless-plugin-gradle to v8.2.1 (#2909)
(cherry picked from commit 31a9ff261e5e195fa2e27615bae0a86956a3c90a)
2026-02-27 12:52:00 -05:00
Mend Renovate fcfe750fcf Update dependency io.mockk:mockk to v1.14.9 (#2904)
(cherry picked from commit c0a1203541931a9090e6769acdb596c9ea4a011b)
2026-02-27 12:51:55 -05:00
Cuong-Tran 6e314e3643 Fix Add Repo input not taking up the full dialog width (#2816)
(cherry picked from commit 82ffc8efa69cb86229fe8b677f12942c80b88a15)

# Conflicts:
#	CHANGELOG.md
2026-02-27 12:51:48 -05:00
Mend Renovate 487ca49c11 Update serialization.version to v1.10.0 (#2879)
(cherry picked from commit d6e17b04c39c9d800c57d75e29714a51fbf902f8)
2026-02-27 12:51:27 -05:00
Mend Renovate 698abe8667 Update dependency com.diffplug.spotless:spotless-plugin-gradle to v8.2.0 (#2892)
(cherry picked from commit e6c67003511b601d49bc175b83596568ddfe09d9)
2026-02-27 12:51:20 -05:00
Mend Renovate 13c9daf9a9 Update dependency io.kotest:kotest-assertions-core to v6.1.1 (#2893)
(cherry picked from commit ede2f56bc6531f69553d0f95cf422b7f6d15b90b)
2026-02-27 12:51:14 -05:00
Mend Renovate eb21454d6d Update Gradle to v8.14.4 (#2894)
(cherry picked from commit 2037ec45006b54da0e64b3e07bae4c87e261ee59)
2026-02-27 12:51:07 -05:00
Cuong-Tran 56347e6d52 Fix memoization in manga bottom action menus (#2886)
(cherry picked from commit 533a578bdb438fe4a23e069386a6616c7daedcc4)
2026-02-27 12:50:46 -05:00
MajorTanya 5c085a36e8 Reword download index message (#2874)
I'm tired of people thinking the current wording is an error. Improved wordings welcome, this was just my first decent guess.

(cherry picked from commit 05d90ea4d652cd7ead385ec954e0ae2dc332a012)

# Conflicts:
#	CHANGELOG.md
2026-02-27 12:50:38 -05:00
Mend Renovate 65ab676946 Update dependency io.kotest:kotest-assertions-core to v6.1.0 (#2870)
(cherry picked from commit 49c4d08b22b6a440b93b58bd78280807550d6198)
2026-02-27 12:50:19 -05:00
MajorTanya 1f51569a35 Add Filters to Updates screen (#2851)
* Add Filters to Updates screen

Behaves basically like the filters in the library:

- Unread: Show/Don't show unread chapters
- Downloaded: Show/Don't show downloaded chapters
- Started: Show/Don't show chapters that have some progress but aren't
  fully Read
- Bookmarked: Show/Don't show chapters that have been bookmarked

Started behaves differently from its Library counterpart because the
actual manga data is not available at this point in time and I thought
calling getManga for each entry without caching would be a pretty bad
idea.

I have modelled this closely on the filter control flow in the
Library, but I'm sure this can be simplified/adjusted in some way.

* Move most filtering logic to SQL

Unread, Started, and Bookmarked filters are now part of the SQL query.

Download state cannot be filtered in the database so it remains in
Kotlin.

Because the Downloaded filter has to be run in Kotlin, the combine
flow uses the preferences flow twice, once to get the SQL query params
and once for the Kotlin filters (only Downloaded at this time).

* Add "Hide excluded scanlators" to update filters

Based on the work done in #1623 but integrated with the other filters
in this PR. Added the user as a co-author for credit.

Co-authored-by: Dani <17619547+shabnix@users.noreply.github.com>

---------

Co-authored-by: Dani <17619547+shabnix@users.noreply.github.com>
(cherry picked from commit bbe9aa8561360f030072fbc49f79748e71c6535e)

# Conflicts:
#	CHANGELOG.md
#	app/src/main/java/eu/kanade/tachiyomi/di/PreferenceModule.kt
#	data/src/main/java/tachiyomi/data/updates/UpdatesRepositoryImpl.kt
#	data/src/main/sqldelight/tachiyomi/migrations/9.sqm
#	domain/src/main/java/tachiyomi/domain/updates/interactor/GetUpdates.kt
2026-02-27 12:35:44 -05:00
Jobobby04 b0d6e16ca3 Fix build 2026-02-27 11:51:08 -05:00
Mend Renovate 85cf54ccc8 Update dependency com.google.firebase:firebase-bom to v34.8.0 (#2856)
(cherry picked from commit 13975d6f7eea21b3ba4be31736038ef2f855bfea)
2026-02-27 11:46:14 -05:00
Mend Renovate 602df5a729 Update dependency androidx.compose:compose-bom to v2026 (#2853)
(cherry picked from commit e659e90c26814c9a29bf668545b4f10294f3c6b9)
2026-02-27 11:46:08 -05:00
Mend Renovate c8102836ce Update dependency com.materialkolor:material-kolor to v5.0.0-alpha05 (#2849)
(cherry picked from commit 99e6fa3c06e1dc24255a73aa5741a72c82d94d91)
2026-02-27 11:46:02 -05:00
Mend Renovate e641575941 Update markdown to v0.39.1 (#2850)
(cherry picked from commit cf13012629571e2097796b50df238f69e62843b3)
2026-02-27 11:45:49 -05:00
NGB-Was-Taken 83afcee4d1 Fix crash when trying to install/update extensions while shizuku isn't running (#2837)
(cherry picked from commit 4ce249c1a0ee9f3a20d91214fd09145e0924b2e4)

# Conflicts:
#	CHANGELOG.md
2026-02-27 11:45:04 -05:00
MajorTanya 2102e0594e Fix nullability of MAL authors breaking search (#2834)
One of these days I'll get through a tracker change without
nullability problems...

(cherry picked from commit edcf84d9022e7436606a0b8c493c1035888ac60a)
2026-02-27 11:44:38 -05:00
Constantin Piber 14c91da6b3 Add a small increment to chapter number before comparison to fix progress sync issues for Suwayomi (#2675)
Due to a `Float->Double->Float` conversion somewhere inside Mihon, the
tracker sees 2.1 as 2.0999999046325684, which means this filter ignores
the 2.1 chapter (which we just tried to mark as read). This small
epsilon is small enough to never bother any serious usage, but large
enough to ignore any such conversion errors.

Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com>
(cherry picked from commit bd5c4d48f980d2d3dcc1112fe499dba17ef8e507)

# Conflicts:
#	CHANGELOG.md
2026-02-27 11:44:26 -05:00
MajorTanya 46c1c6463a Add authors/artists to MAL search results (#2833)
(cherry picked from commit 51b3ab3fd19bdf6a7c3bd2085104392a9c412622)

# Conflicts:
#	CHANGELOG.md
2026-02-27 11:44:10 -05:00
Weblate (bot) 89a521b836 Translations update from Hosted Weblate (#2806)
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/ca/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/ceb/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/fil/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/it/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/ru/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ar/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/bn/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ca/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ceb/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/fil/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/fr/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/it/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ko/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/pt_BR/
Translation: Mihon/Mihon
Translation: Mihon/Mihon Plurals

Co-authored-by: Ahmed TOUCHANE <ahmedtouchane0@gmail.com>
Co-authored-by: Anderhale <anderhale@users.noreply.hosted.weblate.org>
Co-authored-by: Eduard Ereza Martínez <eduard@ereza.cat>
Co-authored-by: Eugene <e.shlyapkin99@gmail.com>
Co-authored-by: Gino Cicatiello <ginocic@gmail.com>
Co-authored-by: Hiroshi <borlonjhayron1119@gmail.com>
Co-authored-by: Luis Antonio <getcyonic+zaorinu@gmail.com>
Co-authored-by: NormalRandomPeople <normal.scribe833@silomails.com>
(cherry picked from commit e6f72000ba62302c3e4817a5f17057e5a8d7eafc)
2026-02-27 11:43:50 -05:00
MajorTanya 65c6ed21ab Optimise MAL search queries by ~11x (#2832)
Previously, the app made one request for the search, and then fired
off 1 request per search result to obtain additional data, such as
each title's synopsis, etc.

However, MAL's search allows field selection during the initial query,
which will return all the data in that first response, avoiding the
massive bunch of requests (and alleviating some pressure on MAL from
our userbase).

By combining the selected fields into one constant, I was able to also
get rid of the MALUserListSearch entirely because it was redundant.
This allows for a unified MALManga->TrackSearch helper, further
reducing complexity.

I got to my "11x" improvement because on page of search results has 10
elements, and this change turns 11 (1+10 for results) requests into 1.

(cherry picked from commit 9bf2d78a421213b1885456f5b54c3286edc539e1)

# Conflicts:
#	CHANGELOG.md
#	app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListApi.kt
2026-02-27 11:42:54 -05:00
Mend Renovate 1b911e7e15 Update dependency org.junit.jupiter:junit-jupiter to v6.0.2 (#2830)
(cherry picked from commit 89c4e3bb39b7450a9aedcf9d720c74c04cd560ff)
2026-02-27 11:41:41 -05:00
Mend Renovate 0535e41051 Update dependency org.jsoup:jsoup to v1.22.1 (#2826)
(cherry picked from commit 47fe792ddc5a342ecc4685d57143cfb40f0682f7)
2026-02-27 11:41:32 -05:00
AntsyLich 3fc802f837 Remember descriptionAnnotator across composition
Closes #2510

Co-authored-by: Cuong-Tran <16017808+cuong-tran@users.noreply.github.com>
(cherry picked from commit 906d6f3cdbd6f7168d9cdea0c3eb8f9c663a09c2)
2026-02-27 11:41:17 -05:00
AntsyLich 976b5cc03e Cleanup extension screen search query predicate
(cherry picked from commit e059190fabe3cbe8498fc3cec7e39b0350f3c289)
2026-02-27 11:41:10 -05:00
AntsyLich a9fe971337 Switch to M3E ExtendedFloatingActionButton
(cherry picked from commit a39b5a56e853a9c11c0984b0385a2e60b0addc3a)
2026-02-27 11:40:06 -05:00
AntsyLich 5d1dbcb390 Switch to MaterialExpressiveTheme
(cherry picked from commit 3e6afee13b9fd5716f7f2d547b3edcd3e17915db)
2026-02-27 11:28:24 -05:00
AntsyLich 8d11ef3244 Use materilalKolor for monet compat color scheme
(cherry picked from commit 9a11ec8ead41cb7199e10f3c7464790a0bd3b1ad)
2026-02-27 11:28:18 -05:00
Weblate (bot) 724a61f513 Translations update from Hosted Weblate (#1536)
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy-plurals/ar/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy-plurals/ko/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/ar/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/es/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/fil/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/fr/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/hr/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/it/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/ko/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/ru/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/tr/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/zh_Hant/
Translation: Mihon/TachiyomiSY
Translation: Mihon/TachiyomiSY Plurals

Co-authored-by: Champ0999 <champ0999@users.noreply.hosted.weblate.org>
Co-authored-by: Dexroneum <Rozhenkov69@gmail.com>
Co-authored-by: Erick Alejandro <erickux@gmail.com>
Co-authored-by: Frosted <frosted@users.noreply.hosted.weblate.org>
Co-authored-by: Infy's Tagalog Translations <ced.paltep10@gmail.com>
Co-authored-by: Luis Antonio <getcyonic+zaorinu@gmail.com>
Co-authored-by: Metin <durmus38metin@gmail.com>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: NormalRandomPeople <normal.scribe833@silomails.com>
Co-authored-by: Swyter <swyterzone@gmail.com>
Co-authored-by: ZerOriSama <godarms2010@live.com>
Co-authored-by: momoehab <momoehab@gmail.com>
Co-authored-by: 안세훈 <on9686@gmail.com>
2026-02-27 11:25:48 -05:00
renovate[bot] 724c774dc9 Update dependency net.zetetic:sqlcipher-android to v4.13.0 (#1544)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-27 11:21:21 -05:00
renovate[bot] 29e0b2e4a5 Update actions/upload-artifact action to v7 (#1557)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-27 11:21:12 -05:00
KaiserBh 2776e41127 feat: Add sync events to SyncYomi (#1558)
* feat: Add sync events to SyncYomi

Now it will send the events back to `SyncYomi` server and then forward those to the notifications services that are enabled, such as discord, telegram, and etc.

* chore: fix build error.
2026-02-27 11:20:59 -05:00
Jobobby04 af1f77418f This is SY not Mihon Crashing 2026-02-13 22:41:04 -05:00
MajorTanya c1df5da062 This is SY not Mihon (#1549) 2026-01-31 11:24:37 -05:00
Jobobby04 f8f645772d Crashfix
Co-authored-by: name <arkon@users.noreply.github.com>
2026-01-01 12:26:13 -05:00
Jobobby04 b1e6fa65d6 Or 2025-12-26 23:31:31 -05:00
Jobobby04 01e8c6cc12 Use ComposeStars from RatingBar library. 2025-12-26 14:56:38 -05:00
Jobobby04 b4668c6829 Lint 2025-12-25 17:43:46 -05:00
Jobobby04 08d6c604bc Cleanup 2025-12-25 17:42:40 -05:00
Constantin Piber 02cec06535 Implement automatic removal of downloads on Suwayomi after reading, configurable via extension settings (#2673)
Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com>
(cherry picked from commit 1263df9d4111511e49a43463c9808060433ce76d)

# Conflicts:
#	CHANGELOG.md
2025-12-25 17:26:02 -05:00
Weblate (bot) ebdb3f7478 Translations update from Hosted Weblate (#2711)
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/ar/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/ka/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ar/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/bn/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/eo/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ka/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ko/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/tr/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/vi/
Translation: Mihon/Mihon
Translation: Mihon/Mihon Plurals

Co-authored-by: Anderhale <anderhale@users.noreply.hosted.weblate.org>
Co-authored-by: Frosted <frosted@users.noreply.hosted.weblate.org>
Co-authored-by: Hasanur Rahman Biplob <hrbiplob10@gmail.com>
Co-authored-by: Jakub Szafranek13 Fabijan <jakubfabijan@tuta.io>
Co-authored-by: Nguyễn Trung Đức <vaicato16@gmail.com>
Co-authored-by: Temuri Doghonadze <temuri.doghonadze@gmail.com>
Co-authored-by: ابْنُ السَدِيمِ <amarlubs2@gmail.com>
Co-authored-by: 안세훈 <on9686@gmail.com>
(cherry picked from commit c96b6ae562cee1220b9fec74708d447413ab8c35)
2025-12-25 17:25:49 -05:00
Mend Renovate 3724d79825 Update dependency androidx.compose:compose-bom to v2025.12.01 (#2651)
(cherry picked from commit 23c427cf60701e46e470fee8b0a7564804ec599e)
2025-12-25 17:25:46 -05:00
Mend Renovate c3e2eb6672 Update markdown to v0.39.0 (#2804)
(cherry picked from commit e3260d56f713d4f5411ae00dfd3da2aba87f4cf2)
2025-12-25 17:25:39 -05:00
Mend Renovate fa91695add Update aboutlib.version to v13.2.1 (#2803)
(cherry picked from commit f37afbcec9f21823cd894036b6ca7f464eb34481)
2025-12-25 17:25:35 -05:00
MajorTanya e7786bd16f Fix pre-1970 upload date display in chapter list (#2779)
A user in #2777 was using the ComicInfo.xml Year/Month/Day fields to
indicate date of publication for some American comics, which often
predate the UNIX Epoch of 1970.

They were seeing "N/A" displays because this line of code discarded
date information for any time before Jan 1st, 1970.

The `toRelativeString` extension function used in the other
`relativeDateText` function already accounts for very distant dates
(anything >7 days away turns into full date, not relative, regardless
of setting, though disabling the relative timestamp setting
circumvents this with the same result). Removing this line should not
cause any issues as it is purely a display difference and the use case
of backdating comics to pre-1970 is worth it in my opinion.

(cherry picked from commit 7a1c8a1b61e07d2e1a402b5daf0e7c04c232f655)

# Conflicts:
#	CHANGELOG.md
2025-12-25 17:25:31 -05:00
Mend Renovate 3d70476b9f Update dependency androidx.activity:activity-compose to v1.12.2 (#2797)
(cherry picked from commit 532b5cf290b448814ce5370bde461d9d5c8f086a)
2025-12-25 17:25:07 -05:00
Mend Renovate e74e0de8f5 Update kotlin monorepo to v2.3.0 (#2794)
(cherry picked from commit 3cb1b2e17a5f77d6133e6bf244304c2d6719aa04)
2025-12-25 17:24:59 -05:00
Luca Auer a2f552d6d2 Minimize memory usage by reducing in-memory cover cache size (#2266)
Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com>
(cherry picked from commit 4c9cfd8da5f9c67daa4b6401a910f979fd79179f)

# Conflicts:
#	CHANGELOG.md
2025-12-25 17:24:53 -05:00
AntsyLich a6bd0bbd2a Fix reader not saving read duration when changing chapter (#2784)
(cherry picked from commit 2e0786f699cc6d4863eb20331739c8325a451e63)

# Conflicts:
#	CHANGELOG.md
2025-12-25 17:24:36 -05:00
Mend Renovate fd42bba188 Update dependency com.google.firebase:firebase-bom to v34.7.0 (#2782)
(cherry picked from commit e7e4d9b6b35033a0568f40e32e94aaf336c96c39)
2025-12-25 17:24:06 -05:00
AntsyLich a0ec735066 Use AGP provided NDK and Build Tools version
(cherry picked from commit 5fe7dd9f0612412afabd7646f89ba38b230fb7e7)

# Conflicts:
#	buildSrc/src/main/kotlin/mihon/buildlogic/AndroidConfig.kt
2025-12-25 17:23:59 -05:00
Mend Renovate 89f5fce19d Update dependency com.android.tools.build:gradle to v8.13.2 (#2780)
(cherry picked from commit 4cb05cc738862be52c5f53e43c943f20712c6153)
2025-12-25 17:23:18 -05:00
Jobobby04 bf711a995c Fix build 2025-12-25 17:23:01 -05:00
AntsyLich d977614b7a Update tracker icons (#2773)
(cherry picked from commit 876c3f951b7e9782054d8f788ab39772ae6cf440)

# Conflicts:
#	CHANGELOG.md
#	app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/Shikimori.kt
2025-12-25 17:22:53 -05:00
Mend Renovate d282df6973 Update dependency androidx.activity:activity-compose to v1.12.1 (#2760)
(cherry picked from commit 08a61a42e9b01f5591615e298c2fecc9f59762ac)
2025-12-25 16:55:40 -05:00
Mend Renovate db5b3a69cc Update dependency io.mockk:mockk to v1.14.7 (#2771)
(cherry picked from commit cadd36ad9a5721d19ea51b68910b8b3276965b3d)
2025-12-25 16:55:35 -05:00
Mend Renovate c70c5dff25 Update dependency io.kotest:kotest-assertions-core to v6.0.7 (#2749)
(cherry picked from commit 556371e1c89bfb0961b63629e79d3fed6a8e7999)
2025-12-25 16:55:24 -05:00
AntsyLich 25ace80419 Cleanup BaseOAuthLoginActivity and TrackLoginActivity (#2748)
(cherry picked from commit c222a28bd14c989b6fa0d53d7497bf063887c9ec)
2025-12-25 16:55:13 -05:00
Jobobby04 b8b468cea7 Minor fixes 2025-12-25 16:49:01 -05:00
NGB-Was-Taken 0ffc798e9a Add preference to toggle chapter URL hash for downloads (#1533) 2025-12-25 16:47:56 -05:00
renovate[bot] ad5a76741a Update actions/upload-artifact action to v6 (#1530)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-25 16:46:49 -05:00
Weblate (bot) 003c5ad39a Translations update from Hosted Weblate (#1529)
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/es/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/fil/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/id/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/it/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/ru/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/tr/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/zh_Hant/
Translation: Mihon/TachiyomiSY

Co-authored-by: Dexroneum <Rozhenkov69@gmail.com>
Co-authored-by: Frosted <frosted@users.noreply.hosted.weblate.org>
Co-authored-by: Gino Cicatiello <ginocic@gmail.com>
Co-authored-by: Hiroshi <borlonjhayron1119@gmail.com>
Co-authored-by: Infy's Tagalog Translations <ced.paltep10@gmail.com>
Co-authored-by: MuhamadSyabitHidayattulloh <tebepc@gmail.com>
Co-authored-by: Nataniel Dika Kurniawan <hikawaart2@gmail.com>
Co-authored-by: Swyter <swyterzone@gmail.com>
Co-authored-by: ZerOriSama <godarms2010@live.com>
2025-12-25 16:46:06 -05:00
NGB-Was-Taken 582d0ef121 Add handling for previously unhandled preferences (delegated MD) (#1524)
* Include romanized titles of the original language in description

* Implement handling for `finalChapterInDesc` preference.

* Handle `preferExtensionLangTitle` preference when fetching manga details.

* Address some warnings, clean up unused code and spotless apply.
2025-12-11 13:58:56 -05:00
NGB-Was-Taken 5566db160b fix deletion of duplicate downloaded chapters when automatically marked as read (#1500) 2025-12-11 13:56:57 -05:00
renovate[bot] 6fb6838656 Update actions/checkout action to v6 (#1522)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-11 13:48:09 -05:00
renovate[bot] 1e5d490c22 Update actions/upload-artifact action to v5 (#1513)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-11 13:48:02 -05:00
renovate[bot] 276aeb0f59 Update gradle/actions action to v5 (#1508)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-11 13:47:56 -05:00
renovate[bot] c62d9d1446 Update actions/github-script action to v8 (#1497)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-11 13:47:44 -05:00
renovate[bot] 4ff18364d9 Update actions/setup-java action to v5 (#1493)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-11 13:47:36 -05:00
renovate[bot] 6c8e4e951a Update dependency net.zetetic:sqlcipher-android to v4.12.0 (#1485)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-11 13:47:28 -05:00
renovate[bot] dc1fde628d Update koin to v4.1.1 (#1466)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-11 13:47:09 -05:00
Weblate (bot) 241b70e5ce Translations update from Hosted Weblate (#1465)
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy-plurals/ar/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy-plurals/es/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy-plurals/fr/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy-plurals/ne/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy-plurals/vi/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/ar/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/de/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/eo/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/es/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/fil/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/fr/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/hr/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/hu/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/id/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/it/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/ja/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/ne/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/pt/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/ru/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/ta/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/tr/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/uk/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/vi/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/zh_Hant/
Translation: Mihon/TachiyomiSY
Translation: Mihon/TachiyomiSY Plurals

Co-authored-by: Acelith <joel.jon@moix.me>
Co-authored-by: Adolfo Jayme Barrientos <fitojb@ubuntu.com>
Co-authored-by: Anderhale <anderhale@users.noreply.hosted.weblate.org>
Co-authored-by: Champ0999 <champ0999@users.noreply.hosted.weblate.org>
Co-authored-by: Conrad Mateman <conradmateme001@gmail.com>
Co-authored-by: Crazyom <naxom@laposte.net>
Co-authored-by: Deleted User <noreply+48943@weblate.org>
Co-authored-by: Dexroneum <Rozhenkov69@gmail.com>
Co-authored-by: Dika <hikawaart2@gmail.com>
Co-authored-by: FateXBlood <fatexblood@gmail.com>
Co-authored-by: Frosted <frosted@users.noreply.hosted.weblate.org>
Co-authored-by: Giorgio Sanna <sannagiorgio1997@gmail.com>
Co-authored-by: Infy's Tagalog Translations <ced.paltep10@gmail.com>
Co-authored-by: Jakub Fabijan <jakubfabijan@tuta.io>
Co-authored-by: João Sousa <joaopsousa99@gmail.com>
Co-authored-by: Karley <siegitsi@gmail.com>
Co-authored-by: Lyfja <45209212+lyfja@users.noreply.github.com>
Co-authored-by: MajorTanya <github@majortanya.eu>
Co-authored-by: Manjul Tamrakar <manjultamrakar4@gmail.com>
Co-authored-by: Manuela Silva <mmsrs@sky.com>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: Mohamed kh <mohamedkhamekhami@gmail.com>
Co-authored-by: Nguyễn Trung Đức <vaicato16@gmail.com>
Co-authored-by: Omgeta <anooptiger@hotmail.com>
Co-authored-by: Rahim Kansous <rahimkansous18@gmail.com>
Co-authored-by: Swyter <swyterzone@gmail.com>
Co-authored-by: TheKingTermux <50316075+TheKingTermux@users.noreply.github.com>
Co-authored-by: WarriorDan <Danpgl@live.it>
Co-authored-by: ZerOriSama <godarms2010@live.com>
Co-authored-by: abc0922001 <abc0922001@hotmail.com>
Co-authored-by: dianisaac <muhandreop@gmail.com>
Co-authored-by: f_pluz <pedroh.lobo20@gmail.com>
Co-authored-by: ssantos <ssantos@web.de>
Co-authored-by: Đào Ngọc Đang Khoa <daongocdangkhoa2510@gmail.com>
Co-authored-by: ابْنُ السَدِيمِ <amarlubs2@gmail.com>
Co-authored-by: தமிழ்நேரம் <anishprabu.t@gmail.com>
2025-12-11 13:46:18 -05:00
Jobobby04 64c755ddf3 Lint 2025-12-05 13:45:55 -05:00
Jobobby04 3ae6c0131b Lanraragi delegation 2025-12-05 13:44:58 -05:00
NGB-Was-Taken e3b43de298 Spotless apply 2025-11-26 18:41:48 +05:45
AntsyLich 02ff6b4e2f Fix mass migration not using the same search queries as individual migration (#2736)
(cherry picked from commit 7161bc2e825bdfd66a1829f7dce42bd0570b1008)
2025-11-26 15:06:06 +05:45
NGB-Was-Taken ee8379b12a Fix shizuku installer not updating installed extensions (#2697)
Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com>

(cherry picked from commit c3d858a5613a133352f6b140916d05de7f752771)
2025-11-26 15:05:26 +05:45
Mend Renovate 20e1cc0a7d Update dependency com.pinterest.ktlint:ktlint-cli to v1.8.0 (#2708)
Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com>

(cherry picked from commit 13552c5ffa796aa9bf5db5e12c758a4b3763bf2b)
2025-11-26 15:02:17 +05:45
Mend Renovate 78b434e794 Update dependency androidx.activity:activity-compose to v1.12.0 (#2725)
(cherry picked from commit e6ca458e1f4cad3786d685ce8412ad40aed5155d)
2025-11-26 14:59:51 +05:45
Mend Renovate 52c8b260e0 Update moko to v0.25.2 (#2723)
(cherry picked from commit 05c7df2ed32b429f1ed3f1425e854c1867813a21)
2025-11-26 14:59:51 +05:45
Mend Renovate cccdc99977 Update sqlite to v2.6.2 (#2724)
(cherry picked from commit 4a3339a21f479bd57a7765cbeb092674aa2e8507)
2025-11-26 14:59:51 +05:45
Mend Renovate ca15d2ccc5 Update lifecycle.version to v2.10.0 (#2726)
(cherry picked from commit 6f497ed03181b15cb79899c689ffe70353656f0b)
2025-11-26 14:59:51 +05:45
Jobobby04 b7b0ffc885 Remove old SmartSearch 2025-11-20 13:20:53 -05:00
Mend Renovate f1a57749c4 Update dependency com.squareup.okio:okio to v3.16.4 (#2716)
(cherry picked from commit c17fc6792a3b8a5b6f31c107f165bfcda44617ae)
2025-11-20 12:53:57 -05:00
Mend Renovate 26d6c09d21 Update dependency io.kotest:kotest-assertions-core to v6.0.5 (#2717)
(cherry picked from commit 9e27ae3d2b63210714d6b16add687d2b37a34736)
2025-11-20 12:53:51 -05:00
Mend Renovate 088e3b6800 Update okhttp monorepo to v5.3.2 (#2720)
(cherry picked from commit 8b5dd39f1cbfd2eb8dd09cf42757206eeba631f7)
2025-11-20 12:53:45 -05:00
Mend Renovate c8ee2dbff4 Update dependency com.diffplug.spotless:spotless-plugin-gradle to v8.1.0 (#2721)
(cherry picked from commit 8d81c94679e4ecc9e452b03feb7c08f524a4969d)
2025-11-20 12:53:39 -05:00
Mend Renovate 835a21b426 Update dependency com.google.firebase:firebase-bom to v34.6.0 (#2707)
(cherry picked from commit e5a693f224190a662f2192a06fd12ae2a03e7dc3)
2025-11-20 12:53:32 -05:00
Mend Renovate 8d67c87639 Update okhttp monorepo to v5.3.1 (#2712)
(cherry picked from commit 7947e1bd6a7bdd99fe6badde8b665da24f92ab7c)
2025-11-20 12:53:24 -05:00
Jobobby04 73cd25e8ba Remove unused migration preferences 2025-11-20 12:50:33 -05:00
Jobobby04 e9ed861f00 Minor cleanup 2025-11-20 12:49:42 -05:00
Jobobby04 e7c1d4deef Minor cleanup 2025-11-20 12:38:09 -05:00
Jobobby04 b8eb75fc68 Throttle E-Hentai requests 2025-11-20 12:37:37 -05:00
NGB-Was-Taken 3d34f3dd2f Exclude MergedSource from MigrationConfigScreen 2025-11-17 08:49:15 +05:45
NGB-Was-Taken 01dc277877 Replace topbar in ReaderAppBars with ReaderTopBar 2025-11-16 20:35:50 +05:45
NGB-Was-Taken b809ae5c6f Optimize imports 2025-11-16 18:48:51 +05:45
NGB-Was-Taken 4c563122f8 Spotless apply 2025-11-16 18:14:20 +05:45
NGB-Was-Taken 4c1124fdb0 Fix compile time errors and make it build 2025-11-16 18:07:44 +05:45
NGB-Was-Taken bdbaecd975 Fix queries and mappers to work with updated views 2025-11-16 18:07:44 +05:45
Mend Renovate 2b8641c1dd Update dependency com.squareup.okio:okio to v3.16.3 (#2709)
(cherry picked from commit cab729c9396d54c98b1e8c4716b93814016deab4)
2025-11-16 18:07:44 +05:45
Mend Renovate f1a90000b2 Update dependency app.cash.sqldelight:sqlite-3-38-dialect to v2.2.1 (#2703)
(cherry picked from commit f6a95a741667871df34288bdb6b67cafe2f79d54)
2025-11-16 18:07:44 +05:45
Weblate (bot) 3bd0f0b447 Translations update from Hosted Weblate (#2687)
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/am/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/bn/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/as/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/bn/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/fil/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/id/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ms/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/my/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ne/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ru/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/tr/
Translation: Mihon/Mihon
Translation: Mihon/Mihon Plurals

Co-authored-by: Anderhale <anderhale@users.noreply.hosted.weblate.org>
Co-authored-by: Anderhale <safwanistaken@gmail.com>
Co-authored-by: Ardiansyahset <ardiantozep@users.noreply.hosted.weblate.org>
Co-authored-by: Infy's Tagalog Translations <ced.paltep10@gmail.com>
Co-authored-by: MajorTanya <github@majortanya.eu>
Co-authored-by: NGB-Was-Taken <76197326+NGB-Was-Taken@users.noreply.github.com>
Co-authored-by: amigo browser <juniperforest1@proton.me>
(cherry picked from commit 32db0a5f4c261062883a11f86b7091f654bff568)
2025-11-16 18:07:44 +05:45
NGB-Was-Taken cb5b618266 Stop tap zones from triggering when scrolling is stopped by tapping (#2680)
(cherry picked from commit 2ec67ac0c1831a68d8d73e2679f8c98a5a48acf5)
2025-11-16 18:07:44 +05:45
Mend Renovate c71c07690a Update sqldelight to v2.2.1 (#2704)
(cherry picked from commit b1b79a63f0ec570ba2eac41f8faa50ecf7301e5d)
2025-11-16 18:07:44 +05:45
Mend Renovate d85d77da01 Update dependency com.android.tools.build:gradle to v8.13.1 (#2685)
(cherry picked from commit ec99ab3aef734e8b9ce156fe7493f72e7a8cc03a)
2025-11-16 18:07:44 +05:45
Weblate (bot) 164d7bc70f Translations update from Hosted Weblate (#2676)
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/it/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/am/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ar/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/as/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/bg/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/bn/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ca/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ceb/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/cv/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/da/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/de/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/el/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/es/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/eu/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/fa/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/fi/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/gl/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/he/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/hr/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/hu/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/it/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/kk/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/kn/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/lt/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/lv/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ms/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ne/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/nn/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/pl/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/pt/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/sa/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/sah/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/sc/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/sk/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/sq/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/sr/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/sv/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/th/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/tr/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/uk/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/zh_Hant/
Translation: Mihon/Mihon
Translation: Mihon/Mihon Plurals

Co-authored-by: FateXBlood <fatexblood@gmail.com>
Co-authored-by: Frosted <frosted@users.noreply.hosted.weblate.org>
Co-authored-by: Gino Cicatiello <ginocic@gmail.com>
Co-authored-by: Lyfja <45209212+lyfja@users.noreply.github.com>
Co-authored-by: MajorTanya <github@majortanya.eu>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: NGB-Was-Taken <76197326+NGB-Was-Taken@users.noreply.github.com>
Co-authored-by: Pitpe11 <giorgos2550@gmail.com>
Co-authored-by: Swyter <swyterzone@gmail.com>
Co-authored-by: ZerOriSama <godarms2010@live.com>

(cherry picked from commit 84d620978bbc5a4698787f5ab81686e7e60767c9)
2025-11-16 18:07:44 +05:45
AntsyLich db51b09f80 Revert "Fix reader tap zones triggering after scrolling was stopped by the user" (#2670)
(cherry picked from commit 412815af067cdf343a6b5c7b5cd38eeb8190d543)
2025-11-16 18:07:44 +05:45
Weblate (bot) 5f8d03ba9b Translations update from Hosted Weblate (#2656)
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/cs/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/cs/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/de/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ja/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/jv/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ru/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/zh_Hant/
Translation: Mihon/Mihon
Translation: Mihon/Mihon Plurals

Co-authored-by: Doministo <doministo@seznam.cz>
Co-authored-by: Lyfja <45209212+lyfja@users.noreply.github.com>
Co-authored-by: Nataniel Dika Kurniawan <hikawaart2@gmail.com>
Co-authored-by: TheKingTermux <50316075+TheKingTermux@users.noreply.github.com>
Co-authored-by: ZerOriSama <godarms2010@live.com>
Co-authored-by: amigo browser <juniperforest1@proton.me>

(cherry picked from commit f7fb68692a7c41f9f09721dde8db574df1fde1ce)
2025-11-16 18:07:44 +05:45
AntsyLich 4cae7b27a6 Fix extra padding appearing in reader after user interactions (#2669)
(cherry picked from commit aa300cb53ea3a02b63c3b3f3fca60d5e7533a8f1)
2025-11-16 18:07:44 +05:45
Trevor Paley edcf939611 Improve WebView multi-window UX (#2662)
- Navigation history for lower windows is preserved when a popup is opened
- Back gesture will close a popup window rather than the entire WebView activity when there is no previous page
- The leftmost close button closes the entire activity as before
- When a popup window is shown, a new button appears to close just that window

(cherry picked from commit 855eea2ada8c09404dee99a965325913b246618f)
2025-11-16 18:07:44 +05:45
Mend Renovate 208d291b3c Update dependency androidx.core:core-splashscreen to v1.2.0 (#2661)
(cherry picked from commit f4703ed83a32afe1d39669f4988233c1fe7c3f32)
2025-11-16 18:07:44 +05:45
NGB-Was-Taken 19f049189a Fix flaky migration tests (#2663)
(cherry picked from commit 506d51a007e730594e4e5f05f00b4f94c4f24e05)
2025-11-16 18:07:44 +05:45
AntsyLich c855276555 Revert "Update dependency androidx.compose:compose-bom to v2025.10.01 (#2522)"
This reverts commit e8bdf58530cdfd6d530ea9a282785bd313e69be4.

(cherry picked from commit ace387f8bf8f451887b8055213be78312a5b4ea7)
2025-11-16 18:07:43 +05:45
Weblate (bot) 9e244e0889 Translations update from Hosted Weblate (#2646)
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/nl/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/hr/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/id/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/jv/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ms/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/tr/
Translation: Mihon/Mihon
Translation: Mihon/Mihon Plurals

Co-authored-by: Frosted <frosted@users.noreply.hosted.weblate.org>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: Nataniel Dika Kurniawan <hikawaart2@gmail.com>
Co-authored-by: Siebrenvde <siebren@siebrenvde.dev>
(cherry picked from commit 5e428071c9a12bc637cbfcf235a33dc19cdef197)
2025-11-16 18:07:43 +05:45
AntsyLich bf7a067908 Fix long strip reader not scrolling on consecutive taps (#2650)
(cherry picked from commit 0acd80dd95094a837c8dc05f3fc29ef3e69bdc21)
2025-11-16 18:07:43 +05:45
bapeey 67c4b71b88 Fix WebView crash introduced in v0.19.2 (#2649)
(cherry picked from commit bdb0ce4779d565fc528e97bd38133a72ff3c1724)
2025-11-16 18:07:43 +05:45
Mend Renovate 1fa8a86cce Update dependency androidx.compose:compose-bom to v2025.10.01 (#2522)
(cherry picked from commit e8bdf58530cdfd6d530ea9a282785bd313e69be4)
2025-11-16 18:07:43 +05:45
Weblate (bot) 73eb98960f Translations update from Hosted Weblate (#2639)
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/es/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/fil/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/tr/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/vi/
Translation: Mihon/Mihon

Co-authored-by: Frosted <frosted@users.noreply.hosted.weblate.org>
Co-authored-by: Infy's Tagalog Translations <ced.paltep10@gmail.com>
Co-authored-by: Nguyễn Trung Đức <vaicato16@gmail.com>
Co-authored-by: Swyter <swyterzone@gmail.com>
(cherry picked from commit e36b4ce60b2b7141c5b6a4205e98853a0d07438b)
2025-11-16 18:07:43 +05:45
AntsyLich 59704221b7 Migrated to the Android specific about libraries gradle plugin
(cherry picked from commit 6d543024a32bba3136841a19942bed4ea8f0736b)
2025-11-16 18:07:43 +05:45
AntsyLich 19c23943ec Handle reader cutout setting with Insets to support Android 15+ (#2640)
(cherry picked from commit 0e0b6d92833f8e4f3aebdcc1f7c8c175084175d6)
2025-11-16 18:07:43 +05:45
Weblate (bot) d068559dee Translations update from Hosted Weblate (#2373)
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/ar/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/hi/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/jv/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/ko/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/ms/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/pt/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/sk/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/tr/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ar/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/de/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/el/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/eo/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/es/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/fil/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/fr/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/hi/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/hr/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/id/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ja/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/jv/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ko/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ms/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ne/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/nl/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/pt/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ro/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ru/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/sk/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/th/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/tr/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/vi/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/zh_Hant/
Translation: Mihon/Mihon
Translation: Mihon/Mihon Plurals

Co-authored-by: Dexroneum <Rozhenkov69@gmail.com>
Co-authored-by: Efe Akın <efeakin1122@gmail.com>
Co-authored-by: Evan Jones (原文轩) <evanjones1883@gmail.com>
Co-authored-by: Farith <mail2@farithadnan.net>
Co-authored-by: Frosted <frosted@users.noreply.hosted.weblate.org>
Co-authored-by: Infy's Tagalog Translations <ced.paltep10@gmail.com>
Co-authored-by: Itsmechinmoy <167056923+itsmechinmoy@users.noreply.github.com>
Co-authored-by: Itsmechinmoy <itsmechinmoy@users.noreply.hosted.weblate.org>
Co-authored-by: Jakub Fabijan <jakubfabijan@tuta.io>
Co-authored-by: Lyfja <45209212+lyfja@users.noreply.github.com>
Co-authored-by: Madddog1997 <madddog1997@gmail.com>
Co-authored-by: Manjul Tamrakar <manjultamrakar4@gmail.com>
Co-authored-by: Manuela Silva <mmsrs@sky.com>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: Mohamed kh <mohamedkhamekhami@gmail.com>
Co-authored-by: MuhamadSyabitHidayattulloh <tebepc@gmail.com>
Co-authored-by: Nataniel Dika Kurniawan <hikawaart2@gmail.com>
Co-authored-by: Omgeta <anooptiger@hotmail.com>
Co-authored-by: Pitpe11 <giorgos2550@gmail.com>
Co-authored-by: Saft Octavian <saftoctavian@gmail.com>
Co-authored-by: Siebrenvde <siebren@siebrenvde.dev>
Co-authored-by: Swyter <swyterzone@gmail.com>
Co-authored-by: TheKingTermux <50316075+TheKingTermux@users.noreply.github.com>
Co-authored-by: Throw Away <throwawayacc4gulshan@gmail.com>
Co-authored-by: ZerOriSama <godarms2010@live.com>
Co-authored-by: keegang 6705 <darunphobwi@gmail.com>
Co-authored-by: ssantos <ssantos@web.de>
Co-authored-by: ɴᴇᴋᴏ <s99095lkjjim@gmail.com>
Co-authored-by: 안세훈 <on9686@gmail.com>

(cherry picked from commit 860955389661ce35d37f499efdd27259b93d8e56)
2025-11-16 18:07:43 +05:45
AntsyLich 8e6b5b8bee Make reader edge-to-edge (#1908)
(cherry picked from commit 5f0c4606681cd59b38ae0855c7827e149fa5488c)

# Conflicts:
#	CHANGELOG.md
#	app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsReaderScreen.kt
#	app/src/main/java/eu/kanade/presentation/reader/ReaderPageIndicator.kt
#	app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderAppBars.kt
#	app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderBottomBar.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt
2025-11-16 18:07:43 +05:45
Naputt1 c99ddbe10f Fix reader tap zones triggering after scrolling was stopped by the user (#2518)
Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com>

(cherry picked from commit ac28b6c80cee7605052299d6f5f43bc588f701d8)
2025-11-16 18:07:43 +05:45
Constantin Piber 23925c4ba6 Update Suwayomi tracker to use GraphQL API instead of REST API (#2585)
(cherry picked from commit cc2877673539db779af00fbefab3802ac52a7719)
2025-11-16 18:07:43 +05:45
Trevor Paley e71f0afd99 Added proper multi window support in WebView instead of treating everything as a redirect (#2584)
(cherry picked from commit 6ab87c793122165f98c36b4b7d9158069ea40f5a)
2025-11-16 18:07:43 +05:45
Kashish Aggarwal 014bf97248 Fix date picker not allowing the same start and finish date in negative time zones (#2617)
Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com>

(cherry picked from commit 8662f80fbf6b7c3aee4945bf656def8341cfdfd3)
2025-11-16 18:07:43 +05:45
anirudhn fc0d666366 Fix scrollbar not showing when animator duration scale animation is turned off (#2398)
(cherry picked from commit 09ec9fc8c54e126692ae68ff260058f3be46a5dd)
2025-11-16 18:07:43 +05:45
c2y5 eb7465e6f9 Fix extension download stuck at pending state in some cases (#2483)
Also auto update extension list whenever a repository is added or removed

Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com>

(cherry picked from commit 87c6f34a558b009be4d316e396ec3eeb4cfbbbf8)
2025-11-16 18:07:43 +05:45
AntsyLich ff6ad20a77 Add option to customize concurrent downloads, increase page concurrency (#2637)
(cherry picked from commit 643762f91325a460c74398d472a555fb00ed9f63)
2025-11-16 18:07:43 +05:45
Mend Renovate 17c528a206 Update markdown to v0.38.1 (#2636)
(cherry picked from commit 7e880014b0f2c42bc430765a19068d93640ce603)
2025-11-16 18:07:43 +05:45
AntsyLich 63f4034a7f Add subtitle support to slider preference and general cleanup (#2635)
(cherry picked from commit f36c259c1faf2ee4a108fd98a5d27d93014ba34c)
2025-11-16 18:07:43 +05:45
AntsyLich 6c1bfc2177 Fix reader "Unable to edit key" error (#2634)
(cherry picked from commit aef3beb15fb2d4acbde9cb2ea4c5f639606d9fc8)
2025-11-16 18:07:43 +05:45
NGB-Was-Taken 45ff1f06ba Update shizuku.version to v13.1.5 (#2566)
Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com>

(cherry picked from commit e9469451acf6c7ad39ff08e344ad5013ddc39337)
2025-11-16 18:07:43 +05:45
AntsyLich 3e287a593a Bump app version code and default user agent
(cherry picked from commit f9793d33233ceb7729fa9cfe5ae55b45a372c54c)
2025-11-16 18:07:43 +05:45
AntsyLich 01420154be Fix migration "Attempt to invoke virtual method" crash (#2632)
(cherry picked from commit 93ba6acea56334573fc506d593affd5bea2a86b2)
2025-11-16 18:07:43 +05:45
AntsyLich 1e4c596d0e Fix migration dialog migrating to wrong entry (#2631)
(cherry picked from commit 5e7fecc2c11b4a175fe1c3f698f7daeb58fe311f)
2025-11-16 18:07:43 +05:45
Mend Renovate 26cb2bbbd1 Update dependency org.junit.jupiter:junit-jupiter to v6.0.1 (#2630)
(cherry picked from commit 343074da5f7b5b6b2bb8116cc65348684d4bf615)
2025-11-16 18:07:43 +05:45
AntsyLich 588db79a64 Fix mass migration advanced search query building (#2629)
(cherry picked from commit 7c08b75555a5444ede4912dc5e32607fac2b9678)
2025-11-16 18:07:43 +05:45
Constantin Piber e5aaf3b31f Migrate Kitsu to use library_id and remote_id properly (#2609)
(cherry picked from commit cbf72f4c60cb85f29f8446ba1adb1cfd29d38a59)

# Conflicts:
#	CHANGELOG.md
#	data/src/main/sqldelight/tachiyomi/migrations/8.sqm
2025-11-16 18:07:43 +05:45
Mend Renovate 9c222b128b Update okhttp monorepo to v5.3.0 (#2628)
(cherry picked from commit 0b6de39f2f878f1188a4fc1ea989517bad38e6ca)
2025-11-16 18:07:43 +05:45
Mend Renovate c66e08d43e Update plugin google-services to v4.4.4 (#2573)
(cherry picked from commit 72c4d1fdee981ca0bc94cd32d0a43bb739f43a61)
2025-11-16 18:07:43 +05:45
Mend Renovate 493d8fc45f Update dependency androidx.work:work-runtime to v2.11.0 (#2626)
(cherry picked from commit 3ff25bc984717052b57484859283c96583d152b2)
2025-11-16 18:07:43 +05:45
Mend Renovate 47993cb55d Update dependency com.squareup.okio:okio to v3.16.2 (#2576)
(cherry picked from commit e9224bc2ba19a5a78dd16c30615f2cae5b02ba5d)
2025-11-16 18:07:43 +05:45
Mend Renovate 4701cbea23 Update dependency com.google.firebase:firebase-bom to v34.5.0 (#2575)
(cherry picked from commit 5ac58d01b82daae809139ccb4245802816d23ff8)
2025-11-16 18:07:43 +05:45
Mend Renovate 70efd6f2bf Update xml.serialization.version to v0.91.3 (#2625)
(cherry picked from commit eefaf028ce7bca41d25f77c73e44a1f36af8703a)
2025-11-16 18:07:43 +05:45
Mend Renovate b85b6a713c Update kotlin monorepo to v2.2.21 (#2624)
(cherry picked from commit 582ccca1ab327864e72fff0fe05da6757584c280)
2025-11-16 18:07:43 +05:45
Mend Renovate 6291529a10 Update dependency io.kotest:kotest-assertions-core to v6.0.4 (#2594)
(cherry picked from commit 8f972115a82cda8619577e22465a047c2a863a1a)
2025-11-16 18:07:43 +05:45
Mend Renovate 160907ab52 Update aboutlib.version to v13 (major) (#2580)
Update aboutlib.version to v13

(cherry picked from commit 6f6c0338110e0fdd16cfc997981a21b6ed4859bc)
2025-11-16 18:07:43 +05:45
Mend Renovate bccd30a80f Update okhttp monorepo to v5.2.1 (#2577)
(cherry picked from commit 57a0ab67112d1966c00d7ec433a2cff70064495e)
2025-11-16 18:07:43 +05:45
Radon Rosborough ef4d3e6c4d Improve handling of downloads for chapters with same metadata and optionally for OSes that don't support Unicode in filename (#2305)
Co-authored-by: jkim <jhskim@hotmail.com>
Co-authored-by: fatotak <111342761+fatotak@users.noreply.github.com>
Co-authored-by: MajorTanya <39014446+MajorTanya@users.noreply.github.com>
Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com>

(cherry picked from commit 58b25d697f7987e9888344e815d5646ec010a663)
2025-11-16 18:07:43 +05:45
Mend Renovate 4fe7a1375a Update okhttp monorepo to v5.2.0 (#2564)
(cherry picked from commit 1a31c7c7ee31eee19030875d11ec1f31eab895a4)
2025-11-16 18:07:43 +05:45
NGB-Was-Taken 02bc195068 Fix disabling incognito mode from notification (#2512)
Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com>

(cherry picked from commit 96e5131358110079587d262d37ec346e10941758)
2025-11-16 18:07:43 +05:45
Mend Renovate 1e20913237 Update dependency com.google.firebase:firebase-bom to v34.3.0 (#2508)
(cherry picked from commit 1d5bc8d2c2e3cb6df56561782e2e2842af3eaa50)
2025-11-16 18:07:43 +05:45
Mend Renovate 48b488fa59 Update dependency org.junit.jupiter:junit-jupiter to v6 (#2553)
(cherry picked from commit 9a45d248b1545ec192b4d5cff9b0756d0a7a12dd)
2025-11-16 18:07:43 +05:45
Mend Renovate 893f3b2e34 Update moko to v0.25.1 (#2550)
(cherry picked from commit 04168ecec84a3e2b470468002c05bbe9e5e538b5)
2025-11-16 18:07:43 +05:45
Mend Renovate 25be12852f Update dependency io.mockk:mockk to v1.14.6 (#2549)
(cherry picked from commit 607f0ea9cd08c070323c4c1a46efec53dc4b1358)
2025-11-16 18:07:43 +05:45
Secozzi 4f0292b000 Update markdown to 0.37.0 (#2516)
(cherry picked from commit 27a4f6f45c0ba639450428f5f58b1c938fe3032e)
2025-11-16 18:07:43 +05:45
Mend Renovate f669fd9205 Update kotlin monorepo to v2.2.20 (#2498)
(cherry picked from commit 5236d003d27d2aaa8a4baaa8aa4dfc0c8b299fea)
2025-11-16 18:07:43 +05:45
Mend Renovate c3e0646b61 Update dependency androidx.work:work-runtime to v2.10.5 (#2523)
(cherry picked from commit d61a41e8192786c8bb958652098a704d79ad5f5d)
2025-11-16 18:07:43 +05:45
Mend Renovate 0d2cad8693 Update sqlite to v2.6.1 (#2525)
(cherry picked from commit 5637860dd2ed637223014433e1e6005885af10a1)
2025-11-16 18:07:43 +05:45
Mend Renovate 237916a37b Update dependency com.diffplug.spotless:spotless-plugin-gradle to v8 (#2526)
(cherry picked from commit d4d18d0898d7fec07e6021e60481948a40b162ad)
2025-11-16 18:07:43 +05:45
Guzmazow 16653f9585 Improve spoofing of X-Requested-With header to support newer WebView versions (#2491)
(cherry picked from commit 065147472e8e683c47d11f3e00386aba2a7c1bac)
2025-11-16 18:07:43 +05:45
Constantin Piber 392b1009c9 Delegate Suwayomi tracker authentication to extension (#2476)
Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com>

(cherry picked from commit 6f635782c22cc0844caa4e4d88cf390005989b0b)
2025-11-16 18:07:43 +05:45
Mend Renovate 10c184e58a Update lifecycle.version to v2.9.4 (#2503)
Update dependency androidx.lifecycle:lifecycle-process to v2.9.4

(cherry picked from commit 86d85f74c097b8b52eb6a91887a055c92e1066f5)
2025-11-16 18:07:43 +05:45
Mend Renovate f6b8756dc0 Update sqlite to v2.6.0 (#2504)
(cherry picked from commit 29e6a2c4a6a32deae4c067c51b7e863b8f8128bb)
2025-11-16 18:07:43 +05:45
Mend Renovate f2654807a4 Update dependency androidx.core:core-ktx to v1.17.0 (#2402)
(cherry picked from commit 60c66bbd3a12e48bff52257c27d6b868e97da1d7)
2025-11-16 18:07:43 +05:45
Mend Renovate ab90b75d73 Update dependency androidx.activity:activity-compose to v1.11.0 (#2499)
(cherry picked from commit 060e5b2e2e8ad85886c4d3362ba1ae56fac52f79)
2025-11-16 18:07:43 +05:45
AntsyLich 0b58a081af Replace compose-stable-marker with compose-runtime-annotation
(cherry picked from commit 4ac9fcd4d3ff2eed59d9c8454d7463b7c9e6dda6)
2025-11-16 18:07:43 +05:45
AntsyLich ae98a5fe58 Bump compile and target sdk
(cherry picked from commit d3b7f7e55ff6609a2cddf1765205ba35c6c26b83)
2025-11-16 18:07:43 +05:45
Mend Renovate 74fa4e3503 Update dependency com.google.firebase:firebase-bom to v34.2.0 (#2376)
(cherry picked from commit 0d926626a1916783b67b3ae8cd2142aa90120e30)
2025-11-16 18:07:43 +05:45
Mend Renovate c20b0f67a8 Update dependency androidx.benchmark:benchmark-macro-junit4 to v1.4.1 (#2496)
(cherry picked from commit 6495a2ea430c82a8481b10ef345669d8ff915cac)
2025-11-16 18:07:43 +05:45
Mend Renovate 098c7196de Update dependency androidx.work:work-runtime to v2.10.4 (#2497)
(cherry picked from commit 94f711ba2a67d0da52ba26978f5c4a103abc7f69)
2025-11-16 18:07:43 +05:45
Mend Renovate 99a25560c1 Update dependency androidx.compose:compose-bom to v2025.09.00 (#2401)
(cherry picked from commit 9f5c4e03b23dab80051afa458361ce62133febbf)
2025-11-16 18:07:43 +05:45
Mend Renovate 79d19a2d8b Update lifecycle.version to v2.9.3 (#2447)
(cherry picked from commit 49562e1915108ac28fa3308d4eed319bb9ed61d5)
2025-11-16 18:07:43 +05:45
Mend Renovate 061d0809bd Update dependency org.jsoup:jsoup to v1.21.2 (#2438)
(cherry picked from commit 57c82b30bab20110832eecc4a825441708eaa02b)
2025-11-16 18:07:43 +05:45
Mend Renovate 0ce0c45cc7 Update dependency io.kotest:kotest-assertions-core to v6.0.3 (#2439)
(cherry picked from commit e573f72cfd5b6c66709ba948ce29c7246a9832e8)
2025-11-16 18:07:43 +05:45
Mend Renovate e910362b16 Update dependency com.android.tools.build:gradle to v8.13.0 (#2449)
(cherry picked from commit bd90307df9ca2f0d424483b29c0dd640eabc0f5f)
2025-11-16 18:07:43 +05:45
Secozzi 96c05bf113 Fix migration progress not updating and category flag mischeck (#2484)
- Fixed an issue where migration progress wasn't updated after a manual source search
- Fixed incorrect logic where the category migration flag was ignored due to checking the chapter flag instead

(cherry picked from commit 16b5317b90b3064d12aa38f687cc30110fd8cdb3)
2025-11-16 18:07:43 +05:45
Mend Renovate 6d2bda5c9d Update plugin firebase-crashlytics to v3.0.6 (#2374)
(cherry picked from commit 83f4b486296f6998efc8ef95fa9d58b75e5de130)
2025-11-16 18:07:43 +05:45
Mend Renovate 4a080fba3f Update dependency com.github.skydoves:compose-stable-marker to v1.0.7 (#2428)
(cherry picked from commit 85f5e5019e59a178f24c93c71644b1c4a08549f3)
2025-11-16 18:07:43 +05:45
AntsyLich ac5b3b164f Bump targetSdk to 35
(cherry picked from commit 4bc3b9f3b6fc87a9285ad3ca1aa8c81d8269d373)
2025-11-16 18:07:43 +05:45
Mend Renovate c43d7dbb31 Update dependency com.android.tools.build:gradle to v8.12.1 (#2417)
(cherry picked from commit feda4101525163c3978a2eb9ab934f9c4db1e873)
2025-11-16 18:07:43 +05:45
Mend Renovate d218fdfcf4 Update dependency sh.calvin.reorderable:reorderable to v3 (#2419)
(cherry picked from commit 200c2df5ba72a39c4116d14827d54a126b77cdc7)
2025-11-16 18:07:43 +05:45
Mend Renovate e59af2fd1f Update dependency io.kotest:kotest-assertions-core to v6 (#2416)
(cherry picked from commit be09cddde2f0799e7eff0003f9dacdb5a6e09947)
2025-11-16 18:07:43 +05:45
AntsyLich 3d761b5bf4 Switch to a fork of QuickJS Java
(cherry picked from commit 498317de52c119a08daaa8d38f3f7d859e7b4990)
2025-11-16 18:07:43 +05:45
Mend Renovate 1892101359 Update kotlin monorepo to v2.2.10 (#2404)
(cherry picked from commit 33b876edc6cd20c73682a165359bec1268aa1199)
2025-11-16 18:07:43 +05:45
Secozzi d76d25379e Don't hardcode app name in strings.xml (#2394)
(cherry picked from commit 3d3c36078a3b8cb741adffd46931aeab9cb38578)
2025-11-16 18:07:43 +05:45
Secozzi c96cf4b11a Fix height of description not being calculated correctly if images are present (#2382)
(cherry picked from commit c6a96b3970f0ba4643f438155653790973fa00f6)
2025-11-16 18:07:27 +05:45
krysanify 31601f523d Fix crash opening filter sheet with empty library and mark as read/unread for selected items (#2355)
(cherry picked from commit d88dbe6409b9c4dd7fbb37757e89c09af73f1fd3)
2025-11-16 17:48:12 +05:45
AntsyLich f9abe20b84 Remove gradle toolchains plugin
(cherry picked from commit d0bad9f0bd6b9d9dc641c81ee2428a0f859d01a8)
2025-11-16 17:48:12 +05:45
AntsyLich f7030ed800 Fix 'Default' category showing in library with no user-added categories (#2371)
(cherry picked from commit 7d717ee7fd9779b85fee29cadc946292cfdcee89)
2025-11-16 17:48:12 +05:45
AntsyLich f4173b3766 Fix title text color in light mode on mass migration list (#2370)
(cherry picked from commit a93f71b82be4489a7a2aefd8fa08bb114cae8db5)
2025-11-16 17:48:12 +05:45
AntsyLich 221a564644 Fix local source EPUB files not loading (#2369)
(cherry picked from commit 9bf3f15fff96b48e6847034c9fcd07f14675130b)
2025-11-16 17:48:12 +05:45
AntsyLich 7458eff2d8 Revert "Add full predictive back support (#2085)" (#2362)
This reverts commit c12bdbae8e7bc14da8966e45a3c450913e32129f.

(cherry picked from commit 1c3e96bf7f463949997c03e2119cfa55fd63dcd0)
2025-11-16 17:48:11 +05:45
Weblate (bot) 187245885a Translations update from Hosted Weblate (#1879)
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/as/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/bg/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/bn/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/de/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/el/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/eo/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/es/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/fil/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/fr/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/hi/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/hr/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/id/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/ja/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/ne/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/pt/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/ro/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/ru/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/tr/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/uk/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/vi/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon-plurals/zh_Hant/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ar/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/bg/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/cs/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/cv/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/de/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/el/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/eo/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/es/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/fil/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/fr/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/gl/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/he/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/hi/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/hr/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/hu/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/id/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/it/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ja/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ml/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/my/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ne/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/nl/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/pt/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ro/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ru/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/sc/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/ta/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/th/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/tr/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/uk/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/vi/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/mihon/mihon/zh_Hant/
Translation: Mihon/Mihon
Translation: Mihon/Mihon Plurals

Co-authored-by: Adolfo Jayme Barrientos <fitojb@ubuntu.com>
Co-authored-by: Ahmed TOUCHANE <ahmedtouchane0@gmail.com>
Co-authored-by: Ajeje Brazorf <lmelonimamo@yahoo.it>
Co-authored-by: Akhil Raj <akhilakae07@gmail.com>
Co-authored-by: Alex Maryson Jr <akamar87@gmail.com>
Co-authored-by: Aviv Ben Ami <avivbenami@gmail.com>
Co-authored-by: B4LiN7 <87660017+B4LiN7@users.noreply.github.com>
Co-authored-by: C201 <derasetad@gmail.com>
Co-authored-by: Conrad Mateman <conradmateme001@gmail.com>
Co-authored-by: Crazyom <naxom@laposte.net>
Co-authored-by: Danilo Issida Goncalves <danissida@hotmail.com>
Co-authored-by: Dexroneum <Rozhenkov69@gmail.com>
Co-authored-by: Doministo <doministo@seznam.cz>
Co-authored-by: FateXBlood <fatexblood@gmail.com>
Co-authored-by: Frosted <frosted@users.noreply.hosted.weblate.org>
Co-authored-by: Giorgio Sanna <sannagiorgio1997@gmail.com>
Co-authored-by: Guillaume Lecocq <guillaume.taylor@gmail.com>
Co-authored-by: Homura Akemi <amber_c001@protonmail.com>
Co-authored-by: Infy's Tagalog Translations <ced.paltep10@gmail.com>
Co-authored-by: Itsmechinmoy <itsmechinmoy@users.noreply.hosted.weblate.org>
Co-authored-by: Jakub Fabijan <jakubfabijan@tuta.io>
Co-authored-by: João Sousa <joaopsousa99@gmail.com>
Co-authored-by: Karley <siegitsi@gmail.com>
Co-authored-by: Lyfja <45209212+lyfja@users.noreply.github.com>
Co-authored-by: Mario Kevin D. A <programas013@gmail.com>
Co-authored-by: Mehedi Talha <meheditalha007@gmail.com>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: Mohamed kh <mohamedkhamekhami@gmail.com>
Co-authored-by: Nguyễn Trung Đức <vaicato16@gmail.com>
Co-authored-by: Pitpe11 <giorgos2550@gmail.com>
Co-authored-by: Prem Kumar <prem12321kumar@gmail.com>
Co-authored-by: Ryo Richie <ryorichie@gmail.com>
Co-authored-by: Saft Octavian <saftoctavian@gmail.com>
Co-authored-by: Siebrenvde <siebren@siebrenvde.dev>
Co-authored-by: Sky children of the Light <tu25261@gmail.com>
Co-authored-by: Swyter <swyterzone@gmail.com>
Co-authored-by: Tahsin Gökalp <tahsinsaan@gmail.com>
Co-authored-by: TheKingTermux <50316075+TheKingTermux@users.noreply.github.com>
Co-authored-by: Yurt Page <yurtpage@gmail.com>
Co-authored-by: ZerOriSama <godarms2010@live.com>
Co-authored-by: abc0922001 <abc0922001@hotmail.com>
Co-authored-by: akir45 <akkn0708@gmail.com>
Co-authored-by: altinat <al@altqx.com>
Co-authored-by: amigo browser <juniperforest1@proton.me>
Co-authored-by: edgole <test.backache009@aleeas.com>
Co-authored-by: f_pluz <pedroh.lobo20@gmail.com>
Co-authored-by: fl0k1 <michele.carnova@gmail.com>
Co-authored-by: gekka <1778962971@qq.com>
Co-authored-by: gulse02 <gnoeoxgulse@gmail.com>
Co-authored-by: kevans <albapazpi@gmail.com>
Co-authored-by: naikhon <naikhon5@gmail.com>
Co-authored-by: pancake <ppzh0@users.noreply.hosted.weblate.org>
Co-authored-by: scb261 <65343233+scb261@users.noreply.github.com>
Co-authored-by: scb261 <scb261261@gmail.com>
Co-authored-by: Đào Ngọc Đang Khoa <daongocdangkhoa2510@gmail.com>
Co-authored-by: ɴᴇᴋᴏ <s99095lkjjim@gmail.com>
Co-authored-by: Артур Давлетов <ar.davletov2013@gmail.com>
Co-authored-by: Георгій Обушенков <heorhii.obushenkov@gmail.com>
Co-authored-by: Димитър Георгиев <dimitar13226@gmail.com>
Co-authored-by: ابومسلم <linuxmint1978@gmail.com>
Co-authored-by: ابْنُ السَدِيمِ <amarlubs2@gmail.com>
Co-authored-by: தமிழ்நேரம் <anishprabu.t@gmail.com>

(cherry picked from commit 45c1a314887732f691e349a9e7684952830341f0)
2025-11-16 17:48:11 +05:45
Radon Rosborough e5d8c2edbc Use ComicInfo.xml for chapter metadata in localSource (#2332)
Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com>

(cherry picked from commit 32257e438e2f0bea7e0bfe84dc72135795d620ad)
2025-11-16 17:48:11 +05:45
anirudhn be4aa39c8a Fixed scrollbar sometimes not showing during scroll or not reaching the bottom with few items (#2304)
(cherry picked from commit 095ef8e74b1c208be25b616ce01d5b198749ee2e)
2025-11-16 17:48:11 +05:45
MajorTanya 014c697773 Add label to privately installed extensions (#2349)
Just adds the same word as the install option ("Private" in English)
next to the extension version and 18+ label.

(cherry picked from commit 549d74a2c9aef0eb41ea18378cd29d4ab9eee2b4)
2025-11-16 17:48:11 +05:45
AntsyLich ea733de80e Fix same manga check logic in mass migration
(cherry picked from commit f1193866f4306384a2a466c6353446bfed2bd9aa)
2025-11-16 17:48:11 +05:45
AntsyLich 3ac5dcd66e Potentially fix library IndexOutOfBound crash (#2341)
(cherry picked from commit c4407eda0eed5a7faed47d4470d79e6b1512b5c2)
2025-11-16 17:48:11 +05:45
AntsyLich 054de1cc6f Remove checksum from release notes and improve download tip
(cherry picked from commit b93337cb3d53278e191cf1dceeaf6c4effdb141d)
2025-11-16 17:48:11 +05:45
AntsyLich b525c0988a Support mass migration in 'Browse -> Migrate' (#2338)
(cherry picked from commit 22f851173b1eca242645f328a46e6038c035d5ec)
2025-11-16 17:48:11 +05:45
AntsyLich 691efe0831 Support mass migration for selected library items (#2336)
(cherry picked from commit 982ebcf777215c90584ad28fae79e9ca8a22a951)

# Conflicts:
#	CHANGELOG.md
#	app/src/main/java/eu/kanade/presentation/manga/components/MangaBottomActionMenu.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryTab.kt
2025-11-16 17:48:11 +05:45
AntsyLich 8317a30d6e Optimize and cleanup library code (#2329)
(cherry picked from commit e62cd0e816402303fdf12513816894624f77e208)

# Conflicts:
#	.editorconfig
#	CHANGELOG.md
#	app/src/main/java/eu/kanade/presentation/library/components/LibraryContent.kt
#	app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateJob.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryScreenModel.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryTab.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/stats/StatsScreenModel.kt
#	data/src/main/sqldelight/tachiyomi/migrations/6.sqm
#	data/src/main/sqldelight/tachiyomi/view/libraryView.sq
2025-11-16 17:48:11 +05:45
Mend Renovate 633937b0bc Update dependency com.android.tools.build:gradle to v8.12.0 (#2331)
(cherry picked from commit 1365b28106c6fb01c920e997ad63c993e6703eef)
2025-11-16 17:48:11 +05:45
Mend Renovate 3152d2803a Update dependency androidx.test.ext:junit-ktx to v1.3.0 (#2327)
Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com>
(cherry picked from commit 7ec28eb3bd2d2ce409249e09b90189af21c2c2e6)
2025-11-16 17:48:11 +05:45
Mend Renovate 883c90adc8 Update dependency androidx.test.espresso:espresso-core to v3.7.0 (#2326)
(cherry picked from commit ff9dfe45ed4b9d4fa07cbc1b7bffbff86f596e5c)
2025-11-16 17:48:11 +05:45
Mend Renovate 8e658be7d7 Update dependency androidx.benchmark:benchmark-macro-junit4 to v1.4.0 (#2325)
(cherry picked from commit 967750ba5804f7ddf4ba230d8f3bb942096025b3)
2025-11-16 17:48:11 +05:45
Mend Renovate c27a4e2bf5 Update dependency androidx.work:work-runtime to v2.10.3 (#2324)
(cherry picked from commit 269af7fe2b5e1b444c1806bbeddfa89ec070ceab)
2025-11-16 17:48:11 +05:45
AwkwardPeak7 257f544a89 Include Manga initialized status in backup (#2285)
(cherry picked from commit 62eec15fe61be88e0ebc8be89a1e445dde55ba7e)

# Conflicts:
#	CHANGELOG.md
#	app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/MangaBackupCreator.kt
#	app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupManga.kt
2025-11-16 17:48:11 +05:45
Secozzi f8cb08ce52 Add option for rendering images in description (#2076)
# Conflicts:
#	CHANGELOG.md
#	app/src/main/java/eu/kanade/domain/ui/UiPreferences.kt
2025-11-16 17:48:03 +05:45
Mend Renovate d970eea7cf Update dependency androidx.compose:compose-bom to v2025.07.00 (#2284)
(cherry picked from commit 4f1faf49f3c1fee757b6a9ec58b15c2a010085c3)
2025-11-16 12:37:36 +05:45
Mend Renovate a45fad81c8 Update okhttp monorepo to v5.1.0 (#2257)
(cherry picked from commit 6d717ea88b7545b3c7edba2dd051ce01f8f8aa7f)
2025-11-16 12:37:36 +05:45
Mend Renovate 76d6cf129a Update kotlin monorepo to v2.2.0 (#2235)
(cherry picked from commit fbb5e6b92f48b5f11fa4413f3a48e475cd431c11)
2025-11-16 12:37:36 +05:45
Mend Renovate 879427446f Update dependency org.jsoup:jsoup to v1.21.1 (#2233)
(cherry picked from commit 8f5f29e7376f0ecd275ed2fb95d13b1b10e8c04c)
2025-11-16 12:37:36 +05:45
Mend Renovate 9edd7b0c04 Update dependency com.squareup.okio:okio to v3.16.0 (#2320)
(cherry picked from commit a4b9c704b65027cd2066802960aeb248dbdf1c1f)
2025-11-16 12:37:36 +05:45
Mend Renovate d97b83fe93 Update plugin firebase-crashlytics to v3.0.5 (#2307)
(cherry picked from commit 9352201b03fad147b16423cf33584ecd58548700)
2025-11-16 12:37:36 +05:45
Mend Renovate 027e6bbb05 Update dependency com.google.firebase:firebase-bom to v34 (#2310)
(cherry picked from commit c715e981bffe2ad896559369515c491d2a76946f)
2025-11-16 12:37:36 +05:45
AntsyLich 4cdead8006 Make local source default chapter sorting match file explorer behavior
Closes #2225

(cherry picked from commit 7f56555d632508379037eb0fba4411079c27ad5b)
2025-11-16 12:37:36 +05:45
Mend Renovate aaff472317 Update dependency com.squareup.logcat:logcat to v0.4 (#2319)
(cherry picked from commit 8636b7a68526e033ced6767666f730e6c50ac1b3)
2025-11-16 12:37:36 +05:45
Mend Renovate 9b2febcd6d Update xml.serialization.version to v0.91.2 (#2317)
(cherry picked from commit a49670bf0dc1bfa3250356be2883ebc2f0b603c3)
2025-11-16 12:37:36 +05:45
Mend Renovate 5de355238d Update dependency com.squareup.logcat:logcat to v0.3 (#2309)
(cherry picked from commit 61cee5c5e04550a9c1f16a40600d9e60e28f072c)
2025-11-16 12:37:36 +05:45
Mend Renovate 644c8ec491 Update dependency com.pinterest.ktlint:ktlint-cli to v1.7.1 (#2281)
(cherry picked from commit d805f0cd2a93720726cc2284a384de3fb1f6abbd)
2025-11-16 12:37:36 +05:45
Mend Renovate 4b516ae4c5 Update dependency io.coil-kt.coil3:coil-bom to v3.3.0 (#2308)
(cherry picked from commit ce07259e8e8fb602d1028013aa0c27ee0ce705c9)
2025-11-16 12:37:36 +05:45
Mend Renovate 223251f868 Update lifecycle.version to v2.9.2 (#2283)
Update dependency androidx.lifecycle:lifecycle-process to v2.9.2

(cherry picked from commit 2f10e7beaa11bdddcb409a2fed9d5f0b97b8ade8)
2025-11-16 12:37:36 +05:45
Mend Renovate 9b7d6bace1 Update dependency io.mockk:mockk to v1.14.5 (#2282)
(cherry picked from commit 4ef8fb958824c500f1a2155951d12490fb55c709)
2025-11-16 12:37:36 +05:45
Mend Renovate c15b8b65e5 Update dependency com.diffplug.spotless:spotless-plugin-gradle to v7.2.1 (#2293)
(cherry picked from commit 084e626669793cf637830827b5b03ae898c3814a)
2025-11-16 12:37:36 +05:45
Mend Renovate 4e9eaa5e81 Update dependency org.junit.jupiter:junit-jupiter to v5.13.4 (#2296)
(cherry picked from commit f93ccaaaa42fdf8091c89260803d9d518d06b9ac)
2025-11-16 12:37:36 +05:45
Mend Renovate 066e10246f Update dependency com.android.tools.build:gradle to v8.11.1 (#2277)
(cherry picked from commit 5585388e2d22879ac62e7fceaf26ae7f40cb8bde)
2025-11-16 12:37:36 +05:45
Matthias Ahouansou 3294dd6ca8 Use median to determine smart update interval (#2251)
Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com>

(cherry picked from commit d60241690b373e42215761b4108e52a7655daaeb)
2025-11-16 12:37:36 +05:45
Mend Renovate 2315295985 Update dependency com.squareup.okio:okio to v3.15.0 (#2256)
(cherry picked from commit 84aa07b7f0b15bbe9f400596007f6714005118bb)
2025-11-16 12:37:36 +05:45
Mend Renovate 56ddf21107 Update dependency com.diffplug.spotless:spotless-plugin-gradle to v7.1.0 (#2274)
(cherry picked from commit 0cc1224094069a321634cc3c1d5924b246ec7959)
2025-11-16 12:37:36 +05:45
Mend Renovate 3f47df21b8 Update serialization.version to v1.9.0 (#2252)
(cherry picked from commit a5a0d8330248174dc86d8f9a238a1c8489c291a6)
2025-11-16 12:37:36 +05:45
Mend Renovate 712407f524 Update dependency org.junit.jupiter:junit-jupiter to v5.13.3 (#2263)
(cherry picked from commit 1fde0275e313412af601e2ffdd79c7cf800678fb)
2025-11-16 12:37:36 +05:45
Mend Renovate 3a49a0a21a Update dependency gradle to v8.14.3 (#2264)
(cherry picked from commit a992f2d46758b741125c416c58a861a6f9ae9bc7)
2025-11-16 12:37:36 +05:45
Mend Renovate 04b3e13ba1 Update aboutlib.version to v12.2.4 (#2261)
(cherry picked from commit d8dd170d1b416cae793db10f9ee0568bfbdfadf9)
2025-11-16 12:37:36 +05:45
Mend Renovate 39bc2b49c0 Update moko to v0.25.0 (#2258)
(cherry picked from commit 6953090dabe3e90132c7c89a55e359a40257751e)
2025-11-16 12:37:36 +05:45
Mend Renovate 9765282640 Update plugin google-services to v4.4.3 (#2250)
(cherry picked from commit ab452a9945c6d34463e100ab63f614b1cf10b76c)
2025-11-16 12:37:36 +05:45
Mend Renovate 320a620afa Update dependency com.google.firebase:firebase-bom to v33.16.0 (#2248)
(cherry picked from commit 7dd595f16e2f484bd46f925c03b77675918208fc)
2025-11-16 12:37:36 +05:45
Mend Renovate ec2a720617 Update dependency com.android.tools.build:gradle to v8.11.0 (#2241)
(cherry picked from commit 6eb2a022f1e0b4a4da5714d69efe69bef584e179)
2025-11-16 12:37:36 +05:45
Mend Renovate 83d2ca7a54 Update dependency org.junit.jupiter:junit-jupiter to v5.13.2 (#2240)
(cherry picked from commit d61c66c286cf2c6d269809e2fbb5d601ed2d59e0)
2025-11-16 12:37:36 +05:45
Mend Renovate 891503c793 Update dependency io.mockk:mockk to v1.14.4 (#2232)
(cherry picked from commit 1e4ee1460893f7969a17f05b569f3673a42b77f0)
2025-11-16 12:37:36 +05:45
AntsyLich 43abc6c797 Fix background crash in mass migration screen
(cherry picked from commit 63943debc2fd4efa1a0418bbfefaea93a24b49fd)
2025-11-16 12:37:36 +05:45
Danny Wu f916e94a4c Add option to hide missing chapter count (#2108)
Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com>

(cherry picked from commit d2c1ff6adf5543e5a593949704d41f2358252593)
2025-11-16 12:37:36 +05:45
AntsyLich fc9b2b6e1e Update manga without chapters even if restricted by source (#2224)
(cherry picked from commit b9e02e92bedf66aa2c4f7ed42b2c6899ed7fd013)
2025-11-16 12:37:36 +05:45
Mend Renovate 66bdd70485 Update dependency com.mohamedrejeb.richeditor:richeditor-compose to v1.0.0-rc13 (#2213)
(cherry picked from commit 103218681a6d9eda2f264e8f09724814dc8d5a96)
2025-11-16 12:37:36 +05:45
Mend Renovate 29024ea03a Update dependency androidx.compose:compose-bom to v2025.06.01 (#2220)
(cherry picked from commit 07136d3969daee988ddc129d091a6923d50f6a5a)
2025-11-16 12:37:36 +05:45
Mend Renovate 6af33905be Update dependency androidx.work:work-runtime to v2.10.2 (#2221)
(cherry picked from commit 4962deeb0cb5766d22ec0d3fb6e88ac50be327de)
2025-11-16 12:37:36 +05:45
Mend Renovate f97d918728 Update dependency com.squareup.okio:okio to v3.13.0 (#2201)
(cherry picked from commit cecf4596f9580806cf3208a518e5acac30becb50)
2025-11-16 12:37:36 +05:45
Mend Renovate 6a38e501d9 Update aboutlib.version to v12.2.3 (#2205)
(cherry picked from commit 0c77afbe038c2ad3db3f09d221f2a03fc2cec237)
2025-11-16 12:37:36 +05:45
Mend Renovate 8310733c4c Update sqlite to v2.5.2 (#2210)
(cherry picked from commit d126b84f954d6a35dd3cc1a29849fb0822714552)
2025-11-16 12:37:36 +05:45
AwkwardPeak7 28f0946877 Ensure app waits for Cloudflare challenge to complete before continuing (#2200)
Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com>

(cherry picked from commit 2df3382148c76d287943fc36e2f55bc16df1cd83)
2025-11-16 12:37:36 +05:45
jobobby04 e135a0dc71 Mass migration implementation (#2110)
There is no way to trigger mass migration at the moment. The functionality will be added in a follow up PR.

Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com>
(cherry picked from commit ee19050cc00b0a787af65b641624d07bb194e155)
2025-11-16 12:37:36 +05:45
AntsyLich 05a65773f0 Further tweak migration config screen sheet
(cherry picked from commit 019fc08da2392725c36e064ffadc4e645edafb63)
2025-11-16 12:37:36 +05:45
AntsyLich 8d794560a0 Add more migration config options and remove skipping option (#2193)
(cherry picked from commit 288f577a45a6835c34ad41caab95794f164b7a0b)
2025-11-16 12:37:36 +05:45
Mend Renovate 4341a98413 Update aboutlib.version to v12.2.2 (#2190)
(cherry picked from commit a47d4ebbdd04ce439c25a564afdb813dc80615d4)
2025-11-16 12:37:36 +05:45
Mend Renovate 24f5a36350 Update dependency sh.calvin.reorderable:reorderable to v2.5.1 (#2183)
(cherry picked from commit 89954e68e3265936718b5dd0664102f9f37b554a)
2025-11-16 12:37:36 +05:45
Mend Renovate f125db6973 Update dependency sh.calvin.reorderable:reorderable to v2.5.0 (#2178)
(cherry picked from commit c3b590cd3dfe70a5736411c6533913f2dadb17bc)
2025-11-16 12:37:36 +05:45
Mend Renovate 4ec969657e Update dependency com.google.firebase:firebase-bom to v33.15.0 (#2177)
(cherry picked from commit cb3c5e9c9c8465d3b1228264964b19ecda8bfc98)
2025-11-16 12:37:36 +05:45
Mend Renovate cb7e790086 Update plugin firebase-crashlytics to v3.0.4 (#2174)
(cherry picked from commit 7fa2834009013b01b06e2d95a80a4b4e09f37d17)
2025-11-16 12:37:36 +05:45
Mend Renovate 9012dafed4 Update dependency gradle to v8.14.2 (#2168)
(cherry picked from commit 95e3c22429adc98fb3ad7b941b5a8aa45322bfdc)
2025-11-16 12:37:36 +05:45
Mend Renovate 8b24d7eded Update okhttp monorepo to v5.0.0-alpha.16 (#2149)
(cherry picked from commit 8bd70342fcd1355c53fef62e597e2aa20229e123)
2025-11-16 12:37:36 +05:45
Mend Renovate dcc537accb Update sqldelight to v2.1.0 (#2119)
Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com>
(cherry picked from commit 92ec6b17a315c12838bf94bd214d216435e0f8f9)
2025-11-16 12:37:36 +05:45
Mend Renovate ab67775f13 Update dependency org.junit.jupiter:junit-jupiter to v5.13.1 (#1754)
Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com>

(cherry picked from commit 591e9c13560f28d71598eb32648387d099ebc881)
2025-11-16 12:37:36 +05:45
Mend Renovate e105828e07 Update dependency androidx.compose:compose-bom to v2025.06.00 (#2175)
(cherry picked from commit 7fed9c2ccfed0179e50b4b8960fcd3eb6d229f53)
2025-11-16 12:37:36 +05:45
Mend Renovate 3c83edaad2 Update dependency com.squareup.logcat:logcat to v0.2.3 (#2126)
(cherry picked from commit ccb554c877e552433cc4fff9164207b02f0a17cf)
2025-11-16 12:37:36 +05:45
Mend Renovate b4f278e5fa Update dependency androidx.appcompat:appcompat to v1.7.1 (#2167)
(cherry picked from commit 5235713d83ab3643d30f2a7f087126d60dbb21f4)
2025-11-16 12:37:36 +05:45
Mend Renovate 29ca687a26 Update lifecycle.version to v2.9.1 (#2173)
(cherry picked from commit 4692010400d4fad2cc51901a355a0c15b865860c)
2025-11-16 12:37:36 +05:45
Mend Renovate ed975cae63 Update aboutlib.version to v12.2.1 (#2170)
(cherry picked from commit be528ba12b82d357170262d825b38033fbd83e91)
2025-11-16 12:37:36 +05:45
Mend Renovate 4fce0944b4 Update dependency me.zhanghai.android.libarchive:library to v1.1.6 (#2171)
(cherry picked from commit 405e536cbf4182e141d221795331c374236c9708)
2025-11-16 12:37:36 +05:45
AntsyLich 4a52898f08 Add option to skip migration config
(cherry picked from commit 8714653a2f3b1a1f536494bcefbe66e7a7bbb4f7)

# Conflicts:
#	app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBrowseScreen.kt
2025-11-16 12:37:36 +05:45
AntsyLich 92b48319ed Cleanup migrate manga dialog and related code (#2156)
(cherry picked from commit 2b126f1ff56b63e470b48a04149e28c609f01148)

# Conflicts:
#	app/src/main/java/eu/kanade/domain/source/service/SourcePreferences.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/MigrationFlags.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/MigrateSearchScreen.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/MigrateSearchScreenDialogScreenModel.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/MigrateSourceSearchScreen.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreen.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/history/HistoryScreenModel.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/history/HistoryTab.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreen.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt
2025-11-16 12:37:36 +05:45
AntsyLich 9e113d80f7 Fix no sources while migrating alongside UI and code cleanup (#2155)
(cherry picked from commit 5919f34fc96f254724bd3042ac2b91ac65912930)
2025-11-16 12:37:36 +05:45
Mend Renovate f960554cf8 Update dependency com.github.requery:sqlite-android to v3.49.0 (#2150)
(cherry picked from commit a4df33caf937a79ab1f70e33ad56e5b3899917e2)
2025-11-16 12:37:36 +05:45
Mend Renovate 0bdea705a5 Update aboutlib.version to v12.2.0 (#2152)
(cherry picked from commit 3580d2da6cc7f09eb3b6f1345c958a0ab0574856)
2025-11-16 12:37:36 +05:45
claymorwan 33361ea7f6 Add Catppuccin theme (#2117)
Mocha for dark and Latte for light, mauve accent

(cherry picked from commit 77eb55874278b7740d43b9144d9253a075cc593c)
2025-11-16 12:37:36 +05:45
Mend Renovate 717240f53c Update dependency com.android.tools.build:gradle to v8.10.1 (#2148)
(cherry picked from commit e1f6d143933ebf445adec5e1b87086551c2dca84)
2025-11-15 18:19:53 +05:45
AntsyLich 5156248a96 Add migration config screen to select and prioritize target sources (#2144)
(cherry picked from commit 2e180005a01f633ad7fafc5cfb3079f0bc858448)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/manga/MigrateMangaScreen.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/MigrateSearchScreenModel.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreen.kt
2025-11-15 18:19:53 +05:45
Mend Renovate e074df469e Update markdown to v0.35.0 (#2143)
(cherry picked from commit 0f59fc1dd42f770a0e7a9359a3eb8baebc826246)
2025-11-15 18:19:53 +05:45
Mend Renovate d1277ecb02 Update dependency com.diffplug.spotless:spotless-plugin-gradle to v7.0.4 (#2146)
(cherry picked from commit d1055475e23a3e20ef41b228056611be82e62515)
2025-11-15 18:19:53 +05:45
Mend Renovate 8bcc235490 Update dependency com.squareup.okio:okio to v3.12.0 (#2147)
(cherry picked from commit 32470657ddcb6976bb4c8f852ec19fe1d4dfb542)
2025-11-15 18:19:53 +05:45
Mend Renovate aaa7171c10 Update dependency me.zhanghai.android.libarchive:library to v1.1.5 (#2142)
(cherry picked from commit 158896cfa9314b89848d4d45b3042b80cefb127e)
2025-11-15 18:19:53 +05:45
Jobobby04 887311b440 Fix notification settings under api 26 2025-06-16 14:44:30 -04:00
Jobobby04 1c90aac059 Add id to staff-edges 2025-06-16 11:28:31 -04:00
Jobobby04 3ad9765dcf Remove +1 in Page Layout reader settings 2025-06-10 14:40:28 -04:00
Jobobby04 cc934607c8 SpotlessApply 2025-05-24 21:07:29 -04:00
Weblate (bot) 5074e68b9c Translations update from Hosted Weblate (#1442)
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy-plurals/ar/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy-plurals/my/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy-plurals/vi/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/ar/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/de/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/es/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/fil/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/fr/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/id/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/it/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/ja/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/ne/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/ru/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/tr/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/uk/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/mihon/tachiyomisy/zh_Hant/
Translation: Mihon/TachiyomiSY
Translation: Mihon/TachiyomiSY Plurals

Co-authored-by: Alex Maryson Jr <akamar87@gmail.com>
Co-authored-by: B4LiN7 <87660017+B4LiN7@users.noreply.github.com>
Co-authored-by: Dexroneum <Rozhenkov69@gmail.com>
Co-authored-by: FateXBlood <fatexblood@gmail.com>
Co-authored-by: Frosted <frosted@users.noreply.hosted.weblate.org>
Co-authored-by: Hualiang <642615676@qq.com>
Co-authored-by: Infy's Tagalog Translations <ced.paltep10@gmail.com>
Co-authored-by: Kosťantin Horovij <lg096066587039@gmail.com>
Co-authored-by: Lapis (Bas77) <sebastianramli77@gmail.com>
Co-authored-by: LordTenebrous <danielmorenoperez836@gmail.com>
Co-authored-by: Mohamed kh <mohamedkhamekhami@gmail.com>
Co-authored-by: Sky children of the Light <tu25261@gmail.com>
Co-authored-by: Swyter <swyterzone@gmail.com>
Co-authored-by: ZerOriSama <godarms2010@live.com>
Co-authored-by: akir45 <akkn0708@gmail.com>
Co-authored-by: edgole <test.backache009@aleeas.com>
Co-authored-by: fl0k1 <michele.carnova@gmail.com>
Co-authored-by: naikhon <naikhon5@gmail.com>
Co-authored-by: qaugji <asteeky9@gmail.com>
Co-authored-by: ɴᴇᴋᴏ <s99095lkjjim@gmail.com>
Co-authored-by: Георгій Обушенков <heorhii.obushenkov@gmail.com>
Co-authored-by: ابومسلم <linuxmint1978@gmail.com>
2025-05-24 20:47:35 -04:00
多能豆 ade41f113d Fix E-Hentai Jump/Seek match for detailed date (#1450) 2025-05-24 20:44:55 -04:00
Jobobby04 95dc82594f More guards against edited data 2025-05-24 20:44:27 -04:00
NGB-Was-Taken 80e585fa91 Change log file extension to .txt (#1449) 2025-05-24 20:19:17 -04:00
Jobobby04 9f110f9db8 Bump version so migation actually runs 2025-05-24 20:18:14 -04:00
NGB-Was-Taken 71470b9e02 Remove the unused mark duplicate as read preference. (#1448)
* Remove the unused mark duplicate as read preference.

* Migrate the old preference to new preference
2025-05-24 20:16:44 -04:00
renovate[bot] 4fd24accac Update dependency net.zetetic:sqlcipher-android to v4.9.0 (#1447)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-24 20:15:17 -04:00
NGB-Was-Taken 31312fecac Fixes screen staying on in library tab. (#1451) 2025-05-24 20:13:43 -04:00
Mend Renovate b80d057922 Update dependency androidx.compose:compose-bom to v2025.05.01 (#2133)
(cherry picked from commit 92b376d9af93da988b695c36c4775d5e6947c048)
2025-05-24 20:12:57 -04:00
Mend Renovate f01d8bc835 Update dependency gradle to v8.14.1 (#2138)
(cherry picked from commit 1a2f09a622017dc5b201eadc6acc667487cf3d4d)
2025-05-24 20:12:48 -04:00
Jobobby04 ddffe71a22 SpotlessApply 2025-05-24 20:12:38 -04:00
AntsyLich 649a19ec57 Fix content cut off in home screen
Closes #2141

(cherry picked from commit 209e982fe4f1da5d1d49cfbfdd178625ee3c70f4)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/home/HomeScreen.kt
2025-05-24 20:10:18 -04:00
Mend Renovate e82fd99a09 Update plugin org.gradle.toolchains.foojay-resolver-convention to v1 (#2130)
(cherry picked from commit 0109102901f942502807e2a7a9f1a58f951c763f)
2025-05-24 20:09:57 -04:00
Mend Renovate 67a9b8e2a0 Update dependency com.pinterest.ktlint:ktlint-cli to v1.6.0 (#2129)
(cherry picked from commit 4117a5167470ae36b4172721b4e4d40373f2a3c6)
2025-05-24 20:09:51 -04:00
Mend Renovate 2000f947c3 Update xml.serialization.version to v0.91.1 (#2112)
(cherry picked from commit 4090a61d08964a8e82f943ac4eb81a52c110005f)
2025-05-24 20:09:45 -04:00
Jobobby04 f992ada0a8 SpotlessApply 2025-05-16 21:16:09 -04:00
Jobobby04 f876cdb037 Use MediaServer in Json for NHentai
Co-authored-by: 4521 <18432684+az4521@users.noreply.github.com>
2025-05-16 20:34:03 -04:00
Jobobby04 f919d42370 Hello Discord 2025-05-16 12:02:37 -04:00
Mend Renovate ab5ff00c39 Update kotlin monorepo to v2.1.21 (#2102)
(cherry picked from commit 625c85cbd68086d605553b2d5ab9cc9cc9460688)
2025-05-15 13:50:17 -04:00
Mend Renovate 422738af56 Update dependency org.jetbrains.kotlinx:kotlinx-collections-immutable to v0.4.0 (#2104)
(cherry picked from commit 737ceeea576074cffcd2e96933aceffdbcc0a03a)
2025-05-15 13:50:08 -04:00
Mend Renovate 81751fc9ce Update dependency io.coil-kt.coil3:coil-bom to v3.2.0 (#2101)
(cherry picked from commit 7933c9eeb7b28ecc2ae31fa337654a80f2371b85)
2025-05-15 13:49:58 -04:00
Jobobby04 9b6c5effc9 Minor refactors 2025-05-15 13:38:03 -04:00
690 changed files with 19341 additions and 9676 deletions
+6 -3
View File
@@ -7,7 +7,7 @@ indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
[*.{xml,sq,sqm}]
[*.{xml,sq,sqm,aidl}]
indent_size = 4
# noinspection EditorConfigKeyCorrectness
@@ -23,9 +23,14 @@ ij_kotlin_name_count_to_use_star_import_for_members = 2147483647
ktlint_code_style = intellij_idea
ktlint_function_naming_ignore_when_annotated_with = Composable
ktlint_standard_class-signature = disabled
ktlint_standard_comment-wrapping = disabled
ktlint_standard_discouraged-comment-location = disabled
ktlint_standard_function-expression-body = disabled
ktlint_standard_function-signature = disabled
ktlint_standard_type-argument-comment = disabled
ktlint_standard_type-parameter-comment = disabled
ktlint_standard_blank-line-between-when-conditions = disabled
# SY
ktlint_standard_filename = disabled
ktlint_standard_argument-list-wrapping = disabled
@@ -33,8 +38,6 @@ ktlint_standard_function-naming = disabled
ktlint_standard_property-naming = disabled
ktlint_standard_multiline-expression-wrapping = disabled
ktlint_standard_string-template-indent = disabled
ktlint_standard_comment-wrapping = disabled
ktlint_standard_max-line-length = disabled
ktlint_standard_type-argument-comment = disabled
ktlint_standard_value-argument-comment = disabled
ktlint_standard_value-parameter-comment = disabled
+1 -1
View File
@@ -100,5 +100,5 @@ body:
required: true
- label: I have filled out all of the requested information in this form, including specific version numbers.
required: true
- label: I understand that **Mihon does not have or fix any extensions**, and I **will not receive help** for any issues related to sources or extensions.
- label: I understand that **TachiyomiSY does not have or fix any extensions**, and I **will not receive help** for any issues related to sources or extensions.
required: true
+4 -4
View File
@@ -12,22 +12,22 @@ jobs:
steps:
- name: Clone repo
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Set up JDK
uses: actions/setup-java@v4
uses: actions/setup-java@v5
with:
java-version: 17
distribution: temurin
- name: Set up gradle
uses: gradle/actions/setup-gradle@v4
uses: gradle/actions/setup-gradle@v5
- name: Build app
run: ./gradlew spotlessCheck assembleDevDebug
- name: Upload APK
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: TachiyomiSY-${{ github.sha }}.apk
path: app/build/outputs/apk/dev/debug/app-dev-debug.apk
+7 -30
View File
@@ -15,20 +15,20 @@ jobs:
steps:
- name: Clone repo
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Setup Android SDK
run: |
${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin/sdkmanager "build-tools;29.0.3"
- name: Set up JDK
uses: actions/setup-java@v4
uses: actions/setup-java@v5
with:
java-version: 17
distribution: temurin
- name: Set up gradle
uses: gradle/actions/setup-gradle@v4
uses: gradle/actions/setup-gradle@v5
# SY -->
- name: Write google-services.json
@@ -71,24 +71,10 @@ jobs:
set -e
mv app/build/outputs/apk/standard/release/app-standard-universal-release-unsigned-signed.apk TachiyomiSY.apk
sha=`sha256sum TachiyomiSY.apk | awk '{ print $1 }'`
echo "APK_UNIVERSAL_SHA=$sha" >> $GITHUB_ENV
mv app/build/outputs/apk/standard/release/app-standard-arm64-v8a-release-unsigned-signed.apk TachiyomiSY-arm64-v8a.apk
sha=`sha256sum TachiyomiSY-arm64-v8a.apk | awk '{ print $1 }'`
echo "APK_ARM64_V8A_SHA=$sha" >> $GITHUB_ENV
mv app/build/outputs/apk/standard/release/app-standard-armeabi-v7a-release-unsigned-signed.apk TachiyomiSY-armeabi-v7a.apk
sha=`sha256sum TachiyomiSY-armeabi-v7a.apk | awk '{ print $1 }'`
echo "APK_ARMEABI_V7A_SHA=$sha" >> $GITHUB_ENV
mv app/build/outputs/apk/standard/release/app-standard-x86-release-unsigned-signed.apk TachiyomiSY-x86.apk
sha=`sha256sum TachiyomiSY-x86.apk | awk '{ print $1 }'`
echo "APK_X86_SHA=$sha" >> $GITHUB_ENV
mv app/build/outputs/apk/standard/release/app-standard-x86_64-release-unsigned-signed.apk TachiyomiSY-x86_64.apk
sha=`sha256sum TachiyomiSY-x86_64.apk | awk '{ print $1 }'`
echo "APK_X86_64_SHA=$sha" >> $GITHUB_ENV
- name: Create release
uses: softprops/action-gh-release@v2
@@ -96,19 +82,10 @@ jobs:
tag_name: ${{ github.run_number }}
name: TachiyomiSY
body: |
---
### Checksums
| Variant | SHA-256 |
| ------- | ------- |
| Universal | ${{ env.APK_UNIVERSAL_SHA }} |
| arm64-v8a | ${{ env.APK_ARM64_V8A_SHA }} |
| armeabi-v7a | ${{ env.APK_ARMEABI_V7A_SHA }} |
| x86 | ${{ env.APK_X86_SHA }} |
| x86_64 | ${{ env.APK_X86_64_SHA }} |
## If you are unsure which version to choose then go with TachiyomiSY.apk
<!-->
> [!TIP]
>
> ### If you are unsure which version to download then go with `TachiyomiSY.apk`
files: |
TachiyomiSY.apk
TachiyomiSY-arm64-v8a.apk
+3 -3
View File
@@ -12,16 +12,16 @@ jobs:
steps:
- name: Clone repo
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Set up JDK
uses: actions/setup-java@v4
uses: actions/setup-java@v5
with:
java-version: 17
distribution: temurin
- name: Set up gradle
uses: gradle/actions/setup-gradle@v4
uses: gradle/actions/setup-gradle@v5
- name: Create Tag
run: |
+1 -1
View File
@@ -10,7 +10,7 @@ jobs:
steps:
- name: Check PR and Add Label
uses: actions/github-script@v7
uses: actions/github-script@v8
with:
script: |
const prAuthor = context.payload.pull_request.user.login;
+1 -1
View File
@@ -60,7 +60,7 @@ Additional features for some extensions, features include custom description, op
* Mangadex
* NHentai
* Puruin
* Tsumino
* LANraragi
## Download
Get the app from our [releases page](https://github.com/jobobby04/tachiyomisy/releases/latest).
+110 -89
View File
@@ -1,16 +1,19 @@
@file:Suppress("ChromeOsAbiSupport")
import mihon.buildlogic.getBuildTime
import mihon.buildlogic.getCommitCount
import mihon.buildlogic.getGitSha
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")
alias(mihonx.plugins.android.application)
alias(mihonx.plugins.compose)
alias(mihonx.plugins.spotless)
kotlin("plugin.parcelize")
kotlin("plugin.serialization")
// id("com.github.zellius.shortcut-helper")
alias(libs.plugins.aboutLibraries)
alias(libs.plugins.kotlin.serialization)
id("com.github.ben-manes.versions")
}
@@ -21,42 +24,26 @@ if (gradle.startParameter.taskRequests.toString().contains("Standard")) {
}
}
// shortcutHelper.setFilePath("./shortcuts.xml")
val supportedAbis = setOf("armeabi-v7a", "arm64-v8a", "x86", "x86_64")
android {
namespace = "eu.kanade.tachiyomi"
defaultConfig {
applicationId = "eu.kanade.tachiyomi.sy"
versionCode = 74
versionCode = 77
versionName = "1.12.0"
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", "INCLUDE_UPDATER", "false")
ndk {
abiFilters += supportedAbis
}
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
splits {
abi {
isEnable = true
reset()
include(*supportedAbis.toTypedArray())
isUniversalApk = true
}
}
buildTypes {
named("debug") {
versionNameSuffix = "-${getCommitCount()}"
versionNameSuffix = "-${getLatestCommitCount()}"
applicationIdSuffix = ".debug"
isPseudoLocalesEnabled = true
}
@@ -72,7 +59,7 @@ android {
isShrinkResources = true
setProguardFiles(listOf(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"))
buildConfigField("String", "BUILD_TIME", "\"${getBuildTime(useLastCommitTime = true)}\"")
buildConfigField("String", "BUILD_TIME", "\"${getBuildTime(useLatestCommitTime = true)}\"")
}
create("benchmark") {
initWith(getByName("release"))
@@ -90,6 +77,15 @@ android {
getByName("benchmark").res.srcDirs("src/debug/res")
}
splits {
abi {
isEnable = true
isUniversalApk = true
reset()
include("armeabi-v7a", "arm64-v8a", "x86", "x86_64")
}
}
flavorDimensions.add("default")
productFlavors {
@@ -106,21 +102,32 @@ android {
}
packaging {
resources.excludes.addAll(
listOf(
jniLibs {
keepDebugSymbols += listOf(
"libandroidx.graphics.path",
"libarchive-jni",
"libconscrypt_jni",
"libimagedecoder",
"libquickjs",
"libsqlite3x",
)
.map { "**/$it.so" }
}
resources {
excludes += setOf(
"kotlin-tooling-metadata.json",
"META-INF/DEPENDENCIES",
"LICENSE.txt",
"META-INF/LICENSE",
"META-INF/**/*.properties",
"META-INF/**/LICENSE.txt",
"META-INF/*.properties",
"META-INF/**/*.properties",
"META-INF/README.md",
"META-INF/NOTICE",
"META-INF/*.version",
),
"META-INF/DEPENDENCIES",
"META-INF/LICENSE",
"META-INF/NOTICE",
"META-INF/README.md",
)
}
}
dependenciesInfo {
includeInApk = false
@@ -129,9 +136,9 @@ android {
buildFeatures {
viewBinding = true
buildConfig = true
aidl = true
// Disable some unused things
aidl = false
renderScript = false
shaders = false
}
@@ -150,12 +157,14 @@ kotlin {
"-opt-in=androidx.compose.foundation.ExperimentalFoundationApi",
"-opt-in=androidx.compose.foundation.layout.ExperimentalLayoutApi",
"-opt-in=androidx.compose.material3.ExperimentalMaterial3Api",
"-opt-in=androidx.compose.material3.ExperimentalMaterial3ExpressiveApi",
"-opt-in=androidx.compose.ui.ExperimentalComposeUiApi",
"-opt-in=coil3.annotation.ExperimentalCoilApi",
"-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi",
"-opt-in=kotlinx.coroutines.FlowPreview",
"-opt-in=kotlinx.coroutines.InternalCoroutinesApi",
"-opt-in=kotlinx.serialization.ExperimentalSerializationApi",
"-Xannotation-default-target=param-property",
)
}
}
@@ -175,97 +184,95 @@ 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(libs.bundles.sqlite)
implementation(libs.androidx.sqlite.bundled)
// SY -->
implementation(sylibs.sqlcipher)
// SY <--
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)
// AndroidX libraries
implementation(androidx.annotation)
implementation(androidx.appcompat)
implementation(androidx.biometricktx)
implementation(androidx.constraintlayout)
implementation(androidx.corektx)
implementation(androidx.splashscreen)
implementation(androidx.recyclerview)
implementation(androidx.viewpager)
implementation(androidx.profileinstaller)
implementation(libs.androidx.annotation)
implementation(libs.androidx.appCompat)
implementation(libs.androidx.biometric)
implementation(libs.androidx.constraintLayout)
implementation(libs.androidx.core)
implementation(libs.androidx.coreSplashScreen)
implementation(libs.androidx.recyclerView)
implementation(libs.androidx.viewPager)
implementation(libs.androidx.profileInstaller)
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")
}
implementation(libs.image.decoder)
// UI libraries
implementation(libs.material)
implementation(libs.flexible.adapter.core)
implementation(libs.photoview)
implementation(libs.directionalviewpager) {
implementation(libs.flexibleAdapter)
implementation(libs.photoView)
implementation(libs.directionalViewPager) {
exclude(group = "androidx.viewpager", module = "viewpager")
}
implementation(libs.insetter)
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)
// Logging
implementation(libs.logcat)
@@ -278,19 +285,20 @@ dependencies {
// Shizuku
implementation(libs.bundles.shizuku)
// String similarity
implementation(libs.stringSimilarity)
// Tests
testImplementation(libs.bundles.test)
testRuntimeOnly(libs.junit.platform.launcher)
// For detecting memory leaks; see https://square.github.io/leakcanary/
// debugImplementation(libs.leakcanary.android)
implementation(libs.leakcanary.plumber)
// debugImplementation(libs.leakCanary.android)
implementation(libs.leakCanary.plumber)
testImplementation(kotlinx.coroutines.test)
testImplementation(libs.kotlinx.coroutines.test)
// SY -->
// Text distance (EH)
implementation(sylibs.simularity)
// Firebase (EH)
implementation(platform(libs.firebase.bom))
implementation(libs.firebase.analytics)
@@ -316,6 +324,19 @@ dependencies {
}
androidComponents {
onVariants { variant ->
val resSource = variant.sources.res ?: return@onVariants
val variantName = variant.name.replaceFirstChar { it.uppercase() }
val replaceShortcutsPlaceholderTask = tasks.register<ReplaceShortcutsPlaceholderTask>(
"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
@@ -325,6 +346,6 @@ androidComponents {
buildscript {
dependencies {
classpath(kotlinx.gradle)
classpath(libs.kotlin.gradle)
}
}
+2
View File
@@ -299,3 +299,5 @@
-dontwarn org.ietf.jgss.GSSManager
-dontwarn org.ietf.jgss.GSSName
-dontwarn org.ietf.jgss.Oid
-dontwarn com.google.re2j.Matcher
-dontwarn com.google.re2j.Pattern
@@ -0,0 +1,7 @@
package mihon.app.shizuku;
interface IShellInterface {
void install(in AssetFileDescriptor apk) = 1;
void destroy() = 16777114;
}
@@ -38,6 +38,7 @@ import mihon.domain.extensionrepo.interactor.ReplaceExtensionRepo
import mihon.domain.extensionrepo.interactor.UpdateExtensionRepo
import mihon.domain.extensionrepo.repository.ExtensionRepoRepository
import mihon.domain.extensionrepo.service.ExtensionRepoService
import mihon.domain.migration.usecases.MigrateMangaUseCase
import mihon.domain.upcoming.interactor.GetUpcomingManga
import tachiyomi.data.category.CategoryRepositoryImpl
import tachiyomi.data.chapter.ChapterRepositoryImpl
@@ -59,6 +60,7 @@ import tachiyomi.domain.category.interactor.SetMangaCategories
import tachiyomi.domain.category.interactor.SetSortModeForCategory
import tachiyomi.domain.category.interactor.UpdateCategory
import tachiyomi.domain.category.repository.CategoryRepository
import tachiyomi.domain.chapter.interactor.GetBookmarkedChaptersByMangaId
import tachiyomi.domain.chapter.interactor.GetChapter
import tachiyomi.domain.chapter.interactor.GetChapterByUrlAndMangaId
import tachiyomi.domain.chapter.interactor.GetChaptersByMangaId
@@ -133,6 +135,11 @@ class DomainModule : InjektModule {
addFactory { SetMangaCategories(get()) }
addFactory { GetExcludedScanlators(get()) }
addFactory { SetExcludedScanlators(get()) }
addFactory {
MigrateMangaUseCase(
get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(),
)
}
addSingletonFactory<ReleaseService> { ReleaseServiceImpl(get(), get()) }
addFactory { GetApplicationRelease(get(), get()) }
@@ -150,6 +157,7 @@ class DomainModule : InjektModule {
addSingletonFactory<ChapterRepository> { ChapterRepositoryImpl(get()) }
addFactory { GetChapter(get()) }
addFactory { GetChaptersByMangaId(get()) }
addFactory { GetBookmarkedChaptersByMangaId(get(), get(), get()) }
addFactory { GetChapterByUrlAndMangaId(get()) }
addFactory { UpdateChapter(get()) }
addFactory { SetReadStatus(get(), get(), get(), get(), get()) }
@@ -28,7 +28,6 @@ import tachiyomi.data.source.SavedSearchRepositoryImpl
import tachiyomi.domain.chapter.interactor.DeleteChapters
import tachiyomi.domain.chapter.interactor.GetChapterByUrl
import tachiyomi.domain.chapter.interactor.GetMergedChaptersByMangaId
import tachiyomi.domain.history.interactor.GetHistoryByMangaId
import tachiyomi.domain.manga.interactor.DeleteByMergeId
import tachiyomi.domain.manga.interactor.DeleteFavoriteEntries
import tachiyomi.domain.manga.interactor.DeleteMangaById
@@ -88,7 +87,6 @@ class SYDomainModule : InjektModule {
addFactory { DeleteChapters(get()) }
addFactory { DeleteMangaById(get()) }
addFactory { FilterSerializer() }
addFactory { GetHistoryByMangaId(get()) }
addFactory { GetChapterByUrl(get()) }
addFactory { GetSourceCategories(get()) }
addFactory { CreateSourceCategory(get()) }
@@ -9,19 +9,22 @@ import tachiyomi.i18n.MR
class BasePreferences(
val context: Context,
private val preferenceStore: PreferenceStore,
preferenceStore: PreferenceStore,
) {
fun downloadedOnly() = preferenceStore.getBoolean(
val downloadedOnly: Preference<Boolean> = preferenceStore.getBoolean(
Preference.appStateKey("pref_downloaded_only"),
false,
)
fun incognitoMode() = preferenceStore.getBoolean(Preference.appStateKey("incognito_mode"), false)
val incognitoMode: Preference<Boolean> = preferenceStore.getBoolean(Preference.appStateKey("incognito_mode"), false)
fun extensionInstaller() = ExtensionInstallerPreference(context, preferenceStore)
val extensionInstaller: ExtensionInstallerPreference = ExtensionInstallerPreference(context, preferenceStore)
fun shownOnboardingFlow() = preferenceStore.getBoolean(Preference.appStateKey("onboarding_complete"), false)
val shownOnboardingFlow: Preference<Boolean> = preferenceStore.getBoolean(
Preference.appStateKey("onboarding_complete"),
false,
)
enum class ExtensionInstaller(val titleRes: StringResource, val requiresSystemPermission: Boolean) {
LEGACY(MR.strings.ext_installer_legacy, true),
@@ -30,9 +33,17 @@ class BasePreferences(
PRIVATE(MR.strings.ext_installer_private, false),
}
fun displayProfile() = preferenceStore.getString("pref_display_profile_key", "")
val displayProfile: Preference<String> = preferenceStore.getString("pref_display_profile_key", "")
fun hardwareBitmapThreshold() = preferenceStore.getInt("pref_hardware_bitmap_threshold", GLUtil.SAFE_TEXTURE_LIMIT)
val hardwareBitmapThreshold: Preference<Int> = preferenceStore.getInt(
"pref_hardware_bitmap_threshold",
GLUtil.SAFE_TEXTURE_LIMIT,
)
fun alwaysDecodeLongStripWithSSIV() = preferenceStore.getBoolean("pref_always_decode_long_strip_with_ssiv", false)
val alwaysDecodeLongStripWithSSIV: Preference<Boolean> = preferenceStore.getBoolean(
"pref_always_decode_long_strip_with_ssiv",
false,
)
val installationId: Preference<String> = preferenceStore.getString(Preference.appStateKey("installation_id"), "")
}
@@ -51,7 +51,7 @@ class SetReadStatus(
return@withNonCancellableContext Result.InternalError(e)
}
if (read && downloadPreferences.removeAfterMarkedAsRead().get()) {
if (read && downloadPreferences.removeAfterMarkedAsRead.get()) {
chaptersToUpdate
.groupBy { it.mangaId }
.forEach { (mangaId, chapters) ->
@@ -119,6 +119,7 @@ class SyncChaptersWithSource(
downloadManager.isChapterDownloaded(
dbChapter.name,
dbChapter.scanlator,
dbChapter.url,
/* SY --> */ manga.ogTitle /* SY <-- */,
manga.source,
)
@@ -126,12 +127,14 @@ class SyncChaptersWithSource(
if (shouldRenameChapter) {
downloadManager.renameChapter(source, manga, dbChapter, chapter)
}
var toChangeChapter = dbChapter.copy(
name = chapter.name,
chapterNumber = chapter.chapterNumber,
scanlator = chapter.scanlator,
sourceOrder = chapter.sourceOrder,
)
if (chapter.dateUpload != 0L) {
toChangeChapter = toChangeChapter.copy(dateUpload = chapter.dateUpload)
}
@@ -173,7 +176,7 @@ class SyncChaptersWithSource(
val deletedChapterNumberDateFetchMap = removedChapters.sortedByDescending { it.dateFetch }
.associate { it.chapterNumber to it.dateFetch }
val markDuplicateAsRead = libraryPreferences.markDuplicateReadChapterAsRead().get()
val markDuplicateAsRead = libraryPreferences.markDuplicateReadChapterAsRead.get()
.contains(LibraryPreferences.MARK_DUPLICATE_CHAPTER_READ_NEW)
// Date fetch is set in such a way that the upper ones will have bigger value than the lower ones
@@ -34,6 +34,7 @@ fun List<Chapter>.applyFilters(
val downloaded = downloadManager.isChapterDownloaded(
chapter.name,
chapter.scanlator,
chapter.url,
/* SY --> */ manga.ogTitle /* SY <-- */,
manga.source,
)
@@ -12,7 +12,7 @@ class GetExtensionLanguages(
) {
fun subscribe(): Flow<List<String>> {
return combine(
preferences.enabledLanguages().changes(),
preferences.enabledLanguages.changes(),
extensionManager.availableExtensionsFlow,
) { enabledLanguage, availableExtensions ->
availableExtensions
@@ -15,7 +15,7 @@ class GetExtensionSources(
val isMultiLangSingleSource =
isMultiSource && extension.sources.map { it.name }.distinct().size == 1
return preferences.disabledSources().changes().map { disabledSources ->
return preferences.disabledSources.changes().map { disabledSources ->
fun Source.isEnabled() = id.toString() !in disabledSources
extension.sources
@@ -13,10 +13,10 @@ class GetExtensionsByType(
) {
fun subscribe(): Flow<Extensions> {
val showNsfwSources = preferences.showNsfwSource().get()
val showNsfwSources = preferences.showNsfwSource.get()
return combine(
preferences.enabledLanguages().changes(),
preferences.enabledLanguages.changes(),
extensionManager.installedExtensionsFlow,
extensionManager.untrustedExtensionsFlow,
extensionManager.availableExtensionsFlow,
@@ -14,11 +14,11 @@ class TrustExtension(
suspend fun isTrusted(pkgInfo: PackageInfo, fingerprints: List<String>): Boolean {
val trustedFingerprints = extensionRepoRepository.getAll().map { it.signingKeyFingerprint }.toHashSet()
val key = "${pkgInfo.packageName}:${PackageInfoCompat.getLongVersionCode(pkgInfo)}:${fingerprints.last()}"
return trustedFingerprints.any { fingerprints.contains(it) } || key in preferences.trustedExtensions().get()
return trustedFingerprints.any { fingerprints.contains(it) } || key in preferences.trustedExtensions.get()
}
fun trust(pkgName: String, versionCode: Long, signatureHash: String) {
preferences.trustedExtensions().getAndSet { exts ->
preferences.trustedExtensions.getAndSet { exts ->
// Remove previously trusted versions
val removed = exts.filterNot { it.startsWith("$pkgName:") }.toMutableSet()
@@ -27,6 +27,6 @@ class TrustExtension(
}
fun revokeAll() {
preferences.trustedExtensions().delete()
preferences.trustedExtensions.delete()
}
}
@@ -15,9 +15,9 @@ class CreateSortTag(
return Result.TagExists
}
val size = preferences.sortTagsForLibrary().get().size
val size = preferences.sortTagsForLibrary.get().size
preferences.sortTagsForLibrary() += encodeTag(size, tag)
preferences.sortTagsForLibrary += encodeTag(size, tag)
return Result.Success
}
@@ -8,7 +8,7 @@ class DeleteSortTag(
) {
fun await(tag: String) {
preferences.sortTagsForLibrary().set(
preferences.sortTagsForLibrary.set(
(getSortTag.await() - tag).mapIndexed { index, s ->
CreateSortTag.encodeTag(index, s)
}.toSet(),
@@ -23,7 +23,7 @@ class GetPagePreviews(
return try {
val pagePreviews = try {
pagePreviewCache.getPageListFromCache(manga, chapterIds, page)
} catch (e: Exception) {
} catch (_: Exception) {
source.getPagePreviewList(manga.toSManga(), chapters.map { it.toSChapter() }, page).also {
pagePreviewCache.putPageListToCache(manga, chapterIds, it)
}
@@ -7,14 +7,14 @@ import tachiyomi.domain.library.service.LibraryPreferences
class GetSortTag(private val preferences: LibraryPreferences) {
fun subscribe(): Flow<List<String>> {
return preferences.sortTagsForLibrary().changes()
return preferences.sortTagsForLibrary.changes()
.map(::mapSortTags)
}
fun await() = getSortTags(preferences).let(::mapSortTags)
companion object {
fun getSortTags(preferences: LibraryPreferences) = preferences.sortTagsForLibrary().get()
fun getSortTags(preferences: LibraryPreferences) = preferences.sortTagsForLibrary.get()
fun mapSortTags(tags: Set<String>) = tags.mapNotNull {
val index = it.indexOf('|')
@@ -23,7 +23,7 @@ class ReorderSortTag(
val reorderedTag = reorderedTags.removeAt(currentIndex)
reorderedTags.add(newPosition, reorderedTag)
preferences.sortTagsForLibrary().set(
preferences.sortTagsForLibrary.set(
reorderedTags.mapIndexed { index, s ->
CreateSortTag.encodeTag(index, s)
}.toSet(),
@@ -44,7 +44,7 @@ class UpdateManga(
// if the manga isn't a favorite (or 'update titles' preference is enabled), set its title from source and update in db
val title =
if (remoteTitle.isNotEmpty() && (!localManga.favorite || libraryPreferences.updateMangaTitles().get())) {
if (remoteTitle.isNotEmpty() && (!localManga.favorite || libraryPreferences.updateMangaTitles.get())) {
remoteTitle
} else {
null
@@ -23,7 +23,7 @@ val Manga.readerOrientation: Long
val Manga.downloadedFilter: TriState
get() {
if (Injekt.get<BasePreferences>().downloadedOnly().get()) return TriState.ENABLED_IS
if (Injekt.get<BasePreferences>().downloadedOnly.get()) return TriState.ENABLED_IS
return when (downloadedFilterRaw) {
Manga.CHAPTER_SHOW_DOWNLOADED -> TriState.ENABLED_IS
Manga.CHAPTER_SHOW_NOT_DOWNLOADED -> TriState.ENABLED_NOT
@@ -38,12 +38,14 @@ fun Manga.chaptersFiltered(): Boolean {
fun Manga.toSManga(): SManga = SManga.create().also {
it.url = url
it.title = title
it.artist = artist
it.author = author
it.description = description
it.genre = genre.orEmpty().joinToString()
it.status = status.toInt()
// SY -->
it.title = ogTitle
it.artist = ogArtist
it.author = ogAuthor
it.description = ogDescription
it.genre = ogGenre.orEmpty().joinToString()
it.status = ogStatus.toInt()
// SY <--
it.thumbnail_url = thumbnailUrl
it.initialized = initialized
}
@@ -11,7 +11,7 @@ class CreateSourceCategory(private val preferences: SourcePreferences) {
}
// Create category.
preferences.sourcesTabCategories() += category
preferences.sourcesTabCategories += category
return Result.Success
}
@@ -7,9 +7,9 @@ import tachiyomi.core.common.preference.minusAssign
class DeleteSourceCategory(private val preferences: SourcePreferences) {
fun await(category: String) {
preferences.sourcesTabSourcesInCategories().getAndSet { sourcesInCategories ->
preferences.sourcesTabSourcesInCategories.getAndSet { sourcesInCategories ->
sourcesInCategories.filterNot { it.substringAfter("|") == category }.toSet()
}
preferences.sourcesTabCategories() -= category
preferences.sourcesTabCategories -= category
}
}
@@ -18,17 +18,17 @@ class GetEnabledSources(
fun subscribe(): Flow<List<Source>> {
return combine(
preferences.pinnedSources().changes(),
preferences.pinnedSources.changes(),
combine(
preferences.enabledLanguages().changes(),
preferences.disabledSources().changes(),
preferences.lastUsedSource().changes(),
preferences.enabledLanguages.changes(),
preferences.disabledSources.changes(),
preferences.lastUsedSource.changes(),
) { a, b, c -> Triple(a, b, c) },
// SY -->
combine(
preferences.dataSaverExcludedSources().changes(),
preferences.sourcesTabSourcesInCategories().changes(),
preferences.sourcesTabCategoriesFilter().changes(),
preferences.dataSaverExcludedSources.changes(),
preferences.sourcesTabSourcesInCategories.changes(),
preferences.sourcesTabCategoriesFilter.changes(),
) { a, b, c -> Triple(a, b, c) },
// SY <--
repository.getSources(),
@@ -7,7 +7,6 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonArray
import tachiyomi.core.common.util.lang.withIOContext
@@ -13,19 +13,19 @@ class GetIncognitoState(
private val extensionManager: ExtensionManager,
) {
fun await(sourceId: Long?): Boolean {
if (basePreferences.incognitoMode().get()) return true
if (basePreferences.incognitoMode.get()) return true
if (sourceId == null) return false
val extensionPackage = extensionManager.getExtensionPackage(sourceId) ?: return false
return extensionPackage in sourcePreferences.incognitoExtensions().get()
return extensionPackage in sourcePreferences.incognitoExtensions.get()
}
fun subscribe(sourceId: Long?): Flow<Boolean> {
if (sourceId == null) return basePreferences.incognitoMode().changes()
if (sourceId == null) return basePreferences.incognitoMode.changes()
return combine(
basePreferences.incognitoMode().changes(),
sourcePreferences.incognitoExtensions().changes(),
basePreferences.incognitoMode.changes(),
sourcePreferences.incognitoExtensions.changes(),
extensionManager.getExtensionPackageAsFlow(sourceId),
) { incognito, incognitoExtensions, extensionPackage ->
incognito || (extensionPackage in incognitoExtensions)
@@ -16,8 +16,8 @@ class GetLanguagesWithSources(
fun subscribe(): Flow<SortedMap<String, List<Source>>> {
return combine(
preferences.enabledLanguages().changes(),
preferences.disabledSources().changes(),
preferences.enabledLanguages.changes(),
preferences.disabledSources.changes(),
repository.getOnlineSources(),
) { enabledLanguage, disabledSource, onlineSources ->
val sortedSources = onlineSources.filterNot { it.id in BlacklistedSources.HIDDEN_SOURCES }.sortedWith(
@@ -9,7 +9,7 @@ class GetShowLatest(
) {
fun subscribe(hasSmartSearchConfig: Boolean): Flow<Boolean> {
return preferences.useNewSourceNavigation().changes()
return preferences.useNewSourceNavigation.changes()
.map {
!hasSmartSearchConfig && !it
}
@@ -9,6 +9,6 @@ class GetSourceCategories(
) {
fun subscribe(): Flow<List<String>> {
return preferences.sourcesTabCategories().changes().map { it.sortedWith(String.CASE_INSENSITIVE_ORDER) }
return preferences.sourcesTabCategories.changes().map { it.sortedWith(String.CASE_INSENSITIVE_ORDER) }
}
}
@@ -16,8 +16,8 @@ class GetSourcesWithFavoriteCount(
fun subscribe(): Flow<List<Pair<Source, Long>>> {
return combine(
preferences.migrationSortingDirection().changes(),
preferences.migrationSortingMode().changes(),
preferences.migrationSortingDirection.changes(),
preferences.migrationSortingMode.changes(),
repository.getSourcesWithFavoriteCount(),
) { direction, mode, list ->
list
@@ -14,7 +14,7 @@ class RenameSourceCategory(
CreateSourceCategory.Result.Success -> {}
}
preferences.sourcesTabSourcesInCategories().getAndSet { sourcesInCategories ->
preferences.sourcesTabSourcesInCategories.getAndSet { sourcesInCategories ->
sourcesInCategories.map {
val index = it.indexOf('|')
if (index != -1 && it.substring(index + 1) == categoryOld) {
@@ -24,7 +24,7 @@ class RenameSourceCategory(
}
}.toSet()
}
preferences.sourcesTabCategories().getAndSet {
preferences.sourcesTabCategories.getAndSet {
it.minus(categoryOld).plus(categoryNew)
}
@@ -7,8 +7,8 @@ class SetMigrateSorting(
) {
fun await(mode: Mode, direction: Direction) {
preferences.migrationSortingMode().set(mode)
preferences.migrationSortingDirection().set(direction)
preferences.migrationSortingMode.set(mode)
preferences.migrationSortingDirection.set(direction)
}
enum class Mode {
@@ -10,7 +10,7 @@ class SetSourceCategories(
fun await(source: Source, sourceCategories: List<String>) {
val sourceIdString = source.id.toString()
preferences.sourcesTabSourcesInCategories().getAndSet { sourcesInCategories ->
preferences.sourcesTabSourcesInCategories.getAndSet { sourcesInCategories ->
val currentSourceCategories = sourcesInCategories.filterNot {
it.substringBefore('|') == sourceIdString
}
@@ -9,7 +9,7 @@ class ToggleExcludeFromDataSaver(
) {
fun await(source: Source) {
preferences.dataSaverExcludedSources().getAndSet {
preferences.dataSaverExcludedSources.getAndSet {
if (source.id.toString() in it) {
it - source.id.toString()
} else {
@@ -7,7 +7,7 @@ class ToggleIncognito(
private val preferences: SourcePreferences,
) {
fun await(extensions: String, enable: Boolean) {
preferences.incognitoExtensions().getAndSet {
preferences.incognitoExtensions.getAndSet {
if (enable) it.plus(extensions) else it.minus(extensions)
}
}
@@ -8,8 +8,8 @@ class ToggleLanguage(
) {
fun await(language: String) {
val isEnabled = language in preferences.enabledLanguages().get()
preferences.enabledLanguages().getAndSet { enabled ->
val isEnabled = language in preferences.enabledLanguages.get()
preferences.enabledLanguages.getAndSet { enabled ->
if (isEnabled) enabled.minus(language) else enabled.plus(language)
}
}
@@ -13,19 +13,19 @@ class ToggleSource(
}
fun await(sourceId: Long, enable: Boolean = isEnabled(sourceId)) {
preferences.disabledSources().getAndSet { disabled ->
preferences.disabledSources.getAndSet { disabled ->
if (enable) disabled.minus("$sourceId") else disabled.plus("$sourceId")
}
}
fun await(sourceIds: List<Long>, enable: Boolean) {
val transformedSourceIds = sourceIds.map { it.toString() }
preferences.disabledSources().getAndSet { disabled ->
preferences.disabledSources.getAndSet { disabled ->
if (enable) disabled.minus(transformedSourceIds) else disabled.plus(transformedSourceIds)
}
}
private fun isEnabled(sourceId: Long): Boolean {
return sourceId.toString() in preferences.disabledSources().get()
return sourceId.toString() in preferences.disabledSources.get()
}
}
@@ -9,8 +9,8 @@ class ToggleSourcePin(
) {
fun await(source: Source) {
val isPinned = source.id.toString() in preferences.pinnedSources().get()
preferences.pinnedSources().getAndSet { pinned ->
val isPinned = source.id.toString() in preferences.pinnedSources.get()
preferences.pinnedSources.getAndSet { pinned ->
if (isPinned) pinned.minus("${source.id}") else pinned.plus("${source.id}")
}
}
@@ -2,91 +2,133 @@ package eu.kanade.domain.source.service
import eu.kanade.domain.source.interactor.SetMigrateSorting
import eu.kanade.tachiyomi.util.system.LocaleHelper
import mihon.domain.migration.models.MigrationFlag
import tachiyomi.core.common.preference.Preference
import tachiyomi.core.common.preference.PreferenceStore
import tachiyomi.core.common.preference.getEnum
import tachiyomi.core.common.preference.getLongArray
import tachiyomi.domain.library.model.LibraryDisplayMode
class SourcePreferences(
private val preferenceStore: PreferenceStore,
preferenceStore: PreferenceStore,
) {
fun sourceDisplayMode() = preferenceStore.getObject(
val sourceDisplayMode: Preference<LibraryDisplayMode> = preferenceStore.getObjectFromString(
"pref_display_mode_catalogue",
LibraryDisplayMode.default,
LibraryDisplayMode.Serializer::serialize,
LibraryDisplayMode.Serializer::deserialize,
)
fun enabledLanguages() = preferenceStore.getStringSet("source_languages", LocaleHelper.getDefaultEnabledLanguages())
val enabledLanguages: Preference<Set<String>> = preferenceStore.getStringSet(
"source_languages",
LocaleHelper.getDefaultEnabledLanguages(),
)
fun disabledSources() = preferenceStore.getStringSet("hidden_catalogues", emptySet())
val disabledSources: Preference<Set<String>> = preferenceStore.getStringSet("hidden_catalogues", emptySet())
fun incognitoExtensions() = preferenceStore.getStringSet("incognito_extensions", emptySet())
val incognitoExtensions: Preference<Set<String>> = preferenceStore.getStringSet("incognito_extensions", emptySet())
fun pinnedSources() = preferenceStore.getStringSet("pinned_catalogues", emptySet())
val pinnedSources: Preference<Set<String>> = preferenceStore.getStringSet("pinned_catalogues", emptySet())
fun lastUsedSource() = preferenceStore.getLong(
val lastUsedSource: Preference<Long> = preferenceStore.getLong(
Preference.appStateKey("last_catalogue_source"),
-1,
)
fun showNsfwSource() = preferenceStore.getBoolean("show_nsfw_source", true)
val showNsfwSource: Preference<Boolean> = preferenceStore.getBoolean("show_nsfw_source", true)
fun migrationSortingMode() = preferenceStore.getEnum("pref_migration_sorting", SetMigrateSorting.Mode.ALPHABETICAL)
val migrationSortingMode: Preference<SetMigrateSorting.Mode> = preferenceStore.getEnum(
"pref_migration_sorting",
SetMigrateSorting.Mode.ALPHABETICAL,
)
fun migrationSortingDirection() = preferenceStore.getEnum(
val migrationSortingDirection: Preference<SetMigrateSorting.Direction> = preferenceStore.getEnum(
"pref_migration_direction",
SetMigrateSorting.Direction.ASCENDING,
)
fun hideInLibraryItems() = preferenceStore.getBoolean("browse_hide_in_library_items", false)
val hideInLibraryItems: Preference<Boolean> = preferenceStore.getBoolean("browse_hide_in_library_items", false)
fun extensionRepos() = preferenceStore.getStringSet("extension_repos", emptySet())
val extensionRepos: Preference<Set<String>> = preferenceStore.getStringSet("extension_repos", emptySet())
fun extensionUpdatesCount() = preferenceStore.getInt("ext_updates_count", 0)
val extensionUpdatesCount: Preference<Int> = preferenceStore.getInt("ext_updates_count", 0)
fun trustedExtensions() = preferenceStore.getStringSet(
val trustedExtensions: Preference<Set<String>> = preferenceStore.getStringSet(
Preference.appStateKey("trusted_extensions"),
emptySet(),
)
fun globalSearchFilterState() = preferenceStore.getBoolean(
val globalSearchFilterState: Preference<Boolean> = preferenceStore.getBoolean(
Preference.appStateKey("has_filters_toggle_state"),
false,
)
// SY -->
fun enableSourceBlacklist() = preferenceStore.getBoolean("eh_enable_source_blacklist", true)
val enableSourceBlacklist: Preference<Boolean> = preferenceStore.getBoolean("eh_enable_source_blacklist", true)
fun sourcesTabCategories() = preferenceStore.getStringSet("sources_tab_categories", mutableSetOf())
val sourcesTabCategories: Preference<Set<String>> = preferenceStore.getStringSet("sources_tab_categories", mutableSetOf())
fun sourcesTabCategoriesFilter() = preferenceStore.getBoolean("sources_tab_categories_filter", false)
val sourcesTabCategoriesFilter: Preference<Boolean> = preferenceStore.getBoolean("sources_tab_categories_filter", false)
fun sourcesTabSourcesInCategories() = preferenceStore.getStringSet("sources_tab_source_categories", mutableSetOf())
val sourcesTabSourcesInCategories: Preference<Set<String>> = preferenceStore.getStringSet("sources_tab_source_categories", mutableSetOf())
fun dataSaver() = preferenceStore.getEnum("data_saver", DataSaver.NONE)
val dataSaver: Preference<DataSaver> = preferenceStore.getEnum("data_saver", DataSaver.NONE)
fun dataSaverIgnoreJpeg() = preferenceStore.getBoolean("ignore_jpeg", false)
val dataSaverIgnoreJpeg: Preference<Boolean> = preferenceStore.getBoolean("ignore_jpeg", false)
fun dataSaverIgnoreGif() = preferenceStore.getBoolean("ignore_gif", true)
val dataSaverIgnoreGif: Preference<Boolean> = preferenceStore.getBoolean("ignore_gif", true)
fun dataSaverImageQuality() = preferenceStore.getInt("data_saver_image_quality", 80)
val dataSaverImageQuality: Preference<Int> = preferenceStore.getInt("data_saver_image_quality", 80)
fun dataSaverImageFormatJpeg() = preferenceStore.getBoolean("data_saver_image_format_jpeg", false)
val dataSaverImageFormatJpeg: Preference<Boolean> = preferenceStore.getBoolean("data_saver_image_format_jpeg", false)
fun dataSaverServer() = preferenceStore.getString("data_saver_server", "")
val dataSaverServer: Preference<String> = preferenceStore.getString("data_saver_server", "")
fun dataSaverColorBW() = preferenceStore.getBoolean("data_saver_color_bw", false)
val dataSaverColorBW: Preference<Boolean> = preferenceStore.getBoolean("data_saver_color_bw", false)
fun dataSaverExcludedSources() = preferenceStore.getStringSet("data_saver_excluded", emptySet())
val dataSaverExcludedSources: Preference<Set<String>> = preferenceStore.getStringSet("data_saver_excluded", emptySet())
fun dataSaverDownloader() = preferenceStore.getBoolean("data_saver_downloader", true)
val dataSaverDownloader: Preference<Boolean> = preferenceStore.getBoolean("data_saver_downloader", true)
enum class DataSaver {
NONE,
BANDWIDTH_HERO,
WSRV_NL,
}
val allowLocalSourceHiddenFolders: Preference<Boolean> = preferenceStore.getBoolean("allow_local_source_hidden_folders", false)
val preferredMangaDexId: Preference<String> = preferenceStore.getString("preferred_mangaDex_id", "0")
val mangadexSyncToLibraryIndexes: Preference<Set<String>> = preferenceStore.getStringSet(
"pref_mangadex_sync_to_library_indexes",
emptySet(),
)
val recommendationSearchFlags: Preference<Int> = preferenceStore.getInt("rec_search_flags", Int.MAX_VALUE)
// SY <--
val migrationSources: Preference<List<Long>> = preferenceStore.getLongArray("migration_sources", emptyList())
val migrationFlags: Preference<Set<MigrationFlag>> = preferenceStore.getObjectFromInt(
key = "migration_flags",
defaultValue = MigrationFlag.entries.toSet(),
serializer = { MigrationFlag.toBit(it) },
deserializer = { value: Int -> MigrationFlag.fromBit(value) },
)
val migrationDeepSearchMode: Preference<Boolean> = preferenceStore.getBoolean("migration_deep_search", false)
val migrationPrioritizeByChapters: Preference<Boolean> = preferenceStore.getBoolean(
"migration_prioritize_by_chapters",
false,
)
val migrationHideUnmatched: Preference<Boolean> = preferenceStore.getBoolean("migration_hide_unmatched", false)
val migrationHideWithoutUpdates: Preference<Boolean> = preferenceStore.getBoolean(
"migration_hide_without_updates",
false,
)
}
@@ -9,21 +9,21 @@ import java.util.UUID
class SyncPreferences(
private val preferenceStore: PreferenceStore,
) {
fun clientHost() = preferenceStore.getString("sync_client_host", "https://sync.tachiyomi.org")
fun clientAPIKey() = preferenceStore.getString("sync_client_api_key", "")
fun lastSyncTimestamp() = preferenceStore.getLong(Preference.appStateKey("last_sync_timestamp"), 0L)
val clientHost: Preference<String> = preferenceStore.getString("sync_client_host", "https://sync.tachiyomi.org")
val clientAPIKey: Preference<String> = preferenceStore.getString("sync_client_api_key", "")
val lastSyncTimestamp: Preference<Long> = preferenceStore.getLong(Preference.appStateKey("last_sync_timestamp"), 0L)
fun lastSyncEtag() = preferenceStore.getString("sync_etag", "")
val lastSyncEtag: Preference<String> = preferenceStore.getString("sync_etag", "")
fun syncInterval() = preferenceStore.getInt("sync_interval", 0)
fun syncService() = preferenceStore.getInt("sync_service", 0)
val syncInterval: Preference<Int> = preferenceStore.getInt("sync_interval", 0)
val syncService: Preference<Int> = preferenceStore.getInt("sync_service", 0)
fun googleDriveAccessToken() = preferenceStore.getString(
val googleDriveAccessToken: Preference<String> = preferenceStore.getString(
Preference.appStateKey("google_drive_access_token"),
"",
)
fun googleDriveRefreshToken() = preferenceStore.getString(
val googleDriveRefreshToken: Preference<String> = preferenceStore.getString(
Preference.appStateKey("google_drive_refresh_token"),
"",
)
@@ -42,7 +42,7 @@ class SyncPreferences(
}
fun isSyncEnabled(): Boolean {
return syncService().get() != 0
return syncService.get() != 0
}
fun getSyncSettings(): SyncSettings {
@@ -34,17 +34,17 @@ class TrackPreferences(
fun trackToken(tracker: Tracker) = preferenceStore.getString(Preference.privateKey("track_token_${tracker.id}"), "")
fun anilistScoreType() = preferenceStore.getString("anilist_score_type", Anilist.POINT_10)
val anilistScoreType: Preference<String> = preferenceStore.getString("anilist_score_type", Anilist.POINT_10)
fun autoUpdateTrack() = preferenceStore.getBoolean("pref_auto_update_manga_sync_key", true)
val autoUpdateTrack: Preference<Boolean> = preferenceStore.getBoolean("pref_auto_update_manga_sync_key", true)
fun autoUpdateTrackOnMarkRead() = preferenceStore.getEnum(
val autoUpdateTrackOnMarkRead: Preference<AutoTrackState> = preferenceStore.getEnum(
"pref_auto_update_manga_on_mark_read",
AutoTrackState.ALWAYS,
)
// SY -->
fun resolveUsingSourceMetadata() = preferenceStore.getBoolean(
val resolveUsingSourceMetadata: Preference<Boolean> = preferenceStore.getBoolean(
"pref_resolve_using_source_metadata_key",
true,
)
@@ -6,6 +6,7 @@ import eu.kanade.domain.ui.model.TabletUiMode
import eu.kanade.domain.ui.model.ThemeMode
import eu.kanade.tachiyomi.util.system.DeviceUtil
import eu.kanade.tachiyomi.util.system.isDynamicColorAvailable
import tachiyomi.core.common.preference.Preference
import tachiyomi.core.common.preference.PreferenceStore
import tachiyomi.core.common.preference.getEnum
import java.time.format.DateTimeFormatter
@@ -13,10 +14,10 @@ import java.time.format.FormatStyle
import java.util.Locale
class UiPreferences(
private val preferenceStore: PreferenceStore,
preferenceStore: PreferenceStore,
) {
fun themeMode() = preferenceStore.getEnum(
val themeMode = preferenceStore.getEnum(
"pref_theme_mode_key",
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
ThemeMode.SYSTEM
@@ -25,7 +26,7 @@ class UiPreferences(
},
)
fun appTheme() = preferenceStore.getEnum(
val appTheme: Preference<AppTheme> = preferenceStore.getEnum(
"pref_app_theme",
if (DeviceUtil.isDynamicColorAvailable) {
AppTheme.MONET
@@ -34,35 +35,37 @@ class UiPreferences(
},
)
fun themeDarkAmoled() = preferenceStore.getBoolean("pref_theme_dark_amoled_key", false)
val themeDarkAmoled: Preference<Boolean> = preferenceStore.getBoolean("pref_theme_dark_amoled_key", false)
fun relativeTime() = preferenceStore.getBoolean("relative_time_v2", true)
val relativeTime: Preference<Boolean> = preferenceStore.getBoolean("relative_time_v2", true)
fun dateFormat() = preferenceStore.getString("app_date_format", "")
val dateFormat: Preference<String> = preferenceStore.getString("app_date_format", "")
fun tabletUiMode() = preferenceStore.getEnum("tablet_ui_mode", TabletUiMode.AUTOMATIC)
val tabletUiMode: Preference<TabletUiMode> = preferenceStore.getEnum("tablet_ui_mode", TabletUiMode.AUTOMATIC)
val imagesInDescription: Preference<Boolean> = preferenceStore.getBoolean("pref_render_images_description", true)
// SY -->
fun expandFilters() = preferenceStore.getBoolean("eh_expand_filters", false)
val expandFilters: Preference<Boolean> = preferenceStore.getBoolean("eh_expand_filters", false)
fun hideFeedTab() = preferenceStore.getBoolean("hide_latest_tab", false)
val hideFeedTab: Preference<Boolean> = preferenceStore.getBoolean("hide_latest_tab", false)
fun feedTabInFront() = preferenceStore.getBoolean("latest_tab_position", false)
val feedTabInFront: Preference<Boolean> = preferenceStore.getBoolean("latest_tab_position", false)
fun recommendsInOverflow() = preferenceStore.getBoolean("recommends_in_overflow", false)
val recommendsInOverflow: Preference<Boolean> = preferenceStore.getBoolean("recommends_in_overflow", false)
fun mergeInOverflow() = preferenceStore.getBoolean("merge_in_overflow", true)
val mergeInOverflow: Preference<Boolean> = preferenceStore.getBoolean("merge_in_overflow", true)
fun previewsRowCount() = preferenceStore.getInt("pref_previews_row_count", 4)
val previewsRowCount: Preference<Int> = preferenceStore.getInt("pref_previews_row_count", 4)
fun useNewSourceNavigation() = preferenceStore.getBoolean("use_new_source_navigation", true)
val useNewSourceNavigation: Preference<Boolean> = preferenceStore.getBoolean("use_new_source_navigation", true)
fun bottomBarLabels() = preferenceStore.getBoolean("pref_show_bottom_bar_labels", true)
val bottomBarLabels: Preference<Boolean> = preferenceStore.getBoolean("pref_show_bottom_bar_labels", true)
fun showNavUpdates() = preferenceStore.getBoolean("pref_show_updates_button", true)
val showNavUpdates: Preference<Boolean> = preferenceStore.getBoolean("pref_show_updates_button", true)
fun showNavHistory() = preferenceStore.getBoolean("pref_show_history_button", true)
val showNavHistory: Preference<Boolean> = preferenceStore.getBoolean("pref_show_history_button", true)
// SY <--
@@ -6,6 +6,7 @@ import tachiyomi.i18n.MR
enum class AppTheme(val titleRes: StringResource?) {
DEFAULT(MR.strings.label_default),
MONET(MR.strings.theme_monet),
CATPPUCCIN(MR.strings.theme_catppuccin),
GREEN_APPLE(MR.strings.theme_greenapple),
LAVENDER(MR.strings.theme_lavender),
MIDNIGHT_DUSK(MR.strings.theme_midnightdusk),
@@ -351,13 +351,17 @@ private fun ExtensionItemContent(
horizontalArrangement = Arrangement.spacedBy(MaterialTheme.padding.extraSmall),
) {
ProvideTextStyle(value = MaterialTheme.typography.bodySmall) {
var hasAlreadyShownAnElement by remember { mutableStateOf(false) }
if (extension is Extension.Installed && extension.lang.isNotEmpty()) {
hasAlreadyShownAnElement = true
Text(
text = LocaleHelper.getSourceDisplayName(extension.lang, LocalContext.current),
)
}
if (extension.versionName.isNotEmpty()) {
if (hasAlreadyShownAnElement) DotSeparatorNoSpaceText()
hasAlreadyShownAnElement = true
Text(
text = extension.versionName,
)
@@ -373,6 +377,8 @@ private fun ExtensionItemContent(
else -> null
}
if (warning != null) {
if (hasAlreadyShownAnElement) DotSeparatorNoSpaceText()
hasAlreadyShownAnElement = true
Text(
text = stringResource(warning).uppercase(),
color = MaterialTheme.colorScheme.error,
@@ -380,6 +386,12 @@ private fun ExtensionItemContent(
overflow = TextOverflow.Ellipsis,
)
}
if (extension is Extension.Installed && !extension.isShared) {
if (hasAlreadyShownAnElement) DotSeparatorNoSpaceText()
Text(
text = stringResource(MR.strings.ext_installer_private),
)
}
if (!installStep.isCompleted()) {
DotSeparatorNoSpaceText()
@@ -41,6 +41,7 @@ fun GlobalSearchScreen(
navigateUp = navigateUp,
onChangeSearchQuery = onChangeSearchQuery,
onSearch = onSearch,
hideSourceFilter = false,
sourceFilter = state.sourceFilter,
onChangeSearchFilter = onChangeSearchFilter,
onlyShowHasResults = state.onlyShowHasResults,
@@ -1,84 +0,0 @@
package eu.kanade.presentation.browse
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.items
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import eu.kanade.presentation.components.AppBar
import eu.kanade.presentation.manga.components.BaseMangaListItem
import eu.kanade.tachiyomi.ui.browse.migration.manga.MigrateMangaScreenModel
import tachiyomi.domain.manga.model.Manga
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.FastScrollLazyColumn
import tachiyomi.presentation.core.components.material.Scaffold
import tachiyomi.presentation.core.screens.EmptyScreen
@Composable
fun MigrateMangaScreen(
navigateUp: () -> Unit,
title: String?,
state: MigrateMangaScreenModel.State,
onClickItem: (Manga) -> Unit,
onClickCover: (Manga) -> Unit,
) {
Scaffold(
topBar = { scrollBehavior ->
AppBar(
title = title,
navigateUp = navigateUp,
scrollBehavior = scrollBehavior,
)
},
) { contentPadding ->
if (state.isEmpty) {
EmptyScreen(
stringRes = MR.strings.empty_screen,
modifier = Modifier.padding(contentPadding),
)
return@Scaffold
}
MigrateMangaContent(
contentPadding = contentPadding,
state = state,
onClickItem = onClickItem,
onClickCover = onClickCover,
)
}
}
@Composable
private fun MigrateMangaContent(
contentPadding: PaddingValues,
state: MigrateMangaScreenModel.State,
onClickItem: (Manga) -> Unit,
onClickCover: (Manga) -> Unit,
) {
FastScrollLazyColumn(
contentPadding = contentPadding,
) {
items(state.titles) { manga ->
MigrateMangaItem(
manga = manga,
onClickItem = onClickItem,
onClickCover = onClickCover,
)
}
}
}
@Composable
private fun MigrateMangaItem(
manga: Manga,
onClickItem: (Manga) -> Unit,
onClickCover: (Manga) -> Unit,
modifier: Modifier = Modifier,
) {
BaseMangaListItem(
modifier = modifier,
manga = manga,
onClickItem = { onClickItem(manga) },
onClickCover = { onClickCover(manga) },
)
}
@@ -32,6 +32,7 @@ fun MigrateSearchScreen(
navigateUp = navigateUp,
onChangeSearchQuery = onChangeSearchQuery,
onSearch = onSearch,
hideSourceFilter = true,
sourceFilter = state.sourceFilter,
onChangeSearchFilter = onChangeSearchFilter,
onlyShowHasResults = state.onlyShowHasResults,
@@ -10,7 +10,6 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.items
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.outlined.ArrowForward
import androidx.compose.material.icons.outlined.ArrowForward
import androidx.compose.material.icons.outlined.ContentCopy
import androidx.compose.material.icons.outlined.CopyAll
import androidx.compose.material.icons.outlined.Done
@@ -30,8 +30,8 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.paging.LoadState
import androidx.paging.compose.LazyPagingItems
import com.gowtham.ratingbar.RatingBar
import com.gowtham.ratingbar.RatingBarConfig
import com.gowtham.ratingbar.ComposeStars
import com.gowtham.ratingbar.RatingBarStyle
import dev.icerock.moko.resources.StringResource
import eu.kanade.presentation.manga.components.MangaCover
import exh.metadata.MetadataUtil
@@ -222,17 +222,18 @@ fun BrowseSourceEHentaiListItem(
verticalArrangement = Arrangement.spacedBy(MaterialTheme.padding.small),
horizontalAlignment = Alignment.Start,
) {
RatingBar(
ComposeStars(
value = rating,
onValueChange = {},
onRatingChanged = {},
config = RatingBarConfig().apply {
isIndicator(true)
numStars(5)
size(18.dp)
activeColor(Color(0xFF005ED7))
inactiveColor(Color(0xE1E2ECFF))
},
numOfStars = 5,
size = 18.dp,
spaceBetween = 2.dp,
hideInactiveStars = false,
style = RatingBarStyle.Fill(
activeColor = Color(0xFF005ED7),
inActiveColor = Color(0xE1E2ECFF),
),
painterEmpty = null,
painterFilled = null,
)
val color = genre?.first?.color
val res = genre?.second
@@ -3,12 +3,12 @@ package eu.kanade.presentation.browse.components
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.FilterList
import androidx.compose.material3.Icon
import androidx.compose.material3.SmallExtendedFloatingActionButton
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import tachiyomi.i18n.MR
import tachiyomi.i18n.sy.SYMR
import tachiyomi.presentation.core.components.material.ExtendedFloatingActionButton
import tachiyomi.presentation.core.i18n.stringResource
@Composable
@@ -17,7 +17,7 @@ fun BrowseSourceFloatingActionButton(
onFabClick: () -> Unit,
modifier: Modifier = Modifier,
) {
ExtendedFloatingActionButton(
SmallExtendedFloatingActionButton(
modifier = modifier,
text = {
Text(
@@ -4,7 +4,6 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ViewList
import androidx.compose.material.icons.automirrored.outlined.Help
import androidx.compose.material.icons.filled.ViewModule
import androidx.compose.material.icons.outlined.Help
import androidx.compose.material.icons.outlined.Public
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBarScrollBehavior
@@ -40,6 +40,7 @@ fun GlobalSearchToolbar(
navigateUp: () -> Unit,
onChangeSearchQuery: (String?) -> Unit,
onSearch: (String) -> Unit,
hideSourceFilter: Boolean,
sourceFilter: SourceFilter,
onChangeSearchFilter: (SourceFilter) -> Unit,
onlyShowHasResults: Boolean,
@@ -73,6 +74,7 @@ fun GlobalSearchToolbar(
horizontalArrangement = Arrangement.spacedBy(MaterialTheme.padding.small),
) {
// TODO: make this UX better; it only applies when triggering a new search
if (!hideSourceFilter) {
FilterChip(
selected = sourceFilter == SourceFilter.PinnedOnly,
onClick = { onChangeSearchFilter(SourceFilter.PinnedOnly) },
@@ -105,6 +107,7 @@ fun GlobalSearchToolbar(
)
VerticalDivider()
}
FilterChip(
selected = onlyShowHasResults,
@@ -4,11 +4,11 @@ import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Add
import androidx.compose.material3.Icon
import androidx.compose.material3.SmallExtendedFloatingActionButton
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.material.ExtendedFloatingActionButton
import tachiyomi.presentation.core.i18n.stringResource
import tachiyomi.presentation.core.util.shouldExpandFAB
@@ -18,7 +18,7 @@ fun CategoryFloatingActionButton(
onCreate: () -> Unit,
modifier: Modifier = Modifier,
) {
ExtendedFloatingActionButton(
SmallExtendedFloatingActionButton(
text = { Text(text = stringResource(MR.strings.action_add)) },
icon = { Icon(imageVector = Icons.Outlined.Add, contentDescription = null) },
onClick = onCreate,
@@ -7,7 +7,6 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.outlined.Label
import androidx.compose.material.icons.outlined.Delete
import androidx.compose.material.icons.outlined.Label
import androidx.compose.material3.ElevatedCard
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
@@ -9,7 +9,6 @@ import androidx.compose.material.icons.automirrored.outlined.Label
import androidx.compose.material.icons.outlined.ArrowDropDown
import androidx.compose.material.icons.outlined.ArrowDropUp
import androidx.compose.material.icons.outlined.Delete
import androidx.compose.material.icons.outlined.Label
import androidx.compose.material3.ElevatedCard
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
@@ -9,7 +9,6 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.outlined.Label
import androidx.compose.material.icons.outlined.Delete
import androidx.compose.material.icons.outlined.Edit
import androidx.compose.material.icons.outlined.Label
import androidx.compose.material3.ElevatedCard
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
@@ -1,9 +1,9 @@
package eu.kanade.presentation.components
import androidx.compose.animation.SizeTransform
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.togetherWith
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.window.Dialog
@@ -32,9 +32,10 @@ fun NavigatorAdaptiveSheet(
) {
ScreenTransition(
navigator = sheetNavigator,
enterTransition = { fadeIn(animationSpec = tween(220, delayMillis = 90)) },
exitTransition = { fadeOut(animationSpec = tween(90)) },
sizeTransform = { SizeTransform() },
transition = {
fadeIn(animationSpec = tween(220, delayMillis = 90)) togetherWith
fadeOut(animationSpec = tween(90))
},
)
}
@@ -21,8 +21,9 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.PlainTooltip
import androidx.compose.material3.Text
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.material3.TooltipAnchorPosition
import androidx.compose.material3.TooltipBox
import androidx.compose.material3.TooltipDefaults
import androidx.compose.material3.TooltipDefaults.rememberTooltipPositionProvider
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.TopAppBarScrollBehavior
@@ -195,7 +196,7 @@ fun AppBarActions(
actions.filterIsInstance<AppBar.Action>().map {
TooltipBox(
positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(),
positionProvider = rememberTooltipPositionProvider(TooltipAnchorPosition.Above),
tooltip = {
PlainTooltip {
Text(it.title)
@@ -220,7 +221,7 @@ fun AppBarActions(
val overflowActions = actions.filterIsInstance<AppBar.OverflowAction>()
if (overflowActions.isNotEmpty()) {
TooltipBox(
positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(),
positionProvider = rememberTooltipPositionProvider(TooltipAnchorPosition.Above),
tooltip = {
PlainTooltip {
Text(stringResource(MR.strings.action_menu_overflow_description))
@@ -349,7 +350,7 @@ fun SearchToolbar(
// Don't show search action
} else if (searchQuery == null) {
TooltipBox(
positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(),
positionProvider = rememberTooltipPositionProvider(TooltipAnchorPosition.Above),
tooltip = {
PlainTooltip {
Text(stringResource(MR.strings.action_search))
@@ -369,7 +370,7 @@ fun SearchToolbar(
}
} else if (searchQuery.isNotEmpty()) {
TooltipBox(
positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(),
positionProvider = rememberTooltipPositionProvider(TooltipAnchorPosition.Above),
tooltip = {
PlainTooltip {
Text(stringResource(MR.strings.action_reset))
@@ -22,7 +22,7 @@ fun relativeDateText(
Instant.ofEpochMilli(dateEpochMillis),
ZoneId.systemDefault(),
)
.takeIf { dateEpochMillis > 0L },
.takeIf { dateEpochMillis != 0L },
)
}
@@ -33,8 +33,8 @@ fun relativeDateText(
val context = LocalContext.current
val preferences = remember { Injekt.get<UiPreferences>() }
val relativeTime = remember { preferences.relativeTime().get() }
val dateFormat = remember { UiPreferences.dateFormat(preferences.dateFormat().get()) }
val relativeTime = remember { preferences.relativeTime.get() }
val dateFormat = remember { UiPreferences.dateFormat(preferences.dateFormat.get()) }
return localDate?.toRelativeString(
context = context,
@@ -4,6 +4,7 @@ import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.DpOffset
import eu.kanade.presentation.manga.DownloadAction
import kotlinx.collections.immutable.persistentListOf
import tachiyomi.i18n.MR
@@ -12,10 +13,44 @@ import tachiyomi.presentation.core.i18n.stringResource
@Composable
fun DownloadDropdownMenu(
modifier: Modifier = Modifier,
expanded: Boolean,
onDismissRequest: () -> Unit,
onDownloadClicked: (DownloadAction) -> Unit,
modifier: Modifier = Modifier,
offset: DpOffset? = null,
) {
if (offset != null) {
DropdownMenu(
expanded = expanded,
onDismissRequest = onDismissRequest,
modifier = modifier,
offset = offset,
content = {
DownloadDropdownMenuItems(
onDismissRequest = onDismissRequest,
onDownloadClicked = onDownloadClicked,
)
},
)
} else {
DropdownMenu(
expanded = expanded,
onDismissRequest = onDismissRequest,
modifier = modifier,
content = {
DownloadDropdownMenuItems(
onDismissRequest = onDismissRequest,
onDownloadClicked = onDownloadClicked,
)
},
)
}
}
@Composable
private fun DownloadDropdownMenuItems(
onDismissRequest: () -> Unit,
onDownloadClicked: (DownloadAction) -> Unit,
) {
val options = persistentListOf(
DownloadAction.NEXT_1_CHAPTER to pluralStringResource(MR.plurals.download_amount, 1, 1),
@@ -23,13 +58,9 @@ fun DownloadDropdownMenu(
DownloadAction.NEXT_10_CHAPTERS to pluralStringResource(MR.plurals.download_amount, 10, 10),
DownloadAction.NEXT_25_CHAPTERS to pluralStringResource(MR.plurals.download_amount, 25, 25),
DownloadAction.UNREAD_CHAPTERS to stringResource(MR.strings.download_unread),
DownloadAction.BOOKMARKED_CHAPTERS to stringResource(MR.strings.download_bookmarked),
)
DropdownMenu(
expanded = expanded,
onDismissRequest = onDismissRequest,
modifier = modifier,
) {
options.map { (downloadAction, string) ->
DropdownMenuItem(
text = { Text(text = string) },
@@ -40,4 +71,3 @@ fun DownloadDropdownMenu(
)
}
}
}
@@ -100,9 +100,9 @@ fun LibrarySettingsDialog(
private fun ColumnScope.FilterPage(
screenModel: LibrarySettingsScreenModel,
) {
val filterDownloaded by screenModel.libraryPreferences.filterDownloaded().collectAsState()
val downloadedOnly by screenModel.preferences.downloadedOnly().collectAsState()
val autoUpdateMangaRestrictions by screenModel.libraryPreferences.autoUpdateMangaRestrictions().collectAsState()
val filterDownloaded by screenModel.libraryPreferences.filterDownloaded.collectAsState()
val downloadedOnly by screenModel.preferences.downloadedOnly.collectAsState()
val autoUpdateMangaRestrictions by screenModel.libraryPreferences.autoUpdateMangaRestrictions.collectAsState()
TriStateItem(
label = stringResource(MR.strings.label_downloaded),
@@ -114,25 +114,25 @@ private fun ColumnScope.FilterPage(
enabled = !downloadedOnly,
onClick = { screenModel.toggleFilter(LibraryPreferences::filterDownloaded) },
)
val filterUnread by screenModel.libraryPreferences.filterUnread().collectAsState()
val filterUnread by screenModel.libraryPreferences.filterUnread.collectAsState()
TriStateItem(
label = stringResource(MR.strings.action_filter_unread),
state = filterUnread,
onClick = { screenModel.toggleFilter(LibraryPreferences::filterUnread) },
)
val filterStarted by screenModel.libraryPreferences.filterStarted().collectAsState()
val filterStarted by screenModel.libraryPreferences.filterStarted.collectAsState()
TriStateItem(
label = stringResource(MR.strings.label_started),
state = filterStarted,
onClick = { screenModel.toggleFilter(LibraryPreferences::filterStarted) },
)
val filterBookmarked by screenModel.libraryPreferences.filterBookmarked().collectAsState()
val filterBookmarked by screenModel.libraryPreferences.filterBookmarked.collectAsState()
TriStateItem(
label = stringResource(MR.strings.action_filter_bookmarked),
state = filterBookmarked,
onClick = { screenModel.toggleFilter(LibraryPreferences::filterBookmarked) },
)
val filterCompleted by screenModel.libraryPreferences.filterCompleted().collectAsState()
val filterCompleted by screenModel.libraryPreferences.filterCompleted.collectAsState()
TriStateItem(
label = stringResource(MR.strings.completed),
state = filterCompleted,
@@ -143,7 +143,7 @@ private fun ColumnScope.FilterPage(
(isDevFlavor || isPreviewBuildType) &&
LibraryPreferences.MANGA_OUTSIDE_RELEASE_PERIOD in autoUpdateMangaRestrictions
) {
val filterIntervalCustom by screenModel.libraryPreferences.filterIntervalCustom().collectAsState()
val filterIntervalCustom by screenModel.libraryPreferences.filterIntervalCustom.collectAsState()
TriStateItem(
label = stringResource(MR.strings.action_filter_interval_custom),
state = filterIntervalCustom,
@@ -151,7 +151,7 @@ private fun ColumnScope.FilterPage(
)
}
// SY -->
val filterLewd by screenModel.libraryPreferences.filterLewd().collectAsState()
val filterLewd by screenModel.libraryPreferences.filterLewd.collectAsState()
TriStateItem(
label = stringResource(SYMR.strings.lewd),
state = filterLewd,
@@ -194,7 +194,7 @@ private fun ColumnScope.SortPage(
) {
val trackers by screenModel.trackersFlow.collectAsState()
// SY -->
val globalSortMode by screenModel.libraryPreferences.sortingMode().collectAsState()
val globalSortMode by screenModel.libraryPreferences.sortingMode.collectAsState()
val sortingMode = if (screenModel.grouping == LibraryGroup.BY_DEFAULT) {
category.sort.type
} else {
@@ -206,9 +206,9 @@ private fun ColumnScope.SortPage(
!globalSortMode.isAscending
}
val hasSortTags by remember {
screenModel.libraryPreferences.sortTagsForLibrary().changes()
screenModel.libraryPreferences.sortTagsForLibrary.changes()
.map { it.isNotEmpty() }
}.collectAsState(initial = screenModel.libraryPreferences.sortTagsForLibrary().get().isNotEmpty())
}.collectAsState(initial = screenModel.libraryPreferences.sortTagsForLibrary.get().isNotEmpty())
// SY <--
val options = remember(trackers.isEmpty()/* SY --> */, hasSortTags/* SY <-- */) {
@@ -287,7 +287,7 @@ private val displayModes = listOf(
private fun ColumnScope.DisplayPage(
screenModel: LibrarySettingsScreenModel,
) {
val displayMode by screenModel.libraryPreferences.displayMode().collectAsState()
val displayMode by screenModel.libraryPreferences.displayMode.collectAsState()
SettingsChipRow(MR.strings.action_display_mode) {
displayModes.map { (titleRes, mode) ->
FilterChip(
@@ -302,9 +302,9 @@ private fun ColumnScope.DisplayPage(
val configuration = LocalConfiguration.current
val columnPreference = remember {
if (configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) {
screenModel.libraryPreferences.landscapeColumns()
screenModel.libraryPreferences.landscapeColumns
} else {
screenModel.libraryPreferences.portraitColumns()
screenModel.libraryPreferences.portraitColumns
}
}
@@ -313,7 +313,7 @@ private fun ColumnScope.DisplayPage(
value = columns,
valueRange = 0..10,
label = stringResource(MR.strings.pref_library_columns),
valueText = if (columns > 0) {
valueString = if (columns > 0) {
columns.toString()
} else {
stringResource(MR.strings.label_auto)
@@ -326,33 +326,33 @@ private fun ColumnScope.DisplayPage(
HeadingItem(MR.strings.overlay_header)
CheckboxItem(
label = stringResource(MR.strings.action_display_download_badge),
pref = screenModel.libraryPreferences.downloadBadge(),
pref = screenModel.libraryPreferences.downloadBadge,
)
CheckboxItem(
label = stringResource(MR.strings.action_display_unread_badge),
pref = screenModel.libraryPreferences.unreadBadge(),
pref = screenModel.libraryPreferences.unreadBadge,
)
CheckboxItem(
label = stringResource(MR.strings.action_display_local_badge),
pref = screenModel.libraryPreferences.localBadge(),
pref = screenModel.libraryPreferences.localBadge,
)
CheckboxItem(
label = stringResource(MR.strings.action_display_language_badge),
pref = screenModel.libraryPreferences.languageBadge(),
pref = screenModel.libraryPreferences.languageBadge,
)
CheckboxItem(
label = stringResource(MR.strings.action_display_show_continue_reading_button),
pref = screenModel.libraryPreferences.showContinueReadingButton(),
pref = screenModel.libraryPreferences.showContinueReadingButton,
)
HeadingItem(MR.strings.tabs_header)
CheckboxItem(
label = stringResource(MR.strings.action_display_show_tabs),
pref = screenModel.libraryPreferences.categoryTabs(),
pref = screenModel.libraryPreferences.categoryTabs,
)
CheckboxItem(
label = stringResource(MR.strings.action_display_show_number_of_items),
pref = screenModel.libraryPreferences.categoryNumberOfItems(),
pref = screenModel.libraryPreferences.categoryNumberOfItems,
)
}
@@ -5,7 +5,6 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.lazy.grid.items
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.util.fastAny
import eu.kanade.tachiyomi.ui.library.LibraryItem
import tachiyomi.domain.library.model.LibraryManga
import tachiyomi.domain.manga.model.MangaCover
@@ -15,7 +14,7 @@ internal fun LibraryComfortableGrid(
items: List<LibraryItem>,
columns: Int,
contentPadding: PaddingValues,
selection: List<LibraryManga>,
selection: Set<Long>,
onClick: (LibraryManga) -> Unit,
onLongClick: (LibraryManga) -> Unit,
onClickContinueReading: ((LibraryManga) -> Unit)?,
@@ -35,7 +34,7 @@ internal fun LibraryComfortableGrid(
) { libraryItem ->
val manga = libraryItem.libraryManga.manga
MangaComfortableGridItem(
isSelected = selection.fastAny { it.id == libraryItem.libraryManga.id },
isSelected = manga.id in selection,
title = manga.title,
coverData = MangaCover(
mangaId = manga.id,
@@ -5,7 +5,6 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.lazy.grid.items
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.util.fastAny
import eu.kanade.tachiyomi.ui.library.LibraryItem
import tachiyomi.domain.library.model.LibraryManga
import tachiyomi.domain.manga.model.MangaCover
@@ -16,7 +15,7 @@ internal fun LibraryCompactGrid(
showTitle: Boolean,
columns: Int,
contentPadding: PaddingValues,
selection: List<LibraryManga>,
selection: Set<Long>,
onClick: (LibraryManga) -> Unit,
onLongClick: (LibraryManga) -> Unit,
onClickContinueReading: ((LibraryManga) -> Unit)?,
@@ -36,7 +35,7 @@ internal fun LibraryCompactGrid(
) { libraryItem ->
val manga = libraryItem.libraryManga.manga
MangaCompactGridItem(
isSelected = selection.fastAny { it.id == libraryItem.libraryManga.id },
isSelected = manga.id in selection,
title = manga.title.takeIf { showTitle },
coverData = MangaCover(
mangaId = manga.id,
@@ -29,22 +29,22 @@ import kotlin.time.Duration.Companion.seconds
fun LibraryContent(
categories: List<Category>,
searchQuery: String?,
selection: List<LibraryManga>,
selection: Set<Long>,
contentPadding: PaddingValues,
currentPage: () -> Int,
currentPage: Int,
hasActiveFilters: Boolean,
showPageTabs: Boolean,
onChangeCurrentPage: (Int) -> Unit,
onMangaClicked: (Long) -> Unit,
onClickManga: (Long) -> Unit,
onContinueReadingClicked: ((LibraryManga) -> Unit)?,
onToggleSelection: (LibraryManga) -> Unit,
onToggleRangeSelection: (LibraryManga) -> Unit,
onRefresh: (Category?) -> Boolean,
onToggleSelection: (Category, LibraryManga) -> Unit,
onToggleRangeSelection: (Category, LibraryManga) -> Unit,
onRefresh: () -> Boolean,
onGlobalSearchClicked: () -> Unit,
getNumberOfMangaForCategory: (Category) -> Int?,
getItemCountForCategory: (Category) -> Int?,
getDisplayMode: (Int) -> PreferenceMutableState<LibraryDisplayMode>,
getColumnsForOrientation: (Boolean) -> PreferenceMutableState<Int>,
getLibraryForPage: (Int) -> List<LibraryItem>,
getItemsForCategory: (Category) -> List<LibraryItem>,
) {
Column(
modifier = Modifier.padding(
@@ -53,15 +53,14 @@ fun LibraryContent(
end = contentPadding.calculateEndPadding(LocalLayoutDirection.current),
),
) {
// SY -->
val coercedCurrentPage = remember(categories) { currentPage().coerceIn(0, categories.lastIndex) }
val pagerState = rememberPagerState(coercedCurrentPage) { categories.size }
val coercedCurrentPage = remember(categories, currentPage) { currentPage.coerceIn(0, categories.lastIndex) }
// SY <--
val pagerState = rememberPagerState(coercedCurrentPage) { categories.size }
val scope = rememberCoroutineScope()
var isRefreshing by remember(pagerState.currentPage) { mutableStateOf(false) }
if (showPageTabs && categories.size > 1) {
if (showPageTabs && categories.isNotEmpty() && (categories.size > 1 || !categories.first().isSystemCategory)) {
LaunchedEffect(categories) {
if (categories.size <= pagerState.currentPage) {
pagerState.scrollToPage(categories.size - 1)
@@ -70,23 +69,20 @@ fun LibraryContent(
LibraryTabs(
categories = categories,
pagerState = pagerState,
getNumberOfMangaForCategory = getNumberOfMangaForCategory,
) { scope.launch { pagerState.animateScrollToPage(it) } }
}
val notSelectionMode = selection.isEmpty()
val onClickManga = { manga: LibraryManga ->
if (notSelectionMode) {
onMangaClicked(manga.manga.id)
} else {
onToggleSelection(manga)
getItemCountForCategory = getItemCountForCategory,
onTabItemClick = {
scope.launch {
pagerState.animateScrollToPage(it)
}
},
)
}
PullRefresh(
refreshing = isRefreshing,
enabled = selection.isEmpty(),
onRefresh = {
val started = onRefresh(categories.getOrNull(currentPage()) ?: return@PullRefresh)
val started = onRefresh()
if (!started) return@PullRefresh
scope.launch {
// Fake refresh status but hide it after a second as it's a long running task
@@ -95,19 +91,25 @@ fun LibraryContent(
isRefreshing = false
}
},
enabled = notSelectionMode,
) {
LibraryPager(
state = pagerState,
contentPadding = PaddingValues(bottom = contentPadding.calculateBottomPadding()),
hasActiveFilters = hasActiveFilters,
selectedManga = selection,
selection = selection,
searchQuery = searchQuery,
onGlobalSearchClicked = onGlobalSearchClicked,
getCategoryForPage = { page -> categories[page] },
getDisplayMode = getDisplayMode,
getColumnsForOrientation = getColumnsForOrientation,
getLibraryForPage = getLibraryForPage,
onClickManga = onClickManga,
getItemsForCategory = getItemsForCategory,
onClickManga = { category, manga ->
if (selection.isNotEmpty()) {
onToggleSelection(category, manga)
} else {
onClickManga(manga.manga.id)
}
},
onLongClickManga = onToggleRangeSelection,
onClickContinueReading = onContinueReadingClicked,
)
@@ -7,7 +7,6 @@ import androidx.compose.foundation.lazy.items
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.compose.ui.util.fastAny
import eu.kanade.tachiyomi.ui.library.LibraryItem
import tachiyomi.domain.library.model.LibraryManga
import tachiyomi.domain.manga.model.MangaCover
@@ -18,7 +17,7 @@ import tachiyomi.presentation.core.util.plus
internal fun LibraryList(
items: List<LibraryItem>,
contentPadding: PaddingValues,
selection: List<LibraryManga>,
selection: Set<Long>,
onClick: (LibraryManga) -> Unit,
onLongClick: (LibraryManga) -> Unit,
onClickContinueReading: ((LibraryManga) -> Unit)?,
@@ -45,7 +44,7 @@ internal fun LibraryList(
) { libraryItem ->
val manga = libraryItem.libraryManga.manga
MangaListItem(
isSelected = selection.fastAny { it.id == libraryItem.libraryManga.id },
isSelected = manga.id in selection,
title = manga.title,
coverData = MangaCover(
mangaId = manga.id,
@@ -20,6 +20,7 @@ import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.unit.dp
import eu.kanade.core.preference.PreferenceMutableState
import eu.kanade.tachiyomi.ui.library.LibraryItem
import tachiyomi.domain.category.model.Category
import tachiyomi.domain.library.model.LibraryDisplayMode
import tachiyomi.domain.library.model.LibraryManga
import tachiyomi.i18n.MR
@@ -31,14 +32,15 @@ fun LibraryPager(
state: PagerState,
contentPadding: PaddingValues,
hasActiveFilters: Boolean,
selectedManga: List<LibraryManga>,
selection: Set<Long>,
searchQuery: String?,
onGlobalSearchClicked: () -> Unit,
getCategoryForPage: (Int) -> Category,
getDisplayMode: (Int) -> PreferenceMutableState<LibraryDisplayMode>,
getColumnsForOrientation: (Boolean) -> PreferenceMutableState<Int>,
getLibraryForPage: (Int) -> List<LibraryItem>,
onClickManga: (LibraryManga) -> Unit,
onLongClickManga: (LibraryManga) -> Unit,
getItemsForCategory: (Category) -> List<LibraryItem>,
onClickManga: (Category, LibraryManga) -> Unit,
onLongClickManga: (Category, LibraryManga) -> Unit,
onClickContinueReading: ((LibraryManga) -> Unit)?,
) {
HorizontalPager(
@@ -50,9 +52,10 @@ fun LibraryPager(
// To make sure only one offscreen page is being composed
return@HorizontalPager
}
val library = getLibraryForPage(page)
val category = getCategoryForPage(page)
val items = getItemsForCategory(category)
if (library.isEmpty()) {
if (items.isEmpty()) {
LibraryPagerEmptyScreen(
searchQuery = searchQuery,
hasActiveFilters = hasActiveFilters,
@@ -72,12 +75,15 @@ fun LibraryPager(
remember { mutableIntStateOf(0) }
}
val onClickManga: (LibraryManga) -> Unit = { onClickManga(category, it) }
val onLongClickManga: (LibraryManga) -> Unit = { onLongClickManga(category, it) }
when (displayMode) {
LibraryDisplayMode.List -> {
LibraryList(
items = library,
items = items,
contentPadding = contentPadding,
selection = selectedManga,
selection = selection,
onClick = onClickManga,
onLongClick = onLongClickManga,
onClickContinueReading = onClickContinueReading,
@@ -87,11 +93,11 @@ fun LibraryPager(
}
LibraryDisplayMode.CompactGrid, LibraryDisplayMode.CoverOnlyGrid -> {
LibraryCompactGrid(
items = library,
items = items,
showTitle = displayMode is LibraryDisplayMode.CompactGrid,
columns = columns,
contentPadding = contentPadding,
selection = selectedManga,
selection = selection,
onClick = onClickManga,
onLongClick = onLongClickManga,
onClickContinueReading = onClickContinueReading,
@@ -101,10 +107,10 @@ fun LibraryPager(
}
LibraryDisplayMode.ComfortableGrid -> {
LibraryComfortableGrid(
items = library,
items = items,
columns = columns,
contentPadding = contentPadding,
selection = selectedManga,
selection = selection,
onClick = onClickManga,
onLongClick = onLongClickManga,
onClickContinueReading = onClickContinueReading,
@@ -18,13 +18,11 @@ import tachiyomi.presentation.core.components.material.TabText
internal fun LibraryTabs(
categories: List<Category>,
pagerState: PagerState,
getNumberOfMangaForCategory: (Category) -> Int?,
getItemCountForCategory: (Category) -> Int?,
onTabItemClick: (Int) -> Unit,
) {
val currentPageIndex = pagerState.currentPage.coerceAtMost(categories.lastIndex)
Column(
modifier = Modifier.zIndex(1f),
) {
Column(modifier = Modifier.zIndex(2f)) {
PrimaryScrollableTabRow(
selectedTabIndex = currentPageIndex,
edgePadding = 0.dp,
@@ -39,7 +37,7 @@ internal fun LibraryTabs(
text = {
TabText(
text = category.visualName,
badgeCount = getNumberOfMangaForCategory(category),
badgeCount = getItemCountForCategory(category),
)
},
unselectedContentColor = MaterialTheme.colorScheme.onSurface,
@@ -66,7 +66,7 @@ fun ChapterSettingsDialog(
)
}
val downloadedOnly = remember { Injekt.get<BasePreferences>().downloadedOnly().get() }
val downloadedOnly = remember { Injekt.get<BasePreferences>().downloadedOnly.get() }
TabbedDialog(
onDismissRequest = onDismissRequest,
@@ -1,10 +1,7 @@
package eu.kanade.presentation.manga
import androidx.activity.compose.BackHandler
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
@@ -27,9 +24,11 @@ import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.PlayArrow
import androidx.compose.material3.Icon
import androidx.compose.material3.SmallExtendedFloatingActionButton
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.material3.animateFloatingActionButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
@@ -69,6 +68,7 @@ import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.source.getNameForMangaInfo
import eu.kanade.tachiyomi.source.online.MetadataSource
import eu.kanade.tachiyomi.source.online.all.EHentai
import eu.kanade.tachiyomi.source.online.all.Lanraragi
import eu.kanade.tachiyomi.source.online.all.MangaDex
import eu.kanade.tachiyomi.source.online.all.NHentai
import eu.kanade.tachiyomi.source.online.english.EightMuses
@@ -87,6 +87,7 @@ import exh.source.isEhBasedManga
import exh.ui.metadata.adapters.EHentaiDescription
import exh.ui.metadata.adapters.EightMusesDescription
import exh.ui.metadata.adapters.HBrowseDescription
import exh.ui.metadata.adapters.LanraragiDescription
import exh.ui.metadata.adapters.MangaDexDescription
import exh.ui.metadata.adapters.NHentaiDescription
import exh.ui.metadata.adapters.PururinDescription
@@ -99,7 +100,6 @@ import tachiyomi.domain.source.model.StubSource
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.TwoPanelBox
import tachiyomi.presentation.core.components.VerticalFastScroller
import tachiyomi.presentation.core.components.material.ExtendedFloatingActionButton
import tachiyomi.presentation.core.components.material.PullRefresh
import tachiyomi.presentation.core.components.material.Scaffold
import tachiyomi.presentation.core.i18n.stringResource
@@ -165,7 +165,7 @@ fun MangaScreen(
onChapterSwipe: (ChapterList.Item, LibraryPreferences.ChapterSwipeAction) -> Unit,
// Chapter selection
onChapterSelected: (ChapterList.Item, Boolean, Boolean, Boolean) -> Unit,
onChapterSelected: (ChapterList.Item, Boolean, Boolean) -> Unit,
onAllChapterSelected: (Boolean) -> Unit,
onInvertSelection: () -> Unit,
) {
@@ -329,7 +329,7 @@ private fun MangaScreenSmallImpl(
onChapterSwipe: (ChapterList.Item, LibraryPreferences.ChapterSwipeAction) -> Unit,
// Chapter selection
onChapterSelected: (ChapterList.Item, Boolean, Boolean, Boolean) -> Unit,
onChapterSelected: (ChapterList.Item, Boolean, Boolean) -> Unit,
onAllChapterSelected: (Boolean) -> Unit,
onInvertSelection: () -> Unit,
) {
@@ -416,12 +416,7 @@ private fun MangaScreenSmallImpl(
val isFABVisible = remember(chapters) {
chapters.fastAny { !it.chapter.read } && !isAnySelected
}
AnimatedVisibility(
visible = isFABVisible,
enter = fadeIn(),
exit = fadeOut(),
) {
ExtendedFloatingActionButton(
SmallExtendedFloatingActionButton(
text = {
val isReading = remember(state.chapters) {
state.chapters.fastAny { it.chapter.read }
@@ -433,8 +428,11 @@ private fun MangaScreenSmallImpl(
icon = { Icon(imageVector = Icons.Filled.PlayArrow, contentDescription = null) },
onClick = onContinueReading,
expanded = chapterListState.shouldExpandFAB(),
modifier = Modifier.animateFloatingActionButton(
visible = isFABVisible,
alignment = Alignment.BottomEnd,
),
)
}
},
) { contentPadding ->
val topPadding = contentPadding.calculateTopPadding()
@@ -527,7 +525,7 @@ private fun MangaScreenSmallImpl(
// SY -->
doSearch = onSearch,
searchMetadataChips = remember(state.meta, state.source.id, state.manga.genre) {
SearchMetadataChips(state.meta, state.source, state.manga.genre)
SearchMetadataChips(state.meta, state.source.id, state.manga.genre)
},
// SY <--
)
@@ -652,7 +650,7 @@ fun MangaScreenLargeImpl(
onChapterSwipe: (ChapterList.Item, LibraryPreferences.ChapterSwipeAction) -> Unit,
// Chapter selection
onChapterSelected: (ChapterList.Item, Boolean, Boolean, Boolean) -> Unit,
onChapterSelected: (ChapterList.Item, Boolean, Boolean) -> Unit,
onAllChapterSelected: (Boolean) -> Unit,
onInvertSelection: () -> Unit,
) {
@@ -735,12 +733,7 @@ fun MangaScreenLargeImpl(
val isFABVisible = remember(chapters) {
chapters.fastAny { !it.chapter.read } && !isAnySelected
}
AnimatedVisibility(
visible = isFABVisible,
enter = fadeIn(),
exit = fadeOut(),
) {
ExtendedFloatingActionButton(
SmallExtendedFloatingActionButton(
text = {
val isReading = remember(state.chapters) {
state.chapters.fastAny { it.chapter.read }
@@ -754,8 +747,11 @@ fun MangaScreenLargeImpl(
icon = { Icon(imageVector = Icons.Filled.PlayArrow, contentDescription = null) },
onClick = onContinueReading,
expanded = chapterListState.shouldExpandFAB(),
modifier = Modifier.animateFloatingActionButton(
visible = isFABVisible,
alignment = Alignment.BottomEnd,
),
)
}
},
) { contentPadding ->
PullRefresh(
@@ -822,7 +818,7 @@ fun MangaScreenLargeImpl(
// SY -->
doSearch = onSearch,
searchMetadataChips = remember(state.meta, state.source.id, state.manga.genre) {
SearchMetadataChips(state.meta, state.source, state.manga.genre)
SearchMetadataChips(state.meta, state.source.id, state.manga.genre)
},
// SY <--
)
@@ -951,7 +947,7 @@ private fun LazyListScope.sharedChapterItems(
// SY <--
onChapterClicked: (Chapter) -> Unit,
onDownloadChapter: ((List<ChapterList.Item>, ChapterDownloadAction) -> Unit)?,
onChapterSelected: (ChapterList.Item, Boolean, Boolean, Boolean) -> Unit,
onChapterSelected: (ChapterList.Item, Boolean, Boolean) -> Unit,
onChapterSwipe: (ChapterList.Item, LibraryPreferences.ChapterSwipeAction) -> Unit,
) {
items(
@@ -1018,14 +1014,14 @@ private fun LazyListScope.sharedChapterItems(
chapterSwipeStartAction = chapterSwipeStartAction,
chapterSwipeEndAction = chapterSwipeEndAction,
onLongClick = {
onChapterSelected(item, !item.selected, true, true)
onChapterSelected(item, !item.selected, true)
haptic.performHapticFeedback(HapticFeedbackType.LongPress)
},
onClick = {
onChapterItemClick(
chapterItem = item,
isAnyChapterSelected = isAnyChapterSelected,
onToggleSelection = { onChapterSelected(item, !item.selected, true, false) },
onToggleSelection = { onChapterSelected(item, !item.selected, false) },
onChapterClicked = onChapterClicked,
)
},
@@ -1089,6 +1085,9 @@ fun metadataDescription(source: Source): MetadataDescriptionComposable? {
is Tsumino -> { state, openMetadataViewer, _ ->
TsuminoDescription(state, openMetadataViewer)
}
is Lanraragi -> { state, openMetadataViewer, _ ->
LanraragiDescription(state, openMetadataViewer)
}
else -> null
}
}
@@ -6,6 +6,7 @@ enum class DownloadAction {
NEXT_10_CHAPTERS,
NEXT_25_CHAPTERS,
UNREAD_CHAPTERS,
BOOKMARKED_CHAPTERS,
}
enum class EditCoverAction {
@@ -9,6 +9,7 @@ import androidx.compose.animation.fadeOut
import androidx.compose.animation.shrinkVertically
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.RowScope
@@ -30,7 +31,6 @@ import androidx.compose.material.icons.outlined.DoneAll
import androidx.compose.material.icons.outlined.Download
import androidx.compose.material.icons.outlined.MoreVert
import androidx.compose.material.icons.outlined.RemoveDone
import androidx.compose.material.icons.outlined.SwapCalls
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
@@ -52,6 +52,7 @@ import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.dp
import eu.kanade.presentation.components.DownloadDropdownMenu
import eu.kanade.presentation.components.DropdownMenu
@@ -92,10 +93,10 @@ fun MangaBottomActionMenu(
) {
val haptic = LocalHapticFeedback.current
val confirm = remember { mutableStateListOf(false, false, false, false, false, false, false) }
var resetJob: Job? = remember { null }
var resetJob by remember { mutableStateOf<Job?>(null) }
val onLongClickItem: (Int) -> Unit = { toConfirmIndex ->
haptic.performHapticFeedback(HapticFeedbackType.LongPress)
(0..<7).forEach { i -> confirm[i] = i == toConfirmIndex }
confirm.indices.forEach { i -> confirm[i] = i == toConfirmIndex }
resetJob?.cancel()
resetJob = scope.launch {
delay(1.seconds)
@@ -192,7 +193,7 @@ private fun RowScope.Button(
targetValue = if (toConfirm) 2f else 1f,
label = "weight",
)
Column(
Box(
modifier = Modifier
.size(48.dp)
.weight(animatedWeight)
@@ -202,6 +203,9 @@ private fun RowScope.Button(
onLongClick = onLongClick,
onClick = onClick,
),
contentAlignment = Alignment.Center,
) {
Column(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
) {
@@ -221,6 +225,7 @@ private fun RowScope.Button(
style = MaterialTheme.typography.labelSmall,
)
}
}
content?.invoke()
}
}
@@ -233,9 +238,9 @@ fun LibraryBottomActionMenu(
onMarkAsUnreadClicked: () -> Unit,
onDownloadClicked: ((DownloadAction) -> Unit)?,
onDeleteClicked: () -> Unit,
onMigrateClicked: (() -> Unit)?,
// SY -->
onClickCleanTitles: (() -> Unit)?,
onClickMigrate: (() -> Unit)?,
onClickCollectRecommendations: (() -> Unit)?,
onClickAddToMangaDex: (() -> Unit)?,
onClickResetInfo: (() -> Unit)?,
@@ -254,12 +259,11 @@ fun LibraryBottomActionMenu(
color = MaterialTheme.colorScheme.surfaceContainerHigh,
) {
val haptic = LocalHapticFeedback.current
val confirm =
remember { mutableStateListOf(false, false, false, false, false /* SY --> */, false /* SY <-- */) }
var resetJob: Job? = remember { null }
val confirm = remember { mutableStateListOf(false, false, false, false, false, false) }
var resetJob by remember { mutableStateOf<Job?>(null) }
val onLongClickItem: (Int) -> Unit = { toConfirmIndex ->
haptic.performHapticFeedback(HapticFeedbackType.LongPress)
(0..<5).forEach { i -> confirm[i] = i == toConfirmIndex }
confirm.indices.forEach { i -> confirm[i] = i == toConfirmIndex }
resetJob?.cancel()
resetJob = scope.launch {
delay(1.seconds)
@@ -270,7 +274,8 @@ fun LibraryBottomActionMenu(
val showOverflow = onClickCleanTitles != null ||
onClickAddToMangaDex != null ||
onClickResetInfo != null ||
onClickCollectRecommendations != null
onClickCollectRecommendations != null ||
onMigrateClicked != null
val configuration = LocalConfiguration.current
val moveMarkPrev = remember { !configuration.isTabletUi() }
var overFlowOpen by remember { mutableStateOf(false) }
@@ -299,11 +304,11 @@ fun LibraryBottomActionMenu(
onLongClick = { onLongClickItem(3) },
onClick = { downloadExpanded = !downloadExpanded },
) {
val onDismissRequest = { downloadExpanded = false }
DownloadDropdownMenu(
expanded = downloadExpanded,
onDismissRequest = onDismissRequest,
onDismissRequest = { downloadExpanded = false },
onDownloadClicked = onDownloadClicked,
offset = BottomBarMenuDpOffset,
)
}
}
@@ -355,10 +360,10 @@ fun LibraryBottomActionMenu(
onClick = onClickCleanTitles,
)
}
if (onClickMigrate != null) {
if (onMigrateClicked != null) {
DropdownMenuItem(
text = { Text(stringResource(MR.strings.migrate)) },
onClick = onClickMigrate,
onClick = onMigrateClicked,
)
}
if (onClickCollectRecommendations != null) {
@@ -388,18 +393,11 @@ fun LibraryBottomActionMenu(
onLongClick = { onLongClickItem(2) },
onClick = onMarkAsUnreadClicked,
)
if (onClickMigrate != null) {
Button(
title = stringResource(MR.strings.migrate),
icon = Icons.Outlined.SwapCalls,
toConfirm = confirm[5],
onLongClick = { onLongClickItem(5) },
onClick = onClickMigrate,
)
}
}
// SY <--
}
}
}
}
private val BottomBarMenuDpOffset = DpOffset(0.dp, 0.dp)
@@ -3,9 +3,6 @@ package eu.kanade.presentation.manga.components
import android.graphics.Bitmap
import android.graphics.drawable.BitmapDrawable
import android.os.Build
import androidx.activity.compose.PredictiveBackHandler
import androidx.compose.animation.core.animate
import androidx.compose.animation.core.tween
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
@@ -28,18 +25,15 @@ import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.dp
import androidx.compose.ui.util.lerp
import androidx.compose.ui.viewinterop.AndroidView
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
@@ -56,14 +50,11 @@ import eu.kanade.presentation.components.DropdownMenu
import eu.kanade.presentation.manga.EditCoverAction
import eu.kanade.tachiyomi.ui.reader.viewer.ReaderPageImageView
import kotlinx.collections.immutable.persistentListOf
import soup.compose.material.motion.MotionConstants
import tachiyomi.domain.manga.model.Manga
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.material.Scaffold
import tachiyomi.presentation.core.i18n.stringResource
import tachiyomi.presentation.core.util.PredictiveBack
import tachiyomi.presentation.core.util.clickableNoIndication
import kotlin.coroutines.cancellation.CancellationException
@Composable
fun MangaCoverDialog(
@@ -162,32 +153,10 @@ fun MangaCoverDialog(
val statusBarPaddingPx = with(LocalDensity.current) { contentPadding.calculateTopPadding().roundToPx() }
val bottomPaddingPx = with(LocalDensity.current) { contentPadding.calculateBottomPadding().roundToPx() }
var scale by remember { mutableFloatStateOf(1f) }
PredictiveBackHandler { progress ->
try {
progress.collect { backEvent ->
scale = lerp(1f, 0.8f, PredictiveBack.transform(backEvent.progress))
}
onDismissRequest()
} catch (e: CancellationException) {
animate(
initialValue = scale,
targetValue = 1f,
animationSpec = tween(durationMillis = MotionConstants.DefaultMotionDuration),
) { value, _ ->
scale = value
}
}
}
Box(
modifier = Modifier
.fillMaxSize()
.clickableNoIndication(onClick = onDismissRequest)
.graphicsLayer {
scaleX = scale
scaleY = scale
},
.clickableNoIndication(onClick = onDismissRequest),
) {
AndroidView(
factory = {
@@ -23,6 +23,7 @@ import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.sizeIn
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.text.appendInlineContent
import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.outlined.CallMerge
@@ -33,7 +34,6 @@ import androidx.compose.material.icons.filled.PersonOutline
import androidx.compose.material.icons.filled.Warning
import androidx.compose.material.icons.outlined.AttachMoney
import androidx.compose.material.icons.outlined.Block
import androidx.compose.material.icons.outlined.CallMerge
import androidx.compose.material.icons.outlined.Close
import androidx.compose.material.icons.outlined.Done
import androidx.compose.material.icons.outlined.DoneAll
@@ -52,6 +52,7 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
@@ -67,9 +68,13 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.LinkAnnotation
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.text.withLink
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
@@ -79,10 +84,15 @@ import coil3.request.ImageRequest
import coil3.request.crossfade
import com.mikepenz.markdown.model.markdownAnnotator
import com.mikepenz.markdown.model.markdownAnnotatorConfig
import com.mikepenz.markdown.utils.getUnescapedTextInNode
import eu.kanade.domain.ui.UiPreferences
import eu.kanade.presentation.components.DropdownMenu
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.util.system.copyToClipboard
import org.intellij.markdown.MarkdownElementTypes
import org.intellij.markdown.MarkdownTokenTypes
import org.intellij.markdown.ast.findChildOfType
import tachiyomi.domain.manga.model.Manga
import tachiyomi.i18n.MR
import tachiyomi.i18n.sy.SYMR
@@ -93,6 +103,8 @@ import tachiyomi.presentation.core.i18n.pluralStringResource
import tachiyomi.presentation.core.i18n.stringResource
import tachiyomi.presentation.core.util.clickableNoIndication
import tachiyomi.presentation.core.util.secondaryItemAlpha
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import java.time.Instant
import java.time.temporal.ChronoUnit
import kotlin.math.roundToInt
@@ -593,8 +605,35 @@ private fun ColumnScope.MangaContentInfo(
}
}
private val descriptionAnnotator = markdownAnnotator(
@Composable
private fun descriptionAnnotator(loadImages: Boolean, linkStyle: SpanStyle) = remember(loadImages, linkStyle) {
markdownAnnotator(
annotate = { content, child ->
if (!loadImages && child.type == MarkdownElementTypes.IMAGE) {
val inlineLink = child.findChildOfType(MarkdownElementTypes.INLINE_LINK)
val url = inlineLink?.findChildOfType(MarkdownElementTypes.LINK_DESTINATION)
?.getUnescapedTextInNode(content)
?: inlineLink?.findChildOfType(MarkdownElementTypes.AUTOLINK)
?.findChildOfType(MarkdownTokenTypes.AUTOLINK)
?.getUnescapedTextInNode(content)
?: return@markdownAnnotator false
val textNode = inlineLink?.findChildOfType(MarkdownElementTypes.LINK_TITLE)
?: inlineLink?.findChildOfType(MarkdownElementTypes.LINK_TEXT)
val altText = textNode?.findChildOfType(MarkdownTokenTypes.TEXT)
?.getUnescapedTextInNode(content).orEmpty()
withLink(LinkAnnotation.Url(url = url)) {
pushStyle(linkStyle)
appendInlineContent(MARKDOWN_INLINE_IMAGE_TAG)
append(altText)
pop()
}
return@markdownAnnotator true
}
if (child.type in DISALLOWED_MARKDOWN_TYPES) {
append(content.substring(child.startOffset, child.endOffset))
return@markdownAnnotator true
@@ -606,6 +645,7 @@ private val descriptionAnnotator = markdownAnnotator(
eolAsNewLine = true,
),
)
}
@Composable
private fun MangaSummary(
@@ -615,10 +655,13 @@ private fun MangaSummary(
onEditNotesClicked: () -> Unit,
modifier: Modifier = Modifier,
) {
val preferences = remember { Injekt.get<UiPreferences>() }
val loadImages = remember { preferences.imagesInDescription.get() }
val animProgress by animateFloatAsState(
targetValue = if (expanded) 1f else 0f,
label = "summary",
)
var infoHeight by remember { mutableIntStateOf(0) }
Layout(
modifier = modifier.clipToBounds(),
contents = listOf(
@@ -631,21 +674,11 @@ private fun MangaSummary(
)
},
{
Column {
MangaNotesSection(
content = notes,
expanded = true,
onEditNotes = onEditNotesClicked,
)
MarkdownRender(
content = description,
modifier = Modifier.secondaryItemAlpha(),
annotator = descriptionAnnotator,
)
}
Column(
modifier = Modifier.onSizeChanged { size ->
infoHeight = size.height
},
{
Column {
) {
MangaNotesSection(
content = notes,
expanded = expanded,
@@ -655,7 +688,11 @@ private fun MangaSummary(
MarkdownRender(
content = description,
modifier = Modifier.secondaryItemAlpha(),
annotator = descriptionAnnotator,
annotator = descriptionAnnotator(
loadImages = loadImages,
linkStyle = getMarkdownLinkStyle().toSpanStyle(),
),
loadImages = loadImages,
)
}
}
@@ -678,14 +715,11 @@ private fun MangaSummary(
}
},
),
) { (shrunk, expanded, actual, scrim), constraints ->
) { (shrunk, actual, scrim), constraints ->
val shrunkHeight = shrunk.single()
.measure(constraints)
.height
val expandedHeight = expanded.single()
.measure(constraints)
.height
val heightDelta = expandedHeight - shrunkHeight
val heightDelta = infoHeight - shrunkHeight
val scrimHeight = 24.dp.roundToPx()
val actualPlaceable = actual.single()
@@ -4,14 +4,19 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.text.InlineTextContent
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Image
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.FirstBaseline
import androidx.compose.ui.text.Placeholder
import androidx.compose.ui.text.PlaceholderVerticalAlign
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.TextLinkStyles
import androidx.compose.ui.text.font.FontFamily
@@ -32,11 +37,13 @@ import com.mikepenz.markdown.compose.elements.MarkdownTableRow
import com.mikepenz.markdown.compose.elements.MarkdownText
import com.mikepenz.markdown.compose.elements.listDepth
import com.mikepenz.markdown.model.DefaultMarkdownColors
import com.mikepenz.markdown.model.DefaultMarkdownInlineContent
import com.mikepenz.markdown.model.DefaultMarkdownTypography
import com.mikepenz.markdown.model.MarkdownAnnotator
import com.mikepenz.markdown.model.MarkdownColors
import com.mikepenz.markdown.model.MarkdownPadding
import com.mikepenz.markdown.model.MarkdownTypography
import com.mikepenz.markdown.model.NoOpImageTransformerImpl
import com.mikepenz.markdown.model.markdownAnnotator
import com.mikepenz.markdown.model.rememberMarkdownState
import org.intellij.markdown.MarkdownTokenTypes.Companion.HTML_TAG
@@ -59,12 +66,15 @@ import org.intellij.markdown.parser.markerblocks.providers.ListMarkerProvider
import org.intellij.markdown.parser.markerblocks.providers.SetextHeaderProvider
import tachiyomi.presentation.core.components.material.padding
const val MARKDOWN_INLINE_IMAGE_TAG = "MARKDOWN_INLINE_IMAGE"
@Composable
fun MarkdownRender(
content: String,
modifier: Modifier = Modifier,
flavour: MarkdownFlavourDescriptor = SimpleMarkdownFlavourDescriptor,
annotator: MarkdownAnnotator = remember { markdownAnnotator() },
loadImages: Boolean = true,
) {
Markdown(
markdownState = rememberMarkdownState(
@@ -77,7 +87,10 @@ fun MarkdownRender(
typography = getMarkdownTypography(),
padding = markdownPadding,
components = markdownComponents,
imageTransformer = Coil3ImageTransformerImpl,
imageTransformer = remember(loadImages) {
if (loadImages) Coil3ImageTransformerImpl else NoOpImageTransformerImpl()
},
inlineContent = getMarkdownInlineContent(),
modifier = modifier,
)
}
@@ -88,24 +101,24 @@ private fun getMarkdownColors(): MarkdownColors {
val codeBackground = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.1f)
return DefaultMarkdownColors(
text = MaterialTheme.colorScheme.onSurface,
codeText = Color.Unspecified,
inlineCodeText = Color.Unspecified,
linkText = Color.Unspecified,
codeBackground = codeBackground,
inlineCodeBackground = codeBackground,
dividerColor = MaterialTheme.colorScheme.outlineVariant,
tableText = Color.Unspecified,
tableBackground = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.05f),
)
}
@Composable
@ReadOnlyComposable
private fun getMarkdownTypography(): MarkdownTypography {
val link = MaterialTheme.typography.bodyMedium.copy(
fun getMarkdownLinkStyle() = MaterialTheme.typography.bodyMedium.copy(
color = MaterialTheme.colorScheme.primary,
fontWeight = FontWeight.Bold,
)
@Composable
@ReadOnlyComposable
private fun getMarkdownTypography(): MarkdownTypography {
val link = getMarkdownLinkStyle()
return DefaultMarkdownTypography(
h1 = MaterialTheme.typography.headlineMedium,
h2 = MaterialTheme.typography.headlineSmall,
@@ -121,7 +134,6 @@ private fun getMarkdownTypography(): MarkdownTypography {
ordered = MaterialTheme.typography.bodyMedium,
bullet = MaterialTheme.typography.bodyMedium,
list = MaterialTheme.typography.bodyMedium,
link = link,
textLink = TextLinkStyles(style = link.toSpanStyle()),
table = MaterialTheme.typography.bodyMedium,
)
@@ -216,6 +228,27 @@ private val markdownComponents = markdownComponents(
},
)
@Composable
@ReadOnlyComposable
private fun getMarkdownInlineContent() = DefaultMarkdownInlineContent(
inlineContent = mapOf(
MARKDOWN_INLINE_IMAGE_TAG to InlineTextContent(
placeholder = Placeholder(
width = MaterialTheme.typography.bodyMedium.fontSize * 1.25,
height = MaterialTheme.typography.bodyMedium.fontSize * 1.25,
placeholderVerticalAlign = PlaceholderVerticalAlign.TextCenter,
),
children = {
Icon(
imageVector = Icons.Outlined.Image,
contentDescription = null,
tint = MaterialTheme.colorScheme.primary,
)
},
),
),
)
private object SimpleMarkdownFlavourDescriptor : CommonMarkFlavourDescriptor() {
override val markerProcessorFactory: MarkerProcessorFactory = SimpleMarkdownProcessFactory
}
@@ -17,7 +17,6 @@ import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
@@ -25,8 +24,6 @@ import eu.kanade.presentation.components.ChipBorder
import eu.kanade.presentation.components.SuggestionChip
import eu.kanade.presentation.components.SuggestionChipDefaults
import eu.kanade.presentation.theme.TachiyomiPreviewTheme
import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.source.online.all.EHentai
import exh.metadata.metadata.EHentaiSearchMetadata
import exh.metadata.metadata.RaisedSearchMetadata
import exh.metadata.metadata.base.RaisedTag
@@ -49,7 +46,7 @@ value class SearchMetadataChips(
val tags: Map<String, List<DisplayTag>>,
) {
companion object {
operator fun invoke(meta: RaisedSearchMetadata?, source: Source, tags: List<String>?): SearchMetadataChips? {
operator fun invoke(meta: RaisedSearchMetadata?, sourceId: Long, tags: List<String>?): SearchMetadataChips? {
return if (meta != null) {
SearchMetadataChips(
meta.tags
@@ -59,11 +56,11 @@ value class SearchMetadataChips(
namespace = it.namespace,
text = it.name,
search = if (!it.namespace.isNullOrEmpty()) {
SourceTagsUtil.getWrappedTag(source.id, namespace = it.namespace, tag = it.name)
SourceTagsUtil.getWrappedTag(sourceId, namespace = it.namespace, tag = it.name)
} else {
SourceTagsUtil.getWrappedTag(source.id, fullTag = it.name)
SourceTagsUtil.getWrappedTag(sourceId, fullTag = it.name)
} ?: it.name,
border = if (source.id == EXH_SOURCE_ID || source.id == EH_SOURCE_ID) {
border = if (sourceId == EXH_SOURCE_ID || sourceId == EH_SOURCE_ID) {
when (it.type) {
EHentaiSearchMetadata.TAG_TYPE_NORMAL -> 2
EHentaiSearchMetadata.TAG_TYPE_LIGHT -> 1
@@ -178,7 +175,6 @@ fun TagsChip(
fun NamespaceTagsPreview() {
TachiyomiPreviewTheme {
Surface {
val context = LocalContext.current
NamespaceTags(
tags = remember {
EHentaiSearchMetadata().apply {
@@ -216,7 +212,7 @@ fun NamespaceTagsPreview() {
),
),
)
}.let { SearchMetadataChips(it, EHentai(EXH_SOURCE_ID, true, context), emptyList()) }!!
}.let { SearchMetadataChips(it, EXH_SOURCE_ID, emptyList()) }!!
},
onClick = {},
)
@@ -7,12 +7,9 @@ import androidx.compose.material.icons.automirrored.outlined.Label
import androidx.compose.material.icons.automirrored.outlined.PlaylistAdd
import androidx.compose.material.icons.outlined.CloudOff
import androidx.compose.material.icons.outlined.GetApp
import androidx.compose.material.icons.outlined.HelpOutline
import androidx.compose.material.icons.outlined.History
import androidx.compose.material.icons.outlined.Info
import androidx.compose.material.icons.outlined.Label
import androidx.compose.material.icons.outlined.NewReleases
import androidx.compose.material.icons.outlined.PlaylistAdd
import androidx.compose.material.icons.outlined.QueryStats
import androidx.compose.material.icons.outlined.Settings
import androidx.compose.material.icons.outlined.Storage
@@ -122,7 +122,7 @@ internal class PermissionStep : OnboardingStep {
color = MaterialTheme.colorScheme.onPrimaryContainer,
)
val crashlyticsPref = privacyPreferences.crashlytics()
val crashlyticsPref = privacyPreferences.crashlytics
val crashlytics by crashlyticsPref.collectAsState()
PermissionSwitch(
title = stringResource(MR.strings.onboarding_permission_crashlytics),
@@ -131,7 +131,7 @@ internal class PermissionStep : OnboardingStep {
onToggleChange = crashlyticsPref::set,
)
val analyticsPref = privacyPreferences.analytics()
val analyticsPref = privacyPreferences.analytics
val analytics by analyticsPref.collectAsState()
PermissionSwitch(
title = stringResource(MR.strings.onboarding_permission_analytics),
@@ -30,7 +30,7 @@ import uy.kohesive.injekt.api.get
internal class StorageStep : OnboardingStep {
private val storagePref = Injekt.get<StoragePreferences>().baseStorageDirectory()
private val storagePref = Injekt.get<StoragePreferences>().baseStorageDirectory
private var _isComplete by mutableStateOf(false)
@@ -19,13 +19,13 @@ internal class ThemeStep : OnboardingStep {
@Composable
override fun Content() {
val themeModePref = uiPreferences.themeMode()
val themeModePref = uiPreferences.themeMode
val themeMode by themeModePref.collectAsState()
val appThemePref = uiPreferences.appTheme()
val appThemePref = uiPreferences.appTheme
val appTheme by appThemePref.collectAsState()
val amoledPref = uiPreferences.themeDarkAmoled()
val amoledPref = uiPreferences.themeDarkAmoled
val amoled by amoledPref.collectAsState()
Column {
@@ -15,13 +15,13 @@ sealed class Preference {
abstract val title: String
abstract val enabled: Boolean
sealed class PreferenceItem<T> : Preference() {
sealed class PreferenceItem<T, R> : Preference() {
// SY -->
abstract val subtitle: CharSequence?
// SY <--
abstract val icon: ImageVector?
abstract val onValueChanged: suspend (value: T) -> Boolean
abstract val onValueChanged: suspend (value: T) -> R
/**
* A basic [PreferenceItem] that only displays texts.
@@ -30,10 +30,11 @@ sealed class Preference {
override val title: String,
override val subtitle: CharSequence? = null,
override val enabled: Boolean = true,
val widget: @Composable (() -> Unit)? = null,
val onClick: (() -> Unit)? = null,
) : PreferenceItem<String>() {
) : PreferenceItem<String, Unit>() {
override val icon: ImageVector? = null
override val onValueChanged: suspend (value: String) -> Boolean = { true }
override val onValueChanged: suspend (value: String) -> Unit = {}
}
/**
@@ -45,7 +46,7 @@ sealed class Preference {
override val subtitle: CharSequence? = null,
override val enabled: Boolean = true,
override val onValueChanged: suspend (value: Boolean) -> Boolean = { true },
) : PreferenceItem<Boolean>() {
) : PreferenceItem<Boolean, Boolean>() {
override val icon: ImageVector? = null
}
@@ -55,12 +56,13 @@ sealed class Preference {
data class SliderPreference(
val value: Int,
override val title: String,
override val subtitle: String? = null,
val valueString: String? = null,
val valueRange: IntProgression = 0..1,
@IntRange(from = 0) val steps: Int = with(valueRange) { (last - first) - 1 },
override val subtitle: String? = null,
override val enabled: Boolean = true,
override val onValueChanged: suspend (value: Int) -> Boolean = { true },
) : PreferenceItem<Int>() {
override val onValueChanged: suspend (value: Int) -> Unit = {},
) : PreferenceItem<Int, Unit>() {
override val icon: ImageVector? = null
}
@@ -78,7 +80,7 @@ sealed class Preference {
override val icon: ImageVector? = null,
override val enabled: Boolean = true,
override val onValueChanged: suspend (value: T) -> Boolean = { true },
) : PreferenceItem<T>() {
) : PreferenceItem<T, Boolean>() {
internal fun internalSet(value: Any) = preference.set(value as T)
internal suspend fun internalOnValueChanged(value: Any) = onValueChanged(value as T)
@@ -99,8 +101,8 @@ sealed class Preference {
{ v, e -> subtitle?.format(e[v]) },
override val icon: ImageVector? = null,
override val enabled: Boolean = true,
override val onValueChanged: suspend (value: String) -> Boolean = { true },
) : PreferenceItem<String>()
override val onValueChanged: suspend (value: String) -> Unit = {},
) : PreferenceItem<String, Unit>()
/**
* A [PreferenceItem] that displays a list of entries as a dialog.
@@ -124,7 +126,7 @@ sealed class Preference {
override val icon: ImageVector? = null,
override val enabled: Boolean = true,
override val onValueChanged: suspend (value: Set<String>) -> Boolean = { true },
) : PreferenceItem<Set<String>>()
) : PreferenceItem<Set<String>, Boolean>()
/**
* A [PreferenceItem] that shows a EditText in the dialog.
@@ -135,7 +137,7 @@ sealed class Preference {
override val subtitle: String? = "%s",
override val enabled: Boolean = true,
override val onValueChanged: suspend (value: String) -> Boolean = { true },
) : PreferenceItem<String>() {
) : PreferenceItem<String, Boolean>() {
override val icon: ImageVector? = null
}
@@ -146,31 +148,31 @@ sealed class Preference {
val tracker: Tracker,
val login: () -> Unit,
val logout: () -> Unit,
) : PreferenceItem<String>() {
) : PreferenceItem<String, Unit>() {
override val title: String = ""
override val enabled: Boolean = true
override val subtitle: String? = null
override val icon: ImageVector? = null
override val onValueChanged: suspend (value: String) -> Boolean = { true }
override val onValueChanged: suspend (value: String) -> Unit = {}
}
data class InfoPreference(
override val title: String,
) : PreferenceItem<String>() {
) : PreferenceItem<String, Unit>() {
override val enabled: Boolean = true
override val subtitle: String? = null
override val icon: ImageVector? = null
override val onValueChanged: suspend (value: String) -> Boolean = { true }
override val onValueChanged: suspend (value: String) -> Unit = {}
}
data class CustomPreference(
override val title: String,
val content: @Composable () -> Unit,
) : PreferenceItem<Unit>() {
) : PreferenceItem<Unit, Unit>() {
override val enabled: Boolean = true
override val subtitle: String? = null
override val icon: ImageVector? = null
override val onValueChanged: suspend (value: Unit) -> Boolean = { true }
override val onValueChanged: suspend (value: Unit) -> Unit = {}
}
}
@@ -178,6 +180,6 @@ sealed class Preference {
override val title: String,
override val enabled: Boolean = true,
val preferenceItems: ImmutableList<PreferenceItem<out Any>>,
val preferenceItems: ImmutableList<PreferenceItem<out Any, out Any>>,
) : Preference()
}
@@ -35,7 +35,7 @@ val LocalPreferenceMinHeight = compositionLocalOf(structuralEqualityPolicy()) {
@Composable
fun StatusWrapper(
item: Preference.PreferenceItem<*>,
item: Preference.PreferenceItem<*, *>,
highlightKey: String?,
content: @Composable () -> Unit,
) {
@@ -56,7 +56,7 @@ fun StatusWrapper(
@Composable
internal fun PreferenceItem(
item: Preference.PreferenceItem<*>,
item: Preference.PreferenceItem<*, *>,
highlightKey: String?,
) {
val scope = rememberCoroutineScope()
@@ -83,17 +83,18 @@ internal fun PreferenceItem(
}
is Preference.PreferenceItem.SliderPreference -> {
BaseSliderItem(
label = item.title,
value = item.value,
valueRange = item.valueRange,
valueText = item.subtitle.takeUnless { it.isNullOrEmpty() } ?: item.value.toString(),
steps = item.steps,
labelStyle = MaterialTheme.typography.titleLarge.copy(fontSize = TitleFontSize),
title = item.title,
subtitle = item.subtitle,
valueString = item.valueString.takeUnless { it.isNullOrEmpty() } ?: item.value.toString(),
onChange = {
scope.launch {
item.onValueChanged(it)
}
},
titleStyle = MaterialTheme.typography.titleLarge.copy(fontSize = TitleFontSize),
modifier = Modifier.padding(
horizontal = PrefsHorizontalPadding,
vertical = PrefsVerticalPadding,
@@ -146,6 +147,7 @@ internal fun PreferenceItem(
title = item.title,
subtitle = item.subtitle,
icon = item.icon,
widget = item.widget,
onPreferenceClick = item.onClick,
)
}
@@ -71,7 +71,7 @@ fun PreferenceScreen(
}
// Create Preference Item
is Preference.PreferenceItem<*> -> item {
is Preference.PreferenceItem<*, *> -> item {
PreferenceItem(
item = preference,
highlightKey = highlightKey,
@@ -13,13 +13,13 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.window.DialogProperties
import eu.kanade.tachiyomi.util.system.toast
import exh.log.xLogE
import exh.source.ExhPreferences
import exh.uconfig.EHConfigurator
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.delay
import kotlinx.coroutines.withContext
import tachiyomi.core.common.util.lang.launchUI
import tachiyomi.domain.UnsortedPreferences
import tachiyomi.i18n.MR
import tachiyomi.i18n.sy.SYMR
import tachiyomi.presentation.core.i18n.stringResource
@@ -29,8 +29,8 @@ import kotlin.time.Duration.Companion.seconds
@Composable
fun ConfigureExhDialog(run: Boolean, onRunning: () -> Unit) {
val unsortedPreferences = remember {
Injekt.get<UnsortedPreferences>()
val exhPreferences = remember {
Injekt.get<ExhPreferences>()
}
var warnDialogOpen by remember { mutableStateOf(false) }
var configureDialogOpen by remember { mutableStateOf(false) }
@@ -38,7 +38,7 @@ fun ConfigureExhDialog(run: Boolean, onRunning: () -> Unit) {
LaunchedEffect(run) {
if (run) {
if (unsortedPreferences.exhShowSettingsUploadWarning().get()) {
if (exhPreferences.exhShowSettingsUploadWarning.get()) {
warnDialogOpen = true
} else {
configureDialogOpen = true
@@ -57,7 +57,7 @@ fun ConfigureExhDialog(run: Boolean, onRunning: () -> Unit) {
confirmButton = {
TextButton(
onClick = {
unsortedPreferences.exhShowSettingsUploadWarning().set(false)
exhPreferences.exhShowSettingsUploadWarning.set(false)
configureDialogOpen = true
warnDialogOpen = false
},
@@ -3,6 +3,7 @@ package eu.kanade.presentation.more.settings.screen
import android.annotation.SuppressLint
import android.content.ActivityNotFoundException
import android.content.Intent
import android.os.Build
import android.provider.Settings
import android.webkit.WebStorage
import android.webkit.WebView
@@ -72,6 +73,7 @@ import exh.pref.DelegateSourcePreferences
import exh.source.BlacklistedSources
import exh.source.EH_SOURCE_ID
import exh.source.EXH_SOURCE_ID
import exh.source.ExhPreferences
import exh.util.toAnnotatedString
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.persistentMapOf
@@ -86,8 +88,8 @@ import tachiyomi.core.common.util.lang.launchNonCancellable
import tachiyomi.core.common.util.lang.withUIContext
import tachiyomi.core.common.util.system.ImageUtil
import tachiyomi.core.common.util.system.logcat
import tachiyomi.domain.UnsortedPreferences
import tachiyomi.domain.chapter.interactor.GetChaptersByMangaId
import tachiyomi.domain.download.service.DownloadPreferences
import tachiyomi.domain.library.service.LibraryPreferences
import tachiyomi.domain.manga.interactor.GetAllManga
import tachiyomi.domain.manga.interactor.ResetViewerFlags
@@ -116,6 +118,7 @@ object SettingsAdvancedScreen : SearchableSettings {
val basePreferences = remember { Injekt.get<BasePreferences>() }
val networkPreferences = remember { Injekt.get<NetworkPreferences>() }
val libraryPreferences = remember { Injekt.get<LibraryPreferences>() }
val downloadPreferences = remember { Injekt.get<DownloadPreferences>() }
return listOf(
Preference.PreferenceItem.TextPreference(
@@ -128,7 +131,7 @@ object SettingsAdvancedScreen : SearchableSettings {
},
),
/* SY --> Preference.PreferenceItem.SwitchPreference(
preference = networkPreferences.verboseLogging(),
preference = networkPreferences.verboseLogging,
title = stringResource(MR.strings.pref_verbose_logging),
subtitle = stringResource(MR.strings.pref_verbose_logging_summary),
onValueChanged = {
@@ -147,9 +150,18 @@ object SettingsAdvancedScreen : SearchableSettings {
Preference.PreferenceItem.TextPreference(
title = stringResource(MR.strings.pref_manage_notifications),
onClick = {
val intent = Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS).apply {
// SY -->
val intent = Intent().apply {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
setAction(Settings.ACTION_APP_NOTIFICATION_SETTINGS)
putExtra(Settings.EXTRA_APP_PACKAGE, context.packageName)
} else {
setAction("android.settings.APP_NOTIFICATION_SETTINGS")
putExtra("app_package", context.packageName)
putExtra("app_uid", context.applicationInfo.uid)
}
}
// SY <--
context.startActivity(intent)
},
),
@@ -157,6 +169,7 @@ object SettingsAdvancedScreen : SearchableSettings {
getDataGroup(),
getNetworkGroup(networkPreferences = networkPreferences),
getLibraryGroup(libraryPreferences = libraryPreferences),
getDownloadsGroup(downloadPreferences = downloadPreferences),
getReaderGroup(basePreferences = basePreferences),
getExtensionsGroup(basePreferences = basePreferences),
// SY -->
@@ -238,7 +251,7 @@ object SettingsAdvancedScreen : SearchableSettings {
val context = LocalContext.current
val networkHelper = remember { Injekt.get<NetworkHelper>() }
val userAgentPref = networkPreferences.defaultUserAgent()
val userAgentPref = networkPreferences.defaultUserAgent
val userAgent by userAgentPref.collectAsState()
return Preference.PreferenceGroup(
@@ -274,7 +287,7 @@ object SettingsAdvancedScreen : SearchableSettings {
},
),
Preference.PreferenceItem.ListPreference(
preference = networkPreferences.dohProvider(),
preference = networkPreferences.dohProvider,
entries = persistentMapOf(
-1 to stringResource(MR.strings.disabled),
PREF_DOH_CLOUDFLARE to "Cloudflare",
@@ -355,14 +368,37 @@ object SettingsAdvancedScreen : SearchableSettings {
},
),
Preference.PreferenceItem.SwitchPreference(
preference = libraryPreferences.updateMangaTitles(),
preference = libraryPreferences.updateMangaTitles,
title = stringResource(MR.strings.pref_update_library_manga_titles),
subtitle = stringResource(MR.strings.pref_update_library_manga_titles_summary),
),
Preference.PreferenceItem.SwitchPreference(
preference = libraryPreferences.disallowNonAsciiFilenames,
title = stringResource(MR.strings.pref_disallow_non_ascii_filenames),
subtitle = stringResource(MR.strings.pref_disallow_non_ascii_filenames_details),
),
),
)
}
// SY ->
@Composable
private fun getDownloadsGroup(
downloadPreferences: DownloadPreferences,
): Preference.PreferenceGroup {
return Preference.PreferenceGroup(
title = stringResource(MR.strings.pref_category_downloads),
preferenceItems = persistentListOf(
Preference.PreferenceItem.SwitchPreference(
preference = downloadPreferences.includeChapterUrlHash,
title = stringResource(SYMR.strings.pref_include_chapter_url_hash),
subtitle = stringResource(SYMR.strings.pref_include_chapter_url_hash_desc),
),
),
)
}
// <- SY
@Composable
private fun getReaderGroup(
basePreferences: BasePreferences,
@@ -374,14 +410,14 @@ object SettingsAdvancedScreen : SearchableSettings {
uri?.let {
val flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
context.contentResolver.takePersistableUriPermission(uri, flags)
basePreferences.displayProfile().set(uri.toString())
basePreferences.displayProfile.set(uri.toString())
}
}
return Preference.PreferenceGroup(
title = stringResource(MR.strings.pref_category_reader),
preferenceItems = persistentListOf(
Preference.PreferenceItem.ListPreference(
preference = basePreferences.hardwareBitmapThreshold(),
preference = basePreferences.hardwareBitmapThreshold,
entries = GLUtil.CUSTOM_TEXTURE_LIMIT_OPTIONS
.mapIndexed { index, option ->
val display = if (index == 0) {
@@ -401,13 +437,13 @@ object SettingsAdvancedScreen : SearchableSettings {
GLUtil.DEVICE_TEXTURE_LIMIT > GLUtil.SAFE_TEXTURE_LIMIT,
),
Preference.PreferenceItem.SwitchPreference(
preference = basePreferences.alwaysDecodeLongStripWithSSIV(),
preference = basePreferences.alwaysDecodeLongStripWithSSIV,
title = stringResource(MR.strings.pref_always_decode_long_strip_with_ssiv_2),
subtitle = stringResource(MR.strings.pref_always_decode_long_strip_with_ssiv_summary),
),
Preference.PreferenceItem.TextPreference(
title = stringResource(MR.strings.pref_display_profile),
subtitle = basePreferences.displayProfile().get(),
subtitle = basePreferences.displayProfile.get(),
onClick = {
chooseColorProfile.launch(arrayOf("*/*"))
},
@@ -422,7 +458,7 @@ object SettingsAdvancedScreen : SearchableSettings {
): Preference.PreferenceGroup {
val context = LocalContext.current
val uriHandler = LocalUriHandler.current
val extensionInstallerPref = basePreferences.extensionInstaller()
val extensionInstallerPref = basePreferences.extensionInstaller
var shizukuMissing by rememberSaveable { mutableStateOf(false) }
val trustExtension = remember { Injekt.get<TrustExtension>() }
@@ -622,12 +658,12 @@ object SettingsAdvancedScreen : SearchableSettings {
@Composable
private fun getDataSaverGroup(): Preference.PreferenceGroup {
val sourcePreferences = remember { Injekt.get<SourcePreferences>() }
val dataSaver by sourcePreferences.dataSaver().collectAsState()
val dataSaver by sourcePreferences.dataSaver.collectAsState()
return Preference.PreferenceGroup(
title = stringResource(SYMR.strings.data_saver),
preferenceItems = persistentListOf(
Preference.PreferenceItem.ListPreference(
preference = sourcePreferences.dataSaver(),
preference = sourcePreferences.dataSaver,
title = stringResource(SYMR.strings.data_saver),
subtitle = stringResource(SYMR.strings.data_saver_summary),
entries = persistentMapOf(
@@ -637,28 +673,28 @@ object SettingsAdvancedScreen : SearchableSettings {
),
),
Preference.PreferenceItem.EditTextPreference(
preference = sourcePreferences.dataSaverServer(),
preference = sourcePreferences.dataSaverServer,
title = stringResource(SYMR.strings.bandwidth_data_saver_server),
subtitle = stringResource(SYMR.strings.data_saver_server_summary),
enabled = dataSaver == DataSaver.BANDWIDTH_HERO,
),
Preference.PreferenceItem.SwitchPreference(
preference = sourcePreferences.dataSaverDownloader(),
preference = sourcePreferences.dataSaverDownloader,
title = stringResource(SYMR.strings.data_saver_downloader),
enabled = dataSaver != DataSaver.NONE,
),
Preference.PreferenceItem.SwitchPreference(
preference = sourcePreferences.dataSaverIgnoreJpeg(),
preference = sourcePreferences.dataSaverIgnoreJpeg,
title = stringResource(SYMR.strings.data_saver_ignore_jpeg),
enabled = dataSaver != DataSaver.NONE,
),
Preference.PreferenceItem.SwitchPreference(
preference = sourcePreferences.dataSaverIgnoreGif(),
preference = sourcePreferences.dataSaverIgnoreGif,
title = stringResource(SYMR.strings.data_saver_ignore_gif),
enabled = dataSaver != DataSaver.NONE,
),
Preference.PreferenceItem.ListPreference(
preference = sourcePreferences.dataSaverImageQuality(),
preference = sourcePreferences.dataSaverImageQuality,
title = stringResource(SYMR.strings.data_saver_image_quality),
subtitle = stringResource(SYMR.strings.data_saver_image_quality_summary),
entries = listOf(
@@ -674,10 +710,10 @@ object SettingsAdvancedScreen : SearchableSettings {
enabled = dataSaver != DataSaver.NONE,
),
kotlin.run {
val dataSaverImageFormatJpeg by sourcePreferences.dataSaverImageFormatJpeg()
val dataSaverImageFormatJpeg by sourcePreferences.dataSaverImageFormatJpeg
.collectAsState()
Preference.PreferenceItem.SwitchPreference(
preference = sourcePreferences.dataSaverImageFormatJpeg(),
preference = sourcePreferences.dataSaverImageFormatJpeg,
title = stringResource(SYMR.strings.data_saver_image_format),
subtitle = if (dataSaverImageFormatJpeg) {
stringResource(SYMR.strings.data_saver_image_format_summary_on)
@@ -688,7 +724,7 @@ object SettingsAdvancedScreen : SearchableSettings {
)
},
Preference.PreferenceItem.SwitchPreference(
preference = sourcePreferences.dataSaverColorBW(),
preference = sourcePreferences.dataSaverColorBW,
title = stringResource(SYMR.strings.data_saver_color_bw),
enabled = dataSaver == DataSaver.BANDWIDTH_HERO,
),
@@ -701,14 +737,14 @@ object SettingsAdvancedScreen : SearchableSettings {
val context = LocalContext.current
val navigator = LocalNavigator.currentOrThrow
val sourcePreferences = remember { Injekt.get<SourcePreferences>() }
val unsortedPreferences = remember { Injekt.get<UnsortedPreferences>() }
val exhPreferences = remember { Injekt.get<ExhPreferences>() }
val delegateSourcePreferences = remember { Injekt.get<DelegateSourcePreferences>() }
val securityPreferences = remember { Injekt.get<SecurityPreferences>() }
return Preference.PreferenceGroup(
title = stringResource(SYMR.strings.developer_tools),
preferenceItems = persistentListOf(
Preference.PreferenceItem.SwitchPreference(
preference = unsortedPreferences.isHentaiEnabled(),
preference = exhPreferences.isHentaiEnabled,
title = stringResource(SYMR.strings.toggle_hentai_features),
subtitle = stringResource(SYMR.strings.toggle_hentai_features_summary),
onValueChanged = {
@@ -723,7 +759,7 @@ object SettingsAdvancedScreen : SearchableSettings {
},
),
Preference.PreferenceItem.SwitchPreference(
preference = delegateSourcePreferences.delegateSources(),
preference = delegateSourcePreferences.delegateSources,
title = stringResource(SYMR.strings.toggle_delegated_sources),
subtitle = stringResource(
SYMR.strings.toggle_delegated_sources_summary,
@@ -733,7 +769,7 @@ object SettingsAdvancedScreen : SearchableSettings {
),
),
Preference.PreferenceItem.ListPreference(
preference = unsortedPreferences.logLevel(),
preference = exhPreferences.logLevel,
title = stringResource(SYMR.strings.log_level),
subtitle = stringResource(SYMR.strings.log_level_summary),
entries = EHLogLevel.entries.mapIndexed { index, ehLogLevel ->
@@ -743,7 +779,7 @@ object SettingsAdvancedScreen : SearchableSettings {
}.toMap().toImmutableMap(),
),
Preference.PreferenceItem.SwitchPreference(
preference = sourcePreferences.enableSourceBlacklist(),
preference = sourcePreferences.enableSourceBlacklist,
title = stringResource(SYMR.strings.enable_source_blacklist),
subtitle = stringResource(
SYMR.strings.enable_source_blacklist_summary,
@@ -777,7 +813,7 @@ object SettingsAdvancedScreen : SearchableSettings {
TextButton(
onClick = {
dismiss()
securityPreferences.encryptDatabase().set(true)
securityPreferences.encryptDatabase.set(true)
},
) {
Text(text = stringResource(MR.strings.action_ok))
@@ -787,7 +823,7 @@ object SettingsAdvancedScreen : SearchableSettings {
}
Preference.PreferenceItem.SwitchPreference(
title = stringResource(SYMR.strings.encrypt_database),
preference = securityPreferences.encryptDatabase(),
preference = securityPreferences.encryptDatabase,
subtitle = stringResource(SYMR.strings.encrypt_database_subtitle),
onValueChanged = {
if (it) {
@@ -56,13 +56,13 @@ object SettingsAppearanceScreen : SearchableSettings {
): Preference.PreferenceGroup {
val context = LocalContext.current
val themeModePref = uiPreferences.themeMode()
val themeModePref = uiPreferences.themeMode
val themeMode by themeModePref.collectAsState()
val appThemePref = uiPreferences.appTheme()
val appThemePref = uiPreferences.appTheme
val appTheme by appThemePref.collectAsState()
val amoledPref = uiPreferences.themeDarkAmoled()
val amoledPref = uiPreferences.themeDarkAmoled
val amoled by amoledPref.collectAsState()
return Preference.PreferenceGroup(
@@ -109,7 +109,7 @@ object SettingsAppearanceScreen : SearchableSettings {
val now = remember { LocalDate.now() }
val dateFormat by uiPreferences.dateFormat().collectAsState()
val dateFormat by uiPreferences.dateFormat.collectAsState()
val formattedNow = remember(dateFormat) {
UiPreferences.dateFormat(dateFormat).format(now)
}
@@ -122,7 +122,7 @@ object SettingsAppearanceScreen : SearchableSettings {
onClick = { navigator.push(AppLanguageScreen()) },
),
Preference.PreferenceItem.ListPreference(
preference = uiPreferences.tabletUiMode(),
preference = uiPreferences.tabletUiMode,
entries = TabletUiMode.entries
.associateWith { stringResource(it.titleRes) }
.toImmutableMap(),
@@ -133,7 +133,7 @@ object SettingsAppearanceScreen : SearchableSettings {
},
),
Preference.PreferenceItem.ListPreference(
preference = uiPreferences.dateFormat(),
preference = uiPreferences.dateFormat,
entries = DateFormats
.associateWith {
val formattedDate = UiPreferences.dateFormat(it).format(now)
@@ -143,7 +143,7 @@ object SettingsAppearanceScreen : SearchableSettings {
title = stringResource(MR.strings.pref_date_format),
),
Preference.PreferenceItem.SwitchPreference(
preference = uiPreferences.relativeTime(),
preference = uiPreferences.relativeTime,
title = stringResource(MR.strings.pref_relative_format),
subtitle = stringResource(
MR.strings.pref_relative_format_summary,
@@ -151,6 +151,10 @@ object SettingsAppearanceScreen : SearchableSettings {
formattedNow,
),
),
Preference.PreferenceItem.SwitchPreference(
preference = uiPreferences.imagesInDescription,
title = stringResource(MR.strings.pref_display_images_description),
),
),
)
}
@@ -158,22 +162,22 @@ object SettingsAppearanceScreen : SearchableSettings {
// SY -->
@Composable
fun getForkGroup(uiPreferences: UiPreferences): Preference.PreferenceGroup {
val previewsRowCount by uiPreferences.previewsRowCount().collectAsState()
val previewsRowCount by uiPreferences.previewsRowCount.collectAsState()
return Preference.PreferenceGroup(
stringResource(SYMR.strings.pref_category_fork),
preferenceItems = persistentListOf(
Preference.PreferenceItem.SwitchPreference(
preference = uiPreferences.expandFilters(),
preference = uiPreferences.expandFilters,
title = stringResource(SYMR.strings.toggle_expand_search_filters),
),
Preference.PreferenceItem.SwitchPreference(
preference = uiPreferences.recommendsInOverflow(),
preference = uiPreferences.recommendsInOverflow,
title = stringResource(SYMR.strings.put_recommends_in_overflow),
subtitle = stringResource(SYMR.strings.put_recommends_in_overflow_summary),
),
Preference.PreferenceItem.SwitchPreference(
preference = uiPreferences.mergeInOverflow(),
preference = uiPreferences.mergeInOverflow,
title = stringResource(SYMR.strings.put_merge_in_overflow),
subtitle = stringResource(SYMR.strings.put_merge_in_overflow_summary),
),
@@ -191,7 +195,7 @@ object SettingsAppearanceScreen : SearchableSettings {
},
valueRange = 0..10,
onValueChanged = {
uiPreferences.previewsRowCount().set(it)
uiPreferences.previewsRowCount.set(it)
true
},
),
@@ -205,15 +209,15 @@ object SettingsAppearanceScreen : SearchableSettings {
stringResource(SYMR.strings.pref_category_navbar),
preferenceItems = persistentListOf(
Preference.PreferenceItem.SwitchPreference(
preference = uiPreferences.showNavUpdates(),
preference = uiPreferences.showNavUpdates,
title = stringResource(SYMR.strings.pref_hide_updates_button),
),
Preference.PreferenceItem.SwitchPreference(
preference = uiPreferences.showNavHistory(),
preference = uiPreferences.showNavHistory,
title = stringResource(SYMR.strings.pref_hide_history_button),
),
Preference.PreferenceItem.SwitchPreference(
preference = uiPreferences.bottomBarLabels(),
preference = uiPreferences.bottomBarLabels,
title = stringResource(SYMR.strings.pref_show_bottom_bar_labels),
),
),
@@ -20,7 +20,6 @@ import eu.kanade.tachiyomi.util.system.AuthenticatorUtil.authenticate
import kotlinx.collections.immutable.persistentListOf
import mihon.domain.extensionrepo.interactor.GetExtensionRepoCount
import tachiyomi.core.common.i18n.stringResource
import tachiyomi.domain.UnsortedPreferences
import tachiyomi.i18n.MR
import tachiyomi.i18n.sy.SYMR
import tachiyomi.presentation.core.i18n.pluralStringResource
@@ -47,9 +46,8 @@ object SettingsBrowseScreen : SearchableSettings {
// SY -->
val scope = rememberCoroutineScope()
val hideFeedTab by remember { Injekt.get<UiPreferences>().hideFeedTab().asState(scope) }
val hideFeedTab by remember { Injekt.get<UiPreferences>().hideFeedTab.asState(scope) }
val uiPreferences = remember { Injekt.get<UiPreferences>() }
val unsortedPreferences = remember { Injekt.get<UnsortedPreferences>() }
// SY <--
return listOf(
// SY -->
@@ -57,7 +55,7 @@ object SettingsBrowseScreen : SearchableSettings {
title = stringResource(MR.strings.label_sources),
preferenceItems = persistentListOf(
kotlin.run {
val count by sourcePreferences.sourcesTabCategories().collectAsState()
val count by sourcePreferences.sourcesTabCategories.collectAsState()
Preference.PreferenceItem.TextPreference(
title = stringResource(MR.strings.action_edit_categories),
subtitle = pluralStringResource(MR.plurals.num_categories, count.size, count.size),
@@ -67,17 +65,17 @@ object SettingsBrowseScreen : SearchableSettings {
)
},
Preference.PreferenceItem.SwitchPreference(
preference = sourcePreferences.sourcesTabCategoriesFilter(),
preference = sourcePreferences.sourcesTabCategoriesFilter,
title = stringResource(SYMR.strings.pref_source_source_filtering),
subtitle = stringResource(SYMR.strings.pref_source_source_filtering_summery),
),
Preference.PreferenceItem.SwitchPreference(
preference = uiPreferences.useNewSourceNavigation(),
preference = uiPreferences.useNewSourceNavigation,
title = stringResource(SYMR.strings.pref_source_navigation),
subtitle = stringResource(SYMR.strings.pref_source_navigation_summery),
),
Preference.PreferenceItem.SwitchPreference(
preference = unsortedPreferences.allowLocalSourceHiddenFolders(),
preference = sourcePreferences.allowLocalSourceHiddenFolders,
title = stringResource(SYMR.strings.pref_local_source_hidden_folders),
subtitle = stringResource(SYMR.strings.pref_local_source_hidden_folders_summery),
),
@@ -87,11 +85,11 @@ object SettingsBrowseScreen : SearchableSettings {
title = stringResource(SYMR.strings.feed),
preferenceItems = persistentListOf(
Preference.PreferenceItem.SwitchPreference(
preference = uiPreferences.hideFeedTab(),
preference = uiPreferences.hideFeedTab,
title = stringResource(SYMR.strings.pref_hide_feed),
),
Preference.PreferenceItem.SwitchPreference(
preference = uiPreferences.feedTabInFront(),
preference = uiPreferences.feedTabInFront,
title = stringResource(SYMR.strings.pref_feed_position),
subtitle = stringResource(SYMR.strings.pref_feed_position_summery),
enabled = hideFeedTab.not(),
@@ -103,7 +101,7 @@ object SettingsBrowseScreen : SearchableSettings {
title = stringResource(MR.strings.label_sources),
preferenceItems = persistentListOf(
Preference.PreferenceItem.SwitchPreference(
preference = sourcePreferences.hideInLibraryItems(),
preference = sourcePreferences.hideInLibraryItems,
title = stringResource(MR.strings.pref_hide_in_library_items),
),
Preference.PreferenceItem.TextPreference(
@@ -119,7 +117,7 @@ object SettingsBrowseScreen : SearchableSettings {
title = stringResource(MR.strings.pref_category_nsfw_content),
preferenceItems = persistentListOf(
Preference.PreferenceItem.SwitchPreference(
preference = sourcePreferences.showNsfwSource(),
preference = sourcePreferences.showNsfwSource,
title = stringResource(MR.strings.pref_show_nsfw_source),
subtitle = stringResource(MR.strings.requires_app_restart),
onValueChanged = {
@@ -119,7 +119,7 @@ object SettingsDataScreen : SearchableSettings {
val storagePreferences = Injekt.get<StoragePreferences>()
val syncPreferences = remember { Injekt.get<SyncPreferences>() }
val syncService by syncPreferences.syncService().collectAsState()
val syncService by syncPreferences.syncService.collectAsState()
return persistentListOf(
getStorageLocationPref(storagePreferences = storagePreferences),
@@ -185,11 +185,11 @@ object SettingsDataScreen : SearchableSettings {
storagePreferences: StoragePreferences,
): Preference.PreferenceItem.TextPreference {
val context = LocalContext.current
val pickStorageLocation = storageLocationPicker(storagePreferences.baseStorageDirectory())
val pickStorageLocation = storageLocationPicker(storagePreferences.baseStorageDirectory)
return Preference.PreferenceItem.TextPreference(
title = stringResource(MR.strings.pref_storage_location),
subtitle = storageLocationText(storagePreferences.baseStorageDirectory()),
subtitle = storageLocationText(storagePreferences.baseStorageDirectory),
onClick = {
try {
pickStorageLocation.launch(null)
@@ -205,7 +205,7 @@ object SettingsDataScreen : SearchableSettings {
val context = LocalContext.current
val navigator = LocalNavigator.currentOrThrow
val lastAutoBackup by backupPreferences.lastAutoBackupTimestamp().collectAsState()
val lastAutoBackup by backupPreferences.lastAutoBackupTimestamp.collectAsState()
val chooseBackup = rememberLauncherForActivityResult(
object : ActivityResultContracts.GetContent() {
@@ -272,7 +272,7 @@ object SettingsDataScreen : SearchableSettings {
// Automatic backups
Preference.PreferenceItem.ListPreference(
preference = backupPreferences.backupInterval(),
preference = backupPreferences.backupInterval,
entries = persistentMapOf(
0 to stringResource(MR.strings.off),
6 to stringResource(MR.strings.update_6hour),
@@ -365,7 +365,7 @@ object SettingsDataScreen : SearchableSettings {
),
// SY <--
Preference.PreferenceItem.SwitchPreference(
preference = libraryPreferences.autoClearChapterCache(),
preference = libraryPreferences.autoClearChapterCache,
title = stringResource(MR.strings.pref_auto_clear_chapter_cache),
),
),
@@ -517,7 +517,7 @@ object SettingsDataScreen : SearchableSettings {
title = stringResource(SYMR.strings.pref_sync_service_category),
preferenceItems = persistentListOf(
Preference.PreferenceItem.ListPreference(
preference = syncPreferences.syncService(),
preference = syncPreferences.syncService,
title = stringResource(SYMR.strings.pref_sync_service),
entries = persistentMapOf(
SyncManager.SyncService.NONE.value to stringResource(MR.strings.off),
@@ -660,7 +660,7 @@ object SettingsDataScreen : SearchableSettings {
val qrScanLauncher = rememberLauncherForActivityResult(ScanContract()) {
if (it.contents != null && it.contents.isNotEmpty()) {
syncPreferences.clientAPIKey().set(it.contents)
syncPreferences.clientAPIKey.set(it.contents)
}
}
val context = LocalContext.current
@@ -677,13 +677,13 @@ object SettingsDataScreen : SearchableSettings {
Preference.PreferenceItem.EditTextPreference(
title = stringResource(SYMR.strings.pref_sync_host),
subtitle = stringResource(SYMR.strings.pref_sync_host_summ),
preference = syncPreferences.clientHost(),
preference = syncPreferences.clientHost,
onValueChanged = { newValue ->
scope.launch {
// Trim spaces at the beginning and end, then remove trailing slash if present
val trimmedValue = newValue.trim()
val modifiedValue = trimmedValue.trimEnd { it == '/' }
syncPreferences.clientHost().set(modifiedValue)
syncPreferences.clientHost.set(modifiedValue)
}
true
},
@@ -691,12 +691,12 @@ object SettingsDataScreen : SearchableSettings {
Preference.PreferenceItem.CustomPreference(
title = stringResource(SYMR.strings.pref_sync_api_key),
) {
val values by syncPreferences.clientAPIKey().collectAsState()
val values by syncPreferences.clientAPIKey.collectAsState()
EditTextPreferenceWidget(
title = stringResource(SYMR.strings.pref_sync_api_key),
subtitle = stringResource(SYMR.strings.pref_sync_api_key_summ),
onConfirm = {
syncPreferences.clientAPIKey().set(it)
syncPreferences.clientAPIKey.set(it)
true
},
icon = null,
@@ -752,8 +752,8 @@ object SettingsDataScreen : SearchableSettings {
@Composable
private fun getAutomaticSyncGroup(syncPreferences: SyncPreferences): Preference.PreferenceGroup {
val context = LocalContext.current
val syncIntervalPref = syncPreferences.syncInterval()
val lastSync by syncPreferences.lastSyncTimestamp().collectAsState()
val syncIntervalPref = syncPreferences.syncInterval
val lastSync by syncPreferences.lastSyncTimestamp.collectAsState()
return Preference.PreferenceGroup(
title = stringResource(SYMR.strings.pref_sync_automatic_category),
@@ -37,20 +37,35 @@ object SettingsDownloadScreen : SearchableSettings {
val allCategories by getCategories.subscribe().collectAsState(initial = emptyList())
val downloadPreferences = remember { Injekt.get<DownloadPreferences>() }
val parallelSourceLimit by downloadPreferences.parallelSourceLimit.collectAsState()
val parallelPageLimit by downloadPreferences.parallelPageLimit.collectAsState()
return listOf(
Preference.PreferenceItem.SwitchPreference(
preference = downloadPreferences.downloadOnlyOverWifi(),
preference = downloadPreferences.downloadOnlyOverWifi,
title = stringResource(MR.strings.connected_to_wifi),
),
Preference.PreferenceItem.SwitchPreference(
preference = downloadPreferences.saveChaptersAsCBZ(),
preference = downloadPreferences.saveChaptersAsCBZ,
title = stringResource(MR.strings.save_chapter_as_cbz),
),
Preference.PreferenceItem.SwitchPreference(
preference = downloadPreferences.splitTallImages(),
preference = downloadPreferences.splitTallImages,
title = stringResource(MR.strings.split_tall_images),
subtitle = stringResource(MR.strings.split_tall_images_summary),
),
Preference.PreferenceItem.SliderPreference(
value = parallelSourceLimit,
valueRange = 1..10,
title = stringResource(MR.strings.pref_download_concurrent_sources),
onValueChanged = { downloadPreferences.parallelSourceLimit.set(it) },
),
Preference.PreferenceItem.SliderPreference(
value = parallelPageLimit,
valueRange = 1..15,
title = stringResource(MR.strings.pref_download_concurrent_pages),
subtitle = stringResource(MR.strings.pref_download_concurrent_pages_summary),
onValueChanged = { downloadPreferences.parallelPageLimit.set(it) },
),
getDeleteChaptersGroup(
downloadPreferences = downloadPreferences,
categories = allCategories,
@@ -72,11 +87,11 @@ object SettingsDownloadScreen : SearchableSettings {
title = stringResource(MR.strings.pref_category_delete_chapters),
preferenceItems = persistentListOf(
Preference.PreferenceItem.SwitchPreference(
preference = downloadPreferences.removeAfterMarkedAsRead(),
preference = downloadPreferences.removeAfterMarkedAsRead,
title = stringResource(MR.strings.pref_remove_after_marked_as_read),
),
Preference.PreferenceItem.ListPreference(
preference = downloadPreferences.removeAfterReadSlots(),
preference = downloadPreferences.removeAfterReadSlots,
entries = persistentMapOf(
-1 to stringResource(MR.strings.disabled),
0 to stringResource(MR.strings.last_read_chapter),
@@ -88,7 +103,7 @@ object SettingsDownloadScreen : SearchableSettings {
title = stringResource(MR.strings.pref_remove_after_read),
),
Preference.PreferenceItem.SwitchPreference(
preference = downloadPreferences.removeBookmarkedChapters(),
preference = downloadPreferences.removeBookmarkedChapters,
title = stringResource(MR.strings.pref_remove_bookmarked_chapters),
),
getExcludedCategoriesPreference(
@@ -105,7 +120,7 @@ object SettingsDownloadScreen : SearchableSettings {
categories: () -> List<Category>,
): Preference.PreferenceItem.MultiSelectListPreference {
return Preference.PreferenceItem.MultiSelectListPreference(
preference = downloadPreferences.removeExcludeCategories(),
preference = downloadPreferences.removeExcludeCategories,
entries = categories()
.associate { it.id.toString() to it.visualName }
.toImmutableMap(),
@@ -118,10 +133,10 @@ object SettingsDownloadScreen : SearchableSettings {
downloadPreferences: DownloadPreferences,
allCategories: List<Category>,
): Preference.PreferenceGroup {
val downloadNewChaptersPref = downloadPreferences.downloadNewChapters()
val downloadNewUnreadChaptersOnlyPref = downloadPreferences.downloadNewUnreadChaptersOnly()
val downloadNewChapterCategoriesPref = downloadPreferences.downloadNewChapterCategories()
val downloadNewChapterCategoriesExcludePref = downloadPreferences.downloadNewChapterCategoriesExclude()
val downloadNewChaptersPref = downloadPreferences.downloadNewChapters
val downloadNewUnreadChaptersOnlyPref = downloadPreferences.downloadNewUnreadChaptersOnly
val downloadNewChapterCategoriesPref = downloadPreferences.downloadNewChapterCategories
val downloadNewChapterCategoriesExcludePref = downloadPreferences.downloadNewChapterCategoriesExclude
val downloadNewChapters by downloadNewChaptersPref.collectAsState()
@@ -179,7 +194,7 @@ object SettingsDownloadScreen : SearchableSettings {
title = stringResource(MR.strings.download_ahead),
preferenceItems = persistentListOf(
Preference.PreferenceItem.ListPreference(
preference = downloadPreferences.autoDownloadWhileReading(),
preference = downloadPreferences.autoDownloadWhileReading,
entries = listOf(0, 2, 3, 5, 10)
.associateWith {
if (it == 0) {
@@ -51,6 +51,7 @@ import exh.eh.EHentaiUpdateWorker
import exh.eh.EHentaiUpdateWorkerConstants
import exh.eh.EHentaiUpdaterStats
import exh.metadata.metadata.EHentaiSearchMetadata
import exh.source.ExhPreferences
import exh.ui.login.EhLoginActivity
import exh.util.nullIfBlank
import kotlinx.collections.immutable.persistentListOf
@@ -63,7 +64,6 @@ import tachiyomi.core.common.util.lang.launchNonCancellable
import tachiyomi.core.common.util.lang.withIOContext
import tachiyomi.core.common.util.lang.withUIContext
import tachiyomi.core.common.util.system.logcat
import tachiyomi.domain.UnsortedPreferences
import tachiyomi.domain.library.service.LibraryPreferences.Companion.DEVICE_CHARGING
import tachiyomi.domain.library.service.LibraryPreferences.Companion.DEVICE_ONLY_ON_WIFI
import tachiyomi.domain.manga.interactor.DeleteFavoriteEntries
@@ -88,22 +88,22 @@ object SettingsEhScreen : SearchableSettings {
@Composable
override fun getTitleRes() = SYMR.strings.pref_category_eh
override fun isEnabled(): Boolean = Injekt.get<UnsortedPreferences>().isHentaiEnabled().get()
override fun isEnabled(): Boolean = Injekt.get<ExhPreferences>().isHentaiEnabled.get()
@Composable
fun Reconfigure(
unsortedPreferences: UnsortedPreferences,
exhPreferences: ExhPreferences,
openWarnConfigureDialogController: () -> Unit,
) {
var initialLoadGuard by remember { mutableStateOf(false) }
val useHentaiAtHome by unsortedPreferences.useHentaiAtHome().collectAsState()
val useJapaneseTitle by unsortedPreferences.useJapaneseTitle().collectAsState()
val useOriginalImages by unsortedPreferences.exhUseOriginalImages().collectAsState()
val ehTagFilterValue by unsortedPreferences.ehTagFilterValue().collectAsState()
val ehTagWatchingValue by unsortedPreferences.ehTagWatchingValue().collectAsState()
val settingsLanguages by unsortedPreferences.exhSettingsLanguages().collectAsState()
val enabledCategories by unsortedPreferences.exhEnabledCategories().collectAsState()
val imageQuality by unsortedPreferences.imageQuality().collectAsState()
val useHentaiAtHome by exhPreferences.useHentaiAtHome.collectAsState()
val useJapaneseTitle by exhPreferences.useJapaneseTitle.collectAsState()
val useOriginalImages by exhPreferences.exhUseOriginalImages.collectAsState()
val ehTagFilterValue by exhPreferences.ehTagFilterValue.collectAsState()
val ehTagWatchingValue by exhPreferences.ehTagWatchingValue.collectAsState()
val settingsLanguages by exhPreferences.exhSettingsLanguages.collectAsState()
val enabledCategories by exhPreferences.exhEnabledCategories.collectAsState()
val imageQuality by exhPreferences.imageQuality.collectAsState()
DisposableEffect(
useHentaiAtHome,
useJapaneseTitle,
@@ -124,15 +124,15 @@ object SettingsEhScreen : SearchableSettings {
@Composable
override fun getPreferences(): List<Preference> {
val unsortedPreferences: UnsortedPreferences = remember { Injekt.get() }
val exhPreferences: ExhPreferences = remember { Injekt.get() }
val getFlatMetadataById: GetFlatMetadataById = remember { Injekt.get() }
val deleteFavoriteEntries: DeleteFavoriteEntries = remember { Injekt.get() }
val getExhFavoriteMangaWithMetadata: GetExhFavoriteMangaWithMetadata = remember { Injekt.get() }
val exhentaiEnabled by unsortedPreferences.enableExhentai().collectAsState()
val exhentaiEnabled by exhPreferences.enableExhentai.collectAsState()
var runConfigureDialog by remember { mutableStateOf(false) }
val openWarnConfigureDialogController = { runConfigureDialog = true }
Reconfigure(unsortedPreferences, openWarnConfigureDialogController)
Reconfigure(exhPreferences, openWarnConfigureDialogController)
ConfigureExhDialog(run = runConfigureDialog, onRunning = { runConfigureDialog = false })
@@ -140,36 +140,36 @@ object SettingsEhScreen : SearchableSettings {
Preference.PreferenceGroup(
stringResource(SYMR.strings.ehentai_prefs_account_settings),
preferenceItems = persistentListOf(
getLoginPreference(unsortedPreferences, openWarnConfigureDialogController),
useHentaiAtHome(exhentaiEnabled, unsortedPreferences),
useJapaneseTitle(exhentaiEnabled, unsortedPreferences),
useOriginalImages(exhentaiEnabled, unsortedPreferences),
getLoginPreference(exhPreferences, openWarnConfigureDialogController),
useHentaiAtHome(exhentaiEnabled, exhPreferences),
useJapaneseTitle(exhentaiEnabled, exhPreferences),
useOriginalImages(exhentaiEnabled, exhPreferences),
watchedTags(exhentaiEnabled),
tagFilterThreshold(exhentaiEnabled, unsortedPreferences),
tagWatchingThreshold(exhentaiEnabled, unsortedPreferences),
settingsLanguages(exhentaiEnabled, unsortedPreferences),
enabledCategories(exhentaiEnabled, unsortedPreferences),
watchedListDefaultState(exhentaiEnabled, unsortedPreferences),
imageQuality(exhentaiEnabled, unsortedPreferences),
enhancedEhentaiView(unsortedPreferences),
tagFilterThreshold(exhentaiEnabled, exhPreferences),
tagWatchingThreshold(exhentaiEnabled, exhPreferences),
settingsLanguages(exhentaiEnabled, exhPreferences),
enabledCategories(exhentaiEnabled, exhPreferences),
watchedListDefaultState(exhentaiEnabled, exhPreferences),
imageQuality(exhentaiEnabled, exhPreferences),
enhancedEhentaiView(exhPreferences),
),
),
Preference.PreferenceGroup(
stringResource(SYMR.strings.favorites_sync),
preferenceItems = persistentListOf(
readOnlySync(unsortedPreferences),
readOnlySync(exhPreferences),
syncFavoriteNotes(),
lenientSync(unsortedPreferences),
lenientSync(exhPreferences),
forceSyncReset(deleteFavoriteEntries),
),
),
Preference.PreferenceGroup(
stringResource(SYMR.strings.gallery_update_checker),
preferenceItems = persistentListOf(
updateCheckerFrequency(unsortedPreferences),
autoUpdateRequirements(unsortedPreferences),
updateCheckerFrequency(exhPreferences),
autoUpdateRequirements(exhPreferences),
updaterStatistics(
unsortedPreferences,
exhPreferences,
getExhFavoriteMangaWithMetadata,
getFlatMetadataById,
),
@@ -180,7 +180,7 @@ object SettingsEhScreen : SearchableSettings {
@Composable
fun getLoginPreference(
unsortedPreferences: UnsortedPreferences,
exhPreferences: ExhPreferences,
openWarnConfigureDialogController: () -> Unit,
): Preference.PreferenceItem.SwitchPreference {
val activityResultContract =
@@ -191,9 +191,9 @@ object SettingsEhScreen : SearchableSettings {
}
}
val context = LocalContext.current
val value by unsortedPreferences.enableExhentai().collectAsState()
val value by exhPreferences.enableExhentai.collectAsState()
return Preference.PreferenceItem.SwitchPreference(
preference = unsortedPreferences.enableExhentai(),
preference = exhPreferences.enableExhentai,
title = stringResource(SYMR.strings.enable_exhentai),
subtitle = if (!value) {
stringResource(SYMR.strings.requires_login)
@@ -202,7 +202,7 @@ object SettingsEhScreen : SearchableSettings {
},
onValueChanged = { newVal ->
if (!newVal) {
unsortedPreferences.enableExhentai().set(false)
exhPreferences.enableExhentai.set(false)
true
} else {
activityResultContract.launch(EhLoginActivity.newIntent(context))
@@ -215,10 +215,10 @@ object SettingsEhScreen : SearchableSettings {
@Composable
fun useHentaiAtHome(
exhentaiEnabled: Boolean,
unsortedPreferences: UnsortedPreferences,
exhPreferences: ExhPreferences,
): Preference.PreferenceItem.ListPreference<Int> {
return Preference.PreferenceItem.ListPreference(
preference = unsortedPreferences.useHentaiAtHome(),
preference = exhPreferences.useHentaiAtHome,
title = stringResource(SYMR.strings.use_hentai_at_home),
subtitle = stringResource(SYMR.strings.use_hentai_at_home_summary),
entries = persistentMapOf(
@@ -232,11 +232,11 @@ object SettingsEhScreen : SearchableSettings {
@Composable
fun useJapaneseTitle(
exhentaiEnabled: Boolean,
unsortedPreferences: UnsortedPreferences,
exhPreferences: ExhPreferences,
): Preference.PreferenceItem.SwitchPreference {
val value by unsortedPreferences.useJapaneseTitle().collectAsState()
val value by exhPreferences.useJapaneseTitle.collectAsState()
return Preference.PreferenceItem.SwitchPreference(
preference = unsortedPreferences.useJapaneseTitle(),
preference = exhPreferences.useJapaneseTitle,
title = stringResource(SYMR.strings.show_japanese_titles),
subtitle = if (value) {
stringResource(SYMR.strings.show_japanese_titles_option_1)
@@ -250,11 +250,11 @@ object SettingsEhScreen : SearchableSettings {
@Composable
fun useOriginalImages(
exhentaiEnabled: Boolean,
unsortedPreferences: UnsortedPreferences,
exhPreferences: ExhPreferences,
): Preference.PreferenceItem.SwitchPreference {
val value by unsortedPreferences.exhUseOriginalImages().collectAsState()
val value by exhPreferences.exhUseOriginalImages.collectAsState()
return Preference.PreferenceItem.SwitchPreference(
preference = unsortedPreferences.exhUseOriginalImages(),
preference = exhPreferences.exhUseOriginalImages,
title = stringResource(SYMR.strings.use_original_images),
subtitle = if (value) {
stringResource(SYMR.strings.use_original_images_on)
@@ -351,9 +351,9 @@ object SettingsEhScreen : SearchableSettings {
@Composable
fun tagFilterThreshold(
exhentaiEnabled: Boolean,
unsortedPreferences: UnsortedPreferences,
exhPreferences: ExhPreferences,
): Preference.PreferenceItem.TextPreference {
val value by unsortedPreferences.ehTagFilterValue().collectAsState()
val value by exhPreferences.ehTagFilterValue.collectAsState()
var dialogOpen by remember { mutableStateOf(false) }
if (dialogOpen) {
TagThresholdDialog(
@@ -364,7 +364,7 @@ object SettingsEhScreen : SearchableSettings {
outsideRangeError = stringResource(SYMR.strings.tag_filtering_threshhold_error),
onValueChange = {
dialogOpen = false
unsortedPreferences.ehTagFilterValue().set(it)
exhPreferences.ehTagFilterValue.set(it)
},
)
}
@@ -381,9 +381,9 @@ object SettingsEhScreen : SearchableSettings {
@Composable
fun tagWatchingThreshold(
exhentaiEnabled: Boolean,
unsortedPreferences: UnsortedPreferences,
exhPreferences: ExhPreferences,
): Preference.PreferenceItem.TextPreference {
val value by unsortedPreferences.ehTagWatchingValue().collectAsState()
val value by exhPreferences.ehTagWatchingValue.collectAsState()
var dialogOpen by remember { mutableStateOf(false) }
if (dialogOpen) {
TagThresholdDialog(
@@ -394,7 +394,7 @@ object SettingsEhScreen : SearchableSettings {
outsideRangeError = stringResource(SYMR.strings.tag_watching_threshhold_error),
onValueChange = {
dialogOpen = false
unsortedPreferences.ehTagWatchingValue().set(it)
exhPreferences.ehTagWatchingValue.set(it)
},
)
}
@@ -604,9 +604,9 @@ object SettingsEhScreen : SearchableSettings {
@Composable
fun settingsLanguages(
exhentaiEnabled: Boolean,
unsortedPreferences: UnsortedPreferences,
exhPreferences: ExhPreferences,
): Preference.PreferenceItem.TextPreference {
val value by unsortedPreferences.exhSettingsLanguages().collectAsState()
val value by exhPreferences.exhSettingsLanguages.collectAsState()
var dialogOpen by remember { mutableStateOf(false) }
if (dialogOpen) {
LanguagesDialog(
@@ -614,7 +614,7 @@ object SettingsEhScreen : SearchableSettings {
initialValue = value,
onValueChange = {
dialogOpen = false
unsortedPreferences.exhSettingsLanguages().set(it)
exhPreferences.exhSettingsLanguages.set(it)
},
)
}
@@ -770,9 +770,9 @@ object SettingsEhScreen : SearchableSettings {
@Composable
fun enabledCategories(
exhentaiEnabled: Boolean,
unsortedPreferences: UnsortedPreferences,
exhPreferences: ExhPreferences,
): Preference.PreferenceItem.TextPreference {
val value by unsortedPreferences.exhEnabledCategories().collectAsState()
val value by exhPreferences.exhEnabledCategories.collectAsState()
var dialogOpen by remember { mutableStateOf(false) }
if (dialogOpen) {
FrontPageCategoriesDialog(
@@ -780,7 +780,7 @@ object SettingsEhScreen : SearchableSettings {
initialValue = value,
onValueChange = {
dialogOpen = false
unsortedPreferences.exhEnabledCategories().set(it)
exhPreferences.exhEnabledCategories.set(it)
},
)
}
@@ -797,10 +797,10 @@ object SettingsEhScreen : SearchableSettings {
@Composable
fun watchedListDefaultState(
exhentaiEnabled: Boolean,
unsortedPreferences: UnsortedPreferences,
exhPreferences: ExhPreferences,
): Preference.PreferenceItem.SwitchPreference {
return Preference.PreferenceItem.SwitchPreference(
preference = unsortedPreferences.exhWatchedListDefaultState(),
preference = exhPreferences.exhWatchedListDefaultState,
title = stringResource(SYMR.strings.watched_list_default),
subtitle = stringResource(SYMR.strings.watched_list_state_summary),
enabled = exhentaiEnabled,
@@ -810,10 +810,10 @@ object SettingsEhScreen : SearchableSettings {
@Composable
fun imageQuality(
exhentaiEnabled: Boolean,
unsortedPreferences: UnsortedPreferences,
exhPreferences: ExhPreferences,
): Preference.PreferenceItem.ListPreference<String> {
return Preference.PreferenceItem.ListPreference(
preference = unsortedPreferences.imageQuality(),
preference = exhPreferences.imageQuality,
title = stringResource(SYMR.strings.eh_image_quality_summary),
subtitle = stringResource(SYMR.strings.eh_image_quality),
entries = persistentMapOf(
@@ -829,18 +829,18 @@ object SettingsEhScreen : SearchableSettings {
}
@Composable
fun enhancedEhentaiView(unsortedPreferences: UnsortedPreferences): Preference.PreferenceItem.SwitchPreference {
fun enhancedEhentaiView(exhPreferences: ExhPreferences): Preference.PreferenceItem.SwitchPreference {
return Preference.PreferenceItem.SwitchPreference(
preference = unsortedPreferences.enhancedEHentaiView(),
preference = exhPreferences.enhancedEHentaiView,
title = stringResource(SYMR.strings.pref_enhanced_e_hentai_view),
subtitle = stringResource(SYMR.strings.pref_enhanced_e_hentai_view_summary),
)
}
@Composable
fun readOnlySync(unsortedPreferences: UnsortedPreferences): Preference.PreferenceItem.SwitchPreference {
fun readOnlySync(exhPreferences: ExhPreferences): Preference.PreferenceItem.SwitchPreference {
return Preference.PreferenceItem.SwitchPreference(
preference = unsortedPreferences.exhReadOnlySync(),
preference = exhPreferences.exhReadOnlySync,
title = stringResource(SYMR.strings.disable_favorites_uploading),
subtitle = stringResource(SYMR.strings.disable_favorites_uploading_summary),
)
@@ -863,9 +863,9 @@ object SettingsEhScreen : SearchableSettings {
}
@Composable
fun lenientSync(unsortedPreferences: UnsortedPreferences): Preference.PreferenceItem.SwitchPreference {
fun lenientSync(exhPreferences: ExhPreferences): Preference.PreferenceItem.SwitchPreference {
return Preference.PreferenceItem.SwitchPreference(
preference = unsortedPreferences.exhLenientSync(),
preference = exhPreferences.exhLenientSync,
title = stringResource(SYMR.strings.ignore_sync_errors),
subtitle = stringResource(SYMR.strings.ignore_sync_errors_summary),
)
@@ -935,12 +935,12 @@ object SettingsEhScreen : SearchableSettings {
@Composable
fun updateCheckerFrequency(
unsortedPreferences: UnsortedPreferences,
exhPreferences: ExhPreferences,
): Preference.PreferenceItem.ListPreference<Int> {
val value by unsortedPreferences.exhAutoUpdateFrequency().collectAsState()
val value by exhPreferences.exhAutoUpdateFrequency.collectAsState()
val context = LocalContext.current
return Preference.PreferenceItem.ListPreference(
preference = unsortedPreferences.exhAutoUpdateFrequency(),
preference = exhPreferences.exhAutoUpdateFrequency,
title = stringResource(SYMR.strings.time_between_batches),
subtitle = if (value == 0) {
stringResource(SYMR.strings.time_between_batches_summary_1, stringResource(MR.strings.app_name))
@@ -971,12 +971,12 @@ object SettingsEhScreen : SearchableSettings {
@Composable
fun autoUpdateRequirements(
unsortedPreferences: UnsortedPreferences,
exhPreferences: ExhPreferences,
): Preference.PreferenceItem.MultiSelectListPreference {
val value by unsortedPreferences.exhAutoUpdateRequirements().collectAsState()
val value by exhPreferences.exhAutoUpdateRequirements.collectAsState()
val context = LocalContext.current
return Preference.PreferenceItem.MultiSelectListPreference(
preference = unsortedPreferences.exhAutoUpdateRequirements(),
preference = exhPreferences.exhAutoUpdateRequirements,
title = stringResource(SYMR.strings.auto_update_restrictions),
subtitle = remember(value) {
context.stringResource(
@@ -1139,7 +1139,7 @@ object SettingsEhScreen : SearchableSettings {
@Composable
fun updaterStatistics(
unsortedPreferences: UnsortedPreferences,
exhPreferences: ExhPreferences,
getExhFavoriteMangaWithMetadata: GetExhFavoriteMangaWithMetadata,
getFlatMetadataById: GetFlatMetadataById,
): Preference.PreferenceItem.TextPreference {
@@ -1150,7 +1150,7 @@ object SettingsEhScreen : SearchableSettings {
value = withIOContext {
try {
val stats =
unsortedPreferences.exhAutoUpdateStats().get().nullIfBlank()?.let {
exhPreferences.exhAutoUpdateStats.get().nullIfBlank()?.let {
Json.decodeFromString<EHentaiUpdaterStats>(it)
}
@@ -25,7 +25,6 @@ import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.persistentMapOf
import kotlinx.collections.immutable.toImmutableMap
import kotlinx.coroutines.launch
import tachiyomi.domain.UnsortedPreferences
import tachiyomi.domain.category.interactor.GetCategories
import tachiyomi.domain.category.interactor.ResetCategoryFlags
import tachiyomi.domain.category.model.Category
@@ -59,9 +58,6 @@ object SettingsLibraryScreen : SearchableSettings {
val getCategories = remember { Injekt.get<GetCategories>() }
val libraryPreferences = remember { Injekt.get<LibraryPreferences>() }
val allCategories by getCategories.subscribe().collectAsState(initial = emptyList())
// SY -->
val unsortedPreferences = remember { Injekt.get<UnsortedPreferences>() }
// SY <--
return listOf(
getCategoriesGroup(LocalNavigator.currentOrThrow, allCategories, libraryPreferences),
@@ -69,7 +65,6 @@ object SettingsLibraryScreen : SearchableSettings {
getBehaviorGroup(libraryPreferences),
// SY -->
getSortingCategory(LocalNavigator.currentOrThrow, libraryPreferences),
getMigrationCategory(unsortedPreferences),
// SY <--
)
}
@@ -84,7 +79,7 @@ object SettingsLibraryScreen : SearchableSettings {
val userCategoriesCount = allCategories.filterNot(Category::isSystemCategory).size
// For default category
val ids = listOf(libraryPreferences.defaultCategory().defaultValue()) +
val ids = listOf(libraryPreferences.defaultCategory.defaultValue()) +
allCategories.fastMap { it.id.toInt() }
val labels = listOf(stringResource(MR.strings.default_category_summary)) +
allCategories.fastMap { it.visualName }
@@ -102,12 +97,12 @@ object SettingsLibraryScreen : SearchableSettings {
onClick = { navigator.push(CategoryScreen()) },
),
Preference.PreferenceItem.ListPreference(
preference = libraryPreferences.defaultCategory(),
preference = libraryPreferences.defaultCategory,
entries = ids.zip(labels).toMap().toImmutableMap(),
title = stringResource(MR.strings.default_category),
),
Preference.PreferenceItem.SwitchPreference(
preference = libraryPreferences.categorizedDisplaySettings(),
preference = libraryPreferences.categorizedDisplaySettings,
title = stringResource(MR.strings.categorized_display_settings),
onValueChanged = {
if (!it) {
@@ -129,9 +124,9 @@ object SettingsLibraryScreen : SearchableSettings {
): Preference.PreferenceGroup {
val context = LocalContext.current
val autoUpdateIntervalPref = libraryPreferences.autoUpdateInterval()
val autoUpdateCategoriesPref = libraryPreferences.updateCategories()
val autoUpdateCategoriesExcludePref = libraryPreferences.updateCategoriesExclude()
val autoUpdateIntervalPref = libraryPreferences.autoUpdateInterval
val autoUpdateCategoriesPref = libraryPreferences.updateCategories
val autoUpdateCategoriesExcludePref = libraryPreferences.updateCategoriesExclude
val autoUpdateInterval by autoUpdateIntervalPref.collectAsState()
@@ -175,7 +170,7 @@ object SettingsLibraryScreen : SearchableSettings {
},
),
Preference.PreferenceItem.MultiSelectListPreference(
preference = libraryPreferences.autoUpdateDeviceRestrictions(),
preference = libraryPreferences.autoUpdateDeviceRestrictions,
entries = persistentMapOf(
DEVICE_ONLY_ON_WIFI to stringResource(MR.strings.connected_to_wifi),
DEVICE_NETWORK_NOT_METERED to stringResource(MR.strings.network_not_metered),
@@ -201,7 +196,7 @@ object SettingsLibraryScreen : SearchableSettings {
),
// SY -->
Preference.PreferenceItem.ListPreference(
preference = libraryPreferences.groupLibraryUpdateType(),
preference = libraryPreferences.groupLibraryUpdateType,
title = stringResource(SYMR.strings.library_group_updates),
entries = persistentMapOf(
GroupLibraryMode.GLOBAL to stringResource(SYMR.strings.library_group_updates_global),
@@ -212,12 +207,12 @@ object SettingsLibraryScreen : SearchableSettings {
),
// SY <--
Preference.PreferenceItem.SwitchPreference(
preference = libraryPreferences.autoUpdateMetadata(),
preference = libraryPreferences.autoUpdateMetadata,
title = stringResource(MR.strings.pref_library_update_refresh_metadata),
subtitle = stringResource(MR.strings.pref_library_update_refresh_metadata_summary),
),
Preference.PreferenceItem.MultiSelectListPreference(
preference = libraryPreferences.autoUpdateMangaRestrictions(),
preference = libraryPreferences.autoUpdateMangaRestrictions,
entries = persistentMapOf(
MANGA_HAS_UNREAD to stringResource(MR.strings.pref_update_only_completely_read),
MANGA_NON_READ to stringResource(MR.strings.pref_update_only_started),
@@ -227,7 +222,7 @@ object SettingsLibraryScreen : SearchableSettings {
title = stringResource(MR.strings.pref_library_update_smart_update),
),
Preference.PreferenceItem.SwitchPreference(
preference = libraryPreferences.newShowUpdatesCount(),
preference = libraryPreferences.newShowUpdatesCount,
title = stringResource(MR.strings.pref_library_update_show_tab_badge),
),
),
@@ -242,7 +237,7 @@ object SettingsLibraryScreen : SearchableSettings {
title = stringResource(MR.strings.pref_behavior),
preferenceItems = persistentListOf(
Preference.PreferenceItem.ListPreference(
preference = libraryPreferences.swipeToStartAction(),
preference = libraryPreferences.swipeToStartAction,
entries = persistentMapOf(
LibraryPreferences.ChapterSwipeAction.Disabled to
stringResource(MR.strings.disabled),
@@ -256,7 +251,7 @@ object SettingsLibraryScreen : SearchableSettings {
title = stringResource(MR.strings.pref_chapter_swipe_start),
),
Preference.PreferenceItem.ListPreference(
preference = libraryPreferences.swipeToEndAction(),
preference = libraryPreferences.swipeToEndAction,
entries = persistentMapOf(
LibraryPreferences.ChapterSwipeAction.Disabled to
stringResource(MR.strings.disabled),
@@ -270,7 +265,7 @@ object SettingsLibraryScreen : SearchableSettings {
title = stringResource(MR.strings.pref_chapter_swipe_end),
),
Preference.PreferenceItem.MultiSelectListPreference(
preference = libraryPreferences.markDuplicateReadChapterAsRead(),
preference = libraryPreferences.markDuplicateReadChapterAsRead,
entries = persistentMapOf(
MARK_DUPLICATE_CHAPTER_READ_EXISTING to
stringResource(MR.strings.pref_mark_duplicate_read_chapter_read_existing),
@@ -286,7 +281,7 @@ object SettingsLibraryScreen : SearchableSettings {
// SY -->
@Composable
fun getSortingCategory(navigator: Navigator, libraryPreferences: LibraryPreferences): Preference.PreferenceGroup {
val tagCount by libraryPreferences.sortTagsForLibrary().collectAsState()
val tagCount by libraryPreferences.sortTagsForLibrary.collectAsState()
return Preference.PreferenceGroup(
stringResource(SYMR.strings.pref_sorting_settings),
preferenceItems = persistentListOf(
@@ -300,22 +295,5 @@ object SettingsLibraryScreen : SearchableSettings {
),
)
}
@Composable
fun getMigrationCategory(unsortedPreferences: UnsortedPreferences): Preference.PreferenceGroup {
val skipPreMigration by unsortedPreferences.skipPreMigration().collectAsState()
val migrationSources by unsortedPreferences.migrationSources().collectAsState()
return Preference.PreferenceGroup(
stringResource(SYMR.strings.migration),
enabled = skipPreMigration || migrationSources.isNotEmpty(),
preferenceItems = persistentListOf(
Preference.PreferenceItem.SwitchPreference(
preference = unsortedPreferences.skipPreMigration(),
title = stringResource(SYMR.strings.skip_pre_migration),
subtitle = stringResource(SYMR.strings.pref_skip_pre_migration_summary),
),
),
)
}
// SY <--
}
@@ -9,7 +9,6 @@ import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.outlined.ChromeReaderMode
import androidx.compose.material.icons.outlined.ChromeReaderMode
import androidx.compose.material.icons.outlined.Code
import androidx.compose.material.icons.outlined.CollectionsBookmark
import androidx.compose.material.icons.outlined.Explore
@@ -44,7 +44,6 @@ import logcat.LogPriority
import tachiyomi.core.common.util.lang.launchIO
import tachiyomi.core.common.util.lang.withUIContext
import tachiyomi.core.common.util.system.logcat
import tachiyomi.domain.UnsortedPreferences
import tachiyomi.i18n.MR
import tachiyomi.i18n.sy.SYMR
import tachiyomi.presentation.core.components.material.padding
@@ -65,14 +64,13 @@ object SettingsMangadexScreen : SearchableSettings {
@Composable
override fun getPreferences(): List<Preference> {
val sourcePreferences: SourcePreferences = remember { Injekt.get() }
val unsortedPreferences: UnsortedPreferences = remember { Injekt.get() }
val trackPreferences: TrackPreferences = remember { Injekt.get() }
val mdex = remember { MdUtil.getEnabledMangaDex(unsortedPreferences, sourcePreferences) } ?: return emptyList()
val mdex = remember { MdUtil.getEnabledMangaDex(sourcePreferences) } ?: return emptyList()
return listOf(
loginPreference(mdex, trackPreferences),
preferredMangaDexId(unsortedPreferences, sourcePreferences),
syncMangaDexIntoThis(unsortedPreferences),
preferredMangaDexId(sourcePreferences),
syncMangaDexIntoThis(sourcePreferences),
syncLibraryToMangaDex(),
)
}
@@ -174,11 +172,10 @@ object SettingsMangadexScreen : SearchableSettings {
@Composable
fun preferredMangaDexId(
unsortedPreferences: UnsortedPreferences,
sourcePreferences: SourcePreferences,
): Preference.PreferenceItem.ListPreference<String> {
return Preference.PreferenceItem.ListPreference(
preference = unsortedPreferences.preferredMangaDexId(),
preference = sourcePreferences.preferredMangaDexId,
title = stringResource(SYMR.strings.mangadex_preffered_source),
subtitle = stringResource(SYMR.strings.mangadex_preffered_source_summary),
entries = MdUtil.getEnabledMangaDexs(sourcePreferences)
@@ -250,7 +247,7 @@ object SettingsMangadexScreen : SearchableSettings {
}
@Composable
fun syncMangaDexIntoThis(unsortedPreferences: UnsortedPreferences): Preference.PreferenceItem.TextPreference {
fun syncMangaDexIntoThis(sourcePreferences: SourcePreferences): Preference.PreferenceItem.TextPreference {
val context = LocalContext.current
var dialogOpen by remember { mutableStateOf(false) }
if (dialogOpen) {
@@ -258,7 +255,7 @@ object SettingsMangadexScreen : SearchableSettings {
onDismissRequest = { dialogOpen = false },
onSelectionConfirmed = { items ->
dialogOpen = false
unsortedPreferences.mangadexSyncToLibraryIndexes().set(
sourcePreferences.mangadexSyncToLibraryIndexes.set(
List(items.size) { index -> (index + 1).toString() }.toSet(),
)
LibraryUpdateJob.startNow(
@@ -1,6 +1,5 @@
package eu.kanade.presentation.more.settings.screen
import android.os.Build
import androidx.compose.runtime.Composable
import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.runtime.getValue
@@ -12,6 +11,7 @@ import eu.kanade.tachiyomi.ui.reader.setting.ReaderOrientation
import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences
import eu.kanade.tachiyomi.ui.reader.setting.ReadingMode
import eu.kanade.tachiyomi.ui.reader.viewer.pager.PagerConfig
import eu.kanade.tachiyomi.util.system.hasDisplayCutout
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.persistentMapOf
import kotlinx.collections.immutable.toImmutableMap
@@ -34,19 +34,19 @@ object SettingsReaderScreen : SearchableSettings {
override fun getPreferences(): List<Preference> {
val readerPref = remember { Injekt.get<ReaderPreferences>() }
// SY -->
val forceHorizontalSeekbar by readerPref.forceHorizontalSeekbar().collectAsState()
val forceHorizontalSeekbar by readerPref.forceHorizontalSeekbar.collectAsState()
// SY <--
return listOf(
Preference.PreferenceItem.ListPreference(
preference = readerPref.defaultReadingMode(),
preference = readerPref.defaultReadingMode,
entries = ReadingMode.entries.drop(1)
.associate { it.flagValue to stringResource(it.stringRes) }
.toImmutableMap(),
title = stringResource(MR.strings.pref_viewer_type),
),
Preference.PreferenceItem.ListPreference(
preference = readerPref.doubleTapAnimSpeed(),
preference = readerPref.doubleTapAnimSpeed,
entries = persistentMapOf(
1 to stringResource(MR.strings.double_tap_anim_speed_0),
500 to stringResource(MR.strings.double_tap_anim_speed_normal),
@@ -55,29 +55,29 @@ object SettingsReaderScreen : SearchableSettings {
title = stringResource(MR.strings.pref_double_tap_anim_speed),
),
Preference.PreferenceItem.SwitchPreference(
preference = readerPref.showReadingMode(),
preference = readerPref.showReadingMode,
title = stringResource(MR.strings.pref_show_reading_mode),
subtitle = stringResource(MR.strings.pref_show_reading_mode_summary),
),
Preference.PreferenceItem.SwitchPreference(
preference = readerPref.showNavigationOverlayOnStart(),
preference = readerPref.showNavigationOverlayOnStart,
title = stringResource(MR.strings.pref_show_navigation_mode),
subtitle = stringResource(MR.strings.pref_show_navigation_mode_summary),
),
// SY -->
Preference.PreferenceItem.SwitchPreference(
preference = readerPref.forceHorizontalSeekbar(),
preference = readerPref.forceHorizontalSeekbar,
title = stringResource(SYMR.strings.pref_force_horz_seekbar),
subtitle = stringResource(SYMR.strings.pref_force_horz_seekbar_summary),
),
Preference.PreferenceItem.SwitchPreference(
preference = readerPref.landscapeVerticalSeekbar(),
preference = readerPref.landscapeVerticalSeekbar,
title = stringResource(SYMR.strings.pref_show_vert_seekbar_landscape),
subtitle = stringResource(SYMR.strings.pref_show_vert_seekbar_landscape_summary),
enabled = !forceHorizontalSeekbar,
),
Preference.PreferenceItem.SwitchPreference(
preference = readerPref.leftVerticalSeekbar(),
preference = readerPref.leftVerticalSeekbar,
title = stringResource(SYMR.strings.pref_left_handed_vertical_seekbar),
subtitle = stringResource(SYMR.strings.pref_left_handed_vertical_seekbar_summary),
enabled = !forceHorizontalSeekbar,
@@ -85,7 +85,7 @@ object SettingsReaderScreen : SearchableSettings {
// SY <--
/* SY -->
Preference.PreferenceItem.SwitchPreference(
preference = readerPref.pageTransitions(),
preference = readerPref.pageTransitions,
title = stringResource(MR.strings.pref_page_transitions),
),
SY <-- */
@@ -108,20 +108,20 @@ object SettingsReaderScreen : SearchableSettings {
@Composable
private fun getDisplayGroup(readerPreferences: ReaderPreferences): Preference.PreferenceGroup {
val fullscreenPref = readerPreferences.fullscreen()
val fullscreenPref = readerPreferences.fullscreen
val fullscreen by fullscreenPref.collectAsState()
return Preference.PreferenceGroup(
title = stringResource(MR.strings.pref_category_display),
preferenceItems = persistentListOf(
Preference.PreferenceItem.ListPreference(
preference = readerPreferences.defaultOrientationType(),
preference = readerPreferences.defaultOrientationType,
entries = ReaderOrientation.entries.drop(1)
.associate { it.flagValue to stringResource(it.stringRes) }
.toImmutableMap(),
title = stringResource(MR.strings.pref_rotation_type),
),
Preference.PreferenceItem.ListPreference(
preference = readerPreferences.readerTheme(),
preference = readerPreferences.readerTheme,
entries = persistentMapOf(
1 to stringResource(MR.strings.black_background),
2 to stringResource(MR.strings.gray_background),
@@ -135,18 +135,16 @@ object SettingsReaderScreen : SearchableSettings {
title = stringResource(MR.strings.pref_fullscreen),
),
Preference.PreferenceItem.SwitchPreference(
preference = readerPreferences.cutoutShort(),
preference = readerPreferences.drawUnderCutout,
title = stringResource(MR.strings.pref_cutout_short),
enabled = fullscreen &&
Build.VERSION.SDK_INT >= Build.VERSION_CODES.P &&
LocalView.current.rootWindowInsets?.displayCutout != null, // has cutout
enabled = LocalView.current.hasDisplayCutout() && fullscreen,
),
Preference.PreferenceItem.SwitchPreference(
preference = readerPreferences.keepScreenOn(),
preference = readerPreferences.keepScreenOn,
title = stringResource(MR.strings.pref_keep_screen_on),
),
Preference.PreferenceItem.SwitchPreference(
preference = readerPreferences.showPageNumber(),
preference = readerPreferences.showPageNumber,
title = stringResource(MR.strings.pref_show_page_number),
),
),
@@ -155,21 +153,21 @@ object SettingsReaderScreen : SearchableSettings {
@Composable
private fun getEInkGroup(readerPreferences: ReaderPreferences): Preference.PreferenceGroup {
val flashPageState by readerPreferences.flashOnPageChange().collectAsState()
val flashPageState by readerPreferences.flashOnPageChange.collectAsState()
val flashMillisPref = readerPreferences.flashDurationMillis()
val flashMillisPref = readerPreferences.flashDurationMillis
val flashMillis by flashMillisPref.collectAsState()
val flashIntervalPref = readerPreferences.flashPageInterval()
val flashIntervalPref = readerPreferences.flashPageInterval
val flashInterval by flashIntervalPref.collectAsState()
val flashColorPref = readerPreferences.flashColor()
val flashColorPref = readerPreferences.flashColor
return Preference.PreferenceGroup(
title = "E-Ink",
preferenceItems = persistentListOf(
Preference.PreferenceItem.SwitchPreference(
preference = readerPreferences.flashOnPageChange(),
preference = readerPreferences.flashOnPageChange,
title = stringResource(MR.strings.pref_flash_page),
subtitle = stringResource(MR.strings.pref_flash_page_summ),
),
@@ -177,23 +175,17 @@ object SettingsReaderScreen : SearchableSettings {
value = flashMillis / ReaderPreferences.MILLI_CONVERSION,
valueRange = 1..15,
title = stringResource(MR.strings.pref_flash_duration),
subtitle = stringResource(MR.strings.pref_flash_duration_summary, flashMillis),
valueString = stringResource(MR.strings.pref_flash_duration_summary, flashMillis),
enabled = flashPageState,
onValueChanged = {
flashMillisPref.set(it * ReaderPreferences.MILLI_CONVERSION)
true
},
onValueChanged = { flashMillisPref.set(it * ReaderPreferences.MILLI_CONVERSION) },
),
Preference.PreferenceItem.SliderPreference(
value = flashInterval,
valueRange = 1..10,
title = stringResource(MR.strings.pref_flash_page_interval),
subtitle = pluralStringResource(MR.plurals.pref_pages, flashInterval, flashInterval),
valueString = pluralStringResource(MR.plurals.pref_pages, flashInterval, flashInterval),
enabled = flashPageState,
onValueChanged = {
flashIntervalPref.set(it)
true
},
onValueChanged = { flashIntervalPref.set(it) },
),
Preference.PreferenceItem.ListPreference(
preference = flashColorPref,
@@ -216,26 +208,19 @@ object SettingsReaderScreen : SearchableSettings {
title = stringResource(MR.strings.pref_category_reading),
preferenceItems = persistentListOf(
Preference.PreferenceItem.SwitchPreference(
preference = readerPreferences.skipRead(),
preference = readerPreferences.skipRead,
title = stringResource(MR.strings.pref_skip_read_chapters),
),
Preference.PreferenceItem.SwitchPreference(
preference = readerPreferences.skipFiltered(),
preference = readerPreferences.skipFiltered,
title = stringResource(MR.strings.pref_skip_filtered_chapters),
),
Preference.PreferenceItem.SwitchPreference(
preference = readerPreferences.skipDupe(),
preference = readerPreferences.skipDupe,
title = stringResource(MR.strings.pref_skip_dupe_chapters),
),
// SY -->
Preference.PreferenceItem.SwitchPreference(
preference = readerPreferences.markReadDupe(),
title = stringResource(SYMR.strings.pref_mark_read_dupe_chapters),
subtitle = stringResource(SYMR.strings.pref_mark_read_dupe_chapters_summary),
),
// SY <--
Preference.PreferenceItem.SwitchPreference(
preference = readerPreferences.alwaysShowChapterTransition(),
preference = readerPreferences.alwaysShowChapterTransition,
title = stringResource(MR.strings.pref_always_show_chapter_transition),
),
),
@@ -244,10 +229,10 @@ object SettingsReaderScreen : SearchableSettings {
@Composable
private fun getPagedGroup(readerPreferences: ReaderPreferences): Preference.PreferenceGroup {
val navModePref = readerPreferences.navigationModePager()
val imageScaleTypePref = readerPreferences.imageScaleType()
val dualPageSplitPref = readerPreferences.dualPageSplitPaged()
val rotateToFitPref = readerPreferences.dualPageRotateToFit()
val navModePref = readerPreferences.navigationModePager
val imageScaleTypePref = readerPreferences.imageScaleType
val dualPageSplitPref = readerPreferences.dualPageSplitPaged
val rotateToFitPref = readerPreferences.dualPageRotateToFit
val navMode by navModePref.collectAsState()
val imageScaleType by imageScaleTypePref.collectAsState()
@@ -266,7 +251,7 @@ object SettingsReaderScreen : SearchableSettings {
title = stringResource(MR.strings.pref_viewer_nav),
),
Preference.PreferenceItem.ListPreference(
preference = readerPreferences.pagerNavInverted(),
preference = readerPreferences.pagerNavInverted,
entries = persistentListOf(
ReaderPreferences.TappingInvertMode.NONE,
ReaderPreferences.TappingInvertMode.HORIZONTAL,
@@ -287,7 +272,7 @@ object SettingsReaderScreen : SearchableSettings {
title = stringResource(MR.strings.pref_image_scale_type),
),
Preference.PreferenceItem.ListPreference(
preference = readerPreferences.zoomStart(),
preference = readerPreferences.zoomStart,
entries = ReaderPreferences.ZoomStart
.mapIndexed { index, it -> index + 1 to stringResource(it) }
.toMap()
@@ -295,22 +280,22 @@ object SettingsReaderScreen : SearchableSettings {
title = stringResource(MR.strings.pref_zoom_start),
),
Preference.PreferenceItem.SwitchPreference(
preference = readerPreferences.cropBorders(),
preference = readerPreferences.cropBorders,
title = stringResource(MR.strings.pref_crop_borders),
),
// SY -->
Preference.PreferenceItem.SwitchPreference(
preference = readerPreferences.pageTransitionsPager(),
preference = readerPreferences.pageTransitionsPager,
title = stringResource(MR.strings.pref_page_transitions),
),
// SY <--
Preference.PreferenceItem.SwitchPreference(
preference = readerPreferences.landscapeZoom(),
preference = readerPreferences.landscapeZoom,
title = stringResource(MR.strings.pref_landscape_zoom),
enabled = imageScaleType == 1,
),
Preference.PreferenceItem.SwitchPreference(
preference = readerPreferences.navigateToPan(),
preference = readerPreferences.navigateToPan,
title = stringResource(MR.strings.pref_navigate_pan),
enabled = navMode != 5,
),
@@ -323,7 +308,7 @@ object SettingsReaderScreen : SearchableSettings {
},
),
Preference.PreferenceItem.SwitchPreference(
preference = readerPreferences.dualPageInvertPaged(),
preference = readerPreferences.dualPageInvertPaged,
title = stringResource(MR.strings.pref_dual_page_invert),
subtitle = stringResource(MR.strings.pref_dual_page_invert_summary),
enabled = dualPageSplit,
@@ -337,7 +322,7 @@ object SettingsReaderScreen : SearchableSettings {
},
),
Preference.PreferenceItem.SwitchPreference(
preference = readerPreferences.dualPageRotateToFitInvert(),
preference = readerPreferences.dualPageRotateToFitInvert,
title = stringResource(MR.strings.pref_page_rotate_invert),
enabled = rotateToFit,
),
@@ -349,10 +334,10 @@ object SettingsReaderScreen : SearchableSettings {
private fun getWebtoonGroup(readerPreferences: ReaderPreferences): Preference.PreferenceGroup {
val numberFormat = remember { NumberFormat.getPercentInstance() }
val navModePref = readerPreferences.navigationModeWebtoon()
val dualPageSplitPref = readerPreferences.dualPageSplitWebtoon()
val rotateToFitPref = readerPreferences.dualPageRotateToFitWebtoon()
val webtoonSidePaddingPref = readerPreferences.webtoonSidePadding()
val navModePref = readerPreferences.navigationModeWebtoon
val dualPageSplitPref = readerPreferences.dualPageSplitWebtoon
val rotateToFitPref = readerPreferences.dualPageRotateToFitWebtoon
val webtoonSidePaddingPref = readerPreferences.webtoonSidePadding
val navMode by navModePref.collectAsState()
val dualPageSplit by dualPageSplitPref.collectAsState()
@@ -371,7 +356,7 @@ object SettingsReaderScreen : SearchableSettings {
title = stringResource(MR.strings.pref_viewer_nav),
),
Preference.PreferenceItem.ListPreference(
preference = readerPreferences.webtoonNavInverted(),
preference = readerPreferences.webtoonNavInverted,
entries = persistentListOf(
ReaderPreferences.TappingInvertMode.NONE,
ReaderPreferences.TappingInvertMode.HORIZONTAL,
@@ -389,14 +374,11 @@ object SettingsReaderScreen : SearchableSettings {
it.WEBTOON_PADDING_MIN..it.WEBTOON_PADDING_MAX
},
title = stringResource(MR.strings.pref_webtoon_side_padding),
subtitle = numberFormat.format(webtoonSidePadding / 100f),
onValueChanged = {
webtoonSidePaddingPref.set(it)
true
},
valueString = numberFormat.format(webtoonSidePadding / 100f),
onValueChanged = { webtoonSidePaddingPref.set(it) },
),
Preference.PreferenceItem.ListPreference(
preference = readerPreferences.readerHideThreshold(),
preference = readerPreferences.readerHideThreshold,
entries = persistentMapOf(
ReaderPreferences.ReaderHideThreshold.HIGHEST to stringResource(MR.strings.pref_highest),
ReaderPreferences.ReaderHideThreshold.HIGH to stringResource(MR.strings.pref_high),
@@ -406,7 +388,7 @@ object SettingsReaderScreen : SearchableSettings {
title = stringResource(MR.strings.pref_hide_threshold),
),
Preference.PreferenceItem.SwitchPreference(
preference = readerPreferences.cropBordersWebtoon(),
preference = readerPreferences.cropBordersWebtoon,
title = stringResource(MR.strings.pref_crop_borders),
),
Preference.PreferenceItem.SwitchPreference(
@@ -418,7 +400,7 @@ object SettingsReaderScreen : SearchableSettings {
},
),
Preference.PreferenceItem.SwitchPreference(
preference = readerPreferences.dualPageInvertWebtoon(),
preference = readerPreferences.dualPageInvertWebtoon,
title = stringResource(MR.strings.pref_dual_page_invert),
subtitle = stringResource(MR.strings.pref_dual_page_invert_summary),
enabled = dualPageSplit,
@@ -432,21 +414,21 @@ object SettingsReaderScreen : SearchableSettings {
},
),
Preference.PreferenceItem.SwitchPreference(
preference = readerPreferences.dualPageRotateToFitInvertWebtoon(),
preference = readerPreferences.dualPageRotateToFitInvertWebtoon,
title = stringResource(MR.strings.pref_page_rotate_invert),
enabled = rotateToFit,
),
Preference.PreferenceItem.SwitchPreference(
preference = readerPreferences.webtoonDoubleTapZoomEnabled(),
preference = readerPreferences.webtoonDoubleTapZoomEnabled,
title = stringResource(MR.strings.pref_double_tap_zoom),
),
Preference.PreferenceItem.SwitchPreference(
preference = readerPreferences.webtoonDisableZoomOut(),
preference = readerPreferences.webtoonDisableZoomOut,
title = stringResource(MR.strings.pref_webtoon_disable_zoom_out),
),
// SY -->
Preference.PreferenceItem.SwitchPreference(
preference = readerPreferences.pageTransitionsWebtoon(),
preference = readerPreferences.pageTransitionsWebtoon,
title = stringResource(MR.strings.pref_page_transitions),
),
// SY <--
@@ -461,12 +443,12 @@ object SettingsReaderScreen : SearchableSettings {
title = stringResource(MR.strings.vertical_plus_viewer),
preferenceItems = persistentListOf(
Preference.PreferenceItem.SwitchPreference(
preference = readerPreferences.continuousVerticalTappingByPage(),
preference = readerPreferences.continuousVerticalTappingByPage,
title = stringResource(SYMR.strings.tap_scroll_page),
subtitle = stringResource(SYMR.strings.tap_scroll_page_summary),
),
Preference.PreferenceItem.SwitchPreference(
preference = readerPreferences.cropBordersContinuousVertical(),
preference = readerPreferences.cropBordersContinuousVertical,
title = stringResource(MR.strings.pref_crop_borders),
),
),
@@ -476,7 +458,7 @@ object SettingsReaderScreen : SearchableSettings {
@Composable
private fun getNavigationGroup(readerPreferences: ReaderPreferences): Preference.PreferenceGroup {
val readWithVolumeKeysPref = readerPreferences.readWithVolumeKeys()
val readWithVolumeKeysPref = readerPreferences.readWithVolumeKeys
val readWithVolumeKeys by readWithVolumeKeysPref.collectAsState()
return Preference.PreferenceGroup(
title = stringResource(MR.strings.pref_reader_navigation),
@@ -486,7 +468,7 @@ object SettingsReaderScreen : SearchableSettings {
title = stringResource(MR.strings.pref_read_with_volume_keys),
),
Preference.PreferenceItem.SwitchPreference(
preference = readerPreferences.readWithVolumeKeysInverted(),
preference = readerPreferences.readWithVolumeKeysInverted,
title = stringResource(MR.strings.pref_read_with_volume_keys_inverted),
enabled = readWithVolumeKeys,
),
@@ -500,11 +482,11 @@ object SettingsReaderScreen : SearchableSettings {
title = stringResource(MR.strings.pref_reader_actions),
preferenceItems = persistentListOf(
Preference.PreferenceItem.SwitchPreference(
preference = readerPreferences.readWithLongTap(),
preference = readerPreferences.readWithLongTap,
title = stringResource(MR.strings.pref_read_with_long_tap),
),
Preference.PreferenceItem.SwitchPreference(
preference = readerPreferences.folderPerManga(),
preference = readerPreferences.folderPerManga,
title = stringResource(MR.strings.pref_create_folder_per_manga),
subtitle = stringResource(MR.strings.pref_create_folder_per_manga_summary),
),
@@ -519,7 +501,7 @@ object SettingsReaderScreen : SearchableSettings {
title = stringResource(SYMR.strings.page_downloading),
preferenceItems = persistentListOf(
Preference.PreferenceItem.ListPreference(
preference = readerPreferences.preloadSize(),
preference = readerPreferences.preloadSize,
title = stringResource(SYMR.strings.reader_preload_amount),
subtitle = stringResource(SYMR.strings.reader_preload_amount_summary),
entries = persistentMapOf(
@@ -534,13 +516,13 @@ object SettingsReaderScreen : SearchableSettings {
),
),
Preference.PreferenceItem.ListPreference(
preference = readerPreferences.readerThreads(),
preference = readerPreferences.readerThreads,
title = stringResource(SYMR.strings.download_threads),
subtitle = stringResource(SYMR.strings.download_threads_summary),
entries = List(5) { it }.associateWith { it.toString() }.toImmutableMap(),
),
Preference.PreferenceItem.ListPreference(
preference = readerPreferences.cacheSize(),
preference = readerPreferences.cacheSize,
title = stringResource(SYMR.strings.reader_cache_size),
subtitle = stringResource(SYMR.strings.reader_cache_size_summary),
entries = persistentMapOf(
@@ -563,7 +545,7 @@ object SettingsReaderScreen : SearchableSettings {
),
),
Preference.PreferenceItem.SwitchPreference(
preference = readerPreferences.aggressivePageLoading(),
preference = readerPreferences.aggressivePageLoading,
title = stringResource(SYMR.strings.aggressively_load_pages),
subtitle = stringResource(SYMR.strings.aggressively_load_pages_summary),
),
@@ -573,26 +555,26 @@ object SettingsReaderScreen : SearchableSettings {
@Composable
private fun getForkSettingsGroup(readerPreferences: ReaderPreferences): Preference.PreferenceGroup {
val pageLayout by readerPreferences.pageLayout().collectAsState()
val pageLayout by readerPreferences.pageLayout.collectAsState()
return Preference.PreferenceGroup(
title = stringResource(SYMR.strings.pref_category_fork),
preferenceItems = persistentListOf(
Preference.PreferenceItem.SwitchPreference(
preference = readerPreferences.readerInstantRetry(),
preference = readerPreferences.readerInstantRetry,
title = stringResource(SYMR.strings.skip_queue_on_retry),
subtitle = stringResource(SYMR.strings.skip_queue_on_retry_summary),
),
Preference.PreferenceItem.SwitchPreference(
preference = readerPreferences.preserveReadingPosition(),
preference = readerPreferences.preserveReadingPosition,
title = stringResource(SYMR.strings.preserve_reading_position),
),
Preference.PreferenceItem.SwitchPreference(
preference = readerPreferences.useAutoWebtoon(),
preference = readerPreferences.useAutoWebtoon,
title = stringResource(SYMR.strings.auto_webtoon_mode),
subtitle = stringResource(SYMR.strings.auto_webtoon_mode_summary),
),
Preference.PreferenceItem.MultiSelectListPreference(
preference = readerPreferences.readerBottomButtons(),
preference = readerPreferences.readerBottomButtons,
title = stringResource(SYMR.strings.reader_bottom_buttons),
subtitle = stringResource(SYMR.strings.reader_bottom_buttons_summary),
entries = ReaderBottomButton.entries
@@ -600,21 +582,21 @@ object SettingsReaderScreen : SearchableSettings {
.toImmutableMap(),
),
Preference.PreferenceItem.ListPreference(
preference = readerPreferences.pageLayout(),
preference = readerPreferences.pageLayout,
title = stringResource(SYMR.strings.page_layout),
subtitle = stringResource(SYMR.strings.automatic_can_still_switch),
entries = ReaderPreferences.PageLayouts
.mapIndexed { index, it -> index + 1 to stringResource(it) }
.mapIndexed { index, it -> index to stringResource(it) }
.toMap()
.toImmutableMap(),
),
Preference.PreferenceItem.SwitchPreference(
preference = readerPreferences.invertDoublePages(),
preference = readerPreferences.invertDoublePages,
title = stringResource(SYMR.strings.invert_double_pages),
enabled = pageLayout != PagerConfig.PageLayout.SINGLE_PAGE,
),
Preference.PreferenceItem.ListPreference(
preference = readerPreferences.centerMarginType(),
preference = readerPreferences.centerMarginType,
title = stringResource(SYMR.strings.center_margin),
subtitle = stringResource(SYMR.strings.pref_center_margin_summary),
entries = ReaderPreferences.CenterMarginTypes
@@ -623,7 +605,7 @@ object SettingsReaderScreen : SearchableSettings {
.toImmutableMap(),
),
Preference.PreferenceItem.ListPreference(
preference = readerPreferences.archiveReaderMode(),
preference = readerPreferences.archiveReaderMode,
title = stringResource(SYMR.strings.pref_archive_reader_mode),
subtitle = stringResource(SYMR.strings.pref_archive_reader_mode_summary),
entries = ReaderPreferences.archiveModeTypes
@@ -183,7 +183,7 @@ private fun SearchResult(
emptySequence()
}
}
is Preference.PreferenceItem<*> -> sequenceOf(null to p)
is Preference.PreferenceItem<*, *> -> sequenceOf(null to p)
}
}
// Don't show info preference

Some files were not shown because too many files have changed in this diff Show More