mirror of
https://github.com/mihonapp/mihon.git
synced 2025-07-15 20:23:18 +02:00
Compare commits
47 Commits
dae7a00b41
...
v0.17.0
Author | SHA1 | Date | |
---|---|---|---|
38d5fc9160 | |||
9454fe4482 | |||
6de06419f8 | |||
fc2f339ea1 | |||
264030d6ec | |||
140083ee39 | |||
2bf7ef5d18 | |||
df9fff60da | |||
aae0e3459c | |||
f7752a98b2 | |||
2ba7ed3280 | |||
c153ac01f5 | |||
47b0e9d7be | |||
d4bf19f957 | |||
01b44c0458 | |||
e1e3ca7a56 | |||
78d2cc75d5 | |||
c550a81598 | |||
0be36a10c3 | |||
e16c3953c7 | |||
f3a2f566c8 | |||
15e3f28aa3 | |||
3bf70b230f | |||
eb3bea8150 | |||
5612ae0149 | |||
dbf6ad2ca7 | |||
d2afbfe4ed | |||
337806d9e1 | |||
443f6e0ae5 | |||
572ee2f02a | |||
ba1343bed8 | |||
9f3d5d13d4 | |||
48166b9b52 | |||
2e2c8d36c1 | |||
788235feec | |||
afa5002988 | |||
9503082d44 | |||
de36357da8 | |||
eb6092bd0c | |||
32d2c2ac1b | |||
4051f180a2 | |||
3ed8a91c7b | |||
87db3f90de | |||
0a4ad89b99 | |||
a72db41bf1 | |||
6b2bba4e54 | |||
7c7af72f8c |
4
.github/ISSUE_TEMPLATE/report_issue.yml
vendored
4
.github/ISSUE_TEMPLATE/report_issue.yml
vendored
@ -53,7 +53,7 @@ body:
|
||||
label: Mihon version
|
||||
description: You can find your Mihon version in **More → About**.
|
||||
placeholder: |
|
||||
Example: "0.16.5"
|
||||
Example: "0.17.0"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
@ -96,7 +96,7 @@ body:
|
||||
required: true
|
||||
- label: I have gone through the [FAQ](https://mihon.app/docs/faq/general) and [troubleshooting guide](https://mihon.app/docs/guides/troubleshooting/).
|
||||
required: true
|
||||
- label: I have updated the app to version **[0.16.5](https://github.com/mihonapp/mihon/releases/latest)**.
|
||||
- label: I have updated the app to version **[0.17.0](https://github.com/mihonapp/mihon/releases/latest)**.
|
||||
required: true
|
||||
- label: I have updated all installed extensions.
|
||||
required: true
|
||||
|
2
.github/ISSUE_TEMPLATE/request_feature.yml
vendored
2
.github/ISSUE_TEMPLATE/request_feature.yml
vendored
@ -31,7 +31,7 @@ body:
|
||||
required: true
|
||||
- label: I have written a short but informative title.
|
||||
required: true
|
||||
- label: I have updated the app to version **[0.16.5](https://github.com/mihonapp/mihon/releases/latest)**.
|
||||
- label: I have updated the app to version **[0.17.0](https://github.com/mihonapp/mihon/releases/latest)**.
|
||||
required: true
|
||||
- label: I will fill out all of the requested information in this form.
|
||||
required: true
|
||||
|
9
.github/renovate.json5
vendored
9
.github/renovate.json5
vendored
@ -2,5 +2,12 @@
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": ["config:base"],
|
||||
"labels": ["Dependencies"],
|
||||
"semanticCommits": "disabled"
|
||||
"semanticCommits": "disabled",
|
||||
"packageRules": [
|
||||
{
|
||||
"groupName": "GitHub Actions",
|
||||
"matchManagers": ["github-actions"],
|
||||
"pinDigests": true,
|
||||
}
|
||||
]
|
||||
}
|
||||
|
21
.github/workflows/build_pull_request.yml
vendored
21
.github/workflows/build_pull_request.yml
vendored
@ -1,10 +1,13 @@
|
||||
name: PR build check
|
||||
on:
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
- 'i18n/src/commonMain/moko-resources/**/strings.xml'
|
||||
- 'i18n/src/commonMain/moko-resources/**/plurals.xml'
|
||||
paths:
|
||||
- '**'
|
||||
- '!**.md'
|
||||
- '!i18n/src/commonMain/moko-resources/**/strings.xml'
|
||||
- '!i18n/src/commonMain/moko-resources/**/plurals.xml'
|
||||
- 'i18n/src/commonMain/moko-resources/base/strings.xml'
|
||||
- 'i18n/src/commonMain/moko-resources/base/plurals.xml'
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
|
||||
@ -20,16 +23,16 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Clone repo
|
||||
uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- name: Validate Gradle Wrapper
|
||||
uses: gradle/actions/wrapper-validation@d156388eb19639ec20ade50009f3d199ce1e2808 # v4.1.0
|
||||
|
||||
- name: Dependency Review
|
||||
uses: actions/dependency-review-action@5a2ce3f5b92ee19cbb1541a4984c76d921601d7c # v4.3.4
|
||||
uses: actions/dependency-review-action@a6993e2c61fd5dc440b409aa1d6904921c5e1894 # v4.3.5
|
||||
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@b36c23c0d998641eff861008f374ee103c25ac73 # v4.4.0
|
||||
uses: actions/setup-java@8df1039502a15bceb9433410b1a100fbe190c53b # v4.5.0
|
||||
with:
|
||||
java-version: 17
|
||||
distribution: adopt
|
||||
@ -41,13 +44,13 @@ jobs:
|
||||
run: ./gradlew spotlessCheck assembleStandardRelease testReleaseUnitTest testStandardReleaseUnitTest
|
||||
|
||||
- name: Upload APK
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
|
||||
with:
|
||||
name: arm64-v8a-${{ github.sha }}
|
||||
path: app/build/outputs/apk/standard/release/app-standard-arm64-v8a-release-unsigned.apk
|
||||
|
||||
- name: Upload mapping
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
|
||||
with:
|
||||
name: mapping-${{ github.sha }}
|
||||
path: app/build/outputs/mapping/standardRelease
|
||||
|
8
.github/workflows/build_push.yml
vendored
8
.github/workflows/build_push.yml
vendored
@ -17,7 +17,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Clone repo
|
||||
uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- name: Validate Gradle Wrapper
|
||||
uses: gradle/actions/wrapper-validation@d156388eb19639ec20ade50009f3d199ce1e2808 # v4.1.0
|
||||
@ -27,7 +27,7 @@ jobs:
|
||||
${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin/sdkmanager "build-tools;29.0.3"
|
||||
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@b36c23c0d998641eff861008f374ee103c25ac73 # v4.4.0
|
||||
uses: actions/setup-java@8df1039502a15bceb9433410b1a100fbe190c53b # v4.5.0
|
||||
with:
|
||||
java-version: 17
|
||||
distribution: adopt
|
||||
@ -39,13 +39,13 @@ jobs:
|
||||
run: ./gradlew spotlessCheck assembleStandardRelease testReleaseUnitTest testStandardReleaseUnitTest
|
||||
|
||||
- name: Upload APK
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
|
||||
with:
|
||||
name: arm64-v8a-${{ github.sha }}
|
||||
path: app/build/outputs/apk/standard/release/app-standard-arm64-v8a-release-unsigned.apk
|
||||
|
||||
- name: Upload mapping
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
|
||||
with:
|
||||
name: mapping-${{ github.sha }}
|
||||
path: app/build/outputs/mapping/standardRelease
|
||||
|
22
.gitignore
vendored
22
.gitignore
vendored
@ -1,18 +1,16 @@
|
||||
# Build files
|
||||
.gradle
|
||||
.kotlin
|
||||
/local.properties
|
||||
/.idea/workspace.xml
|
||||
.DS_Store
|
||||
build
|
||||
|
||||
# IDE files
|
||||
*.iml
|
||||
.idea/*
|
||||
!.idea/icon.png
|
||||
*iml
|
||||
*.iml
|
||||
/captures
|
||||
|
||||
# Built files
|
||||
*/build
|
||||
/build
|
||||
*.apk
|
||||
app/**/output.json
|
||||
# Configuration files
|
||||
local.properties
|
||||
|
||||
# Unnecessary file
|
||||
*.swp
|
||||
# macOS specific files
|
||||
.DS_Store
|
||||
|
232
CHANGELOG.md
232
CHANGELOG.md
@ -2,133 +2,267 @@
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
The format is a modified version of [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
- `Added` - for new features.
|
||||
- `Changed ` - for changes in existing functionality.
|
||||
- `Improved` - for enhancement or optimization in existing functionality.
|
||||
- `Removed` - for now removed features.
|
||||
- `Fixed` - for any bug fixes.
|
||||
- `Other` - for technical stuff.
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [v0.17.0] - 2024-10-26
|
||||
### Added
|
||||
- Option to disable reader zoom out ([@Splintorien](https://github.com/Splintorien)) ([#302](https://github.com/mihonapp/mihon/pull/302))
|
||||
- Source name and tracker urls to app generated `ComicInfo.xml` file ([@Shamicen](https://github.com/Shamicen)) ([#459](https://github.com/mihonapp/mihon/pull/459))
|
||||
- Option to migrate in Duplicate entry dialog ([@sirlag](https://github.com/sirlag)) ([#492](https://github.com/mihonapp/mihon/pull/492))
|
||||
- Upcoming screen to visualize expected update dates ([@sirlag](https://github.com/sirlag)) ([#420](https://github.com/mihonapp/mihon/pull/420))
|
||||
- Only show upcoming updates in the future ([@sirlag](https://github.com/sirlag)) ([#606](https://github.com/mihonapp/mihon/pull/606))
|
||||
- Add Quantity Badge to Upcoming Screen ([@Animeboynz](https://github.com/Animeboynz), [@AntsyLich](https://github.com/AntsyLich)) ([#1250](https://github.com/mihonapp/mihon/pull/1250))
|
||||
- Crash screen error message to the top of the crash log generated from that screen ([@FooIbar](https://github.com/FooIbar)) ([#742](https://github.com/mihonapp/mihon/pull/742))
|
||||
- Support for 7Zip and RAR5 archives ([@FooIbar](https://github.com/FooIbar), [@null2264](https://github.com/null2264)) ([#949](https://github.com/mihonapp/mihon/pull/949), [#967](https://github.com/mihonapp/mihon/pull/967))
|
||||
- Support for 7Zip and RAR5 archives ([@FooIbar](https://github.com/FooIbar)) ([#949](https://github.com/mihonapp/mihon/pull/949))
|
||||
- Extra configuration options to e-ink page flashes ([@sirlag](https://github.com/sirlag)) ([#625](https://github.com/mihonapp/mihon/pull/625))
|
||||
- 8-bit+ AVIF image support ([@WerctFourth](https://github.com/WerctFourth)) ([#971](https://github.com/mihonapp/mihon/pull/971))
|
||||
- Smart update dialog message when no predicted released date exists ([@Animeboynz](https://github.com/Animeboynz)) ([#977](https://github.com/mihonapp/mihon/pull/977))
|
||||
- Save global search "Has result" choice ([@AntsyLich](https://github.com/AntsyLich)) ([`5a61ca5`](https://github.com/mihonapp/mihon/commit/5a61ca5535fe0d9e8e7bcb9e665ba2f9cb0cf649))
|
||||
- Option to copy reader panel to clipboard ([@Animeboynz](https://github.com/Animeboynz)) ([#1003](https://github.com/mihonapp/mihon/pull/1003))
|
||||
- Copy Tracker URL option to tracker sheet ([@mm12](https://github.com/mm12)) ([#1101](https://github.com/mihonapp/mihon/pull/1101))
|
||||
- A button to exclude all scanlators in exclude scanlators dialog ([@AntsyLich](https://github.com/AntsyLich)) ([`84b2164`](https://github.com/mihonapp/mihon/commit/84b2164787a795f3fd757c325cbfb6ef660ac3a3))
|
||||
- Open in browser option to reader menu ([@mm12](https://github.com/mm12)) ([#1110](https://github.com/mihonapp/mihon/pull/1110))
|
||||
- Reorder reader menu overflow items ([@AntsyLich](https://github.com/AntsyLich)) ([`788235f`](https://github.com/mihonapp/mihon/commit/788235feeca241228eac0561339dd07b5ea0b77d))
|
||||
- Option to skip downloading duplicate read chapters ([@shabnix](https://github.com/shabnix)) ([#1125](https://github.com/mihonapp/mihon/pull/1125))
|
||||
- Add confirmation dialog when adding repo via URI ([@Animeboynz](https://github.com/Animeboynz)) ([#1158](https://github.com/mihonapp/mihon/pull/1158))
|
||||
- Add "show entry" action to download notifications ([@mm12](https://github.com/mm12), [@AntsyLich](https://github.com/AntsyLich)) ([#1159](https://github.com/mihonapp/mihon/pull/1159))
|
||||
- Option to update trackers when chapter marked as read ([@Animeboynz](https://github.com/Animeboynz), [@AntsyLich](https://github.com/AntsyLich)) ([#1177](https://github.com/mihonapp/mihon/pull/1177), [#1365](https://github.com/mihonapp/mihon/pull/1365), [#1374](https://github.com/mihonapp/mihon/pull/1374))
|
||||
- Toast to restart app when User-Agent is changed ([@NGB-Was-Taken](https://github.com/NGB-Was-Taken)) ([#1204](https://github.com/mihonapp/mihon/pull/1204))
|
||||
- Added more profile compilation status (p) ([`c8bb78d`](https://github.com/mihonapp/mihon/commit/c8bb78d91afc2824baaca999f0095559c49d1306))
|
||||
- Add option to opt out of Analytics and Crashlytics ([@Animeboynz](https://github.com/Animeboynz)) ([#1237](https://github.com/mihonapp/mihon/pull/1237))
|
||||
- Rework Firebase setup ([@AntsyLich](https://github.com/AntsyLich)) ([`15e3f28`](https://github.com/mihonapp/mihon/commit/15e3f28aa36bec3c31f212c572ab57ce960cc862))
|
||||
- Added random library sort ([@jackhamilton](https://github.com/jackhamilton)) ([#1317](https://github.com/mihonapp/mihon/pull/1317))
|
||||
- Make sure random library sort is at the bottom ([@AntsyLich](https://github.com/AntsyLich)) ([`2e2c8d3`](https://github.com/mihonapp/mihon/commit/2e2c8d36c1e23bf274c7c19f1242e14b0c7afbc1))
|
||||
- Confirmation dialog when removing privately installed extensions ([@Animeboynz](https://github.com/Animeboynz), [@AntsyLich](https://github.com/AntsyLich)) ([#1320](https://github.com/mihonapp/mihon/pull/1320))
|
||||
- Option to backup non-library read entries ([@Animeboynz](https://github.com/Animeboynz), [@jobobby04](https://github.com/jobobby04), [@AntsyLich](https://github.com/AntsyLich)) ([#1324](https://github.com/mihonapp/mihon/pull/1324))
|
||||
|
||||
### Changed
|
||||
- Read archive files from memory instead of extracting files to internal storage ([@FooIbar](https://github.com/FooIbar)) ([#326](https://github.com/mihonapp/mihon/pull/326))
|
||||
- Try to get resource from Extension before checking in the app ([@beer-psi](https://github.com/beer-psi)) ([#433](https://github.com/mihonapp/mihon/pull/433))
|
||||
- Default user agent ([@AntsyLich](https://github.com/AntsyLich)) ([`8160b47`](https://github.com/mihonapp/mihon/commit/8160b47ff5fbbd9b32caeb462b5be881fabd3449))
|
||||
- Read archive files from memory instead of temporarily extracting to internal storage ([@FooIbar](https://github.com/FooIbar)) ([#326](https://github.com/mihonapp/mihon/pull/326))
|
||||
- Fix dual page split ([@FooIbar](https://github.com/FooIbar)) ([#485](https://github.com/mihonapp/mihon/pull/485))
|
||||
- Bump default user agent ([@AntsyLich](https://github.com/AntsyLich)) ([`8160b47`](https://github.com/mihonapp/mihon/commit/8160b47ff5fbbd9b32caeb462b5be881fabd3449))
|
||||
- Wait for sources to be initialized before performing source related tasks ([@jobobby04](https://github.com/jobobby04)) ([`a08e03f`](https://github.com/mihonapp/mihon/commit/a08e03f5cbf3f4e6be1de35f97ef8ebb26a1210e))
|
||||
- Duplicate entry dialog UI ([@sirlag](https://github.com/sirlag)) ([#492](https://github.com/mihonapp/mihon/pull/492))
|
||||
- Extension trust system ([@AntsyLich](https://github.com/AntsyLich), [@Animeboynz](https://github.com/Animeboynz) ([#570](https://github.com/mihonapp/mihon/pull/570), [#1057](https://github.com/mihonapp/mihon/pull/1057))
|
||||
- Extension trust system
|
||||
- Store extension repo details from `repo.json` in database ([@sirlag](https://github.com/sirlag)) ([#506](https://github.com/mihonapp/mihon/pull/506))
|
||||
- Fix extension repo migration not triggering ([@AntsyLich](https://github.com/AntsyLich)) ([`9672ea8`](https://github.com/mihonapp/mihon/commit/9672ea8b1b06f464800e310c96e060ead182f7ca))
|
||||
- Refactor the ExtensionRepoService to use DTOs ([@MajorTanya](https://github.com/MajorTanya)) ([#573](https://github.com/mihonapp/mihon/pull/573))
|
||||
- Fix extension repo name is used to construct URL instead of baseUrl ([@MajorTanya](https://github.com/MajorTanya)) ([#572](https://github.com/mihonapp/mihon/pull/572))
|
||||
- Fix crash with `TypeReference` issue when creating extension repo ([@AntsyLich](https://github.com/AntsyLich)) ([#574](https://github.com/mihonapp/mihon/pull/574), [`e020ae5`](https://github.com/mihonapp/mihon/commit/e020ae5ed558e80742ef0ad8bfa0f69af0959d5a))
|
||||
- Fix mishap in [`e020ae5`](https://github.com/mihonapp/mihon/commit/e020ae5ed558e80742ef0ad8bfa0f69af0959d5a) ([@AntsyLich](https://github.com/AntsyLich)) ([`6965e59`](https://github.com/mihonapp/mihon/commit/6965e59a643c67a2bf81b3c69ec70268e5da5797))
|
||||
- Backup and Restore ([@Animeboynz](https://github.com/Animeboynz)) ([#1057](https://github.com/mihonapp/mihon/pull/1057))
|
||||
- Trust extension by repo ([@AntsyLich](https://github.com/AntsyLich)) ([#570](https://github.com/mihonapp/mihon/pull/570))-
|
||||
- From M2 ripple to M3 ([@FooIbar](https://github.com/FooIbar)) ([#675](https://github.com/mihonapp/mihon/pull/675))
|
||||
- Increased continue reading button size ([@AntsyLich](https://github.com/AntsyLich), [@Animeboynz](https://github.com/Animeboynz)) ([`e17f70f`](https://github.com/mihonapp/mihon/commit/e17f70f7226ea031fc1f962c9dfea3e404ba53ad))
|
||||
- Global search "Has result" choice is now sticky ([@AntsyLich](https://github.com/AntsyLich)) ([`5a61ca5`](https://github.com/mihonapp/mihon/commit/5a61ca5535fe0d9e8e7bcb9e665ba2f9cb0cf649))
|
||||
- Make category backup/restore not dependant on library backup ([@AntsyLich](https://github.com/AntsyLich)) ([`56fb4f6`](https://github.com/mihonapp/mihon/commit/56fb4f62a152e87a71892aa68c78cac51a2c8596))
|
||||
- Rename backup restore error log file ([@AntsyLich](https://github.com/AntsyLich)) ([`2858ef8`](https://github.com/mihonapp/mihon/commit/2858ef835fec8d7278b1d0cad1b5664104d1e4b0))
|
||||
- Keyboard type in add extension repo dialog ([@xbjfk](https://github.com/xbjfk)) ([#764](https://github.com/mihonapp/mihon/pull/764))
|
||||
- Adjust collapse/open animation on manga description ([@AntsyLich](https://github.com/AntsyLich), [@ivaniskandar](https://github.com/ivaniskandar)) ([`1c16fc7`](https://github.com/mihonapp/mihon/commit/1c16fc79c2ac4c4be30308fed84ffb371dab5902))
|
||||
- Kitsu domain to `kitsu.app` ([@MajorTanya](https://github.com/MajorTanya)) ([#1106](https://github.com/mihonapp/mihon/pull/1106))
|
||||
- Respect privacy settings in extension update notification ([@Animeboynz](https://github.com/Animeboynz)) ([#1156](https://github.com/mihonapp/mihon/pull/1156))
|
||||
- Hide keyboard when a Tracker SearchResultItem is clicked ([@Animeboynz](https://github.com/Animeboynz)) ([#1168](https://github.com/mihonapp/mihon/pull/1168))
|
||||
- Enable 'Split Tall Images' by default ([@Smol-Ame](https://github.com/Smol-Ame)) ([#1185](https://github.com/mihonapp/mihon/pull/1185))
|
||||
- Ignore "intent://" urls on webview ([@bapeey](https://github.com/bapeey)) ([#1193](https://github.com/mihonapp/mihon/pull/1193))
|
||||
- Make reader chapter navigator slightly wider on small screens (p) ([#1202](https://github.com/mihonapp/mihon/pull/1202))
|
||||
- Re-enable fetching chapters list for entries with licenced status ([@Animeboynz](https://github.com/Animeboynz)) ([#1230](https://github.com/mihonapp/mihon/pull/1230))
|
||||
- Change casing for Extention Repos String ([@Animeboynz](https://github.com/Animeboynz)) ([#1248](https://github.com/mihonapp/mihon/pull/1248))
|
||||
- Retain remote last chapter read if it's higher than the local one for EnhancedTracker ([@brewkunz](https://github.com/brewkunz)) ([#1301](https://github.com/mihonapp/mihon/pull/1301))
|
||||
- Adjust expandable fab animation (p) ([`eb6092b`](https://github.com/mihonapp/mihon/commit/eb6092bd0cfa09694985a8bafdd8bbf2815190a1))
|
||||
- "Invalidate downloads index" to "Reindex downloads" ([@AntsyLich](https://github.com/AntsyLich)) ([`d2afbfe`](https://github.com/mihonapp/mihon/commit/d2afbfe4ede283076aae40633c79c3f90b4390e7))
|
||||
|
||||
### Improvement
|
||||
- Long strip reader performance ([@FooIbar](https://github.com/FooIbar), [@wwww-wwww](https://github.com/wwww-wwww)) ([#687](https://github.com/mihonapp/mihon/pull/687))
|
||||
### Improved
|
||||
- Reader performance
|
||||
- Avoid unnecessary copying when processing reader image ([@FooIbar](https://github.com/FooIbar)) ([#691](https://github.com/mihonapp/mihon/pull/691))
|
||||
- Significantly improve performance when loading extremely long images in long strip mode ([@FooIbar](https://github.com/FooIbar)) ([#692](https://github.com/mihonapp/mihon/pull/692))
|
||||
- Use `Bitmap.Config.HARDWARE` if possible to improve image loading speed ([@wwww-wwww](https://github.com/wwww-wwww)) ([#687](https://github.com/mihonapp/mihon/pull/687))
|
||||
- Improve preloading in long strip mode ([@FooIbar](https://github.com/FooIbar)) ([#1076](https://github.com/mihonapp/mihon/pull/1076))
|
||||
- Performance when looking up specific files ([@raxod502](https://github.com/raxod502)) ([#728](https://github.com/mihonapp/mihon/pull/728))
|
||||
- Chapter number parsing ([@Naputt1](https://github.com/Naputt1)) ([`6a80305`](https://github.com/mihonapp/mihon/commit/6a80305d6c572da6c08c0c69f5c25ff26ecf7383))
|
||||
- Error message on restoring if backup decoding fails ([@vetleledaal](https://github.com/vetleledaal)) ([#1056](https://github.com/mihonapp/mihon/pull/1056))
|
||||
|
||||
### Removed
|
||||
- Legacy download folder names no longer supported ([@AntsyLich](https://github.com/AntsyLich)) ([`e55e5f6`](https://github.com/mihonapp/mihon/commit/e55e5f6f64f872475d370d6ce0c186e2601776e4))
|
||||
- Remove legacy broken source and history backup ([@AntsyLich](https://github.com/AntsyLich)) ([`518abf0`](https://github.com/mihonapp/mihon/commit/518abf032ccb9bb45d197927be2a5faca4167d29))
|
||||
- Remove more unnecessary permissions from Firebase dependency ([@AntsyLich](https://github.com/AntsyLich)) ([`02af9b1`](https://github.com/mihonapp/mihon/commit/02af9b1acf9f590d29560bc3fc90d206e8e6e1af))
|
||||
- Fix mishap in `02af9b1` ([@AntsyLich](https://github.com/AntsyLich)) ([`f22767d`](https://github.com/mihonapp/mihon/commit/f22767d863a0fa001f93f24092cd5ade87350502))
|
||||
|
||||
### Fixed
|
||||
- Creating `ComicInfo.xml` file for local source ([@FooIbar](https://github.com/FooIbar)) ([#325](https://github.com/mihonapp/mihon/pull/325))
|
||||
- Extracting `ComicInfo.xml` from local source archives ([@FooIbar](https://github.com/FooIbar)) ([#325](https://github.com/mihonapp/mihon/pull/325))
|
||||
- Chapter download indicator ([@ivaniskandar](https://github.com/ivaniskandar)) ([`d8b9a9f`](https://github.com/mihonapp/mihon/commit/d8b9a9f593911569ff2bceb49b4f020978d0d2e1))
|
||||
- Issues with shizuku in a multi user setup ([@Redjard](https://github.com/Redjard)) ([#494](https://github.com/mihonapp/mihon/pull/494))
|
||||
- Occasional black bar when scrolling in long strip reader ([@FooIbar](https://github.com/FooIbar)) ([#563](https://github.com/mihonapp/mihon/pull/563))
|
||||
- Fix reader page image not being decoded until it's visible ([@FooIbar](https://github.com/FooIbar)) ([#563](https://github.com/mihonapp/mihon/pull/563))
|
||||
- Reader chapter progress slider visuals ([@FooIbar](https://github.com/FooIbar)) ([#674](https://github.com/mihonapp/mihon/pull/674))
|
||||
- Extension being marked as not installed instead of untrusted after updating with private installer ([@AntsyLich](https://github.com/AntsyLich)) ([`2114514`](https://github.com/mihonapp/mihon/commit/21145144cdf550aa775047603e06e261951ebc42))
|
||||
- Extension update counter not updating due to extension being marked as untrusted ([@AntsyLich](https://github.com/AntsyLich)) ([`2114514`](https://github.com/mihonapp/mihon/commit/21145144cdf550aa775047603e06e261951ebc42))
|
||||
- `Key "extension-XXX-YYY" was already used` crash ([@AntsyLich](https://github.com/AntsyLich)) ([`2114514`](https://github.com/mihonapp/mihon/commit/21145144cdf550aa775047603e06e261951ebc42))
|
||||
- Navigation layout tap zones shifting after zooming out in webtoon readers ([@FooIbar](https://github.com/FooIbar)) ([#767](https://github.com/mihonapp/mihon/pull/767))
|
||||
- Some extension not loading due to missing classes ([@AwkwardPeak7](https://github.com/AwkwardPeak7)) ([#783](https://github.com/mihonapp/mihon/pull/783))
|
||||
- Theme colors in accordance to upstream changes ([@CrepeTF](https://github.com/CrepeTF), [@AntsyLich](https://github.com/AntsyLich)) ([#766](https://github.com/mihonapp/mihon/pull/766), [#963](https://github.com/mihonapp/mihon/pull/963), [#976](https://github.com/mihonapp/mihon/pull/976))
|
||||
- Theme colors in accordance to upstream changes ([@CrepeTF](https://github.com/CrepeTF), [@AntsyLich](https://github.com/AntsyLich)) ([#766](https://github.com/mihonapp/mihon/pull/766), [#963](https://github.com/mihonapp/mihon/pull/963), [#976](https://github.com/mihonapp/mihon/pull/976), [9a34ace](https://github.com/mihonapp/mihon/commit/9a34ace09c66274e6c2b3f9446058a0fa99d4bd0))
|
||||
- Crash when requesting folder access on non-conforming devices ([@mainrs](https://github.com/mainrs)) ([#726](https://github.com/mihonapp/mihon/pull/726))
|
||||
- Fix unexpected skips in strong skipping mode ([@FooIbar](https://github.com/FooIbar)) ([#940](https://github.com/mihonapp/mihon/pull/940))
|
||||
- Bugged color for Date/Scanlator in chapter list for read chapters ([@ivaniskandar](https://github.com/ivaniskandar)) ([`15d9992`](https://github.com/mihonapp/mihon/commit/15d999229fcce865001d5fa77d0163e6e80e38db))
|
||||
- Categories having same `order` after restoring backup ([@Cologler](https://github.com/Cologler)) ([`119bcbf`](https://github.com/mihonapp/mihon/commit/119bcbf8ed2415664922ea77fadf0da1165d1732))
|
||||
- Filter by "Tracking" temporarily stuck after signing out of tracker ([@AntsyLich](https://github.com/AntsyLich)) ([#987](https://github.com/mihonapp/mihon/pull/987))
|
||||
- Fix login prompts despite being logged in to trackers in Manga screen ([@AntsyLich](https://github.com/AntsyLich)) ([`cbcd8bd`](https://github.com/mihonapp/mihon/commit/cbcd8bd6682023f728568f2b44da26124618aed7))
|
||||
- JXL image downloading and loading ([@FooIbar](https://github.com/FooIbar)) ([#993](https://github.com/mihonapp/mihon/pull/993))
|
||||
- Crash when using `%` in category name ([@Animeboynz](https://github.com/Animeboynz), [@FooIbar](https://github.com/FooIbar)) ([#1030](https://github.com/mihonapp/mihon/pull/1030))
|
||||
- Fix item disappearing when fast scrolling ([@cuong-tran](https://github.com/cuong-tran)) ([#1035](https://github.com/mihonapp/mihon/pull/1035))
|
||||
- Library is backed up while being disabled ([@AntsyLich](https://github.com/AntsyLich)) ([`56fb4f6`](https://github.com/mihonapp/mihon/commit/56fb4f62a152e87a71892aa68c78cac51a2c8596))
|
||||
- Crash on list with 0 item but only sticky header ([@cuong-tran](https://github.com/cuong-tran)) ([#1083](https://github.com/mihonapp/mihon/pull/1083))
|
||||
- Crash on list with only sticky header ([@cuong-tran](https://github.com/cuong-tran)) ([#1083](https://github.com/mihonapp/mihon/pull/1083))
|
||||
- Crash when trying to clear cookies of some source ([@FooIbar](https://github.com/FooIbar)) ([#1084](https://github.com/mihonapp/mihon/pull/1084))
|
||||
- MAL search results not showing start dates ([@MajorTanya](https://github.com/MajorTanya)) ([#1098](https://github.com/mihonapp/mihon/pull/1098))
|
||||
- Android SDK 35 API collision ([@AntsyLich](https://github.com/AntsyLich)) ([`fdb9617`](https://github.com/mihonapp/mihon/commit/fdb96179c6373eb0a8e7d6daea671a315d5ce5f0))
|
||||
- Manga next update calculation when considering custom fetch interval ([@cuong-tran](https://github.com/cuong-tran)) ([#1206](https://github.com/mihonapp/mihon/pull/1206))
|
||||
- WheelPicker Manual Input ([@Animeboynz](https://github.com/Animeboynz)) ([#1209](https://github.com/mihonapp/mihon/pull/1209))
|
||||
- EnhancedTracker not auto binding when adding manga to library ([@brewkunz](https://github.com/brewkunz)) ([#1298](https://github.com/mihonapp/mihon/pull/1298))
|
||||
- Step count in settings slider ([@abdurisaq](https://github.com/abdurisaq)) ([#1356](https://github.com/mihonapp/mihon/pull/1356))
|
||||
- Freezing in some screens due to blocking call ([@cuong-tran](https://github.com/cuong-tran)) ([#1364](https://github.com/mihonapp/mihon/pull/1364))
|
||||
- Crash when removing non-existent tracked entry from tracker ([@cuong-tran](https://github.com/cuong-tran)) ([#1380](https://github.com/mihonapp/mihon/pull/1380))
|
||||
|
||||
### Other
|
||||
- Code cleanup
|
||||
- Minor refactor of theming when expressions ([@MajorTanya](https://github.com/MajorTanya)) ([#396](https://github.com/mihonapp/mihon/pull/396))
|
||||
- Inside `WorkerInfoScreen` ([@AntsyLich](https://github.com/AntsyLich)) ([`5aec8f8`](https://github.com/mihonapp/mihon/commit/5aec8f8018236a38106483da08f9cbc28261ac9b))
|
||||
- Inside `ChapterDownloadIndicator`, `MangaChapterListItem` ([@AntsyLich](https://github.com/AntsyLich)) ([`b7e091d`](https://github.com/mihonapp/mihon/commit/b7e091d5d039e00cababc7daf555280df6cf9c03))
|
||||
- MangaCoverFetcher ([@ivaniskandar](https://github.com/ivaniskandar)) ([`1365695`](https://github.com/mihonapp/mihon/commit/13656959ae0606736f6ca9eb62699dc23e467c2f))
|
||||
- Cleanup `LibraryScreenModel` `LibraryMap.applySort` and some more ([@AntsyLich](https://github.com/AntsyLich)) ([`2beb89d`](https://github.com/mihonapp/mihon/commit/2beb89d53163a6d288f8acdebe0f5d26fea8ab3e))
|
||||
- Address `overridePendingTransition` deprecation ([@MajorTanya](https://github.com/MajorTanya)) ([#410](https://github.com/mihonapp/mihon/pull/410))
|
||||
- Prioritize extension classes and files over app ([@beer-psi](https://github.com/beer-psi)) ([#433](https://github.com/mihonapp/mihon/pull/433))
|
||||
- Use compose pager implementation ([@ivaniskandar](https://github.com/ivaniskandar)) ([`84984ef`](https://github.com/mihonapp/mihon/commit/84984ef7e1d7242924120cd2f171cb9dd75bc916))
|
||||
- Switch to coil3 from coil2 ([@ivaniskandar](https://github.com/ivaniskandar)) ([`f72b6e4`](https://github.com/mihonapp/mihon/commit/f72b6e4d7c1f2f93d705402e4d80c94160bef54d))
|
||||
- Fix GIF not playing ([@jobobby04](https://github.com/jobobby04)) ([`59bedb3`](https://github.com/mihonapp/mihon/commit/59bedb33ff59ad5db1df2e93567a2266fb63eacc))
|
||||
- Accommodate db for sync support ([@kaiserbh](https://github.com/kaiserbh)) ([#450](https://github.com/mihonapp/mihon/pull/450))
|
||||
- Fix webtoon last visible item position calculation ([@FooIbar](https://github.com/FooIbar)) ([#562](https://github.com/mihonapp/mihon/pull/562))
|
||||
- Migrate from `com.google.accompanist:accompanist-webview` to `io.github.kevinnzou:compose-webview` ([@sirlag](https://github.com/sirlag)) ([#569](https://github.com/mihonapp/mihon/pull/569))
|
||||
- Rewrite migrations ([@ghostbear](https://github.com/ghostbear)) ([#577](https://github.com/mihonapp/mihon/pull/577))
|
||||
- Further improve migration ([@ghostbear](https://github.com/ghostbear)) ([#588](https://github.com/mihonapp/mihon/pull/588))
|
||||
- Fix migrations not running ([@ghostbear](https://github.com/ghostbear)) ([#604](https://github.com/mihonapp/mihon/pull/604))
|
||||
- Fix MigratorTest after updating to Kotlin 2 ([@cuong-tran](https://github.com/cuong-tran)) ([#896](https://github.com/mihonapp/mihon/pull/896))
|
||||
- Add MigratorTest to build script ([@cuong-tran](https://github.com/cuong-tran)) ([#896](https://github.com/mihonapp/mihon/pull/896))
|
||||
- Fix UI freeze after migration ([@AntsyLich](https://github.com/AntsyLich)) ([`3f1d28c`](https://github.com/mihonapp/mihon/commit/3f1d28c3833e6b868152149ed02b3fb8c54eccef))
|
||||
- Fix some migrations never running ([@MajorTanya](https://github.com/MajorTanya), [@AntsyLich](https://github.com/AntsyLich)) ([#1030](https://github.com/mihonapp/mihon/pull/1030))
|
||||
- Add ProGuard rule to keep `mihon` namespace classes ([@MajorTanya](https://github.com/MajorTanya)) ([#605](https://github.com/mihonapp/mihon/pull/605))
|
||||
- Use gradle plugins to share build configuration instead of subprojects ([@AntsyLich](https://github.com/AntsyLich)) ([`e448e40`](https://github.com/mihonapp/mihon/commit/e448e40406e8d9916120a278e42829a6f1b25a7a))
|
||||
- Remove dependency on compose material 2 components ([@AntsyLich](https://github.com/AntsyLich)) ([`fb94230`](https://github.com/mihonapp/mihon/commit/fb9423028eb017c110cb805f2d0601e5b02e50f9))
|
||||
- Upload PR build artifacts to GitHub ([@FooIbar](https://github.com/FooIbar)) ([#941](https://github.com/mihonapp/mihon/pull/941))
|
||||
- Refactor archive support with libarchive ([@FooIbar](https://github.com/FooIbar)) ([#949](https://github.com/mihonapp/mihon/pull/949))
|
||||
- Add safeguard to prevent ArchiveInputStream from being closed twice ([@null2264](https://github.com/null2264)) ([#967](https://github.com/mihonapp/mihon/pull/967))
|
||||
- Move archive related code to :core:archive ([@AntsyLich](https://github.com/AntsyLich)) ([`bd7b354`](https://github.com/mihonapp/mihon/commit/bd7b35419861df6d426d6ec0a188391910d0f615))
|
||||
- Replace detekt with ktlint via spotless ([@AntsyLich](https://github.com/AntsyLich)) ([#1130](https://github.com/mihonapp/mihon/pull/1130), [#1136](https://github.com/mihonapp/mihon/pull/1136), [#1138](https://github.com/mihonapp/mihon/pull/1138))
|
||||
- Refrain from running spotless on weblate files ([@AntsyLich](https://github.com/AntsyLich)) ([`32d2c2a`](https://github.com/mihonapp/mihon/commit/32d2c2ac1bc224cbda2f09a4023d7d120ea0e954))
|
||||
- Use feature flags in compose compiler plugin ([@AntsyLich](https://github.com/AntsyLich)) ([`8f9a325`](https://github.com/mihonapp/mihon/commit/8f9a325895bb7b94c2ec92dd969094fc30b3b5e2))- PagerPageHolder: lazy init loading indicator ([@AntsyLich](https://github.com/AntsyLich), [@ivaniskandar](https://github.com/ivaniskandar)) ([`a45eb5e`](https://github.com/mihonapp/mihon/commit/a45eb5e5288159dbbbbb5f92140ce0dd32a8f3ab))
|
||||
- Collect MangaScreen state with lifecycle ([@AntsyLich](https://github.com/AntsyLich), [@ivaniskandar](https://github.com/ivaniskandar)) ([`03eb756`](https://github.com/mihonapp/mihon/commit/03eb756ecba0692d88d3a76254afc4c157fa225b))
|
||||
- Add stable marker to Manga data class ([@AntsyLich](https://github.com/AntsyLich), [@ivaniskandar](https://github.com/ivaniskandar)) ([`03eb756`](https://github.com/mihonapp/mihon/commit/03eb756ecba0692d88d3a76254afc4c157fa225b))
|
||||
- Use DTOs to parse tracking API responses ([@MajorTanya](https://github.com/MajorTanya)) ([#1103](https://github.com/mihonapp/mihon/pull/1103))
|
||||
- Fix Kitsu ratingTwenty being typed as String ([@MajorTanya](https://github.com/MajorTanya)) ([#1191](https://github.com/mihonapp/mihon/pull/1191))
|
||||
- Fix Kitsu `synopsis` nullability ([@MajorTanya](https://github.com/MajorTanya)) ([#1233](https://github.com/mihonapp/mihon/pull/1233))
|
||||
- Fix AniList `ALSearchItem.status` nullibility ([@Secozzi](https://github.com/Secozzi)) ([#1297](https://github.com/mihonapp/mihon/pull/1297))
|
||||
- Migrate some classpaths to gradle plugins ([@AntsyLich](https://github.com/AntsyLich)) ([`fc1c804`](https://github.com/mihonapp/mihon/commit/fc1c804bfda1d76c0399bbb6214e75b3def951cc))
|
||||
- Add crashlytics to standard builds ([@AntsyLich](https://github.com/AntsyLich)) ([`3c611b9`](https://github.com/mihonapp/mihon/commit/3c611b95fb79e5ac972019b76c7b24f46a3087fd))
|
||||
- Switch to stable compose ([@AntsyLich](https://github.com/AntsyLich)) ([`2baffa6`](https://github.com/mihonapp/mihon/commit/2baffa62cade1abd978d5fd03151b47fc87fd31e))
|
||||
- Switch from inorichi injekt to kohesive Injekt ([@AntsyLich](https://github.com/AntsyLich)) ([#1205](https://github.com/mihonapp/mihon/pull/1205))
|
||||
- Use custom injekt register with inorichi patch ([@AntsyLich](https://github.com/AntsyLich)) ([`83fd474`](https://github.com/mihonapp/mihon/commit/83fd4746eda1b99f35292b0c2211e606a421b3eb))
|
||||
- Use TextFieldState in BasicTextField where applicable (p) ([#1201](https://github.com/mihonapp/mihon/pull/1201))
|
||||
- Bump NDK version ([@AntsyLich](https://github.com/AntsyLich)) ([#1203](https://github.com/mihonapp/mihon/pull/1203))
|
||||
- Move firebase permission removal to standard flavor ([@AntsyLich](https://github.com/AntsyLich)) ([`be671b4`](https://github.com/mihonapp/mihon/commit/be671b42cefd70180644e01bb065a18cb7701bf9))
|
||||
- Adjust distinct checker in WidgetManager and run on default dispatcher (p) ([`9b8ab6a`](https://github.com/mihonapp/mihon/commit/9b8ab6acc25a5f99c9c5eebf9cc250975931c57c))
|
||||
- Update resources exclusion rules (p) ([`481cfed`](https://github.com/mihonapp/mihon/commit/481cfedf08576cecfbb35616837bd8f627d8f959))
|
||||
- Bump compile sdk to 35 (p) ([`37419cd`](https://github.com/mihonapp/mihon/commit/37419cdc26c2b5c4f8583fc2ba439b08fab42856))
|
||||
- ChapterNavigator: dispatch page change only when needed (p) ([`f84d9a0`](https://github.com/mihonapp/mihon/commit/f84d9a08b4af768b1e9920c43cc445c86f5427fc))
|
||||
- Remove usage of deprecated accompanist SystemUiController ([@AntsyLich](https://github.com/AntsyLich)) ([`2ba3f06`](https://github.com/mihonapp/mihon/commit/2ba3f0612c08c7021fed2f6d96cd538da2f34a13))
|
||||
- Run PR check when base strings are changed ([@AntsyLich](https://github.com/AntsyLich)) ([`4051f18`](https://github.com/mihonapp/mihon/commit/4051f180a2e36e8a2cde6c55f0bea7952fdc4704))
|
||||
- Fix PR build check ([@AntsyLich](https://github.com/AntsyLich)) ([`9503082`](https://github.com/mihonapp/mihon/commit/9503082d44b5bd868ee1bfc42741dc978d1d9047))
|
||||
- Cleanup .gitignore files ([@AntsyLich](https://github.com/AntsyLich)) ([`afa5002`](https://github.com/mihonapp/mihon/commit/afa50029882655af8d5eea40aed7644fce4564d8))
|
||||
- Pass uncaught exception to default handler in GlobalExceptionHandler (so it's reported to crashlytics) ([@AntsyLich](https://github.com/AntsyLich)) ([`f3a2f56`](https://github.com/mihonapp/mihon/commit/f3a2f566c8a09ab862758ae69b43da2a2cd8f1db))
|
||||
|
||||
## [v0.16.5] - 2024-04-09
|
||||
### Added
|
||||
- Setting to install custom color profiles to get true colors ([@wwww-wwww](https://github.com/wwww-wwww)) ([#523](https://github.com/mihonapp/mihon/pull/523))
|
||||
- Relative date for up to a week in the future ([@sirlag](https://github.com/sirlag)) ([#415](https://github.com/mihonapp/mihon/pull/415))
|
||||
- Advance setting to install custom color profiles ([@wwww-wwww](https://github.com/wwww-wwww)) ([#523](https://github.com/mihonapp/mihon/pull/523))
|
||||
|
||||
### Changed
|
||||
- Permanently enable 32-bit color mode ([@wwww-wwww](https://github.com/wwww-wwww)) ([#523](https://github.com/mihonapp/mihon/pull/523))
|
||||
|
||||
### Fixed
|
||||
- Fix wrong dates in Updates and History tab due to time zone issues ([@sirlag](https://github.com/sirlag)) ([#402](https://github.com/mihonapp/mihon/pull/402), [#415](https://github.com/mihonapp/mihon/pull/415))
|
||||
- Fix app infinitely retries tracker update instead of failing after 3 tries ([@MajorTanya](https://github.com/MajorTanya)) ([#411](https://github.com/mihonapp/mihon/pull/411))
|
||||
- Fix crash on Pixel devices ([`ab06720`](https://github.com/mihonapp/mihon/commit/ab067209661eceefc04c65f6bdbfcaa8a1264651))
|
||||
- Fix crash when opening some heif/heic images ([@az4521](https://github.com/az4521)) ([#466](https://github.com/mihonapp/mihon/pull/466))
|
||||
- Fix crash in track date selection dialog ([@ivaniskandar](https://github.com/ivaniskandar)) ([`c348fac`](https://github.com/mihonapp/mihon/commit/c348fac78fac479fb123bd617c01c78b9ca851d5))
|
||||
- Fix dates for saved images on Samsung devices ([@MajorTanya](https://github.com/MajorTanya)) ([#552](https://github.com/mihonapp/mihon/pull/552))
|
||||
- Fix colors getting distorted when opening CMYK jpeg images ([@wwww-wwww](https://github.com/wwww-wwww)) ([#523](https://github.com/mihonapp/mihon/pull/523))
|
||||
- Wrong dates in Updates and History tab due to time zone issues ([@sirlag](https://github.com/sirlag)) ([#402](https://github.com/mihonapp/mihon/pull/402))
|
||||
- Fix extra date header introduced by parent PR ([@sirlag](https://github.com/sirlag)) ([#415](https://github.com/mihonapp/mihon/pull/415))
|
||||
- Fix build time in about screen displayed in UTC ([@AntsyLich](https://github.com/AntsyLich)) ([`aed53d3`](https://github.com/mihonapp/mihon/commit/aed53d3bdc85ce0e899fbb90b9f9cad0f1b86480))
|
||||
- App infinitely retries tracker update instead of failing after 3 tries ([@MajorTanya](https://github.com/MajorTanya)) ([#411](https://github.com/mihonapp/mihon/pull/411))
|
||||
- Crash on Pixel devices (was introduced due to compose update) ([`ab06720`](https://github.com/mihonapp/mihon/commit/ab067209661eceefc04c65f6bdbfcaa8a1264651))
|
||||
- Crash when opening some heif/heic images ([@az4521](https://github.com/az4521)) ([#466](https://github.com/mihonapp/mihon/pull/466))
|
||||
- Crash when putting app in background while track date selection dialog is open ([@ivaniskandar](https://github.com/ivaniskandar)) ([`c348fac`](https://github.com/mihonapp/mihon/commit/c348fac78fac479fb123bd617c01c78b9ca851d5))
|
||||
- Dates for saved images not following the specification (fixes date issue mainly on Samsung devices) ([@MajorTanya](https://github.com/MajorTanya)) ([#552](https://github.com/mihonapp/mihon/pull/552))
|
||||
- Colors getting distorted when opening CMYK jpeg images ([@wwww-wwww](https://github.com/wwww-wwww)) ([#523](https://github.com/mihonapp/mihon/pull/523))
|
||||
|
||||
## [v0.16.4] - 2024-02-26
|
||||
### Fixed
|
||||
- Circumvent MAL block ([@AntsyLich](https://github.com/AntsyLich)) ([`085ad8d`](https://github.com/mihonapp/mihon/commit/085ad8d44637c375a8ed24aba3a6f75f5b0cc9ee))
|
||||
## [v0.16.4] - 2024-02-27
|
||||
### Changed
|
||||
- Don't include custom user agent for MAL (circumvents MAL block) ([@AntsyLich](https://github.com/AntsyLich)) ([`085ad8d`](https://github.com/mihonapp/mihon/commit/085ad8d44637c375a8ed24aba3a6f75f5b0cc9ee))
|
||||
|
||||
## [v0.16.3] - 2024-01-30
|
||||
### Added
|
||||
- Copy extension debug info when clicking logo or name in the extension details screen ([@MajorTanya](https://github.com/MajorTanya)) ([#271](https://github.com/mihonapp/mihon/pull/271))
|
||||
|
||||
### Changed
|
||||
- Rename extension update error file to `mihon_update_errors.txt` ([@mjishnu](https://github.com/mjishnu)) ([#253](https://github.com/mihonapp/mihon/pull/253))
|
||||
- Hide display cutoff setting in reader settings sheet if fullscreen is off ([@Riztard](https://github.com/Riztard)) ([#241](https://github.com/mihonapp/mihon/pull/241))
|
||||
- Hide display cutoff setting in reader settings sheet if fullscreen is disabled ([@Riztard](https://github.com/Riztard)) ([#241](https://github.com/mihonapp/mihon/pull/241))
|
||||
- Library update error filename to `mihon_update_errors.txt` from `tachiyomi_update_errors.txt` ([@mjishnu](https://github.com/mjishnu)) ([#253](https://github.com/mihonapp/mihon/pull/253))
|
||||
|
||||
### Fixed
|
||||
- Fix bottom sheet display issues on non-Tablet UI ([@theolm](https://github.com/theolm)) ([#182](https://github.com/mihonapp/mihon/pull/182))
|
||||
- Fix crash when switching screen while a list is scrolling ([@theolm](https://github.com/theolm)) ([#272](https://github.com/mihonapp/mihon/pull/272))
|
||||
- Fix newly installed extensions not being recognized by Mihon ([@AwkwardPeak7](https://github.com/AwkwardPeak7)) ([#275](https://github.com/mihonapp/mihon/pull/275))
|
||||
- Fix error handling when refreshing MAL OAuth token ([@AntsyLich](https://github.com/AntsyLich)) ([`0f4de03`](https://github.com/mihonapp/mihon/commit/0f4de03d7a77b52490dc9a95e96a308b93b26e4f))
|
||||
- Bottom sheet UI issues on non-tablet devices ([@theolm](https://github.com/theolm)) ([#182](https://github.com/mihonapp/mihon/pull/182))
|
||||
- Crash when switching screen while a list is scrolling ([@theolm](https://github.com/theolm)) ([#272](https://github.com/mihonapp/mihon/pull/272))
|
||||
- Newly installed extensions not being recognized by Mihon ([@AwkwardPeak7](https://github.com/AwkwardPeak7)) ([#275](https://github.com/mihonapp/mihon/pull/275))
|
||||
- Failing to refresh MAL token being inferred as token expiration ([@AntsyLich](https://github.com/AntsyLich)) ([`0f4de03`](https://github.com/mihonapp/mihon/commit/0f4de03d7a77b52490dc9a95e96a308b93b26e4f))
|
||||
|
||||
### Other
|
||||
- Add `detekt` (kotlin code analyzer) to the project ([@theolm](https://github.com/theolm)) ([#216](https://github.com/mihonapp/mihon/pull/216))
|
||||
|
||||
## [v0.16.2] - 2024-01-28
|
||||
### Added
|
||||
- Scanlator filter is now part of Backup ([@jobobby04](https://github.com/jobobby04)) ([#166](https://github.com/mihonapp/mihon/pull/166))
|
||||
|
||||
### Changed
|
||||
- Rename crash log filename to `mihon_crash_logs.txt` ([@MajorTanya](https://github.com/MajorTanya)) ([#234](https://github.com/mihonapp/mihon/pull/234))
|
||||
- Backup now contains scanlator filter of a series ([@jobobby04](https://github.com/jobobby04)) ([#166](https://github.com/mihonapp/mihon/pull/166))
|
||||
- App icon scaling ([@AntsyLich](https://github.com/AntsyLich)) ([`26815c7`](https://github.com/mihonapp/mihon/commit/26815c7356111394665467c1e81255ac9ee33c1a))
|
||||
- Tracker OAuth client to Mihon's (fixes login issue for Shikimori tracker) ([@AntsyLich](https://github.com/AntsyLich)) ([`e3f33e2`](https://github.com/mihonapp/mihon/commit/e3f33e24f5e928ac8a85d1f500fd42d4715fc6b5))
|
||||
- Tracker user agents ([@AntsyLich](https://github.com/AntsyLich), [@kitsumed](https://github.com/kitsumed)) ([`e3f33e2`](https://github.com/mihonapp/mihon/commit/e3f33e24f5e928ac8a85d1f500fd42d4715fc6b5))
|
||||
- Crash log filename to `mihon_crash_logs.txt` from `tachiyomi_crash_logs.txt` ([@MajorTanya](https://github.com/MajorTanya)) ([#234](https://github.com/mihonapp/mihon/pull/234))
|
||||
- Don't try to refresh MAL token after refresh token expires ([@AntsyLich](https://github.com/AntsyLich)) ([`32188f9`](https://github.com/mihonapp/mihon/commit/32188f9f65009a18250674ef1bd6e57d351c1fba))
|
||||
|
||||
### Fixed
|
||||
- "Flash screen on page change" Making the screen goes blank ([@AntsyLich](https://github.com/AntsyLich)) ([`38d6ab8`](https://github.com/mihonapp/mihon/commit/38d6ab80ce868707829dbc81de4170afe3c2f2a5))
|
||||
- App icon scaling ([@AntsyLich](https://github.com/AntsyLich)) ([`26815c7`](https://github.com/mihonapp/mihon/commit/26815c7356111394665467c1e81255ac9ee33c1a))
|
||||
- "Flash screen on page change" making the screen full black ([@AntsyLich](https://github.com/AntsyLich)) ([`38d6ab8`](https://github.com/mihonapp/mihon/commit/38d6ab80ce868707829dbc81de4170afe3c2f2a5))
|
||||
- Faulty MangaUpdates score in database ([@AntsyLich](https://github.com/AntsyLich) ([`a024218`](https://github.com/mihonapp/mihon/commit/a024218410953a389b8af4880fa7ae6cc30124a2)
|
||||
- Updating extension not reflecting correctly ([@AntsyLich](https://github.com/AntsyLich)) ([`cb06898`](https://github.com/mihonapp/mihon/commit/cb068984303f811692531bf6f14902ae118d8ac7))
|
||||
- Inconsistent button height with some languages in "Data and storage" ([@theolm](https://github.com/theolm)) ([#202](https://github.com/mihonapp/mihon/pull/202))
|
||||
- Fix chapter not being marked as read in some cases with Enhanced Trackers ([@Secozzi](https://github.com/Secozzi)) ([#219](https://github.com/mihonapp/mihon/pull/219))
|
||||
- And various tracker related fixes ([@AntsyLich](https://github.com/AntsyLich), [@kitsumed](https://github.com/kitsumed), [@Secozzi](https://github.com/Secozzi)) ([`a024218`](https://github.com/mihonapp/mihon/commit/a024218410953a389b8af4880fa7ae6cc30124a2), [`e3f33e2`](https://github.com/mihonapp/mihon/commit/e3f33e24f5e928ac8a85d1f500fd42d4715fc6b5), [`32188f9`](https://github.com/mihonapp/mihon/commit/32188f9f65009a18250674ef1bd6e57d351c1fba))
|
||||
- Inconsistent button height in "Data and storage" for some languages ([@theolm](https://github.com/theolm)) ([#202](https://github.com/mihonapp/mihon/pull/202))
|
||||
- Chapter not being marked as read locally when refreshing Enhanced Trackers ([@Secozzi](https://github.com/Secozzi)) ([#219](https://github.com/mihonapp/mihon/pull/219))
|
||||
|
||||
### Other
|
||||
- Make `last_modified_at` field in database be `0` on insert ([@kaiserbh](https://github.com/kaiserbh)) ([#113](https://github.com/mihonapp/mihon/pull/113))
|
||||
- Remove usage of `.not()` where possible in code ([@AntsyLich](https://github.com/AntsyLich)) ([`3940740`](https://github.com/mihonapp/mihon/commit/39407407f282dbb7fa972b12053c26b3e3bd66d8))
|
||||
- Use type-safe project accessors ([@theolm](https://github.com/theolm)) ([#194](https://github.com/mihonapp/mihon/pull/194))
|
||||
- Legacy tracker model properties now has the same type as the domain ones ([@AntsyLich](https://github.com/AntsyLich)) ([#245](https://github.com/mihonapp/mihon/pull/245))
|
||||
|
||||
## [v0.16.1] - 2024-01-18
|
||||
### Changed
|
||||
- Branding to Mihon (for references we missed) ([@AntsyLich](https://github.com/AntsyLich)) ([`6539406`](https://github.com/mihonapp/mihon/commit/653940613d661eb371aab3b3c3a8181e4e308c43))
|
||||
- Preview builds are now called Beta builds ([@AntsyLich](https://github.com/AntsyLich)) ([`3c3a1cd`](https://github.com/mihonapp/mihon/commit/3c3a1cd448ab1f653ddd12b2afe0cba38968d1b9))
|
||||
|
||||
### Fixed
|
||||
- App Icon not filled ([@AntsyLich](https://github.com/AntsyLich)) ([`1849715`](https://github.com/mihonapp/mihon/commit/18497154183356bb0d469b27827f9f7d6b7a3130))
|
||||
- App icon not following the [specification](https://developer.android.com/develop/ui/views/launch/icon_design_adaptive) ([@AntsyLich](https://github.com/AntsyLich)) ([`1849715`](https://github.com/mihonapp/mihon/commit/18497154183356bb0d469b27827f9f7d6b7a3130))
|
||||
- MangaUpdates default score being set to -1.0 ([@AntsyLich](https://github.com/AntsyLich)) ([`99fd273`](https://github.com/mihonapp/mihon/commit/99fd2731f5d9d374700e89fa67d4d5bf611bbafa))
|
||||
|
||||
## [v0.16.0] - 2024-01-16
|
||||
### Changed
|
||||
- Branding to Mihon ([@AntsyLich](https://github.com/AntsyLich))
|
||||
- Minimum supported Android version to 8 ([@AntsyLich](https://github.com/AntsyLich)) ([`dfb3091`](https://github.com/mihonapp/mihon/commit/dfb3091e380dda3e9bfb64bf5c9a685cf3a03d0e))
|
||||
|
||||
"The end of 立ち読み (Tachiyomi) is the beginning of みほん (Mihon)"
|
||||
Credit to LinkCable, the icon designer, for this poetic quote.
|
||||
|
||||
What's New?
|
||||
Well, nothing, except you now you need Android 8+ to install the app.
|
||||
|
||||
[unreleased]: https://github.com/mihonapp/mihon/compare/v0.16.5...HEAD
|
||||
[unreleased]: https://github.com/mihonapp/mihon/compare/v0.17.0...main
|
||||
[v0.17.0]: https://github.com/mihonapp/mihon/compare/v0.16.5...v0.17.0
|
||||
[v0.16.5]: https://github.com/mihonapp/mihon/compare/v0.16.4...v0.16.5
|
||||
[v0.16.4]: https://github.com/mihonapp/mihon/compare/v0.16.3...v0.16.4
|
||||
[v0.16.3]: https://github.com/mihonapp/mihon/compare/v0.16.2...v0.16.3
|
||||
[v0.16.2]: https://github.com/mihonapp/mihon/compare/v0.16.1...v0.16.2
|
||||
[v0.16.1]: https://github.com/mihonapp/mihon/compare/v0.16.0...v0.16.1
|
||||
[v0.16.0]: https://github.com/mihonapp/mihon/releases/tag/v0.16.0
|
||||
[v0.16.0]: https://github.com/mihonapp/mihon/compare/a9c7cbf...v0.16.0
|
||||
|
3
app/.gitignore
vendored
3
app/.gitignore
vendored
@ -1,3 +0,0 @@
|
||||
/build
|
||||
*iml
|
||||
*.iml
|
@ -28,8 +28,8 @@ android {
|
||||
defaultConfig {
|
||||
applicationId = "app.mihon"
|
||||
|
||||
versionCode = 7
|
||||
versionName = "0.16.5"
|
||||
versionCode = 8
|
||||
versionName = "0.17.0"
|
||||
|
||||
buildConfigField("String", "COMMIT_COUNT", "\"${getCommitCount()}\"")
|
||||
buildConfigField("String", "COMMIT_SHA", "\"${getGitSha()}\"")
|
||||
|
11
app/src/dev/java/mihon/core/firebase/FirebaseConfig.kt
Normal file
11
app/src/dev/java/mihon/core/firebase/FirebaseConfig.kt
Normal file
@ -0,0 +1,11 @@
|
||||
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
|
||||
}
|
@ -5,7 +5,7 @@ import kotlin.contracts.ExperimentalContracts
|
||||
import kotlin.contracts.contract
|
||||
|
||||
fun <T : R, R : Any> List<T>.insertSeparators(
|
||||
generator: (T?, T?) -> R?,
|
||||
generator: (before: T?, after: T?) -> R?,
|
||||
): List<R> {
|
||||
if (isEmpty()) return emptyList()
|
||||
val newList = mutableListOf<R>()
|
||||
@ -19,6 +19,24 @@ fun <T : R, R : Any> List<T>.insertSeparators(
|
||||
return newList
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to [eu.kanade.core.util.insertSeparators] but iterates from last to first element
|
||||
*/
|
||||
fun <T : R, R : Any> List<T>.insertSeparatorsReversed(
|
||||
generator: (before: T?, after: T?) -> R?,
|
||||
): List<R> {
|
||||
if (isEmpty()) return emptyList()
|
||||
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) {
|
||||
if (shouldAdd) {
|
||||
add(value)
|
||||
|
@ -5,6 +5,7 @@ import eu.kanade.domain.track.model.toDomainTrack
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.track.EnhancedTracker
|
||||
import eu.kanade.tachiyomi.data.track.Tracker
|
||||
import eu.kanade.tachiyomi.data.track.TrackerManager
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.util.lang.convertEpochMillisZone
|
||||
import logcat.LogPriority
|
||||
@ -14,17 +15,16 @@ import tachiyomi.core.common.util.system.logcat
|
||||
import tachiyomi.domain.chapter.interactor.GetChaptersByMangaId
|
||||
import tachiyomi.domain.history.interactor.GetHistory
|
||||
import tachiyomi.domain.manga.model.Manga
|
||||
import tachiyomi.domain.track.interactor.GetTracks
|
||||
import tachiyomi.domain.track.interactor.InsertTrack
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.time.ZoneOffset
|
||||
|
||||
class AddTracks(
|
||||
private val getTracks: GetTracks,
|
||||
private val insertTrack: InsertTrack,
|
||||
private val syncChapterProgressWithTrack: SyncChapterProgressWithTrack,
|
||||
private val getChaptersByMangaId: GetChaptersByMangaId,
|
||||
private val trackerManager: TrackerManager,
|
||||
) {
|
||||
|
||||
// TODO: update all trackers based on common data
|
||||
@ -79,7 +79,7 @@ class AddTracks(
|
||||
|
||||
suspend fun bindEnhancedTrackers(manga: Manga, source: Source) = withNonCancellableContext {
|
||||
withIOContext {
|
||||
getTracks.await(manga.id)
|
||||
trackerManager.loggedInTrackers()
|
||||
.filterIsInstance<EnhancedTracker>()
|
||||
.filter { it.accept(source) }
|
||||
.forEach { service ->
|
||||
@ -87,11 +87,11 @@ class AddTracks(
|
||||
service.match(manga)?.let { track ->
|
||||
track.manga_id = manga.id
|
||||
(service as Tracker).bind(track)
|
||||
insertTrack.await(track.toDomainTrack()!!)
|
||||
insertTrack.await(track.toDomainTrack(idRequired = false)!!)
|
||||
|
||||
syncChapterProgressWithTrack.await(
|
||||
manga.id,
|
||||
track.toDomainTrack()!!,
|
||||
track.toDomainTrack(idRequired = false)!!,
|
||||
service,
|
||||
)
|
||||
}
|
||||
|
@ -0,0 +1,10 @@
|
||||
package eu.kanade.domain.track.model
|
||||
|
||||
import dev.icerock.moko.resources.StringResource
|
||||
import tachiyomi.i18n.MR
|
||||
|
||||
enum class AutoTrackState(val titleRes: StringResource) {
|
||||
ALWAYS(MR.strings.lock_always),
|
||||
ASK(MR.strings.default_category_summary),
|
||||
NEVER(MR.strings.lock_never),
|
||||
}
|
@ -1,9 +1,11 @@
|
||||
package eu.kanade.domain.track.service
|
||||
|
||||
import eu.kanade.domain.track.model.AutoTrackState
|
||||
import eu.kanade.tachiyomi.data.track.Tracker
|
||||
import eu.kanade.tachiyomi.data.track.anilist.Anilist
|
||||
import tachiyomi.core.common.preference.Preference
|
||||
import tachiyomi.core.common.preference.PreferenceStore
|
||||
import tachiyomi.core.common.preference.getEnum
|
||||
|
||||
class TrackPreferences(
|
||||
private val preferenceStore: PreferenceStore,
|
||||
@ -35,4 +37,9 @@ class TrackPreferences(
|
||||
fun anilistScoreType() = preferenceStore.getString("anilist_score_type", Anilist.POINT_10)
|
||||
|
||||
fun autoUpdateTrack() = preferenceStore.getBoolean("pref_auto_update_manga_sync_key", true)
|
||||
|
||||
fun autoUpdateTrackOnMarkRead() = preferenceStore.getEnum(
|
||||
"pref_auto_update_manga_on_mark_read",
|
||||
AutoTrackState.ALWAYS,
|
||||
)
|
||||
}
|
||||
|
@ -6,6 +6,8 @@ import androidx.compose.foundation.layout.ColumnScope
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Refresh
|
||||
import androidx.compose.material3.FilterChip
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
@ -27,6 +29,7 @@ import tachiyomi.domain.library.model.LibrarySort
|
||||
import tachiyomi.domain.library.model.sort
|
||||
import tachiyomi.domain.library.service.LibraryPreferences
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.presentation.core.components.BaseSortItem
|
||||
import tachiyomi.presentation.core.components.CheckboxItem
|
||||
import tachiyomi.presentation.core.components.HeadingItem
|
||||
import tachiyomi.presentation.core.components.SettingsChipRow
|
||||
@ -163,22 +166,38 @@ private fun ColumnScope.SortPage(
|
||||
val sortingMode = category.sort.type
|
||||
val sortDescending = !category.sort.isAscending
|
||||
|
||||
val trackerSortOption = if (trackers.isEmpty()) {
|
||||
emptyList()
|
||||
} else {
|
||||
listOf(MR.strings.action_sort_tracker_score to LibrarySort.Type.TrackerMean)
|
||||
val options = remember(trackers.isEmpty()) {
|
||||
val trackerMeanPair = if (trackers.isNotEmpty()) {
|
||||
MR.strings.action_sort_tracker_score to LibrarySort.Type.TrackerMean
|
||||
} else {
|
||||
null
|
||||
}
|
||||
listOfNotNull(
|
||||
MR.strings.action_sort_alpha to LibrarySort.Type.Alphabetical,
|
||||
MR.strings.action_sort_total to LibrarySort.Type.TotalChapters,
|
||||
MR.strings.action_sort_last_read to LibrarySort.Type.LastRead,
|
||||
MR.strings.action_sort_last_manga_update to LibrarySort.Type.LastUpdate,
|
||||
MR.strings.action_sort_unread_count to LibrarySort.Type.UnreadCount,
|
||||
MR.strings.action_sort_latest_chapter to LibrarySort.Type.LatestChapter,
|
||||
MR.strings.action_sort_chapter_fetch_date to LibrarySort.Type.ChapterFetchDate,
|
||||
MR.strings.action_sort_date_added to LibrarySort.Type.DateAdded,
|
||||
trackerMeanPair,
|
||||
MR.strings.action_sort_random to LibrarySort.Type.Random,
|
||||
)
|
||||
}
|
||||
|
||||
listOf(
|
||||
MR.strings.action_sort_alpha to LibrarySort.Type.Alphabetical,
|
||||
MR.strings.action_sort_total to LibrarySort.Type.TotalChapters,
|
||||
MR.strings.action_sort_last_read to LibrarySort.Type.LastRead,
|
||||
MR.strings.action_sort_last_manga_update to LibrarySort.Type.LastUpdate,
|
||||
MR.strings.action_sort_unread_count to LibrarySort.Type.UnreadCount,
|
||||
MR.strings.action_sort_latest_chapter to LibrarySort.Type.LatestChapter,
|
||||
MR.strings.action_sort_chapter_fetch_date to LibrarySort.Type.ChapterFetchDate,
|
||||
MR.strings.action_sort_date_added to LibrarySort.Type.DateAdded,
|
||||
).plus(trackerSortOption).map { (titleRes, mode) ->
|
||||
options.map { (titleRes, mode) ->
|
||||
if (mode == LibrarySort.Type.Random) {
|
||||
BaseSortItem(
|
||||
label = stringResource(titleRes),
|
||||
icon = Icons.Default.Refresh
|
||||
.takeIf { sortingMode == LibrarySort.Type.Random },
|
||||
onClick = {
|
||||
screenModel.setSort(category, mode, LibrarySort.Direction.Ascending)
|
||||
},
|
||||
)
|
||||
return@map
|
||||
}
|
||||
SortItem(
|
||||
label = stringResource(titleRes),
|
||||
sortDescending = sortDescending.takeIf { sortingMode == mode },
|
||||
|
@ -14,11 +14,13 @@ import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Check
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.ListItem
|
||||
import androidx.compose.material3.ListItemDefaults
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedButton
|
||||
import androidx.compose.material3.Switch
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
@ -34,13 +36,18 @@ import androidx.lifecycle.DefaultLifecycleObserver
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.compose.LocalLifecycleOwner
|
||||
import eu.kanade.presentation.util.rememberRequestPackageInstallsPermissionState
|
||||
import eu.kanade.tachiyomi.core.security.PrivacyPreferences
|
||||
import eu.kanade.tachiyomi.util.system.launchRequestPackageInstallsPermission
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.presentation.core.i18n.stringResource
|
||||
import tachiyomi.presentation.core.util.collectAsState
|
||||
import tachiyomi.presentation.core.util.secondaryItemAlpha
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
internal class PermissionStep : OnboardingStep {
|
||||
|
||||
private val privacyPreferences: PrivacyPreferences by injectLazy()
|
||||
|
||||
private var notificationGranted by mutableStateOf(false)
|
||||
private var batteryGranted by mutableStateOf(false)
|
||||
|
||||
@ -73,7 +80,7 @@ internal class PermissionStep : OnboardingStep {
|
||||
}
|
||||
|
||||
Column {
|
||||
PermissionItem(
|
||||
PermissionCheckbox(
|
||||
title = stringResource(MR.strings.onboarding_permission_install_apps),
|
||||
subtitle = stringResource(MR.strings.onboarding_permission_install_apps_description),
|
||||
granted = installGranted,
|
||||
@ -89,7 +96,7 @@ internal class PermissionStep : OnboardingStep {
|
||||
// no-op. resulting checks is being done on resume
|
||||
},
|
||||
)
|
||||
PermissionItem(
|
||||
PermissionCheckbox(
|
||||
title = stringResource(MR.strings.onboarding_permission_notifications),
|
||||
subtitle = stringResource(MR.strings.onboarding_permission_notifications_description),
|
||||
granted = notificationGranted,
|
||||
@ -97,7 +104,7 @@ internal class PermissionStep : OnboardingStep {
|
||||
)
|
||||
}
|
||||
|
||||
PermissionItem(
|
||||
PermissionCheckbox(
|
||||
title = stringResource(MR.strings.onboarding_permission_ignore_battery_opts),
|
||||
subtitle = stringResource(MR.strings.onboarding_permission_ignore_battery_opts_description),
|
||||
granted = batteryGranted,
|
||||
@ -109,6 +116,29 @@ internal class PermissionStep : OnboardingStep {
|
||||
context.startActivity(intent)
|
||||
},
|
||||
)
|
||||
|
||||
HorizontalDivider(
|
||||
modifier = Modifier.padding(vertical = 8.dp, horizontal = 16.dp),
|
||||
color = MaterialTheme.colorScheme.onPrimaryContainer,
|
||||
)
|
||||
|
||||
val crashlyticsPref = privacyPreferences.crashlytics()
|
||||
val crashlytics by crashlyticsPref.collectAsState()
|
||||
PermissionSwitch(
|
||||
title = stringResource(MR.strings.onboarding_permission_crashlytics),
|
||||
subtitle = stringResource(MR.strings.onboarding_permission_crashlytics_description),
|
||||
granted = crashlytics,
|
||||
onToggleChange = crashlyticsPref::set,
|
||||
)
|
||||
|
||||
val analyticsPref = privacyPreferences.analytics()
|
||||
val analytics by analyticsPref.collectAsState()
|
||||
PermissionSwitch(
|
||||
title = stringResource(MR.strings.onboarding_permission_analytics),
|
||||
subtitle = stringResource(MR.strings.onboarding_permission_analytics_description),
|
||||
granted = analytics,
|
||||
onToggleChange = analyticsPref::set,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -127,7 +157,7 @@ internal class PermissionStep : OnboardingStep {
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun PermissionItem(
|
||||
private fun PermissionCheckbox(
|
||||
title: String,
|
||||
subtitle: String,
|
||||
granted: Boolean,
|
||||
@ -157,4 +187,26 @@ internal class PermissionStep : OnboardingStep {
|
||||
colors = ListItemDefaults.colors(containerColor = Color.Transparent),
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun PermissionSwitch(
|
||||
title: String,
|
||||
subtitle: String,
|
||||
granted: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
onToggleChange: (Boolean) -> Unit,
|
||||
) {
|
||||
ListItem(
|
||||
modifier = modifier,
|
||||
headlineContent = { Text(text = title) },
|
||||
supportingContent = { Text(text = subtitle) },
|
||||
trailingContent = {
|
||||
Switch(
|
||||
checked = granted,
|
||||
onCheckedChange = onToggleChange,
|
||||
)
|
||||
},
|
||||
colors = ListItemDefaults.colors(containerColor = Color.Transparent),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,6 @@ import eu.kanade.presentation.more.settings.widget.TriStateListDialog
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.persistentMapOf
|
||||
import kotlinx.collections.immutable.toImmutableMap
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import tachiyomi.domain.category.interactor.GetCategories
|
||||
import tachiyomi.domain.category.model.Category
|
||||
import tachiyomi.domain.download.service.DownloadPreferences
|
||||
@ -35,7 +34,7 @@ object SettingsDownloadScreen : SearchableSettings {
|
||||
@Composable
|
||||
override fun getPreferences(): List<Preference> {
|
||||
val getCategories = remember { Injekt.get<GetCategories>() }
|
||||
val allCategories by getCategories.subscribe().collectAsState(initial = runBlocking { getCategories.await() })
|
||||
val allCategories by getCategories.subscribe().collectAsState(initial = emptyList())
|
||||
|
||||
val downloadPreferences = remember { Injekt.get<DownloadPreferences>() }
|
||||
return listOf(
|
||||
|
@ -24,7 +24,6 @@ import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.persistentMapOf
|
||||
import kotlinx.collections.immutable.toImmutableMap
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import tachiyomi.domain.category.interactor.GetCategories
|
||||
import tachiyomi.domain.category.interactor.ResetCategoryFlags
|
||||
import tachiyomi.domain.category.model.Category
|
||||
@ -53,7 +52,7 @@ object SettingsLibraryScreen : SearchableSettings {
|
||||
override fun getPreferences(): List<Preference> {
|
||||
val getCategories = remember { Injekt.get<GetCategories>() }
|
||||
val libraryPreferences = remember { Injekt.get<LibraryPreferences>() }
|
||||
val allCategories by getCategories.subscribe().collectAsState(initial = runBlocking { getCategories.await() })
|
||||
val allCategories by getCategories.subscribe().collectAsState(initial = emptyList())
|
||||
|
||||
return listOf(
|
||||
getCategoriesGroup(LocalNavigator.currentOrThrow, allCategories, libraryPreferences),
|
||||
|
@ -7,6 +7,7 @@ import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import eu.kanade.presentation.more.settings.Preference
|
||||
import eu.kanade.tachiyomi.core.security.PrivacyPreferences
|
||||
import eu.kanade.tachiyomi.core.security.SecurityPreferences
|
||||
import eu.kanade.tachiyomi.util.system.AuthenticatorUtil.authenticate
|
||||
import eu.kanade.tachiyomi.util.system.AuthenticatorUtil.isAuthenticationSupported
|
||||
@ -28,55 +29,91 @@ object SettingsSecurityScreen : SearchableSettings {
|
||||
|
||||
@Composable
|
||||
override fun getPreferences(): List<Preference> {
|
||||
val context = LocalContext.current
|
||||
val securityPreferences = remember { Injekt.get<SecurityPreferences>() }
|
||||
val authSupported = remember { context.isAuthenticationSupported() }
|
||||
val privacyPreferences = remember { Injekt.get<PrivacyPreferences>() }
|
||||
return listOf(
|
||||
getSecurityGroup(securityPreferences),
|
||||
getFirebaseGroup(privacyPreferences),
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun getSecurityGroup(
|
||||
securityPreferences: SecurityPreferences,
|
||||
): Preference.PreferenceGroup {
|
||||
val context = LocalContext.current
|
||||
val authSupported = remember { context.isAuthenticationSupported() }
|
||||
val useAuthPref = securityPreferences.useAuthenticator()
|
||||
val useAuth by useAuthPref.collectAsState()
|
||||
|
||||
return listOf(
|
||||
Preference.PreferenceItem.SwitchPreference(
|
||||
pref = useAuthPref,
|
||||
title = stringResource(MR.strings.lock_with_biometrics),
|
||||
enabled = authSupported,
|
||||
onValueChanged = {
|
||||
(context as FragmentActivity).authenticate(
|
||||
title = context.stringResource(MR.strings.lock_with_biometrics),
|
||||
)
|
||||
},
|
||||
),
|
||||
Preference.PreferenceItem.ListPreference(
|
||||
pref = securityPreferences.lockAppAfter(),
|
||||
title = stringResource(MR.strings.lock_when_idle),
|
||||
enabled = authSupported && useAuth,
|
||||
entries = LockAfterValues
|
||||
.associateWith {
|
||||
when (it) {
|
||||
-1 -> stringResource(MR.strings.lock_never)
|
||||
0 -> stringResource(MR.strings.lock_always)
|
||||
else -> pluralStringResource(MR.plurals.lock_after_mins, count = it, it)
|
||||
return Preference.PreferenceGroup(
|
||||
title = stringResource(MR.strings.pref_security),
|
||||
preferenceItems = persistentListOf(
|
||||
Preference.PreferenceItem.SwitchPreference(
|
||||
pref = useAuthPref,
|
||||
title = stringResource(MR.strings.lock_with_biometrics),
|
||||
enabled = authSupported,
|
||||
onValueChanged = {
|
||||
(context as FragmentActivity).authenticate(
|
||||
title = context.stringResource(MR.strings.lock_with_biometrics),
|
||||
)
|
||||
},
|
||||
),
|
||||
Preference.PreferenceItem.ListPreference(
|
||||
pref = securityPreferences.lockAppAfter(),
|
||||
title = stringResource(MR.strings.lock_when_idle),
|
||||
enabled = authSupported && useAuth,
|
||||
entries = LockAfterValues
|
||||
.associateWith {
|
||||
when (it) {
|
||||
-1 -> stringResource(MR.strings.lock_never)
|
||||
0 -> stringResource(MR.strings.lock_always)
|
||||
else -> pluralStringResource(MR.plurals.lock_after_mins, count = it, it)
|
||||
}
|
||||
}
|
||||
}
|
||||
.toImmutableMap(),
|
||||
onValueChanged = {
|
||||
(context as FragmentActivity).authenticate(
|
||||
title = context.stringResource(MR.strings.lock_when_idle),
|
||||
)
|
||||
},
|
||||
.toImmutableMap(),
|
||||
onValueChanged = {
|
||||
(context as FragmentActivity).authenticate(
|
||||
title = context.stringResource(MR.strings.lock_when_idle),
|
||||
)
|
||||
},
|
||||
),
|
||||
|
||||
Preference.PreferenceItem.SwitchPreference(
|
||||
pref = securityPreferences.hideNotificationContent(),
|
||||
title = stringResource(MR.strings.hide_notification_content),
|
||||
),
|
||||
Preference.PreferenceItem.ListPreference(
|
||||
pref = securityPreferences.secureScreen(),
|
||||
title = stringResource(MR.strings.secure_screen),
|
||||
entries = SecurityPreferences.SecureScreenMode.entries
|
||||
.associateWith { stringResource(it.titleRes) }
|
||||
.toImmutableMap(),
|
||||
),
|
||||
Preference.PreferenceItem.InfoPreference(stringResource(MR.strings.secure_screen_summary)),
|
||||
),
|
||||
Preference.PreferenceItem.SwitchPreference(
|
||||
pref = securityPreferences.hideNotificationContent(),
|
||||
title = stringResource(MR.strings.hide_notification_content),
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun getFirebaseGroup(
|
||||
privacyPreferences: PrivacyPreferences,
|
||||
): Preference.PreferenceGroup {
|
||||
return Preference.PreferenceGroup(
|
||||
title = stringResource(MR.strings.pref_firebase),
|
||||
preferenceItems = persistentListOf(
|
||||
Preference.PreferenceItem.SwitchPreference(
|
||||
pref = privacyPreferences.crashlytics(),
|
||||
title = stringResource(MR.strings.onboarding_permission_crashlytics),
|
||||
subtitle = stringResource(MR.strings.onboarding_permission_crashlytics_description),
|
||||
),
|
||||
Preference.PreferenceItem.SwitchPreference(
|
||||
pref = privacyPreferences.analytics(),
|
||||
title = stringResource(MR.strings.onboarding_permission_analytics),
|
||||
subtitle = stringResource(MR.strings.onboarding_permission_analytics_description),
|
||||
),
|
||||
Preference.PreferenceItem.InfoPreference(stringResource(MR.strings.firebase_summary)),
|
||||
),
|
||||
Preference.PreferenceItem.ListPreference(
|
||||
pref = securityPreferences.secureScreen(),
|
||||
title = stringResource(MR.strings.secure_screen),
|
||||
entries = SecurityPreferences.SecureScreenMode.entries
|
||||
.associateWith { stringResource(it.titleRes) }
|
||||
.toImmutableMap(),
|
||||
),
|
||||
Preference.PreferenceItem.InfoPreference(stringResource(MR.strings.secure_screen_summary)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -40,6 +40,7 @@ import androidx.compose.ui.text.input.VisualTransformation
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import dev.icerock.moko.resources.StringResource
|
||||
import eu.kanade.domain.track.model.AutoTrackState
|
||||
import eu.kanade.domain.track.service.TrackPreferences
|
||||
import eu.kanade.presentation.more.settings.Preference
|
||||
import eu.kanade.tachiyomi.data.track.EnhancedTracker
|
||||
@ -53,6 +54,7 @@ import eu.kanade.tachiyomi.util.system.openInBrowser
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.collections.immutable.toPersistentMap
|
||||
import tachiyomi.core.common.util.lang.launchIO
|
||||
import tachiyomi.core.common.util.lang.withUIContext
|
||||
import tachiyomi.domain.source.service.SourceManager
|
||||
@ -85,6 +87,7 @@ object SettingsTrackingScreen : SearchableSettings {
|
||||
val trackPreferences = remember { Injekt.get<TrackPreferences>() }
|
||||
val trackerManager = remember { Injekt.get<TrackerManager>() }
|
||||
val sourceManager = remember { Injekt.get<SourceManager>() }
|
||||
val autoTrackStatePref = trackPreferences.autoUpdateTrackOnMarkRead()
|
||||
|
||||
var dialog by remember { mutableStateOf<Any?>(null) }
|
||||
dialog?.run {
|
||||
@ -125,6 +128,13 @@ object SettingsTrackingScreen : SearchableSettings {
|
||||
pref = trackPreferences.autoUpdateTrack(),
|
||||
title = stringResource(MR.strings.pref_auto_update_manga_sync),
|
||||
),
|
||||
Preference.PreferenceItem.ListPreference(
|
||||
pref = trackPreferences.autoUpdateTrackOnMarkRead(),
|
||||
title = stringResource(MR.strings.pref_auto_update_manga_on_mark_read),
|
||||
entries = AutoTrackState.entries
|
||||
.associateWith { stringResource(it.titleRes) }
|
||||
.toPersistentMap(),
|
||||
),
|
||||
Preference.PreferenceGroup(
|
||||
title = stringResource(MR.strings.services),
|
||||
preferenceItems = persistentListOf(
|
||||
|
@ -45,8 +45,8 @@ fun ReaderAppBars(
|
||||
onClickTopAppBar: () -> Unit,
|
||||
bookmarked: Boolean,
|
||||
onToggleBookmarked: () -> Unit,
|
||||
onOpenInBrowser: (() -> Unit)?,
|
||||
onOpenInWebView: (() -> Unit)?,
|
||||
onOpenInBrowser: (() -> Unit)?,
|
||||
onShare: (() -> Unit)?,
|
||||
|
||||
viewer: Viewer?,
|
||||
@ -56,7 +56,7 @@ fun ReaderAppBars(
|
||||
enabledPrevious: Boolean,
|
||||
currentPage: Int,
|
||||
totalPages: Int,
|
||||
onSliderValueChange: (Int) -> Unit,
|
||||
onPageIndexChange: (Int) -> Unit,
|
||||
|
||||
readingMode: ReadingMode,
|
||||
onClickReadingMode: () -> Unit,
|
||||
@ -120,14 +120,6 @@ fun ReaderAppBars(
|
||||
onClick = onToggleBookmarked,
|
||||
),
|
||||
)
|
||||
onOpenInBrowser?.let {
|
||||
add(
|
||||
AppBar.OverflowAction(
|
||||
title = stringResource(MR.strings.action_open_in_browser),
|
||||
onClick = it,
|
||||
),
|
||||
)
|
||||
}
|
||||
onOpenInWebView?.let {
|
||||
add(
|
||||
AppBar.OverflowAction(
|
||||
@ -136,6 +128,14 @@ fun ReaderAppBars(
|
||||
),
|
||||
)
|
||||
}
|
||||
onOpenInBrowser?.let {
|
||||
add(
|
||||
AppBar.OverflowAction(
|
||||
title = stringResource(MR.strings.action_open_in_browser),
|
||||
onClick = it,
|
||||
),
|
||||
)
|
||||
}
|
||||
onShare?.let {
|
||||
add(
|
||||
AppBar.OverflowAction(
|
||||
@ -176,9 +176,8 @@ fun ReaderAppBars(
|
||||
enabledPrevious = enabledPrevious,
|
||||
currentPage = currentPage,
|
||||
totalPages = totalPages,
|
||||
onSliderValueChange = onSliderValueChange,
|
||||
onPageIndexChange = onPageIndexChange,
|
||||
)
|
||||
|
||||
BottomReaderBar(
|
||||
backgroundColor = backgroundColor,
|
||||
readingMode = readingMode,
|
||||
|
@ -4,6 +4,7 @@ import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.interaction.collectIsDraggedAsState
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
@ -16,7 +17,6 @@ import androidx.compose.material3.FilledIconButton
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButtonDefaults
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Slider
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.surfaceColorAtElevation
|
||||
import androidx.compose.runtime.Composable
|
||||
@ -29,6 +29,7 @@ import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
||||
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||
@ -38,8 +39,8 @@ import androidx.compose.ui.unit.dp
|
||||
import eu.kanade.presentation.theme.TachiyomiPreviewTheme
|
||||
import eu.kanade.presentation.util.isTabletUi
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.presentation.core.components.material.Slider
|
||||
import tachiyomi.presentation.core.i18n.stringResource
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
@Composable
|
||||
fun ChapterNavigator(
|
||||
@ -50,7 +51,7 @@ fun ChapterNavigator(
|
||||
enabledPrevious: Boolean,
|
||||
currentPage: Int,
|
||||
totalPages: Int,
|
||||
onSliderValueChange: (Int) -> Unit,
|
||||
onPageIndexChange: (Int) -> Unit,
|
||||
) {
|
||||
val isTabletUi = isTabletUi()
|
||||
val horizontalPadding = if (isTabletUi) 24.dp else 8.dp
|
||||
@ -97,7 +98,11 @@ fun ChapterNavigator(
|
||||
.padding(horizontal = 16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Text(text = currentPage.toString())
|
||||
Box(contentAlignment = Alignment.CenterEnd) {
|
||||
Text(text = currentPage.toString())
|
||||
// Taking up full length so the slider doesn't shift when 'currentPage' length changes
|
||||
Text(text = totalPages.toString(), color = Color.Transparent)
|
||||
}
|
||||
|
||||
val interactionSource = remember { MutableInteractionSource() }
|
||||
val sliderDragged by interactionSource.collectIsDraggedAsState()
|
||||
@ -110,14 +115,11 @@ fun ChapterNavigator(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(horizontal = 8.dp),
|
||||
value = currentPage.toFloat(),
|
||||
valueRange = 1f..totalPages.toFloat(),
|
||||
steps = totalPages - 2,
|
||||
onValueChange = {
|
||||
val new = it.roundToInt() - 1
|
||||
if (new != currentPage) {
|
||||
onSliderValueChange(new)
|
||||
}
|
||||
value = currentPage,
|
||||
valueRange = 1..totalPages,
|
||||
onValueChange = f@{
|
||||
if (it == currentPage) return@f
|
||||
onPageIndexChange(it - 1)
|
||||
},
|
||||
interactionSource = interactionSource,
|
||||
)
|
||||
@ -158,7 +160,7 @@ private fun ChapterNavigatorPreview() {
|
||||
enabledPrevious = true,
|
||||
currentPage = currentPage,
|
||||
totalPages = 10,
|
||||
onSliderValueChange = { currentPage = it },
|
||||
onPageIndexChange = { currentPage = (it + 1) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ import eu.kanade.domain.DomainModule
|
||||
import eu.kanade.domain.base.BasePreferences
|
||||
import eu.kanade.domain.ui.UiPreferences
|
||||
import eu.kanade.domain.ui.model.setAppCompatDelegateThemeMode
|
||||
import eu.kanade.tachiyomi.core.security.PrivacyPreferences
|
||||
import eu.kanade.tachiyomi.crash.CrashActivity
|
||||
import eu.kanade.tachiyomi.crash.GlobalExceptionHandler
|
||||
import eu.kanade.tachiyomi.data.coil.BufferedSourceFetcher
|
||||
@ -50,6 +51,7 @@ import kotlinx.coroutines.flow.onEach
|
||||
import logcat.AndroidLogcatLogger
|
||||
import logcat.LogPriority
|
||||
import logcat.LogcatLogger
|
||||
import mihon.core.firebase.FirebaseConfig
|
||||
import mihon.core.migration.Migrator
|
||||
import mihon.core.migration.migrations.migrations
|
||||
import org.conscrypt.Conscrypt
|
||||
@ -67,6 +69,7 @@ import java.security.Security
|
||||
class App : Application(), DefaultLifecycleObserver, SingletonImageLoader.Factory {
|
||||
|
||||
private val basePreferences: BasePreferences by injectLazy()
|
||||
private val privacyPreferences: PrivacyPreferences by injectLazy()
|
||||
private val networkPreferences: NetworkPreferences by injectLazy()
|
||||
|
||||
private val disableIncognitoReceiver = DisableIncognitoReceiver()
|
||||
@ -75,6 +78,7 @@ class App : Application(), DefaultLifecycleObserver, SingletonImageLoader.Factor
|
||||
override fun onCreate() {
|
||||
super<Application>.onCreate()
|
||||
patchInjekt()
|
||||
FirebaseConfig.init(applicationContext)
|
||||
|
||||
GlobalExceptionHandler.initialize(applicationContext, CrashActivity::class.java)
|
||||
|
||||
@ -97,6 +101,8 @@ class App : Application(), DefaultLifecycleObserver, SingletonImageLoader.Factor
|
||||
|
||||
ProcessLifecycleOwner.get().lifecycle.addObserver(this)
|
||||
|
||||
val scope = ProcessLifecycleOwner.get().lifecycleScope
|
||||
|
||||
// Show notification to disable Incognito Mode when it's enabled
|
||||
basePreferences.incognitoMode().changes()
|
||||
.onEach { enabled ->
|
||||
@ -124,14 +130,22 @@ class App : Application(), DefaultLifecycleObserver, SingletonImageLoader.Factor
|
||||
cancelNotification(Notifications.ID_INCOGNITO_MODE)
|
||||
}
|
||||
}
|
||||
.launchIn(ProcessLifecycleOwner.get().lifecycleScope)
|
||||
.launchIn(scope)
|
||||
|
||||
privacyPreferences.analytics()
|
||||
.changes()
|
||||
.onEach(FirebaseConfig::setAnalyticsEnabled)
|
||||
.launchIn(scope)
|
||||
|
||||
privacyPreferences.crashlytics()
|
||||
.changes()
|
||||
.onEach(FirebaseConfig::setCrashlyticsEnabled)
|
||||
.launchIn(scope)
|
||||
|
||||
setAppCompatDelegateThemeMode(Injekt.get<UiPreferences>().themeMode().get())
|
||||
|
||||
// Updates widget update
|
||||
with(WidgetManager(Injekt.get(), Injekt.get())) {
|
||||
init(ProcessLifecycleOwner.get().lifecycleScope)
|
||||
}
|
||||
WidgetManager(Injekt.get(), Injekt.get()).apply { init(scope) }
|
||||
|
||||
if (!LogcatLogger.isInstalled && networkPreferences.verboseLogging().get()) {
|
||||
LogcatLogger.install(AndroidLogcatLogger(LogPriority.VERBOSE))
|
||||
|
@ -11,7 +11,6 @@ import kotlinx.serialization.encoding.Encoder
|
||||
import kotlinx.serialization.json.Json
|
||||
import logcat.LogPriority
|
||||
import tachiyomi.core.common.util.system.logcat
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
class GlobalExceptionHandler private constructor(
|
||||
private val applicationContext: Context,
|
||||
@ -31,13 +30,9 @@ class GlobalExceptionHandler private constructor(
|
||||
}
|
||||
|
||||
override fun uncaughtException(thread: Thread, exception: Throwable) {
|
||||
try {
|
||||
logcat(priority = LogPriority.ERROR, throwable = exception)
|
||||
launchActivity(applicationContext, activityToBeLaunched, exception)
|
||||
exitProcess(0)
|
||||
} catch (_: Exception) {
|
||||
defaultHandler.uncaughtException(thread, exception)
|
||||
}
|
||||
logcat(priority = LogPriority.ERROR, throwable = exception)
|
||||
launchActivity(applicationContext, activityToBeLaunched, exception)
|
||||
defaultHandler.uncaughtException(thread, exception)
|
||||
}
|
||||
|
||||
private fun launchActivity(
|
||||
|
@ -27,6 +27,7 @@ import tachiyomi.core.common.util.system.logcat
|
||||
import tachiyomi.domain.backup.service.BackupPreferences
|
||||
import tachiyomi.domain.manga.interactor.GetFavorites
|
||||
import tachiyomi.domain.manga.model.Manga
|
||||
import tachiyomi.domain.manga.repository.MangaRepository
|
||||
import tachiyomi.i18n.MR
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
@ -43,6 +44,7 @@ class BackupCreator(
|
||||
private val parser: ProtoBuf = Injekt.get(),
|
||||
private val getFavorites: GetFavorites = Injekt.get(),
|
||||
private val backupPreferences: BackupPreferences = Injekt.get(),
|
||||
private val mangaRepository: MangaRepository = Injekt.get(),
|
||||
|
||||
private val categoriesBackupCreator: CategoriesBackupCreator = CategoriesBackupCreator(),
|
||||
private val mangaBackupCreator: MangaBackupCreator = MangaBackupCreator(),
|
||||
@ -75,7 +77,9 @@ class BackupCreator(
|
||||
throw IllegalStateException(context.stringResource(MR.strings.create_backup_file_error))
|
||||
}
|
||||
|
||||
val backupManga = backupMangas(getFavorites.await(), options)
|
||||
val nonFavoriteManga = if (options.readEntries) mangaRepository.getReadMangaNotInLibrary() else emptyList()
|
||||
val backupManga = backupMangas(getFavorites.await() + nonFavoriteManga, options)
|
||||
|
||||
val backup = Backup(
|
||||
backupManga = backupManga,
|
||||
backupCategories = backupCategories(options),
|
||||
|
@ -10,6 +10,7 @@ data class BackupOptions(
|
||||
val chapters: Boolean = true,
|
||||
val tracking: Boolean = true,
|
||||
val history: Boolean = true,
|
||||
val readEntries: Boolean = true,
|
||||
val appSettings: Boolean = true,
|
||||
val extensionRepoSettings: Boolean = true,
|
||||
val sourceSettings: Boolean = true,
|
||||
@ -22,6 +23,7 @@ data class BackupOptions(
|
||||
chapters,
|
||||
tracking,
|
||||
history,
|
||||
readEntries,
|
||||
appSettings,
|
||||
extensionRepoSettings,
|
||||
sourceSettings,
|
||||
@ -60,6 +62,12 @@ data class BackupOptions(
|
||||
getter = BackupOptions::categories,
|
||||
setter = { options, enabled -> options.copy(categories = enabled) },
|
||||
),
|
||||
Entry(
|
||||
label = MR.strings.non_library_settings,
|
||||
getter = BackupOptions::readEntries,
|
||||
setter = { options, enabled -> options.copy(readEntries = enabled) },
|
||||
enabled = { it.libraryEntries },
|
||||
),
|
||||
)
|
||||
|
||||
val settingsOptions = persistentListOf(
|
||||
@ -92,10 +100,11 @@ data class BackupOptions(
|
||||
chapters = array[2],
|
||||
tracking = array[3],
|
||||
history = array[4],
|
||||
appSettings = array[5],
|
||||
extensionRepoSettings = array[6],
|
||||
sourceSettings = array[7],
|
||||
privateSettings = array[8],
|
||||
readEntries = array[5],
|
||||
appSettings = array[6],
|
||||
extensionRepoSettings = array[7],
|
||||
sourceSettings = array[8],
|
||||
privateSettings = array[9],
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
@file:Suppress("PropertyName", "ktlint:standard:property-naming")
|
||||
@file:Suppress("PropertyName")
|
||||
|
||||
package eu.kanade.tachiyomi.data.database.models
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
@file:Suppress("PropertyName", "ktlint:standard:property-naming")
|
||||
@file:Suppress("PropertyName")
|
||||
|
||||
package eu.kanade.tachiyomi.data.database.models
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
@file:Suppress("PropertyName", "ktlint:standard:property-naming")
|
||||
@file:Suppress("PropertyName")
|
||||
|
||||
package eu.kanade.tachiyomi.data.database.models
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
@file:Suppress("PropertyName", "ktlint:standard:property-naming")
|
||||
@file:Suppress("PropertyName")
|
||||
|
||||
package eu.kanade.tachiyomi.data.database.models
|
||||
|
||||
|
@ -96,13 +96,13 @@ class DownloadCache(
|
||||
private val diskCacheFile: File
|
||||
get() = File(context.cacheDir, "dl_index_cache_v3")
|
||||
|
||||
private val rootDownloadsDirLock = Mutex()
|
||||
private val rootDownloadsDirMutex = Mutex()
|
||||
private var rootDownloadsDir = RootDirectory(storageManager.getDownloadsDirectory())
|
||||
|
||||
init {
|
||||
// Attempt to read cache file
|
||||
scope.launch {
|
||||
rootDownloadsDirLock.withLock {
|
||||
rootDownloadsDirMutex.withLock {
|
||||
try {
|
||||
if (diskCacheFile.exists()) {
|
||||
val diskCache = diskCacheFile.inputStream().use {
|
||||
@ -112,7 +112,7 @@ class DownloadCache(
|
||||
lastRenew = System.currentTimeMillis()
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
logcat(LogPriority.ERROR, e) { "Failed to initialize disk cache" }
|
||||
logcat(LogPriority.ERROR, e) { "Failed to initialize from disk cache" }
|
||||
diskCacheFile.delete()
|
||||
}
|
||||
}
|
||||
@ -198,7 +198,7 @@ class DownloadCache(
|
||||
* @param manga the manga of the chapter.
|
||||
*/
|
||||
suspend fun addChapter(chapterDirName: String, mangaUniFile: UniFile, manga: Manga) {
|
||||
rootDownloadsDirLock.withLock {
|
||||
rootDownloadsDirMutex.withLock {
|
||||
// Retrieve the cached source directory or cache a new one
|
||||
var sourceDir = rootDownloadsDir.sourceDirs[manga.source]
|
||||
if (sourceDir == null) {
|
||||
@ -230,7 +230,7 @@ class DownloadCache(
|
||||
* @param manga the manga of the chapter.
|
||||
*/
|
||||
suspend fun removeChapter(chapter: Chapter, manga: Manga) {
|
||||
rootDownloadsDirLock.withLock {
|
||||
rootDownloadsDirMutex.withLock {
|
||||
val sourceDir = rootDownloadsDir.sourceDirs[manga.source] ?: return
|
||||
val mangaDir = sourceDir.mangaDirs[provider.getMangaDirName(manga.title)] ?: return
|
||||
provider.getValidChapterDirNames(chapter.name, chapter.scanlator).forEach {
|
||||
@ -250,7 +250,7 @@ class DownloadCache(
|
||||
* @param manga the manga of the chapter.
|
||||
*/
|
||||
suspend fun removeChapters(chapters: List<Chapter>, manga: Manga) {
|
||||
rootDownloadsDirLock.withLock {
|
||||
rootDownloadsDirMutex.withLock {
|
||||
val sourceDir = rootDownloadsDir.sourceDirs[manga.source] ?: return
|
||||
val mangaDir = sourceDir.mangaDirs[provider.getMangaDirName(manga.title)] ?: return
|
||||
chapters.forEach { chapter ->
|
||||
@ -271,7 +271,7 @@ class DownloadCache(
|
||||
* @param manga the manga to remove.
|
||||
*/
|
||||
suspend fun removeManga(manga: Manga) {
|
||||
rootDownloadsDirLock.withLock {
|
||||
rootDownloadsDirMutex.withLock {
|
||||
val sourceDir = rootDownloadsDir.sourceDirs[manga.source] ?: return
|
||||
val mangaDirName = provider.getMangaDirName(manga.title)
|
||||
if (sourceDir.mangaDirs.containsKey(mangaDirName)) {
|
||||
@ -283,7 +283,7 @@ class DownloadCache(
|
||||
}
|
||||
|
||||
suspend fun removeSource(source: Source) {
|
||||
rootDownloadsDirLock.withLock {
|
||||
rootDownloadsDirMutex.withLock {
|
||||
rootDownloadsDir.sourceDirs -= source.id
|
||||
}
|
||||
|
||||
@ -322,10 +322,10 @@ class DownloadCache(
|
||||
|
||||
val sourceMap = sources.associate { provider.getSourceDirName(it).lowercase() to it.id }
|
||||
|
||||
rootDownloadsDirLock.withLock {
|
||||
rootDownloadsDir = RootDirectory(storageManager.getDownloadsDirectory())
|
||||
rootDownloadsDirMutex.withLock {
|
||||
val updatedRootDir = RootDirectory(storageManager.getDownloadsDirectory())
|
||||
|
||||
val sourceDirs = rootDownloadsDir.dir?.listFiles().orEmpty()
|
||||
updatedRootDir.sourceDirs = updatedRootDir.dir?.listFiles().orEmpty()
|
||||
.filter { it.isDirectory && !it.name.isNullOrBlank() }
|
||||
.mapNotNull { dir ->
|
||||
val sourceId = sourceMap[dir.name!!.lowercase()]
|
||||
@ -333,36 +333,35 @@ class DownloadCache(
|
||||
}
|
||||
.toMap()
|
||||
|
||||
rootDownloadsDir.sourceDirs = sourceDirs
|
||||
updatedRootDir.sourceDirs.values.map { sourceDir ->
|
||||
async {
|
||||
sourceDir.mangaDirs = sourceDir.dir?.listFiles().orEmpty()
|
||||
.filter { it.isDirectory && !it.name.isNullOrBlank() }
|
||||
.associate { it.name!! to MangaDirectory(it) }
|
||||
|
||||
sourceDirs.values
|
||||
.map { sourceDir ->
|
||||
async {
|
||||
sourceDir.mangaDirs = sourceDir.dir?.listFiles().orEmpty()
|
||||
.filter { it.isDirectory && !it.name.isNullOrBlank() }
|
||||
.associate { it.name!! to MangaDirectory(it) }
|
||||
|
||||
sourceDir.mangaDirs.values.forEach { mangaDir ->
|
||||
val chapterDirs = mangaDir.dir?.listFiles().orEmpty()
|
||||
.mapNotNull {
|
||||
when {
|
||||
// Ignore incomplete downloads
|
||||
it.name?.endsWith(Downloader.TMP_DIR_SUFFIX) == true -> null
|
||||
// Folder of images
|
||||
it.isDirectory -> it.name
|
||||
// CBZ files
|
||||
it.isFile && it.extension == "cbz" -> it.nameWithoutExtension
|
||||
// Anything else is irrelevant
|
||||
else -> null
|
||||
}
|
||||
sourceDir.mangaDirs.values.forEach { mangaDir ->
|
||||
val chapterDirs = mangaDir.dir?.listFiles().orEmpty()
|
||||
.mapNotNull {
|
||||
when {
|
||||
// Ignore incomplete downloads
|
||||
it.name?.endsWith(Downloader.TMP_DIR_SUFFIX) == true -> null
|
||||
// Folder of images
|
||||
it.isDirectory -> it.name
|
||||
// CBZ files
|
||||
it.isFile && it.extension == "cbz" -> it.nameWithoutExtension
|
||||
// Anything else is irrelevant
|
||||
else -> null
|
||||
}
|
||||
.toMutableSet()
|
||||
}
|
||||
.toMutableSet()
|
||||
|
||||
mangaDir.chapterDirs = chapterDirs
|
||||
}
|
||||
mangaDir.chapterDirs = chapterDirs
|
||||
}
|
||||
}
|
||||
}
|
||||
.awaitAll()
|
||||
|
||||
rootDownloadsDir = updatedRootDir
|
||||
}
|
||||
|
||||
_isInitializing.emit(false)
|
||||
|
@ -1,4 +1,4 @@
|
||||
@file:Suppress("PropertyName", "ktlint:standard:property-naming")
|
||||
@file:Suppress("PropertyName")
|
||||
|
||||
package eu.kanade.tachiyomi.data.track.model
|
||||
|
||||
|
@ -5,6 +5,7 @@ import eu.kanade.domain.base.BasePreferences
|
||||
import eu.kanade.domain.source.service.SourcePreferences
|
||||
import eu.kanade.domain.track.service.TrackPreferences
|
||||
import eu.kanade.domain.ui.UiPreferences
|
||||
import eu.kanade.tachiyomi.core.security.PrivacyPreferences
|
||||
import eu.kanade.tachiyomi.core.security.SecurityPreferences
|
||||
import eu.kanade.tachiyomi.network.NetworkPreferences
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences
|
||||
@ -39,6 +40,9 @@ class PreferenceModule(val app: Application) : InjektModule {
|
||||
addSingletonFactory {
|
||||
SecurityPreferences(get())
|
||||
}
|
||||
addSingletonFactory {
|
||||
PrivacyPreferences(get())
|
||||
}
|
||||
addSingletonFactory {
|
||||
LibraryPreferences(get())
|
||||
}
|
||||
|
@ -1,8 +1,15 @@
|
||||
package eu.kanade.tachiyomi.ui.browse.extension
|
||||
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||
import eu.kanade.presentation.browse.ExtensionScreen
|
||||
@ -12,6 +19,7 @@ import eu.kanade.presentation.more.settings.screen.browse.ExtensionReposScreen
|
||||
import eu.kanade.tachiyomi.extension.model.Extension
|
||||
import eu.kanade.tachiyomi.ui.browse.extension.details.ExtensionDetailsScreen
|
||||
import eu.kanade.tachiyomi.ui.webview.WebViewScreen
|
||||
import eu.kanade.tachiyomi.util.system.isPackageInstalled
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.presentation.core.i18n.stringResource
|
||||
@ -21,7 +29,10 @@ fun extensionsTab(
|
||||
extensionsScreenModel: ExtensionsScreenModel,
|
||||
): TabContent {
|
||||
val navigator = LocalNavigator.currentOrThrow
|
||||
val context = LocalContext.current
|
||||
|
||||
val state by extensionsScreenModel.state.collectAsState()
|
||||
var privateExtensionToUninstall by remember { mutableStateOf<Extension?>(null) }
|
||||
|
||||
return TabContent(
|
||||
titleRes = MR.strings.label_extensions,
|
||||
@ -45,7 +56,13 @@ fun extensionsTab(
|
||||
onLongClickItem = { extension ->
|
||||
when (extension) {
|
||||
is Extension.Available -> extensionsScreenModel.installExtension(extension)
|
||||
else -> extensionsScreenModel.uninstallExtension(extension)
|
||||
else -> {
|
||||
if (context.isPackageInstalled(extension.pkgName)) {
|
||||
extensionsScreenModel.uninstallExtension(extension)
|
||||
} else {
|
||||
privateExtensionToUninstall = extension
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
onClickItemCancel = extensionsScreenModel::cancelInstallUpdateExtension,
|
||||
@ -68,6 +85,50 @@ fun extensionsTab(
|
||||
onUpdateExtension = extensionsScreenModel::updateExtension,
|
||||
onRefresh = extensionsScreenModel::findAvailableExtensions,
|
||||
)
|
||||
|
||||
privateExtensionToUninstall?.let { extension ->
|
||||
ExtensionUninstallConfirmation(
|
||||
extensionName = extension.name,
|
||||
onClickConfirm = {
|
||||
extensionsScreenModel.uninstallExtension(extension)
|
||||
},
|
||||
onDismissRequest = {
|
||||
privateExtensionToUninstall = null
|
||||
},
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ExtensionUninstallConfirmation(
|
||||
extensionName: String,
|
||||
onClickConfirm: () -> Unit,
|
||||
onDismissRequest: () -> Unit,
|
||||
) {
|
||||
AlertDialog(
|
||||
title = {
|
||||
Text(text = stringResource(MR.strings.ext_confirm_remove))
|
||||
},
|
||||
text = {
|
||||
Text(text = stringResource(MR.strings.remove_private_extension_message, extensionName))
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
onClickConfirm()
|
||||
onDismissRequest()
|
||||
},
|
||||
) {
|
||||
Text(text = stringResource(MR.strings.ext_remove))
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(onClick = onDismissRequest) {
|
||||
Text(text = stringResource(MR.strings.action_cancel))
|
||||
}
|
||||
},
|
||||
onDismissRequest = onDismissRequest,
|
||||
)
|
||||
}
|
||||
|
@ -72,6 +72,7 @@ import tachiyomi.domain.track.model.Track
|
||||
import tachiyomi.source.local.isLocal
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import kotlin.random.Random
|
||||
|
||||
/**
|
||||
* Typealias for the library manga, using the category as keys, and list of manga as values.
|
||||
@ -300,10 +301,17 @@ class LibraryScreenModel(
|
||||
val item2Score = trackerScores[i2.libraryManga.id] ?: defaultTrackerScoreSortValue
|
||||
item1Score.compareTo(item2Score)
|
||||
}
|
||||
LibrarySort.Type.Random -> {
|
||||
error("Why Are We Still Here? Just To Suffer?")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return mapValues { (key, value) ->
|
||||
if (key.sort.type == LibrarySort.Type.Random) {
|
||||
return@mapValues value.shuffled(Random(libraryPreferences.randomSortSeed().get()))
|
||||
}
|
||||
|
||||
val comparator = key.sort.comparator()
|
||||
.let { if (key.sort.isAscending) it else it.reversed() }
|
||||
.thenComparator(sortAlphabetically)
|
||||
|
@ -278,12 +278,13 @@ class MainActivity : BaseActivity() {
|
||||
@Composable
|
||||
private fun HandleOnNewIntent(context: Context, navigator: Navigator) {
|
||||
LaunchedEffect(Unit) {
|
||||
callbackFlow<Intent> {
|
||||
callbackFlow {
|
||||
val componentActivity = context as ComponentActivity
|
||||
val consumer = Consumer<Intent> { trySend(it) }
|
||||
componentActivity.addOnNewIntentListener(consumer)
|
||||
awaitClose { componentActivity.removeOnNewIntentListener(consumer) }
|
||||
}.collectLatest { handleIntentAction(it, navigator) }
|
||||
}
|
||||
.collectLatest { handleIntentAction(it, navigator) }
|
||||
}
|
||||
}
|
||||
|
||||
@ -339,6 +340,7 @@ class MainActivity : BaseActivity() {
|
||||
* When custom animation is used, status and navigation bar color will be set to transparent and will be restored
|
||||
* after the animation is finished.
|
||||
*/
|
||||
@Suppress("Deprecation")
|
||||
private fun setSplashScreenExitAnimation(splashScreen: SplashScreen?) {
|
||||
val root = findViewById<View>(android.R.id.content)
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S && splashScreen != null) {
|
||||
|
@ -25,6 +25,8 @@ import eu.kanade.domain.manga.model.downloadedFilter
|
||||
import eu.kanade.domain.manga.model.toSManga
|
||||
import eu.kanade.domain.track.interactor.AddTracks
|
||||
import eu.kanade.domain.track.interactor.TrackChapter
|
||||
import eu.kanade.domain.track.model.AutoTrackState
|
||||
import eu.kanade.domain.track.service.TrackPreferences
|
||||
import eu.kanade.presentation.manga.DownloadAction
|
||||
import eu.kanade.presentation.manga.components.ChapterDownloadAction
|
||||
import eu.kanade.presentation.util.formattedMessage
|
||||
@ -38,6 +40,7 @@ import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences
|
||||
import eu.kanade.tachiyomi.util.chapter.getNextUnread
|
||||
import eu.kanade.tachiyomi.util.removeCovers
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.async
|
||||
@ -92,6 +95,7 @@ class MangaScreenModel(
|
||||
private val mangaId: Long,
|
||||
private val isFromSource: Boolean,
|
||||
private val libraryPreferences: LibraryPreferences = Injekt.get(),
|
||||
private val trackPreferences: TrackPreferences = Injekt.get(),
|
||||
readerPreferences: ReaderPreferences = Injekt.get(),
|
||||
private val trackerManager: TrackerManager = Injekt.get(),
|
||||
private val trackChapter: TrackChapter = Injekt.get(),
|
||||
@ -137,6 +141,7 @@ class MangaScreenModel(
|
||||
|
||||
val chapterSwipeStartAction = libraryPreferences.swipeToEndAction().get()
|
||||
val chapterSwipeEndAction = libraryPreferences.swipeToStartAction().get()
|
||||
var autoTrackState = trackPreferences.autoUpdateTrackOnMarkRead().get()
|
||||
|
||||
private val skipFiltered by readerPreferences.skipFiltered().asState(screenModelScope)
|
||||
|
||||
@ -731,13 +736,25 @@ class MangaScreenModel(
|
||||
chapters = chapters.toTypedArray(),
|
||||
)
|
||||
|
||||
if (!read) return@launchIO
|
||||
if (
|
||||
successState?.hasLoggedInTrackers == false ||
|
||||
!read || autoTrackState == AutoTrackState.NEVER
|
||||
) {
|
||||
return@launchIO
|
||||
}
|
||||
|
||||
val tracks = getTracks.await(mangaId)
|
||||
val maxChapterNumber = chapters.maxOf { it.chapterNumber }
|
||||
val shouldPromptTrackingUpdate = tracks.any { track -> maxChapterNumber > track.lastChapterRead }
|
||||
|
||||
if (!shouldPromptTrackingUpdate) return@launchIO
|
||||
if (autoTrackState == AutoTrackState.ALWAYS) {
|
||||
trackChapter.await(context, mangaId, maxChapterNumber)
|
||||
withUIContext {
|
||||
context.toast(context.stringResource(MR.strings.trackers_updated_summary, maxChapterNumber.toInt()))
|
||||
}
|
||||
return@launchIO
|
||||
}
|
||||
|
||||
val result = snackbarHostState.showSnackbar(
|
||||
message = context.stringResource(MR.strings.confirm_tracker_update, maxChapterNumber.toInt()),
|
||||
|
@ -824,7 +824,11 @@ private data class TrackerRemoveScreen(
|
||||
|
||||
fun deleteMangaFromService() {
|
||||
screenModelScope.launchNonCancellable {
|
||||
(tracker as DeletableTracker).delete(track)
|
||||
try {
|
||||
(tracker as DeletableTracker).delete(track)
|
||||
} catch (e: Exception) {
|
||||
logcat(LogPriority.ERROR, e) { "Failed to delete entry from service" }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -390,8 +390,8 @@ class ReaderActivity : BaseActivity() {
|
||||
onClickTopAppBar = ::openMangaScreen,
|
||||
bookmarked = state.bookmarked,
|
||||
onToggleBookmarked = viewModel::toggleChapterBookmark,
|
||||
onOpenInBrowser = ::openChapterInBrowser.takeIf { isHttpSource },
|
||||
onOpenInWebView = ::openChapterInWebView.takeIf { isHttpSource },
|
||||
onOpenInBrowser = ::openChapterInBrowser.takeIf { isHttpSource },
|
||||
onShare = ::shareChapter.takeIf { isHttpSource },
|
||||
|
||||
viewer = state.viewer,
|
||||
@ -401,7 +401,7 @@ class ReaderActivity : BaseActivity() {
|
||||
enabledPrevious = state.viewerChapters?.prevChapter != null,
|
||||
currentPage = state.currentPage,
|
||||
totalPages = state.totalPages,
|
||||
onSliderValueChange = {
|
||||
onPageIndexChange = {
|
||||
isScrollingThroughPages = true
|
||||
moveToPageIndex(it)
|
||||
},
|
||||
@ -565,12 +565,6 @@ class ReaderActivity : BaseActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun openChapterInBrowser() {
|
||||
assistUrl?.let {
|
||||
openInBrowser(it.toUri(), forceDefaultBrowser = false)
|
||||
}
|
||||
}
|
||||
|
||||
private fun openChapterInWebView() {
|
||||
val manga = viewModel.manga ?: return
|
||||
val source = viewModel.getSource() ?: return
|
||||
@ -580,6 +574,12 @@ class ReaderActivity : BaseActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun openChapterInBrowser() {
|
||||
assistUrl?.let {
|
||||
openInBrowser(it.toUri(), forceDefaultBrowser = false)
|
||||
}
|
||||
}
|
||||
|
||||
private fun shareChapter() {
|
||||
assistUrl?.let {
|
||||
val intent = it.toUri().toShareIntent(this, type = "text/plain")
|
||||
|
@ -1,18 +1,25 @@
|
||||
package mihon.feature.upcoming
|
||||
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyListState
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.outlined.HelpOutline
|
||||
import androidx.compose.material3.Badge
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalUriHandler
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||
import eu.kanade.presentation.components.AppBar
|
||||
@ -27,9 +34,9 @@ import tachiyomi.core.common.Constants
|
||||
import tachiyomi.domain.manga.model.Manga
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.presentation.core.components.FastScrollLazyColumn
|
||||
import tachiyomi.presentation.core.components.ListGroupHeader
|
||||
import tachiyomi.presentation.core.components.TwoPanelBox
|
||||
import tachiyomi.presentation.core.components.material.Scaffold
|
||||
import tachiyomi.presentation.core.components.material.padding
|
||||
import tachiyomi.presentation.core.i18n.stringResource
|
||||
import java.time.LocalDate
|
||||
import java.time.YearMonth
|
||||
@ -99,6 +106,33 @@ private fun UpcomingToolbar() {
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DateHeading(
|
||||
date: LocalDate,
|
||||
mangaCount: Int,
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
) {
|
||||
Text(
|
||||
text = relativeDateText(date),
|
||||
modifier = Modifier
|
||||
.padding(MaterialTheme.padding.small)
|
||||
.padding(start = MaterialTheme.padding.small),
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
)
|
||||
Badge(
|
||||
containerColor = MaterialTheme.colorScheme.primary,
|
||||
contentColor = MaterialTheme.colorScheme.onPrimary,
|
||||
) {
|
||||
Text("$mangaCount")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun UpcomingScreenSmallImpl(
|
||||
listState: LazyListState,
|
||||
@ -140,7 +174,10 @@ private fun UpcomingScreenSmallImpl(
|
||||
)
|
||||
}
|
||||
is UpcomingUIModel.Header -> {
|
||||
ListGroupHeader(text = relativeDateText(item.date))
|
||||
DateHeading(
|
||||
date = item.date,
|
||||
mangaCount = item.mangaCount,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -188,7 +225,10 @@ private fun UpcomingScreenLargeImpl(
|
||||
)
|
||||
}
|
||||
is UpcomingUIModel.Header -> {
|
||||
ListGroupHeader(text = relativeDateText(item.date))
|
||||
DateHeading(
|
||||
date = item.date,
|
||||
mangaCount = item.mangaCount,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import androidx.compose.ui.util.fastMap
|
||||
import androidx.compose.ui.util.fastMapIndexedNotNull
|
||||
import cafe.adriel.voyager.core.model.StateScreenModel
|
||||
import cafe.adriel.voyager.core.model.screenModelScope
|
||||
import eu.kanade.core.util.insertSeparators
|
||||
import eu.kanade.core.util.insertSeparatorsReversed
|
||||
import eu.kanade.tachiyomi.util.lang.toLocalDate
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.ImmutableMap
|
||||
@ -33,7 +33,7 @@ class UpcomingScreenModel(
|
||||
val upcomingItems = it.toUpcomingUIModels()
|
||||
state.copy(
|
||||
items = upcomingItems,
|
||||
events = it.toEvents(),
|
||||
events = upcomingItems.toEvents(),
|
||||
headerIndexes = upcomingItems.getHeaderIndexes(),
|
||||
)
|
||||
}
|
||||
@ -42,13 +42,16 @@ class UpcomingScreenModel(
|
||||
}
|
||||
|
||||
private fun List<Manga>.toUpcomingUIModels(): ImmutableList<UpcomingUIModel> {
|
||||
var mangaCount = 0
|
||||
return fastMap { UpcomingUIModel.Item(it) }
|
||||
.insertSeparators { before, after ->
|
||||
.insertSeparatorsReversed { before, after ->
|
||||
if (after != null) mangaCount++
|
||||
|
||||
val beforeDate = before?.manga?.expectedNextUpdate?.toLocalDate()
|
||||
val afterDate = after?.manga?.expectedNextUpdate?.toLocalDate()
|
||||
|
||||
if (beforeDate != afterDate && afterDate != null) {
|
||||
UpcomingUIModel.Header(afterDate)
|
||||
UpcomingUIModel.Header(afterDate, mangaCount).also { mangaCount = 0 }
|
||||
} else {
|
||||
null
|
||||
}
|
||||
@ -56,9 +59,9 @@ class UpcomingScreenModel(
|
||||
.toImmutableList()
|
||||
}
|
||||
|
||||
private fun List<Manga>.toEvents(): ImmutableMap<LocalDate, Int> {
|
||||
return groupBy { it.expectedNextUpdate?.toLocalDate() ?: LocalDate.MAX }
|
||||
.mapValues { it.value.size }
|
||||
private fun List<UpcomingUIModel>.toEvents(): ImmutableMap<LocalDate, Int> {
|
||||
return filterIsInstance<UpcomingUIModel.Header>()
|
||||
.associate { it.date to it.mangaCount }
|
||||
.toImmutableMap()
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,6 @@ import tachiyomi.domain.manga.model.Manga
|
||||
import java.time.LocalDate
|
||||
|
||||
sealed interface UpcomingUIModel {
|
||||
data class Header(val date: LocalDate) : UpcomingUIModel
|
||||
data class Header(val date: LocalDate, val mangaCount: Int) : UpcomingUIModel
|
||||
data class Item(val manga: Manga) : UpcomingUIModel
|
||||
}
|
||||
|
@ -20,6 +20,15 @@
|
||||
tools:node="remove" />
|
||||
|
||||
<application>
|
||||
<!-- 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 unnecessary stuff from Firebase -->
|
||||
<meta-data
|
||||
android:name="google_analytics_adid_collection_enabled"
|
||||
|
25
app/src/standard/java/mihon/core/firebase/FirebaseConfig.kt
Normal file
25
app/src/standard/java/mihon/core/firebase/FirebaseConfig.kt
Normal file
@ -0,0 +1,25 @@
|
||||
package mihon.core.firebase
|
||||
|
||||
import android.content.Context
|
||||
import com.google.firebase.FirebaseApp
|
||||
import com.google.firebase.analytics.FirebaseAnalytics
|
||||
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||
|
||||
object FirebaseConfig {
|
||||
private lateinit var analytics: FirebaseAnalytics
|
||||
private lateinit var crashlytics: FirebaseCrashlytics
|
||||
|
||||
fun init(context: Context) {
|
||||
analytics = FirebaseAnalytics.getInstance(context)
|
||||
FirebaseApp.initializeApp(context)
|
||||
crashlytics = FirebaseCrashlytics.getInstance()
|
||||
}
|
||||
|
||||
fun setAnalyticsEnabled(enabled: Boolean) {
|
||||
analytics.setAnalyticsCollectionEnabled(enabled)
|
||||
}
|
||||
|
||||
fun setCrashlyticsEnabled(enabled: Boolean) {
|
||||
crashlytics.isCrashlyticsCollectionEnabled = enabled
|
||||
}
|
||||
}
|
1
buildSrc/.gitignore
vendored
1
buildSrc/.gitignore
vendored
@ -1 +0,0 @@
|
||||
/build
|
@ -6,6 +6,18 @@ plugins {
|
||||
|
||||
val libs = the<LibrariesForLibs>()
|
||||
|
||||
val xmlFormatExclude = buildList(2) {
|
||||
add("**/build/**/*.xml")
|
||||
|
||||
projectDir
|
||||
.resolve("src/commonMain/moko-resources")
|
||||
.takeIf { it.isDirectory }
|
||||
?.let(::fileTree)
|
||||
?.matching { exclude("/base/**") }
|
||||
?.let(::add)
|
||||
}
|
||||
.toTypedArray()
|
||||
|
||||
spotless {
|
||||
kotlin {
|
||||
target("**/*.kt", "**/*.kts")
|
||||
@ -23,7 +35,7 @@ spotless {
|
||||
}
|
||||
format("xml") {
|
||||
target("**/*.xml")
|
||||
targetExclude("**/build/**/*.xml")
|
||||
targetExclude(*xmlFormatExclude)
|
||||
trimTrailingWhitespace()
|
||||
endWithNewline()
|
||||
}
|
||||
|
1
core-metadata/.gitignore
vendored
1
core-metadata/.gitignore
vendored
@ -1 +0,0 @@
|
||||
/build
|
1
core/archive/.gitignore
vendored
1
core/archive/.gitignore
vendored
@ -1 +0,0 @@
|
||||
/build
|
1
core/common/.gitignore
vendored
1
core/common/.gitignore
vendored
@ -1 +0,0 @@
|
||||
/build
|
@ -0,0 +1,11 @@
|
||||
package eu.kanade.tachiyomi.core.security
|
||||
|
||||
import tachiyomi.core.common.preference.PreferenceStore
|
||||
|
||||
class PrivacyPreferences(
|
||||
private val preferenceStore: PreferenceStore,
|
||||
) {
|
||||
fun crashlytics() = preferenceStore.getBoolean("crashlytics", true)
|
||||
|
||||
fun analytics() = preferenceStore.getBoolean("analytics", true)
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
@file:Suppress("FunctionName", "ktlint:standard:function-naming")
|
||||
@file:Suppress("FunctionName")
|
||||
|
||||
package eu.kanade.tachiyomi.network
|
||||
|
||||
|
1
data/.gitignore
vendored
1
data/.gitignore
vendored
@ -1 +0,0 @@
|
||||
/build
|
@ -49,6 +49,10 @@ class MangaRepositoryImpl(
|
||||
return handler.awaitList { mangasQueries.getFavorites(MangaMapper::mapManga) }
|
||||
}
|
||||
|
||||
override suspend fun getReadMangaNotInLibrary(): List<Manga> {
|
||||
return handler.awaitList { mangasQueries.getReadMangaNotInLibrary(MangaMapper::mapManga) }
|
||||
}
|
||||
|
||||
override suspend fun getLibraryManga(): List<LibraryManga> {
|
||||
return handler.awaitList { libraryViewQueries.library(MangaMapper::mapLibraryManga) }
|
||||
}
|
||||
|
@ -78,6 +78,15 @@ SELECT *
|
||||
FROM mangas
|
||||
WHERE favorite = 1;
|
||||
|
||||
getReadMangaNotInLibrary:
|
||||
SELECT *
|
||||
FROM mangas
|
||||
WHERE favorite = 0 AND _id IN (
|
||||
SELECT DISTINCT chapters.manga_id
|
||||
FROM chapters
|
||||
WHERE read = 1 OR last_page_read != 0
|
||||
);
|
||||
|
||||
getAllManga:
|
||||
SELECT *
|
||||
FROM mangas;
|
||||
|
1
domain/.gitignore
vendored
1
domain/.gitignore
vendored
@ -1 +0,0 @@
|
||||
/build
|
@ -6,6 +6,7 @@ import tachiyomi.domain.category.repository.CategoryRepository
|
||||
import tachiyomi.domain.library.model.LibrarySort
|
||||
import tachiyomi.domain.library.model.plus
|
||||
import tachiyomi.domain.library.service.LibraryPreferences
|
||||
import kotlin.random.Random
|
||||
|
||||
class SetSortModeForCategory(
|
||||
private val preferences: LibraryPreferences,
|
||||
@ -15,6 +16,9 @@ class SetSortModeForCategory(
|
||||
suspend fun await(categoryId: Long?, type: LibrarySort.Type, direction: LibrarySort.Direction) {
|
||||
val category = categoryId?.let { categoryRepository.get(it) }
|
||||
val flags = (category?.flags ?: 0) + type + direction
|
||||
if (type == LibrarySort.Type.Random) {
|
||||
preferences.randomSortSeed().set(Random.nextInt())
|
||||
}
|
||||
if (category != null && preferences.categorizedDisplaySettings().get()) {
|
||||
categoryRepository.updatePartial(
|
||||
CategoryUpdate(
|
||||
|
@ -30,7 +30,8 @@ data class LibrarySort(
|
||||
data object LatestChapter : Type(0b00010100)
|
||||
data object ChapterFetchDate : Type(0b00011000)
|
||||
data object DateAdded : Type(0b00011100)
|
||||
data object TrackerMean : Type(0b000100000)
|
||||
data object TrackerMean : Type(0b00100000)
|
||||
data object Random : Type(0b00111100)
|
||||
|
||||
companion object {
|
||||
fun valueOf(flag: Long): Type {
|
||||
@ -77,6 +78,7 @@ data class LibrarySort(
|
||||
Type.ChapterFetchDate,
|
||||
Type.DateAdded,
|
||||
Type.TrackerMean,
|
||||
Type.Random,
|
||||
)
|
||||
}
|
||||
val directions by lazy { setOf(Direction.Ascending, Direction.Descending) }
|
||||
@ -104,6 +106,7 @@ data class LibrarySort(
|
||||
"CHAPTER_FETCH_DATE" -> Type.ChapterFetchDate
|
||||
"DATE_ADDED" -> Type.DateAdded
|
||||
"TRACKER_MEAN" -> Type.TrackerMean
|
||||
"RANDOM" -> Type.Random
|
||||
else -> Type.Alphabetical
|
||||
}
|
||||
val ascending = if (values[1] == "ASCENDING") Direction.Ascending else Direction.Descending
|
||||
@ -125,6 +128,7 @@ data class LibrarySort(
|
||||
Type.ChapterFetchDate -> "CHAPTER_FETCH_DATE"
|
||||
Type.DateAdded -> "DATE_ADDED"
|
||||
Type.TrackerMean -> "TRACKER_MEAN"
|
||||
Type.Random -> "RANDOM"
|
||||
}
|
||||
val direction = if (direction == Direction.Ascending) "ASCENDING" else "DESCENDING"
|
||||
return "$type,$direction"
|
||||
|
@ -26,6 +26,8 @@ class LibraryPreferences(
|
||||
LibrarySort.Serializer::deserialize,
|
||||
)
|
||||
|
||||
fun randomSortSeed() = preferenceStore.getInt("library_random_sort_seed", 0)
|
||||
|
||||
fun portraitColumns() = preferenceStore.getInt("pref_library_columns_portrait_key", 0)
|
||||
|
||||
fun landscapeColumns() = preferenceStore.getInt("pref_library_columns_landscape_key", 0)
|
||||
|
@ -17,6 +17,8 @@ interface MangaRepository {
|
||||
|
||||
suspend fun getFavorites(): List<Manga>
|
||||
|
||||
suspend fun getReadMangaNotInLibrary(): List<Manga>
|
||||
|
||||
suspend fun getLibraryManga(): List<LibraryManga>
|
||||
|
||||
fun getLibraryMangaAsFlow(): Flow<List<LibraryManga>>
|
||||
|
@ -12,7 +12,7 @@ class LibraryFlagsTest {
|
||||
@Test
|
||||
fun `Check the amount of flags`() {
|
||||
LibraryDisplayMode.values.size shouldBe 4
|
||||
LibrarySort.types.size shouldBe 9
|
||||
LibrarySort.types.size shouldBe 10
|
||||
LibrarySort.directions.size shouldBe 2
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
[versions]
|
||||
agp_version = "8.7.0"
|
||||
agp_version = "8.7.1"
|
||||
lifecycle_version = "2.8.6"
|
||||
paging_version = "3.3.2"
|
||||
interpolator_version = "1.0.0"
|
||||
@ -7,7 +7,7 @@ interpolator_version = "1.0.0"
|
||||
[libraries]
|
||||
gradle = { module = "com.android.tools.build:gradle", version.ref = "agp_version" }
|
||||
|
||||
annotation = "androidx.annotation:annotation:1.8.2"
|
||||
annotation = "androidx.annotation:annotation:1.9.0"
|
||||
appcompat = "androidx.appcompat:appcompat:1.7.0"
|
||||
biometricktx = "androidx.biometric:biometric-ktx:1.2.0-alpha05"
|
||||
constraintlayout = "androidx.constraintlayout:constraintlayout:2.1.4"
|
||||
@ -28,7 +28,7 @@ paging-compose = { module = "androidx.paging:paging-compose", version.ref = "pag
|
||||
|
||||
interpolator = { group = "androidx.interpolator", name = "interpolator", version.ref = "interpolator_version" }
|
||||
|
||||
benchmark-macro = "androidx.benchmark:benchmark-macro-junit4:1.3.2"
|
||||
benchmark-macro = "androidx.benchmark:benchmark-macro-junit4:1.3.3"
|
||||
test-ext = "androidx.test.ext:junit-ktx:1.2.1"
|
||||
test-espresso-core = "androidx.test.espresso:espresso-core:3.6.1"
|
||||
test-uiautomator = "androidx.test.uiautomator:uiautomator:2.3.0"
|
||||
|
@ -1,8 +1,8 @@
|
||||
[versions]
|
||||
compose-bom = "2024.09.03"
|
||||
compose-bom = "2024.10.00"
|
||||
|
||||
[libraries]
|
||||
activity = "androidx.activity:activity-compose:1.9.2"
|
||||
activity = "androidx.activity:activity-compose:1.9.3"
|
||||
bom = { group = "androidx.compose", name = "compose-bom", version.ref = "compose-bom" }
|
||||
foundation = { module = "androidx.compose.foundation:foundation" }
|
||||
animation = { module = "androidx.compose.animation:animation" }
|
||||
@ -15,4 +15,4 @@ ui-util = { module = "androidx.compose.ui:ui-util" }
|
||||
material3-core = { module = "androidx.compose.material3:material3" }
|
||||
material-icons = { module = "androidx.compose.material:material-icons-extended" }
|
||||
|
||||
glance = "androidx.glance:glance-appwidget:1.1.0"
|
||||
glance = "androidx.glance:glance-appwidget:1.1.1"
|
||||
|
@ -1,7 +1,7 @@
|
||||
[versions]
|
||||
kotlin_version = "2.0.21"
|
||||
serialization_version = "1.7.3"
|
||||
xml_serialization_version = "0.86.3"
|
||||
xml_serialization_version = "0.90.2"
|
||||
|
||||
[libraries]
|
||||
reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin_version" }
|
||||
|
@ -4,13 +4,13 @@ leakcanary = "2.14"
|
||||
moko = "0.24.2"
|
||||
okhttp_version = "5.0.0-alpha.14"
|
||||
richtext = "0.20.0"
|
||||
shizuku_version = "12.2.0"
|
||||
shizuku_version = "13.1.0"
|
||||
sqldelight = "2.0.2"
|
||||
sqlite = "2.4.0"
|
||||
voyager = "1.0.0"
|
||||
spotless = "6.25.0"
|
||||
ktlint-core = "1.3.1"
|
||||
firebase-bom = "33.4.0"
|
||||
ktlint-core = "1.4.0"
|
||||
firebase-bom = "33.5.1"
|
||||
|
||||
[libraries]
|
||||
desugar = "com.android.tools:desugar_jdk_libs:2.1.2"
|
||||
@ -32,7 +32,7 @@ jsoup = "org.jsoup:jsoup:1.18.1"
|
||||
|
||||
disklrucache = "com.jakewharton:disklrucache:2.0.2"
|
||||
unifile = "com.github.tachiyomiorg:unifile:e0def6b3dc"
|
||||
libarchive = "me.zhanghai.android.libarchive:library:1.1.2"
|
||||
libarchive = "me.zhanghai.android.libarchive:library:1.1.4"
|
||||
|
||||
sqlite-framework = { module = "androidx.sqlite:sqlite-framework", version.ref = "sqlite" }
|
||||
sqlite-ktx = { module = "androidx.sqlite:sqlite-ktx", version.ref = "sqlite" }
|
||||
@ -89,7 +89,7 @@ sqldelight-coroutines = { module = "app.cash.sqldelight:coroutines-extensions-jv
|
||||
sqldelight-android-paging = { module = "app.cash.sqldelight:androidx-paging3-extensions", version.ref = "sqldelight" }
|
||||
sqldelight-dialects-sql = { module = "app.cash.sqldelight:sqlite-3-38-dialect", version.ref = "sqldelight" }
|
||||
|
||||
junit = "org.junit.jupiter:junit-jupiter:5.11.2"
|
||||
junit = "org.junit.jupiter:junit-jupiter:5.11.3"
|
||||
kotest-assertions = "io.kotest:kotest-assertions-core:5.9.1"
|
||||
mockk = "io.mockk:mockk:1.13.13"
|
||||
|
||||
|
0
i18n/.gitignore
vendored
0
i18n/.gitignore
vendored
@ -2,4 +2,4 @@
|
||||
|
||||
This module houses the string resources and translations.
|
||||
|
||||
Original English strings are manged in `src/commonMain/resources/MR/base/`. Translations are done externally via Weblate. See [our website](https://mihon.app/docs/contribute#translation) for more details.
|
||||
Original English strings are managed in `src/commonMain/moko-resources/base/`. Translations are done externally via Weblate. See [our website](https://mihon.app/docs/contribute#translation) for more details.
|
@ -69,6 +69,7 @@
|
||||
<string name="action_sort_chapter_fetch_date">Chapter fetch date</string>
|
||||
<string name="action_sort_date_added">Date added</string>
|
||||
<string name="action_sort_tracker_score">Tracker score</string>
|
||||
<string name="action_sort_random">Random</string>
|
||||
<string name="action_search">Search</string>
|
||||
<string name="action_search_hint">Search…</string>
|
||||
<string name="action_search_settings">Search settings</string>
|
||||
@ -190,6 +191,10 @@
|
||||
<string name="onboarding_permission_notifications_description">Get notified for library updates and more.</string>
|
||||
<string name="onboarding_permission_ignore_battery_opts">Background battery usage</string>
|
||||
<string name="onboarding_permission_ignore_battery_opts_description">Avoid interruptions to long-running library updates, downloads, and backup restores.</string>
|
||||
<string name="onboarding_permission_crashlytics">Send crash logs</string>
|
||||
<string name="onboarding_permission_crashlytics_description">Send anonymized crash logs to the developers.</string>
|
||||
<string name="onboarding_permission_analytics">Allow analytics</string>
|
||||
<string name="onboarding_permission_analytics_description">Send anonymized usage data to improve app features.</string>
|
||||
<string name="onboarding_permission_action_grant">Grant</string>
|
||||
<string name="onboarding_guides_new_user">New to %s? We recommend checking out the getting started guide.</string>
|
||||
<string name="onboarding_guides_returning_user">Reinstalling %s?</string>
|
||||
@ -242,6 +247,9 @@
|
||||
<string name="pref_app_language">App language</string>
|
||||
|
||||
<string name="pref_category_security">Security and privacy</string>
|
||||
<string name="pref_security">Security</string>
|
||||
<string name="pref_firebase">Analytics and Crash logs</string>
|
||||
|
||||
<string name="lock_with_biometrics">Require unlock</string>
|
||||
<string name="lock_when_idle">Lock when idle</string>
|
||||
<string name="lock_always">Always</string>
|
||||
@ -249,6 +257,7 @@
|
||||
<string name="hide_notification_content">Hide notification content</string>
|
||||
<string name="secure_screen">Secure screen</string>
|
||||
<string name="secure_screen_summary">Secure screen hides app contents when switching apps and block screenshots</string>
|
||||
<string name="firebase_summary">Sending crash logs and analytics will allow us to identify and fix issues, improve performance, and make future updates more relevant to your needs</string>
|
||||
|
||||
<string name="pref_category_nsfw_content">NSFW (18+) sources</string>
|
||||
<string name="pref_show_nsfw_source">Show in sources and extensions lists</string>
|
||||
@ -317,10 +326,13 @@
|
||||
<string name="ext_trust">Trust</string>
|
||||
<string name="ext_untrusted">Untrusted</string>
|
||||
<string name="ext_uninstall">Uninstall</string>
|
||||
<string name="ext_remove">Remove</string>
|
||||
<string name="ext_confirm_remove">Remove Extension?</string>
|
||||
<string name="ext_app_info">App info</string>
|
||||
<string name="untrusted_extension">Untrusted extension</string>
|
||||
<string name="untrusted_extension_message">Malicious extensions can read any stored login credentials or execute arbitrary code.\n\nBy trusting this extension, you accept these risks.</string>
|
||||
<string name="obsolete_extension_message">This extension is no longer available. It may not function properly and can cause issues with the app. Uninstalling it is recommended.</string>
|
||||
<string name="remove_private_extension_message">Do you really want to remove \"%s\" extension?</string>
|
||||
<string name="extension_api_error">Failed to fetch available extensions</string>
|
||||
<string name="ext_info_version">Version</string>
|
||||
<string name="ext_info_language">Language</string>
|
||||
@ -497,6 +509,7 @@
|
||||
<!-- Tracking section -->
|
||||
<string name="tracking_guide">Tracking guide</string>
|
||||
<string name="pref_auto_update_manga_sync">Update progress after reading</string>
|
||||
<string name="pref_auto_update_manga_on_mark_read">Update progress when marked as read</string>
|
||||
<string name="services">Trackers</string>
|
||||
<string name="tracking_info">One-way sync to update the chapter progress in external tracker services. Set up tracking for individual entries from their tracking button.</string>
|
||||
<string name="enhanced_services">Enhanced trackers</string>
|
||||
@ -534,6 +547,7 @@
|
||||
<string name="source_settings">Source settings</string>
|
||||
<string name="extensionRepo_settings">Extension repos</string>
|
||||
<string name="private_settings">Include sensitive settings (e.g., tracker login tokens)</string>
|
||||
<string name="non_library_settings">All read entries</string>
|
||||
<string name="creating_backup">Creating backup</string>
|
||||
<string name="creating_backup_error">Backup failed</string>
|
||||
<string name="missing_storage_permission">Storage permissions not granted</string>
|
||||
@ -569,7 +583,7 @@
|
||||
<string name="pref_reset_user_agent_string">Reset default user agent string</string>
|
||||
<string name="requires_app_restart">Requires app restart to take effect</string>
|
||||
<string name="cookies_cleared">Cookies cleared</string>
|
||||
<string name="pref_invalidate_download_cache">Invalidate downloads index</string>
|
||||
<string name="pref_invalidate_download_cache">Reindex downloads</string>
|
||||
<string name="pref_invalidate_download_cache_summary">Force app to recheck downloaded chapters</string>
|
||||
<string name="download_cache_invalidated">Downloads index invalidated</string>
|
||||
<string name="pref_clear_database">Clear database</string>
|
||||
@ -726,6 +740,7 @@
|
||||
<string name="exclude_scanlators">Exclude scanlators</string>
|
||||
<string name="no_scanlators_found">No scanlators found</string>
|
||||
<string name="confirm_tracker_update">Update trackers to chapter %d?</string>
|
||||
<string name="trackers_updated_summary">Trackers updated to chapter %d</string>
|
||||
|
||||
<!-- Tracking Screen -->
|
||||
<string name="manga_tracking_tab">Tracking</string>
|
||||
|
1
macrobenchmark/.gitignore
vendored
1
macrobenchmark/.gitignore
vendored
@ -1 +0,0 @@
|
||||
/build
|
1
presentation-core/.gitignore
vendored
1
presentation-core/.gitignore
vendored
@ -1 +0,0 @@
|
||||
/build
|
@ -28,7 +28,6 @@ import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.RadioButton
|
||||
import androidx.compose.material3.Slider
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
@ -46,6 +45,7 @@ import tachiyomi.core.common.preference.Preference
|
||||
import tachiyomi.core.common.preference.TriState
|
||||
import tachiyomi.core.common.preference.toggle
|
||||
import tachiyomi.presentation.core.components.material.DISABLED_ALPHA
|
||||
import tachiyomi.presentation.core.components.material.Slider
|
||||
import tachiyomi.presentation.core.components.material.padding
|
||||
import tachiyomi.presentation.core.i18n.stringResource
|
||||
import tachiyomi.presentation.core.theme.header
|
||||
@ -98,12 +98,21 @@ fun SortItem(label: String, sortDescending: Boolean?, onClick: () -> Unit) {
|
||||
null -> null
|
||||
}
|
||||
|
||||
BaseSortItem(
|
||||
label = label,
|
||||
icon = arrowIcon,
|
||||
onClick = onClick,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun BaseSortItem(label: String, icon: ImageVector?, onClick: () -> Unit) {
|
||||
BaseSettingsItem(
|
||||
label = label,
|
||||
widget = {
|
||||
if (arrowIcon != null) {
|
||||
if (icon != null) {
|
||||
Icon(
|
||||
imageVector = arrowIcon,
|
||||
imageVector = icon,
|
||||
contentDescription = null,
|
||||
tint = MaterialTheme.colorScheme.primary,
|
||||
)
|
||||
@ -183,17 +192,14 @@ fun SliderItem(
|
||||
}
|
||||
|
||||
Slider(
|
||||
value = value.toFloat(),
|
||||
onValueChange = {
|
||||
val newValue = it.toInt()
|
||||
if (newValue != value) {
|
||||
onChange(newValue)
|
||||
haptic.performHapticFeedback(HapticFeedbackType.TextHandleMove)
|
||||
}
|
||||
},
|
||||
modifier = Modifier.weight(1.5f),
|
||||
valueRange = min.toFloat()..max.toFloat(),
|
||||
steps = max - min,
|
||||
value = value,
|
||||
onValueChange = f@{
|
||||
if (it == value) return@f
|
||||
onChange(it)
|
||||
haptic.performHapticFeedback(HapticFeedbackType.TextHandleMove)
|
||||
},
|
||||
valueRange = min..max,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -9,11 +9,11 @@ import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.shrinkHorizontally
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.sizeIn
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.material3.FloatingActionButton
|
||||
import androidx.compose.material3.FloatingActionButtonDefaults
|
||||
import androidx.compose.material3.FloatingActionButtonElevation
|
||||
@ -46,12 +46,8 @@ fun ExtendedFloatingActionButton(
|
||||
contentColor: Color = contentColorFor(containerColor),
|
||||
elevation: FloatingActionButtonElevation = FloatingActionButtonDefaults.elevation(),
|
||||
) {
|
||||
val minWidth by animateDpAsState(
|
||||
targetValue = if (expanded) ExtendedFabMinimumWidth else FabContainerWidth,
|
||||
label = "minWidth",
|
||||
)
|
||||
FloatingActionButton(
|
||||
modifier = modifier.sizeIn(minWidth = minWidth),
|
||||
modifier = modifier,
|
||||
onClick = onClick,
|
||||
interactionSource = interactionSource,
|
||||
shape = shape,
|
||||
@ -59,18 +55,29 @@ fun ExtendedFloatingActionButton(
|
||||
contentColor = contentColor,
|
||||
elevation = elevation,
|
||||
) {
|
||||
val minWidth by animateDpAsState(
|
||||
targetValue = if (expanded) ExtendedFabMinimumWidth else FabContainerWidth,
|
||||
animationSpec = tween(
|
||||
durationMillis = 500,
|
||||
easing = EasingEmphasizedCubicBezier,
|
||||
),
|
||||
label = "minWidth",
|
||||
)
|
||||
val startPadding by animateDpAsState(
|
||||
targetValue = if (expanded) ExtendedFabIconSize / 2 else 0.dp,
|
||||
animationSpec = tween(
|
||||
durationMillis = if (expanded) 300 else 900,
|
||||
easing = EasingEmphasizedCubicBezier,
|
||||
),
|
||||
label = "startPadding",
|
||||
)
|
||||
val endPadding by animateDpAsState(
|
||||
targetValue = if (expanded) ExtendedFabTextPadding else 0.dp,
|
||||
label = "endPadding",
|
||||
)
|
||||
|
||||
Row(
|
||||
modifier = Modifier.padding(start = startPadding, end = endPadding),
|
||||
modifier = Modifier
|
||||
.sizeIn(minWidth = minWidth)
|
||||
.padding(start = startPadding),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
) {
|
||||
icon()
|
||||
AnimatedVisibility(
|
||||
@ -78,8 +85,7 @@ fun ExtendedFloatingActionButton(
|
||||
enter = ExtendedFabExpandAnimation,
|
||||
exit = ExtendedFabCollapseAnimation,
|
||||
) {
|
||||
Row {
|
||||
Spacer(Modifier.width(ExtendedFabIconPadding))
|
||||
Box(modifier = Modifier.padding(start = ExtendedFabIconPadding, end = ExtendedFabTextPadding)) {
|
||||
text()
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,48 @@
|
||||
package tachiyomi.presentation.core.components.material
|
||||
|
||||
import androidx.annotation.IntRange
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.material3.Slider
|
||||
import androidx.compose.material3.SliderColors
|
||||
import androidx.compose.material3.SliderDefaults
|
||||
import androidx.compose.material3.SliderState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
|
||||
@Composable
|
||||
fun Slider(
|
||||
value: Int,
|
||||
onValueChange: (Int) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
enabled: Boolean = true,
|
||||
valueRange: ClosedRange<Int> = 0..1,
|
||||
@IntRange(from = 0) steps: Int = with(valueRange) { (endInclusive - start) - 1 },
|
||||
onValueChangeFinished: (() -> Unit)? = null,
|
||||
colors: SliderColors = SliderDefaults.colors(),
|
||||
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
|
||||
thumb: @Composable (SliderState) -> Unit = {
|
||||
SliderDefaults.Thumb(
|
||||
interactionSource = interactionSource,
|
||||
colors = colors,
|
||||
enabled = enabled,
|
||||
)
|
||||
},
|
||||
track: @Composable (SliderState) -> Unit = { sliderState ->
|
||||
SliderDefaults.Track(colors = colors, enabled = enabled, sliderState = sliderState)
|
||||
},
|
||||
) {
|
||||
Slider(
|
||||
value = value.toFloat(),
|
||||
onValueChange = { onValueChange(it.toInt()) },
|
||||
modifier = modifier,
|
||||
enabled = enabled,
|
||||
valueRange = with(valueRange) { start.toFloat()..endInclusive.toFloat() },
|
||||
steps = steps,
|
||||
onValueChangeFinished = onValueChangeFinished,
|
||||
colors = colors,
|
||||
interactionSource = interactionSource,
|
||||
thumb = thumb,
|
||||
track = track,
|
||||
)
|
||||
}
|
@ -82,5 +82,5 @@ val CustomIcons.Discord: ImageVector
|
||||
return _discord!!
|
||||
}
|
||||
|
||||
@Suppress("ObjectPropertyName", "ktlint:standard:backing-property-naming")
|
||||
@Suppress("ObjectPropertyName")
|
||||
private var _discord: ImageVector? = null
|
||||
|
@ -59,5 +59,5 @@ val CustomIcons.Facebook: ImageVector
|
||||
return _facebook!!
|
||||
}
|
||||
|
||||
@Suppress("ObjectPropertyName", "ktlint:standard:backing-property-naming")
|
||||
@Suppress("ObjectPropertyName")
|
||||
private var _facebook: ImageVector? = null
|
||||
|
@ -64,5 +64,5 @@ val CustomIcons.Github: ImageVector
|
||||
return _github!!
|
||||
}
|
||||
|
||||
@Suppress("ObjectPropertyName", "ktlint:standard:backing-property-naming")
|
||||
@Suppress("ObjectPropertyName")
|
||||
private var _github: ImageVector? = null
|
||||
|
@ -90,5 +90,5 @@ val CustomIcons.Reddit: ImageVector
|
||||
return _reddit!!
|
||||
}
|
||||
|
||||
@Suppress("ObjectPropertyName", "ktlint:standard:backing-property-naming")
|
||||
@Suppress("ObjectPropertyName")
|
||||
private var _reddit: ImageVector? = null
|
||||
|
@ -57,5 +57,5 @@ val CustomIcons.X: ImageVector
|
||||
return _x!!
|
||||
}
|
||||
|
||||
@Suppress("ObjectPropertyName", "ktlint:standard:backing-property-naming")
|
||||
@Suppress("ObjectPropertyName")
|
||||
private var _x: ImageVector? = null
|
||||
|
@ -4,12 +4,10 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import tachiyomi.core.common.preference.Preference
|
||||
|
||||
@Composable
|
||||
fun <T> Preference<T>.collectAsState(scope: CoroutineScope = rememberCoroutineScope()): State<T> {
|
||||
val flow = remember(this) { stateIn(scope) }
|
||||
return flow.collectAsState()
|
||||
fun <T> Preference<T>.collectAsState(): State<T> {
|
||||
val flow = remember(this) { changes() }
|
||||
return flow.collectAsState(initial = get())
|
||||
}
|
||||
|
1
presentation-widget/.gitignore
vendored
1
presentation-widget/.gitignore
vendored
@ -1 +0,0 @@
|
||||
/build
|
@ -20,6 +20,7 @@ dependencies {
|
||||
api(projects.i18n)
|
||||
|
||||
implementation(compose.glance)
|
||||
implementation(libs.material)
|
||||
|
||||
implementation(kotlinx.immutables)
|
||||
|
||||
|
1
source-api/.gitignore
vendored
1
source-api/.gitignore
vendored
@ -1 +0,0 @@
|
||||
/build
|
@ -1,4 +1,4 @@
|
||||
@file:Suppress("PropertyName", "ktlint:standard:property-naming")
|
||||
@file:Suppress("PropertyName")
|
||||
|
||||
package eu.kanade.tachiyomi.source.model
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
@file:Suppress("PropertyName", "ktlint:standard:property-naming")
|
||||
@file:Suppress("PropertyName")
|
||||
|
||||
package eu.kanade.tachiyomi.source.model
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
@file:Suppress("PropertyName", "ktlint:standard:property-naming")
|
||||
@file:Suppress("PropertyName")
|
||||
|
||||
package eu.kanade.tachiyomi.source.model
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
@file:Suppress("PropertyName", "ktlint:standard:property-naming")
|
||||
@file:Suppress("PropertyName")
|
||||
|
||||
package eu.kanade.tachiyomi.source.model
|
||||
|
||||
|
1
source-local/.gitignore
vendored
1
source-local/.gitignore
vendored
@ -1 +0,0 @@
|
||||
/build
|
@ -18,7 +18,7 @@ import kotlinx.serialization.json.decodeFromStream
|
||||
import logcat.LogPriority
|
||||
import mihon.core.archive.archiveReader
|
||||
import mihon.core.archive.epubReader
|
||||
import nl.adaptivity.xmlutil.AndroidXmlReader
|
||||
import nl.adaptivity.xmlutil.core.AndroidXmlReader
|
||||
import nl.adaptivity.xmlutil.serialization.XML
|
||||
import tachiyomi.core.common.i18n.stringResource
|
||||
import tachiyomi.core.common.storage.extension
|
||||
@ -55,10 +55,10 @@ actual class LocalSource(
|
||||
private val json: Json by injectLazy()
|
||||
private val xml: XML by injectLazy()
|
||||
|
||||
@Suppress("PrivatePropertyName", "ktlint:standard:property-naming")
|
||||
@Suppress("PrivatePropertyName")
|
||||
private val PopularFilters = FilterList(OrderBy.Popular(context))
|
||||
|
||||
@Suppress("PrivatePropertyName", "ktlint:standard:property-naming")
|
||||
@Suppress("PrivatePropertyName")
|
||||
private val LatestFilters = FilterList(OrderBy.Latest(context))
|
||||
|
||||
override val name: String = context.stringResource(MR.strings.local_source)
|
||||
|
Reference in New Issue
Block a user