Compare commits
150 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 759fd4d4e3 | |||
| fc956fc791 | |||
| 9d7346157b | |||
| 0f0f4cf4a9 | |||
| 426ef65102 | |||
| 95c834581b | |||
| 71f2daf8f3 | |||
| 7ec14cd9f0 | |||
| c23c9491fc | |||
| 29f3766c87 | |||
| 07c89890bc | |||
| 64a54f55b3 | |||
| f7202e67cc | |||
| 155b03c176 | |||
| 6b0482576b | |||
| c137bafd68 | |||
| 49bdffdc28 | |||
| f1b32d531a | |||
| a5ec6c5cdd | |||
| 9c56cdb1c1 | |||
| 543de065a6 | |||
| 33296e1faf | |||
| d1a90c0bb7 | |||
| 9fa61d33be | |||
| 0e9dcc7855 | |||
| 6738c6072d | |||
| 29033c539c | |||
| eaa3413c37 | |||
| 73d9d1d46d | |||
| 94f9aaf351 | |||
| e21149cb37 | |||
| 11aad16f59 | |||
| 33a3918e86 | |||
| d655b8ecdf | |||
| 70a8bef7a5 | |||
| 999a8613cf | |||
| 5721a02bca | |||
| e303b88b90 | |||
| a62dd5821a | |||
| a0786d9b09 | |||
| 04580ce357 | |||
| b759f2f02a | |||
| 8ae8068ecd | |||
| eecd9367d4 | |||
| 55dee69838 | |||
| a730ca5444 | |||
| cebd8fe0a8 | |||
| 55a979c5f7 | |||
| 728f3fc349 | |||
| a9a3ed1d16 | |||
| 36f13a7c6a | |||
| 37a2ccc678 | |||
| bb39088dd7 | |||
| c5546e1095 | |||
| 2d12c670db | |||
| 3db4bccebc | |||
| 2f23ad6bfd | |||
| de1898a2c9 | |||
| eb135ec22d | |||
| bf6c646dc7 | |||
| 9ce16d5e1c | |||
| 619ff726c8 | |||
| 730ceaaf49 | |||
| 07b701cb3c | |||
| b64c6b78ea | |||
| 521bce5c08 | |||
| a719ed8c9e | |||
| f6fc2d7e2f | |||
| 48d43c4f07 | |||
| f4fa86b2dc | |||
| 37db0dc1f6 | |||
| 1ada03b07a | |||
| f4c1e7c2d5 | |||
| 6c5282c598 | |||
| 7899474a36 | |||
| 225b419bba | |||
| fa64103a1c | |||
| 57e0e99f06 | |||
| efde7afa8e | |||
| f929a4bc26 | |||
| d35141c1cc | |||
| 6988966019 | |||
| f6d8ebbb0a | |||
| ae45df9fcf | |||
| f332344681 | |||
| c6abb340ca | |||
| 99dbb16a7a | |||
| f62e8933d7 | |||
| ee3c2fd79c | |||
| 6b08b873a8 | |||
| a3f2f49ab8 | |||
| 524f5cc6ab | |||
| a35e084b9e | |||
| 78f7fba67b | |||
| 69d1db3018 | |||
| d1b317e5c8 | |||
| fff40e031f | |||
| 5be2ec51ba | |||
| 1c2a7af13e | |||
| 182158acb0 | |||
| 21f92bfb3a | |||
| a5522ef732 | |||
| 239793f7fd | |||
| 4e9cfe4602 | |||
| f548c85e7a | |||
| 576349c446 | |||
| 9b00e0458b | |||
| 6a1ff99441 | |||
| 0121fe9397 | |||
| 5c47c7a409 | |||
| 8bb4f33f2e | |||
| 5f5fd51668 | |||
| c7bbad93b2 | |||
| 1a4a2506f4 | |||
| 7b7a594ddb | |||
| c2eece0fff | |||
| d29a4ff381 | |||
| 31f967235f | |||
| 7d6e746257 | |||
| d306139047 | |||
| 7e6811692e | |||
| 8df0446020 | |||
| 8ccf8fc74d | |||
| 4deaa41c53 | |||
| c843789f66 | |||
| 78da81fa42 | |||
| 4fc96f263d | |||
| 6a12b54ecb | |||
| 8ffcd5efec | |||
| 26121efeb4 | |||
| 1ecf3a567b | |||
| 20fff5798d | |||
| 0ba580ba30 | |||
| aaf28ee4f1 | |||
| 8558c110a9 | |||
| 3865583c28 | |||
| b2cc61f6fd | |||
| 47dd58de2a | |||
| 67d42c9c2b | |||
| b97f322d6f | |||
| d8cc4f8b45 | |||
| f78752fbdf | |||
| d968d58cd6 | |||
| 54d5f9baaf | |||
| c1bf53e28a | |||
| 517fd3a8f4 | |||
| 089d1aba57 | |||
| 46bf139f01 | |||
| c3fb5c0bec | |||
| 000a4ffc3f |
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||||
|
"extends": [
|
||||||
|
"config:base"
|
||||||
|
],
|
||||||
|
"labels": ["Dependencies"],
|
||||||
|
"includePaths": [".github/workflows/*", "gradle/sy.versions.toml"],
|
||||||
|
}
|
||||||
@@ -15,7 +15,7 @@ jobs:
|
|||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Validate Gradle Wrapper
|
- name: Validate Gradle Wrapper
|
||||||
uses: gradle/wrapper-validation-action@v1
|
uses: gradle/actions/wrapper-validation@v4
|
||||||
|
|
||||||
build:
|
build:
|
||||||
name: Build app
|
name: Build app
|
||||||
@@ -27,19 +27,19 @@ jobs:
|
|||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Set up JDK
|
- name: Set up JDK
|
||||||
uses: actions/setup-java@v3
|
uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
java-version: 17
|
java-version: 17
|
||||||
distribution: adopt
|
distribution: adopt
|
||||||
|
|
||||||
- name: Set up gradle
|
- name: Set up gradle
|
||||||
uses: gradle/actions/setup-gradle@v3
|
uses: gradle/actions/setup-gradle@v4
|
||||||
|
|
||||||
- name: Build app
|
- name: Build app
|
||||||
run: ./gradlew detekt assembleDevDebug
|
run: ./gradlew detekt assembleDevDebug
|
||||||
|
|
||||||
- name: Upload APK
|
- name: Upload APK
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: TachiyomiSY-${{ github.sha }}.apk
|
name: TachiyomiSY-${{ github.sha }}.apk
|
||||||
path: app/build/outputs/apk/dev/debug/app-dev-debug.apk
|
path: app/build/outputs/apk/dev/debug/app-dev-debug.apk
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ jobs:
|
|||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Validate Gradle Wrapper
|
- name: Validate Gradle Wrapper
|
||||||
uses: gradle/wrapper-validation-action@v2
|
uses: gradle/actions/wrapper-validation@v4
|
||||||
|
|
||||||
- name: Setup Android SDK
|
- name: Setup Android SDK
|
||||||
run: |
|
run: |
|
||||||
@@ -31,18 +31,18 @@ jobs:
|
|||||||
distribution: adopt
|
distribution: adopt
|
||||||
|
|
||||||
- name: Set up gradle
|
- name: Set up gradle
|
||||||
uses: gradle/actions/setup-gradle@v3
|
uses: gradle/actions/setup-gradle@v4
|
||||||
|
|
||||||
# SY <--
|
# SY <--
|
||||||
- name: Write google-services.json
|
- name: Write google-services.json
|
||||||
uses: DamianReeves/write-file-action@v1.2
|
uses: DamianReeves/write-file-action@v1.3
|
||||||
with:
|
with:
|
||||||
path: app/google-services.json
|
path: app/google-services.json
|
||||||
contents: ${{ secrets.GOOGLE_SERVICES_TEXT }}
|
contents: ${{ secrets.GOOGLE_SERVICES_TEXT }}
|
||||||
write-mode: overwrite
|
write-mode: overwrite
|
||||||
|
|
||||||
- name: Write client_secrets.json
|
- name: Write client_secrets.json
|
||||||
uses: DamianReeves/write-file-action@v1.2
|
uses: DamianReeves/write-file-action@v1.3
|
||||||
with:
|
with:
|
||||||
path: app/src/main/assets/client_secrets.json
|
path: app/src/main/assets/client_secrets.json
|
||||||
contents: ${{ secrets.CLIENT_SECRETS_TEXT }}
|
contents: ${{ secrets.CLIENT_SECRETS_TEXT }}
|
||||||
@@ -86,7 +86,7 @@ jobs:
|
|||||||
echo "APK_X86_64_SHA=$sha" >> $GITHUB_ENV
|
echo "APK_X86_64_SHA=$sha" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Create release
|
- name: Create release
|
||||||
uses: softprops/action-gh-release@v1
|
uses: softprops/action-gh-release@v2
|
||||||
with:
|
with:
|
||||||
tag_name: ${{ github.run_number }}
|
tag_name: ${{ github.run_number }}
|
||||||
name: TachiyomiSY
|
name: TachiyomiSY
|
||||||
|
|||||||
@@ -3,12 +3,11 @@ name: Remote Dispatch Action Initiator
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- 'master'
|
- 'preview'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
trigger_preview_build:
|
trigger_preview_build:
|
||||||
name: Trigger preview build
|
name: Trigger preview build
|
||||||
if: ${{ github.ref == 'refs/heads/master' }}
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
@@ -16,7 +15,7 @@ jobs:
|
|||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Validate Gradle Wrapper
|
- name: Validate Gradle Wrapper
|
||||||
uses: gradle/wrapper-validation-action@v1
|
uses: gradle/actions/wrapper-validation@v4
|
||||||
|
|
||||||
- name: Create Tag
|
- name: Create Tag
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
.gradle
|
.gradle
|
||||||
|
.kotlin
|
||||||
/local.properties
|
/local.properties
|
||||||
/.idea/workspace.xml
|
/.idea/workspace.xml
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|||||||
+1
-1
@@ -26,7 +26,7 @@ Before you start, please note that the ability to use following technologies is
|
|||||||
|
|
||||||
## Linting
|
## Linting
|
||||||
|
|
||||||
To auto-fix some linting errors, run the `ktlintFormat` Gradle task.
|
Run the `detekt` gradle task. If the build fails, a report of issues can be found in `app/build/reports/detekt/`. The report is availble in several formats and details each issue that needs attention.
|
||||||
|
|
||||||
## Getting help
|
## Getting help
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ Features of Mihon(original) include:
|
|||||||
* Online reading from a variety of sources
|
* Online reading from a variety of sources
|
||||||
* Local reading of downloaded content
|
* Local reading of downloaded content
|
||||||
* A configurable reader with multiple viewers, reading directions and other settings.
|
* A configurable reader with multiple viewers, reading directions and other settings.
|
||||||
* Tracker support: [MyAnimeList](https://myanimelist.net/), [AniList](https://anilist.co/), [Kitsu](https://kitsu.io/), [MangaUpdates](https://mangaupdates.com), [Shikimori](https://shikimori.one), and [Bangumi](https://bgm.tv/) support
|
* Tracker support: [MyAnimeList](https://myanimelist.net/), [AniList](https://anilist.co/), [Kitsu](https://kitsu.app/), [MangaUpdates](https://mangaupdates.com), [Shikimori](https://shikimori.one), and [Bangumi](https://bgm.tv/) support
|
||||||
* Categories to organize your library
|
* Categories to organize your library
|
||||||
* Light and dark themes
|
* Light and dark themes
|
||||||
* Schedule updating your library for new chapters
|
* Schedule updating your library for new chapters
|
||||||
@@ -67,6 +67,15 @@ Get the app from our [releases page](https://github.com/jobobby04/tachiyomisy/re
|
|||||||
|
|
||||||
If you want to try new features before they get to the stable release, you can download the preview version [here](https://github.com/jobobby04/tachiyomisypreview/releases).
|
If you want to try new features before they get to the stable release, you can download the preview version [here](https://github.com/jobobby04/tachiyomisypreview/releases).
|
||||||
|
|
||||||
|
## Translation
|
||||||
|
Feel free to translate the project on [Weblate](https://hosted.weblate.org/projects/mihon/tachiyomisy/)
|
||||||
|
|
||||||
|
<details><summary>Translation Progress</summary>
|
||||||
|
<a href="https://hosted.weblate.org/engage/mihon/">
|
||||||
|
<img src="https://hosted.weblate.org/widgets/mihon/-/tachiyomisy/multi-auto.svg" alt="Translation status" />
|
||||||
|
</a>
|
||||||
|
</details>
|
||||||
|
|
||||||
## Issues, Feature Requests and Contributing
|
## Issues, Feature Requests and Contributing
|
||||||
|
|
||||||
Please make sure to read the full guidelines. Your issue may be closed without warning if you do not.
|
Please make sure to read the full guidelines. Your issue may be closed without warning if you do not.
|
||||||
@@ -88,9 +97,7 @@ Please make sure to read the full guidelines. Your issue may be closed without w
|
|||||||
* If it could be device-dependent, try reproducing on another device (if possible)
|
* If it could be device-dependent, try reproducing on another device (if possible)
|
||||||
* Don't group unrelated requests into one issue
|
* Don't group unrelated requests into one issue
|
||||||
|
|
||||||
DO: https://github.com/tachiyomiorg/tachiyomi/issues/24 https://github.com/tachiyomiorg/tachiyomi/issues/71
|
Use the [issue forms](https://github.com/jobobby04/TachiyomiSY/issues/new/choose) to submit a bug.
|
||||||
|
|
||||||
DON'T: https://github.com/tachiyomiorg/tachiyomi/issues/75
|
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
|||||||
+9
-11
@@ -29,7 +29,7 @@ android {
|
|||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId = "eu.kanade.tachiyomi.sy"
|
applicationId = "eu.kanade.tachiyomi.sy"
|
||||||
|
|
||||||
versionCode = 67
|
versionCode = 69
|
||||||
versionName = "1.10.5"
|
versionName = "1.10.5"
|
||||||
|
|
||||||
buildConfigField("String", "COMMIT_COUNT", "\"${getCommitCount()}\"")
|
buildConfigField("String", "COMMIT_COUNT", "\"${getCommitCount()}\"")
|
||||||
@@ -155,7 +155,6 @@ dependencies {
|
|||||||
implementation(compose.activity)
|
implementation(compose.activity)
|
||||||
implementation(compose.foundation)
|
implementation(compose.foundation)
|
||||||
implementation(compose.material3.core)
|
implementation(compose.material3.core)
|
||||||
implementation(compose.material.core)
|
|
||||||
implementation(compose.material.icons)
|
implementation(compose.material.icons)
|
||||||
implementation(compose.animation)
|
implementation(compose.animation)
|
||||||
implementation(compose.animation.graphics)
|
implementation(compose.animation.graphics)
|
||||||
@@ -164,12 +163,14 @@ dependencies {
|
|||||||
implementation(compose.ui.util)
|
implementation(compose.ui.util)
|
||||||
implementation(compose.accompanist.systemuicontroller)
|
implementation(compose.accompanist.systemuicontroller)
|
||||||
|
|
||||||
|
implementation(androidx.interpolator)
|
||||||
|
|
||||||
implementation(androidx.paging.runtime)
|
implementation(androidx.paging.runtime)
|
||||||
implementation(androidx.paging.compose)
|
implementation(androidx.paging.compose)
|
||||||
|
|
||||||
implementation(libs.bundles.sqlite)
|
implementation(libs.bundles.sqlite)
|
||||||
// SY -->
|
// SY -->
|
||||||
implementation(libs.sqlcipher)
|
implementation(sylibs.sqlcipher)
|
||||||
// SY <--
|
// SY <--
|
||||||
|
|
||||||
implementation(kotlinx.reflect)
|
implementation(kotlinx.reflect)
|
||||||
@@ -211,10 +212,6 @@ dependencies {
|
|||||||
// Disk
|
// Disk
|
||||||
implementation(libs.disklrucache)
|
implementation(libs.disklrucache)
|
||||||
implementation(libs.unifile)
|
implementation(libs.unifile)
|
||||||
implementation(libs.bundles.archive)
|
|
||||||
// SY -->
|
|
||||||
implementation(libs.zip4j)
|
|
||||||
// SY <--
|
|
||||||
|
|
||||||
// Preferences
|
// Preferences
|
||||||
implementation(libs.preferencektx)
|
implementation(libs.preferencektx)
|
||||||
@@ -247,9 +244,6 @@ dependencies {
|
|||||||
implementation(libs.compose.grid)
|
implementation(libs.compose.grid)
|
||||||
|
|
||||||
|
|
||||||
implementation(libs.google.api.services.drive)
|
|
||||||
implementation(libs.google.api.client.oauth)
|
|
||||||
|
|
||||||
// Logging
|
// Logging
|
||||||
implementation(libs.logcat)
|
implementation(libs.logcat)
|
||||||
|
|
||||||
@@ -282,6 +276,10 @@ dependencies {
|
|||||||
// RatingBar (SY)
|
// RatingBar (SY)
|
||||||
implementation(sylibs.ratingbar)
|
implementation(sylibs.ratingbar)
|
||||||
implementation(sylibs.composeRatingbar)
|
implementation(sylibs.composeRatingbar)
|
||||||
|
|
||||||
|
// Google drive
|
||||||
|
implementation(sylibs.google.api.services.drive)
|
||||||
|
implementation(sylibs.google.api.client.oauth)
|
||||||
}
|
}
|
||||||
|
|
||||||
androidComponents {
|
androidComponents {
|
||||||
@@ -303,7 +301,7 @@ androidComponents {
|
|||||||
tasks {
|
tasks {
|
||||||
// See https://kotlinlang.org/docs/reference/experimental.html#experimental-status-of-experimental-api(-markers)
|
// See https://kotlinlang.org/docs/reference/experimental.html#experimental-status-of-experimental-api(-markers)
|
||||||
withType<KotlinCompile> {
|
withType<KotlinCompile> {
|
||||||
kotlinOptions.freeCompilerArgs += listOf(
|
compilerOptions.freeCompilerArgs.addAll(
|
||||||
"-Xcontext-receivers",
|
"-Xcontext-receivers",
|
||||||
"-opt-in=androidx.compose.foundation.layout.ExperimentalLayoutApi",
|
"-opt-in=androidx.compose.foundation.layout.ExperimentalLayoutApi",
|
||||||
"-opt-in=androidx.compose.material.ExperimentalMaterialApi",
|
"-opt-in=androidx.compose.material.ExperimentalMaterialApi",
|
||||||
|
|||||||
Vendored
+4
-3
@@ -47,6 +47,10 @@
|
|||||||
-dontnote rx.internal.util.PlatformDependent
|
-dontnote rx.internal.util.PlatformDependent
|
||||||
##---------------End: proguard configuration for RxJava 1.x ----------
|
##---------------End: proguard configuration for RxJava 1.x ----------
|
||||||
|
|
||||||
|
##---------------Begin: proguard configuration for okhttp ----------
|
||||||
|
-keepclasseswithmembers class okhttp3.MultipartBody$Builder { *; }
|
||||||
|
##---------------End: proguard configuration for okhttp ----------
|
||||||
|
|
||||||
##---------------Begin: proguard configuration for kotlinx.serialization ----------
|
##---------------Begin: proguard configuration for kotlinx.serialization ----------
|
||||||
-keepattributes *Annotation*, InnerClasses
|
-keepattributes *Annotation*, InnerClasses
|
||||||
-dontnote kotlinx.serialization.** # core serialization annotations
|
-dontnote kotlinx.serialization.** # core serialization annotations
|
||||||
@@ -123,9 +127,6 @@
|
|||||||
# XmlUtil
|
# XmlUtil
|
||||||
-keep public enum nl.adaptivity.xmlutil.EventType { *; }
|
-keep public enum nl.adaptivity.xmlutil.EventType { *; }
|
||||||
|
|
||||||
# Apache Commons Compress
|
|
||||||
-keep class * extends org.apache.commons.compress.archivers.zip.ZipExtraField { <init>(); }
|
|
||||||
|
|
||||||
# Firebase
|
# Firebase
|
||||||
-keep class com.google.firebase.installations.** { *; }
|
-keep class com.google.firebase.installations.** { *; }
|
||||||
-keep interface com.google.firebase.installations.** { *; }
|
-keep interface com.google.firebase.installations.** { *; }
|
||||||
|
|||||||
@@ -49,6 +49,11 @@ class SourcePreferences(
|
|||||||
emptySet(),
|
emptySet(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
fun globalSearchFilterState() = preferenceStore.getBoolean(
|
||||||
|
Preference.appStateKey("has_filters_toggle_state"),
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
|
||||||
// SY -->
|
// SY -->
|
||||||
fun enableSourceBlacklist() = preferenceStore.getBoolean("eh_enable_source_blacklist", true)
|
fun enableSourceBlacklist() = preferenceStore.getBoolean("eh_enable_source_blacklist", true)
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ class SyncPreferences(
|
|||||||
)
|
)
|
||||||
|
|
||||||
fun uniqueDeviceID(): String {
|
fun uniqueDeviceID(): String {
|
||||||
val uniqueIDPreference = preferenceStore.getString("unique_device_id", "")
|
val uniqueIDPreference = preferenceStore.getString(Preference.appStateKey("unique_device_id"), "")
|
||||||
|
|
||||||
// Retrieve the current value of the preference
|
// Retrieve the current value of the preference
|
||||||
var uniqueID = uniqueIDPreference.get()
|
var uniqueID = uniqueIDPreference.get()
|
||||||
@@ -53,12 +53,14 @@ class SyncPreferences(
|
|||||||
tracking = preferenceStore.getBoolean("tracking", true).get(),
|
tracking = preferenceStore.getBoolean("tracking", true).get(),
|
||||||
history = preferenceStore.getBoolean("history", true).get(),
|
history = preferenceStore.getBoolean("history", true).get(),
|
||||||
appSettings = preferenceStore.getBoolean("appSettings", true).get(),
|
appSettings = preferenceStore.getBoolean("appSettings", true).get(),
|
||||||
|
extensionRepoSettings = preferenceStore.getBoolean("extensionRepoSettings", true).get(),
|
||||||
sourceSettings = preferenceStore.getBoolean("sourceSettings", true).get(),
|
sourceSettings = preferenceStore.getBoolean("sourceSettings", true).get(),
|
||||||
privateSettings = preferenceStore.getBoolean("privateSettings", true).get(),
|
privateSettings = preferenceStore.getBoolean("privateSettings", true).get(),
|
||||||
|
|
||||||
// SY -->
|
// SY -->
|
||||||
customInfo = preferenceStore.getBoolean("customInfo", true).get(),
|
customInfo = preferenceStore.getBoolean("customInfo", true).get(),
|
||||||
readEntries = preferenceStore.getBoolean("readEntries", true).get()
|
readEntries = preferenceStore.getBoolean("readEntries", true).get(),
|
||||||
|
savedSearches = preferenceStore.getBoolean("savedSearches", true).get(),
|
||||||
// SY <--
|
// SY <--
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -70,12 +72,14 @@ class SyncPreferences(
|
|||||||
preferenceStore.getBoolean("tracking", true).set(syncSettings.tracking)
|
preferenceStore.getBoolean("tracking", true).set(syncSettings.tracking)
|
||||||
preferenceStore.getBoolean("history", true).set(syncSettings.history)
|
preferenceStore.getBoolean("history", true).set(syncSettings.history)
|
||||||
preferenceStore.getBoolean("appSettings", true).set(syncSettings.appSettings)
|
preferenceStore.getBoolean("appSettings", true).set(syncSettings.appSettings)
|
||||||
|
preferenceStore.getBoolean("extensionRepoSettings", true).set(syncSettings.extensionRepoSettings)
|
||||||
preferenceStore.getBoolean("sourceSettings", true).set(syncSettings.sourceSettings)
|
preferenceStore.getBoolean("sourceSettings", true).set(syncSettings.sourceSettings)
|
||||||
preferenceStore.getBoolean("privateSettings", true).set(syncSettings.privateSettings)
|
preferenceStore.getBoolean("privateSettings", true).set(syncSettings.privateSettings)
|
||||||
|
|
||||||
// SY -->
|
// SY -->
|
||||||
preferenceStore.getBoolean("customInfo", true).set(syncSettings.customInfo)
|
preferenceStore.getBoolean("customInfo", true).set(syncSettings.customInfo)
|
||||||
preferenceStore.getBoolean("readEntries", true).set(syncSettings.readEntries)
|
preferenceStore.getBoolean("readEntries", true).set(syncSettings.readEntries)
|
||||||
|
preferenceStore.getBoolean("savedSearches", true).set(syncSettings.savedSearches)
|
||||||
// SY <--
|
// SY <--
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,11 +7,13 @@ data class SyncSettings(
|
|||||||
val tracking: Boolean = true,
|
val tracking: Boolean = true,
|
||||||
val history: Boolean = true,
|
val history: Boolean = true,
|
||||||
val appSettings: Boolean = true,
|
val appSettings: Boolean = true,
|
||||||
|
val extensionRepoSettings: Boolean = true,
|
||||||
val sourceSettings: Boolean = true,
|
val sourceSettings: Boolean = true,
|
||||||
val privateSettings: Boolean = false,
|
val privateSettings: Boolean = false,
|
||||||
|
|
||||||
// SY -->
|
// SY -->
|
||||||
val customInfo: Boolean = true,
|
val customInfo: Boolean = true,
|
||||||
val readEntries: Boolean = true
|
val readEntries: Boolean = true,
|
||||||
|
val savedSearches: Boolean = true,
|
||||||
// SY <--
|
// SY <--
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -198,7 +198,7 @@ private fun ExtensionDetails(
|
|||||||
key = { it.source.id },
|
key = { it.source.id },
|
||||||
) { source ->
|
) { source ->
|
||||||
SourceSwitchPreference(
|
SourceSwitchPreference(
|
||||||
modifier = Modifier.animateItem(),
|
modifier = Modifier.animateItemPlacement(),
|
||||||
source = source,
|
source = source,
|
||||||
onClickSourcePreferences = onClickSourcePreferences,
|
onClickSourcePreferences = onClickSourcePreferences,
|
||||||
onClickSource = onClickSource,
|
onClickSource = onClickSource,
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ private fun ExtensionFilterContent(
|
|||||||
) {
|
) {
|
||||||
items(state.languages) { language ->
|
items(state.languages) { language ->
|
||||||
SwitchPreferenceWidget(
|
SwitchPreferenceWidget(
|
||||||
modifier = Modifier.animateItem(),
|
modifier = Modifier.animateItemPlacement(),
|
||||||
title = LocaleHelper.getSourceDisplayName(language, context),
|
title = LocaleHelper.getSourceDisplayName(language, context),
|
||||||
checked = language in state.enabledLanguages,
|
checked = language in state.enabledLanguages,
|
||||||
onCheckedChanged = { onClickLang(language) },
|
onCheckedChanged = { onClickLang(language) },
|
||||||
|
|||||||
@@ -188,14 +188,14 @@ private fun ExtensionContent(
|
|||||||
}
|
}
|
||||||
ExtensionHeader(
|
ExtensionHeader(
|
||||||
textRes = header.textRes,
|
textRes = header.textRes,
|
||||||
modifier = Modifier.animateItem(),
|
modifier = Modifier.animateItemPlacement(),
|
||||||
action = action,
|
action = action,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
is ExtensionUiModel.Header.Text -> {
|
is ExtensionUiModel.Header.Text -> {
|
||||||
ExtensionHeader(
|
ExtensionHeader(
|
||||||
text = header.text,
|
text = header.text,
|
||||||
modifier = Modifier.animateItem(),
|
modifier = Modifier.animateItemPlacement(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -213,7 +213,7 @@ private fun ExtensionContent(
|
|||||||
},
|
},
|
||||||
) { item ->
|
) { item ->
|
||||||
ExtensionItem(
|
ExtensionItem(
|
||||||
modifier = Modifier.animateItem(),
|
modifier = Modifier.animateItemPlacement(),
|
||||||
item = item,
|
item = item,
|
||||||
onClickItem = {
|
onClickItem = {
|
||||||
when (it) {
|
when (it) {
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ fun FeedScreen(
|
|||||||
key = { it.feed.id },
|
key = { it.feed.id },
|
||||||
) { item ->
|
) { item ->
|
||||||
GlobalSearchResultItem(
|
GlobalSearchResultItem(
|
||||||
modifier = Modifier.animateItem(),
|
modifier = Modifier.animateItemPlacement(),
|
||||||
title = item.title,
|
title = item.title,
|
||||||
subtitle = item.subtitle,
|
subtitle = item.subtitle,
|
||||||
onLongClick = {
|
onLongClick = {
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import androidx.compose.foundation.layout.PaddingValues
|
|||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.State
|
import androidx.compose.runtime.State
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import eu.kanade.presentation.browse.components.GlobalSearchCardRow
|
import eu.kanade.presentation.browse.components.GlobalSearchCardRow
|
||||||
import eu.kanade.presentation.browse.components.GlobalSearchErrorResultItem
|
import eu.kanade.presentation.browse.components.GlobalSearchErrorResultItem
|
||||||
import eu.kanade.presentation.browse.components.GlobalSearchLoadingResultItem
|
import eu.kanade.presentation.browse.components.GlobalSearchLoadingResultItem
|
||||||
@@ -81,7 +80,6 @@ internal fun GlobalSearchContent(
|
|||||||
} ?: source.name,
|
} ?: source.name,
|
||||||
subtitle = LocaleHelper.getLocalizedDisplayName(source.lang),
|
subtitle = LocaleHelper.getLocalizedDisplayName(source.lang),
|
||||||
onClick = { onClickSource(source) },
|
onClick = { onClickSource(source) },
|
||||||
modifier = Modifier.animateItem(),
|
|
||||||
) {
|
) {
|
||||||
when (result) {
|
when (result) {
|
||||||
SearchItemResult.Loading -> {
|
SearchItemResult.Loading -> {
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ private fun MigrateSourceList(
|
|||||||
key = { (source, _) -> "migrate-${source.id}" },
|
key = { (source, _) -> "migrate-${source.id}" },
|
||||||
) { (source, count) ->
|
) { (source, count) ->
|
||||||
MigrateSourceItem(
|
MigrateSourceItem(
|
||||||
modifier = Modifier.animateItem(),
|
modifier = Modifier.animateItemPlacement(),
|
||||||
source = source,
|
source = source,
|
||||||
count = count,
|
count = count,
|
||||||
onClickItem = { onClickItem(source) },
|
onClickItem = { onClickItem(source) },
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import androidx.compose.foundation.layout.padding
|
|||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.automirrored.outlined.ArrowForward
|
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.ContentCopy
|
||||||
import androidx.compose.material.icons.outlined.CopyAll
|
import androidx.compose.material.icons.outlined.CopyAll
|
||||||
import androidx.compose.material.icons.outlined.Done
|
import androidx.compose.material.icons.outlined.Done
|
||||||
@@ -94,7 +95,7 @@ fun MigrationListScreen(
|
|||||||
Row(
|
Row(
|
||||||
Modifier
|
Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.animateItem()
|
.animateItemPlacement()
|
||||||
.padding(horizontal = 16.dp)
|
.padding(horizontal = 16.dp)
|
||||||
.height(IntrinsicSize.Min),
|
.height(IntrinsicSize.Min),
|
||||||
horizontalArrangement = Arrangement.SpaceBetween,
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
|
|||||||
@@ -153,7 +153,7 @@ fun SourceFeedList(
|
|||||||
key = { it.id },
|
key = { it.id },
|
||||||
) { item ->
|
) { item ->
|
||||||
GlobalSearchResultItem(
|
GlobalSearchResultItem(
|
||||||
modifier = Modifier.animateItem(),
|
modifier = Modifier.animateItemPlacement(),
|
||||||
title = item.title,
|
title = item.title,
|
||||||
subtitle = null,
|
subtitle = null,
|
||||||
onLongClick = if (item is SourceFeedUI.SourceSavedSearch) {
|
onLongClick = if (item is SourceFeedUI.SourceSavedSearch) {
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ private fun SourcesFilterContent(
|
|||||||
contentType = "source-filter-header",
|
contentType = "source-filter-header",
|
||||||
) {
|
) {
|
||||||
SourcesFilterHeader(
|
SourcesFilterHeader(
|
||||||
modifier = Modifier.animateItem(),
|
modifier = Modifier.animateItemPlacement(),
|
||||||
language = language,
|
language = language,
|
||||||
enabled = enabled,
|
enabled = enabled,
|
||||||
onClickItem = onClickLanguage,
|
onClickItem = onClickLanguage,
|
||||||
@@ -95,7 +95,7 @@ private fun SourcesFilterContent(
|
|||||||
sources.none { it.id.toString() in state.disabledSources }
|
sources.none { it.id.toString() in state.disabledSources }
|
||||||
}
|
}
|
||||||
SourcesFilterToggle(
|
SourcesFilterToggle(
|
||||||
modifier = Modifier.animateItem(),
|
modifier = Modifier.animateItemPlacement(),
|
||||||
isEnabled = toggleEnabled,
|
isEnabled = toggleEnabled,
|
||||||
onClickItem = {
|
onClickItem = {
|
||||||
onClickSources(!toggleEnabled, sources)
|
onClickSources(!toggleEnabled, sources)
|
||||||
@@ -109,7 +109,7 @@ private fun SourcesFilterContent(
|
|||||||
contentType = { "source-filter-item" },
|
contentType = { "source-filter-item" },
|
||||||
) { source ->
|
) { source ->
|
||||||
SourcesFilterItem(
|
SourcesFilterItem(
|
||||||
modifier = Modifier.animateItem(),
|
modifier = Modifier.animateItemPlacement(),
|
||||||
source = source,
|
source = source,
|
||||||
enabled = "${source.id}" !in state.disabledSources,
|
enabled = "${source.id}" !in state.disabledSources,
|
||||||
onClickItem = onClickSource,
|
onClickItem = onClickSource,
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ fun SourcesScreen(
|
|||||||
when (model) {
|
when (model) {
|
||||||
is SourceUiModel.Header -> {
|
is SourceUiModel.Header -> {
|
||||||
SourceHeader(
|
SourceHeader(
|
||||||
modifier = Modifier.animateItem(),
|
modifier = Modifier.animateItemPlacement(),
|
||||||
language = model.language,
|
language = model.language,
|
||||||
// SY -->
|
// SY -->
|
||||||
isCategory = model.isCategory,
|
isCategory = model.isCategory,
|
||||||
@@ -89,7 +89,7 @@ fun SourcesScreen(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
is SourceUiModel.Item -> SourceItem(
|
is SourceUiModel.Item -> SourceItem(
|
||||||
modifier = Modifier.animateItem(),
|
modifier = Modifier.animateItemPlacement(),
|
||||||
source = model.source,
|
source = model.source,
|
||||||
// SY -->
|
// SY -->
|
||||||
showLatest = state.showLatest,
|
showLatest = state.showLatest,
|
||||||
|
|||||||
+4
-2
@@ -30,6 +30,9 @@ import tachiyomi.presentation.core.i18n.stringResource
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun GlobalSearchResultItem(
|
fun GlobalSearchResultItem(
|
||||||
|
// SY -->
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
// SY <--
|
||||||
title: String,
|
title: String,
|
||||||
// SY -->
|
// SY -->
|
||||||
subtitle: String?,
|
subtitle: String?,
|
||||||
@@ -38,10 +41,9 @@ fun GlobalSearchResultItem(
|
|||||||
// SY -->
|
// SY -->
|
||||||
onLongClick: (() -> Unit)? = null,
|
onLongClick: (() -> Unit)? = null,
|
||||||
// SY <--
|
// SY <--
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
content: @Composable () -> Unit,
|
content: @Composable () -> Unit,
|
||||||
) {
|
) {
|
||||||
Column(modifier = modifier) {
|
Column(modifier) {
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(
|
.padding(
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ private fun CategoryContent(
|
|||||||
key = { _, category -> "category-${category.id}" },
|
key = { _, category -> "category-${category.id}" },
|
||||||
) { index, category ->
|
) { index, category ->
|
||||||
CategoryListItem(
|
CategoryListItem(
|
||||||
modifier = Modifier.animateItem(),
|
modifier = Modifier.animateItemPlacement(),
|
||||||
category = category,
|
category = category,
|
||||||
canMoveUp = index != 0,
|
canMoveUp = index != 0,
|
||||||
canMoveDown = index != categories.lastIndex,
|
canMoveDown = index != categories.lastIndex,
|
||||||
|
|||||||
+3
-2
@@ -10,7 +10,8 @@ import androidx.compose.ui.Modifier
|
|||||||
import tachiyomi.i18n.MR
|
import tachiyomi.i18n.MR
|
||||||
import tachiyomi.presentation.core.components.material.ExtendedFloatingActionButton
|
import tachiyomi.presentation.core.components.material.ExtendedFloatingActionButton
|
||||||
import tachiyomi.presentation.core.i18n.stringResource
|
import tachiyomi.presentation.core.i18n.stringResource
|
||||||
import tachiyomi.presentation.core.util.shouldExpandFAB
|
import tachiyomi.presentation.core.util.isScrolledToEnd
|
||||||
|
import tachiyomi.presentation.core.util.isScrollingUp
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun CategoryFloatingActionButton(
|
fun CategoryFloatingActionButton(
|
||||||
@@ -22,7 +23,7 @@ fun CategoryFloatingActionButton(
|
|||||||
text = { Text(text = stringResource(MR.strings.action_add)) },
|
text = { Text(text = stringResource(MR.strings.action_add)) },
|
||||||
icon = { Icon(imageVector = Icons.Outlined.Add, contentDescription = null) },
|
icon = { Icon(imageVector = Icons.Outlined.Add, contentDescription = null) },
|
||||||
onClick = onCreate,
|
onClick = onCreate,
|
||||||
expanded = lazyListState.shouldExpandFAB(),
|
expanded = lazyListState.isScrollingUp() || lazyListState.isScrolledToEnd(),
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -26,7 +26,7 @@ fun BiometricTimesContent(
|
|||||||
) {
|
) {
|
||||||
items(timeRanges, key = { it.formattedString }) { timeRange ->
|
items(timeRanges, key = { it.formattedString }) { timeRange ->
|
||||||
BiometricTimesListItem(
|
BiometricTimesListItem(
|
||||||
modifier = Modifier.animateItem(),
|
modifier = Modifier.animateItemPlacement(),
|
||||||
timeRange = timeRange,
|
timeRange = timeRange,
|
||||||
onDelete = { onClickDelete(timeRange) },
|
onDelete = { onClickDelete(timeRange) },
|
||||||
)
|
)
|
||||||
|
|||||||
+1
-1
@@ -27,7 +27,7 @@ fun SortTagContent(
|
|||||||
) {
|
) {
|
||||||
itemsIndexed(tags, key = { _, tag -> tag }) { index, tag ->
|
itemsIndexed(tags, key = { _, tag -> tag }) { index, tag ->
|
||||||
SortTagListItem(
|
SortTagListItem(
|
||||||
modifier = Modifier.animateItem(),
|
modifier = Modifier.animateItemPlacement(),
|
||||||
tag = tag,
|
tag = tag,
|
||||||
canMoveUp = index != 0,
|
canMoveUp = index != 0,
|
||||||
canMoveDown = index != tags.lastIndex,
|
canMoveDown = index != tags.lastIndex,
|
||||||
|
|||||||
+1
-1
@@ -26,7 +26,7 @@ fun SourceCategoryContent(
|
|||||||
) {
|
) {
|
||||||
items(categories, key = { it }) { category ->
|
items(categories, key = { it }) { category ->
|
||||||
SourceCategoryListItem(
|
SourceCategoryListItem(
|
||||||
modifier = Modifier.animateItem(),
|
modifier = Modifier.animateItemPlacement(),
|
||||||
category = category,
|
category = category,
|
||||||
onRename = { onClickRename(category) },
|
onRename = { onClickRename(category) },
|
||||||
onDelete = { onClickDelete(category) },
|
onDelete = { onClickDelete(category) },
|
||||||
|
|||||||
@@ -7,8 +7,6 @@ import androidx.compose.animation.fadeOut
|
|||||||
import androidx.compose.animation.togetherWith
|
import androidx.compose.animation.togetherWith
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.unit.Dp
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import androidx.compose.ui.window.Dialog
|
import androidx.compose.ui.window.Dialog
|
||||||
import androidx.compose.ui.window.DialogProperties
|
import androidx.compose.ui.window.DialogProperties
|
||||||
import cafe.adriel.voyager.core.annotation.InternalVoyagerApi
|
import cafe.adriel.voyager.core.annotation.InternalVoyagerApi
|
||||||
@@ -23,7 +21,6 @@ import tachiyomi.presentation.core.components.AdaptiveSheet as AdaptiveSheetImpl
|
|||||||
@Composable
|
@Composable
|
||||||
fun NavigatorAdaptiveSheet(
|
fun NavigatorAdaptiveSheet(
|
||||||
screen: Screen,
|
screen: Screen,
|
||||||
tonalElevation: Dp = 1.dp,
|
|
||||||
enableSwipeDismiss: (Navigator) -> Boolean = { true },
|
enableSwipeDismiss: (Navigator) -> Boolean = { true },
|
||||||
onDismissRequest: () -> Unit,
|
onDismissRequest: () -> Unit,
|
||||||
) {
|
) {
|
||||||
@@ -31,7 +28,6 @@ fun NavigatorAdaptiveSheet(
|
|||||||
screen = screen,
|
screen = screen,
|
||||||
content = { sheetNavigator ->
|
content = { sheetNavigator ->
|
||||||
AdaptiveSheet(
|
AdaptiveSheet(
|
||||||
tonalElevation = tonalElevation,
|
|
||||||
enableSwipeDismiss = enableSwipeDismiss(sheetNavigator),
|
enableSwipeDismiss = enableSwipeDismiss(sheetNavigator),
|
||||||
onDismissRequest = onDismissRequest,
|
onDismissRequest = onDismissRequest,
|
||||||
) {
|
) {
|
||||||
@@ -73,7 +69,6 @@ fun NavigatorAdaptiveSheet(
|
|||||||
fun AdaptiveSheet(
|
fun AdaptiveSheet(
|
||||||
onDismissRequest: () -> Unit,
|
onDismissRequest: () -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
tonalElevation: Dp = 1.dp,
|
|
||||||
enableSwipeDismiss: Boolean = true,
|
enableSwipeDismiss: Boolean = true,
|
||||||
content: @Composable () -> Unit,
|
content: @Composable () -> Unit,
|
||||||
) {
|
) {
|
||||||
@@ -86,7 +81,6 @@ fun AdaptiveSheet(
|
|||||||
AdaptiveSheetImpl(
|
AdaptiveSheetImpl(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
isTabletUi = isTabletUi,
|
isTabletUi = isTabletUi,
|
||||||
tonalElevation = tonalElevation,
|
|
||||||
enableSwipeDismiss = enableSwipeDismiss,
|
enableSwipeDismiss = enableSwipeDismiss,
|
||||||
onDismissRequest = onDismissRequest,
|
onDismissRequest = onDismissRequest,
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
|||||||
import androidx.compose.foundation.text.BasicTextField
|
import androidx.compose.foundation.text.BasicTextField
|
||||||
import androidx.compose.foundation.text.KeyboardActions
|
import androidx.compose.foundation.text.KeyboardActions
|
||||||
import androidx.compose.foundation.text.KeyboardOptions
|
import androidx.compose.foundation.text.KeyboardOptions
|
||||||
import androidx.compose.material.TextFieldDefaults
|
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.automirrored.outlined.ArrowBack
|
import androidx.compose.material.icons.automirrored.outlined.ArrowBack
|
||||||
import androidx.compose.material.icons.outlined.Close
|
import androidx.compose.material.icons.outlined.Close
|
||||||
@@ -21,6 +20,7 @@ import androidx.compose.material3.LocalContentColor
|
|||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.PlainTooltip
|
import androidx.compose.material3.PlainTooltip
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TextFieldDefaults
|
||||||
import androidx.compose.material3.TooltipBox
|
import androidx.compose.material3.TooltipBox
|
||||||
import androidx.compose.material3.TooltipDefaults
|
import androidx.compose.material3.TooltipDefaults
|
||||||
import androidx.compose.material3.TopAppBar
|
import androidx.compose.material3.TopAppBar
|
||||||
@@ -312,7 +312,7 @@ fun SearchToolbar(
|
|||||||
visualTransformation = visualTransformation,
|
visualTransformation = visualTransformation,
|
||||||
interactionSource = interactionSource,
|
interactionSource = interactionSource,
|
||||||
decorationBox = { innerTextField ->
|
decorationBox = { innerTextField ->
|
||||||
TextFieldDefaults.TextFieldDecorationBox(
|
TextFieldDefaults.DecorationBox(
|
||||||
value = searchQuery,
|
value = searchQuery,
|
||||||
innerTextField = innerTextField,
|
innerTextField = innerTextField,
|
||||||
enabled = true,
|
enabled = true,
|
||||||
@@ -331,6 +331,7 @@ fun SearchToolbar(
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
container = {},
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ fun TabbedDialog(
|
|||||||
PrimaryTabRow(
|
PrimaryTabRow(
|
||||||
modifier = Modifier.weight(1f),
|
modifier = Modifier.weight(1f),
|
||||||
selectedTabIndex = pagerState.currentPage,
|
selectedTabIndex = pagerState.currentPage,
|
||||||
|
containerColor = MaterialTheme.colorScheme.surfaceContainerHigh,
|
||||||
divider = {},
|
divider = {},
|
||||||
) {
|
) {
|
||||||
tabTitles.fastForEachIndexed { index, tab ->
|
tabTitles.fastForEachIndexed { index, tab ->
|
||||||
|
|||||||
@@ -114,14 +114,14 @@ private fun HistoryScreenContent(
|
|||||||
when (item) {
|
when (item) {
|
||||||
is HistoryUiModel.Header -> {
|
is HistoryUiModel.Header -> {
|
||||||
ListGroupHeader(
|
ListGroupHeader(
|
||||||
modifier = Modifier.animateItem(),
|
modifier = Modifier.animateItemPlacement(),
|
||||||
text = relativeDateText(item.date),
|
text = relativeDateText(item.date),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
is HistoryUiModel.Item -> {
|
is HistoryUiModel.Item -> {
|
||||||
val value = item.item
|
val value = item.item
|
||||||
HistoryItem(
|
HistoryItem(
|
||||||
modifier = Modifier.animateItem(),
|
modifier = Modifier.animateItemPlacement(),
|
||||||
history = value,
|
history = value,
|
||||||
onClickCover = { onClickCover(value) },
|
onClickCover = { onClickCover(value) },
|
||||||
onClickResume = { onClickResume(value) },
|
onClickResume = { onClickResume(value) },
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ private fun ColumnScope.FilterPage(
|
|||||||
)
|
)
|
||||||
// SY <--
|
// SY <--
|
||||||
|
|
||||||
val trackers = remember { screenModel.trackers }
|
val trackers by screenModel.trackersFlow.collectAsState()
|
||||||
when (trackers.size) {
|
when (trackers.size) {
|
||||||
0 -> {
|
0 -> {
|
||||||
// No trackers
|
// No trackers
|
||||||
@@ -188,6 +188,7 @@ private fun ColumnScope.SortPage(
|
|||||||
category: Category?,
|
category: Category?,
|
||||||
screenModel: LibrarySettingsScreenModel,
|
screenModel: LibrarySettingsScreenModel,
|
||||||
) {
|
) {
|
||||||
|
val trackers by screenModel.trackersFlow.collectAsState()
|
||||||
// SY -->
|
// SY -->
|
||||||
val globalSortMode by screenModel.libraryPreferences.sortingMode().collectAsState()
|
val globalSortMode by screenModel.libraryPreferences.sortingMode().collectAsState()
|
||||||
val sortingMode = if (screenModel.grouping == LibraryGroup.BY_DEFAULT) {
|
val sortingMode = if (screenModel.grouping == LibraryGroup.BY_DEFAULT) {
|
||||||
@@ -206,12 +207,12 @@ private fun ColumnScope.SortPage(
|
|||||||
}.collectAsState(initial = screenModel.libraryPreferences.sortTagsForLibrary().get().isNotEmpty())
|
}.collectAsState(initial = screenModel.libraryPreferences.sortTagsForLibrary().get().isNotEmpty())
|
||||||
// SY <--
|
// SY <--
|
||||||
|
|
||||||
val trackerSortOption =
|
|
||||||
if (screenModel.trackers.isEmpty()) {
|
val trackerSortOption = if (trackers.isEmpty()) {
|
||||||
emptyList()
|
emptyList()
|
||||||
} else {
|
} else {
|
||||||
listOf(MR.strings.action_sort_tracker_score to LibrarySort.Type.TrackerMean)
|
listOf(MR.strings.action_sort_tracker_score to LibrarySort.Type.TrackerMean)
|
||||||
}
|
}
|
||||||
|
|
||||||
listOfNotNull(
|
listOfNotNull(
|
||||||
MR.strings.action_sort_alpha to LibrarySort.Type.Alphabetical,
|
MR.strings.action_sort_alpha to LibrarySort.Type.Alphabetical,
|
||||||
@@ -346,12 +347,13 @@ private fun ColumnScope.GroupPage(
|
|||||||
screenModel: LibrarySettingsScreenModel,
|
screenModel: LibrarySettingsScreenModel,
|
||||||
hasCategories: Boolean,
|
hasCategories: Boolean,
|
||||||
) {
|
) {
|
||||||
val groups = remember(hasCategories, screenModel.trackers) {
|
val trackers by screenModel.trackersFlow.collectAsState()
|
||||||
|
val groups = remember(hasCategories, trackers) {
|
||||||
buildList {
|
buildList {
|
||||||
add(LibraryGroup.BY_DEFAULT)
|
add(LibraryGroup.BY_DEFAULT)
|
||||||
add(LibraryGroup.BY_SOURCE)
|
add(LibraryGroup.BY_SOURCE)
|
||||||
add(LibraryGroup.BY_STATUS)
|
add(LibraryGroup.BY_STATUS)
|
||||||
if (screenModel.trackers.isNotEmpty()) {
|
if (trackers.isNotEmpty()) {
|
||||||
add(LibraryGroup.BY_TRACK_STATUS)
|
add(LibraryGroup.BY_TRACK_STATUS)
|
||||||
}
|
}
|
||||||
if (hasCategories) {
|
if (hasCategories) {
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import androidx.compose.ui.graphics.Color
|
|||||||
import androidx.compose.ui.graphics.Shadow
|
import androidx.compose.ui.graphics.Shadow
|
||||||
import androidx.compose.ui.text.TextStyle
|
import androidx.compose.ui.text.TextStyle
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
|
import androidx.compose.ui.unit.Dp
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import eu.kanade.presentation.manga.components.MangaCover
|
import eu.kanade.presentation.manga.components.MangaCover
|
||||||
@@ -42,15 +43,22 @@ import tachiyomi.i18n.MR
|
|||||||
import tachiyomi.presentation.core.components.BadgeGroup
|
import tachiyomi.presentation.core.components.BadgeGroup
|
||||||
import tachiyomi.presentation.core.i18n.stringResource
|
import tachiyomi.presentation.core.i18n.stringResource
|
||||||
import tachiyomi.presentation.core.util.selectedBackground
|
import tachiyomi.presentation.core.util.selectedBackground
|
||||||
|
import tachiyomi.domain.manga.model.MangaCover as MangaCoverModel
|
||||||
|
|
||||||
object CommonMangaItemDefaults {
|
object CommonMangaItemDefaults {
|
||||||
val GridHorizontalSpacer = 4.dp
|
val GridHorizontalSpacer = 4.dp
|
||||||
val GridVerticalSpacer = 4.dp
|
val GridVerticalSpacer = 4.dp
|
||||||
|
|
||||||
|
@Suppress("ConstPropertyName")
|
||||||
const val BrowseFavoriteCoverAlpha = 0.34f
|
const val BrowseFavoriteCoverAlpha = 0.34f
|
||||||
}
|
}
|
||||||
|
|
||||||
private val ContinueReadingButtonSize = 28.dp
|
private val ContinueReadingButtonSizeSmall = 28.dp
|
||||||
|
private val ContinueReadingButtonSizeLarge = 32.dp
|
||||||
|
|
||||||
|
private val ContinueReadingButtonIconSizeSmall = 16.dp
|
||||||
|
private val ContinueReadingButtonIconSizeLarge = 20.dp
|
||||||
|
|
||||||
private val ContinueReadingButtonGridPadding = 6.dp
|
private val ContinueReadingButtonGridPadding = 6.dp
|
||||||
private val ContinueReadingButtonListSpacing = 8.dp
|
private val ContinueReadingButtonListSpacing = 8.dp
|
||||||
|
|
||||||
@@ -62,7 +70,7 @@ private const val GridSelectedCoverAlpha = 0.76f
|
|||||||
*/
|
*/
|
||||||
@Composable
|
@Composable
|
||||||
fun MangaCompactGridItem(
|
fun MangaCompactGridItem(
|
||||||
coverData: tachiyomi.domain.manga.model.MangaCover,
|
coverData: MangaCoverModel,
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
onLongClick: () -> Unit,
|
onLongClick: () -> Unit,
|
||||||
isSelected: Boolean = false,
|
isSelected: Boolean = false,
|
||||||
@@ -96,10 +104,12 @@ fun MangaCompactGridItem(
|
|||||||
)
|
)
|
||||||
} else if (onClickContinueReading != null) {
|
} else if (onClickContinueReading != null) {
|
||||||
ContinueReadingButton(
|
ContinueReadingButton(
|
||||||
|
size = ContinueReadingButtonSizeLarge,
|
||||||
|
iconSize = ContinueReadingButtonIconSizeLarge,
|
||||||
|
onClick = onClickContinueReading,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(ContinueReadingButtonGridPadding)
|
.padding(ContinueReadingButtonGridPadding)
|
||||||
.align(Alignment.BottomEnd),
|
.align(Alignment.BottomEnd),
|
||||||
onClickContinueReading = onClickContinueReading,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -148,11 +158,13 @@ private fun BoxScope.CoverTextOverlay(
|
|||||||
)
|
)
|
||||||
if (onClickContinueReading != null) {
|
if (onClickContinueReading != null) {
|
||||||
ContinueReadingButton(
|
ContinueReadingButton(
|
||||||
|
size = ContinueReadingButtonSizeSmall,
|
||||||
|
iconSize = ContinueReadingButtonIconSizeSmall,
|
||||||
|
onClick = onClickContinueReading,
|
||||||
modifier = Modifier.padding(
|
modifier = Modifier.padding(
|
||||||
end = ContinueReadingButtonGridPadding,
|
end = ContinueReadingButtonGridPadding,
|
||||||
bottom = ContinueReadingButtonGridPadding,
|
bottom = ContinueReadingButtonGridPadding,
|
||||||
),
|
),
|
||||||
onClickContinueReading = onClickContinueReading,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -163,7 +175,7 @@ private fun BoxScope.CoverTextOverlay(
|
|||||||
*/
|
*/
|
||||||
@Composable
|
@Composable
|
||||||
fun MangaComfortableGridItem(
|
fun MangaComfortableGridItem(
|
||||||
coverData: tachiyomi.domain.manga.model.MangaCover,
|
coverData: MangaCoverModel,
|
||||||
title: String,
|
title: String,
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
onLongClick: () -> Unit,
|
onLongClick: () -> Unit,
|
||||||
@@ -194,10 +206,12 @@ fun MangaComfortableGridItem(
|
|||||||
content = {
|
content = {
|
||||||
if (onClickContinueReading != null) {
|
if (onClickContinueReading != null) {
|
||||||
ContinueReadingButton(
|
ContinueReadingButton(
|
||||||
|
size = ContinueReadingButtonSizeLarge,
|
||||||
|
iconSize = ContinueReadingButtonIconSizeLarge,
|
||||||
|
onClick = onClickContinueReading,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(ContinueReadingButtonGridPadding)
|
.padding(ContinueReadingButtonGridPadding)
|
||||||
.align(Alignment.BottomEnd),
|
.align(Alignment.BottomEnd),
|
||||||
onClickContinueReading = onClickContinueReading,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -309,14 +323,14 @@ private fun GridItemSelectable(
|
|||||||
private fun Modifier.selectedOutline(
|
private fun Modifier.selectedOutline(
|
||||||
isSelected: Boolean,
|
isSelected: Boolean,
|
||||||
color: Color,
|
color: Color,
|
||||||
) = this then drawBehind { if (isSelected) drawRect(color = color) }
|
) = drawBehind { if (isSelected) drawRect(color = color) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Layout of list item.
|
* Layout of list item.
|
||||||
*/
|
*/
|
||||||
@Composable
|
@Composable
|
||||||
fun MangaListItem(
|
fun MangaListItem(
|
||||||
coverData: tachiyomi.domain.manga.model.MangaCover,
|
coverData: MangaCoverModel,
|
||||||
title: String,
|
title: String,
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
onLongClick: () -> Unit,
|
onLongClick: () -> Unit,
|
||||||
@@ -354,8 +368,10 @@ fun MangaListItem(
|
|||||||
BadgeGroup(content = badge)
|
BadgeGroup(content = badge)
|
||||||
if (onClickContinueReading != null) {
|
if (onClickContinueReading != null) {
|
||||||
ContinueReadingButton(
|
ContinueReadingButton(
|
||||||
modifier = Modifier.padding(start = ContinueReadingButtonListSpacing),
|
size = ContinueReadingButtonSizeSmall,
|
||||||
onClickContinueReading = onClickContinueReading,
|
iconSize = ContinueReadingButtonIconSizeSmall,
|
||||||
|
onClick = onClickContinueReading,
|
||||||
|
modifier = Modifier.padding(start = ContinueReadingButtonListSpacing)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -363,23 +379,25 @@ fun MangaListItem(
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun ContinueReadingButton(
|
private fun ContinueReadingButton(
|
||||||
|
size: Dp,
|
||||||
|
iconSize: Dp,
|
||||||
|
onClick: () -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
onClickContinueReading: () -> Unit,
|
|
||||||
) {
|
) {
|
||||||
Box(modifier = modifier) {
|
Box(modifier = modifier) {
|
||||||
FilledIconButton(
|
FilledIconButton(
|
||||||
onClick = onClickContinueReading,
|
onClick = onClick,
|
||||||
modifier = Modifier.size(ContinueReadingButtonSize),
|
|
||||||
shape = MaterialTheme.shapes.small,
|
shape = MaterialTheme.shapes.small,
|
||||||
colors = IconButtonDefaults.filledIconButtonColors(
|
colors = IconButtonDefaults.filledIconButtonColors(
|
||||||
containerColor = MaterialTheme.colorScheme.primaryContainer.copy(alpha = 0.9f),
|
containerColor = MaterialTheme.colorScheme.primaryContainer.copy(alpha = 0.9f),
|
||||||
contentColor = contentColorFor(MaterialTheme.colorScheme.primaryContainer),
|
contentColor = contentColorFor(MaterialTheme.colorScheme.primaryContainer),
|
||||||
),
|
),
|
||||||
|
modifier = Modifier.size(size)
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Filled.PlayArrow,
|
imageVector = Icons.Filled.PlayArrow,
|
||||||
contentDescription = stringResource(MR.strings.action_resume),
|
contentDescription = stringResource(MR.strings.action_resume),
|
||||||
modifier = Modifier.size(16.dp),
|
modifier = Modifier.size(iconSize),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,7 +102,8 @@ import tachiyomi.presentation.core.components.material.ExtendedFloatingActionBut
|
|||||||
import tachiyomi.presentation.core.components.material.PullRefresh
|
import tachiyomi.presentation.core.components.material.PullRefresh
|
||||||
import tachiyomi.presentation.core.components.material.Scaffold
|
import tachiyomi.presentation.core.components.material.Scaffold
|
||||||
import tachiyomi.presentation.core.i18n.stringResource
|
import tachiyomi.presentation.core.i18n.stringResource
|
||||||
import tachiyomi.presentation.core.util.shouldExpandFAB
|
import tachiyomi.presentation.core.util.isScrolledToEnd
|
||||||
|
import tachiyomi.presentation.core.util.isScrollingUp
|
||||||
import tachiyomi.source.local.isLocal
|
import tachiyomi.source.local.isLocal
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import java.time.ZoneId
|
import java.time.ZoneId
|
||||||
@@ -430,7 +431,7 @@ private fun MangaScreenSmallImpl(
|
|||||||
},
|
},
|
||||||
icon = { Icon(imageVector = Icons.Filled.PlayArrow, contentDescription = null) },
|
icon = { Icon(imageVector = Icons.Filled.PlayArrow, contentDescription = null) },
|
||||||
onClick = onContinueReading,
|
onClick = onContinueReading,
|
||||||
expanded = chapterListState.shouldExpandFAB(),
|
expanded = chapterListState.isScrollingUp() || chapterListState.isScrolledToEnd(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -754,7 +755,7 @@ fun MangaScreenLargeImpl(
|
|||||||
},
|
},
|
||||||
icon = { Icon(imageVector = Icons.Filled.PlayArrow, contentDescription = null) },
|
icon = { Icon(imageVector = Icons.Filled.PlayArrow, contentDescription = null) },
|
||||||
onClick = onContinueReading,
|
onClick = onContinueReading,
|
||||||
expanded = chapterListState.shouldExpandFAB(),
|
expanded = chapterListState.isScrollingUp() || chapterListState.isScrolledToEnd(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ fun MangaBottomActionMenu(
|
|||||||
Surface(
|
Surface(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
shape = MaterialTheme.shapes.large.copy(bottomEnd = ZeroCornerSize, bottomStart = ZeroCornerSize),
|
shape = MaterialTheme.shapes.large.copy(bottomEnd = ZeroCornerSize, bottomStart = ZeroCornerSize),
|
||||||
tonalElevation = 3.dp,
|
color = MaterialTheme.colorScheme.surfaceContainerHigh,
|
||||||
) {
|
) {
|
||||||
val haptic = LocalHapticFeedback.current
|
val haptic = LocalHapticFeedback.current
|
||||||
val confirm = remember { mutableStateListOf(false, false, false, false, false, false, false) }
|
val confirm = remember { mutableStateListOf(false, false, false, false, false, false, false) }
|
||||||
@@ -251,7 +251,7 @@ fun LibraryBottomActionMenu(
|
|||||||
Surface(
|
Surface(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
shape = MaterialTheme.shapes.large.copy(bottomEnd = ZeroCornerSize, bottomStart = ZeroCornerSize),
|
shape = MaterialTheme.shapes.large.copy(bottomEnd = ZeroCornerSize, bottomStart = ZeroCornerSize),
|
||||||
tonalElevation = 3.dp,
|
color = MaterialTheme.colorScheme.surfaceContainerHigh,
|
||||||
) {
|
) {
|
||||||
val haptic = LocalHapticFeedback.current
|
val haptic = LocalHapticFeedback.current
|
||||||
val confirm =
|
val confirm =
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ import androidx.compose.runtime.remember
|
|||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.alpha
|
|
||||||
import androidx.compose.ui.draw.clipToBounds
|
import androidx.compose.ui.draw.clipToBounds
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
@@ -69,9 +68,6 @@ fun MangaChapterListItem(
|
|||||||
onChapterSwipe: (LibraryPreferences.ChapterSwipeAction) -> Unit,
|
onChapterSwipe: (LibraryPreferences.ChapterSwipeAction) -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
val textAlpha = if (read) ReadItemAlpha else 1f
|
|
||||||
val textSubtitleAlpha = if (read) ReadItemAlpha else SecondaryItemAlpha
|
|
||||||
|
|
||||||
val start = getSwipeAction(
|
val start = getSwipeAction(
|
||||||
action = chapterSwipeStartAction,
|
action = chapterSwipeStartAction,
|
||||||
read = read,
|
read = read,
|
||||||
@@ -136,15 +132,20 @@ fun MangaChapterListItem(
|
|||||||
Text(
|
Text(
|
||||||
text = title,
|
text = title,
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
color = LocalContentColor.current.copy(alpha = textAlpha),
|
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
onTextLayout = { textHeight = it.size.height },
|
onTextLayout = { textHeight = it.size.height },
|
||||||
|
color = LocalContentColor.current.copy(alpha = if (read) ReadItemAlpha else 1f),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Row(modifier = Modifier.alpha(textSubtitleAlpha)) {
|
Row {
|
||||||
ProvideTextStyle(value = MaterialTheme.typography.bodySmall) {
|
val subtitleStyle = MaterialTheme.typography.bodySmall
|
||||||
|
.merge(
|
||||||
|
color = LocalContentColor.current
|
||||||
|
.copy(alpha = if (read) ReadItemAlpha else SecondaryItemAlpha)
|
||||||
|
)
|
||||||
|
ProvideTextStyle(value = subtitleStyle) {
|
||||||
if (date != null) {
|
if (date != null) {
|
||||||
Text(
|
Text(
|
||||||
text = date,
|
text = date,
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ import androidx.compose.ui.viewinterop.AndroidView
|
|||||||
import androidx.compose.ui.window.Dialog
|
import androidx.compose.ui.window.Dialog
|
||||||
import androidx.compose.ui.window.DialogProperties
|
import androidx.compose.ui.window.DialogProperties
|
||||||
import androidx.core.view.updatePadding
|
import androidx.core.view.updatePadding
|
||||||
|
import coil3.asDrawable
|
||||||
import coil3.imageLoader
|
import coil3.imageLoader
|
||||||
import coil3.request.CachePolicy
|
import coil3.request.CachePolicy
|
||||||
import coil3.request.ImageRequest
|
import coil3.request.ImageRequest
|
||||||
|
|||||||
@@ -102,9 +102,12 @@ fun SetIntervalDialog(
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
} else {
|
||||||
Spacer(Modifier.height(MaterialTheme.padding.small))
|
Text(
|
||||||
|
stringResource(MR.strings.manga_interval_expected_update_null),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
Spacer(Modifier.height(MaterialTheme.padding.small))
|
||||||
|
|
||||||
if (onValueChanged != null && (isDevFlavor || isPreviewBuildType)) {
|
if (onValueChanged != null && (isDevFlavor || isPreviewBuildType)) {
|
||||||
Text(stringResource(MR.strings.manga_interval_custom_amount))
|
Text(stringResource(MR.strings.manga_interval_custom_amount))
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package eu.kanade.presentation.manga.components
|
|||||||
|
|
||||||
import androidx.compose.animation.animateContentSize
|
import androidx.compose.animation.animateContentSize
|
||||||
import androidx.compose.animation.core.animateFloatAsState
|
import androidx.compose.animation.core.animateFloatAsState
|
||||||
|
import androidx.compose.animation.core.spring
|
||||||
import androidx.compose.animation.graphics.res.animatedVectorResource
|
import androidx.compose.animation.graphics.res.animatedVectorResource
|
||||||
import androidx.compose.animation.graphics.res.rememberAnimatedVectorPainter
|
import androidx.compose.animation.graphics.res.rememberAnimatedVectorPainter
|
||||||
import androidx.compose.animation.graphics.vector.AnimatedImageVector
|
import androidx.compose.animation.graphics.vector.AnimatedImageVector
|
||||||
@@ -289,7 +290,8 @@ fun ExpandableMangaDescription(
|
|||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(top = 8.dp)
|
.padding(top = 8.dp)
|
||||||
.padding(vertical = 12.dp)
|
.padding(vertical = 12.dp)
|
||||||
.animateContentSize(),
|
.animateContentSize(animationSpec = spring())
|
||||||
|
.fillMaxWidth(),
|
||||||
) {
|
) {
|
||||||
var showMenu by remember { mutableStateOf(false) }
|
var showMenu by remember { mutableStateOf(false) }
|
||||||
var tagSelected by remember { mutableStateOf("") }
|
var tagSelected by remember { mutableStateOf("") }
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import androidx.compose.foundation.layout.FlowRow
|
|||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.material3.LocalMinimumInteractiveComponentSize
|
import androidx.compose.material3.LocalMinimumInteractiveComponentEnforcement
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.SuggestionChip
|
import androidx.compose.material3.SuggestionChip
|
||||||
import androidx.compose.material3.Surface
|
import androidx.compose.material3.Surface
|
||||||
@@ -141,7 +141,7 @@ fun TagsChip(
|
|||||||
border: ChipBorder? = SuggestionChipDefaults.suggestionChipBorder(),
|
border: ChipBorder? = SuggestionChipDefaults.suggestionChipBorder(),
|
||||||
borderM3: BorderStroke? = SuggestionChipDefaultsM3.suggestionChipBorder(enabled = true),
|
borderM3: BorderStroke? = SuggestionChipDefaultsM3.suggestionChipBorder(enabled = true),
|
||||||
) {
|
) {
|
||||||
CompositionLocalProvider(LocalMinimumInteractiveComponentSize provides 0.dp) {
|
CompositionLocalProvider(LocalMinimumInteractiveComponentEnforcement provides false) {
|
||||||
if (onClick != null) {
|
if (onClick != null) {
|
||||||
SuggestionChip(
|
SuggestionChip(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ import tachiyomi.i18n.MR
|
|||||||
import tachiyomi.presentation.core.components.material.TextButton
|
import tachiyomi.presentation.core.components.material.TextButton
|
||||||
import tachiyomi.presentation.core.components.material.padding
|
import tachiyomi.presentation.core.components.material.padding
|
||||||
import tachiyomi.presentation.core.i18n.stringResource
|
import tachiyomi.presentation.core.i18n.stringResource
|
||||||
|
import tachiyomi.presentation.core.util.isScrolledToEnd
|
||||||
|
import tachiyomi.presentation.core.util.isScrolledToStart
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ScanlatorFilterDialog(
|
fun ScanlatorFilterDialog(
|
||||||
@@ -95,8 +97,8 @@ fun ScanlatorFilterDialog(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (state.canScrollBackward) HorizontalDivider(modifier = Modifier.align(Alignment.TopCenter))
|
if (!state.isScrolledToStart()) HorizontalDivider(modifier = Modifier.align(Alignment.TopCenter))
|
||||||
if (state.canScrollForward) HorizontalDivider(modifier = Modifier.align(Alignment.BottomCenter))
|
if (!state.isScrolledToEnd()) HorizontalDivider(modifier = Modifier.align(Alignment.BottomCenter))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
properties = DialogProperties(
|
properties = DialogProperties(
|
||||||
@@ -109,8 +111,14 @@ fun ScanlatorFilterDialog(
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
FlowRow {
|
FlowRow {
|
||||||
TextButton(onClick = mutableExcludedScanlators::clear) {
|
if (mutableExcludedScanlators.isEmpty()) {
|
||||||
Text(text = stringResource(MR.strings.action_reset))
|
TextButton(onClick = { mutableExcludedScanlators.addAll(availableScanlators) }) {
|
||||||
|
Text(text = stringResource(MR.strings.action_select_all))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
TextButton(onClick = mutableExcludedScanlators::clear) {
|
||||||
|
Text(text = stringResource(MR.strings.action_reset))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Spacer(modifier = Modifier.weight(1f))
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
TextButton(onClick = onDismissRequest) {
|
TextButton(onClick = onDismissRequest) {
|
||||||
|
|||||||
@@ -28,11 +28,11 @@ import androidx.compose.runtime.setValue
|
|||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.platform.LocalLifecycleOwner
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.core.content.getSystemService
|
import androidx.core.content.getSystemService
|
||||||
import androidx.lifecycle.DefaultLifecycleObserver
|
import androidx.lifecycle.DefaultLifecycleObserver
|
||||||
import androidx.lifecycle.LifecycleOwner
|
import androidx.lifecycle.LifecycleOwner
|
||||||
import androidx.lifecycle.compose.LocalLifecycleOwner
|
|
||||||
import eu.kanade.presentation.util.rememberRequestPackageInstallsPermissionState
|
import eu.kanade.presentation.util.rememberRequestPackageInstallsPermissionState
|
||||||
import eu.kanade.tachiyomi.util.system.launchRequestPackageInstallsPermission
|
import eu.kanade.tachiyomi.util.system.launchRequestPackageInstallsPermission
|
||||||
import tachiyomi.i18n.MR
|
import tachiyomi.i18n.MR
|
||||||
|
|||||||
@@ -7,12 +7,12 @@ import androidx.compose.animation.fadeOut
|
|||||||
import androidx.compose.animation.shrinkVertically
|
import androidx.compose.animation.shrinkVertically
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.CompositionLocalProvider
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.compositionLocalOf
|
import androidx.compose.runtime.compositionLocalOf
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.runtime.structuralEqualityPolicy
|
import androidx.compose.runtime.structuralEqualityPolicy
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import eu.kanade.domain.track.service.TrackPreferences
|
|
||||||
import eu.kanade.presentation.more.settings.widget.EditTextPreferenceWidget
|
import eu.kanade.presentation.more.settings.widget.EditTextPreferenceWidget
|
||||||
import eu.kanade.presentation.more.settings.widget.InfoWidget
|
import eu.kanade.presentation.more.settings.widget.InfoWidget
|
||||||
import eu.kanade.presentation.more.settings.widget.ListPreferenceWidget
|
import eu.kanade.presentation.more.settings.widget.ListPreferenceWidget
|
||||||
@@ -23,8 +23,6 @@ import eu.kanade.presentation.more.settings.widget.TrackingPreferenceWidget
|
|||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import tachiyomi.presentation.core.components.SliderItem
|
import tachiyomi.presentation.core.components.SliderItem
|
||||||
import tachiyomi.presentation.core.util.collectAsState
|
import tachiyomi.presentation.core.util.collectAsState
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
|
|
||||||
val LocalPreferenceHighlighted = compositionLocalOf(structuralEqualityPolicy()) { false }
|
val LocalPreferenceHighlighted = compositionLocalOf(structuralEqualityPolicy()) { false }
|
||||||
val LocalPreferenceMinHeight = compositionLocalOf(structuralEqualityPolicy()) { 56.dp }
|
val LocalPreferenceMinHeight = compositionLocalOf(structuralEqualityPolicy()) { 56.dp }
|
||||||
@@ -156,16 +154,14 @@ internal fun PreferenceItem(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
is Preference.PreferenceItem.TrackerPreference -> {
|
is Preference.PreferenceItem.TrackerPreference -> {
|
||||||
val uName by Injekt.get<TrackPreferences>()
|
val isLoggedIn by item.tracker.let { tracker ->
|
||||||
.trackUsername(item.tracker)
|
tracker.isLoggedInFlow.collectAsState(tracker.isLoggedIn)
|
||||||
.collectAsState()
|
|
||||||
item.tracker.run {
|
|
||||||
TrackingPreferenceWidget(
|
|
||||||
tracker = this,
|
|
||||||
checked = uName.isNotEmpty(),
|
|
||||||
onClick = { if (isLoggedIn) item.logout() else item.login() },
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
TrackingPreferenceWidget(
|
||||||
|
tracker = item.tracker,
|
||||||
|
checked = isLoggedIn,
|
||||||
|
onClick = { if (isLoggedIn) item.logout() else item.login() },
|
||||||
|
)
|
||||||
}
|
}
|
||||||
is Preference.PreferenceItem.InfoPreference -> {
|
is Preference.PreferenceItem.InfoPreference -> {
|
||||||
InfoWidget(text = item.title)
|
InfoWidget(text = item.title)
|
||||||
|
|||||||
+11
-1
@@ -127,7 +127,17 @@ object SettingsDataScreen : SearchableSettings {
|
|||||||
val flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or
|
val flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or
|
||||||
Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
||||||
|
|
||||||
context.contentResolver.takePersistableUriPermission(uri, flags)
|
// For some reason InkBook devices do not implement the SAF properly. Persistable URI grants do not
|
||||||
|
// work. However, simply retrieving the URI and using it works fine for these devices. Access is not
|
||||||
|
// revoked after the app is closed or the device is restarted.
|
||||||
|
// This also holds for some Samsung devices. Thus, we simply execute inside of a try-catch block and
|
||||||
|
// ignore the exception if it is thrown.
|
||||||
|
try {
|
||||||
|
context.contentResolver.takePersistableUriPermission(uri, flags)
|
||||||
|
} catch (e: SecurityException) {
|
||||||
|
logcat(LogPriority.ERROR, e)
|
||||||
|
context.toast(MR.strings.file_picker_uri_permission_unsupported)
|
||||||
|
}
|
||||||
|
|
||||||
UniFile.fromUri(context, uri)?.let {
|
UniFile.fromUri(context, uri)?.let {
|
||||||
storageDirPref.set(it.uri.toString())
|
storageDirPref.set(it.uri.toString())
|
||||||
|
|||||||
@@ -84,9 +84,6 @@ object SettingsLibraryScreen : SearchableSettings {
|
|||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
val userCategoriesCount = allCategories.filterNot(Category::isSystemCategory).size
|
val userCategoriesCount = allCategories.filterNot(Category::isSystemCategory).size
|
||||||
|
|
||||||
val defaultCategory by libraryPreferences.defaultCategory().collectAsState()
|
|
||||||
val selectedCategory = allCategories.find { it.id == defaultCategory.toLong() }
|
|
||||||
|
|
||||||
// For default category
|
// For default category
|
||||||
val ids = listOf(libraryPreferences.defaultCategory().defaultValue()) +
|
val ids = listOf(libraryPreferences.defaultCategory().defaultValue()) +
|
||||||
allCategories.fastMap { it.id.toInt() }
|
allCategories.fastMap { it.id.toInt() }
|
||||||
@@ -108,7 +105,6 @@ object SettingsLibraryScreen : SearchableSettings {
|
|||||||
Preference.PreferenceItem.ListPreference(
|
Preference.PreferenceItem.ListPreference(
|
||||||
pref = libraryPreferences.defaultCategory(),
|
pref = libraryPreferences.defaultCategory(),
|
||||||
title = stringResource(MR.strings.default_category),
|
title = stringResource(MR.strings.default_category),
|
||||||
subtitle = selectedCategory?.visualName ?: stringResource(MR.strings.default_category_summary),
|
|
||||||
entries = ids.zip(labels).toMap().toImmutableMap(),
|
entries = ids.zip(labels).toMap().toImmutableMap(),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
|
|||||||
+61
-5
@@ -17,6 +17,7 @@ import kotlinx.collections.immutable.persistentMapOf
|
|||||||
import kotlinx.collections.immutable.toImmutableMap
|
import kotlinx.collections.immutable.toImmutableMap
|
||||||
import tachiyomi.i18n.MR
|
import tachiyomi.i18n.MR
|
||||||
import tachiyomi.i18n.sy.SYMR
|
import tachiyomi.i18n.sy.SYMR
|
||||||
|
import tachiyomi.presentation.core.i18n.pluralStringResource
|
||||||
import tachiyomi.presentation.core.i18n.stringResource
|
import tachiyomi.presentation.core.i18n.stringResource
|
||||||
import tachiyomi.presentation.core.util.collectAsState
|
import tachiyomi.presentation.core.util.collectAsState
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
@@ -88,12 +89,8 @@ object SettingsReaderScreen : SearchableSettings {
|
|||||||
title = stringResource(MR.strings.pref_page_transitions),
|
title = stringResource(MR.strings.pref_page_transitions),
|
||||||
),
|
),
|
||||||
SY <-- */
|
SY <-- */
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
|
||||||
pref = readerPref.flashOnPageChange(),
|
|
||||||
title = stringResource(MR.strings.pref_flash_page),
|
|
||||||
subtitle = stringResource(MR.strings.pref_flash_page_summ),
|
|
||||||
),
|
|
||||||
getDisplayGroup(readerPreferences = readerPref),
|
getDisplayGroup(readerPreferences = readerPref),
|
||||||
|
getEInkGroup(readerPreferences = readerPref),
|
||||||
getReadingGroup(readerPreferences = readerPref),
|
getReadingGroup(readerPreferences = readerPref),
|
||||||
getPagedGroup(readerPreferences = readerPref),
|
getPagedGroup(readerPreferences = readerPref),
|
||||||
getWebtoonGroup(readerPreferences = readerPref),
|
getWebtoonGroup(readerPreferences = readerPref),
|
||||||
@@ -156,6 +153,65 @@ object SettingsReaderScreen : SearchableSettings {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun getEInkGroup(readerPreferences: ReaderPreferences): Preference.PreferenceGroup {
|
||||||
|
val flashPageState by readerPreferences.flashOnPageChange().collectAsState()
|
||||||
|
|
||||||
|
val flashMillisPref = readerPreferences.flashDurationMillis()
|
||||||
|
val flashMillis by flashMillisPref.collectAsState()
|
||||||
|
|
||||||
|
val flashIntervalPref = readerPreferences.flashPageInterval()
|
||||||
|
val flashInterval by flashIntervalPref.collectAsState()
|
||||||
|
|
||||||
|
val flashColorPref = readerPreferences.flashColor()
|
||||||
|
|
||||||
|
return Preference.PreferenceGroup(
|
||||||
|
title = "E-Ink",
|
||||||
|
preferenceItems = persistentListOf(
|
||||||
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
|
pref = readerPreferences.flashOnPageChange(),
|
||||||
|
title = stringResource(MR.strings.pref_flash_page),
|
||||||
|
subtitle = stringResource(MR.strings.pref_flash_page_summ),
|
||||||
|
),
|
||||||
|
Preference.PreferenceItem.SliderPreference(
|
||||||
|
value = flashMillis / ReaderPreferences.MILLI_CONVERSION,
|
||||||
|
min = 1,
|
||||||
|
max = 15,
|
||||||
|
title = stringResource(MR.strings.pref_flash_duration),
|
||||||
|
subtitle = stringResource(MR.strings.pref_flash_duration_summary, flashMillis),
|
||||||
|
onValueChanged = {
|
||||||
|
flashMillisPref.set(it * ReaderPreferences.MILLI_CONVERSION)
|
||||||
|
true
|
||||||
|
},
|
||||||
|
enabled = flashPageState,
|
||||||
|
),
|
||||||
|
Preference.PreferenceItem.SliderPreference(
|
||||||
|
value = flashInterval,
|
||||||
|
min = 1,
|
||||||
|
max = 10,
|
||||||
|
title = stringResource(MR.strings.pref_flash_page_interval),
|
||||||
|
subtitle = pluralStringResource(MR.plurals.pref_pages, flashInterval, flashInterval),
|
||||||
|
onValueChanged = {
|
||||||
|
flashIntervalPref.set(it)
|
||||||
|
true
|
||||||
|
},
|
||||||
|
enabled = flashPageState,
|
||||||
|
),
|
||||||
|
Preference.PreferenceItem.ListPreference(
|
||||||
|
pref = flashColorPref,
|
||||||
|
title = stringResource(MR.strings.pref_flash_with),
|
||||||
|
entries = persistentMapOf(
|
||||||
|
ReaderPreferences.FlashColor.BLACK to stringResource(MR.strings.pref_flash_style_black),
|
||||||
|
ReaderPreferences.FlashColor.WHITE to stringResource(MR.strings.pref_flash_style_white),
|
||||||
|
ReaderPreferences.FlashColor.WHITE_BLACK
|
||||||
|
to stringResource(MR.strings.pref_flash_style_white_black),
|
||||||
|
),
|
||||||
|
enabled = flashPageState,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun getReadingGroup(readerPreferences: ReaderPreferences): Preference.PreferenceGroup {
|
private fun getReadingGroup(readerPreferences: ReaderPreferences): Preference.PreferenceGroup {
|
||||||
return Preference.PreferenceGroup(
|
return Preference.PreferenceGroup(
|
||||||
|
|||||||
+1
-1
@@ -46,7 +46,7 @@ fun ExtensionReposContent(
|
|||||||
repos.forEach {
|
repos.forEach {
|
||||||
item {
|
item {
|
||||||
ExtensionRepoListItem(
|
ExtensionRepoListItem(
|
||||||
modifier = Modifier.animateItem(),
|
modifier = Modifier.animateItemPlacement(),
|
||||||
repo = it,
|
repo = it,
|
||||||
onOpenWebsite = { onOpenWebsite(it) },
|
onOpenWebsite = { onOpenWebsite(it) },
|
||||||
onDelete = { onClickDelete(it.baseUrl) },
|
onDelete = { onClickDelete(it.baseUrl) },
|
||||||
|
|||||||
+3
@@ -1,6 +1,7 @@
|
|||||||
package eu.kanade.presentation.more.settings.screen.browse.components
|
package eu.kanade.presentation.more.settings.screen.browse.components
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.text.KeyboardOptions
|
||||||
import androidx.compose.material3.AlertDialog
|
import androidx.compose.material3.AlertDialog
|
||||||
import androidx.compose.material3.OutlinedTextField
|
import androidx.compose.material3.OutlinedTextField
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
@@ -14,6 +15,7 @@ import androidx.compose.runtime.setValue
|
|||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.focus.FocusRequester
|
import androidx.compose.ui.focus.FocusRequester
|
||||||
import androidx.compose.ui.focus.focusRequester
|
import androidx.compose.ui.focus.focusRequester
|
||||||
|
import androidx.compose.ui.text.input.KeyboardType
|
||||||
import kotlinx.collections.immutable.ImmutableSet
|
import kotlinx.collections.immutable.ImmutableSet
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import mihon.domain.extensionrepo.model.ExtensionRepo
|
import mihon.domain.extensionrepo.model.ExtensionRepo
|
||||||
@@ -74,6 +76,7 @@ fun ExtensionRepoCreateDialog(
|
|||||||
Text(text = stringResource(msgRes))
|
Text(text = stringResource(msgRes))
|
||||||
},
|
},
|
||||||
isError = name.isNotEmpty() && nameAlreadyExists,
|
isError = name.isNotEmpty() && nameAlreadyExists,
|
||||||
|
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Uri),
|
||||||
singleLine = true,
|
singleLine = true,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-3
@@ -6,7 +6,6 @@ import android.content.Intent
|
|||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.compose.foundation.layout.ColumnScope
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
@@ -69,7 +68,7 @@ class CreateBackupScreen : Screen() {
|
|||||||
LazyColumnWithAction(
|
LazyColumnWithAction(
|
||||||
contentPadding = contentPadding,
|
contentPadding = contentPadding,
|
||||||
actionLabel = stringResource(MR.strings.action_create),
|
actionLabel = stringResource(MR.strings.action_create),
|
||||||
actionEnabled = state.options.anyEnabled(),
|
actionEnabled = state.options.canCreate(),
|
||||||
onClickAction = {
|
onClickAction = {
|
||||||
if (!BackupCreateJob.isManualJobRunning(context)) {
|
if (!BackupCreateJob.isManualJobRunning(context)) {
|
||||||
try {
|
try {
|
||||||
@@ -104,7 +103,7 @@ class CreateBackupScreen : Screen() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun ColumnScope.Options(
|
private fun Options(
|
||||||
options: ImmutableList<BackupOptions.Entry>,
|
options: ImmutableList<BackupOptions.Entry>,
|
||||||
state: CreateBackupScreenModel.State,
|
state: CreateBackupScreenModel.State,
|
||||||
model: CreateBackupScreenModel,
|
model: CreateBackupScreenModel,
|
||||||
|
|||||||
+1
-1
@@ -63,7 +63,7 @@ class RestoreBackupScreen(
|
|||||||
LazyColumnWithAction(
|
LazyColumnWithAction(
|
||||||
contentPadding = contentPadding,
|
contentPadding = contentPadding,
|
||||||
actionLabel = stringResource(MR.strings.action_restore),
|
actionLabel = stringResource(MR.strings.action_restore),
|
||||||
actionEnabled = state.canRestore && state.options.anyEnabled(),
|
actionEnabled = state.canRestore && state.options.canRestore(),
|
||||||
onClickAction = {
|
onClickAction = {
|
||||||
model.startRestore()
|
model.startRestore()
|
||||||
navigator.pop()
|
navigator.pop()
|
||||||
|
|||||||
+5
-1
@@ -49,7 +49,7 @@ class SyncSettingsSelector : Screen() {
|
|||||||
LazyColumnWithAction(
|
LazyColumnWithAction(
|
||||||
contentPadding = contentPadding,
|
contentPadding = contentPadding,
|
||||||
actionLabel = stringResource(SYMR.strings.label_sync),
|
actionLabel = stringResource(SYMR.strings.label_sync),
|
||||||
actionEnabled = state.options.anyEnabled(),
|
actionEnabled = state.options.canCreate(),
|
||||||
onClickAction = {
|
onClickAction = {
|
||||||
if (!SyncDataJob.isRunning(context)) {
|
if (!SyncDataJob.isRunning(context)) {
|
||||||
model.syncNow(context)
|
model.syncNow(context)
|
||||||
@@ -122,12 +122,14 @@ private class SyncSettingsSelectorModel(
|
|||||||
tracking = syncSettings.tracking,
|
tracking = syncSettings.tracking,
|
||||||
history = syncSettings.history,
|
history = syncSettings.history,
|
||||||
appSettings = syncSettings.appSettings,
|
appSettings = syncSettings.appSettings,
|
||||||
|
extensionRepoSettings = syncSettings.extensionRepoSettings,
|
||||||
sourceSettings = syncSettings.sourceSettings,
|
sourceSettings = syncSettings.sourceSettings,
|
||||||
privateSettings = syncSettings.privateSettings,
|
privateSettings = syncSettings.privateSettings,
|
||||||
|
|
||||||
// SY -->
|
// SY -->
|
||||||
customInfo = syncSettings.customInfo,
|
customInfo = syncSettings.customInfo,
|
||||||
readEntries = syncSettings.readEntries,
|
readEntries = syncSettings.readEntries,
|
||||||
|
savedSearches = syncSettings.savedSearches,
|
||||||
// SY <--
|
// SY <--
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -140,12 +142,14 @@ private class SyncSettingsSelectorModel(
|
|||||||
tracking = backupOptions.tracking,
|
tracking = backupOptions.tracking,
|
||||||
history = backupOptions.history,
|
history = backupOptions.history,
|
||||||
appSettings = backupOptions.appSettings,
|
appSettings = backupOptions.appSettings,
|
||||||
|
extensionRepoSettings = backupOptions.extensionRepoSettings,
|
||||||
sourceSettings = backupOptions.sourceSettings,
|
sourceSettings = backupOptions.sourceSettings,
|
||||||
privateSettings = backupOptions.privateSettings,
|
privateSettings = backupOptions.privateSettings,
|
||||||
|
|
||||||
// SY -->
|
// SY -->
|
||||||
customInfo = backupOptions.customInfo,
|
customInfo = backupOptions.customInfo,
|
||||||
readEntries = backupOptions.readEntries,
|
readEntries = backupOptions.readEntries,
|
||||||
|
savedSearches = backupOptions.savedSearches,
|
||||||
// SY <--
|
// SY <--
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-2
@@ -223,13 +223,12 @@ fun AppThemePreviewItem(
|
|||||||
contentAlignment = Alignment.BottomCenter,
|
contentAlignment = Alignment.BottomCenter,
|
||||||
) {
|
) {
|
||||||
Surface(
|
Surface(
|
||||||
tonalElevation = 3.dp,
|
color = MaterialTheme.colorScheme.surfaceContainer,
|
||||||
) {
|
) {
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.height(32.dp)
|
.height(32.dp)
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.background(MaterialTheme.colorScheme.surfaceVariant)
|
|
||||||
.padding(horizontal = 8.dp),
|
.padding(horizontal = 8.dp),
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
) {
|
) {
|
||||||
|
|||||||
+4
-2
@@ -26,6 +26,8 @@ import androidx.compose.ui.unit.dp
|
|||||||
import tachiyomi.i18n.MR
|
import tachiyomi.i18n.MR
|
||||||
import tachiyomi.presentation.core.components.ScrollbarLazyColumn
|
import tachiyomi.presentation.core.components.ScrollbarLazyColumn
|
||||||
import tachiyomi.presentation.core.i18n.stringResource
|
import tachiyomi.presentation.core.i18n.stringResource
|
||||||
|
import tachiyomi.presentation.core.util.isScrolledToEnd
|
||||||
|
import tachiyomi.presentation.core.util.isScrolledToStart
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun <T> ListPreferenceWidget(
|
fun <T> ListPreferenceWidget(
|
||||||
@@ -67,8 +69,8 @@ fun <T> ListPreferenceWidget(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (state.canScrollBackward) HorizontalDivider(modifier = Modifier.align(Alignment.TopCenter))
|
if (!state.isScrolledToStart()) HorizontalDivider(modifier = Modifier.align(Alignment.TopCenter))
|
||||||
if (state.canScrollForward) HorizontalDivider(modifier = Modifier.align(Alignment.BottomCenter))
|
if (!state.isScrolledToEnd()) HorizontalDivider(modifier = Modifier.align(Alignment.BottomCenter))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
confirmButton = {
|
confirmButton = {
|
||||||
|
|||||||
+12
-2
@@ -30,6 +30,8 @@ import androidx.compose.ui.draw.clip
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import tachiyomi.i18n.MR
|
import tachiyomi.i18n.MR
|
||||||
import tachiyomi.presentation.core.i18n.stringResource
|
import tachiyomi.presentation.core.i18n.stringResource
|
||||||
|
import tachiyomi.presentation.core.util.isScrolledToEnd
|
||||||
|
import tachiyomi.presentation.core.util.isScrolledToStart
|
||||||
|
|
||||||
private enum class State {
|
private enum class State {
|
||||||
CHECKED, INVERSED, UNCHECKED
|
CHECKED, INVERSED, UNCHECKED
|
||||||
@@ -113,8 +115,16 @@ fun <T> TriStateListDialog(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (listState.canScrollBackward) HorizontalDivider(modifier = Modifier.align(Alignment.TopCenter))
|
if (!listState.isScrolledToStart()) {
|
||||||
if (listState.canScrollForward) HorizontalDivider(modifier = Modifier.align(Alignment.BottomCenter))
|
HorizontalDivider(
|
||||||
|
modifier = Modifier.align(Alignment.TopCenter),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (!listState.isScrolledToEnd()) {
|
||||||
|
HorizontalDivider(
|
||||||
|
modifier = Modifier.align(Alignment.BottomCenter),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -7,19 +7,42 @@ import androidx.compose.runtime.LaunchedEffect
|
|||||||
import androidx.compose.runtime.Stable
|
import androidx.compose.runtime.Stable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlin.time.Duration.Companion.seconds
|
import tachiyomi.presentation.core.util.collectAsState
|
||||||
|
import uy.kohesive.injekt.Injekt
|
||||||
|
import uy.kohesive.injekt.api.get
|
||||||
|
import kotlin.time.Duration.Companion.milliseconds
|
||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
class DisplayRefreshHost {
|
class DisplayRefreshHost {
|
||||||
|
|
||||||
internal var currentDisplayRefresh by mutableStateOf(false)
|
internal var currentDisplayRefresh by mutableStateOf(false)
|
||||||
|
private val readerPreferences = Injekt.get<ReaderPreferences>()
|
||||||
|
|
||||||
|
internal val flashMillis = readerPreferences.flashDurationMillis()
|
||||||
|
internal val flashMode = readerPreferences.flashColor()
|
||||||
|
|
||||||
|
internal val flashIntervalPref = readerPreferences.flashPageInterval()
|
||||||
|
|
||||||
|
// Internal State for Flash
|
||||||
|
private var flashInterval = flashIntervalPref.get()
|
||||||
|
private var timesCalled = 0
|
||||||
|
|
||||||
fun flash() {
|
fun flash() {
|
||||||
currentDisplayRefresh = true
|
if (timesCalled % flashInterval == 0) {
|
||||||
|
currentDisplayRefresh = true
|
||||||
|
}
|
||||||
|
timesCalled += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setInterval(interval: Int) {
|
||||||
|
flashInterval = interval
|
||||||
|
timesCalled = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,18 +52,39 @@ fun DisplayRefreshHost(
|
|||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
val currentDisplayRefresh = hostState.currentDisplayRefresh
|
val currentDisplayRefresh = hostState.currentDisplayRefresh
|
||||||
|
val refreshDuration by hostState.flashMillis.collectAsState()
|
||||||
|
val flashMode by hostState.flashMode.collectAsState()
|
||||||
|
val flashInterval by hostState.flashIntervalPref.collectAsState()
|
||||||
|
|
||||||
|
var currentColor by remember { mutableStateOf<Color?>(null) }
|
||||||
|
|
||||||
LaunchedEffect(currentDisplayRefresh) {
|
LaunchedEffect(currentDisplayRefresh) {
|
||||||
if (currentDisplayRefresh) {
|
if (!currentDisplayRefresh) {
|
||||||
delay(1.5.seconds)
|
currentColor = null
|
||||||
hostState.currentDisplayRefresh = false
|
return@LaunchedEffect
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val refreshDurationHalf = refreshDuration.milliseconds / 2
|
||||||
|
currentColor = if (flashMode == ReaderPreferences.FlashColor.BLACK) {
|
||||||
|
Color.Black
|
||||||
|
} else {
|
||||||
|
Color.White
|
||||||
|
}
|
||||||
|
delay(refreshDurationHalf)
|
||||||
|
if (flashMode == ReaderPreferences.FlashColor.WHITE_BLACK) {
|
||||||
|
currentColor = Color.Black
|
||||||
|
}
|
||||||
|
delay(refreshDurationHalf)
|
||||||
|
hostState.currentDisplayRefresh = false
|
||||||
|
}
|
||||||
|
|
||||||
|
LaunchedEffect(flashInterval) {
|
||||||
|
hostState.setInterval(flashInterval)
|
||||||
}
|
}
|
||||||
|
|
||||||
Canvas(
|
Canvas(
|
||||||
modifier = modifier.fillMaxSize(),
|
modifier = modifier.fillMaxSize(),
|
||||||
) {
|
) {
|
||||||
if (currentDisplayRefresh) {
|
currentColor?.let { drawRect(it) }
|
||||||
drawRect(Color.Black)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import androidx.compose.foundation.layout.Column
|
|||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.outlined.ContentCopy
|
||||||
import androidx.compose.material.icons.outlined.Photo
|
import androidx.compose.material.icons.outlined.Photo
|
||||||
import androidx.compose.material.icons.outlined.Save
|
import androidx.compose.material.icons.outlined.Save
|
||||||
import androidx.compose.material.icons.outlined.Share
|
import androidx.compose.material.icons.outlined.Share
|
||||||
@@ -31,9 +32,9 @@ fun ReaderPageActionsDialog(
|
|||||||
onDismissRequest: () -> Unit,
|
onDismissRequest: () -> Unit,
|
||||||
// SY -->
|
// SY -->
|
||||||
onSetAsCover: (useExtraPage: Boolean) -> Unit,
|
onSetAsCover: (useExtraPage: Boolean) -> Unit,
|
||||||
onShare: (useExtraPage: Boolean) -> Unit,
|
onShare: (copy: Boolean, useExtraPage: Boolean) -> Unit,
|
||||||
onSave: (useExtraPage: Boolean) -> Unit,
|
onSave: (useExtraPage: Boolean) -> Unit,
|
||||||
onShareCombined: () -> Unit,
|
onShareCombined: (copy: Boolean) -> Unit,
|
||||||
onSaveCombined: () -> Unit,
|
onSaveCombined: () -> Unit,
|
||||||
hasExtraPage: Boolean,
|
hasExtraPage: Boolean,
|
||||||
// SY <--
|
// SY <--
|
||||||
@@ -43,9 +44,7 @@ fun ReaderPageActionsDialog(
|
|||||||
var useExtraPage by remember { mutableStateOf(false) }
|
var useExtraPage by remember { mutableStateOf(false) }
|
||||||
// SY <--
|
// SY <--
|
||||||
|
|
||||||
AdaptiveSheet(
|
AdaptiveSheet(onDismissRequest = onDismissRequest) {
|
||||||
onDismissRequest = onDismissRequest,
|
|
||||||
) {
|
|
||||||
Column(modifier = Modifier.padding(vertical = 16.dp)) {
|
Column(modifier = Modifier.padding(vertical = 16.dp)) {
|
||||||
Row(
|
Row(
|
||||||
horizontalArrangement = Arrangement.spacedBy(MaterialTheme.padding.small),
|
horizontalArrangement = Arrangement.spacedBy(MaterialTheme.padding.small),
|
||||||
@@ -64,6 +63,25 @@ fun ReaderPageActionsDialog(
|
|||||||
icon = Icons.Outlined.Photo,
|
icon = Icons.Outlined.Photo,
|
||||||
onClick = { showSetCoverDialog = true },
|
onClick = { showSetCoverDialog = true },
|
||||||
)
|
)
|
||||||
|
ActionButton(
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
title = stringResource(
|
||||||
|
// SY -->
|
||||||
|
if (hasExtraPage) {
|
||||||
|
SYMR.strings.action_copy_first_page
|
||||||
|
} else {
|
||||||
|
MR.strings.action_copy_to_clipboard
|
||||||
|
},
|
||||||
|
// SY <--
|
||||||
|
),
|
||||||
|
icon = Icons.Outlined.ContentCopy,
|
||||||
|
onClick = {
|
||||||
|
// SY -->
|
||||||
|
onShare(true, false)
|
||||||
|
// SY <--
|
||||||
|
onDismissRequest()
|
||||||
|
},
|
||||||
|
)
|
||||||
ActionButton(
|
ActionButton(
|
||||||
modifier = Modifier.weight(1f),
|
modifier = Modifier.weight(1f),
|
||||||
title = stringResource(
|
title = stringResource(
|
||||||
@@ -78,7 +96,7 @@ fun ReaderPageActionsDialog(
|
|||||||
icon = Icons.Outlined.Share,
|
icon = Icons.Outlined.Share,
|
||||||
onClick = {
|
onClick = {
|
||||||
// SY -->
|
// SY -->
|
||||||
onShare(false)
|
onShare(false, false)
|
||||||
// SY <--
|
// SY <--
|
||||||
onDismissRequest()
|
onDismissRequest()
|
||||||
},
|
},
|
||||||
@@ -116,12 +134,21 @@ fun ReaderPageActionsDialog(
|
|||||||
showSetCoverDialog = true
|
showSetCoverDialog = true
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
ActionButton(
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
title = stringResource(SYMR.strings.action_copy_second_page),
|
||||||
|
icon = Icons.Outlined.ContentCopy,
|
||||||
|
onClick = {
|
||||||
|
onShare(true, true)
|
||||||
|
onDismissRequest()
|
||||||
|
},
|
||||||
|
)
|
||||||
ActionButton(
|
ActionButton(
|
||||||
modifier = Modifier.weight(1f),
|
modifier = Modifier.weight(1f),
|
||||||
title = stringResource(SYMR.strings.action_share_second_page),
|
title = stringResource(SYMR.strings.action_share_second_page),
|
||||||
icon = Icons.Outlined.Share,
|
icon = Icons.Outlined.Share,
|
||||||
onClick = {
|
onClick = {
|
||||||
onShare(true)
|
onShare(false, true)
|
||||||
onDismissRequest()
|
onDismissRequest()
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -138,12 +165,21 @@ fun ReaderPageActionsDialog(
|
|||||||
Row(
|
Row(
|
||||||
horizontalArrangement = Arrangement.spacedBy(MaterialTheme.padding.small),
|
horizontalArrangement = Arrangement.spacedBy(MaterialTheme.padding.small),
|
||||||
) {
|
) {
|
||||||
|
ActionButton(
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
title = stringResource(SYMR.strings.action_copy_combined_page),
|
||||||
|
icon = Icons.Outlined.ContentCopy,
|
||||||
|
onClick = {
|
||||||
|
onShareCombined(true)
|
||||||
|
onDismissRequest()
|
||||||
|
},
|
||||||
|
)
|
||||||
ActionButton(
|
ActionButton(
|
||||||
modifier = Modifier.weight(1f),
|
modifier = Modifier.weight(1f),
|
||||||
title = stringResource(SYMR.strings.action_share_combined_page),
|
title = stringResource(SYMR.strings.action_share_combined_page),
|
||||||
icon = Icons.Outlined.Share,
|
icon = Icons.Outlined.Share,
|
||||||
onClick = {
|
onClick = {
|
||||||
onShareCombined()
|
onShareCombined(false)
|
||||||
onDismissRequest()
|
onDismissRequest()
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -5,11 +5,14 @@ import androidx.compose.material3.FilterChip
|
|||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences
|
||||||
import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsScreenModel
|
import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsScreenModel
|
||||||
import tachiyomi.i18n.MR
|
import tachiyomi.i18n.MR
|
||||||
import tachiyomi.i18n.sy.SYMR
|
import tachiyomi.i18n.sy.SYMR
|
||||||
import tachiyomi.presentation.core.components.CheckboxItem
|
import tachiyomi.presentation.core.components.CheckboxItem
|
||||||
import tachiyomi.presentation.core.components.SettingsChipRow
|
import tachiyomi.presentation.core.components.SettingsChipRow
|
||||||
|
import tachiyomi.presentation.core.components.SliderItem
|
||||||
|
import tachiyomi.presentation.core.i18n.pluralStringResource
|
||||||
import tachiyomi.presentation.core.i18n.stringResource
|
import tachiyomi.presentation.core.i18n.stringResource
|
||||||
import tachiyomi.presentation.core.util.collectAsState
|
import tachiyomi.presentation.core.util.collectAsState
|
||||||
|
|
||||||
@@ -20,9 +23,27 @@ private val themes = listOf(
|
|||||||
MR.strings.automatic_background to 3,
|
MR.strings.automatic_background to 3,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
private val flashColors = listOf(
|
||||||
|
MR.strings.pref_flash_style_black to ReaderPreferences.FlashColor.BLACK,
|
||||||
|
MR.strings.pref_flash_style_white to ReaderPreferences.FlashColor.WHITE,
|
||||||
|
MR.strings.pref_flash_style_white_black to ReaderPreferences.FlashColor.WHITE_BLACK,
|
||||||
|
)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
internal fun ColumnScope.GeneralPage(screenModel: ReaderSettingsScreenModel) {
|
internal fun ColumnScope.GeneralPage(screenModel: ReaderSettingsScreenModel) {
|
||||||
val readerTheme by screenModel.preferences.readerTheme().collectAsState()
|
val readerTheme by screenModel.preferences.readerTheme().collectAsState()
|
||||||
|
|
||||||
|
val flashPageState by screenModel.preferences.flashOnPageChange().collectAsState()
|
||||||
|
|
||||||
|
val flashMillisPref = screenModel.preferences.flashDurationMillis()
|
||||||
|
val flashMillis by flashMillisPref.collectAsState()
|
||||||
|
|
||||||
|
val flashIntervalPref = screenModel.preferences.flashPageInterval()
|
||||||
|
val flashInterval by flashIntervalPref.collectAsState()
|
||||||
|
|
||||||
|
val flashColorPref = screenModel.preferences.flashColor()
|
||||||
|
val flashColor by flashColorPref.collectAsState()
|
||||||
|
|
||||||
SettingsChipRow(MR.strings.pref_reader_theme) {
|
SettingsChipRow(MR.strings.pref_reader_theme) {
|
||||||
themes.map { (labelRes, value) ->
|
themes.map { (labelRes, value) ->
|
||||||
FilterChip(
|
FilterChip(
|
||||||
@@ -95,6 +116,35 @@ internal fun ColumnScope.GeneralPage(screenModel: ReaderSettingsScreenModel) {
|
|||||||
label = stringResource(MR.strings.pref_flash_page),
|
label = stringResource(MR.strings.pref_flash_page),
|
||||||
pref = screenModel.preferences.flashOnPageChange(),
|
pref = screenModel.preferences.flashOnPageChange(),
|
||||||
)
|
)
|
||||||
|
if (flashPageState) {
|
||||||
|
SliderItem(
|
||||||
|
value = flashMillis / ReaderPreferences.MILLI_CONVERSION,
|
||||||
|
label = stringResource(MR.strings.pref_flash_duration),
|
||||||
|
valueText = stringResource(MR.strings.pref_flash_duration_summary, flashMillis),
|
||||||
|
onChange = { flashMillisPref.set(it * ReaderPreferences.MILLI_CONVERSION) },
|
||||||
|
min = 1,
|
||||||
|
max = 15,
|
||||||
|
)
|
||||||
|
SliderItem(
|
||||||
|
value = flashInterval,
|
||||||
|
label = stringResource(MR.strings.pref_flash_page_interval),
|
||||||
|
valueText = pluralStringResource(MR.plurals.pref_pages, flashInterval, flashInterval),
|
||||||
|
onChange = {
|
||||||
|
flashIntervalPref.set(it)
|
||||||
|
},
|
||||||
|
min = 1,
|
||||||
|
max = 10,
|
||||||
|
)
|
||||||
|
SettingsChipRow(MR.strings.pref_flash_with) {
|
||||||
|
flashColors.map { (labelRes, value) ->
|
||||||
|
FilterChip(
|
||||||
|
selected = flashColor == value,
|
||||||
|
onClick = { flashColorPref.set(value) },
|
||||||
|
label = { Text(stringResource(labelRes)) },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// SY -->
|
// SY -->
|
||||||
CheckboxItem(
|
CheckboxItem(
|
||||||
|
|||||||
@@ -8,6 +8,12 @@ internal abstract class BaseColorScheme {
|
|||||||
abstract val darkScheme: ColorScheme
|
abstract val darkScheme: ColorScheme
|
||||||
abstract val lightScheme: ColorScheme
|
abstract val lightScheme: ColorScheme
|
||||||
|
|
||||||
|
// Cannot be pure black as there's content scrolling behind it
|
||||||
|
// https://m3.material.io/components/navigation-bar/guidelines#90615a71-607e-485e-9e09-778bfc080563
|
||||||
|
private val surfaceContainer = Color(0xFF0C0C0C)
|
||||||
|
private val surfaceContainerHigh = Color(0xFF131313)
|
||||||
|
private val surfaceContainerHighest = Color(0xFF1B1B1B)
|
||||||
|
|
||||||
fun getColorScheme(isDark: Boolean, isAmoled: Boolean): ColorScheme {
|
fun getColorScheme(isDark: Boolean, isAmoled: Boolean): ColorScheme {
|
||||||
if (!isDark) return lightScheme
|
if (!isDark) return lightScheme
|
||||||
|
|
||||||
@@ -18,6 +24,12 @@ internal abstract class BaseColorScheme {
|
|||||||
onBackground = Color.White,
|
onBackground = Color.White,
|
||||||
surface = Color.Black,
|
surface = Color.Black,
|
||||||
onSurface = Color.White,
|
onSurface = Color.White,
|
||||||
|
surfaceVariant = surfaceContainer, // Navigation bar background (ThemePrefWidget)
|
||||||
|
surfaceContainerLowest = surfaceContainer,
|
||||||
|
surfaceContainerLow = surfaceContainer,
|
||||||
|
surfaceContainer = surfaceContainer, // Navigation bar background
|
||||||
|
surfaceContainerHigh = surfaceContainerHigh,
|
||||||
|
surfaceContainerHighest = surfaceContainerHighest,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+67
-43
@@ -19,53 +19,77 @@ internal object GreenAppleColorScheme : BaseColorScheme() {
|
|||||||
|
|
||||||
override val darkScheme = darkColorScheme(
|
override val darkScheme = darkColorScheme(
|
||||||
primary = Color(0xFF7ADB8F),
|
primary = Color(0xFF7ADB8F),
|
||||||
onPrimary = Color(0xFF003915),
|
onPrimary = Color(0xFF003917),
|
||||||
primaryContainer = Color(0xFF005322),
|
primaryContainer = Color(0xFF017737),
|
||||||
onPrimaryContainer = Color(0xFF96F8A9),
|
onPrimaryContainer = Color(0xFFFFFFFF),
|
||||||
inversePrimary = Color(0xFF006D2F),
|
secondary = Color(0xFF7ADB8F), // Unread badge
|
||||||
secondary = Color(0xFF7ADB8F),
|
onSecondary = Color(0xFF003917), // Unread badge text
|
||||||
onSecondary = Color(0xFF003915),
|
secondaryContainer = Color(0xFF017737), // Navigation bar selector pill & progress indicator (remaining)
|
||||||
secondaryContainer = Color(0xFF005322),
|
onSecondaryContainer = Color(0xFFFFFFFF), // Navigation bar selected icon
|
||||||
onSecondaryContainer = Color(0xFF96F8A9),
|
tertiary = Color(0xFFFFB3AC), // Downloaded badge
|
||||||
tertiary = Color(0xFFFFB3AA),
|
onTertiary = Color(0xFF680008), // Downloaded badge text
|
||||||
onTertiary = Color(0xFF680006),
|
tertiaryContainer = Color(0xFFC7282A),
|
||||||
tertiaryContainer = Color(0xFF93000D),
|
onTertiaryContainer = Color(0xFFFFFFFF),
|
||||||
onTertiaryContainer = Color(0xFFFFDAD5),
|
error = Color(0xFFFFB4AB),
|
||||||
background = Color(0xFF1A1C19),
|
onError = Color(0xFF690005),
|
||||||
onBackground = Color(0xFFE1E3DD),
|
errorContainer = Color(0xFF93000A),
|
||||||
surface = Color(0xFF1A1C19),
|
onErrorContainer = Color(0xFFFFDAD6),
|
||||||
onSurface = Color(0xFFE1E3DD),
|
background = Color(0xFF0F1510),
|
||||||
surfaceVariant = Color(0xFF414941),
|
onBackground = Color(0xFFDFE4DB),
|
||||||
onSurfaceVariant = Color(0xFFC1C8BE),
|
surface = Color(0xFF0F1510),
|
||||||
surfaceTint = Color(0xFF7ADB8F),
|
onSurface = Color(0xFFDFE4DB),
|
||||||
inverseSurface = Color(0xFFE1E3DD),
|
surfaceVariant = Color(0xFF3F493F), // Navigation bar background (ThemePrefWidget)
|
||||||
inverseOnSurface = Color(0xFF1A1C19),
|
onSurfaceVariant = Color(0xFFBECABC),
|
||||||
outline = Color(0xFF8B9389),
|
outline = Color(0xFF889487),
|
||||||
|
outlineVariant = Color(0xFF3F493F),
|
||||||
|
scrim = Color(0xFF000000),
|
||||||
|
inverseSurface = Color(0xFFDFE4DB),
|
||||||
|
inverseOnSurface = Color(0xFF2C322C),
|
||||||
|
inversePrimary = Color(0xFF006D32),
|
||||||
|
surfaceDim = Color(0xFF0F1510),
|
||||||
|
surfaceBright = Color(0xFF353B35),
|
||||||
|
surfaceContainerLowest = Color(0xFF0A0F0B),
|
||||||
|
surfaceContainerLow = Color(0xFF181D18),
|
||||||
|
surfaceContainer = Color(0xFF1C211C), // Navigation bar background
|
||||||
|
surfaceContainerHigh = Color(0xFF262B26),
|
||||||
|
surfaceContainerHighest = Color(0xFF313630),
|
||||||
)
|
)
|
||||||
|
|
||||||
override val lightScheme = lightColorScheme(
|
override val lightScheme = lightColorScheme(
|
||||||
primary = Color(0xFF006D2F),
|
primary = Color(0xFF005927),
|
||||||
onPrimary = Color(0xFFFFFFFF),
|
onPrimary = Color(0xFFFFFFFF),
|
||||||
primaryContainer = Color(0xFF96F8A9),
|
primaryContainer = Color(0xFF188140),
|
||||||
onPrimaryContainer = Color(0xFF002109),
|
onPrimaryContainer = Color(0xFFFFFFFF),
|
||||||
|
secondary = Color(0xFF005927), // Unread badge
|
||||||
|
onSecondary = Color(0xFFFFFFFF), // Unread badge text
|
||||||
|
secondaryContainer = Color(0xFF97f7a9), // Navigation bar selector pill & progress indicator (remaining)
|
||||||
|
onSecondaryContainer = Color(0xFF000000), // Navigation bar selected icon
|
||||||
|
tertiary = Color(0xFF9D0012), // Downloaded badge
|
||||||
|
onTertiary = Color(0xFFFFFFFF), // Downloaded badge text
|
||||||
|
tertiaryContainer = Color(0xFFD33131),
|
||||||
|
onTertiaryContainer = Color(0xFFFFFFFF),
|
||||||
|
error = Color(0xFFBA1A1A),
|
||||||
|
onError = Color(0xFFFFFFFF),
|
||||||
|
errorContainer = Color(0xFFFFDAD6),
|
||||||
|
onErrorContainer = Color(0xFF410002),
|
||||||
|
background = Color(0xFFF6FBF2),
|
||||||
|
onBackground = Color(0xFF181D18),
|
||||||
|
surface = Color(0xFFF6FBF2),
|
||||||
|
onSurface = Color(0xFF181D18),
|
||||||
|
surfaceVariant = Color(0xFFDAE6D7), // Navigation bar background (ThemePrefWidget)
|
||||||
|
onSurfaceVariant = Color(0xFF3F493F),
|
||||||
|
outline = Color(0xFF6F7A6E),
|
||||||
|
outlineVariant = Color(0xFFBECABC),
|
||||||
|
scrim = Color(0xFF000000),
|
||||||
|
inverseSurface = Color(0xFF2C322C),
|
||||||
|
inverseOnSurface = Color(0xFFEDF2E9),
|
||||||
inversePrimary = Color(0xFF7ADB8F),
|
inversePrimary = Color(0xFF7ADB8F),
|
||||||
secondary = Color(0xFF006D2F),
|
surfaceDim = Color(0xFFD6DCD3),
|
||||||
onSecondary = Color(0xFFFFFFFF),
|
surfaceBright = Color(0xFFF6FBF2),
|
||||||
secondaryContainer = Color(0xFF96F8A9),
|
surfaceContainerLowest = Color(0xFFFFFFFF),
|
||||||
onSecondaryContainer = Color(0xFF002109),
|
surfaceContainerLow = Color(0xFFF0F5EC),
|
||||||
tertiary = Color(0xFFB91D22),
|
surfaceContainer = Color(0xFFEAEFE6), // Navigation bar background
|
||||||
onTertiary = Color(0xFFFFFFFF),
|
surfaceContainerHigh = Color(0xFFE4EAE1),
|
||||||
tertiaryContainer = Color(0xFFFFDAD5),
|
surfaceContainerHighest = Color(0xFFDFE4DB),
|
||||||
onTertiaryContainer = Color(0xFF410003),
|
|
||||||
background = Color(0xFFFBFDF7),
|
|
||||||
onBackground = Color(0xFF1A1C19),
|
|
||||||
surface = Color(0xFFFBFDF7),
|
|
||||||
onSurface = Color(0xFF1A1C19),
|
|
||||||
surfaceVariant = Color(0xFFDDE5DA),
|
|
||||||
onSurfaceVariant = Color(0xFF414941),
|
|
||||||
surfaceTint = Color(0xFF006D2F),
|
|
||||||
inverseSurface = Color(0xFF2F312E),
|
|
||||||
inverseOnSurface = Color(0xFFF0F2EC),
|
|
||||||
outline = Color(0xFF717970),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,53 +18,77 @@ internal object LavenderColorScheme : BaseColorScheme() {
|
|||||||
|
|
||||||
override val darkScheme = darkColorScheme(
|
override val darkScheme = darkColorScheme(
|
||||||
primary = Color(0xFFA177FF),
|
primary = Color(0xFFA177FF),
|
||||||
onPrimary = Color(0xFF111129),
|
onPrimary = Color(0xFF3D0090),
|
||||||
primaryContainer = Color(0xFFA177FF),
|
primaryContainer = Color(0xFFA177FF),
|
||||||
onPrimaryContainer = Color(0xFF111129),
|
onPrimaryContainer = Color(0xFFFFFFFF),
|
||||||
inversePrimary = Color(0xFF006D2F),
|
secondary = Color(0xFFA177FF), // Unread badge
|
||||||
secondary = Color(0xFFA177FF),
|
onSecondary = Color(0xFFFFFFFF), // Unread badge text
|
||||||
onSecondary = Color(0xFF111129),
|
secondaryContainer = Color(0xFF423271), // Navigation bar selector pill & progress indicator (remaining)
|
||||||
secondaryContainer = Color(0xFFA177FF),
|
onSecondaryContainer = Color(0xFFA177FF), // Navigation bar selected icon
|
||||||
onSecondaryContainer = Color(0xFF111129),
|
tertiary = Color(0xFFCDBDFF), // Downloaded badge
|
||||||
tertiary = Color(0xFF5E25E1),
|
onTertiary = Color(0xFF360096), // Downloaded badge text
|
||||||
onTertiary = Color(0xFFE8E8E8),
|
tertiaryContainer = Color(0xFF5512D8),
|
||||||
tertiaryContainer = Color(0xFF111129),
|
onTertiaryContainer = Color(0xFFEFE6FF),
|
||||||
onTertiaryContainer = Color(0xFFDEE8FF),
|
error = Color(0xFFFFB4AB),
|
||||||
|
onError = Color(0xFF690005),
|
||||||
|
errorContainer = Color(0xFF93000A),
|
||||||
|
onErrorContainer = Color(0xFFFFDAD6),
|
||||||
background = Color(0xFF111129),
|
background = Color(0xFF111129),
|
||||||
onBackground = Color(0xFFDEE8FF),
|
onBackground = Color(0xFFE7E0EC),
|
||||||
surface = Color(0xFF111129),
|
surface = Color(0xFF111129),
|
||||||
onSurface = Color(0xFFDEE8FF),
|
onSurface = Color(0xFFE7E0EC),
|
||||||
surfaceVariant = Color(0x2CB6B6B6),
|
surfaceVariant = Color(0xFF3D2F6B), // Navigation bar background (ThemePrefWidget)
|
||||||
onSurfaceVariant = Color(0xFFE8E8E8),
|
onSurfaceVariant = Color(0xFFCBC3D6),
|
||||||
surfaceTint = Color(0xFFA177FF),
|
outline = Color(0xFF958E9F),
|
||||||
inverseSurface = Color(0xFF221247),
|
outlineVariant = Color(0xFF4A4453),
|
||||||
inverseOnSurface = Color(0xFFDEE8FF),
|
scrim = Color(0xFF000000),
|
||||||
outline = Color(0xA8905FFF),
|
inverseSurface = Color(0xFFE7E0EC),
|
||||||
|
inverseOnSurface = Color(0xFF322F38),
|
||||||
|
inversePrimary = Color(0xFF6D41C8),
|
||||||
|
surfaceDim = Color(0xFF111129),
|
||||||
|
surfaceBright = Color(0xFF3B3841),
|
||||||
|
surfaceContainerLowest = Color(0xFF15132d),
|
||||||
|
surfaceContainerLow = Color(0xFF171531),
|
||||||
|
surfaceContainer = Color(0xFF1D193B), // Navigation bar background
|
||||||
|
surfaceContainerHigh = Color(0xFF241f41),
|
||||||
|
surfaceContainerHighest = Color(0xFF282446),
|
||||||
)
|
)
|
||||||
|
|
||||||
override val lightScheme = lightColorScheme(
|
override val lightScheme = lightColorScheme(
|
||||||
primary = Color(0xFF7B46AF),
|
primary = Color(0xFF6D41C8),
|
||||||
onPrimary = Color(0xFFEDE2FF),
|
onPrimary = Color(0xFFFFFFFF),
|
||||||
primaryContainer = Color(0xFF7B46AF),
|
primaryContainer = Color(0xFF7B46AF),
|
||||||
onPrimaryContainer = Color(0xFFEDE2FF),
|
onPrimaryContainer = Color(0xFF130038),
|
||||||
inversePrimary = Color(0xFFD6BAFF),
|
secondary = Color(0xFF7B46AF), // Unread badge
|
||||||
secondary = Color(0xFF7B46AF),
|
onSecondary = Color(0xFFEDE2FF), // Unread badge text
|
||||||
onSecondary = Color(0xFFEDE2FF),
|
secondaryContainer = Color(0xFFC9B0E6), // Navigation bar selector pill & progress indicator (remaining)
|
||||||
secondaryContainer = Color(0xFF7B46AF),
|
onSecondaryContainer = Color(0xFF7B46AF), // Navigation bar selector icon
|
||||||
onSecondaryContainer = Color(0xFFEDE2FF),
|
tertiary = Color(0xFFEDE2FF), // Downloaded badge
|
||||||
tertiary = Color(0xFFEDE2FF),
|
onTertiary = Color(0xFF7B46AF), // Downloaded badge text
|
||||||
onTertiary = Color(0xFF7B46AF),
|
tertiaryContainer = Color(0xFF6D3BF0),
|
||||||
tertiaryContainer = Color(0xFFEDE2FF),
|
onTertiaryContainer = Color(0xFFFFFFFF),
|
||||||
onTertiaryContainer = Color(0xFF7B46AF),
|
error = Color(0xFFBA1A1A),
|
||||||
|
onError = Color(0xFFFFFFFF),
|
||||||
|
errorContainer = Color(0xFFFFDAD6),
|
||||||
|
onErrorContainer = Color(0xFF410002),
|
||||||
background = Color(0xFFEDE2FF),
|
background = Color(0xFFEDE2FF),
|
||||||
onBackground = Color(0xFF1B1B22),
|
onBackground = Color(0xFF1D1A22),
|
||||||
surface = Color(0xFFEDE2FF),
|
surface = Color(0xFFEDE2FF),
|
||||||
onSurface = Color(0xFF1B1B22),
|
onSurface = Color(0xFF1D1A22),
|
||||||
surfaceVariant = Color(0xFFB9B0CC),
|
surfaceVariant = Color(0xFFE4D5F8), // Navigation bar background (ThemePrefWidget)
|
||||||
onSurfaceVariant = Color(0xD849454E),
|
onSurfaceVariant = Color(0xFF4A4453),
|
||||||
surfaceTint = Color(0xFF7B46AF),
|
outline = Color(0xFF7B7485),
|
||||||
inverseSurface = Color(0xFF313033),
|
outlineVariant = Color(0xFFCBC3D6),
|
||||||
inverseOnSurface = Color(0xFFF3EFF4),
|
scrim = Color(0xFF000000),
|
||||||
outline = Color(0xFF7B46AF),
|
inverseSurface = Color(0xFF322F38),
|
||||||
|
inverseOnSurface = Color(0xFFF5EEFA),
|
||||||
|
inversePrimary = Color(0xFFA177FF),
|
||||||
|
surfaceDim = Color(0xFFDED7E3),
|
||||||
|
surfaceBright = Color(0xFFEDE2FF),
|
||||||
|
surfaceContainerLowest = Color(0xFFDACCEC),
|
||||||
|
surfaceContainerLow = Color(0xFFDED0F1),
|
||||||
|
surfaceContainer = Color(0xFFE4D5F8), // Navigation bar background
|
||||||
|
surfaceContainerHigh = Color(0xFFEADCFD),
|
||||||
|
surfaceContainerHighest = Color(0xFFEEE2FF),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+24
-14
@@ -23,24 +23,29 @@ internal object MidnightDuskColorScheme : BaseColorScheme() {
|
|||||||
primaryContainer = Color(0xFFBD1C5C),
|
primaryContainer = Color(0xFFBD1C5C),
|
||||||
onPrimaryContainer = Color(0xFFFFFFFF),
|
onPrimaryContainer = Color(0xFFFFFFFF),
|
||||||
inversePrimary = Color(0xFFF02475),
|
inversePrimary = Color(0xFFF02475),
|
||||||
secondary = Color(0xFFF02475),
|
secondary = Color(0xFFF02475), // Unread badge
|
||||||
onSecondary = Color(0xFFFFFFFF),
|
onSecondary = Color(0xFF16151D), // Unread badge text
|
||||||
secondaryContainer = Color(0xFFF02475),
|
secondaryContainer = Color(0xFF66183C), // Navigation bar selector pill & progress indicator (remaining)
|
||||||
onSecondaryContainer = Color(0xFFFFFFFF),
|
onSecondaryContainer = Color(0xFFF02475), // Navigation bar selector icon
|
||||||
tertiary = Color(0xFF55971C),
|
tertiary = Color(0xFF55971C), // Downloaded badge
|
||||||
onTertiary = Color(0xFFFFFFFF),
|
onTertiary = Color(0xFF16151D), // Downloaded badge text
|
||||||
tertiaryContainer = Color(0xFF386412),
|
tertiaryContainer = Color(0xFF386412),
|
||||||
onTertiaryContainer = Color(0xFFE5E1E5),
|
onTertiaryContainer = Color(0xFFE5E1E5),
|
||||||
background = Color(0xFF16151D),
|
background = Color(0xFF16151D),
|
||||||
onBackground = Color(0xFFE5E1E5),
|
onBackground = Color(0xFFE5E1E5),
|
||||||
surface = Color(0xFF16151D),
|
surface = Color(0xFF16151D),
|
||||||
onSurface = Color(0xFFE5E1E5),
|
onSurface = Color(0xFFE5E1E5),
|
||||||
surfaceVariant = Color(0xFF524346),
|
surfaceVariant = Color(0xFF281624), // Navigation bar background (ThemePrefWidget)
|
||||||
onSurfaceVariant = Color(0xFFD6C1C4),
|
onSurfaceVariant = Color(0xFFD6C1C4),
|
||||||
surfaceTint = Color(0xFFF02475),
|
surfaceTint = Color(0xFFF02475),
|
||||||
inverseSurface = Color(0xFF333043),
|
inverseSurface = Color(0xFF333043),
|
||||||
inverseOnSurface = Color(0xFFFFFFFF),
|
inverseOnSurface = Color(0xFFFFFFFF),
|
||||||
outline = Color(0xFF9F8C8F),
|
outline = Color(0xFF9F8C8F),
|
||||||
|
surfaceContainerLowest = Color(0xFF221320),
|
||||||
|
surfaceContainerLow = Color(0xFF251522),
|
||||||
|
surfaceContainer = Color(0xFF281624), // Navigation bar background
|
||||||
|
surfaceContainerHigh = Color(0xFF2D1C2A),
|
||||||
|
surfaceContainerHighest = Color(0xFF2F1F2C),
|
||||||
)
|
)
|
||||||
|
|
||||||
override val lightScheme = lightColorScheme(
|
override val lightScheme = lightColorScheme(
|
||||||
@@ -49,23 +54,28 @@ internal object MidnightDuskColorScheme : BaseColorScheme() {
|
|||||||
primaryContainer = Color(0xFFFFD9E1),
|
primaryContainer = Color(0xFFFFD9E1),
|
||||||
onPrimaryContainer = Color(0xFF3F0017),
|
onPrimaryContainer = Color(0xFF3F0017),
|
||||||
inversePrimary = Color(0xFFFFB1C4),
|
inversePrimary = Color(0xFFFFB1C4),
|
||||||
secondary = Color(0xFFBB0054),
|
secondary = Color(0xFFBB0054), // Unread badge
|
||||||
onSecondary = Color(0xFFFFFFFF),
|
onSecondary = Color(0xFFFFFFFF), // Unread badge text
|
||||||
secondaryContainer = Color(0xFFFFD9E1),
|
secondaryContainer = Color(0xFFEFBAD4), // Navigation bar selector pill & progress indicator (remaining)
|
||||||
onSecondaryContainer = Color(0xFF3F0017),
|
onSecondaryContainer = Color(0xFFD1377C), // Navigation bar selector icon
|
||||||
tertiary = Color(0xFF006638),
|
tertiary = Color(0xFF006638), // Downloaded badge
|
||||||
onTertiary = Color(0xFFFFFFFF),
|
onTertiary = Color(0xFFFFFFFF), // Downloaded badge text
|
||||||
tertiaryContainer = Color(0xFF00894b),
|
tertiaryContainer = Color(0xFF00894b),
|
||||||
onTertiaryContainer = Color(0xFF2D1600),
|
onTertiaryContainer = Color(0xFF2D1600),
|
||||||
background = Color(0xFFFFFBFF),
|
background = Color(0xFFFFFBFF),
|
||||||
onBackground = Color(0xFF1C1B1F),
|
onBackground = Color(0xFF1C1B1F),
|
||||||
surface = Color(0xFFFFFBFF),
|
surface = Color(0xFFFFFBFF),
|
||||||
onSurface = Color(0xFF1C1B1F),
|
onSurface = Color(0xFF1C1B1F),
|
||||||
surfaceVariant = Color(0xFFF3DDE0),
|
surfaceVariant = Color(0xFFF9E6F1), // Navigation bar background (ThemePrefWidget)
|
||||||
onSurfaceVariant = Color(0xFF524346),
|
onSurfaceVariant = Color(0xFF524346),
|
||||||
surfaceTint = Color(0xFFBB0054),
|
surfaceTint = Color(0xFFBB0054),
|
||||||
inverseSurface = Color(0xFF313033),
|
inverseSurface = Color(0xFF313033),
|
||||||
inverseOnSurface = Color(0xFFF4F0F4),
|
inverseOnSurface = Color(0xFFF4F0F4),
|
||||||
outline = Color(0xFF847376),
|
outline = Color(0xFF847376),
|
||||||
|
surfaceContainerLowest = Color(0xFFDAC0CD),
|
||||||
|
surfaceContainerLow = Color(0xFFE8D1DD),
|
||||||
|
surfaceContainer = Color(0xFFF9E6F1), // Navigation bar background
|
||||||
|
surfaceContainerHigh = Color(0xFFFCF3F8),
|
||||||
|
surfaceContainerHighest = Color(0xFFFEF9FC),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,19 +17,19 @@ internal object NordColorScheme : BaseColorScheme() {
|
|||||||
primaryContainer = Color(0xFF88C0D0),
|
primaryContainer = Color(0xFF88C0D0),
|
||||||
onPrimaryContainer = Color(0xFF2E3440),
|
onPrimaryContainer = Color(0xFF2E3440),
|
||||||
inversePrimary = Color(0xFF397E91),
|
inversePrimary = Color(0xFF397E91),
|
||||||
secondary = Color(0xFF81A1C1),
|
secondary = Color(0xFF81A1C1), // Unread badge
|
||||||
onSecondary = Color(0xFF2E3440),
|
onSecondary = Color(0xFF2E3440), // Unread badge text
|
||||||
secondaryContainer = Color(0xFF81A1C1),
|
secondaryContainer = Color(0xFF506275), // Navigation bar selector pill & progress indicator (remaining)
|
||||||
onSecondaryContainer = Color(0xFF2E3440),
|
onSecondaryContainer = Color(0xFF88C0D0), // Navigation bar selector icon
|
||||||
tertiary = Color(0xFF5E81AC),
|
tertiary = Color(0xFF5E81AC), // Downloaded badge
|
||||||
onTertiary = Color(0xFF000000),
|
onTertiary = Color(0xFF000000), // Downloaded badge text
|
||||||
tertiaryContainer = Color(0xFF5E81AC),
|
tertiaryContainer = Color(0xFF5E81AC),
|
||||||
onTertiaryContainer = Color(0xFF000000),
|
onTertiaryContainer = Color(0xFF000000),
|
||||||
background = Color(0xFF2E3440),
|
background = Color(0xFF2E3440),
|
||||||
onBackground = Color(0xFFECEFF4),
|
onBackground = Color(0xFFECEFF4),
|
||||||
surface = Color(0xFF3B4252),
|
surface = Color(0xFF2E3440),
|
||||||
onSurface = Color(0xFFECEFF4),
|
onSurface = Color(0xFFECEFF4),
|
||||||
surfaceVariant = Color(0xFF2E3440),
|
surfaceVariant = Color(0xFF414C5C), // Navigation bar background (ThemePrefWidget)
|
||||||
onSurfaceVariant = Color(0xFFECEFF4),
|
onSurfaceVariant = Color(0xFFECEFF4),
|
||||||
surfaceTint = Color(0xFF88C0D0),
|
surfaceTint = Color(0xFF88C0D0),
|
||||||
inverseSurface = Color(0xFFD8DEE9),
|
inverseSurface = Color(0xFFD8DEE9),
|
||||||
@@ -39,6 +39,11 @@ internal object NordColorScheme : BaseColorScheme() {
|
|||||||
onError = Color(0xFF2E3440),
|
onError = Color(0xFF2E3440),
|
||||||
errorContainer = Color(0xFFBF616A),
|
errorContainer = Color(0xFFBF616A),
|
||||||
onErrorContainer = Color(0xFF000000),
|
onErrorContainer = Color(0xFF000000),
|
||||||
|
surfaceContainerLowest = Color(0xFF373F4D),
|
||||||
|
surfaceContainerLow = Color(0xFF3E4756),
|
||||||
|
surfaceContainer = Color(0xFF414C5C),
|
||||||
|
surfaceContainerHigh = Color(0xFF4E5766),
|
||||||
|
surfaceContainerHighest = Color(0xFF505968), // Navigation bar background
|
||||||
)
|
)
|
||||||
|
|
||||||
override val lightScheme = lightColorScheme(
|
override val lightScheme = lightColorScheme(
|
||||||
@@ -47,19 +52,19 @@ internal object NordColorScheme : BaseColorScheme() {
|
|||||||
primaryContainer = Color(0xFF5E81AC),
|
primaryContainer = Color(0xFF5E81AC),
|
||||||
onPrimaryContainer = Color(0xFF000000),
|
onPrimaryContainer = Color(0xFF000000),
|
||||||
inversePrimary = Color(0xFF8CA8CD),
|
inversePrimary = Color(0xFF8CA8CD),
|
||||||
secondary = Color(0xFF81A1C1),
|
secondary = Color(0xFF81A1C1), // Unread badge
|
||||||
onSecondary = Color(0xFF2E3440),
|
onSecondary = Color(0xFF2E3440), // Unread badge text
|
||||||
secondaryContainer = Color(0xFF81A1C1),
|
secondaryContainer = Color(0xFF91B4D7), // Navigation bar selector pill & progress indicator (remaining)
|
||||||
onSecondaryContainer = Color(0xFF2E3440),
|
onSecondaryContainer = Color(0xFF2E3440), // Navigation bar selector icon
|
||||||
tertiary = Color(0xFF88C0D0),
|
tertiary = Color(0xFF88C0D0), // Downloaded badge
|
||||||
onTertiary = Color(0xFF2E3440),
|
onTertiary = Color(0xFF2E3440), // Downloaded badge text
|
||||||
tertiaryContainer = Color(0xFF88C0D0),
|
tertiaryContainer = Color(0xFF88C0D0),
|
||||||
onTertiaryContainer = Color(0xFF2E3440),
|
onTertiaryContainer = Color(0xFF2E3440),
|
||||||
background = Color(0xFFECEFF4),
|
background = Color(0xFFECEFF4),
|
||||||
onBackground = Color(0xFF2E3440),
|
onBackground = Color(0xFF2E3440),
|
||||||
surface = Color(0xFFE5E9F0),
|
surface = Color(0xFFE5E9F0),
|
||||||
onSurface = Color(0xFF2E3440),
|
onSurface = Color(0xFF2E3440),
|
||||||
surfaceVariant = Color(0xFFffffff),
|
surfaceVariant = Color(0xFFDAE0EA), // Navigation bar background (ThemePrefWidget)
|
||||||
onSurfaceVariant = Color(0xFF2E3440),
|
onSurfaceVariant = Color(0xFF2E3440),
|
||||||
surfaceTint = Color(0xFF5E81AC),
|
surfaceTint = Color(0xFF5E81AC),
|
||||||
inverseSurface = Color(0xFF3B4252),
|
inverseSurface = Color(0xFF3B4252),
|
||||||
@@ -68,5 +73,10 @@ internal object NordColorScheme : BaseColorScheme() {
|
|||||||
onError = Color(0xFFECEFF4),
|
onError = Color(0xFFECEFF4),
|
||||||
errorContainer = Color(0xFFBF616A),
|
errorContainer = Color(0xFFBF616A),
|
||||||
onErrorContainer = Color(0xFF000000),
|
onErrorContainer = Color(0xFF000000),
|
||||||
|
surfaceContainerLowest = Color(0xFFD1D7E0),
|
||||||
|
surfaceContainerLow = Color(0xFFD6DCE6),
|
||||||
|
surfaceContainer = Color(0xFFDAE0EA), // Navigation bar background
|
||||||
|
surfaceContainerHigh = Color(0xFFE9EDF3),
|
||||||
|
surfaceContainerHighest = Color(0xFFF2F4F8),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+67
-43
@@ -18,54 +18,78 @@ import androidx.compose.ui.graphics.Color
|
|||||||
internal object StrawberryColorScheme : BaseColorScheme() {
|
internal object StrawberryColorScheme : BaseColorScheme() {
|
||||||
|
|
||||||
override val darkScheme = darkColorScheme(
|
override val darkScheme = darkColorScheme(
|
||||||
primary = Color(0xFFFFB2B9),
|
primary = Color(0xFFFFB2B8),
|
||||||
onPrimary = Color(0xFF67001B),
|
onPrimary = Color(0xFF67001D),
|
||||||
primaryContainer = Color(0xFF91002A),
|
primaryContainer = Color(0xFFD53855),
|
||||||
onPrimaryContainer = Color(0xFFFFDADD),
|
onPrimaryContainer = Color(0xFFFFFFFF),
|
||||||
inversePrimary = Color(0xFFB61E40),
|
secondary = Color(0xFFED4A65), // Unread badge
|
||||||
secondary = Color(0xFFFFB2B9),
|
onSecondary = Color(0xFF201A1A), // Unread badge text
|
||||||
onSecondary = Color(0xFF67001B),
|
secondaryContainer = Color(0xFF91002A), // Navigation bar selector pill & progress indicator (remaining)
|
||||||
secondaryContainer = Color(0xFF91002A),
|
onSecondaryContainer = Color(0xFFFFFFFF), // Navigation bar selector icon
|
||||||
onSecondaryContainer = Color(0xFFFFDADD),
|
tertiary = Color(0xFFE8C08E), // Downloaded badge
|
||||||
tertiary = Color(0xFFE8C08E),
|
onTertiary = Color(0xFF201A1A), // Downloaded badge text
|
||||||
onTertiary = Color(0xFF432C06),
|
tertiaryContainer = Color(0xFF775930),
|
||||||
tertiaryContainer = Color(0xFF5D421B),
|
onTertiaryContainer = Color(0xFFFFF7F1),
|
||||||
onTertiaryContainer = Color(0xFFFFDDB1),
|
error = Color(0xFFFFB4AB),
|
||||||
|
onError = Color(0xFF690005),
|
||||||
|
errorContainer = Color(0xFF93000A),
|
||||||
|
onErrorContainer = Color(0xFFFFDAD6),
|
||||||
background = Color(0xFF201A1A),
|
background = Color(0xFF201A1A),
|
||||||
onBackground = Color(0xFFECDFDF),
|
onBackground = Color(0xFFF7DCDD),
|
||||||
surface = Color(0xFF201A1A),
|
surface = Color(0xFF201A1A),
|
||||||
onSurface = Color(0xFFECDFDF),
|
onSurface = Color(0xFFF7DCDD),
|
||||||
surfaceVariant = Color(0xFF534344),
|
surfaceVariant = Color(0xFF322727), // Navigation bar background (ThemePrefWidget)
|
||||||
onSurfaceVariant = Color(0xFFD7C1C2),
|
onSurfaceVariant = Color(0xFFE1BEC0),
|
||||||
surfaceTint = Color(0xFFFFB2B9),
|
outline = Color(0xFFA9898B),
|
||||||
inverseSurface = Color(0xFFECDFDF),
|
outlineVariant = Color(0xFF594042),
|
||||||
inverseOnSurface = Color(0xFF201A1A),
|
scrim = Color(0xFF000000),
|
||||||
outline = Color(0xFFA08C8D),
|
inverseSurface = Color(0xFFF7DCDD),
|
||||||
|
inverseOnSurface = Color(0xFF3D2C2D),
|
||||||
|
inversePrimary = Color(0xFFB61F40),
|
||||||
|
surfaceDim = Color(0xFF1D1011),
|
||||||
|
surfaceBright = Color(0xFF463536),
|
||||||
|
surfaceContainerLowest = Color(0xFF2C2222),
|
||||||
|
surfaceContainerLow = Color(0xFF302525),
|
||||||
|
surfaceContainer = Color(0xFF322727), // Navigation bar background
|
||||||
|
surfaceContainerHigh = Color(0xFF3C2F2F),
|
||||||
|
surfaceContainerHighest = Color(0xFF463737),
|
||||||
)
|
)
|
||||||
|
|
||||||
override val lightScheme = lightColorScheme(
|
override val lightScheme = lightColorScheme(
|
||||||
primary = Color(0xFFB61E40),
|
primary = Color(0xFFA10833),
|
||||||
onPrimary = Color(0xFFFFFFFF),
|
onPrimary = Color(0xFFFFFFFF),
|
||||||
primaryContainer = Color(0xFFFFDADD),
|
primaryContainer = Color(0xFFD53855),
|
||||||
onPrimaryContainer = Color(0xFF40000D),
|
onPrimaryContainer = Color(0xFFFFFFFF),
|
||||||
inversePrimary = Color(0xFFFFB2B9),
|
secondary = Color(0xFFA10833), // Unread badge
|
||||||
secondary = Color(0xFFB61E40),
|
onSecondary = Color(0xFFFFFFFF), // Unread badge text
|
||||||
onSecondary = Color(0xFFFFFFFF),
|
secondaryContainer = Color(0xFFD53855), // Navigation bar selector pill & progress indicator (remaining)
|
||||||
secondaryContainer = Color(0xFFFFDADD),
|
onSecondaryContainer = Color(0xFFF6EAED), // Navigation bar selector icon
|
||||||
onSecondaryContainer = Color(0xFF40000D),
|
tertiary = Color(0xFF5F441D), // Downloaded badge
|
||||||
tertiary = Color(0xFF775930),
|
onTertiary = Color(0xFFFFFFFF), // Downloaded badge text
|
||||||
onTertiary = Color(0xFFFFFFFF),
|
tertiaryContainer = Color(0xFF87683D),
|
||||||
tertiaryContainer = Color(0xFFFFDDB1),
|
onTertiaryContainer = Color(0xFFFFFFFF),
|
||||||
onTertiaryContainer = Color(0xFF2A1800),
|
error = Color(0xFFBA1A1A),
|
||||||
background = Color(0xFFFCFCFC),
|
onError = Color(0xFFFFFFFF),
|
||||||
onBackground = Color(0xFF201A1A),
|
errorContainer = Color(0xFFFFDAD6),
|
||||||
surface = Color(0xFFFCFCFC),
|
onErrorContainer = Color(0xFF410002),
|
||||||
onSurface = Color(0xFF201A1A),
|
background = Color(0xFFFAFAFA),
|
||||||
surfaceVariant = Color(0xFFF4DDDD),
|
onBackground = Color(0xFF261819),
|
||||||
onSurfaceVariant = Color(0xFF534344),
|
surface = Color(0xFFFAFAFA),
|
||||||
surfaceTint = Color(0xFFB61E40),
|
onSurface = Color(0xFF261819),
|
||||||
inverseSurface = Color(0xFF362F2F),
|
surfaceVariant = Color(0xFFF6EAED), // Navigation bar background (ThemePrefWidget)
|
||||||
inverseOnSurface = Color(0xFFFBEDED),
|
onSurfaceVariant = Color(0xFF594042),
|
||||||
outline = Color(0xFF857374),
|
outline = Color(0xFF8D7071),
|
||||||
|
outlineVariant = Color(0xFFE1BEC0),
|
||||||
|
scrim = Color(0xFF000000),
|
||||||
|
inverseSurface = Color(0xFF3D2C2D),
|
||||||
|
inverseOnSurface = Color(0xFFFFECED),
|
||||||
|
inversePrimary = Color(0xFFFFB2B8),
|
||||||
|
surfaceDim = Color(0xFFEED4D5),
|
||||||
|
surfaceBright = Color(0xFFFFF8F7),
|
||||||
|
surfaceContainerLowest = Color(0xFFF7DCDD),
|
||||||
|
surfaceContainerLow = Color(0xFFFDE2E3),
|
||||||
|
surfaceContainer = Color(0xFFF6EAED), // Navigation bar background
|
||||||
|
surfaceContainerHigh = Color(0xFFFFF0F0),
|
||||||
|
surfaceContainerHighest = Color(0xFFFFFFFF),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+24
-14
@@ -22,19 +22,19 @@ internal object TachiyomiColorScheme : BaseColorScheme() {
|
|||||||
primaryContainer = Color(0xFF00429B),
|
primaryContainer = Color(0xFF00429B),
|
||||||
onPrimaryContainer = Color(0xFFD9E2FF),
|
onPrimaryContainer = Color(0xFFD9E2FF),
|
||||||
inversePrimary = Color(0xFF0058CA),
|
inversePrimary = Color(0xFF0058CA),
|
||||||
secondary = Color(0xFFB0C6FF),
|
secondary = Color(0xFFB0C6FF), // Unread badge
|
||||||
onSecondary = Color(0xFF002D6E),
|
onSecondary = Color(0xFF002D6E), // Unread badge text
|
||||||
secondaryContainer = Color(0xFF00429B),
|
secondaryContainer = Color(0xFF00429B), // Navigation bar selector pill & pro
|
||||||
onSecondaryContainer = Color(0xFFD9E2FF),
|
onSecondaryContainer = Color(0xFFD9E2FF), // Navigation bar selector icon
|
||||||
tertiary = Color(0xFF7ADC77),
|
tertiary = Color(0xFF7ADC77), // Downloaded badge
|
||||||
onTertiary = Color(0xFF003909),
|
onTertiary = Color(0xFF003909), // Downloaded badge text
|
||||||
tertiaryContainer = Color(0xFF005312),
|
tertiaryContainer = Color(0xFF005312),
|
||||||
onTertiaryContainer = Color(0xFF95F990),
|
onTertiaryContainer = Color(0xFF95F990),
|
||||||
background = Color(0xFF1B1B1F),
|
background = Color(0xFF1B1B1F),
|
||||||
onBackground = Color(0xFFE3E2E6),
|
onBackground = Color(0xFFE3E2E6),
|
||||||
surface = Color(0xFF1B1B1F),
|
surface = Color(0xFF1B1B1F),
|
||||||
onSurface = Color(0xFFE3E2E6),
|
onSurface = Color(0xFFE3E2E6),
|
||||||
surfaceVariant = Color(0xFF44464F),
|
surfaceVariant = Color(0xFF211F26), // Navigation bar background (ThemePrefWidget)
|
||||||
onSurfaceVariant = Color(0xFFC5C6D0),
|
onSurfaceVariant = Color(0xFFC5C6D0),
|
||||||
surfaceTint = Color(0xFFB0C6FF),
|
surfaceTint = Color(0xFFB0C6FF),
|
||||||
inverseSurface = Color(0xFFE3E2E6),
|
inverseSurface = Color(0xFFE3E2E6),
|
||||||
@@ -45,6 +45,11 @@ internal object TachiyomiColorScheme : BaseColorScheme() {
|
|||||||
onErrorContainer = Color(0xFFFFDAD6),
|
onErrorContainer = Color(0xFFFFDAD6),
|
||||||
outline = Color(0xFF8F9099),
|
outline = Color(0xFF8F9099),
|
||||||
outlineVariant = Color(0xFF44464F),
|
outlineVariant = Color(0xFF44464F),
|
||||||
|
surfaceContainerLowest = Color(0xFF1A181D),
|
||||||
|
surfaceContainerLow = Color(0xFF1E1C22),
|
||||||
|
surfaceContainer = Color(0xFF211F26), // Navigation bar background
|
||||||
|
surfaceContainerHigh = Color(0xFF292730),
|
||||||
|
surfaceContainerHighest = Color(0xFF302E38),
|
||||||
)
|
)
|
||||||
|
|
||||||
override val lightScheme = lightColorScheme(
|
override val lightScheme = lightColorScheme(
|
||||||
@@ -53,19 +58,19 @@ internal object TachiyomiColorScheme : BaseColorScheme() {
|
|||||||
primaryContainer = Color(0xFFD9E2FF),
|
primaryContainer = Color(0xFFD9E2FF),
|
||||||
onPrimaryContainer = Color(0xFF001945),
|
onPrimaryContainer = Color(0xFF001945),
|
||||||
inversePrimary = Color(0xFFB0C6FF),
|
inversePrimary = Color(0xFFB0C6FF),
|
||||||
secondary = Color(0xFF0058CA),
|
secondary = Color(0xFF0058CA), // Unread badge
|
||||||
onSecondary = Color(0xFFFFFFFF),
|
onSecondary = Color(0xFFFFFFFF), // Unread badge text
|
||||||
secondaryContainer = Color(0xFFD9E2FF),
|
secondaryContainer = Color(0xFFD9E2FF), // Navigation bar selector pill & progress indicator (remaining)
|
||||||
onSecondaryContainer = Color(0xFF001945),
|
onSecondaryContainer = Color(0xFF001945), // Navigation bar selector icon
|
||||||
tertiary = Color(0xFF006E1B),
|
tertiary = Color(0xFF006E1B), // Downloaded badge
|
||||||
onTertiary = Color(0xFFFFFFFF),
|
onTertiary = Color(0xFFFFFFFF), // Downloaded badge text
|
||||||
tertiaryContainer = Color(0xFF95F990),
|
tertiaryContainer = Color(0xFF95F990),
|
||||||
onTertiaryContainer = Color(0xFF002203),
|
onTertiaryContainer = Color(0xFF002203),
|
||||||
background = Color(0xFFFEFBFF),
|
background = Color(0xFFFEFBFF),
|
||||||
onBackground = Color(0xFF1B1B1F),
|
onBackground = Color(0xFF1B1B1F),
|
||||||
surface = Color(0xFFFEFBFF),
|
surface = Color(0xFFFEFBFF),
|
||||||
onSurface = Color(0xFF1B1B1F),
|
onSurface = Color(0xFF1B1B1F),
|
||||||
surfaceVariant = Color(0xFFE1E2EC),
|
surfaceVariant = Color(0xFFF3EDF7), // Navigation bar background (ThemePrefWidget)
|
||||||
onSurfaceVariant = Color(0xFF44464F),
|
onSurfaceVariant = Color(0xFF44464F),
|
||||||
surfaceTint = Color(0xFF0058CA),
|
surfaceTint = Color(0xFF0058CA),
|
||||||
inverseSurface = Color(0xFF303034),
|
inverseSurface = Color(0xFF303034),
|
||||||
@@ -76,5 +81,10 @@ internal object TachiyomiColorScheme : BaseColorScheme() {
|
|||||||
onErrorContainer = Color(0xFF410002),
|
onErrorContainer = Color(0xFF410002),
|
||||||
outline = Color(0xFF757780),
|
outline = Color(0xFF757780),
|
||||||
outlineVariant = Color(0xFFC5C6D0),
|
outlineVariant = Color(0xFFC5C6D0),
|
||||||
|
surfaceContainerLowest = Color(0xFFF5F1F8),
|
||||||
|
surfaceContainerLow = Color(0xFFF7F2FA),
|
||||||
|
surfaceContainer = Color(0xFFF3EDF7), // Navigation bar background
|
||||||
|
surfaceContainerHigh = Color(0xFFFCF7FF),
|
||||||
|
surfaceContainerHighest = Color(0xFFFCF7FF),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,24 +23,29 @@ internal object TakoColorScheme : BaseColorScheme() {
|
|||||||
primaryContainer = Color(0xFFF3B375),
|
primaryContainer = Color(0xFFF3B375),
|
||||||
onPrimaryContainer = Color(0xFF38294E),
|
onPrimaryContainer = Color(0xFF38294E),
|
||||||
inversePrimary = Color(0xFF84531E),
|
inversePrimary = Color(0xFF84531E),
|
||||||
secondary = Color(0xFFF3B375),
|
secondary = Color(0xFFF3B375), // Unread badge
|
||||||
onSecondary = Color(0xFF38294E),
|
onSecondary = Color(0xFF38294E), // Unread badge text
|
||||||
secondaryContainer = Color(0xFFF3B375),
|
secondaryContainer = Color(0xFF5C4D4B), // Navigation bar selector pill & progress indicator (remaining)
|
||||||
onSecondaryContainer = Color(0xFF38294E),
|
onSecondaryContainer = Color(0xFFF3B375), // Navigation bar selector icon
|
||||||
tertiary = Color(0xFF66577E),
|
tertiary = Color(0xFF66577E), // Downloaded badge
|
||||||
onTertiary = Color(0xFFF3B375),
|
onTertiary = Color(0xFFF3B375), // Downloaded badge text
|
||||||
tertiaryContainer = Color(0xFF4E4065),
|
tertiaryContainer = Color(0xFF4E4065),
|
||||||
onTertiaryContainer = Color(0xFFEDDCFF),
|
onTertiaryContainer = Color(0xFFEDDCFF),
|
||||||
background = Color(0xFF21212E),
|
background = Color(0xFF21212E),
|
||||||
onBackground = Color(0xFFE3E0F2),
|
onBackground = Color(0xFFE3E0F2),
|
||||||
surface = Color(0xFF21212E),
|
surface = Color(0xFF21212E),
|
||||||
onSurface = Color(0xFFE3E0F2),
|
onSurface = Color(0xFFE3E0F2),
|
||||||
surfaceVariant = Color(0xFF49454E),
|
surfaceVariant = Color(0xFF2A2A3C), // Navigation bar background (ThemePrefWidget)
|
||||||
onSurfaceVariant = Color(0xFFCBC4CE),
|
onSurfaceVariant = Color(0xFFCBC4CE),
|
||||||
surfaceTint = Color(0xFF66577E),
|
surfaceTint = Color(0xFF66577E),
|
||||||
inverseSurface = Color(0xFFE5E1E6),
|
inverseSurface = Color(0xFFE5E1E6),
|
||||||
inverseOnSurface = Color(0xFF1B1B1E),
|
inverseOnSurface = Color(0xFF1B1B1E),
|
||||||
outline = Color(0xFF958F99),
|
outline = Color(0xFF958F99),
|
||||||
|
surfaceContainerLowest = Color(0xFF20202E),
|
||||||
|
surfaceContainerLow = Color(0xFF262636),
|
||||||
|
surfaceContainer = Color(0xFF2A2A3C), // Navigation bar background
|
||||||
|
surfaceContainerHigh = Color(0xFF303044),
|
||||||
|
surfaceContainerHighest = Color(0xFF36364D),
|
||||||
)
|
)
|
||||||
|
|
||||||
override val lightScheme = lightColorScheme(
|
override val lightScheme = lightColorScheme(
|
||||||
@@ -49,23 +54,28 @@ internal object TakoColorScheme : BaseColorScheme() {
|
|||||||
primaryContainer = Color(0xFF66577E),
|
primaryContainer = Color(0xFF66577E),
|
||||||
onPrimaryContainer = Color(0xFFF3B375),
|
onPrimaryContainer = Color(0xFFF3B375),
|
||||||
inversePrimary = Color(0xFFD6BAFF),
|
inversePrimary = Color(0xFFD6BAFF),
|
||||||
secondary = Color(0xFF66577E),
|
secondary = Color(0xFF66577E), // Unread badge
|
||||||
onSecondary = Color(0xFFF3B375),
|
onSecondary = Color(0xFFF3B375), // Unread badge text
|
||||||
secondaryContainer = Color(0xFF66577E),
|
secondaryContainer = Color(0xFFC8BED0), // Navigation bar selector pill & progress indicator (remaining)
|
||||||
onSecondaryContainer = Color(0xFFF3B375),
|
onSecondaryContainer = Color(0xFF66577E), // Navigation bar selector icon
|
||||||
tertiary = Color(0xFFF3B375),
|
tertiary = Color(0xFFF3B375), // Downloaded badge
|
||||||
onTertiary = Color(0xFF574360),
|
onTertiary = Color(0xFF574360), // Downloaded badge text
|
||||||
tertiaryContainer = Color(0xFFFDD6B0),
|
tertiaryContainer = Color(0xFFFDD6B0),
|
||||||
onTertiaryContainer = Color(0xFF221437),
|
onTertiaryContainer = Color(0xFF221437),
|
||||||
background = Color(0xFFF7F5FF),
|
background = Color(0xFFF7F5FF),
|
||||||
onBackground = Color(0xFF1B1B22),
|
onBackground = Color(0xFF1B1B22),
|
||||||
surface = Color(0xFFF7F5FF),
|
surface = Color(0xFFF7F5FF),
|
||||||
onSurface = Color(0xFF1B1B22),
|
onSurface = Color(0xFF1B1B22),
|
||||||
surfaceVariant = Color(0xFFE8E0EB),
|
surfaceVariant = Color(0xFFE8E0EB), // Navigation bar background (ThemePrefWidget)
|
||||||
onSurfaceVariant = Color(0xFF49454E),
|
onSurfaceVariant = Color(0xFF49454E),
|
||||||
surfaceTint = Color(0xFF66577E),
|
surfaceTint = Color(0xFF66577E),
|
||||||
inverseSurface = Color(0xFF313033),
|
inverseSurface = Color(0xFF313033),
|
||||||
inverseOnSurface = Color(0xFFF3EFF4),
|
inverseOnSurface = Color(0xFFF3EFF4),
|
||||||
outline = Color(0xFF7A757E),
|
outline = Color(0xFF7A757E),
|
||||||
|
surfaceContainerLowest = Color(0xFFD7D0DA),
|
||||||
|
surfaceContainerLow = Color(0xFFDFD8E2),
|
||||||
|
surfaceContainer = Color(0xFFE8E0EB), // Navigation bar background
|
||||||
|
surfaceContainerHigh = Color(0xFFEEE6F1),
|
||||||
|
surfaceContainerHighest = Color(0xFFF7EEFA),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+24
-14
@@ -15,24 +15,29 @@ internal object TealTurqoiseColorScheme : BaseColorScheme() {
|
|||||||
primaryContainer = Color(0xFF40E0D0),
|
primaryContainer = Color(0xFF40E0D0),
|
||||||
onPrimaryContainer = Color(0xFF000000),
|
onPrimaryContainer = Color(0xFF000000),
|
||||||
inversePrimary = Color(0xFF008080),
|
inversePrimary = Color(0xFF008080),
|
||||||
secondary = Color(0xFF40E0D0),
|
secondary = Color(0xFF40E0D0), // Unread badge
|
||||||
onSecondary = Color(0xFF000000),
|
onSecondary = Color(0xFF000000), // Unread badge text
|
||||||
secondaryContainer = Color(0xFF18544E),
|
secondaryContainer = Color(0xFF18544E), // Navigation bar selector pill & progress indicator (remaining)
|
||||||
onSecondaryContainer = Color(0xFF40E0D0),
|
onSecondaryContainer = Color(0xFF40E0D0), // Navigation bar selector icon
|
||||||
tertiary = Color(0xFFBF1F2F),
|
tertiary = Color(0xFFBF1F2F), // Downloaded badge
|
||||||
onTertiary = Color(0xFFFFFFFF),
|
onTertiary = Color(0xFFFFFFFF), // Downloaded badge text
|
||||||
tertiaryContainer = Color(0xFF200508),
|
tertiaryContainer = Color(0xFF200508),
|
||||||
onTertiaryContainer = Color(0xFFBF1F2F),
|
onTertiaryContainer = Color(0xFFBF1F2F),
|
||||||
background = Color(0xFF202125),
|
background = Color(0xFF202125),
|
||||||
onBackground = Color(0xFFDFDEDA),
|
onBackground = Color(0xFFDFDEDA),
|
||||||
surface = Color(0xFF202125),
|
surface = Color(0xFF202125),
|
||||||
onSurface = Color(0xFFDFDEDA),
|
onSurface = Color(0xFFDFDEDA),
|
||||||
surfaceVariant = Color(0xFF3F4947),
|
surfaceVariant = Color(0xFF233133), // Navigation bar background (ThemePrefWidget)
|
||||||
onSurfaceVariant = Color(0xFFDFDEDA),
|
onSurfaceVariant = Color(0xFFDFDEDA),
|
||||||
surfaceTint = Color(0xFF40E0D0),
|
surfaceTint = Color(0xFF40E0D0),
|
||||||
inverseSurface = Color(0xFFDFDEDA),
|
inverseSurface = Color(0xFFDFDEDA),
|
||||||
inverseOnSurface = Color(0xFF202125),
|
inverseOnSurface = Color(0xFF202125),
|
||||||
outline = Color(0xFF899391),
|
outline = Color(0xFF899391),
|
||||||
|
surfaceContainerLowest = Color(0xFF202C2E),
|
||||||
|
surfaceContainerLow = Color(0xFF222F31),
|
||||||
|
surfaceContainer = Color(0xFF233133), // Navigation bar background
|
||||||
|
surfaceContainerHigh = Color(0xFF28383A),
|
||||||
|
surfaceContainerHighest = Color(0xFF2F4244),
|
||||||
)
|
)
|
||||||
|
|
||||||
override val lightScheme = lightColorScheme(
|
override val lightScheme = lightColorScheme(
|
||||||
@@ -41,23 +46,28 @@ internal object TealTurqoiseColorScheme : BaseColorScheme() {
|
|||||||
primaryContainer = Color(0xFF008080),
|
primaryContainer = Color(0xFF008080),
|
||||||
onPrimaryContainer = Color(0xFFFFFFFF),
|
onPrimaryContainer = Color(0xFFFFFFFF),
|
||||||
inversePrimary = Color(0xFF40E0D0),
|
inversePrimary = Color(0xFF40E0D0),
|
||||||
secondary = Color(0xFF008080),
|
secondary = Color(0xFF008080), // Unread badge text
|
||||||
onSecondary = Color(0xFFFFFFFF),
|
onSecondary = Color(0xFFFFFFFF), // Unread badge text
|
||||||
secondaryContainer = Color(0xFFBFDFDF),
|
secondaryContainer = Color(0xFFCFE5E4), // Navigation bar selector pill & progress indicator (remaining)
|
||||||
onSecondaryContainer = Color(0xFF008080),
|
onSecondaryContainer = Color(0xFF008080), // Navigation bar selector icon
|
||||||
tertiary = Color(0xFFFF7F7F),
|
tertiary = Color(0xFFFF7F7F), // Downloaded badge
|
||||||
onTertiary = Color(0xFF000000),
|
onTertiary = Color(0xFF000000), // Downloaded badge text
|
||||||
tertiaryContainer = Color(0xFF2A1616),
|
tertiaryContainer = Color(0xFF2A1616),
|
||||||
onTertiaryContainer = Color(0xFFFF7F7F),
|
onTertiaryContainer = Color(0xFFFF7F7F),
|
||||||
background = Color(0xFFFAFAFA),
|
background = Color(0xFFFAFAFA),
|
||||||
onBackground = Color(0xFF050505),
|
onBackground = Color(0xFF050505),
|
||||||
surface = Color(0xFFFAFAFA),
|
surface = Color(0xFFFAFAFA),
|
||||||
onSurface = Color(0xFF050505),
|
onSurface = Color(0xFF050505),
|
||||||
surfaceVariant = Color(0xFFDAE5E2),
|
surfaceVariant = Color(0xFFEBF3F1), // Navigation bar background (ThemePrefWidget)
|
||||||
onSurfaceVariant = Color(0xFF050505),
|
onSurfaceVariant = Color(0xFF050505),
|
||||||
surfaceTint = Color(0xFFBFDFDF),
|
surfaceTint = Color(0xFFBFDFDF),
|
||||||
inverseSurface = Color(0xFF050505),
|
inverseSurface = Color(0xFF050505),
|
||||||
inverseOnSurface = Color(0xFFFAFAFA),
|
inverseOnSurface = Color(0xFFFAFAFA),
|
||||||
outline = Color(0xFF6F7977),
|
outline = Color(0xFF6F7977),
|
||||||
|
surfaceContainerLowest = Color(0xFFE1E9E7),
|
||||||
|
surfaceContainerLow = Color(0xFFE6EEEC),
|
||||||
|
surfaceContainer = Color(0xFFEBF3F1), // Navigation bar background
|
||||||
|
surfaceContainerHigh = Color(0xFFF0F8F6),
|
||||||
|
surfaceContainerHighest = Color(0xFFF7FFFD),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+24
-14
@@ -22,24 +22,29 @@ internal object TidalWaveColorScheme : BaseColorScheme() {
|
|||||||
primaryContainer = Color(0xFF004d61),
|
primaryContainer = Color(0xFF004d61),
|
||||||
onPrimaryContainer = Color(0xFFb8eaff),
|
onPrimaryContainer = Color(0xFFb8eaff),
|
||||||
inversePrimary = Color(0xFFa12b03),
|
inversePrimary = Color(0xFFa12b03),
|
||||||
secondary = Color(0xFF5ed4fc),
|
secondary = Color(0xFF5ed4fc), // Unread badge
|
||||||
onSecondary = Color(0xFF003544),
|
onSecondary = Color(0xFF003544), // Unread badge text
|
||||||
secondaryContainer = Color(0xFF004d61),
|
secondaryContainer = Color(0xFF004d61), // Navigation bar selector pill & progress indicator (remaining)
|
||||||
onSecondaryContainer = Color(0xFFb8eaff),
|
onSecondaryContainer = Color(0xFFb8eaff), // Navigation bar selector icon
|
||||||
tertiary = Color(0xFF92f7bc),
|
tertiary = Color(0xFF92f7bc), // Downloaded badge
|
||||||
onTertiary = Color(0xFF001c3b),
|
onTertiary = Color(0xFF001c3b), // Downloaded badge text
|
||||||
tertiaryContainer = Color(0xFFc3fada),
|
tertiaryContainer = Color(0xFFc3fada),
|
||||||
onTertiaryContainer = Color(0xFF78ffd6),
|
onTertiaryContainer = Color(0xFF78ffd6),
|
||||||
background = Color(0xFF001c3b),
|
background = Color(0xFF001c3b),
|
||||||
onBackground = Color(0xFFd5e3ff),
|
onBackground = Color(0xFFd5e3ff),
|
||||||
surface = Color(0xFF001c3b),
|
surface = Color(0xFF001c3b),
|
||||||
onSurface = Color(0xFFd5e3ff),
|
onSurface = Color(0xFFd5e3ff),
|
||||||
surfaceVariant = Color(0xFF40484c),
|
surfaceVariant = Color(0xFF082b4b), // Navigation bar background (ThemePrefWidget)
|
||||||
onSurfaceVariant = Color(0xFFbfc8cc),
|
onSurfaceVariant = Color(0xFFbfc8cc),
|
||||||
surfaceTint = Color(0xFF5ed4fc),
|
surfaceTint = Color(0xFF5ed4fc),
|
||||||
inverseSurface = Color(0xFFffe3c4),
|
inverseSurface = Color(0xFFffe3c4),
|
||||||
inverseOnSurface = Color(0xFF001c3b),
|
inverseOnSurface = Color(0xFF001c3b),
|
||||||
outline = Color(0xFF8a9296),
|
outline = Color(0xFF8a9296),
|
||||||
|
surfaceContainerLowest = Color(0xFF072642),
|
||||||
|
surfaceContainerLow = Color(0xFF072947),
|
||||||
|
surfaceContainer = Color(0xFF082b4b), // Navigation bar background
|
||||||
|
surfaceContainerHigh = Color(0xFF093257),
|
||||||
|
surfaceContainerHighest = Color(0xFF0A3861),
|
||||||
)
|
)
|
||||||
|
|
||||||
override val lightScheme = lightColorScheme(
|
override val lightScheme = lightColorScheme(
|
||||||
@@ -48,23 +53,28 @@ internal object TidalWaveColorScheme : BaseColorScheme() {
|
|||||||
primaryContainer = Color(0xFFB4D4DF),
|
primaryContainer = Color(0xFFB4D4DF),
|
||||||
onPrimaryContainer = Color(0xFF001f28),
|
onPrimaryContainer = Color(0xFF001f28),
|
||||||
inversePrimary = Color(0xFFff987f),
|
inversePrimary = Color(0xFFff987f),
|
||||||
secondary = Color(0xFF006780),
|
secondary = Color(0xFF006780), // Unread badge
|
||||||
onSecondary = Color(0xFFffffff),
|
onSecondary = Color(0xFFffffff), // Unread badge text
|
||||||
secondaryContainer = Color(0xFFb8eaff),
|
secondaryContainer = Color(0xFF9AE1FF), // Navigation bar selector pill & progress indicator (remaining)
|
||||||
onSecondaryContainer = Color(0xFF001f28),
|
onSecondaryContainer = Color(0xFF001f28), // Navigation bar selector icon
|
||||||
tertiary = Color(0xFF92f7bc),
|
tertiary = Color(0xFF92f7bc), // Downloaded badge
|
||||||
onTertiary = Color(0xFF001c3b),
|
onTertiary = Color(0xFF001c3b), // Downloaded badge text
|
||||||
tertiaryContainer = Color(0xFFc3fada),
|
tertiaryContainer = Color(0xFFc3fada),
|
||||||
onTertiaryContainer = Color(0xFF78ffd6),
|
onTertiaryContainer = Color(0xFF78ffd6),
|
||||||
background = Color(0xFFfdfbff),
|
background = Color(0xFFfdfbff),
|
||||||
onBackground = Color(0xFF001c3b),
|
onBackground = Color(0xFF001c3b),
|
||||||
surface = Color(0xFFfdfbff),
|
surface = Color(0xFFfdfbff),
|
||||||
onSurface = Color(0xFF001c3b),
|
onSurface = Color(0xFF001c3b),
|
||||||
surfaceVariant = Color(0xFFdce4e8),
|
surfaceVariant = Color(0xFFe8eff5), // Navigation bar background (ThemePrefWidget)
|
||||||
onSurfaceVariant = Color(0xFF40484c),
|
onSurfaceVariant = Color(0xFF40484c),
|
||||||
surfaceTint = Color(0xFF006780),
|
surfaceTint = Color(0xFF006780),
|
||||||
inverseSurface = Color(0xFF020400),
|
inverseSurface = Color(0xFF020400),
|
||||||
inverseOnSurface = Color(0xFFffe3c4),
|
inverseOnSurface = Color(0xFFffe3c4),
|
||||||
outline = Color(0xFF70787c),
|
outline = Color(0xFF70787c),
|
||||||
|
surfaceContainerLowest = Color(0xFFe2e8ec),
|
||||||
|
surfaceContainerLow = Color(0xFFe5ecf1),
|
||||||
|
surfaceContainer = Color(0xFFe8eff5), // Navigation bar background
|
||||||
|
surfaceContainerHigh = Color(0xFFedf4fA),
|
||||||
|
surfaceContainerHighest = Color(0xFFf5faff),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,24 +17,29 @@ internal object YinYangColorScheme : BaseColorScheme() {
|
|||||||
primaryContainer = Color(0xFFFFFFFF),
|
primaryContainer = Color(0xFFFFFFFF),
|
||||||
onPrimaryContainer = Color(0xFF000000),
|
onPrimaryContainer = Color(0xFF000000),
|
||||||
inversePrimary = Color(0xFFCECECE),
|
inversePrimary = Color(0xFFCECECE),
|
||||||
secondary = Color(0xFFFFFFFF),
|
secondary = Color(0xFFFFFFFF), // Unread badge
|
||||||
onSecondary = Color(0xFF5A5A5A),
|
onSecondary = Color(0xFF5A5A5A), // Unread badge text
|
||||||
secondaryContainer = Color(0xFF717171),
|
secondaryContainer = Color(0xFF717171), // Navigation bar selector pill & progress indicator (remaining)
|
||||||
onSecondaryContainer = Color(0xFFE4E4E4),
|
onSecondaryContainer = Color(0xFFE4E4E4), // Navigation bar selector icon
|
||||||
tertiary = Color(0xFF000000),
|
tertiary = Color(0xFF000000), // Downloaded badge
|
||||||
onTertiary = Color(0xFFFFFFFF),
|
onTertiary = Color(0xFFFFFFFF), // Downloaded badge text
|
||||||
tertiaryContainer = Color(0xFF00419E),
|
tertiaryContainer = Color(0xFF00419E),
|
||||||
onTertiaryContainer = Color(0xFFD8E2FF),
|
onTertiaryContainer = Color(0xFFD8E2FF),
|
||||||
background = Color(0xFF1E1E1E),
|
background = Color(0xFF1E1E1E),
|
||||||
onBackground = Color(0xFFE6E6E6),
|
onBackground = Color(0xFFE6E6E6),
|
||||||
surface = Color(0xFF1E1E1E),
|
surface = Color(0xFF1E1E1E),
|
||||||
onSurface = Color(0xFFE6E6E6),
|
onSurface = Color(0xFFE6E6E6),
|
||||||
surfaceVariant = Color(0xFF4E4E4E),
|
surfaceVariant = Color(0xFF313131), // Navigation bar background (ThemePrefWidget)
|
||||||
onSurfaceVariant = Color(0xFFD1D1D1),
|
onSurfaceVariant = Color(0xFFD1D1D1),
|
||||||
surfaceTint = Color(0xFFFFFFFF),
|
surfaceTint = Color(0xFFFFFFFF),
|
||||||
inverseSurface = Color(0xFFE6E6E6),
|
inverseSurface = Color(0xFFE6E6E6),
|
||||||
inverseOnSurface = Color(0xFF1E1E1E),
|
inverseOnSurface = Color(0xFF1E1E1E),
|
||||||
outline = Color(0xFF999999),
|
outline = Color(0xFF999999),
|
||||||
|
surfaceContainerLowest = Color(0xFF2A2A2A),
|
||||||
|
surfaceContainerLow = Color(0xFF2D2D2D),
|
||||||
|
surfaceContainer = Color(0xFF313131), // Navigation bar background
|
||||||
|
surfaceContainerHigh = Color(0xFF383838),
|
||||||
|
surfaceContainerHighest = Color(0xFF3F3F3F),
|
||||||
)
|
)
|
||||||
|
|
||||||
override val lightScheme = lightColorScheme(
|
override val lightScheme = lightColorScheme(
|
||||||
@@ -43,23 +48,28 @@ internal object YinYangColorScheme : BaseColorScheme() {
|
|||||||
primaryContainer = Color(0xFF000000),
|
primaryContainer = Color(0xFF000000),
|
||||||
onPrimaryContainer = Color(0xFFFFFFFF),
|
onPrimaryContainer = Color(0xFFFFFFFF),
|
||||||
inversePrimary = Color(0xFFA6A6A6),
|
inversePrimary = Color(0xFFA6A6A6),
|
||||||
secondary = Color(0xFF000000),
|
secondary = Color(0xFF000000), // Unread badge
|
||||||
onSecondary = Color(0xFFFFFFFF),
|
onSecondary = Color(0xFFFFFFFF), // Unread badge text
|
||||||
secondaryContainer = Color(0xFFDDDDDD),
|
secondaryContainer = Color(0xFFDDDDDD), // Navigation bar selector pill & progress indicator (remaining)
|
||||||
onSecondaryContainer = Color(0xFF0C0C0C),
|
onSecondaryContainer = Color(0xFF0C0C0C), // Navigation bar selector icon
|
||||||
tertiary = Color(0xFFFFFFFF),
|
tertiary = Color(0xFFFFFFFF), // Downloaded badge
|
||||||
onTertiary = Color(0xFF000000),
|
onTertiary = Color(0xFF000000), // Downloaded badge text
|
||||||
tertiaryContainer = Color(0xFFD8E2FF),
|
tertiaryContainer = Color(0xFFD8E2FF),
|
||||||
onTertiaryContainer = Color(0xFF001947),
|
onTertiaryContainer = Color(0xFF001947),
|
||||||
background = Color(0xFFFDFDFD),
|
background = Color(0xFFFDFDFD),
|
||||||
onBackground = Color(0xFF222222),
|
onBackground = Color(0xFF222222),
|
||||||
surface = Color(0xFFFDFDFD),
|
surface = Color(0xFFFDFDFD),
|
||||||
onSurface = Color(0xFF222222),
|
onSurface = Color(0xFF222222),
|
||||||
surfaceVariant = Color(0xFFEDEDED),
|
surfaceVariant = Color(0xFFE8E8E8), // Navigation bar background (ThemePrefWidget)
|
||||||
onSurfaceVariant = Color(0xFF515151),
|
onSurfaceVariant = Color(0xFF515151),
|
||||||
surfaceTint = Color(0xFF000000),
|
surfaceTint = Color(0xFF000000),
|
||||||
inverseSurface = Color(0xFF333333),
|
inverseSurface = Color(0xFF333333),
|
||||||
inverseOnSurface = Color(0xFFF4F4F4),
|
inverseOnSurface = Color(0xFFF4F4F4),
|
||||||
outline = Color(0xFF838383),
|
outline = Color(0xFF838383),
|
||||||
|
surfaceContainerLowest = Color(0xFFCFCFCF),
|
||||||
|
surfaceContainerLow = Color(0xFFDADADA),
|
||||||
|
surfaceContainer = Color(0xFFE8E8E8), // Navigation bar background
|
||||||
|
surfaceContainerHigh = Color(0xFFECECEC),
|
||||||
|
surfaceContainerHighest = Color(0xFFEFEFEF),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,24 +23,29 @@ internal object YotsubaColorScheme : BaseColorScheme() {
|
|||||||
primaryContainer = Color(0xFF862200),
|
primaryContainer = Color(0xFF862200),
|
||||||
onPrimaryContainer = Color(0xFFFFDBCF),
|
onPrimaryContainer = Color(0xFFFFDBCF),
|
||||||
inversePrimary = Color(0xFFAE3200),
|
inversePrimary = Color(0xFFAE3200),
|
||||||
secondary = Color(0xFFFFB59D),
|
secondary = Color(0xFFFFB59D), // Unread badge
|
||||||
onSecondary = Color(0xFF5F1600),
|
onSecondary = Color(0xFF5F1600), // Unread badge text
|
||||||
secondaryContainer = Color(0xFF862200),
|
secondaryContainer = Color(0xFF862200), // Navigation bar selector pill & progress indicator (remaining)
|
||||||
onSecondaryContainer = Color(0xFFFFDBCF),
|
onSecondaryContainer = Color(0xFFFFDBCF), // Navigation bar selector icon
|
||||||
tertiary = Color(0xFFD7C68D),
|
tertiary = Color(0xFFD7C68D), // Downloaded badge
|
||||||
onTertiary = Color(0xFF3A2F05),
|
onTertiary = Color(0xFF3A2F05), // Downloaded badge text
|
||||||
tertiaryContainer = Color(0xFF524619),
|
tertiaryContainer = Color(0xFF524619),
|
||||||
onTertiaryContainer = Color(0xFFF5E2A7),
|
onTertiaryContainer = Color(0xFFF5E2A7),
|
||||||
background = Color(0xFF211A18),
|
background = Color(0xFF211A18),
|
||||||
onBackground = Color(0xFFEDE0DD),
|
onBackground = Color(0xFFEDE0DD),
|
||||||
surface = Color(0xFF211A18),
|
surface = Color(0xFF211A18),
|
||||||
onSurface = Color(0xFFEDE0DD),
|
onSurface = Color(0xFFEDE0DD),
|
||||||
surfaceVariant = Color(0xFF53433F),
|
surfaceVariant = Color(0xFF332723), // Navigation bar background (ThemePrefWidget)
|
||||||
onSurfaceVariant = Color(0xFFD8C2BC),
|
onSurfaceVariant = Color(0xFFD8C2BC),
|
||||||
surfaceTint = Color(0xFFFFB59D),
|
surfaceTint = Color(0xFFFFB59D),
|
||||||
inverseSurface = Color(0xFFEDE0DD),
|
inverseSurface = Color(0xFFEDE0DD),
|
||||||
inverseOnSurface = Color(0xFF211A18),
|
inverseOnSurface = Color(0xFF211A18),
|
||||||
outline = Color(0xFFA08C87),
|
outline = Color(0xFFA08C87),
|
||||||
|
surfaceContainerLowest = Color(0xFF2E221F),
|
||||||
|
surfaceContainerLow = Color(0xFF312521),
|
||||||
|
surfaceContainer = Color(0xFF332723), // Navigation bar background
|
||||||
|
surfaceContainerHigh = Color(0xFF413531),
|
||||||
|
surfaceContainerHighest = Color(0xFF4C403D),
|
||||||
)
|
)
|
||||||
|
|
||||||
override val lightScheme = lightColorScheme(
|
override val lightScheme = lightColorScheme(
|
||||||
@@ -49,23 +54,28 @@ internal object YotsubaColorScheme : BaseColorScheme() {
|
|||||||
primaryContainer = Color(0xFFFFDBCF),
|
primaryContainer = Color(0xFFFFDBCF),
|
||||||
onPrimaryContainer = Color(0xFF3B0A00),
|
onPrimaryContainer = Color(0xFF3B0A00),
|
||||||
inversePrimary = Color(0xFFFFB59D),
|
inversePrimary = Color(0xFFFFB59D),
|
||||||
secondary = Color(0xFFAE3200),
|
secondary = Color(0xFFAE3200), // Unread badge
|
||||||
onSecondary = Color(0xFFFFFFFF),
|
onSecondary = Color(0xFFFFFFFF), // Unread badge text
|
||||||
secondaryContainer = Color(0xFFFFDBCF),
|
secondaryContainer = Color(0xFFEBCDC2), // Navigation bar selector pill & progress indicator (remaining)
|
||||||
onSecondaryContainer = Color(0xFF3B0A00),
|
onSecondaryContainer = Color(0xFF3B0A00), // Navigation bar selector icon
|
||||||
tertiary = Color(0xFF6B5E2F),
|
tertiary = Color(0xFF6B5E2F), // Downloaded badge
|
||||||
onTertiary = Color(0xFFFFFFFF),
|
onTertiary = Color(0xFFFFFFFF), // Downloaded badge text
|
||||||
tertiaryContainer = Color(0xFFF5E2A7),
|
tertiaryContainer = Color(0xFFF5E2A7),
|
||||||
onTertiaryContainer = Color(0xFF231B00),
|
onTertiaryContainer = Color(0xFF231B00),
|
||||||
background = Color(0xFFFCFCFC),
|
background = Color(0xFFFCFCFC),
|
||||||
onBackground = Color(0xFF211A18),
|
onBackground = Color(0xFF211A18),
|
||||||
surface = Color(0xFFFCFCFC),
|
surface = Color(0xFFFCFCFC),
|
||||||
onSurface = Color(0xFF211A18),
|
onSurface = Color(0xFF211A18),
|
||||||
surfaceVariant = Color(0xFFF5DED8),
|
surfaceVariant = Color(0xFFF6EBE7), // Navigation bar background (ThemePrefWidget)
|
||||||
onSurfaceVariant = Color(0xFF53433F),
|
onSurfaceVariant = Color(0xFF53433F),
|
||||||
surfaceTint = Color(0xFFAE3200),
|
surfaceTint = Color(0xFFAE3200),
|
||||||
inverseSurface = Color(0xFF362F2D),
|
inverseSurface = Color(0xFF362F2D),
|
||||||
inverseOnSurface = Color(0xFFFBEEEB),
|
inverseOnSurface = Color(0xFFFBEEEB),
|
||||||
outline = Color(0xFF85736E),
|
outline = Color(0xFF85736E),
|
||||||
|
surfaceContainerLowest = Color(0xFFECE3E0),
|
||||||
|
surfaceContainerLow = Color(0xFFF1E7E4),
|
||||||
|
surfaceContainer = Color(0xFFF6EBE7), // Navigation bar background
|
||||||
|
surfaceContainerHigh = Color(0xFFFAF4F2),
|
||||||
|
surfaceContainerHighest = Color(0xFFFBF6F4),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ fun TrackInfoDialogHome(
|
|||||||
onNewSearch: (TrackItem) -> Unit,
|
onNewSearch: (TrackItem) -> Unit,
|
||||||
onOpenInBrowser: (TrackItem) -> Unit,
|
onOpenInBrowser: (TrackItem) -> Unit,
|
||||||
onRemoved: (TrackItem) -> Unit,
|
onRemoved: (TrackItem) -> Unit,
|
||||||
|
onCopyLink: (TrackItem) -> Unit,
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@@ -116,6 +117,7 @@ fun TrackInfoDialogHome(
|
|||||||
onNewSearch = { onNewSearch(item) },
|
onNewSearch = { onNewSearch(item) },
|
||||||
onOpenInBrowser = { onOpenInBrowser(item) },
|
onOpenInBrowser = { onOpenInBrowser(item) },
|
||||||
onRemoved = { onRemoved(item) },
|
onRemoved = { onRemoved(item) },
|
||||||
|
onCopyLink = { onCopyLink(item) },
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
TrackInfoItemEmpty(
|
TrackInfoItemEmpty(
|
||||||
@@ -144,6 +146,7 @@ private fun TrackInfoItem(
|
|||||||
onNewSearch: () -> Unit,
|
onNewSearch: () -> Unit,
|
||||||
onOpenInBrowser: () -> Unit,
|
onOpenInBrowser: () -> Unit,
|
||||||
onRemoved: () -> Unit,
|
onRemoved: () -> Unit,
|
||||||
|
onCopyLink: () -> Unit,
|
||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
Column {
|
Column {
|
||||||
@@ -153,6 +156,7 @@ private fun TrackInfoItem(
|
|||||||
TrackLogoIcon(
|
TrackLogoIcon(
|
||||||
tracker = tracker,
|
tracker = tracker,
|
||||||
onClick = onOpenInBrowser,
|
onClick = onOpenInBrowser,
|
||||||
|
onLongClick = onCopyLink,
|
||||||
)
|
)
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@@ -179,6 +183,7 @@ private fun TrackInfoItem(
|
|||||||
TrackInfoItemMenu(
|
TrackInfoItemMenu(
|
||||||
onOpenInBrowser = onOpenInBrowser,
|
onOpenInBrowser = onOpenInBrowser,
|
||||||
onRemoved = onRemoved,
|
onRemoved = onRemoved,
|
||||||
|
onCopyLink = onCopyLink,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,7 +191,7 @@ private fun TrackInfoItem(
|
|||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(top = 12.dp)
|
.padding(top = 12.dp)
|
||||||
.clip(MaterialTheme.shapes.medium)
|
.clip(MaterialTheme.shapes.medium)
|
||||||
.background(MaterialTheme.colorScheme.surface)
|
.background(MaterialTheme.colorScheme.surfaceContainerHighest)
|
||||||
.padding(8.dp)
|
.padding(8.dp)
|
||||||
.clip(RoundedCornerShape(6.dp)),
|
.clip(RoundedCornerShape(6.dp)),
|
||||||
) {
|
) {
|
||||||
@@ -287,6 +292,7 @@ private fun TrackInfoItemEmpty(
|
|||||||
private fun TrackInfoItemMenu(
|
private fun TrackInfoItemMenu(
|
||||||
onOpenInBrowser: () -> Unit,
|
onOpenInBrowser: () -> Unit,
|
||||||
onRemoved: () -> Unit,
|
onRemoved: () -> Unit,
|
||||||
|
onCopyLink: () -> Unit,
|
||||||
) {
|
) {
|
||||||
var expanded by remember { mutableStateOf(false) }
|
var expanded by remember { mutableStateOf(false) }
|
||||||
Box(modifier = Modifier.wrapContentSize(Alignment.TopStart)) {
|
Box(modifier = Modifier.wrapContentSize(Alignment.TopStart)) {
|
||||||
@@ -307,6 +313,13 @@ private fun TrackInfoItemMenu(
|
|||||||
expanded = false
|
expanded = false
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
DropdownMenuItem(
|
||||||
|
text = { Text(stringResource(MR.strings.action_copy_link)) },
|
||||||
|
onClick = {
|
||||||
|
onCopyLink()
|
||||||
|
expanded = false
|
||||||
|
},
|
||||||
|
)
|
||||||
DropdownMenuItem(
|
DropdownMenuItem(
|
||||||
text = { Text(stringResource(MR.strings.action_remove)) },
|
text = { Text(stringResource(MR.strings.action_remove)) },
|
||||||
onClick = {
|
onClick = {
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ internal class TrackInfoDialogHomePreviewProvider :
|
|||||||
onNewSearch = {},
|
onNewSearch = {},
|
||||||
onOpenInBrowser = {},
|
onOpenInBrowser = {},
|
||||||
onRemoved = {},
|
onRemoved = {},
|
||||||
|
onCopyLink = {},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,6 +72,7 @@ internal class TrackInfoDialogHomePreviewProvider :
|
|||||||
onNewSearch = {},
|
onNewSearch = {},
|
||||||
onOpenInBrowser = {},
|
onOpenInBrowser = {},
|
||||||
onRemoved = {},
|
onRemoved = {},
|
||||||
|
onCopyLink = {},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,8 @@ import tachiyomi.presentation.core.components.WheelTextPicker
|
|||||||
import tachiyomi.presentation.core.components.material.AlertDialogContent
|
import tachiyomi.presentation.core.components.material.AlertDialogContent
|
||||||
import tachiyomi.presentation.core.components.material.padding
|
import tachiyomi.presentation.core.components.material.padding
|
||||||
import tachiyomi.presentation.core.i18n.stringResource
|
import tachiyomi.presentation.core.i18n.stringResource
|
||||||
|
import tachiyomi.presentation.core.util.isScrolledToEnd
|
||||||
|
import tachiyomi.presentation.core.util.isScrolledToStart
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun TrackStatusSelector(
|
fun TrackStatusSelector(
|
||||||
@@ -84,8 +86,8 @@ fun TrackStatusSelector(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (state.canScrollBackward) HorizontalDivider(modifier = Modifier.align(Alignment.TopCenter))
|
if (!state.isScrolledToStart()) HorizontalDivider(modifier = Modifier.align(Alignment.TopCenter))
|
||||||
if (state.canScrollForward) HorizontalDivider(modifier = Modifier.align(Alignment.BottomCenter))
|
if (!state.isScrolledToEnd()) HorizontalDivider(modifier = Modifier.align(Alignment.BottomCenter))
|
||||||
},
|
},
|
||||||
onConfirm = onConfirm,
|
onConfirm = onConfirm,
|
||||||
onDismissRequest = onDismissRequest,
|
onDismissRequest = onDismissRequest,
|
||||||
|
|||||||
@@ -22,9 +22,10 @@ import tachiyomi.presentation.core.util.clickableNoIndication
|
|||||||
fun TrackLogoIcon(
|
fun TrackLogoIcon(
|
||||||
tracker: Tracker,
|
tracker: Tracker,
|
||||||
onClick: (() -> Unit)? = null,
|
onClick: (() -> Unit)? = null,
|
||||||
|
onLongClick: (() -> Unit)? = null,
|
||||||
) {
|
) {
|
||||||
val modifier = if (onClick != null) {
|
val modifier = if (onClick != null) {
|
||||||
Modifier.clickableNoIndication(onClick = onClick)
|
Modifier.clickableNoIndication(onClick = onClick, onLongClick = onLongClick)
|
||||||
} else {
|
} else {
|
||||||
Modifier
|
Modifier
|
||||||
}
|
}
|
||||||
@@ -53,6 +54,7 @@ private fun TrackLogoIconPreviews(
|
|||||||
TrackLogoIcon(
|
TrackLogoIcon(
|
||||||
tracker = tracker,
|
tracker = tracker,
|
||||||
onClick = null,
|
onClick = null,
|
||||||
|
onLongClick = null,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ internal fun LazyListScope.updatesLastUpdatedItem(
|
|||||||
item(key = "updates-lastUpdated") {
|
item(key = "updates-lastUpdated") {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.animateItem()
|
.animateItemPlacement()
|
||||||
.padding(horizontal = MaterialTheme.padding.medium, vertical = MaterialTheme.padding.small),
|
.padding(horizontal = MaterialTheme.padding.medium, vertical = MaterialTheme.padding.small),
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
@@ -94,14 +94,14 @@ internal fun LazyListScope.updatesUiItems(
|
|||||||
when (item) {
|
when (item) {
|
||||||
is UpdatesUiModel.Header -> {
|
is UpdatesUiModel.Header -> {
|
||||||
ListGroupHeader(
|
ListGroupHeader(
|
||||||
modifier = Modifier.animateItem(),
|
modifier = Modifier.animateItemPlacement(),
|
||||||
text = relativeDateText(item.date),
|
text = relativeDateText(item.date),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
is UpdatesUiModel.Item -> {
|
is UpdatesUiModel.Item -> {
|
||||||
val updatesItem = item.item
|
val updatesItem = item.item
|
||||||
UpdatesUiItem(
|
UpdatesUiItem(
|
||||||
modifier = Modifier.animateItem(),
|
modifier = Modifier.animateItemPlacement(),
|
||||||
update = updatesItem.update,
|
update = updatesItem.update,
|
||||||
selected = updatesItem.selected,
|
selected = updatesItem.selected,
|
||||||
readProgress = updatesItem.update.lastPageRead
|
readProgress = updatesItem.update.lastPageRead
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ import androidx.compose.runtime.mutableStateOf
|
|||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.platform.LocalLifecycleOwner
|
||||||
import androidx.lifecycle.DefaultLifecycleObserver
|
import androidx.lifecycle.DefaultLifecycleObserver
|
||||||
import androidx.lifecycle.LifecycleOwner
|
import androidx.lifecycle.LifecycleOwner
|
||||||
import androidx.lifecycle.compose.LocalLifecycleOwner
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun rememberRequestPackageInstallsPermissionState(initialValue: Boolean = false): Boolean {
|
fun rememberRequestPackageInstallsPermissionState(initialValue: Boolean = false): Boolean {
|
||||||
|
|||||||
@@ -199,30 +199,39 @@ class App : Application(), DefaultLifecycleObserver, SingletonImageLoader.Factor
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("MagicNumber")
|
||||||
override fun newImageLoader(context: Context): ImageLoader {
|
override fun newImageLoader(context: Context): ImageLoader {
|
||||||
return ImageLoader.Builder(this).apply {
|
return ImageLoader.Builder(this).apply {
|
||||||
val callFactoryLazy = lazy { Injekt.get<NetworkHelper>().client }
|
val callFactoryLazy = lazy { Injekt.get<NetworkHelper>().client }
|
||||||
components {
|
components {
|
||||||
|
// NetworkFetcher.Factory
|
||||||
add(OkHttpNetworkFetcherFactory(callFactoryLazy::value))
|
add(OkHttpNetworkFetcherFactory(callFactoryLazy::value))
|
||||||
|
// Decoder.Factory
|
||||||
add(TachiyomiImageDecoder.Factory())
|
add(TachiyomiImageDecoder.Factory())
|
||||||
add(MangaCoverFetcher.MangaFactory(callFactoryLazy))
|
// Fetcher.Factory
|
||||||
add(MangaCoverFetcher.MangaCoverFactory(callFactoryLazy))
|
|
||||||
add(MangaKeyer())
|
|
||||||
add(MangaCoverKeyer())
|
|
||||||
add(BufferedSourceFetcher.Factory())
|
add(BufferedSourceFetcher.Factory())
|
||||||
|
add(MangaCoverFetcher.MangaCoverFactory(callFactoryLazy))
|
||||||
|
add(MangaCoverFetcher.MangaFactory(callFactoryLazy))
|
||||||
// SY -->
|
// SY -->
|
||||||
add(PagePreviewKeyer())
|
|
||||||
add(PagePreviewFetcher.Factory(callFactoryLazy))
|
add(PagePreviewFetcher.Factory(callFactoryLazy))
|
||||||
// SY <--
|
// SY <--
|
||||||
|
// Keyer
|
||||||
|
add(MangaCoverKeyer())
|
||||||
|
add(MangaKeyer())
|
||||||
|
// SY -->
|
||||||
|
add(PagePreviewKeyer())
|
||||||
|
// SY <--
|
||||||
}
|
}
|
||||||
|
|
||||||
crossfade((300 * this@App.animatorDurationScale).toInt())
|
crossfade((300 * this@App.animatorDurationScale).toInt())
|
||||||
allowRgb565(DeviceUtil.isLowRamDevice(this@App))
|
allowRgb565(DeviceUtil.isLowRamDevice(this@App))
|
||||||
if (networkPreferences.verboseLogging().get()) logger(DebugLogger())
|
if (networkPreferences.verboseLogging().get()) logger(DebugLogger())
|
||||||
|
|
||||||
// Coil spawns a new thread for every image load by default
|
// Coil spawns a new thread for every image load by default
|
||||||
fetcherDispatcher(Dispatchers.IO.limitedParallelism(8))
|
fetcherCoroutineContext(Dispatchers.IO.limitedParallelism(8))
|
||||||
decoderDispatcher(Dispatchers.IO.limitedParallelism(2))
|
decoderCoroutineContext(Dispatchers.IO.limitedParallelism(3))
|
||||||
}.build()
|
}
|
||||||
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStart(owner: LifecycleOwner) {
|
override fun onStart(owner: LifecycleOwner) {
|
||||||
|
|||||||
@@ -3,19 +3,21 @@ package eu.kanade.tachiyomi.data.backup
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import eu.kanade.tachiyomi.data.backup.models.Backup
|
import eu.kanade.tachiyomi.data.backup.models.Backup
|
||||||
import eu.kanade.tachiyomi.data.backup.models.BackupSerializer
|
import kotlinx.serialization.SerializationException
|
||||||
import kotlinx.serialization.protobuf.ProtoBuf
|
import kotlinx.serialization.protobuf.ProtoBuf
|
||||||
import okio.buffer
|
import okio.buffer
|
||||||
import okio.gzip
|
import okio.gzip
|
||||||
import okio.source
|
import okio.source
|
||||||
|
import tachiyomi.core.common.i18n.stringResource
|
||||||
|
import tachiyomi.i18n.MR
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
import java.io.IOException
|
||||||
|
|
||||||
class BackupDecoder(
|
class BackupDecoder(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
private val parser: ProtoBuf = Injekt.get(),
|
private val parser: ProtoBuf = Injekt.get(),
|
||||||
) {
|
) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decode a potentially-gzipped backup.
|
* Decode a potentially-gzipped backup.
|
||||||
*/
|
*/
|
||||||
@@ -27,13 +29,25 @@ class BackupDecoder(
|
|||||||
require(2)
|
require(2)
|
||||||
}
|
}
|
||||||
val id1id2 = peeked.readShort()
|
val id1id2 = peeked.readShort()
|
||||||
val backupString = if (id1id2.toInt() == 0x1f8b) { // 0x1f8b is gzip magic bytes
|
val backupString = when (id1id2.toInt()) {
|
||||||
source.gzip().buffer()
|
0x1f8b -> source.gzip().buffer() // 0x1f8b is gzip magic bytes
|
||||||
} else {
|
MAGIC_JSON_SIGNATURE1, MAGIC_JSON_SIGNATURE2, MAGIC_JSON_SIGNATURE3 -> {
|
||||||
source
|
throw IOException(context.stringResource(MR.strings.invalid_backup_file_json))
|
||||||
|
}
|
||||||
|
else -> source
|
||||||
}.use { it.readByteArray() }
|
}.use { it.readByteArray() }
|
||||||
|
|
||||||
parser.decodeFromByteArray(BackupSerializer, backupString)
|
try {
|
||||||
|
parser.decodeFromByteArray(Backup.serializer(), backupString)
|
||||||
|
} catch (_: SerializationException) {
|
||||||
|
throw IOException(context.stringResource(MR.strings.invalid_backup_file_unknown))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val MAGIC_JSON_SIGNATURE1 = 0x7b7d // `{}`
|
||||||
|
private const val MAGIC_JSON_SIGNATURE2 = 0x7b22 // `{"`
|
||||||
|
private const val MAGIC_JSON_SIGNATURE3 = 0x7b0a // `{\n`
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,16 +6,17 @@ import com.hippo.unifile.UniFile
|
|||||||
import eu.kanade.tachiyomi.BuildConfig
|
import eu.kanade.tachiyomi.BuildConfig
|
||||||
import eu.kanade.tachiyomi.data.backup.BackupFileValidator
|
import eu.kanade.tachiyomi.data.backup.BackupFileValidator
|
||||||
import eu.kanade.tachiyomi.data.backup.create.creators.CategoriesBackupCreator
|
import eu.kanade.tachiyomi.data.backup.create.creators.CategoriesBackupCreator
|
||||||
|
import eu.kanade.tachiyomi.data.backup.create.creators.ExtensionRepoBackupCreator
|
||||||
import eu.kanade.tachiyomi.data.backup.create.creators.MangaBackupCreator
|
import eu.kanade.tachiyomi.data.backup.create.creators.MangaBackupCreator
|
||||||
import eu.kanade.tachiyomi.data.backup.create.creators.PreferenceBackupCreator
|
import eu.kanade.tachiyomi.data.backup.create.creators.PreferenceBackupCreator
|
||||||
import eu.kanade.tachiyomi.data.backup.create.creators.SavedSearchBackupCreator
|
import eu.kanade.tachiyomi.data.backup.create.creators.SavedSearchBackupCreator
|
||||||
import eu.kanade.tachiyomi.data.backup.create.creators.SourcesBackupCreator
|
import eu.kanade.tachiyomi.data.backup.create.creators.SourcesBackupCreator
|
||||||
import eu.kanade.tachiyomi.data.backup.models.Backup
|
import eu.kanade.tachiyomi.data.backup.models.Backup
|
||||||
import eu.kanade.tachiyomi.data.backup.models.BackupCategory
|
import eu.kanade.tachiyomi.data.backup.models.BackupCategory
|
||||||
|
import eu.kanade.tachiyomi.data.backup.models.BackupExtensionRepos
|
||||||
import eu.kanade.tachiyomi.data.backup.models.BackupManga
|
import eu.kanade.tachiyomi.data.backup.models.BackupManga
|
||||||
import eu.kanade.tachiyomi.data.backup.models.BackupPreference
|
import eu.kanade.tachiyomi.data.backup.models.BackupPreference
|
||||||
import eu.kanade.tachiyomi.data.backup.models.BackupSavedSearch
|
import eu.kanade.tachiyomi.data.backup.models.BackupSavedSearch
|
||||||
import eu.kanade.tachiyomi.data.backup.models.BackupSerializer
|
|
||||||
import eu.kanade.tachiyomi.data.backup.models.BackupSource
|
import eu.kanade.tachiyomi.data.backup.models.BackupSource
|
||||||
import eu.kanade.tachiyomi.data.backup.models.BackupSourcePreferences
|
import eu.kanade.tachiyomi.data.backup.models.BackupSourcePreferences
|
||||||
import kotlinx.serialization.protobuf.ProtoBuf
|
import kotlinx.serialization.protobuf.ProtoBuf
|
||||||
@@ -51,6 +52,7 @@ class BackupCreator(
|
|||||||
private val categoriesBackupCreator: CategoriesBackupCreator = CategoriesBackupCreator(),
|
private val categoriesBackupCreator: CategoriesBackupCreator = CategoriesBackupCreator(),
|
||||||
private val mangaBackupCreator: MangaBackupCreator = MangaBackupCreator(),
|
private val mangaBackupCreator: MangaBackupCreator = MangaBackupCreator(),
|
||||||
private val preferenceBackupCreator: PreferenceBackupCreator = PreferenceBackupCreator(),
|
private val preferenceBackupCreator: PreferenceBackupCreator = PreferenceBackupCreator(),
|
||||||
|
private val extensionRepoBackupCreator: ExtensionRepoBackupCreator = ExtensionRepoBackupCreator(),
|
||||||
private val sourcesBackupCreator: SourcesBackupCreator = SourcesBackupCreator(),
|
private val sourcesBackupCreator: SourcesBackupCreator = SourcesBackupCreator(),
|
||||||
// SY -->
|
// SY -->
|
||||||
private val savedSearchBackupCreator: SavedSearchBackupCreator = SavedSearchBackupCreator(),
|
private val savedSearchBackupCreator: SavedSearchBackupCreator = SavedSearchBackupCreator(),
|
||||||
@@ -62,47 +64,49 @@ class BackupCreator(
|
|||||||
suspend fun backup(uri: Uri, options: BackupOptions): String {
|
suspend fun backup(uri: Uri, options: BackupOptions): String {
|
||||||
var file: UniFile? = null
|
var file: UniFile? = null
|
||||||
try {
|
try {
|
||||||
file = (
|
file = if (isAutoBackup) {
|
||||||
if (isAutoBackup) {
|
// Get dir of file and create
|
||||||
// Get dir of file and create
|
val dir = UniFile.fromUri(context, uri)
|
||||||
val dir = UniFile.fromUri(context, uri)
|
|
||||||
|
|
||||||
// Delete older backups
|
// Delete older backups
|
||||||
dir?.listFiles { _, filename -> FILENAME_REGEX.matches(filename) }
|
dir?.listFiles { _, filename -> FILENAME_REGEX.matches(filename) }
|
||||||
.orEmpty()
|
.orEmpty()
|
||||||
.sortedByDescending { it.name }
|
.sortedByDescending { it.name }
|
||||||
.drop(MAX_AUTO_BACKUPS - 1)
|
.drop(MAX_AUTO_BACKUPS - 1)
|
||||||
.forEach { it.delete() }
|
.forEach { it.delete() }
|
||||||
|
|
||||||
// Create new file to place backup
|
// Create new file to place backup
|
||||||
dir?.createFile(getFilename())
|
dir?.createFile(getFilename())
|
||||||
} else {
|
} else {
|
||||||
UniFile.fromUri(context, uri)
|
UniFile.fromUri(context, uri)
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
|
||||||
if (file == null || !file.isFile) {
|
if (file == null || !file.isFile) {
|
||||||
throw IllegalStateException(context.stringResource(MR.strings.create_backup_file_error))
|
throw IllegalStateException(context.stringResource(MR.strings.create_backup_file_error))
|
||||||
}
|
}
|
||||||
|
|
||||||
val databaseManga = getFavorites.await() /* SY --> */ +
|
val backupManga = backupMangas(
|
||||||
if (options.readEntries) {
|
getFavorites.await() /* SY --> */ +
|
||||||
handler.awaitList { mangasQueries.getReadMangaNotInLibrary(MangaMapper::mapManga) }
|
if (options.readEntries) {
|
||||||
} else {
|
handler.awaitList { mangasQueries.getReadMangaNotInLibrary(MangaMapper::mapManga) }
|
||||||
emptyList()
|
} else {
|
||||||
} + getMergedManga.await() // SY <--
|
emptyList()
|
||||||
|
} + getMergedManga.await(), // SY <--
|
||||||
|
options
|
||||||
|
)
|
||||||
val backup = Backup(
|
val backup = Backup(
|
||||||
backupManga = backupMangas(databaseManga, options),
|
backupManga = backupManga,
|
||||||
backupCategories = backupCategories(options),
|
backupCategories = backupCategories(options),
|
||||||
backupSources = backupSources(databaseManga),
|
backupSources = backupSources(backupManga),
|
||||||
backupPreferences = backupAppPreferences(options),
|
backupPreferences = backupAppPreferences(options),
|
||||||
|
backupExtensionRepo = backupExtensionRepos(options),
|
||||||
backupSourcePreferences = backupSourcePreferences(options),
|
backupSourcePreferences = backupSourcePreferences(options),
|
||||||
// SY -->
|
// SY -->
|
||||||
backupSavedSearches = backupSavedSearches(),
|
backupSavedSearches = backupSavedSearches(options),
|
||||||
// SY <--
|
// SY <--
|
||||||
)
|
)
|
||||||
|
|
||||||
val byteArray = parser.encodeToByteArray(BackupSerializer, backup)
|
val byteArray = parser.encodeToByteArray(Backup.serializer(), backup)
|
||||||
if (byteArray.isEmpty()) {
|
if (byteArray.isEmpty()) {
|
||||||
throw IllegalStateException(context.stringResource(MR.strings.empty_backup_error))
|
throw IllegalStateException(context.stringResource(MR.strings.empty_backup_error))
|
||||||
}
|
}
|
||||||
@@ -135,32 +139,42 @@ class BackupCreator(
|
|||||||
suspend fun backupCategories(options: BackupOptions): List<BackupCategory> {
|
suspend fun backupCategories(options: BackupOptions): List<BackupCategory> {
|
||||||
if (!options.categories) return emptyList()
|
if (!options.categories) return emptyList()
|
||||||
|
|
||||||
return categoriesBackupCreator.backupCategories()
|
return categoriesBackupCreator()
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun backupMangas(mangas: List<Manga>, options: BackupOptions): List<BackupManga> {
|
suspend fun backupMangas(mangas: List<Manga>, options: BackupOptions): List<BackupManga> {
|
||||||
return mangaBackupCreator.backupMangas(mangas, options)
|
if (!options.libraryEntries) return emptyList()
|
||||||
|
|
||||||
|
return mangaBackupCreator(mangas, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun backupSources(mangas: List<Manga>): List<BackupSource> {
|
fun backupSources(mangas: List<BackupManga>): List<BackupSource> {
|
||||||
return sourcesBackupCreator.backupSources(mangas)
|
return sourcesBackupCreator(mangas)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun backupAppPreferences(options: BackupOptions): List<BackupPreference> {
|
fun backupAppPreferences(options: BackupOptions): List<BackupPreference> {
|
||||||
if (!options.appSettings) return emptyList()
|
if (!options.appSettings) return emptyList()
|
||||||
|
|
||||||
return preferenceBackupCreator.backupAppPreferences(includePrivatePreferences = options.privateSettings)
|
return preferenceBackupCreator.createApp(includePrivatePreferences = options.privateSettings)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun backupSourcePreferences(options: BackupOptions): List<BackupSourcePreferences> {
|
fun backupSourcePreferences(options: BackupOptions): List<BackupSourcePreferences> {
|
||||||
if (!options.sourceSettings) return emptyList()
|
if (!options.sourceSettings) return emptyList()
|
||||||
|
|
||||||
return preferenceBackupCreator.backupSourcePreferences(includePrivatePreferences = options.privateSettings)
|
return preferenceBackupCreator.createSource(includePrivatePreferences = options.privateSettings)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun backupExtensionRepos(options: BackupOptions): List<BackupExtensionRepos> {
|
||||||
|
if (!options.extensionRepoSettings) return emptyList()
|
||||||
|
|
||||||
|
return extensionRepoBackupCreator()
|
||||||
}
|
}
|
||||||
|
|
||||||
// SY -->
|
// SY -->
|
||||||
suspend fun backupSavedSearches(): List<BackupSavedSearch> {
|
suspend fun backupSavedSearches(options: BackupOptions): List<BackupSavedSearch> {
|
||||||
return savedSearchBackupCreator.backupSavedSearches()
|
if (!options.savedSearches) return emptyList()
|
||||||
|
|
||||||
|
return savedSearchBackupCreator()
|
||||||
}
|
}
|
||||||
// SY <--
|
// SY <--
|
||||||
|
|
||||||
|
|||||||
@@ -12,11 +12,13 @@ data class BackupOptions(
|
|||||||
val tracking: Boolean = true,
|
val tracking: Boolean = true,
|
||||||
val history: Boolean = true,
|
val history: Boolean = true,
|
||||||
val appSettings: Boolean = true,
|
val appSettings: Boolean = true,
|
||||||
|
val extensionRepoSettings: Boolean = true,
|
||||||
val sourceSettings: Boolean = true,
|
val sourceSettings: Boolean = true,
|
||||||
val privateSettings: Boolean = false,
|
val privateSettings: Boolean = false,
|
||||||
// SY -->
|
// SY -->
|
||||||
val customInfo: Boolean = true,
|
val customInfo: Boolean = true,
|
||||||
val readEntries: Boolean = true,
|
val readEntries: Boolean = true,
|
||||||
|
val savedSearches: Boolean = true,
|
||||||
// SY <--
|
// SY <--
|
||||||
) {
|
) {
|
||||||
|
|
||||||
@@ -27,15 +29,17 @@ data class BackupOptions(
|
|||||||
tracking,
|
tracking,
|
||||||
history,
|
history,
|
||||||
appSettings,
|
appSettings,
|
||||||
|
extensionRepoSettings,
|
||||||
sourceSettings,
|
sourceSettings,
|
||||||
privateSettings,
|
privateSettings,
|
||||||
// SY -->
|
// SY -->
|
||||||
customInfo,
|
customInfo,
|
||||||
readEntries,
|
readEntries,
|
||||||
|
savedSearches,
|
||||||
// SY <--
|
// SY <--
|
||||||
)
|
)
|
||||||
|
|
||||||
fun anyEnabled() = libraryEntries || appSettings || sourceSettings
|
fun canCreate() = libraryEntries || categories || appSettings || extensionRepoSettings || sourceSettings || savedSearches
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val libraryOptions = persistentListOf(
|
val libraryOptions = persistentListOf(
|
||||||
@@ -44,12 +48,6 @@ data class BackupOptions(
|
|||||||
getter = BackupOptions::libraryEntries,
|
getter = BackupOptions::libraryEntries,
|
||||||
setter = { options, enabled -> options.copy(libraryEntries = enabled) },
|
setter = { options, enabled -> options.copy(libraryEntries = enabled) },
|
||||||
),
|
),
|
||||||
Entry(
|
|
||||||
label = MR.strings.categories,
|
|
||||||
getter = BackupOptions::categories,
|
|
||||||
setter = { options, enabled -> options.copy(categories = enabled) },
|
|
||||||
enabled = { it.libraryEntries },
|
|
||||||
),
|
|
||||||
Entry(
|
Entry(
|
||||||
label = MR.strings.chapters,
|
label = MR.strings.chapters,
|
||||||
getter = BackupOptions::chapters,
|
getter = BackupOptions::chapters,
|
||||||
@@ -68,6 +66,11 @@ data class BackupOptions(
|
|||||||
setter = { options, enabled -> options.copy(history = enabled) },
|
setter = { options, enabled -> options.copy(history = enabled) },
|
||||||
enabled = { it.libraryEntries },
|
enabled = { it.libraryEntries },
|
||||||
),
|
),
|
||||||
|
Entry(
|
||||||
|
label = MR.strings.categories,
|
||||||
|
getter = BackupOptions::categories,
|
||||||
|
setter = { options, enabled -> options.copy(categories = enabled) },
|
||||||
|
),
|
||||||
// SY -->
|
// SY -->
|
||||||
Entry(
|
Entry(
|
||||||
label = SYMR.strings.custom_entry_info,
|
label = SYMR.strings.custom_entry_info,
|
||||||
@@ -81,6 +84,11 @@ data class BackupOptions(
|
|||||||
setter = { options, enabled -> options.copy(readEntries = enabled) },
|
setter = { options, enabled -> options.copy(readEntries = enabled) },
|
||||||
enabled = { it.libraryEntries },
|
enabled = { it.libraryEntries },
|
||||||
),
|
),
|
||||||
|
Entry(
|
||||||
|
label = SYMR.strings.saved_searches,
|
||||||
|
getter = BackupOptions::savedSearches,
|
||||||
|
setter = { options, enabled -> options.copy(savedSearches = enabled) },
|
||||||
|
),
|
||||||
// SY <--
|
// SY <--
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -90,6 +98,11 @@ data class BackupOptions(
|
|||||||
getter = BackupOptions::appSettings,
|
getter = BackupOptions::appSettings,
|
||||||
setter = { options, enabled -> options.copy(appSettings = enabled) },
|
setter = { options, enabled -> options.copy(appSettings = enabled) },
|
||||||
),
|
),
|
||||||
|
Entry(
|
||||||
|
label = MR.strings.extensionRepo_settings,
|
||||||
|
getter = BackupOptions::extensionRepoSettings,
|
||||||
|
setter = { options, enabled -> options.copy(extensionRepoSettings = enabled) },
|
||||||
|
),
|
||||||
Entry(
|
Entry(
|
||||||
label = MR.strings.source_settings,
|
label = MR.strings.source_settings,
|
||||||
getter = BackupOptions::sourceSettings,
|
getter = BackupOptions::sourceSettings,
|
||||||
@@ -110,11 +123,13 @@ data class BackupOptions(
|
|||||||
tracking = array[3],
|
tracking = array[3],
|
||||||
history = array[4],
|
history = array[4],
|
||||||
appSettings = array[5],
|
appSettings = array[5],
|
||||||
sourceSettings = array[6],
|
extensionRepoSettings = array[6],
|
||||||
privateSettings = array[7],
|
sourceSettings = array[7],
|
||||||
|
privateSettings = array[8],
|
||||||
// SY -->
|
// SY -->
|
||||||
customInfo = array[8],
|
customInfo = array[9],
|
||||||
readEntries = array[9],
|
readEntries = array[10],
|
||||||
|
savedSearches = array[11],
|
||||||
// SY <--
|
// SY <--
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -11,7 +11,7 @@ class CategoriesBackupCreator(
|
|||||||
private val getCategories: GetCategories = Injekt.get(),
|
private val getCategories: GetCategories = Injekt.get(),
|
||||||
) {
|
) {
|
||||||
|
|
||||||
suspend fun backupCategories(): List<BackupCategory> {
|
suspend operator fun invoke(): List<BackupCategory> {
|
||||||
return getCategories.await()
|
return getCategories.await()
|
||||||
.filterNot(Category::isSystemCategory)
|
.filterNot(Category::isSystemCategory)
|
||||||
.map(backupCategoryMapper)
|
.map(backupCategoryMapper)
|
||||||
|
|||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
package eu.kanade.tachiyomi.data.backup.create.creators
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.data.backup.models.BackupExtensionRepos
|
||||||
|
import eu.kanade.tachiyomi.data.backup.models.backupExtensionReposMapper
|
||||||
|
import mihon.domain.extensionrepo.interactor.GetExtensionRepo
|
||||||
|
import uy.kohesive.injekt.Injekt
|
||||||
|
import uy.kohesive.injekt.api.get
|
||||||
|
|
||||||
|
class ExtensionRepoBackupCreator(
|
||||||
|
private val getExtensionRepos: GetExtensionRepo = Injekt.get(),
|
||||||
|
) {
|
||||||
|
|
||||||
|
suspend operator fun invoke(): List<BackupExtensionRepos> {
|
||||||
|
return getExtensionRepos.getAll()
|
||||||
|
.map(backupExtensionReposMapper)
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -34,7 +34,7 @@ class MangaBackupCreator(
|
|||||||
// SY <--
|
// SY <--
|
||||||
) {
|
) {
|
||||||
|
|
||||||
suspend fun backupMangas(mangas: List<Manga>, options: BackupOptions): List<BackupManga> {
|
suspend operator fun invoke(mangas: List<Manga>, options: BackupOptions): List<BackupManga> {
|
||||||
return mangas.map {
|
return mangas.map {
|
||||||
backupManga(it, options)
|
backupManga(it, options)
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -22,12 +22,12 @@ class PreferenceBackupCreator(
|
|||||||
private val preferenceStore: PreferenceStore = Injekt.get(),
|
private val preferenceStore: PreferenceStore = Injekt.get(),
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun backupAppPreferences(includePrivatePreferences: Boolean): List<BackupPreference> {
|
fun createApp(includePrivatePreferences: Boolean): List<BackupPreference> {
|
||||||
return preferenceStore.getAll().toBackupPreferences()
|
return preferenceStore.getAll().toBackupPreferences()
|
||||||
.withPrivatePreferences(includePrivatePreferences)
|
.withPrivatePreferences(includePrivatePreferences)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun backupSourcePreferences(includePrivatePreferences: Boolean): List<BackupSourcePreferences> {
|
fun createSource(includePrivatePreferences: Boolean): List<BackupSourcePreferences> {
|
||||||
return sourceManager.getCatalogueSources()
|
return sourceManager.getCatalogueSources()
|
||||||
.filterIsInstance<ConfigurableSource>()
|
.filterIsInstance<ConfigurableSource>()
|
||||||
.map {
|
.map {
|
||||||
|
|||||||
+1
-1
@@ -10,7 +10,7 @@ class SavedSearchBackupCreator(
|
|||||||
private val handler: DatabaseHandler = Injekt.get()
|
private val handler: DatabaseHandler = Injekt.get()
|
||||||
) {
|
) {
|
||||||
|
|
||||||
suspend fun backupSavedSearches(): List<BackupSavedSearch> {
|
suspend operator fun invoke(): List<BackupSavedSearch> {
|
||||||
return handler.awaitList { saved_searchQueries.selectAll(backupSavedSearchMapper) }
|
return handler.awaitList { saved_searchQueries.selectAll(backupSavedSearchMapper) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -1,8 +1,8 @@
|
|||||||
package eu.kanade.tachiyomi.data.backup.create.creators
|
package eu.kanade.tachiyomi.data.backup.create.creators
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.data.backup.models.BackupManga
|
||||||
import eu.kanade.tachiyomi.data.backup.models.BackupSource
|
import eu.kanade.tachiyomi.data.backup.models.BackupSource
|
||||||
import eu.kanade.tachiyomi.source.Source
|
import eu.kanade.tachiyomi.source.Source
|
||||||
import tachiyomi.domain.manga.model.Manga
|
|
||||||
import tachiyomi.domain.source.service.SourceManager
|
import tachiyomi.domain.source.service.SourceManager
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
@@ -11,10 +11,10 @@ class SourcesBackupCreator(
|
|||||||
private val sourceManager: SourceManager = Injekt.get(),
|
private val sourceManager: SourceManager = Injekt.get(),
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun backupSources(mangas: List<Manga>): List<BackupSource> {
|
operator fun invoke(mangas: List<BackupManga>): List<BackupSource> {
|
||||||
return mangas
|
return mangas
|
||||||
.asSequence()
|
.asSequence()
|
||||||
.map(Manga::source)
|
.map(BackupManga::source)
|
||||||
.distinct()
|
.distinct()
|
||||||
.map(sourceManager::getOrStub)
|
.map(sourceManager::getOrStub)
|
||||||
.map { it.toBackupSource() }
|
.map { it.toBackupSource() }
|
||||||
|
|||||||
@@ -1,12 +1,9 @@
|
|||||||
package eu.kanade.tachiyomi.data.backup.models
|
package eu.kanade.tachiyomi.data.backup.models
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.Serializer
|
|
||||||
import kotlinx.serialization.protobuf.ProtoNumber
|
import kotlinx.serialization.protobuf.ProtoNumber
|
||||||
|
|
||||||
@Serializer(forClass = Backup::class)
|
@Suppress("MagicNumber")
|
||||||
object BackupSerializer
|
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class Backup(
|
data class Backup(
|
||||||
@ProtoNumber(1) val backupManga: List<BackupManga>,
|
@ProtoNumber(1) val backupManga: List<BackupManga>,
|
||||||
@@ -15,6 +12,7 @@ data class Backup(
|
|||||||
@ProtoNumber(101) var backupSources: List<BackupSource> = emptyList(),
|
@ProtoNumber(101) var backupSources: List<BackupSource> = emptyList(),
|
||||||
@ProtoNumber(104) var backupPreferences: List<BackupPreference> = emptyList(),
|
@ProtoNumber(104) var backupPreferences: List<BackupPreference> = emptyList(),
|
||||||
@ProtoNumber(105) var backupSourcePreferences: List<BackupSourcePreferences> = emptyList(),
|
@ProtoNumber(105) var backupSourcePreferences: List<BackupSourcePreferences> = emptyList(),
|
||||||
|
@ProtoNumber(106) var backupExtensionRepo: List<BackupExtensionRepos> = emptyList(),
|
||||||
// SY specific values
|
// SY specific values
|
||||||
@ProtoNumber(600) var backupSavedSearches: List<BackupSavedSearch> = emptyList(),
|
@ProtoNumber(600) var backupSavedSearches: List<BackupSavedSearch> = emptyList(),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package eu.kanade.tachiyomi.data.backup.models
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import kotlinx.serialization.protobuf.ProtoNumber
|
||||||
|
import mihon.domain.extensionrepo.model.ExtensionRepo
|
||||||
|
|
||||||
|
@Suppress("MagicNumber")
|
||||||
|
@Serializable
|
||||||
|
class BackupExtensionRepos(
|
||||||
|
@ProtoNumber(1) var baseUrl: String,
|
||||||
|
@ProtoNumber(2) var name: String,
|
||||||
|
@ProtoNumber(3) var shortName: String?,
|
||||||
|
@ProtoNumber(4) var website: String,
|
||||||
|
@ProtoNumber(5) var signingKeyFingerprint: String,
|
||||||
|
)
|
||||||
|
|
||||||
|
val backupExtensionReposMapper = { repo: ExtensionRepo ->
|
||||||
|
BackupExtensionRepos(
|
||||||
|
baseUrl = repo.baseUrl,
|
||||||
|
name = repo.name,
|
||||||
|
shortName = repo.shortName,
|
||||||
|
website = repo.website,
|
||||||
|
signingKeyFingerprint = repo.signingKeyFingerprint,
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -5,11 +5,13 @@ import android.net.Uri
|
|||||||
import eu.kanade.tachiyomi.data.backup.BackupDecoder
|
import eu.kanade.tachiyomi.data.backup.BackupDecoder
|
||||||
import eu.kanade.tachiyomi.data.backup.BackupNotifier
|
import eu.kanade.tachiyomi.data.backup.BackupNotifier
|
||||||
import eu.kanade.tachiyomi.data.backup.models.BackupCategory
|
import eu.kanade.tachiyomi.data.backup.models.BackupCategory
|
||||||
|
import eu.kanade.tachiyomi.data.backup.models.BackupExtensionRepos
|
||||||
import eu.kanade.tachiyomi.data.backup.models.BackupManga
|
import eu.kanade.tachiyomi.data.backup.models.BackupManga
|
||||||
import eu.kanade.tachiyomi.data.backup.models.BackupPreference
|
import eu.kanade.tachiyomi.data.backup.models.BackupPreference
|
||||||
import eu.kanade.tachiyomi.data.backup.models.BackupSavedSearch
|
import eu.kanade.tachiyomi.data.backup.models.BackupSavedSearch
|
||||||
import eu.kanade.tachiyomi.data.backup.models.BackupSourcePreferences
|
import eu.kanade.tachiyomi.data.backup.models.BackupSourcePreferences
|
||||||
import eu.kanade.tachiyomi.data.backup.restore.restorers.CategoriesRestorer
|
import eu.kanade.tachiyomi.data.backup.restore.restorers.CategoriesRestorer
|
||||||
|
import eu.kanade.tachiyomi.data.backup.restore.restorers.ExtensionRepoRestorer
|
||||||
import eu.kanade.tachiyomi.data.backup.restore.restorers.MangaRestorer
|
import eu.kanade.tachiyomi.data.backup.restore.restorers.MangaRestorer
|
||||||
import eu.kanade.tachiyomi.data.backup.restore.restorers.PreferenceRestorer
|
import eu.kanade.tachiyomi.data.backup.restore.restorers.PreferenceRestorer
|
||||||
import eu.kanade.tachiyomi.data.backup.restore.restorers.SavedSearchRestorer
|
import eu.kanade.tachiyomi.data.backup.restore.restorers.SavedSearchRestorer
|
||||||
@@ -34,6 +36,7 @@ class BackupRestorer(
|
|||||||
|
|
||||||
private val categoriesRestorer: CategoriesRestorer = CategoriesRestorer(),
|
private val categoriesRestorer: CategoriesRestorer = CategoriesRestorer(),
|
||||||
private val preferenceRestorer: PreferenceRestorer = PreferenceRestorer(context),
|
private val preferenceRestorer: PreferenceRestorer = PreferenceRestorer(context),
|
||||||
|
private val extensionRepoRestorer: ExtensionRepoRestorer = ExtensionRepoRestorer(),
|
||||||
private val mangaRestorer: MangaRestorer = MangaRestorer(isSync),
|
private val mangaRestorer: MangaRestorer = MangaRestorer(isSync),
|
||||||
// SY -->
|
// SY -->
|
||||||
private val savedSearchRestorer: SavedSearchRestorer = SavedSearchRestorer(),
|
private val savedSearchRestorer: SavedSearchRestorer = SavedSearchRestorer(),
|
||||||
@@ -74,8 +77,11 @@ class BackupRestorer(
|
|||||||
val backupMaps = backup.backupSources + backup.backupBrokenSources.map { it.toBackupSource() }
|
val backupMaps = backup.backupSources + backup.backupBrokenSources.map { it.toBackupSource() }
|
||||||
sourceMapping = backupMaps.associate { it.sourceId to it.name }
|
sourceMapping = backupMaps.associate { it.sourceId to it.name }
|
||||||
|
|
||||||
if (options.library) {
|
if (options.libraryEntries) {
|
||||||
restoreAmount += backup.backupManga.size + 1 // +1 for categories
|
restoreAmount += backup.backupManga.size
|
||||||
|
}
|
||||||
|
if (options.categories) {
|
||||||
|
restoreAmount += 1
|
||||||
}
|
}
|
||||||
// SY -->
|
// SY -->
|
||||||
if (options.savedSearches) {
|
if (options.savedSearches) {
|
||||||
@@ -85,12 +91,15 @@ class BackupRestorer(
|
|||||||
if (options.appSettings) {
|
if (options.appSettings) {
|
||||||
restoreAmount += 1
|
restoreAmount += 1
|
||||||
}
|
}
|
||||||
|
if (options.extensionRepoSettings) {
|
||||||
|
restoreAmount += backup.backupExtensionRepo.size
|
||||||
|
}
|
||||||
if (options.sourceSettings) {
|
if (options.sourceSettings) {
|
||||||
restoreAmount += 1
|
restoreAmount += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
coroutineScope {
|
coroutineScope {
|
||||||
if (options.library) {
|
if (options.categories) {
|
||||||
restoreCategories(backup.backupCategories)
|
restoreCategories(backup.backupCategories)
|
||||||
}
|
}
|
||||||
// SY -->
|
// SY -->
|
||||||
@@ -104,8 +113,11 @@ class BackupRestorer(
|
|||||||
if (options.sourceSettings) {
|
if (options.sourceSettings) {
|
||||||
restoreSourcePreferences(backup.backupSourcePreferences)
|
restoreSourcePreferences(backup.backupSourcePreferences)
|
||||||
}
|
}
|
||||||
if (options.library) {
|
if (options.libraryEntries) {
|
||||||
restoreManga(backup.backupManga, backup.backupCategories)
|
restoreManga(backup.backupManga, if (options.categories) backup.backupCategories else emptyList())
|
||||||
|
}
|
||||||
|
if (options.extensionRepoSettings) {
|
||||||
|
restoreExtensionRepos(backup.backupExtensionRepo)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: optionally trigger online library + tracker update
|
// TODO: optionally trigger online library + tracker update
|
||||||
@@ -114,7 +126,7 @@ class BackupRestorer(
|
|||||||
|
|
||||||
private fun CoroutineScope.restoreCategories(backupCategories: List<BackupCategory>) = launch {
|
private fun CoroutineScope.restoreCategories(backupCategories: List<BackupCategory>) = launch {
|
||||||
ensureActive()
|
ensureActive()
|
||||||
categoriesRestorer.restoreCategories(backupCategories)
|
categoriesRestorer(backupCategories)
|
||||||
|
|
||||||
restoreProgress += 1
|
restoreProgress += 1
|
||||||
notifier.showRestoreProgress(
|
notifier.showRestoreProgress(
|
||||||
@@ -150,7 +162,7 @@ class BackupRestorer(
|
|||||||
ensureActive()
|
ensureActive()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
mangaRestorer.restoreManga(it, backupCategories)
|
mangaRestorer.restore(it, backupCategories)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
val sourceName = sourceMapping[it.source] ?: it.source.toString()
|
val sourceName = sourceMapping[it.source] ?: it.source.toString()
|
||||||
errors.add(Date() to "${it.title} [$sourceName]: ${e.message}")
|
errors.add(Date() to "${it.title} [$sourceName]: ${e.message}")
|
||||||
@@ -163,7 +175,7 @@ class BackupRestorer(
|
|||||||
|
|
||||||
private fun CoroutineScope.restoreAppPreferences(preferences: List<BackupPreference>) = launch {
|
private fun CoroutineScope.restoreAppPreferences(preferences: List<BackupPreference>) = launch {
|
||||||
ensureActive()
|
ensureActive()
|
||||||
preferenceRestorer.restoreAppPreferences(preferences)
|
preferenceRestorer.restoreApp(preferences)
|
||||||
|
|
||||||
restoreProgress += 1
|
restoreProgress += 1
|
||||||
notifier.showRestoreProgress(
|
notifier.showRestoreProgress(
|
||||||
@@ -176,7 +188,7 @@ class BackupRestorer(
|
|||||||
|
|
||||||
private fun CoroutineScope.restoreSourcePreferences(preferences: List<BackupSourcePreferences>) = launch {
|
private fun CoroutineScope.restoreSourcePreferences(preferences: List<BackupSourcePreferences>) = launch {
|
||||||
ensureActive()
|
ensureActive()
|
||||||
preferenceRestorer.restoreSourcePreferences(preferences)
|
preferenceRestorer.restoreSource(preferences)
|
||||||
|
|
||||||
restoreProgress += 1
|
restoreProgress += 1
|
||||||
notifier.showRestoreProgress(
|
notifier.showRestoreProgress(
|
||||||
@@ -187,10 +199,33 @@ class BackupRestorer(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun CoroutineScope.restoreExtensionRepos(
|
||||||
|
backupExtensionRepo: List<BackupExtensionRepos>
|
||||||
|
) = launch {
|
||||||
|
backupExtensionRepo
|
||||||
|
.forEach {
|
||||||
|
ensureActive()
|
||||||
|
|
||||||
|
try {
|
||||||
|
extensionRepoRestorer(it)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
errors.add(Date() to "Error Adding Repo: ${it.name} : ${e.message}")
|
||||||
|
}
|
||||||
|
|
||||||
|
restoreProgress += 1
|
||||||
|
notifier.showRestoreProgress(
|
||||||
|
context.stringResource(MR.strings.extensionRepo_settings),
|
||||||
|
restoreProgress,
|
||||||
|
restoreAmount,
|
||||||
|
isSync,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun writeErrorLog(): File {
|
private fun writeErrorLog(): File {
|
||||||
try {
|
try {
|
||||||
if (errors.isNotEmpty()) {
|
if (errors.isNotEmpty()) {
|
||||||
val file = context.createFileInCacheDir("tachiyomi_restore.txt")
|
val file = context.createFileInCacheDir("mihon_restore_error.txt")
|
||||||
val sdf = SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.getDefault())
|
val sdf = SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.getDefault())
|
||||||
|
|
||||||
file.bufferedWriter().use { out ->
|
file.bufferedWriter().use { out ->
|
||||||
|
|||||||
@@ -6,8 +6,10 @@ import tachiyomi.i18n.MR
|
|||||||
import tachiyomi.i18n.sy.SYMR
|
import tachiyomi.i18n.sy.SYMR
|
||||||
|
|
||||||
data class RestoreOptions(
|
data class RestoreOptions(
|
||||||
val library: Boolean = true,
|
val libraryEntries: Boolean = true,
|
||||||
|
val categories: Boolean = true,
|
||||||
val appSettings: Boolean = true,
|
val appSettings: Boolean = true,
|
||||||
|
val extensionRepoSettings: Boolean = true,
|
||||||
val sourceSettings: Boolean = true,
|
val sourceSettings: Boolean = true,
|
||||||
// SY -->
|
// SY -->
|
||||||
val savedSearches: Boolean = true,
|
val savedSearches: Boolean = true,
|
||||||
@@ -15,28 +17,40 @@ data class RestoreOptions(
|
|||||||
) {
|
) {
|
||||||
|
|
||||||
fun asBooleanArray() = booleanArrayOf(
|
fun asBooleanArray() = booleanArrayOf(
|
||||||
library,
|
libraryEntries,
|
||||||
|
categories,
|
||||||
appSettings,
|
appSettings,
|
||||||
|
extensionRepoSettings,
|
||||||
sourceSettings,
|
sourceSettings,
|
||||||
// SY -->
|
// SY -->
|
||||||
savedSearches
|
savedSearches,
|
||||||
// SY <--
|
// SY <--
|
||||||
)
|
)
|
||||||
|
|
||||||
fun anyEnabled() = library || appSettings || sourceSettings /* SY --> */ || savedSearches /* SY <-- */
|
fun canRestore() = libraryEntries || categories || appSettings || extensionRepoSettings || sourceSettings /* SY --> */ || savedSearches /* SY <-- */
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val options = persistentListOf(
|
val options = persistentListOf(
|
||||||
Entry(
|
Entry(
|
||||||
label = MR.strings.label_library,
|
label = MR.strings.label_library,
|
||||||
getter = RestoreOptions::library,
|
getter = RestoreOptions::libraryEntries,
|
||||||
setter = { options, enabled -> options.copy(library = enabled) },
|
setter = { options, enabled -> options.copy(libraryEntries = enabled) },
|
||||||
|
),
|
||||||
|
Entry(
|
||||||
|
label = MR.strings.categories,
|
||||||
|
getter = RestoreOptions::categories,
|
||||||
|
setter = { options, enabled -> options.copy(categories = enabled) },
|
||||||
),
|
),
|
||||||
Entry(
|
Entry(
|
||||||
label = MR.strings.app_settings,
|
label = MR.strings.app_settings,
|
||||||
getter = RestoreOptions::appSettings,
|
getter = RestoreOptions::appSettings,
|
||||||
setter = { options, enabled -> options.copy(appSettings = enabled) },
|
setter = { options, enabled -> options.copy(appSettings = enabled) },
|
||||||
),
|
),
|
||||||
|
Entry(
|
||||||
|
label = MR.strings.extensionRepo_settings,
|
||||||
|
getter = RestoreOptions::extensionRepoSettings,
|
||||||
|
setter = { options, enabled -> options.copy(extensionRepoSettings = enabled) },
|
||||||
|
),
|
||||||
Entry(
|
Entry(
|
||||||
label = MR.strings.source_settings,
|
label = MR.strings.source_settings,
|
||||||
getter = RestoreOptions::sourceSettings,
|
getter = RestoreOptions::sourceSettings,
|
||||||
@@ -52,11 +66,13 @@ data class RestoreOptions(
|
|||||||
)
|
)
|
||||||
|
|
||||||
fun fromBooleanArray(array: BooleanArray) = RestoreOptions(
|
fun fromBooleanArray(array: BooleanArray) = RestoreOptions(
|
||||||
library = array[0],
|
libraryEntries = array[0],
|
||||||
appSettings = array[1],
|
categories = array[1],
|
||||||
sourceSettings = array[2],
|
appSettings = array[2],
|
||||||
|
extensionRepoSettings = array[3],
|
||||||
|
sourceSettings = array[4],
|
||||||
// SY -->
|
// SY -->
|
||||||
savedSearches = array[3]
|
savedSearches = array[5]
|
||||||
// SY <--
|
// SY <--
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-8
@@ -13,7 +13,7 @@ class CategoriesRestorer(
|
|||||||
private val libraryPreferences: LibraryPreferences = Injekt.get(),
|
private val libraryPreferences: LibraryPreferences = Injekt.get(),
|
||||||
) {
|
) {
|
||||||
|
|
||||||
suspend fun restoreCategories(backupCategories: List<BackupCategory>) {
|
suspend operator fun invoke(backupCategories: List<BackupCategory>) {
|
||||||
if (backupCategories.isNotEmpty()) {
|
if (backupCategories.isNotEmpty()) {
|
||||||
val dbCategories = getCategories.await()
|
val dbCategories = getCategories.await()
|
||||||
val dbCategoriesByName = dbCategories.associateBy { it.name }
|
val dbCategoriesByName = dbCategories.associateBy { it.name }
|
||||||
@@ -21,14 +21,15 @@ class CategoriesRestorer(
|
|||||||
|
|
||||||
val categories = backupCategories
|
val categories = backupCategories
|
||||||
.sortedBy { it.order }
|
.sortedBy { it.order }
|
||||||
.distinctBy { it.name }
|
|
||||||
.map {
|
.map {
|
||||||
val newOrder = nextOrder++
|
val dbCategory = dbCategoriesByName[it.name]
|
||||||
dbCategoriesByName[it.name]
|
if (dbCategory != null) return@map dbCategory
|
||||||
?: handler.awaitOneExecutable {
|
val order = nextOrder++
|
||||||
categoriesQueries.insert(it.name, newOrder, it.flags)
|
handler.awaitOneExecutable {
|
||||||
categoriesQueries.selectLastInsertedRowId()
|
categoriesQueries.insert(it.name, order, it.flags)
|
||||||
}.let { id -> it.toCategory(id).copy(order = newOrder) }
|
categoriesQueries.selectLastInsertedRowId()
|
||||||
|
}
|
||||||
|
.let { id -> it.toCategory(id).copy(order = order) }
|
||||||
}
|
}
|
||||||
|
|
||||||
libraryPreferences.categorizedDisplaySettings().set(
|
libraryPreferences.categorizedDisplaySettings().set(
|
||||||
|
|||||||
+40
@@ -0,0 +1,40 @@
|
|||||||
|
package eu.kanade.tachiyomi.data.backup.restore.restorers
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.data.backup.models.BackupExtensionRepos
|
||||||
|
import mihon.domain.extensionrepo.interactor.GetExtensionRepo
|
||||||
|
import tachiyomi.data.DatabaseHandler
|
||||||
|
import uy.kohesive.injekt.Injekt
|
||||||
|
import uy.kohesive.injekt.api.get
|
||||||
|
|
||||||
|
class ExtensionRepoRestorer(
|
||||||
|
private val handler: DatabaseHandler = Injekt.get(),
|
||||||
|
private val getExtensionRepos: GetExtensionRepo = Injekt.get()
|
||||||
|
) {
|
||||||
|
|
||||||
|
suspend operator fun invoke(
|
||||||
|
backupRepo: BackupExtensionRepos,
|
||||||
|
) {
|
||||||
|
val dbRepos = getExtensionRepos.getAll()
|
||||||
|
val existingReposBySHA = dbRepos.associateBy { it.signingKeyFingerprint }
|
||||||
|
val existingReposByUrl = dbRepos.associateBy { it.baseUrl }
|
||||||
|
|
||||||
|
val urlExists = existingReposByUrl[backupRepo.baseUrl]
|
||||||
|
val shaExists = existingReposBySHA[backupRepo.signingKeyFingerprint]
|
||||||
|
|
||||||
|
if (urlExists != null && urlExists.signingKeyFingerprint != backupRepo.signingKeyFingerprint) {
|
||||||
|
error("Already Exists with different signing key fingerprint")
|
||||||
|
} else if (shaExists != null) {
|
||||||
|
error("${shaExists.name} has the same signing key fingerprint")
|
||||||
|
} else {
|
||||||
|
handler.await {
|
||||||
|
extension_reposQueries.insert(
|
||||||
|
backupRepo.baseUrl,
|
||||||
|
backupRepo.name,
|
||||||
|
backupRepo.shortName,
|
||||||
|
backupRepo.website,
|
||||||
|
backupRepo.signingKeyFingerprint
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -68,7 +68,7 @@ class MangaRestorer(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun restoreManga(
|
suspend fun restore(
|
||||||
backupManga: BackupManga,
|
backupManga: BackupManga,
|
||||||
backupCategories: List<BackupCategory>,
|
backupCategories: List<BackupCategory>,
|
||||||
) {
|
) {
|
||||||
|
|||||||
+2
-2
@@ -22,14 +22,14 @@ class PreferenceRestorer(
|
|||||||
private val preferenceStore: PreferenceStore = Injekt.get(),
|
private val preferenceStore: PreferenceStore = Injekt.get(),
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun restoreAppPreferences(preferences: List<BackupPreference>) {
|
fun restoreApp(preferences: List<BackupPreference>) {
|
||||||
restorePreferences(preferences, preferenceStore)
|
restorePreferences(preferences, preferenceStore)
|
||||||
|
|
||||||
LibraryUpdateJob.setupTask(context)
|
LibraryUpdateJob.setupTask(context)
|
||||||
BackupCreateJob.setupTask(context)
|
BackupCreateJob.setupTask(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun restoreSourcePreferences(preferences: List<BackupSourcePreferences>) {
|
fun restoreSource(preferences: List<BackupSourcePreferences>) {
|
||||||
preferences.forEach {
|
preferences.forEach {
|
||||||
val sourcePrefs = AndroidPreferenceStore(context, sourcePreferences(it.sourceKey))
|
val sourcePrefs = AndroidPreferenceStore(context, sourcePreferences(it.sourceKey))
|
||||||
restorePreferences(it.prefs, sourcePrefs)
|
restorePreferences(it.prefs, sourcePrefs)
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ import okhttp3.CacheControl
|
|||||||
import okhttp3.Call
|
import okhttp3.Call
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import okhttp3.internal.http.HTTP_NOT_MODIFIED
|
|
||||||
import okio.FileSystem
|
import okio.FileSystem
|
||||||
import okio.Path.Companion.toOkioPath
|
import okio.Path.Companion.toOkioPath
|
||||||
import okio.Source
|
import okio.Source
|
||||||
@@ -348,5 +347,7 @@ class MangaCoverFetcher(
|
|||||||
|
|
||||||
private val CACHE_CONTROL_NO_STORE = CacheControl.Builder().noStore().build()
|
private val CACHE_CONTROL_NO_STORE = CacheControl.Builder().noStore().build()
|
||||||
private val CACHE_CONTROL_NO_NETWORK_NO_CACHE = CacheControl.Builder().noCache().onlyIfCached().build()
|
private val CACHE_CONTROL_NO_NETWORK_NO_CACHE = CacheControl.Builder().noCache().onlyIfCached().build()
|
||||||
|
|
||||||
|
private const val HTTP_NOT_MODIFIED = 304
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import okhttp3.CacheControl
|
|||||||
import okhttp3.Call
|
import okhttp3.Call
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import okhttp3.internal.http.HTTP_NOT_MODIFIED
|
|
||||||
import okio.FileSystem
|
import okio.FileSystem
|
||||||
import okio.Path.Companion.toOkioPath
|
import okio.Path.Companion.toOkioPath
|
||||||
import okio.Source
|
import okio.Source
|
||||||
@@ -260,5 +259,7 @@ class PagePreviewFetcher(
|
|||||||
companion object {
|
companion object {
|
||||||
private val CACHE_CONTROL_NO_STORE = CacheControl.Builder().noStore().build()
|
private val CACHE_CONTROL_NO_STORE = CacheControl.Builder().noStore().build()
|
||||||
private val CACHE_CONTROL_NO_NETWORK_NO_CACHE = CacheControl.Builder().noCache().onlyIfCached().build()
|
private val CACHE_CONTROL_NO_NETWORK_NO_CACHE = CacheControl.Builder().noCache().onlyIfCached().build()
|
||||||
|
|
||||||
|
private const val HTTP_NOT_MODIFIED = 304
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
package eu.kanade.tachiyomi.data.coil
|
package eu.kanade.tachiyomi.data.coil
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import coil3.ImageLoader
|
import coil3.ImageLoader
|
||||||
import coil3.asCoilImage
|
import coil3.asImage
|
||||||
import coil3.decode.DecodeResult
|
import coil3.decode.DecodeResult
|
||||||
import coil3.decode.DecodeUtils
|
import coil3.decode.DecodeUtils
|
||||||
import coil3.decode.Decoder
|
import coil3.decode.Decoder
|
||||||
@@ -11,37 +12,37 @@ import coil3.decode.ImageSource
|
|||||||
import coil3.fetch.SourceFetchResult
|
import coil3.fetch.SourceFetchResult
|
||||||
import coil3.request.Options
|
import coil3.request.Options
|
||||||
import coil3.request.bitmapConfig
|
import coil3.request.bitmapConfig
|
||||||
|
import com.hippo.unifile.UniFile
|
||||||
import eu.kanade.tachiyomi.util.storage.CbzCrypto
|
import eu.kanade.tachiyomi.util.storage.CbzCrypto
|
||||||
|
import eu.kanade.tachiyomi.util.storage.CbzCrypto.getCoverStream
|
||||||
import eu.kanade.tachiyomi.util.system.GLUtil
|
import eu.kanade.tachiyomi.util.system.GLUtil
|
||||||
import net.lingala.zip4j.ZipFile
|
import mihon.core.common.archive.archiveReader
|
||||||
import net.lingala.zip4j.model.FileHeader
|
|
||||||
import okio.BufferedSource
|
import okio.BufferedSource
|
||||||
import tachiyomi.core.common.util.system.ImageUtil
|
import tachiyomi.core.common.util.system.ImageUtil
|
||||||
import tachiyomi.decoder.ImageDecoder
|
import tachiyomi.decoder.ImageDecoder
|
||||||
|
import uy.kohesive.injekt.Injekt
|
||||||
|
import uy.kohesive.injekt.api.get
|
||||||
|
import java.io.BufferedInputStream
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A [Decoder] that uses built-in [ImageDecoder] to decode images that is not supported by the system.
|
* A [Decoder] that uses built-in [ImageDecoder] to decode images that is not supported by the system.
|
||||||
*/
|
*/
|
||||||
class TachiyomiImageDecoder(private val resources: ImageSource, private val options: Options) : Decoder {
|
class TachiyomiImageDecoder(private val resources: ImageSource, private val options: Options) : Decoder {
|
||||||
|
private val context = Injekt.get<Application>()
|
||||||
|
|
||||||
override suspend fun decode(): DecodeResult {
|
override suspend fun decode(): DecodeResult {
|
||||||
// SY -->
|
// SY -->
|
||||||
var zip4j: ZipFile? = null
|
var coverStream: BufferedInputStream? = null
|
||||||
var entry: FileHeader? = null
|
|
||||||
|
|
||||||
if (resources.sourceOrNull()?.peek()?.use { CbzCrypto.detectCoverImageArchive(it.inputStream()) } == true) {
|
if (resources.sourceOrNull()?.peek()?.use { CbzCrypto.detectCoverImageArchive(it.inputStream()) } == true) {
|
||||||
if (resources.source().peek().use { ImageUtil.findImageType(it.inputStream()) == null }) {
|
if (resources.source().peek().use { ImageUtil.findImageType(it.inputStream()) == null }) {
|
||||||
zip4j = ZipFile(resources.file().toFile().absolutePath)
|
coverStream = UniFile.fromFile(resources.file().toFile())
|
||||||
entry = zip4j.fileHeaders.firstOrNull {
|
?.archiveReader(context = context)
|
||||||
it.fileName.equals(CbzCrypto.DEFAULT_COVER_NAME, ignoreCase = true)
|
?.getCoverStream()
|
||||||
}
|
|
||||||
|
|
||||||
if (zip4j.isEncrypted) zip4j.setPassword(CbzCrypto.getDecryptedPasswordCbz())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val decoder = resources.sourceOrNull()?.use {
|
val decoder = resources.sourceOrNull()?.use {
|
||||||
zip4j.use { zipFile ->
|
coverStream.use { coverStream ->
|
||||||
ImageDecoder.newInstance(zipFile?.getInputStream(entry) ?: it.inputStream(), options.cropBorders, displayProfile)
|
ImageDecoder.newInstance(coverStream ?: it.inputStream(), options.cropBorders, displayProfile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// SY <--
|
// SY <--
|
||||||
@@ -80,7 +81,7 @@ class TachiyomiImageDecoder(private val resources: ImageSource, private val opti
|
|||||||
}
|
}
|
||||||
|
|
||||||
return DecodeResult(
|
return DecodeResult(
|
||||||
image = bitmap.asCoilImage(),
|
image = bitmap.asImage(),
|
||||||
isSampled = sampleSize > 1,
|
isSampled = sampleSize > 1,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import eu.kanade.tachiyomi.source.Source
|
|||||||
import eu.kanade.tachiyomi.source.model.Page
|
import eu.kanade.tachiyomi.source.model.Page
|
||||||
import eu.kanade.tachiyomi.util.storage.DiskUtil
|
import eu.kanade.tachiyomi.util.storage.DiskUtil
|
||||||
import exh.log.xLogE
|
import exh.log.xLogE
|
||||||
|
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.asFlow
|
import kotlinx.coroutines.flow.asFlow
|
||||||
import kotlinx.coroutines.flow.drop
|
import kotlinx.coroutines.flow.drop
|
||||||
@@ -20,6 +21,7 @@ import logcat.LogPriority
|
|||||||
import tachiyomi.core.common.i18n.stringResource
|
import tachiyomi.core.common.i18n.stringResource
|
||||||
import tachiyomi.core.common.storage.extension
|
import tachiyomi.core.common.storage.extension
|
||||||
import tachiyomi.core.common.util.lang.launchIO
|
import tachiyomi.core.common.util.lang.launchIO
|
||||||
|
import tachiyomi.core.common.util.system.ImageUtil
|
||||||
import tachiyomi.core.common.util.system.logcat
|
import tachiyomi.core.common.util.system.logcat
|
||||||
import tachiyomi.domain.category.interactor.GetCategories
|
import tachiyomi.domain.category.interactor.GetCategories
|
||||||
import tachiyomi.domain.chapter.model.Chapter
|
import tachiyomi.domain.chapter.model.Chapter
|
||||||
@@ -35,6 +37,7 @@ import uy.kohesive.injekt.api.get
|
|||||||
* and retrieved through dependency injection. You can use this class to queue new chapters or query
|
* and retrieved through dependency injection. You can use this class to queue new chapters or query
|
||||||
* downloaded chapters.
|
* downloaded chapters.
|
||||||
*/
|
*/
|
||||||
|
@OptIn(DelicateCoroutinesApi::class)
|
||||||
class DownloadManager(
|
class DownloadManager(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
private val provider: DownloadProvider = Injekt.get(),
|
private val provider: DownloadProvider = Injekt.get(),
|
||||||
@@ -168,7 +171,7 @@ class DownloadManager(
|
|||||||
source,
|
source,
|
||||||
)
|
)
|
||||||
val files = chapterDir?.listFiles().orEmpty()
|
val files = chapterDir?.listFiles().orEmpty()
|
||||||
.filter { "image" in it.type.orEmpty() }
|
.filter { it.isFile && ImageUtil.isImage(it.name) { it.openInputStream() } }
|
||||||
|
|
||||||
if (files.isEmpty()) {
|
if (files.isEmpty()) {
|
||||||
throw Exception(context.stringResource(MR.strings.page_list_empty_error))
|
throw Exception(context.stringResource(MR.strings.page_list_empty_error))
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import exh.util.DataSaver
|
|||||||
import exh.util.DataSaver.Companion.getImage
|
import exh.util.DataSaver.Companion.getImage
|
||||||
import kotlinx.coroutines.CancellationException
|
import kotlinx.coroutines.CancellationException
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.SupervisorJob
|
import kotlinx.coroutines.SupervisorJob
|
||||||
@@ -43,10 +44,10 @@ import kotlinx.coroutines.flow.update
|
|||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.supervisorScope
|
import kotlinx.coroutines.supervisorScope
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
|
import mihon.core.common.archive.ZipWriter
|
||||||
import nl.adaptivity.xmlutil.serialization.XML
|
import nl.adaptivity.xmlutil.serialization.XML
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import tachiyomi.core.common.i18n.stringResource
|
import tachiyomi.core.common.i18n.stringResource
|
||||||
import tachiyomi.core.common.storage.addFilesToZip
|
|
||||||
import tachiyomi.core.common.storage.extension
|
import tachiyomi.core.common.storage.extension
|
||||||
import tachiyomi.core.common.util.lang.launchIO
|
import tachiyomi.core.common.util.lang.launchIO
|
||||||
import tachiyomi.core.common.util.lang.launchNow
|
import tachiyomi.core.common.util.lang.launchNow
|
||||||
@@ -64,18 +65,15 @@ import tachiyomi.domain.track.interactor.GetTracks
|
|||||||
import tachiyomi.i18n.MR
|
import tachiyomi.i18n.MR
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
import java.io.BufferedOutputStream
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import java.util.zip.CRC32
|
|
||||||
import java.util.zip.ZipEntry
|
|
||||||
import java.util.zip.ZipOutputStream
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class is the one in charge of downloading chapters.
|
* This class is the one in charge of downloading chapters.
|
||||||
*
|
*
|
||||||
* Its queue contains the list of chapters to download.
|
* Its queue contains the list of chapters to download.
|
||||||
*/
|
*/
|
||||||
|
@OptIn(DelicateCoroutinesApi::class)
|
||||||
class Downloader(
|
class Downloader(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
private val provider: DownloadProvider,
|
private val provider: DownloadProvider,
|
||||||
@@ -551,14 +549,8 @@ class Downloader(
|
|||||||
* @param file the file where the image is already downloaded.
|
* @param file the file where the image is already downloaded.
|
||||||
*/
|
*/
|
||||||
private fun getImageExtension(response: Response, file: UniFile): String {
|
private fun getImageExtension(response: Response, file: UniFile): String {
|
||||||
// Read content type if available.
|
|
||||||
val mime = response.body.contentType()?.run { if (type == "image") "image/$subtype" else null }
|
val mime = response.body.contentType()?.run { if (type == "image") "image/$subtype" else null }
|
||||||
// Else guess from the uri.
|
return ImageUtil.getExtensionFromMimeType(mime) { file.openInputStream() }
|
||||||
?: context.contentResolver.getType(file.uri)
|
|
||||||
// Else read magic numbers.
|
|
||||||
?: ImageUtil.findImageType { file.openInputStream() }?.mime
|
|
||||||
|
|
||||||
return ImageUtil.getExtensionFromMimeType(mime)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun splitTallImageIfNeeded(page: Page, tmpDir: UniFile) {
|
private fun splitTallImageIfNeeded(page: Page, tmpDir: UniFile) {
|
||||||
@@ -623,70 +615,19 @@ class Downloader(
|
|||||||
tmpDir: UniFile,
|
tmpDir: UniFile,
|
||||||
) {
|
) {
|
||||||
// SY -->
|
// SY -->
|
||||||
if (CbzCrypto.getPasswordProtectDlPref() && CbzCrypto.isPasswordSet()) {
|
val encrypt = CbzCrypto.getPasswordProtectDlPref() && CbzCrypto.isPasswordSet()
|
||||||
archiveEncryptedChapter(mangaDir, dirname, tmpDir)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// SY <--
|
// SY <--
|
||||||
|
|
||||||
val zip = mangaDir.createFile("$dirname.cbz$TMP_DIR_SUFFIX")!!
|
val zip = mangaDir.createFile("$dirname.cbz$TMP_DIR_SUFFIX")!!
|
||||||
ZipOutputStream(BufferedOutputStream(zip.openOutputStream())).use { zipOut ->
|
ZipWriter(context, zip, /* SY --> */ encrypt /* SY <-- */).use { writer ->
|
||||||
zipOut.setMethod(ZipEntry.STORED)
|
tmpDir.listFiles()?.forEach { file ->
|
||||||
|
writer.write(file)
|
||||||
tmpDir.listFiles()?.forEach { img ->
|
|
||||||
img.openInputStream().use { input ->
|
|
||||||
val data = input.readBytes()
|
|
||||||
val size = img.length()
|
|
||||||
val entry = ZipEntry(img.name).apply {
|
|
||||||
val crc = CRC32().apply {
|
|
||||||
update(data)
|
|
||||||
}
|
|
||||||
setCrc(crc.value)
|
|
||||||
|
|
||||||
compressedSize = size
|
|
||||||
setSize(size)
|
|
||||||
}
|
|
||||||
zipOut.putNextEntry(entry)
|
|
||||||
zipOut.write(data)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
zip.renameTo("$dirname.cbz")
|
zip.renameTo("$dirname.cbz")
|
||||||
tmpDir.delete()
|
tmpDir.delete()
|
||||||
}
|
}
|
||||||
|
|
||||||
// SY -->
|
|
||||||
|
|
||||||
private fun archiveEncryptedChapter(
|
|
||||||
mangaDir: UniFile,
|
|
||||||
dirname: String,
|
|
||||||
tmpDir: UniFile,
|
|
||||||
) {
|
|
||||||
tmpDir.filePath?.let { addPaddingToImage(File(it)) }
|
|
||||||
|
|
||||||
tmpDir.listFiles()?.toList()?.let { files ->
|
|
||||||
mangaDir.createFile("$dirname.cbz$TMP_DIR_SUFFIX")
|
|
||||||
?.addFilesToZip(files, CbzCrypto.getDecryptedPasswordCbz())
|
|
||||||
}
|
|
||||||
|
|
||||||
mangaDir.findFile("$dirname.cbz$TMP_DIR_SUFFIX")?.renameTo("$dirname.cbz")
|
|
||||||
tmpDir.delete()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun addPaddingToImage(imageDir: File) {
|
|
||||||
imageDir.listFiles()
|
|
||||||
// using ImageUtils isImage and findImageType functions causes IO errors when deleting files to set Exif Metadata
|
|
||||||
// it should be safe to assume that all files with image extensions are actual images at this point
|
|
||||||
?.filter {
|
|
||||||
it.extension.equals("jpg", true) ||
|
|
||||||
it.extension.equals("jpeg", true) ||
|
|
||||||
it.extension.equals("png", true) ||
|
|
||||||
it.extension.equals("webp", true)
|
|
||||||
}
|
|
||||||
?.forEach { ImageUtil.addPaddingToImageExif(it) }
|
|
||||||
}
|
|
||||||
// SY <--
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a ComicInfo.xml file inside the given directory.
|
* Creates a ComicInfo.xml file inside the given directory.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import android.graphics.BitmapFactory
|
|||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
import androidx.core.app.NotificationManagerCompat
|
import androidx.core.app.NotificationManagerCompat
|
||||||
|
import coil3.asDrawable
|
||||||
import coil3.imageLoader
|
import coil3.imageLoader
|
||||||
import coil3.request.ImageRequest
|
import coil3.request.ImageRequest
|
||||||
import coil3.request.transformations
|
import coil3.request.transformations
|
||||||
@@ -27,6 +28,7 @@ import eu.kanade.tachiyomi.util.system.cancelNotification
|
|||||||
import eu.kanade.tachiyomi.util.system.getBitmapOrNull
|
import eu.kanade.tachiyomi.util.system.getBitmapOrNull
|
||||||
import eu.kanade.tachiyomi.util.system.notificationBuilder
|
import eu.kanade.tachiyomi.util.system.notificationBuilder
|
||||||
import eu.kanade.tachiyomi.util.system.notify
|
import eu.kanade.tachiyomi.util.system.notify
|
||||||
|
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||||
import tachiyomi.core.common.Constants
|
import tachiyomi.core.common.Constants
|
||||||
import tachiyomi.core.common.i18n.pluralStringResource
|
import tachiyomi.core.common.i18n.pluralStringResource
|
||||||
import tachiyomi.core.common.i18n.stringResource
|
import tachiyomi.core.common.i18n.stringResource
|
||||||
@@ -41,6 +43,7 @@ import uy.kohesive.injekt.api.get
|
|||||||
import java.math.RoundingMode
|
import java.math.RoundingMode
|
||||||
import java.text.NumberFormat
|
import java.text.NumberFormat
|
||||||
|
|
||||||
|
@OptIn(DelicateCoroutinesApi::class)
|
||||||
class LibraryUpdateNotifier(
|
class LibraryUpdateNotifier(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user