Compare commits
No commits in common. "master" and "1.9.2" have entirely different histories.
@ -1,40 +1,7 @@
|
|||||||
root = true
|
|
||||||
|
|
||||||
[*]
|
|
||||||
charset = utf-8
|
|
||||||
indent_size = 2
|
|
||||||
indent_style = space
|
|
||||||
insert_final_newline = true
|
|
||||||
trim_trailing_whitespace = true
|
|
||||||
|
|
||||||
[*.{xml,sq,sqm}]
|
|
||||||
indent_size = 4
|
|
||||||
|
|
||||||
# noinspection EditorConfigKeyCorrectness
|
|
||||||
[*.{kt,kts}]
|
[*.{kt,kts}]
|
||||||
indent_size=4
|
indent_size=4
|
||||||
max_line_length = 120
|
insert_final_newline=true
|
||||||
|
|
||||||
ij_kotlin_allow_trailing_comma=true
|
ij_kotlin_allow_trailing_comma=true
|
||||||
ij_kotlin_allow_trailing_comma_on_call_site=true
|
ij_kotlin_allow_trailing_comma_on_call_site=true
|
||||||
ij_kotlin_name_count_to_use_star_import = 2147483647
|
ij_kotlin_name_count_to_use_star_import = 2147483647
|
||||||
ij_kotlin_name_count_to_use_star_import_for_members = 2147483647
|
ij_kotlin_name_count_to_use_star_import_for_members = 2147483647
|
||||||
|
|
||||||
ktlint_code_style = intellij_idea
|
|
||||||
ktlint_function_naming_ignore_when_annotated_with = Composable
|
|
||||||
ktlint_standard_class-signature = disabled
|
|
||||||
ktlint_standard_discouraged-comment-location = disabled
|
|
||||||
ktlint_standard_function-expression-body = disabled
|
|
||||||
ktlint_standard_function-signature = disabled
|
|
||||||
# SY
|
|
||||||
ktlint_standard_filename = disabled
|
|
||||||
ktlint_standard_argument-list-wrapping = disabled
|
|
||||||
ktlint_standard_function-naming = disabled
|
|
||||||
ktlint_standard_property-naming = disabled
|
|
||||||
ktlint_standard_multiline-expression-wrapping = disabled
|
|
||||||
ktlint_standard_string-template-indent = disabled
|
|
||||||
ktlint_standard_comment-wrapping = disabled
|
|
||||||
ktlint_standard_max-line-length = disabled
|
|
||||||
ktlint_standard_type-argument-comment = disabled
|
|
||||||
ktlint_standard_value-argument-comment = disabled
|
|
||||||
ktlint_standard_value-parameter-comment = disabled
|
|
||||||
|
1
.github/FUNDING.yml
vendored
Normal file
1
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
ko_fi: inorichi
|
34
.github/ISSUE_TEMPLATE.md
vendored
Executable file
34
.github/ISSUE_TEMPLATE.md
vendored
Executable file
@ -0,0 +1,34 @@
|
|||||||
|
**PLEASE READ THIS**
|
||||||
|
|
||||||
|
I acknowledge that:
|
||||||
|
|
||||||
|
- I have updated:
|
||||||
|
- To the latest version of the app (stable is v1.9.2)
|
||||||
|
- All extensions
|
||||||
|
- I have tried the troubleshooting guide: https://tachiyomi.org/help/guides/troubleshooting-problems/
|
||||||
|
- If this is an issue with an extension, that I should be opening an issue in https://github.com/tachiyomiorg/tachiyomi-extensions
|
||||||
|
- I have searched the existing issues and this is new ticket **NOT** a duplicate or related to another open or closed issue
|
||||||
|
- I will fill out the title and the information in this template
|
||||||
|
|
||||||
|
Note that the issue will be automatically closed if you do not fill out the title or requested information.
|
||||||
|
|
||||||
|
**DELETE THIS SECTION IF YOU HAVE READ AND ACKNOWLEDGED IT**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Device information
|
||||||
|
* Tachiyomi version: ?
|
||||||
|
* Android version: ?
|
||||||
|
* Device: ?
|
||||||
|
|
||||||
|
## Steps to reproduce
|
||||||
|
1. First step
|
||||||
|
2. Second step
|
||||||
|
|
||||||
|
## Issue/Request
|
||||||
|
?
|
||||||
|
|
||||||
|
## Other details
|
||||||
|
Additional details and attachments.
|
||||||
|
|
||||||
|
If you're experiencing crashes, share the crash logs from More → Settings → Advanced → Dump crash logs.
|
13
.github/ISSUE_TEMPLATE/config.yml
vendored
13
.github/ISSUE_TEMPLATE/config.yml
vendored
@ -1,8 +1,11 @@
|
|||||||
blank_issues_enabled: false
|
blank_issues_enabled: false
|
||||||
contact_links:
|
contact_links:
|
||||||
- name: ❌ Help with Extensions
|
- name: ⚠️ Extension/source issue
|
||||||
url: https://mihon.app/docs/faq/browse/extensions
|
url: https://github.com/tachiyomiorg/tachiyomi-extensions/issues/new/choose
|
||||||
about: For extension-related questions/issues
|
about: Issues and requests for extensions and sources should be opened in the tachiyomi-extensions repository instead
|
||||||
- name: 🖥️ Mihon website
|
- name: 📦 Tachiyomi extensions
|
||||||
url: https://mihon.app/
|
url: https://tachiyomi.org/extensions
|
||||||
|
about: List of all available extensions with download links
|
||||||
|
- name: 🖥️ Tachiyomi website
|
||||||
|
url: https://tachiyomi.org/help/
|
||||||
about: Guides, troubleshooting, and answers to common questions
|
about: Guides, troubleshooting, and answers to common questions
|
||||||
|
30
.github/ISSUE_TEMPLATE/report_issue.yml
vendored
30
.github/ISSUE_TEMPLATE/report_issue.yml
vendored
@ -1,5 +1,5 @@
|
|||||||
name: 🐞 Issue report
|
name: 🐞 Issue report
|
||||||
description: Report an issue in TachiyomiSY
|
description: Report an issue in Tachiyomi
|
||||||
labels: [Bug]
|
labels: [Bug]
|
||||||
body:
|
body:
|
||||||
|
|
||||||
@ -43,17 +43,17 @@ body:
|
|||||||
attributes:
|
attributes:
|
||||||
label: Crash logs
|
label: Crash logs
|
||||||
description: |
|
description: |
|
||||||
If you're experiencing crashes, if possible, go to the app's **More → Settings → Advanced** page, press **Dump crash logs** and share the crash logs here.
|
If you're experiencing crashes, share the crash logs from **More → Settings → Advanced** then press **Dump crash logs**.
|
||||||
placeholder: |
|
placeholder: |
|
||||||
You can upload the crash log file as an attachment, or paste the crash logs in plain text if needed.
|
You can paste the crash logs in plain text or upload it as an attachment.
|
||||||
|
|
||||||
- type: input
|
- type: input
|
||||||
id: tachiyomisy-version
|
id: tachiyomi-version
|
||||||
attributes:
|
attributes:
|
||||||
label: TachiyomiSY version
|
label: Tachiyomi version
|
||||||
description: You can find your TachiyomiSY version in **More → About**.
|
description: You can find your Tachiyomi version in **More → About**.
|
||||||
placeholder: |
|
placeholder: |
|
||||||
Example: "1.12.0"
|
Example: "1.9.2"
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
|
|
||||||
@ -63,7 +63,7 @@ body:
|
|||||||
label: Android version
|
label: Android version
|
||||||
description: You can find this somewhere in your Android settings.
|
description: You can find this somewhere in your Android settings.
|
||||||
placeholder: |
|
placeholder: |
|
||||||
Example: "Android 14"
|
Example: "Android 11"
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
|
|
||||||
@ -73,7 +73,7 @@ body:
|
|||||||
label: Device
|
label: Device
|
||||||
description: List your device and model.
|
description: List your device and model.
|
||||||
placeholder: |
|
placeholder: |
|
||||||
Example: "Google Pixel 8"
|
Example: "Google Pixel 5"
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
|
|
||||||
@ -90,15 +90,19 @@ body:
|
|||||||
label: Acknowledgements
|
label: Acknowledgements
|
||||||
description: Read this carefully, we will close and ignore your issue if you skimmed through this.
|
description: Read this carefully, we will close and ignore your issue if you skimmed through this.
|
||||||
options:
|
options:
|
||||||
|
- label: This is a TachiyomiSY specific issue that does not happen in [Tachiyomi Preview](https://github.com/tachiyomiorg/tachiyomi/).
|
||||||
|
required: true
|
||||||
- label: I have searched the existing issues and this is a new ticket, **NOT** a duplicate or related to another open or closed issue.
|
- label: I have searched the existing issues and this is a new ticket, **NOT** a duplicate or related to another open or closed issue.
|
||||||
required: true
|
required: true
|
||||||
- label: I have written a short but informative title.
|
- label: I have written a short but informative title.
|
||||||
required: true
|
required: true
|
||||||
- label: I have gone through the [FAQ](https://mihon.app/docs/faq/general) and [troubleshooting guide](https://mihon.app/docs/guides/troubleshooting/).
|
- label: If this is an issue with an extension, I should be opening an issue in the [extensions repository](https://github.com/tachiyomiorg/tachiyomi-extensions/issues/new/choose).
|
||||||
required: true
|
required: true
|
||||||
- label: I have updated the app to version **[1.12.0](https://github.com/jobobby04/tachiyomisy/releases/latest)**.
|
- label: I have tried the [troubleshooting guide](https://tachiyomi.org/help/guides/troubleshooting/).
|
||||||
required: true
|
required: true
|
||||||
- label: I have filled out all of the requested information in this form, including specific version numbers.
|
- label: I have updated the app to version **[1.9.2](https://github.com/jobobby04/tachiyomisy/releases/latest)**.
|
||||||
required: true
|
required: true
|
||||||
- label: I understand that **Mihon does not have or fix any extensions**, and I **will not receive help** for any issues related to sources or extensions.
|
- label: I have updated all installed extensions.
|
||||||
|
required: true
|
||||||
|
- label: I will fill out all of the requested information in this form.
|
||||||
required: true
|
required: true
|
||||||
|
8
.github/ISSUE_TEMPLATE/request_feature.yml
vendored
8
.github/ISSUE_TEMPLATE/request_feature.yml
vendored
@ -1,5 +1,5 @@
|
|||||||
name: ⭐ Feature request
|
name: ⭐ Feature request
|
||||||
description: Suggest a feature to improve TachiyomiSY
|
description: Suggest a feature to improve Tachiyomi
|
||||||
labels: [Feature request]
|
labels: [Feature request]
|
||||||
body:
|
body:
|
||||||
|
|
||||||
@ -7,7 +7,7 @@ body:
|
|||||||
id: feature-description
|
id: feature-description
|
||||||
attributes:
|
attributes:
|
||||||
label: Describe your suggested feature
|
label: Describe your suggested feature
|
||||||
description: How can TachiyomiSY be improved?
|
description: How can Tachiyomi be improved?
|
||||||
placeholder: |
|
placeholder: |
|
||||||
Example:
|
Example:
|
||||||
"It should work like this..."
|
"It should work like this..."
|
||||||
@ -31,7 +31,9 @@ body:
|
|||||||
required: true
|
required: true
|
||||||
- label: I have written a short but informative title.
|
- label: I have written a short but informative title.
|
||||||
required: true
|
required: true
|
||||||
- label: I have updated the app to version **[1.12.0](https://github.com/jobobby04/tachiyomisy/releases/latest)**.
|
- label: If this is an issue with an extension, I should be opening an issue in the [extensions repository](https://github.com/tachiyomiorg/tachiyomi-extensions/issues/new/choose).
|
||||||
|
required: true
|
||||||
|
- label: I have updated the app to version **[1.9.2](https://github.com/jobobby04/tachiyomisy/releases/latest)**.
|
||||||
required: true
|
required: true
|
||||||
- label: I will fill out all of the requested information in this form.
|
- label: I will fill out all of the requested information in this form.
|
||||||
required: true
|
required: true
|
||||||
|
BIN
.github/readme-images/screens.png
vendored
BIN
.github/readme-images/screens.png
vendored
Binary file not shown.
Before Width: | Height: | Size: 713 KiB After Width: | Height: | Size: 489 KiB |
7
.github/renovate.json5
vendored
7
.github/renovate.json5
vendored
@ -1,7 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
|
||||||
"extends": ["config:base"],
|
|
||||||
"labels": ["Dependencies"],
|
|
||||||
"includePaths": [".github/workflows/*", "gradle/sy.versions.toml"],
|
|
||||||
"semanticCommits": "disabled"
|
|
||||||
}
|
|
35
.github/workflows/build_check.yml
vendored
35
.github/workflows/build_check.yml
vendored
@ -6,28 +6,39 @@ concurrency:
|
|||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
check_wrapper:
|
||||||
name: Build app
|
name: Validate Gradle Wrapper
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Clone repo
|
- name: Clone repo
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Set up JDK
|
- name: Validate Gradle Wrapper
|
||||||
uses: actions/setup-java@v4
|
uses: gradle/wrapper-validation-action@v1
|
||||||
|
|
||||||
|
build:
|
||||||
|
name: Build app
|
||||||
|
needs: check_wrapper
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Clone repo
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Set up JDK 11
|
||||||
|
uses: actions/setup-java@v3
|
||||||
with:
|
with:
|
||||||
java-version: 17
|
java-version: 11
|
||||||
distribution: temurin
|
distribution: adopt
|
||||||
|
|
||||||
- name: Set up gradle
|
|
||||||
uses: gradle/actions/setup-gradle@v4
|
|
||||||
|
|
||||||
- name: Build app
|
- name: Build app
|
||||||
run: ./gradlew spotlessCheck assembleDevDebug
|
uses: gradle/gradle-command-action@v2
|
||||||
|
with:
|
||||||
|
arguments: assembleDevDebug
|
||||||
|
|
||||||
- name: Upload APK
|
- name: Upload APK
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v3
|
||||||
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
|
||||||
|
55
.github/workflows/build_push.yml
vendored
55
.github/workflows/build_push.yml
vendored
@ -15,45 +15,30 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Clone repo
|
- name: Clone repo
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Setup Android SDK
|
- name: Validate Gradle Wrapper
|
||||||
run: |
|
uses: gradle/wrapper-validation-action@v1
|
||||||
${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin/sdkmanager "build-tools;29.0.3"
|
|
||||||
|
|
||||||
- name: Set up JDK
|
- name: Set up JDK 11
|
||||||
uses: actions/setup-java@v4
|
uses: actions/setup-java@v3
|
||||||
with:
|
with:
|
||||||
java-version: 17
|
java-version: 11
|
||||||
distribution: temurin
|
distribution: adopt
|
||||||
|
|
||||||
- name: Set up gradle
|
# SY <--
|
||||||
uses: gradle/actions/setup-gradle@v4
|
|
||||||
|
|
||||||
# SY -->
|
|
||||||
- name: Write google-services.json
|
- name: Write google-services.json
|
||||||
uses: DamianReeves/write-file-action@v1.3
|
uses: DamianReeves/write-file-action@v1.2
|
||||||
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
|
||||||
|
# SY -->
|
||||||
|
|
||||||
- name: Write client_secrets.json
|
- name: Build app and run unit tests
|
||||||
uses: DamianReeves/write-file-action@v1.3
|
uses: gradle/gradle-command-action@v2
|
||||||
with:
|
with:
|
||||||
path: app/src/main/assets/client_secrets.json
|
arguments: lintKotlin assembleStandardRelease testStandardReleaseUnitTest --stacktrace
|
||||||
contents: ${{ secrets.CLIENT_SECRETS_TEXT }}
|
|
||||||
write-mode: overwrite
|
|
||||||
# SY <--
|
|
||||||
|
|
||||||
- name: Check code format
|
|
||||||
run: ./gradlew spotlessCheck
|
|
||||||
|
|
||||||
- name: Build app
|
|
||||||
run: ./gradlew assembleStandardRelease
|
|
||||||
|
|
||||||
- name: Run unit tests
|
|
||||||
run: ./gradlew testReleaseUnitTest testStandardReleaseUnitTest
|
|
||||||
|
|
||||||
- name: Sign APK
|
- name: Sign APK
|
||||||
uses: r0adkll/sign-android-release@v1
|
uses: r0adkll/sign-android-release@v1
|
||||||
@ -63,8 +48,6 @@ jobs:
|
|||||||
alias: ${{ secrets.ALIAS }}
|
alias: ${{ secrets.ALIAS }}
|
||||||
keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }}
|
keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }}
|
||||||
keyPassword: ${{ secrets.KEY_PASSWORD }}
|
keyPassword: ${{ secrets.KEY_PASSWORD }}
|
||||||
env:
|
|
||||||
BUILD_TOOLS_VERSION: '35.0.1'
|
|
||||||
|
|
||||||
- name: Clean up build artifacts
|
- name: Clean up build artifacts
|
||||||
run: |
|
run: |
|
||||||
@ -74,24 +57,24 @@ jobs:
|
|||||||
sha=`sha256sum TachiyomiSY.apk | awk '{ print $1 }'`
|
sha=`sha256sum TachiyomiSY.apk | awk '{ print $1 }'`
|
||||||
echo "APK_UNIVERSAL_SHA=$sha" >> $GITHUB_ENV
|
echo "APK_UNIVERSAL_SHA=$sha" >> $GITHUB_ENV
|
||||||
|
|
||||||
mv app/build/outputs/apk/standard/release/app-standard-arm64-v8a-release-unsigned-signed.apk TachiyomiSY-arm64-v8a.apk
|
cp app/build/outputs/apk/standard/release/app-standard-arm64-v8a-release-unsigned-signed.apk TachiyomiSY-arm64-v8a.apk
|
||||||
sha=`sha256sum TachiyomiSY-arm64-v8a.apk | awk '{ print $1 }'`
|
sha=`sha256sum TachiyomiSY-arm64-v8a.apk | awk '{ print $1 }'`
|
||||||
echo "APK_ARM64_V8A_SHA=$sha" >> $GITHUB_ENV
|
echo "APK_ARM64_V8A_SHA=$sha" >> $GITHUB_ENV
|
||||||
|
|
||||||
mv app/build/outputs/apk/standard/release/app-standard-armeabi-v7a-release-unsigned-signed.apk TachiyomiSY-armeabi-v7a.apk
|
cp app/build/outputs/apk/standard/release/app-standard-armeabi-v7a-release-unsigned-signed.apk TachiyomiSY-armeabi-v7a.apk
|
||||||
sha=`sha256sum TachiyomiSY-armeabi-v7a.apk | awk '{ print $1 }'`
|
sha=`sha256sum TachiyomiSY-armeabi-v7a.apk | awk '{ print $1 }'`
|
||||||
echo "APK_ARMEABI_V7A_SHA=$sha" >> $GITHUB_ENV
|
echo "APK_ARMEABI_V7A_SHA=$sha" >> $GITHUB_ENV
|
||||||
|
|
||||||
mv app/build/outputs/apk/standard/release/app-standard-x86-release-unsigned-signed.apk TachiyomiSY-x86.apk
|
cp app/build/outputs/apk/standard/release/app-standard-x86-release-unsigned-signed.apk TachiyomiSY-x86.apk
|
||||||
sha=`sha256sum TachiyomiSY-x86.apk | awk '{ print $1 }'`
|
sha=`sha256sum TachiyomiSY-x86.apk | awk '{ print $1 }'`
|
||||||
echo "APK_X86_SHA=$sha" >> $GITHUB_ENV
|
echo "APK_X86_SHA=$sha" >> $GITHUB_ENV
|
||||||
|
|
||||||
mv app/build/outputs/apk/standard/release/app-standard-x86_64-release-unsigned-signed.apk TachiyomiSY-x86_64.apk
|
cp app/build/outputs/apk/standard/release/app-standard-x86_64-release-unsigned-signed.apk TachiyomiSY-x86_64.apk
|
||||||
sha=`sha256sum TachiyomiSY-x86_64.apk | awk '{ print $1 }'`
|
sha=`sha256sum TachiyomiSY-x86_64.apk | awk '{ print $1 }'`
|
||||||
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@v2
|
uses: softprops/action-gh-release@v1
|
||||||
with:
|
with:
|
||||||
tag_name: ${{ github.run_number }}
|
tag_name: ${{ github.run_number }}
|
||||||
name: TachiyomiSY
|
name: TachiyomiSY
|
||||||
@ -107,8 +90,6 @@ jobs:
|
|||||||
| armeabi-v7a | ${{ env.APK_ARMEABI_V7A_SHA }} |
|
| armeabi-v7a | ${{ env.APK_ARMEABI_V7A_SHA }} |
|
||||||
| x86 | ${{ env.APK_X86_SHA }} |
|
| x86 | ${{ env.APK_X86_SHA }} |
|
||||||
| x86_64 | ${{ env.APK_X86_64_SHA }} |
|
| x86_64 | ${{ env.APK_X86_64_SHA }} |
|
||||||
|
|
||||||
## If you are unsure which version to choose then go with TachiyomiSY.apk
|
|
||||||
files: |
|
files: |
|
||||||
TachiyomiSY.apk
|
TachiyomiSY.apk
|
||||||
TachiyomiSY-arm64-v8a.apk
|
TachiyomiSY-arm64-v8a.apk
|
||||||
|
29
.github/workflows/build_push_preview.yml
vendored
29
.github/workflows/build_push_preview.yml
vendored
@ -3,30 +3,28 @@ name: Remote Dispatch Action Initiator
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- 'preview'
|
- 'master'
|
||||||
|
|
||||||
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:
|
||||||
- name: Clone repo
|
- name: Clone repo
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Set up JDK
|
- name: Validate Gradle Wrapper
|
||||||
uses: actions/setup-java@v4
|
uses: gradle/wrapper-validation-action@v1
|
||||||
with:
|
|
||||||
java-version: 17
|
|
||||||
distribution: temurin
|
|
||||||
|
|
||||||
- name: Set up gradle
|
- name: TAG - Bump version and push tag
|
||||||
uses: gradle/actions/setup-gradle@v4
|
uses: anothrNick/github-tag-action@1.39.0
|
||||||
|
env:
|
||||||
- name: Create Tag
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
run: |
|
WITH_V: true
|
||||||
git tag "preview-${{ github.run_number }}"
|
RELEASE_BRANCHES: master
|
||||||
git push origin "preview-${{ github.run_number }}"
|
DEFAULT_BUMP: patch
|
||||||
|
|
||||||
- name: PING - Dispatch initiating repository event
|
- name: PING - Dispatch initiating repository event
|
||||||
run: |
|
run: |
|
||||||
@ -34,6 +32,3 @@ jobs:
|
|||||||
-H 'Accept: application/vnd.github.everest-preview+json' \
|
-H 'Accept: application/vnd.github.everest-preview+json' \
|
||||||
-u ${{ secrets.ACCESS_TOKEN }} \
|
-u ${{ secrets.ACCESS_TOKEN }} \
|
||||||
--data '{"event_type": "ping", "client_payload": { "repository": "'"$GITHUB_REPOSITORY"'" }}'
|
--data '{"event_type": "ping", "client_payload": { "repository": "'"$GITHUB_REPOSITORY"'" }}'
|
||||||
|
|
||||||
- name: Run unit tests
|
|
||||||
run: ./gradlew testDebugUnitTest testDevDebugUnitTest
|
|
||||||
|
18
.github/workflows/issue_moderator.yml
vendored
18
.github/workflows/issue_moderator.yml
vendored
@ -11,11 +11,9 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Moderate issues
|
- name: Moderate issues
|
||||||
uses: tachiyomiorg/issue-moderator-action@v2.6.1
|
uses: tachiyomiorg/issue-moderator-action@v1
|
||||||
with:
|
with:
|
||||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
duplicate-label: Duplicate
|
|
||||||
|
|
||||||
auto-close-rules: |
|
auto-close-rules: |
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
@ -33,19 +31,5 @@ jobs:
|
|||||||
"regex": "^(?!.*myanimelist.*).*(aniyomi|anime).*$",
|
"regex": "^(?!.*myanimelist.*).*(aniyomi|anime).*$",
|
||||||
"ignoreCase": true,
|
"ignoreCase": true,
|
||||||
"message": "Tachiyomi does not support anime, and has no plans to support anime. In addition Tachiyomi is not affiliated with Aniyomi https://github.com/jmir1/aniyomi"
|
"message": "Tachiyomi does not support anime, and has no plans to support anime. In addition Tachiyomi is not affiliated with Aniyomi https://github.com/jmir1/aniyomi"
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "both",
|
|
||||||
"regex": ".*(?:fail(?:ed|ure|s)?|can\\s*(?:no|')?t|(?:not|un).*able|(?<!n[o']?t )blocked by|error) (?:to )?(?:get past|by ?pass|penetrate)?.*cloud ?fl?are.*",
|
|
||||||
"ignoreCase": true,
|
|
||||||
"labels": ["Cloudflare protected"],
|
|
||||||
"message": "Refer to the **Solving Cloudflare issues** section at https://mihon.app/docs/guides/troubleshooting/#cloudflare. If it doesn't work, migrate to other sources or wait until they lower their protection."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "both",
|
|
||||||
"regex": "^.*(myanimelist|mal).*$",
|
|
||||||
"ignoreCase": true,
|
|
||||||
"message": "For issues with linking MyAnimeList, please follow these steps:\n1. Update Mihon to version 0.16.4 or newer\n2. Change your default User-Agent (`More → Settings → Advanced → Default user agent string`)\n3. Close and restart Mihon\n4. Attempt to link MyAnimeList again\n\nIf you had MyAnimeList linked before, try to unlink it first before trying these steps."
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
auto-close-ignore-label: do-not-autoclose
|
|
||||||
|
19
.github/workflows/lock.yml
vendored
Normal file
19
.github/workflows/lock.yml
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
name: Lock threads
|
||||||
|
|
||||||
|
on:
|
||||||
|
# Daily
|
||||||
|
schedule:
|
||||||
|
- cron: '0 0 * * *'
|
||||||
|
# Manual trigger
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
lock:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: dessant/lock-threads@v4
|
||||||
|
with:
|
||||||
|
github-token: ${{ github.token }}
|
||||||
|
issue-inactive-days: '2'
|
||||||
|
pr-inactive-days: '2'
|
26
.github/workflows/pr_label.yml
vendored
26
.github/workflows/pr_label.yml
vendored
@ -1,26 +0,0 @@
|
|||||||
name: Label PRs
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
types: [opened]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
label_pr:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Check PR and Add Label
|
|
||||||
uses: actions/github-script@v7
|
|
||||||
with:
|
|
||||||
script: |
|
|
||||||
const prAuthor = context.payload.pull_request.user.login;
|
|
||||||
|
|
||||||
if (prAuthor === 'weblate') {
|
|
||||||
const labels = ['Translations'];
|
|
||||||
await github.issues.addLabels({
|
|
||||||
owner: context.repo.owner,
|
|
||||||
repo: context.repo.repo,
|
|
||||||
issue_number: context.payload.pull_request.number,
|
|
||||||
labels: labels
|
|
||||||
});
|
|
||||||
}
|
|
37
.gitignore
vendored
37
.gitignore
vendored
@ -1,24 +1,23 @@
|
|||||||
# Build files
|
|
||||||
.gradle
|
.gradle
|
||||||
.kotlin
|
/local.properties
|
||||||
build
|
/.idea/workspace.xml
|
||||||
|
|
||||||
# IDE files
|
|
||||||
*.iml
|
|
||||||
.idea/*
|
|
||||||
!.idea/icon.png
|
|
||||||
/captures
|
|
||||||
|
|
||||||
# Configuration files
|
|
||||||
local.properties
|
|
||||||
|
|
||||||
# macOS specific files
|
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
.idea/
|
||||||
|
*iml
|
||||||
|
*.iml
|
||||||
|
/mainframer
|
||||||
|
/.mainframer
|
||||||
|
|
||||||
# SY ignores
|
# Built files
|
||||||
google-services.json
|
*/build
|
||||||
/app/src/main/assets/client_secrets.json
|
/build
|
||||||
*.apk
|
*.apk
|
||||||
|
app/**/output.json
|
||||||
|
|
||||||
# Custom ignores
|
# Unnecessary file
|
||||||
/keys
|
*.swp
|
||||||
|
|
||||||
|
TODO.md
|
||||||
|
CHANGELOG.md
|
||||||
|
/captures
|
||||||
|
build.sh
|
||||||
|
BIN
.idea/icon.png
generated
BIN
.idea/icon.png
generated
Binary file not shown.
Before Width: | Height: | Size: 14 KiB |
@ -60,7 +60,7 @@ representative at an online or offline event.
|
|||||||
|
|
||||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||||
reported to the community moderators responsible for enforcement at
|
reported to the community moderators responsible for enforcement at
|
||||||
the [Mihon Discord server](https://discord.gg/mihon).
|
the [Tachiyomi Discord server](https://discord.gg/tachiyomi).
|
||||||
All complaints will be reviewed and investigated promptly and fairly.
|
All complaints will be reviewed and investigated promptly and fairly.
|
||||||
|
|
||||||
All community moderators are obligated to respect the privacy and security of the
|
All community moderators are obligated to respect the privacy and security of the
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
Looking to report an issue/bug or make a feature request? Please refer to the [README file](/README.md#issues-feature-requests-and-contributing).
|
Looking to report an issue/bug or make a feature request? Please refer to the [README file](https://github.com/tachiyomiorg/tachiyomi#issues-feature-requests-and-contributing).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -9,7 +9,7 @@ Thanks for your interest in contributing to Tachiyomi!
|
|||||||
|
|
||||||
Pull requests are welcome!
|
Pull requests are welcome!
|
||||||
|
|
||||||
If you're interested in taking on [an open issue](https://github.com/jobobby04/TachiyomiSY/issues), please comment on it so others are aware.
|
If you're interested in taking on [an open issue](https://github.com/tachiyomiorg/tachiyomi/issues), please comment on it so others are aware.
|
||||||
You do not need to ask for permission nor an assignment.
|
You do not need to ask for permission nor an assignment.
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
@ -26,39 +26,25 @@ Before you start, please note that the ability to use following technologies is
|
|||||||
|
|
||||||
## Getting help
|
## Getting help
|
||||||
|
|
||||||
- Join [the Discord server](https://discord.gg/mihon) for online help and to ask questions while developing.
|
- Join [the Discord server](https://discord.gg/tachiyomi) for online help and to ask questions while developing.
|
||||||
|
|
||||||
# Translations
|
# Translations
|
||||||
|
|
||||||
Translations are done externally via Weblate. See [our website](https://mihon.app/docs/contribute#translation) for more details.
|
Translations are done externally via Weblate. See [our website](https://tachiyomi.org/help/contribution/#translation) for more details.
|
||||||
|
|
||||||
|
|
||||||
# Forks
|
# Forks
|
||||||
|
|
||||||
Forks are allowed so long as they abide by [the project's LICENSE](/LICENSE).
|
Forks are allowed so long as they abide by [the project's LICENSE](https://github.com/tachiyomiorg/tachiyomi/blob/master/LICENSE).
|
||||||
|
|
||||||
When creating a fork, remember to:
|
When creating a fork, remember to:
|
||||||
|
|
||||||
- To avoid confusion with the main app:
|
- To avoid confusion with the main app:
|
||||||
- Change the app name
|
- Change the app name
|
||||||
- Change the app icon
|
- Change the app icon
|
||||||
- Change or disable the [app update checker](/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateChecker.kt)
|
- Change or disable the [app update checker](https://github.com/tachiyomiorg/tachiyomi/blob/master/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateChecker.kt)
|
||||||
- To avoid installation conflicts:
|
- To avoid installation conflicts:
|
||||||
- Change the `applicationId` in [`build.gradle.kts`](/app/build.gradle.kts)
|
- Change the `applicationId` in [`build.gradle.kts`](https://github.com/tachiyomiorg/tachiyomi/blob/master/app/build.gradle.kts)
|
||||||
|
- To avoid having your data polluting the main app's analytics and crash report services:
|
||||||
|
- If you want to use Firebase analytics, replace [`google-services.json`](https://github.com/tachiyomiorg/tachiyomi/blob/master/app/src/standard/google-services.json) with your own
|
||||||
### Supporting Cloud Sync - Google Drive Implementation
|
- If you want to use ACRA crash reporting, replace the `ACRA_URI` endpoint in [`build.gradle.kts`](https://github.com/tachiyomiorg/tachiyomi/blob/master/app/build.gradle.kts) with your own
|
||||||
1. Go to [Google Cloud Console](https://console.cloud.google.com)
|
|
||||||
2. Create a new project
|
|
||||||
3. Go to API & Services -> Library -> Google Drive API and click enable
|
|
||||||
4. Go to API & Services -> Oauth consent screen
|
|
||||||
5. Create it, fill in the app name, user support email, and developer contact information
|
|
||||||
6. In the next screen, click add or remove scopes, and add the `.../auth/drive.appdata` and `.../auth/drive.file` scopes
|
|
||||||
7. Don't add any test users and go back to the dashboard
|
|
||||||
8. Click publish
|
|
||||||
9. Go to API & Services -> Credentials
|
|
||||||
10. Click Create credentials -> Oauth client ID
|
|
||||||
11. Select Android, give it a name, and set `eu.kanade.google.oauth` as the package name
|
|
||||||
12. To get the SHA-1 key, run `keytool -printcert -jarfile app-standard-universal-release.apk` on your apk, and copy the listed SHA-1
|
|
||||||
13. Expand advanced settings, and enable Custom URL scheme
|
|
||||||
14. After that just download the json, name it to `client_secrets.json` and put it in `app/src/main/assets/`
|
|
||||||
|
36
README.md
36
README.md
@ -1,20 +1,20 @@
|
|||||||
| Preview Builds | Release Builds | Mihon Support Server |
|
| Preview Builds | Release Builds | Tachiyomi Support Server |
|
||||||
|-------|----------|----------|
|
|-------|----------|----------|
|
||||||
| [](https://github.com/jobobby04/TachiyomiSYPreview/releases) | [](https://github.com/jobobby04/tachiyomisy/releases/latest) | [](https://discord.gg/mihon) |
|
| [](https://github.com/jobobby04/TachiyomiSYPreview/releases) | [](https://github.com/jobobby04/tachiyomisy/releases/latest) | [](https://discord.gg/tachiyomi) |
|
||||||
|
|
||||||
|
|
||||||
# TachiyomiSY
|
# TachiyomiSY
|
||||||
Mihon is a free and open source manga reader for Android 6.0 and above. This version of Mihon, TachiyomiSY was based off TachiyomiAZ. This version is meant to push forward in the ways of usability and features. TachiyomiSY tries to push forward where it can, but staying in a place where it can easily grab updates and features from the main app, it tries to make new features, or take features from other forks like J2K and Neko.
|
Tachiyomi is a free and open source manga reader for Android 6.0 and above. This version of Tachiyomi, TachiyomiSY was based off TachiyomiAZ. This version is meant to push forward in the ways of usability and features. TachiyomiSY tries to push forward where it can, but staying in a place where it can easily grab updates and features from the main app, it tries to make new features, or take features from other forks like J2K and Neko.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
Features of Mihon(original) include:
|
Features of Tachiyomi(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.app/), [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.io/), [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
|
||||||
@ -42,6 +42,7 @@ Features of TachiyomiSY include:
|
|||||||
* Page preload customization
|
* Page preload customization
|
||||||
* Customize image cache size
|
* Customize image cache size
|
||||||
* Batch import of custom sources and featured extensions
|
* Batch import of custom sources and featured extensions
|
||||||
|
* Automatic CAPTCHA solving
|
||||||
* Advanced source settings page, searching, enable/disable all
|
* Advanced source settings page, searching, enable/disable all
|
||||||
* Click tag for local search, long click tag for global search
|
* Click tag for local search, long click tag for global search
|
||||||
* Merge multiple of the same manga from different sources
|
* Merge multiple of the same manga from different sources
|
||||||
@ -67,23 +68,14 @@ 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.
|
||||||
|
|
||||||
<details><summary>Issues</summary>
|
<details><summary>Issues</summary>
|
||||||
|
|
||||||
1. **Before reporting a new issue, take a look at the [FAQ](https://mihon.app/docs/faq/general), the [changelog](https://github.com/jobobby04/tachiyomisy/releases) and the already opened [issues](https://github.com/jobobby04/tachiyomisy/issues).**
|
1. **Before reporting a new issue, take a look at the [FAQ](https://tachiyomi.org/help/faq/), the [changelog](https://github.com/jobobby04/tachiyomisy/releases) and the already opened [issues](https://github.com/jobobby04/tachiyomisy/issues).**
|
||||||
2. If you are unsure, ask here: [](https://discord.gg/mihon)
|
2. If you are unsure, ask here: [](https://discord.gg/tachiyomi)
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
@ -91,13 +83,15 @@ Please make sure to read the full guidelines. Your issue may be closed without w
|
|||||||
|
|
||||||
* Include version (More → About → Version)
|
* Include version (More → About → Version)
|
||||||
* If not latest, try updating, it may have already been solved
|
* If not latest, try updating, it may have already been solved
|
||||||
* Preview version is equal to the number of commits as seen on the main page
|
* Preview version is equal to the number of commits as seen in the main page
|
||||||
* Include steps to reproduce (if not obvious from description)
|
* Include steps to reproduce (if not obvious from description)
|
||||||
* Include screenshot (if needed)
|
* Include screenshot (if needed)
|
||||||
* 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
|
||||||
|
|
||||||
Use the [issue forms](https://github.com/jobobby04/TachiyomiSY/issues/new/choose) to submit a bug.
|
DO: https://github.com/tachiyomiorg/tachiyomi/issues/24 https://github.com/tachiyomiorg/tachiyomi/issues/71
|
||||||
|
|
||||||
|
DON'T: https://github.com/tachiyomiorg/tachiyomi/issues/75
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
@ -106,7 +100,7 @@ Use the [issue forms](https://github.com/jobobby04/TachiyomiSY/issues/new/choose
|
|||||||
* Write a detailed issue, explaining what it should do or how. Avoid writing just "like X app does"
|
* Write a detailed issue, explaining what it should do or how. Avoid writing just "like X app does"
|
||||||
* Include screenshot (if needed)
|
* Include screenshot (if needed)
|
||||||
|
|
||||||
Source requests are not accepted.
|
Source requests should be created at https://github.com/tachiyomiorg/tachiyomi-extensions, they do not belong in this repository.
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<details><summary>Contributing</summary>
|
<details><summary>Contributing</summary>
|
||||||
@ -121,5 +115,5 @@ See [CODE_OF_CONDUCT.md](./CODE_OF_CONDUCT.md).
|
|||||||
|
|
||||||
## FAQ
|
## FAQ
|
||||||
|
|
||||||
[See our website.](https://mihon.app/)
|
[See our website.](https://tachiyomi.org/)
|
||||||
You can also reach out to us on [Discord](https://discord.gg/mihon).
|
You can also reach out to us on [Discord](https://discord.gg/tachiyomi).
|
6
app/.gitignore
vendored
Executable file
6
app/.gitignore
vendored
Executable file
@ -0,0 +1,6 @@
|
|||||||
|
/build
|
||||||
|
*iml
|
||||||
|
*.iml
|
||||||
|
custom.gradle
|
||||||
|
google-services.json
|
||||||
|
output.json
|
@ -1,46 +1,41 @@
|
|||||||
@file:Suppress("ChromeOsAbiSupport")
|
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||||
|
import org.jmailen.gradle.kotlinter.tasks.LintTask
|
||||||
import mihon.buildlogic.getBuildTime
|
|
||||||
import mihon.buildlogic.getCommitCount
|
|
||||||
import mihon.buildlogic.getGitSha
|
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("mihon.android.application")
|
id("com.android.application")
|
||||||
id("mihon.android.application.compose")
|
id("com.mikepenz.aboutlibraries.plugin")
|
||||||
|
kotlin("android")
|
||||||
kotlin("plugin.parcelize")
|
kotlin("plugin.parcelize")
|
||||||
kotlin("plugin.serialization")
|
kotlin("plugin.serialization")
|
||||||
//id("com.github.zellius.shortcut-helper")
|
//id("com.github.zellius.shortcut-helper")
|
||||||
alias(libs.plugins.aboutLibraries)
|
|
||||||
id("com.github.ben-manes.versions")
|
id("com.github.ben-manes.versions")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gradle.startParameter.taskRequests.toString().contains("Standard")) {
|
if (gradle.startParameter.taskRequests.toString().contains("Standard")) {
|
||||||
pluginManager.apply {
|
apply<com.google.gms.googleservices.GoogleServicesPlugin>()
|
||||||
apply(libs.plugins.google.services.get().pluginId)
|
// Firebase Crashlytics
|
||||||
apply(libs.plugins.firebase.crashlytics.get().pluginId)
|
apply(plugin = "com.google.firebase.crashlytics")
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//shortcutHelper.setFilePath("./shortcuts.xml")
|
//shortcutHelper.setFilePath("./shortcuts.xml")
|
||||||
|
|
||||||
val supportedAbis = setOf("armeabi-v7a", "arm64-v8a", "x86", "x86_64")
|
val SUPPORTED_ABIS = setOf("armeabi-v7a", "arm64-v8a", "x86", "x86_64")
|
||||||
|
|
||||||
android {
|
android {
|
||||||
namespace = "eu.kanade.tachiyomi"
|
namespace = "eu.kanade.tachiyomi"
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId = "eu.kanade.tachiyomi.sy"
|
applicationId = "eu.kanade.tachiyomi.sy"
|
||||||
|
versionCode = 49
|
||||||
versionCode = 75
|
versionName = "1.9.2"
|
||||||
versionName = "1.12.0"
|
|
||||||
|
|
||||||
buildConfigField("String", "COMMIT_COUNT", "\"${getCommitCount()}\"")
|
buildConfigField("String", "COMMIT_COUNT", "\"${getCommitCount()}\"")
|
||||||
buildConfigField("String", "COMMIT_SHA", "\"${getGitSha()}\"")
|
buildConfigField("String", "COMMIT_SHA", "\"${getGitSha()}\"")
|
||||||
buildConfigField("String", "BUILD_TIME", "\"${getBuildTime(useLastCommitTime = false)}\"")
|
buildConfigField("String", "BUILD_TIME", "\"${getBuildTime()}\"")
|
||||||
buildConfigField("boolean", "INCLUDE_UPDATER", "false")
|
buildConfigField("boolean", "INCLUDE_UPDATER", "false")
|
||||||
|
|
||||||
ndk {
|
ndk {
|
||||||
abiFilters += supportedAbis
|
abiFilters += SUPPORTED_ABIS
|
||||||
}
|
}
|
||||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
}
|
}
|
||||||
@ -49,7 +44,7 @@ android {
|
|||||||
abi {
|
abi {
|
||||||
isEnable = true
|
isEnable = true
|
||||||
reset()
|
reset()
|
||||||
include(*supportedAbis.toTypedArray())
|
include(*SUPPORTED_ABIS.toTypedArray())
|
||||||
isUniversalApk = true
|
isUniversalApk = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -71,8 +66,6 @@ android {
|
|||||||
isMinifyEnabled = true
|
isMinifyEnabled = true
|
||||||
isShrinkResources = true
|
isShrinkResources = true
|
||||||
setProguardFiles(listOf(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"))
|
setProguardFiles(listOf(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"))
|
||||||
|
|
||||||
buildConfigField("String", "BUILD_TIME", "\"${getBuildTime(useLastCommitTime = true)}\"")
|
|
||||||
}
|
}
|
||||||
create("benchmark") {
|
create("benchmark") {
|
||||||
initWith(getByName("release"))
|
initWith(getByName("release"))
|
||||||
@ -80,7 +73,6 @@ android {
|
|||||||
signingConfig = signingConfigs.getByName("debug")
|
signingConfig = signingConfigs.getByName("debug")
|
||||||
matchingFallbacks.add("release")
|
matchingFallbacks.add("release")
|
||||||
isDebuggable = false
|
isDebuggable = false
|
||||||
isProfileable = true
|
|
||||||
versionNameSuffix = "-benchmark"
|
versionNameSuffix = "-benchmark"
|
||||||
applicationIdSuffix = ".benchmark"
|
applicationIdSuffix = ".benchmark"
|
||||||
}
|
}
|
||||||
@ -101,25 +93,22 @@ android {
|
|||||||
dimension = "default"
|
dimension = "default"
|
||||||
}
|
}
|
||||||
create("dev") {
|
create("dev") {
|
||||||
|
// Include pseudolocales: https://developer.android.com/guide/topics/resources/pseudolocales
|
||||||
|
resourceConfigurations.addAll(listOf("en", "en_XA", "ar_XB", "xxhdpi"))
|
||||||
dimension = "default"
|
dimension = "default"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
packaging {
|
packagingOptions {
|
||||||
resources.excludes.addAll(
|
resources.excludes.addAll(listOf(
|
||||||
listOf(
|
|
||||||
"kotlin-tooling-metadata.json",
|
|
||||||
"META-INF/DEPENDENCIES",
|
"META-INF/DEPENDENCIES",
|
||||||
"LICENSE.txt",
|
"LICENSE.txt",
|
||||||
"META-INF/LICENSE",
|
"META-INF/LICENSE",
|
||||||
"META-INF/**/LICENSE.txt",
|
"META-INF/LICENSE.txt",
|
||||||
"META-INF/*.properties",
|
|
||||||
"META-INF/**/*.properties",
|
|
||||||
"META-INF/README.md",
|
"META-INF/README.md",
|
||||||
"META-INF/NOTICE",
|
"META-INF/NOTICE",
|
||||||
"META-INF/*.version",
|
"META-INF/*.kotlin_module",
|
||||||
),
|
))
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dependenciesInfo {
|
dependenciesInfo {
|
||||||
@ -128,7 +117,7 @@ android {
|
|||||||
|
|
||||||
buildFeatures {
|
buildFeatures {
|
||||||
viewBinding = true
|
viewBinding = true
|
||||||
buildConfig = true
|
compose = true
|
||||||
|
|
||||||
// Disable some unused things
|
// Disable some unused things
|
||||||
aidl = false
|
aidl = false
|
||||||
@ -140,63 +129,44 @@ android {
|
|||||||
abortOnError = false
|
abortOnError = false
|
||||||
checkReleaseBuilds = false
|
checkReleaseBuilds = false
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
kotlin {
|
composeOptions {
|
||||||
compilerOptions {
|
kotlinCompilerExtensionVersion = compose.versions.compiler.get()
|
||||||
freeCompilerArgs.addAll(
|
|
||||||
"-opt-in=androidx.compose.animation.ExperimentalAnimationApi",
|
|
||||||
"-opt-in=androidx.compose.animation.graphics.ExperimentalAnimationGraphicsApi",
|
|
||||||
"-opt-in=androidx.compose.foundation.ExperimentalFoundationApi",
|
|
||||||
"-opt-in=androidx.compose.foundation.layout.ExperimentalLayoutApi",
|
|
||||||
"-opt-in=androidx.compose.material3.ExperimentalMaterial3Api",
|
|
||||||
"-opt-in=androidx.compose.ui.ExperimentalComposeUiApi",
|
|
||||||
"-opt-in=coil3.annotation.ExperimentalCoilApi",
|
|
||||||
"-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi",
|
|
||||||
"-opt-in=kotlinx.coroutines.FlowPreview",
|
|
||||||
"-opt-in=kotlinx.coroutines.InternalCoroutinesApi",
|
|
||||||
"-opt-in=kotlinx.serialization.ExperimentalSerializationApi",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(projects.i18n)
|
implementation(project(":i18n"))
|
||||||
// SY -->
|
implementation(project(":core"))
|
||||||
implementation(projects.i18nSy)
|
implementation(project(":source-api"))
|
||||||
// SY <--
|
implementation(project(":data"))
|
||||||
implementation(projects.core.common)
|
implementation(project(":domain"))
|
||||||
implementation(projects.coreMetadata)
|
implementation(project(":presentation-core"))
|
||||||
implementation(projects.sourceApi)
|
implementation(project(":presentation-widget"))
|
||||||
implementation(projects.sourceLocal)
|
|
||||||
implementation(projects.data)
|
|
||||||
implementation(projects.domain)
|
|
||||||
implementation(projects.presentationCore)
|
|
||||||
implementation(projects.presentationWidget)
|
|
||||||
|
|
||||||
// Compose
|
// Compose
|
||||||
|
implementation(platform(compose.bom))
|
||||||
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)
|
||||||
debugImplementation(compose.ui.tooling)
|
implementation(compose.ui.tooling)
|
||||||
implementation(compose.ui.tooling.preview)
|
|
||||||
implementation(compose.ui.util)
|
implementation(compose.ui.util)
|
||||||
|
implementation(compose.accompanist.webview)
|
||||||
implementation(androidx.interpolator)
|
implementation(compose.accompanist.flowlayout)
|
||||||
|
implementation(compose.accompanist.permissions)
|
||||||
|
implementation(compose.accompanist.themeadapter)
|
||||||
|
implementation(compose.accompanist.systemuicontroller)
|
||||||
|
|
||||||
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 -->
|
|
||||||
implementation(sylibs.sqlcipher)
|
|
||||||
// SY <--
|
|
||||||
|
|
||||||
implementation(kotlinx.reflect)
|
implementation(kotlinx.reflect)
|
||||||
implementation(kotlinx.immutables)
|
|
||||||
|
|
||||||
implementation(platform(kotlinx.coroutines.bom))
|
implementation(platform(kotlinx.coroutines.bom))
|
||||||
implementation(kotlinx.bundles.coroutines)
|
implementation(kotlinx.bundles.coroutines)
|
||||||
@ -206,6 +176,7 @@ dependencies {
|
|||||||
implementation(androidx.appcompat)
|
implementation(androidx.appcompat)
|
||||||
implementation(androidx.biometricktx)
|
implementation(androidx.biometricktx)
|
||||||
implementation(androidx.constraintlayout)
|
implementation(androidx.constraintlayout)
|
||||||
|
implementation(androidx.coordinatorlayout)
|
||||||
implementation(androidx.corektx)
|
implementation(androidx.corektx)
|
||||||
implementation(androidx.splashscreen)
|
implementation(androidx.splashscreen)
|
||||||
implementation(androidx.recyclerview)
|
implementation(androidx.recyclerview)
|
||||||
@ -215,17 +186,20 @@ dependencies {
|
|||||||
implementation(androidx.bundles.lifecycle)
|
implementation(androidx.bundles.lifecycle)
|
||||||
|
|
||||||
// Job scheduling
|
// Job scheduling
|
||||||
implementation(androidx.workmanager)
|
implementation(androidx.bundles.workmanager)
|
||||||
|
|
||||||
// RxJava
|
// RX
|
||||||
implementation(libs.rxjava)
|
implementation(libs.bundles.reactivex)
|
||||||
|
implementation(libs.flowreactivenetwork)
|
||||||
|
|
||||||
// Networking
|
// Network client
|
||||||
implementation(libs.bundles.okhttp)
|
implementation(libs.bundles.okhttp)
|
||||||
implementation(libs.okio)
|
implementation(libs.okio)
|
||||||
implementation(libs.conscrypt.android) // TLS 1.3 support for Android < 10
|
|
||||||
|
|
||||||
// Data serialization (JSON, protobuf, xml)
|
// TLS 1.3 support for Android < 10
|
||||||
|
implementation(libs.conscrypt.android)
|
||||||
|
|
||||||
|
// Data serialization (JSON, protobuf)
|
||||||
implementation(kotlinx.bundles.serialization)
|
implementation(kotlinx.bundles.serialization)
|
||||||
|
|
||||||
// HTML parser
|
// HTML parser
|
||||||
@ -234,67 +208,64 @@ dependencies {
|
|||||||
// Disk
|
// Disk
|
||||||
implementation(libs.disklrucache)
|
implementation(libs.disklrucache)
|
||||||
implementation(libs.unifile)
|
implementation(libs.unifile)
|
||||||
|
implementation(libs.junrar)
|
||||||
|
|
||||||
// Preferences
|
// Preferences
|
||||||
implementation(libs.preferencektx)
|
implementation(libs.preferencektx)
|
||||||
|
|
||||||
// Dependency injection
|
// Dependency injection
|
||||||
implementation(libs.injekt)
|
implementation(libs.injekt.core)
|
||||||
|
|
||||||
// Image loading
|
// Image loading
|
||||||
implementation(platform(libs.coil.bom))
|
|
||||||
implementation(libs.bundles.coil)
|
implementation(libs.bundles.coil)
|
||||||
implementation(libs.subsamplingscaleimageview) {
|
implementation(libs.subsamplingscaleimageview) {
|
||||||
exclude(module = "image-decoder")
|
exclude(module = "image-decoder")
|
||||||
}
|
}
|
||||||
implementation(libs.image.decoder)
|
implementation(libs.image.decoder)
|
||||||
|
|
||||||
|
// Sort
|
||||||
|
implementation(libs.natural.comparator)
|
||||||
|
|
||||||
// UI libraries
|
// UI libraries
|
||||||
implementation(libs.material)
|
implementation(libs.material)
|
||||||
implementation(libs.flexible.adapter.core)
|
implementation(libs.flexible.adapter.core)
|
||||||
|
implementation(libs.flexible.adapter.ui)
|
||||||
implementation(libs.photoview)
|
implementation(libs.photoview)
|
||||||
implementation(libs.directionalviewpager) {
|
implementation(libs.directionalviewpager) {
|
||||||
exclude(group = "androidx.viewpager", module = "viewpager")
|
exclude(group = "androidx.viewpager", module = "viewpager")
|
||||||
}
|
}
|
||||||
implementation(libs.insetter)
|
implementation(libs.insetter)
|
||||||
implementation(libs.richeditor.compose)
|
implementation(libs.bundles.richtext)
|
||||||
implementation(libs.aboutLibraries.compose)
|
implementation(libs.aboutLibraries.compose)
|
||||||
|
implementation(libs.cascade)
|
||||||
implementation(libs.bundles.voyager)
|
implementation(libs.bundles.voyager)
|
||||||
implementation(libs.compose.materialmotion)
|
implementation(libs.wheelpicker)
|
||||||
implementation(libs.swipe)
|
implementation(libs.materialmotion.core)
|
||||||
implementation(libs.compose.webview)
|
|
||||||
implementation(libs.compose.grid)
|
|
||||||
implementation(libs.reorderable)
|
|
||||||
implementation(libs.bundles.markdown)
|
|
||||||
|
|
||||||
// Logging
|
// Logging
|
||||||
implementation(libs.logcat)
|
implementation(libs.logcat)
|
||||||
|
|
||||||
// Crash reports/analytics
|
// Crash reports/analytics
|
||||||
// "standardImplementation"(platform(libs.firebase.bom))
|
// implementation(libs.acra.http)
|
||||||
// "standardImplementation"(libs.firebase.analytics)
|
// "standardImplementation"(libs.firebase.analytics)
|
||||||
// "standardImplementation"(libs.firebase.crashlytics)
|
|
||||||
|
|
||||||
// Shizuku
|
// Shizuku
|
||||||
implementation(libs.bundles.shizuku)
|
implementation(libs.bundles.shizuku)
|
||||||
|
|
||||||
// Tests
|
// Tests
|
||||||
testImplementation(libs.bundles.test)
|
testImplementation(libs.junit)
|
||||||
|
|
||||||
// For detecting memory leaks; see https://square.github.io/leakcanary/
|
// For detecting memory leaks; see https://square.github.io/leakcanary/
|
||||||
// debugImplementation(libs.leakcanary.android)
|
// debugImplementation(libs.leakcanary.android)
|
||||||
implementation(libs.leakcanary.plumber)
|
implementation(libs.leakcanary.plumber)
|
||||||
|
|
||||||
testImplementation(kotlinx.coroutines.test)
|
|
||||||
|
|
||||||
// SY -->
|
// SY -->
|
||||||
// Text distance (EH)
|
// Text distance (EH)
|
||||||
implementation (sylibs.simularity)
|
implementation (sylibs.simularity)
|
||||||
|
|
||||||
// Firebase (EH)
|
// Firebase (EH)
|
||||||
implementation(platform(libs.firebase.bom))
|
implementation(sylibs.firebase.analytics)
|
||||||
implementation(libs.firebase.analytics)
|
implementation(sylibs.firebase.crashlytics.ktx)
|
||||||
implementation(libs.firebase.crashlytics)
|
|
||||||
|
|
||||||
// Better logging (EH)
|
// Better logging (EH)
|
||||||
implementation(sylibs.xlog)
|
implementation(sylibs.xlog)
|
||||||
@ -302,20 +273,15 @@ 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)
|
|
||||||
|
|
||||||
// Koin
|
|
||||||
implementation(sylibs.koin.core)
|
|
||||||
implementation(sylibs.koin.android)
|
|
||||||
|
|
||||||
// ZXing Android Embedded
|
|
||||||
implementation(sylibs.zxing.android.embedded)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
androidComponents {
|
androidComponents {
|
||||||
|
beforeVariants { variantBuilder ->
|
||||||
|
// Disables standardBenchmark
|
||||||
|
if (variantBuilder.buildType == "benchmark") {
|
||||||
|
variantBuilder.enable = variantBuilder.productFlavors.containsAll(listOf("default" to "dev"))
|
||||||
|
}
|
||||||
|
}
|
||||||
onVariants(selector().withFlavor("default" to "standard")) {
|
onVariants(selector().withFlavor("default" to "standard")) {
|
||||||
// Only excluding in standard flavor because this breaks
|
// Only excluding in standard flavor because this breaks
|
||||||
// Layout Inspector's Compose tree
|
// Layout Inspector's Compose tree
|
||||||
@ -323,6 +289,46 @@ androidComponents {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tasks {
|
||||||
|
|
||||||
|
withType<LintTask>().configureEach {
|
||||||
|
exclude { it.file.path.contains("generated[\\\\/]".toRegex()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
// See https://kotlinlang.org/docs/reference/experimental.html#experimental-status-of-experimental-api(-markers)
|
||||||
|
withType<KotlinCompile> {
|
||||||
|
kotlinOptions.freeCompilerArgs += listOf(
|
||||||
|
"-opt-in=coil.annotation.ExperimentalCoilApi",
|
||||||
|
"-opt-in=com.google.accompanist.permissions.ExperimentalPermissionsApi",
|
||||||
|
"-opt-in=androidx.compose.foundation.layout.ExperimentalLayoutApi",
|
||||||
|
"-opt-in=androidx.compose.material.ExperimentalMaterialApi",
|
||||||
|
"-opt-in=androidx.compose.material3.ExperimentalMaterial3Api",
|
||||||
|
"-opt-in=androidx.compose.material.ExperimentalMaterialApi",
|
||||||
|
"-opt-in=androidx.compose.ui.ExperimentalComposeUiApi",
|
||||||
|
"-opt-in=androidx.compose.foundation.ExperimentalFoundationApi",
|
||||||
|
"-opt-in=androidx.compose.animation.ExperimentalAnimationApi",
|
||||||
|
"-opt-in=androidx.compose.animation.graphics.ExperimentalAnimationGraphicsApi",
|
||||||
|
"-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi",
|
||||||
|
"-opt-in=kotlinx.coroutines.FlowPreview",
|
||||||
|
"-opt-in=kotlinx.coroutines.InternalCoroutinesApi",
|
||||||
|
"-opt-in=kotlinx.serialization.ExperimentalSerializationApi",
|
||||||
|
)
|
||||||
|
|
||||||
|
if (project.findProperty("tachiyomi.enableComposeCompilerMetrics") == "true") {
|
||||||
|
kotlinOptions.freeCompilerArgs += listOf(
|
||||||
|
"-P",
|
||||||
|
"plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=" +
|
||||||
|
project.buildDir.absolutePath + "/compose_metrics"
|
||||||
|
)
|
||||||
|
kotlinOptions.freeCompilerArgs += listOf(
|
||||||
|
"-P",
|
||||||
|
"plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=" +
|
||||||
|
project.buildDir.absolutePath + "/compose_metrics"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath(kotlinx.gradle)
|
classpath(kotlinx.gradle)
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
-allowaccessmodification
|
-allowaccessmodification
|
||||||
-dontusemixedcaseclassnames
|
-dontusemixedcaseclassnames
|
||||||
-ignorewarnings
|
|
||||||
-verbose
|
-verbose
|
||||||
|
|
||||||
-keepattributes *Annotation*
|
-keepattributes *Annotation*
|
||||||
|
74
app/proguard-rules.pro
vendored
74
app/proguard-rules.pro
vendored
@ -1,19 +1,14 @@
|
|||||||
-dontobfuscate
|
-dontobfuscate
|
||||||
|
|
||||||
-keep,allowoptimization class eu.kanade.**
|
|
||||||
-keep,allowoptimization class tachiyomi.**
|
|
||||||
-keep,allowoptimization class mihon.**
|
|
||||||
|
|
||||||
# Keep common dependencies used in extensions
|
# Keep common dependencies used in extensions
|
||||||
-keep,allowoptimization class androidx.preference.** { public protected *; }
|
-keep,allowoptimization class androidx.preference.** { public protected *; }
|
||||||
-keep,allowoptimization class kotlin.** { public protected *; }
|
-keep,allowoptimization class kotlin.** { public protected *; }
|
||||||
-keep,allowoptimization class kotlinx.coroutines.** { public protected *; }
|
-keep,allowoptimization class kotlinx.coroutines.** { public protected *; }
|
||||||
-keep,allowoptimization class kotlinx.serialization.** { public protected *; }
|
-keep,allowoptimization class kotlinx.serialization.** { public protected *; }
|
||||||
-keep,allowoptimization class kotlin.time.** { public protected *; }
|
|
||||||
-keep,allowoptimization class okhttp3.** { public protected *; }
|
-keep,allowoptimization class okhttp3.** { public protected *; }
|
||||||
-keep,allowoptimization class okio.** { public protected *; }
|
-keep,allowoptimization class okio.** { public protected *; }
|
||||||
-keep,allowoptimization class org.jsoup.** { public protected *; }
|
|
||||||
-keep,allowoptimization class rx.** { public protected *; }
|
-keep,allowoptimization class rx.** { public protected *; }
|
||||||
|
-keep,allowoptimization class org.jsoup.** { public protected *; }
|
||||||
-keep,allowoptimization class app.cash.quickjs.** { public protected *; }
|
-keep,allowoptimization class app.cash.quickjs.** { public protected *; }
|
||||||
-keep,allowoptimization class uy.kohesive.injekt.** { public protected *; }
|
-keep,allowoptimization class uy.kohesive.injekt.** { public protected *; }
|
||||||
|
|
||||||
@ -47,13 +42,9 @@
|
|||||||
-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.AnnotationsKt # core serialization annotations
|
||||||
|
|
||||||
# kotlinx-serialization-json specific. Add this if you have java.lang.NoClassDefFoundError kotlinx.serialization.json.JsonObjectSerializer
|
# kotlinx-serialization-json specific. Add this if you have java.lang.NoClassDefFoundError kotlinx.serialization.json.JsonObjectSerializer
|
||||||
-keepclassmembers class kotlinx.serialization.json.** {
|
-keepclassmembers class kotlinx.serialization.json.** {
|
||||||
@ -127,25 +118,6 @@
|
|||||||
# XmlUtil
|
# XmlUtil
|
||||||
-keep public enum nl.adaptivity.xmlutil.EventType { *; }
|
-keep public enum nl.adaptivity.xmlutil.EventType { *; }
|
||||||
|
|
||||||
# Firebase
|
|
||||||
-keep class com.google.firebase.installations.** { *; }
|
|
||||||
-keep interface com.google.firebase.installations.** { *; }
|
|
||||||
|
|
||||||
# Google Drive
|
|
||||||
-keep class com.google.api.services.** { *; }
|
|
||||||
|
|
||||||
# Google OAuth
|
|
||||||
-keep class com.google.api.client.** { *; }
|
|
||||||
|
|
||||||
# SY -->
|
|
||||||
# SqlCipher
|
|
||||||
-keepclassmembers class net.zetetic.database.sqlcipher.SQLiteCustomFunction { *; }
|
|
||||||
-keepclassmembers class net.zetetic.database.sqlcipher.SQLiteConnection { *; }
|
|
||||||
-keepclassmembers class net.zetetic.database.sqlcipher.SQLiteGlobal { *; }
|
|
||||||
-keepclassmembers class net.zetetic.database.sqlcipher.SQLiteDebug { *; }
|
|
||||||
-keepclassmembers class net.zetetic.database.sqlcipher.SQLiteDebug$* { *; }
|
|
||||||
# SY <--
|
|
||||||
|
|
||||||
# Design library
|
# Design library
|
||||||
-dontwarn com.google.android.material.**
|
-dontwarn com.google.android.material.**
|
||||||
-keep class com.google.android.material.** { *; }
|
-keep class com.google.android.material.** { *; }
|
||||||
@ -155,6 +127,13 @@
|
|||||||
-keep class com.hippo.image.** { *; }
|
-keep class com.hippo.image.** { *; }
|
||||||
-keep interface com.hippo.image.** { *; }
|
-keep interface com.hippo.image.** { *; }
|
||||||
|
|
||||||
|
# == Nucleus
|
||||||
|
-keepclassmembers class * extends nucleus.presenter.Presenter {
|
||||||
|
<init>();
|
||||||
|
}
|
||||||
|
|
||||||
|
# TODO Changeloglib? Does it need proguard?
|
||||||
|
|
||||||
# === Injekt
|
# === Injekt
|
||||||
## From original config: "Attempt to fix: java.lang.NoClassDefFoundError: uy.kohesive.injekt.registry.default.DefaultRegistrar$NOKEY$1"
|
## From original config: "Attempt to fix: java.lang.NoClassDefFoundError: uy.kohesive.injekt.registry.default.DefaultRegistrar$NOKEY$1"
|
||||||
-keep class uy.kohesive.injekt.** { *; }
|
-keep class uy.kohesive.injekt.** { *; }
|
||||||
@ -264,38 +243,3 @@
|
|||||||
-keep class com.google.apphosting.api.ApiProxy {
|
-keep class com.google.apphosting.api.ApiProxy {
|
||||||
static *** getCurrentEnvironment (...);
|
static *** getCurrentEnvironment (...);
|
||||||
}
|
}
|
||||||
|
|
||||||
# R8 full mode
|
|
||||||
-keepattributes Signature
|
|
||||||
-keep,allowoptimization class kotlin.coroutines.Continuation
|
|
||||||
-keep,allowoptimization class * extends uy.kohesive.injekt.api.TypeReference
|
|
||||||
-keep,allowoptimization public class io.requery.android.database.sqlite.SQLiteConnection { *; }
|
|
||||||
|
|
||||||
# Keep apache http client
|
|
||||||
-keep class org.apache.http.** { *; }
|
|
||||||
|
|
||||||
# Suggested rules
|
|
||||||
-dontwarn com.oracle.svm.core.annotate.AutomaticFeature
|
|
||||||
-dontwarn com.oracle.svm.core.annotate.Delete
|
|
||||||
-dontwarn com.oracle.svm.core.annotate.Substitute
|
|
||||||
-dontwarn com.oracle.svm.core.annotate.TargetClass
|
|
||||||
-dontwarn com.oracle.svm.core.configure.ResourcesRegistry
|
|
||||||
-dontwarn org.graalvm.nativeimage.ImageSingletons
|
|
||||||
-dontwarn org.graalvm.nativeimage.hosted.Feature$BeforeAnalysisAccess
|
|
||||||
-dontwarn org.graalvm.nativeimage.hosted.Feature
|
|
||||||
-dontwarn org.slf4j.impl.StaticLoggerBinder
|
|
||||||
-dontwarn java.lang.Module
|
|
||||||
-dontwarn org.graalvm.nativeimage.hosted.RuntimeResourceAccess
|
|
||||||
-dontwarn org.jspecify.annotations.NullMarked
|
|
||||||
-dontwarn javax.naming.InvalidNameException
|
|
||||||
-dontwarn javax.naming.NamingException
|
|
||||||
-dontwarn javax.naming.directory.Attribute
|
|
||||||
-dontwarn javax.naming.directory.Attributes
|
|
||||||
-dontwarn javax.naming.ldap.LdapName
|
|
||||||
-dontwarn javax.naming.ldap.Rdn
|
|
||||||
-dontwarn org.ietf.jgss.GSSContext
|
|
||||||
-dontwarn org.ietf.jgss.GSSCredential
|
|
||||||
-dontwarn org.ietf.jgss.GSSException
|
|
||||||
-dontwarn org.ietf.jgss.GSSManager
|
|
||||||
-dontwarn org.ietf.jgss.GSSName
|
|
||||||
-dontwarn org.ietf.jgss.Oid
|
|
@ -1,11 +0,0 @@
|
|||||||
package mihon.core.firebase
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
|
|
||||||
object FirebaseConfig {
|
|
||||||
fun init(context: Context) = Unit
|
|
||||||
|
|
||||||
fun setAnalyticsEnabled(enabled: Boolean) = Unit
|
|
||||||
|
|
||||||
fun setCrashlyticsEnabled(enabled: Boolean) = Unit
|
|
||||||
}
|
|
@ -8,9 +8,7 @@
|
|||||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||||
|
|
||||||
<!-- Storage -->
|
<!-- Storage -->
|
||||||
<uses-permission
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
|
||||||
tools:ignore="ScopedStorage" />
|
|
||||||
|
|
||||||
<!-- For background jobs -->
|
<!-- For background jobs -->
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||||
@ -23,99 +21,43 @@
|
|||||||
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />
|
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />
|
||||||
<uses-permission android:name="android.permission.UPDATE_PACKAGES_WITHOUT_USER_ACTION" />
|
<uses-permission android:name="android.permission.UPDATE_PACKAGES_WITHOUT_USER_ACTION" />
|
||||||
<!-- To view extension packages in API 30+ -->
|
<!-- To view extension packages in API 30+ -->
|
||||||
<uses-permission
|
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
|
||||||
android:name="android.permission.QUERY_ALL_PACKAGES"
|
|
||||||
tools:ignore="QueryAllPackagesPermission" />
|
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||||
<uses-permission
|
<uses-permission android:name="android.permission.READ_APP_SPECIFIC_LOCALES" />
|
||||||
android:name="android.permission.READ_APP_SPECIFIC_LOCALES"
|
|
||||||
tools:ignore="ProtectedPermissions" />
|
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
|
<!-- Remove permission from Firebase dependency -->
|
||||||
|
<uses-permission android:name="com.google.android.gms.permission.AD_ID"
|
||||||
<!-- Remove unnecessary permissions from Firebase dependency -->
|
|
||||||
<uses-permission
|
|
||||||
android:name="com.google.android.finsky.permission.BIND_GET_INSTALL_REFERRER_SERVICE"
|
|
||||||
tools:node="remove" />
|
|
||||||
|
|
||||||
<uses-permission
|
|
||||||
android:name="com.google.android.gms.permission.AD_ID"
|
|
||||||
tools:node="remove" />
|
|
||||||
|
|
||||||
<uses-permission
|
|
||||||
android:name="android.permission.ACCESS_ADSERVICES_ATTRIBUTION"
|
|
||||||
tools:node="remove" />
|
|
||||||
|
|
||||||
<uses-permission
|
|
||||||
android:name="android.permission.ACCESS_ADSERVICES_AD_ID"
|
|
||||||
tools:node="remove" />
|
tools:node="remove" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name=".App"
|
android:name=".App"
|
||||||
android:allowBackup="false"
|
android:allowBackup="false"
|
||||||
android:enableOnBackInvokedCallback="true"
|
|
||||||
android:hardwareAccelerated="true"
|
android:hardwareAccelerated="true"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:largeHeap="true"
|
android:largeHeap="true"
|
||||||
android:localeConfig="@xml/locales_config"
|
android:localeConfig="@xml/locales_config"
|
||||||
android:networkSecurityConfig="@xml/network_security_config"
|
|
||||||
android:preserveLegacyExternalStorage="true"
|
|
||||||
android:requestLegacyExternalStorage="true"
|
android:requestLegacyExternalStorage="true"
|
||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
|
android:theme="@style/Theme.Tachiyomi"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/Theme.Tachiyomi">
|
android:networkSecurityConfig="@xml/network_security_config">
|
||||||
|
|
||||||
|
<!-- enable profiling by macrobenchmark -->
|
||||||
|
<profileable
|
||||||
|
android:shell="true"
|
||||||
|
tools:targetApi="q" />
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.main.MainActivity"
|
android:name=".ui.main.MainActivity"
|
||||||
android:exported="true"
|
|
||||||
android:launchMode="singleTop"
|
android:launchMode="singleTop"
|
||||||
android:theme="@style/Theme.Tachiyomi.SplashScreen">
|
android:theme="@style/Theme.Tachiyomi.SplashScreen"
|
||||||
|
android:exported="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
|
||||||
<!-- Deep link to add repos -->
|
|
||||||
<intent-filter android:label="@string/action_add_repo">
|
|
||||||
<action android:name="android.intent.action.VIEW" />
|
|
||||||
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
|
||||||
|
|
||||||
<data android:scheme="tachiyomi" />
|
|
||||||
<data android:host="add-repo" />
|
|
||||||
</intent-filter>
|
|
||||||
|
|
||||||
<!-- Open backup files -->
|
|
||||||
<intent-filter android:label="@string/pref_restore_backup">
|
|
||||||
<action android:name="android.intent.action.VIEW" />
|
|
||||||
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
|
||||||
|
|
||||||
<data android:scheme="file" />
|
|
||||||
<data android:scheme="content" />
|
|
||||||
<data android:host="*" />
|
|
||||||
<data android:mimeType="*/*" />
|
|
||||||
<!--
|
|
||||||
Work around Android's ugly primitive PatternMatcher
|
|
||||||
implementation that can't cope with finding a . early in
|
|
||||||
the path unless it's explicitly matched.
|
|
||||||
|
|
||||||
See https://stackoverflow.com/a/31028507
|
|
||||||
-->
|
|
||||||
<data android:pathPattern=".*\\.tachibk" />
|
|
||||||
<data android:pathPattern=".*\\..*\\.tachibk" />
|
|
||||||
<data android:pathPattern=".*\\..*\\..*\\.tachibk" />
|
|
||||||
<data android:pathPattern=".*\\..*\\..*\\..*\\.tachibk" />
|
|
||||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.tachibk" />
|
|
||||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\.tachibk" />
|
|
||||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\.tachibk" />
|
|
||||||
</intent-filter>
|
|
||||||
|
|
||||||
<!--suppress AndroidDomInspection -->
|
<!--suppress AndroidDomInspection -->
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.app.shortcuts"
|
android:name="android.app.shortcuts"
|
||||||
@ -123,16 +65,16 @@
|
|||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
|
android:process=":error_handler"
|
||||||
android:name=".crash.CrashActivity"
|
android:name=".crash.CrashActivity"
|
||||||
android:exported="false"
|
android:exported="false" />
|
||||||
android:process=":error_handler" />
|
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.deeplink.DeepLinkActivity"
|
android:name=".ui.main.DeepLinkActivity"
|
||||||
android:exported="true"
|
|
||||||
android:label="@string/action_search"
|
|
||||||
android:launchMode="singleTask"
|
android:launchMode="singleTask"
|
||||||
android:theme="@android:style/Theme.NoDisplay">
|
android:theme="@android:style/Theme.NoDisplay"
|
||||||
|
android:label="@string/action_global_search"
|
||||||
|
android:exported="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.SEARCH" />
|
<action android:name="android.intent.action.SEARCH" />
|
||||||
<action android:name="com.google.android.gms.actions.SEARCH_ACTION" />
|
<action android:name="com.google.android.gms.actions.SEARCH_ACTION" />
|
||||||
@ -156,21 +98,20 @@
|
|||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.reader.ReaderActivity"
|
android:name=".ui.reader.ReaderActivity"
|
||||||
android:exported="false"
|
android:launchMode="singleTask"
|
||||||
android:launchMode="singleTask">
|
android:exported="false">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="com.samsung.android.support.REMOTE_ACTION" />
|
<action android:name="com.samsung.android.support.REMOTE_ACTION" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
|
||||||
<meta-data
|
<meta-data android:name="com.samsung.android.support.REMOTE_ACTION"
|
||||||
android:name="com.samsung.android.support.REMOTE_ACTION"
|
|
||||||
android:resource="@xml/s_pen_actions"/>
|
android:resource="@xml/s_pen_actions"/>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.security.UnlockActivity"
|
android:name=".ui.security.UnlockActivity"
|
||||||
android:exported="false"
|
android:theme="@style/Theme.Tachiyomi"
|
||||||
android:theme="@style/Theme.Tachiyomi" />
|
android:exported="false" />
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.webview.WebViewActivity"
|
android:name=".ui.webview.WebViewActivity"
|
||||||
@ -179,30 +120,12 @@
|
|||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".extension.util.ExtensionInstallActivity"
|
android:name=".extension.util.ExtensionInstallActivity"
|
||||||
android:exported="false"
|
android:theme="@android:style/Theme.Translucent.NoTitleBar"
|
||||||
android:theme="@android:style/Theme.Translucent.NoTitleBar" />
|
android:exported="false" />
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.setting.track.TrackLoginActivity"
|
android:name=".ui.setting.track.AnilistLoginActivity"
|
||||||
android:exported="true"
|
android:label="Anilist"
|
||||||
android:label="@string/track_activity_name">
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.intent.action.VIEW" />
|
|
||||||
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
|
||||||
|
|
||||||
<data android:scheme="mihon" />
|
|
||||||
|
|
||||||
<data android:host="anilist-auth" />
|
|
||||||
<data android:host="bangumi-auth" />
|
|
||||||
<data android:host="myanimelist-auth" />
|
|
||||||
<data android:host="shikimori-auth" />
|
|
||||||
</intent-filter>
|
|
||||||
</activity>
|
|
||||||
<activity
|
|
||||||
android:name=".ui.setting.track.GoogleDriveLoginActivity"
|
|
||||||
android:label="GoogleDrive"
|
|
||||||
android:exported="true">
|
android:exported="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
@ -211,7 +134,53 @@
|
|||||||
<category android:name="android.intent.category.BROWSABLE" />
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
|
||||||
<data
|
<data
|
||||||
android:scheme="eu.kanade.google.oauth" />
|
android:host="anilist-auth"
|
||||||
|
android:scheme="tachiyomi" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
<activity
|
||||||
|
android:name=".ui.setting.track.MyAnimeListLoginActivity"
|
||||||
|
android:label="MyAnimeList"
|
||||||
|
android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
|
||||||
|
<data
|
||||||
|
android:host="myanimelist-auth"
|
||||||
|
android:scheme="tachiyomi" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
<activity
|
||||||
|
android:name=".ui.setting.track.ShikimoriLoginActivity"
|
||||||
|
android:label="Shikimori"
|
||||||
|
android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
|
||||||
|
<data
|
||||||
|
android:host="shikimori-auth"
|
||||||
|
android:scheme="tachiyomi" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
<activity
|
||||||
|
android:name=".ui.setting.track.BangumiLoginActivity"
|
||||||
|
android:label="Bangumi"
|
||||||
|
android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
|
||||||
|
<data
|
||||||
|
android:host="bangumi-auth"
|
||||||
|
android:scheme="tachiyomi" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
@ -224,10 +193,38 @@
|
|||||||
android:name=".data.notification.NotificationReceiver"
|
android:name=".data.notification.NotificationReceiver"
|
||||||
android:exported="false" />
|
android:exported="false" />
|
||||||
|
|
||||||
<service
|
<receiver
|
||||||
android:name=".extension.util.ExtensionInstallService"
|
android:name="tachiyomi.presentation.widget.UpdatesGridGlanceReceiver"
|
||||||
|
android:enabled="@bool/glance_appwidget_available"
|
||||||
android:exported="false"
|
android:exported="false"
|
||||||
android:foregroundServiceType="shortService" />
|
android:label="@string/label_recent_updates">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||||
|
</intent-filter>
|
||||||
|
|
||||||
|
<meta-data
|
||||||
|
android:name="android.appwidget.provider"
|
||||||
|
android:resource="@xml/updates_grid_glance_widget_info" />
|
||||||
|
</receiver>
|
||||||
|
|
||||||
|
<service
|
||||||
|
android:name=".data.library.LibraryUpdateService"
|
||||||
|
android:exported="false" />
|
||||||
|
|
||||||
|
<service
|
||||||
|
android:name=".data.download.DownloadService"
|
||||||
|
android:exported="false" />
|
||||||
|
|
||||||
|
<service
|
||||||
|
android:name=".data.updater.AppUpdateService"
|
||||||
|
android:exported="false" />
|
||||||
|
|
||||||
|
<service
|
||||||
|
android:name=".data.backup.BackupRestoreService"
|
||||||
|
android:exported="false" />
|
||||||
|
|
||||||
|
<service android:name=".extension.util.ExtensionInstallService"
|
||||||
|
android:exported="false" />
|
||||||
|
|
||||||
<service
|
<service
|
||||||
android:name="androidx.appcompat.app.AppLocalesMetadataHolderService"
|
android:name="androidx.appcompat.app.AppLocalesMetadataHolderService"
|
||||||
@ -238,11 +235,6 @@
|
|||||||
android:value="true" />
|
android:value="true" />
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
<service
|
|
||||||
android:name="androidx.work.impl.foreground.SystemForegroundService"
|
|
||||||
android:foregroundServiceType="dataSync"
|
|
||||||
tools:node="merge" />
|
|
||||||
|
|
||||||
<provider
|
<provider
|
||||||
android:name="androidx.core.content.FileProvider"
|
android:name="androidx.core.content.FileProvider"
|
||||||
android:authorities="${applicationId}.provider"
|
android:authorities="${applicationId}.provider"
|
||||||
@ -256,9 +248,9 @@
|
|||||||
<provider
|
<provider
|
||||||
android:name="rikka.shizuku.ShizukuProvider"
|
android:name="rikka.shizuku.ShizukuProvider"
|
||||||
android:authorities="${applicationId}.shizuku"
|
android:authorities="${applicationId}.shizuku"
|
||||||
|
android:multiprocess="false"
|
||||||
android:enabled="true"
|
android:enabled="true"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:multiprocess="false"
|
|
||||||
android:permission="android.permission.INTERACT_ACROSS_USERS_FULL" />
|
android:permission="android.permission.INTERACT_ACROSS_USERS_FULL" />
|
||||||
|
|
||||||
<meta-data
|
<meta-data
|
||||||
@ -268,14 +260,6 @@
|
|||||||
android:name="android.webkit.WebView.MetricsOptOut"
|
android:name="android.webkit.WebView.MetricsOptOut"
|
||||||
android:value="true" />
|
android:value="true" />
|
||||||
|
|
||||||
<!-- Disable for manual opt-in -->
|
|
||||||
<meta-data
|
|
||||||
android:name="firebase_analytics_collection_enabled"
|
|
||||||
android:value="false" />
|
|
||||||
<meta-data
|
|
||||||
android:name="firebase_crashlytics_collection_enabled"
|
|
||||||
android:value="false" />
|
|
||||||
|
|
||||||
<!-- Disable advertising ID collection for Firebase -->
|
<!-- Disable advertising ID collection for Firebase -->
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="google_analytics_adid_collection_enabled"
|
android:name="google_analytics_adid_collection_enabled"
|
||||||
@ -359,7 +343,7 @@
|
|||||||
<data android:scheme="https" />
|
<data android:scheme="https" />
|
||||||
<data android:scheme="http" />
|
<data android:scheme="http" />
|
||||||
|
|
||||||
<data android:host="pururin.me" />
|
<data android:host="pururin.io" />
|
||||||
|
|
||||||
<data android:pathPattern="/gallery/..*" />
|
<data android:pathPattern="/gallery/..*" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
@ -413,13 +397,6 @@
|
|||||||
android:scheme="tachiyomisy" />
|
android:scheme="tachiyomisy" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
|
||||||
android:name="com.journeyapps.barcodescanner.CaptureActivity"
|
|
||||||
tools:remove="screenOrientation" />
|
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
<uses-sdk tools:overrideLibrary="rikka.shizuku.api"
|
|
||||||
tools:ignore="ManifestOrder" />
|
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,10 +0,0 @@
|
|||||||
package eu.kanade.core.preference
|
|
||||||
|
|
||||||
import androidx.compose.ui.state.ToggleableState
|
|
||||||
import tachiyomi.core.common.preference.CheckboxState
|
|
||||||
|
|
||||||
fun <T> CheckboxState.TriState<T>.asToggleableState() = when (this) {
|
|
||||||
is CheckboxState.TriState.Exclude -> ToggleableState.Indeterminate
|
|
||||||
is CheckboxState.TriState.Include -> ToggleableState.On
|
|
||||||
is CheckboxState.TriState.None -> ToggleableState.Off
|
|
||||||
}
|
|
@ -1,7 +1,8 @@
|
|||||||
package tachiyomi.core.common.preference
|
package eu.kanade.core.prefs
|
||||||
|
|
||||||
|
import androidx.compose.ui.state.ToggleableState
|
||||||
|
|
||||||
sealed class CheckboxState<T>(open val value: T) {
|
sealed class CheckboxState<T>(open val value: T) {
|
||||||
|
|
||||||
abstract fun next(): CheckboxState<T>
|
abstract fun next(): CheckboxState<T>
|
||||||
|
|
||||||
sealed class State<T>(override val value: T) : CheckboxState<T>(value) {
|
sealed class State<T>(override val value: T) : CheckboxState<T>(value) {
|
||||||
@ -18,7 +19,6 @@ sealed class CheckboxState<T>(open val value: T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed class TriState<T>(override val value: T) : CheckboxState<T>(value) {
|
sealed class TriState<T>(override val value: T) : CheckboxState<T>(value) {
|
||||||
data class Include<T>(override val value: T) : TriState<T>(value)
|
data class Include<T>(override val value: T) : TriState<T>(value)
|
||||||
data class Exclude<T>(override val value: T) : TriState<T>(value)
|
data class Exclude<T>(override val value: T) : TriState<T>(value)
|
||||||
@ -31,6 +31,14 @@ sealed class CheckboxState<T>(open val value: T) {
|
|||||||
is None -> Include(value)
|
is None -> Include(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun asState(): ToggleableState {
|
||||||
|
return when (this) {
|
||||||
|
is Exclude -> ToggleableState.Indeterminate
|
||||||
|
is Include -> ToggleableState.On
|
||||||
|
is None -> ToggleableState.Off
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,11 +1,11 @@
|
|||||||
package eu.kanade.core.preference
|
package eu.kanade.core.prefs
|
||||||
|
|
||||||
import androidx.compose.runtime.MutableState
|
import androidx.compose.runtime.MutableState
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import tachiyomi.core.common.preference.Preference
|
import tachiyomi.core.preference.Preference
|
||||||
|
|
||||||
class PreferenceMutableState<T>(
|
class PreferenceMutableState<T>(
|
||||||
private val preference: Preference<T>,
|
private val preference: Preference<T>,
|
||||||
@ -31,7 +31,7 @@ class PreferenceMutableState<T>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun component2(): (T) -> Unit {
|
override fun component2(): (T) -> Unit {
|
||||||
return preference::set
|
return { preference.set(it) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,41 +1,32 @@
|
|||||||
package eu.kanade.core.util
|
package eu.kanade.core.util
|
||||||
|
|
||||||
import androidx.compose.ui.util.fastFilter
|
|
||||||
import androidx.compose.ui.util.fastForEach
|
import androidx.compose.ui.util.fastForEach
|
||||||
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
import kotlin.contracts.ExperimentalContracts
|
import kotlin.contracts.ExperimentalContracts
|
||||||
import kotlin.contracts.contract
|
import kotlin.contracts.contract
|
||||||
|
|
||||||
fun <T : R, R : Any> List<T>.insertSeparators(
|
fun <T : R, R : Any> List<T>.insertSeparators(
|
||||||
generator: (before: T?, after: T?) -> R?,
|
generator: (T?, T?) -> R?,
|
||||||
): List<R> {
|
): List<R> {
|
||||||
if (isEmpty()) return emptyList()
|
if (isEmpty()) return emptyList()
|
||||||
val newList = mutableListOf<R>()
|
val newList = mutableListOf<R>()
|
||||||
for (i in -1..lastIndex) {
|
for (i in -1..lastIndex) {
|
||||||
val before = getOrNull(i)
|
val before = getOrNull(i)
|
||||||
before?.let(newList::add)
|
before?.let { newList.add(it) }
|
||||||
val after = getOrNull(i + 1)
|
val after = getOrNull(i + 1)
|
||||||
val separator = generator.invoke(before, after)
|
val separator = generator.invoke(before, after)
|
||||||
separator?.let(newList::add)
|
separator?.let { newList.add(it) }
|
||||||
}
|
}
|
||||||
return newList
|
return newList
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Similar to [eu.kanade.core.util.insertSeparators] but iterates from last to first element
|
* Returns a new map containing only the key entries of [transform] that are not null.
|
||||||
*/
|
*/
|
||||||
fun <T : R, R : Any> List<T>.insertSeparatorsReversed(
|
inline fun <K, V, R> Map<out K, V>.mapNotNullKeys(transform: (Map.Entry<K?, V>) -> R?): ConcurrentHashMap<R, V> {
|
||||||
generator: (before: T?, after: T?) -> R?,
|
val mutableMap = ConcurrentHashMap<R, V>()
|
||||||
): List<R> {
|
forEach { element -> transform(element)?.let { mutableMap[it] = element.value } }
|
||||||
if (isEmpty()) return emptyList()
|
return mutableMap
|
||||||
val newList = mutableListOf<R>()
|
|
||||||
for (i in size downTo 0) {
|
|
||||||
val after = getOrNull(i)
|
|
||||||
after?.let(newList::add)
|
|
||||||
val before = getOrNull(i - 1)
|
|
||||||
val separator = generator.invoke(before, after)
|
|
||||||
separator?.let(newList::add)
|
|
||||||
}
|
|
||||||
return newList.asReversed()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <E> HashSet<E>.addOrRemove(value: E, shouldAdd: Boolean) {
|
fun <E> HashSet<E>.addOrRemove(value: E, shouldAdd: Boolean) {
|
||||||
@ -46,6 +37,21 @@ fun <E> HashSet<E>.addOrRemove(value: E, shouldAdd: Boolean) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list containing only elements matching the given [predicate].
|
||||||
|
*
|
||||||
|
* **Do not use for collections that come from public APIs**, since they may not support random
|
||||||
|
* access in an efficient way, and this method may actually be a lot slower. Only use for
|
||||||
|
* collections that are created by code we control and are known to support random access.
|
||||||
|
*/
|
||||||
|
@OptIn(ExperimentalContracts::class)
|
||||||
|
inline fun <T> List<T>.fastFilter(predicate: (T) -> Boolean): List<T> {
|
||||||
|
contract { callsInPlace(predicate) }
|
||||||
|
val destination = ArrayList<T>()
|
||||||
|
fastForEach { if (predicate(it)) destination.add(it) }
|
||||||
|
return destination
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a list containing all elements not matching the given [predicate].
|
* Returns a list containing all elements not matching the given [predicate].
|
||||||
*
|
*
|
||||||
@ -56,7 +62,27 @@ fun <E> HashSet<E>.addOrRemove(value: E, shouldAdd: Boolean) {
|
|||||||
@OptIn(ExperimentalContracts::class)
|
@OptIn(ExperimentalContracts::class)
|
||||||
inline fun <T> List<T>.fastFilterNot(predicate: (T) -> Boolean): List<T> {
|
inline fun <T> List<T>.fastFilterNot(predicate: (T) -> Boolean): List<T> {
|
||||||
contract { callsInPlace(predicate) }
|
contract { callsInPlace(predicate) }
|
||||||
return fastFilter { !predicate(it) }
|
val destination = ArrayList<T>()
|
||||||
|
fastForEach { if (!predicate(it)) destination.add(it) }
|
||||||
|
return destination
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list containing only the non-null results of applying the
|
||||||
|
* given [transform] function to each element in the original collection.
|
||||||
|
*
|
||||||
|
* **Do not use for collections that come from public APIs**, since they may not support random
|
||||||
|
* access in an efficient way, and this method may actually be a lot slower. Only use for
|
||||||
|
* collections that are created by code we control and are known to support random access.
|
||||||
|
*/
|
||||||
|
@OptIn(ExperimentalContracts::class)
|
||||||
|
inline fun <T, R> List<T>.fastMapNotNull(transform: (T) -> R?): List<R> {
|
||||||
|
contract { callsInPlace(transform) }
|
||||||
|
val destination = ArrayList<R>()
|
||||||
|
fastForEach { element ->
|
||||||
|
transform(element)?.let { destination.add(it) }
|
||||||
|
}
|
||||||
|
return destination
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -97,3 +123,26 @@ inline fun <T> List<T>.fastCountNot(predicate: (T) -> Boolean): Int {
|
|||||||
fastForEach { if (predicate(it)) --count }
|
fastForEach { if (predicate(it)) --count }
|
||||||
return count
|
return count
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list containing only elements from the given collection
|
||||||
|
* having distinct keys returned by the given [selector] function.
|
||||||
|
*
|
||||||
|
* Among elements of the given collection with equal keys, only the first one will be present in the resulting list.
|
||||||
|
* The elements in the resulting list are in the same order as they were in the source collection.
|
||||||
|
*
|
||||||
|
* **Do not use for collections that come from public APIs**, since they may not support random
|
||||||
|
* access in an efficient way, and this method may actually be a lot slower. Only use for
|
||||||
|
* collections that are created by code we control and are known to support random access.
|
||||||
|
*/
|
||||||
|
@OptIn(ExperimentalContracts::class)
|
||||||
|
inline fun <T, K> List<T>.fastDistinctBy(selector: (T) -> K): List<T> {
|
||||||
|
contract { callsInPlace(selector) }
|
||||||
|
val set = HashSet<K>()
|
||||||
|
val list = ArrayList<T>()
|
||||||
|
fastForEach {
|
||||||
|
val key = selector(it)
|
||||||
|
if (set.add(key)) list.add(it)
|
||||||
|
}
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
16
app/src/main/java/eu/kanade/core/util/DurationUtils.kt
Normal file
16
app/src/main/java/eu/kanade/core/util/DurationUtils.kt
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package eu.kanade.core.util
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
|
import kotlin.time.Duration
|
||||||
|
|
||||||
|
fun Duration.toDurationString(context: Context, fallback: String): String {
|
||||||
|
return toComponents { days, hours, minutes, seconds, _ ->
|
||||||
|
buildList(4) {
|
||||||
|
if (days != 0L) add(context.getString(R.string.day_short, days))
|
||||||
|
if (hours != 0) add(context.getString(R.string.hour_short, hours))
|
||||||
|
if (minutes != 0 && (days == 0L || hours == 0)) add(context.getString(R.string.minute_short, minutes))
|
||||||
|
if (seconds != 0 && days == 0L && hours == 0) add(context.getString(R.string.seconds_short, seconds))
|
||||||
|
}.joinToString(" ").ifBlank { fallback }
|
||||||
|
}
|
||||||
|
}
|
61
app/src/main/java/eu/kanade/core/util/RxJavaExtensions.kt
Normal file
61
app/src/main/java/eu/kanade/core/util/RxJavaExtensions.kt
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
package eu.kanade.core.util
|
||||||
|
|
||||||
|
import kotlinx.coroutines.CancellationException
|
||||||
|
import kotlinx.coroutines.CoroutineStart
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.GlobalScope
|
||||||
|
import kotlinx.coroutines.channels.awaitClose
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.callbackFlow
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import rx.Emitter
|
||||||
|
import rx.Observable
|
||||||
|
import rx.Observer
|
||||||
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
|
fun <T : Any> Observable<T>.asFlow(): Flow<T> = callbackFlow {
|
||||||
|
val observer = object : Observer<T> {
|
||||||
|
override fun onNext(t: T) {
|
||||||
|
trySend(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onError(e: Throwable) {
|
||||||
|
close(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCompleted() {
|
||||||
|
close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val subscription = subscribe(observer)
|
||||||
|
awaitClose { subscription.unsubscribe() }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T : Any> Flow<T>.asObservable(
|
||||||
|
context: CoroutineContext = Dispatchers.Unconfined,
|
||||||
|
backpressureMode: Emitter.BackpressureMode = Emitter.BackpressureMode.NONE,
|
||||||
|
): Observable<T> {
|
||||||
|
return Observable.create(
|
||||||
|
{ emitter ->
|
||||||
|
/*
|
||||||
|
* ATOMIC is used here to provide stable behaviour of subscribe+dispose pair even if
|
||||||
|
* asObservable is already invoked from unconfined
|
||||||
|
*/
|
||||||
|
val job = GlobalScope.launch(context = context, start = CoroutineStart.ATOMIC) {
|
||||||
|
try {
|
||||||
|
collect { emitter.onNext(it) }
|
||||||
|
emitter.onCompleted()
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
// Ignore `CancellationException` as error, since it indicates "normal cancellation"
|
||||||
|
if (e !is CancellationException) {
|
||||||
|
emitter.onError(e)
|
||||||
|
} else {
|
||||||
|
emitter.onCompleted()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
emitter.setCancellation { job.cancel() }
|
||||||
|
},
|
||||||
|
backpressureMode,
|
||||||
|
)
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
package eu.kanade.data.source
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.source.model.FilterList
|
||||||
|
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||||
|
import eu.kanade.tachiyomi.source.model.MetadataMangasPage
|
||||||
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
|
import eu.kanade.tachiyomi.source.online.all.EHentai
|
||||||
|
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||||
|
import tachiyomi.core.util.lang.awaitSingle
|
||||||
|
|
||||||
|
abstract class EHentaiPagingSource(override val source: EHentai) : SourcePagingSource(source) {
|
||||||
|
|
||||||
|
override fun getPageLoadResult(
|
||||||
|
params: LoadParams<Long>,
|
||||||
|
mangasPage: MangasPage,
|
||||||
|
): LoadResult.Page<Long, Pair<SManga, RaisedSearchMetadata?>> {
|
||||||
|
mangasPage as MetadataMangasPage
|
||||||
|
val metadata = mangasPage.mangasMetadata
|
||||||
|
|
||||||
|
return LoadResult.Page(
|
||||||
|
data = mangasPage.mangas
|
||||||
|
.mapIndexed { index, sManga -> sManga to metadata.getOrNull(index) },
|
||||||
|
prevKey = null,
|
||||||
|
nextKey = mangasPage.nextKey,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class EHentaiSearchPagingSource(source: EHentai, val query: String, val filters: FilterList) : EHentaiPagingSource(source) {
|
||||||
|
override suspend fun requestNextPage(currentPage: Int): MangasPage {
|
||||||
|
return source.fetchSearchManga(currentPage, query, filters).awaitSingle()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class EHentaiPopularPagingSource(source: EHentai) : EHentaiPagingSource(source) {
|
||||||
|
override suspend fun requestNextPage(currentPage: Int): MangasPage {
|
||||||
|
return source.fetchPopularManga(currentPage).awaitSingle()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class EHentaiLatestPagingSource(source: EHentai) : EHentaiPagingSource(source) {
|
||||||
|
override suspend fun requestNextPage(currentPage: Int): MangasPage {
|
||||||
|
return source.fetchLatestUpdates(currentPage).awaitSingle()
|
||||||
|
}
|
||||||
|
}
|
19
app/src/main/java/eu/kanade/data/source/SourceMapper.kt
Normal file
19
app/src/main/java/eu/kanade/data/source/SourceMapper.kt
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package eu.kanade.data.source
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||||
|
import eu.kanade.tachiyomi.source.SourceManager
|
||||||
|
import tachiyomi.domain.source.model.Source
|
||||||
|
|
||||||
|
val sourceMapper: (eu.kanade.tachiyomi.source.Source) -> Source = { source ->
|
||||||
|
Source(
|
||||||
|
source.id,
|
||||||
|
source.lang,
|
||||||
|
source.name,
|
||||||
|
supportsLatest = false,
|
||||||
|
isStub = source is SourceManager.StubSource,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val catalogueSourceMapper: (CatalogueSource) -> Source = { source ->
|
||||||
|
sourceMapper(source).copy(supportsLatest = source.supportsLatest)
|
||||||
|
}
|
@ -0,0 +1,87 @@
|
|||||||
|
package eu.kanade.data.source
|
||||||
|
|
||||||
|
import androidx.paging.PagingState
|
||||||
|
import eu.kanade.domain.source.model.SourcePagingSourceType
|
||||||
|
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||||
|
import eu.kanade.tachiyomi.source.model.FilterList
|
||||||
|
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||||
|
import eu.kanade.tachiyomi.source.model.MetadataMangasPage
|
||||||
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
|
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||||
|
import tachiyomi.core.util.lang.awaitSingle
|
||||||
|
import tachiyomi.core.util.lang.withIOContext
|
||||||
|
|
||||||
|
abstract class SourcePagingSource(
|
||||||
|
protected open val source: CatalogueSource,
|
||||||
|
) : SourcePagingSourceType() {
|
||||||
|
|
||||||
|
abstract suspend fun requestNextPage(currentPage: Int): MangasPage
|
||||||
|
|
||||||
|
override suspend fun load(params: LoadParams<Long>): LoadResult<Long, /*SY --> */ Pair<SManga, RaisedSearchMetadata?>/*SY <-- */> {
|
||||||
|
val page = params.key ?: 1
|
||||||
|
|
||||||
|
val mangasPage = try {
|
||||||
|
withIOContext {
|
||||||
|
requestNextPage(page.toInt())
|
||||||
|
.takeIf { it.mangas.isNotEmpty() }
|
||||||
|
?: throw NoResultsException()
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
return LoadResult.Error(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SY -->
|
||||||
|
return getPageLoadResult(params, mangasPage)
|
||||||
|
// SY <--
|
||||||
|
}
|
||||||
|
|
||||||
|
// SY -->
|
||||||
|
open fun getPageLoadResult(params: LoadParams<Long>, mangasPage: MangasPage): LoadResult.Page<Long, /*SY --> */ Pair<SManga, RaisedSearchMetadata?>/*SY <-- */> {
|
||||||
|
val page = params.key ?: 1
|
||||||
|
|
||||||
|
// SY -->
|
||||||
|
val metadata = if (mangasPage is MetadataMangasPage) {
|
||||||
|
mangasPage.mangasMetadata
|
||||||
|
} else {
|
||||||
|
emptyList()
|
||||||
|
}
|
||||||
|
// SY <--
|
||||||
|
|
||||||
|
return LoadResult.Page(
|
||||||
|
data = mangasPage.mangas
|
||||||
|
// SY -->
|
||||||
|
.mapIndexed { index, sManga -> sManga to metadata.getOrNull(index) },
|
||||||
|
// SY <--
|
||||||
|
prevKey = null,
|
||||||
|
nextKey = if (mangasPage.hasNextPage) page + 1 else null,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
// SY <--
|
||||||
|
|
||||||
|
override fun getRefreshKey(state: PagingState<Long, /*SY --> */ Pair<SManga, RaisedSearchMetadata?>/*SY <-- */>): Long? {
|
||||||
|
return state.anchorPosition?.let { anchorPosition ->
|
||||||
|
val anchorPage = state.closestPageToPosition(anchorPosition)
|
||||||
|
anchorPage?.prevKey ?: anchorPage?.nextKey
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SourceSearchPagingSource(source: CatalogueSource, val query: String, val filters: FilterList) : SourcePagingSource(source) {
|
||||||
|
override suspend fun requestNextPage(currentPage: Int): MangasPage {
|
||||||
|
return source.fetchSearchManga(currentPage, query, filters).awaitSingle()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SourcePopularPagingSource(source: CatalogueSource) : SourcePagingSource(source) {
|
||||||
|
override suspend fun requestNextPage(currentPage: Int): MangasPage {
|
||||||
|
return source.fetchPopularManga(currentPage).awaitSingle()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SourceLatestPagingSource(source: CatalogueSource) : SourcePagingSource(source) {
|
||||||
|
override suspend fun requestNextPage(currentPage: Int): MangasPage {
|
||||||
|
return source.fetchLatestUpdates(currentPage).awaitSingle()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class NoResultsException : Exception()
|
@ -0,0 +1,91 @@
|
|||||||
|
package eu.kanade.data.source
|
||||||
|
|
||||||
|
import eu.kanade.domain.source.model.SourcePagingSourceType
|
||||||
|
import eu.kanade.domain.source.repository.SourceRepository
|
||||||
|
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||||
|
import eu.kanade.tachiyomi.source.LocalSource
|
||||||
|
import eu.kanade.tachiyomi.source.SourceManager
|
||||||
|
import eu.kanade.tachiyomi.source.model.FilterList
|
||||||
|
import eu.kanade.tachiyomi.source.online.all.EHentai
|
||||||
|
import exh.source.MERGED_SOURCE_ID
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
|
import tachiyomi.data.DatabaseHandler
|
||||||
|
import tachiyomi.domain.source.model.Source
|
||||||
|
import tachiyomi.domain.source.model.SourceWithCount
|
||||||
|
|
||||||
|
class SourceRepositoryImpl(
|
||||||
|
private val sourceManager: SourceManager,
|
||||||
|
private val handler: DatabaseHandler,
|
||||||
|
) : SourceRepository {
|
||||||
|
|
||||||
|
override fun getSources(): Flow<List<Source>> {
|
||||||
|
return sourceManager.catalogueSources.map { sources ->
|
||||||
|
sources.map(catalogueSourceMapper)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getOnlineSources(): Flow<List<Source>> {
|
||||||
|
return sourceManager.onlineSources.map { sources ->
|
||||||
|
sources.map(sourceMapper)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getSourcesWithFavoriteCount(): Flow<List<Pair<Source, Long>>> {
|
||||||
|
val sourceIdWithFavoriteCount = handler.subscribeToList { mangasQueries.getSourceIdWithFavoriteCount() }
|
||||||
|
return sourceIdWithFavoriteCount.map { sourceIdsWithCount ->
|
||||||
|
sourceIdsWithCount
|
||||||
|
.filterNot { it.source == LocalSource.ID /* SY --> */ || it.source == MERGED_SOURCE_ID /* SY <-- */ }
|
||||||
|
.map { (sourceId, count) ->
|
||||||
|
val source = sourceManager.getOrStub(sourceId).run {
|
||||||
|
sourceMapper(this)
|
||||||
|
}
|
||||||
|
source to count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getSourcesWithNonLibraryManga(): Flow<List<SourceWithCount>> {
|
||||||
|
val sourceIdWithNonLibraryManga = handler.subscribeToList { mangasQueries.getSourceIdsWithNonLibraryManga() }
|
||||||
|
return sourceIdWithNonLibraryManga.map { sourceId ->
|
||||||
|
sourceId.map { (sourceId, count) ->
|
||||||
|
val source = sourceManager.getOrStub(sourceId)
|
||||||
|
SourceWithCount(sourceMapper(source), count)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun search(
|
||||||
|
sourceId: Long,
|
||||||
|
query: String,
|
||||||
|
filterList: FilterList,
|
||||||
|
): SourcePagingSourceType {
|
||||||
|
val source = sourceManager.get(sourceId) as CatalogueSource
|
||||||
|
// SY -->
|
||||||
|
if (source is EHentai) {
|
||||||
|
return EHentaiSearchPagingSource(source, query, filterList)
|
||||||
|
}
|
||||||
|
// SY <--
|
||||||
|
return SourceSearchPagingSource(source, query, filterList)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getPopular(sourceId: Long): SourcePagingSourceType {
|
||||||
|
val source = sourceManager.get(sourceId) as CatalogueSource
|
||||||
|
// SY -->
|
||||||
|
if (source is EHentai) {
|
||||||
|
return EHentaiPopularPagingSource(source)
|
||||||
|
}
|
||||||
|
// SY <--
|
||||||
|
return SourcePopularPagingSource(source)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getLatest(sourceId: Long): SourcePagingSourceType {
|
||||||
|
val source = sourceManager.get(sourceId) as CatalogueSource
|
||||||
|
// SY -->
|
||||||
|
if (source is EHentai) {
|
||||||
|
return EHentaiLatestPagingSource(source)
|
||||||
|
}
|
||||||
|
// SY <--
|
||||||
|
return SourceLatestPagingSource(source)
|
||||||
|
}
|
||||||
|
}
|
@ -1,103 +1,77 @@
|
|||||||
package eu.kanade.domain
|
package eu.kanade.domain
|
||||||
|
|
||||||
import eu.kanade.domain.chapter.interactor.GetAvailableScanlators
|
import eu.kanade.data.source.SourceRepositoryImpl
|
||||||
|
import eu.kanade.domain.category.interactor.CreateCategoryWithName
|
||||||
|
import eu.kanade.domain.category.interactor.DeleteCategory
|
||||||
|
import eu.kanade.domain.category.interactor.RenameCategory
|
||||||
|
import eu.kanade.domain.category.interactor.ReorderCategory
|
||||||
|
import eu.kanade.domain.category.interactor.ResetCategoryFlags
|
||||||
|
import eu.kanade.domain.category.interactor.SetDisplayModeForCategory
|
||||||
|
import eu.kanade.domain.category.interactor.SetMangaCategories
|
||||||
|
import eu.kanade.domain.category.interactor.SetSortModeForCategory
|
||||||
|
import eu.kanade.domain.category.interactor.UpdateCategory
|
||||||
|
import eu.kanade.domain.chapter.interactor.GetChapter
|
||||||
|
import eu.kanade.domain.chapter.interactor.GetChapterByMangaId
|
||||||
|
import eu.kanade.domain.chapter.interactor.SetMangaDefaultChapterFlags
|
||||||
import eu.kanade.domain.chapter.interactor.SetReadStatus
|
import eu.kanade.domain.chapter.interactor.SetReadStatus
|
||||||
import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource
|
import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource
|
||||||
|
import eu.kanade.domain.chapter.interactor.SyncChaptersWithTrackServiceTwoWay
|
||||||
|
import eu.kanade.domain.chapter.interactor.UpdateChapter
|
||||||
import eu.kanade.domain.download.interactor.DeleteDownload
|
import eu.kanade.domain.download.interactor.DeleteDownload
|
||||||
import eu.kanade.domain.extension.interactor.GetExtensionLanguages
|
import eu.kanade.domain.extension.interactor.GetExtensionLanguages
|
||||||
import eu.kanade.domain.extension.interactor.GetExtensionSources
|
import eu.kanade.domain.extension.interactor.GetExtensionSources
|
||||||
import eu.kanade.domain.extension.interactor.GetExtensionsByType
|
import eu.kanade.domain.extension.interactor.GetExtensionsByType
|
||||||
import eu.kanade.domain.extension.interactor.TrustExtension
|
import eu.kanade.domain.history.interactor.GetNextChapters
|
||||||
import eu.kanade.domain.manga.interactor.GetExcludedScanlators
|
import eu.kanade.domain.manga.interactor.GetDuplicateLibraryManga
|
||||||
import eu.kanade.domain.manga.interactor.SetExcludedScanlators
|
import eu.kanade.domain.manga.interactor.GetFavorites
|
||||||
|
import eu.kanade.domain.manga.interactor.GetLibraryManga
|
||||||
|
import eu.kanade.domain.manga.interactor.GetManga
|
||||||
|
import eu.kanade.domain.manga.interactor.GetMangaWithChapters
|
||||||
|
import eu.kanade.domain.manga.interactor.NetworkToLocalManga
|
||||||
|
import eu.kanade.domain.manga.interactor.ResetViewerFlags
|
||||||
|
import eu.kanade.domain.manga.interactor.SetMangaChapterFlags
|
||||||
import eu.kanade.domain.manga.interactor.SetMangaViewerFlags
|
import eu.kanade.domain.manga.interactor.SetMangaViewerFlags
|
||||||
import eu.kanade.domain.manga.interactor.UpdateManga
|
import eu.kanade.domain.manga.interactor.UpdateManga
|
||||||
import eu.kanade.domain.source.interactor.GetEnabledSources
|
import eu.kanade.domain.source.interactor.GetEnabledSources
|
||||||
import eu.kanade.domain.source.interactor.GetIncognitoState
|
|
||||||
import eu.kanade.domain.source.interactor.GetLanguagesWithSources
|
import eu.kanade.domain.source.interactor.GetLanguagesWithSources
|
||||||
|
import eu.kanade.domain.source.interactor.GetRemoteManga
|
||||||
import eu.kanade.domain.source.interactor.GetSourcesWithFavoriteCount
|
import eu.kanade.domain.source.interactor.GetSourcesWithFavoriteCount
|
||||||
|
import eu.kanade.domain.source.interactor.GetSourcesWithNonLibraryManga
|
||||||
import eu.kanade.domain.source.interactor.SetMigrateSorting
|
import eu.kanade.domain.source.interactor.SetMigrateSorting
|
||||||
import eu.kanade.domain.source.interactor.ToggleIncognito
|
|
||||||
import eu.kanade.domain.source.interactor.ToggleLanguage
|
import eu.kanade.domain.source.interactor.ToggleLanguage
|
||||||
import eu.kanade.domain.source.interactor.ToggleSource
|
import eu.kanade.domain.source.interactor.ToggleSource
|
||||||
import eu.kanade.domain.source.interactor.ToggleSourcePin
|
import eu.kanade.domain.source.interactor.ToggleSourcePin
|
||||||
import eu.kanade.domain.track.interactor.AddTracks
|
import eu.kanade.domain.source.repository.SourceRepository
|
||||||
import eu.kanade.domain.track.interactor.RefreshTracks
|
import eu.kanade.domain.track.interactor.DeleteTrack
|
||||||
import eu.kanade.domain.track.interactor.SyncChapterProgressWithTrack
|
import eu.kanade.domain.track.interactor.GetTracks
|
||||||
import eu.kanade.domain.track.interactor.TrackChapter
|
import eu.kanade.domain.track.interactor.GetTracksPerManga
|
||||||
import eu.kanade.tachiyomi.di.InjektModule
|
import eu.kanade.domain.track.interactor.InsertTrack
|
||||||
import eu.kanade.tachiyomi.di.addFactory
|
|
||||||
import eu.kanade.tachiyomi.di.addSingletonFactory
|
|
||||||
import mihon.data.repository.ExtensionRepoRepositoryImpl
|
|
||||||
import mihon.domain.chapter.interactor.FilterChaptersForDownload
|
|
||||||
import mihon.domain.extensionrepo.interactor.CreateExtensionRepo
|
|
||||||
import mihon.domain.extensionrepo.interactor.DeleteExtensionRepo
|
|
||||||
import mihon.domain.extensionrepo.interactor.GetExtensionRepo
|
|
||||||
import mihon.domain.extensionrepo.interactor.GetExtensionRepoCount
|
|
||||||
import mihon.domain.extensionrepo.interactor.ReplaceExtensionRepo
|
|
||||||
import mihon.domain.extensionrepo.interactor.UpdateExtensionRepo
|
|
||||||
import mihon.domain.extensionrepo.repository.ExtensionRepoRepository
|
|
||||||
import mihon.domain.extensionrepo.service.ExtensionRepoService
|
|
||||||
import mihon.domain.upcoming.interactor.GetUpcomingManga
|
|
||||||
import tachiyomi.data.category.CategoryRepositoryImpl
|
import tachiyomi.data.category.CategoryRepositoryImpl
|
||||||
import tachiyomi.data.chapter.ChapterRepositoryImpl
|
import tachiyomi.data.chapter.ChapterRepositoryImpl
|
||||||
import tachiyomi.data.history.HistoryRepositoryImpl
|
import tachiyomi.data.history.HistoryRepositoryImpl
|
||||||
import tachiyomi.data.manga.MangaRepositoryImpl
|
import tachiyomi.data.manga.MangaRepositoryImpl
|
||||||
import tachiyomi.data.release.ReleaseServiceImpl
|
import tachiyomi.data.source.SourceDataRepositoryImpl
|
||||||
import tachiyomi.data.source.SourceRepositoryImpl
|
|
||||||
import tachiyomi.data.source.StubSourceRepositoryImpl
|
|
||||||
import tachiyomi.data.track.TrackRepositoryImpl
|
import tachiyomi.data.track.TrackRepositoryImpl
|
||||||
import tachiyomi.data.updates.UpdatesRepositoryImpl
|
import tachiyomi.data.updates.UpdatesRepositoryImpl
|
||||||
import tachiyomi.domain.category.interactor.CreateCategoryWithName
|
|
||||||
import tachiyomi.domain.category.interactor.DeleteCategory
|
|
||||||
import tachiyomi.domain.category.interactor.GetCategories
|
import tachiyomi.domain.category.interactor.GetCategories
|
||||||
import tachiyomi.domain.category.interactor.RenameCategory
|
|
||||||
import tachiyomi.domain.category.interactor.ReorderCategory
|
|
||||||
import tachiyomi.domain.category.interactor.ResetCategoryFlags
|
|
||||||
import tachiyomi.domain.category.interactor.SetDisplayMode
|
|
||||||
import tachiyomi.domain.category.interactor.SetMangaCategories
|
|
||||||
import tachiyomi.domain.category.interactor.SetSortModeForCategory
|
|
||||||
import tachiyomi.domain.category.interactor.UpdateCategory
|
|
||||||
import tachiyomi.domain.category.repository.CategoryRepository
|
import tachiyomi.domain.category.repository.CategoryRepository
|
||||||
import tachiyomi.domain.chapter.interactor.GetChapter
|
|
||||||
import tachiyomi.domain.chapter.interactor.GetChapterByUrlAndMangaId
|
|
||||||
import tachiyomi.domain.chapter.interactor.GetChaptersByMangaId
|
|
||||||
import tachiyomi.domain.chapter.interactor.SetMangaDefaultChapterFlags
|
|
||||||
import tachiyomi.domain.chapter.interactor.ShouldUpdateDbChapter
|
import tachiyomi.domain.chapter.interactor.ShouldUpdateDbChapter
|
||||||
import tachiyomi.domain.chapter.interactor.UpdateChapter
|
|
||||||
import tachiyomi.domain.chapter.repository.ChapterRepository
|
import tachiyomi.domain.chapter.repository.ChapterRepository
|
||||||
import tachiyomi.domain.history.interactor.GetHistory
|
import tachiyomi.domain.history.interactor.GetHistory
|
||||||
import tachiyomi.domain.history.interactor.GetNextChapters
|
|
||||||
import tachiyomi.domain.history.interactor.GetTotalReadDuration
|
import tachiyomi.domain.history.interactor.GetTotalReadDuration
|
||||||
import tachiyomi.domain.history.interactor.RemoveHistory
|
import tachiyomi.domain.history.interactor.RemoveHistory
|
||||||
import tachiyomi.domain.history.interactor.UpsertHistory
|
import tachiyomi.domain.history.interactor.UpsertHistory
|
||||||
import tachiyomi.domain.history.repository.HistoryRepository
|
import tachiyomi.domain.history.repository.HistoryRepository
|
||||||
import tachiyomi.domain.manga.interactor.FetchInterval
|
|
||||||
import tachiyomi.domain.manga.interactor.GetDuplicateLibraryManga
|
|
||||||
import tachiyomi.domain.manga.interactor.GetFavorites
|
|
||||||
import tachiyomi.domain.manga.interactor.GetLibraryManga
|
|
||||||
import tachiyomi.domain.manga.interactor.GetManga
|
|
||||||
import tachiyomi.domain.manga.interactor.GetMangaByUrlAndSourceId
|
|
||||||
import tachiyomi.domain.manga.interactor.GetMangaWithChapters
|
|
||||||
import tachiyomi.domain.manga.interactor.NetworkToLocalManga
|
|
||||||
import tachiyomi.domain.manga.interactor.ResetViewerFlags
|
|
||||||
import tachiyomi.domain.manga.interactor.SetMangaChapterFlags
|
|
||||||
import tachiyomi.domain.manga.interactor.UpdateMangaNotes
|
|
||||||
import tachiyomi.domain.manga.repository.MangaRepository
|
import tachiyomi.domain.manga.repository.MangaRepository
|
||||||
import tachiyomi.domain.release.interactor.GetApplicationRelease
|
import tachiyomi.domain.source.repository.SourceDataRepository
|
||||||
import tachiyomi.domain.release.service.ReleaseService
|
|
||||||
import tachiyomi.domain.source.interactor.GetRemoteManga
|
|
||||||
import tachiyomi.domain.source.interactor.GetSourcesWithNonLibraryManga
|
|
||||||
import tachiyomi.domain.source.repository.SourceRepository
|
|
||||||
import tachiyomi.domain.source.repository.StubSourceRepository
|
|
||||||
import tachiyomi.domain.track.interactor.DeleteTrack
|
|
||||||
import tachiyomi.domain.track.interactor.GetTracks
|
|
||||||
import tachiyomi.domain.track.interactor.GetTracksPerManga
|
|
||||||
import tachiyomi.domain.track.interactor.InsertTrack
|
|
||||||
import tachiyomi.domain.track.repository.TrackRepository
|
import tachiyomi.domain.track.repository.TrackRepository
|
||||||
import tachiyomi.domain.updates.interactor.GetUpdates
|
import tachiyomi.domain.updates.interactor.GetUpdates
|
||||||
import tachiyomi.domain.updates.repository.UpdatesRepository
|
import tachiyomi.domain.updates.repository.UpdatesRepository
|
||||||
|
import uy.kohesive.injekt.api.InjektModule
|
||||||
import uy.kohesive.injekt.api.InjektRegistrar
|
import uy.kohesive.injekt.api.InjektRegistrar
|
||||||
|
import uy.kohesive.injekt.api.addFactory
|
||||||
|
import uy.kohesive.injekt.api.addSingletonFactory
|
||||||
|
import uy.kohesive.injekt.api.get
|
||||||
|
|
||||||
class DomainModule : InjektModule {
|
class DomainModule : InjektModule {
|
||||||
|
|
||||||
@ -105,58 +79,43 @@ class DomainModule : InjektModule {
|
|||||||
addSingletonFactory<CategoryRepository> { CategoryRepositoryImpl(get()) }
|
addSingletonFactory<CategoryRepository> { CategoryRepositoryImpl(get()) }
|
||||||
addFactory { GetCategories(get()) }
|
addFactory { GetCategories(get()) }
|
||||||
addFactory { ResetCategoryFlags(get(), get()) }
|
addFactory { ResetCategoryFlags(get(), get()) }
|
||||||
addFactory { SetDisplayMode(get()) }
|
addFactory { SetDisplayModeForCategory(get(), get()) }
|
||||||
addFactory { SetSortModeForCategory(get(), get()) }
|
addFactory { SetSortModeForCategory(get(), get()) }
|
||||||
addFactory { CreateCategoryWithName(get(), get()) }
|
addFactory { CreateCategoryWithName(get(), get()) }
|
||||||
addFactory { RenameCategory(get()) }
|
addFactory { RenameCategory(get()) }
|
||||||
addFactory { ReorderCategory(get()) }
|
addFactory { ReorderCategory(get()) }
|
||||||
addFactory { UpdateCategory(get()) }
|
addFactory { UpdateCategory(get()) }
|
||||||
addFactory { DeleteCategory(get(), get(), get()) }
|
addFactory { DeleteCategory(get()) }
|
||||||
|
|
||||||
addSingletonFactory<MangaRepository> { MangaRepositoryImpl(get()) }
|
addSingletonFactory<MangaRepository> { MangaRepositoryImpl(get()) }
|
||||||
addFactory { GetDuplicateLibraryManga(get()) }
|
addFactory { GetDuplicateLibraryManga(get()) }
|
||||||
addFactory { GetFavorites(get()) }
|
addFactory { GetFavorites(get()) }
|
||||||
addFactory { GetLibraryManga(get()) }
|
addFactory { GetLibraryManga(get()) }
|
||||||
addFactory { GetMangaWithChapters(get(), get()) }
|
addFactory { GetMangaWithChapters(get(), get()) }
|
||||||
addFactory { GetMangaByUrlAndSourceId(get()) }
|
|
||||||
addFactory { GetManga(get()) }
|
addFactory { GetManga(get()) }
|
||||||
addFactory { GetNextChapters(get(), get(), get(), get()) }
|
addFactory { GetNextChapters(get(), get(), get(), get()) }
|
||||||
addFactory { GetUpcomingManga(get()) }
|
|
||||||
addFactory { ResetViewerFlags(get()) }
|
addFactory { ResetViewerFlags(get()) }
|
||||||
addFactory { SetMangaChapterFlags(get()) }
|
addFactory { SetMangaChapterFlags(get()) }
|
||||||
addFactory { FetchInterval(get()) }
|
|
||||||
addFactory { SetMangaDefaultChapterFlags(get(), get(), get()) }
|
addFactory { SetMangaDefaultChapterFlags(get(), get(), get()) }
|
||||||
addFactory { SetMangaViewerFlags(get()) }
|
addFactory { SetMangaViewerFlags(get()) }
|
||||||
addFactory { NetworkToLocalManga(get()) }
|
addFactory { NetworkToLocalManga(get()) }
|
||||||
addFactory { UpdateManga(get(), get()) }
|
addFactory { UpdateManga(get()) }
|
||||||
addFactory { UpdateMangaNotes(get()) }
|
|
||||||
addFactory { SetMangaCategories(get()) }
|
addFactory { SetMangaCategories(get()) }
|
||||||
addFactory { GetExcludedScanlators(get()) }
|
|
||||||
addFactory { SetExcludedScanlators(get()) }
|
|
||||||
|
|
||||||
addSingletonFactory<ReleaseService> { ReleaseServiceImpl(get(), get()) }
|
|
||||||
addFactory { GetApplicationRelease(get(), get()) }
|
|
||||||
|
|
||||||
addSingletonFactory<TrackRepository> { TrackRepositoryImpl(get()) }
|
addSingletonFactory<TrackRepository> { TrackRepositoryImpl(get()) }
|
||||||
addFactory { TrackChapter(get(), get(), get(), get()) }
|
|
||||||
addFactory { AddTracks(get(), get(), get(), get()) }
|
|
||||||
addFactory { RefreshTracks(get(), get(), get(), get()) }
|
|
||||||
addFactory { DeleteTrack(get()) }
|
addFactory { DeleteTrack(get()) }
|
||||||
addFactory { GetTracksPerManga(get(), get()) }
|
addFactory { GetTracksPerManga(get()) }
|
||||||
addFactory { GetTracks(get()) }
|
addFactory { GetTracks(get()) }
|
||||||
addFactory { InsertTrack(get()) }
|
addFactory { InsertTrack(get()) }
|
||||||
addFactory { SyncChapterProgressWithTrack(get(), get(), get()) }
|
|
||||||
|
|
||||||
addSingletonFactory<ChapterRepository> { ChapterRepositoryImpl(get()) }
|
addSingletonFactory<ChapterRepository> { ChapterRepositoryImpl(get()) }
|
||||||
addFactory { GetChapter(get()) }
|
addFactory { GetChapter(get()) }
|
||||||
addFactory { GetChaptersByMangaId(get()) }
|
addFactory { GetChapterByMangaId(get()) }
|
||||||
addFactory { GetChapterByUrlAndMangaId(get()) }
|
|
||||||
addFactory { UpdateChapter(get()) }
|
addFactory { UpdateChapter(get()) }
|
||||||
addFactory { SetReadStatus(get(), get(), get(), get(), get()) }
|
addFactory { SetReadStatus(get(), get(), get(), get(), get()) }
|
||||||
addFactory { ShouldUpdateDbChapter() }
|
addFactory { ShouldUpdateDbChapter() }
|
||||||
addFactory { SyncChaptersWithSource(get(), get(), get(), get(), get(), get(), get(), get(), get()) }
|
addFactory { SyncChaptersWithSource(get(), get(), get(), get()) }
|
||||||
addFactory { GetAvailableScanlators(get()) }
|
addFactory { SyncChaptersWithTrackServiceTwoWay(get(), get()) }
|
||||||
addFactory { FilterChaptersForDownload(get(), get(), get(), get()) }
|
|
||||||
|
|
||||||
addSingletonFactory<HistoryRepository> { HistoryRepositoryImpl(get()) }
|
addSingletonFactory<HistoryRepository> { HistoryRepositoryImpl(get()) }
|
||||||
addFactory { GetHistory(get()) }
|
addFactory { GetHistory(get()) }
|
||||||
@ -174,7 +133,7 @@ class DomainModule : InjektModule {
|
|||||||
addFactory { GetUpdates(get()) }
|
addFactory { GetUpdates(get()) }
|
||||||
|
|
||||||
addSingletonFactory<SourceRepository> { SourceRepositoryImpl(get(), get()) }
|
addSingletonFactory<SourceRepository> { SourceRepositoryImpl(get(), get()) }
|
||||||
addSingletonFactory<StubSourceRepository> { StubSourceRepositoryImpl(get()) }
|
addSingletonFactory<SourceDataRepository> { SourceDataRepositoryImpl(get()) }
|
||||||
addFactory { GetEnabledSources(get(), get()) }
|
addFactory { GetEnabledSources(get(), get()) }
|
||||||
addFactory { GetLanguagesWithSources(get(), get()) }
|
addFactory { GetLanguagesWithSources(get(), get()) }
|
||||||
addFactory { GetRemoteManga(get()) }
|
addFactory { GetRemoteManga(get()) }
|
||||||
@ -184,17 +143,5 @@ class DomainModule : InjektModule {
|
|||||||
addFactory { ToggleLanguage(get()) }
|
addFactory { ToggleLanguage(get()) }
|
||||||
addFactory { ToggleSource(get()) }
|
addFactory { ToggleSource(get()) }
|
||||||
addFactory { ToggleSourcePin(get()) }
|
addFactory { ToggleSourcePin(get()) }
|
||||||
addFactory { TrustExtension(get(), get()) }
|
|
||||||
|
|
||||||
addSingletonFactory<ExtensionRepoRepository> { ExtensionRepoRepositoryImpl(get()) }
|
|
||||||
addFactory { ExtensionRepoService(get(), get()) }
|
|
||||||
addFactory { GetExtensionRepo(get()) }
|
|
||||||
addFactory { GetExtensionRepoCount(get()) }
|
|
||||||
addFactory { CreateExtensionRepo(get(), get()) }
|
|
||||||
addFactory { DeleteExtensionRepo(get()) }
|
|
||||||
addFactory { ReplaceExtensionRepo(get()) }
|
|
||||||
addFactory { UpdateExtensionRepo(get(), get()) }
|
|
||||||
addFactory { ToggleIncognito(get()) }
|
|
||||||
addFactory { GetIncognitoState(get(), get(), get()) }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,61 @@
|
|||||||
package eu.kanade.domain
|
package eu.kanade.domain
|
||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
|
import eu.kanade.domain.chapter.interactor.DeleteChapters
|
||||||
|
import eu.kanade.domain.chapter.interactor.GetChapterByUrl
|
||||||
|
import eu.kanade.domain.chapter.interactor.GetMergedChapterByMangaId
|
||||||
|
import eu.kanade.domain.history.interactor.GetHistoryByMangaId
|
||||||
import eu.kanade.domain.manga.interactor.CreateSortTag
|
import eu.kanade.domain.manga.interactor.CreateSortTag
|
||||||
|
import eu.kanade.domain.manga.interactor.DeleteByMergeId
|
||||||
|
import eu.kanade.domain.manga.interactor.DeleteFavoriteEntries
|
||||||
|
import eu.kanade.domain.manga.interactor.DeleteMangaById
|
||||||
|
import eu.kanade.domain.manga.interactor.DeleteMergeById
|
||||||
import eu.kanade.domain.manga.interactor.DeleteSortTag
|
import eu.kanade.domain.manga.interactor.DeleteSortTag
|
||||||
|
import eu.kanade.domain.manga.interactor.GetAllManga
|
||||||
|
import eu.kanade.domain.manga.interactor.GetExhFavoriteMangaWithMetadata
|
||||||
|
import eu.kanade.domain.manga.interactor.GetFavoriteEntries
|
||||||
|
import eu.kanade.domain.manga.interactor.GetFlatMetadataById
|
||||||
|
import eu.kanade.domain.manga.interactor.GetIdsOfFavoriteMangaWithMetadata
|
||||||
|
import eu.kanade.domain.manga.interactor.GetManga
|
||||||
|
import eu.kanade.domain.manga.interactor.GetMangaBySource
|
||||||
|
import eu.kanade.domain.manga.interactor.GetMergedManga
|
||||||
|
import eu.kanade.domain.manga.interactor.GetMergedMangaById
|
||||||
|
import eu.kanade.domain.manga.interactor.GetMergedMangaForDownloading
|
||||||
|
import eu.kanade.domain.manga.interactor.GetMergedReferencesById
|
||||||
import eu.kanade.domain.manga.interactor.GetPagePreviews
|
import eu.kanade.domain.manga.interactor.GetPagePreviews
|
||||||
|
import eu.kanade.domain.manga.interactor.GetSearchMetadata
|
||||||
|
import eu.kanade.domain.manga.interactor.GetSearchTags
|
||||||
|
import eu.kanade.domain.manga.interactor.GetSearchTitles
|
||||||
import eu.kanade.domain.manga.interactor.GetSortTag
|
import eu.kanade.domain.manga.interactor.GetSortTag
|
||||||
|
import eu.kanade.domain.manga.interactor.InsertFavoriteEntries
|
||||||
|
import eu.kanade.domain.manga.interactor.InsertFlatMetadata
|
||||||
|
import eu.kanade.domain.manga.interactor.InsertMergedReference
|
||||||
import eu.kanade.domain.manga.interactor.ReorderSortTag
|
import eu.kanade.domain.manga.interactor.ReorderSortTag
|
||||||
|
import eu.kanade.domain.manga.interactor.SetMangaFilteredScanlators
|
||||||
|
import eu.kanade.domain.manga.interactor.UpdateMergedSettings
|
||||||
|
import eu.kanade.domain.source.interactor.CountFeedSavedSearchBySourceId
|
||||||
|
import eu.kanade.domain.source.interactor.CountFeedSavedSearchGlobal
|
||||||
import eu.kanade.domain.source.interactor.CreateSourceCategory
|
import eu.kanade.domain.source.interactor.CreateSourceCategory
|
||||||
|
import eu.kanade.domain.source.interactor.CreateSourceRepo
|
||||||
|
import eu.kanade.domain.source.interactor.DeleteFeedSavedSearchById
|
||||||
|
import eu.kanade.domain.source.interactor.DeleteSavedSearchById
|
||||||
import eu.kanade.domain.source.interactor.DeleteSourceCategory
|
import eu.kanade.domain.source.interactor.DeleteSourceCategory
|
||||||
|
import eu.kanade.domain.source.interactor.DeleteSourceRepos
|
||||||
import eu.kanade.domain.source.interactor.GetExhSavedSearch
|
import eu.kanade.domain.source.interactor.GetExhSavedSearch
|
||||||
|
import eu.kanade.domain.source.interactor.GetFeedSavedSearchBySourceId
|
||||||
|
import eu.kanade.domain.source.interactor.GetFeedSavedSearchGlobal
|
||||||
|
import eu.kanade.domain.source.interactor.GetSavedSearchById
|
||||||
|
import eu.kanade.domain.source.interactor.GetSavedSearchBySourceId
|
||||||
|
import eu.kanade.domain.source.interactor.GetSavedSearchBySourceIdFeed
|
||||||
|
import eu.kanade.domain.source.interactor.GetSavedSearchGlobalFeed
|
||||||
import eu.kanade.domain.source.interactor.GetShowLatest
|
import eu.kanade.domain.source.interactor.GetShowLatest
|
||||||
import eu.kanade.domain.source.interactor.GetSourceCategories
|
import eu.kanade.domain.source.interactor.GetSourceCategories
|
||||||
|
import eu.kanade.domain.source.interactor.GetSourceRepos
|
||||||
|
import eu.kanade.domain.source.interactor.InsertFeedSavedSearch
|
||||||
|
import eu.kanade.domain.source.interactor.InsertSavedSearch
|
||||||
import eu.kanade.domain.source.interactor.RenameSourceCategory
|
import eu.kanade.domain.source.interactor.RenameSourceCategory
|
||||||
import eu.kanade.domain.source.interactor.SetSourceCategories
|
import eu.kanade.domain.source.interactor.SetSourceCategories
|
||||||
import eu.kanade.domain.source.interactor.ToggleExcludeFromDataSaver
|
import eu.kanade.domain.source.interactor.ToggleExcludeFromDataSaver
|
||||||
import eu.kanade.tachiyomi.di.InjektModule
|
|
||||||
import eu.kanade.tachiyomi.di.addFactory
|
|
||||||
import eu.kanade.tachiyomi.di.addSingletonFactory
|
|
||||||
import eu.kanade.tachiyomi.source.online.MetadataSource
|
import eu.kanade.tachiyomi.source.online.MetadataSource
|
||||||
import exh.search.SearchEngine
|
import exh.search.SearchEngine
|
||||||
import tachiyomi.data.manga.CustomMangaRepositoryImpl
|
import tachiyomi.data.manga.CustomMangaRepositoryImpl
|
||||||
@ -25,55 +64,19 @@ import tachiyomi.data.manga.MangaMergeRepositoryImpl
|
|||||||
import tachiyomi.data.manga.MangaMetadataRepositoryImpl
|
import tachiyomi.data.manga.MangaMetadataRepositoryImpl
|
||||||
import tachiyomi.data.source.FeedSavedSearchRepositoryImpl
|
import tachiyomi.data.source.FeedSavedSearchRepositoryImpl
|
||||||
import tachiyomi.data.source.SavedSearchRepositoryImpl
|
import tachiyomi.data.source.SavedSearchRepositoryImpl
|
||||||
import tachiyomi.domain.chapter.interactor.DeleteChapters
|
|
||||||
import tachiyomi.domain.chapter.interactor.GetChapterByUrl
|
|
||||||
import tachiyomi.domain.chapter.interactor.GetMergedChaptersByMangaId
|
|
||||||
import tachiyomi.domain.manga.interactor.DeleteByMergeId
|
|
||||||
import tachiyomi.domain.manga.interactor.DeleteFavoriteEntries
|
|
||||||
import tachiyomi.domain.manga.interactor.DeleteMangaById
|
|
||||||
import tachiyomi.domain.manga.interactor.DeleteMergeById
|
|
||||||
import tachiyomi.domain.manga.interactor.GetAllManga
|
|
||||||
import tachiyomi.domain.manga.interactor.GetCustomMangaInfo
|
import tachiyomi.domain.manga.interactor.GetCustomMangaInfo
|
||||||
import tachiyomi.domain.manga.interactor.GetExhFavoriteMangaWithMetadata
|
|
||||||
import tachiyomi.domain.manga.interactor.GetFavoriteEntries
|
|
||||||
import tachiyomi.domain.manga.interactor.GetFlatMetadataById
|
|
||||||
import tachiyomi.domain.manga.interactor.GetIdsOfFavoriteMangaWithMetadata
|
|
||||||
import tachiyomi.domain.manga.interactor.GetManga
|
|
||||||
import tachiyomi.domain.manga.interactor.GetMangaBySource
|
|
||||||
import tachiyomi.domain.manga.interactor.GetMergedManga
|
|
||||||
import tachiyomi.domain.manga.interactor.GetMergedMangaById
|
|
||||||
import tachiyomi.domain.manga.interactor.GetMergedMangaForDownloading
|
|
||||||
import tachiyomi.domain.manga.interactor.GetMergedReferencesById
|
|
||||||
import tachiyomi.domain.manga.interactor.GetReadMangaNotInLibraryView
|
|
||||||
import tachiyomi.domain.manga.interactor.GetSearchMetadata
|
|
||||||
import tachiyomi.domain.manga.interactor.GetSearchTags
|
|
||||||
import tachiyomi.domain.manga.interactor.GetSearchTitles
|
|
||||||
import tachiyomi.domain.manga.interactor.InsertFavoriteEntries
|
|
||||||
import tachiyomi.domain.manga.interactor.InsertFavoriteEntryAlternative
|
|
||||||
import tachiyomi.domain.manga.interactor.InsertFlatMetadata
|
|
||||||
import tachiyomi.domain.manga.interactor.InsertMergedReference
|
|
||||||
import tachiyomi.domain.manga.interactor.SetCustomMangaInfo
|
import tachiyomi.domain.manga.interactor.SetCustomMangaInfo
|
||||||
import tachiyomi.domain.manga.interactor.UpdateMergedSettings
|
|
||||||
import tachiyomi.domain.manga.repository.CustomMangaRepository
|
import tachiyomi.domain.manga.repository.CustomMangaRepository
|
||||||
import tachiyomi.domain.manga.repository.FavoritesEntryRepository
|
import tachiyomi.domain.manga.repository.FavoritesEntryRepository
|
||||||
import tachiyomi.domain.manga.repository.MangaMergeRepository
|
import tachiyomi.domain.manga.repository.MangaMergeRepository
|
||||||
import tachiyomi.domain.manga.repository.MangaMetadataRepository
|
import tachiyomi.domain.manga.repository.MangaMetadataRepository
|
||||||
import tachiyomi.domain.source.interactor.CountFeedSavedSearchBySourceId
|
|
||||||
import tachiyomi.domain.source.interactor.CountFeedSavedSearchGlobal
|
|
||||||
import tachiyomi.domain.source.interactor.DeleteFeedSavedSearchById
|
|
||||||
import tachiyomi.domain.source.interactor.DeleteSavedSearchById
|
|
||||||
import tachiyomi.domain.source.interactor.GetFeedSavedSearchBySourceId
|
|
||||||
import tachiyomi.domain.source.interactor.GetFeedSavedSearchGlobal
|
|
||||||
import tachiyomi.domain.source.interactor.GetSavedSearchById
|
|
||||||
import tachiyomi.domain.source.interactor.GetSavedSearchBySourceId
|
|
||||||
import tachiyomi.domain.source.interactor.GetSavedSearchBySourceIdFeed
|
|
||||||
import tachiyomi.domain.source.interactor.GetSavedSearchGlobalFeed
|
|
||||||
import tachiyomi.domain.source.interactor.InsertFeedSavedSearch
|
|
||||||
import tachiyomi.domain.source.interactor.InsertSavedSearch
|
|
||||||
import tachiyomi.domain.source.repository.FeedSavedSearchRepository
|
import tachiyomi.domain.source.repository.FeedSavedSearchRepository
|
||||||
import tachiyomi.domain.source.repository.SavedSearchRepository
|
import tachiyomi.domain.source.repository.SavedSearchRepository
|
||||||
import tachiyomi.domain.track.interactor.IsTrackUnfollowed
|
import uy.kohesive.injekt.api.InjektModule
|
||||||
import uy.kohesive.injekt.api.InjektRegistrar
|
import uy.kohesive.injekt.api.InjektRegistrar
|
||||||
|
import uy.kohesive.injekt.api.addFactory
|
||||||
|
import uy.kohesive.injekt.api.addSingletonFactory
|
||||||
|
import uy.kohesive.injekt.api.get
|
||||||
import xyz.nulldev.ts.api.http.serializer.FilterSerializer
|
import xyz.nulldev.ts.api.http.serializer.FilterSerializer
|
||||||
|
|
||||||
class SYDomainModule : InjektModule {
|
class SYDomainModule : InjektModule {
|
||||||
@ -82,12 +85,17 @@ class SYDomainModule : InjektModule {
|
|||||||
addFactory { GetShowLatest(get()) }
|
addFactory { GetShowLatest(get()) }
|
||||||
addFactory { ToggleExcludeFromDataSaver(get()) }
|
addFactory { ToggleExcludeFromDataSaver(get()) }
|
||||||
addFactory { SetSourceCategories(get()) }
|
addFactory { SetSourceCategories(get()) }
|
||||||
|
addFactory { SetMangaFilteredScanlators(get()) }
|
||||||
addFactory { GetAllManga(get()) }
|
addFactory { GetAllManga(get()) }
|
||||||
addFactory { GetMangaBySource(get()) }
|
addFactory { GetMangaBySource(get()) }
|
||||||
addFactory { DeleteChapters(get()) }
|
addFactory { DeleteChapters(get()) }
|
||||||
addFactory { DeleteMangaById(get()) }
|
addFactory { DeleteMangaById(get()) }
|
||||||
addFactory { FilterSerializer() }
|
addFactory { FilterSerializer() }
|
||||||
|
addFactory { GetHistoryByMangaId(get()) }
|
||||||
addFactory { GetChapterByUrl(get()) }
|
addFactory { GetChapterByUrl(get()) }
|
||||||
|
addFactory { CreateSourceRepo(get()) }
|
||||||
|
addFactory { DeleteSourceRepos(get()) }
|
||||||
|
addFactory { GetSourceRepos(get()) }
|
||||||
addFactory { GetSourceCategories(get()) }
|
addFactory { GetSourceCategories(get()) }
|
||||||
addFactory { CreateSourceCategory(get()) }
|
addFactory { CreateSourceCategory(get()) }
|
||||||
addFactory { RenameSourceCategory(get(), get()) }
|
addFactory { RenameSourceCategory(get(), get()) }
|
||||||
@ -98,8 +106,6 @@ class SYDomainModule : InjektModule {
|
|||||||
addFactory { ReorderSortTag(get(), get()) }
|
addFactory { ReorderSortTag(get(), get()) }
|
||||||
addFactory { GetPagePreviews(get(), get()) }
|
addFactory { GetPagePreviews(get(), get()) }
|
||||||
addFactory { SearchEngine() }
|
addFactory { SearchEngine() }
|
||||||
addFactory { IsTrackUnfollowed() }
|
|
||||||
addFactory { GetReadMangaNotInLibraryView(get()) }
|
|
||||||
|
|
||||||
// Required for [MetadataSource]
|
// Required for [MetadataSource]
|
||||||
addFactory<MetadataSource.GetMangaId> { GetManga(get()) }
|
addFactory<MetadataSource.GetMangaId> { GetManga(get()) }
|
||||||
@ -119,7 +125,7 @@ class SYDomainModule : InjektModule {
|
|||||||
addFactory { GetMergedManga(get()) }
|
addFactory { GetMergedManga(get()) }
|
||||||
addFactory { GetMergedMangaById(get()) }
|
addFactory { GetMergedMangaById(get()) }
|
||||||
addFactory { GetMergedReferencesById(get()) }
|
addFactory { GetMergedReferencesById(get()) }
|
||||||
addFactory { GetMergedChaptersByMangaId(get(), get()) }
|
addFactory { GetMergedChapterByMangaId(get(), get()) }
|
||||||
addFactory { InsertMergedReference(get()) }
|
addFactory { InsertMergedReference(get()) }
|
||||||
addFactory { UpdateMergedSettings(get()) }
|
addFactory { UpdateMergedSettings(get()) }
|
||||||
addFactory { DeleteByMergeId(get()) }
|
addFactory { DeleteByMergeId(get()) }
|
||||||
@ -130,7 +136,6 @@ class SYDomainModule : InjektModule {
|
|||||||
addFactory { GetFavoriteEntries(get()) }
|
addFactory { GetFavoriteEntries(get()) }
|
||||||
addFactory { InsertFavoriteEntries(get()) }
|
addFactory { InsertFavoriteEntries(get()) }
|
||||||
addFactory { DeleteFavoriteEntries(get()) }
|
addFactory { DeleteFavoriteEntries(get()) }
|
||||||
addFactory { InsertFavoriteEntryAlternative(get()) }
|
|
||||||
|
|
||||||
addSingletonFactory<SavedSearchRepository> { SavedSearchRepositoryImpl(get()) }
|
addSingletonFactory<SavedSearchRepository> { SavedSearchRepositoryImpl(get()) }
|
||||||
addFactory { GetSavedSearchById(get()) }
|
addFactory { GetSavedSearchById(get()) }
|
||||||
|
89
app/src/main/java/eu/kanade/domain/UnsortedPreferences.kt
Normal file
89
app/src/main/java/eu/kanade/domain/UnsortedPreferences.kt
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
package eu.kanade.domain
|
||||||
|
|
||||||
|
import tachiyomi.core.preference.PreferenceStore
|
||||||
|
|
||||||
|
class UnsortedPreferences(
|
||||||
|
private val preferenceStore: PreferenceStore,
|
||||||
|
) {
|
||||||
|
|
||||||
|
// SY -->
|
||||||
|
|
||||||
|
fun migrateFlags() = preferenceStore.getInt("migrate_flags", Int.MAX_VALUE)
|
||||||
|
|
||||||
|
fun defaultMangaOrder() = preferenceStore.getString("default_manga_order", "")
|
||||||
|
|
||||||
|
fun migrationSources() = preferenceStore.getString("migrate_sources", "")
|
||||||
|
|
||||||
|
fun smartMigration() = preferenceStore.getBoolean("smart_migrate", false)
|
||||||
|
|
||||||
|
fun useSourceWithMost() = preferenceStore.getBoolean("use_source_with_most", false)
|
||||||
|
|
||||||
|
fun skipPreMigration() = preferenceStore.getBoolean("skip_pre_migration", false)
|
||||||
|
|
||||||
|
fun hideNotFoundMigration() = preferenceStore.getBoolean("hide_not_found_migration", false)
|
||||||
|
|
||||||
|
fun isHentaiEnabled() = preferenceStore.getBoolean("eh_is_hentai_enabled", true)
|
||||||
|
|
||||||
|
fun enableExhentai() = preferenceStore.getBoolean("enable_exhentai", false)
|
||||||
|
|
||||||
|
fun imageQuality() = preferenceStore.getString("ehentai_quality", "auto")
|
||||||
|
|
||||||
|
fun useHentaiAtHome() = preferenceStore.getInt("eh_enable_hah", 0)
|
||||||
|
|
||||||
|
fun useJapaneseTitle() = preferenceStore.getBoolean("use_jp_title", false)
|
||||||
|
|
||||||
|
fun exhUseOriginalImages() = preferenceStore.getBoolean("eh_useOrigImages", false)
|
||||||
|
|
||||||
|
fun ehTagFilterValue() = preferenceStore.getInt("eh_tag_filtering_value", 0)
|
||||||
|
|
||||||
|
fun ehTagWatchingValue() = preferenceStore.getInt("eh_tag_watching_value", 0)
|
||||||
|
|
||||||
|
// EH Cookies
|
||||||
|
fun memberIdVal() = preferenceStore.getString("eh_ipb_member_id", "")
|
||||||
|
|
||||||
|
fun passHashVal() = preferenceStore.getString("eh_ipb_pass_hash", "")
|
||||||
|
fun igneousVal() = preferenceStore.getString("eh_igneous", "")
|
||||||
|
fun ehSettingsProfile() = preferenceStore.getInt("eh_ehSettingsProfile", -1)
|
||||||
|
fun exhSettingsProfile() = preferenceStore.getInt("eh_exhSettingsProfile", -1)
|
||||||
|
fun exhSettingsKey() = preferenceStore.getString("eh_settingsKey", "")
|
||||||
|
fun exhSessionCookie() = preferenceStore.getString("eh_sessionCookie", "")
|
||||||
|
fun exhHathPerksCookies() = preferenceStore.getString("eh_hathPerksCookie", "")
|
||||||
|
|
||||||
|
fun exhShowSyncIntro() = preferenceStore.getBoolean("eh_show_sync_intro", true)
|
||||||
|
|
||||||
|
fun exhReadOnlySync() = preferenceStore.getBoolean("eh_sync_read_only", false)
|
||||||
|
|
||||||
|
fun exhLenientSync() = preferenceStore.getBoolean("eh_lenient_sync", false)
|
||||||
|
|
||||||
|
fun exhShowSettingsUploadWarning() = preferenceStore.getBoolean("eh_showSettingsUploadWarning2", true)
|
||||||
|
|
||||||
|
fun logLevel() = preferenceStore.getInt("eh_log_level", 0)
|
||||||
|
|
||||||
|
fun exhAutoUpdateFrequency() = preferenceStore.getInt("eh_auto_update_frequency", 1)
|
||||||
|
|
||||||
|
fun exhAutoUpdateRequirements() = preferenceStore.getStringSet("eh_auto_update_restrictions", emptySet())
|
||||||
|
|
||||||
|
fun exhAutoUpdateStats() = preferenceStore.getString("eh_auto_update_stats", "")
|
||||||
|
|
||||||
|
fun exhWatchedListDefaultState() = preferenceStore.getBoolean("eh_watched_list_default_state", false)
|
||||||
|
|
||||||
|
fun exhSettingsLanguages() = preferenceStore.getString(
|
||||||
|
"eh_settings_languages",
|
||||||
|
"false*false*false\nfalse*false*false\nfalse*false*false\nfalse*false*false\nfalse*false*false\nfalse*false*false\nfalse*false*false\nfalse*false*false\nfalse*false*false\nfalse*false*false\nfalse*false*false\nfalse*false*false\nfalse*false*false\nfalse*false*false\nfalse*false*false\nfalse*false*false\nfalse*false*false",
|
||||||
|
)
|
||||||
|
|
||||||
|
fun exhEnabledCategories() = preferenceStore.getString(
|
||||||
|
"eh_enabled_categories",
|
||||||
|
"false,false,false,false,false,false,false,false,false,false",
|
||||||
|
)
|
||||||
|
|
||||||
|
fun enhancedEHentaiView() = preferenceStore.getBoolean("enhanced_e_hentai_view", true)
|
||||||
|
|
||||||
|
fun preferredMangaDexId() = preferenceStore.getString("preferred_mangaDex_id", "0")
|
||||||
|
|
||||||
|
fun mangadexSyncToLibraryIndexes() = preferenceStore.getStringSet("pref_mangadex_sync_to_library_indexes", emptySet())
|
||||||
|
|
||||||
|
fun allowLocalSourceHiddenFolders() = preferenceStore.getBoolean("allow_local_source_hidden_folders", false)
|
||||||
|
|
||||||
|
fun extensionRepos() = preferenceStore.getStringSet("extension_repos", emptySet())
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package eu.kanade.domain.backup.service
|
||||||
|
|
||||||
|
import tachiyomi.core.preference.PreferenceStore
|
||||||
|
import tachiyomi.core.provider.FolderProvider
|
||||||
|
|
||||||
|
class BackupPreferences(
|
||||||
|
private val folderProvider: FolderProvider,
|
||||||
|
private val preferenceStore: PreferenceStore,
|
||||||
|
) {
|
||||||
|
|
||||||
|
fun backupsDirectory() = preferenceStore.getString("backup_directory", folderProvider.path())
|
||||||
|
|
||||||
|
fun numberOfBackups() = preferenceStore.getInt("backup_slots", 2)
|
||||||
|
|
||||||
|
fun backupInterval() = preferenceStore.getInt("backup_interval", 12)
|
||||||
|
}
|
@ -1,38 +1,24 @@
|
|||||||
package eu.kanade.domain.base
|
package eu.kanade.domain.base
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import dev.icerock.moko.resources.StringResource
|
import eu.kanade.tachiyomi.util.system.isPreviewBuildType
|
||||||
import eu.kanade.tachiyomi.util.system.GLUtil
|
import eu.kanade.tachiyomi.util.system.isReleaseBuildType
|
||||||
import tachiyomi.core.common.preference.Preference
|
import tachiyomi.core.preference.PreferenceStore
|
||||||
import tachiyomi.core.common.preference.PreferenceStore
|
|
||||||
import tachiyomi.i18n.MR
|
|
||||||
|
|
||||||
class BasePreferences(
|
class BasePreferences(
|
||||||
val context: Context,
|
val context: Context,
|
||||||
private val preferenceStore: PreferenceStore,
|
private val preferenceStore: PreferenceStore,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun downloadedOnly() = preferenceStore.getBoolean(
|
fun confirmExit() = preferenceStore.getBoolean("pref_confirm_exit", false)
|
||||||
Preference.appStateKey("pref_downloaded_only"),
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
|
|
||||||
fun incognitoMode() = preferenceStore.getBoolean(Preference.appStateKey("incognito_mode"), false)
|
fun downloadedOnly() = preferenceStore.getBoolean("pref_downloaded_only", false)
|
||||||
|
|
||||||
|
fun incognitoMode() = preferenceStore.getBoolean("incognito_mode", false)
|
||||||
|
|
||||||
|
fun automaticExtUpdates() = preferenceStore.getBoolean("automatic_ext_updates", true)
|
||||||
|
|
||||||
fun extensionInstaller() = ExtensionInstallerPreference(context, preferenceStore)
|
fun extensionInstaller() = ExtensionInstallerPreference(context, preferenceStore)
|
||||||
|
|
||||||
fun shownOnboardingFlow() = preferenceStore.getBoolean(Preference.appStateKey("onboarding_complete"), false)
|
fun acraEnabled() = preferenceStore.getBoolean("acra.enable", isPreviewBuildType || isReleaseBuildType)
|
||||||
|
|
||||||
enum class ExtensionInstaller(val titleRes: StringResource, val requiresSystemPermission: Boolean) {
|
|
||||||
LEGACY(MR.strings.ext_installer_legacy, true),
|
|
||||||
PACKAGEINSTALLER(MR.strings.ext_installer_packageinstaller, true),
|
|
||||||
SHIZUKU(MR.strings.ext_installer_shizuku, false),
|
|
||||||
PRIVATE(MR.strings.ext_installer_private, false),
|
|
||||||
}
|
|
||||||
|
|
||||||
fun displayProfile() = preferenceStore.getString("pref_display_profile_key", "")
|
|
||||||
|
|
||||||
fun hardwareBitmapThreshold() = preferenceStore.getInt("pref_hardware_bitmap_threshold", GLUtil.SAFE_TEXTURE_LIMIT)
|
|
||||||
|
|
||||||
fun alwaysDecodeLongStripWithSSIV() = preferenceStore.getBoolean("pref_always_decode_long_strip_with_ssiv", false)
|
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
package eu.kanade.domain.base
|
package eu.kanade.domain.base
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import eu.kanade.domain.base.BasePreferences.ExtensionInstaller
|
import eu.kanade.tachiyomi.data.preference.PreferenceValues.ExtensionInstaller
|
||||||
import eu.kanade.tachiyomi.util.system.hasMiuiPackageInstaller
|
import eu.kanade.tachiyomi.util.system.hasMiuiPackageInstaller
|
||||||
import eu.kanade.tachiyomi.util.system.isShizukuInstalled
|
import eu.kanade.tachiyomi.util.system.isShizukuInstalled
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import tachiyomi.core.common.preference.Preference
|
import tachiyomi.core.preference.Preference
|
||||||
import tachiyomi.core.common.preference.PreferenceStore
|
import tachiyomi.core.preference.PreferenceStore
|
||||||
import tachiyomi.core.common.preference.getEnum
|
import tachiyomi.core.preference.getEnum
|
||||||
|
|
||||||
class ExtensionInstallerPreference(
|
class ExtensionInstallerPreference(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
@ -18,7 +18,7 @@ class ExtensionInstallerPreference(
|
|||||||
|
|
||||||
override fun key() = "extension_installer"
|
override fun key() = "extension_installer"
|
||||||
|
|
||||||
val entries get() = ExtensionInstaller.entries.run {
|
val entries get() = ExtensionInstaller.values().run {
|
||||||
if (context.hasMiuiPackageInstaller) {
|
if (context.hasMiuiPackageInstaller) {
|
||||||
filter { it != ExtensionInstaller.PACKAGEINSTALLER }
|
filter { it != ExtensionInstaller.PACKAGEINSTALLER }
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
package tachiyomi.domain.category.interactor
|
package eu.kanade.domain.category.interactor
|
||||||
|
|
||||||
|
import eu.kanade.domain.library.service.LibraryPreferences
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
import tachiyomi.core.common.util.lang.withNonCancellableContext
|
import tachiyomi.core.util.lang.withNonCancellableContext
|
||||||
import tachiyomi.core.common.util.system.logcat
|
import tachiyomi.core.util.system.logcat
|
||||||
import tachiyomi.domain.category.model.Category
|
import tachiyomi.domain.category.model.Category
|
||||||
import tachiyomi.domain.category.repository.CategoryRepository
|
import tachiyomi.domain.category.repository.CategoryRepository
|
||||||
import tachiyomi.domain.library.service.LibraryPreferences
|
|
||||||
|
|
||||||
class CreateCategoryWithName(
|
class CreateCategoryWithName(
|
||||||
private val categoryRepository: CategoryRepository,
|
private val categoryRepository: CategoryRepository,
|
||||||
@ -14,8 +14,10 @@ class CreateCategoryWithName(
|
|||||||
|
|
||||||
private val initialFlags: Long
|
private val initialFlags: Long
|
||||||
get() {
|
get() {
|
||||||
val sort = preferences.sortingMode().get()
|
val sort = preferences.librarySortingMode().get()
|
||||||
return sort.type.flag or sort.direction.flag
|
return preferences.libraryDisplayMode().get().flag or
|
||||||
|
sort.type.flag or
|
||||||
|
sort.direction.flag
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun await(name: String): Result = withNonCancellableContext {
|
suspend fun await(name: String): Result = withNonCancellableContext {
|
||||||
@ -37,11 +39,11 @@ class CreateCategoryWithName(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed interface Result {
|
sealed class Result {
|
||||||
// SY -->
|
// SY -->
|
||||||
data class Success(val category: Category) : Result
|
data class Success(val category: Category) : Result()
|
||||||
|
|
||||||
// SY <--
|
// SY <--
|
||||||
data class InternalError(val error: Throwable) : Result
|
data class InternalError(val error: Throwable) : Result()
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
package eu.kanade.domain.category.interactor
|
||||||
|
|
||||||
|
import logcat.LogPriority
|
||||||
|
import tachiyomi.core.util.lang.withNonCancellableContext
|
||||||
|
import tachiyomi.core.util.system.logcat
|
||||||
|
import tachiyomi.domain.category.model.CategoryUpdate
|
||||||
|
import tachiyomi.domain.category.repository.CategoryRepository
|
||||||
|
|
||||||
|
class DeleteCategory(
|
||||||
|
private val categoryRepository: CategoryRepository,
|
||||||
|
) {
|
||||||
|
|
||||||
|
suspend fun await(categoryId: Long) = withNonCancellableContext {
|
||||||
|
try {
|
||||||
|
categoryRepository.delete(categoryId)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
logcat(LogPriority.ERROR, e)
|
||||||
|
return@withNonCancellableContext Result.InternalError(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
val categories = categoryRepository.getAll()
|
||||||
|
val updates = categories.mapIndexed { index, category ->
|
||||||
|
CategoryUpdate(
|
||||||
|
id = category.id,
|
||||||
|
order = index.toLong(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
categoryRepository.updatePartial(updates)
|
||||||
|
Result.Success
|
||||||
|
} catch (e: Exception) {
|
||||||
|
logcat(LogPriority.ERROR, e)
|
||||||
|
Result.InternalError(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed class Result {
|
||||||
|
object Success : Result()
|
||||||
|
data class InternalError(val error: Throwable) : Result()
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +1,8 @@
|
|||||||
package tachiyomi.domain.category.interactor
|
package eu.kanade.domain.category.interactor
|
||||||
|
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
import tachiyomi.core.common.util.lang.withNonCancellableContext
|
import tachiyomi.core.util.lang.withNonCancellableContext
|
||||||
import tachiyomi.core.common.util.system.logcat
|
import tachiyomi.core.util.system.logcat
|
||||||
import tachiyomi.domain.category.model.Category
|
import tachiyomi.domain.category.model.Category
|
||||||
import tachiyomi.domain.category.model.CategoryUpdate
|
import tachiyomi.domain.category.model.CategoryUpdate
|
||||||
import tachiyomi.domain.category.repository.CategoryRepository
|
import tachiyomi.domain.category.repository.CategoryRepository
|
||||||
@ -28,8 +28,8 @@ class RenameCategory(
|
|||||||
|
|
||||||
suspend fun await(category: Category, name: String) = await(category.id, name)
|
suspend fun await(category: Category, name: String) = await(category.id, name)
|
||||||
|
|
||||||
sealed interface Result {
|
sealed class Result {
|
||||||
data object Success : Result
|
object Success : Result()
|
||||||
data class InternalError(val error: Throwable) : Result
|
data class InternalError(val error: Throwable) : Result()
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,20 +1,28 @@
|
|||||||
package tachiyomi.domain.category.interactor
|
package eu.kanade.domain.category.interactor
|
||||||
|
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import kotlinx.coroutines.sync.withLock
|
import kotlinx.coroutines.sync.withLock
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
import tachiyomi.core.common.util.lang.withNonCancellableContext
|
import tachiyomi.core.util.lang.withNonCancellableContext
|
||||||
import tachiyomi.core.common.util.system.logcat
|
import tachiyomi.core.util.system.logcat
|
||||||
import tachiyomi.domain.category.model.Category
|
import tachiyomi.domain.category.model.Category
|
||||||
import tachiyomi.domain.category.model.CategoryUpdate
|
import tachiyomi.domain.category.model.CategoryUpdate
|
||||||
import tachiyomi.domain.category.repository.CategoryRepository
|
import tachiyomi.domain.category.repository.CategoryRepository
|
||||||
|
import java.util.Collections
|
||||||
|
|
||||||
class ReorderCategory(
|
class ReorderCategory(
|
||||||
private val categoryRepository: CategoryRepository,
|
private val categoryRepository: CategoryRepository,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private val mutex = Mutex()
|
private val mutex = Mutex()
|
||||||
|
|
||||||
suspend fun await(category: Category, newIndex: Int) = withNonCancellableContext {
|
suspend fun moveUp(category: Category): Result =
|
||||||
|
await(category, MoveTo.UP)
|
||||||
|
|
||||||
|
suspend fun moveDown(category: Category): Result =
|
||||||
|
await(category, MoveTo.DOWN)
|
||||||
|
|
||||||
|
private suspend fun await(category: Category, moveTo: MoveTo) = withNonCancellableContext {
|
||||||
mutex.withLock {
|
mutex.withLock {
|
||||||
val categories = categoryRepository.getAll()
|
val categories = categoryRepository.getAll()
|
||||||
.filterNot(Category::isSystemCategory)
|
.filterNot(Category::isSystemCategory)
|
||||||
@ -25,8 +33,13 @@ class ReorderCategory(
|
|||||||
return@withNonCancellableContext Result.Unchanged
|
return@withNonCancellableContext Result.Unchanged
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val newPosition = when (moveTo) {
|
||||||
|
MoveTo.UP -> currentIndex - 1
|
||||||
|
MoveTo.DOWN -> currentIndex + 1
|
||||||
|
}.toInt()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
categories.add(newIndex, categories.removeAt(currentIndex))
|
Collections.swap(categories, currentIndex, newPosition)
|
||||||
|
|
||||||
val updates = categories.mapIndexed { index, category ->
|
val updates = categories.mapIndexed { index, category ->
|
||||||
CategoryUpdate(
|
CategoryUpdate(
|
||||||
@ -44,9 +57,14 @@ class ReorderCategory(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed interface Result {
|
sealed class Result {
|
||||||
data object Success : Result
|
object Success : Result()
|
||||||
data object Unchanged : Result
|
object Unchanged : Result()
|
||||||
data class InternalError(val error: Throwable) : Result
|
data class InternalError(val error: Throwable) : Result()
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum class MoveTo {
|
||||||
|
UP,
|
||||||
|
DOWN,
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
package eu.kanade.domain.category.interactor
|
||||||
|
|
||||||
|
import eu.kanade.domain.library.service.LibraryPreferences
|
||||||
|
import tachiyomi.domain.category.repository.CategoryRepository
|
||||||
|
import tachiyomi.domain.library.model.plus
|
||||||
|
|
||||||
|
class ResetCategoryFlags(
|
||||||
|
private val preferences: LibraryPreferences,
|
||||||
|
private val categoryRepository: CategoryRepository,
|
||||||
|
) {
|
||||||
|
|
||||||
|
suspend fun await() {
|
||||||
|
val display = preferences.libraryDisplayMode().get()
|
||||||
|
val sort = preferences.librarySortingMode().get()
|
||||||
|
categoryRepository.updateAllFlags(display + sort.type + sort.direction)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
package eu.kanade.domain.category.interactor
|
||||||
|
|
||||||
|
import eu.kanade.domain.library.model.LibraryGroup
|
||||||
|
import eu.kanade.domain.library.service.LibraryPreferences
|
||||||
|
import tachiyomi.domain.category.model.Category
|
||||||
|
import tachiyomi.domain.category.model.CategoryUpdate
|
||||||
|
import tachiyomi.domain.category.repository.CategoryRepository
|
||||||
|
import tachiyomi.domain.library.model.LibraryDisplayMode
|
||||||
|
import tachiyomi.domain.library.model.plus
|
||||||
|
|
||||||
|
class SetDisplayModeForCategory(
|
||||||
|
private val preferences: LibraryPreferences,
|
||||||
|
private val categoryRepository: CategoryRepository,
|
||||||
|
) {
|
||||||
|
|
||||||
|
suspend fun await(categoryId: Long, display: LibraryDisplayMode) {
|
||||||
|
// SY -->
|
||||||
|
if (preferences.groupLibraryBy().get() != LibraryGroup.BY_DEFAULT) {
|
||||||
|
preferences.libraryDisplayMode().set(display)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// SY <--
|
||||||
|
val category = categoryRepository.get(categoryId) ?: return
|
||||||
|
val flags = category.flags + display
|
||||||
|
if (preferences.categorizedDisplaySettings().get()) {
|
||||||
|
categoryRepository.updatePartial(
|
||||||
|
CategoryUpdate(
|
||||||
|
id = category.id,
|
||||||
|
flags = flags,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
preferences.libraryDisplayMode().set(display)
|
||||||
|
categoryRepository.updateAllFlags(flags)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun await(category: Category, display: LibraryDisplayMode) {
|
||||||
|
await(category.id, display)
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
package tachiyomi.domain.category.interactor
|
package eu.kanade.domain.category.interactor
|
||||||
|
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
import tachiyomi.core.common.util.system.logcat
|
import tachiyomi.core.util.system.logcat
|
||||||
import tachiyomi.domain.manga.repository.MangaRepository
|
import tachiyomi.domain.manga.repository.MangaRepository
|
||||||
|
|
||||||
class SetMangaCategories(
|
class SetMangaCategories(
|
@ -0,0 +1,41 @@
|
|||||||
|
package eu.kanade.domain.category.interactor
|
||||||
|
|
||||||
|
import eu.kanade.domain.library.model.LibraryGroup
|
||||||
|
import eu.kanade.domain.library.service.LibraryPreferences
|
||||||
|
import tachiyomi.domain.category.model.Category
|
||||||
|
import tachiyomi.domain.category.model.CategoryUpdate
|
||||||
|
import tachiyomi.domain.category.repository.CategoryRepository
|
||||||
|
import tachiyomi.domain.library.model.LibrarySort
|
||||||
|
import tachiyomi.domain.library.model.plus
|
||||||
|
|
||||||
|
class SetSortModeForCategory(
|
||||||
|
private val preferences: LibraryPreferences,
|
||||||
|
private val categoryRepository: CategoryRepository,
|
||||||
|
) {
|
||||||
|
|
||||||
|
suspend fun await(categoryId: Long, type: LibrarySort.Type, direction: LibrarySort.Direction) {
|
||||||
|
// SY -->
|
||||||
|
if (preferences.groupLibraryBy().get() != LibraryGroup.BY_DEFAULT) {
|
||||||
|
preferences.librarySortingMode().set(LibrarySort(type, direction))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// SY <--
|
||||||
|
val category = categoryRepository.get(categoryId) ?: return
|
||||||
|
val flags = category.flags + type + direction
|
||||||
|
if (preferences.categorizedDisplaySettings().get()) {
|
||||||
|
categoryRepository.updatePartial(
|
||||||
|
CategoryUpdate(
|
||||||
|
id = category.id,
|
||||||
|
flags = flags,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
preferences.librarySortingMode().set(LibrarySort(type, direction))
|
||||||
|
categoryRepository.updateAllFlags(flags)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun await(category: Category, type: LibrarySort.Type, direction: LibrarySort.Direction) {
|
||||||
|
await(category.id, type, direction)
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
package tachiyomi.domain.category.interactor
|
package eu.kanade.domain.category.interactor
|
||||||
|
|
||||||
import tachiyomi.core.common.util.lang.withNonCancellableContext
|
import tachiyomi.core.util.lang.withNonCancellableContext
|
||||||
import tachiyomi.domain.category.model.CategoryUpdate
|
import tachiyomi.domain.category.model.CategoryUpdate
|
||||||
import tachiyomi.domain.category.repository.CategoryRepository
|
import tachiyomi.domain.category.repository.CategoryRepository
|
||||||
|
|
||||||
@ -17,8 +17,8 @@ class UpdateCategory(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed interface Result {
|
sealed class Result {
|
||||||
data object Success : Result
|
object Success : Result()
|
||||||
data class Error(val error: Exception) : Result
|
data class Error(val error: Exception) : Result()
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package tachiyomi.domain.chapter.interactor
|
package eu.kanade.domain.chapter.interactor
|
||||||
|
|
||||||
import tachiyomi.domain.chapter.repository.ChapterRepository
|
import tachiyomi.domain.chapter.repository.ChapterRepository
|
||||||
|
|
@ -1,36 +0,0 @@
|
|||||||
package eu.kanade.domain.chapter.interactor
|
|
||||||
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
|
||||||
import kotlinx.coroutines.flow.map
|
|
||||||
import tachiyomi.domain.chapter.repository.ChapterRepository
|
|
||||||
|
|
||||||
class GetAvailableScanlators(
|
|
||||||
private val repository: ChapterRepository,
|
|
||||||
) {
|
|
||||||
|
|
||||||
private fun List<String>.cleanupAvailableScanlators(): Set<String> {
|
|
||||||
return mapNotNull { it.ifBlank { null } }.toSet()
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun await(mangaId: Long): Set<String> {
|
|
||||||
return repository.getScanlatorsByMangaId(mangaId)
|
|
||||||
.cleanupAvailableScanlators()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun subscribe(mangaId: Long): Flow<Set<String>> {
|
|
||||||
return repository.getScanlatorsByMangaIdAsFlow(mangaId)
|
|
||||||
.map { it.cleanupAvailableScanlators() }
|
|
||||||
}
|
|
||||||
|
|
||||||
// SY -->
|
|
||||||
suspend fun awaitMerge(mangaId: Long): Set<String> {
|
|
||||||
return repository.getScanlatorsByMergeId(mangaId)
|
|
||||||
.cleanupAvailableScanlators()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun subscribeMerge(mangaId: Long): Flow<Set<String>> {
|
|
||||||
return repository.getScanlatorsByMergeIdAsFlow(mangaId)
|
|
||||||
.map { it.cleanupAvailableScanlators() }
|
|
||||||
}
|
|
||||||
// SY <--
|
|
||||||
}
|
|
@ -1,7 +1,7 @@
|
|||||||
package tachiyomi.domain.chapter.interactor
|
package eu.kanade.domain.chapter.interactor
|
||||||
|
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
import tachiyomi.core.common.util.system.logcat
|
import tachiyomi.core.util.system.logcat
|
||||||
import tachiyomi.domain.chapter.model.Chapter
|
import tachiyomi.domain.chapter.model.Chapter
|
||||||
import tachiyomi.domain.chapter.repository.ChapterRepository
|
import tachiyomi.domain.chapter.repository.ChapterRepository
|
||||||
|
|
@ -1,17 +1,17 @@
|
|||||||
package tachiyomi.domain.chapter.interactor
|
package eu.kanade.domain.chapter.interactor
|
||||||
|
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
import tachiyomi.core.common.util.system.logcat
|
import tachiyomi.core.util.system.logcat
|
||||||
import tachiyomi.domain.chapter.model.Chapter
|
import tachiyomi.domain.chapter.model.Chapter
|
||||||
import tachiyomi.domain.chapter.repository.ChapterRepository
|
import tachiyomi.domain.chapter.repository.ChapterRepository
|
||||||
|
|
||||||
class GetChaptersByMangaId(
|
class GetChapterByMangaId(
|
||||||
private val chapterRepository: ChapterRepository,
|
private val chapterRepository: ChapterRepository,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
suspend fun await(mangaId: Long, applyScanlatorFilter: Boolean = false): List<Chapter> {
|
suspend fun await(mangaId: Long): List<Chapter> {
|
||||||
return try {
|
return try {
|
||||||
chapterRepository.getChapterByMangaId(mangaId, applyScanlatorFilter)
|
chapterRepository.getChapterByMangaId(mangaId)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logcat(LogPriority.ERROR, e)
|
logcat(LogPriority.ERROR, e)
|
||||||
emptyList()
|
emptyList()
|
@ -1,7 +1,7 @@
|
|||||||
package tachiyomi.domain.chapter.interactor
|
package eu.kanade.domain.chapter.interactor
|
||||||
|
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
import tachiyomi.core.common.util.system.logcat
|
import tachiyomi.core.util.system.logcat
|
||||||
import tachiyomi.domain.chapter.model.Chapter
|
import tachiyomi.domain.chapter.model.Chapter
|
||||||
import tachiyomi.domain.chapter.repository.ChapterRepository
|
import tachiyomi.domain.chapter.repository.ChapterRepository
|
||||||
|
|
@ -1,40 +1,28 @@
|
|||||||
package tachiyomi.domain.chapter.interactor
|
package eu.kanade.domain.chapter.interactor
|
||||||
|
|
||||||
|
import eu.kanade.domain.manga.interactor.GetMergedReferencesById
|
||||||
import exh.source.MERGED_SOURCE_ID
|
import exh.source.MERGED_SOURCE_ID
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.flowOf
|
import kotlinx.coroutines.flow.flowOf
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
import tachiyomi.core.common.util.system.logcat
|
import tachiyomi.core.util.system.logcat
|
||||||
import tachiyomi.domain.chapter.model.Chapter
|
import tachiyomi.domain.chapter.model.Chapter
|
||||||
import tachiyomi.domain.chapter.repository.ChapterRepository
|
import tachiyomi.domain.chapter.repository.ChapterRepository
|
||||||
import tachiyomi.domain.manga.interactor.GetMergedReferencesById
|
|
||||||
import tachiyomi.domain.manga.model.MergedMangaReference
|
import tachiyomi.domain.manga.model.MergedMangaReference
|
||||||
|
|
||||||
class GetMergedChaptersByMangaId(
|
class GetMergedChapterByMangaId(
|
||||||
private val chapterRepository: ChapterRepository,
|
private val chapterRepository: ChapterRepository,
|
||||||
private val getMergedReferencesById: GetMergedReferencesById,
|
private val getMergedReferencesById: GetMergedReferencesById,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
suspend fun await(
|
suspend fun await(mangaId: Long, dedupe: Boolean = true): List<Chapter> {
|
||||||
mangaId: Long,
|
return transformMergedChapters(getMergedReferencesById.await(mangaId), getFromDatabase(mangaId), dedupe)
|
||||||
dedupe: Boolean = true,
|
|
||||||
applyScanlatorFilter: Boolean = false,
|
|
||||||
): List<Chapter> {
|
|
||||||
return transformMergedChapters(
|
|
||||||
getMergedReferencesById.await(mangaId),
|
|
||||||
getFromDatabase(mangaId, applyScanlatorFilter),
|
|
||||||
dedupe,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun subscribe(
|
suspend fun subscribe(mangaId: Long, dedupe: Boolean = true): Flow<List<Chapter>> {
|
||||||
mangaId: Long,
|
|
||||||
dedupe: Boolean = true,
|
|
||||||
applyScanlatorFilter: Boolean = false,
|
|
||||||
): Flow<List<Chapter>> {
|
|
||||||
return try {
|
return try {
|
||||||
chapterRepository.getMergedChapterByMangaIdAsFlow(mangaId, applyScanlatorFilter)
|
chapterRepository.getMergedChapterByMangaIdAsFlow(mangaId)
|
||||||
.combine(getMergedReferencesById.subscribe(mangaId)) { chapters, references ->
|
.combine(getMergedReferencesById.subscribe(mangaId)) { chapters, references ->
|
||||||
transformMergedChapters(references, chapters, dedupe)
|
transformMergedChapters(references, chapters, dedupe)
|
||||||
}
|
}
|
||||||
@ -44,30 +32,20 @@ class GetMergedChaptersByMangaId(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun getFromDatabase(
|
private suspend fun getFromDatabase(mangaId: Long): List<Chapter> {
|
||||||
mangaId: Long,
|
|
||||||
applyScanlatorFilter: Boolean = false,
|
|
||||||
): List<Chapter> {
|
|
||||||
return try {
|
return try {
|
||||||
chapterRepository.getMergedChapterByMangaId(mangaId, applyScanlatorFilter)
|
chapterRepository.getMergedChapterByMangaId(mangaId)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logcat(LogPriority.ERROR, e)
|
logcat(LogPriority.ERROR, e)
|
||||||
emptyList()
|
emptyList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun transformMergedChapters(
|
fun transformMergedChapters(mangaReferences: List<MergedMangaReference>, chapterList: List<Chapter>, dedupe: Boolean): List<Chapter> {
|
||||||
mangaReferences: List<MergedMangaReference>,
|
|
||||||
chapterList: List<Chapter>,
|
|
||||||
dedupe: Boolean,
|
|
||||||
): List<Chapter> {
|
|
||||||
return if (dedupe) dedupeChapterList(mangaReferences, chapterList) else chapterList
|
return if (dedupe) dedupeChapterList(mangaReferences, chapterList) else chapterList
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun dedupeChapterList(
|
private fun dedupeChapterList(mangaReferences: List<MergedMangaReference>, chapterList: List<Chapter>): List<Chapter> {
|
||||||
mangaReferences: List<MergedMangaReference>,
|
|
||||||
chapterList: List<Chapter>,
|
|
||||||
): List<Chapter> {
|
|
||||||
return when (mangaReferences.firstOrNull { it.mangaSourceId == MERGED_SOURCE_ID }?.chapterSortMode) {
|
return when (mangaReferences.firstOrNull { it.mangaSourceId == MERGED_SOURCE_ID }?.chapterSortMode) {
|
||||||
MergedMangaReference.CHAPTER_SORT_NO_DEDUPE, MergedMangaReference.CHAPTER_SORT_NONE -> chapterList
|
MergedMangaReference.CHAPTER_SORT_NO_DEDUPE, MergedMangaReference.CHAPTER_SORT_NONE -> chapterList
|
||||||
MergedMangaReference.CHAPTER_SORT_PRIORITY -> dedupeByPriority(mangaReferences, chapterList)
|
MergedMangaReference.CHAPTER_SORT_PRIORITY -> dedupeByPriority(mangaReferences, chapterList)
|
||||||
@ -93,10 +71,7 @@ class GetMergedChaptersByMangaId(
|
|||||||
return chapterList.maxByOrNull { it.chapterNumber }?.mangaId
|
return chapterList.maxByOrNull { it.chapterNumber }?.mangaId
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun dedupeByPriority(
|
private fun dedupeByPriority(mangaReferences: List<MergedMangaReference>, chapterList: List<Chapter>): List<Chapter> {
|
||||||
mangaReferences: List<MergedMangaReference>,
|
|
||||||
chapterList: List<Chapter>,
|
|
||||||
): List<Chapter> {
|
|
||||||
val sortedChapterList = mutableListOf<Chapter>()
|
val sortedChapterList = mutableListOf<Chapter>()
|
||||||
|
|
||||||
var existingChapterIndex: Int
|
var existingChapterIndex: Int
|
||||||
@ -111,11 +86,8 @@ class GetMergedChaptersByMangaId(
|
|||||||
val oldChapterIndex = existingChapterIndex
|
val oldChapterIndex = existingChapterIndex
|
||||||
if (chapter.isRecognizedNumber) {
|
if (chapter.isRecognizedNumber) {
|
||||||
existingChapterIndex = sortedChapterList.indexOfFirst {
|
existingChapterIndex = sortedChapterList.indexOfFirst {
|
||||||
// check if the chapter is not already there
|
it.isRecognizedNumber && it.chapterNumber == chapter.chapterNumber && // check if the chapter is not already there
|
||||||
it.isRecognizedNumber &&
|
it.mangaId != chapter.mangaId // allow multiple chapters of the same number from the same source
|
||||||
it.chapterNumber == chapter.chapterNumber &&
|
|
||||||
// allow multiple chapters of the same number from the same source
|
|
||||||
it.mangaId != chapter.mangaId
|
|
||||||
}
|
}
|
||||||
if (existingChapterIndex == -1) {
|
if (existingChapterIndex == -1) {
|
||||||
sortedChapterList.add(oldChapterIndex + 1, chapter)
|
sortedChapterList.add(oldChapterIndex + 1, chapter)
|
@ -1,9 +1,9 @@
|
|||||||
package tachiyomi.domain.chapter.interactor
|
package eu.kanade.domain.chapter.interactor
|
||||||
|
|
||||||
import tachiyomi.core.common.util.lang.withNonCancellableContext
|
import eu.kanade.domain.library.service.LibraryPreferences
|
||||||
import tachiyomi.domain.library.service.LibraryPreferences
|
import eu.kanade.domain.manga.interactor.GetFavorites
|
||||||
import tachiyomi.domain.manga.interactor.GetFavorites
|
import eu.kanade.domain.manga.interactor.SetMangaChapterFlags
|
||||||
import tachiyomi.domain.manga.interactor.SetMangaChapterFlags
|
import tachiyomi.core.util.lang.withNonCancellableContext
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
|
|
||||||
class SetMangaDefaultChapterFlags(
|
class SetMangaDefaultChapterFlags(
|
@ -1,15 +1,14 @@
|
|||||||
package eu.kanade.domain.chapter.interactor
|
package eu.kanade.domain.chapter.interactor
|
||||||
|
|
||||||
import eu.kanade.domain.download.interactor.DeleteDownload
|
import eu.kanade.domain.download.interactor.DeleteDownload
|
||||||
|
import eu.kanade.domain.download.service.DownloadPreferences
|
||||||
import exh.source.MERGED_SOURCE_ID
|
import exh.source.MERGED_SOURCE_ID
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
import tachiyomi.core.common.util.lang.withNonCancellableContext
|
import tachiyomi.core.util.lang.withNonCancellableContext
|
||||||
import tachiyomi.core.common.util.system.logcat
|
import tachiyomi.core.util.system.logcat
|
||||||
import tachiyomi.domain.chapter.interactor.GetMergedChaptersByMangaId
|
|
||||||
import tachiyomi.domain.chapter.model.Chapter
|
import tachiyomi.domain.chapter.model.Chapter
|
||||||
import tachiyomi.domain.chapter.model.ChapterUpdate
|
import tachiyomi.domain.chapter.model.ChapterUpdate
|
||||||
import tachiyomi.domain.chapter.repository.ChapterRepository
|
import tachiyomi.domain.chapter.repository.ChapterRepository
|
||||||
import tachiyomi.domain.download.service.DownloadPreferences
|
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
import tachiyomi.domain.manga.repository.MangaRepository
|
import tachiyomi.domain.manga.repository.MangaRepository
|
||||||
|
|
||||||
@ -19,7 +18,7 @@ class SetReadStatus(
|
|||||||
private val mangaRepository: MangaRepository,
|
private val mangaRepository: MangaRepository,
|
||||||
private val chapterRepository: ChapterRepository,
|
private val chapterRepository: ChapterRepository,
|
||||||
// SY -->
|
// SY -->
|
||||||
private val getMergedChaptersByMangaId: GetMergedChaptersByMangaId,
|
private val getMergedChapterByMangaId: GetMergedChapterByMangaId,
|
||||||
// SY <--
|
// SY <--
|
||||||
) {
|
) {
|
||||||
|
|
||||||
@ -78,7 +77,7 @@ class SetReadStatus(
|
|||||||
private suspend fun awaitMerged(mangaId: Long, read: Boolean) = withNonCancellableContext f@{
|
private suspend fun awaitMerged(mangaId: Long, read: Boolean) = withNonCancellableContext f@{
|
||||||
return@f await(
|
return@f await(
|
||||||
read = read,
|
read = read,
|
||||||
chapters = getMergedChaptersByMangaId
|
chapters = getMergedChapterByMangaId
|
||||||
.await(mangaId, dedupe = false)
|
.await(mangaId, dedupe = false)
|
||||||
.toTypedArray(),
|
.toTypedArray(),
|
||||||
)
|
)
|
||||||
@ -91,9 +90,9 @@ class SetReadStatus(
|
|||||||
}
|
}
|
||||||
// SY <--
|
// SY <--
|
||||||
|
|
||||||
sealed interface Result {
|
sealed class Result {
|
||||||
data object Success : Result
|
object Success : Result()
|
||||||
data object NoChapters : Result
|
object NoChapters : Result()
|
||||||
data class InternalError(val error: Throwable) : Result
|
data class InternalError(val error: Throwable) : Result()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,41 +2,37 @@ package eu.kanade.domain.chapter.interactor
|
|||||||
|
|
||||||
import eu.kanade.domain.chapter.model.copyFromSChapter
|
import eu.kanade.domain.chapter.model.copyFromSChapter
|
||||||
import eu.kanade.domain.chapter.model.toSChapter
|
import eu.kanade.domain.chapter.model.toSChapter
|
||||||
import eu.kanade.domain.manga.interactor.GetExcludedScanlators
|
|
||||||
import eu.kanade.domain.manga.interactor.UpdateManga
|
import eu.kanade.domain.manga.interactor.UpdateManga
|
||||||
import eu.kanade.domain.manga.model.toSManga
|
import eu.kanade.domain.manga.model.toSManga
|
||||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||||
import eu.kanade.tachiyomi.data.download.DownloadProvider
|
import eu.kanade.tachiyomi.data.download.DownloadProvider
|
||||||
import eu.kanade.tachiyomi.source.Source
|
import eu.kanade.tachiyomi.source.Source
|
||||||
|
import eu.kanade.tachiyomi.source.isLocal
|
||||||
import eu.kanade.tachiyomi.source.model.SChapter
|
import eu.kanade.tachiyomi.source.model.SChapter
|
||||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||||
|
import eu.kanade.tachiyomi.util.chapter.ChapterRecognition
|
||||||
import exh.source.isEhBasedManga
|
import exh.source.isEhBasedManga
|
||||||
import tachiyomi.data.chapter.ChapterSanitizer
|
import tachiyomi.data.chapter.ChapterSanitizer
|
||||||
import tachiyomi.domain.chapter.interactor.GetChaptersByMangaId
|
|
||||||
import tachiyomi.domain.chapter.interactor.ShouldUpdateDbChapter
|
import tachiyomi.domain.chapter.interactor.ShouldUpdateDbChapter
|
||||||
import tachiyomi.domain.chapter.interactor.UpdateChapter
|
|
||||||
import tachiyomi.domain.chapter.model.Chapter
|
import tachiyomi.domain.chapter.model.Chapter
|
||||||
import tachiyomi.domain.chapter.model.NoChaptersException
|
import tachiyomi.domain.chapter.model.NoChaptersException
|
||||||
import tachiyomi.domain.chapter.model.toChapterUpdate
|
import tachiyomi.domain.chapter.model.toChapterUpdate
|
||||||
import tachiyomi.domain.chapter.repository.ChapterRepository
|
import tachiyomi.domain.chapter.repository.ChapterRepository
|
||||||
import tachiyomi.domain.chapter.service.ChapterRecognition
|
|
||||||
import tachiyomi.domain.library.service.LibraryPreferences
|
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
import tachiyomi.source.local.isLocal
|
import uy.kohesive.injekt.Injekt
|
||||||
|
import uy.kohesive.injekt.api.get
|
||||||
import java.lang.Long.max
|
import java.lang.Long.max
|
||||||
import java.time.ZonedDateTime
|
import java.util.Date
|
||||||
import java.util.TreeSet
|
import java.util.TreeSet
|
||||||
|
|
||||||
class SyncChaptersWithSource(
|
class SyncChaptersWithSource(
|
||||||
private val downloadManager: DownloadManager,
|
private val downloadManager: DownloadManager = Injekt.get(),
|
||||||
private val downloadProvider: DownloadProvider,
|
private val downloadProvider: DownloadProvider = Injekt.get(),
|
||||||
private val chapterRepository: ChapterRepository,
|
private val chapterRepository: ChapterRepository = Injekt.get(),
|
||||||
private val shouldUpdateDbChapter: ShouldUpdateDbChapter,
|
private val shouldUpdateDbChapter: ShouldUpdateDbChapter = Injekt.get(),
|
||||||
private val updateManga: UpdateManga,
|
private val updateManga: UpdateManga = Injekt.get(),
|
||||||
private val updateChapter: UpdateChapter,
|
private val updateChapter: UpdateChapter = Injekt.get(),
|
||||||
private val getChaptersByMangaId: GetChaptersByMangaId,
|
private val getChapterByMangaId: GetChapterByMangaId = Injekt.get(),
|
||||||
private val getExcludedScanlators: GetExcludedScanlators,
|
|
||||||
private val libraryPreferences: LibraryPreferences,
|
|
||||||
) {
|
) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -51,16 +47,11 @@ class SyncChaptersWithSource(
|
|||||||
rawSourceChapters: List<SChapter>,
|
rawSourceChapters: List<SChapter>,
|
||||||
manga: Manga,
|
manga: Manga,
|
||||||
source: Source,
|
source: Source,
|
||||||
manualFetch: Boolean = false,
|
|
||||||
fetchWindow: Pair<Long, Long> = Pair(0, 0),
|
|
||||||
): List<Chapter> {
|
): List<Chapter> {
|
||||||
if (rawSourceChapters.isEmpty() && !source.isLocal()) {
|
if (rawSourceChapters.isEmpty() && !source.isLocal()) {
|
||||||
throw NoChaptersException()
|
throw NoChaptersException()
|
||||||
}
|
}
|
||||||
|
|
||||||
val now = ZonedDateTime.now()
|
|
||||||
val nowMillis = now.toInstant().toEpochMilli()
|
|
||||||
|
|
||||||
val sourceChapters = rawSourceChapters
|
val sourceChapters = rawSourceChapters
|
||||||
.distinctBy { it.url }
|
.distinctBy { it.url }
|
||||||
.mapIndexed { i, sChapter ->
|
.mapIndexed { i, sChapter ->
|
||||||
@ -70,58 +61,58 @@ class SyncChaptersWithSource(
|
|||||||
.copy(mangaId = manga.id, sourceOrder = i.toLong())
|
.copy(mangaId = manga.id, sourceOrder = i.toLong())
|
||||||
}
|
}
|
||||||
|
|
||||||
val dbChapters = getChaptersByMangaId.await(manga.id)
|
// Chapters from db.
|
||||||
|
val dbChapters = getChapterByMangaId.await(manga.id)
|
||||||
|
|
||||||
val newChapters = mutableListOf<Chapter>()
|
// Chapters from the source not in db.
|
||||||
val updatedChapters = mutableListOf<Chapter>()
|
val toAdd = mutableListOf<Chapter>()
|
||||||
val removedChapters = dbChapters.filterNot { dbChapter ->
|
|
||||||
|
// Chapters whose metadata have changed.
|
||||||
|
val toChange = mutableListOf<Chapter>()
|
||||||
|
|
||||||
|
// Chapters from the db not in source.
|
||||||
|
val toDelete = dbChapters.filterNot { dbChapter ->
|
||||||
sourceChapters.any { sourceChapter ->
|
sourceChapters.any { sourceChapter ->
|
||||||
dbChapter.url == sourceChapter.url
|
dbChapter.url == sourceChapter.url
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val rightNow = Date().time
|
||||||
|
|
||||||
// Used to not set upload date of older chapters
|
// Used to not set upload date of older chapters
|
||||||
// to a higher value than newer chapters
|
// to a higher value than newer chapters
|
||||||
var maxSeenUploadDate = 0L
|
var maxSeenUploadDate = 0L
|
||||||
|
|
||||||
|
val sManga = manga.toSManga()
|
||||||
for (sourceChapter in sourceChapters) {
|
for (sourceChapter in sourceChapters) {
|
||||||
var chapter = sourceChapter
|
var chapter = sourceChapter
|
||||||
|
|
||||||
// Update metadata from source if necessary.
|
// Update metadata from source if necessary.
|
||||||
if (source is HttpSource) {
|
if (source is HttpSource) {
|
||||||
val sChapter = chapter.toSChapter()
|
val sChapter = chapter.toSChapter()
|
||||||
source.prepareNewChapter(sChapter, manga.toSManga())
|
source.prepareNewChapter(sChapter, sManga)
|
||||||
chapter = chapter.copyFromSChapter(sChapter)
|
chapter = chapter.copyFromSChapter(sChapter)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recognize chapter number for the chapter.
|
// Recognize chapter number for the chapter.
|
||||||
val chapterNumber = ChapterRecognition.parseChapterNumber(
|
val chapterNumber = ChapterRecognition.parseChapterNumber(manga.title, chapter.name, chapter.chapterNumber)
|
||||||
manga.title,
|
|
||||||
chapter.name,
|
|
||||||
chapter.chapterNumber,
|
|
||||||
)
|
|
||||||
chapter = chapter.copy(chapterNumber = chapterNumber)
|
chapter = chapter.copy(chapterNumber = chapterNumber)
|
||||||
|
|
||||||
val dbChapter = dbChapters.find { it.url == chapter.url }
|
val dbChapter = dbChapters.find { it.url == chapter.url }
|
||||||
|
|
||||||
if (dbChapter == null) {
|
if (dbChapter == null) {
|
||||||
val toAddChapter = if (chapter.dateUpload == 0L) {
|
val toAddChapter = if (chapter.dateUpload == 0L) {
|
||||||
val altDateUpload = if (maxSeenUploadDate == 0L) nowMillis else maxSeenUploadDate
|
val altDateUpload = if (maxSeenUploadDate == 0L) rightNow else maxSeenUploadDate
|
||||||
chapter.copy(dateUpload = altDateUpload)
|
chapter.copy(dateUpload = altDateUpload)
|
||||||
} else {
|
} else {
|
||||||
maxSeenUploadDate = max(maxSeenUploadDate, sourceChapter.dateUpload)
|
maxSeenUploadDate = max(maxSeenUploadDate, sourceChapter.dateUpload)
|
||||||
chapter
|
chapter
|
||||||
}
|
}
|
||||||
newChapters.add(toAddChapter)
|
toAdd.add(toAddChapter)
|
||||||
} else {
|
} else {
|
||||||
if (shouldUpdateDbChapter.await(dbChapter, chapter)) {
|
if (shouldUpdateDbChapter.await(dbChapter, chapter)) {
|
||||||
val shouldRenameChapter = downloadProvider.isChapterDirNameChanged(dbChapter, chapter) &&
|
val shouldRenameChapter = downloadProvider.isChapterDirNameChanged(dbChapter, chapter) &&
|
||||||
downloadManager.isChapterDownloaded(
|
downloadManager.isChapterDownloaded(dbChapter.name, dbChapter.scanlator, /* SY --> */ manga.ogTitle /* SY <-- */, manga.source)
|
||||||
dbChapter.name,
|
|
||||||
dbChapter.scanlator,
|
|
||||||
/* SY --> */ manga.ogTitle /* SY <-- */,
|
|
||||||
manga.source,
|
|
||||||
)
|
|
||||||
|
|
||||||
if (shouldRenameChapter) {
|
if (shouldRenameChapter) {
|
||||||
downloadManager.renameChapter(source, manga, dbChapter, chapter)
|
downloadManager.renameChapter(source, manga, dbChapter, chapter)
|
||||||
@ -135,59 +126,38 @@ class SyncChaptersWithSource(
|
|||||||
if (chapter.dateUpload != 0L) {
|
if (chapter.dateUpload != 0L) {
|
||||||
toChangeChapter = toChangeChapter.copy(dateUpload = chapter.dateUpload)
|
toChangeChapter = toChangeChapter.copy(dateUpload = chapter.dateUpload)
|
||||||
}
|
}
|
||||||
updatedChapters.add(toChangeChapter)
|
toChange.add(toChangeChapter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return if there's nothing to add, delete, or update to avoid unnecessary db transactions.
|
// Return if there's nothing to add, delete or change, avoiding unnecessary db transactions.
|
||||||
if (newChapters.isEmpty() && removedChapters.isEmpty() && updatedChapters.isEmpty()) {
|
if (toAdd.isEmpty() && toDelete.isEmpty() && toChange.isEmpty()) {
|
||||||
if (manualFetch || manga.fetchInterval == 0 || manga.nextUpdate < fetchWindow.first) {
|
|
||||||
updateManga.awaitUpdateFetchInterval(
|
|
||||||
manga,
|
|
||||||
now,
|
|
||||||
fetchWindow,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return emptyList()
|
return emptyList()
|
||||||
}
|
}
|
||||||
|
|
||||||
val changedOrDuplicateReadUrls = mutableSetOf<String>()
|
val reAdded = mutableListOf<Chapter>()
|
||||||
|
|
||||||
val deletedChapterNumbers = TreeSet<Double>()
|
val deletedChapterNumbers = TreeSet<Float>()
|
||||||
val deletedReadChapterNumbers = TreeSet<Double>()
|
val deletedReadChapterNumbers = TreeSet<Float>()
|
||||||
val deletedBookmarkedChapterNumbers = TreeSet<Double>()
|
val deletedBookmarkedChapterNumbers = TreeSet<Float>()
|
||||||
|
|
||||||
val readChapterNumbers = dbChapters
|
toDelete.forEach { chapter ->
|
||||||
.asSequence()
|
|
||||||
.filter { it.read && it.isRecognizedNumber }
|
|
||||||
.map { it.chapterNumber }
|
|
||||||
.toSet()
|
|
||||||
|
|
||||||
removedChapters.forEach { chapter ->
|
|
||||||
if (chapter.read) deletedReadChapterNumbers.add(chapter.chapterNumber)
|
if (chapter.read) deletedReadChapterNumbers.add(chapter.chapterNumber)
|
||||||
if (chapter.bookmark) deletedBookmarkedChapterNumbers.add(chapter.chapterNumber)
|
if (chapter.bookmark) deletedBookmarkedChapterNumbers.add(chapter.chapterNumber)
|
||||||
deletedChapterNumbers.add(chapter.chapterNumber)
|
deletedChapterNumbers.add(chapter.chapterNumber)
|
||||||
}
|
}
|
||||||
|
|
||||||
val deletedChapterNumberDateFetchMap = removedChapters.sortedByDescending { it.dateFetch }
|
val deletedChapterNumberDateFetchMap = toDelete.sortedByDescending { it.dateFetch }
|
||||||
.associate { it.chapterNumber to it.dateFetch }
|
.associate { it.chapterNumber to it.dateFetch }
|
||||||
|
|
||||||
val markDuplicateAsRead = libraryPreferences.markDuplicateReadChapterAsRead().get()
|
|
||||||
.contains(LibraryPreferences.MARK_DUPLICATE_CHAPTER_READ_NEW)
|
|
||||||
|
|
||||||
// Date fetch is set in such a way that the upper ones will have bigger value than the lower ones
|
// Date fetch is set in such a way that the upper ones will have bigger value than the lower ones
|
||||||
// Sources MUST return the chapters from most to less recent, which is common.
|
// Sources MUST return the chapters from most to less recent, which is common.
|
||||||
var itemCount = newChapters.size
|
var itemCount = toAdd.size
|
||||||
var updatedToAdd = newChapters.map { toAddItem ->
|
var updatedToAdd = toAdd.map { toAddItem ->
|
||||||
var chapter = toAddItem.copy(dateFetch = nowMillis + itemCount--)
|
var chapter = toAddItem.copy(dateFetch = rightNow + itemCount--)
|
||||||
|
|
||||||
if (chapter.chapterNumber in readChapterNumbers && markDuplicateAsRead) {
|
if (chapter.isRecognizedNumber.not() || chapter.chapterNumber !in deletedChapterNumbers) return@map chapter
|
||||||
changedOrDuplicateReadUrls.add(chapter.url)
|
|
||||||
chapter = chapter.copy(read = true)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!chapter.isRecognizedNumber || chapter.chapterNumber !in deletedChapterNumbers) return@map chapter
|
|
||||||
|
|
||||||
chapter = chapter.copy(
|
chapter = chapter.copy(
|
||||||
read = chapter.chapterNumber in deletedReadChapterNumbers,
|
read = chapter.chapterNumber in deletedReadChapterNumbers,
|
||||||
@ -199,19 +169,19 @@ class SyncChaptersWithSource(
|
|||||||
chapter = chapter.copy(dateFetch = it)
|
chapter = chapter.copy(dateFetch = it)
|
||||||
}
|
}
|
||||||
|
|
||||||
changedOrDuplicateReadUrls.add(chapter.url)
|
reAdded.add(chapter)
|
||||||
|
|
||||||
chapter
|
chapter
|
||||||
}
|
}
|
||||||
|
|
||||||
// --> EXH (carry over reading progress)
|
// --> EXH (carry over reading progress)
|
||||||
if (manga.isEhBasedManga()) {
|
if (manga.isEhBasedManga()) {
|
||||||
val finalAdded = updatedToAdd.filterNot { it.url in changedOrDuplicateReadUrls }
|
val finalAdded = updatedToAdd.subtract(reAdded)
|
||||||
if (finalAdded.isNotEmpty()) {
|
if (finalAdded.isNotEmpty()) {
|
||||||
val max = dbChapters.maxOfOrNull { it.lastPageRead }
|
val max = dbChapters.maxOfOrNull { it.lastPageRead }
|
||||||
if (max != null && max > 0) {
|
if (max != null && max > 0) {
|
||||||
updatedToAdd = updatedToAdd.map {
|
updatedToAdd = updatedToAdd.map {
|
||||||
if (it.url !in changedOrDuplicateReadUrls) {
|
if (it !in reAdded) {
|
||||||
it.copy(lastPageRead = max)
|
it.copy(lastPageRead = max)
|
||||||
} else {
|
} else {
|
||||||
it
|
it
|
||||||
@ -222,8 +192,8 @@ class SyncChaptersWithSource(
|
|||||||
}
|
}
|
||||||
// <-- EXH
|
// <-- EXH
|
||||||
|
|
||||||
if (removedChapters.isNotEmpty()) {
|
if (toDelete.isNotEmpty()) {
|
||||||
val toDeleteIds = removedChapters.map { it.id }
|
val toDeleteIds = toDelete.map { it.id }
|
||||||
chapterRepository.removeChaptersWithIds(toDeleteIds)
|
chapterRepository.removeChaptersWithIds(toDeleteIds)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,18 +201,17 @@ class SyncChaptersWithSource(
|
|||||||
updatedToAdd = chapterRepository.addAll(updatedToAdd)
|
updatedToAdd = chapterRepository.addAll(updatedToAdd)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (updatedChapters.isNotEmpty()) {
|
if (toChange.isNotEmpty()) {
|
||||||
val chapterUpdates = updatedChapters.map { it.toChapterUpdate() }
|
val chapterUpdates = toChange.map { it.toChapterUpdate() }
|
||||||
updateChapter.awaitAll(chapterUpdates)
|
updateChapter.awaitAll(chapterUpdates)
|
||||||
}
|
}
|
||||||
updateManga.awaitUpdateFetchInterval(manga, now, fetchWindow)
|
|
||||||
|
|
||||||
// Set this manga as updated since chapters were changed
|
// Set this manga as updated since chapters were changed
|
||||||
// Note that last_update actually represents last time the chapter list changed at all
|
// Note that last_update actually represents last time the chapter list changed at all
|
||||||
updateManga.awaitUpdateLastUpdate(manga.id)
|
updateManga.awaitUpdateLastUpdate(manga.id)
|
||||||
|
|
||||||
val excludedScanlators = getExcludedScanlators.await(manga.id).toHashSet()
|
val reAddedUrls = reAdded.map { it.url }.toHashSet()
|
||||||
|
|
||||||
return updatedToAdd.filterNot { it.url in changedOrDuplicateReadUrls || it.scanlator in excludedScanlators }
|
return updatedToAdd.filterNot { it.url in reAddedUrls }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,41 @@
|
|||||||
|
package eu.kanade.domain.chapter.interactor
|
||||||
|
|
||||||
|
import eu.kanade.domain.track.interactor.InsertTrack
|
||||||
|
import eu.kanade.domain.track.model.toDbTrack
|
||||||
|
import eu.kanade.tachiyomi.data.track.TrackService
|
||||||
|
import logcat.LogPriority
|
||||||
|
import tachiyomi.core.util.system.logcat
|
||||||
|
import tachiyomi.domain.chapter.model.Chapter
|
||||||
|
import tachiyomi.domain.chapter.model.toChapterUpdate
|
||||||
|
import tachiyomi.domain.track.model.Track
|
||||||
|
import uy.kohesive.injekt.Injekt
|
||||||
|
import uy.kohesive.injekt.api.get
|
||||||
|
|
||||||
|
class SyncChaptersWithTrackServiceTwoWay(
|
||||||
|
private val updateChapter: UpdateChapter = Injekt.get(),
|
||||||
|
private val insertTrack: InsertTrack = Injekt.get(),
|
||||||
|
) {
|
||||||
|
|
||||||
|
suspend fun await(
|
||||||
|
chapters: List<Chapter>,
|
||||||
|
remoteTrack: Track,
|
||||||
|
service: TrackService,
|
||||||
|
) {
|
||||||
|
val sortedChapters = chapters.sortedBy { it.chapterNumber }
|
||||||
|
val chapterUpdates = sortedChapters
|
||||||
|
.filter { chapter -> chapter.chapterNumber <= remoteTrack.lastChapterRead && !chapter.read }
|
||||||
|
.map { it.copy(read = true).toChapterUpdate() }
|
||||||
|
|
||||||
|
// only take into account continuous reading
|
||||||
|
val localLastRead = sortedChapters.takeWhile { it.read }.lastOrNull()?.chapterNumber ?: 0F
|
||||||
|
val updatedTrack = remoteTrack.copy(lastChapterRead = localLastRead.toDouble())
|
||||||
|
|
||||||
|
try {
|
||||||
|
service.update(updatedTrack.toDbTrack())
|
||||||
|
updateChapter.awaitAll(chapterUpdates)
|
||||||
|
insertTrack.await(updatedTrack)
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
logcat(LogPriority.WARN, e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
package tachiyomi.domain.chapter.interactor
|
package eu.kanade.domain.chapter.interactor
|
||||||
|
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
import tachiyomi.core.common.util.system.logcat
|
import tachiyomi.core.util.system.logcat
|
||||||
import tachiyomi.domain.chapter.model.ChapterUpdate
|
import tachiyomi.domain.chapter.model.ChapterUpdate
|
||||||
import tachiyomi.domain.chapter.repository.ChapterRepository
|
import tachiyomi.domain.chapter.repository.ChapterRepository
|
||||||
|
|
@ -11,7 +11,7 @@ fun Chapter.toSChapter(): SChapter {
|
|||||||
it.url = url
|
it.url = url
|
||||||
it.name = name
|
it.name = name
|
||||||
it.date_upload = dateUpload
|
it.date_upload = dateUpload
|
||||||
it.chapter_number = chapterNumber.toFloat()
|
it.chapter_number = chapterNumber
|
||||||
it.scanlator = scanlator
|
it.scanlator = scanlator
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -21,8 +21,8 @@ fun Chapter.copyFromSChapter(sChapter: SChapter): Chapter {
|
|||||||
name = sChapter.name,
|
name = sChapter.name,
|
||||||
url = sChapter.url,
|
url = sChapter.url,
|
||||||
dateUpload = sChapter.date_upload,
|
dateUpload = sChapter.date_upload,
|
||||||
chapterNumber = sChapter.chapter_number.toDouble(),
|
chapterNumber = sChapter.chapter_number,
|
||||||
scanlator = sChapter.scanlator?.ifBlank { null }?.trim(),
|
scanlator = sChapter.scanlator?.ifBlank { null },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,7 +37,6 @@ fun Chapter.toDbChapter(): DbChapter = ChapterImpl().also {
|
|||||||
it.last_page_read = lastPageRead.toInt()
|
it.last_page_read = lastPageRead.toInt()
|
||||||
it.date_fetch = dateFetch
|
it.date_fetch = dateFetch
|
||||||
it.date_upload = dateUpload
|
it.date_upload = dateUpload
|
||||||
it.chapter_number = chapterNumber.toFloat()
|
it.chapter_number = chapterNumber
|
||||||
it.source_order = sourceOrder.toInt()
|
it.source_order = sourceOrder.toInt()
|
||||||
it.last_modified = lastModifiedAt
|
|
||||||
}
|
}
|
||||||
|
@ -1,45 +1,57 @@
|
|||||||
package eu.kanade.domain.chapter.model
|
package eu.kanade.domain.chapter.model
|
||||||
|
|
||||||
import eu.kanade.domain.manga.model.downloadedFilter
|
import eu.kanade.domain.manga.model.downloadedFilter
|
||||||
|
import eu.kanade.domain.manga.model.isLocal
|
||||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||||
import eu.kanade.tachiyomi.ui.manga.ChapterList
|
import eu.kanade.tachiyomi.data.download.model.Download
|
||||||
|
import eu.kanade.tachiyomi.ui.manga.ChapterItem
|
||||||
|
import eu.kanade.tachiyomi.util.chapter.getChapterSort
|
||||||
|
import exh.md.utils.MdUtil
|
||||||
import tachiyomi.domain.chapter.model.Chapter
|
import tachiyomi.domain.chapter.model.Chapter
|
||||||
import tachiyomi.domain.chapter.service.getChapterSort
|
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
import tachiyomi.domain.manga.model.applyFilter
|
import tachiyomi.domain.manga.model.TriStateFilter
|
||||||
import tachiyomi.source.local.isLocal
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Applies the view filters to the list of chapters obtained from the database.
|
* Applies the view filters to the list of chapters obtained from the database.
|
||||||
* @return an observable of the list of chapters filtered and sorted.
|
* @return an observable of the list of chapters filtered and sorted.
|
||||||
*/
|
*/
|
||||||
fun List<Chapter>.applyFilters(
|
fun List<Chapter>.applyFilters(manga: Manga, downloadManager: DownloadManager): List<Chapter> {
|
||||||
manga: Manga,
|
|
||||||
downloadManager: DownloadManager, /* SY --> */
|
|
||||||
mergedManga: Map<Long, Manga>, /* SY <-- */
|
|
||||||
): List<Chapter> {
|
|
||||||
val isLocalManga = manga.isLocal()
|
val isLocalManga = manga.isLocal()
|
||||||
val unreadFilter = manga.unreadFilter
|
val unreadFilter = manga.unreadFilter
|
||||||
val downloadedFilter = manga.downloadedFilter
|
val downloadedFilter = manga.downloadedFilter
|
||||||
val bookmarkedFilter = manga.bookmarkedFilter
|
val bookmarkedFilter = manga.bookmarkedFilter
|
||||||
|
|
||||||
return filter { chapter -> applyFilter(unreadFilter) { !chapter.read } }
|
return filter { chapter ->
|
||||||
.filter { chapter -> applyFilter(bookmarkedFilter) { chapter.bookmark } }
|
when (unreadFilter) {
|
||||||
|
TriStateFilter.DISABLED -> true
|
||||||
|
TriStateFilter.ENABLED_IS -> !chapter.read
|
||||||
|
TriStateFilter.ENABLED_NOT -> chapter.read
|
||||||
|
}
|
||||||
|
}
|
||||||
.filter { chapter ->
|
.filter { chapter ->
|
||||||
|
when (bookmarkedFilter) {
|
||||||
|
TriStateFilter.DISABLED -> true
|
||||||
|
TriStateFilter.ENABLED_IS -> chapter.bookmark
|
||||||
|
TriStateFilter.ENABLED_NOT -> !chapter.bookmark
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.filter { chapter ->
|
||||||
|
val downloaded = downloadManager.isChapterDownloaded(chapter.name, chapter.scanlator, /* SY --> */ manga.ogTitle /* SY <-- */, manga.source)
|
||||||
|
val downloadState = when {
|
||||||
|
downloaded -> Download.State.DOWNLOADED
|
||||||
|
else -> Download.State.NOT_DOWNLOADED
|
||||||
|
}
|
||||||
|
when (downloadedFilter) {
|
||||||
|
TriStateFilter.DISABLED -> true
|
||||||
|
TriStateFilter.ENABLED_IS -> downloadState == Download.State.DOWNLOADED || isLocalManga
|
||||||
|
TriStateFilter.ENABLED_NOT -> downloadState != Download.State.DOWNLOADED && !isLocalManga
|
||||||
|
}
|
||||||
|
}
|
||||||
// SY -->
|
// SY -->
|
||||||
@Suppress("NAME_SHADOWING")
|
.filter { chapter ->
|
||||||
val manga = mergedManga.getOrElse(chapter.mangaId) { manga }
|
manga.filteredScanlators.isNullOrEmpty() || MdUtil.getScanlators(chapter.scanlator).any { group -> manga.filteredScanlators!!.contains(group) }
|
||||||
|
}
|
||||||
// SY <--
|
// SY <--
|
||||||
applyFilter(downloadedFilter) {
|
|
||||||
val downloaded = downloadManager.isChapterDownloaded(
|
|
||||||
chapter.name,
|
|
||||||
chapter.scanlator,
|
|
||||||
/* SY --> */ manga.ogTitle /* SY <-- */,
|
|
||||||
manga.source,
|
|
||||||
)
|
|
||||||
downloaded || isLocalManga
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.sortedWith(getChapterSort(manga))
|
.sortedWith(getChapterSort(manga))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,14 +59,37 @@ fun List<Chapter>.applyFilters(
|
|||||||
* Applies the view filters to the list of chapters obtained from the database.
|
* Applies the view filters to the list of chapters obtained from the database.
|
||||||
* @return an observable of the list of chapters filtered and sorted.
|
* @return an observable of the list of chapters filtered and sorted.
|
||||||
*/
|
*/
|
||||||
fun List<ChapterList.Item>.applyFilters(manga: Manga): Sequence<ChapterList.Item> {
|
fun List<ChapterItem>.applyFilters(manga: Manga): Sequence<ChapterItem> {
|
||||||
val isLocalManga = manga.isLocal()
|
val isLocalManga = manga.isLocal()
|
||||||
val unreadFilter = manga.unreadFilter
|
val unreadFilter = manga.unreadFilter
|
||||||
val downloadedFilter = manga.downloadedFilter
|
val downloadedFilter = manga.downloadedFilter
|
||||||
val bookmarkedFilter = manga.bookmarkedFilter
|
val bookmarkedFilter = manga.bookmarkedFilter
|
||||||
return asSequence()
|
return asSequence()
|
||||||
.filter { (chapter) -> applyFilter(unreadFilter) { !chapter.read } }
|
.filter { (chapter) ->
|
||||||
.filter { (chapter) -> applyFilter(bookmarkedFilter) { chapter.bookmark } }
|
when (unreadFilter) {
|
||||||
.filter { applyFilter(downloadedFilter) { it.isDownloaded || isLocalManga } }
|
TriStateFilter.DISABLED -> true
|
||||||
|
TriStateFilter.ENABLED_IS -> !chapter.read
|
||||||
|
TriStateFilter.ENABLED_NOT -> chapter.read
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.filter { (chapter) ->
|
||||||
|
when (bookmarkedFilter) {
|
||||||
|
TriStateFilter.DISABLED -> true
|
||||||
|
TriStateFilter.ENABLED_IS -> chapter.bookmark
|
||||||
|
TriStateFilter.ENABLED_NOT -> !chapter.bookmark
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.filter {
|
||||||
|
when (downloadedFilter) {
|
||||||
|
TriStateFilter.DISABLED -> true
|
||||||
|
TriStateFilter.ENABLED_IS -> it.isDownloaded || isLocalManga
|
||||||
|
TriStateFilter.ENABLED_NOT -> !it.isDownloaded && !isLocalManga
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// SY -->
|
||||||
|
.filter { chapter ->
|
||||||
|
manga.filteredScanlators.isNullOrEmpty() || MdUtil.getScanlators(chapter.chapter.scanlator).any { group -> manga.filteredScanlators!!.contains(group) }
|
||||||
|
}
|
||||||
|
// SY <--
|
||||||
.sortedWith { (chapter1), (chapter2) -> getChapterSort(manga).invoke(chapter1, chapter2) }
|
.sortedWith { (chapter1), (chapter2) -> getChapterSort(manga).invoke(chapter1, chapter2) }
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
package eu.kanade.domain.download.interactor
|
package eu.kanade.domain.download.interactor
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||||
import tachiyomi.core.common.util.lang.withNonCancellableContext
|
import eu.kanade.tachiyomi.source.SourceManager
|
||||||
|
import tachiyomi.core.util.lang.withNonCancellableContext
|
||||||
import tachiyomi.domain.chapter.model.Chapter
|
import tachiyomi.domain.chapter.model.Chapter
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
import tachiyomi.domain.source.service.SourceManager
|
|
||||||
|
|
||||||
class DeleteDownload(
|
class DeleteDownload(
|
||||||
private val sourceManager: SourceManager,
|
private val sourceManager: SourceManager,
|
||||||
|
@ -0,0 +1,34 @@
|
|||||||
|
package eu.kanade.domain.download.service
|
||||||
|
|
||||||
|
import tachiyomi.core.preference.PreferenceStore
|
||||||
|
import tachiyomi.core.provider.FolderProvider
|
||||||
|
|
||||||
|
class DownloadPreferences(
|
||||||
|
private val folderProvider: FolderProvider,
|
||||||
|
private val preferenceStore: PreferenceStore,
|
||||||
|
) {
|
||||||
|
|
||||||
|
fun downloadsDirectory() = preferenceStore.getString("download_directory", folderProvider.path())
|
||||||
|
|
||||||
|
fun downloadOnlyOverWifi() = preferenceStore.getBoolean("pref_download_only_over_wifi_key", true)
|
||||||
|
|
||||||
|
fun saveChaptersAsCBZ() = preferenceStore.getBoolean("save_chapter_as_cbz", true)
|
||||||
|
|
||||||
|
fun splitTallImages() = preferenceStore.getBoolean("split_tall_images", false)
|
||||||
|
|
||||||
|
fun autoDownloadWhileReading() = preferenceStore.getInt("auto_download_while_reading", 0)
|
||||||
|
|
||||||
|
fun removeAfterReadSlots() = preferenceStore.getInt("remove_after_read_slots", -1)
|
||||||
|
|
||||||
|
fun removeAfterMarkedAsRead() = preferenceStore.getBoolean("pref_remove_after_marked_as_read_key", false)
|
||||||
|
|
||||||
|
fun removeBookmarkedChapters() = preferenceStore.getBoolean("pref_remove_bookmarked", false)
|
||||||
|
|
||||||
|
fun removeExcludeCategories() = preferenceStore.getStringSet("remove_exclude_categories", emptySet())
|
||||||
|
|
||||||
|
fun downloadNewChapters() = preferenceStore.getBoolean("download_new", false)
|
||||||
|
|
||||||
|
fun downloadNewChapterCategories() = preferenceStore.getStringSet("download_new_categories", emptySet())
|
||||||
|
|
||||||
|
fun downloadNewChapterCategoriesExclude() = preferenceStore.getStringSet("download_new_categories_exclude", emptySet())
|
||||||
|
}
|
@ -23,7 +23,7 @@ class GetExtensionSources(
|
|||||||
ExtensionSourceItem(
|
ExtensionSourceItem(
|
||||||
source = source,
|
source = source,
|
||||||
enabled = source.isEnabled(),
|
enabled = source.isEnabled(),
|
||||||
labelAsName = isMultiSource && !isMultiLangSingleSource,
|
labelAsName = isMultiSource && isMultiLangSingleSource.not(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,13 +20,12 @@ class GetExtensionsByType(
|
|||||||
extensionManager.installedExtensionsFlow,
|
extensionManager.installedExtensionsFlow,
|
||||||
extensionManager.untrustedExtensionsFlow,
|
extensionManager.untrustedExtensionsFlow,
|
||||||
extensionManager.availableExtensionsFlow,
|
extensionManager.availableExtensionsFlow,
|
||||||
) { enabledLanguages, _installed, _untrusted, _available ->
|
) { _activeLanguages, _installed, _untrusted, _available ->
|
||||||
val (updates, installed) = _installed
|
val (updates, installed) = _installed
|
||||||
.filter { (showNsfwSources || !it.isNsfw) }
|
.filter { (showNsfwSources || it.isNsfw.not()) }
|
||||||
.sortedWith(
|
.sortedWith(
|
||||||
compareBy<Extension.Installed> {
|
compareBy<Extension.Installed> { it.isObsolete.not() /* SY --> */ && it.isRedundant.not() /* SY <-- */ }
|
||||||
!it.isObsolete /* SY --> */ && !it.isRedundant /* SY <-- */
|
.thenBy(String.CASE_INSENSITIVE_ORDER) { it.name },
|
||||||
}.thenBy(String.CASE_INSENSITIVE_ORDER) { it.name },
|
|
||||||
)
|
)
|
||||||
.partition { it.hasUpdate }
|
.partition { it.hasUpdate }
|
||||||
|
|
||||||
@ -37,13 +36,13 @@ class GetExtensionsByType(
|
|||||||
.filter { extension ->
|
.filter { extension ->
|
||||||
_installed.none { it.pkgName == extension.pkgName } &&
|
_installed.none { it.pkgName == extension.pkgName } &&
|
||||||
_untrusted.none { it.pkgName == extension.pkgName } &&
|
_untrusted.none { it.pkgName == extension.pkgName } &&
|
||||||
(showNsfwSources || !extension.isNsfw)
|
(showNsfwSources || extension.isNsfw.not())
|
||||||
}
|
}
|
||||||
.flatMap { ext ->
|
.flatMap { ext ->
|
||||||
if (ext.sources.isEmpty()) {
|
if (ext.sources.isEmpty()) {
|
||||||
return@flatMap if (ext.lang in enabledLanguages) listOf(ext) else emptyList()
|
return@flatMap if (ext.lang in _activeLanguages) listOf(ext) else emptyList()
|
||||||
}
|
}
|
||||||
ext.sources.filter { it.lang in enabledLanguages }
|
ext.sources.filter { it.lang in _activeLanguages }
|
||||||
.map {
|
.map {
|
||||||
ext.copy(
|
ext.copy(
|
||||||
name = it.name,
|
name = it.name,
|
||||||
|
@ -1,32 +0,0 @@
|
|||||||
package eu.kanade.domain.extension.interactor
|
|
||||||
|
|
||||||
import android.content.pm.PackageInfo
|
|
||||||
import androidx.core.content.pm.PackageInfoCompat
|
|
||||||
import eu.kanade.domain.source.service.SourcePreferences
|
|
||||||
import mihon.domain.extensionrepo.repository.ExtensionRepoRepository
|
|
||||||
import tachiyomi.core.common.preference.getAndSet
|
|
||||||
|
|
||||||
class TrustExtension(
|
|
||||||
private val extensionRepoRepository: ExtensionRepoRepository,
|
|
||||||
private val preferences: SourcePreferences,
|
|
||||||
) {
|
|
||||||
|
|
||||||
suspend fun isTrusted(pkgInfo: PackageInfo, fingerprints: List<String>): Boolean {
|
|
||||||
val trustedFingerprints = extensionRepoRepository.getAll().map { it.signingKeyFingerprint }.toHashSet()
|
|
||||||
val key = "${pkgInfo.packageName}:${PackageInfoCompat.getLongVersionCode(pkgInfo)}:${fingerprints.last()}"
|
|
||||||
return trustedFingerprints.any { fingerprints.contains(it) } || key in preferences.trustedExtensions().get()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun trust(pkgName: String, versionCode: Long, signatureHash: String) {
|
|
||||||
preferences.trustedExtensions().getAndSet { exts ->
|
|
||||||
// Remove previously trusted versions
|
|
||||||
val removed = exts.filterNot { it.startsWith("$pkgName:") }.toMutableSet()
|
|
||||||
|
|
||||||
removed.also { it += "$pkgName:$versionCode:$signatureHash" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun revokeAll() {
|
|
||||||
preferences.trustedExtensions().delete()
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,13 @@
|
|||||||
|
package eu.kanade.domain.history.interactor
|
||||||
|
|
||||||
|
import tachiyomi.domain.history.model.History
|
||||||
|
import tachiyomi.domain.history.repository.HistoryRepository
|
||||||
|
|
||||||
|
class GetHistoryByMangaId(
|
||||||
|
private val repository: HistoryRepository,
|
||||||
|
) {
|
||||||
|
|
||||||
|
suspend fun await(mangaId: Long): List<History> {
|
||||||
|
return repository.getByMangaId(mangaId)
|
||||||
|
}
|
||||||
|
}
|
@ -1,19 +1,19 @@
|
|||||||
package tachiyomi.domain.history.interactor
|
package eu.kanade.domain.history.interactor
|
||||||
|
|
||||||
|
import eu.kanade.domain.chapter.interactor.GetChapterByMangaId
|
||||||
|
import eu.kanade.domain.chapter.interactor.GetMergedChapterByMangaId
|
||||||
|
import eu.kanade.domain.manga.interactor.GetManga
|
||||||
|
import eu.kanade.tachiyomi.util.chapter.getChapterSort
|
||||||
import exh.source.MERGED_SOURCE_ID
|
import exh.source.MERGED_SOURCE_ID
|
||||||
import exh.source.isEhBasedManga
|
import exh.source.isEhBasedManga
|
||||||
import tachiyomi.domain.chapter.interactor.GetChaptersByMangaId
|
|
||||||
import tachiyomi.domain.chapter.interactor.GetMergedChaptersByMangaId
|
|
||||||
import tachiyomi.domain.chapter.model.Chapter
|
import tachiyomi.domain.chapter.model.Chapter
|
||||||
import tachiyomi.domain.chapter.service.getChapterSort
|
|
||||||
import tachiyomi.domain.history.repository.HistoryRepository
|
import tachiyomi.domain.history.repository.HistoryRepository
|
||||||
import tachiyomi.domain.manga.interactor.GetManga
|
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
|
|
||||||
class GetNextChapters(
|
class GetNextChapters(
|
||||||
private val getChaptersByMangaId: GetChaptersByMangaId,
|
private val getChapterByMangaId: GetChapterByMangaId,
|
||||||
// SY -->
|
// SY -->
|
||||||
private val getMergedChaptersByMangaId: GetMergedChaptersByMangaId,
|
private val getMergedChapterByMangaId: GetMergedChapterByMangaId,
|
||||||
// SY <--
|
// SY <--
|
||||||
private val getManga: GetManga,
|
private val getManga: GetManga,
|
||||||
private val historyRepository: HistoryRepository,
|
private val historyRepository: HistoryRepository,
|
||||||
@ -29,7 +29,7 @@ class GetNextChapters(
|
|||||||
|
|
||||||
// SY -->
|
// SY -->
|
||||||
if (manga.source == MERGED_SOURCE_ID) {
|
if (manga.source == MERGED_SOURCE_ID) {
|
||||||
val chapters = getMergedChaptersByMangaId.await(mangaId, applyScanlatorFilter = true)
|
val chapters = getMergedChapterByMangaId.await(mangaId)
|
||||||
.sortedWith(getChapterSort(manga, sortDescending = false))
|
.sortedWith(getChapterSort(manga, sortDescending = false))
|
||||||
|
|
||||||
return if (onlyUnread) {
|
return if (onlyUnread) {
|
||||||
@ -39,7 +39,7 @@ class GetNextChapters(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (manga.isEhBasedManga()) {
|
if (manga.isEhBasedManga()) {
|
||||||
val chapters = getChaptersByMangaId.await(mangaId, applyScanlatorFilter = true)
|
val chapters = getChapterByMangaId.await(mangaId)
|
||||||
.sortedWith(getChapterSort(manga, sortDescending = false))
|
.sortedWith(getChapterSort(manga, sortDescending = false))
|
||||||
|
|
||||||
return if (onlyUnread) {
|
return if (onlyUnread) {
|
||||||
@ -50,7 +50,7 @@ class GetNextChapters(
|
|||||||
}
|
}
|
||||||
// SY <--
|
// SY <--
|
||||||
|
|
||||||
val chapters = getChaptersByMangaId.await(mangaId, applyScanlatorFilter = true)
|
val chapters = getChapterByMangaId.await(mangaId)
|
||||||
.sortedWith(getChapterSort(manga, sortDescending = false))
|
.sortedWith(getChapterSort(manga, sortDescending = false))
|
||||||
|
|
||||||
return if (onlyUnread) {
|
return if (onlyUnread) {
|
||||||
@ -60,11 +60,7 @@ class GetNextChapters(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun await(
|
suspend fun await(mangaId: Long, fromChapterId: Long, onlyUnread: Boolean = true): List<Chapter> {
|
||||||
mangaId: Long,
|
|
||||||
fromChapterId: Long,
|
|
||||||
onlyUnread: Boolean = true,
|
|
||||||
): List<Chapter> {
|
|
||||||
val chapters = await(mangaId, onlyUnread)
|
val chapters = await(mangaId, onlyUnread)
|
||||||
val currChapterIndex = chapters.indexOfFirst { it.id == fromChapterId }
|
val currChapterIndex = chapters.indexOfFirst { it.id == fromChapterId }
|
||||||
val nextChapters = chapters.subList(max(0, currChapterIndex), chapters.size)
|
val nextChapters = chapters.subList(max(0, currChapterIndex), chapters.size)
|
@ -1,4 +1,4 @@
|
|||||||
package tachiyomi.domain.library.model
|
package eu.kanade.domain.library.model
|
||||||
|
|
||||||
enum class GroupLibraryMode {
|
enum class GroupLibraryMode {
|
||||||
GLOBAL,
|
GLOBAL,
|
@ -0,0 +1,32 @@
|
|||||||
|
package eu.kanade.domain.library.model
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
|
|
||||||
|
object LibraryGroup {
|
||||||
|
|
||||||
|
const val BY_DEFAULT = 0
|
||||||
|
const val BY_SOURCE = 1
|
||||||
|
const val BY_STATUS = 2
|
||||||
|
const val BY_TRACK_STATUS = 3
|
||||||
|
const val UNGROUPED = 4
|
||||||
|
|
||||||
|
fun groupTypeStringRes(type: Int, hasCategories: Boolean = true): Int {
|
||||||
|
return when (type) {
|
||||||
|
BY_STATUS -> R.string.status
|
||||||
|
BY_SOURCE -> R.string.label_sources
|
||||||
|
BY_TRACK_STATUS -> R.string.tracking_status
|
||||||
|
UNGROUPED -> R.string.ungrouped
|
||||||
|
else -> if (hasCategories) R.string.categories else R.string.ungrouped
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun groupTypeDrawableRes(type: Int): Int {
|
||||||
|
return when (type) {
|
||||||
|
BY_STATUS -> R.drawable.ic_progress_clock_24dp
|
||||||
|
BY_TRACK_STATUS -> R.drawable.ic_sync_24dp
|
||||||
|
BY_SOURCE -> R.drawable.ic_browse_filled_24dp
|
||||||
|
UNGROUPED -> R.drawable.ic_ungroup_24dp
|
||||||
|
else -> R.drawable.ic_label_24dp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,128 @@
|
|||||||
|
package eu.kanade.domain.library.service
|
||||||
|
|
||||||
|
import eu.kanade.domain.library.model.GroupLibraryMode
|
||||||
|
import eu.kanade.domain.library.model.LibraryGroup
|
||||||
|
import eu.kanade.tachiyomi.data.preference.DEVICE_ONLY_ON_WIFI
|
||||||
|
import eu.kanade.tachiyomi.data.preference.MANGA_HAS_UNREAD
|
||||||
|
import eu.kanade.tachiyomi.data.preference.MANGA_NON_COMPLETED
|
||||||
|
import eu.kanade.tachiyomi.data.preference.MANGA_NON_READ
|
||||||
|
import eu.kanade.tachiyomi.widget.ExtendedNavigationView
|
||||||
|
import tachiyomi.core.preference.PreferenceStore
|
||||||
|
import tachiyomi.core.preference.getEnum
|
||||||
|
import tachiyomi.domain.library.model.LibraryDisplayMode
|
||||||
|
import tachiyomi.domain.library.model.LibrarySort
|
||||||
|
import tachiyomi.domain.manga.model.Manga
|
||||||
|
|
||||||
|
class LibraryPreferences(
|
||||||
|
private val preferenceStore: PreferenceStore,
|
||||||
|
) {
|
||||||
|
|
||||||
|
fun libraryDisplayMode() = preferenceStore.getObject("pref_display_mode_library", LibraryDisplayMode.default, LibraryDisplayMode.Serializer::serialize, LibraryDisplayMode.Serializer::deserialize)
|
||||||
|
|
||||||
|
fun librarySortingMode() = preferenceStore.getObject("library_sorting_mode", LibrarySort.default, LibrarySort.Serializer::serialize, LibrarySort.Serializer::deserialize)
|
||||||
|
|
||||||
|
fun portraitColumns() = preferenceStore.getInt("pref_library_columns_portrait_key", 0)
|
||||||
|
|
||||||
|
fun landscapeColumns() = preferenceStore.getInt("pref_library_columns_landscape_key", 0)
|
||||||
|
|
||||||
|
fun libraryUpdateInterval() = preferenceStore.getInt("pref_library_update_interval_key", 0)
|
||||||
|
fun libraryUpdateLastTimestamp() = preferenceStore.getLong("library_update_last_timestamp", 0L)
|
||||||
|
|
||||||
|
fun libraryUpdateDeviceRestriction() = preferenceStore.getStringSet("library_update_restriction", setOf(DEVICE_ONLY_ON_WIFI))
|
||||||
|
fun libraryUpdateMangaRestriction() = preferenceStore.getStringSet("library_update_manga_restriction", setOf(MANGA_HAS_UNREAD, MANGA_NON_COMPLETED, MANGA_NON_READ))
|
||||||
|
|
||||||
|
fun autoUpdateMetadata() = preferenceStore.getBoolean("auto_update_metadata", false)
|
||||||
|
|
||||||
|
fun autoUpdateTrackers() = preferenceStore.getBoolean("auto_update_trackers", false)
|
||||||
|
|
||||||
|
fun showContinueReadingButton() = preferenceStore.getBoolean("display_continue_reading_button", false)
|
||||||
|
|
||||||
|
// region Filter
|
||||||
|
|
||||||
|
fun filterDownloaded() = preferenceStore.getInt("pref_filter_library_downloaded", ExtendedNavigationView.Item.TriStateGroup.State.IGNORE.value)
|
||||||
|
|
||||||
|
fun filterUnread() = preferenceStore.getInt("pref_filter_library_unread", ExtendedNavigationView.Item.TriStateGroup.State.IGNORE.value)
|
||||||
|
|
||||||
|
fun filterStarted() = preferenceStore.getInt("pref_filter_library_started", ExtendedNavigationView.Item.TriStateGroup.State.IGNORE.value)
|
||||||
|
|
||||||
|
fun filterBookmarked() = preferenceStore.getInt("pref_filter_library_bookmarked", ExtendedNavigationView.Item.TriStateGroup.State.IGNORE.value)
|
||||||
|
|
||||||
|
fun filterCompleted() = preferenceStore.getInt("pref_filter_library_completed", ExtendedNavigationView.Item.TriStateGroup.State.IGNORE.value)
|
||||||
|
|
||||||
|
// SY -->
|
||||||
|
fun filterLewd() = preferenceStore.getInt("pref_filter_library_lewd", ExtendedNavigationView.Item.TriStateGroup.State.IGNORE.value)
|
||||||
|
// SY <--
|
||||||
|
|
||||||
|
fun filterTracking(name: Int) = preferenceStore.getInt("pref_filter_library_tracked_$name", ExtendedNavigationView.Item.TriStateGroup.State.IGNORE.value)
|
||||||
|
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
// region Badges
|
||||||
|
|
||||||
|
fun downloadBadge() = preferenceStore.getBoolean("display_download_badge", false)
|
||||||
|
|
||||||
|
fun localBadge() = preferenceStore.getBoolean("display_local_badge", true)
|
||||||
|
|
||||||
|
fun languageBadge() = preferenceStore.getBoolean("display_language_badge", false)
|
||||||
|
|
||||||
|
fun newShowUpdatesCount() = preferenceStore.getBoolean("library_show_updates_count", true)
|
||||||
|
fun newUpdatesCount() = preferenceStore.getInt("library_unseen_updates_count", 0)
|
||||||
|
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
// region Category
|
||||||
|
|
||||||
|
fun defaultCategory() = preferenceStore.getInt("default_category", -1)
|
||||||
|
|
||||||
|
fun lastUsedCategory() = preferenceStore.getInt("last_used_category", 0)
|
||||||
|
|
||||||
|
fun categoryTabs() = preferenceStore.getBoolean("display_category_tabs", true)
|
||||||
|
|
||||||
|
fun categoryNumberOfItems() = preferenceStore.getBoolean("display_number_of_items", false)
|
||||||
|
|
||||||
|
fun categorizedDisplaySettings() = preferenceStore.getBoolean("categorized_display", false)
|
||||||
|
|
||||||
|
fun libraryUpdateCategories() = preferenceStore.getStringSet("library_update_categories", emptySet())
|
||||||
|
|
||||||
|
fun libraryUpdateCategoriesExclude() = preferenceStore.getStringSet("library_update_categories_exclude", emptySet())
|
||||||
|
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
// region Chapter
|
||||||
|
|
||||||
|
fun filterChapterByRead() = preferenceStore.getLong("default_chapter_filter_by_read", Manga.SHOW_ALL)
|
||||||
|
|
||||||
|
fun filterChapterByDownloaded() = preferenceStore.getLong("default_chapter_filter_by_downloaded", Manga.SHOW_ALL)
|
||||||
|
|
||||||
|
fun filterChapterByBookmarked() = preferenceStore.getLong("default_chapter_filter_by_bookmarked", Manga.SHOW_ALL)
|
||||||
|
|
||||||
|
// and upload date
|
||||||
|
fun sortChapterBySourceOrNumber() = preferenceStore.getLong("default_chapter_sort_by_source_or_number", Manga.CHAPTER_SORTING_SOURCE)
|
||||||
|
|
||||||
|
fun displayChapterByNameOrNumber() = preferenceStore.getLong("default_chapter_display_by_name_or_number", Manga.CHAPTER_DISPLAY_NAME)
|
||||||
|
|
||||||
|
fun sortChapterByAscendingOrDescending() = preferenceStore.getLong("default_chapter_sort_by_ascending_or_descending", Manga.CHAPTER_SORT_DESC)
|
||||||
|
|
||||||
|
fun setChapterSettingsDefault(manga: Manga) {
|
||||||
|
filterChapterByRead().set(manga.unreadFilterRaw)
|
||||||
|
filterChapterByDownloaded().set(manga.downloadedFilterRaw)
|
||||||
|
filterChapterByBookmarked().set(manga.bookmarkedFilterRaw)
|
||||||
|
sortChapterBySourceOrNumber().set(manga.sorting)
|
||||||
|
displayChapterByNameOrNumber().set(manga.displayMode)
|
||||||
|
sortChapterByAscendingOrDescending().set(if (manga.sortDescending()) Manga.CHAPTER_SORT_DESC else Manga.CHAPTER_SORT_ASC)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun autoClearChapterCache() = preferenceStore.getBoolean("auto_clear_chapter_cache", false)
|
||||||
|
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
// SY -->
|
||||||
|
|
||||||
|
fun sortTagsForLibrary() = preferenceStore.getStringSet("sort_tags_for_library", mutableSetOf())
|
||||||
|
|
||||||
|
fun groupLibraryUpdateType() = preferenceStore.getEnum("group_library_update_type", GroupLibraryMode.GLOBAL)
|
||||||
|
|
||||||
|
fun groupLibraryBy() = preferenceStore.getInt("group_library_by", LibraryGroup.BY_DEFAULT)
|
||||||
|
|
||||||
|
// SY <--
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
package eu.kanade.domain.manga.interactor
|
package eu.kanade.domain.manga.interactor
|
||||||
|
|
||||||
import tachiyomi.core.common.preference.plusAssign
|
import eu.kanade.domain.library.service.LibraryPreferences
|
||||||
import tachiyomi.domain.library.service.LibraryPreferences
|
import eu.kanade.tachiyomi.util.preference.plusAssign
|
||||||
|
|
||||||
class CreateSortTag(
|
class CreateSortTag(
|
||||||
private val preferences: LibraryPreferences,
|
private val preferences: LibraryPreferences,
|
||||||
@ -23,8 +23,8 @@ class CreateSortTag(
|
|||||||
}
|
}
|
||||||
|
|
||||||
sealed class Result {
|
sealed class Result {
|
||||||
data object TagExists : Result()
|
object TagExists : Result()
|
||||||
data object Success : Result()
|
object Success : Result()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package tachiyomi.domain.manga.interactor
|
package eu.kanade.domain.manga.interactor
|
||||||
|
|
||||||
import tachiyomi.domain.manga.repository.MangaMergeRepository
|
import tachiyomi.domain.manga.repository.MangaMergeRepository
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package tachiyomi.domain.manga.interactor
|
package eu.kanade.domain.manga.interactor
|
||||||
|
|
||||||
import tachiyomi.domain.manga.repository.FavoritesEntryRepository
|
import tachiyomi.domain.manga.repository.FavoritesEntryRepository
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package tachiyomi.domain.manga.interactor
|
package eu.kanade.domain.manga.interactor
|
||||||
|
|
||||||
import tachiyomi.domain.manga.repository.MangaRepository
|
import tachiyomi.domain.manga.repository.MangaRepository
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package tachiyomi.domain.manga.interactor
|
package eu.kanade.domain.manga.interactor
|
||||||
|
|
||||||
import tachiyomi.domain.manga.repository.MangaMergeRepository
|
import tachiyomi.domain.manga.repository.MangaMergeRepository
|
||||||
|
|
@ -1,6 +1,6 @@
|
|||||||
package eu.kanade.domain.manga.interactor
|
package eu.kanade.domain.manga.interactor
|
||||||
|
|
||||||
import tachiyomi.domain.library.service.LibraryPreferences
|
import eu.kanade.domain.library.service.LibraryPreferences
|
||||||
|
|
||||||
class DeleteSortTag(
|
class DeleteSortTag(
|
||||||
private val preferences: LibraryPreferences,
|
private val preferences: LibraryPreferences,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package tachiyomi.domain.manga.interactor
|
package eu.kanade.domain.manga.interactor
|
||||||
|
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
import tachiyomi.domain.manga.repository.MangaRepository
|
import tachiyomi.domain.manga.repository.MangaRepository
|
@ -0,0 +1,13 @@
|
|||||||
|
package eu.kanade.domain.manga.interactor
|
||||||
|
|
||||||
|
import tachiyomi.domain.manga.model.Manga
|
||||||
|
import tachiyomi.domain.manga.repository.MangaRepository
|
||||||
|
|
||||||
|
class GetDuplicateLibraryManga(
|
||||||
|
private val mangaRepository: MangaRepository,
|
||||||
|
) {
|
||||||
|
|
||||||
|
suspend fun await(title: String): Manga? {
|
||||||
|
return mangaRepository.getDuplicateLibraryManga(title.lowercase())
|
||||||
|
}
|
||||||
|
}
|
@ -1,24 +0,0 @@
|
|||||||
package eu.kanade.domain.manga.interactor
|
|
||||||
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
|
||||||
import kotlinx.coroutines.flow.map
|
|
||||||
import tachiyomi.data.DatabaseHandler
|
|
||||||
|
|
||||||
class GetExcludedScanlators(
|
|
||||||
private val handler: DatabaseHandler,
|
|
||||||
) {
|
|
||||||
|
|
||||||
suspend fun await(mangaId: Long): Set<String> {
|
|
||||||
return handler.awaitList {
|
|
||||||
excluded_scanlatorsQueries.getExcludedScanlatorsByMangaId(mangaId)
|
|
||||||
}
|
|
||||||
.toSet()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun subscribe(mangaId: Long): Flow<Set<String>> {
|
|
||||||
return handler.subscribeToList {
|
|
||||||
excluded_scanlatorsQueries.getExcludedScanlatorsByMangaId(mangaId)
|
|
||||||
}
|
|
||||||
.map { it.toSet() }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,4 +1,4 @@
|
|||||||
package tachiyomi.domain.manga.interactor
|
package eu.kanade.domain.manga.interactor
|
||||||
|
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
import tachiyomi.domain.manga.repository.MangaMetadataRepository
|
import tachiyomi.domain.manga.repository.MangaMetadataRepository
|
@ -1,4 +1,4 @@
|
|||||||
package tachiyomi.domain.manga.interactor
|
package eu.kanade.domain.manga.interactor
|
||||||
|
|
||||||
import tachiyomi.domain.manga.model.FavoriteEntry
|
import tachiyomi.domain.manga.model.FavoriteEntry
|
||||||
import tachiyomi.domain.manga.repository.FavoritesEntryRepository
|
import tachiyomi.domain.manga.repository.FavoritesEntryRepository
|
@ -1,4 +1,4 @@
|
|||||||
package tachiyomi.domain.manga.interactor
|
package eu.kanade.domain.manga.interactor
|
||||||
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
@ -1,11 +1,11 @@
|
|||||||
package tachiyomi.domain.manga.interactor
|
package eu.kanade.domain.manga.interactor
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.source.online.MetadataSource
|
import eu.kanade.tachiyomi.source.online.MetadataSource
|
||||||
import exh.metadata.metadata.base.FlatMetadata
|
import exh.metadata.metadata.base.FlatMetadata
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
import tachiyomi.core.common.util.system.logcat
|
import tachiyomi.core.util.system.logcat
|
||||||
import tachiyomi.domain.manga.repository.MangaMetadataRepository
|
import tachiyomi.domain.manga.repository.MangaMetadataRepository
|
||||||
|
|
||||||
class GetFlatMetadataById(
|
class GetFlatMetadataById(
|
@ -1,4 +1,4 @@
|
|||||||
package tachiyomi.domain.manga.interactor
|
package eu.kanade.domain.manga.interactor
|
||||||
|
|
||||||
import tachiyomi.domain.manga.repository.MangaMetadataRepository
|
import tachiyomi.domain.manga.repository.MangaMetadataRepository
|
||||||
|
|
@ -1,14 +1,10 @@
|
|||||||
package tachiyomi.domain.manga.interactor
|
package eu.kanade.domain.manga.interactor
|
||||||
|
|
||||||
import kotlinx.coroutines.delay
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.catch
|
import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.coroutines.flow.retry
|
import kotlinx.coroutines.flow.retry
|
||||||
import logcat.LogPriority
|
|
||||||
import tachiyomi.core.common.util.system.logcat
|
|
||||||
import tachiyomi.domain.library.model.LibraryManga
|
import tachiyomi.domain.library.model.LibraryManga
|
||||||
import tachiyomi.domain.manga.repository.MangaRepository
|
import tachiyomi.domain.manga.repository.MangaRepository
|
||||||
import kotlin.time.Duration.Companion.seconds
|
|
||||||
|
|
||||||
class GetLibraryManga(
|
class GetLibraryManga(
|
||||||
private val mangaRepository: MangaRepository,
|
private val mangaRepository: MangaRepository,
|
||||||
@ -20,15 +16,15 @@ class GetLibraryManga(
|
|||||||
|
|
||||||
fun subscribe(): Flow<List<LibraryManga>> {
|
fun subscribe(): Flow<List<LibraryManga>> {
|
||||||
return mangaRepository.getLibraryMangaAsFlow()
|
return mangaRepository.getLibraryMangaAsFlow()
|
||||||
.retry {
|
// SY -->
|
||||||
if (it is NullPointerException) {
|
.let {
|
||||||
delay(0.5.seconds)
|
var retries = 0
|
||||||
true
|
it.retry {
|
||||||
} else {
|
(retries++ < 3) && it is NullPointerException
|
||||||
false
|
}.onEach {
|
||||||
}
|
retries = 0
|
||||||
}.catch {
|
|
||||||
this@GetLibraryManga.logcat(LogPriority.ERROR, it)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// SY <--
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,9 +1,9 @@
|
|||||||
package tachiyomi.domain.manga.interactor
|
package eu.kanade.domain.manga.interactor
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.source.online.MetadataSource
|
import eu.kanade.tachiyomi.source.online.MetadataSource
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
import tachiyomi.core.common.util.system.logcat
|
import tachiyomi.core.util.system.logcat
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
import tachiyomi.domain.manga.repository.MangaRepository
|
import tachiyomi.domain.manga.repository.MangaRepository
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package tachiyomi.domain.manga.interactor
|
package eu.kanade.domain.manga.interactor
|
||||||
|
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
import tachiyomi.domain.manga.repository.MangaRepository
|
import tachiyomi.domain.manga.repository.MangaRepository
|
@ -1,4 +1,4 @@
|
|||||||
package tachiyomi.domain.manga.interactor
|
package eu.kanade.domain.manga.interactor
|
||||||
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
@ -12,10 +12,10 @@ class GetMangaWithChapters(
|
|||||||
private val chapterRepository: ChapterRepository,
|
private val chapterRepository: ChapterRepository,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
suspend fun subscribe(id: Long, applyScanlatorFilter: Boolean = false): Flow<Pair<Manga, List<Chapter>>> {
|
suspend fun subscribe(id: Long): Flow<Pair<Manga, List<Chapter>>> {
|
||||||
return combine(
|
return combine(
|
||||||
mangaRepository.getMangaByIdAsFlow(id),
|
mangaRepository.getMangaByIdAsFlow(id),
|
||||||
chapterRepository.getChapterByMangaIdAsFlow(id, applyScanlatorFilter),
|
chapterRepository.getChapterByMangaIdAsFlow(id),
|
||||||
) { manga, chapters ->
|
) { manga, chapters ->
|
||||||
Pair(manga, chapters)
|
Pair(manga, chapters)
|
||||||
}
|
}
|
||||||
@ -25,7 +25,7 @@ class GetMangaWithChapters(
|
|||||||
return mangaRepository.getMangaById(id)
|
return mangaRepository.getMangaById(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun awaitChapters(id: Long, applyScanlatorFilter: Boolean = false): List<Chapter> {
|
suspend fun awaitChapters(id: Long): List<Chapter> {
|
||||||
return chapterRepository.getChapterByMangaId(id, applyScanlatorFilter)
|
return chapterRepository.getChapterByMangaId(id)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,8 +1,8 @@
|
|||||||
package tachiyomi.domain.manga.interactor
|
package eu.kanade.domain.manga.interactor
|
||||||
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
import tachiyomi.core.common.util.system.logcat
|
import tachiyomi.core.util.system.logcat
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
import tachiyomi.domain.manga.repository.MangaMergeRepository
|
import tachiyomi.domain.manga.repository.MangaMergeRepository
|
||||||
|
|
@ -1,8 +1,8 @@
|
|||||||
package tachiyomi.domain.manga.interactor
|
package eu.kanade.domain.manga.interactor
|
||||||
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
import tachiyomi.core.common.util.system.logcat
|
import tachiyomi.core.util.system.logcat
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
import tachiyomi.domain.manga.repository.MangaMergeRepository
|
import tachiyomi.domain.manga.repository.MangaMergeRepository
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package tachiyomi.domain.manga.interactor
|
package eu.kanade.domain.manga.interactor
|
||||||
|
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
import tachiyomi.domain.manga.repository.MangaMergeRepository
|
import tachiyomi.domain.manga.repository.MangaMergeRepository
|
@ -1,8 +1,8 @@
|
|||||||
package tachiyomi.domain.manga.interactor
|
package eu.kanade.domain.manga.interactor
|
||||||
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
import tachiyomi.core.common.util.system.logcat
|
import tachiyomi.core.util.system.logcat
|
||||||
import tachiyomi.domain.manga.model.MergedMangaReference
|
import tachiyomi.domain.manga.model.MergedMangaReference
|
||||||
import tachiyomi.domain.manga.repository.MangaMergeRepository
|
import tachiyomi.domain.manga.repository.MangaMergeRepository
|
||||||
|
|
@ -1,5 +1,6 @@
|
|||||||
package eu.kanade.domain.manga.interactor
|
package eu.kanade.domain.manga.interactor
|
||||||
|
|
||||||
|
import eu.kanade.domain.chapter.interactor.GetChapterByMangaId
|
||||||
import eu.kanade.domain.chapter.model.toSChapter
|
import eu.kanade.domain.chapter.model.toSChapter
|
||||||
import eu.kanade.domain.manga.model.PagePreview
|
import eu.kanade.domain.manga.model.PagePreview
|
||||||
import eu.kanade.domain.manga.model.toSManga
|
import eu.kanade.domain.manga.model.toSManga
|
||||||
@ -7,23 +8,22 @@ import eu.kanade.tachiyomi.data.cache.PagePreviewCache
|
|||||||
import eu.kanade.tachiyomi.source.PagePreviewSource
|
import eu.kanade.tachiyomi.source.PagePreviewSource
|
||||||
import eu.kanade.tachiyomi.source.Source
|
import eu.kanade.tachiyomi.source.Source
|
||||||
import exh.source.getMainSource
|
import exh.source.getMainSource
|
||||||
import tachiyomi.domain.chapter.interactor.GetChaptersByMangaId
|
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
|
|
||||||
class GetPagePreviews(
|
class GetPagePreviews(
|
||||||
private val pagePreviewCache: PagePreviewCache,
|
private val pagePreviewCache: PagePreviewCache,
|
||||||
private val getChaptersByMangaId: GetChaptersByMangaId,
|
private val getChapters: GetChapterByMangaId,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
suspend fun await(manga: Manga, source: Source, page: Int): Result {
|
suspend fun await(manga: Manga, source: Source, page: Int): Result {
|
||||||
@Suppress("NAME_SHADOWING")
|
@Suppress("NAME_SHADOWING")
|
||||||
val source = source.getMainSource<PagePreviewSource>() ?: return Result.Unused
|
val source = source.getMainSource<PagePreviewSource>() ?: return Result.Unused
|
||||||
val chapters = getChaptersByMangaId.await(manga.id).sortedByDescending { it.sourceOrder }
|
val chapters = getChapters.await(manga.id).sortedByDescending { it.sourceOrder }
|
||||||
val chapterIds = chapters.map { it.id }
|
val chapterIds = chapters.map { it.id }
|
||||||
return try {
|
return try {
|
||||||
val pagePreviews = try {
|
val pagePreviews = try {
|
||||||
pagePreviewCache.getPageListFromCache(manga, chapterIds, page)
|
pagePreviewCache.getPageListFromCache(manga, chapterIds, page)
|
||||||
} catch (_: Exception) {
|
} catch (e: Exception) {
|
||||||
source.getPagePreviewList(manga.toSManga(), chapters.map { it.toSChapter() }, page).also {
|
source.getPagePreviewList(manga.toSManga(), chapters.map { it.toSChapter() }, page).also {
|
||||||
pagePreviewCache.putPageListToCache(manga, chapterIds, it)
|
pagePreviewCache.putPageListToCache(manga, chapterIds, it)
|
||||||
}
|
}
|
||||||
@ -41,7 +41,7 @@ class GetPagePreviews(
|
|||||||
}
|
}
|
||||||
|
|
||||||
sealed class Result {
|
sealed class Result {
|
||||||
data object Unused : Result()
|
object Unused : Result()
|
||||||
data class Success(
|
data class Success(
|
||||||
val pagePreviews: List<PagePreview>,
|
val pagePreviews: List<PagePreview>,
|
||||||
val hasNextPage: Boolean,
|
val hasNextPage: Boolean,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package tachiyomi.domain.manga.interactor
|
package eu.kanade.domain.manga.interactor
|
||||||
|
|
||||||
import exh.metadata.sql.models.SearchMetadata
|
import exh.metadata.sql.models.SearchMetadata
|
||||||
import tachiyomi.domain.manga.repository.MangaMetadataRepository
|
import tachiyomi.domain.manga.repository.MangaMetadataRepository
|
@ -1,4 +1,4 @@
|
|||||||
package tachiyomi.domain.manga.interactor
|
package eu.kanade.domain.manga.interactor
|
||||||
|
|
||||||
import exh.metadata.sql.models.SearchTag
|
import exh.metadata.sql.models.SearchTag
|
||||||
import tachiyomi.domain.manga.repository.MangaMetadataRepository
|
import tachiyomi.domain.manga.repository.MangaMetadataRepository
|
@ -1,4 +1,4 @@
|
|||||||
package tachiyomi.domain.manga.interactor
|
package eu.kanade.domain.manga.interactor
|
||||||
|
|
||||||
import exh.metadata.sql.models.SearchTitle
|
import exh.metadata.sql.models.SearchTitle
|
||||||
import tachiyomi.domain.manga.repository.MangaMetadataRepository
|
import tachiyomi.domain.manga.repository.MangaMetadataRepository
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user