Compare commits

...

91 Commits

Author SHA1 Message Date
26ddc6e3aa Release v0.13.5 2022-07-08 15:52:48 -04:00
1dc4a52f61 Bump dependencies 2022-07-08 09:11:36 -04:00
473a4fec70 Fix cherry pick errors 2022-07-08 09:11:28 -04:00
1919c2d925 Update default user agent string
(cherry picked from commit 7d3fe0ed43)
2022-07-08 08:58:55 -04:00
71e31e6c03 Add MIME type mapping for image/jxl (fixes #7117)
(cherry picked from commit 591df8abcc)
2022-07-08 08:58:46 -04:00
c01df7f0a1 Increase height of transition view in webtoon viewers (fixes #7242)
(cherry picked from commit 46734c525f)
2022-07-08 08:57:45 -04:00
6024f6175b Extension API: change fallback source and logic (#7400)
* Extension API: change fallback source and logic

* remove ghproxy

(cherry picked from commit 284445c364)
2022-07-08 08:56:51 -04:00
33500e5b69 RateLimitInterceptor: ignore canceled calls (#7389)
* RateLimitInterceptor: ignore canceled calls

* SpecificHostRateLimit: ignore canceled calls

(cherry picked from commit 5b8cd68cf3)
2022-07-08 08:56:29 -04:00
17899a6d6d Add new "Lavender" theme (#7343)
* Add new "Lavender" theme

* Add light theme values for Lavender theme

* Fix order of enums

* Fix accented UI elements in set categories sheet being different colors

Co-authored-by: CrepeTF <trungnguyen02@outlookcom>
(cherry picked from commit ad106bd884)
2022-07-08 08:56:15 -04:00
4c3eb68d3a Use primary color for excluded tristate filter icon (fixes #7360)
(cherry picked from commit 3ca1ce4636)
2022-07-08 08:55:59 -04:00
29ced9642d Fix downloader crash related to UnmeteredSource (#7365)
Fix crash when starting a download with chaqpters from a UnmeteredSource

(cherry picked from commit 470a576441)
2022-07-08 08:55:52 -04:00
af82591d85 Fix accented UI elements in library sheet being different colors
(cherry picked from commit cd5bcc3673)
2022-07-08 08:55:38 -04:00
5bc4a446ec Fix wrapped long page numbers in reader (closes #7300)
(cherry picked from commit 6bc484617e)
2022-07-08 08:55:01 -04:00
83e93b254e Don't show clipboard copy confirmation toast on Android 13 or above
(cherry picked from commit 40f5d26945)
2022-07-08 08:53:46 -04:00
49c7dd0cac Add more DoH providers (#7256)
* Add more DoH providers

* Fix IPs

(cherry picked from commit 18ea6c4f65)
2022-07-08 08:53:41 -04:00
96d2fb62e4 ChapterSourceSync: set default timestamp to max timestamp (#7197)
(cherry picked from commit dd5da56695)
2022-07-08 08:53:19 -04:00
c76a136d3f Fix global update ignoring network constraint (#7188)
* update library update network constraint logic

* add explicit 'only on unmetered network' update constraint

(cherry picked from commit 63238b388d)
2022-07-08 08:52:49 -04:00
940409a4c3 Local Source - qol, cleanup and cover related fixes (#7166)
* Local Source - qol, cleanup and cover related fixes

* Review Changes

(cherry picked from commit ad17eb1386)
2022-07-08 08:52:26 -04:00
071dd88ef8 Add ability to show manga when clicking item in migration search process (#7134)
(cherry picked from commit bbb69482e1)
2022-07-08 08:51:26 -04:00
a58a4634e2 Fix reader menu appearing then disappearing in webtoon viewer when there is no next chapter (#7115)
(cherry picked from commit 6580f5771f)
2022-07-08 08:51:13 -04:00
5979e72662 Fix webtoon viewer showing transition view when going to next/prev chapter using next/prev button (#7133)
(cherry picked from commit b21bcc2d45)
2022-07-08 08:51:04 -04:00
010436e797 Change jsDelivr CDN URL to Fastly (#7156)
(cherry picked from commit 7b242bf118)
2022-07-08 08:50:54 -04:00
980709cccb Use jsDelivr as fallback when GitHub can't be reached for extensions (closes #5517)
Re-implementation of 24bb2f02dc

(cherry picked from commit d61bfd7caf)
2022-07-08 08:50:35 -04:00
fe80356756 Save reader progress when activity is paused (#7121)
(cherry picked from commit f1ab34e27c)
2022-07-08 08:50:06 -04:00
cecf532ffd Fix category tabs incorrect scroll position (#7120)
(cherry picked from commit 6d655ff757)
2022-07-08 08:49:57 -04:00
6cb255e60a Add switch to DownloadPageLoader when chapter is downloaded (#7119)
(cherry picked from commit 63627c81eb)
2022-07-08 08:49:48 -04:00
b46fb7d1e1 Fix "Move to top" showing at the most top item in download queue (#7109)
(cherry picked from commit b26daf8824)
2022-07-08 08:49:21 -04:00
8874193927 Update build workflow actions
(cherry picked from commit 8bee5accb7)
2022-07-08 08:49:04 -04:00
a4515ad251 Check for app updates by comparing semver (#7100)
Instead of just checking whether the current app version *matches* with
latest app version in GitHub Releases, compare the semver from the tag
names to check whether the latter is greater and the app needs an update

Reference: semver spec #11 https://semver.org/#spec-item-11

Co-authored-by: Andreas <6576096+ghostbear@users.noreply.github.com>

Co-authored-by: Andreas <6576096+ghostbear@users.noreply.github.com>
(cherry picked from commit e7ed130f2a)
2022-07-08 08:48:39 -04:00
55b0b57699 Use theme primary color for slider track (#7102)
(cherry picked from commit bc053580ad)
2022-07-08 08:48:00 -04:00
aab7795b4c Don't save categories in backup if not selected (#7101)
Currently, manually created backups contain list of categories even if
Categories option is not selected during Backup Prompt. This leads to
empty categories being created when restoring such backup files

This commit adds a check before saving categories list info to the
backup file. The check is the same check which is used while backing up
category info of manga in library

Tested and worked successfully on app installed on Android 12

(cherry picked from commit 11c01235ac)
2022-07-08 08:47:51 -04:00
196a8e6829 Rename "navigation layout" to "tap zones"
(cherry picked from commit c49d862fc5)
2022-07-08 08:47:43 -04:00
972cd98d7b Fix removing manga from library reverts during global update (#7063)
* Fix removing manga from library reverts during global update

* Review Changes

* Review changes 2

(cherry picked from commit c4088bad12)
2022-07-08 08:47:12 -04:00
a16b5d241b Add -r flag to ShizukuInstaller createCommand (#7080)
(cherry picked from commit 49d3ddb830)
2022-07-08 08:46:49 -04:00
bfa918140f Fix Android 13 icon sizing
(cherry picked from commit 9fdc803c14)
2022-07-08 08:46:27 -04:00
0721de5b81 Add links to website FAQ for library update and download warning notifications
(cherry picked from commit 70698e6494)
2022-07-08 08:45:48 -04:00
a409fde519 Download new chapters when only excluded categories is selected (#6984)
(cherry picked from commit 06bec0ad54)
2022-07-08 08:45:29 -04:00
8e34a30dce Fix skipped library entries and size warning notifications using same ID
(cherry picked from commit 91ed3a4a5f)
2022-07-08 08:43:55 -04:00
ba43462041 Fix update warning notifications being cut off (fixes #6983)
(cherry picked from commit 20145f7a12)
2022-07-08 08:43:47 -04:00
c8ae936ce9 Default to downloading as CBZ (closes #6942)
Generally seems fine. People with weak devices may experience some issues, but they can toggle it off/extract the archives separately if needed.

(cherry picked from commit 883945e3e8)
2022-07-08 08:43:39 -04:00
853f949140 Add battery not low restriction for global updates (closes #6980)
(cherry picked from commit 3feea71146)
2022-07-08 08:43:31 -04:00
615b01a006 Fix chapter transition setting for one page chapters (#6998)
(cherry picked from commit 5e32b8e49f)
2022-07-08 08:43:14 -04:00
0eb5a3176b Delete entire app_webview folder when clearing WebView data
(cherry picked from commit 6e95fde4ec)
2022-07-08 08:43:01 -04:00
867a5a3ea0 Move clear webview data action to network group
(cherry picked from commit bf0bb5aa88)
2022-07-08 08:42:45 -04:00
42eaaa497f Release v0.13.4 2022-04-22 17:29:18 -04:00
96c894ce5b Revert history Compose/SQLDelight changes 2022-04-22 17:27:58 -04:00
c0214103a9 Temporarily remove chapter name cleaning
To be added back in a more consistent manner later around the app. Probably when more things are Compose-y with less repetition.
2022-04-22 14:03:43 -04:00
2b76a97989 Add advanced setting to clear WebView data 2022-04-22 14:00:42 -04:00
9d77052d9c Enable verbose logging in dev flavor by default (#6979) 2022-04-22 12:34:53 -04:00
b4981058a2 Add indexes to creational tables (#6974) 2022-04-22 08:03:07 -04:00
032aa64195 Lift Compose theme to abstract controller 2022-04-21 22:58:28 -04:00
7c8e8317a8 Simplify history item description building 2022-04-21 22:47:51 -04:00
eb1cfc4cd4 Add abstract ComposeController 2022-04-21 22:42:37 -04:00
f1e5cccee7 Add placeholder color for Compose manga covers 2022-04-21 19:02:54 -04:00
bc2ed763bd Default auto backups to 2 2022-04-21 17:13:33 -04:00
a35995b898 Fix crash on History tab when there is no next chapter (#6970) 2022-04-21 16:48:45 -04:00
b1f46ed830 Migrate History screen database calls to SQLDelight (#6933)
* Migrate History screen database call to SQLDelight

- Move all migrations to SQLDelight
- Move all tables to SQLDelight

Co-authored-by: inorichi <3521738+inorichi@users.noreply.github.com>

* Changes from review comments

* Add adapters to database

* Remove logging of database version in App

* Change query name for paging source queries

* Update migrations

* Make SQLite Callback handle migration

- To ensure it updates the database

* Use SQLDelight Schema version for Callback database version

Co-authored-by: inorichi <3521738+inorichi@users.noreply.github.com>
2022-04-21 15:45:56 -04:00
6c1565a7d4 Make links in new update dialog clickable
Co-authored-by: Jays2Kings <Jays2Kings@users.noreply.github.com>
2022-04-19 22:39:33 -04:00
2ca6b655ad Replace ignore button in new update dialog with link to GitHub page
Not enough room for 3 buttons. Users can still tap outside or back out of the dialog if they want to ignore it.
2022-04-18 22:45:58 -04:00
a83a481ac8 Update junrar 2022-04-18 17:14:47 -04:00
65a8b63b3b Move chapter name cleaning logic to holder (fixes #6955) 2022-04-18 09:26:43 -04:00
b20ca36db9 Fix AppBar not unlifting when scrolling using ComposeView (#6952) 2022-04-17 14:33:35 -04:00
189f92d7e8 Show better error message when empty backup creation is attempted (closes #6941) 2022-04-17 11:51:24 -04:00
cdd4ec6233 Increase default OkHttp call timeout to 2 minutes
Which is still stupidly high, but maybe it'll be lenient enough for certain people.
2022-04-17 11:32:47 -04:00
ef1bb4e800 Show parsed Markdown for new version info (closes #6940) 2022-04-17 11:30:05 -04:00
c475acd1ea Migrate History screen to Compose (#6922)
* Migrate History screen to Compose

- Migrate screen
- Strip logic from presenter into use cases and repository
- Setup for other screen being able to migrate to Compose with Theme

* Changes from review comments
2022-04-17 10:36:22 -04:00
7d50d7ff52 Add elevation to navigation rails (#6947)
Co-authored-by: CrepeTF <trungnguyen02@outlookcom>
2022-04-17 10:29:09 -04:00
28522f4f90 Release v0.13.3 2022-04-15 16:37:25 -04:00
ec3a227a02 Weblate translations (#6890)
Co-authored-by: Ajeje Brazorf <lmelonimamo@yahoo.it>
Co-authored-by: Alessandro Jean <alessandrojean@gmail.com>
Co-authored-by: DarKCroX <darkcrox.2020@outlook.com>
Co-authored-by: Eduard Ereza Martínez <eduard@ereza.cat>
Co-authored-by: Eric <alchemillatruth@purelymail.com>
Co-authored-by: GTX155 <kirchoabv@mail.bg>
Co-authored-by: Giorgio Sanna <sannagiorgio1997@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Huang Zhiyi <hzy980512@126.com>
Co-authored-by: J. Lavoie <j.lavoie@net-c.ca>
Co-authored-by: Jetspectre <jetspectre1@gmail.com>
Co-authored-by: Jozef Hollý <j2.00ghz@gmail.com>
Co-authored-by: Lauri <lauri.kangasaho@hotmail.com>
Co-authored-by: Lyfja <yassinelaoud@gmail.com>
Co-authored-by: Lzmxya <lzmxya@gmail.com>
Co-authored-by: Marco Santos <enum.scima@gmail.com>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: Nicol Bolas <creepyweirdo1031@gmail.com>
Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Co-authored-by: Pierre Kim <admin@manateeshome.com>
Co-authored-by: Pilfer <pescao@gmail.com>
Co-authored-by: Pitpe11 <giorgos2550@gmail.com>
Co-authored-by: Rikishaaa <jebote90@gmail.com>
Co-authored-by: Santiago José Gutiérrez Llanod <gutierrezapata17@gmail.com>
Co-authored-by: Sebastian Mihai Crap <sebastiancrap@gmail.com>
Co-authored-by: Shjosan <shjosan@kakmix.co>
Co-authored-by: Subham Jena <subhamjena8465@gmail.com>
Co-authored-by: Swyter <swyterzone@gmail.com>
Co-authored-by: Vetle Ledaal <vetle.ledaal@gmail.com>
Co-authored-by: Zero O <godarms2010@live.com>
Co-authored-by: altinat <poiiiii4yy@gmail.com>
Co-authored-by: Роман <Rozhenkov69@gmail.com>
Co-authored-by: אילון קטן <eilonkatan@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/bg/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ca/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/cs/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/de/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/el/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/es/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/es_419/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/fi/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/fil/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/fr/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/he/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/hi/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/hr/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/it/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ja/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ko/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ms/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/or/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ro/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ru/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sc/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sr/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sv/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/th/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/tr/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/vi/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/zh_Hant/
Translation: Tachiyomi/Tachiyomi 0.x

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Ajeje Brazorf <lmelonimamo@yahoo.it>
Co-authored-by: Alessandro Jean <alessandrojean@gmail.com>
Co-authored-by: DarKCroX <darkcrox.2020@outlook.com>
Co-authored-by: Eduard Ereza Martínez <eduard@ereza.cat>
Co-authored-by: Eric <alchemillatruth@purelymail.com>
Co-authored-by: GTX155 <kirchoabv@mail.bg>
Co-authored-by: Giorgio Sanna <sannagiorgio1997@gmail.com>
Co-authored-by: Huang Zhiyi <hzy980512@126.com>
Co-authored-by: J. Lavoie <j.lavoie@net-c.ca>
Co-authored-by: Jetspectre <jetspectre1@gmail.com>
Co-authored-by: Lauri <lauri.kangasaho@hotmail.com>
Co-authored-by: Lyfja <yassinelaoud@gmail.com>
Co-authored-by: Lzmxya <lzmxya@gmail.com>
Co-authored-by: Marco Santos <enum.scima@gmail.com>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: Nicol Bolas <creepyweirdo1031@gmail.com>
Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Co-authored-by: Pierre Kim <admin@manateeshome.com>
Co-authored-by: Pilfer <pescao@gmail.com>
Co-authored-by: Pitpe11 <giorgos2550@gmail.com>
Co-authored-by: Rikishaaa <jebote90@gmail.com>
Co-authored-by: Santiago José Gutiérrez Llanod <gutierrezapata17@gmail.com>
Co-authored-by: Sebastian Mihai Crap <sebastiancrap@gmail.com>
Co-authored-by: Shjosan <shjosan@kakmix.co>
Co-authored-by: Subham Jena <subhamjena8465@gmail.com>
Co-authored-by: Swyter <swyterzone@gmail.com>
Co-authored-by: Vetle Ledaal <vetle.ledaal@gmail.com>
Co-authored-by: Zero O <godarms2010@live.com>
Co-authored-by: altinat <poiiiii4yy@gmail.com>
Co-authored-by: Роман <Rozhenkov69@gmail.com>
Co-authored-by: אילון קטן <eilonkatan@gmail.com>
2022-04-15 16:35:30 -04:00
89decf3474 Always remove manga title from if it prefixes chapter names (related to #6913) 2022-04-15 15:52:48 -04:00
0b2794e843 Limit package name overriding to Android 8+ (related to #6846) 2022-04-15 13:43:54 -04:00
554dfb5874 Bump Material Components 2022-04-15 13:36:24 -04:00
9c30fa1da3 Update F-Droid migration guide link 2022-04-15 12:11:01 -04:00
e81bd61e24 Adjust update/download warnings
This is a partial revert/evolution of 538dd60580

- Back to notifications, because Android 12+ may cut off toasts
- Notifications now automatically dismiss after 30s on Android 8+ (taken from J2K)
- Also warn if more than 30 chapters are queued for download
2022-04-15 10:24:54 -04:00
7a0b54bb38 Set network call timeout to 90 seconds (instead of infinite) 2022-04-15 09:56:35 -04:00
f060daf8c4 Rollback to stable OkHttp
There's some weird crashes related to it. Happy Eyeballs will return once we upgrade again.
2022-04-14 22:37:51 -04:00
c1976ef599 Avoid some crashes 2022-04-14 18:28:16 -04:00
f16fb4e1e4 Minor cleanup 2022-04-14 18:15:47 -04:00
5da2c82f47 Avoid crashing if picture can't be saved (related to #6905) 2022-04-13 18:45:49 -04:00
d443245d66 Update Skip Updating preference strings. (#6900)
* Update Skip Updating preference strings.

* Complete -> Completed

* hasn't -> haven't

* Apply suggestions from code review

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

Co-authored-by: arkon <arkon@users.noreply.github.com>
2022-04-13 18:35:58 -04:00
9be3eea5fd Remove dependency review step from push workflow 2022-04-13 18:35:46 -04:00
07a9fd061d Add dependency review step to workflows 2022-04-13 18:34:33 -04:00
2a070c0b1e Add clear cookies option to WebView menu 2022-04-13 17:48:05 -04:00
7b5106d206 Update ACRA 2022-04-13 17:44:49 -04:00
821d9cdb02 Show different update notification for F-Droid installations 2022-04-13 17:44:43 -04:00
28575936d3 Move learn more text in skipped entries notification to main content
Because people apparently don't realize they can tap actions
2022-04-12 23:08:00 -04:00
83a04da4a0 Stop allowing keeping app data on uninstall
Seems to be more trouble than it's worth since it makes the app uninstallable without manually deleting app data. Users have to go out of their way to save data into the app data folder now anyway.
2022-04-12 17:27:09 -04:00
0894b1394f Fix cover sharing error string (#6911) 2022-04-12 09:10:32 -04:00
eb33d3c991 Remove build flavor checks for update warnings
"stable" was invalid anyway, it should've been "release"
2022-04-11 23:05:00 -04:00
d7f01abf3a Update Coil 2022-04-11 23:04:19 -04:00
80635343ae Update ACRA 2022-04-11 23:04:07 -04:00
107 changed files with 1597 additions and 577 deletions

View File

@ -3,7 +3,7 @@
I acknowledge that: I acknowledge that:
- I have updated: - I have updated:
- To the latest version of the app (stable is v0.13.2) - To the latest version of the app (stable is v0.13.5)
- All extensions - All extensions
- I have tried the troubleshooting guide: https://tachiyomi.org/help/guides/troubleshooting-problems/ - I have tried the troubleshooting guide: https://tachiyomi.org/help/guides/troubleshooting-problems/
- If this is an issue with an extension, that I should be opening an issue in https://github.com/tachiyomiorg/tachiyomi-extensions - If this is an issue with an extension, that I should be opening an issue in https://github.com/tachiyomiorg/tachiyomi-extensions

View File

@ -53,7 +53,7 @@ body:
label: Tachiyomi version label: Tachiyomi version
description: You can find your Tachiyomi version in **More → About**. description: You can find your Tachiyomi version in **More → About**.
placeholder: | placeholder: |
Example: "0.13.2" Example: "0.13.5"
validations: validations:
required: true required: true
@ -98,7 +98,7 @@ body:
required: true required: true
- label: I have tried the [troubleshooting guide](https://tachiyomi.org/help/guides/troubleshooting/). - label: I have tried the [troubleshooting guide](https://tachiyomi.org/help/guides/troubleshooting/).
required: true required: true
- label: I have updated the app to version **[0.13.2](https://github.com/tachiyomiorg/tachiyomi/releases/latest)**. - label: I have updated the app to version **[0.13.5](https://github.com/tachiyomiorg/tachiyomi/releases/latest)**.
required: true required: true
- label: I have updated all installed extensions. - label: I have updated all installed extensions.
required: true required: true

View File

@ -33,7 +33,7 @@ body:
required: true required: true
- label: If this is an issue with an extension, I should be opening an issue in the [extensions repository](https://github.com/tachiyomiorg/tachiyomi-extensions/issues/new/choose). - label: If this is an issue with an extension, I should be opening an issue in the [extensions repository](https://github.com/tachiyomiorg/tachiyomi-extensions/issues/new/choose).
required: true required: true
- label: I have updated the app to version **[0.13.2](https://github.com/tachiyomiorg/tachiyomi/releases/latest)**. - label: I have updated the app to version **[0.13.5](https://github.com/tachiyomiorg/tachiyomi/releases/latest)**.
required: true required: true
- label: I will fill out all of the requested information in this form. - label: I will fill out all of the requested information in this form.
required: true required: true

View File

@ -5,6 +5,9 @@ on:
- '**.md' - '**.md'
- 'app/src/main/res/**/strings.xml' - 'app/src/main/res/**/strings.xml'
permissions:
contents: read
jobs: jobs:
build: build:
name: Build app name: Build app
@ -12,15 +15,19 @@ jobs:
steps: steps:
- name: Clone repo - name: Clone repo
uses: actions/checkout@v2 uses: actions/checkout@v3
- name: Validate Gradle Wrapper - name: Validate Gradle Wrapper
uses: gradle/wrapper-validation-action@v1 uses: gradle/wrapper-validation-action@v1
- name: Dependency Review
uses: actions/dependency-review-action@v1
- name: Set up JDK 11 - name: Set up JDK 11
uses: actions/setup-java@v1 uses: actions/setup-java@v3
with: with:
java-version: 11 java-version: 11
distribution: adopt
- name: Copy CI gradle.properties - name: Copy CI gradle.properties
run: | run: |

View File

@ -19,15 +19,16 @@ jobs:
all_but_latest: true all_but_latest: true
- name: Clone repo - name: Clone repo
uses: actions/checkout@v2 uses: actions/checkout@v3
- name: Validate Gradle Wrapper - name: Validate Gradle Wrapper
uses: gradle/wrapper-validation-action@v1 uses: gradle/wrapper-validation-action@v1
- name: Set up JDK 11 - name: Set up JDK 11
uses: actions/setup-java@v1 uses: actions/setup-java@v3
with: with:
java-version: 11 java-version: 11
distribution: adopt
- name: Copy CI gradle.properties - name: Copy CI gradle.properties
run: | run: |

View File

@ -24,8 +24,8 @@ android {
applicationId = "eu.kanade.tachiyomi" applicationId = "eu.kanade.tachiyomi"
minSdk = AndroidConfig.minSdk minSdk = AndroidConfig.minSdk
targetSdk = AndroidConfig.targetSdk targetSdk = AndroidConfig.targetSdk
versionCode = 78 versionCode = 81
versionName = "0.13.2" versionName = "0.13.5"
buildConfigField("String", "COMMIT_COUNT", "\"${getCommitCount()}\"") buildConfigField("String", "COMMIT_COUNT", "\"${getCommitCount()}\"")
buildConfigField("String", "COMMIT_SHA", "\"${getGitSha()}\"") buildConfigField("String", "COMMIT_SHA", "\"${getGitSha()}\"")
@ -155,7 +155,7 @@ dependencies {
implementation(androidx.bundles.lifecycle) implementation(androidx.bundles.lifecycle)
// Job scheduling // Job scheduling
implementation(androidx.work.runtime) implementation(androidx.bundles.workmanager)
// RX // RX
implementation(libs.bundles.reactivex) implementation(libs.bundles.reactivex)
@ -219,6 +219,7 @@ dependencies {
exclude(group = "androidx.viewpager", module = "viewpager") exclude(group = "androidx.viewpager", module = "viewpager")
} }
implementation(libs.insetter) implementation(libs.insetter)
implementation(libs.markwon)
// Conductor // Conductor
implementation(libs.bundles.conductor) implementation(libs.bundles.conductor)

View File

@ -26,7 +26,6 @@
android:name=".App" android:name=".App"
android:allowBackup="false" android:allowBackup="false"
android:hardwareAccelerated="true" android:hardwareAccelerated="true"
android:hasFragileUserData="true"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="@string/app_name" android:label="@string/app_name"
android:largeHeap="true" android:largeHeap="true"

View File

@ -1,5 +1,6 @@
package eu.kanade.tachiyomi package eu.kanade.tachiyomi
import android.annotation.SuppressLint
import android.app.ActivityManager import android.app.ActivityManager
import android.app.Application import android.app.Application
import android.app.PendingIntent import android.app.PendingIntent
@ -8,6 +9,7 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.IntentFilter import android.content.IntentFilter
import android.os.Build import android.os.Build
import android.os.Looper
import android.webkit.WebView import android.webkit.WebView
import androidx.appcompat.app.AppCompatDelegate import androidx.appcompat.app.AppCompatDelegate
import androidx.core.app.NotificationManagerCompat import androidx.core.app.NotificationManagerCompat
@ -34,6 +36,7 @@ import eu.kanade.tachiyomi.util.preference.asImmediateFlow
import eu.kanade.tachiyomi.util.system.AuthenticatorUtil import eu.kanade.tachiyomi.util.system.AuthenticatorUtil
import eu.kanade.tachiyomi.util.system.WebViewUtil import eu.kanade.tachiyomi.util.system.WebViewUtil
import eu.kanade.tachiyomi.util.system.animatorDurationScale import eu.kanade.tachiyomi.util.system.animatorDurationScale
import eu.kanade.tachiyomi.util.system.isDevFlavor
import eu.kanade.tachiyomi.util.system.logcat import eu.kanade.tachiyomi.util.system.logcat
import eu.kanade.tachiyomi.util.system.notification import eu.kanade.tachiyomi.util.system.notification
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
@ -56,6 +59,7 @@ open class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory {
private val disableIncognitoReceiver = DisableIncognitoReceiver() private val disableIncognitoReceiver = DisableIncognitoReceiver()
@SuppressLint("LaunchActivityFromNotification")
override fun onCreate() { override fun onCreate() {
super<Application>.onCreate() super<Application>.onCreate()
@ -150,27 +154,31 @@ open class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory {
} }
override fun getPackageName(): String { override fun getPackageName(): String {
try { // This causes freezes in Android 6/7 for some reason
// Override the value passed as X-Requested-With in WebView requests if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val stackTrace = Thread.currentThread().stackTrace try {
for (element in stackTrace) { // Override the value passed as X-Requested-With in WebView requests
if ("org.chromium.base.BuildInfo".equals(element.className, ignoreCase = true)) { val stackTrace = Looper.getMainLooper().thread.stackTrace
if ("getAll".equals(element.methodName, ignoreCase = true)) { val chromiumElement = stackTrace.find {
return WebViewUtil.SPOOF_PACKAGE_NAME it.className.equals(
} "org.chromium.base.BuildInfo",
break ignoreCase = true,
)
} }
if (chromiumElement?.methodName.equals("getAll", ignoreCase = true)) {
return WebViewUtil.SPOOF_PACKAGE_NAME
}
} catch (e: Exception) {
} }
} catch (e: Exception) {
} }
return super.getPackageName() return super.getPackageName()
} }
protected open fun setupAcra() { protected open fun setupAcra() {
if (BuildConfig.FLAVOR != "dev") { if (isDevFlavor.not()) {
initAcra { initAcra {
buildConfigClass = BuildConfig::class.java buildConfigClass = BuildConfig::class.java
excludeMatchingSharedPreferencesKeys = arrayOf(".*username.*", ".*password.*", ".*token.*") excludeMatchingSharedPreferencesKeys = listOf(".*username.*", ".*password.*", ".*token.*")
httpSender { httpSender {
uri = BuildConfig.ACRA_URI uri = BuildConfig.ACRA_URI

View File

@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.data.backup.full
import android.content.Context import android.content.Context
import android.net.Uri import android.net.Uri
import com.hippo.unifile.UniFile import com.hippo.unifile.UniFile
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.backup.AbstractBackupManager import eu.kanade.tachiyomi.data.backup.AbstractBackupManager
import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_CATEGORY import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_CATEGORY
import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_CATEGORY_MASK import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_CATEGORY_MASK
@ -54,7 +55,7 @@ class FullBackupManager(context: Context) : AbstractBackupManager(context) {
backup = Backup( backup = Backup(
backupManga(databaseManga, flags), backupManga(databaseManga, flags),
backupCategories(), backupCategories(flags),
emptyList(), emptyList(),
backupExtensionInfo(databaseManga), backupExtensionInfo(databaseManga),
) )
@ -90,6 +91,10 @@ class FullBackupManager(context: Context) : AbstractBackupManager(context) {
} }
val byteArray = parser.encodeToByteArray(BackupSerializer, backup!!) val byteArray = parser.encodeToByteArray(BackupSerializer, backup!!)
if (byteArray.isEmpty()) {
throw IllegalStateException(context.getString(R.string.empty_backup_error))
}
file.openOutputStream().also { file.openOutputStream().also {
// Force overwrite old file // Force overwrite old file
(it as? FileOutputStream)?.channel?.truncate(0) (it as? FileOutputStream)?.channel?.truncate(0)
@ -128,10 +133,15 @@ class FullBackupManager(context: Context) : AbstractBackupManager(context) {
* *
* @return list of [BackupCategory] to be backed up * @return list of [BackupCategory] to be backed up
*/ */
private fun backupCategories(): List<BackupCategory> { private fun backupCategories(options: Int): List<BackupCategory> {
return databaseHelper.getCategories() // Check if user wants category information in backup
.executeAsBlocking() return if (options and BACKUP_CATEGORY_MASK == BACKUP_CATEGORY) {
.map { BackupCategory.copyFrom(it) } databaseHelper.getCategories()
.executeAsBlocking()
.map { BackupCategory.copyFrom(it) }
} else {
emptyList()
}
} }
/** /**

View File

@ -1,5 +1,6 @@
package eu.kanade.tachiyomi.data.download package eu.kanade.tachiyomi.data.download
import android.app.PendingIntent
import android.content.Context import android.content.Context
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
@ -184,8 +185,10 @@ internal class DownloadNotifier(private val context: Context) {
* Called when the downloader receives a warning. * Called when the downloader receives a warning.
* *
* @param reason the text to show. * @param reason the text to show.
* @param timeout duration after which to automatically dismiss the notification.
* Only works on Android 8+.
*/ */
fun onWarning(reason: String) { fun onWarning(reason: String, timeout: Long? = null, contentIntent: PendingIntent? = null) {
with(errorNotificationBuilder) { with(errorNotificationBuilder) {
setContentTitle(context.getString(R.string.download_notifier_downloader_title)) setContentTitle(context.getString(R.string.download_notifier_downloader_title))
setStyle(NotificationCompat.BigTextStyle().bigText(reason)) setStyle(NotificationCompat.BigTextStyle().bigText(reason))
@ -194,6 +197,8 @@ internal class DownloadNotifier(private val context: Context) {
clearActions() clearActions()
setContentIntent(NotificationHandler.openDownloadManagerPendingActivity(context)) setContentIntent(NotificationHandler.openDownloadManagerPendingActivity(context))
setProgress(0, 0, false) setProgress(0, 0, false)
timeout?.let { setTimeoutAfter(it) }
contentIntent?.let { setContentIntent(it) }
show(Notifications.ID_DOWNLOAD_CHAPTER_ERROR) show(Notifications.ID_DOWNLOAD_CHAPTER_ERROR)
} }

View File

@ -1,18 +1,17 @@
package eu.kanade.tachiyomi.data.download package eu.kanade.tachiyomi.data.download
import android.content.Context import android.content.Context
import android.webkit.MimeTypeMap
import android.widget.Toast
import com.hippo.unifile.UniFile import com.hippo.unifile.UniFile
import com.jakewharton.rxrelay.BehaviorRelay import com.jakewharton.rxrelay.BehaviorRelay
import com.jakewharton.rxrelay.PublishRelay import com.jakewharton.rxrelay.PublishRelay
import eu.kanade.tachiyomi.BuildConfig
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.cache.ChapterCache import eu.kanade.tachiyomi.data.cache.ChapterCache
import eu.kanade.tachiyomi.data.database.models.Chapter import eu.kanade.tachiyomi.data.database.models.Chapter
import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.download.model.Download import eu.kanade.tachiyomi.data.download.model.Download
import eu.kanade.tachiyomi.data.download.model.DownloadQueue import eu.kanade.tachiyomi.data.download.model.DownloadQueue
import eu.kanade.tachiyomi.data.library.LibraryUpdateNotifier
import eu.kanade.tachiyomi.data.notification.NotificationHandler
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.source.UnmeteredSource import eu.kanade.tachiyomi.source.UnmeteredSource
@ -28,7 +27,6 @@ import eu.kanade.tachiyomi.util.storage.DiskUtil
import eu.kanade.tachiyomi.util.storage.saveTo import eu.kanade.tachiyomi.util.storage.saveTo
import eu.kanade.tachiyomi.util.system.ImageUtil import eu.kanade.tachiyomi.util.system.ImageUtil
import eu.kanade.tachiyomi.util.system.logcat import eu.kanade.tachiyomi.util.system.logcat
import eu.kanade.tachiyomi.util.system.toast
import kotlinx.coroutines.async import kotlinx.coroutines.async
import logcat.LogPriority import logcat.LogPriority
import okhttp3.Response import okhttp3.Response
@ -275,14 +273,22 @@ class Downloader(
// Start downloader if needed // Start downloader if needed
if (autoStart && wasEmpty) { if (autoStart && wasEmpty) {
val queuedDownloads = queue.filter { it.source !is UnmeteredSource }.count()
val maxDownloadsFromSource = queue val maxDownloadsFromSource = queue
.groupBy { it.source } .groupBy { it.source }
.filterKeys { it !is UnmeteredSource } .filterKeys { it !is UnmeteredSource }
.maxOf { it.value.size } .maxOfOrNull { it.value.size }
// TODO: show warnings in stable ?: 0
if (maxDownloadsFromSource > CHAPTERS_PER_SOURCE_QUEUE_WARNING_THRESHOLD && BuildConfig.FLAVOR != "stable") { if (
queuedDownloads > DOWNLOADS_QUEUED_WARNING_THRESHOLD ||
maxDownloadsFromSource > CHAPTERS_PER_SOURCE_QUEUE_WARNING_THRESHOLD
) {
withUIContext { withUIContext {
context.toast(R.string.download_queue_size_warning, Toast.LENGTH_LONG) notifier.onWarning(
context.getString(R.string.download_queue_size_warning),
WARNING_NOTIF_TIMEOUT_MS,
NotificationHandler.openUrl(context, LibraryUpdateNotifier.HELP_WARNING_URL),
)
} }
} }
DownloadService.start(context) DownloadService.start(context)
@ -465,7 +471,7 @@ class Downloader(
// Else read magic numbers. // Else read magic numbers.
?: ImageUtil.findImageType { file.openInputStream() }?.mime ?: ImageUtil.findImageType { file.openInputStream() }?.mime
return MimeTypeMap.getSingleton().getExtensionFromMimeType(mime) ?: "jpg" return ImageUtil.getExtensionFromMimeType(mime)
} }
/** /**
@ -561,7 +567,9 @@ class Downloader(
companion object { companion object {
const val TMP_DIR_SUFFIX = "_tmp" const val TMP_DIR_SUFFIX = "_tmp"
const val WARNING_NOTIF_TIMEOUT_MS = 30_000L
const val CHAPTERS_PER_SOURCE_QUEUE_WARNING_THRESHOLD = 15 const val CHAPTERS_PER_SOURCE_QUEUE_WARNING_THRESHOLD = 15
private const val DOWNLOADS_QUEUED_WARNING_THRESHOLD = 30
} }
} }

View File

@ -8,9 +8,7 @@ import androidx.work.PeriodicWorkRequestBuilder
import androidx.work.WorkManager import androidx.work.WorkManager
import androidx.work.Worker import androidx.work.Worker
import androidx.work.WorkerParameters import androidx.work.WorkerParameters
import eu.kanade.tachiyomi.data.preference.DEVICE_CHARGING import eu.kanade.tachiyomi.data.preference.*
import eu.kanade.tachiyomi.data.preference.DEVICE_ONLY_ON_WIFI
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.util.system.isConnectedToWifi import eu.kanade.tachiyomi.util.system.isConnectedToWifi
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
@ -21,8 +19,9 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
override fun doWork(): Result { override fun doWork(): Result {
val preferences = Injekt.get<PreferencesHelper>() val preferences = Injekt.get<PreferencesHelper>()
if (requiresWifiConnection(preferences) && !context.isConnectedToWifi()) { val restrictions = preferences.libraryUpdateDeviceRestriction().get()
Result.failure() if ((DEVICE_ONLY_ON_WIFI in restrictions) && !context.isConnectedToWifi()) {
return Result.failure()
} }
return if (LibraryUpdateService.start(context)) { return if (LibraryUpdateService.start(context)) {
@ -41,8 +40,9 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
if (interval > 0) { if (interval > 0) {
val restrictions = preferences.libraryUpdateDeviceRestriction().get() val restrictions = preferences.libraryUpdateDeviceRestriction().get()
val constraints = Constraints.Builder() val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED) .setRequiredNetworkType(if (DEVICE_NETWORK_NOT_METERED in restrictions) { NetworkType.UNMETERED } else { NetworkType.CONNECTED })
.setRequiresCharging(DEVICE_CHARGING in restrictions) .setRequiresCharging(DEVICE_CHARGING in restrictions)
.setRequiresBatteryNotLow(DEVICE_BATTERY_NOT_LOW in restrictions)
.build() .build()
val request = PeriodicWorkRequestBuilder<LibraryUpdateJob>( val request = PeriodicWorkRequestBuilder<LibraryUpdateJob>(
@ -60,10 +60,5 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
WorkManager.getInstance(context).cancelAllWorkByTag(TAG) WorkManager.getInstance(context).cancelAllWorkByTag(TAG)
} }
} }
fun requiresWifiConnection(preferences: PreferencesHelper): Boolean {
val restrictions = preferences.libraryUpdateDeviceRestriction().get()
return DEVICE_ONLY_ON_WIFI in restrictions
}
} }
} }

View File

@ -90,6 +90,21 @@ class LibraryUpdateNotifier(private val context: Context) {
) )
} }
fun showQueueSizeWarningNotification() {
val notificationBuilder = context.notificationBuilder(Notifications.CHANNEL_LIBRARY_PROGRESS) {
setContentTitle(context.getString(R.string.label_warning))
setStyle(NotificationCompat.BigTextStyle().bigText(context.getString(R.string.notification_size_warning)))
setSmallIcon(R.drawable.ic_warning_white_24dp)
setTimeoutAfter(Downloader.WARNING_NOTIF_TIMEOUT_MS)
setContentIntent(NotificationHandler.openUrl(context, HELP_WARNING_URL))
}
context.notificationManager.notify(
Notifications.ID_LIBRARY_SIZE_WARNING,
notificationBuilder.build(),
)
}
/** /**
* Shows notification containing update entries that failed with action to open full log. * Shows notification containing update entries that failed with action to open full log.
* *
@ -128,8 +143,9 @@ class LibraryUpdateNotifier(private val context: Context) {
Notifications.ID_LIBRARY_SKIPPED, Notifications.ID_LIBRARY_SKIPPED,
context.notificationBuilder(Notifications.CHANNEL_LIBRARY_SKIPPED) { context.notificationBuilder(Notifications.CHANNEL_LIBRARY_SKIPPED) {
setContentTitle(context.resources.getString(R.string.notification_update_skipped, skipped)) setContentTitle(context.resources.getString(R.string.notification_update_skipped, skipped))
setContentText(context.getString(R.string.learn_more))
setSmallIcon(R.drawable.ic_tachi) setSmallIcon(R.drawable.ic_tachi)
addAction(R.drawable.ic_help_24dp, context.getString(R.string.learn_more), NotificationHandler.openUrl(context, HELP_SKIPPED_URL)) setContentIntent(NotificationHandler.openUrl(context, HELP_SKIPPED_URL))
} }
.build(), .build(),
) )
@ -325,6 +341,10 @@ class LibraryUpdateNotifier(private val context: Context) {
} }
return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT) return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
} }
companion object {
const val HELP_WARNING_URL = "https://tachiyomi.org/help/faq/#why-does-the-app-warn-about-large-bulk-updates-and-downloads"
}
} }
private const val NOTIF_MAX_CHAPTERS = 5 private const val NOTIF_MAX_CHAPTERS = 5

View File

@ -5,9 +5,7 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.IBinder import android.os.IBinder
import android.os.PowerManager import android.os.PowerManager
import android.widget.Toast
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import eu.kanade.tachiyomi.BuildConfig
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.cache.CoverCache import eu.kanade.tachiyomi.data.cache.CoverCache
import eu.kanade.tachiyomi.data.database.DatabaseHelper import eu.kanade.tachiyomi.data.database.DatabaseHelper
@ -43,7 +41,6 @@ import eu.kanade.tachiyomi.util.system.acquireWakeLock
import eu.kanade.tachiyomi.util.system.createFileInCacheDir import eu.kanade.tachiyomi.util.system.createFileInCacheDir
import eu.kanade.tachiyomi.util.system.isServiceRunning import eu.kanade.tachiyomi.util.system.isServiceRunning
import eu.kanade.tachiyomi.util.system.logcat import eu.kanade.tachiyomi.util.system.logcat
import eu.kanade.tachiyomi.util.system.toast
import kotlinx.coroutines.CoroutineExceptionHandler import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@ -177,6 +174,8 @@ class LibraryUpdateService(
*/ */
override fun onDestroy() { override fun onDestroy() {
updateJob?.cancel() updateJob?.cancel()
// Despite what Android Studio
// states this can be null
ioScope?.cancel() ioScope?.cancel()
if (wakeLock.isHeld) { if (wakeLock.isHeld) {
wakeLock.release() wakeLock.release()
@ -236,8 +235,7 @@ class LibraryUpdateService(
/** /**
* Adds list of manga to be updated. * Adds list of manga to be updated.
* *
* @param category the ID of the category to update, or -1 if no category specified. * @param categoryId the ID of the category to update, or -1 if no category specified.
* @param target the target to update.
*/ */
fun addMangaToQueue(categoryId: Int) { fun addMangaToQueue(categoryId: Int) {
val libraryManga = db.getLibraryMangas().executeAsBlocking() val libraryManga = db.getLibraryMangas().executeAsBlocking()
@ -271,19 +269,17 @@ class LibraryUpdateService(
.groupBy { it.source } .groupBy { it.source }
.filterKeys { sourceManager.get(it) !is UnmeteredSource } .filterKeys { sourceManager.get(it) !is UnmeteredSource }
.maxOfOrNull { it.value.size } ?: 0 .maxOfOrNull { it.value.size } ?: 0
// TODO: show warnings in stable if (maxUpdatesFromSource > MANGA_PER_SOURCE_QUEUE_WARNING_THRESHOLD) {
if (maxUpdatesFromSource > MANGA_PER_SOURCE_QUEUE_WARNING_THRESHOLD && BuildConfig.FLAVOR != "stable") { notifier.showQueueSizeWarningNotification()
toast(R.string.notification_size_warning, Toast.LENGTH_LONG)
} }
} }
/** /**
* Method that updates the given list of manga. It's called in a background thread, so it's safe * Method that updates manga in [mangaToUpdate]. It's called in a background thread, so it's safe
* to do heavy operations or network calls here. * to do heavy operations or network calls here.
* For each manga it calls [updateManga] and updates the notification showing the current * For each manga it calls [updateManga] and updates the notification showing the current
* progress. * progress.
* *
* @param mangaToUpdate the list to update
* @return an observable delivering the progress of each update. * @return an observable delivering the progress of each update.
*/ */
suspend fun updateChapterList() { suspend fun updateChapterList() {
@ -309,35 +305,38 @@ class LibraryUpdateService(
return@async return@async
} }
// Don't continue to update if manga not in library
db.getManga(manga.id!!).executeAsBlocking() ?: return@forEach
withUpdateNotification( withUpdateNotification(
currentlyUpdatingManga, currentlyUpdatingManga,
progressCount, progressCount,
manga, manga,
) { manga -> ) { mangaWithNotif ->
try { try {
when { when {
MANGA_NON_COMPLETED in restrictions && manga.status == SManga.COMPLETED -> { MANGA_NON_COMPLETED in restrictions && mangaWithNotif.status == SManga.COMPLETED ->
skippedUpdates.add(manga to getString(R.string.skipped_reason_completed)) skippedUpdates.add(mangaWithNotif to getString(R.string.skipped_reason_completed))
}
MANGA_HAS_UNREAD in restrictions && manga.unreadCount != 0 -> { MANGA_HAS_UNREAD in restrictions && mangaWithNotif.unreadCount != 0 ->
skippedUpdates.add(manga to getString(R.string.skipped_reason_not_caught_up)) skippedUpdates.add(mangaWithNotif to getString(R.string.skipped_reason_not_caught_up))
}
MANGA_NON_READ in restrictions && manga.totalChapters > 0 && !manga.hasStarted -> { MANGA_NON_READ in restrictions && mangaWithNotif.totalChapters > 0 && !mangaWithNotif.hasStarted ->
skippedUpdates.add(manga to getString(R.string.skipped_reason_not_started)) skippedUpdates.add(mangaWithNotif to getString(R.string.skipped_reason_not_started))
}
else -> { else -> {
// Convert to the manga that contains new chapters // Convert to the manga that contains new chapters
val (newChapters, _) = updateManga(manga) val (newChapters, _) = updateManga(mangaWithNotif)
if (newChapters.isNotEmpty()) { if (newChapters.isNotEmpty()) {
if (manga.shouldDownloadNewChapters(db, preferences)) { if (mangaWithNotif.shouldDownloadNewChapters(db, preferences)) {
downloadChapters(manga, newChapters) downloadChapters(mangaWithNotif, newChapters)
hasDownloads.set(true) hasDownloads.set(true)
} }
// Convert to the manga that contains new chapters // Convert to the manga that contains new chapters
newUpdates.add( newUpdates.add(
manga to newChapters.sortedByDescending { ch -> ch.source_order } mangaWithNotif to newChapters.sortedByDescending { ch -> ch.source_order }
.toTypedArray(), .toTypedArray(),
) )
} }
@ -356,11 +355,11 @@ class LibraryUpdateService(
e.message e.message
} }
} }
failedUpdates.add(manga to errorMessage) failedUpdates.add(mangaWithNotif to errorMessage)
} }
if (preferences.autoUpdateTrackers()) { if (preferences.autoUpdateTrackers()) {
updateTrackings(manga, loggedServices) updateTrackings(mangaWithNotif, loggedServices)
} }
} }
} }
@ -408,6 +407,7 @@ class LibraryUpdateService(
suspend fun updateManga(manga: Manga): Pair<List<Chapter>, List<Chapter>> { suspend fun updateManga(manga: Manga): Pair<List<Chapter>, List<Chapter>> {
val source = sourceManager.getOrStub(manga.source) val source = sourceManager.getOrStub(manga.source)
var networkSManga: SManga? = null
// Update manga details metadata // Update manga details metadata
if (preferences.autoUpdateMetadata()) { if (preferences.autoUpdateMetadata()) {
val updatedManga = source.getMangaDetails(manga.toMangaInfo()) val updatedManga = source.getMangaDetails(manga.toMangaInfo())
@ -419,14 +419,26 @@ class LibraryUpdateService(
sManga.thumbnail_url = manga.thumbnail_url sManga.thumbnail_url = manga.thumbnail_url
} }
manga.copyFrom(sManga) networkSManga = sManga
db.insertManga(manga).executeAsBlocking()
} }
val chapters = source.getChapterList(manga.toMangaInfo()) val chapters = source.getChapterList(manga.toMangaInfo())
.map { it.toSChapter() } .map { it.toSChapter() }
return syncChaptersWithSource(db, chapters, manga, source) // Get manga from database to account for if it was removed
// from library or database
val dbManga = db.getManga(manga.id!!).executeAsBlocking()
?: return Pair(emptyList(), emptyList())
// Copy into [dbManga] to retain favourite value
networkSManga?.let {
dbManga.copyFrom(it)
db.insertManga(dbManga).executeAsBlocking()
}
// [dbmanga] was used so that manga data doesn't get overwritten
// incase manga gets new chapter
return syncChaptersWithSource(db, chapters, dbManga, source)
} }
private suspend fun updateCovers() { private suspend fun updateCovers() {
@ -449,16 +461,16 @@ class LibraryUpdateService(
currentlyUpdatingManga, currentlyUpdatingManga,
progressCount, progressCount,
manga, manga,
) { manga -> ) { mangaWithNotif ->
sourceManager.get(manga.source)?.let { source -> sourceManager.get(mangaWithNotif.source)?.let { source ->
try { try {
val networkManga = val networkManga =
source.getMangaDetails(manga.toMangaInfo()) source.getMangaDetails(mangaWithNotif.toMangaInfo())
val sManga = networkManga.toSManga() val sManga = networkManga.toSManga()
manga.prepUpdateCover(coverCache, sManga, true) mangaWithNotif.prepUpdateCover(coverCache, sManga, true)
sManga.thumbnail_url?.let { sManga.thumbnail_url?.let {
manga.thumbnail_url = it mangaWithNotif.thumbnail_url = it
db.insertManga(manga).executeAsBlocking() db.insertManga(mangaWithNotif).executeAsBlocking()
} }
} catch (e: Throwable) { } catch (e: Throwable) {
// Ignore errors and continue // Ignore errors and continue

View File

@ -26,10 +26,11 @@ object Notifications {
private const val GROUP_LIBRARY = "group_library" private const val GROUP_LIBRARY = "group_library"
const val CHANNEL_LIBRARY_PROGRESS = "library_progress_channel" const val CHANNEL_LIBRARY_PROGRESS = "library_progress_channel"
const val ID_LIBRARY_PROGRESS = -101 const val ID_LIBRARY_PROGRESS = -101
const val ID_LIBRARY_SIZE_WARNING = -103
const val CHANNEL_LIBRARY_ERROR = "library_errors_channel" const val CHANNEL_LIBRARY_ERROR = "library_errors_channel"
const val ID_LIBRARY_ERROR = -102 const val ID_LIBRARY_ERROR = -102
const val CHANNEL_LIBRARY_SKIPPED = "library_skipped_channel" const val CHANNEL_LIBRARY_SKIPPED = "library_skipped_channel"
const val ID_LIBRARY_SKIPPED = -103 const val ID_LIBRARY_SKIPPED = -104
/** /**
* Notification channel and ids used by the downloader. * Notification channel and ids used by the downloader.

View File

@ -3,7 +3,9 @@ package eu.kanade.tachiyomi.data.preference
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
const val DEVICE_ONLY_ON_WIFI = "wifi" const val DEVICE_ONLY_ON_WIFI = "wifi"
const val DEVICE_NETWORK_NOT_METERED = "network_not_metered"
const val DEVICE_CHARGING = "ac" const val DEVICE_CHARGING = "ac"
const val DEVICE_BATTERY_NOT_LOW = "battery_not_low"
const val MANGA_NON_COMPLETED = "manga_ongoing" const val MANGA_NON_COMPLETED = "manga_ongoing"
const val MANGA_HAS_UNREAD = "manga_fully_read" const val MANGA_HAS_UNREAD = "manga_fully_read"
@ -28,13 +30,14 @@ object PreferenceValues {
enum class AppTheme(val titleResId: Int?) { enum class AppTheme(val titleResId: Int?) {
DEFAULT(R.string.label_default), DEFAULT(R.string.label_default),
MONET(R.string.theme_monet), MONET(R.string.theme_monet),
GREEN_APPLE(R.string.theme_greenapple),
LAVENDER(R.string.theme_lavender),
MIDNIGHT_DUSK(R.string.theme_midnightdusk), MIDNIGHT_DUSK(R.string.theme_midnightdusk),
STRAWBERRY_DAIQUIRI(R.string.theme_strawberrydaiquiri), STRAWBERRY_DAIQUIRI(R.string.theme_strawberrydaiquiri),
YOTSUBA(R.string.theme_yotsuba),
TAKO(R.string.theme_tako), TAKO(R.string.theme_tako),
GREEN_APPLE(R.string.theme_greenapple),
TEALTURQUOISE(R.string.theme_tealturquoise), TEALTURQUOISE(R.string.theme_tealturquoise),
YINYANG(R.string.theme_yinyang), YINYANG(R.string.theme_yinyang),
YOTSUBA(R.string.theme_yotsuba),
// Deprecated // Deprecated
DARK_BLUE(null), DARK_BLUE(null),

View File

@ -18,6 +18,7 @@ import eu.kanade.tachiyomi.ui.library.setting.SortModeSetting
import eu.kanade.tachiyomi.ui.reader.setting.OrientationType import eu.kanade.tachiyomi.ui.reader.setting.OrientationType
import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType
import eu.kanade.tachiyomi.util.system.DeviceUtil import eu.kanade.tachiyomi.util.system.DeviceUtil
import eu.kanade.tachiyomi.util.system.isDevFlavor
import eu.kanade.tachiyomi.widget.ExtendedNavigationView import eu.kanade.tachiyomi.widget.ExtendedNavigationView
import java.io.File import java.io.File
import java.text.DateFormat import java.text.DateFormat
@ -203,11 +204,11 @@ class PreferencesHelper(val context: Context) {
fun downloadOnlyOverWifi() = prefs.getBoolean(Keys.downloadOnlyOverWifi, true) fun downloadOnlyOverWifi() = prefs.getBoolean(Keys.downloadOnlyOverWifi, true)
fun saveChaptersAsCBZ() = flowPrefs.getBoolean("save_chapter_as_cbz", false) fun saveChaptersAsCBZ() = flowPrefs.getBoolean("save_chapter_as_cbz", true)
fun folderPerManga() = prefs.getBoolean(Keys.folderPerManga, false) fun folderPerManga() = prefs.getBoolean(Keys.folderPerManga, false)
fun numberOfBackups() = flowPrefs.getInt("backup_slots", 1) fun numberOfBackups() = flowPrefs.getInt("backup_slots", 2)
fun backupInterval() = flowPrefs.getInt("backup_interval", 0) fun backupInterval() = flowPrefs.getInt("backup_interval", 0)
@ -277,10 +278,10 @@ class PreferencesHelper(val context: Context) {
fun pinnedSources() = flowPrefs.getStringSet("pinned_catalogues", emptySet()) fun pinnedSources() = flowPrefs.getStringSet("pinned_catalogues", emptySet())
fun downloadNew() = flowPrefs.getBoolean("download_new", false) fun downloadNewChapter() = flowPrefs.getBoolean("download_new", false)
fun downloadNewCategories() = flowPrefs.getStringSet("download_new_categories", emptySet()) fun downloadNewChapterCategories() = flowPrefs.getStringSet("download_new_categories", emptySet())
fun downloadNewCategoriesExclude() = flowPrefs.getStringSet("download_new_categories_exclude", emptySet()) fun downloadNewChapterCategoriesExclude() = flowPrefs.getStringSet("download_new_categories_exclude", emptySet())
fun defaultCategory() = prefs.getInt(Keys.defaultCategory, -1) fun defaultCategory() = prefs.getInt(Keys.defaultCategory, -1)
@ -319,7 +320,7 @@ class PreferencesHelper(val context: Context) {
if (DeviceUtil.isMiui) Values.ExtensionInstaller.LEGACY else Values.ExtensionInstaller.PACKAGEINSTALLER, if (DeviceUtil.isMiui) Values.ExtensionInstaller.LEGACY else Values.ExtensionInstaller.PACKAGEINSTALLER,
) )
fun verboseLogging() = prefs.getBoolean(Keys.verboseLogging, false) fun verboseLogging() = prefs.getBoolean(Keys.verboseLogging, isDevFlavor)
fun autoClearChapterCache() = prefs.getBoolean(Keys.autoClearChapterCache, false) fun autoClearChapterCache() = prefs.getBoolean(Keys.autoClearChapterCache, false)

View File

@ -13,6 +13,8 @@ import eu.kanade.tachiyomi.util.storage.DiskUtil
import eu.kanade.tachiyomi.util.storage.cacheImageDir import eu.kanade.tachiyomi.util.storage.cacheImageDir
import eu.kanade.tachiyomi.util.storage.getUriCompat import eu.kanade.tachiyomi.util.storage.getUriCompat
import eu.kanade.tachiyomi.util.system.ImageUtil import eu.kanade.tachiyomi.util.system.ImageUtil
import eu.kanade.tachiyomi.util.system.logcat
import logcat.LogPriority
import okio.IOException import okio.IOException
import java.io.ByteArrayInputStream import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
@ -30,11 +32,7 @@ class ImageSaver(
val type = ImageUtil.findImageType(data) ?: throw Exception("Not an image") val type = ImageUtil.findImageType(data) ?: throw Exception("Not an image")
val filename = DiskUtil.buildValidFilename("${image.name}.${type.extension}") val filename = DiskUtil.buildValidFilename("${image.name}.${type.extension}")
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q || image.location !is Location.Pictures) {
return save(data(), image.location.directory(context), filename)
}
if (image.location !is Location.Pictures) {
return save(data(), image.location.directory(context), filename) return save(data(), image.location.directory(context), filename)
} }
@ -54,13 +52,18 @@ class ImageSaver(
val picture = context.contentResolver.insert( val picture = context.contentResolver.insert(
pictureDir, pictureDir,
contentValues, contentValues,
) ?: throw IOException("Couldn't create file") ) ?: throw IOException(context.getString(R.string.error_saving_picture))
data().use { input -> try {
@Suppress("BlockingMethodInNonBlockingContext") data().use { input ->
context.contentResolver.openOutputStream(picture, "w").use { output -> @Suppress("BlockingMethodInNonBlockingContext")
input.copyTo(output!!) context.contentResolver.openOutputStream(picture, "w").use { output ->
input.copyTo(output!!)
}
} }
} catch (e: Exception) {
logcat(LogPriority.ERROR, e)
throw IOException(context.getString(R.string.error_saving_picture))
} }
DiskUtil.scanMedia(context, picture) DiskUtil.scanMedia(context, picture)

View File

@ -8,6 +8,7 @@ import eu.kanade.tachiyomi.network.NetworkHelper
import eu.kanade.tachiyomi.network.await import eu.kanade.tachiyomi.network.await
import eu.kanade.tachiyomi.network.parseAs import eu.kanade.tachiyomi.network.parseAs
import eu.kanade.tachiyomi.util.lang.withIOContext import eu.kanade.tachiyomi.util.lang.withIOContext
import eu.kanade.tachiyomi.util.system.getInstallerPackageName
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import java.util.Date import java.util.Date
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
@ -33,14 +34,19 @@ class AppUpdateChecker {
// Check if latest version is different from current version // Check if latest version is different from current version
if (isNewVersion(it.version)) { if (isNewVersion(it.version)) {
AppUpdateResult.NewUpdate(it) if (context.getInstallerPackageName() == "org.fdroid.fdroid") {
AppUpdateResult.NewUpdateFdroidInstallation
} else {
AppUpdateResult.NewUpdate(it)
}
} else { } else {
AppUpdateResult.NoNewUpdate AppUpdateResult.NoNewUpdate
} }
} }
if (result is AppUpdateResult.NewUpdate) { when (result) {
AppUpdateNotifier(context).promptUpdate(result.release) is AppUpdateResult.NewUpdate -> AppUpdateNotifier(context).promptUpdate(result.release)
is AppUpdateResult.NewUpdateFdroidInstallation -> AppUpdateNotifier(context).promptFdroidUpdate()
} }
result result
@ -50,6 +56,7 @@ class AppUpdateChecker {
private fun isNewVersion(versionTag: String): Boolean { private fun isNewVersion(versionTag: String): Boolean {
// Removes prefixes like "r" or "v" // Removes prefixes like "r" or "v"
val newVersion = versionTag.replace("[^\\d.]".toRegex(), "") val newVersion = versionTag.replace("[^\\d.]".toRegex(), "")
val oldVersion = BuildConfig.VERSION_NAME.replace("[^\\d.]".toRegex(), "")
return if (BuildConfig.PREVIEW) { return if (BuildConfig.PREVIEW) {
// Preview builds: based on releases in "tachiyomiorg/tachiyomi-preview" repo // Preview builds: based on releases in "tachiyomiorg/tachiyomi-preview" repo
@ -58,7 +65,15 @@ class AppUpdateChecker {
} else { } else {
// Release builds: based on releases in "tachiyomiorg/tachiyomi" repo // Release builds: based on releases in "tachiyomiorg/tachiyomi" repo
// tagged as something like "v0.1.2" // tagged as something like "v0.1.2"
newVersion != BuildConfig.VERSION_NAME val newSemVer = newVersion.split(".").map { it.toInt() }
val oldSemVer = oldVersion.split(".").map { it.toInt() }
oldSemVer.mapIndexed { index, i ->
if (newSemVer[index] > i) {
return true
}
}
false
} }
} }
} }

View File

@ -58,6 +58,22 @@ internal class AppUpdateNotifier(private val context: Context) {
notificationBuilder.show() notificationBuilder.show()
} }
/**
* Some people are still installing the app from F-Droid, so we avoid prompting GitHub-based
* updates.
*
* We can prompt them to migrate to the GitHub version though.
*/
fun promptFdroidUpdate() {
with(notificationBuilder) {
setContentTitle(context.getString(R.string.update_check_notification_update_available))
setContentText(context.getString(R.string.update_check_fdroid_migration_info))
setSmallIcon(R.drawable.ic_tachi)
setContentIntent(NotificationHandler.openUrl(context, "https://tachiyomi.org/help/faq/#how-do-i-migrate-from-the-f-droid-version"))
}
notificationBuilder.show()
}
/** /**
* Call when apk download starts. * Call when apk download starts.
* *

View File

@ -2,5 +2,6 @@ package eu.kanade.tachiyomi.data.updater
sealed class AppUpdateResult { sealed class AppUpdateResult {
class NewUpdate(val release: GithubRelease) : AppUpdateResult() class NewUpdate(val release: GithubRelease) : AppUpdateResult()
object NewUpdateFdroidInstallation : AppUpdateResult()
object NoNewUpdate : AppUpdateResult() object NoNewUpdate : AppUpdateResult()
} }

View File

@ -244,11 +244,6 @@ class ExtensionManager(
installer.updateInstallStep(downloadId, InstallStep.Installing) installer.updateInstallStep(downloadId, InstallStep.Installing)
} }
fun setInstallationResult(downloadId: Long, result: Boolean) {
val step = if (result) InstallStep.Installed else InstallStep.Error
installer.updateInstallStep(downloadId, step)
}
fun updateInstallStep(downloadId: Long, step: InstallStep) { fun updateInstallStep(downloadId: Long, step: InstallStep) {
installer.updateInstallStep(downloadId, step) installer.updateInstallStep(downloadId, step)
} }

View File

@ -11,7 +11,9 @@ import eu.kanade.tachiyomi.network.NetworkHelper
import eu.kanade.tachiyomi.network.await import eu.kanade.tachiyomi.network.await
import eu.kanade.tachiyomi.network.parseAs import eu.kanade.tachiyomi.network.parseAs
import eu.kanade.tachiyomi.util.lang.withIOContext import eu.kanade.tachiyomi.util.lang.withIOContext
import eu.kanade.tachiyomi.util.system.logcat
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import logcat.LogPriority
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import java.util.Date import java.util.Date
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
@ -21,11 +23,27 @@ internal class ExtensionGithubApi {
private val networkService: NetworkHelper by injectLazy() private val networkService: NetworkHelper by injectLazy()
private val preferences: PreferencesHelper by injectLazy() private val preferences: PreferencesHelper by injectLazy()
private var requiresFallbackSource = false
suspend fun findExtensions(): List<Extension.Available> { suspend fun findExtensions(): List<Extension.Available> {
return withIOContext { return withIOContext {
val extensions = networkService.client val githubResponse = if (requiresFallbackSource) null else try {
.newCall(GET("${REPO_URL_PREFIX}index.min.json")) networkService.client
.await() .newCall(GET("${REPO_URL_PREFIX}index.min.json"))
.await()
} catch (e: Throwable) {
logcat(LogPriority.ERROR, e) { "Failed to get extensions from GitHub" }
requiresFallbackSource = true
null
}
val response = githubResponse ?: run {
networkService.client
.newCall(GET("${FALLBACK_REPO_URL_PREFIX}index.min.json"))
.await()
}
val extensions = response
.parseAs<List<ExtensionJsonObject>>() .parseAs<List<ExtensionJsonObject>>()
.toExtensions() .toExtensions()
@ -85,7 +103,7 @@ internal class ExtensionGithubApi {
hasChangelog = it.hasChangelog == 1, hasChangelog = it.hasChangelog == 1,
sources = it.sources?.toExtensionSources() ?: emptyList(), sources = it.sources?.toExtensionSources() ?: emptyList(),
apkName = it.apk, apkName = it.apk,
iconUrl = "${REPO_URL_PREFIX}icon/${it.apk.replace(".apk", ".png")}", iconUrl = "${getUrlPrefix()}icon/${it.apk.replace(".apk", ".png")}",
) )
} }
} }
@ -101,11 +119,20 @@ internal class ExtensionGithubApi {
} }
fun getApkUrl(extension: Extension.Available): String { fun getApkUrl(extension: Extension.Available): String {
return "${REPO_URL_PREFIX}apk/${extension.apkName}" return "${getUrlPrefix()}apk/${extension.apkName}"
}
private fun getUrlPrefix(): String {
return if (requiresFallbackSource) {
FALLBACK_REPO_URL_PREFIX
} else {
REPO_URL_PREFIX
}
} }
} }
private const val REPO_URL_PREFIX = "https://raw.githubusercontent.com/tachiyomiorg/tachiyomi-extensions/repo/" private const val REPO_URL_PREFIX = "https://raw.githubusercontent.com/tachiyomiorg/tachiyomi-extensions/repo/"
private const val FALLBACK_REPO_URL_PREFIX = "https://gcore.jsdelivr.net/gh/tachiyomiorg/tachiyomi-extensions@repo/"
@Serializable @Serializable
private data class ExtensionJsonObject( private data class ExtensionJsonObject(

View File

@ -52,9 +52,9 @@ class ShizukuInstaller(private val service: Service) : Installer(service) {
val size = service.getUriSize(entry.uri) ?: throw IllegalStateException() val size = service.getUriSize(entry.uri) ?: throw IllegalStateException()
service.contentResolver.openInputStream(entry.uri)!!.use { service.contentResolver.openInputStream(entry.uri)!!.use {
val createCommand = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { val createCommand = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
"pm install-create --user current -i ${service.packageName} -S $size" "pm install-create --user current -r -i ${service.packageName} -S $size"
} else { } else {
"pm install-create -i ${service.packageName} -S $size" "pm install-create -r -i ${service.packageName} -S $size"
} }
val createResult = exec(createCommand) val createResult = exec(createCommand)
sessionId = SESSION_ID_REGEX.find(createResult.out)?.value sessionId = SESSION_ID_REGEX.find(createResult.out)?.value

View File

@ -29,9 +29,9 @@ class AndroidCookieJar : CookieJar {
} }
} }
fun remove(url: HttpUrl, cookieNames: List<String>? = null, maxAge: Int = -1) { fun remove(url: HttpUrl, cookieNames: List<String>? = null, maxAge: Int = -1): Int {
val urlString = url.toString() val urlString = url.toString()
val cookies = manager.getCookie(urlString) ?: return val cookies = manager.getCookie(urlString) ?: return 0
fun List<String>.filterNames(): List<String> { fun List<String>.filterNames(): List<String> {
return if (cookieNames != null) { return if (cookieNames != null) {
@ -41,10 +41,11 @@ class AndroidCookieJar : CookieJar {
} }
} }
cookies.split(";") return cookies.split(";")
.map { it.substringBefore("=") } .map { it.substringBefore("=") }
.filterNames() .filterNames()
.onEach { manager.setCookie(urlString, "$it=;Max-Age=$maxAge") } .onEach { manager.setCookie(urlString, "$it=;Max-Age=$maxAge") }
.count()
} }
fun removeAll() { fun removeAll() {

View File

@ -13,6 +13,10 @@ const val PREF_DOH_CLOUDFLARE = 1
const val PREF_DOH_GOOGLE = 2 const val PREF_DOH_GOOGLE = 2
const val PREF_DOH_ADGUARD = 3 const val PREF_DOH_ADGUARD = 3
const val PREF_DOH_QUAD9 = 4 const val PREF_DOH_QUAD9 = 4
const val PREF_DOH_ALIDNS = 5
const val PREF_DOH_DNSPOD = 6
const val PREF_DOH_360 = 7
const val PREF_DOH_QUAD101 = 8
fun OkHttpClient.Builder.dohCloudflare() = dns( fun OkHttpClient.Builder.dohCloudflare() = dns(
DnsOverHttps.Builder().client(build()) DnsOverHttps.Builder().client(build())
@ -68,3 +72,51 @@ fun OkHttpClient.Builder.dohQuad9() = dns(
) )
.build(), .build(),
) )
fun OkHttpClient.Builder.dohAliDNS() = dns(
DnsOverHttps.Builder().client(build())
.url("https://dns.alidns.com/dns-query".toHttpUrl())
.bootstrapDnsHosts(
InetAddress.getByName("223.5.5.5"),
InetAddress.getByName("223.6.6.6"),
InetAddress.getByName("2400:3200::1"),
InetAddress.getByName("2400:3200:baba::1"),
)
.build(),
)
fun OkHttpClient.Builder.dohDNSPod() = dns(
DnsOverHttps.Builder().client(build())
.url("https://doh.pub/dns-query".toHttpUrl())
.bootstrapDnsHosts(
InetAddress.getByName("1.12.12.12"),
InetAddress.getByName("120.53.53.53"),
)
.build(),
)
fun OkHttpClient.Builder.doh360() = dns(
DnsOverHttps.Builder().client(build())
.url("https://doh.360.cn/dns-query".toHttpUrl())
.bootstrapDnsHosts(
InetAddress.getByName("101.226.4.6"),
InetAddress.getByName("218.30.118.6"),
InetAddress.getByName("123.125.81.6"),
InetAddress.getByName("140.207.198.6"),
InetAddress.getByName("180.163.249.75"),
InetAddress.getByName("101.199.113.208"),
InetAddress.getByName("36.99.170.86"),
)
.build(),
)
fun OkHttpClient.Builder.dohQuad101() = dns(
DnsOverHttps.Builder().client(build())
.url("https://dns.twnic.tw/dns-query".toHttpUrl())
.bootstrapDnsHosts(
InetAddress.getByName("101.101.101.101"),
InetAddress.getByName("2001:de4::101"),
InetAddress.getByName("2001:de4::102"),
)
.build(),
)

View File

@ -27,7 +27,8 @@ class NetworkHelper(context: Context) {
.cookieJar(cookieManager) .cookieJar(cookieManager)
.connectTimeout(30, TimeUnit.SECONDS) .connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS) .readTimeout(30, TimeUnit.SECONDS)
.fastFallback(true) .callTimeout(2, TimeUnit.MINUTES)
// .fastFallback(true) // TODO: re-enable when OkHttp 5 is stabler
.addInterceptor(UserAgentInterceptor()) .addInterceptor(UserAgentInterceptor())
if (preferences.verboseLogging()) { if (preferences.verboseLogging()) {
@ -42,6 +43,10 @@ class NetworkHelper(context: Context) {
PREF_DOH_GOOGLE -> builder.dohGoogle() PREF_DOH_GOOGLE -> builder.dohGoogle()
PREF_DOH_ADGUARD -> builder.dohAdGuard() PREF_DOH_ADGUARD -> builder.dohAdGuard()
PREF_DOH_QUAD9 -> builder.dohQuad9() PREF_DOH_QUAD9 -> builder.dohQuad9()
PREF_DOH_ALIDNS -> builder.dohAliDNS()
PREF_DOH_DNSPOD -> builder.dohDNSPod()
PREF_DOH_360 -> builder.doh360()
PREF_DOH_QUAD101 -> builder.dohQuad101()
} }
return builder return builder

View File

@ -4,6 +4,7 @@ import android.os.SystemClock
import okhttp3.Interceptor import okhttp3.Interceptor
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Response import okhttp3.Response
import java.io.IOException
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
/** /**
@ -36,6 +37,11 @@ private class RateLimitInterceptor(
private val rateLimitMillis = unit.toMillis(period) private val rateLimitMillis = unit.toMillis(period)
override fun intercept(chain: Interceptor.Chain): Response { override fun intercept(chain: Interceptor.Chain): Response {
// Ignore canceled calls, otherwise they would jam the queue
if (chain.call().isCanceled()) {
throw IOException()
}
synchronized(requestQueue) { synchronized(requestQueue) {
val now = SystemClock.elapsedRealtime() val now = SystemClock.elapsedRealtime()
val waitTime = if (requestQueue.size < permits) { val waitTime = if (requestQueue.size < permits) {
@ -51,6 +57,11 @@ private class RateLimitInterceptor(
} }
} }
// Final check
if (chain.call().isCanceled()) {
throw IOException()
}
if (requestQueue.size == permits) { if (requestQueue.size == permits) {
requestQueue.removeAt(0) requestQueue.removeAt(0)
} }

View File

@ -5,6 +5,7 @@ import okhttp3.HttpUrl
import okhttp3.Interceptor import okhttp3.Interceptor
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Response import okhttp3.Response
import java.io.IOException
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
/** /**
@ -41,9 +42,13 @@ class SpecificHostRateLimitInterceptor(
private val host = httpUrl.host private val host = httpUrl.host
override fun intercept(chain: Interceptor.Chain): Response { override fun intercept(chain: Interceptor.Chain): Response {
if (chain.request().url.host != host) { // Ignore canceled calls, otherwise they would jam the queue
if (chain.call().isCanceled()) {
throw IOException()
} else if (chain.request().url.host != host) {
return chain.proceed(chain.request()) return chain.proceed(chain.request())
} }
synchronized(requestQueue) { synchronized(requestQueue) {
val now = SystemClock.elapsedRealtime() val now = SystemClock.elapsedRealtime()
val waitTime = if (requestQueue.size < permits) { val waitTime = if (requestQueue.size < permits) {
@ -59,6 +64,11 @@ class SpecificHostRateLimitInterceptor(
} }
} }
// Final check
if (chain.call().isCanceled()) {
throw IOException()
}
if (requestQueue.size == permits) { if (requestQueue.size == permits) {
requestQueue.removeAt(0) requestQueue.removeAt(0)
} }

View File

@ -2,7 +2,9 @@ package eu.kanade.tachiyomi.source
import android.content.Context import android.content.Context
import com.github.junrar.Archive import com.github.junrar.Archive
import com.hippo.unifile.UniFile
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.cache.CoverCache
import eu.kanade.tachiyomi.source.model.Filter import eu.kanade.tachiyomi.source.model.Filter
import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.model.MangasPage import eu.kanade.tachiyomi.source.model.MangasPage
@ -17,7 +19,6 @@ import eu.kanade.tachiyomi.util.lang.compareToCaseInsensitiveNaturalOrder
import eu.kanade.tachiyomi.util.storage.DiskUtil import eu.kanade.tachiyomi.util.storage.DiskUtil
import eu.kanade.tachiyomi.util.storage.EpubFile import eu.kanade.tachiyomi.util.storage.EpubFile
import eu.kanade.tachiyomi.util.system.ImageUtil import eu.kanade.tachiyomi.util.system.ImageUtil
import eu.kanade.tachiyomi.util.system.logcat
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonObject
@ -26,10 +27,11 @@ import kotlinx.serialization.json.decodeFromStream
import kotlinx.serialization.json.intOrNull import kotlinx.serialization.json.intOrNull
import kotlinx.serialization.json.jsonArray import kotlinx.serialization.json.jsonArray
import kotlinx.serialization.json.jsonPrimitive import kotlinx.serialization.json.jsonPrimitive
import logcat.LogPriority
import rx.Observable import rx.Observable
import tachiyomi.source.model.ChapterInfo import tachiyomi.source.model.ChapterInfo
import tachiyomi.source.model.MangaInfo import tachiyomi.source.model.MangaInfo
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import java.io.File import java.io.File
import java.io.FileInputStream import java.io.FileInputStream
@ -37,130 +39,104 @@ import java.io.InputStream
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import java.util.zip.ZipFile import java.util.zip.ZipFile
class LocalSource(private val context: Context) : CatalogueSource, UnmeteredSource { class LocalSource(
private val context: Context,
companion object { private val coverCache: CoverCache = Injekt.get(),
const val ID = 0L ) : CatalogueSource, UnmeteredSource {
const val HELP_URL = "https://tachiyomi.org/help/guides/local-manga/"
private const val COVER_NAME = "cover.jpg"
private val LATEST_THRESHOLD = TimeUnit.MILLISECONDS.convert(7, TimeUnit.DAYS)
fun updateCover(context: Context, manga: SManga, input: InputStream): File? {
val dir = getBaseDirectories(context).firstOrNull()
if (dir == null) {
input.close()
return null
}
var cover = getCoverFile(File("${dir.absolutePath}/${manga.url}"))
if (cover == null) {
cover = File("${dir.absolutePath}/${manga.url}", COVER_NAME)
}
// It might not exist if using the external SD card
cover.parentFile?.mkdirs()
input.use {
cover.outputStream().use {
input.copyTo(it)
}
}
manga.thumbnail_url = cover.absolutePath
return cover
}
/**
* Returns valid cover file inside [parent] directory.
*/
private fun getCoverFile(parent: File): File? {
return parent.listFiles()?.find { it.nameWithoutExtension == "cover" }?.takeIf {
it.isFile && ImageUtil.isImage(it.name) { it.inputStream() }
}
}
private fun getBaseDirectories(context: Context): List<File> {
val c = context.getString(R.string.app_name) + File.separator + "local"
return DiskUtil.getExternalStorages(context).map { File(it.absolutePath, c) }
}
}
private val json: Json by injectLazy() private val json: Json by injectLazy()
override val id = ID override val name: String = context.getString(R.string.local_source)
override val name = context.getString(R.string.local_source)
override val lang = "other" override val id: Long = ID
override val supportsLatest = true
override val lang: String = "other"
override fun toString() = name override fun toString() = name
override val supportsLatest: Boolean = true
// Browse related
override fun fetchPopularManga(page: Int) = fetchSearchManga(page, "", POPULAR_FILTERS) override fun fetchPopularManga(page: Int) = fetchSearchManga(page, "", POPULAR_FILTERS)
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> { override fun fetchLatestUpdates(page: Int) = fetchSearchManga(page, "", LATEST_FILTERS)
val baseDirs = getBaseDirectories(context)
val time = if (filters === LATEST_FILTERS) System.currentTimeMillis() - LATEST_THRESHOLD else 0L override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> {
var mangaDirs = baseDirs val baseDirsFiles = getBaseDirectoriesFiles(context)
.asSequence()
.mapNotNull { it.listFiles()?.toList() } var mangaDirs = baseDirsFiles
.flatten() // Filter out files that are hidden and is not a folder
.filter { it.isDirectory } .filter { it.isDirectory && !it.name.startsWith('.') }
.filterNot { it.name.startsWith('.') }
.filter { if (time == 0L) it.name.contains(query, ignoreCase = true) else it.lastModified() >= time }
.distinctBy { it.name } .distinctBy { it.name }
val state = ((if (filters.isEmpty()) POPULAR_FILTERS else filters)[0] as OrderBy).state val lastModifiedLimit = if (filters === LATEST_FILTERS) System.currentTimeMillis() - LATEST_THRESHOLD else 0L
when (state?.index) { // Filter by query or last modified
0 -> { mangaDirs = mangaDirs.filter {
mangaDirs = if (state.ascending) { if (lastModifiedLimit == 0L) {
mangaDirs.sortedWith(compareBy(String.CASE_INSENSITIVE_ORDER, { it.name })) it.name.contains(query, ignoreCase = true)
} else { } else {
mangaDirs.sortedWith(compareByDescending(String.CASE_INSENSITIVE_ORDER, { it.name })) it.lastModified() >= lastModifiedLimit
}
}
1 -> {
mangaDirs = if (state.ascending) {
mangaDirs.sortedBy(File::lastModified)
} else {
mangaDirs.sortedByDescending(File::lastModified)
}
} }
} }
filters.forEach { filter ->
when (filter) {
is OrderBy -> {
when (filter.state!!.index) {
0 -> {
mangaDirs = if (filter.state!!.ascending) {
mangaDirs.sortedWith(compareBy(String.CASE_INSENSITIVE_ORDER) { it.name })
} else {
mangaDirs.sortedWith(compareByDescending(String.CASE_INSENSITIVE_ORDER) { it.name })
}
}
1 -> {
mangaDirs = if (filter.state!!.ascending) {
mangaDirs.sortedBy(File::lastModified)
} else {
mangaDirs.sortedByDescending(File::lastModified)
}
}
}
}
else -> { /* Do nothing */ }
}
}
// Transform mangaDirs to list of SManga
val mangas = mangaDirs.map { mangaDir -> val mangas = mangaDirs.map { mangaDir ->
SManga.create().apply { SManga.create().apply {
title = mangaDir.name title = mangaDir.name
url = mangaDir.name url = mangaDir.name
// Try to find the cover // Try to find the cover
for (dir in baseDirs) { val cover = getCoverFile(mangaDir.name, baseDirsFiles)
val cover = getCoverFile(File("${dir.absolutePath}/$url")) if (cover != null && cover.exists()) {
if (cover != null && cover.exists()) { thumbnail_url = cover.absolutePath
thumbnail_url = cover.absolutePath
break
}
} }
}
}
val sManga = this // Fetch chapters of all the manga
val mangaInfo = this.toMangaInfo() mangas.forEach { manga ->
runBlocking { val mangaInfo = manga.toMangaInfo()
val chapters = getChapterList(mangaInfo) runBlocking {
if (chapters.isNotEmpty()) { val chapters = getChapterList(mangaInfo)
val chapter = chapters.last().toSChapter() if (chapters.isNotEmpty()) {
val format = getFormat(chapter) val chapter = chapters.last().toSChapter()
if (format is Format.Epub) { val format = getFormat(chapter)
EpubFile(format.file).use { epub ->
epub.fillMangaMetadata(sManga)
}
}
// Copy the cover from the first chapter found. if (format is Format.Epub) {
if (thumbnail_url == null) { EpubFile(format.file).use { epub ->
try { epub.fillMangaMetadata(manga)
val dest = updateCover(chapter, sManga)
thumbnail_url = dest?.absolutePath
} catch (e: Exception) {
logcat(LogPriority.ERROR, e)
}
} }
} }
// Copy the cover from the first chapter found if not available
if (manga.thumbnail_url == null) {
updateCover(chapter, manga)
}
} }
} }
} }
@ -168,38 +144,44 @@ class LocalSource(private val context: Context) : CatalogueSource, UnmeteredSour
return Observable.just(MangasPage(mangas.toList(), false)) return Observable.just(MangasPage(mangas.toList(), false))
} }
override fun fetchLatestUpdates(page: Int) = fetchSearchManga(page, "", LATEST_FILTERS) // Manga details related
override suspend fun getMangaDetails(manga: MangaInfo): MangaInfo { override suspend fun getMangaDetails(manga: MangaInfo): MangaInfo {
val localDetails = getBaseDirectories(context) var mangaInfo = manga
.asSequence()
.mapNotNull { File(it, manga.key).listFiles()?.toList() } val baseDirsFile = getBaseDirectoriesFiles(context)
.flatten()
val coverFile = getCoverFile(manga.key, baseDirsFile)
coverFile?.let {
mangaInfo = mangaInfo.copy(cover = it.absolutePath)
}
val localDetails = getMangaDirsFiles(manga.key, baseDirsFile)
.firstOrNull { it.extension.equals("json", ignoreCase = true) } .firstOrNull { it.extension.equals("json", ignoreCase = true) }
return if (localDetails != null) { if (localDetails != null) {
val obj = json.decodeFromStream<JsonObject>(localDetails.inputStream()) val obj = json.decodeFromStream<JsonObject>(localDetails.inputStream())
manga.copy( mangaInfo = mangaInfo.copy(
title = obj["title"]?.jsonPrimitive?.contentOrNull ?: manga.title, title = obj["title"]?.jsonPrimitive?.contentOrNull ?: mangaInfo.title,
author = obj["author"]?.jsonPrimitive?.contentOrNull ?: manga.author, author = obj["author"]?.jsonPrimitive?.contentOrNull ?: mangaInfo.author,
artist = obj["artist"]?.jsonPrimitive?.contentOrNull ?: manga.artist, artist = obj["artist"]?.jsonPrimitive?.contentOrNull ?: mangaInfo.artist,
description = obj["description"]?.jsonPrimitive?.contentOrNull ?: manga.description, description = obj["description"]?.jsonPrimitive?.contentOrNull ?: mangaInfo.description,
genres = obj["genre"]?.jsonArray?.map { it.jsonPrimitive.content } ?: manga.genres, genres = obj["genre"]?.jsonArray?.map { it.jsonPrimitive.content } ?: mangaInfo.genres,
status = obj["status"]?.jsonPrimitive?.intOrNull ?: manga.status, status = obj["status"]?.jsonPrimitive?.intOrNull ?: mangaInfo.status,
) )
} else {
manga
} }
return mangaInfo
} }
// Chapters
override suspend fun getChapterList(manga: MangaInfo): List<ChapterInfo> { override suspend fun getChapterList(manga: MangaInfo): List<ChapterInfo> {
val sManga = manga.toSManga() val sManga = manga.toSManga()
val chapters = getBaseDirectories(context) val baseDirsFile = getBaseDirectoriesFiles(context)
.asSequence() return getMangaDirsFiles(manga.key, baseDirsFile)
.mapNotNull { File(it, manga.key).listFiles()?.toList() } // Only keep supported formats
.flatten()
.filter { it.isDirectory || isSupportedFile(it.extension) } .filter { it.isDirectory || isSupportedFile(it.extension) }
.map { chapterFile -> .map { chapterFile ->
SChapter.create().apply { SChapter.create().apply {
@ -211,15 +193,14 @@ class LocalSource(private val context: Context) : CatalogueSource, UnmeteredSour
} }
date_upload = chapterFile.lastModified() date_upload = chapterFile.lastModified()
ChapterRecognition.parseChapterNumber(this, sManga)
val format = getFormat(chapterFile) val format = getFormat(chapterFile)
if (format is Format.Epub) { if (format is Format.Epub) {
EpubFile(format.file).use { epub -> EpubFile(format.file).use { epub ->
epub.fillChapterMetadata(this) epub.fillChapterMetadata(this)
} }
} }
name = getCleanChapterTitle(name)
ChapterRecognition.parseChapterNumber(this, sManga)
} }
} }
.map { it.toChapterInfo() } .map { it.toChapterInfo() }
@ -228,19 +209,24 @@ class LocalSource(private val context: Context) : CatalogueSource, UnmeteredSour
if (c == 0) c2.name.compareToCaseInsensitiveNaturalOrder(c1.name) else c if (c == 0) c2.name.compareToCaseInsensitiveNaturalOrder(c1.name) else c
} }
.toList() .toList()
return chapters
} }
override suspend fun getPageList(chapter: ChapterInfo) = throw Exception("Unused") // Filters
override fun getFilterList() = FilterList(OrderBy(context))
/** private val POPULAR_FILTERS = FilterList(OrderBy(context))
* Trim whitespace/delimiter characters from chapter names. private val LATEST_FILTERS = FilterList(OrderBy(context).apply { state = Filter.Sort.Selection(1, false) })
*/
private fun getCleanChapterTitle(chapterName: String): String {
return chapterName.trim(*WHITESPACE_CHARS.toCharArray(), '-', '_', ',', ':')
}
private class OrderBy(context: Context) : Filter.Sort(
context.getString(R.string.local_filter_order_by),
arrayOf(context.getString(R.string.title), context.getString(R.string.date)),
Selection(0, true),
)
// Unused stuff
override suspend fun getPageList(chapter: ChapterInfo) = throw UnsupportedOperationException("Unused")
// Miscellaneous
private fun isSupportedFile(extension: String): Boolean { private fun isSupportedFile(extension: String): Boolean {
return extension.lowercase() in SUPPORTED_ARCHIVE_TYPES return extension.lowercase() in SUPPORTED_ARCHIVE_TYPES
} }
@ -304,54 +290,89 @@ class LocalSource(private val context: Context) : CatalogueSource, UnmeteredSour
} }
} }
} }
.also { coverCache.clearMemoryCache() }
} }
override fun getFilterList() = POPULAR_FILTERS
private val POPULAR_FILTERS = FilterList(OrderBy(context))
private val LATEST_FILTERS = FilterList(OrderBy(context).apply { state = Filter.Sort.Selection(1, false) })
private class OrderBy(context: Context) : Filter.Sort(
context.getString(R.string.local_filter_order_by),
arrayOf(context.getString(R.string.title), context.getString(R.string.date)),
Selection(0, true),
)
sealed class Format { sealed class Format {
data class Directory(val file: File) : Format() data class Directory(val file: File) : Format()
data class Zip(val file: File) : Format() data class Zip(val file: File) : Format()
data class Rar(val file: File) : Format() data class Rar(val file: File) : Format()
data class Epub(val file: File) : Format() data class Epub(val file: File) : Format()
} }
companion object {
const val ID = 0L
const val HELP_URL = "https://tachiyomi.org/help/guides/local-manga/"
private const val DEFAULT_COVER_NAME = "cover.jpg"
private val LATEST_THRESHOLD = TimeUnit.MILLISECONDS.convert(7, TimeUnit.DAYS)
private fun getBaseDirectories(context: Context): Sequence<File> {
val localFolder = context.getString(R.string.app_name) + File.separator + "local"
return DiskUtil.getExternalStorages(context)
.map { File(it.absolutePath, localFolder) }
.asSequence()
}
private fun getBaseDirectoriesFiles(context: Context): Sequence<File> {
return getBaseDirectories(context)
// Get all the files inside all baseDir
.flatMap { it.listFiles().orEmpty().toList() }
}
private fun getMangaDir(mangaUrl: String, baseDirsFile: Sequence<File>): File? {
return baseDirsFile
// Get the first mangaDir or null
.firstOrNull { it.isDirectory && it.name == mangaUrl }
}
private fun getMangaDirsFiles(mangaUrl: String, baseDirsFile: Sequence<File>): Sequence<File> {
return baseDirsFile
// Filter out ones that are not related to the manga and is not a directory
.filter { it.isDirectory && it.name == mangaUrl }
// Get all the files inside the filtered folders
.flatMap { it.listFiles().orEmpty().toList() }
}
private fun getCoverFile(mangaUrl: String, baseDirsFile: Sequence<File>): File? {
return getMangaDirsFiles(mangaUrl, baseDirsFile)
// Get all file whose names start with 'cover'
.filter { it.isFile && it.nameWithoutExtension.equals("cover", ignoreCase = true) }
// Get the first actual image
.firstOrNull {
ImageUtil.isImage(it.name) { it.inputStream() }
}
}
fun updateCover(context: Context, manga: SManga, inputStream: InputStream): File? {
val baseDirsFiles = getBaseDirectoriesFiles(context)
val mangaDir = getMangaDir(manga.url, baseDirsFiles)
if (mangaDir == null) {
inputStream.close()
return null
}
var coverFile = getCoverFile(manga.url, baseDirsFiles)
if (coverFile == null) {
coverFile = File(mangaDir.absolutePath, DEFAULT_COVER_NAME)
}
// It might not exist at this point
coverFile.parentFile?.mkdirs()
inputStream.use { input ->
coverFile.outputStream().use { output ->
input.copyTo(output)
}
}
// Create a .nomedia file
DiskUtil.createNoMediaFile(UniFile.fromFile(mangaDir), context)
manga.thumbnail_url = coverFile.absolutePath
return coverFile
}
}
} }
private val SUPPORTED_ARCHIVE_TYPES = listOf("zip", "cbz", "rar", "cbr", "epub") private val SUPPORTED_ARCHIVE_TYPES = listOf("zip", "cbz", "rar", "cbr", "epub")
private val WHITESPACE_CHARS = arrayOf(
' ',
'\u0009',
'\u000A',
'\u000B',
'\u000C',
'\u000D',
'\u0020',
'\u0085',
'\u00A0',
'\u1680',
'\u2000',
'\u2001',
'\u2002',
'\u2003',
'\u2004',
'\u2005',
'\u2006',
'\u2007',
'\u2008',
'\u2009',
'\u200A',
'\u2028',
'\u2029',
'\u202F',
'\u205F',
'\u3000',
)

View File

@ -371,6 +371,6 @@ abstract class HttpSource : CatalogueSource {
override fun getFilterList() = FilterList() override fun getFilterList() = FilterList()
companion object { companion object {
const val DEFAULT_USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36 Edg/88.0.705.63" const val DEFAULT_USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.124 Safari/537.36 Edg/102.0.1245.44"
} }
} }

View File

@ -97,7 +97,7 @@ abstract class DialogController : Controller {
/** /**
* Dismiss the dialog and pop this controller * Dismiss the dialog and pop this controller
*/ */
private fun dismissDialog() { fun dismissDialog() {
if (dismissed) { if (dismissed) {
return return
} }

View File

@ -20,6 +20,9 @@ interface ThemingDelegate {
PreferenceValues.AppTheme.GREEN_APPLE -> { PreferenceValues.AppTheme.GREEN_APPLE -> {
resIds += R.style.Theme_Tachiyomi_GreenApple resIds += R.style.Theme_Tachiyomi_GreenApple
} }
PreferenceValues.AppTheme.LAVENDER -> {
resIds += R.style.Theme_Tachiyomi_Lavender
}
PreferenceValues.AppTheme.MIDNIGHT_DUSK -> { PreferenceValues.AppTheme.MIDNIGHT_DUSK -> {
resIds += R.style.Theme_Tachiyomi_MidnightDusk resIds += R.style.Theme_Tachiyomi_MidnightDusk
} }

View File

@ -259,11 +259,11 @@ class ExtensionDetailsController(bundle: Bundle? = null) :
?.map { it.baseUrl } ?.map { it.baseUrl }
?.distinct() ?: emptyList() ?.distinct() ?: emptyList()
urls.forEach { val cleared = urls.sumOf {
network.cookieManager.remove(it.toHttpUrl()) network.cookieManager.remove(it.toHttpUrl())
} }
logcat { "Cleared cookies for: ${urls.joinToString()}" } logcat { "Cleared $cleared cookies for: ${urls.joinToString()}" }
} }
private fun Source.isEnabled(): Boolean { private fun Source.isEnabled(): Boolean {

View File

@ -129,7 +129,10 @@ class SearchController(
} }
(targetController as? SearchController)?.copyManga(manga, newManga) (targetController as? SearchController)?.copyManga(manga, newManga)
} }
.setNeutralButton(android.R.string.cancel, null) .setNeutralButton(activity?.getString(R.string.action_show_manga)) { _, _ ->
dismissDialog()
router.pushController(MangaController(newManga).withFadeTransaction())
}
.create() .create()
} }
} }

View File

@ -42,10 +42,10 @@ open class TriStateItem(val filter: Filter.TriState) : AbstractFlexibleItem<TriS
else -> throw Exception("Unknown state") else -> throw Exception("Unknown state")
}, },
)?.apply { )?.apply {
val color = if (filter.state == Filter.TriState.STATE_INCLUDE) { val color = if (filter.state == Filter.TriState.STATE_IGNORE) {
view.context.getResourceColor(R.attr.colorAccent)
} else {
view.context.getResourceColor(R.attr.colorOnBackground, 0.38f) view.context.getResourceColor(R.attr.colorOnBackground, 0.38f)
} else {
view.context.getResourceColor(R.attr.colorPrimary)
} }
setTint(color) setTint(color)

View File

@ -36,7 +36,7 @@ data class DownloadHeaderItem(
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
if (this === other) return true if (this === other) return true
if (other is DownloadHeaderItem) { if (other is DownloadHeaderItem) {
return name == other.name return id == other.id && name == other.name
} }
return false return false
} }

View File

@ -89,7 +89,7 @@ class DownloadHolder(private val view: View, val adapter: DownloadAdapter) :
view.popupMenu( view.popupMenu(
menuRes = R.menu.download_single, menuRes = R.menu.download_single,
initMenu = { initMenu = {
findItem(R.id.move_to_top).isVisible = bindingAdapterPosition != 0 findItem(R.id.move_to_top).isVisible = bindingAdapterPosition > 1
findItem(R.id.move_to_bottom).isVisible = findItem(R.id.move_to_bottom).isVisible =
bindingAdapterPosition != adapter.itemCount - 1 bindingAdapterPosition != adapter.itemCount - 1
}, },

View File

@ -8,7 +8,6 @@ import android.view.MenuInflater
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import androidx.appcompat.view.ActionMode import androidx.appcompat.view.ActionMode
import androidx.core.view.doOnAttach
import androidx.core.view.isVisible import androidx.core.view.isVisible
import com.bluelinelabs.conductor.ControllerChangeHandler import com.bluelinelabs.conductor.ControllerChangeHandler
import com.bluelinelabs.conductor.ControllerChangeType import com.bluelinelabs.conductor.ControllerChangeType
@ -304,8 +303,10 @@ class LibraryController(
onTabsSettingsChanged(firstLaunch = true) onTabsSettingsChanged(firstLaunch = true)
// Delay the scroll position to allow the view to be properly measured. // Delay the scroll position to allow the view to be properly measured.
view.doOnAttach { view.post {
(activity as? MainActivity)?.binding?.tabs?.setScrollPosition(binding.libraryPager.currentItem, 0f, true) if (isAttached) {
(activity as? MainActivity)?.binding?.tabs?.setScrollPosition(binding.libraryPager.currentItem, 0f, true)
}
} }
// Send the manga map to child fragments after the adapter is updated. // Send the manga map to child fragments after the adapter is updated.

View File

@ -795,7 +795,7 @@ class MangaController :
} }
} catch (e: Throwable) { } catch (e: Throwable) {
logcat(LogPriority.ERROR, e) logcat(LogPriority.ERROR, e)
activity?.toast(R.string.error_saving_cover) activity?.toast(R.string.error_sharing_cover)
} }
} }

View File

@ -6,6 +6,7 @@ import androidx.core.text.buildSpannedString
import androidx.core.text.color import androidx.core.text.color
import androidx.core.view.isVisible import androidx.core.view.isVisible
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.models.Chapter
import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.databinding.ChaptersItemBinding import eu.kanade.tachiyomi.databinding.ChaptersItemBinding
import eu.kanade.tachiyomi.source.LocalSource import eu.kanade.tachiyomi.source.LocalSource
@ -35,6 +36,8 @@ class ChapterHolder(
itemView.context.getString(R.string.display_mode_chapter, number) itemView.context.getString(R.string.display_mode_chapter, number)
} }
else -> chapter.name else -> chapter.name
// TODO: show cleaned name consistently around the app
// else -> cleanChapterName(chapter, manga)
} }
// Set correct text color // Set correct text color
@ -80,4 +83,47 @@ class ChapterHolder(
binding.download.isVisible = item.manga.source != LocalSource.ID binding.download.isVisible = item.manga.source != LocalSource.ID
binding.download.setState(item.status, item.progress) binding.download.setState(item.status, item.progress)
} }
private fun cleanChapterName(chapter: Chapter, manga: Manga): String {
return chapter.name
.trim()
.removePrefix(manga.title)
.trim(*CHAPTER_TRIM_CHARS)
}
} }
private val CHAPTER_TRIM_CHARS = arrayOf(
// Whitespace
' ',
'\u0009',
'\u000A',
'\u000B',
'\u000C',
'\u000D',
'\u0020',
'\u0085',
'\u00A0',
'\u1680',
'\u2000',
'\u2001',
'\u2002',
'\u2003',
'\u2004',
'\u2005',
'\u2006',
'\u2007',
'\u2008',
'\u2009',
'\u200A',
'\u2028',
'\u2029',
'\u202F',
'\u205F',
'\u3000',
// Separators
'-',
'_',
',',
':',
).toCharArray()

View File

@ -121,6 +121,7 @@ class AboutController : SettingsController(), NoAppBarElevationController {
is AppUpdateResult.NoNewUpdate -> { is AppUpdateResult.NoNewUpdate -> {
activity?.toast(R.string.update_check_no_new_updates) activity?.toast(R.string.update_check_no_new_updates)
} }
else -> {}
} }
} catch (error: Exception) { } catch (error: Exception) {
activity?.toast(error.message) activity?.toast(error.message)

View File

@ -2,35 +2,58 @@ package eu.kanade.tachiyomi.ui.more
import android.app.Dialog import android.app.Dialog
import android.os.Bundle import android.os.Bundle
import android.text.method.LinkMovementMethod
import android.view.View
import android.widget.TextView
import androidx.core.os.bundleOf import androidx.core.os.bundleOf
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.updater.AppUpdateResult import eu.kanade.tachiyomi.data.updater.AppUpdateResult
import eu.kanade.tachiyomi.data.updater.AppUpdateService import eu.kanade.tachiyomi.data.updater.AppUpdateService
import eu.kanade.tachiyomi.ui.base.controller.DialogController import eu.kanade.tachiyomi.ui.base.controller.DialogController
import eu.kanade.tachiyomi.ui.base.controller.openInBrowser
import io.noties.markwon.Markwon
class NewUpdateDialogController(bundle: Bundle? = null) : DialogController(bundle) { class NewUpdateDialogController(bundle: Bundle? = null) : DialogController(bundle) {
constructor(update: AppUpdateResult.NewUpdate) : this( constructor(update: AppUpdateResult.NewUpdate) : this(
bundleOf(BODY_KEY to update.release.info, URL_KEY to update.release.getDownloadLink()), bundleOf(
BODY_KEY to update.release.info,
RELEASE_URL_KEY to update.release.releaseLink,
DOWNLOAD_URL_KEY to update.release.getDownloadLink(),
),
) )
override fun onCreateDialog(savedViewState: Bundle?): Dialog { override fun onCreateDialog(savedViewState: Bundle?): Dialog {
val releaseBody = args.getString(BODY_KEY)!!
.replace("""---(\R|.)*Checksums(\R|.)*""".toRegex(), "")
val info = Markwon.create(activity!!).toMarkdown(releaseBody)
return MaterialAlertDialogBuilder(activity!!) return MaterialAlertDialogBuilder(activity!!)
.setTitle(R.string.update_check_notification_update_available) .setTitle(R.string.update_check_notification_update_available)
.setMessage(args.getString(BODY_KEY) ?: "") .setMessage(info)
.setPositiveButton(R.string.update_check_confirm) { _, _ -> .setPositiveButton(R.string.update_check_confirm) { _, _ ->
val appContext = applicationContext applicationContext?.let { context ->
if (appContext != null) {
// Start download // Start download
val url = args.getString(URL_KEY) ?: "" val url = args.getString(DOWNLOAD_URL_KEY)!!
AppUpdateService.start(appContext, url) AppUpdateService.start(context, url)
} }
} }
.setNegativeButton(R.string.update_check_ignore, null) .setNeutralButton(R.string.update_check_open) { _, _ ->
openInBrowser(args.getString(RELEASE_URL_KEY)!!)
}
.create() .create()
} }
override fun onAttach(view: View) {
super.onAttach(view)
// Make links in Markdown text clickable
(dialog?.findViewById(android.R.id.message) as? TextView)?.movementMethod =
LinkMovementMethod.getInstance()
}
} }
private const val BODY_KEY = "NewUpdateDialogController.body" private const val BODY_KEY = "NewUpdateDialogController.body"
private const val URL_KEY = "NewUpdateDialogController.key" private const val RELEASE_URL_KEY = "NewUpdateDialogController.release_url"
private const val DOWNLOAD_URL_KEY = "NewUpdateDialogController.download_url"

View File

@ -226,6 +226,11 @@ class ReaderActivity : BaseRxActivity<ReaderPresenter>() {
super.onSaveInstanceState(outState) super.onSaveInstanceState(outState)
} }
override fun onPause() {
presenter.saveProgress()
super.onPause()
}
/** /**
* Set menu visibility again on activity resume to apply immersive mode again if needed. * Set menu visibility again on activity resume to apply immersive mode again if needed.
* Helps with rotations. * Helps with rotations.

View File

@ -4,7 +4,6 @@ import android.app.Application
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import com.jakewharton.rxrelay.BehaviorRelay import com.jakewharton.rxrelay.BehaviorRelay
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.cache.CoverCache import eu.kanade.tachiyomi.data.cache.CoverCache
import eu.kanade.tachiyomi.data.database.DatabaseHelper import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.models.History import eu.kanade.tachiyomi.data.database.models.History
@ -22,6 +21,7 @@ import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.source.model.Page import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
import eu.kanade.tachiyomi.ui.reader.loader.ChapterLoader import eu.kanade.tachiyomi.ui.reader.loader.ChapterLoader
import eu.kanade.tachiyomi.ui.reader.loader.HttpPageLoader
import eu.kanade.tachiyomi.ui.reader.model.InsertPage import eu.kanade.tachiyomi.ui.reader.model.InsertPage
import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
@ -345,6 +345,14 @@ class ReaderPresenter(
* that the user doesn't have to wait too long to continue reading. * that the user doesn't have to wait too long to continue reading.
*/ */
private fun preload(chapter: ReaderChapter) { private fun preload(chapter: ReaderChapter) {
if (chapter.pageLoader is HttpPageLoader) {
val manga = manga ?: return
val isDownloaded = downloadManager.isChapterDownloaded(chapter.chapter, manga)
if (isDownloaded) {
chapter.state = ReaderChapter.State.Wait
}
}
if (chapter.state != ReaderChapter.State.Wait && chapter.state !is ReaderChapter.State.Error) { if (chapter.state != ReaderChapter.State.Wait && chapter.state !is ReaderChapter.State.Error) {
return return
} }
@ -456,6 +464,10 @@ class ReaderPresenter(
} }
} }
fun saveProgress() {
getCurrentChapter()?.let { onChapterChanged(it) }
}
/** /**
* Called from the activity to preload the given [chapter]. * Called from the activity to preload the given [chapter].
*/ */
@ -662,20 +674,22 @@ class ReaderPresenter(
Observable Observable
.fromCallable { .fromCallable {
if (manga.isLocal()) { stream().use {
val context = Injekt.get<Application>() if (manga.isLocal()) {
LocalSource.updateCover(context, manga, stream()) val context = Injekt.get<Application>()
manga.updateCoverLastModified(db) LocalSource.updateCover(context, manga, it)
R.string.cover_updated
SetAsCoverResult.Success
} else {
if (manga.favorite) {
coverCache.setCustomCoverToCache(manga, stream())
manga.updateCoverLastModified(db) manga.updateCoverLastModified(db)
coverCache.clearMemoryCache() coverCache.clearMemoryCache()
SetAsCoverResult.Success SetAsCoverResult.Success
} else { } else {
SetAsCoverResult.AddToLibraryFirst if (manga.favorite) {
coverCache.setCustomCoverToCache(manga, it)
manga.updateCoverLastModified(db)
coverCache.clearMemoryCache()
SetAsCoverResult.Success
} else {
SetAsCoverResult.AddToLibraryFirst
}
} }
} }
} }

View File

@ -110,7 +110,7 @@ open class ReaderPageImageView @JvmOverloads constructor(
private fun SubsamplingScaleImageView.landscapeZoom(forward: Boolean) { private fun SubsamplingScaleImageView.landscapeZoom(forward: Boolean) {
if (config != null && config!!.landscapeZoom && config!!.minimumScaleType == SCALE_TYPE_CENTER_INSIDE && sWidth > sHeight && scale == minScale) { if (config != null && config!!.landscapeZoom && config!!.minimumScaleType == SCALE_TYPE_CENTER_INSIDE && sWidth > sHeight && scale == minScale) {
handler.postDelayed({ handler?.postDelayed({
val point = when (config!!.zoomStartPosition) { val point = when (config!!.zoomStartPosition) {
ZoomStartPosition.LEFT -> if (forward) PointF(0F, 0F) else PointF(sWidth.toFloat(), 0F) ZoomStartPosition.LEFT -> if (forward) PointF(0F, 0F) else PointF(sWidth.toFloat(), 0F)
ZoomStartPosition.RIGHT -> if (forward) PointF(sWidth.toFloat(), 0F) else PointF(0F, 0F) ZoomStartPosition.RIGHT -> if (forward) PointF(sWidth.toFloat(), 0F) else PointF(0F, 0F)

View File

@ -26,7 +26,6 @@ class ReaderTransitionView @JvmOverloads constructor(context: Context, attrs: At
is ChapterTransition.Prev -> bindPrevChapterTransition(transition) is ChapterTransition.Prev -> bindPrevChapterTransition(transition)
is ChapterTransition.Next -> bindNextChapterTransition(transition) is ChapterTransition.Next -> bindNextChapterTransition(transition)
} }
missingChapterWarning(transition) missingChapterWarning(transition)
} }

View File

@ -66,9 +66,14 @@ abstract class PagerViewer(val activity: ReaderActivity) : BaseViewer {
set(value) { set(value) {
field = value field = value
if (value) { if (value) {
awaitingIdleViewerChapters?.let { awaitingIdleViewerChapters?.let { viewerChapters ->
setChaptersInternal(it) setChaptersInternal(viewerChapters)
awaitingIdleViewerChapters = null awaitingIdleViewerChapters = null
if (viewerChapters.currChapter.pages?.size == 1) {
adapter.nextTransition?.to?.let {
activity.requestPreloadChapter(it)
}
}
} }
} }
} }

View File

@ -46,7 +46,7 @@ class WebtoonTransitionHolder(
layout.orientation = LinearLayout.VERTICAL layout.orientation = LinearLayout.VERTICAL
layout.gravity = Gravity.CENTER layout.gravity = Gravity.CENTER
val paddingVertical = 48.dpToPx val paddingVertical = 128.dpToPx
val paddingHorizontal = 32.dpToPx val paddingHorizontal = 32.dpToPx
layout.setPadding(paddingHorizontal, paddingVertical, paddingHorizontal, paddingVertical) layout.setPadding(paddingHorizontal, paddingVertical, paddingHorizontal, paddingVertical)

View File

@ -103,6 +103,12 @@ class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = tr
activity.requestPreloadChapter(firstItem.to) activity.requestPreloadChapter(firstItem.to)
} }
} }
val lastIndex = layoutManager.findLastEndVisibleItemPosition()
val lastItem = adapter.items.getOrNull(lastIndex)
if (lastItem is ChapterTransition.Next && lastItem.to == null) {
activity.showMenu()
}
} }
}, },
) )
@ -216,9 +222,6 @@ class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = tr
if (toChapter != null) { if (toChapter != null) {
logcat { "Request preload destination chapter because we're on the transition" } logcat { "Request preload destination chapter because we're on the transition" }
activity.requestPreloadChapter(toChapter) activity.requestPreloadChapter(toChapter)
} else if (transition is ChapterTransition.Next) {
// No more chapters, show menu because the user is probably going to close the reader
activity.showMenu()
} }
} }
@ -245,7 +248,7 @@ class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = tr
logcat { "moveToPage" } logcat { "moveToPage" }
val position = adapter.items.indexOf(page) val position = adapter.items.indexOf(page)
if (position != -1) { if (position != -1) {
recycler.scrollToPosition(position) layoutManager.scrollToPositionWithOffset(position, 0)
if (layoutManager.findLastEndVisibleItemPosition() == -1) { if (layoutManager.findLastEndVisibleItemPosition() == -1) {
onScrolled(pos = position) onScrolled(pos = position)
} }

View File

@ -4,10 +4,11 @@ import android.annotation.SuppressLint
import android.content.ActivityNotFoundException import android.content.ActivityNotFoundException
import android.content.Intent import android.content.Intent
import android.provider.Settings import android.provider.Settings
import android.webkit.WebStorage
import android.webkit.WebView
import androidx.core.net.toUri import androidx.core.net.toUri
import androidx.preference.PreferenceScreen import androidx.preference.PreferenceScreen
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import eu.kanade.tachiyomi.BuildConfig
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.cache.ChapterCache import eu.kanade.tachiyomi.data.cache.ChapterCache
import eu.kanade.tachiyomi.data.database.DatabaseHelper import eu.kanade.tachiyomi.data.database.DatabaseHelper
@ -15,9 +16,13 @@ import eu.kanade.tachiyomi.data.library.LibraryUpdateService
import eu.kanade.tachiyomi.data.library.LibraryUpdateService.Target import eu.kanade.tachiyomi.data.library.LibraryUpdateService.Target
import eu.kanade.tachiyomi.data.preference.PreferenceValues import eu.kanade.tachiyomi.data.preference.PreferenceValues
import eu.kanade.tachiyomi.network.NetworkHelper import eu.kanade.tachiyomi.network.NetworkHelper
import eu.kanade.tachiyomi.network.PREF_DOH_360
import eu.kanade.tachiyomi.network.PREF_DOH_ADGUARD import eu.kanade.tachiyomi.network.PREF_DOH_ADGUARD
import eu.kanade.tachiyomi.network.PREF_DOH_ALIDNS
import eu.kanade.tachiyomi.network.PREF_DOH_CLOUDFLARE import eu.kanade.tachiyomi.network.PREF_DOH_CLOUDFLARE
import eu.kanade.tachiyomi.network.PREF_DOH_DNSPOD
import eu.kanade.tachiyomi.network.PREF_DOH_GOOGLE import eu.kanade.tachiyomi.network.PREF_DOH_GOOGLE
import eu.kanade.tachiyomi.network.PREF_DOH_QUAD101
import eu.kanade.tachiyomi.network.PREF_DOH_QUAD9 import eu.kanade.tachiyomi.network.PREF_DOH_QUAD9
import eu.kanade.tachiyomi.ui.base.controller.openInBrowser import eu.kanade.tachiyomi.ui.base.controller.openInBrowser
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
@ -38,11 +43,16 @@ import eu.kanade.tachiyomi.util.preference.summaryRes
import eu.kanade.tachiyomi.util.preference.switchPreference import eu.kanade.tachiyomi.util.preference.switchPreference
import eu.kanade.tachiyomi.util.preference.titleRes import eu.kanade.tachiyomi.util.preference.titleRes
import eu.kanade.tachiyomi.util.system.DeviceUtil import eu.kanade.tachiyomi.util.system.DeviceUtil
import eu.kanade.tachiyomi.util.system.isDevFlavor
import eu.kanade.tachiyomi.util.system.isPackageInstalled import eu.kanade.tachiyomi.util.system.isPackageInstalled
import eu.kanade.tachiyomi.util.system.logcat
import eu.kanade.tachiyomi.util.system.powerManager import eu.kanade.tachiyomi.util.system.powerManager
import eu.kanade.tachiyomi.util.system.setDefaultSettings
import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.util.system.toast
import logcat.LogPriority
import rikka.sui.Sui import rikka.sui.Sui
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import java.io.File
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
class SettingsAdvancedController : SettingsController() { class SettingsAdvancedController : SettingsController() {
@ -55,7 +65,7 @@ class SettingsAdvancedController : SettingsController() {
override fun setupPreferenceScreen(screen: PreferenceScreen) = screen.apply { override fun setupPreferenceScreen(screen: PreferenceScreen) = screen.apply {
titleRes = R.string.pref_category_advanced titleRes = R.string.pref_category_advanced
if (BuildConfig.FLAVOR != "dev") { if (isDevFlavor.not()) {
switchPreference { switchPreference {
key = "acra.enable" key = "acra.enable"
titleRes = R.string.pref_enable_acra titleRes = R.string.pref_enable_acra
@ -78,7 +88,7 @@ class SettingsAdvancedController : SettingsController() {
key = Keys.verboseLogging key = Keys.verboseLogging
titleRes = R.string.pref_verbose_logging titleRes = R.string.pref_verbose_logging
summaryRes = R.string.pref_verbose_logging_summary summaryRes = R.string.pref_verbose_logging_summary
defaultValue = false defaultValue = isDevFlavor
onChange { onChange {
activity?.toast(R.string.requires_app_restart) activity?.toast(R.string.requires_app_restart)
@ -161,6 +171,12 @@ class SettingsAdvancedController : SettingsController() {
activity?.toast(R.string.cookies_cleared) activity?.toast(R.string.cookies_cleared)
} }
} }
preference {
key = "pref_clear_webview_data"
titleRes = R.string.pref_clear_webview_data
onClick { clearWebViewData() }
}
intListPreference { intListPreference {
key = Keys.dohProvider key = Keys.dohProvider
titleRes = R.string.pref_dns_over_https titleRes = R.string.pref_dns_over_https
@ -170,6 +186,10 @@ class SettingsAdvancedController : SettingsController() {
"Google", "Google",
"AdGuard", "AdGuard",
"Quad9", "Quad9",
"AliDNS",
"DNSPod",
"360",
"Quad 101",
) )
entryValues = arrayOf( entryValues = arrayOf(
"-1", "-1",
@ -177,6 +197,10 @@ class SettingsAdvancedController : SettingsController() {
PREF_DOH_GOOGLE.toString(), PREF_DOH_GOOGLE.toString(),
PREF_DOH_ADGUARD.toString(), PREF_DOH_ADGUARD.toString(),
PREF_DOH_QUAD9.toString(), PREF_DOH_QUAD9.toString(),
PREF_DOH_ALIDNS.toString(),
PREF_DOH_DNSPOD.toString(),
PREF_DOH_360.toString(),
PREF_DOH_QUAD101.toString(),
) )
defaultValue = "-1" defaultValue = "-1"
summary = "%s" summary = "%s"
@ -274,10 +298,29 @@ class SettingsAdvancedController : SettingsController() {
resources?.getString(R.string.used_cache, chapterCache.readableSize) resources?.getString(R.string.used_cache, chapterCache.readableSize)
} }
} catch (e: Throwable) { } catch (e: Throwable) {
logcat(LogPriority.ERROR, e)
withUIContext { activity?.toast(R.string.cache_delete_error) } withUIContext { activity?.toast(R.string.cache_delete_error) }
} }
} }
} }
private fun clearWebViewData() {
if (activity == null) return
try {
val webview = WebView(activity!!)
webview.setDefaultSettings()
webview.clearCache(true)
webview.clearFormData()
webview.clearHistory()
webview.clearSslPreferences()
WebStorage.getInstance().deleteAllData()
activity?.applicationInfo?.dataDir?.let { File("$it/app_webview/").deleteRecursively() }
activity?.toast(R.string.webview_data_deleted)
} catch (e: Throwable) {
logcat(LogPriority.ERROR, e)
activity?.toast(R.string.cache_delete_error)
}
}
} }
private const val CLEAR_CACHE_KEY = "pref_clear_cache_key" private const val CLEAR_CACHE_KEY = "pref_clear_cache_key"

View File

@ -125,20 +125,20 @@ class SettingsDownloadController : SettingsController() {
titleRes = R.string.pref_category_auto_download titleRes = R.string.pref_category_auto_download
switchPreference { switchPreference {
bindTo(preferences.downloadNew()) bindTo(preferences.downloadNewChapter())
titleRes = R.string.pref_download_new titleRes = R.string.pref_download_new
} }
preference { preference {
bindTo(preferences.downloadNewCategories()) bindTo(preferences.downloadNewChapterCategories())
titleRes = R.string.categories titleRes = R.string.categories
onClick { onClick {
DownloadCategoriesDialog().showDialog(router) DownloadCategoriesDialog().showDialog(router)
} }
visibleIf(preferences.downloadNew()) { it } visibleIf(preferences.downloadNewChapter()) { it }
fun updateSummary() { fun updateSummary() {
val selectedCategories = preferences.downloadNewCategories().get() val selectedCategories = preferences.downloadNewChapterCategories().get()
.mapNotNull { id -> categories.find { it.id == id.toInt() } } .mapNotNull { id -> categories.find { it.id == id.toInt() } }
.sortedBy { it.order } .sortedBy { it.order }
val includedItemsText = if (selectedCategories.isEmpty()) { val includedItemsText = if (selectedCategories.isEmpty()) {
@ -147,7 +147,7 @@ class SettingsDownloadController : SettingsController() {
selectedCategories.joinToString { it.name } selectedCategories.joinToString { it.name }
} }
val excludedCategories = preferences.downloadNewCategoriesExclude().get() val excludedCategories = preferences.downloadNewChapterCategoriesExclude().get()
.mapNotNull { id -> categories.find { it.id == id.toInt() } } .mapNotNull { id -> categories.find { it.id == id.toInt() } }
.sortedBy { it.order } .sortedBy { it.order }
val excludedItemsText = if (excludedCategories.isEmpty()) { val excludedItemsText = if (excludedCategories.isEmpty()) {
@ -163,10 +163,10 @@ class SettingsDownloadController : SettingsController() {
} }
} }
preferences.downloadNewCategories().asFlow() preferences.downloadNewChapterCategories().asFlow()
.onEach { updateSummary() } .onEach { updateSummary() }
.launchIn(viewScope) .launchIn(viewScope)
preferences.downloadNewCategoriesExclude().asFlow() preferences.downloadNewChapterCategoriesExclude().asFlow()
.onEach { updateSummary() } .onEach { updateSummary() }
.launchIn(viewScope) .launchIn(viewScope)
} }
@ -254,8 +254,8 @@ class SettingsDownloadController : SettingsController() {
var selected = categories var selected = categories
.map { .map {
when (it.id.toString()) { when (it.id.toString()) {
in preferences.downloadNewCategories().get() -> QuadStateTextView.State.CHECKED.ordinal in preferences.downloadNewChapterCategories().get() -> QuadStateTextView.State.CHECKED.ordinal
in preferences.downloadNewCategoriesExclude().get() -> QuadStateTextView.State.INVERSED.ordinal in preferences.downloadNewChapterCategoriesExclude().get() -> QuadStateTextView.State.INVERSED.ordinal
else -> QuadStateTextView.State.UNCHECKED.ordinal else -> QuadStateTextView.State.UNCHECKED.ordinal
} }
} }
@ -282,8 +282,8 @@ class SettingsDownloadController : SettingsController() {
.map { categories[it].id.toString() } .map { categories[it].id.toString() }
.toSet() .toSet()
preferences.downloadNewCategories().set(included) preferences.downloadNewChapterCategories().set(included)
preferences.downloadNewCategoriesExclude().set(excluded) preferences.downloadNewChapterCategoriesExclude().set(excluded)
} }
.setNegativeButton(android.R.string.cancel, null) .setNegativeButton(android.R.string.cancel, null)
.create() .create()

View File

@ -11,12 +11,7 @@ import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.DatabaseHelper import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.models.Category import eu.kanade.tachiyomi.data.database.models.Category
import eu.kanade.tachiyomi.data.library.LibraryUpdateJob import eu.kanade.tachiyomi.data.library.LibraryUpdateJob
import eu.kanade.tachiyomi.data.preference.DEVICE_CHARGING import eu.kanade.tachiyomi.data.preference.*
import eu.kanade.tachiyomi.data.preference.DEVICE_ONLY_ON_WIFI
import eu.kanade.tachiyomi.data.preference.MANGA_HAS_UNREAD
import eu.kanade.tachiyomi.data.preference.MANGA_NON_COMPLETED
import eu.kanade.tachiyomi.data.preference.MANGA_NON_READ
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.track.TrackManager import eu.kanade.tachiyomi.data.track.TrackManager
import eu.kanade.tachiyomi.databinding.PrefLibraryColumnsBinding import eu.kanade.tachiyomi.databinding.PrefLibraryColumnsBinding
import eu.kanade.tachiyomi.ui.base.controller.DialogController import eu.kanade.tachiyomi.ui.base.controller.DialogController
@ -159,8 +154,8 @@ class SettingsLibraryController : SettingsController() {
multiSelectListPreference { multiSelectListPreference {
bindTo(preferences.libraryUpdateDeviceRestriction()) bindTo(preferences.libraryUpdateDeviceRestriction())
titleRes = R.string.pref_library_update_restriction titleRes = R.string.pref_library_update_restriction
entriesRes = arrayOf(R.string.connected_to_wifi, R.string.charging) entriesRes = arrayOf(R.string.connected_to_wifi, R.string.network_not_metered, R.string.charging, R.string.battery_not_low)
entryValues = arrayOf(DEVICE_ONLY_ON_WIFI, DEVICE_CHARGING) entryValues = arrayOf(DEVICE_ONLY_ON_WIFI, DEVICE_NETWORK_NOT_METERED, DEVICE_CHARGING, DEVICE_BATTERY_NOT_LOW)
visibleIf(preferences.libraryUpdateInterval()) { it > 0 } visibleIf(preferences.libraryUpdateInterval()) { it > 0 }
@ -176,7 +171,9 @@ class SettingsLibraryController : SettingsController() {
.map { .map {
when (it) { when (it) {
DEVICE_ONLY_ON_WIFI -> context.getString(R.string.connected_to_wifi) DEVICE_ONLY_ON_WIFI -> context.getString(R.string.connected_to_wifi)
DEVICE_NETWORK_NOT_METERED -> context.getString(R.string.network_not_metered)
DEVICE_CHARGING -> context.getString(R.string.charging) DEVICE_CHARGING -> context.getString(R.string.charging)
DEVICE_BATTERY_NOT_LOW -> context.getString(R.string.battery_not_low)
else -> it else -> it
} }
} }

View File

@ -66,7 +66,7 @@ class ClearDatabaseController :
adapter = FlexibleAdapter<ClearDatabaseSourceItem>(null, this, true) adapter = FlexibleAdapter<ClearDatabaseSourceItem>(null, this, true)
binding.recycler.adapter = adapter binding.recycler.adapter = adapter
binding.recycler.layoutManager = LinearLayoutManager(activity) binding.recycler.layoutManager = LinearLayoutManager(activity!!)
binding.recycler.setHasFixedSize(true) binding.recycler.setHasFixedSize(true)
adapter?.fastScroller = binding.fastScroller adapter?.fastScroller = binding.fastScroller
recycler = binding.recycler recycler = binding.recycler

View File

@ -17,17 +17,20 @@ import androidx.lifecycle.lifecycleScope
import eu.kanade.tachiyomi.BuildConfig import eu.kanade.tachiyomi.BuildConfig
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.databinding.WebviewActivityBinding import eu.kanade.tachiyomi.databinding.WebviewActivityBinding
import eu.kanade.tachiyomi.network.NetworkHelper
import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.source.online.HttpSource
import eu.kanade.tachiyomi.ui.base.activity.BaseActivity import eu.kanade.tachiyomi.ui.base.activity.BaseActivity
import eu.kanade.tachiyomi.util.system.WebViewClientCompat import eu.kanade.tachiyomi.util.system.WebViewClientCompat
import eu.kanade.tachiyomi.util.system.WebViewUtil import eu.kanade.tachiyomi.util.system.WebViewUtil
import eu.kanade.tachiyomi.util.system.getResourceColor import eu.kanade.tachiyomi.util.system.getResourceColor
import eu.kanade.tachiyomi.util.system.logcat
import eu.kanade.tachiyomi.util.system.openInBrowser import eu.kanade.tachiyomi.util.system.openInBrowser
import eu.kanade.tachiyomi.util.system.setDefaultSettings import eu.kanade.tachiyomi.util.system.setDefaultSettings
import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.util.system.toast
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import okhttp3.HttpUrl.Companion.toHttpUrl
import reactivecircus.flowbinding.appcompat.navigationClicks import reactivecircus.flowbinding.appcompat.navigationClicks
import reactivecircus.flowbinding.swiperefreshlayout.refreshes import reactivecircus.flowbinding.swiperefreshlayout.refreshes
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
@ -37,11 +40,16 @@ class WebViewActivity : BaseActivity() {
private lateinit var binding: WebviewActivityBinding private lateinit var binding: WebviewActivityBinding
private val sourceManager: SourceManager by injectLazy() private val sourceManager: SourceManager by injectLazy()
private val network: NetworkHelper by injectLazy()
private var bundle: Bundle? = null private var bundle: Bundle? = null
private var isRefreshing: Boolean = false private var isRefreshing: Boolean = false
init {
registerSecureActivity(this)
}
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -176,6 +184,7 @@ class WebViewActivity : BaseActivity() {
R.id.action_web_refresh -> refreshPage() R.id.action_web_refresh -> refreshPage()
R.id.action_web_share -> shareWebpage() R.id.action_web_share -> shareWebpage()
R.id.action_web_browser -> openInBrowser() R.id.action_web_browser -> openInBrowser()
R.id.action_clear_cookies -> clearCookies()
} }
return super.onOptionsItemSelected(item) return super.onOptionsItemSelected(item)
} }
@ -207,8 +216,10 @@ class WebViewActivity : BaseActivity() {
openInBrowser(binding.webview.url!!, forceDefaultBrowser = true) openInBrowser(binding.webview.url!!, forceDefaultBrowser = true)
} }
init { private fun clearCookies() {
registerSecureActivity(this) val url = binding.webview.url!!
val cleared = network.cookieManager.remove(url.toHttpUrl())
logcat { "Cleared $cleared cookies for: $url" }
} }
companion object { companion object {

View File

@ -56,14 +56,14 @@ fun Manga.shouldDownloadNewChapters(db: DatabaseHelper, prefs: PreferencesHelper
if (!favorite) return false if (!favorite) return false
// Boolean to determine if user wants to automatically download new chapters. // Boolean to determine if user wants to automatically download new chapters.
val downloadNew = prefs.downloadNew().get() val downloadNewChapter = prefs.downloadNewChapter().get()
if (!downloadNew) return false if (!downloadNewChapter) return false
val categoriesToDownload = prefs.downloadNewCategories().get().map(String::toInt) val includedCategories = prefs.downloadNewChapterCategories().get().map { it.toInt() }
val categoriesToExclude = prefs.downloadNewCategoriesExclude().get().map(String::toInt) val excludedCategories = prefs.downloadNewChapterCategoriesExclude().get().map { it.toInt() }
// Default: download from all categories // Default: Download from all categories
if (categoriesToDownload.isEmpty() && categoriesToExclude.isEmpty()) return true if (includedCategories.isEmpty() && excludedCategories.isEmpty()) return true
// Get all categories, else default category (0) // Get all categories, else default category (0)
val categoriesForManga = val categoriesForManga =
@ -72,8 +72,11 @@ fun Manga.shouldDownloadNewChapters(db: DatabaseHelper, prefs: PreferencesHelper
.takeUnless { it.isEmpty() } ?: listOf(0) .takeUnless { it.isEmpty() } ?: listOf(0)
// In excluded category // In excluded category
if (categoriesForManga.intersect(categoriesToExclude).isNotEmpty()) return false if (categoriesForManga.any { it in excludedCategories }) return false
// Included category not selected
if (includedCategories.isEmpty()) return true
// In included category // In included category
return categoriesForManga.intersect(categoriesToDownload).isNotEmpty() return categoriesForManga.any { it in includedCategories }
} }

View File

@ -11,6 +11,7 @@ import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import java.util.Date import java.util.Date
import java.util.TreeSet import java.util.TreeSet
import kotlin.math.max
/** /**
* Helper method for syncing the list of chapters from the source with the ones from the database. * Helper method for syncing the list of chapters from the source with the ones from the database.
@ -59,6 +60,9 @@ fun syncChaptersWithSource(
} }
} }
var maxTimestamp = 0L // in previous chapters to add
val rightNow = Date().time
for (sourceChapter in sourceChapters) { for (sourceChapter in sourceChapters) {
// This forces metadata update for the main viewable things in the chapter list. // This forces metadata update for the main viewable things in the chapter list.
if (source is HttpSource) { if (source is HttpSource) {
@ -72,7 +76,9 @@ fun syncChaptersWithSource(
// Add the chapter if not in db already, or update if the metadata changed. // Add the chapter if not in db already, or update if the metadata changed.
if (dbChapter == null) { if (dbChapter == null) {
if (sourceChapter.date_upload == 0L) { if (sourceChapter.date_upload == 0L) {
sourceChapter.date_upload = Date().time sourceChapter.date_upload = if (maxTimestamp == 0L) rightNow else maxTimestamp
} else {
maxTimestamp = max(maxTimestamp, sourceChapter.date_upload)
} }
toAdd.add(sourceChapter) toAdd.add(sourceChapter)
} else { } else {
@ -97,6 +103,7 @@ fun syncChaptersWithSource(
return Pair(emptyList(), emptyList()) return Pair(emptyList(), emptyList())
} }
// Keep it a List instead of a Set. See #6372.
val readded = mutableListOf<Chapter>() val readded = mutableListOf<Chapter>()
db.inTransaction { db.inTransaction {
@ -154,6 +161,7 @@ fun syncChaptersWithSource(
db.updateLastUpdated(manga).executeAsBlocking() db.updateLastUpdated(manga).executeAsBlocking()
} }
@Suppress("ConvertArgumentToSet")
return Pair(toAdd.subtract(readded).toList(), toDelete.subtract(readded).toList()) return Pair(toAdd.subtract(readded).toList(), toDelete.subtract(readded).toList())
} }

View File

@ -0,0 +1,6 @@
package eu.kanade.tachiyomi.util.system
import eu.kanade.tachiyomi.BuildConfig
val isDevFlavor: Boolean
get() = BuildConfig.FLAVOR == "dev"

View File

@ -87,7 +87,11 @@ fun Context.copyToClipboard(label: String, content: String) {
val clipboard = getSystemService<ClipboardManager>()!! val clipboard = getSystemService<ClipboardManager>()!!
clipboard.setPrimaryClip(ClipData.newPlainText(label, content)) clipboard.setPrimaryClip(ClipData.newPlainText(label, content))
toast(getString(R.string.copied_to_clipboard, content.truncateCenter(50))) // Android 13 and higher shows a visual confirmation of copied contents
// https://developer.android.com/about/versions/13/features/copy-paste
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.S_V2) {
toast(getString(R.string.copied_to_clipboard, content.truncateCenter(50)))
}
} catch (e: Throwable) { } catch (e: Throwable) {
logcat(LogPriority.ERROR, e) logcat(LogPriority.ERROR, e)
toast(R.string.clipboard_copy_error) toast(R.string.clipboard_copy_error)
@ -382,6 +386,19 @@ fun Context.isPackageInstalled(packageName: String): Boolean {
} }
} }
fun Context.getInstallerPackageName(): String? {
return try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
packageManager.getInstallSourceInfo(packageName).installingPackageName
} else {
@Suppress("DEPRECATION")
packageManager.getInstallerPackageName(packageName)
}
} catch (e: Exception) {
null
}
}
fun Context.getApplicationIcon(pkgName: String): Drawable? { fun Context.getApplicationIcon(pkgName: String): Drawable? {
return try { return try {
packageManager.getApplicationIcon(pkgName) packageManager.getApplicationIcon(pkgName)

View File

@ -10,6 +10,7 @@ import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.graphics.drawable.GradientDrawable import android.graphics.drawable.GradientDrawable
import android.os.Build import android.os.Build
import android.webkit.MimeTypeMap
import androidx.core.graphics.alpha import androidx.core.graphics.alpha
import androidx.core.graphics.applyCanvas import androidx.core.graphics.applyCanvas
import androidx.core.graphics.blue import androidx.core.graphics.blue
@ -56,6 +57,12 @@ object ImageUtil {
return null return null
} }
fun getExtensionFromMimeType(mime: String?): String {
return MimeTypeMap.getSingleton().getExtensionFromMimeType(mime)
?: SUPPLEMENTARY_MIMETYPE_MAPPING[mime]
?: "jpg"
}
fun isAnimatedAndSupported(stream: InputStream): Boolean { fun isAnimatedAndSupported(stream: InputStream): Boolean {
try { try {
val type = getImageType(stream) ?: return false val type = getImageType(stream) ?: return false
@ -392,4 +399,10 @@ object ImageUtil {
private fun Int.isWhite(): Boolean = private fun Int.isWhite(): Boolean =
red + blue + green > 740 red + blue + green > 740
// Android doesn't include some mappings
private val SUPPLEMENTARY_MIMETYPE_MAPPING = mapOf(
// https://issuetracker.google.com/issues/182703810
"image/jxl" to "jxl",
)
} }

View File

@ -73,7 +73,7 @@ open class ExtendedNavigationView @JvmOverloads constructor(
* @param context any context. * @param context any context.
* @param resId the vector resource to load and tint * @param resId the vector resource to load and tint
*/ */
fun tintVector(context: Context, resId: Int, @AttrRes colorAttrRes: Int = R.attr.colorAccent): Drawable { fun tintVector(context: Context, resId: Int, @AttrRes colorAttrRes: Int = R.attr.colorPrimary): Drawable {
return AppCompatResources.getDrawable(context, resId)!!.apply { return AppCompatResources.getDrawable(context, resId)!!.apply {
setTint(context.getResourceColor(if (enabled) colorAttrRes else R.attr.colorControlNormal)) setTint(context.getResourceColor(if (enabled) colorAttrRes else R.attr.colorControlNormal))
} }

View File

@ -29,7 +29,7 @@ class QuadStateTextView @JvmOverloads constructor(context: Context, attrs: Attri
val tint = if (state == State.UNCHECKED) { val tint = if (state == State.UNCHECKED) {
context.getThemeColor(R.attr.colorControlNormal) context.getThemeColor(R.attr.colorControlNormal)
} else { } else {
context.getThemeColor(R.attr.colorAccent) context.getThemeColor(R.attr.colorPrimary)
} }
if (tint != 0) { if (tint != 0) {
TextViewCompat.setCompoundDrawableTintList(this, ColorStateList.valueOf(tint)) TextViewCompat.setCompoundDrawableTintList(this, ColorStateList.valueOf(tint))

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="?attr/colorPrimary" android:state_enabled="true"/>
<item android:alpha="@dimen/material_emphasis_disabled" android:color="?attr/colorOnSurface"/>
</selector>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:alpha="0.24" android:color="?attr/colorPrimary" android:state_enabled="true"/>
<item android:alpha="@dimen/material_emphasis_disabled" android:color="?attr/colorOnSurface"/>
</selector>

View File

@ -1,8 +1,12 @@
<?xml version="1.0" encoding="utf-8"?> <vector xmlns:android="http://schemas.android.com/apk/res/android"
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> android:width="108dp"
<item android:height="108dp"
android:width="36dp" android:viewportWidth="108"
android:height="36dp" android:viewportHeight="108">
android:drawable="@drawable/ic_tachi" <path
android:gravity="center" /> android:pathData="M50.61,39.254C50.65,40.029 50.691,41.036 50.719,41.513L50.773,42.371L44.96,42.331C41.772,42.303 39.049,42.235 38.926,42.166C38.695,42.058 38.682,42.248 38.682,44.944L38.682,47.831L38.995,47.75C39.893,47.491 43.53,47.395 53.796,47.395C64.064,47.395 67.698,47.491 68.611,47.75L68.911,47.831L68.911,44.944C68.911,42.248 68.897,42.058 68.678,42.166C68.542,42.235 65.819,42.303 62.634,42.331L56.819,42.371L56.873,41.513C56.9,41.036 56.941,40.029 56.981,39.254L57.037,37.864L50.555,37.864L50.61,39.254ZM44.645,49.329C43.23,49.861 42.086,50.377 42.086,50.459C42.086,50.555 42.276,51.044 42.509,51.563C43.597,53.973 45.312,59.937 45.79,62.945C45.87,63.53 46.008,64.008 46.089,64.008C46.171,64.008 47.505,63.572 49.072,63.041C51.1,62.333 51.889,62.006 51.889,61.856C51.889,61.42 49.467,53.551 48.322,50.282C47.805,48.839 47.586,48.349 47.41,48.362C47.287,48.362 46.049,48.798 44.645,49.329Z"
</layer-list> android:fillColor="#000000"/>
<path
android:pathData="M59.406,49.397C58.957,52.257 57.282,57.785 55.484,62.333L54.545,64.688L37.456,64.688L37.456,70.136L70.544,70.136L70.544,64.688L65.493,64.688C61.503,64.688 60.454,64.648 60.509,64.511C60.55,64.43 60.876,63.708 61.23,62.918C61.571,62.128 62.252,60.426 62.728,59.12C63.641,56.614 65.643,50.364 65.643,49.997C65.643,49.819 65.016,49.614 62.756,49.057C61.163,48.662 59.788,48.349 59.706,48.349C59.624,48.349 59.488,48.825 59.406,49.397Z"
android:fillColor="#000000"/>
</vector>

View File

@ -17,7 +17,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:fitsSystemWindows="true" android:fitsSystemWindows="true"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toEndOf="@id/side_nav"
app:layout_constraintTop_toTopOf="parent"> app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.appbar.MaterialToolbar <com.google.android.material.appbar.MaterialToolbar
@ -35,7 +35,7 @@
android:background="?attr/colorTertiary" android:background="?attr/colorTertiary"
android:visibility="gone" android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toEndOf="@id/side_nav"
app:layout_constraintTop_toBottomOf="@+id/appbar" app:layout_constraintTop_toBottomOf="@+id/appbar"
tools:visibility="visible"> tools:visibility="visible">
@ -56,7 +56,7 @@
android:background="?attr/colorPrimary" android:background="?attr/colorPrimary"
android:visibility="gone" android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toEndOf="@id/side_nav"
app:layout_constraintTop_toBottomOf="@+id/downloaded_only" app:layout_constraintTop_toBottomOf="@+id/downloaded_only"
tools:visibility="visible"> tools:visibility="visible">
@ -73,11 +73,10 @@
<com.google.android.material.navigationrail.NavigationRailView <com.google.android.material.navigationrail.NavigationRailView
android:id="@+id/side_nav" android:id="@+id/side_nav"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="0dp" android:layout_height="match_parent"
app:elevation="0dp" android:paddingTop="?attr/actionBarSize"
app:layout_constraintBottom_toBottomOf="parent" app:elevation="1dp"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/incognito_mode"
app:menu="@menu/main_nav" /> app:menu="@menu/main_nav" />
<com.google.android.material.tabs.TabLayout <com.google.android.material.tabs.TabLayout

View File

@ -95,9 +95,10 @@
<TextView <TextView
android:id="@+id/left_page_text" android:id="@+id/left_page_text"
android:layout_width="32dp" android:layout_width="wrap_content"
android:layout_height="match_parent" android:layout_height="match_parent"
android:gravity="center" android:gravity="center"
android:minWidth="32dp"
android:textColor="?attr/colorOnSurface" android:textColor="?attr/colorOnSurface"
android:textSize="15sp" android:textSize="15sp"
tools:text="1" /> tools:text="1" />
@ -116,9 +117,10 @@
<TextView <TextView
android:id="@+id/right_page_text" android:id="@+id/right_page_text"
android:layout_width="32dp" android:layout_width="wrap_content"
android:layout_height="match_parent" android:layout_height="match_parent"
android:gravity="center" android:gravity="center"
android:minWidth="32dp"
android:textColor="?attr/colorOnSurface" android:textColor="?attr/colorOnSurface"
android:textSize="15sp" android:textSize="15sp"
tools:text="15" /> tools:text="15" />

View File

@ -11,7 +11,6 @@
android:id="@+id/upper_text" android:id="@+id/upper_text"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:textAppearance="?attr/textAppearanceTitleMedium" android:textAppearance="?attr/textAppearanceTitleMedium"
tools:text="Top" /> tools:text="Top" />
@ -19,7 +18,7 @@
android:id="@+id/warning" android:id="@+id/warning"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="16dp" android:layout_marginTop="16dp"
android:gravity="center_vertical"> android:gravity="center_vertical">
<ImageView <ImageView
@ -44,6 +43,7 @@
android:id="@+id/lower_text" android:id="@+id/lower_text"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:textAppearance="?attr/textAppearanceTitleMedium" android:textAppearance="?attr/textAppearanceTitleMedium"
tools:text="Bottom" /> tools:text="Bottom" />

View File

@ -31,4 +31,9 @@
android:title="@string/action_open_in_browser" android:title="@string/action_open_in_browser"
app:showAsAction="never" /> app:showAsAction="never" />
<item
android:id="@+id/action_clear_cookies"
android:title="@string/pref_clear_cookies"
app:showAsAction="never" />
</menu> </menu>

View File

@ -250,7 +250,7 @@
<string name="secure_screen_summary">Ocultar contenido de la aplicación al cambiar entre aplicaciones y bloquear las capturas de pantalla</string> <string name="secure_screen_summary">Ocultar contenido de la aplicación al cambiar entre aplicaciones y bloquear las capturas de pantalla</string>
<string name="secure_screen">Pantalla segura</string> <string name="secure_screen">Pantalla segura</string>
<plurals name="lock_after_mins"> <plurals name="lock_after_mins">
<item quantity="one">Después de 1 minuto</item> <item quantity="one">Después de %1$s minuto</item>
<item quantity="other">Después de %1$s minutos</item> <item quantity="other">Después de %1$s minutos</item>
</plurals> </plurals>
<string name="lock_never">Nunca</string> <string name="lock_never">Nunca</string>
@ -364,7 +364,7 @@
<string name="username">Nombre de usuario</string> <string name="username">Nombre de usuario</string>
<string name="login_title">Iniciar sesión en %1$s</string> <string name="login_title">Iniciar sesión en %1$s</string>
<plurals name="download_queue_summary"> <plurals name="download_queue_summary">
<item quantity="one">Queda 1</item> <item quantity="one">Queda %1$s</item>
<item quantity="other">Quedan %1$s</item> <item quantity="other">Quedan %1$s</item>
</plurals> </plurals>
<string name="downloaded_only_summary">Filtrar todo el manga en tu libreria</string> <string name="downloaded_only_summary">Filtrar todo el manga en tu libreria</string>
@ -416,7 +416,7 @@
\n\"%1$s\"</string> \n\"%1$s\"</string>
<string name="delete_downloads_for_manga">¿Eliminar capítulos descargados\?</string> <string name="delete_downloads_for_manga">¿Eliminar capítulos descargados\?</string>
<plurals name="manga_num_chapters"> <plurals name="manga_num_chapters">
<item quantity="one">1 capítulo</item> <item quantity="one">%1$s capítulo</item>
<item quantity="other">%1$s capítulos</item> <item quantity="other">%1$s capítulos</item>
</plurals> </plurals>
<string name="manga_info_collapse">Menos</string> <string name="manga_info_collapse">Menos</string>
@ -448,11 +448,11 @@
<string name="notification_chapters_single_and_more">Capítulo %1$s y %2$d más</string> <string name="notification_chapters_single_and_more">Capítulo %1$s y %2$d más</string>
<string name="notification_chapters_single">Capítulo %1$s</string> <string name="notification_chapters_single">Capítulo %1$s</string>
<plurals name="notification_chapters_generic"> <plurals name="notification_chapters_generic">
<item quantity="one">1 nuevo capítulo</item> <item quantity="one">%1$d nuevo capítulo</item>
<item quantity="other">%1$d nuevos capítulos</item> <item quantity="other">%1$d nuevos capítulos</item>
</plurals> </plurals>
<plurals name="notification_new_chapters_summary"> <plurals name="notification_new_chapters_summary">
<item quantity="one">Para 1 título</item> <item quantity="one">Para %d título</item>
<item quantity="other">Para %d títulos</item> <item quantity="other">Para %d títulos</item>
</plurals> </plurals>
<string name="notification_new_chapters">Nuevos capítulos encontrados</string> <string name="notification_new_chapters">Nuevos capítulos encontrados</string>
@ -504,7 +504,7 @@
<string name="pref_category_reading_mode">Modo de lectura</string> <string name="pref_category_reading_mode">Modo de lectura</string>
<string name="pref_category_theme">Tema</string> <string name="pref_category_theme">Tema</string>
<plurals name="num_trackers"> <plurals name="num_trackers">
<item quantity="one">1 rastreador</item> <item quantity="one">%d rastreador</item>
<item quantity="other">%d rastreadores</item> <item quantity="other">%d rastreadores</item>
</plurals> </plurals>
<string name="channel_errors">Errores</string> <string name="channel_errors">Errores</string>
@ -519,7 +519,7 @@
<string name="ext_nsfw_short">18+</string> <string name="ext_nsfw_short">18+</string>
<string name="parental_controls_info">Esto no evita que las extensiones no oficiales o potencialmente marcadas incorrectamente muestren contenido para mayores de 18 años dentro de la aplicación.</string> <string name="parental_controls_info">Esto no evita que las extensiones no oficiales o potencialmente marcadas incorrectamente muestren contenido para mayores de 18 años dentro de la aplicación.</string>
<plurals name="missing_chapters_warning"> <plurals name="missing_chapters_warning">
<item quantity="one">Omitiendo 1 capítulo, o la fuente no lo encuentra o se ha filtrado</item> <item quantity="one">Omitiendo %d capítulo, o la fuente no lo encuentra o se ha filtrado</item>
<item quantity="other">Omitiendo %d capítulos, o la fuente no los encuentra o se han filtrado</item> <item quantity="other">Omitiendo %d capítulos, o la fuente no los encuentra o se han filtrado</item>
</plurals> </plurals>
<string name="share_page_info">%1$s: %2$s, página %3$d</string> <string name="share_page_info">%1$s: %2$s, página %3$d</string>
@ -714,4 +714,5 @@
<string name="notification_update_skipped">%1$d actualización(es) omitida(s)</string> <string name="notification_update_skipped">%1$d actualización(es) omitida(s)</string>
<string name="rotation_reverse_portrait">Retrato inverso</string> <string name="rotation_reverse_portrait">Retrato inverso</string>
<string name="action_move_to_top_all_for_series">Mover la serie al principio</string> <string name="action_move_to_top_all_for_series">Mover la serie al principio</string>
<string name="disabled_nav">Desactivado</string>
</resources> </resources>

View File

@ -441,7 +441,7 @@
<string name="ext_updates_pending">Налични ъпдейти</string> <string name="ext_updates_pending">Налични ъпдейти</string>
<string name="pref_category_display">Показване</string> <string name="pref_category_display">Показване</string>
<string name="hide_notification_content">Скривай съдържанието на уведомленията</string> <string name="hide_notification_content">Скривай съдържанието на уведомленията</string>
<string name="secure_screen_summary">Скрий съдържанието на приложението и блокирай скрийншотове</string> <string name="secure_screen_summary">Скрий съдържанието на приложението и блокирай снимките на екрана</string>
<plurals name="lock_after_mins"> <plurals name="lock_after_mins">
<item quantity="one">След 1 минута</item> <item quantity="one">След 1 минута</item>
<item quantity="other">След %1$s минути</item> <item quantity="other">След %1$s минути</item>
@ -723,4 +723,7 @@
<string name="connected_to_wifi">Само през Wi-Fi</string> <string name="connected_to_wifi">Само през Wi-Fi</string>
<string name="download_queue_size_warning">Предупреждение: големите масови изтегляния могат да доведат до забавяне на източниците и/или блокиране на Tachiyomi</string> <string name="download_queue_size_warning">Предупреждение: големите масови изтегляния могат да доведат до забавяне на източниците и/или блокиране на Tachiyomi</string>
<string name="action_filter_started">Започнати</string> <string name="action_filter_started">Започнати</string>
<string name="action_show_manga">Покажи манга</string>
<string name="action_faq_and_guides">Често задавани въпроси и ръководства</string>
<string name="action_display_cover_only_grid">Решетка само с корици</string>
</resources> </resources>

View File

@ -708,10 +708,11 @@
<string name="skipped_reason_completed">S\'ha omès perquè la sèrie està completada</string> <string name="skipped_reason_completed">S\'ha omès perquè la sèrie està completada</string>
<string name="skipped_reason_not_started">S\'ha omès perquè no hi ha cap capítol llegit</string> <string name="skipped_reason_not_started">S\'ha omès perquè no hi ha cap capítol llegit</string>
<string name="skipped_reason_not_caught_up">S\'ha omès perquè hi ha capítols no llegits</string> <string name="skipped_reason_not_caught_up">S\'ha omès perquè hi ha capítols no llegits</string>
<string name="learn_more">Més informació</string> <string name="learn_more">Premeu per a obtenir més informació</string>
<string name="channel_skipped">Omesa</string> <string name="channel_skipped">Omesa</string>
<string name="notification_update_error">Han fallat %1$d actualitzacions</string> <string name="notification_update_error">Han fallat %1$d actualitzacions</string>
<string name="notification_update_skipped">S\'han omès %1$d actualitzacions</string> <string name="notification_update_skipped">S\'han omès %1$d actualitzacions</string>
<string name="rotation_reverse_portrait">Vertical inversa</string> <string name="rotation_reverse_portrait">Vertical inversa</string>
<string name="action_move_to_top_all_for_series">Mou la sèrie a dalt de tot</string> <string name="action_move_to_top_all_for_series">Mou la sèrie a dalt de tot</string>
<string name="disabled_nav">Desactivat</string>
</resources> </resources>

View File

@ -723,4 +723,5 @@
<string name="learn_more">Zjistit více</string> <string name="learn_more">Zjistit více</string>
<string name="skipped_reason_not_started">Přeskočeno, protože nebyly přečteny žádné kapitoly</string> <string name="skipped_reason_not_started">Přeskočeno, protože nebyly přečteny žádné kapitoly</string>
<string name="skipped_reason_completed">Přeskočeno, protože série je dokončena</string> <string name="skipped_reason_completed">Přeskočeno, protože série je dokončena</string>
<string name="disabled_nav">Zakázáno</string>
</resources> </resources>

View File

@ -6,7 +6,7 @@
<string name="chapters">Kapitel</string> <string name="chapters">Kapitel</string>
<string name="history">Verlauf</string> <string name="history">Verlauf</string>
<string name="label_settings">Einstellungen</string> <string name="label_settings">Einstellungen</string>
<string name="label_download_queue">Downloadwarteschlange</string> <string name="label_download_queue">Download-Warteschlange</string>
<string name="label_library">Bibliothek</string> <string name="label_library">Bibliothek</string>
<string name="label_recent_manga">Verlauf</string> <string name="label_recent_manga">Verlauf</string>
<string name="label_backup">Sichern und Wiederherstellen</string> <string name="label_backup">Sichern und Wiederherstellen</string>
@ -80,7 +80,7 @@
<string name="all">Alle</string> <string name="all">Alle</string>
<string name="pref_library_update_restriction">Geräteeinschränkungen für automatische Aktualisierungen</string> <string name="pref_library_update_restriction">Geräteeinschränkungen für automatische Aktualisierungen</string>
<string name="charging">Am Laden</string> <string name="charging">Am Laden</string>
<string name="pref_update_only_non_completed">Ist abgeschlossene Serie</string> <string name="pref_update_only_non_completed">Mit dem Status „Abgeschlossen</string>
<string name="pref_auto_update_manga_sync">Fortschritt nach dem Lesen aktualisieren</string> <string name="pref_auto_update_manga_sync">Fortschritt nach dem Lesen aktualisieren</string>
<string name="pref_start_screen">Startbildschirm</string> <string name="pref_start_screen">Startbildschirm</string>
<string name="default_category">Standardkategorie</string> <string name="default_category">Standardkategorie</string>
@ -128,7 +128,7 @@
<string name="pref_remove_after_read">Automatisch nach dem Lesen löschen</string> <string name="pref_remove_after_read">Automatisch nach dem Lesen löschen</string>
<string name="custom_dir">Eigener Speicherort</string> <string name="custom_dir">Eigener Speicherort</string>
<string name="disabled">Deaktiviert</string> <string name="disabled">Deaktiviert</string>
<string name="last_read_chapter">ab zuletzt gelesenem Kapitel</string> <string name="last_read_chapter">Ab zuletzt gelesenem Kapitel</string>
<string name="second_to_last">Ab zweitletzt gelesenem Kapitel</string> <string name="second_to_last">Ab zweitletzt gelesenem Kapitel</string>
<string name="third_to_last">Ab drittletzt gelesenem Kapitel</string> <string name="third_to_last">Ab drittletzt gelesenem Kapitel</string>
<string name="fourth_to_last">Ab viertletzt gelesenem Kapitel</string> <string name="fourth_to_last">Ab viertletzt gelesenem Kapitel</string>
@ -673,7 +673,7 @@
<string name="pref_verbose_logging_summary">Ausführliche Protokolle im Systemprotokoll ausgeben (verringert die Anwendungsleistung)</string> <string name="pref_verbose_logging_summary">Ausführliche Protokolle im Systemprotokoll ausgeben (verringert die Anwendungsleistung)</string>
<string name="action_display_language_badge">Sprache</string> <string name="action_display_language_badge">Sprache</string>
<string name="label_warning">Warnung</string> <string name="label_warning">Warnung</string>
<string name="notification_size_warning">Achtung: Große Aktualisierungen schaden Quellen und könnten zu langsameren Aktualisierungen sowie höherem Akkuverbrauch führen</string> <string name="notification_size_warning">Große Aktualisierungen schaden Quellen und könnten zu langsameren Aktualisierungen sowie höherem Akkuverbrauch führen</string>
<string name="backup_info">Automatische Sicherungen sind sehr zu empfehlen. Du solltest auch Kopien an anderen Orten aufbewahren.</string> <string name="backup_info">Automatische Sicherungen sind sehr zu empfehlen. Du solltest auch Kopien an anderen Orten aufbewahren.</string>
<string name="connected_to_wifi">Nur über WLAN</string> <string name="connected_to_wifi">Nur über WLAN</string>
<string name="update_72hour">Alle 3 Tage</string> <string name="update_72hour">Alle 3 Tage</string>
@ -686,8 +686,8 @@
<string name="database_clean">Datenbank bereinigt</string> <string name="database_clean">Datenbank bereinigt</string>
<string name="extension_api_error">Herunterladen der Erweiterungsliste ist fehlgeschlagen</string> <string name="extension_api_error">Herunterladen der Erweiterungsliste ist fehlgeschlagen</string>
<string name="privacy_policy">Datenschutzbestimmungen</string> <string name="privacy_policy">Datenschutzbestimmungen</string>
<string name="pref_update_only_completely_read">Hat ungelesene Kapitel</string> <string name="pref_update_only_completely_read">Mit ungelesenen Kapiteln</string>
<string name="pref_library_update_manga_restriction">Aktualisierung überspringen</string> <string name="pref_library_update_manga_restriction">Aktualisierung der Titel überspringen</string>
<string name="library_errors_help">Für Hilfe zum Beheben von Fehlern bei Bibliotheksaktualisierungen, siehe %1$s</string> <string name="library_errors_help">Für Hilfe zum Beheben von Fehlern bei Bibliotheksaktualisierungen, siehe %1$s</string>
<string name="save_chapter_as_cbz">Als CBZ-Archiv speichern</string> <string name="save_chapter_as_cbz">Als CBZ-Archiv speichern</string>
<string name="cancelled">Abgebrochen</string> <string name="cancelled">Abgebrochen</string>
@ -704,15 +704,17 @@
<string name="pref_landscape_zoom">Bild im Querformat vergrößern</string> <string name="pref_landscape_zoom">Bild im Querformat vergrößern</string>
<string name="pref_navigate_pan">Innerhalb der Seite navigieren</string> <string name="pref_navigate_pan">Innerhalb der Seite navigieren</string>
<string name="action_filter_started">Angefangen</string> <string name="action_filter_started">Angefangen</string>
<string name="pref_update_only_started">Keine gelesenen Kapitel</string> <string name="pref_update_only_started">Die noch nicht begonnen wurden</string>
<string name="skipped_reason_completed">Übersprungen, da die Serie abgeschlossen ist</string> <string name="skipped_reason_completed">Übersprungen, da die Serie abgeschlossen ist</string>
<string name="skipped_reason_not_caught_up">Übersprungen, weil es ungelesene Kapitel gibt</string> <string name="skipped_reason_not_caught_up">Übersprungen, weil es ungelesene Kapitel gibt</string>
<string name="skipped_reason_not_started">Übersprungen, weil keine Kapitel gelesen wurden</string> <string name="skipped_reason_not_started">Übersprungen, weil keine Kapitel gelesen wurden</string>
<string name="notification_update_error">%1$d Aktualisierung(en) fehlgeschlagen</string> <string name="notification_update_error">%1$d Aktualisierung(en) fehlgeschlagen</string>
<string name="notification_update_skipped">%1$d Aktualisierung(en) übersprungen</string> <string name="notification_update_skipped">%1$d Aktualisierung(en) übersprungen</string>
<string name="channel_skipped">Übersprungen</string> <string name="channel_skipped">Übersprungen</string>
<string name="learn_more">Mehr erfahren</string> <string name="learn_more">Antippen, um mehr zu erfahren</string>
<string name="rotation_reverse_portrait">Umgekehrtes Hochformat</string> <string name="rotation_reverse_portrait">Umgekehrtes Hochformat</string>
<string name="action_move_to_top_all_for_series">Serie nach oben verschieben</string> <string name="action_move_to_top_all_for_series">Serie nach oben verschieben</string>
<string name="disabled_nav">Deaktiviert</string> <string name="disabled_nav">Deaktiviert</string>
<string name="error_saving_picture">Fehler beim Speichern des Bildes</string>
<string name="update_check_fdroid_migration_info">Eine neue Version ist aus dem offiziellen Repository verfügbar. Tippe, um zu erfahren, wie man aus inoffiziellen F-Droid-Versionen migriert.</string>
</resources> </resources>

View File

@ -87,7 +87,7 @@
<string name="all">Όλα</string> <string name="all">Όλα</string>
<string name="pref_library_update_restriction">Περιορισμοί αυτόματων ενημερώσεων συσκευής</string> <string name="pref_library_update_restriction">Περιορισμοί αυτόματων ενημερώσεων συσκευής</string>
<string name="charging">Φορτίζει</string> <string name="charging">Φορτίζει</string>
<string name="pref_update_only_non_completed">Ολοκληρωμένη σειρά</string> <string name="pref_update_only_non_completed">Με κατάσταση \"Ολοκληρωμένο\"</string>
<string name="pref_auto_update_manga_sync">Ενημέρωση προόδου μετά την ανάγνωση</string> <string name="pref_auto_update_manga_sync">Ενημέρωση προόδου μετά την ανάγνωση</string>
<string name="pref_start_screen">Οθόνη εκκίνησης</string> <string name="pref_start_screen">Οθόνη εκκίνησης</string>
<string name="default_category">Προεπιλεγμένη κατηγορία</string> <string name="default_category">Προεπιλεγμένη κατηγορία</string>
@ -686,8 +686,8 @@
<string name="database_clean">Καθαρισμός βάσης δεδομένων</string> <string name="database_clean">Καθαρισμός βάσης δεδομένων</string>
<string name="extension_api_error">Απέτυχε η λήψη λίστας επεκτάσεων</string> <string name="extension_api_error">Απέτυχε η λήψη λίστας επεκτάσεων</string>
<string name="privacy_policy">Πολιτική απορρήτου</string> <string name="privacy_policy">Πολιτική απορρήτου</string>
<string name="pref_library_update_manga_restriction">Παράλειψη ενημέρωσης</string> <string name="pref_library_update_manga_restriction">Παράλειψη ενημέρωσης τίτλων</string>
<string name="pref_update_only_completely_read">Έχει αδιάβαστα κεφάλαια</string> <string name="pref_update_only_completely_read">Με αδιάβαστο(α) κεφάλαιο(α)</string>
<string name="library_errors_help">Για βοήθεια σχετικά με τον τρόπο διόρθωσης σφαλμάτων ενημέρωσης βιβλιοθήκης, ανατρέξτε στο %1$s</string> <string name="library_errors_help">Για βοήθεια σχετικά με τον τρόπο διόρθωσης σφαλμάτων ενημέρωσης βιβλιοθήκης, ανατρέξτε στο %1$s</string>
<string name="save_chapter_as_cbz">Αποθήκευση ως αρχείο CBZ</string> <string name="save_chapter_as_cbz">Αποθήκευση ως αρχείο CBZ</string>
<string name="cancelled">Ακυρώθηκε</string> <string name="cancelled">Ακυρώθηκε</string>
@ -703,16 +703,18 @@
\nΘέλετε ακόμα να συνεχίσετε;</string> \nΘέλετε ακόμα να συνεχίσετε;</string>
<string name="action_display_cover_only_grid">Πλέγμα μόνο με εξώφυλλα</string> <string name="action_display_cover_only_grid">Πλέγμα μόνο με εξώφυλλα</string>
<string name="action_filter_started">Ξεκίνησε</string> <string name="action_filter_started">Ξεκίνησε</string>
<string name="pref_update_only_started">Δεν έχει διαβασμένα κεφάλαια</string> <string name="pref_update_only_started">Που δεν έχουν ξεκινήσει</string>
<string name="pref_navigate_pan">Πλοήγηση για οριζόντια μετακίνηση</string> <string name="pref_navigate_pan">Πλοήγηση για οριζόντια μετακίνηση</string>
<string name="skipped_reason_completed">Παραλείφθηκε επειδή η σειρά ολοκληρώθηκε</string> <string name="skipped_reason_completed">Παραλείφθηκε επειδή η σειρά ολοκληρώθηκε</string>
<string name="skipped_reason_not_caught_up">Παραβλέφθηκε επειδή υπάρχουν μη αναγνωσμένα κεφάλαια</string> <string name="skipped_reason_not_caught_up">Παραβλέφθηκε επειδή υπάρχουν μη αναγνωσμένα κεφάλαια</string>
<string name="skipped_reason_not_started">Παραλείπεται επειδή δεν έχουν διαβαστεί κεφάλαια</string> <string name="skipped_reason_not_started">Παραλείπεται επειδή δεν έχουν διαβαστεί κεφάλαια</string>
<string name="notification_update_error">%1$d ενημέρωση(ες) απέτυχε(-αν)</string> <string name="notification_update_error">%1$d ενημέρωση(ες) απέτυχε(-αν)</string>
<string name="learn_more">Μάθετε περισσότερα</string> <string name="learn_more">Πατήστε για να μάθετε περισσότερα</string>
<string name="channel_skipped">Παραλήφθηκαν</string> <string name="channel_skipped">Παραλήφθηκαν</string>
<string name="notification_update_skipped">%1$d ενημέρωση(εις) παραλείφθηκε(-αν)</string> <string name="notification_update_skipped">%1$d ενημέρωση(εις) παραλείφθηκε(-αν)</string>
<string name="rotation_reverse_portrait">Αντίστροφο πορτρέτο</string> <string name="rotation_reverse_portrait">Αντίστροφο πορτρέτο</string>
<string name="action_move_to_top_all_for_series">Μετακίνηση σειράς στην κορυφή</string> <string name="action_move_to_top_all_for_series">Μετακίνηση σειράς στην κορυφή</string>
<string name="disabled_nav">Απενεργοποιημένο</string> <string name="disabled_nav">Απενεργοποιημένο</string>
<string name="update_check_fdroid_migration_info">Μια νέα έκδοση είναι διαθέσιμη από τις επίσημες κυκλοφορίες. Πατήστε για να μάθετε πώς να μεταβείτε από ανεπίσημες κυκλοφορίες του F-Droid.</string>
<string name="error_saving_picture">Σφάλμα κατά την αποθήκευση της εικόνας</string>
</resources> </resources>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="name">Nombre</string> <string name="name">Español</string>
<!-- Activities and fragments labels (toolbar title) --> <!-- Activities and fragments labels (toolbar title) -->
<string name="label_settings">Ajustes</string> <string name="label_settings">Ajustes</string>
<string name="label_download_queue">Cola de descargas</string> <string name="label_download_queue">Cola de descargas</string>
@ -63,7 +63,7 @@
<string name="update_48hour">Cada 2 días</string> <string name="update_48hour">Cada 2 días</string>
<string name="pref_library_update_restriction">Restricciones de actualización automática del dispositivo</string> <string name="pref_library_update_restriction">Restricciones de actualización automática del dispositivo</string>
<string name="charging">Mientras se carga la batería</string> <string name="charging">Mientras se carga la batería</string>
<string name="pref_update_only_non_completed">Serie completada</string> <string name="pref_update_only_non_completed">Series completadas</string>
<string name="pref_auto_update_manga_sync">Actualizar progreso al terminar un capítulo</string> <string name="pref_auto_update_manga_sync">Actualizar progreso al terminar un capítulo</string>
<!-- Reader section --> <!-- Reader section -->
<string name="pref_fullscreen">Pantalla completa</string> <string name="pref_fullscreen">Pantalla completa</string>
@ -644,7 +644,7 @@
<string name="information_empty_category_dialog">Todavía no existen categorías.</string> <string name="information_empty_category_dialog">Todavía no existen categorías.</string>
<string name="notification_updating">Actualizando biblioteca… (%1$d/%2$d)</string> <string name="notification_updating">Actualizando biblioteca… (%1$d/%2$d)</string>
<string name="error_no_match">No se han encontrado coincidencias</string> <string name="error_no_match">No se han encontrado coincidencias</string>
<string name="source_unsupported">No se admite el origen</string> <string name="source_unsupported">Fuente no soportada</string>
<string name="unread">No leídos</string> <string name="unread">No leídos</string>
<string name="tracker_komga_warning">Este servicio de seguimiento sólo es compatible con la fuente Komga.</string> <string name="tracker_komga_warning">Este servicio de seguimiento sólo es compatible con la fuente Komga.</string>
<string name="error_sharing_cover">Error al compartir portada</string> <string name="error_sharing_cover">Error al compartir portada</string>
@ -703,7 +703,7 @@
<string name="pref_verbose_logging">Registro detallado</string> <string name="pref_verbose_logging">Registro detallado</string>
<string name="pref_verbose_logging_summary">Mostrar registros detallados en el registro del sistema (reduce el rendimiento de la aplicación)</string> <string name="pref_verbose_logging_summary">Mostrar registros detallados en el registro del sistema (reduce el rendimiento de la aplicación)</string>
<string name="label_warning">Advertencia</string> <string name="label_warning">Advertencia</string>
<string name="notification_size_warning">Cuidado: las actualizaciones grandes pueden implicar un mayor uso de la batería y que los distintos servicios bloqueen o ralenticen el acceso a tu dispositivo</string> <string name="notification_size_warning">Las actualizaciones grandes pueden implicar un mayor uso de la batería y que los distintos servicios bloqueen o ralenticen el acceso a tu dispositivo</string>
<string name="action_display_language_badge">Idioma</string> <string name="action_display_language_badge">Idioma</string>
<string name="backup_info">Es una buena idea tener copias de respaldo automáticas, así como respaldarlas fuera de tu dispositivo.</string> <string name="backup_info">Es una buena idea tener copias de respaldo automáticas, así como respaldarlas fuera de tu dispositivo.</string>
<string name="connected_to_wifi">Solo con Wi-Fi</string> <string name="connected_to_wifi">Solo con Wi-Fi</string>
@ -717,8 +717,8 @@
<string name="clear_database_source_item_count">Hay %1$d manga que no pertenece a la biblioteca en la base de datos</string> <string name="clear_database_source_item_count">Hay %1$d manga que no pertenece a la biblioteca en la base de datos</string>
<string name="extension_api_error">No se pudo descargar el listado de extensiones</string> <string name="extension_api_error">No se pudo descargar el listado de extensiones</string>
<string name="privacy_policy">Política de privacidad</string> <string name="privacy_policy">Política de privacidad</string>
<string name="pref_update_only_completely_read">Capítulos sin leer</string> <string name="pref_update_only_completely_read">Con capítulos sin leer</string>
<string name="pref_library_update_manga_restriction">Omitir la actualización</string> <string name="pref_library_update_manga_restriction">Omitir actualizaciones</string>
<string name="library_errors_help">Si necesitas ayuda para resolver los errores de actualización de la biblioteca mira en %1$s</string> <string name="library_errors_help">Si necesitas ayuda para resolver los errores de actualización de la biblioteca mira en %1$s</string>
<string name="save_chapter_as_cbz">Guardar como archivo CBZ</string> <string name="save_chapter_as_cbz">Guardar como archivo CBZ</string>
<string name="on_hiatus">En pausa</string> <string name="on_hiatus">En pausa</string>
@ -735,15 +735,17 @@
\n \n
\n¿Quieres seguir\?</string> \n¿Quieres seguir\?</string>
<string name="action_filter_started">Empezados</string> <string name="action_filter_started">Empezados</string>
<string name="pref_update_only_started">Sin capítulos leídos</string> <string name="pref_update_only_started">Series sin empezar</string>
<string name="skipped_reason_completed">Omitido porque la serie está completa</string> <string name="skipped_reason_completed">Omitido porque la serie está completa</string>
<string name="skipped_reason_not_caught_up">Omitido porque hay capítulos sin leer</string> <string name="skipped_reason_not_caught_up">Omitido porque hay capítulos sin leer</string>
<string name="skipped_reason_not_started">Omitido porque no hay capítulos leídos</string> <string name="skipped_reason_not_started">Omitido porque no hay capítulos leídos</string>
<string name="learn_more">Más información</string> <string name="learn_more">Ver más detalles</string>
<string name="channel_skipped">Omitidas</string> <string name="channel_skipped">Omitidas</string>
<string name="notification_update_error">Actualizaciones fallidas: %1$d</string> <string name="notification_update_error">Actualizaciones fallidas: %1$d</string>
<string name="notification_update_skipped">Actualizaciones omitidas: %1$d</string> <string name="notification_update_skipped">Actualizaciones omitidas: %1$d</string>
<string name="rotation_reverse_portrait">En vertical, al revés</string> <string name="rotation_reverse_portrait">En vertical, al revés</string>
<string name="action_move_to_top_all_for_series">Mover al primer puesto</string> <string name="action_move_to_top_all_for_series">Mover al primer puesto</string>
<string name="disabled_nav">Desactivado</string> <string name="disabled_nav">Desactivado</string>
<string name="update_check_fdroid_migration_info">Hay una actualización disponible en la página oficial. Toca para aprender a migrar desde una versión no oficial de F-Droid.</string>
<string name="error_saving_picture">No se ha podido guardar la imagen</string>
</resources> </resources>

View File

@ -62,7 +62,7 @@
<string name="information_no_downloads">Ei latauksia</string> <string name="information_no_downloads">Ei latauksia</string>
<string name="information_no_recent">Ei viimeisimpiä päivityksiä</string> <string name="information_no_recent">Ei viimeisimpiä päivityksiä</string>
<string name="information_no_recent_manga">Ei mitään luettu viime aikoina</string> <string name="information_no_recent_manga">Ei mitään luettu viime aikoina</string>
<string name="information_empty_library">Kirjastosi on tyhjä. Lisää sarjoja kirjastoosi Selaa-kohdasta.</string> <string name="information_empty_library">Kirjastosi on tyhjä.</string>
<string name="information_empty_category">Sinulla ei ole kategorioita. Napauta pluspainiketta, jos haluat luoda sellaisen kirjaston järjestämistä varten.</string> <string name="information_empty_category">Sinulla ei ole kategorioita. Napauta pluspainiketta, jos haluat luoda sellaisen kirjaston järjestämistä varten.</string>
<string name="download_notifier_downloader_title">Lataaja</string> <string name="download_notifier_downloader_title">Lataaja</string>
<string name="download_notifier_title_error">Virhe</string> <string name="download_notifier_title_error">Virhe</string>
@ -104,7 +104,7 @@
<string name="action_display">Näkymä</string> <string name="action_display">Näkymä</string>
<string name="action_display_grid">Kompakti ruudukko</string> <string name="action_display_grid">Kompakti ruudukko</string>
<string name="action_display_list">Lista</string> <string name="action_display_list">Lista</string>
<string name="action_display_download_badge">Näytä ladattujen määrä</string> <string name="action_display_download_badge">Ladatut luvut</string>
<string name="action_cancel">Peruuta</string> <string name="action_cancel">Peruuta</string>
<string name="action_sort">Järjestä</string> <string name="action_sort">Järjestä</string>
<string name="action_install">Asenna</string> <string name="action_install">Asenna</string>
@ -125,17 +125,17 @@
<string name="pref_library_columns">Kohteita per rivi</string> <string name="pref_library_columns">Kohteita per rivi</string>
<string name="portrait">Pystysuunta</string> <string name="portrait">Pystysuunta</string>
<string name="landscape">Vaakataso</string> <string name="landscape">Vaakataso</string>
<string name="pref_library_update_interval">Päivitystiheys</string> <string name="pref_library_update_interval">Automaattinen päivitys</string>
<string name="update_never">Manuaalinen</string> <string name="update_never">Pois</string>
<string name="update_6hour">Kuuden tunnin välein</string> <string name="update_6hour">Kuuden tunnin välein</string>
<string name="update_12hour">12 tunnin välein</string> <string name="update_12hour">12 tunnin välein</string>
<string name="update_24hour">Päivittäin</string> <string name="update_24hour">Päivittäin</string>
<string name="update_48hour">Kahden päivän välein</string> <string name="update_48hour">Kahden päivän välein</string>
<string name="update_weekly">Viikoittain</string> <string name="update_weekly">Viikoittain</string>
<string name="all">Kaikki</string> <string name="all">Kaikki</string>
<string name="pref_library_update_restriction">Päivityksen rajoitukset</string> <string name="pref_library_update_restriction">Automaattisen päivityksen laitteistorajoitukset</string>
<string name="charging">Latauksessa</string> <string name="charging">Latauksessa</string>
<string name="pref_update_only_non_completed">Päivitä vain jatkuvat sarjat</string> <string name="pref_update_only_non_completed">Sarja on päättynyt</string>
<string name="pref_auto_update_manga_sync">Päivitä luvun edistyminen lukemisen jälkeen</string> <string name="pref_auto_update_manga_sync">Päivitä luvun edistyminen lukemisen jälkeen</string>
<string name="pref_start_screen">Aloitusnäyttö</string> <string name="pref_start_screen">Aloitusnäyttö</string>
<string name="default_category">Oletus kategoria</string> <string name="default_category">Oletus kategoria</string>
@ -372,7 +372,7 @@
<string name="notification_check_updates">Etsitään uusia lukuja</string> <string name="notification_check_updates">Etsitään uusia lukuja</string>
<string name="lock_when_idle">Lukitse käyttämättömänä</string> <string name="lock_when_idle">Lukitse käyttämättömänä</string>
<string name="secure_screen">Salaa näyttö</string> <string name="secure_screen">Salaa näyttö</string>
<string name="secure_screen_summary">Piilota sovelluksen sisältö kun sovelluksia vaihdetaan ja estä kuvakaappauksien otto</string> <string name="secure_screen_summary">Turvallinen ruutu piilottaa sovelluksen sisäln sovelluksia vaihdettaessa ja estää kuvakaappauksen ottamisen</string>
<string name="pref_disable_battery_optimization">Poista akun optimointi käytöstä</string> <string name="pref_disable_battery_optimization">Poista akun optimointi käytöstä</string>
<string name="pref_disable_battery_optimization_summary">Auttaa taustalla pyörivien kirjaston päivitysten ja varmuuskopioiden kanssa</string> <string name="pref_disable_battery_optimization_summary">Auttaa taustalla pyörivien kirjaston päivitysten ja varmuuskopioiden kanssa</string>
<string name="battery_optimization_disabled">Akun optimointi on jo poistettu käytöstä</string> <string name="battery_optimization_disabled">Akun optimointi on jo poistettu käytöstä</string>
@ -451,7 +451,7 @@
<item quantity="other">Valmistui %1$s virheitä löytyi %2$s</item> <item quantity="other">Valmistui %1$s virheitä löytyi %2$s</item>
</plurals> </plurals>
<string name="pref_true_color_summary">Vähentää juovia, mutta vaikuttaa suorituskykyyn</string> <string name="pref_true_color_summary">Vähentää juovia, mutta vaikuttaa suorituskykyyn</string>
<string name="action_display_unread_badge">Näytä lukemattomien määrä</string> <string name="action_display_unread_badge">Lukemattomat</string>
<string name="viewer">Lukutila</string> <string name="viewer">Lukutila</string>
<string name="battery_optimization_setting_activity_not_found">Laiteasetuksia ei voitu avata</string> <string name="battery_optimization_setting_activity_not_found">Laiteasetuksia ei voitu avata</string>
<string name="tracking_info">Yksisuuntainen synkronointi lukujen seurantapalveluiden päivittämiseksi. Määritä yksittäisten mangamerkintöjen seuranta seurantapainikkeesta.</string> <string name="tracking_info">Yksisuuntainen synkronointi lukujen seurantapalveluiden päivittämiseksi. Määritä yksittäisten mangamerkintöjen seuranta seurantapainikkeesta.</string>
@ -542,7 +542,7 @@
<string name="spen_previous_page">Edellinen sivu</string> <string name="spen_previous_page">Edellinen sivu</string>
<string name="migration_help_guide">Lähteen siirto-opas</string> <string name="migration_help_guide">Lähteen siirto-opas</string>
<string name="pref_category_nsfw_content">NSFW (18+) lähteet</string> <string name="pref_category_nsfw_content">NSFW (18+) lähteet</string>
<string name="pref_show_nsfw_source">Näytä lähdeluettelossa</string> <string name="pref_show_nsfw_source">Näytä lähde- ja lisäosaluettelossa</string>
<string name="file_picker_error">Tiedostonvalitsinsovellusta ei löytynyt</string> <string name="file_picker_error">Tiedostonvalitsinsovellusta ei löytynyt</string>
<string name="myanimelist_relogin">Kirjaudu uudelleen MAL: iin</string> <string name="myanimelist_relogin">Kirjaudu uudelleen MAL: iin</string>
<string name="pref_viewer_nav">Navigointiasettelu</string> <string name="pref_viewer_nav">Navigointiasettelu</string>
@ -582,7 +582,7 @@
<string name="pref_download_new_categories_details">Poissuljettuihin kategorioihin kuuluvia mangoja ei ladata, vaikka ne olisivat myös sisällytetyissä kategorioissa.</string> <string name="pref_download_new_categories_details">Poissuljettuihin kategorioihin kuuluvia mangoja ei ladata, vaikka ne olisivat myös sisällytetyissä kategorioissa.</string>
<string name="pref_category_auto_download">Automaattinen lataus</string> <string name="pref_category_auto_download">Automaattinen lataus</string>
<string name="pref_library_update_categories_details">Poissuljettuihin kategorioihin sisältyvää mangaa ei päivitetä, vaikka ne olisivat myös sisällytetyissä kategorioissa.</string> <string name="pref_library_update_categories_details">Poissuljettuihin kategorioihin sisältyvää mangaa ei päivitetä, vaikka ne olisivat myös sisällytetyissä kategorioissa.</string>
<string name="action_show_errors">Näytä virheet</string> <string name="action_show_errors">Näytä lisätiedot</string>
<string name="update_check_eol">Tätä Android-versiota ei enää tueta</string> <string name="update_check_eol">Tätä Android-versiota ei enää tueta</string>
<string name="clipboard_copy_error">Kopiointi leikepöydälle epäonnistui</string> <string name="clipboard_copy_error">Kopiointi leikepöydälle epäonnistui</string>
<string name="rotation_landscape">Vaakatasossa</string> <string name="rotation_landscape">Vaakatasossa</string>
@ -606,4 +606,63 @@
<string name="on">Päällä</string> <string name="on">Päällä</string>
<string name="getting_started_guide">Aloitusopas</string> <string name="getting_started_guide">Aloitusopas</string>
<string name="download_queue_size_warning">Varoitus: massalataukset voivat johtaa siihen, että lähteet muuttuvat hitaammiksi käyttää ja/tai ne estävät Tachiyomin käytön</string> <string name="download_queue_size_warning">Varoitus: massalataukset voivat johtaa siihen, että lähteet muuttuvat hitaammiksi käyttää ja/tai ne estävät Tachiyomin käytön</string>
<string name="pref_library_update_show_tab_badge">Näytä lukemattomien määrä päivitys ikoneissa</string>
<string name="alignment_center">Keskimmäinen</string>
<string name="pref_library_update_refresh_trackers_summary">Päivitä seurantapalvelimet kirjaston päivityksen yhteydessä</string>
<plurals name="relative_time">
<item quantity="one">Eilen</item>
<item quantity="other">%1$d päivää sitten</item>
</plurals>
<string name="action_show_manga">Näytä manga</string>
<string name="action_display_cover_only_grid">Kansikuva ruudukko</string>
<string name="theme_monet">Dynaaminen</string>
<string name="theme_greenapple">Vihreä omena</string>
<string name="alignment_bottom">Alin</string>
<string name="recently">Viimeaikoina</string>
<string name="label_default">Oletus</string>
<string name="action_filter_started">Aloitettu</string>
<string name="action_display_local_badge">Laitteelle tallennettu manga</string>
<string name="pref_library_update_refresh_trackers">Päivitä seurantapalvelimet automaattisesti</string>
<string name="action_sort_count">Yhteenlaskettu manga</string>
<string name="action_start_downloading_now">Aloita lataaminen nyt</string>
<string name="theme_yinyang">Ying ja Yang</string>
<string name="theme_midnightdusk">Keskiyön hämärä</string>
<string name="theme_strawberrydaiquiri">Mansikka Daiquiri</string>
<string name="pref_category_appearance">Ulkonäkö</string>
<string name="theme_tealturquoise">Sinivihreä ja turkoosi</string>
<string name="theme_yotsuba">Yotsuba</string>
<string name="alignment_top">Päällimmäinen</string>
<string name="pref_side_nav_icon_alignment">Sivunavigaation kuvakkeiden kohdistus</string>
<string name="pref_dark_theme_pure_black">Täysin musta pimeätila</string>
<string name="pref_category_navigation">Navigaatio</string>
<string name="pref_update_only_started">Ei lukemattomia lukuja</string>
<string name="pref_relative_format">Suhteelliset aikamerkit</string>
<string name="pref_relative_time_short">Lyhyt (tänään, eilen)</string>
<string name="pref_relative_time_long">Pitkä (lyhyt+, N päivää sitten)</string>
<string name="relative_time_today">Tänään</string>
<string name="pref_update_only_completely_read">Sarjalla on lukemattomia kappaleita</string>
<string name="pref_app_theme">Sovelluksen teema</string>
<string name="label_warning">Varoitus</string>
<string name="confirm_lock_change">Tunnistaudu vahvistaaksesi muutokset</string>
<string name="action_display_language_badge">Kieli</string>
<string name="pref_category_timestamps">Aikaleimat</string>
<string name="action_faq_and_guides">Usein kysytyt kysymykset ja oppaat</string>
<string name="pref_library_update_manga_restriction">Ohita päivitys</string>
<string name="action_move_to_top_all_for_series">Siirrä sarja päällimmäiseksi</string>
<string name="theme_tako">Tako</string>
<string name="update_72hour">Joka 3. Päivä</string>
<string name="connected_to_wifi">Ainoastaan WiFillä</string>
<string name="pref_inverted_colors">Käänteisväri</string>
<string name="webtoon_side_padding_5">5%</string>
<string name="ext_app_info">Sovelluksen tiedot</string>
<string name="ext_installer_legacy">Perinteinen</string>
<string name="rotation_reverse_portrait">Käänteinen kuva</string>
<string name="categorized_display_settings">Kategoria kohtaiset asetukset lajittelulle ja näytölle</string>
<string name="ext_installer_shizuku_stopped">Shizuku on pysähtynyt</string>
<string name="disabled_nav">Poistettu käytöstä</string>
<string name="ext_installer_shizuku_unavailable_dialog">Asenna ja aja Shizuku käyttääksesi Shizukua laajennusten asentamiseen</string>
<string name="ext_update_all">Päivitä kaikki</string>
<string name="extension_api_error">Laajennusluettelon halu epäonnistui</string>
<string name="ext_install_service_notif">Asennetaan laajennusta…</string>
<string name="ext_installer_pref">Asentaja</string>
</resources> </resources>

View File

@ -520,7 +520,7 @@
<string name="ext_nsfw_short">18+</string> <string name="ext_nsfw_short">18+</string>
<plurals name="missing_chapters_warning"> <plurals name="missing_chapters_warning">
<item quantity="one">Lalaktawan ang %d kabanata, siguro baka wala sa source ito, o baka nasala ito</item> <item quantity="one">Lalaktawan ang %d kabanata, siguro baka wala sa source ito, o baka nasala ito</item>
<item quantity="other">Lalaktawan ang %d (na) kabanata, siguro baka wala sa source sila, o baka nasala sila</item> <item quantity="other">Lalaktawan ang %d (na) kabanata, siguro baka sa source ang mga ito, o baka nasala sila</item>
</plurals> </plurals>
<string name="no_chapters_error">Walang nakitang kabanata</string> <string name="no_chapters_error">Walang nakitang kabanata</string>
<string name="confirm_set_chapter_settings">Gusto mo bang i-save at ipagpaubaya ang pagsasaayos na ito\?</string> <string name="confirm_set_chapter_settings">Gusto mo bang i-save at ipagpaubaya ang pagsasaayos na ito\?</string>
@ -604,7 +604,7 @@
<string name="local_invalid_format">Walang bisa ang ayos ng kabanata</string> <string name="local_invalid_format">Walang bisa ang ayos ng kabanata</string>
<string name="chapter_not_found">Hindi makita ang kabanata</string> <string name="chapter_not_found">Hindi makita ang kabanata</string>
<string name="source_unsupported">Di suportado ang source</string> <string name="source_unsupported">Di suportado ang source</string>
<string name="unread">Hindi basahin</string> <string name="unread">Hindi nababasa</string>
<string name="alignment_center">Gitna</string> <string name="alignment_center">Gitna</string>
<string name="pref_side_nav_icon_alignment">Hilera ng nabigasyon sa gilid</string> <string name="pref_side_nav_icon_alignment">Hilera ng nabigasyon sa gilid</string>
<string name="error_sharing_cover">Di maibahagi ang cover</string> <string name="error_sharing_cover">Di maibahagi ang cover</string>
@ -690,7 +690,7 @@
<string name="pref_update_only_completely_read">May hindi pa nabasang kabanata</string> <string name="pref_update_only_completely_read">May hindi pa nabasang kabanata</string>
<string name="pref_library_update_manga_restriction">Lakdawan ang pag-update</string> <string name="pref_library_update_manga_restriction">Lakdawan ang pag-update</string>
<string name="save_chapter_as_cbz">I-save bilang CBZ archive</string> <string name="save_chapter_as_cbz">I-save bilang CBZ archive</string>
<string name="publishing_finished">Tapos na\'ng mailathala</string> <string name="publishing_finished">Tapos nang mailathala</string>
<string name="on_hiatus">Naka-hiatus</string> <string name="on_hiatus">Naka-hiatus</string>
<string name="cancelled">Kinansela</string> <string name="cancelled">Kinansela</string>
<string name="backup_restore_invalid_uri">Error: walang URI</string> <string name="backup_restore_invalid_uri">Error: walang URI</string>
@ -714,4 +714,5 @@
<string name="rotation_reverse_portrait">Baligtad na patayo</string> <string name="rotation_reverse_portrait">Baligtad na patayo</string>
<string name="notification_update_skipped">Nilaktawan ang %1$d (na) update</string> <string name="notification_update_skipped">Nilaktawan ang %1$d (na) update</string>
<string name="action_move_to_top_all_for_series">Ilagay sa taas ang serye</string> <string name="action_move_to_top_all_for_series">Ilagay sa taas ang serye</string>
<string name="disabled_nav">Nakasara</string>
</resources> </resources>

View File

@ -14,7 +14,7 @@
<string name="action_filter_downloaded">Téléchargés</string> <string name="action_filter_downloaded">Téléchargés</string>
<string name="action_filter_bookmarked">Signets</string> <string name="action_filter_bookmarked">Signets</string>
<string name="action_filter_unread">Non lus</string> <string name="action_filter_unread">Non lus</string>
<string name="action_filter_empty">Enlever le filtre</string> <string name="action_filter_empty">Retirer le filtre</string>
<string name="action_sort_alpha">Alphabétiquement</string> <string name="action_sort_alpha">Alphabétiquement</string>
<string name="action_sort_last_read">Dernier lu</string> <string name="action_sort_last_read">Dernier lu</string>
<string name="action_search">Rechercher</string> <string name="action_search">Rechercher</string>
@ -748,4 +748,5 @@
<string name="channel_skipped">Ignoré</string> <string name="channel_skipped">Ignoré</string>
<string name="rotation_reverse_portrait">Portrait inversé</string> <string name="rotation_reverse_portrait">Portrait inversé</string>
<string name="action_move_to_top_all_for_series">Déplacer la série vers le haut</string> <string name="action_move_to_top_all_for_series">Déplacer la série vers le haut</string>
<string name="disabled_nav">Désactivé</string>
</resources> </resources>

View File

@ -264,38 +264,38 @@
<string name="backup_choice">מה אתה רוצה לגבות\?</string> <string name="backup_choice">מה אתה רוצה לגבות\?</string>
<string name="backup_restore_content">פעולת שחזור משתמשת במקורות בכדי להשיג נתונים, עלויות הספק עשויות לחול. <string name="backup_restore_content">פעולת שחזור משתמשת במקורות בכדי להשיג נתונים, עלויות הספק עשויות לחול.
\n \n
\nוודא שהתקנת את כל התוספים הנחוצים והתחרת למקורות ושירותי המעקב לפני השחזור.</string> \nוודא שהתקנת את כל התוספים הנחוצים והתחברת למקורות ושירותי המעקב לפני השחזור.</string>
<string name="restore_completed">השחזור הושלם</string> <string name="restore_completed">השחזור הושלם</string>
<string name="backup_created">גיבוי נוצר</string> <string name="backup_created">גיבוי נוצר</string>
<string name="pref_backup_slots">מספר גיבויים אוטומטיים מקסימליים</string> <string name="pref_backup_slots">מספר גיבויים מקסימלי</string>
<string name="pref_backup_interval">תדירות גיבוי</string> <string name="pref_backup_interval">תדירות גיבוי</string>
<string name="pref_backup_service_category">שירות</string> <string name="pref_backup_service_category">גיבויים אוטומטיים</string>
<string name="pref_backup_directory">מיקום גיבוי</string> <string name="pref_backup_directory">מיקום גיבוי</string>
<string name="pref_restore_backup_summ">שחזר ספרייה מקובץ גיבוי</string> <string name="pref_restore_backup_summ">שחזר ספרייה מקובץ גיבוי</string>
<string name="pref_restore_backup">שחזור גיבוי</string> <string name="pref_restore_backup">שחזור גיבוי</string>
<string name="pref_create_backup_summ">ניתן לשימוש על מנת לשחזר את הספרייה הנוכחית</string> <string name="pref_create_backup_summ">ניתן לשימוש על מנת לשחזר את הספרייה הנוכחית</string>
<string name="pref_create_backup">צור גיבוי</string> <string name="pref_create_backup">צור גיבוי</string>
<string name="services">שירותים</string> <string name="services">שירותים</string>
<string name="pref_auto_update_manga_sync">סנכרן פרקים לאחר סיום קריאה</string> <string name="pref_auto_update_manga_sync">עדכן התקדמות לאחר הקריאה</string>
<string name="pref_download_new">הורד פרקים חדשים</string> <string name="pref_download_new">הורדת פרקים חדשים</string>
<string name="fifth_to_last">פרק חמישי מהסוף</string> <string name="fifth_to_last">הפרק החמישי מהסוף שנקרא</string>
<string name="fourth_to_last">פרק רביעי מהסוף</string> <string name="fourth_to_last">הפרק הרביעי מהסוף שנקרא</string>
<string name="third_to_last">פרק שלישי מהסוף</string> <string name="third_to_last">הפרק השלישי מהסוף שנקרא</string>
<string name="second_to_last">פרק שני מהסוף</string> <string name="second_to_last">הפרק השני מהסוף שנקרא</string>
<string name="last_read_chapter">פרק שנקרא בפעם האחרונה</string> <string name="last_read_chapter">פרק שנקרא בפעם האחרונה</string>
<string name="custom_dir">מיקום מותאם אישית</string> <string name="custom_dir">מיקום מותאם אישית</string>
<string name="pref_remove_after_read">הסר לאחר סיום קריאה</string> <string name="pref_remove_after_read">אוטומטי לאחר סיום הקריאה</string>
<string name="pref_remove_after_marked_as_read">הסר כאשר מסומן כנקרא</string> <string name="pref_remove_after_marked_as_read">אחרי שמסומן ידנית כנקרא</string>
<string name="pref_download_directory">מיקום הורדה</string> <string name="pref_download_directory">מיקום הורדה</string>
<string name="pref_always_show_chapter_transition">הצג תמיד מעברי פרקים</string> <string name="pref_always_show_chapter_transition">הצג תמיד מעברי פרקים</string>
<string name="color_filter_a_value">אלפא</string> <string name="color_filter_a_value">אלפא</string>
<string name="color_filter_b_value">כחול</string> <string name="color_filter_b_value">כחול</string>
<string name="color_filter_g_value">ירוק</string> <string name="color_filter_g_value">ירוק</string>
<string name="color_filter_r_value">אדום</string> <string name="color_filter_r_value">אדום</string>
<string name="rotation_force_landscape">כפה מצב מאוזן</string> <string name="rotation_force_landscape">מאוזן נעול</string>
<string name="rotation_force_portrait">כפה מצב מאונך</string> <string name="rotation_force_portrait">מאונך נעול</string>
<string name="rotation_free">חופשי</string> <string name="rotation_free">חופשי</string>
<string name="pref_rotation_type">סיבוב</string> <string name="pref_rotation_type">ברירת המחדל של סוג הסיבוב</string>
<string name="double_tap_anim_speed_fast">מהירה</string> <string name="double_tap_anim_speed_fast">מהירה</string>
<string name="double_tap_anim_speed_normal">רגילה</string> <string name="double_tap_anim_speed_normal">רגילה</string>
<string name="double_tap_anim_speed_0">בלי אנימציה</string> <string name="double_tap_anim_speed_0">בלי אנימציה</string>
@ -315,7 +315,7 @@
<string name="vertical_viewer">אנכי</string> <string name="vertical_viewer">אנכי</string>
<string name="right_to_left_viewer">ימין לשמאל</string> <string name="right_to_left_viewer">ימין לשמאל</string>
<string name="left_to_right_viewer">שמאל לימין</string> <string name="left_to_right_viewer">שמאל לימין</string>
<string name="pref_viewer_type">מציג ברירת מחדל</string> <string name="pref_viewer_type">ברירת המחדל של מצב הקריאה</string>
<string name="black_background">שחור</string> <string name="black_background">שחור</string>
<string name="white_background">לבן</string> <string name="white_background">לבן</string>
<string name="pref_reader_theme">צבע רקע</string> <string name="pref_reader_theme">צבע רקע</string>
@ -327,15 +327,15 @@
<string name="pref_keep_screen_on">השאר מסך דלוק</string> <string name="pref_keep_screen_on">השאר מסך דלוק</string>
<string name="filter_mode_darken">שרוף / מוחשך</string> <string name="filter_mode_darken">שרוף / מוחשך</string>
<string name="filter_mode_screen">מסך</string> <string name="filter_mode_screen">מסך</string>
<string name="pref_custom_color_filter">השתמש במסנן צבע מותאם אישית</string> <string name="pref_custom_color_filter">מסנן צבע מותאם אישית</string>
<string name="pref_custom_brightness">השתמש בבהירות מותאמת אישית</string> <string name="pref_custom_brightness">בהירות מותאמת אישית</string>
<string name="pref_crop_borders">חתוך גבולות</string> <string name="pref_crop_borders">חתוך גבולות</string>
<string name="pref_true_color">צבע 32-סיביות</string> <string name="pref_true_color">צבע 32-סיביות</string>
<string name="pref_show_page_number">הצג מספר עמוד</string> <string name="pref_show_page_number">הצג מספר עמוד</string>
<string name="pref_double_tap_anim_speed">מהירות הנפשה בהקשה כפולה</string> <string name="pref_double_tap_anim_speed">מהירות הנפשה בהקשה כפולה</string>
<string name="pref_page_transitions">הנפשת מעברי דפים</string> <string name="pref_page_transitions">הנפשת מעברי דפים</string>
<string name="pref_cutout_short">הצג תוכן באזור החתוך</string> <string name="pref_cutout_short">הצג תוכן באזור החתוך</string>
<string name="pref_enable_automatic_extension_updates">בדוק אם קיימים עדכונים עבור תוספים</string> <string name="pref_enable_automatic_extension_updates">בדוק אם קיימים עדכוני הרחבות</string>
<string name="untrusted_extension">תוסף לא מאומת</string> <string name="untrusted_extension">תוסף לא מאומת</string>
<string name="obsolete_extension_message">תוסף זה אינו זמין עוד.</string> <string name="obsolete_extension_message">תוסף זה אינו זמין עוד.</string>
<string name="pref_fullscreen">מסך מלא</string> <string name="pref_fullscreen">מסך מלא</string>
@ -492,4 +492,63 @@
<string name="update_72hour">כל 3 ימים</string> <string name="update_72hour">כל 3 ימים</string>
<string name="connected_to_wifi">רק ב Wi-Fi</string> <string name="connected_to_wifi">רק ב Wi-Fi</string>
<string name="restrictions">הגבלות: %s</string> <string name="restrictions">הגבלות: %s</string>
<string name="pref_show_reading_mode_summary">הראה לזמן קצר את הסגנון כשהקראן נפתח</string>
<string name="pref_read_with_tapping_inverted">לחיצה הופכית</string>
<string name="off">כבוי</string>
<string name="on">פעיל</string>
<string name="pref_grayscale">טווח גווני האפור</string>
<string name="pref_inverted_colors">הופכי</string>
<string name="tapping_inverted_horizontal">אופקי</string>
<string name="right_and_left_nav">ימין ושמאל</string>
<string name="nav_zone_next">הבא</string>
<string name="nav_zone_right">ימין</string>
<string name="rotation_type">סוג הסיבוב</string>
<string name="rotation_portrait">מאונך</string>
<string name="rotation_landscape">מאוזן</string>
<string name="webtoon_side_padding_5">5%</string>
<string name="webtoon_side_padding_10">10%</string>
<string name="webtoon_side_padding_15">15%</string>
<string name="pref_hide_threshold">רגישות החבאת התפריט בגלילה</string>
<string name="pref_highest">הכי גבוה</string>
<string name="pref_high">גבוה</string>
<string name="pref_low">נמוך</string>
<string name="pref_lowest">הכי נמוך</string>
<string name="pref_category_delete_chapters">מחק פרקים</string>
<string name="pref_remove_exclude_categories">קטגוריות מוחרגות</string>
<string name="pref_download_new_categories_details">מנגה הנמצאת בקטגוריית מנועי ההורדות לא תעודכן גם אם היא נכללת בקטגורייה אחרת שכן מורדת.</string>
<string name="save_chapter_as_cbz">שמור כארכיון CBZ</string>
<string name="enhanced_services">שירותים משופרים</string>
<string name="edge_nav">גבול</string>
<string name="l_nav">עשוי בצורת L</string>
<string name="nav_zone_left">שמאל</string>
<string name="nav_zone_prev">הקודם</string>
<string name="pref_category_reading">קריאה</string>
<string name="webtoon_side_padding_20">20%</string>
<string name="webtoon_side_padding_25">25%</string>
<string name="pref_category_reading_mode">מצב קריאה</string>
<string name="webtoon_side_padding_0">ללא</string>
<string name="pref_category_auto_download">הורדה אוטומטית</string>
<string name="gray_background">אפור</string>
<string name="vertical_plus_viewer">אנכי מתמשך</string>
<string name="pager_viewer">עמודים</string>
<string name="rotation_reverse_portrait">מאונך הפוך</string>
<string name="pref_create_folder_per_manga">שמור דפים בתיקיות נפרדות</string>
<string name="tapping_inverted_vertical">אנכי</string>
<string name="tapping_inverted_both">שניהם</string>
<string name="pref_reader_actions">פעולות</string>
<string name="pref_read_with_long_tap">הראה בלחיצה ארוכה</string>
<string name="automatic_background">אוטומטי</string>
<string name="pref_remove_bookmarked_chapters">אפשר מחיקת פרקים שסומנו</string>
<string name="disabled">לא מאופשר</string>
<string name="pref_create_folder_per_manga_summary">צור תיקיות בהתאם לכותרת המנגה</string>
<string name="enhanced_tracking_info">שירותים המספקים שירותים משופרים למקורות ספציפיים. מנגות יהיו במעקב אוטומטי אחרי הוספה לספרייה שלך.</string>
<string name="backup_restore_missing_sources">מקורות חסרים:</string>
<string name="invalid_backup_file">קובץ גיבוי לא תקין</string>
<string name="invalid_backup_file_missing_data">חסרים נתונים בקובץ.</string>
<string name="invalid_backup_file_missing_manga">הגיבוי לא מכיל שום מנגה.</string>
<string name="pref_search_pinned_sources_only">כלול רק מקורות נעוצים</string>
<string name="source_not_found_name">מקור לא נמצא: %1$s</string>
<string name="tracker_not_logged_in">לא מחובר ל: %1$s</string>
<string name="backup_restore_invalid_uri">שגיאה: URI ריק</string>
<string name="action_track">מעקב</string>
</resources> </resources>

View File

@ -349,7 +349,7 @@
<string name="lock_always">हमेशा</string> <string name="lock_always">हमेशा</string>
<string name="lock_never">कभी नहीँ</string> <string name="lock_never">कभी नहीँ</string>
<plurals name="lock_after_mins"> <plurals name="lock_after_mins">
<item quantity="one">1 मिनट के बाद</item> <item quantity="one">%1$s मिनट के बाद</item>
<item quantity="other">%1$s मिनट के बाद</item> <item quantity="other">%1$s मिनट के बाद</item>
</plurals> </plurals>
<string name="secure_screen">स्क्रीन सुरक्षित करें</string> <string name="secure_screen">स्क्रीन सुरक्षित करें</string>
@ -380,8 +380,8 @@
<string name="email">ईमेल पता</string> <string name="email">ईमेल पता</string>
<string name="pref_always_show_chapter_transition">हमेशा अध्याय संक्रमण दिखाएं</string> <string name="pref_always_show_chapter_transition">हमेशा अध्याय संक्रमण दिखाएं</string>
<plurals name="notification_new_chapters_summary"> <plurals name="notification_new_chapters_summary">
<item quantity="one">1 शीर्षक के लिए</item> <item quantity="one">%d शीर्षक के लिए</item>
<item quantity="other">%d शीर्षक के लिए</item> <item quantity="other">%d शीर्षकों के लिए</item>
</plurals> </plurals>
<string name="action_menu">मेन्यू</string> <string name="action_menu">मेन्यू</string>
<string name="action_reorganize_by">पुनःक्रमित</string> <string name="action_reorganize_by">पुनःक्रमित</string>
@ -436,8 +436,8 @@
<string name="restore_duration">%02d मिनट,%02d सेकंड</string> <string name="restore_duration">%02d मिनट,%02d सेकंड</string>
<string name="downloaded_only_summary">अपने पुस्तकालय में सभी मंगा फ़िल्टर करे</string> <string name="downloaded_only_summary">अपने पुस्तकालय में सभी मंगा फ़िल्टर करे</string>
<plurals name="download_queue_summary"> <plurals name="download_queue_summary">
<item quantity="one">1 शेष</item> <item quantity="one">%1$s बचा हुआ</item>
<item quantity="other">%1$s शेष</item> <item quantity="other">%1$s बचा हुआ</item>
</plurals> </plurals>
<string name="pref_search_pinned_sources_only">केवल पिन किए गए स्रोत शामिल हैं</string> <string name="pref_search_pinned_sources_only">केवल पिन किए गए स्रोत शामिल हैं</string>
<string name="viewer">पढ़न मोड</string> <string name="viewer">पढ़न मोड</string>
@ -482,7 +482,7 @@
<string name="action_disable">बंद करें</string> <string name="action_disable">बंद करें</string>
<string name="action_start">प्रारंभ</string> <string name="action_start">प्रारंभ</string>
<plurals name="manga_num_chapters"> <plurals name="manga_num_chapters">
<item quantity="one">1 अध्याय</item> <item quantity="one">%1$s अध्याय</item>
<item quantity="other">%1$s अध्याय</item> <item quantity="other">%1$s अध्याय</item>
</plurals> </plurals>
<string name="label_network">नेटवर्क</string> <string name="label_network">नेटवर्क</string>
@ -504,7 +504,7 @@
<string name="pref_category_theme">थीम</string> <string name="pref_category_theme">थीम</string>
<string name="action_sort_date_added">तारीख को जोड़ा गया</string> <string name="action_sort_date_added">तारीख को जोड़ा गया</string>
<plurals name="num_trackers"> <plurals name="num_trackers">
<item quantity="one">1 ट्रैकर</item> <item quantity="one">%d ट्रैकर</item>
<item quantity="other">%d ट्रैकरस</item> <item quantity="other">%d ट्रैकरस</item>
</plurals> </plurals>
<string name="no_pinned_sources">कोई पिन किया हुआ सोर्स नही है</string> <string name="no_pinned_sources">कोई पिन किया हुआ सोर्स नही है</string>
@ -519,8 +519,8 @@
<string name="ext_nsfw_short">18+</string> <string name="ext_nsfw_short">18+</string>
<string name="parental_controls_info">यह अनौपचारिक या संभावित रूप से फ़्लैग किए गए एक्सटेंशन को ऐप के भीतर NSFW (18+) सामग्री के सामने आने से नहीं रोकता है।</string> <string name="parental_controls_info">यह अनौपचारिक या संभावित रूप से फ़्लैग किए गए एक्सटेंशन को ऐप के भीतर NSFW (18+) सामग्री के सामने आने से नहीं रोकता है।</string>
<plurals name="missing_chapters_warning"> <plurals name="missing_chapters_warning">
<item quantity="one">1 अध्याय छोड़ा जा रहा है, या तो स्रोत में यह अनुपलब्ध है या इसे फ़िल्टर कर दिया गया है</item> <item quantity="one">%d अध्याय को छोड़कर, या तो स्रोत में यह अनुपलब्ध है या इसे फ़िल्टर कर दिया गया है</item>
<item quantity="other">%d अध्याय छोड़े जा रहा है, या तो स्रोत में यह अनुपलब्ध है या इसे फ़िल्टर कर दिया गया है</item> <item quantity="other">%d अध्यायों को छोड़कर, या तो स्रोत में वे नहीं है या उन्हें फ़िल्टर कर दिया गया है</item>
</plurals> </plurals>
<string name="chapter_settings_updated">अपडेट किए गए डिफ़ॉल्ट अध्याय सेटिंग्स</string> <string name="chapter_settings_updated">अपडेट किए गए डिफ़ॉल्ट अध्याय सेटिंग्स</string>
<string name="no_chapters_error">कोई अध्याय नहीं मिला</string> <string name="no_chapters_error">कोई अध्याय नहीं मिला</string>
@ -703,6 +703,16 @@
<string name="skipped_reason_not_started">छोड़ दिया गया क्योंकि कोई अध्याय पढ़ा नहीं गया</string> <string name="skipped_reason_not_started">छोड़ दिया गया क्योंकि कोई अध्याय पढ़ा नहीं गया</string>
<string name="pref_update_only_started">कोई अध्याय नहीं पढ़ा</string> <string name="pref_update_only_started">कोई अध्याय नहीं पढ़ा</string>
<string name="action_show_manga">मंगा दिखाएँ</string> <string name="action_show_manga">मंगा दिखाएँ</string>
<string name="action_filter_started">शुरू किया</string> <string name="action_filter_started">शुरू किया गया</string>
<string name="action_display_cover_only_grid">केवल कवर ग्रिड</string> <string name="action_display_cover_only_grid">केवल कवर ग्रिड</string>
<string name="disabled_nav">अक्षम</string>
<string name="rotation_reverse_portrait">रिवर्स पोर्ट्रेट</string>
<string name="notification_update_error">%1$d अपडेट विफल</string>
<string name="confirm_manga_add_duplicate">आपकी लाइब्रेरी में एक ही नाम के साथ लेकिन एक अलग स्रोत (%1$s) से एक प्रविष्टि है।
\n
\nक्या आप अभी भी जारी रखना चाहते हैं\?</string>
<string name="notification_update_skipped">%1$d अपडेट छोड़े गए</string>
<string name="pref_navigate_pan">पैन पर नेविगेट करें</string>
<string name="pref_landscape_zoom">ज़ूम लैंडस्केप इमेज</string>
<string name="action_move_to_top_all_for_series">श्रृंखला को शीर्ष पर ले जाएं</string>
</resources> </resources>

View File

@ -271,7 +271,7 @@
<string name="notification_first_add_to_library">Prije toga, dodaj manga u biblioteku</string> <string name="notification_first_add_to_library">Prije toga, dodaj manga u biblioteku</string>
<string name="notification_cover_update_failed">Neuspjelo ažuriranje naslovnice</string> <string name="notification_cover_update_failed">Neuspjelo ažuriranje naslovnice</string>
<plurals name="notification_chapters_multiple_and_more"> <plurals name="notification_chapters_multiple_and_more">
<item quantity="one">Poglavlja %1$s i još %2$s</item> <item quantity="one">Poglavlja %1$s i još jedno</item>
<item quantity="few">Poglavlja %1$s i još %2$s</item> <item quantity="few">Poglavlja %1$s i još %2$s</item>
<item quantity="other">Poglavlja %1$s i još %2$s</item> <item quantity="other">Poglavlja %1$s i još %2$s</item>
</plurals> </plurals>
@ -726,4 +726,5 @@
<string name="notification_update_skipped">Preskočena aktualiziranja: %1$d</string> <string name="notification_update_skipped">Preskočena aktualiziranja: %1$d</string>
<string name="rotation_reverse_portrait">Preokrenuto uspravno</string> <string name="rotation_reverse_portrait">Preokrenuto uspravno</string>
<string name="action_move_to_top_all_for_series">Pomakni serijal na vrh</string> <string name="action_move_to_top_all_for_series">Pomakni serijal na vrh</string>
<string name="disabled_nav">Deaktivirano</string>
</resources> </resources>

View File

@ -73,7 +73,7 @@
<string name="all">Tutte</string> <string name="all">Tutte</string>
<string name="pref_library_update_restriction">Restrizioni del dispositivo agli aggiornamenti automatici</string> <string name="pref_library_update_restriction">Restrizioni del dispositivo agli aggiornamenti automatici</string>
<string name="charging">In carica</string> <string name="charging">In carica</string>
<string name="pref_update_only_non_completed">È una serie completa</string> <string name="pref_update_only_non_completed">Con stato \"completa\"</string>
<string name="pref_auto_update_manga_sync">Aggiorna il tracking dopo la lettura</string> <string name="pref_auto_update_manga_sync">Aggiorna il tracking dopo la lettura</string>
<string name="pref_start_screen">Schermata iniziale</string> <string name="pref_start_screen">Schermata iniziale</string>
<!-- Reader section --> <!-- Reader section -->
@ -707,7 +707,7 @@
<string name="action_display_language_badge">Lingua</string> <string name="action_display_language_badge">Lingua</string>
<string name="label_warning">Attenzione</string> <string name="label_warning">Attenzione</string>
<string name="backup_info">I backup automatici sono altamente consigliati. Dovresti tenere delle copie anche in altri posti.</string> <string name="backup_info">I backup automatici sono altamente consigliati. Dovresti tenere delle copie anche in altri posti.</string>
<string name="notification_size_warning">Attenzione: grossi aggiornamenti danneggiano le fonti, possono rallentare gli aggiornamenti e aumentare il consumo di batteria</string> <string name="notification_size_warning">Grossi aggiornamenti danneggiano le fonti, possono rallentare gli aggiornamenti e aumentare il consumo di batteria</string>
<string name="connected_to_wifi">Solo su Wi-Fi</string> <string name="connected_to_wifi">Solo su Wi-Fi</string>
<string name="update_72hour">Ogni 3 giorni</string> <string name="update_72hour">Ogni 3 giorni</string>
<string name="download_queue_size_warning">Attenzione: grossi download di massa possono rallentare le fonti e/o bloccare tachiyomi</string> <string name="download_queue_size_warning">Attenzione: grossi download di massa possono rallentare le fonti e/o bloccare tachiyomi</string>
@ -719,8 +719,8 @@
<string name="database_clean">Database pulito</string> <string name="database_clean">Database pulito</string>
<string name="extension_api_error">Impossibile ottenere l\'elenco estensioni</string> <string name="extension_api_error">Impossibile ottenere l\'elenco estensioni</string>
<string name="privacy_policy">Politica sulla privacy</string> <string name="privacy_policy">Politica sulla privacy</string>
<string name="pref_update_only_completely_read">Ha capitoli non letti</string> <string name="pref_update_only_completely_read">Con capitoli non letti</string>
<string name="pref_library_update_manga_restriction">Salta l\'aggiornamento</string> <string name="pref_library_update_manga_restriction">Salta l\'aggiornamento di serie</string>
<string name="library_errors_help">Per un aiuto su come risolvere gli errori di aggiornamento della libreria vedi %1$s</string> <string name="library_errors_help">Per un aiuto su come risolvere gli errori di aggiornamento della libreria vedi %1$s</string>
<string name="save_chapter_as_cbz">Salva come archivio CBZ</string> <string name="save_chapter_as_cbz">Salva come archivio CBZ</string>
<string name="cancelled">Cancellata</string> <string name="cancelled">Cancellata</string>
@ -737,15 +737,17 @@
\nVuoi comunque continuare\?</string> \nVuoi comunque continuare\?</string>
<string name="action_display_cover_only_grid">Griglia con solo copertine</string> <string name="action_display_cover_only_grid">Griglia con solo copertine</string>
<string name="action_filter_started">Iniziati</string> <string name="action_filter_started">Iniziati</string>
<string name="pref_update_only_started">Nessun capitolo letto</string> <string name="pref_update_only_started">Che non sono state iniziate</string>
<string name="skipped_reason_completed">Saltato perché la serie è completa</string> <string name="skipped_reason_completed">Saltato perché la serie è completa</string>
<string name="skipped_reason_not_caught_up">Saltato perché ci sono capitoli non letti</string> <string name="skipped_reason_not_caught_up">Saltato perché ci sono capitoli non letti</string>
<string name="skipped_reason_not_started">Saltato perché non ci sono capitoli letti</string> <string name="skipped_reason_not_started">Saltato perché non ci sono capitoli letti</string>
<string name="channel_skipped">Saltato</string> <string name="channel_skipped">Saltato</string>
<string name="notification_update_error">%1$d aggiornamento(i) fallito(i)</string> <string name="notification_update_error">%1$d aggiornamento(i) fallito(i)</string>
<string name="notification_update_skipped">%1$d aggiornamento(i) saltato(i)</string> <string name="notification_update_skipped">%1$d aggiornamento(i) saltato(i)</string>
<string name="learn_more">Approfondisci</string> <string name="learn_more">Tocca per approfondire</string>
<string name="rotation_reverse_portrait">Verticale inverso</string> <string name="rotation_reverse_portrait">Verticale inverso</string>
<string name="action_move_to_top_all_for_series">Sposta la serie in cima</string> <string name="action_move_to_top_all_for_series">Sposta la serie in cima</string>
<string name="disabled_nav">Disattivato</string> <string name="disabled_nav">Disattivato</string>
<string name="update_check_fdroid_migration_info">C\'è una nuova versione ufficiale disponibile. Tocca per imparare a migrare dalle release non ufficiali di F-droid.</string>
<string name="error_saving_picture">Errore durante il salvataggio dell\'immagine</string>
</resources> </resources>

View File

@ -702,4 +702,5 @@
<string name="notification_update_error">%1$d件の更新に失敗しました</string> <string name="notification_update_error">%1$d件の更新に失敗しました</string>
<string name="rotation_reverse_portrait">縦向き(反転)</string> <string name="rotation_reverse_portrait">縦向き(反転)</string>
<string name="action_move_to_top_all_for_series">シリーズをトップに移動</string> <string name="action_move_to_top_all_for_series">シリーズをトップに移動</string>
<string name="disabled_nav">無効</string>
</resources> </resources>

View File

@ -12,8 +12,8 @@
<string name="action_filter_bookmarked">북마크됨</string> <string name="action_filter_bookmarked">북마크됨</string>
<string name="action_filter_unread">읽지 않음</string> <string name="action_filter_unread">읽지 않음</string>
<string name="action_filter_empty">필터 제거</string> <string name="action_filter_empty">필터 제거</string>
<string name="action_sort_alpha">알파벳 순으로</string> <string name="action_sort_alpha">알파벳 순</string>
<string name="action_sort_last_read">읽은 순으로</string> <string name="action_sort_last_read">마지막으로 읽은 순</string>
<string name="action_search">검색</string> <string name="action_search">검색</string>
<string name="action_select_all">전체 선택</string> <string name="action_select_all">전체 선택</string>
<string name="action_mark_as_read">읽음으로 표시</string> <string name="action_mark_as_read">읽음으로 표시</string>
@ -34,10 +34,10 @@
<string name="action_edit_cover">표지 수정</string> <string name="action_edit_cover">표지 수정</string>
<string name="action_stop">정지</string> <string name="action_stop">정지</string>
<string name="action_remove">제거</string> <string name="action_remove">제거</string>
<string name="action_resume">계속 읽기</string> <string name="action_resume">계속</string>
<string name="action_open_in_browser">브라우저에서 열기</string> <string name="action_open_in_browser">브라우저에서 열기</string>
<string name="action_display_mode">타이틀 표시 변경</string> <string name="action_display_mode">타이틀 표시 변경</string>
<string name="action_display_grid">그리드</string> <string name="action_display_grid">작은 그리드</string>
<string name="action_display_list">리스트</string> <string name="action_display_list">리스트</string>
<string name="action_cancel">취소</string> <string name="action_cancel">취소</string>
<string name="action_sort">정렬</string> <string name="action_sort">정렬</string>
@ -49,7 +49,7 @@
<string name="label_library">서재</string> <string name="label_library">서재</string>
<string name="label_recent_manga">기록</string> <string name="label_recent_manga">기록</string>
<string name="label_recent_updates">업데이트</string> <string name="label_recent_updates">업데이트</string>
<string name="action_sort_total">모든 회차</string> <string name="action_sort_total">회차의 수 순</string>
<string name="action_previous_chapter">이전 화</string> <string name="action_previous_chapter">이전 화</string>
<string name="action_next_chapter">다음 화</string> <string name="action_next_chapter">다음 화</string>
<string name="action_retry">재시도</string> <string name="action_retry">재시도</string>
@ -77,14 +77,14 @@
<string name="portrait">세로</string> <string name="portrait">세로</string>
<string name="landscape">가로</string> <string name="landscape">가로</string>
<string name="pref_library_update_interval">자동 업데이트</string> <string name="pref_library_update_interval">자동 업데이트</string>
<string name="update_never">수동</string> <string name="update_never">끄기</string>
<string name="update_6hour">6시간</string> <string name="update_6hour">6시간</string>
<string name="update_12hour">12시간</string> <string name="update_12hour">12시간</string>
<string name="update_24hour">1일</string> <string name="update_24hour">1일</string>
<string name="update_48hour">2일</string> <string name="update_48hour">2일</string>
<string name="update_weekly">1주</string> <string name="update_weekly">1주</string>
<string name="all">전부</string> <string name="all">전부</string>
<string name="pref_library_update_restriction">서재 업데이트 제한</string> <string name="pref_library_update_restriction">자동 업데이트 조건</string>
<string name="charging">충전중</string> <string name="charging">충전중</string>
<string name="pref_start_screen">시작 화면</string> <string name="pref_start_screen">시작 화면</string>
<string name="default_category">기본 카테고리</string> <string name="default_category">기본 카테고리</string>
@ -146,9 +146,9 @@
<string name="pref_restore_backup">백업 복원</string> <string name="pref_restore_backup">백업 복원</string>
<string name="pref_restore_backup_summ">백업 파일에서 서재 복원</string> <string name="pref_restore_backup_summ">백업 파일에서 서재 복원</string>
<string name="pref_backup_directory">백업 위치</string> <string name="pref_backup_directory">백업 위치</string>
<string name="pref_backup_service_category">서비스</string> <string name="pref_backup_service_category">자동 백업</string>
<string name="pref_backup_interval">백업 주기</string> <string name="pref_backup_interval">백업 주기</string>
<string name="pref_backup_slots">최대 자동 백업</string> <string name="pref_backup_slots">최대 백업</string>
<string name="backup_created">백업 생성됨</string> <string name="backup_created">백업 생성됨</string>
<string name="restore_completed">복원 완료</string> <string name="restore_completed">복원 완료</string>
<string name="restoring_backup">백업 복원중</string> <string name="restoring_backup">백업 복원중</string>
@ -162,7 +162,7 @@
<string name="pref_clear_database">데이터베이스 삭제</string> <string name="pref_clear_database">데이터베이스 삭제</string>
<string name="pref_clear_database_summary">서재에 추가되지 않은 만화의 기록을 삭제합니다</string> <string name="pref_clear_database_summary">서재에 추가되지 않은 만화의 기록을 삭제합니다</string>
<string name="clear_database_confirmation">확실합니까\? 서재에 없는 만화의 읽은 기록이 삭제됩니다</string> <string name="clear_database_confirmation">확실합니까\? 서재에 없는 만화의 읽은 기록이 삭제됩니다</string>
<string name="pref_refresh_library_tracking">동기화 메타데이터 새로 고침</string> <string name="pref_refresh_library_tracking">트래커 동기화 새로고침</string>
<string name="pref_refresh_library_tracking_summary">상태 및 평점, 마지막으로 읽은 회차를 동기화 서비스로부터 업데이트합니다</string> <string name="pref_refresh_library_tracking_summary">상태 및 평점, 마지막으로 읽은 회차를 동기화 서비스로부터 업데이트합니다</string>
<string name="version">버전</string> <string name="version">버전</string>
<string name="pref_enable_acra">오류 보고서 전송</string> <string name="pref_enable_acra">오류 보고서 전송</string>
@ -219,7 +219,7 @@
<string name="chapter_progress">페이지: %1$d</string> <string name="chapter_progress">페이지: %1$d</string>
<string name="no_next_chapter">다음 화가 없습니다</string> <string name="no_next_chapter">다음 화가 없습니다</string>
<string name="no_previous_chapter">이전 화가 없습니다</string> <string name="no_previous_chapter">이전 화가 없습니다</string>
<string name="decode_image_error">이미지를 디코드 할 수 없습니다</string> <string name="decode_image_error">이미지를 로드할 수 없습니다</string>
<string name="confirm_set_image_as_cover">이 이미지를 표지로 사용합니까\?</string> <string name="confirm_set_image_as_cover">이 이미지를 표지로 사용합니까\?</string>
<string name="transition_finished">완료:</string> <string name="transition_finished">완료:</string>
<string name="transition_current">현재:</string> <string name="transition_current">현재:</string>
@ -250,7 +250,7 @@
<string name="download_notifier_unknown_error">다운로드 중에 예기치 않은 오류가 발생하였습니다</string> <string name="download_notifier_unknown_error">다운로드 중에 예기치 않은 오류가 발생하였습니다</string>
<string name="download_notifier_download_paused">다운로드 일시중지됨</string> <string name="download_notifier_download_paused">다운로드 일시중지됨</string>
<string name="action_display_download_badge">다운로드된 회차</string> <string name="action_display_download_badge">다운로드된 회차</string>
<string name="pref_update_only_non_completed">연재 중인 만화만 업데이트</string> <string name="pref_update_only_non_completed">연재가 끝남</string>
<string name="pref_auto_update_manga_sync">읽은 기록 동기화</string> <string name="pref_auto_update_manga_sync">읽은 기록 동기화</string>
<string name="default_category_summary">항상 물어보기</string> <string name="default_category_summary">항상 물어보기</string>
<string name="pref_create_backup_summ">현재 서재를 나중에 복구하는 데 사용 가능</string> <string name="pref_create_backup_summ">현재 서재를 나중에 복구하는 데 사용 가능</string>
@ -286,7 +286,7 @@
<string name="licensed">판권작</string> <string name="licensed">판권작</string>
<string name="copied_to_clipboard">클립보드에 복사됨: <string name="copied_to_clipboard">클립보드에 복사됨:
\n%1$s</string> \n%1$s</string>
<string name="show_title">제목 표시</string> <string name="show_title">소스 제목</string>
<string name="custom_download">다운로드 할 회차 직접 입력</string> <string name="custom_download">다운로드 할 회차 직접 입력</string>
<string name="download_custom">사용자 정의</string> <string name="download_custom">사용자 정의</string>
<string name="reading">읽는 중</string> <string name="reading">읽는 중</string>
@ -308,7 +308,7 @@
<string name="download_notifier_text_only_wifi">Wi-Fi 연결 사용 불가능</string> <string name="download_notifier_text_only_wifi">Wi-Fi 연결 사용 불가능</string>
<string name="download_notifier_no_network">네트워크 연결 사용 불가능</string> <string name="download_notifier_no_network">네트워크 연결 사용 불가능</string>
<string name="channel_common">일반</string> <string name="channel_common">일반</string>
<string name="pref_read_with_long_tap">길게 눌러 대화상자 표시</string> <string name="pref_read_with_long_tap">길게 눌러 표시</string>
<string name="action_open_in_web_view">WebView로 열기</string> <string name="action_open_in_web_view">WebView로 열기</string>
<string name="pref_true_color">32비트 컬러</string> <string name="pref_true_color">32비트 컬러</string>
<string name="pref_skip_read_chapters">읽음 표시된 회차 건너뛰기</string> <string name="pref_skip_read_chapters">읽음 표시된 회차 건너뛰기</string>
@ -339,7 +339,7 @@
<string name="logout">로그아웃</string> <string name="logout">로그아웃</string>
<string name="logout_title">%1$s 에서 로그아웃 하시겠습니까\?</string> <string name="logout_title">%1$s 에서 로그아웃 하시겠습니까\?</string>
<plurals name="download_queue_summary"> <plurals name="download_queue_summary">
<item quantity="other">%1$s 개 남았습니다</item> <item quantity="other">%1$s 개 남</item>
</plurals> </plurals>
<string name="notification_incognito_text">시크릿 모드 끄기</string> <string name="notification_incognito_text">시크릿 모드 끄기</string>
<string name="label_downloaded_only">다운로드가 완료된 항목만 표시</string> <string name="label_downloaded_only">다운로드가 완료된 항목만 표시</string>
@ -349,10 +349,10 @@
<string name="licenses">오픈 소스 라이센스</string> <string name="licenses">오픈 소스 라이센스</string>
<string name="battery_optimization_setting_activity_not_found">디바이스 설정을 열 수 없습니다</string> <string name="battery_optimization_setting_activity_not_found">디바이스 설정을 열 수 없습니다</string>
<string name="pref_disable_battery_optimization">배터리 최적화 끄기</string> <string name="pref_disable_battery_optimization">배터리 최적화 끄기</string>
<string name="restore_miui_warning">MIUI 최적화가 꺼져 있을 경우 백업/복원 기능 정상 작동하지 않을 수 있습니다.</string> <string name="restore_miui_warning">MIUI 최적화가 꺼져 있을 경우 백업/복원 기능 정상 작동하지 않을 수 있습니다.</string>
<string name="restore_in_progress">복원이 이미 진행중 입니다</string> <string name="restore_in_progress">복원이 이미 진행중 입니다</string>
<string name="requires_app_restart">설정을 적용하기 위해 앱을 재시작해야 합니다</string> <string name="requires_app_restart">설정을 적용하기 위해 앱을 재시작해야 합니다</string>
<string name="pref_dns_over_https">DNS over HTTPS</string> <string name="pref_dns_over_https">DNS over HTTPS (DoH)</string>
<string name="label_data">데이터</string> <string name="label_data">데이터</string>
<string name="backup_in_progress">백업이 이미 진행중입니다</string> <string name="backup_in_progress">백업이 이미 진행중입니다</string>
<string name="restoring_backup_error">백업 복원 실패</string> <string name="restoring_backup_error">백업 복원 실패</string>
@ -392,8 +392,8 @@
<string name="label_default">기본값</string> <string name="label_default">기본값</string>
<string name="action_select_inverse">선택 반전</string> <string name="action_select_inverse">선택 반전</string>
<string name="action_search_settings">검색 설정</string> <string name="action_search_settings">검색 설정</string>
<string name="action_sort_date_added">추가된 날짜</string> <string name="action_sort_date_added">서재에 추가된 시간 순</string>
<string name="action_sort_latest_chapter">최신 화</string> <string name="action_sort_latest_chapter">최신 화 업로드 순</string>
<string name="l_nav">L자 모양</string> <string name="l_nav">L자 모양</string>
<string name="pref_read_with_tapping_inverted">터치 반전</string> <string name="pref_read_with_tapping_inverted">터치 반전</string>
<string name="tapping_inverted_none">없음</string> <string name="tapping_inverted_none">없음</string>
@ -500,4 +500,207 @@
<string name="channel_app_updates">앱 업데이트</string> <string name="channel_app_updates">앱 업데이트</string>
<string name="channel_progress">진행 상황</string> <string name="channel_progress">진행 상황</string>
<string name="channel_errors">오류</string> <string name="channel_errors">오류</string>
<string name="database_clean">데이터베이스 정리</string>
<string name="learn_more">터치하여 자세히 알아보기</string>
<string name="chapter_settings_updated">기본 회차 설정을 업데이트 했습니다</string>
<string name="channel_skipped">건너뜀</string>
<string name="channel_new_chapters">회차 업데이트</string>
<string name="pref_jump_to_chapters">시작 시 회차 표시</string>
<string name="include">포함: %s</string>
<string name="label_background_activity">백그라운드 활동</string>
<string name="pref_update_only_completely_read">안 읽은 회차가 있음</string>
<string name="categorized_display_settings">카테고리 별 표시/정렬 설정</string>
<string name="ext_installer_shizuku_unavailable_dialog">Shizuku를 확장기능 인스톨러로 사용하려면 Shizuku를 먼저 설치해 주세요.</string>
<string name="ext_update_all">전부 업데이트</string>
<string name="backup_restore_invalid_uri">에러: 빈 URI</string>
<string name="invalid_backup_file_missing_manga">백업에 만화가 포함되어있지 않습니다.</string>
<string name="pref_dump_crash_logs_summary">개발자와 공유할 수 있는 오류 로그 파일을 생성합니다</string>
<string name="crash_log_saved">오류 로그가 저장되었습니다</string>
<string name="privacy_policy">개인정보 보호 정책</string>
<string name="share_page_info">%1$s: %2$s, %3$d페이지</string>
<string name="clear_history_confirmation">계속하시겠습니까\? 모든 기록이 삭제됩니다.</string>
<string name="disabled_nav">비활성화</string>
<string name="invalid_backup_file_missing_data">파일에 필요한 데이터가 포함되어있지 않습니다.</string>
<string name="backup_restore_missing_sources">없어진 소스:</string>
<string name="backup_restore_missing_trackers">로그인 되지않은 트래커:</string>
<string name="pref_auto_clear_chapter_cache">앱 종료 시 회차 캐시 삭제</string>
<string name="clear_database_source_item_count">데이터베이스에 없는 만화가 %1$d개 있습니다</string>
<string name="about_dont_kill_my_app">일부 제조사는 백그라운드 서비스를 종료하는 추가적인 제한 사항이 있습니다. 자세한 사항은 웹사이트를 참조하세요.</string>
<string name="pref_tablet_ui_mode">태블릿 UI</string>
<string name="tabs_header"></string>
<string name="http_error_hint">WebView에서 사이트 열기</string>
<string name="pinned_sources">핀 설정됨</string>
<string name="action_global_search_query">\"%1$s\"를 전역 검색합니다</string>
<string name="local_source_help_guide">로컬 저장소 사용법</string>
<string name="no_pinned_sources">핀 설정된 소스가 없습니다</string>
<string name="local_invalid_format">잘못된 회차 포맷</string>
<string name="unknown_status">알 수 없는 상태</string>
<string name="on_hiatus">휴재중</string>
<string name="manga_info_expand">상세정보 표시</string>
<string name="manga_info_collapse">상세정보 숨김</string>
<string name="clipboard_copy_error">클립보드로 복사에 실패하였습니다</string>
<string name="tracker_komga_warning">이 트래커는 Komga 소스에만 호환됩니다.</string>
<plurals name="num_trackers">
<item quantity="other">%d개의 트래커</item>
</plurals>
<string name="add_tracking">트래커 추가</string>
<string name="paused">일시정지</string>
<string name="error_invalid_date_supplied">잘못된 날짜입니다</string>
<string name="myanimelist_relogin">MAL에 다시 로그인해 주세요</string>
<string name="loader_not_implemented_error">소스를 찾을 수 없습니다</string>
<string name="page_list_empty_error">페이지를 찾을 수 없습니다</string>
<plurals name="missing_chapters_warning">
<item quantity="other">소스에 존재하지 않거나 필터링되어 있는 %d개의 회차를 건너뛰었습니다</item>
</plurals>
<string name="pref_clear_history">내역 삭제</string>
<string name="clear_history_completed">기록이 삭제되었습니다</string>
<string name="download_insufficient_space">저장 공간이 부족하여 회차를 다운로드 할 수 없습니다</string>
<string name="download_queue_size_warning">경고: 한꺼번에 많은 양을 다운로드 할 경우 소스가 느려지거나 Tachiyomi를 차단할 수 있습니다</string>
<string name="notification_check_updates">새로운 회차 확인 중</string>
<string name="notification_size_warning">경고: 대량의 업데이트는 소스에 과도한 부하를 줄 수 있고 배터리 사용량을 증가시킵니다</string>
<string name="notification_chapters_single">%1$s화</string>
<string name="notification_update_error">%1$d개의 업데이트가 실패했습니다</string>
<string name="notification_update_skipped">%1$d개의 업데이트를 건너 뛰었습니다</string>
<string name="library_errors_help">서재 업데이트 오류를 해결하려면 %1$s를 참조하세요</string>
<string name="skipped_reason_completed">완결된 만화를 건너 뛰었습니다</string>
<string name="skipped_reason_not_started">읽지 않은 만화를 건너 뛰었습니다</string>
<string name="update_check_eol">이 안드로이드 버젼은 더이상 지원되지 않습니다</string>
<plurals name="update_check_notification_ext_updates">
<item quantity="other">%d개의 확장기능 업데이트가 있습니다</item>
</plurals>
<string name="information_cloudflare_bypass_failure">Cloudflare를 통과하지 못했습니다</string>
<string name="information_webview_required">Tachiyomi를 사용하려면 WebView가 필요합니다</string>
<string name="information_webview_outdated">호환성을 위해 WebView 어플리케이션을 업데이트 해 주세요</string>
<string name="pref_navigate_pan">페이지 내 이동</string>
<string name="obsolete_extension_message">이 확장기능은 더이상 이용이 불가능합니다.</string>
<string name="ext_install_service_notif">확장기능 설치 중…</string>
<string name="ext_installer_legacy">레거시</string>
<string name="webtoon_side_padding_10">10%</string>
<string name="action_track">트래킹</string>
<string name="pref_refresh_library_covers">서재 만화 표지 새로고침</string>
<string name="pref_dump_crash_logs">오류 로그 덤프</string>
<string name="chapter_not_found">회차를 찾을 수 없습니다</string>
<string name="error_no_match">결과가 없습니다</string>
<string name="channel_crash_logs">오류 로그</string>
<string name="ext_nsfw_warning">19금 콘텐츠가 포함될 수 있습니다</string>
<string name="action_filter_tracked">트래커 사용</string>
<string name="action_start">시작</string>
<string name="source_not_found_name">소스 %1$s를 찾을 수 없습니다</string>
<string name="action_start_downloading_now">지금 다운로드 시작</string>
<string name="ext_installer_pref">인스톨러</string>
<string name="ext_installer_shizuku_stopped">Shizuku가 실행 중이 아닙니다</string>
<string name="manga_from_library">서재의 만화</string>
<string name="downloaded_chapters">다운로드된 회차</string>
<string name="publishing_finished">완결됨</string>
<string name="confirm_manga_add_duplicate">서재에 제목이 같지만 소스가 다른 항목이 있습니다 (%1$s).
\n
\n계속하시겠습니까\?</string>
<string name="unread">읽지 않음</string>
<string name="cancelled">취소됨</string>
<string name="no_chapters_error">검색된 회차가 없습니다</string>
<string name="source_unsupported">지원되지 않는 소스입니다</string>
<string name="download_notifier_download_finish">다운로드 완료</string>
<string name="spen_previous_page">이전 페이지</string>
<string name="action_show_manga">만화 보기</string>
<string name="action_desc">내림차순</string>
<string name="theme_monet">활력</string>
<string name="action_display_cover_only_grid">표지 그리드</string>
<string name="action_reorganize_by">재정렬</string>
<string name="action_newest">최신 순</string>
<string name="pref_category_theme">테마</string>
<string name="theme_midnightdusk">한밤중의 어둠</string>
<string name="ext_obsolete">지원 종료</string>
<string name="tracker_not_logged_in">로그인 불가: %1$s</string>
<string name="no_results_found">검색 결과가 없습니다</string>
<string name="pref_dual_page_invert_summary">이중 페이지 분할 시 배치가 읽는 방향과 다를 경우 사용하세요</string>
<string name="ext_nsfw_short">19금</string>
<string name="action_filter_started">읽는 중</string>
<string name="action_display_show_tabs">카테고리 탭 보이기</string>
<string name="action_sort_chapter_fetch_date">정보가 갱신된 시간 순</string>
<string name="action_sort_count">만화의 총 개수</string>
<string name="action_webview_back">뒤로가기</string>
<string name="battery_optimization_disabled">배터리 최적화가 이미 꺼져 있습니다</string>
<string name="action_order_by_chapter_number">회차 번호 순</string>
<string name="action_move_to_top">맨 위로 이동</string>
<string name="action_sort_last_checked">마지막으로 확인한 순</string>
<string name="action_order_by_upload_date">업로드 날짜 순</string>
<string name="action_move_to_bottom">맨 아래로 이동</string>
<string name="action_asc">오름차순</string>
<string name="action_oldest">오래된 순</string>
<string name="theme_tealturquoise">옥색</string>
<string name="recently">최근</string>
<string name="theme_strawberrydaiquiri">딸기 칵테일</string>
<string name="extension_api_error">확장기능 목록 취득 실패</string>
<string name="pref_library_update_refresh_trackers_summary">서재 업데이트 시 트래커 갱신</string>
<string name="exclude">제외: %s</string>
<string name="unofficial_extension_message">이 확장기능은 공식 확장기능이 아닙니다.</string>
<string name="tracking_info">트래커 서비스에 만화 진행 상황을 동기화합니다. 트래킹 버튼을 이용하여 각각의 만화 별로 트래킹을 설정하세요.</string>
<string name="webtoon_side_padding_20">20%</string>
<string name="webtoon_side_padding_25">25%</string>
<string name="tracking_guide">트래커 가이드</string>
<string name="enhanced_services">향상된 서비스</string>
<string name="webtoon_side_padding_5">5%</string>
<string name="webtoon_side_padding_15">15%</string>
<string name="pref_download_new_categories_details">카테고리가 다운로드에서 제외된 경우 다른 카테고리에 포함되어 있어도 다운로드 되지 않습니다.</string>
<string name="enhanced_tracking_info">특정 소스에 향상된 서비스를 제공합니다. 서재에 만화가 추가될 시 자동으로 트래킹 됩니다.</string>
<string name="pref_search_pinned_sources_only">핀 설정된 소스만 포함</string>
<string name="backup_restore_content_full">백업 파일에서 데이터가 복구됩니다.
\n
\n복구 완료 후 없어진 소스를 다시 설치하고 트래킹 서비스에 로그인 해야 합니다.</string>
<string name="backup_info">자동 백업이 매우 권장됩니다. 백업 파일은 다른 장소에 나눠 보관하세요.</string>
<string name="pref_disable_battery_optimization_summary">백그라운드 서재 업데이트와 라이브러리 업데이트를 도울 수 있습니다</string>
<string name="pref_verbose_logging">자세한 로그</string>
<string name="pref_verbose_logging_summary">자세한 로그를 시스템 로그에 기록 (성능이 하락할 수 있습니다)</string>
<string name="badges_header">배지</string>
<string name="date">날짜</string>
<string name="local_filter_order_by">정렬</string>
<string name="track_started_reading_date">읽기 시작한 날짜</string>
<string name="track_finished_reading_date">다 읽은 날짜</string>
<plurals name="notification_new_chapters_summary">
<item quantity="other">%d개의 만화</item>
</plurals>
<plurals name="notification_chapters_generic">
<item quantity="other">%1$d개의 새로운 회차</item>
</plurals>
<string name="skipped_reason_not_caught_up">읽지 않은 회차가 있는 만화를 건너 뛰었습니다</string>
<string name="information_empty_category_dialog">등록된 카테고리가 없습니다.</string>
<string name="pref_create_folder_per_manga_summary">만화 제목에 따라 폴더 생성</string>
<string name="migration_help_guide">소스 이전 설명서</string>
<string name="migration_selection_prompt">원본 소스를 선택하세요</string>
<string name="action_display_local_badge">로컬 만화</string>
<string name="action_display_show_number_of_items">항목 수 보이기</string>
<string name="action_disable">끄기</string>
<string name="action_pin"></string>
<string name="action_unpin">핀 해제</string>
<string name="action_cancel_all">모두 취소</string>
<string name="cancel_all_for_series">이 만화의 항목을 모두 취소</string>
<string name="action_webview_forward">앞으로가기</string>
<string name="pref_create_folder_per_manga">각각의 폴더에 페이지 저장</string>
<string name="action_faq_and_guides">FAQ와 설명서</string>
<string name="pref_update_only_started">읽은 회차 없음</string>
<string name="action_move_to_top_all_for_series">만화 전체를 맨 위로 이동</string>
<string name="action_webview_refresh">새로고침</string>
<string name="theme_greenapple">초록 사과</string>
<string name="theme_tako">문어</string>
<string name="theme_yinyang">음과 양</string>
<string name="theme_yotsuba">요츠바</string>
<string name="pref_side_nav_icon_alignment">네비게이션 아이콘 정렬</string>
<string name="alignment_top"></string>
<string name="alignment_center">중앙</string>
<string name="alignment_bottom">아래</string>
<string name="pref_category_nsfw_content">19금 소스</string>
<string name="pref_show_nsfw_source">소스 또는 확장기능 목록에 보이기</string>
<string name="parental_controls_info">오류 또는 잘못된 분류로 인하여 19금 콘텐츠가 표시될 가능성이 있습니다.</string>
<string name="action_show_errors">터치하여 자세히 보기</string>
<string name="update_72hour">3일</string>
<string name="restrictions">제한: %s</string>
<string name="pref_library_update_categories_details">카테고리가 업데이트에서 제외된 경우 다른 카테고리에 포함되어 있어도 업데이트 되지 않습니다.</string>
<string name="ext_updates_pending">업데이트 대기 중</string>
<string name="pref_library_update_refresh_metadata_summary">서재 업데이트 시 새로운 표지와 설명 확인</string>
<string name="notification_chapters_single_and_more">%1$s화와 그 이후 %2$d화</string>
<string name="notification_chapters_multiple">%1$s화</string>
<plurals name="notification_chapters_multiple_and_more">
<item quantity="other">%1$s화와 그 이후 %2$d화</item>
</plurals>
<string name="file_picker_error">파일 선택 어플리케이션이 없습니다</string>
</resources> </resources>

View File

@ -83,7 +83,7 @@
<string name="all">Semua</string> <string name="all">Semua</string>
<string name="pref_library_update_restriction">Sekatan kemas kini automatik peranti</string> <string name="pref_library_update_restriction">Sekatan kemas kini automatik peranti</string>
<string name="charging">Ketika mengecas</string> <string name="charging">Ketika mengecas</string>
<string name="pref_update_only_non_completed">Siri sudah selesai</string> <string name="pref_update_only_non_completed">Dengan status \"Sudah selesai\"</string>
<string name="pref_auto_update_manga_sync">Kemas kini selepas dibaca</string> <string name="pref_auto_update_manga_sync">Kemas kini selepas dibaca</string>
<string name="pref_start_screen">Skrin permulaan</string> <string name="pref_start_screen">Skrin permulaan</string>
<string name="default_category">Kategori lalai</string> <string name="default_category">Kategori lalai</string>
@ -674,8 +674,8 @@
<string name="clear_database_source_item_count">%1$d manga bukan pustaka dalam pangkalan data</string> <string name="clear_database_source_item_count">%1$d manga bukan pustaka dalam pangkalan data</string>
<string name="extension_api_error">Gagal mendapatkan senarai sambungan</string> <string name="extension_api_error">Gagal mendapatkan senarai sambungan</string>
<string name="privacy_policy">Dasar privasi</string> <string name="privacy_policy">Dasar privasi</string>
<string name="pref_library_update_manga_restriction">Langkau mengemaskini</string> <string name="pref_library_update_manga_restriction">Langkau mengemaskini siri</string>
<string name="pref_update_only_completely_read">Ada bab yang belum dibaca</string> <string name="pref_update_only_completely_read">Dengan bab yang belum dibaca</string>
<string name="library_errors_help">Untuk bantuan cara menyelesaikan ralat kemas kini pustaka, lihat %1$s</string> <string name="library_errors_help">Untuk bantuan cara menyelesaikan ralat kemas kini pustaka, lihat %1$s</string>
<string name="save_chapter_as_cbz">Simpan sebagai arkib CBZ</string> <string name="save_chapter_as_cbz">Simpan sebagai arkib CBZ</string>
<string name="cancelled">Dibatalkan</string> <string name="cancelled">Dibatalkan</string>
@ -691,7 +691,7 @@
\nAdakah anda masih ingin meneruskan\?</string> \nAdakah anda masih ingin meneruskan\?</string>
<string name="action_display_cover_only_grid">Cuma grid muka hadapan</string> <string name="action_display_cover_only_grid">Cuma grid muka hadapan</string>
<string name="skipped_reason_completed">Dilangkau kerana siri sudah lengkap</string> <string name="skipped_reason_completed">Dilangkau kerana siri sudah lengkap</string>
<string name="pref_update_only_started">Tiada bab dibaca</string> <string name="pref_update_only_started">Yang mana bacaan belum dimulakan</string>
<string name="skipped_reason_not_caught_up">Dilangkau kerana ada bab yang belum dibaca</string> <string name="skipped_reason_not_caught_up">Dilangkau kerana ada bab yang belum dibaca</string>
<string name="skipped_reason_not_started">Dilangkau kerana masih belum membaca mana-mana bab</string> <string name="skipped_reason_not_started">Dilangkau kerana masih belum membaca mana-mana bab</string>
<string name="pref_landscape_zoom">Zum imej landskap</string> <string name="pref_landscape_zoom">Zum imej landskap</string>
@ -699,7 +699,10 @@
<string name="notification_update_error">%1$d kemas kini gagal</string> <string name="notification_update_error">%1$d kemas kini gagal</string>
<string name="notification_update_skipped">%1$d kemas kini dilangkau</string> <string name="notification_update_skipped">%1$d kemas kini dilangkau</string>
<string name="channel_skipped">Dilangkau</string> <string name="channel_skipped">Dilangkau</string>
<string name="learn_more">Ketahui selebihnya</string> <string name="learn_more">Ketik untuk ketahui selebihnya</string>
<string name="rotation_reverse_portrait">Potret terbalik</string> <string name="rotation_reverse_portrait">Potret terbalik</string>
<string name="action_move_to_top_all_for_series">Alih siri ke atas</string> <string name="action_move_to_top_all_for_series">Alih siri ke atas</string>
<string name="disabled_nav">Dinyahkan</string>
<string name="error_saving_picture">Ralat menyimpan gambar</string>
<string name="update_check_fdroid_migration_info">Versi baharu tersedia daripada pengeluaran rasmi. Ketik untuk mengetahui bagaimana untuk berhijrah daripada keluaran tidak rasmi F-Droid.</string>
</resources> </resources>

View File

@ -711,7 +711,8 @@
<string name="pref_auto_clear_chapter_cache">Tøm kapittelbufferen ved lukking av appen</string> <string name="pref_auto_clear_chapter_cache">Tøm kapittelbufferen ved lukking av appen</string>
<string name="notification_update_error">%1$d oppdatering(er) mislyktes</string> <string name="notification_update_error">%1$d oppdatering(er) mislyktes</string>
<string name="notification_update_skipped">%1$d oppdatering(er) hoppet over</string> <string name="notification_update_skipped">%1$d oppdatering(er) hoppet over</string>
<string name="learn_more">Lær mer</string> <string name="learn_more">Trykk for å finne ut mer</string>
<string name="skipped_reason_not_started">Hoppet over fordi ingen kapitler er lest</string> <string name="skipped_reason_not_started">Hoppet over fordi ingen kapitler er lest</string>
<string name="channel_skipped">Hoppet over</string> <string name="channel_skipped">Hoppet over</string>
<string name="disabled_nav">Deaktivert</string>
</resources> </resources>

View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Colors for Lavender theme
~
~ Color scheme by Osyx
~
~ Key colors:
~ Primary #A177FF
~ Secondary #A177FF
~ Tertiary #5E25E1
~ Neutral #111129
-->
<resources>
<color name="lavender_primary">#A177FF</color>
<color name="lavender_onPrimary">#111129</color>
<color name="lavender_primaryContainer">#A177FF</color>
<color name="lavender_onPrimaryContainer">#111129</color>
<color name="lavender_secondary">#A177FF</color>
<color name="lavender_onSecondary">#111129</color>
<color name="lavender_secondaryContainer">#A177FF</color>
<color name="lavender_onSecondaryContainer">#111129</color>
<color name="lavender_tertiary">#5E25E1</color>
<color name="lavender_onTertiary">#E8E8E8</color>
<color name="lavender_tertiaryContainer">#111129</color>
<color name="lavender_onTertiaryContainer">#DEE8FF</color>
<color name="lavender_background">#111129</color>
<color name="lavender_onBackground">#DEE8FF</color>
<color name="lavender_surface">#111129</color>
<color name="lavender_onSurface">#DEE8FF</color>
<color name="lavender_surfaceVariant">#2CB6B6B6</color>
<color name="lavender_onSurfaceVariant">#E8E8E8</color>
<color name="lavender_outline">#A8905FFF</color>
<color name="lavender_inverseOnSurface">#DEE8FF</color>
<color name="lavender_inverseSurface">#221247</color>
<color name="lavender_primaryInverse">#A177FF</color>
<color name="lavender_elevationOverlay">@color/lavender_primary</color>
</resources>

View File

@ -1,2 +1,83 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources></resources> <resources>
<string name="download_notifier_title_error">ତ୍ରୁଟି</string>
<string name="date">ତାରିଖ</string>
<string name="privacy_policy">ଗୋପନୀୟତା ନୀତି</string>
<string name="black_background">କଳା</string>
<string name="white_background">ଧଳା</string>
<string name="nav_zone_left">ବାମ</string>
<string name="nav_zone_right">ଡାହାଣ</string>
<string name="left_to_right_viewer">ବାମରୁ ଡାହାଣ</string>
<string name="right_to_left_viewer">ଡାହାଣରୁ ବାମ</string>
<string name="zoom_start_left">ବାମ</string>
<string name="zoom_start_right">ଡାହାଣ</string>
<string name="version">ସଂସ୍କରଣ</string>
<string name="description">ବର୍ଣ୍ଣନା</string>
<string name="in_library">ଲାଇବ୍ରେରୀରେ</string>
<string name="manga_info_full_title_label">ଆଖ୍ୟା</string>
<string name="copied_to_clipboard">କ୍ଲିପବୋର୍ଡରେ କପି କରିନିଆଗଲା:
\n%1$s</string>
<string name="manga_cover">ମଲାଟ</string>
<string name="learn_more">ଅଧିକ ଜାଣନ୍ତୁ</string>
<string name="channel_progress">ପ୍ରଗତି</string>
<string name="email">ଇମେଲ୍ ଠିକଣା</string>
<string name="action_filter_started">ଆରମ୍ଭ କରିଛନ୍ତି</string>
<string name="action_sort_alpha">ବର୍ଣ୍ଣମାଳା ଅନୁଯାୟୀ</string>
<string name="action_newest">ସବୁଠୁ ନୂଆ</string>
<string name="action_asc">ଆରୋହଣ</string>
<string name="ext_language_info">ଭାଷା: %1$s</string>
<string name="action_oldest">ସବୁଠୁ ପୁରୁଣା</string>
<string name="add_to_library">ଲାଇବ୍ରେରୀରେ ଯୋଡ଼ନ୍ତୁ</string>
<string name="action_desc">ଅବରୋହଣ</string>
<string name="pref_category_library">ଲାଇବ୍ରେରୀ</string>
<string name="pref_category_reader">ପାଠକ</string>
<plurals name="relative_time">
<item quantity="one">ଗତକାଲି</item>
<item quantity="other">%1$d ଦିନ ପୂର୍ବେ</item>
</plurals>
<string name="title">ଆଖ୍ୟା</string>
<string name="action_sort">ସଜାନ୍ତୁ</string>
<string name="name">ନାମ</string>
<string name="history">ଇତିବୃତ୍ତି</string>
<string name="label_default">ଡିଫଲ୍ଟ</string>
<string name="manga">ମାଙ୍ଗା</string>
<string name="action_edit">ସମ୍ପାଦନା</string>
<string name="action_add">ଯୋଡ଼ନ୍ତୁ</string>
<string name="action_edit_cover">ମଲାଟ ସମ୍ପାଦନା</string>
<string name="on">ଚାଲୁ</string>
<string name="off">ବନ୍ଦ</string>
<string name="action_sort_date_added">ଯୋଡ଼ାଯିବା ତାରିଖ</string>
<string name="action_select_all">ସବୁ ଚୟନ କରନ୍ତୁ</string>
<string name="pref_incognito_mode">ଅପରିଚିତ ମୋଡ୍</string>
<string name="action_display_language_badge">ଭାଷା</string>
<string name="action_menu">ମେନୁ</string>
<string name="action_filter">ଶୋଧନ</string>
<string name="action_filter_downloaded">ଡାଉନଲୋଡ୍ ହୋଇଅଛି</string>
<string name="action_filter_bookmarked">ବୁକମାର୍କ ହୋଇଅଛି</string>
<string name="action_filter_tracked">ଟ୍ରାକ୍ ହୋଇଅଛି</string>
<string name="action_filter_unread">ପଢ଼ି ନାହାଁନ୍ତି</string>
<string name="action_filter_empty">ଶୋଧକ ହଟାନ୍ତୁ</string>
<string name="action_sort_count">ସର୍ବମୋଟ ମାଙ୍ଗା</string>
<string name="action_sort_last_read">ଶେଷ ପଠନ</string>
<string name="action_sort_chapter_fetch_date">ଅଣାଯିବା ତାରିଖ</string>
<string name="pref_category_advanced">ବିକଶିତ</string>
<string name="pref_category_theme">ଥିମ୍</string>
<string name="pref_theme_mode">ଗାଢ଼ ମୋଡ୍</string>
<string name="theme_light">ବନ୍ଦ</string>
<string name="theme_dark">ଚାଲୁ</string>
<string name="pref_app_theme">ଆପ୍ ଥିମ୍</string>
<string name="password">ପାସ୍‍ୱାର୍ଡ଼</string>
<string name="update_never">ବନ୍ଦ</string>
<string name="pref_category_appearance">ରୂପ</string>
<string name="theme_system">ସିଷ୍ଟମ୍ କୁ ଅନୁସରଣ କରିବା</string>
<string name="relative_time_today">ଆଜି</string>
<string name="portrait">ପୋର୍ଟ୍ରେଟ୍</string>
<string name="landscape">ଲ୍ୟାଣ୍ଡସ୍କେପ୍</string>
<string name="update_48hour">ପ୍ରତି ଦିନରେ</string>
<string name="ext_app_info">ଆପ୍ ସୂଚନା</string>
<string name="ext_version_info">ସଂସ୍କରଣ: %1$s</string>
<string name="pref_keep_screen_on">ସ୍କ୍ରିନ୍ ସଚଳ ରଖନ୍ତୁ</string>
<string name="update_6hour">ପ୍ରତି ୬ ଘଣ୍ଟାରେ</string>
<string name="update_12hour">ପ୍ରତି ୧୨ ଘଣ୍ଟାରେ</string>
<string name="update_72hour">ପ୍ରତି ୩ ଦିନରେ</string>
</resources>

View File

@ -82,7 +82,7 @@
<string name="all">Todas</string> <string name="all">Todas</string>
<string name="pref_library_update_restriction">Restrições do dispositivo para atualizações automáticas</string> <string name="pref_library_update_restriction">Restrições do dispositivo para atualizações automáticas</string>
<string name="charging">Carregando</string> <string name="charging">Carregando</string>
<string name="pref_update_only_non_completed">É uma série finalizada</string> <string name="pref_update_only_non_completed">Com o estado \"Completo\"</string>
<string name="pref_auto_update_manga_sync">Atualizar o progresso após a leitura</string> <string name="pref_auto_update_manga_sync">Atualizar o progresso após a leitura</string>
<string name="pref_start_screen">Tela inicial</string> <string name="pref_start_screen">Tela inicial</string>
<string name="default_category">Categoria padrão</string> <string name="default_category">Categoria padrão</string>
@ -672,7 +672,7 @@
<string name="pref_verbose_logging_summary">Imprime registros detalhados no registro de eventos do sistema (reduz o desempenho do aplicativo)</string> <string name="pref_verbose_logging_summary">Imprime registros detalhados no registro de eventos do sistema (reduz o desempenho do aplicativo)</string>
<string name="pref_verbose_logging">Registro de eventos verboso</string> <string name="pref_verbose_logging">Registro de eventos verboso</string>
<string name="action_display_language_badge">Idioma</string> <string name="action_display_language_badge">Idioma</string>
<string name="notification_size_warning">Aviso: atualizações com muitos itens prejudicam as fontes e podem deixar as atualizações lentas e aumentar o uso da bateria</string> <string name="notification_size_warning">Atualizações com muitos itens prejudicam as fontes e podem deixar as atualizações lentas e aumentar o uso da bateria</string>
<string name="label_warning">Aviso</string> <string name="label_warning">Aviso</string>
<string name="backup_info">Backups automáticos são altamente recomendados. Você deve manter cópias em outros locais também.</string> <string name="backup_info">Backups automáticos são altamente recomendados. Você deve manter cópias em outros locais também.</string>
<string name="connected_to_wifi">Somente no Wi-Fi</string> <string name="connected_to_wifi">Somente no Wi-Fi</string>
@ -686,8 +686,8 @@
<string name="database_clean">Banco de dados limpo</string> <string name="database_clean">Banco de dados limpo</string>
<string name="extension_api_error">Erro ao obter a lista de extensões</string> <string name="extension_api_error">Erro ao obter a lista de extensões</string>
<string name="privacy_policy">Política de privacidade</string> <string name="privacy_policy">Política de privacidade</string>
<string name="pref_update_only_completely_read">Possui capítulos não lidos</string> <string name="pref_update_only_completely_read">Com capítulos não lidos</string>
<string name="pref_library_update_manga_restriction">Pular a atualização</string> <string name="pref_library_update_manga_restriction">Pular a atualização de títulos</string>
<string name="library_errors_help">Para obter ajuda sobre como corrigir erros de atualização da biblioteca, veja %1$s</string> <string name="library_errors_help">Para obter ajuda sobre como corrigir erros de atualização da biblioteca, veja %1$s</string>
<string name="save_chapter_as_cbz">Salvar como arquivo CBZ</string> <string name="save_chapter_as_cbz">Salvar como arquivo CBZ</string>
<string name="publishing_finished">Publicação finalizada</string> <string name="publishing_finished">Publicação finalizada</string>
@ -704,15 +704,17 @@
<string name="pref_landscape_zoom">Dar zoom em imagens horizontais</string> <string name="pref_landscape_zoom">Dar zoom em imagens horizontais</string>
<string name="action_display_cover_only_grid">Grade somente com capas</string> <string name="action_display_cover_only_grid">Grade somente com capas</string>
<string name="action_filter_started">Iniciado</string> <string name="action_filter_started">Iniciado</string>
<string name="pref_update_only_started">Sem capítulos lidos</string> <string name="pref_update_only_started">Que não tiveram a leitura iniciada</string>
<string name="skipped_reason_completed">Pulado porque a série está finalizada</string> <string name="skipped_reason_completed">Pulado porque a série está finalizada</string>
<string name="skipped_reason_not_caught_up">Pulado porque há capítulos não lidos</string> <string name="skipped_reason_not_caught_up">Pulado porque há capítulos não lidos</string>
<string name="skipped_reason_not_started">Pulado porque nenhum capítulo foi lido</string> <string name="skipped_reason_not_started">Pulado porque nenhum capítulo foi lido</string>
<string name="notification_update_skipped">%1$d atualização(ões) pulada(s)</string> <string name="notification_update_skipped">%1$d atualização(ões) pulada(s)</string>
<string name="channel_skipped">Puladas</string> <string name="channel_skipped">Puladas</string>
<string name="notification_update_error">%1$d atualização(ões) falhou(aram)</string> <string name="notification_update_error">%1$d atualização(ões) falhou(aram)</string>
<string name="learn_more">Saiba mais</string> <string name="learn_more">Toque para saber mais</string>
<string name="rotation_reverse_portrait">Retrato invertido</string> <string name="rotation_reverse_portrait">Retrato invertido</string>
<string name="action_move_to_top_all_for_series">Mover série para o topo</string> <string name="action_move_to_top_all_for_series">Mover série para o topo</string>
<string name="disabled_nav">Desativado</string> <string name="disabled_nav">Desativado</string>
<string name="update_check_fdroid_migration_info">Uma nova versão está disponível nos releases oficiais. Toque para saber como migrar dos releases não oficiais do F-Droid.</string>
<string name="error_saving_picture">Erro ao salvar a imagem</string>
</resources> </resources>

View File

@ -620,4 +620,7 @@
<string name="theme_tako">Tako</string> <string name="theme_tako">Tako</string>
<string name="theme_yinyang">Yin și Yang</string> <string name="theme_yinyang">Yin și Yang</string>
<string name="theme_yotsuba">Yotsuba</string> <string name="theme_yotsuba">Yotsuba</string>
<string name="publishing_finished">Editare finalizată</string>
<string name="cancelled">Anulat</string>
<string name="on_hiatus">În pauză</string>
</resources> </resources>

View File

@ -156,7 +156,7 @@
<string name="pref_rotation_type">Ориентация по умолчанию</string> <string name="pref_rotation_type">Ориентация по умолчанию</string>
<string name="pref_show_page_number">Номер страницы</string> <string name="pref_show_page_number">Номер страницы</string>
<string name="pref_start_screen">Начальный экран</string> <string name="pref_start_screen">Начальный экран</string>
<string name="pref_update_only_non_completed">Завершенная серия</string> <string name="pref_update_only_non_completed">Серия завершена</string>
<string name="pref_viewer_type">Режим чтения</string> <string name="pref_viewer_type">Режим чтения</string>
<string name="pref_zoom_start">Стартовая позиция увеличения</string> <string name="pref_zoom_start">Стартовая позиция увеличения</string>
<string name="reading">Читаю</string> <string name="reading">Читаю</string>
@ -696,7 +696,7 @@
<string name="pref_verbose_logging_summary">Записывать подробный журнал в системный журнал (снижает производительность приложения)</string> <string name="pref_verbose_logging_summary">Записывать подробный журнал в системный журнал (снижает производительность приложения)</string>
<string name="action_display_language_badge">Язык</string> <string name="action_display_language_badge">Язык</string>
<string name="label_warning">Предупреждение</string> <string name="label_warning">Предупреждение</string>
<string name="notification_size_warning">Предупреждение: большое количество обновлений серий могут привести к замедлению работы источников и увеличению расхода батареи</string> <string name="notification_size_warning">Большое количество обновлений серий могут привести к замедлению работы источников и увеличению расхода батареи</string>
<string name="backup_info">Настоятельно рекомендуется использовать автоматические резервные копии. Вы также должны хранить копии в разных папках.</string> <string name="backup_info">Настоятельно рекомендуется использовать автоматические резервные копии. Вы также должны хранить копии в разных папках.</string>
<string name="connected_to_wifi">Только по Wi-Fi</string> <string name="connected_to_wifi">Только по Wi-Fi</string>
<string name="update_72hour">Каждые 3 дня</string> <string name="update_72hour">Каждые 3 дня</string>
@ -709,8 +709,8 @@
<string name="database_clean">Очистка базы данных</string> <string name="database_clean">Очистка базы данных</string>
<string name="extension_api_error">Не удалось получить список расширений</string> <string name="extension_api_error">Не удалось получить список расширений</string>
<string name="privacy_policy">Политика конфиденциальности</string> <string name="privacy_policy">Политика конфиденциальности</string>
<string name="pref_update_only_completely_read">Имеет непрочитанные главы</string> <string name="pref_update_only_completely_read">Есть непрочитанные главы</string>
<string name="pref_library_update_manga_restriction">Пропускать обновление</string> <string name="pref_library_update_manga_restriction">Пропускать обновления</string>
<string name="library_errors_help">Для помощи в исправлении ошибок библиотеки, нажать %1$s</string> <string name="library_errors_help">Для помощи в исправлении ошибок библиотеки, нажать %1$s</string>
<string name="save_chapter_as_cbz">Сохранить как архив CBZ</string> <string name="save_chapter_as_cbz">Сохранить как архив CBZ</string>
<string name="cancelled">Отменено</string> <string name="cancelled">Отменено</string>
@ -731,11 +731,13 @@
<string name="skipped_reason_completed">Пропущено, так как серия завершена</string> <string name="skipped_reason_completed">Пропущено, так как серия завершена</string>
<string name="skipped_reason_not_caught_up">Пропущено, потому что есть непрочитанные главы</string> <string name="skipped_reason_not_caught_up">Пропущено, потому что есть непрочитанные главы</string>
<string name="skipped_reason_not_started">Пропущено, потому что серия не начата</string> <string name="skipped_reason_not_started">Пропущено, потому что серия не начата</string>
<string name="learn_more">Подробнее</string> <string name="learn_more">Нажать для подробностей</string>
<string name="channel_skipped">Пропущено</string> <string name="channel_skipped">Пропущено</string>
<string name="notification_update_error">%1$d обновление(ий) не удалось</string> <string name="notification_update_error">%1$d обновление(ий) не удалось</string>
<string name="notification_update_skipped">%1$d обновление(ий) пропущено</string> <string name="notification_update_skipped">%1$d обновление(ий) пропущено</string>
<string name="rotation_reverse_portrait">Портретная наоборот</string> <string name="rotation_reverse_portrait">Портретная наоборот</string>
<string name="action_move_to_top_all_for_series">Переместить серию в начало</string> <string name="action_move_to_top_all_for_series">Переместить серию в начало</string>
<string name="disabled_nav">Отключено</string> <string name="disabled_nav">Отключено</string>
<string name="update_check_fdroid_migration_info">Новая версия доступна на оф. странице Tachiyomi. Нажмите, чтобы узнать как мигрировать с неофициальной версии из F-Droid.</string>
<string name="error_saving_picture">Не удалось сохранить изображение</string>
</resources> </resources>

View File

@ -689,7 +689,7 @@
<string name="save_chapter_as_cbz">Sarva comente archìviu CBZ</string> <string name="save_chapter_as_cbz">Sarva comente archìviu CBZ</string>
<string name="library_errors_help">Pro tènnere un\'agiudu pro acontzare sos errores de agiornamentu de sa biblioteca pòmpia·ti %1$s</string> <string name="library_errors_help">Pro tènnere un\'agiudu pro acontzare sos errores de agiornamentu de sa biblioteca pòmpia·ti %1$s</string>
<string name="pref_library_update_manga_restriction">Brinca sos agiornamentos</string> <string name="pref_library_update_manga_restriction">Brinca sos agiornamentos</string>
<string name="pref_update_only_completely_read">Tenet capìtulos non lèghidos</string> <string name="pref_update_only_completely_read">Cun capìtulos non lèghidos</string>
<string name="action_faq_and_guides">PF e ghias</string> <string name="action_faq_and_guides">PF e ghias</string>
<string name="publishing_finished">Publicatzione acabada</string> <string name="publishing_finished">Publicatzione acabada</string>
<string name="on_hiatus">In pàusa</string> <string name="on_hiatus">In pàusa</string>
@ -700,7 +700,7 @@
<string name="pref_landscape_zoom">Ismànnia s\'immàgine in orizontale</string> <string name="pref_landscape_zoom">Ismànnia s\'immàgine in orizontale</string>
<string name="action_filter_started">Incumintzadu</string> <string name="action_filter_started">Incumintzadu</string>
<string name="action_display_cover_only_grid">Grìllia cun coberteddas ebbia</string> <string name="action_display_cover_only_grid">Grìllia cun coberteddas ebbia</string>
<string name="pref_update_only_started">Perunu capìtulu lèghidu</string> <string name="pref_update_only_started">No incumintzadas</string>
<string name="confirm_manga_add_duplicate">Tenes un\'elementu in sa biblioteca tua cun su matessi nùmene ma dae una fonte diferente (%1$s). <string name="confirm_manga_add_duplicate">Tenes un\'elementu in sa biblioteca tua cun su matessi nùmene ma dae una fonte diferente (%1$s).
\n \n
\nBoles sighire su matessi\?</string> \nBoles sighire su matessi\?</string>
@ -708,10 +708,13 @@
<string name="skipped_reason_completed">Brincadu ca sa sèrie est acabada</string> <string name="skipped_reason_completed">Brincadu ca sa sèrie est acabada</string>
<string name="skipped_reason_not_caught_up">Brincadu ca bi sunt capìtulos non lèghidos</string> <string name="skipped_reason_not_caught_up">Brincadu ca bi sunt capìtulos non lèghidos</string>
<string name="skipped_reason_not_started">Brincadu ca non bi sunt capìtulos lèghidos</string> <string name="skipped_reason_not_started">Brincadu ca non bi sunt capìtulos lèghidos</string>
<string name="learn_more">Àteras informatziones</string> <string name="learn_more">Toca pro àteras informatziones</string>
<string name="channel_skipped">Brincadu</string> <string name="channel_skipped">Brincadu</string>
<string name="notification_update_error">%1$d agiornamentu(os) fallidu(os)</string> <string name="notification_update_error">%1$d agiornamentu(os) fallidu(os)</string>
<string name="notification_update_skipped">%1$d agiornamentu(os) brincadu(os)</string> <string name="notification_update_skipped">%1$d agiornamentu(os) brincadu(os)</string>
<string name="rotation_reverse_portrait">Verticale a s\'imbesse</string> <string name="rotation_reverse_portrait">Verticale a s\'imbesse</string>
<string name="action_move_to_top_all_for_series">Move sa sèrie cara a pitzos</string> <string name="action_move_to_top_all_for_series">Move sa sèrie cara a pitzos</string>
<string name="disabled_nav">Disabilitadu</string>
<string name="error_saving_picture">Errore in su sarvamentu de s\'immàgine</string>
<string name="update_check_fdroid_migration_info">B\'est una versione noa ufitziale a disponimentu. Toca pro imparare comente tramudare dae sas versiones no ufitziales de F-Droid.</string>
</resources> </resources>

View File

@ -274,7 +274,7 @@
<string name="lock_always">Увек</string> <string name="lock_always">Увек</string>
<string name="lock_never">Никада</string> <string name="lock_never">Никада</string>
<plurals name="lock_after_mins"> <plurals name="lock_after_mins">
<item quantity="one">Након %1$s минут</item> <item quantity="one">After 1%1$s minutes</item>
<item quantity="few">Након %1$s минута</item> <item quantity="few">Након %1$s минута</item>
<item quantity="other">Након %1$s минута</item> <item quantity="other">Након %1$s минута</item>
</plurals> </plurals>
@ -495,9 +495,9 @@
<string name="pref_category_reading_mode">Начин читања</string> <string name="pref_category_reading_mode">Начин читања</string>
<string name="ext_installer_pref">Instaler</string> <string name="ext_installer_pref">Instaler</string>
<plurals name="missing_chapters_warning"> <plurals name="missing_chapters_warning">
<item quantity="one">Прескаче се %d поглавље, или не постоји у извору или је филтером издвојено</item> <item quantity="one">Preskače se %d poglavlje,ili ne postoji u izvori ili su izdvojeni filterom</item>
<item quantity="few">Прескаче се %d поглавља, или не постоји у извору или је филтером издвојено</item> <item quantity="few">Preskače se %d poglavlje,ili ne postoji u izvori ili su izdvojeni filterom</item>
<item quantity="other">Прескаче се %d поглавља, или не постоји у извору или је филтером издвојено</item> <item quantity="other">Preskače se %d poglavlje,ili ne postoji u izvori ili su izdvojeni filterom</item>
</plurals> </plurals>
<string name="pref_category_auto_download">Аутоматско преузимање</string> <string name="pref_category_auto_download">Аутоматско преузимање</string>
<string name="action_track">Прати</string> <string name="action_track">Прати</string>
@ -529,9 +529,9 @@
<string name="unknown_status">Nepoznat status</string> <string name="unknown_status">Nepoznat status</string>
<string name="local_filter_order_by">Poređaj po</string> <string name="local_filter_order_by">Poređaj po</string>
<plurals name="num_trackers"> <plurals name="num_trackers">
<item quantity="one">%d трекер</item> <item quantity="one">%d tragač</item>
<item quantity="few">%d трекера</item> <item quantity="few">%d tragača</item>
<item quantity="other">%d трекера</item> <item quantity="other">%d tragač</item>
</plurals> </plurals>
<string name="enhanced_services">Побољшани сервиси</string> <string name="enhanced_services">Побољшани сервиси</string>
<string name="tracker_not_logged_in">Нисте пријаљени у: %1$s</string> <string name="tracker_not_logged_in">Нисте пријаљени у: %1$s</string>
@ -711,7 +711,7 @@
\n \n
\nDa li i dalje želite da nastavite\?</string> \nDa li i dalje želite da nastavite\?</string>
<string name="notification_update_error">%1$d ažuriranje nije uspelo</string> <string name="notification_update_error">%1$d ažuriranje nije uspelo</string>
<string name="learn_more">Saznajte više</string> <string name="learn_more">Pritisnite za više</string>
<string name="library_errors_help">Za pomoć o tome kako da popravite greške u ažuriranju kolekcije, pogledajte %1$s</string> <string name="library_errors_help">Za pomoć o tome kako da popravite greške u ažuriranju kolekcije, pogledajte %1$s</string>
<string name="skipped_reason_not_started">Preskočeno jer nijedno poglavlje nije pročitano</string> <string name="skipped_reason_not_started">Preskočeno jer nijedno poglavlje nije pročitano</string>
<string name="channel_skipped">Preskočeno</string> <string name="channel_skipped">Preskočeno</string>
@ -726,4 +726,5 @@
<string name="notification_update_skipped">%1$d ažuriranje je preskočeno</string> <string name="notification_update_skipped">%1$d ažuriranje je preskočeno</string>
<string name="skipped_reason_completed">Preskočeno jer je serijal završen</string> <string name="skipped_reason_completed">Preskočeno jer je serijal završen</string>
<string name="skipped_reason_not_caught_up">Preskočeno jer ima nepročitanih poglavlja</string> <string name="skipped_reason_not_caught_up">Preskočeno jer ima nepročitanih poglavlja</string>
<string name="disabled_nav">Onesposobljen</string>
</resources> </resources>

View File

@ -87,7 +87,7 @@
<string name="all">Alla</string> <string name="all">Alla</string>
<string name="pref_library_update_restriction">Automatiska uppdateringar av enhetsbegränsningar</string> <string name="pref_library_update_restriction">Automatiska uppdateringar av enhetsbegränsningar</string>
<string name="charging">Laddning</string> <string name="charging">Laddning</string>
<string name="pref_update_only_non_completed">Är avslutad serie</string> <string name="pref_update_only_non_completed">Med status \"Avslutat\"</string>
<string name="pref_auto_update_manga_sync">Uppdatera förlopp efter läsning</string> <string name="pref_auto_update_manga_sync">Uppdatera förlopp efter läsning</string>
<string name="pref_start_screen">Startskärm</string> <string name="pref_start_screen">Startskärm</string>
<string name="default_category">Standardkategori</string> <string name="default_category">Standardkategori</string>
@ -686,20 +686,20 @@
<string name="database_clean">Rengör databasen</string> <string name="database_clean">Rengör databasen</string>
<string name="backup_restore_invalid_uri">Fel: tom URI</string> <string name="backup_restore_invalid_uri">Fel: tom URI</string>
<string name="library_errors_help">För hjälp med att åtgärda fel i biblioteksuppdateringar, se %1$s</string> <string name="library_errors_help">För hjälp med att åtgärda fel i biblioteksuppdateringar, se %1$s</string>
<string name="pref_library_update_manga_restriction">Hoppa över uppdatering</string> <string name="pref_library_update_manga_restriction">Hoppa över att uppdatera titlar</string>
<string name="cancelled">Avbruten</string> <string name="cancelled">Avbruten</string>
<string name="on_hiatus">På uppehåll</string> <string name="on_hiatus">På uppehåll</string>
<string name="publishing_finished">Publiceringen avslutad</string> <string name="publishing_finished">Publiceringen avslutad</string>
<string name="save_chapter_as_cbz">Spara som CBZ-arkiv</string> <string name="save_chapter_as_cbz">Spara som CBZ-arkiv</string>
<string name="privacy_policy">Integritetspolicy</string> <string name="privacy_policy">Integritetspolicy</string>
<string name="action_faq_and_guides">Vanliga frågor och guider</string> <string name="action_faq_and_guides">Vanliga frågor och guider</string>
<string name="pref_update_only_completely_read">Har olästa kapitel</string> <string name="pref_update_only_completely_read">Med olästa kapitel</string>
<string name="extension_api_error">Det gick inte att hämta tilläggslistan</string> <string name="extension_api_error">Det gick inte att hämta tilläggslistan</string>
<string name="webtoon_side_padding_5">5%</string> <string name="webtoon_side_padding_5">5%</string>
<string name="action_show_manga">Visa manga</string> <string name="action_show_manga">Visa manga</string>
<string name="action_filter_started">Startad</string> <string name="action_filter_started">Startad</string>
<string name="action_display_cover_only_grid">Endast omslags-rutnät</string> <string name="action_display_cover_only_grid">Endast omslags-rutnät</string>
<string name="pref_update_only_started">Inga lästa kapitel</string> <string name="pref_update_only_started">Som inte har startats</string>
<string name="pref_navigate_pan">Navigera till pan</string> <string name="pref_navigate_pan">Navigera till pan</string>
<string name="confirm_manga_add_duplicate">Du har en post i ditt bibliotek med samma namn men från en annan källa (%1$s). <string name="confirm_manga_add_duplicate">Du har en post i ditt bibliotek med samma namn men från en annan källa (%1$s).
\n \n
@ -708,10 +708,13 @@
<string name="skipped_reason_completed">Hoppade över eftersom serien är klar</string> <string name="skipped_reason_completed">Hoppade över eftersom serien är klar</string>
<string name="skipped_reason_not_caught_up">Hoppade över eftersom det finns olästa kapitel</string> <string name="skipped_reason_not_caught_up">Hoppade över eftersom det finns olästa kapitel</string>
<string name="skipped_reason_not_started">Hoppade över eftersom inga kapitel läses</string> <string name="skipped_reason_not_started">Hoppade över eftersom inga kapitel läses</string>
<string name="learn_more">Läs mer</string> <string name="learn_more">Tryck på för att få veta mer</string>
<string name="notification_update_error">%1$d uppdatering(ar) misslyckades</string> <string name="notification_update_error">%1$d uppdatering(ar) misslyckades</string>
<string name="notification_update_skipped">%1$d uppdatering(ar) hoppades över</string> <string name="notification_update_skipped">%1$d uppdatering(ar) hoppades över</string>
<string name="channel_skipped">Hoppat över</string> <string name="channel_skipped">Hoppat över</string>
<string name="rotation_reverse_portrait">Omvänt porträtt</string> <string name="rotation_reverse_portrait">Omvänt porträtt</string>
<string name="action_move_to_top_all_for_series">Flytta serien till toppen</string> <string name="action_move_to_top_all_for_series">Flytta serien till toppen</string>
<string name="disabled_nav">Inaktiverad</string>
<string name="error_saving_picture">Fel vid lagring av bild</string>
<string name="update_check_fdroid_migration_info">En ny version finns tillgänglig i de officiella utgåvorna. Tryck på för att lära dig hur du flyttar från inofficiella F-Droid-versioner.</string>
</resources> </resources>

View File

@ -702,4 +702,5 @@
<string name="channel_skipped">ข้ามแล้ว</string> <string name="channel_skipped">ข้ามแล้ว</string>
<string name="rotation_reverse_portrait">แนวตั้งแบบกลับด้าน</string> <string name="rotation_reverse_portrait">แนวตั้งแบบกลับด้าน</string>
<string name="action_move_to_top_all_for_series">ย้ายเรื่องไปด้านบน</string> <string name="action_move_to_top_all_for_series">ย้ายเรื่องไปด้านบน</string>
<string name="disabled_nav">ปิดใช้งาน</string>
</resources> </resources>

View File

@ -87,7 +87,7 @@
<string name="all">Tümü</string> <string name="all">Tümü</string>
<string name="pref_library_update_restriction">Otomatik güncellemeler aygıt kısıtlamaları</string> <string name="pref_library_update_restriction">Otomatik güncellemeler aygıt kısıtlamaları</string>
<string name="charging">Şarj oluyor</string> <string name="charging">Şarj oluyor</string>
<string name="pref_update_only_non_completed">Tamamlanan seriler</string> <string name="pref_update_only_non_completed">\"Tamamlanan\" durumda olan</string>
<string name="pref_auto_update_manga_sync">Okuyunca ilerlemeyi güncelle</string> <string name="pref_auto_update_manga_sync">Okuyunca ilerlemeyi güncelle</string>
<string name="pref_start_screen">Başlangıç ekranı</string> <string name="pref_start_screen">Başlangıç ekranı</string>
<string name="default_category">Varsayılan kategori</string> <string name="default_category">Varsayılan kategori</string>
@ -672,7 +672,7 @@
<string name="label_warning">Uyarı</string> <string name="label_warning">Uyarı</string>
<string name="action_display_language_badge">Dil</string> <string name="action_display_language_badge">Dil</string>
<string name="backup_info">Otomatik yedeklemeler şiddetle tavsiye edilir. Kopyaları başka yerlerde de tutmalısınız.</string> <string name="backup_info">Otomatik yedeklemeler şiddetle tavsiye edilir. Kopyaları başka yerlerde de tutmalısınız.</string>
<string name="notification_size_warning">Uyarı: büyük güncellemeler kaynaklara zarar verir ve daha yavaş güncellemelere ve de pil kullanımının artmasına neden olabilir</string> <string name="notification_size_warning">Büyük güncellemeler kaynaklara zarar verir ve daha yavaş güncellemelere ve ayrıca pil kullanımının artmasına neden olabilir</string>
<string name="pref_verbose_logging">Ayrıntılı günlük kaydı</string> <string name="pref_verbose_logging">Ayrıntılı günlük kaydı</string>
<string name="pref_verbose_logging_summary">Ayrıntılı günlükleri sistem günlüğüne yaz (uygulama performansını düşürür)</string> <string name="pref_verbose_logging_summary">Ayrıntılı günlükleri sistem günlüğüne yaz (uygulama performansını düşürür)</string>
<string name="connected_to_wifi">Yalnızca Wi-Fi\'de</string> <string name="connected_to_wifi">Yalnızca Wi-Fi\'de</string>
@ -685,7 +685,7 @@
<string name="clear_database_source_item_count">Veri tabanında %1$d kitaplık dışı manga</string> <string name="clear_database_source_item_count">Veri tabanında %1$d kitaplık dışı manga</string>
<string name="database_clean">Veri tabanı temiz</string> <string name="database_clean">Veri tabanı temiz</string>
<string name="extension_api_error">Uzantı listesi alınamadı</string> <string name="extension_api_error">Uzantı listesi alınamadı</string>
<string name="pref_library_update_manga_restriction">Güncellemeyi atla</string> <string name="pref_library_update_manga_restriction">Başlıkları güncellemeyi atla</string>
<string name="save_chapter_as_cbz">CBZ arşivi olarak kaydet</string> <string name="save_chapter_as_cbz">CBZ arşivi olarak kaydet</string>
<string name="publishing_finished">Yayımı tamamlandı</string> <string name="publishing_finished">Yayımı tamamlandı</string>
<string name="privacy_policy">Gizlilik politikası</string> <string name="privacy_policy">Gizlilik politikası</string>
@ -701,8 +701,8 @@
<string name="action_display_cover_only_grid">Sadece-kapak ızgara</string> <string name="action_display_cover_only_grid">Sadece-kapak ızgara</string>
<string name="backup_restore_invalid_uri">Hata: boş URI</string> <string name="backup_restore_invalid_uri">Hata: boş URI</string>
<string name="action_faq_and_guides">SSS ve Kılavuzlar</string> <string name="action_faq_and_guides">SSS ve Kılavuzlar</string>
<string name="pref_update_only_completely_read">Okunmayan bölümleri olan</string> <string name="pref_update_only_completely_read">Okunmayan bölüm(ler)i olan</string>
<string name="pref_update_only_started">Yalnızca okumaya başlanan mangaları güncelleme</string> <string name="pref_update_only_started">Bu başlamadı</string>
<string name="skipped_reason_completed">Manga tamamlandığı için atlandı</string> <string name="skipped_reason_completed">Manga tamamlandığı için atlandı</string>
<string name="skipped_reason_not_caught_up">Okunmamış bölümler olduğu için atlandı</string> <string name="skipped_reason_not_caught_up">Okunmamış bölümler olduğu için atlandı</string>
<string name="skipped_reason_not_started">Hiçbir bölüm okunmadığı için atlandı</string> <string name="skipped_reason_not_started">Hiçbir bölüm okunmadığı için atlandı</string>
@ -710,9 +710,11 @@
<string name="pref_landscape_zoom">Yatay görseli yakınlaştır</string> <string name="pref_landscape_zoom">Yatay görseli yakınlaştır</string>
<string name="notification_update_error">%1$d güncelleme başarısız oldu</string> <string name="notification_update_error">%1$d güncelleme başarısız oldu</string>
<string name="notification_update_skipped">%1$d güncelleme atlandı</string> <string name="notification_update_skipped">%1$d güncelleme atlandı</string>
<string name="learn_more">Daha fazla bilgi edin</string> <string name="learn_more">Daha fazla bilgi edinmek için dokunun</string>
<string name="channel_skipped">Atlandı</string> <string name="channel_skipped">Atlandı</string>
<string name="rotation_reverse_portrait">Ters dikey</string> <string name="rotation_reverse_portrait">Ters dikey</string>
<string name="action_move_to_top_all_for_series">Seriyi en üste taşı</string> <string name="action_move_to_top_all_for_series">Seriyi en üste taşı</string>
<string name="disabled_nav">Devre dışı</string> <string name="disabled_nav">Devre dışı</string>
<string name="update_check_fdroid_migration_info">Resmi yayınlardan yeni bir sürüm var. Resmi olmayan F-Droid sürümlerinden nasıl geçiş yapacağınızı öğrenmek için dokunun.</string>
<string name="error_saving_picture">Resim kaydedilirken hata oluştu</string>
</resources> </resources>

View File

@ -629,7 +629,7 @@
<string name="date">Ngày</string> <string name="date">Ngày</string>
<string name="local_filter_order_by">Xếp theo</string> <string name="local_filter_order_by">Xếp theo</string>
<string name="local_invalid_format">Định dạng chương không đúng</string> <string name="local_invalid_format">Định dạng chương không đúng</string>
<string name="chapter_not_found">Chương không tìm thấy</string> <string name="chapter_not_found">Không tìm thấy chương</string>
<string name="on">Bật</string> <string name="on">Bật</string>
<string name="off">Tắt</string> <string name="off">Tắt</string>
<string name="pref_library_update_refresh_trackers_summary">Cập nhật theo dõi khi cập nhật thư viện</string> <string name="pref_library_update_refresh_trackers_summary">Cập nhật theo dõi khi cập nhật thư viện</string>
@ -736,4 +736,5 @@
<string name="skipped_reason_not_started">Đã bỏ qua vì không có chương được đọc</string> <string name="skipped_reason_not_started">Đã bỏ qua vì không có chương được đọc</string>
<string name="channel_skipped">Bỏ qua</string> <string name="channel_skipped">Bỏ qua</string>
<string name="action_move_to_top_all_for_series">Di chuyển bộ truyện lên đầu</string> <string name="action_move_to_top_all_for_series">Di chuyển bộ truyện lên đầu</string>
<string name="disabled_nav">Vô hiệu hóa</string>
</resources> </resources>

View File

@ -87,7 +87,7 @@
<string name="all">全部</string> <string name="all">全部</string>
<string name="pref_library_update_restriction">设备自动更新限制</string> <string name="pref_library_update_restriction">设备自动更新限制</string>
<string name="charging">正在充电</string> <string name="charging">正在充电</string>
<string name="pref_update_only_non_completed">已完结连载</string> <string name="pref_update_only_non_completed">状态为“已完结</string>
<string name="pref_auto_update_manga_sync">阅读后更新进度</string> <string name="pref_auto_update_manga_sync">阅读后更新进度</string>
<string name="pref_start_screen">起始页面</string> <string name="pref_start_screen">起始页面</string>
<string name="default_category">默认分类</string> <string name="default_category">默认分类</string>
@ -662,7 +662,7 @@
<string name="label_warning">警告</string> <string name="label_warning">警告</string>
<string name="action_display_language_badge">语言</string> <string name="action_display_language_badge">语言</string>
<string name="backup_info">强烈建议启用自动备份,你也应该在其他地方保存副本。</string> <string name="backup_info">强烈建议启用自动备份,你也应该在其他地方保存副本。</string>
<string name="notification_size_warning">警告:大型更新会损害图源,并可能导致更新速度变慢以及电池用量增加</string> <string name="notification_size_warning">大型更新会损害图源,并可能导致更新速度变慢以及电池用量增加</string>
<string name="connected_to_wifi">仅连接至 Wi-Fi 时</string> <string name="connected_to_wifi">仅连接至 Wi-Fi 时</string>
<string name="update_72hour">每 3 天</string> <string name="update_72hour">每 3 天</string>
<string name="download_queue_size_warning">警告:批量下载可能会导致图源变慢和/或图源封锁 Tachiyomi</string> <string name="download_queue_size_warning">警告:批量下载可能会导致图源变慢和/或图源封锁 Tachiyomi</string>
@ -674,8 +674,8 @@
<string name="clear_database_source_item_count">数据库有 %1$d 本漫画不在书架中</string> <string name="clear_database_source_item_count">数据库有 %1$d 本漫画不在书架中</string>
<string name="extension_api_error">无法获取扩展插件列表</string> <string name="extension_api_error">无法获取扩展插件列表</string>
<string name="privacy_policy">隐私政策</string> <string name="privacy_policy">隐私政策</string>
<string name="pref_update_only_completely_read">有未读完的章节</string> <string name="pref_update_only_completely_read">有未读章节</string>
<string name="pref_library_update_manga_restriction">跳过更新</string> <string name="pref_library_update_manga_restriction">跳过更新标题</string>
<string name="library_errors_help">有关如何修复库更新错误的帮助,请参阅 %1$s</string> <string name="library_errors_help">有关如何修复库更新错误的帮助,请参阅 %1$s</string>
<string name="save_chapter_as_cbz">保存为 CBZ 存档</string> <string name="save_chapter_as_cbz">保存为 CBZ 存档</string>
<string name="publishing_finished">发布完成</string> <string name="publishing_finished">发布完成</string>
@ -692,15 +692,17 @@
\n \n
\n你仍希望继续吗</string> \n你仍希望继续吗</string>
<string name="action_filter_started">已开始</string> <string name="action_filter_started">已开始</string>
<string name="pref_update_only_started">无已读章节</string> <string name="pref_update_only_started">尚未开始</string>
<string name="skipped_reason_completed">跳过,因连载完结</string> <string name="skipped_reason_completed">跳过,因连载完结</string>
<string name="skipped_reason_not_caught_up">跳过,因有未读章节</string> <string name="skipped_reason_not_caught_up">跳过,因有未读章节</string>
<string name="skipped_reason_not_started">跳过,因无已读章节</string> <string name="skipped_reason_not_started">跳过,因无已读章节</string>
<string name="learn_more">了解更多</string> <string name="learn_more">轻按了解更多</string>
<string name="notification_update_error">%1$d 个更新失败了</string> <string name="notification_update_error">%1$d 个更新失败了</string>
<string name="notification_update_skipped">已跳过 %1$d 个更新</string> <string name="notification_update_skipped">已跳过 %1$d 个更新</string>
<string name="channel_skipped">已跳过</string> <string name="channel_skipped">已跳过</string>
<string name="rotation_reverse_portrait">反转竖屏</string> <string name="rotation_reverse_portrait">反转竖屏</string>
<string name="action_move_to_top_all_for_series">将连载移动到顶部</string> <string name="action_move_to_top_all_for_series">将连载置顶</string>
<string name="disabled_nav">已禁用</string> <string name="disabled_nav">已禁用</string>
<string name="error_saving_picture">保存图片出错</string>
<string name="update_check_fdroid_migration_info">新版本可从官方版本中获得。 轻按以了解如何从非官方 F-Droid 版本迁移。</string>
</resources> </resources>

View File

@ -506,7 +506,7 @@
<string name="pref_category_delete_chapters">刪除章節</string> <string name="pref_category_delete_chapters">刪除章節</string>
<string name="chapter_settings_updated">已更新章節設定預設值</string> <string name="chapter_settings_updated">已更新章節設定預設值</string>
<plurals name="missing_chapters_warning"> <plurals name="missing_chapters_warning">
<item quantity="other">略過了 %d 章,也許是來源沒有這些章節,或其已被你的篩選規則排除</item> <item quantity="other">略過了 %d 章,也許是來源沒有這些章節,或其已被篩選規則排除</item>
</plurals> </plurals>
<string name="action_search_settings">搜尋設定</string> <string name="action_search_settings">搜尋設定</string>
<string name="chapter_settings">章節設定</string> <string name="chapter_settings">章節設定</string>
@ -701,4 +701,6 @@
<string name="notification_update_error">%1$d 項更新失敗</string> <string name="notification_update_error">%1$d 項更新失敗</string>
<string name="notification_update_skipped">已略過 %1$d 項更新</string> <string name="notification_update_skipped">已略過 %1$d 項更新</string>
<string name="channel_skipped">略過</string> <string name="channel_skipped">略過</string>
<string name="action_move_to_top_all_for_series">置頂此叢書</string>
<string name="disabled_nav">已停用</string>
</resources> </resources>

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