Compare commits

...

718 Commits

Author SHA1 Message Date
Jobobby04 b021f57273 Update Readme, images and issue templates 2020-12-12 14:06:15 -05:00
Jobobby04 958b6d4b71 Release 1.4.0 2020-12-12 13:27:13 -05:00
Jobobby04 6f712c7f17 Lint 2020-12-12 12:36:29 -05:00
arkon 134f776a86 Hide incomplete NSFW source labelling settings
(cherry picked from commit a3b1690d38)
2020-12-12 12:21:32 -05:00
arkon d91ac659fd Force MAL logout on update
(cherry picked from commit a3bad75899)
2020-12-12 12:20:39 -05:00
arkon bd8f703c28 Update Gradle
(cherry picked from commit d1aaafbfff)
2020-12-12 12:20:31 -05:00
Jozef Hollý bbeca97524 Weblate translations (#4078)
Co-authored-by: Ajeje Brazorf <lmelonimamo@yahoo.it>
Co-authored-by: Alessandro Jean <alessandrojean@gmail.com>
Co-authored-by: Ava <Sasu.ruotsalainen@live.fi>
Co-authored-by: C201 <derasetad@gmail.com>
Co-authored-by: DarKCroX <darkcrox.2020@outlook.com>
Co-authored-by: Eduard Ereza Martínez <eduard@ereza.cat>
Co-authored-by: Eric <spice2wolf@gmail.com>
Co-authored-by: HaruSasaki <aiqusubaru@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: Kurocon <weblate@kurocon.nl>
Co-authored-by: Mario Kevin D. A <programas013@gmail.com>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: Oğuz Ersen <oguzersen@protonmail.com>
Co-authored-by: Paulo Pinho <kebrus@gmail.com>
Co-authored-by: Pitpe11 <giorgos2550@gmail.com>
Co-authored-by: Samuel Carvalho de Araújo <samuelnegro12345@gmail.com>
Co-authored-by: Tooster <max@polarczyk.pl>
Co-authored-by: Woodyx <shiposhouyou@gmail.com>
Co-authored-by: Yassin <yassinelaoud@gmail.com>
Co-authored-by: f0roots <f0rootss@gmail.com>
Co-authored-by: sunbeams001 <sunbeams001@gmail.com>
Co-authored-by: Роман <Rozhenkov69@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ar/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ca/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/cv/
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/fr/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/hr/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/id/
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/ms/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/nl/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pl/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pt/
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/tr/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/zh_Hans/
Translation: Tachiyomi/Strings

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: Ava <Sasu.ruotsalainen@live.fi>
Co-authored-by: C201 <derasetad@gmail.com>
Co-authored-by: DarKCroX <darkcrox.2020@outlook.com>
Co-authored-by: Eduard Ereza Martínez <eduard@ereza.cat>
Co-authored-by: Eric <spice2wolf@gmail.com>
Co-authored-by: HaruSasaki <aiqusubaru@gmail.com>
Co-authored-by: Huang Zhiyi <hzy980512@126.com>
Co-authored-by: J. Lavoie <j.lavoie@net-c.ca>
Co-authored-by: Kurocon <weblate@kurocon.nl>
Co-authored-by: Mario Kevin D. A <programas013@gmail.com>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: Oğuz Ersen <oguzersen@protonmail.com>
Co-authored-by: Paulo Pinho <kebrus@gmail.com>
Co-authored-by: Pitpe11 <giorgos2550@gmail.com>
Co-authored-by: Samuel Carvalho de Araújo <samuelnegro12345@gmail.com>
Co-authored-by: Tooster <max@polarczyk.pl>
Co-authored-by: Woodyx <shiposhouyou@gmail.com>
Co-authored-by: Yassin <yassinelaoud@gmail.com>
Co-authored-by: f0roots <f0rootss@gmail.com>
Co-authored-by: sunbeams001 <sunbeams001@gmail.com>
Co-authored-by: Роман <Rozhenkov69@gmail.com>
(cherry picked from commit 93d4af99bf)
2020-12-12 12:20:22 -05:00
arkon 6e346b231e Revert "Distinguish between no results and loading when sorting global search results"
This reverts commit 2be9871d05.

(cherry picked from commit c950595fe3)
2020-12-12 12:20:13 -05:00
arkon cb1a1e29be Don't scroll to top when navigating back/forward in WebView
(cherry picked from commit 8ffd3a8ed2)
2020-12-12 12:20:02 -05:00
arkon 7d11cc4837 Add text selection shortcut to invoke global search (closes #4058)
(cherry picked from commit b6e246c6b2)
2020-12-12 12:19:53 -05:00
arkon 0137262e4c Update to Kotlin 1.4.21 and kotlinter 3.3.0
(cherry picked from commit 59859e124f)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateService.kt
2020-12-12 12:19:44 -05:00
arkon 45086af3ae Use WebView auth flow for MAL (fixes #4100)
(cherry picked from commit 2bb7a33bc3)
2020-12-12 12:18:40 -05:00
Taco d33cb59af5 Update libraries, some lints (#4099)
* Update some plugins

* Fix some miscellaneous lints

(cherry picked from commit c2b8fea291)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/data/backup/AbstractBackupManager.kt
#	app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateService.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/SearchPresenter.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/sources/MigrationSourcesPresenter.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourcePresenter.kt
2020-12-12 12:18:30 -05:00
arkon 161d4e237f Update to Kotlin 1.4.20
(cherry picked from commit 08ab7f6aa0)
2020-12-12 12:11:29 -05:00
arkon 0db60d68f0 Use more up-to-date fork of junrar
(cherry picked from commit 560f0bba5c)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/source/LocalSource.kt
2020-12-12 12:11:19 -05:00
arkon 11b10f00dd Update AndroidX and Material Components dependencies
(cherry picked from commit 722437a022)
2020-12-12 12:09:30 -05:00
Jobobby04 8fbc6aa29b Convert intercept activity to a stateflow 2020-11-30 20:34:48 -05:00
Jobobby04 ee18f94788 Convert Favorites sync to a StateFlow 2020-11-30 20:22:29 -05:00
Jobobby04 9a2ed755b7 Cleanup EH and AZ preferences 2020-11-30 15:11:58 -05:00
Jobobby04 f1a6218a4b Throw a error when the 509 gif is given when your downloading or loading a chapter from Exh and E-H 2020-11-30 13:21:56 -05:00
Jobobby04 bff654eac8 Cleanup 2020-11-30 13:19:41 -05:00
Jobobby04 5e5b155992 Run getRecs in IO 2020-11-30 13:19:28 -05:00
Jobobby04 dacc5502fc Fix community recommendation stalling 2020-11-30 13:19:02 -05:00
Jobobby04 e7169bda19 Fix exclude from deletion 2020-11-30 13:02:47 -05:00
Jobobby04 8110a2cabd Cleanup 2020-11-29 20:38:36 -05:00
Jobobby04 1118fe7cf7 More recs cleanup 2020-11-29 20:38:22 -05:00
Jobobby04 5b54fc8885 Localize the similar manga no results error 2020-11-29 20:38:07 -05:00
Jobobby04 2e75cc0cc9 Add title to similar manga header 2020-11-29 20:35:46 -05:00
arkon 3f89d8ec99 Add Galician locale
(cherry picked from commit 8a44b1dabe)
2020-11-29 18:53:06 -05:00
arkon b44ffd1d63 Fix annotations package name
(cherry picked from commit b39191ff50)
2020-11-29 18:52:50 -05:00
Jobobby04 9bad33930a Fix weird recs map sort 2020-11-29 18:52:32 -05:00
Jobobby04 e23b048d53 Fixes to reader ui from @CrepTF 2020-11-29 18:52:01 -05:00
Jozef Hollý d291b41080 Weblate translations (#3997)
Co-authored-by: AXEL IVAN GARCIA BERNAL <ga419623@uaeh.edu.mx>
Co-authored-by: Ajeje Brazorf <lmelonimamo@yahoo.it>
Co-authored-by: Alessandro Jean <alessandrojean@gmail.com>
Co-authored-by: Alex <linuxrf@gmail.com>
Co-authored-by: Allan Nordhøy <epost@anotheragency.no>
Co-authored-by: Andreas E <andreas.everos@gmail.com>
Co-authored-by: Aria Moradi <aria.moradi007@gmail.com>
Co-authored-by: Ava <Sasu.ruotsalainen@live.fi>
Co-authored-by: C201 <derasetad@gmail.com>
Co-authored-by: DarKCroX <darkcrox.2020@outlook.com>
Co-authored-by: Eduard Ereza Martínez <eduard@ereza.cat>
Co-authored-by: Eric <spice2wolf@gmail.com>
Co-authored-by: HaruSasaki <aiqusubaru@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: Johkum <jacobomur@gmail.com>
Co-authored-by: Kurocon <weblate@kurocon.nl>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: Oğuz Ersen <oguzersen@protonmail.com>
Co-authored-by: Paulo Pinho <kebrus@gmail.com>
Co-authored-by: Pitpe11 <giorgos2550@gmail.com>
Co-authored-by: Rostyslav <info@ubilling.net.ua>
Co-authored-by: Simon Mattila <simon.mattila@protonmail.com>
Co-authored-by: The Pumpkin God <sbh13112002@gmail.com>
Co-authored-by: Tooster <max@polarczyk.pl>
Co-authored-by: Tristan Garnier <espeletpro@gmail.com>
Co-authored-by: Woodyx <shiposhouyou@gmail.com>
Co-authored-by: Yassin El Aoud <yassinelaoud@gmail.com>
Co-authored-by: george k <norhorn@gmail.com>
Co-authored-by: Николаев Павел Дмитриевич <pavliknikolaev128@gmail.com>
Co-authored-by: Роман <Rozhenkov69@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ar/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ca/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/cv/
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/fa/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/fi/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/fr/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/gl/
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/id/
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/ms/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/nl/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pl/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pt/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ru/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sah/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sc/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sv/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/tr/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/uk/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/zh_Hans/
Translation: Tachiyomi/Strings

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: AXEL IVAN GARCIA BERNAL <ga419623@uaeh.edu.mx>
Co-authored-by: Ajeje Brazorf <lmelonimamo@yahoo.it>
Co-authored-by: Alessandro Jean <alessandrojean@gmail.com>
Co-authored-by: Alex <linuxrf@gmail.com>
Co-authored-by: Allan Nordhøy <epost@anotheragency.no>
Co-authored-by: Andreas E <andreas.everos@gmail.com>
Co-authored-by: Aria Moradi <aria.moradi007@gmail.com>
Co-authored-by: Ava <Sasu.ruotsalainen@live.fi>
Co-authored-by: C201 <derasetad@gmail.com>
Co-authored-by: DarKCroX <darkcrox.2020@outlook.com>
Co-authored-by: Eduard Ereza Martínez <eduard@ereza.cat>
Co-authored-by: Eric <spice2wolf@gmail.com>
Co-authored-by: HaruSasaki <aiqusubaru@gmail.com>
Co-authored-by: Huang Zhiyi <hzy980512@126.com>
Co-authored-by: J. Lavoie <j.lavoie@net-c.ca>
Co-authored-by: Johkum <jacobomur@gmail.com>
Co-authored-by: Kurocon <weblate@kurocon.nl>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: Oğuz Ersen <oguzersen@protonmail.com>
Co-authored-by: Paulo Pinho <kebrus@gmail.com>
Co-authored-by: Pitpe11 <giorgos2550@gmail.com>
Co-authored-by: Rostyslav <info@ubilling.net.ua>
Co-authored-by: Simon Mattila <simon.mattila@protonmail.com>
Co-authored-by: The Pumpkin God <sbh13112002@gmail.com>
Co-authored-by: Tooster <max@polarczyk.pl>
Co-authored-by: Tristan Garnier <espeletpro@gmail.com>
Co-authored-by: Woodyx <shiposhouyou@gmail.com>
Co-authored-by: Yassin El Aoud <yassinelaoud@gmail.com>
Co-authored-by: george k <norhorn@gmail.com>
Co-authored-by: Николаев Павел Дмитриевич <pavliknikolaev128@gmail.com>
Co-authored-by: Роман <Rozhenkov69@gmail.com>
(cherry picked from commit 9814d20404)
2020-11-29 17:20:39 -05:00
arkon 177981da6c Use regular minified extensions JSON instead of explicitly handling gzip encoding
Turns out GitHub *does* do gzip encoding by default, it just doesn't show up in the header logs for some reason...

(cherry picked from commit 6664dfb048)
2020-11-29 17:20:14 -05:00
arkon a19d59cdf0 Fix crash when a preference doesn't have a title (e.g. info preference)
(cherry picked from commit 3133a63cf8)
2020-11-29 17:20:05 -05:00
Andreas E 6a1a7275c8 Enhance incognito mode (#4073)
* When in Incognito Mode don't set lastUsedSource

* When in Incognito Mode don't save chapter progress

Still allows tracking and mark as read when reaching last page

* When in Incognito Mode don't mark as read (overwritten if hasTrackers)

(cherry picked from commit c9c0f3d014)
2020-11-29 17:19:40 -05:00
Jobobby04 4a1e832bf5 Revert "Cool gray theme (#169)"
This reverts commit ac31f12138.
2020-11-29 17:19:29 -05:00
CrepeTF edc2065ea3 Tweak default dark theme colors (#4074)
(cherry picked from commit ff66f307dd)
2020-11-29 17:19:19 -05:00
arkon 0bb153fba9 Revert edge to edge
This was a bigger headache than it was worth. To note, phone landscape wasn't considered, so the navbar overlaps the content on the side. Additionally, the ability to programatically control the navbar scrim is missing, so it'd have to manually be added.

(cherry picked from commit e048d66f74)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryView.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt
2020-11-29 17:19:09 -05:00
arkon 495d63e66b Replace more Kotlin synthetics
(cherry picked from commit 66e3fa7df8)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceController.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt
2020-11-29 17:16:20 -05:00
Jobobby04 ede4f40133 Cleanup rec changes 2020-11-29 17:13:44 -05:00
she11sh0cked 2cefc93797 Rework code to enable UI rendered error messages (#172) 2020-11-29 16:24:25 -05:00
arkon 9d16b0efd2 Replace more Kotlin synthetics
(cherry picked from commit 019a0f31c7)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/SourceComfortableGridHolder.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/SourceItem.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryComfortableGridHolder.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCompactGridHolder.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryHolder.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryItem.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryListHolder.kt
#	app/src/main/java/eu/kanade/tachiyomi/widget/preference/LoginDialogPreference.kt
2020-11-29 00:23:09 -05:00
arkon c9c808a782 Replace Kotlin synthetic views in viewholders
(cherry picked from commit 749c2071af)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/ExtensionHolder.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/manga/MangaHolder.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/sources/SelectionHeader.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/sources/SourceHolder.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourceHolder.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/SourceComfortableGridHolder.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/SourceGridHolder.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/SourceHolder.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/SourceListHolder.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryComfortableGridHolder.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCompactGridHolder.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryHolder.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChapterHolder.kt
2020-11-29 00:23:08 -05:00
Jobobby04 6f9edb7903 Add this back 2020-11-29 00:23:08 -05:00
arkon 7017b7b3ea Replace more usages of Kotlin synthetic views
(cherry picked from commit 322d66d282)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt
2020-11-29 00:23:07 -05:00
arkon 65cf11ec10 Fix keyboard sometimes affecting bottom inset padding
(cherry picked from commit aa98cd0da0)
2020-11-29 00:23:07 -05:00
arkon 02946af081 Move NSFW source setting into Browse settings
(cherry picked from commit c8316c7254)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsMainController.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/setting/search/SettingsSearchHelper.kt
2020-11-29 00:23:06 -05:00
arkon 2b627128a6 Fall back to filename in backup creation notification if path not available
(cherry picked from commit 6b9180844d)
2020-11-29 00:23:06 -05:00
arkon efa1f47392 Fix restore in Android 11
(cherry picked from commit c0e4863229)
2020-11-29 00:23:05 -05:00
arkon 3f55759b8b Distinguish between no results and loading when sorting global search results
(cherry picked from commit 2be9871d05)
2020-11-29 00:23:05 -05:00
arkon 41433eb262 More bottom inset padding fixes
(cherry picked from commit 776f6a9a16)
2020-11-29 00:23:04 -05:00
Jobobby04 160d6ea013 Replace more menu Tachi logo with SY logo 2020-11-29 00:23:03 -05:00
CrepeTF ac31f12138 Cool gray theme (#169)
* Added "Cool gray" (Google gray)

* Added "Cool gray" (Google gray) theme
2020-11-27 13:14:31 -05:00
arkon 9f542aaed4 Use jcenter to get 1.x dependencies
(cherry picked from commit 10163aab21)
2020-11-27 13:11:25 -05:00
arkon ec31d8605a Handle bottom insets in FAB controllers too
(cherry picked from commit 60b2a4ea9d)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt
2020-11-27 13:10:32 -05:00
Jobobby04 ad38a79752 Use a shared flow for the exh redirect to latest 2020-11-27 13:01:58 -05:00
Jobobby04 643aa377bf Update XLog 2020-11-26 19:12:00 -05:00
Jobobby04 fcc2b1773b Update firebase 2020-11-25 15:49:33 -05:00
Jobobby04 92970bb812 Log to file cleanup 2020-11-25 15:13:06 -05:00
arkon 7129b79785 Further abstract how bottom navbar padding is applied
(cherry picked from commit 56e1e3e205)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourceController.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryView.kt
2020-11-25 15:12:35 -05:00
arkon 6aaa9dcdb7 Handle bottom navbar padding when drawing edge to edge
(cherry picked from commit 0f805cd45e)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourceController.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryView.kt
2020-11-25 15:07:38 -05:00
arkon 5c76faa638 Create extension function for applying system insets
(cherry picked from commit 1d7c692e89)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt
2020-11-25 15:05:57 -05:00
arkon 0f6745d4a3 Add global search progress bar (closes #3727)
(cherry picked from commit 38bc8ec6b4)
2020-11-25 15:05:10 -05:00
arkon 438646727e Remove 10 results per source limit from global search (still limited to 1 page)
(cherry picked from commit 2154e3aa2d)
2020-11-25 15:04:45 -05:00
arkon bb7b79a6e9 Add help shortcut for source migration (closes #3951)
(cherry picked from commit 56c19e57a9)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/sources/MigrationSourcesController.kt
2020-11-25 15:04:32 -05:00
arkon d0293fef0a Fix transparent navbar when bottom sheets are opened (fixes #3848)
(cherry picked from commit d548c690d6)
2020-11-25 14:59:44 -05:00
arkon 0228d4611a Use ViewCompat for setting MainActivity inset paddings
(cherry picked from commit 3fa70dade3)
2020-11-25 14:59:34 -05:00
arkon f594ee66e5 More restore code cleanup
(cherry picked from commit 368c30a2cc)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/data/backup/AbstractBackupRestore.kt
#	app/src/main/java/eu/kanade/tachiyomi/data/backup/full/FullBackupRestore.kt
#	app/src/main/java/eu/kanade/tachiyomi/data/backup/legacy/LegacyBackupRestore.kt
2020-11-25 14:59:24 -05:00
arkon 610cad3bc5 Update Firebase
(cherry picked from commit 5539e4591f)
2020-11-25 14:52:20 -05:00
arkon b25e604bc2 Set preview/experimental compiler flags instead of using annotations
(cherry picked from commit 781971ee81)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt
2020-11-25 14:52:06 -05:00
arkon b4be82d021 Pad bottom of MoreController so bottom nav doesn't overlap content
(cherry picked from commit 1140316d1b)
2020-11-21 18:13:15 -05:00
Jobobby04 9985646e58 Lint 2020-11-21 16:54:33 -05:00
arkon 383a797469 Some more code cleanup
(cherry picked from commit cf6c48744a)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/data/backup/AbstractBackupRestore.kt
#	app/src/main/java/eu/kanade/tachiyomi/data/backup/full/FullBackupManager.kt
#	app/src/main/java/eu/kanade/tachiyomi/data/backup/full/FullBackupRestore.kt
#	app/src/main/java/eu/kanade/tachiyomi/data/backup/legacy/LegacyBackupManager.kt
#	app/src/main/java/eu/kanade/tachiyomi/data/backup/legacy/LegacyBackupRestore.kt
2020-11-21 16:53:42 -05:00
arkon 692e7e17d8 Default automatic legacy backups to true for now
(cherry picked from commit eed6db8e92)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt
2020-11-21 16:34:29 -05:00
arkon 978acec659 Some more code cleanup
(cherry picked from commit 858664bfd7)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/data/backup/full/FullBackupManager.kt
#	app/src/main/java/eu/kanade/tachiyomi/data/backup/legacy/LegacyBackupManager.kt
2020-11-21 16:33:45 -05:00
arkon 22019a8046 Merge restore entry points, avoid unnecessary new strings
(cherry picked from commit eceac4d6e3)
2020-11-21 16:31:37 -05:00
arkon b456d69aec Remove "full_" from v3 backup default file names
(cherry picked from commit 47a172df1f)
2020-11-21 16:31:27 -05:00
arkon a5abdaa5b1 Minor cleanup
(cherry picked from commit f2c0732c40)
2020-11-21 16:31:18 -05:00
arkon 8156804f7a Fix manga info description scrim on Android 5
(cherry picked from commit a150762c63)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoHeaderAdapter.kt
2020-11-21 16:30:59 -05:00
arkon be6f9d4a9f Fix non-transparent navigation bar
(cherry picked from commit 2695bdddf8)
2020-11-21 16:28:23 -05:00
Dominik Chrástecký 61b0039a78 add support for S Pen actions (#4029)
(cherry picked from commit c9b1a425a7)
2020-11-21 16:28:14 -05:00
arkon 72e95ea6fc Draw under navbar in Android 9+
(cherry picked from commit 122b2b1a8e)
2020-11-21 16:28:03 -05:00
arkon d6e7c1851b Update AGP for AS 4.1.1
(cherry picked from commit 2351c1b426)
2020-11-21 16:27:52 -05:00
arkon 99a27376d6 Remove TravisCI build config
(cherry picked from commit 0b5128dfd1)
2020-11-21 16:27:22 -05:00
arkon 97452ba9c8 Remove a stray trailing dash
(cherry picked from commit c0519e8670)
2020-11-21 16:27:14 -05:00
arkon 197019c65b Update dependencies
(cherry picked from commit fd545db1bd)
2020-11-21 16:27:02 -05:00
arkon 2b9c25cf71 Tweak manga info header
(cherry picked from commit 6991c224b2)

# Conflicts:
#	app/src/main/res/layout/manga_info_header.xml
2020-11-21 16:26:48 -05:00
arkon 76330f51c9 Add 1.x page model converters
(cherry picked from commit 7dc70c9eab)
2020-11-21 16:25:17 -05:00
arkon 3898a72cf8 Hide locale subtitle for local source
(cherry picked from commit e32445f2cf)
2020-11-21 16:25:07 -05:00
Jobobby04 1e98b09f24 Use more core-ktx 2020-11-21 16:24:16 -05:00
Jobobby04 2bece67f6e Fix Mangadex random button not showing results for some manga because they have no chapters 2020-11-13 22:48:08 -05:00
Jobobby04 7978dc9d2c Fix Mangadex random button returning the same result multiple times 2020-11-13 22:48:08 -05:00
jobobby04 9e41605512 [SKIP CI] Move back to r0adkll's sign release 2020-11-12 19:35:04 -05:00
Jobobby04 6e8ac9cc10 Fix Full backup, DELETE ALL FULL BACKUPS MADE BEFORE THIS UPDATE 2020-11-12 14:58:58 -05:00
Jobobby04 0594efb1c8 Cleanup 2020-11-11 17:30:38 -05:00
Jobobby04 a35e7871e8 Enhance file logging 2020-11-11 17:28:54 -05:00
Jobobby04 67aafab46a Forgot to commit this 2020-11-08 15:11:42 -05:00
Jobobby04 89a20be7ef Fix E-H Sync favorites getting stuck 2020-11-08 15:02:26 -05:00
Jobobby04 a4e05f297c Fix icon tint for share and save cover 2020-11-07 14:44:04 -05:00
Jobobby04 803ee3d547 Fix mangadex login dialog crash 2020-11-06 18:19:11 -05:00
Jobobby04 c6b0d0c9a5 Update SY french translation(From Adam-sama) 2020-11-06 15:50:46 -05:00
Jobobby04 d1887d4847 New Icon! Thanks to Aytox who made it! 2020-11-06 15:50:44 -05:00
Jobobby04 e987ba8c3e Lets try this out for full backup categories 2020-11-06 14:24:55 -05:00
Jobobby04 acefd33e2e Cleanup 2020-11-06 14:24:28 -05:00
Jobobby04 319c41905e Update latest tab with the new global search update 2020-11-05 00:31:00 -05:00
Jobobby04 079dd953bd Replace elvis operators with .orEmpty where possible 2020-11-04 22:10:13 -05:00
Jobobby04 015c610205 Use stable versions of RxUtil functions 2020-11-04 21:44:08 -05:00
Jobobby04 56ef3fd018 Remove unused values 2020-11-04 21:41:06 -05:00
arkon fe064a067e Update to serialization 1.0.1 and coroutines 1.4.1
(cherry picked from commit 8aa6486bf7)

# Conflicts:
#	app/build.gradle
2020-11-04 21:03:17 -05:00
arkon f283fbfd6f Singleton instance of Json serializer
(cherry picked from commit d21c147203)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/AppModule.kt
2020-11-04 21:01:55 -05:00
arkon 505a0db164 Fix Bangumi login (fixes #3994)
(cherry picked from commit 9b10e851d1)
2020-11-04 21:01:16 -05:00
arkon 4d00b2f8ce Update dependencies
(cherry picked from commit 6675508b24)

# Conflicts:
#	app/build.gradle
2020-11-04 21:01:07 -05:00
arkon c2ccbe5aff Use 1.x API to fetch manga details in browse view
(cherry picked from commit 7310ec4fe4)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourcePresenter.kt
2020-11-04 20:59:51 -05:00
Andreas E 98dade1b4d Change list view font size back to 16sp (#3978)
Make list view font size bigger again

(cherry picked from commit b1ce3693ed)
2020-11-04 20:58:51 -05:00
arkon eed7ef0aa8 Add Uzbek locale
(cherry picked from commit deb1ed5623)
2020-11-04 20:58:41 -05:00
Jozef Hollý 3f71795d05 Weblate translations (#3895)
Co-authored-by: Adam <bessaa935@gmail.com>
Co-authored-by: Ashraf Is <rediancool@gmail.com>
Co-authored-by: Ashraf Isl <rediancool@gmail.com>
Co-authored-by: C201 <derasetad@gmail.com>
Co-authored-by: Credits125Cre <credits125@gmail.com>
Co-authored-by: Eduard Ereza Martínez <eduard@ereza.cat>
Co-authored-by: Eva Godoy <godoytraduccion@gmail.com>
Co-authored-by: Hara Desu <aqjbgr09@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Huang Zhiyi <hzy980512@126.com>
Co-authored-by: Jozef Hollý <j2.00ghz@gmail.com>
Co-authored-by: Kurocon <weblate@kurocon.nl>
Co-authored-by: Luka Paun <croluxgame@gmail.com>
Co-authored-by: Lyaiya <hipsnafoha@outlook.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: Mubarek Seyd Juhar <mubareksej@gmail.com>
Co-authored-by: Nico <nicknicola94@gmail.com>
Co-authored-by: Paulo Pinho <kebrus@gmail.com>
Co-authored-by: Pitpe11 <giorgos2550@gmail.com>
Co-authored-by: Pxeexe <johongira192@gmail.com>
Co-authored-by: Rostyslav <info@ubilling.net.ua>
Co-authored-by: Ruud Schouten <ruud.schouten@outlook.com>
Co-authored-by: Salem Almashaikhi <salemnabil1@outlook.com>
Co-authored-by: darkbeast13 <nikhil15mps@gmail.com>
Co-authored-by: f0roots <f0rootss@gmail.com>
Co-authored-by: opb <myniceaddress@outlook.com>
Co-authored-by: İlle <derasetad@gmail.com>
Co-authored-by: Роман <Rozhenkov69@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/am/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ar/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/bn/
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/cv/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/el/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/es_419/
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/hi/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/hr/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/id/
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/nl/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pl/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pt/
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/uk/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/uz/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/zh_Hant/
Translation: Tachiyomi/Strings

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Adam <bessaa935@gmail.com>
Co-authored-by: Ashraf Is <rediancool@gmail.com>
Co-authored-by: C201 <derasetad@gmail.com>
Co-authored-by: Credits125Cre <credits125@gmail.com>
Co-authored-by: Eduard Ereza Martínez <eduard@ereza.cat>
Co-authored-by: Eva Godoy <godoytraduccion@gmail.com>
Co-authored-by: Hara Desu <aqjbgr09@gmail.com>
Co-authored-by: Huang Zhiyi <hzy980512@126.com>
Co-authored-by: Kurocon <weblate@kurocon.nl>
Co-authored-by: Luka Paun <croluxgame@gmail.com>
Co-authored-by: Lyaiya <hipsnafoha@outlook.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: Mubarek Seyd Juhar <mubareksej@gmail.com>
Co-authored-by: Nico <nicknicola94@gmail.com>
Co-authored-by: Paulo Pinho <kebrus@gmail.com>
Co-authored-by: Pitpe11 <giorgos2550@gmail.com>
Co-authored-by: Pxeexe <johongira192@gmail.com>
Co-authored-by: Rostyslav <info@ubilling.net.ua>
Co-authored-by: Ruud Schouten <ruud.schouten@outlook.com>
Co-authored-by: Salem Almashaikhi <salemnabil1@outlook.com>
Co-authored-by: darkbeast13 <nikhil15mps@gmail.com>
Co-authored-by: f0roots <f0rootss@gmail.com>
Co-authored-by: opb <myniceaddress@outlook.com>
Co-authored-by: Роман <Rozhenkov69@gmail.com>
(cherry picked from commit 0902d7cca9)
2020-11-04 20:58:32 -05:00
arkon d9b41ce4c5 Fix Bangumi API response deserialization (fixes #3977)
(cherry picked from commit 95ec903862)
2020-11-04 20:58:22 -05:00
arkon 195dbbf1c2 Consume and extend 1.x Source API
TODO: make the rest of the app actually call the 1.x functions
(cherry picked from commit 2ab6af6471)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/source/model/SManga.kt
2020-11-04 20:58:14 -05:00
Andreas E c12fb337f5 Replace language code in Global Search with secondary text (#3972)
Replace language code in Global Search with secondary text

(cherry picked from commit 9493577de2)
2020-11-04 20:56:45 -05:00
Jobobby04 4a4cdcb682 Add french translation for SY strings 2020-11-04 20:52:24 -05:00
Jobobby04 76de2d4447 Bind to the correct dialog view, fixed manga info edit crash 2020-11-04 17:18:10 -05:00
Jobobby04 7cbd7bd419 Cleanup 2020-11-01 19:19:57 -05:00
Jobobby04 8f1f6d5a97 Fix mangadex update interval not updating the interval on first click 2020-10-31 22:04:54 -04:00
Jobobby04 98bfe34e18 Update lewd manga checker with new sources and tags 2020-10-31 17:33:59 -04:00
Jobobby04 95c331b8b4 Convert all SY specific things to use ViewBindings instead of synthetics 2020-10-29 23:43:24 -04:00
Jobobby04 528f6c7f65 Drop humanize and guava(an older version still gets compiled in), use custom humanize solution for E-Hentai updater stats 2020-10-29 23:41:54 -04:00
Jobobby04 fe798e40cb Remove kotlin synthetics from E-Hentai settings 2020-10-29 21:52:27 -04:00
Jobobby04 133fe61408 Change manga edit to say Edit info 2020-10-29 21:50:44 -04:00
Jobobby04 3b5249c8bc Convert java threads to kotlin coroutines 2020-10-29 15:29:43 -04:00
Jobobby04 46998d81f4 Do a bit of cleanup 2020-10-29 15:28:48 -04:00
Jobobby04 fccf609c81 Fix NHentai covers 2020-10-29 14:25:37 -04:00
Jobobby04 406b5a89c8 Fix smart background for real this time, fix issues with theme not changing 2020-10-29 00:37:07 -04:00
Jobobby04 4881571293 Big refactor for the E-Hentai config builder, I sucked when making my additions, now its better 2020-10-29 00:13:25 -04:00
Jobobby04 9cba544ffd Refactor and cleanup a bunch of code 2020-10-27 23:05:53 -04:00
Jobobby04 114fb723dc Trim Mangadex descriptions, fixes extra blank lines 2020-10-27 17:59:21 -04:00
Jobobby04 8e03375664 Deeplink using pathPattern instead of pathPrefix 2020-10-26 21:53:31 -04:00
Jobobby04 6142e9be1c More mangadex deeplink tweaks 2020-10-26 21:51:28 -04:00
Jobobby04 24be0aa50b For E-Hentai manga display chapter date with the E-Hentai date format 2020-10-26 19:40:12 -04:00
Jobobby04 a7cfae1603 Mangadex deeplink tweaks 2020-10-26 19:39:37 -04:00
Jobobby04 079405c17e More tweaks to delegated manga views 2020-10-26 19:23:59 -04:00
Jobobby04 105302aa7b Fix delegated sources trying to always open in SY, even with links SY doesnt support 2020-10-26 14:53:48 -04:00
Jobobby04 05269c557d Make TF happy, cleanup the more info menu 2020-10-26 14:28:56 -04:00
Jobobby04 35217036ce Fix chapters in delegated manga where you haven't filtered any groups 2020-10-26 13:07:55 -04:00
Jobobby04 eb3a987826 Implement Neko similar manga, Mangadex only recommendations 2020-10-26 02:13:02 -04:00
Jobobby04 3f1dede133 Fix a oppsies 2020-10-25 23:41:15 -04:00
Jobobby04 e9cef78d19 Filter scanlators on delegated manga 2020-10-25 20:24:30 -04:00
Jobobby04 32232c80aa Extra info updates 2020-10-25 20:19:02 -04:00
Jobobby04 112bbdfcf7 Remove outdated comment 2020-10-25 18:12:36 -04:00
Jobobby04 415f30f38a Manga metadata is now easier to use in the manga view 2020-10-25 13:37:08 -04:00
Jobobby04 2a24f659d2 Disable things that dont work how I want them to 2020-10-24 23:56:40 -04:00
Jobobby04 484cb86ca9 Cleanup 2020-10-24 22:53:43 -04:00
Jobobby04 a21d7f4f90 Request a new image from E-Hentai if it fails to download, should make E-Hentai downloads more relaible 2020-10-24 22:00:45 -04:00
Jobobby04 a75cf8ec53 Attempt a new way to move chapters between EH manga versions 2020-10-24 21:59:56 -04:00
Jobobby04 b252a9e060 Fixed EH update helper crashes 2020-10-24 19:41:16 -04:00
Jobobby04 fa7c6716f4 Remove EH legacy code 2020-10-24 19:07:46 -04:00
Jobobby04 99b1f6e56f Cleanup 2020-10-24 19:07:16 -04:00
Jobobby04 a2cda24e01 Fix broken menu after clicking source, move latest to the top 2020-10-24 17:17:00 -04:00
Jobobby04 c049ce9018 Convert E-Hentai Update helper to Flows 2020-10-24 16:44:20 -04:00
Jobobby04 1a0109df1d Cleanup 2020-10-24 15:44:52 -04:00
Jobobby04 c999229700 Use bundleOf everywhere I can 2020-10-24 14:28:03 -04:00
arkon 86fc50d62b Janky workaround for collapsed global search covers
(cherry picked from commit 837ce62844)
2020-10-24 14:15:19 -04:00
Andreas E b9bddd264b Update Global search layout to match Library and Browse (#3892)
* Update Global Search card item to be comfortable with rounded corners

* Remove card background

(cherry picked from commit a2b1acd70f)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/GlobalSearchCardHolder.kt
#	app/src/main/res/layout/global_search_controller_card.xml
#	app/src/main/res/layout/global_search_controller_comfortable_card_item.xml
2020-10-24 14:08:28 -04:00
Andreas E 4937c7fff2 Fix missing chapter warning when chapter number is not recognized (#3928)
* Fix missing chapter warning when chapter number is not recognized

* Add case where ch number is recognized as zero but has no ch number

Yes this will ignore ch 0

* Use RegEx to double check if ch. name contains potential ch. number

(cherry picked from commit f1350bc33e)
2020-10-24 13:41:22 -04:00
arkon 6419d79960 Fix Shikimori login (closes #3966)
(cherry picked from commit 6af0eb4068)
2020-10-24 13:41:13 -04:00
arkon 295fe37a9d Use default height for extended FAB (closes #3949)
(cherry picked from commit 538c168641)
2020-10-24 13:41:04 -04:00
arkon 3ff2321a95 Lower minWidth for extended FAB (fixes #3939)
(cherry picked from commit 832a4fa68e)
2020-10-24 13:40:54 -04:00
arkon 8322f7b95f Show locale in sources list items
(cherry picked from commit ed41604f56)
2020-10-24 13:40:40 -04:00
Jobobby04 3ed0ef5e3e Cleanup 2020-10-24 13:39:28 -04:00
Jobobby04 b850a8729f Remove old backup code I tried for dummy restore 2020-10-24 13:39:04 -04:00
Jobobby04 024a39d06b Lets try this for sort by tag performance 2020-10-24 13:38:45 -04:00
Jobobby04 01496ab34c Cleanup some merged manga code 2020-10-24 13:38:25 -04:00
Jobobby04 9a45891ed6 Fix saving cover putting it in a weird folder, cleanup 2020-10-21 23:02:32 -04:00
Jobobby04 5e531ba469 Put manga metadata into backups 2020-10-21 23:01:57 -04:00
Jobobby04 cb6a991e9f Fix share cover name, make ainz happy by hiding other options 2020-10-21 17:03:15 -04:00
Jobobby04 96989bfa53 Likely fix smart background 2020-10-21 14:59:39 -04:00
Jobobby04 b1048d8014 Fix migrate extra data like chapter filters and viewer 2020-10-20 16:13:34 -04:00
Jobobby04 89d9768759 Re-add some stuff from EH that I lost along the way 2020-10-19 21:05:24 -04:00
Jobobby04 1dfe3890a9 Add intercept activity source choosing 2020-10-19 18:41:41 -04:00
Jobobby04 a4a1c2827c Fix some backup duplication issues 2020-10-19 18:39:08 -04:00
Jobobby04 0b68bb20a8 Copy categories over from the original manga to the merged manga 2020-10-19 16:08:11 -04:00
Jobobby04 a8b1e8fdb0 Switch to the Mangadex extension for the low quality covers setting 2020-10-19 15:47:14 -04:00
Jobobby04 9945752667 Support the short title setting in NHentai 2020-10-19 15:46:08 -04:00
Jobobby04 05c2b43ffb Fix the release builder for AGP 4.1.0 2020-10-19 00:46:00 -04:00
Jobobby04 b2cd5648bb Update to android gradle plugin 4.1.0 to see if I fixed the action 2020-10-18 23:12:20 -04:00
Jobobby04 853f195d0e Hide biometric lock times when biometric lock is not enabled 2020-10-17 17:07:35 -04:00
Jobobby04 a481f3239c Throttle E-Hentai migrations 2020-10-16 19:33:24 -04:00
Jobobby04 510ae46fbf Lint 2020-10-15 11:27:56 -04:00
Jobobby04 c3a5439d26 Fixes for delete if in category 2020-10-15 11:27:30 -04:00
Jobobby04 a4273bb9a2 Add share/save manga cover when expanded from J2k, not tested 2020-10-15 11:26:39 -04:00
Carlos 0b6f7c5e23 Add push to mangadex
(cherry picked from commit 869f24f2092c761bc2a7bf075784bc8b7cbaea23)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt
#	app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateService.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsSiteController.kt
#	app/src/main/res/values/strings_neko.xml
2020-10-14 18:43:27 -04:00
Jobobby04 c789203ff8 fix some mangadex manga not being marked as complete in status 2020-10-14 17:48:12 -04:00
Carlos 7f73094bb4 follows sort yolo
(cherry picked from commit 097d44ef35b021ba11e164f45234356fd8395540)

# Conflicts:
#	app/src/main/java/exh/md/handlers/FollowsHandler.kt
2020-10-14 17:43:40 -04:00
Jobobby04 a2a21bbbb7 Fix strings(again) 2020-10-14 17:36:51 -04:00
Jobobby04 c42e8739f6 Move some functions to the abstract backup manager 2020-10-14 17:36:22 -04:00
Jobobby04 d9ce86aca6 Dedupe some code, move over read and bookmarks properly 2020-10-14 15:19:46 -04:00
Jobobby04 f4200e2146 Rewrite backup categories 2020-10-14 14:15:14 -04:00
Jobobby04 e32f4eb317 Replace migrate button with merge 2020-10-14 14:06:05 -04:00
Jobobby04 e7c16cd0d1 Also apply changes to online restore 2020-10-14 13:15:54 -04:00
Jobobby04 f91d1af373 Dont break after finding one chapter 2020-10-14 13:10:24 -04:00
Jobobby04 326dc27009 Find chapter based on the url 2020-10-14 13:05:52 -04:00
Jobobby04 0a790c3c25 Fix grammer 2020-10-14 13:05:36 -04:00
Jobobby04 f6fd8a8ddb Make offline the default 2020-10-14 12:46:39 -04:00
Jobobby04 413c88d99f Fix backups always loading the full backup restore mode, even when legacy restore was used 2020-10-13 23:29:21 -04:00
Jobobby04 d15a473ed1 Enable the proguard rules 2020-10-13 21:53:23 -04:00
Jobobby04 c31beccf3c Lets try this 2020-10-13 21:33:34 -04:00
Jobobby04 f92c09b0f6 More comments 2020-10-13 20:55:18 -04:00
Jobobby04 5b056c6b70 Comment it all out 2020-10-13 20:27:36 -04:00
Jobobby04 2281a7a03d Comment out even more for a test 2020-10-13 17:23:43 -04:00
Jobobby04 713dcdfe53 Comment out some new rules for testing 2020-10-13 16:51:47 -04:00
Jobobby04 f3fc479020 Revert temp fixes, add serialization progurd rules
This reverts commit 543e089982.
2020-10-13 13:49:28 -04:00
Soitora 13196a68b1 Darken the description colors (#3858)
* Darken the description colors

* Restore UpdatesHolder.kt

* Use the same color as the Extensions subtitles

(cherry picked from commit 9f05d563f9)
2020-10-13 12:39:14 -04:00
arkon 90452a7833 Use secondary color for manga info header action button default state
(cherry picked from commit 72d114d46a)
2020-10-13 12:39:00 -04:00
Taco 8722c1806e Use some more KTX and Compat stuff (#3933)
* Use more KTX extensions

* Update Android Studio

* Use more Compat classes

(cherry picked from commit 60755d0c26)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestoreService.kt
#	app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateService.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsBackupController.kt
2020-10-13 12:38:23 -04:00
Jobobby04 543e089982 Revert the converter factory back to gson 2020-10-13 11:43:46 -04:00
Jobobby04 b67db6a25e Manually deserialize saved searches, fix NHentai 2020-10-13 11:34:29 -04:00
Jobobby04 3dd10df45e Likely fixed the full backup crashing for some users 2020-10-12 23:03:38 -04:00
Jobobby04 22f81758b0 Refactor custom manga info manager 2020-10-12 22:35:45 -04:00
Jobobby04 405b0580fc Implement exclude categories from deletion 2020-10-12 22:11:16 -04:00
Jobobby04 eea1f696ca Update dependencies 2020-10-12 21:52:20 -04:00
Jobobby04 7e93557bd2 Remove markwan dependancy 2020-10-12 21:50:06 -04:00
Jobobby04 36c0d24143 Cleanup 2020-10-12 20:20:42 -04:00
jobobby04 445878794c Make a protobuf based backup system (#112)
* Make a protobuf based backup system, restore not tested

* Fix a number

* Remove uneeded change

* Remove more uneeded changes

* Use 1.x style models, backup should be 100% compatible with the 1.x backups

* Fix restore service not running

* Fix offline chapter restore
Cleanup saved searches restore(untested)

* Implement onlione/offline option, fix merged manga restore online, fix restore total

* Allow setting auto backup to use a full backup

* Fix for saved searches restore

* Edit some comments

* Convert flows back to observables

* Fix a model

* Fixes and comment only the SY specific things

* Move SY values range to 600 from 60

* Combine legacy and full backup services into one
Deduplicate a lot of code
Simplify a lot of stuff
Modify comments

* Cleanup

* Remove unneeded protobuf config edit because its now the default

* Migrate to kotlinx.serialization for backup saved searches

* Cleanup saved searches more, move gson type adapters to the legacy package
2020-10-12 14:41:56 -04:00
Jobobby04 f3365cef67 Convert SY specific usages of Gson to Kotlin Serialization
Cleanup saved searches a bit
Cleanup json parsing
2020-10-12 14:20:54 -04:00
arkon bbfce97125 Trust user-added CAs (closes https://github.com/inorichi/tachiyomi-extensions/issues/4581)
(cherry picked from commit a689e4e041)
2020-10-11 16:07:35 -04:00
arkon 232f5b8aab Migrate to kotlinx.serialization for Bangumi
(cherry picked from commit f5aa36c787)
2020-10-11 16:07:24 -04:00
arkon 4f575f37c0 Migrate to kotlinx.serialization for Shikimori
(cherry picked from commit f8d82cb052)
2020-10-11 16:07:11 -04:00
arkon 5b4f17777c Migrate to kotlinx.serialization for download store and deleter
(cherry picked from commit 980feb6c96)
2020-10-11 15:53:50 -04:00
arkon 38c3a926bb Migrate to kotlinx.serialization for Anilist
(cherry picked from commit e7d6605490)
2020-10-11 15:53:42 -04:00
arkon b4cf0e9723 Migrate to kotlinx.serialization for extensions and update fetching
(cherry picked from commit 7a476abb53)

# Conflicts:
#	build.gradle.kts
2020-10-11 15:53:27 -04:00
arkon 4d64734dec [SKIP CI] Remove dev build logic from Travis CI config (#3873)
(cherry picked from commit 19581792fc)

# Conflicts:
#	.travis/build.sh
2020-10-11 15:37:19 -04:00
specterflare 30d3d88d03 [SKIP CI] Replace dead link in README with correct one (#3929)
(cherry picked from commit aadc6a56cd)

# Conflicts:
#	README.md
2020-10-11 15:36:13 -04:00
arkon 57803bce2f Bump minimum WebView version to 84
(cherry picked from commit b88e444cbc)
2020-10-11 15:34:53 -04:00
arkon 6d235e23ff Update dependencies
(cherry picked from commit 6c792d2821)
2020-10-11 15:34:34 -04:00
arkon 428720fb74 Update AboutLibraries
(cherry picked from commit 9afb445620)

# Conflicts:
#	build.gradle.kts
2020-10-11 15:34:15 -04:00
jobobby04 f32ccf1c6d Remove pong 2020-10-10 01:01:39 -04:00
Jobobby04 776a4b2a24 History fixes 2020-10-10 00:32:39 -04:00
Jobobby04 883af56a9a Do some work on the workflows 2020-10-09 13:19:51 -04:00
arkon a9279fbb2e Cancel previous CI workflow runs
(cherry picked from commit a249373bf5)

# Conflicts:
#	README.md
2020-10-09 13:06:13 -04:00
arkon 6dc55a3fc4 Use eskatos/gradle-command-action instead of manually handling caching
(cherry picked from commit e1eb030b18)

# Conflicts:
#	.github/workflows/build_check.yml
2020-10-09 13:04:43 -04:00
Aakash Singh f0e2367071 skip ci in commit message condition check (#3902)
* skip ci condition check

* always Validate Gradle Wrapper

* naming workflow jobs

(cherry picked from commit 6aea0f48ed)

# Conflicts:
#	.github/workflows/build_check.yml
2020-10-09 13:04:02 -04:00
arkon 8e27ffcad7 Add Amharic locale
(cherry picked from commit 842295348e)
2020-10-09 13:02:30 -04:00
Jozef Hollý 856a149032 Translations (Continuous) (#3886)
* Weblate translations

Co-authored-by: Ajeje Brazorf <lmelonimamo@yahoo.it>
Co-authored-by: Alessandro Jean <alessandrojean@gmail.com>
Co-authored-by: Alessandro Zangrandi <alessandro@mzit.it>
Co-authored-by: Alex <linuxrf@gmail.com>
Co-authored-by: Allan Nordhøy <epost@anotheragency.no>
Co-authored-by: Ava <Sasu.ruotsalainen@live.fi>
Co-authored-by: DarKCroX <darkcrox.2020@outlook.com>
Co-authored-by: Eduard Ereza Martínez <eduard@ereza.cat>
Co-authored-by: Eric <spice2wolf@gmail.com>
Co-authored-by: Félix D <felix.desmaretz@protonmail.com>
Co-authored-by: Hara Desu <aqjbgr09@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Huang Zhiyi <hzy980512@126.com>
Co-authored-by: Josh Ciardi <jbciardi@gmail.com>
Co-authored-by: Juan Aranda <juan50055005@gmail.com>
Co-authored-by: Kurocon <weblate@kurocon.nl>
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: Mubarek Juhar <mubareksej@gmail.com>
Co-authored-by: Nikita Epifanov <nikgreens@protonmail.com>
Co-authored-by: Nin Gun <luis_noxer@hotmail.es>
Co-authored-by: Oğuz Ersen <oguzersen@protonmail.com>
Co-authored-by: Paulo Pinho <kebrus@gmail.com>
Co-authored-by: Pitpe11 <giorgos2550@gmail.com>
Co-authored-by: Redya Rachmandanu <redyarachmandanu@gmail.com>
Co-authored-by: Rostyslav <info@ubilling.net.ua>
Co-authored-by: Salem Almashaikhi <salemnabil1@outlook.com>
Co-authored-by: Samuel Carvalho de Araújo <samuelnegro12345@gmail.com>
Co-authored-by: Shashank Pujari <shashankppujari@gmail.com>
Co-authored-by: Simon Mattila <simon.mattila@protonmail.com>
Co-authored-by: Yassin El Aoud <yassinelaoud@gmail.com>
Co-authored-by: abidin toumi <abidin24@disroot.org>
Co-authored-by: darkbeast13 <nikhil15mps@gmail.com>
Co-authored-by: f0roots <f0rootss@gmail.com>
Co-authored-by: monolifed <monolifed@protonmail.com>
Co-authored-by: ssantos <ssantos@web.de>
Co-authored-by: İlle <derasetad@gmail.com>
Co-authored-by: Роман <Rozhenkov69@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/am/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ar/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ca/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/cv/
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/en_US/
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/hi/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/hr/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/id/
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/kn/
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/nl/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pt/
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/sv/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/tr/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/uk/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/zh_Hant/
Translation: Tachiyomi/Strings

* Deleted translation using Weblate (Belarusian)

* Deleted translation using Weblate (Bengali (Bangladesh))

* Deleted translation using Weblate (Spanish (Mexico))

* Deleted translation using Weblate (Tigrinya)

* Deleted translation using Weblate (English (United States))

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: Alessandro Zangrandi <alessandro@mzit.it>
Co-authored-by: Alex <linuxrf@gmail.com>
Co-authored-by: Allan Nordhøy <epost@anotheragency.no>
Co-authored-by: Ava <Sasu.ruotsalainen@live.fi>
Co-authored-by: DarKCroX <darkcrox.2020@outlook.com>
Co-authored-by: Eduard Ereza Martínez <eduard@ereza.cat>
Co-authored-by: Eric <spice2wolf@gmail.com>
Co-authored-by: Félix D <felix.desmaretz@protonmail.com>
Co-authored-by: Hara Desu <aqjbgr09@gmail.com>
Co-authored-by: Huang Zhiyi <hzy980512@126.com>
Co-authored-by: Josh Ciardi <jbciardi@gmail.com>
Co-authored-by: Juan Aranda <juan50055005@gmail.com>
Co-authored-by: Kurocon <weblate@kurocon.nl>
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: Mubarek Juhar <mubareksej@gmail.com>
Co-authored-by: Nikita Epifanov <nikgreens@protonmail.com>
Co-authored-by: Nin Gun <luis_noxer@hotmail.es>
Co-authored-by: Oğuz Ersen <oguzersen@protonmail.com>
Co-authored-by: Paulo Pinho <kebrus@gmail.com>
Co-authored-by: Pitpe11 <giorgos2550@gmail.com>
Co-authored-by: Redya Rachmandanu <redyarachmandanu@gmail.com>
Co-authored-by: Rostyslav <info@ubilling.net.ua>
Co-authored-by: Salem Almashaikhi <salemnabil1@outlook.com>
Co-authored-by: Samuel Carvalho de Araújo <samuelnegro12345@gmail.com>
Co-authored-by: Shashank Pujari <shashankppujari@gmail.com>
Co-authored-by: Simon Mattila <simon.mattila@protonmail.com>
Co-authored-by: Yassin El Aoud <yassinelaoud@gmail.com>
Co-authored-by: abidin toumi <abidin24@disroot.org>
Co-authored-by: darkbeast13 <nikhil15mps@gmail.com>
Co-authored-by: f0roots <f0rootss@gmail.com>
Co-authored-by: monolifed <monolifed@protonmail.com>
Co-authored-by: ssantos <ssantos@web.de>
Co-authored-by: İlle <derasetad@gmail.com>
Co-authored-by: Роман <Rozhenkov69@gmail.com>
(cherry picked from commit 2992a0f4d8)
2020-10-09 13:02:21 -04:00
Aakash Singh c94e6c0304 Workflow improvements (#3891)
* add caching steps to build_check workflow

* add gradle.properites for github runner

* refactor ci-gradle.properties

* specify ndk versiion in build.gradle

* remove ndk install and cache steps from build_check

* moved runner files to separate folder

* refactor build_check.yml

(cherry picked from commit e8f5963a57)
2020-10-09 13:01:50 -04:00
Jobobby04 292dbf85c9 Cleanup 2020-10-09 12:59:40 -04:00
Jobobby04 96a5b456f5 Remove tooltip 2020-10-03 17:43:10 -04:00
jobobby04 05bcdadbd5 Merge pull request #125 from jobobby04/pr
Update to preview
2020-10-03 17:27:39 -04:00
arkon 95de42ad80 Prevent tag search if browsing from latest (sort of closes #3625)
(cherry picked from commit 4cbe497770)
2020-10-03 13:05:29 -04:00
Aakash Singh d26b8a9e41 Update issue_closer.yml (#3885)
Limit the issue_closer workflow to run only when the issue is opened, edited or reopened

(cherry picked from commit 76a53097b1)
2020-10-03 13:02:51 -04:00
arkon 8404b1c0c2 Set activated states for manga info favorite/tracker buttons
(cherry picked from commit 0904692f15)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoHeaderAdapter.kt
#	app/src/main/res/layout/manga_info_header.xml
2020-10-03 13:01:25 -04:00
arkon eef8b776f6 Reorder chapter filters to better match library filters
(cherry picked from commit 65bacd288b)
2020-10-03 12:58:26 -04:00
Andreas E 527e26137f Remove from queue after read (#3870)
* Add option to remove chapter from download queue after marked as read

* Begone bug

There was a bug when one queued a new download to the downloader. Which resulted in getChapterDownloadOrNull() would not find the corresponding download for the provided chapter

* Fix review comment

* Remove preference and just remove from queue

(cherry picked from commit 11ab3b2c2e)
2020-10-03 12:57:42 -04:00
Andreas E f6d3c38d03 Ability to delete reading history (#3871)
* Added ability to delete history for all manga

* Fix review comments

(cherry picked from commit 812368e332)
2020-10-03 12:57:29 -04:00
arkon 2772e4960e Add banner for Incognito Mode
(cherry picked from commit cf39ae0000)
2020-10-03 12:57:20 -04:00
arkon 085722e077 Show downloaded only banner in all views
(cherry picked from commit 7194f65203)
2020-10-03 12:57:10 -04:00
arkon 6a3a5c58d4 Minor string cleanup for Incognito Mode
(cherry picked from commit 4b78ff324d)
2020-10-03 12:57:01 -04:00
Platiplus e1d7713f14 [Feature Request] Option to turn off History - #3772 (#3855)
* Implementing do not save chapter history preference

* Refactor of labels

* Changing incognito mode from Readers section to More

* Fixing imports and removing unused strings

(cherry picked from commit 79ccfcd553)
2020-10-03 12:56:53 -04:00
arkon 925e9d9516 Update AndroidX dependencies
(cherry picked from commit 2df6a4dde8)
2020-10-03 12:54:58 -04:00
Jobobby04 a0cf7730f5 Undo some weird thing SY had 2020-10-02 22:01:25 -04:00
Unlocked e1fc94e6d3 Fix visual issue with bottom padding in filters sheet (#3881)
(cherry picked from commit 25d1c40cda)
2020-10-02 12:14:49 -04:00
arkon dc7a492d75 Update subsampling-scale-image-view
(cherry picked from commit 969b57ade9)
2020-10-02 12:14:18 -04:00
Jobobby04 63aab6f11e Fix deleting history not refreshing the view 2020-10-02 12:06:49 -04:00
Jobobby04 32748fa056 Allow migrating extra info like viewer, chapter filters, and other stuff 2020-10-01 22:12:37 -04:00
Jobobby04 1a55f4845c Fix manual search using browse's menu 2020-10-01 21:43:43 -04:00
Jobobby04 b4194de9e0 Fix SY filters not properly setting 2020-10-01 10:07:44 -04:00
Jobobby04 4f864152ea Cleanup some code 2020-09-30 19:48:26 -04:00
Jobobby04 c501c9ecc3 Modify the looks of the extra info for a few sources 2020-09-30 19:29:44 -04:00
Jobobby04 4bd88fa194 Add source categories removing the source in the language as a option 2020-09-30 18:27:09 -04:00
Jobobby04 604b4ec01e Fix expanding tags on E-Hentai and similar manga 2020-09-30 17:52:24 -04:00
Jobobby04 789f1392ac Fix clicking the updates button multiple times opening multiple download menus 2020-09-29 19:16:33 -04:00
Jobobby04 1b9c66896a Add a double click action on the updates bottom bar button to open downloads 2020-09-29 15:52:39 -04:00
Andreas E c6db5a01dd Fix color filter sheet content alignment (#3862)
Fix color filter sheet content alignment

(cherry picked from commit bddeb86223)
2020-09-29 12:41:56 -04:00
arkon 3a07ee3deb Fix chapter filter icon tinting
(cherry picked from commit b5986b509e)
2020-09-29 12:41:28 -04:00
jobobby04 9c76f1fd8f Match infinite history and search history from preview (#3827)
* Add infinite history and search history

* Cleanup code

(cherry picked from commit 9d2adcd512)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/data/database/queries/HistoryQueries.kt
#	app/src/main/java/eu/kanade/tachiyomi/data/database/queries/RawQueries.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/recent/history/HistoryController.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/recent/history/HistoryPresenter.kt
2020-09-29 12:41:10 -04:00
arkon 8acd834783 Use tristate checkboxes for chapters list filters
(cherry picked from commit fb3756420b)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt
2020-09-29 12:35:40 -04:00
arkon 7494033b90 Fix scrolled content being visible behind navigation view group
(cherry picked from commit 2eab43a669)
2020-09-29 12:26:30 -04:00
arkon 703263246e Clean up bottom nav bar scrolling behavior toggling
(cherry picked from commit caeab0a63b)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt
2020-09-29 12:26:21 -04:00
arkon 59020deb6f Tweak navigation view group header style
(cherry picked from commit 7c69b1b649)
2020-09-29 12:25:33 -04:00
scb261 2130a2a67e Add option to hide bottom bar when scrolling (#3758)
* [wip] hardcoded flag for hide on scroll

* add corresponding option in settings

* clean up a little

Co-authored-by: arkon <arkon@users.noreply.github.com>
(cherry picked from commit 3784d1a8f2)
2020-09-29 12:25:25 -04:00
scb261 a8946e4f98 Add ability to choose what to remove for selected mangas (#3796)
* [wip] started to change manga delete options

* Change dialog for deleting selected manga

* Move array to appropriate file

* Make first option enabled by default

* Use radio buttons to reduce amount of clicks

* Revert "Use radio buttons to reduce amount of clicks"

(cherry picked from commit 458e761b45)
2020-09-29 12:25:16 -04:00
arkon c59ca51944 Color selected bottom nav item with accent color when theme isn't blue
(cherry picked from commit 371b0b2132)
2020-09-29 12:25:05 -04:00
arkon ad03dfee97 Use same padding as source icons for extensions
(cherry picked from commit 5d1ca64768)
2020-09-29 12:24:55 -04:00
arkon 3b5a869fd0 Color selected tab with accent color when theme isn't blue
(cherry picked from commit 972a595c74)
2020-09-29 12:24:47 -04:00
arkon 815ac9d55b Remove card backgrounds from browse lists
(cherry picked from commit a3c598a3e1)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/manga/MigrationMangaController.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/sources/MigrationSourcesController.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourceHolder.kt
2020-09-29 12:24:33 -04:00
arkon 7b76823b60 Use background color for list view
(cherry picked from commit 9ce8c5c160)
2020-09-29 12:17:18 -04:00
arkon ab7bd3ebc2 Shorten settings search package name
(cherry picked from commit 79bbc99882)
2020-09-29 12:17:10 -04:00
Carlos 4faaf577be Update Ben Manes versions lib (#3843)
Update Ben Manes versions lib

(cherry picked from commit 31867362dc)
2020-09-29 12:16:55 -04:00
Jobobby04 4805d3c0c0 Manage Exhentai better, if login is disabled the source will disappear 2020-09-29 12:15:41 -04:00
Jobobby04 3c8fe2ed0e Make mangadex icon in settings smol 2020-09-27 17:23:42 -04:00
Jobobby04 d7433a0cd8 Change reader preload amount to Page Preload amount 2020-09-25 14:36:21 -04:00
Jobobby04 a8e80c663e String tweaks 2020-09-25 10:27:58 -04:00
Jobobby04 1b90590260 Cleanup Autoscroll coroutine code 2020-09-25 10:26:42 -04:00
Jobobby04 a903a48718 Add source setting controllers to search settings, hide settings in the E-Hentai settings when not logged in 2020-09-25 10:26:42 -04:00
Carlos 1038913e2c Update strings_sy.xml (#120)
remove neko strings
2020-09-25 10:25:58 -04:00
Jobobby04 748e5d5b0f History tweak 2020-09-24 09:19:36 -04:00
arkon ea3f90f107 Minor settings search code cleanup
(cherry picked from commit 3bce07e873)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsMainController.kt
2020-09-24 09:13:48 -04:00
arkon 26557b3257 #3520 Searchable Settings (#3683)
* Adding class stubs for settings search, UI elements.

* -  implement searchable settings
- `SettingsController.setupPreferenceScreen` must return a PreferenceScreen

* Remove unneeded SettingsControllerFactory.

* Set query hint, clean up code smell.

* Add search button to MoreController, stop infinite recursion.

* - initialize SearchResultCollection once in Activity.onCreate

* - implement prefernce highlighting after settings search

* - Ensure all Preferences have a key set or else the highlighting effect will have no effect on it.
- remove ExtensionFilterController and SourceFilterController from settingControllersList in SettingsSearchHelper, since those are related to Extensions and not Settings

* Limiting search to settings menu only, localized breadcrumb string, and code cleanup after code review.

* - moved call to SettingsSearchHelper.initPreferenceSearchResultCollection() into SettingsSearchController

* Code review cleanup and refactoring.

* Inlined non-reused key strings.

* Adding more UI polish, add comments for future enhancements.

* - retain search query when navigating *away* from SettingsSearchController
- keep `searchItem` in `expandActionView` state until user goes back (fixes the empty view in `SettingsSearchSearchController` issue)

Co-authored-by: mpm11011 <markuscicero5@gmail.com>
Co-authored-by: lmj0011 <9396189+lmj0011@users.noreply.github.com>
(cherry picked from commit 766f9e37b5)

# Conflicts:
#	app/build.gradle
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourceFilterController.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/more/AboutController.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAdvancedController.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsLibraryController.kt
2020-09-24 09:09:45 -04:00
arkon 89eea4ab91 Move manga info summary more/less button toggle
(cherry picked from commit a9bed90d02)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoHeaderAdapter.kt
#	app/src/main/res/layout/manga_info_header.xml
2020-09-24 08:41:48 -04:00
arkon 616fbe4afe Center reader transition text properly (fixes #3819)
(cherry picked from commit 01ad405dd2)
2020-09-24 08:24:16 -04:00
arkon c57abf67eb Move Gradle wrapper validation into build action
(cherry picked from commit 274f0edd76)

# Conflicts:
#	.github/workflows/build_check.yml
2020-09-24 08:23:58 -04:00
arkon 4aff2d79b7 Remove support for backup v1
(cherry picked from commit 88aea311f8)
2020-09-24 08:22:09 -04:00
arkon a87f6811e5 Minor updates
(cherry picked from commit 477aedbffa)
2020-09-24 08:22:00 -04:00
arkon 10f15d54f3 Add sah locale (closes #3818)
(cherry picked from commit b898442fe3)
2020-09-24 08:21:48 -04:00
Jobobby04 91c05e76bc Fix mangadex manga getting set to completed when not actually finished 2020-09-22 14:22:21 -04:00
Jobobby04 caa6dd6d62 Fix issues with mangadex tracking, infinite loading and showing up on non-mangadex manga 2020-09-22 13:45:50 -04:00
Jobobby04 ffc80c084d Parse the error Mangadex sends so people know what they are doing wrong 2020-09-17 12:10:12 -04:00
Jobobby04 9ee712aea4 Fix some mangadex login imports 2020-09-17 10:41:41 -04:00
Jobobby04 11fbc1faf9 Use XLog in more places 2020-09-17 09:05:19 -04:00
Jobobby04 bd6e048108 Fix search in latest + browse view 2020-09-17 00:43:38 -04:00
Jobobby04 a3be1c2c39 Fix merged manga getting backed up 2020-09-16 14:19:16 -04:00
Jobobby04 cbbb3bbf72 Trim the created tag to account for user errors 2020-09-16 13:00:39 -04:00
Jobobby04 67c99c9c42 More fixing to the sort by tags logic 2020-09-16 12:58:25 -04:00
Jobobby04 905e1b68c6 Sort by tag settings is able to sort the tags and save the changes 2020-09-16 12:25:08 -04:00
Jobobby04 f5998505a3 Cleanup 2020-09-15 23:34:14 -04:00
Jobobby04 67e1fee4c5 Fix everything about the sort by tag list 2020-09-15 23:16:49 -04:00
Jobobby04 db70a62c8f Fix sort tag preference 2020-09-15 18:21:26 -04:00
arkon a4d3fa5878 Fix downloaded only filter
(cherry picked from commit 7641bb4d0d)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt
2020-09-15 18:18:33 -04:00
Jobobby04 a8aef554bd Migrate button tweak 2020-09-15 18:16:29 -04:00
Jay 2583be9923 Send manga/chapter/page details when sharing a chapter page
(cherry picked from commit 004e1c98ee)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt
2020-09-15 18:16:06 -04:00
arkon 573768482f Tri-state library filters (closes #1814)
Based on https://github.com/inorichi/tachiyomi/pull/2127.

Co-authored-by: hXtreme <hXtreme@users.noreply.github.com>
(cherry picked from commit 687f3d48ea)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsSheet.kt
#	app/src/main/java/eu/kanade/tachiyomi/widget/ExtendedNavigationView.kt
2020-09-15 16:29:44 -04:00
arkon 8df978a91c Clean up global chapter settings code
(cherry picked from commit da5f10a2f1)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourcePresenter.kt
2020-09-15 14:52:31 -04:00
lmj0011 763335bd85 [feature] add ability to set global filter/sort/display for Manga chapters (#3622)
* - [feature] add ability to set global filter/sort/display for Manga chapters

* - move default chapter settings functionality to overflow menu
- code clean up

* - show confirmation dialog when user selects "Set as Default" option in Chapter Settings

* - hide overflow menu in LibrarySettingsSheet

* - apply default chapter settings if manga is added to Library from a Source's browsing screen

Co-authored-by: arkon <arkon@users.noreply.github.com>
(cherry picked from commit 64050e8266)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt
2020-09-15 14:27:42 -04:00
arkon 4e8c30b7fe Start updating manga info view header design (SY edition)
(cherry picked from commit 791a7d5a01)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoHeaderAdapter.kt
#	app/src/main/res/layout/manga_info_header.xml
2020-09-15 14:08:14 -04:00
Jobobby04 07973bff32 Revert "Disable tag sorting for release"
This reverts commit 70bef08ed6.
2020-09-15 13:29:03 -04:00
Jobobby04 c69972f83a Revert "Hide dedupe by priority for release"
This reverts commit 92ae67630c.
2020-09-15 13:28:58 -04:00
Jobobby04 d05ea94d78 Revert "Hide parental controls section for release"
This reverts commit 02b90000f0.
2020-09-15 13:28:50 -04:00
Jobobby04 332a631b6c Release 1.3.1
Validate Gradle Wrapper / Validation (push) Successful in 13s
2020-09-15 13:21:37 -04:00
Jobobby04 70bef08ed6 Disable tag sorting for release 2020-09-15 13:03:15 -04:00
Jobobby04 de05f88d5f Fix Mangadex 2 factor auth
Fix Backups with merge manga breaking(I think)
Tweak preload settings, make the max 20, defaults to 10
Add tag based sorting
2020-09-15 13:00:40 -04:00
Jay 89427ff37e Send manga/chapter/page details when sharing a chapter page
(cherry picked from commit 32aea55f424d77e78be50f288996fe04053db009)
2020-09-14 21:15:40 -04:00
Jobobby04 63617f3079 Release 1.3.0
Validate Gradle Wrapper / Validation (push) Failing after 23s
2020-09-14 20:24:48 -04:00
Jobobby04 0f9f7ffc28 Cleanup 2020-09-14 14:36:56 -04:00
Jobobby04 9aab9d4ca4 Fix autofill exclusion 2020-09-14 14:06:48 -04:00
Jobobby04 92ae67630c Hide dedupe by priority for release 2020-09-14 12:47:54 -04:00
arkon 02b90000f0 Hide parental controls section for release
(cherry picked from commit 76c795d0d0)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsMainController.kt
2020-09-14 12:42:39 -04:00
arkon 6ed5d858aa Fix Kotlinter name typo
(cherry picked from commit b20bced3ca)
2020-09-14 12:40:58 -04:00
arkon 83bc059573 Fix Chinese plurals
(cherry picked from commit 4f2da9a78f)
2020-09-14 12:40:47 -04:00
Jozef Hollý ad39af55d6 Translated using Weblate (Bulgarian) (#3646)
Currently translated at 99.4% (574 of 577 strings)

Translated using Weblate (Filipino)

Currently translated at 100.0% (577 of 577 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (577 of 577 strings)

Translated using Weblate (French)

Currently translated at 100.0% (577 of 577 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (577 of 577 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (577 of 577 strings)

Translated using Weblate (Croatian)

Currently translated at 100.0% (577 of 577 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (577 of 577 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (577 of 577 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (577 of 577 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (577 of 577 strings)

Translated using Weblate (Sardinian)

Currently translated at 100.0% (577 of 577 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (577 of 577 strings)

Translated using Weblate (Dutch)

Currently translated at 100.0% (577 of 577 strings)

Translated using Weblate (Finnish)

Currently translated at 100.0% (577 of 577 strings)

Translated using Weblate (Chuvash)

Currently translated at 100.0% (577 of 577 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (577 of 577 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (577 of 577 strings)

Translated using Weblate (Greek)

Currently translated at 100.0% (577 of 577 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (577 of 577 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (577 of 577 strings)

Translated using Weblate (Malay)

Currently translated at 100.0% (577 of 577 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (577 of 577 strings)

Translated using Weblate (German)

Currently translated at 100.0% (577 of 577 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Hindi)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (French)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Finnish)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Malay)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (German)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (576 of 576 strings)

Update translation files

Updated by "Cleanup translation files" hook in Weblate.

Translated using Weblate (Italian)

Currently translated at 98.9% (570 of 576 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (French)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Yakut)

Currently translated at 87.3% (503 of 576 strings)

Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sah/

Translated using Weblate (Bulgarian)

Currently translated at 96.7% (557 of 576 strings)

Translated using Weblate (Chuvash)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Vietnamese)

Currently translated at 86.2% (497 of 576 strings)

Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/vi/

Translated using Weblate (Japanese)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (German)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Arabic)

Currently translated at 95.4% (550 of 576 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Hindi)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Yakut)

Currently translated at 85.2% (491 of 576 strings)

Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sah/

Translated using Weblate (Croatian)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Sardinian)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Chinese (Traditional))

Currently translated at 99.6% (574 of 576 strings)

Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/zh_Hant/

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Finnish)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Chuvash)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Hindi)

Currently translated at 99.3% (572 of 576 strings)

Translated using Weblate (German)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Filipino)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Spanish (Latin America))

Currently translated at 100.0% (576 of 576 strings)

Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/es_419/

Translated using Weblate (Greek)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Malay)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Portuguese)

Currently translated at 99.8% (575 of 576 strings)

Translated using Weblate (French)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Latvian)

Currently translated at 33.6% (194 of 576 strings)

Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/lv/

Translated using Weblate (Arabic)

Currently translated at 91.8% (529 of 576 strings)

Translated using Weblate (Latvian)

Currently translated at 33.3% (192 of 576 strings)

Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/lv/

Translated using Weblate (Latvian)

Currently translated at 33.3% (192 of 576 strings)

Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/lv/

Translated using Weblate (French)

Currently translated at 99.8% (575 of 576 strings)

Translated using Weblate (Croatian)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Chinese (Traditional))

Currently translated at 98.7% (569 of 576 strings)

Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/zh_Hant/

Translated using Weblate (Indonesian)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Croatian)

Currently translated at 99.4% (573 of 576 strings)

Translated using Weblate (Finnish)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Bengali (Bangladesh))

Currently translated at 0.5% (3 of 576 strings)

Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/bn_BD/

Translated using Weblate (Filipino)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Japanese)

Currently translated at 97.7% (563 of 576 strings)

Translated using Weblate (Swedish)

Currently translated at 100.0% (576 of 576 strings)

Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sv/

Translated using Weblate (Turkish)

Currently translated at 99.8% (575 of 576 strings)

Translated using Weblate (Greek)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Finnish)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Dutch)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Chuvash)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Hindi)

Currently translated at 99.1% (571 of 576 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Polish)

Currently translated at 96.8% (558 of 576 strings)

Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pl/

Translated using Weblate (Malay)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Bengali)

Currently translated at 57.6% (332 of 576 strings)

Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/bn/

Translated using Weblate (Bengali)

Currently translated at 57.6% (332 of 576 strings)

Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/bn/

Added translation using Weblate (Bengali (Bangladesh))

Translated using Weblate (Yakut)

Currently translated at 80.2% (462 of 576 strings)

Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sah/

Translated using Weblate (Russian)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Bengali)

Currently translated at 58.3% (336 of 576 strings)

Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/bn/

Translated using Weblate (Sardinian)

Currently translated at 99.6% (574 of 576 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Chinese (Traditional))

Currently translated at 98.0% (565 of 576 strings)

Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/zh_Hant/

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Greek)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Chuvash)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Filipino)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Spanish (Latin America))

Currently translated at 100.0% (576 of 576 strings)

Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/es_419/

Translated using Weblate (Spanish (Latin America))

Currently translated at 100.0% (576 of 576 strings)

Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/es_419/

Translated using Weblate (Finnish)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Dutch)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Indonesian)

Currently translated at 98.9% (570 of 576 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Chuvash)

Currently translated at 99.6% (574 of 576 strings)

Translated using Weblate (Malay)

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 90.4% (521 of 576 strings)

Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/nb_NO/

Translated using Weblate (Malay)

Currently translated at 99.8% (575 of 576 strings)

Translated using Weblate (Swedish)

Currently translated at 100.0% (576 of 576 strings)

Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sv/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (576 of 576 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 99.8% (575 of 576 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 99.8% (575 of 576 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 99.6% (574 of 576 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 99.6% (574 of 576 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 99.4% (573 of 576 strings)

Translated using Weblate (German)

Currently translated at 100.0% (576 of 576 strings)

Co-authored-by: Ajeje Brazorf <lmelonimamo@yahoo.it>
Co-authored-by: Alessandro Jean <alessandrojean@gmail.com>
Co-authored-by: Alessandro Zangrandi <alessandro@mzit.it>
Co-authored-by: Alex <linuxrf@gmail.com>
Co-authored-by: Ava <Sasu.ruotsalainen@live.fi>
Co-authored-by: DarKCroX <darkcrox.2020@outlook.com>
Co-authored-by: Eduard Ereza Martínez <eduard@ereza.cat>
Co-authored-by: Eric <spice2wolf@gmail.com>
Co-authored-by: Gabriel Lebis <gableb@hotmail.fr>
Co-authored-by: George <georgeramzy37@gmail.com>
Co-authored-by: Hara Desu <aqjbgr09@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Huang Zhiyi <hzy980512@126.com>
Co-authored-by: Kurocon <weblate@kurocon.nl>
Co-authored-by: Marco Santos <enum.scima@gmail.com>
Co-authored-by: Matteo Gaeta <matteo.gaeta.1998@gmail.com>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: Paulo Pinho <kebrus@gmail.com>
Co-authored-by: Pitpe11 <giorgos2550@gmail.com>
Co-authored-by: RealKC <mitrut.e.super@gmail.com>
Co-authored-by: Rostyslav <info@ubilling.net.ua>
Co-authored-by: Samuel Carvalho de Araújo <samuelnegro12345@gmail.com>
Co-authored-by: Whod <whodizhod@gmail.com>
Co-authored-by: Yassin El Aoud <yassinelaoud@gmail.com>
Co-authored-by: darkbeast13 <nikhil15mps@gmail.com>
Co-authored-by: monolifed <monolifed@protonmail.com>
Co-authored-by: İlle <derasetad@gmail.com>
Co-authored-by: Роман <Rozhenkov69@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ar/
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/cv/
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/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/hi/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/hr/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/id/
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/ms/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/nl/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pt/
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/tr/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/uk/
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/zh_Hans/
Translation: Tachiyomi/Strings

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: Alessandro Zangrandi <alessandro@mzit.it>
Co-authored-by: Alex <linuxrf@gmail.com>
Co-authored-by: Ava <Sasu.ruotsalainen@live.fi>
Co-authored-by: DarKCroX <darkcrox.2020@outlook.com>
Co-authored-by: Eduard Ereza Martínez <eduard@ereza.cat>
Co-authored-by: Eric <spice2wolf@gmail.com>
Co-authored-by: Gabriel Lebis <gableb@hotmail.fr>
Co-authored-by: George <georgeramzy37@gmail.com>
Co-authored-by: Hara Desu <aqjbgr09@gmail.com>
Co-authored-by: Huang Zhiyi <hzy980512@126.com>
Co-authored-by: Kurocon <weblate@kurocon.nl>
Co-authored-by: Marco Santos <enum.scima@gmail.com>
Co-authored-by: Matteo Gaeta <matteo.gaeta.1998@gmail.com>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: Paulo Pinho <kebrus@gmail.com>
Co-authored-by: Pitpe11 <giorgos2550@gmail.com>
Co-authored-by: RealKC <mitrut.e.super@gmail.com>
Co-authored-by: Rostyslav <info@ubilling.net.ua>
Co-authored-by: Samuel Carvalho de Araújo <samuelnegro12345@gmail.com>
Co-authored-by: Whod <whodizhod@gmail.com>
Co-authored-by: Yassin El Aoud <yassinelaoud@gmail.com>
Co-authored-by: darkbeast13 <nikhil15mps@gmail.com>
Co-authored-by: monolifed <monolifed@protonmail.com>
Co-authored-by: İlle <derasetad@gmail.com>
Co-authored-by: Роман <Rozhenkov69@gmail.com>
(cherry picked from commit 8e0ba3650b)
2020-09-14 12:40:33 -04:00
arkon 8d5b2f40b3 Use Kolinter Gradle plugin for linting instead of ktlint directly
(cherry picked from commit 76f6fe4601)
2020-09-13 23:08:52 -04:00
arkon 49bee1af91 Update to Preivews new update checker, while keeping the SY repos and versions
(cherry picked from commit ca1373f36b)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/data/updater/UpdateChecker.kt
#	app/src/main/java/eu/kanade/tachiyomi/data/updater/github/GithubService.kt
#	app/src/main/java/eu/kanade/tachiyomi/data/updater/github/GithubUpdateChecker.kt
2020-09-13 23:03:22 -04:00
Jobobby04 a48508a98e reader light theme chapters bottom sheet fixes 2020-09-13 22:52:11 -04:00
arkon 4e3288b2af Use background color for some lists
(cherry picked from commit c0789cd6ba)
2020-09-13 22:51:46 -04:00
arkon 0f16150613 Replace deprecated system window insets usage
(cherry picked from commit af47103707)
2020-09-13 22:24:06 -04:00
arkon 6dd7491ffe Remove list dividers
(cherry picked from commit c466baaa25)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChapterDividerItemDecoration.kt
2020-09-13 22:24:06 -04:00
Jobobby04 02e6eaae12 Cleanup and fix a few compiler warnings 2020-09-13 22:24:03 -04:00
Jobobby04 73523dbff8 Remove Manga Plus delegation as it is not needed with the new extension update 2020-09-13 18:54:38 -04:00
Jobobby04 58a503814d Update firebase crashlytics 2020-09-13 18:46:14 -04:00
Jobobby04 7a834ea9f4 Mangadex tweaks, fix global update crashing sometimes 2020-09-13 18:45:57 -04:00
Jobobby04 dcca19e6b8 Undo Reds manga title changes 2020-09-12 19:21:54 -04:00
arkon 210fd000b3 Update OkHttp and Conscrypt
(cherry picked from commit 670294a427)
2020-09-12 13:51:55 -04:00
arkon 3d6f8ddd13 Update to Kotlin 1.4.10
(cherry picked from commit 21ddae6a86)
2020-09-12 13:51:55 -04:00
Andreas E a4578611d7 Always show missing chapter warning if there are missing chapters (#3755)
* Always show missing chapter warning if there are missing chapters

* Change function parameter names

(cherry picked from commit 9f260c3513)
2020-09-12 13:51:55 -04:00
Jobobby04 bb6932ff80 Mangadex follows, tell browse there are no more pages 2020-09-12 13:51:54 -04:00
AbdullahM0hamed 8dce9a674b Fix title on light theme (#101) 2020-09-12 13:51:19 -04:00
Jobobby04 b93298c411 Add MangaDex only implementation of Mangadex Follows list
Add login dialog that pops up whenever you are not logged in when trying to browse MangaDex
Remove attempts at porting over chapter read history from older galleries to new ones
Disable latest for ExHentai, it was browse without buttons anyway
2020-09-11 23:12:13 -04:00
Jobobby04 8928aa77eb Disable logging thread info, it wasnt very useful and made the log difficult to read 2020-09-10 20:27:49 -04:00
jobobby04 a6e6fa0099 Merge pull request #96 from AbdullahM0hamed/patch-1
Remove navigationBarColor from Black-Red theme
2020-09-10 18:43:46 -04:00
AbdullahM0hamed c23edd5b72 Remove navigationBarColor from Black-Red theme 2020-09-10 23:42:14 +01:00
AbdullahM0hamed c8a4ec37e0 Add Black-Red theme (#95)
* Appveyor

* stuff

* resolve conflict

* Let's try this again

* try again

* More fixing

* remove appveyor

* revert build.gradle

* Revert "revert build.gradle"

This reverts commit feaaa78157ffe8d6d6af7d6d63a74bc14b92f584.

* Undo line change

* Update build.gradle

* Update MainActivity.kt

Co-authored-by: AbdullahM0hamed<AbdullahM0hamed@users.noreply.github.com>
2020-09-10 17:06:49 -04:00
Jobobby04 f62d277894 Opps, forgot to push these changes 2020-09-08 12:04:53 -04:00
Jobobby04 b7efc21ea9 Update pt-rBR translation(curtsy of 0k//lux)
Change some gallery references to manga
2020-09-08 11:57:10 -04:00
Jobobby04 238b2d108d Cleanup 2020-09-06 22:43:58 -04:00
Jobobby04 bdaf0f7492 Fix exclusion in library search 2020-09-06 22:43:45 -04:00
Jobobby04 ced8dc750a Cleanup 2020-09-06 21:30:36 -04:00
Jobobby04 035fb9e755 Add biometric lock times 2020-09-06 21:30:22 -04:00
Jobobby04 86defec57c Fix latest + browse page crash when source returns null 2020-09-06 20:05:10 -04:00
Jobobby04 f20e5d864d Move from kizitonwose time to kotlin duration 2020-09-06 16:24:43 -04:00
Jobobby04 d83f938e07 Add a option to allow local source to read hidden folders 2020-09-06 00:31:08 -04:00
Jobobby04 b4e73cb1eb Upgrade the cleanup downloads to the new J2k version 2020-09-05 19:43:12 -04:00
arkon 604c7c703a Fix text alignment in transition view when no more chapters available
(cherry picked from commit b55d394a1f)
2020-09-05 19:20:53 -04:00
Andreas E 20021dbf54 Add spacing on top of sources/extensions/migrate lists (#3751)
(cherry picked from commit 5e2e177aa9)
2020-09-05 19:20:42 -04:00
arkon 281fb9c67b Refactor common chapter transition views into separate view
(cherry picked from commit 86e59977de)
2020-09-05 19:19:49 -04:00
arkon 7579bb026f Localize "No chapters found" error
(cherry picked from commit 66baf01e43)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateService.kt
2020-09-05 19:19:37 -04:00
Andreas E 61fb836be4 Add missing chapter warning (#3745)
* Add missing chapter warning

* Flip calculation instead of flipping variables

* Change logic

* Change tint based on reader theme

* Add missing chapter warning to WebtoonTransitionHolder

* Add chapter warning between current/finished and prev/next

* Fix mix up of TextViews

* Fix review comments

(cherry picked from commit 7a33e198dc)
2020-09-05 19:11:20 -04:00
scb261 d83361dfe3 Change sources sort to case-insensitive (#3743)
(cherry picked from commit 4b493ebbaf)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/sources/MigrationSourcesPresenter.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourceFilterController.kt
2020-09-05 19:11:02 -04:00
arkon a5a79c1127 Remove unused string, fix improperly formatted Slovak string
(cherry picked from commit 565e8cf00b)
2020-09-05 19:03:58 -04:00
arkon 2f0f938d5e Update Conscrypt
(cherry picked from commit 738a3999b4)

# Conflicts:
#	app/build.gradle
2020-09-05 19:03:52 -04:00
arkon 750a6c3d11 Move share manga button to toolbar menu
(cherry picked from commit 8bedc8f456)
2020-09-05 19:02:48 -04:00
arkon b65305c73e Update dependencies
(cherry picked from commit d9000f6fd1)
2020-09-05 19:02:38 -04:00
Jobobby04 85ef1031b5 Display read progress on read chapters for E/Exhentai manga 2020-09-05 19:02:09 -04:00
Jobobby04 69c530dc34 Fix migrate to source with most chapters 2020-09-05 18:19:04 -04:00
Jobobby04 ea620a8c74 Probably fix previously read exh chapters affect updated gallery chapters 2020-09-05 18:18:39 -04:00
Jobobby04 1fdbae5bf8 Cleanup 2020-09-05 18:17:48 -04:00
Jobobby04 a1d54880c3 Merged manga implementation, man this took forever to make and bugfix, its not even done 2020-09-05 18:17:33 -04:00
Jobobby04 d21a652944 Remake the merged database, has support for future features 2020-09-04 17:31:35 -04:00
Jobobby04 444d346874 Probably make previously read exh chapters affect updated gallery chapters when loading the new version in the source 2020-08-25 02:09:15 -04:00
Jobobby04 41b8786415 Cleanup some mangatype logs 2020-08-25 02:07:40 -04:00
Jobobby04 d97805e38b Respect manga chapter order for reader chapter list, as well as fix page progress updating 2020-08-25 00:12:07 -04:00
Jobobby04 eafe3a62e4 Fix the bottom sheet and remove the bookmark button at the top of the reader 2020-08-24 19:25:47 -04:00
Jobobby04 0a502fcf31 Cleanup merged source code so I can modify it easier later on 2020-08-24 17:28:14 -04:00
Jobobby04 80960d87f2 Cleanup 2020-08-24 17:25:10 -04:00
Jobobby04 166aebdf25 Grab started filter from J2k 2020-08-23 21:59:43 -04:00
Jobobby04 b8836b9b6f Update firebase 2020-08-23 21:57:06 -04:00
Jobobby04 1d70f0b1dd Lint 2020-08-22 22:13:14 -04:00
Jobobby04 1240cc5232 Reader bottom sheet transparency, as well as a half fix for the fullscreen reader bug 2020-08-22 22:12:59 -04:00
Jobobby04 0abee585fc Some more cleanup to Save as CBZ 2020-08-22 18:41:42 -04:00
arkon 4870bb153d Filter out hidden directories for local source (closes #3706)
(cherry picked from commit fe7c7e72f5)
2020-08-22 18:19:33 -04:00
Jobobby04 f2b90bd772 Cleanup 2020-08-22 18:19:33 -04:00
arkon d77c65b515 Clean up X-Requested-With change
This only really affects the initial request, subsequent requests may still use the package name.

(cherry picked from commit 9920ff617b)
2020-08-22 18:17:48 -04:00
armangido 5004e2d62c Update WebViewActivity.kt (#3617)
This code added is for some extension that blocks tachiyomi, by tricking it that it was sent by a android browser, nothing major changes,

(cherry picked from commit 3f1355c413)
2020-08-22 18:17:37 -04:00
arkon 6e4a0ca1ea Update ActionMode styling
(cherry picked from commit 4929e66ecc)
2020-08-22 18:17:29 -04:00
arkon 883ffaa815 AndroidX dependency updates
(cherry picked from commit 4c31e3fc5f)
2020-08-22 18:17:08 -04:00
Jobobby04 3967a569c4 Cleanup Save as CBZ 2020-08-22 18:12:32 -04:00
Jobobby04 79e4e3d2a0 Add chapters bottom sheet for reader 2020-08-22 17:37:42 -04:00
Jobobby04 4b12e977c0 Cleanup some code 2020-08-22 17:37:42 -04:00
Fahad1998 4333999b85 Add Save As CBZ (#84)
Co-authored-by: Fahad1998 <f1998>
2020-08-22 17:37:03 -04:00
Fahad1998 fae290cf22 data saver fix (#85)
Co-authored-by: Fahad1998 <f1998>
2020-08-22 17:35:50 -04:00
Jobobby04 9ecf83f842 Delegate mangaplus so that it doesnt crash the app, it is literally just a copy of the extension with no extra features, but at least the app doesnt crash when you use it now 2020-08-21 16:27:01 -04:00
Jobobby04 f594962731 Cleanup 2020-08-21 15:32:42 -04:00
Jobobby04 048eecf655 Optimize and cleanup data saver 2020-08-21 15:32:29 -04:00
Fahad1998 90253f3bd4 Add Data Saver (#82)
Co-authored-by: Fahad1998 <f1998>
2020-08-21 13:50:08 -04:00
Jobobby04 0deb6f6b8d Finish some more advanced mangadex delegation features, more to come later 2020-08-20 20:50:37 -04:00
Jobobby04 294ade035e Rename LewdSource to MetadataSource to account for that Metadata will not always be for lewd sources 2020-08-19 18:45:56 -04:00
Jobobby04 64bb34b50d Delegate Mangadex (Part 1) 2020-08-19 18:20:05 -04:00
Jobobby04 9efb1482f9 Updated delegation system to account for custom headers 2020-08-19 18:19:22 -04:00
Jobobby04 aff15b3ee2 Remove library search log 2020-08-19 18:14:42 -04:00
Jobobby04 d86f3ffad8 Add a custom view change handler, makes it fade only one way 2020-08-19 02:08:58 -04:00
arkon 2a3eef0610 Don't enqueue bookmarked chapters for deletion (fixes #3691)
(cherry picked from commit 4c8665c9f0)
2020-08-18 22:32:06 -04:00
arkon 3b87111f22 Minor wording edit
(cherry picked from commit ba67781431)

# Conflicts:
#	app/src/main/res/values/strings.xml
2020-08-18 22:31:50 -04:00
arkon b654613345 Use core-ktx for bolding chapter transition text
(cherry picked from commit 4ef25c75b7)
2020-08-18 22:31:20 -04:00
arkon 136b25fb92 Dependency updates
(cherry picked from commit 3aafc671f8)

# Conflicts:
#	app/build.gradle
2020-08-18 22:31:00 -04:00
arkon f3875bda50 Update to Kotlin 1.4
(cherry picked from commit 967df6f7a3)

# Conflicts:
#	app/build.gradle
2020-08-18 22:29:54 -04:00
Jobobby04 c41148b465 Make animations smoother, add change handlers to bottom nav transactions, make animations go by their default value instead of a custom fast one 2020-08-18 22:23:39 -04:00
Jobobby04 eb0a1668f8 Made the ViewHeightAnimator duration configurable 2020-08-18 22:07:39 -04:00
Jobobby04 f7bc3e0a82 Cleanup some strings 2020-08-18 22:07:14 -04:00
Jobobby04 2e4def13e3 Add custom browese view, disabled by default and can be enabled in the settings
Signed-off-by: Jobobby04 <jobobby04@users.noreply.github.com>
2020-08-18 22:05:56 -04:00
Jobobby04 9e0e2db25d Add dynamic category library update upgrades 2020-08-18 18:55:00 -04:00
Jobobby04 20aa5b9aa1 Cleanup E-Hentai 2020-08-18 18:31:00 -04:00
Jobobby04 6ce4612aa7 Fix latest packages 2020-08-16 20:57:10 -04:00
Jobobby04 b51d147986 Cleanup 2020-08-16 20:47:09 -04:00
Jobobby04 bc896cf605 Make XLog display debug info in a debug build 2020-08-16 20:40:30 -04:00
Jobobby04 e48f274072 Updates and cleanup build.gradle 2020-08-15 23:01:16 -04:00
Jobobby04 a6b98e24dc Undo linting 2020-08-15 15:57:07 -04:00
Jobobby04 9a26a3e5a2 Revert "Slight gradle cleanup, plugin updates"
This reverts commit 08d11914af.
2020-08-14 18:54:34 -04:00
Jobobby04 eeb0f76cce Cleanup 2020-08-14 18:41:21 -04:00
Jobobby04 bcd36c8fad Add tap to move by page for continues vertical reader 2020-08-14 18:41:21 -04:00
Jobobby04 7f7b2901cb Convert autoscroll to a coroutine 2020-08-14 18:41:21 -04:00
Jobobby04 84b9b4db55 Cleanup 2020-08-14 18:41:21 -04:00
Jobobby04 a5c10dbf28 Add no title grid option 2020-08-14 18:41:21 -04:00
Jobobby04 5fee3ac05a Add a option to open the library bottom sheet in the library Settings 2020-08-14 18:41:21 -04:00
Jobobby04 d3603a664c Un-break XLog network logging, code contributed from Neko 2020-08-14 18:41:21 -04:00
Jobobby04 7ccaea0d72 Remove unused hitomi class 2020-08-14 18:41:20 -04:00
Jobobby04 921f7aad01 Make FAB disappear on image expand 2020-08-14 18:41:20 -04:00
Jobobby04 bc549c56d6 Automatic linting fixes 2020-08-14 18:41:20 -04:00
Jobobby04 b639e1e4d7 Delete my pull request tester in favor of previews 2020-08-14 18:41:13 -04:00
arkon 4f877820b2 Add PR build check action
(cherry picked from commit 19a7f37efa)
2020-08-14 18:41:13 -04:00
arkon c35e0a0c29 Unhide parental controls settings
(cherry picked from commit c3084ac43a)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsMainController.kt
2020-08-14 18:41:13 -04:00
TacoTheDank 08d11914af Slight gradle cleanup, plugin updates
(cherry picked from commit 159146e197)

# Conflicts:
#	app/build.gradle
#	build.gradle.kts
2020-08-14 18:41:13 -04:00
Jobobby04 309bd83730 Update gradle wrapper
(cherry picked from commit 67ddf4a5b8)
2020-08-14 18:40:55 -04:00
Taco 6b158cc864 Optimize images using ezgif (#3649) 2020-08-12 22:45:32 -04:00
Jobobby04 7d82be964c Add long click to copy on the special manga views 2020-08-12 22:34:20 -04:00
Jobobby04 525c3f84e4 Enable click to copy to clipboard in the more info 2020-08-12 22:32:13 -04:00
Jobobby04 ef37811020 Expand manga thumbnails 2020-08-12 21:10:39 -04:00
Jobobby04 0d033c7080 Cleanup some delegation code 2020-08-12 18:46:05 -04:00
Jobobby04 7557369d1f Release 1.2.0 2020-08-12 15:06:34 -04:00
Jobobby04 3e1804da8a Lazily instantiate some variables in EHSourceHelpers 2020-08-12 14:20:32 -04:00
Jobobby04 2ab0927313 Add PervEden to clean titles 2020-08-12 14:04:00 -04:00
Jobobby04 98b6a221fd NHentai/Hitomi say "All" when toString is called 2020-08-12 13:45:25 -04:00
Jobobby04 4733a62980 Wrap hitomi upload date in a Try/Catch to solve errors 2020-08-12 13:41:03 -04:00
Jobobby04 a5276fdadc When refreshing in groups update globally(tmep fix, hopefully grouping will update the group later) 2020-08-12 01:19:52 -04:00
Jobobby04 906ac9e00c Fix bugs with migrating manga with the action mode 2020-08-12 01:18:45 -04:00
arkon 8ae3b8e313 Update issue templates
(cherry picked from commit aa607e0ecb)
2020-08-12 00:34:18 -04:00
arkon ce36e6b242 Split out NSFW source setting to separate section
Temporarily hidden until feature is ready for stable release.

(cherry picked from commit 65b32ddeb2)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsMainController.kt
2020-08-12 00:34:10 -04:00
arkon cfd3d59516 Fix Chinese plural string
(cherry picked from commit 5e9bdc2690)
2020-08-12 00:33:33 -04:00
Jozef Hollý ae915d7823 Translated using Weblate (Swedish) (#3580)
Currently translated at 99.8% (573 of 574 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sv/

Translated using Weblate (Finnish)

Currently translated at 100.0% (574 of 574 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/fi/

Translated using Weblate (Swedish)

Currently translated at 99.6% (572 of 574 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sv/

Translated using Weblate (Greek)

Currently translated at 99.4% (571 of 574 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/el/

Translated using Weblate (Russian)

Currently translated at 100.0% (574 of 574 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ru/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (574 of 574 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pt_BR/

Translated using Weblate (Malay)

Currently translated at 100.0% (574 of 574 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ms/

Translated using Weblate (Spanish)

Currently translated at 100.0% (574 of 574 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/es/

Translated using Weblate (German)

Currently translated at 100.0% (574 of 574 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/de/

Translated using Weblate (Chuvash)

Currently translated at 100.0% (572 of 572 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/cv/

Translated using Weblate (Dutch)

Currently translated at 100.0% (572 of 572 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/nl/

Translated using Weblate (Yakut)

Currently translated at 74.8% (428 of 572 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sah/

Translated using Weblate (Filipino)

Currently translated at 100.0% (572 of 572 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/fil/

Translated using Weblate (Finnish)

Currently translated at 100.0% (572 of 572 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/fi/

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (572 of 572 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/zh_Hans/

Translated using Weblate (Russian)

Currently translated at 100.0% (572 of 572 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ru/

Translated using Weblate (Spanish)

Currently translated at 100.0% (572 of 572 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/es/

Translated using Weblate (Turkish)

Currently translated at 100.0% (572 of 572 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/tr/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (572 of 572 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pt_BR/

Translated using Weblate (Chuvash)

Currently translated at 100.0% (572 of 572 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/cv/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (572 of 572 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pt_BR/

Translated using Weblate (Malay)

Currently translated at 100.0% (572 of 572 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ms/

Translated using Weblate (German)

Currently translated at 100.0% (572 of 572 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/de/

Translated using Weblate (Indonesian)

Currently translated at 99.6% (568 of 570 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/id/

Translated using Weblate (Yakut)

Currently translated at 70.3% (401 of 570 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sah/

Translated using Weblate (Yakut)

Currently translated at 70.3% (401 of 570 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sah/

Translated using Weblate (Chuvash)

Currently translated at 100.0% (570 of 570 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/cv/

Translated using Weblate (Filipino)

Currently translated at 100.0% (570 of 570 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/fil/

Translated using Weblate (Chinese (Traditional))

Currently translated at 99.1% (565 of 570 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/zh_Hant/

Translated using Weblate (Finnish)

Currently translated at 100.0% (570 of 570 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/fi/

Translated using Weblate (Greek)

Currently translated at 100.0% (570 of 570 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/el/

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (570 of 570 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/zh_Hans/

Translated using Weblate (Turkish)

Currently translated at 100.0% (570 of 570 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/tr/

Translated using Weblate (Russian)

Currently translated at 100.0% (570 of 570 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ru/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (570 of 570 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pt_BR/

Translated using Weblate (Dutch)

Currently translated at 100.0% (570 of 570 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/nl/

Translated using Weblate (Malay)

Currently translated at 100.0% (570 of 570 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ms/

Translated using Weblate (Spanish)

Currently translated at 100.0% (570 of 570 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/es/

Translated using Weblate (German)

Currently translated at 99.4% (567 of 570 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/de/

Translated using Weblate (Yakut)

Currently translated at 70.3% (401 of 570 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sah/

Translated using Weblate (Yakut)

Currently translated at 70.3% (401 of 570 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sah/

Translated using Weblate (Yakut)

Currently translated at 70.3% (401 of 570 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sah/

Translated using Weblate (Yakut)

Currently translated at 63.8% (364 of 570 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sah/

Translated using Weblate (Yakut)

Currently translated at 63.8% (364 of 570 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sah/

Translated using Weblate (Yakut)

Currently translated at 63.5% (362 of 570 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sah/

Translated using Weblate (Yakut)

Currently translated at 63.5% (362 of 570 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sah/

Translated using Weblate (Yakut)

Currently translated at 63.3% (361 of 570 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sah/

Translated using Weblate (Yakut)

Currently translated at 63.3% (361 of 570 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sah/

Translated using Weblate (Yakut)

Currently translated at 62.4% (356 of 570 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sah/

Translated using Weblate (Yakut)

Currently translated at 62.4% (356 of 570 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sah/

Translated using Weblate (Yakut)

Currently translated at 61.7% (352 of 570 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sah/

Translated using Weblate (Yakut)

Currently translated at 61.7% (352 of 570 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sah/

Translated using Weblate (Yakut)

Currently translated at 61.7% (352 of 570 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sah/

Translated using Weblate (Yakut)

Currently translated at 61.7% (352 of 570 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sah/

Translated using Weblate (Yakut)

Currently translated at 61.5% (351 of 570 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sah/

Translated using Weblate (Yakut)

Currently translated at 60.7% (346 of 570 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sah/

Translated using Weblate (Yakut)

Currently translated at 60.7% (346 of 570 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sah/

Translated using Weblate (Yakut)

Currently translated at 60.7% (346 of 570 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sah/

Translated using Weblate (Yakut)

Currently translated at 60.0% (342 of 570 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sah/

Translated using Weblate (Yakut)

Currently translated at 58.9% (336 of 570 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sah/

Translated using Weblate (Yakut)

Currently translated at 58.9% (336 of 570 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sah/

Translated using Weblate (Yakut)

Currently translated at 58.7% (335 of 570 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sah/

Translated using Weblate (Yakut)

Currently translated at 58.7% (335 of 570 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sah/

Translated using Weblate (Yakut)

Currently translated at 58.7% (335 of 570 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sah/

Translated using Weblate (Yakut)

Currently translated at 58.7% (335 of 570 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sah/

Translated using Weblate (Malay)

Currently translated at 100.0% (567 of 567 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ms/

Translated using Weblate (Russian)

Currently translated at 100.0% (567 of 567 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ru/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (567 of 567 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pt_BR/

Translated using Weblate (Spanish)

Currently translated at 100.0% (567 of 567 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/es/

Translated using Weblate (German)

Currently translated at 100.0% (567 of 567 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/de/

Translated using Weblate (Yakut)

Currently translated at 49.6% (281 of 566 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sah/

Translated using Weblate (Portuguese)

Currently translated at 100.0% (566 of 566 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pt/

Translated using Weblate (Yakut)

Currently translated at 32.6% (185 of 566 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sah/

Translated using Weblate (Yakut)

Currently translated at 10.4% (59 of 566 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sah/

Translated using Weblate (Chuvash)

Currently translated at 100.0% (566 of 566 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/cv/

Translated using Weblate (Persian)

Currently translated at 96.6% (547 of 566 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/fa/

Added translation using Weblate (Yakut)

Translated using Weblate (Catalan)

Currently translated at 100.0% (566 of 566 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ca/

Translated using Weblate (Russian)

Currently translated at 100.0% (566 of 566 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ru/

Translated using Weblate (Spanish)

Currently translated at 100.0% (566 of 566 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/es/

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (566 of 566 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/zh_Hans/

Translated using Weblate (Spanish (Latin America))

Currently translated at 99.8% (565 of 566 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/es_419/

Translated using Weblate (Spanish (Latin America))

Currently translated at 99.8% (565 of 566 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/es_419/

Translated using Weblate (Greek)

Currently translated at 100.0% (566 of 566 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/el/

Translated using Weblate (Dutch)

Currently translated at 100.0% (566 of 566 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/nl/

Translated using Weblate (Czech)

Currently translated at 64.1% (363 of 566 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/cs/

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (566 of 566 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/zh_Hans/

Translated using Weblate (Italian)

Currently translated at 98.7% (559 of 566 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/it/

Translated using Weblate (Chuvash)

Currently translated at 100.0% (566 of 566 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/cv/

Translated using Weblate (Sardinian)

Currently translated at 99.8% (565 of 566 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sc/

Translated using Weblate (Filipino)

Currently translated at 100.0% (566 of 566 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/fil/

Translated using Weblate (Turkish)

Currently translated at 100.0% (566 of 566 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/tr/

Translated using Weblate (Indonesian)

Currently translated at 100.0% (566 of 566 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/id/

Translated using Weblate (Finnish)

Currently translated at 100.0% (566 of 566 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/fi/

Translated using Weblate (Norwegian Bokmål)

Currently translated at 90.4% (512 of 566 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/nb_NO/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (566 of 566 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pt_BR/

Translated using Weblate (Malay)

Currently translated at 100.0% (566 of 566 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ms/

Translated using Weblate (German)

Currently translated at 100.0% (566 of 566 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/de/

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (565 of 565 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/uk/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (565 of 565 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pt_BR/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (565 of 565 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pt_BR/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (565 of 565 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pt_BR/

Translated using Weblate (Sardinian)

Currently translated at 100.0% (565 of 565 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sc/

Translated using Weblate (Chuvash)

Currently translated at 100.0% (565 of 565 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/cv/

Translated using Weblate (Filipino)

Currently translated at 100.0% (565 of 565 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/fil/

Translated using Weblate (Norwegian Bokmål)

Currently translated at 89.3% (505 of 565 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/nb_NO/

Translated using Weblate (Spanish (Latin America))

Currently translated at 99.6% (563 of 565 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/es_419/

Translated using Weblate (Portuguese)

Currently translated at 100.0% (565 of 565 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pt/

Translated using Weblate (Catalan)

Currently translated at 100.0% (565 of 565 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ca/

Translated using Weblate (Greek)

Currently translated at 100.0% (565 of 565 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/el/

Translated using Weblate (Filipino)

Currently translated at 100.0% (565 of 565 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/fil/

Translated using Weblate (Dutch)

Currently translated at 100.0% (565 of 565 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/nl/

Translated using Weblate (Finnish)

Currently translated at 100.0% (565 of 565 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/fi/

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (565 of 565 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/zh_Hans/

Translated using Weblate (Turkish)

Currently translated at 100.0% (565 of 565 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/tr/

Translated using Weblate (Japanese)

Currently translated at 100.0% (565 of 565 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ja/

Translated using Weblate (Japanese)

Currently translated at 100.0% (565 of 565 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ja/

Translated using Weblate (German)

Currently translated at 100.0% (565 of 565 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/de/

Translated using Weblate (Malay)

Currently translated at 100.0% (565 of 565 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ms/

Co-authored-by: Hosted Weblate <hosted@weblate.org>
(cherry picked from commit 9ce994168a)
2020-08-12 00:33:25 -04:00
arkon b4b4497e7e Lift toolbar on scroll in extension details and manga controllers
(cherry picked from commit 748a720199)
2020-08-12 00:33:17 -04:00
arkon 19055e1699 Allow annotating SourceFactory with @Nsfw to block all sources within it
(cherry picked from commit 8db34eb3dd)
2020-08-12 00:33:07 -04:00
arkon f006467138 Add 18+ warnings in extensions list
(cherry picked from commit b657bba96e)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/ExtensionHolder.kt
2020-08-12 00:32:57 -04:00
Jobobby04 a740f79b56 Update readme 2020-08-12 00:28:37 -04:00
Jobobby04 6c388ae906 Cleanup images, replace some icons 2020-08-12 00:23:18 -04:00
Jobobby04 3fa5322133 Delegate NHentai, to continue using NHentai download the extension, SY requires NHentai version 1.2.28 2020-08-12 00:23:18 -04:00
Jobobby04 5a1bc6e25b Delegate Perv Eden, to continue using it download the extensions(there is a English extension and a Italian extension) 2020-08-12 00:21:29 -04:00
Jobobby04 51d0a67908 Account for custom delegated image requests, fixes Hitomi pages 2020-08-11 15:20:11 -04:00
Jobobby04 69f4d1fd46 Likely fix Hitomi extension 2020-08-11 01:35:36 -04:00
Jobobby04 8b53568fc8 Cleanup some hitomi leftovers 2020-08-10 23:47:26 -04:00
Jobobby04 d978b6d088 Update readme 2020-08-10 23:31:32 -04:00
Jobobby04 9a3fdc23e6 Delegate hitomi, it is now the first fully delegated factory source. To continue using hitomi please download the extension. This comes with a lot of fixes for future delegated factory sources 2020-08-10 23:29:10 -04:00
Jobobby04 f8efe5d189 Make a new debug function to help delegation 2020-08-10 21:15:48 -04:00
Jobobby04 aae23f5ef3 Delegate 8Muses, please manually migrate over your comics to the extension, as the old version of the 8Muses comics cannot support the new comics format 2020-08-10 21:15:08 -04:00
Jobobby04 eee2c34abf Fix library actions overflow menu 2020-08-10 18:30:10 -04:00
Jobobby04 c272eb6059 Move the Realm init out of the globalscope in hope it fixes crashes 2020-08-10 14:45:18 -04:00
Jobobby04 74065afc27 Hopefully fix issues with certain actions for some people 2020-08-10 00:55:39 -04:00
Jobobby04 ead5a258be More drag protection 2020-08-10 00:54:56 -04:00
Jobobby04 f9cf017594 Set smart reader background as the default 2020-08-09 20:22:26 -04:00
Mike 1211b2c86a Fix Hitomi chapters (#75) 2020-08-09 20:00:49 -04:00
Jobobby04 2bc845b1d2 Simple way to get chapter date for nHentai 2020-08-09 19:44:17 -04:00
Jobobby04 da8ed5c74f Fix zoom out webtoon showing in pager mode 2020-08-09 19:42:03 -04:00
arkon d7d1d97f5f Add option to prevent deleting bookmarked chapters (closes #2082)
(cherry picked from commit dbaac69fad)
2020-08-09 19:20:01 -04:00
arkon 63510b2e60 Minor cleanup
(cherry picked from commit b6a1e89535)
2020-08-09 19:19:53 -04:00
arkon d7976e6054 Minor rewording of chapter deletion settings
(cherry picked from commit cce919750a)
2020-08-09 19:19:45 -04:00
arkon c82d7db570 Bubble up sources with results in global search (closes #3598)
(cherry picked from commit 9376b223bb)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/GlobalSearchPresenter.kt
2020-08-09 19:19:32 -04:00
arkon b6f8db81ee Update OkHttp
(cherry picked from commit 6f047fb5aa)
2020-08-09 19:18:14 -04:00
arkon a2fb89066c Swallow errors when trying to determine available disk space when downloading (closes #3603)
(cherry picked from commit 3e6b0117fd)
2020-08-09 19:18:05 -04:00
arkon 6f71bb3abe Allow partially loading extensions with individually marked NSFW sources
(cherry picked from commit 421dfb4a2d)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/ExtensionPresenter.kt
2020-08-09 19:17:55 -04:00
Jobobby04 e945de74f2 Add manga grouping in library!! This was inspired by J2ks version of the feature 2020-08-09 19:13:47 -04:00
Jobobby04 0e43234c23 More cleanup for drag and drop 2020-08-08 17:09:30 -04:00
arkon f8c4bbdfd8 Option to hide NSFW extensions (closes #1312) (SY will expand more on this when preview finishes it)
(cherry picked from commit abaca6e676)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/ExtensionPresenter.kt
2020-08-08 16:47:29 -04:00
Jobobby04 c834c2fbb0 Tweak dragging so it works in action mode if there is only 1 manga selected 2020-08-08 16:32:03 -04:00
arkon ad62a6b10b Add mark as read/unread to library (closes #156)
Adapted from https://github.com/CarlosEsco/Neko/commit/e51276a1acb233467bbb1c7214be0ec105c62cb7

(cherry picked from commit 8bab1d9798)
2020-08-08 16:07:34 -04:00
arkon 04fbb70981 Explicitly depend on core-ktx
(cherry picked from commit 13d31669ac)
2020-08-08 16:07:25 -04:00
Jobobby04 340e534ca9 Remove uneeded checks for should move, fixes moving a manga to the first positon 2020-08-08 16:07:18 -04:00
Jobobby04 5714f183a8 Update drag and drop to work like J2k's new version
Cleanup some stuff from the continue reading button
2020-08-07 23:34:58 -04:00
Jobobby04 b6f6607d91 Cleanup readme 2020-08-06 21:27:10 -04:00
arkon aa794f4703 Fix MAL 0/10 scores (closes #3623)
(cherry picked from commit c1dfdeb500)
2020-08-06 21:21:43 -04:00
arkon a6d6a0fca6 Dismiss add manga snackbar when leaving controller (closes #3614)
(cherry picked from commit dda7e677a5)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt
2020-08-06 21:21:34 -04:00
Jobobby04 aa6f1a0de5 Cleanup 2020-08-06 21:09:25 -04:00
Jobobby04 52b9a1dbd2 Fix resources being in the wrong spot for some reason 2020-08-06 18:32:29 -04:00
Jobobby04 2f98dd2046 Add continue reading button, some resources gotten from J2k 2020-08-06 17:45:18 -04:00
Jobobby04 f60b29c763 Replace cleanup downloads for loops with forEach loops 2020-08-06 16:15:40 -04:00
Jobobby04 c2adf2fe0a Copy smart background from J2k 2020-08-06 16:11:00 -04:00
Jobobby04 c340884adb Copy enable/disable zoom out in webtoon reader from J2k 2020-08-06 14:59:58 -04:00
Jobobby04 0125f326b4 Copy cleanup orphaned downloads from J2k 2020-08-06 14:59:31 -04:00
Jobobby04 2de87f8d29 Cleanup 2020-08-06 14:57:54 -04:00
arkon 165b243aab Warn before restoring backup if trackers aren't logged in
(cherry picked from commit b1fb401f63)
2020-08-05 22:56:46 -04:00
arkon 961f7f9b6d Fix toolbar being expanded when opening preference dialogs
(cherry picked from commit 885ace111e)
2020-08-05 22:56:35 -04:00
Jobobby04 61094edeed Cleanup some code 2020-08-05 22:46:04 -04:00
Jobobby04 fbe4f6ad62 Dont download new chapters after refreshing a manga if its from E/ExHentai 2020-08-05 20:46:14 -04:00
Jobobby04 c552934acc Fix quick clean nHentai manga 2020-08-05 18:26:02 -04:00
Jobobby04 44c9df8c9b Add quick clean E-Hentai/nHentai titles, select them in your library and you can quick clean them 2020-08-05 18:23:36 -04:00
jobobby04 594a02fa69 Fix release builder 2020-08-05 15:01:24 -04:00
Jobobby04 510a67a755 Finishing a E-Hentai chapter will now mark previous chapters as read 2020-08-05 14:28:40 -04:00
Jobobby04 882856a028 Lint 2020-08-05 13:32:28 -04:00
Jobobby04 76adeae5ed Fix bug when pressing download unread chapters on a E-Hentai manga from library will download the latest chapter even if its read 2020-08-05 13:32:11 -04:00
arkon eb3c9a1d58 Move tracker setting dialogs
(cherry picked from commit 885552b792)
2020-08-04 23:35:31 -04:00
arkon 29f74ba423 Minor cleanup
(cherry picked from commit 4f02872a84)
2020-08-04 23:35:22 -04:00
arkon 571778adc1 Revert "Use insetter library for handling inset padding" (fixes #3586)
This reverts commit 3ddd1033c3.

(cherry picked from commit ecec1bd102)
2020-08-04 23:35:12 -04:00
Jobobby04 64c5b70c78 Redo the EH library search engine, make it work for every manga, meaning exclusion, partial matching, and a bunch of other things now working the library search 2020-08-04 23:34:26 -04:00
Jobobby04 bb87392eef Code cleanup 2020-08-04 22:51:56 -04:00
Jobobby04 29e1697d2e Fix migration crash because fetch chapter list through a exception 2020-08-03 19:44:02 -04:00
arkon 025d794962 Fix snackbars not being in viewport properly
(cherry picked from commit 060f0682f4)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceController.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt
2020-08-03 18:25:27 -04:00
arkon a284f5cd08 Use dialog to show what's new release info
(cherry picked from commit 88032e11df)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourceController.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt
2020-08-03 18:24:11 -04:00
arkon ee6b536b94 Adjust vertical reading mode tap zones (closes #3551)
Basically L shapes, where top/left goes back, bottom/right goes forward, and middle opens the menu.

(cherry picked from commit 493c8b0943)
2020-08-03 18:14:22 -04:00
arkon 285f65ca4f Remove Tagalog translations (closes #3579)
(cherry picked from commit af2ef0621a)
2020-08-03 18:14:10 -04:00
arkon d07dbee9b0 Explicitly dismiss progress notification on downloader stop
(cherry picked from commit 095461e31b)
2020-08-03 18:14:02 -04:00
arkon a5e1f92b05 Use insetter library for handling inset padding
(cherry picked from commit 3ddd1033c3)
2020-08-03 18:13:53 -04:00
arkon 417a31cfad Adjust download badge color again
(cherry picked from commit 912687ac78)
2020-08-03 18:13:45 -04:00
arkon a84df3501a Request gzipped version of extensions repo
(cherry picked from commit 40a9595012)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/extension/api/ExtensionGithubApi.kt
2020-08-03 18:13:38 -04:00
arkon 01137bf476 Fix manga title disappearing in toolbar when pushing another controller
(cherry picked from commit 12ff37d052)
2020-08-03 18:08:33 -04:00
arkon 4c20ba38cb Revert "Use AndroidX WebKit library"
This reverts commit 7e7eb9f39f.

(cherry picked from commit 4857073f30)

# Conflicts:
#	app/build.gradle
2020-08-03 18:08:24 -04:00
Jobobby04 cb4daa81c4 Add a release builder action 2020-08-03 17:33:07 -04:00
Jobobby04 4f803494ff Update the EH search engine to fix issues with the current search features 2020-08-03 17:21:10 -04:00
Jobobby04 fb19f6b860 Update nHentai internal logic to be the same as the extension 2020-08-03 12:54:46 -04:00
jobobby04 885c94f9c8 Make the preview builder only happen on master 2020-08-03 12:47:16 -04:00
joseph619 a5b7ad6495 Update preview images to 1.1.0 2020-08-02 21:02:49 -04:00
Jobobby04 b9583a31c9 Update readme
Remote Dispatch Action Initiator / ping-pong (push) Failing after 10s
2020-08-02 16:29:13 -04:00
Jobobby04 926fa85ccd Release 1.1.1 2020-08-02 16:26:07 -04:00
Jobobby04 b91252df67 HBrowse url matching sorta fixed 2020-08-02 16:24:54 -04:00
arkon 3893c90eb2 Make download badges lighter to improve contrast (closes #3571)
(cherry picked from commit 2e9d89574d)
2020-08-02 15:11:29 -04:00
Jozef Hollý d5f4783aca Translated using Weblate (Russian) (#3549)
Currently translated at 100.0% (565 of 565 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ru/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (565 of 565 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pt_BR/

Translated using Weblate (Indonesian)

Currently translated at 100.0% (565 of 565 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/id/

Translated using Weblate (Hindi)

Currently translated at 100.0% (565 of 565 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/hi/

Translated using Weblate (Spanish)

Currently translated at 100.0% (565 of 565 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/es/

Translated using Weblate (Russian)

Currently translated at 100.0% (564 of 564 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ru/

Translated using Weblate (Georgian)

Currently translated at 9.3% (53 of 564 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ka/

Translated using Weblate (Tagalog)

Currently translated at 73.9% (417 of 564 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/tl/

Translated using Weblate (Serbian)

Currently translated at 79.9% (451 of 564 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sr/

Translated using Weblate (Thai)

Currently translated at 58.1% (328 of 564 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/th/

Translated using Weblate (Norwegian Bokmål)

Currently translated at 88.6% (500 of 564 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/nb_NO/

Translated using Weblate (Czech)

Currently translated at 64.0% (361 of 564 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/cs/

Translated using Weblate (Korean)

Currently translated at 57.9% (327 of 564 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ko/

Translated using Weblate (Hungarian)

Currently translated at 35.6% (201 of 564 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/hu/

Translated using Weblate (Bengali)

Currently translated at 60.4% (341 of 564 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/bn/

Translated using Weblate (Czech)

Currently translated at 63.8% (360 of 564 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/cs/

Co-authored-by: Hosted Weblate <hosted@weblate.org>
(cherry picked from commit 569c99496b)
2020-08-02 15:11:12 -04:00
arkon b0bcfa9db0 Fix crash when filter groups contain items with identical names (closes #3568)
(cherry picked from commit ea3b8767de)
2020-08-02 15:11:01 -04:00
arkon 01ea86ab90 Move download warnings/errors to separate notification channel
(cherry picked from commit 8e8c30c1eb)
2020-08-02 15:10:52 -04:00
arkon 475299d9b3 Revert "Downgrade coroutines and flow-preferences"
This reverts commit b47ee8857b.

(cherry picked from commit d921ba81c8)
2020-08-02 15:10:43 -04:00
arkon 951bb1f3c6 Fix downloads not working for custom SD card paths (closes #3564)
(cherry picked from commit ad9f646102)
2020-08-02 15:10:34 -04:00
arkon 1f7e69e13c Don't show completed notification if download error notification was shown
(cherry picked from commit 2ef277bcef)
2020-08-02 15:10:23 -04:00
arkon 5fbaa7d6be Fix history item icon tint in light blue theme
(cherry picked from commit 9e396e1624)
2020-08-02 15:09:22 -04:00
Jobobby04 cce1b135c9 Tweak HBrowse migration 2020-08-02 15:08:47 -04:00
Jobobby04 b344a3944e Fix certain HBrowse manga 2020-08-02 15:06:49 -04:00
arkon 7f416bda7c Fix dividers in migrate list
(cherry picked from commit 9708d84e60)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/manga/MigrationMangaController.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/sources/MigrationSourcesController.kt
2020-08-02 00:58:13 -04:00
arkon 3b08c7fdea Fix last used source pinned status
(cherry picked from commit 4efc195548)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourcePresenter.kt
2020-08-02 00:55:28 -04:00
Jobobby04 e346d95b0e Delegate HBrowse 2020-08-02 00:50:52 -04:00
arkon 0fe8990f99 Filter out chapter entries with duplicate URLs (fixes #3552)
(cherry picked from commit 0d15cbe334)
2020-08-01 16:40:43 -04:00
jobobby04 35ed8e2d34 Update README.md 2020-08-01 15:29:14 -04:00
Jobobby04 12d01b9da3 Release 1.1.0
Remote Dispatch Action Initiator / ping-pong (push) Failing after 10s
2020-08-01 15:07:32 -04:00
Jobobby04 2b7ffc8ba2 Fix 8Muses chapters 2020-08-01 14:34:28 -04:00
arkon 1b91062767 Fix for reader crash in < Android 9
(cherry picked from commit 85ed7a7457)
2020-08-01 14:03:26 -04:00
Jobobby04 4a71eb2ff0 Fix hitomi.la thumbnails 2020-08-01 13:17:16 -04:00
arkon 6fe9284c07 Update issue templates
(cherry picked from commit b8a98ef5e4)

# Conflicts:
#	.github/readme-images/screens.png
#	app/build.gradle
2020-08-01 13:01:00 -04:00
Jozef Hollý 51c2a1b048 Translated using Weblate (French) (#3528)
Currently translated at 99.8% (563 of 564 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/fr/

Translated using Weblate (Kannada)

Currently translated at 100.0% (564 of 564 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/kn/

Translated using Weblate (Chinese (Traditional))

Currently translated at 98.7% (557 of 564 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/zh_Hant/

Translated using Weblate (Hindi)

Currently translated at 100.0% (564 of 564 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/hi/

Translated using Weblate (Japanese)

Currently translated at 100.0% (564 of 564 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ja/

Translated using Weblate (Marathi)

Currently translated at 41.4% (234 of 564 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/mr/

Translated using Weblate (Swedish)

Currently translated at 100.0% (564 of 564 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sv/

Translated using Weblate (Russian)

Currently translated at 100.0% (564 of 564 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ru/

Translated using Weblate (Spanish)

Currently translated at 100.0% (564 of 564 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/es/

Translated using Weblate (Chinese (Traditional))

Currently translated at 97.8% (552 of 564 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/zh_Hant/

Translated using Weblate (Chuvash)

Currently translated at 100.0% (564 of 564 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/cv/

Translated using Weblate (Croatian)

Currently translated at 100.0% (564 of 564 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/hr/

Translated using Weblate (Portuguese)

Currently translated at 100.0% (564 of 564 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pt/

Translated using Weblate (Sardinian)

Currently translated at 100.0% (564 of 564 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sc/

Translated using Weblate (Dutch)

Currently translated at 100.0% (564 of 564 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/nl/

Translated using Weblate (Catalan)

Currently translated at 100.0% (564 of 564 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ca/

Translated using Weblate (Greek)

Currently translated at 100.0% (564 of 564 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/el/

Translated using Weblate (Indonesian)

Currently translated at 100.0% (564 of 564 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/id/

Translated using Weblate (Turkish)

Currently translated at 100.0% (564 of 564 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/tr/

Translated using Weblate (Finnish)

Currently translated at 100.0% (564 of 564 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/fi/

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (564 of 564 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/zh_Hans/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (564 of 564 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pt_BR/

Translated using Weblate (Malay)

Currently translated at 100.0% (564 of 564 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ms/

Translated using Weblate (German)

Currently translated at 100.0% (564 of 564 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/de/

Update translation files

Updated by "Cleanup translation files" hook in Weblate.

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/

Translated using Weblate (Malay)

Currently translated at 100.0% (564 of 564 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ms/

Translated using Weblate (German)

Currently translated at 100.0% (564 of 564 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/de/

Translated using Weblate (Catalan)

Currently translated at 100.0% (564 of 564 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ca/

Translated using Weblate (Russian)

Currently translated at 100.0% (564 of 564 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ru/

Translated using Weblate (Spanish)

Currently translated at 100.0% (564 of 564 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/es/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (564 of 564 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pt_BR/

Translated using Weblate (Filipino)

Currently translated at 100.0% (563 of 563 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/fil/

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (563 of 563 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/uk/

Translated using Weblate (Sardinian)

Currently translated at 100.0% (563 of 563 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sc/

Translated using Weblate (Dutch)

Currently translated at 100.0% (563 of 563 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/nl/

Translated using Weblate (Indonesian)

Currently translated at 100.0% (563 of 563 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/id/

Translated using Weblate (Czech)

Currently translated at 63.9% (360 of 563 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/cs/

Co-authored-by: Hosted Weblate <hosted@weblate.org>
(cherry picked from commit c8fa90f473)
2020-08-01 12:58:31 -04:00
arkon 03b3046ece Downgrade coroutines and flow-preferences
(cherry picked from commit b47ee8857b)

# Conflicts:
#	app/build.gradle
2020-08-01 12:57:52 -04:00
arkon ea2f050f86 Temporarily revert to stable version of androidx.biometric (closes #3425)
(cherry picked from commit 131dfa62c4)
2020-08-01 12:54:04 -04:00
arkon f41077449a Temporarily unrevert crop borders unification (closes #3487)
Reverts 1920568057

(cherry picked from commit 6a5af438dd)
2020-08-01 12:53:54 -04:00
arkon aad0ac7296 Shift WebView checks to necessary places only to allow for basic usage
(cherry picked from commit ccc0a61158)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/App.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/main/ForceCloseActivity.kt
2020-08-01 12:53:39 -04:00
arkon 5e59d05598 Fix tap region for manga summary
(cherry picked from commit e990ad25eb)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoHeaderAdapter.kt
#	app/src/main/res/layout/manga_info_header.xml
2020-08-01 12:51:55 -04:00
arkon 337d270d2a Actually fix library search properly
(cherry picked from commit 98a4d1e763)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt
2020-08-01 12:34:35 -04:00
arkon 09c9e15281 Fix library search query being lost when returning (closes #3473)
(cherry picked from commit f762598c5c)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryAdapter.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryView.kt
2020-08-01 12:32:21 -04:00
arkon 057ccf74ce More core-ktx usages
(cherry picked from commit ec56c27071)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChapterDividerItemDecoration.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/more/AboutController.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAdvancedController.kt
2020-08-01 12:26:35 -04:00
arkon c21771823c Use Kotlin extensions for preference editing
(cherry picked from commit eb0e0a1952)
2020-08-01 12:17:18 -04:00
arkon 987e5bcf33 Make source options dialog into a controller to retain state
(cherry picked from commit 01a837fde6)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourceController.kt
2020-08-01 12:17:03 -04:00
arkon 3920a5a73b Hide cutout option when appropriate in reader settings sheet (closes #2982)
(cherry picked from commit b9488645d4)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderSettingsSheet.kt
2020-08-01 12:10:44 -04:00
arkon 00701aeda1 Update ConstraintLayout
(cherry picked from commit 7a94b477cb)
2020-08-01 12:09:31 -04:00
arkon bb47188d5c Fix download status updates not appearing in chapters list (fixes #3358)
(cherry picked from commit 99710b45d1)
2020-08-01 12:09:21 -04:00
Jobobby04 06e57b790e Blacklist the nHentai extension non-english sources, and a few debug function edits 2020-07-30 16:15:38 -04:00
Jobobby04 ff48e89161 Now really fix internal sources download badges not showing up, plus some refactoring and testing debug functions 2020-07-30 15:56:18 -04:00
arkon e338bb0f47 Split download notifications into progress and complete channels
(cherry picked from commit 3813743e3d)
2020-07-29 23:21:01 -04:00
Jobobby04 ae48c1d7d4 Fix nHentai and E-Hentai manga download badges when the extension is installed as well. Closes #55 2020-07-29 23:13:58 -04:00
Jobobby04 243c65d012 Cleanup unused paramater 2020-07-29 21:13:45 -04:00
Jobobby04 e9903a6678 Pressing download unread chapters on E/ExHentai manga in your library will only download the latest version of the gallery 2020-07-29 20:53:07 -04:00
Jobobby04 afe32f1099 Pressing download next on a E/Exhentai manga will download the latest chapter 2020-07-29 20:41:19 -04:00
Jobobby04 acf2ad7c77 E/ExHentai manga fab, dont return chapter if its already read 2020-07-29 20:31:25 -04:00
Jobobby04 4286fd606a Update realms to 7.0.1 in hope of fixing android 7.1.2 SY 2020-07-29 20:23:30 -04:00
Jimmy Low 70d134b375 [Feature Request] - Download Complete Remidner #3475 (#3527)
* [Feat] Show a download complete notification channel when all downloads are completed. Auto cancels when onclick and navigate to download screen.

* [Feat] Update the download message string to shorten the length.

(cherry picked from commit 7e73ede47a)
2020-07-29 19:27:19 -04:00
arkon a8d0564eb0 Replace VectorDrawableCompat.create() with AppCompatResources.getDrawable()
Fixes crash when loading pin icon in Android 5/6.

(cherry picked from commit 9bb2334b69)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/widget/ExtendedNavigationView.kt
2020-07-29 18:43:43 -04:00
Jobobby04 df6bbbd4c6 Fix source category deletion crash 2020-07-29 00:26:14 -04:00
Jobobby04 7a08fa3398 Hide the pin button in merge with another 2020-07-29 00:02:18 -04:00
Jobobby04 46d9c024da Recommendations crash fix 2020-07-28 23:38:36 -04:00
Jobobby04 2c49466a42 Fix crash on E-Hentai when pressing the FAB when the chapters havent loaded yet 2020-07-28 22:33:43 -04:00
Jobobby04 a6cba5c87d Add special view for browsing E/Exhentai! All the important info is now in front of your face when browsing, it is on by default and can be toggled off in the E-Hentai settings. Let me know if you find any errors 2020-07-28 16:55:33 -04:00
arkon 032504f128 Fix getting stuck in chapter loop when chapters have identical URLs
(cherry picked from commit b0106aa420)
2020-07-27 17:48:08 -04:00
Jobobby04 f5b6fc5b54 Cleanup 2020-07-27 13:33:42 -04:00
Jobobby04 c0e1ca1185 Parse more info when browsing E/Exhentai (cont) 2020-07-26 21:45:44 -04:00
arkon fa812830b8 Explicitly destroy webview on activity destroy
(cherry picked from commit 33e5fea96c)
2020-07-26 18:15:14 -04:00
arkon b4c68f454d Prevent spamming updates with newly favorited manga
(cherry picked from commit f0a1dcd120)
2020-07-26 18:15:06 -04:00
arkon a13166b69d Fix source item flashing when pinning
(cherry picked from commit 26d5a87bef)
2020-07-26 18:14:41 -04:00
arkon 0556c5c2ff Show lang code in source long press dialog
(cherry picked from commit 52ae208df3)
2020-07-26 18:14:32 -04:00
arkon c449a59696 Remove explicit source browse button, tint pin icon when pinned
(cherry picked from commit 34aaa7fb0a)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/sources/SourceHolder.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourceHolder.kt
2020-07-26 18:14:05 -04:00
arkon 2339388d6f Fix Chinese plurals
(cherry picked from commit a8c784355c)
2020-07-26 18:01:26 -04:00
arkon 9c669d040a Don't show chapter number in history item when unknown
(cherry picked from commit 0aed93becf)
2020-07-26 18:01:16 -04:00
Jozef Hollý 82acb4412a Translated using Weblate (Croatian) (#3421)
Currently translated at 100.0% (563 of 563 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/hr/

Translated using Weblate (Chinese (Traditional))

Currently translated at 98.5% (555 of 563 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/zh_Hant/

Translated using Weblate (Russian)

Currently translated at 100.0% (563 of 563 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ru/

Translated using Weblate (Latvian)

Currently translated at 34.6% (195 of 563 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/lv/

Translated using Weblate (Spanish)

Currently translated at 100.0% (563 of 563 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/es/

Translated using Weblate (Greek)

Currently translated at 100.0% (563 of 563 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/el/

Translated using Weblate (French)

Currently translated at 100.0% (563 of 563 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/fr/

Translated using Weblate (Finnish)

Currently translated at 100.0% (563 of 563 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/fi/

Translated using Weblate (Turkish)

Currently translated at 100.0% (563 of 563 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/tr/

Translated using Weblate (Indonesian)

Currently translated at 100.0% (563 of 563 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/id/

Translated using Weblate (Kannada)

Currently translated at 100.0% (563 of 563 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/kn/

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (563 of 563 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/zh_Hans/

Translated using Weblate (Hindi)

Currently translated at 100.0% (563 of 563 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/hi/

Translated using Weblate (Portuguese)

Currently translated at 100.0% (563 of 563 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pt/

Translated using Weblate (Catalan)

Currently translated at 100.0% (563 of 563 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ca/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (563 of 563 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pt_BR/

Translated using Weblate (Malay)

Currently translated at 100.0% (563 of 563 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ms/

Translated using Weblate (Chuvash)

Currently translated at 100.0% (563 of 563 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/cv/

Translated using Weblate (German)

Currently translated at 100.0% (563 of 563 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/de/

Translated using Weblate (Latvian)

Currently translated at 27.4% (154 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/lv/

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/zh_Hans/

Translated using Weblate (Latvian)

Currently translated at 26.6% (150 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/lv/

Translated using Weblate (Latvian)

Currently translated at 25.2% (142 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/lv/

Translated using Weblate (German)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/de/

Translated using Weblate (Portuguese)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pt/

Translated using Weblate (Latvian)

Currently translated at 21.8% (123 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/lv/

Translated using Weblate (Filipino)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/fil/

Translated using Weblate (Italian)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/it/

Translated using Weblate (French)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/fr/

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/uk/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pt_BR/

Translated using Weblate (Russian)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ru/

Translated using Weblate (Spanish)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/es/

Translated using Weblate (Romanian)

Currently translated at 99.8% (561 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ro/

Translated using Weblate (Spanish (Latin America))

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/es_419/

Translated using Weblate (Catalan)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ca/

Translated using Weblate (Chinese (Traditional))

Currently translated at 98.3% (553 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/zh_Hant/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pt_BR/

Translated using Weblate (Sardinian)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sc/

Translated using Weblate (Dutch)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/nl/

Translated using Weblate (Finnish)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/fi/

Translated using Weblate (Turkish)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/tr/

Translated using Weblate (German)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/de/

Translated using Weblate (Chuvash)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/cv/

Translated using Weblate (Chinese (Traditional))

Currently translated at 98.3% (553 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/zh_Hant/

Translated using Weblate (Indonesian)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/id/

Translated using Weblate (Indonesian)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/id/

Translated using Weblate (Chinese (Simplified))

Currently translated at 99.8% (561 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/zh_Hans/

Translated using Weblate (Greek)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/el/

Translated using Weblate (Malay)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ms/

Translated using Weblate (German)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/de/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pt_BR/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pt_BR/

Translated using Weblate (Georgian)

Currently translated at 6.9% (39 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ka/

Translated using Weblate (Sardinian)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sc/

Translated using Weblate (Indonesian)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/id/

Translated using Weblate (Chuvash)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/cv/

Translated using Weblate (French)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/fr/

Translated using Weblate (Catalan)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ca/

Translated using Weblate (Russian)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ru/

Translated using Weblate (Spanish)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/es/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pt_BR/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pt_BR/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pt_BR/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pt_BR/

Translated using Weblate (Kannada)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/kn/

Translated using Weblate (Hindi)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/hi/

Translated using Weblate (Filipino)

Currently translated at 97.8% (550 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/fil/

Translated using Weblate (Spanish (Latin America))

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/es_419/

Translated using Weblate (Vietnamese)

Currently translated at 87.5% (492 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/vi/

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/uk/

Translated using Weblate (Portuguese)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pt/

Translated using Weblate (Chuvash)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/cv/

Translated using Weblate (Finnish)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/fi/

Translated using Weblate (Greek)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/el/

Translated using Weblate (Turkish)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/tr/

Translated using Weblate (Dutch)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/nl/

Translated using Weblate (Indonesian)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/id/

Translated using Weblate (German)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/de/

Translated using Weblate (Croatian)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/hr/

Translated using Weblate (Malay)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ms/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pt_BR/

Translated using Weblate (Indonesian)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/id/

Translated using Weblate (Chuvash)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/cv/

Translated using Weblate (Swedish)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sv/

Translated using Weblate (Polish)

Currently translated at 99.8% (561 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pl/

Translated using Weblate (Dutch)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/nl/

Translated using Weblate (Hindi)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/hi/

Translated using Weblate (Greek)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/el/

Translated using Weblate (Catalan)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ca/

Translated using Weblate (Portuguese)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pt/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pt_BR/

Translated using Weblate (Italian)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/it/

Translated using Weblate (French)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/fr/

Translated using Weblate (German)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/de/

Translated using Weblate (German)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/de/

Translated using Weblate (Filipino)

Currently translated at 56.0% (315 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/fil/

Translated using Weblate (Sardinian)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sc/

Translated using Weblate (Norwegian Bokmål)

Currently translated at 90.0% (506 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/nb_NO/

Translated using Weblate (Greek)

Currently translated at 99.6% (560 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/el/

Translated using Weblate (Turkish)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/tr/

Translated using Weblate (Romanian)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ro/

Translated using Weblate (Chuvash)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/cv/

Translated using Weblate (Finnish)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/fi/

Translated using Weblate (Chuvash)

Currently translated at 99.2% (558 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/cv/

Translated using Weblate (Chinese (Simplified))

Currently translated at 99.8% (561 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/zh_Hans/

Translated using Weblate (Russian)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ru/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pt_BR/

Translated using Weblate (Malay)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ms/

Translated using Weblate (Spanish)

Currently translated at 100.0% (562 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/es/

Translated using Weblate (German)

Currently translated at 99.8% (561 of 562 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/de/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (560 of 560 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pt_BR/

Translated using Weblate (Malay)

Currently translated at 100.0% (560 of 560 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ms/

Translated using Weblate (Malay)

Currently translated at 100.0% (559 of 559 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ms/

Translated using Weblate (Italian)

Currently translated at 99.6% (557 of 559 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/it/

Translated using Weblate (French)

Currently translated at 100.0% (559 of 559 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/fr/

Translated using Weblate (German)

Currently translated at 100.0% (559 of 559 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/de/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (559 of 559 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pt_BR/

Translated using Weblate (Malay)

Currently translated at 100.0% (558 of 558 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ms/

Translated using Weblate (Turkish)

Currently translated at 100.0% (558 of 558 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/tr/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (558 of 558 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pt_BR/

Translated using Weblate (Finnish)

Currently translated at 100.0% (557 of 557 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/fi/

Translated using Weblate (Turkish)

Currently translated at 100.0% (557 of 557 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/tr/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (557 of 557 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pt_BR/

Translated using Weblate (German)

Currently translated at 100.0% (557 of 557 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/de/

Translated using Weblate (Chuvash)

Currently translated at 100.0% (556 of 556 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/cv/

Translated using Weblate (Chinese (Simplified))

Currently translated at 99.8% (555 of 556 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/zh_Hans/

Translated using Weblate (Swedish)

Currently translated at 99.4% (553 of 556 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sv/

Translated using Weblate (Greek)

Currently translated at 100.0% (556 of 556 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/el/

Translated using Weblate (Korean)

Currently translated at 58.6% (326 of 556 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ko/

Translated using Weblate (Italian)

Currently translated at 100.0% (556 of 556 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/it/

Translated using Weblate (Hungarian)

Currently translated at 36.6% (204 of 556 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/hu/

Translated using Weblate (French)

Currently translated at 100.0% (556 of 556 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/fr/

Translated using Weblate (French)

Currently translated at 100.0% (556 of 556 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/fr/

Translated using Weblate (German)

Currently translated at 100.0% (556 of 556 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/de/

Translated using Weblate (Bengali)

Currently translated at 61.8% (344 of 556 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/bn/

Translated using Weblate (French)

Currently translated at 100.0% (556 of 556 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/fr/

Translated using Weblate (Croatian)

Currently translated at 100.0% (556 of 556 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/hr/

Translated using Weblate (Spanish (Latin America))

Currently translated at 100.0% (556 of 556 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/es_419/

Translated using Weblate (Spanish)

Currently translated at 100.0% (556 of 556 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/es/

Translated using Weblate (Spanish (Latin America))

Currently translated at 86.8% (483 of 556 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/es_419/

Translated using Weblate (Spanish (Latin America))

Currently translated at 77.3% (430 of 556 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/es_419/

Translated using Weblate (Spanish)

Currently translated at 100.0% (556 of 556 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/es/

Translated using Weblate (Spanish (Latin America))

Currently translated at 75.7% (421 of 556 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/es_419/

Translated using Weblate (Spanish)

Currently translated at 100.0% (556 of 556 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/es/

Translated using Weblate (Spanish (Latin America))

Currently translated at 67.9% (378 of 556 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/es_419/

Translated using Weblate (Japanese)

Currently translated at 99.8% (555 of 556 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ja/

Translated using Weblate (Spanish (Latin America))

Currently translated at 67.8% (377 of 556 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/es_419/

Translated using Weblate (Spanish)

Currently translated at 100.0% (556 of 556 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/es/

Translated using Weblate (Spanish (Latin America))

Currently translated at 65.6% (365 of 556 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/es_419/

Translated using Weblate (Spanish (Latin America))

Currently translated at 64.5% (359 of 556 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/es_419/

Translated using Weblate (Spanish)

Currently translated at 100.0% (556 of 556 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/es/

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (556 of 556 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/uk/

Translated using Weblate (Spanish (Latin America))

Currently translated at 59.7% (332 of 556 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/es_419/

Translated using Weblate (Spanish)

Currently translated at 100.0% (556 of 556 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/es/

Translated using Weblate (Chinese (Traditional))

Currently translated at 98.0% (545 of 556 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/zh_Hant/

Translated using Weblate (Turkish)

Currently translated at 100.0% (556 of 556 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/tr/

Translated using Weblate (Russian)

Currently translated at 100.0% (556 of 556 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ru/

Translated using Weblate (Chinese (Traditional))

Currently translated at 97.4% (542 of 556 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/zh_Hant/

Translated using Weblate (Romanian)

Currently translated at 100.0% (556 of 556 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ro/

Translated using Weblate (Indonesian)

Currently translated at 100.0% (556 of 556 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/id/

Translated using Weblate (Chinese (Traditional))

Currently translated at 97.3% (541 of 556 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/zh_Hant/

Translated using Weblate (Finnish)

Currently translated at 100.0% (556 of 556 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/fi/

Translated using Weblate (Chuvash)

Currently translated at 100.0% (556 of 556 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/cv/

Translated using Weblate (Spanish (Latin America))

Currently translated at 17.4% (97 of 556 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/es_419/

Translated using Weblate (Russian)

Currently translated at 100.0% (556 of 556 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ru/

Translated using Weblate (Hindi)

Currently translated at 99.8% (555 of 556 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/hi/

Translated using Weblate (Greek)

Currently translated at 100.0% (556 of 556 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/el/

Translated using Weblate (Chinese (Simplified))

Currently translated at 99.8% (555 of 556 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/zh_Hans/

Translated using Weblate (Portuguese)

Currently translated at 100.0% (556 of 556 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pt/

Translated using Weblate (French)

Currently translated at 100.0% (556 of 556 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/fr/

Translated using Weblate (Chuvash)

Currently translated at 100.0% (556 of 556 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/cv/

Translated using Weblate (Sardinian)

Currently translated at 99.6% (554 of 556 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/sc/

Translated using Weblate (Russian)

Currently translated at 100.0% (556 of 556 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ru/

Translated using Weblate (Malay)

Currently translated at 100.0% (556 of 556 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/ms/

Translated using Weblate (Spanish)

Currently translated at 100.0% (556 of 556 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/es/

Translated using Weblate (German)

Currently translated at 100.0% (556 of 556 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/de/

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (556 of 556 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/pt_BR/

Update translation files

Updated by "Cleanup translation files" hook in Weblate.

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/

Translated using Weblate (Czech)

Currently translated at 65.2% (362 of 555 strings)

Translation: Tachiyomi/Strings
Translate-URL: https://hosted.weblate.org/projects/tachiyomi/strings/cs/

Co-authored-by: Hosted Weblate <hosted@weblate.org>
(cherry picked from commit 1ea0804209)
2020-07-26 18:01:04 -04:00
Jobobby04 23b0c3305d Parse more info when browsing E/ExHentai 2020-07-26 17:29:16 -04:00
Jobobby04 47373a9483 Fix manga info divider for the first chapter in certain situations 2020-07-25 23:15:51 -04:00
arkon 87e3a610e1 Add pin icon to sources list (closes #2862)
(cherry picked from commit a52fbb012a)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourceController.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourceHolder.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourceItem.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourcePresenter.kt
2020-07-25 22:40:43 -04:00
arkon 94d14af2a4 Add operator functions for handling set preferences
(cherry picked from commit 2dc47352f8)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourceFilterController.kt
2020-07-25 22:30:21 -04:00
arkon 99becd4fd6 Show message when searching with no pinned sources
(cherry picked from commit e95a5be21d)
2020-07-25 22:19:08 -04:00
arkon f21ef47c87 Fix weird backstack behaviour after clearing database
Shouldn't affect anything since controllers are recreated when entering different sections.

(cherry picked from commit abd69d4f91)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAdvancedController.kt
2020-07-25 22:18:59 -04:00
arkon 2ef7212128 Minor optimizations for local source dir lookups
(cherry picked from commit d749e309f8)
2020-07-25 22:13:13 -04:00
arkon 0003d11da3 Update dependencies
(cherry picked from commit e4d075fb91)
2020-07-25 22:13:04 -04:00
arkon bf49023693 Lazily find chapter directories
(cherry picked from commit 71c6c71081)
2020-07-25 22:12:53 -04:00
arkon e1bdb1dd0f Inline extension functions
(cherry picked from commit d2b14bcfc4)
2020-07-25 22:12:44 -04:00
arkon 2222c030b8 Increase dismiss timeout for what's new snackbar
(cherry picked from commit 2c04c81bd1)
2020-07-25 22:12:35 -04:00
arkon 1631bfd5c6 Use some more core-ktx extensions
(cherry picked from commit dd66c83c50)
2020-07-25 22:11:55 -04:00
arkon 72f3ebb70d Replace custom visibility extension functions
(cherry picked from commit 9e51d82154)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/SearchController.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/sources/SourceHolder.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourceHolder.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCompactGridHolder.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryListHolder.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoHeaderAdapter.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt
2020-07-25 22:11:44 -04:00
arkon 17e5ebd171 Hide manga title in toolbar when at top
(cherry picked from commit bdc441a5be)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt
2020-07-25 21:29:33 -04:00
arkon b2059288b7 Update Material Components
(cherry picked from commit 2dcb73700b)
2020-07-25 21:20:55 -04:00
arkon f24926fc81 More consistent library list view padding (closes #3509)
(cherry picked from commit 9a55cf880e)
2020-07-25 21:20:39 -04:00
arkon aba324a461 Hide tracking button if none logged in, show for non-favorited manga (closes #3507)
(cherry picked from commit 6742cdeb8b)
2020-07-25 21:20:21 -04:00
Jobobby04 4a19f8cff2 Remove the dividers between the new view 2020-07-25 21:20:07 -04:00
arkon 302db11482 Remove divider between manga info header and chapters header
(cherry picked from commit c37377bffa)
2020-07-25 21:05:26 -04:00
Ken Swenson 1af2698b72 fix: Download on WiFi regardless of metered status (#3489)
* fix: Download on WiFi regardless of metered status

fixes #3395

* fix: check if not WiFi rather than checking if connection is mobile

(cherry picked from commit 76147a9be7)
2020-07-25 21:05:16 -04:00
Jobobby04 3e9c8dbfd2 Add a special view to replace descriptions for integrated and delegated sources!
As the integrated and delegated websites don't actually have descriptions, just info, I decided to make a special view for them! with all the info you need available to you in front of your face, there is now no need to go searching through the description! This is likely the most work I have put into 1 feature in the whole time I have been developing TachiyomiSY!
2020-07-25 21:04:13 -04:00
Jobobby04 a38cb2ab5f Downloader conflict fixing 2020-07-24 23:19:57 -04:00
Jobobby04 589464d723 More rename downloaded chapter tweaks 2020-07-24 23:11:36 -04:00
Jobobby04 d7f3b399f4 Make the rename function do less lookups 2020-07-24 22:41:07 -04:00
Jobobby04 646aeb66c5 Inline the foreach functions 2020-07-24 22:37:54 -04:00
Jobobby04 135f0bdd95 Add scanlator to download pending deleter chapter data class 2020-07-24 22:26:31 -04:00
Jobobby04 80394dab4a Tweaks based on comments in the PR 2020-07-24 22:16:23 -04:00
Jobobby04 75e9911317 SY maybe supports J2k downloads now 2020-07-24 21:46:59 -04:00
Jobobby04 a311a3b497 Fix auto captcha opening when you dont have the option enabled (temp fix) 2020-07-24 12:36:20 -04:00
Jobobby04 f3b6855684 Add cancel buttons to tag watching and tag filtering settings. Fix the - sign saying there was a input error in the tag filtering input 2020-07-20 20:54:39 -04:00
Jobobby04 2ee69c2ac4 Fixes for a few strings 2020-07-20 15:15:28 -04:00
Jobobby04 ff0516726b pt-rBR fixes and updates by SamOak! 2020-07-19 22:51:29 -04:00
Jobobby04 7e5de79d5f Revert "Migrate library to ViewPager2"
This reverts commit 570db67894.
2020-07-19 21:56:41 -04:00
arkon dabb7a0494 Don't initialize mangas if viewing source in list view if on metered connection
(cherry picked from commit c401915fb5)
2020-07-19 21:56:10 -04:00
Jobobby04 ff1e0d7578 Allow hitomi users to select whether they want to download images as Webp or not 2020-07-19 20:06:47 -04:00
Jobobby04 4771fa529d Update latest tab with the new global search features 2020-07-19 19:52:50 -04:00
Jobobby04 8e94afb9c1 Add a option to put the recommendations into the overflow menu instead of the manga page 2020-07-19 19:22:08 -04:00
arkon 570db67894 Migrate library to ViewPager2
(cherry picked from commit 2a202bd510)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/widget/RecyclerViewPagerAdapter.kt
2020-07-19 18:56:55 -04:00
arkon 875b2fbccd Rename chapters_controller to manga_controller
(cherry picked from commit dcd8ed08fc)
2020-07-19 18:52:54 -04:00
arkon e562f0392d Explicitly show "No results found" in global search instead of hiding row
(cherry picked from commit d3ebedeef2)
2020-07-19 18:52:44 -04:00
arkon e142af00fa Add ripple to global search source title
(cherry picked from commit d2e2ebbe45)
2020-07-19 18:52:35 -04:00
arkon a5c4098109 Show tracker status in button
(cherry picked from commit a443dc3040)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoHeaderAdapter.kt
#	app/src/main/res/drawable/ic_done_white_18dp.xml
2020-07-19 18:52:23 -04:00
arkon 62091790a5 Update subsampling-scale-image-view
(cherry picked from commit 4e6cc013e5)

# Conflicts:
#	build.gradle.kts
2020-07-19 18:48:25 -04:00
arkon 7ddfedd9c7 Switch to tachiyomiorg fork of subsampling-scale-image-view
(cherry picked from commit 0c65d54d89)
2020-07-19 18:44:22 -04:00
arkon 70a779e4d0 Manga about section layout tweaks
(cherry picked from commit ccd0e0cdfe)

# Conflicts:
#	app/src/main/res/layout/manga_info_header.xml
2020-07-19 18:44:16 -04:00
arkon fd40f35371 Move chapter filter/sort/display settings into a sheet
(cherry picked from commit 9278ca3f5e)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt
#	app/src/main/res/menu/chapters.xml
2020-07-19 18:39:59 -04:00
arkon f66aff9ed7 Toggle about section when tapping on header/empty space
(cherry picked from commit d7a70b962b)
2020-07-19 18:33:23 -04:00
arkon 29ad0e091f Long press favorite button to manage categories
(cherry picked from commit fff0f841fa)
2020-07-19 18:33:13 -04:00
arkon fa580aa3c9 Fix checked state for manga header buttons
(cherry picked from commit 8ba426350f)
2020-07-19 18:32:57 -04:00
arkon bd8bc3a3cb Remove redundant Reading Mode header
(cherry picked from commit 5452e29840)
2020-07-19 18:32:39 -04:00
arkon 52f2644035 Tweak track search dialog list item paddings
(cherry picked from commit 148f8e6d11)
2020-07-19 18:32:26 -04:00
arkon 7a97d6f20d Update Android Gradle plugin for Android Studio 4.0.1
(cherry picked from commit 13a5662a84)
2020-07-19 18:25:21 -04:00
arkon 8de67c49bc Include source ID if name not found in restore error log (closes #3018)
(cherry picked from commit 6713a7ae3c)
2020-07-19 18:25:11 -04:00
arkon 7530a7bd4e Move edit categories to overflow
(cherry picked from commit 88ee86b7ef)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt
#	app/src/main/res/menu/chapters.xml
2020-07-19 18:24:55 -04:00
arkon 1ac7043163 Allow category names with different casing (fixes #3465)
(cherry picked from commit 4bc2288806)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/data/database/models/Category.kt
2020-07-19 18:20:05 -04:00
Jobobby04 8e24797e50 More translation fixes for pt-rBR by SamOak! 2020-07-19 18:15:41 -04:00
Jobobby04 4513af8425 Make the resume/start button go to the latest version for EH manga 2020-07-19 18:15:38 -04:00
Jobobby04 78d1a6cecb Cleanup library a bit 2020-07-19 14:23:35 -04:00
Jobobby04 a9e9fe59c6 Updates to the pt-rBR translation from SamOak! 2020-07-17 14:03:03 -04:00
Jobobby04 a8f2f03562 Tsumino is now supported by the new tag display, you may have to refresh your Tsumino manga for them to work properly. Also Set the groundwork for more special features 2020-07-16 22:37:33 -04:00
Jobobby04 9e986bbeb6 Add pt-rBR translation, thanks to SamOak! 2020-07-16 17:29:05 -04:00
Jobobby04 b904bf99e8 Cleanup 2020-07-16 17:27:47 -04:00
Jobobby04 8b95d93a96 Add custom tag view for namespaced sources (E-Hentai, nHentai, Hitomi.la, and Pururin) 2020-07-16 17:27:36 -04:00
Jobobby04 74012e0830 Revert tweaked browse tab view 2020-07-15 19:16:51 -04:00
Jobobby04 362f0a6671 Made almost all the strings SY uses translatable! If people would like to help translate, feel free to join the Tachiyomi discord server (https://discord.gg/tachiyomi), and jump in the tachiyomi-az-sy channel and I can give you a rundown on how to do it 2020-07-15 19:16:21 -04:00
Jobobby04 0ca87a3763 Use androidx preferenceManager for EHLogLevel 2020-07-14 01:50:17 -04:00
Jobobby04 840ab68922 Global search and latest card fixes 2020-07-14 01:49:23 -04:00
Jobobby04 4663d64c05 Cleanup some errors 2020-07-14 01:01:55 -04:00
Jobobby04 4b7c33be16 Remove unused build.gradle option 2020-07-14 00:04:13 -04:00
Jobobby04 8c40e4d635 Try to fix my firebase issues with dev builds 2020-07-13 13:48:53 -04:00
arkon eaae98d072 Enable more WebView settings to better mimic regular browser
(cherry picked from commit a928d9fa0b)
2020-07-13 13:38:50 -04:00
arkon 5ffc21fc9e Don't capitalize buttons (closes #3454)
(cherry picked from commit d8f4e6b45f)
2020-07-13 13:38:40 -04:00
Jobobby04 294caa25a4 Manga cover editing fixes 2020-07-13 13:25:05 -04:00
Jobobby04 923f5213cd Add author and artist wrapping if a EH based source 2020-07-12 23:27:35 -04:00
Jobobby04 8434b880c6 Fix date added not showing up 2020-07-12 22:50:08 -04:00
Jobobby04 badd43046b Reimplement Eh tag searching into the new manga page 2020-07-12 22:50:05 -04:00
arkon 00d5fd8fe4 Replace some usages of findViewById
(cherry picked from commit 5ef5087406)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt
2020-07-12 19:37:18 -04:00
arkon 3bd6b8524f Fix manga info actions being cut off
(cherry picked from commit 135c371d88)

# Conflicts:
#	app/src/main/res/layout/manga_info_header.xml
2020-07-12 19:34:00 -04:00
Jobobby04 362ba1bf69 Cleanup unused library migration code 2020-07-12 19:32:08 -04:00
arkon 450b76f495 Remove unused CoverCache param from LibraryController
(cherry picked from commit 966c196f4a)
2020-07-12 19:30:01 -04:00
arkon 1188ee10d8 Use view binding for sheets
(cherry picked from commit dc43e41896)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/SourceFilterSheet.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderSettingsSheet.kt
2020-07-12 19:29:50 -04:00
Jobobby04 372e570fac Use Tachi previews info + chapters manga page, plus of course SY features integrated into it
Add missed invert tap settings
Add missed extension open in settings overflow menu option
Cleanup
2020-07-12 19:21:29 -04:00
arkon 8ab2a823b5 Speed up controller fade and tab expansion animations
(cherry picked from commit 4809d06d04)
2020-07-12 16:39:58 -04:00
arkon 7fb197a752 Move edit cover to manga info
(cherry picked from commit 9f7fda0bc5)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersPresenter.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoHeaderAdapter.kt
#	app/src/main/res/menu/chapters.xml
2020-07-12 16:39:52 -04:00
arkon 7046d304e0 Hide toolbars when reader color filter sheet is opened
(cherry picked from commit 66ef1a8206)
2020-07-12 16:34:44 -04:00
arkon dfa4eda33b Remove redundant layout for reader color filter sheet
(cherry picked from commit beaffc3870)
2020-07-12 16:34:36 -04:00
arkon a229d015ad Remove color filter preview image
(cherry picked from commit 8536ecb611)
2020-07-12 16:34:26 -04:00
arkon eacdf4e161 Remove 32-bit color setting from reader sheet
(cherry picked from commit d7a89b0f8c)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderSettingsSheet.kt
#	app/src/main/res/layout/reader_settings_sheet.xml
2020-07-12 16:34:13 -04:00
arkon 9569f13190 Reorder animation speed options
(cherry picked from commit 943081e80d)
2020-07-12 16:32:14 -04:00
arkon 02ba0eca32 Update some icons
(cherry picked from commit 3f007a1edd)
2020-07-12 16:32:05 -04:00
arkon e3d2e5b89d Add option to reverse tapping (#3360)
* Add option to reverse tapping

* Fix string for preference key

* Invert tapping for Webtoon and Vertical

* Use enum instead of boolean

* Add option to reader sheet

* Hide from reader sheet if tapping disabled and remove hard coded string

* Hide option if tapping disabled

(cherry picked from commit 04d83e9a6a)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ViewerConfig.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerViewer.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsReaderController.kt
#	app/src/main/res/layout/reader_settings_sheet.xml
2020-07-12 16:31:40 -04:00
arkon a9317dff88 Group theme settings into category
(cherry picked from commit fa5d2276c0)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsGeneralController.kt
2020-07-12 16:23:14 -04:00
arkon c2c2a3be01 Split general reader settings into reading mode and display
(cherry picked from commit d353a3457d)
2020-07-12 16:21:42 -04:00
arkon 57565fce2d Make page transitions setting apply to webtoon viewer as well
(cherry picked from commit b363b9fc1a)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderSettingsSheet.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ViewerConfig.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt
#	app/src/main/res/layout/reader_settings_sheet.xml
2020-07-12 16:21:21 -04:00
arkon 439b78c39f Unify crop borders settings
(cherry picked from commit 1920568057)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderSettingsSheet.kt
#	app/src/main/res/layout/reader_settings_sheet.xml
2020-07-12 16:16:58 -04:00
arkon fbb14a35a9 Add shortcut to global search query from library (closes #2183)
(cherry picked from commit 763da19c9d)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt
2020-07-12 16:11:23 -04:00
arkon c0a4f4e93a Add ability to sort library by date added (closes #1287)
(cherry picked from commit 1813dbbf59)

# Conflicts:
#	app/build.gradle
#	app/src/main/java/eu/kanade/tachiyomi/data/database/DbOpenCallback.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/SearchPresenter.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourcePresenter.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsSheet.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySort.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersPresenter.kt
2020-07-12 16:08:15 -04:00
arkon c543622268 Hide invert volume keys setting when volume keys isn't enabled
(cherry picked from commit 339169b624)
2020-07-12 15:41:50 -04:00
arkon 43034db5e5 Prevent downloads when less than 50MB of disk space is available (closes #1018)
(cherry picked from commit 93960315d9)
2020-07-12 15:41:34 -04:00
arkon 27ad39b6ce Attach some FABs and snackbars to root CoordinatorLayout
Fixes some issues around snackbars sometimes being out of view.

(cherry picked from commit 479eb1ba71)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceController.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt
2020-07-12 15:41:11 -04:00
arkon 04749a8fce Don't capitalize category names
(cherry picked from commit 962d8e5fd2)
2020-07-12 15:19:39 -04:00
arkon 15b23e35cd Update dependencies, remove play-services-oss-licenses
(cherry picked from commit 40639c0933)

# Conflicts:
#	app/build.gradle
2020-07-12 15:19:27 -04:00
Rani Sargees a839372d9f fix batch add log
(cherry picked from commit 629bca4100243d61cf07bbb0f47f6a1ed84031cb)
2020-07-12 15:16:52 -04:00
Jobobby04 e1fd0d1a4a Fix crash on random manga due to tracking 2020-07-11 21:03:23 -04:00
Jobobby04 6469121f41 Rewrite and enable manga cover editing, Manga info edit is finished! 2020-07-11 20:55:06 -04:00
Jobobby04 b8129ff4f6 Rewrite and enable genre tag editing 2020-07-11 18:34:16 -04:00
Jobobby04 201356afeb Reload the info once editing is done 2020-07-11 15:31:15 -04:00
Jobobby04 2e033356aa Manga info edit will now not break everything 2020-07-11 15:22:11 -04:00
Jobobby04 044c638079 Very basic manga info edit, currently will break everything if used, tags and cover edit not working 2020-07-11 14:53:59 -04:00
Jobobby04 bbf1c4ffd9 Update realms to 6.1.0, hopefully fix the startup crash with it 2020-07-11 13:37:55 -04:00
849 changed files with 40632 additions and 21339 deletions
+2 -2
View File
@@ -14,9 +14,9 @@
* Catalogue requests should be created at https://github.com/inorichi/tachiyomi-extensions#readme, not here * Catalogue requests should be created at https://github.com/inorichi/tachiyomi-extensions#readme, not here
# Bugs # Bugs
* Include version (Setting > About > Version) * Include version (More > About > Version)
* If not latest, try updating, it may have already been solved * If not latest, try updating, it may have already been solved
* Dev version is equal to the number of commits as seen in the main page * Preview version is equal to the number of commits as seen in the main page
* Include steps to reproduce (if not obvious from description) * Include steps to reproduce (if not obvious from description)
* Include screenshot (if needed) * Include screenshot (if needed)
* If it could be device-dependent, try reproducing on another device (if possible) * If it could be device-dependent, try reproducing on another device (if possible)
+2 -2
View File
@@ -2,7 +2,7 @@
I acknowledge that: I acknowledge that:
- I have updated to the latest version of the app (stable is v0.9.2) - I have updated to the latest version of the app (stable is v1.4.0)
- I have updated all extensions - I have updated all extensions
- If this is an issue with an extension, that I should be opening an issue in https://github.com/inorichi/tachiyomi-extensions - If this is an issue with an extension, that I should be opening an issue in https://github.com/inorichi/tachiyomi-extensions
@@ -10,7 +10,7 @@ I acknowledge that:
--- ---
### Device information ## Device information
* Tachiyomi version: ? * Tachiyomi version: ?
* Android version: ? * Android version: ?
* Device: ? * Device: ?
+3 -3
View File
@@ -9,7 +9,7 @@ labels: "bug"
I acknowledge that: I acknowledge that:
- I have updated to the latest version of the app (stable is v0.9.2) - I have updated to the latest version of the app (stable is v1.4.0)
- I have updated all extensions - I have updated all extensions
- If this is an issue with an extension, that I should be opening an issue in https://github.com/inorichi/tachiyomi-extensions - If this is an issue with an extension, that I should be opening an issue in https://github.com/inorichi/tachiyomi-extensions
@@ -17,7 +17,7 @@ I acknowledge that:
--- ---
### Device information ## Device information
* Tachiyomi version: ? * Tachiyomi version: ?
* Android version: ? * Android version: ?
* Device: ? * Device: ?
@@ -32,5 +32,5 @@ This should happen.
### Actual behavior ### Actual behavior
This happened instead. This happened instead.
### Other details ## Other details
Additional details and attachments. Additional details and attachments.
+8
View File
@@ -0,0 +1,8 @@
blank_issues_enabled: false
contact_links:
- name: Tachiyomi help website
url: https://tachiyomi.org/help/
about: Common questions are answered here.
- name: Tachiyomi extensions GitHub repository
url: https://github.com/inorichi/tachiyomi-extensions
about: Issues about an extension/source/catalogue should be opened here instead.
+3 -3
View File
@@ -9,7 +9,7 @@ labels: "feature"
I acknowledge that: I acknowledge that:
- I have updated to the latest version of the app (stable is v0.9.2) - I have updated to the latest version of the app (stable is v1.4.0)
- I have updated all extensions - I have updated all extensions
- If this is an issue with an extension, that I should be opening an issue in https://github.com/inorichi/tachiyomi-extensions - If this is an issue with an extension, that I should be opening an issue in https://github.com/inorichi/tachiyomi-extensions
@@ -17,8 +17,8 @@ I acknowledge that:
--- ---
### Why/User Benefit/User Problem ## Why/User Benefit/User Problem
(explain why this feature should be added) (explain why this feature should be added)
### What/Requirements ## What/Requirements
(explain how this feature would behave) (explain how this feature would behave)
+1 -1
View File
@@ -2,7 +2,7 @@
name: "Extension/source/catalogue issue" name: "Extension/source/catalogue issue"
about: "Do not open an issue here. See https://github.com/inorichi/tachiyomi-extensions" about: "Do not open an issue here. See https://github.com/inorichi/tachiyomi-extensions"
title: "THIS ISSUE IS IN THE WRONG REPO; SEE https://github.com/inorichi/tachiyomi-extensions" title: "THIS ISSUE IS IN THE WRONG REPO; SEE https://github.com/inorichi/tachiyomi-extensions"
labels: "catalog" labels: "catalog, invalid"
--- ---
DO NOT OPEN AN ISSUE IN THIS REPO. SEE https://github.com/inorichi/tachiyomi-extensions DO NOT OPEN AN ISSUE IN THIS REPO. SEE https://github.com/inorichi/tachiyomi-extensions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 453 KiB

After

Width:  |  Height:  |  Size: 1.7 MiB

+34
View File
@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 21.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 1000 1000" style="enable-background:new 0 0 1000 1000;" xml:space="preserve">
<style type="text/css">
.st0{fill:#232B30;}
.st1{fill:#2E84BF;}
.st2{fill:#CE2828;}
</style>
<g id="Calque_2">
<path class="st0" d="M304.4,891.3h391.2c107,0,194.5-87.5,194.5-194.5V305.6c0-107-87.5-194.5-194.5-194.5H304.4
c-107,0-194.5,87.5-194.5,194.5v391.2C109.9,803.8,197.5,891.3,304.4,891.3z"/>
</g>
<g id="Calque_1">
<path class="st1" d="M474.4,242.2c115.3-1.4,144.2,48.2,185.2,74.7c21.6,8.3,17.7,16.3,26.2,28.7c2.5,3.5,5.5,5,9.5,7.5
c30.3,18.2-10.8,39.6-28.2,40.3c7.1-4.6,13.2-5.9,17.7-12.4c-0.3,0-0.6,0-0.9,0c0-0.3,0-0.6,0-0.9c-14.6-4-13.3,8.8-29.2,6.2
c3.5-0.4,12.6-5.8,12.4-13.3c-11.9-7.2-31.6-15.2-46.9-14.2c-0.1,0.4-0.1,0.4-0.2,0.8c36.3,24.2,25.7,57.3,47.1,63.8
c-11.6-0.5-5.9,2.1,0,7.1c-14.6-3-16.1-19.2-23-33.6c-7.8-12.9-15.4-28.5-23.9-29.2c-2,9.2,2,56.4,14.7,46.6
c-10,12.3,4.4,7.2,11,4.7c-23.9,19-35.1,13.8-42.8-13.8c-6.2-13.4-14.6-34.2-19.5-46.6c-2.8-7.1-7.5-13.3-13.6-17.9
c-41.8-31.2-72.8-33.3-116.9-26.1c-11.1-21.4-27.5-40.4-38.9-61.9C435,247.7,452,242.4,474.4,242.2z"/>
<path class="st1" d="M313.4,336C395.3,494.3,482,442.7,607.1,502.8c109.3,67.9,83.8,212.8-30.1,257.7c0-28.3,0-56.6,0-84.9
c46.4-45.1,20.7-112.1-37.1-125c-68.8-15-145.6-29.5-191.7-62.5C298,450.3,286.6,386.8,313.4,336z"/>
<path class="st1" d="M424.8,690.6c0.1,25.4,1.9,53.9-0.9,77.8c-94.2-25.7-162.5-103.3-124.7-192.8c0,4.7,0,9.4,0,14.2
C307.8,650,359.3,682.6,424.8,690.6z"/>
</g>
<g id="Calque_3">
<path class="st2" d="M247,198l138.9,37.1L500,414.7l47.8-72.5c34.5,14.5,37,85.5,55.7,96.4l-23,34.5
C477,444.9,387.8,439.9,351.3,364.7C317.9,311.3,247.1,198.1,247,198z"/>
<path class="st2" d="M602.6,255.5c16.2,9.6,33.1,19.8,46.5,32.8c7.5,7.2,14.9,12.3,25.3,18.3c3.9,2.2,4.7,2.1,7.8,4.7L753,198
l-137.1,37.1L602.6,255.5z"/>
<path class="st2" d="M500.9,841l61.9-50.4l0.9-212.3c0,0-4.5-11.4-85.2-25.5c-17.1-3-29.7-7.2-29.8-7.2l-12.3-3.6l1.8,248.5
L500.9,841z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

@@ -0,0 +1,6 @@
org.gradle.daemon=false
org.gradle.jvmargs=-Xmx5120m
org.gradle.workers.max=2
kotlin.incremental=false
kotlin.compiler.execution.strategy=in-process
-25
View File
@@ -1,25 +0,0 @@
name: Pull Request Checker
on:
pull_request:
jobs:
apk:
name: Generate APK
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v2
- name: set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8
- name: Get NDK
run: sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;21.0.6113669"
- name: Build Release APK
run: bash ./gradlew assembleDebug --stacktrace
- name: Upload APK
uses: actions/upload-artifact@v2
with:
name: TachiyomiSY-${{ github.sha }}.apk
path: app/build/outputs/apk/dev/debug/app-dev-debug.apk
@@ -2,38 +2,42 @@ name: Remote Dispatch Action Initiator
on: on:
push: push:
repository_dispatch: branches:
- 'master'
jobs: jobs:
ping-pong: check_wrapper:
name: Validate Gradle Wrapper
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@master - name: Clone repo
with: uses: actions/checkout@v2
fetch-depth: '0'
- name: Set CISKIP flag to false - name: Validate Gradle Wrapper
run: echo ::set-env name=CISKIP::'false' uses: gradle/wrapper-validation-action@v1
- name: Set CISKIP flag if action has ci skip
if: contains(github.event.action, 'skip-ci') || contains(github.event.action, 'skip-ci') || contains(github.event.action, 'skip ci') || contains(github.event.action, 'ci skip') || contains(github.event.action, 'ci-skip') preview:
run: echo ::set-env name=CISKIP::'true' name: Build app preview
- name: Exho needs: check_wrapper
run: echo env.CISKIP if: "!startsWith(github.event.head_commit.message, '[SKIP CI]')"
runs-on: ubuntu-latest
steps:
- name: Clone repo
uses: actions/checkout@v2
- name: TAG - Bump version and push tag - name: TAG - Bump version and push tag
uses: anothrNick/github-tag-action@1.17.2 uses: anothrNick/github-tag-action@1.17.2
if: github.event.action != 'pong' && env.CISKIP == 'false'
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
WITH_V: true WITH_V: true
RELEASE_BRANCHES: master RELEASE_BRANCHES: master
DEFAULT_BUMP: patch DEFAULT_BUMP: patch
- name: PING - Dispatch initiating repository event - name: PING - Dispatch initiating repository event
if: github.event.action != 'pong' && env.CISKIP == 'false'
run: | run: |
curl -X POST https://api.github.com/repos/jobobby04/TachiyomiSYPreview/dispatches \ curl -X POST https://api.github.com/repos/jobobby04/TachiyomiSYPreview/dispatches \
-H 'Accept: application/vnd.github.everest-preview+json' \ -H 'Accept: application/vnd.github.everest-preview+json' \
-u ${{ secrets.ACCESS_TOKEN }} \ -u ${{ secrets.ACCESS_TOKEN }} \
--data '{"event_type": "ping", "client_payload": { "repository": "'"$GITHUB_REPOSITORY"'" }}' --data '{"event_type": "ping", "client_payload": { "repository": "'"$GITHUB_REPOSITORY"'" }}'
- name: ACK - Acknowledge pong from remote repository
if: github.event.action == 'pong'
run: |
echo "PONG received from '${{ github.event.client_payload.repository }}'"
@@ -0,0 +1,96 @@
name: Release Builder
on:
push:
branches:
- 'release'
jobs:
check_wrapper:
name: Validate Gradle Wrapper
runs-on: ubuntu-latest
steps:
- name: Clone repo
uses: actions/checkout@v2
- name: Validate Gradle Wrapper
uses: gradle/wrapper-validation-action@v1
build:
name: Build app release
needs: check_wrapper
if: "!startsWith(github.event.head_commit.message, '[SKIP CI]')"
runs-on: ubuntu-latest
steps:
- name: Cancel previous runs
uses: styfle/cancel-workflow-action@0.5.0
with:
access_token: ${{ github.token }}
- name: Clone repo
uses: actions/checkout@v2
- name: Set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8
- name: Copy CI gradle.properties
run: |
mkdir -p ~/.gradle
cp .github/runner-files/ci-gradle.properties ~/.gradle/gradle.properties
- name: Write google-services.json
uses: DamianReeves/write-file-action@v1.0
with:
# The path to the file to write
path: app/google-services.json
# The contents of the file
contents: ${{ secrets.GOOGLE_SERVICES_TEXT }}
# The mode of writing to use: `overwrite`, `append`, or `preserve`.
write-mode: overwrite # optional, default is preserve
- name: Build app
uses: eskatos/gradle-command-action@v1
with:
arguments: assembleRelease --stacktrace
wrapper-cache-enabled: true
dependencies-cache-enabled: true
configuration-cache-enabled: true
- name: Sign Android Release
uses: r0adkll/sign-android-release@v1
with:
# The directory to find your release to sign
releaseDirectory: app/build/outputs/apk/standard/release
# The key used to sign your release in base64 encoded format
signingKeyBase64: ${{ secrets.SIGNING_KEY }}
# The key alias
alias: ${{ secrets.ALIAS }}
# The password to the keystore
keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }}
# The password for the key
keyPassword: ${{ secrets.KEY_PASSWORD }}
- name: Create Release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.run_number }}
release_name: TachiyomiSY
draft: true
prerelease: false
- name: Upload Release APK
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ${{ env.SIGNED_RELEASE_FILE }}
asset_name: TachiyomiSY.apk
asset_content_type: application/vnd.android.package-archive
+52
View File
@@ -0,0 +1,52 @@
name: CI
on: [pull_request]
jobs:
check_wrapper:
name: Validate Gradle Wrapper
runs-on: ubuntu-latest
steps:
- name: Clone repo
uses: actions/checkout@v2
- name: Validate Gradle Wrapper
uses: gradle/wrapper-validation-action@v1
build:
name: Build app
needs: check_wrapper
if: "!startsWith(github.event.head_commit.message, '[SKIP CI]')"
runs-on: ubuntu-latest
steps:
- name: Cancel previous runs
uses: styfle/cancel-workflow-action@0.5.0
with:
access_token: ${{ github.token }}
- name: Clone repo
uses: actions/checkout@v2
- name: Set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8
- name: Copy CI gradle.properties
run: |
mkdir -p ~/.gradle
cp .github/runner-files/ci-gradle.properties ~/.gradle/gradle.properties
- name: Build app
uses: eskatos/gradle-command-action@v1
with:
arguments: assembleStandardDebug
wrapper-cache-enabled: true
dependencies-cache-enabled: true
configuration-cache-enabled: true
- name: Upload APK
uses: actions/upload-artifact@v2
with:
name: TachiyomiSY-${{ github.sha }}.apk
path: app/build/outputs/apk/dev/debug/app-dev-debug.apk
+4 -1
View File
@@ -1,5 +1,8 @@
name: Issue closer name: Issue closer
on: [issues] on:
issues:
types: [opened, edited, reopened]
jobs: jobs:
autoclose: autoclose:
runs-on: ubuntu-latest runs-on: ubuntu-latest
-81
View File
@@ -1,81 +0,0 @@
dist: trusty
language: android
android:
components:
- tools
- platform-tools
- build-tools-29.0.3
- android-29
- extra-android-m2repository
- extra-google-m2repository
- extra-android-support
- extra-google-google_play_services
licenses:
- 'android-sdk-license-.+'
- 'android-sdk-preview-license-.+'
before_install:
- yes | sdkmanager "platforms;android-29" # workaround for accepting the license
- if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then
openssl aes-256-cbc -K $encrypted_e56be693d4fd_key -iv $encrypted_e56be693d4fd_iv -in "$PWD/.travis/secrets.tar.enc" -out secrets.tar -d;
tar xf secrets.tar;
mv debug.keystore "$HOME/.android";
fi
- mkdir "$ANDROID_HOME/licenses" || true
- echo -e "\n24333f8a63b6825ea9c5514f83c2829b004d1fee" > "$ANDROID_HOME/licenses/android-sdk-license"
- echo -e "\n84831b9409646a918e30573bab4c9c91346d8abd" > "$ANDROID_HOME/licenses/android-sdk-preview-license"
install:
- echo y | sdkmanager "ndk-bundle"
before_script:
- export ANDROID_NDK_HOME=$ANDROID_HOME/ndk-bundle
script: ".travis/build.sh"
before_cache:
- rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
- rm -fr $HOME/.gradle/caches/*/plugin-resolution/
cache:
directories:
- "$HOME/.gradle/caches/"
- "$HOME/.gradle/wrapper/"
- "$HOME/.android/build-cache"
deploy:
- provider: releases
api_key:
secure: qmS9SyMq8xPDqaY83rvAFyZcvic24lGBj3MFt22RhVJzIXAAN/vqL1R70PnNiCF7CE+R7PaDlBpwjxDMBiuh0QQNc1oX6cgepUbro4/Nt7NFFfCvKXaFdR1cSgYouhuHmy0SS0/alrcfhQ2bPwcm1/vAOiSa8Wu7hsXhCcxbFyEbXZVD11QZmiffEM0py+OeuqOFo2JxZaGRu2z04E/u5TWep1ZEuhFRCC87PGgFqABgg6jYYebQOUZADG/0G8581HTGU0mdwueYsiA35ncRzpV2V8DajEEBd5wOe5d8SyMtE+6Qs5PD9KcXAqGGe4QRmrJMX5EcLQaLZf/Qd5s9SFZVHb1aJIw/y05w4L5dlVpsjx5WuUAYAVg7Ol5UawofFo/hYkYCNmfub67wJQdHSIxPif7V6YeON6RQQMpc5GBYY9eA6ZxhrdA2m7eyoOT3jcbdaVJwC0jMGhn26hkgJfTo1LfAUs85Cs3BrK8w6Poqc/Jb+4Y0NhdGIKgO5tS3vY54cTJVVrQTq4/XmME4ZnzOX3HaOqzfyt/6M4gEQMvaeFksxwoFhocV7wfaCq9ps/Kdq2dl4KwoqRV2WqVaauqzCP4XPSlVLaJqztsw0wboupcaZepWJ2a/6j9IrKo1pEnyeHF5y+k0SUAxL0X8iKZ0uPxsgoVrlNtqXJWNGvA=
file: tachiyomi-v*.apk
file_glob: true
skip_cleanup: true
on:
tags: true
repo: inorichi/tachiyomi
- provider: script
script: ".travis/deploy.sh"
skip_cleanup: true
on:
branch: master
condition: "-z $TRAVIS_TAG"
repo: inorichi/tachiyomi
- provider: script
script: ".travis/deploy.sh"
skip_cleanup: true
on:
branch: dev
condition: "-z $TRAVIS_TAG"
repo: inorichi/tachiyomi
env:
global:
- secure: Ita1+tzo7P5IC2yqU3KgRcXt+5DTpP0103Hx/ECYi42/7rLt+TC7PMjl2yH3Z189+tGwLq0Ol1KJ2Z5Rn3q7EaQgD0+WRkH/ijtrjKoVh7dyItIBp7yowZpA0TJHQ4EZpGSxZakKbIP4di8XMxJ2+5VzEivYUt04LCUpzugemL6b6XOfUmOZykVxV2UDAlPPggklITYBXkHUa0mwJhjS1aPPeeR3PhVXomkqfuOJOKejPXXXJope9fhAnmopHA7ISfjIrTuwDVQJqNSuco+O9kQShmlu0C8pob1vFGPEDvafaDS8SZ9A6gKT1ZfgSUqVmvDbx0WLX8XugBLrQedtZv63esOa1WUyGhgFVpeJjexlszXlhyfP1gH5QbzRr+EiSaagCyjf9II2veLAtU5cFY+nj6KBdKQsazIMRHf8SAQlWASyJYMED/N9RnUFxSf1rnLGqiY2ezjycx4ieFj7vhlbTgyao1GHjjR9cwNuntdMYWhY8+Vc7Fctmzm46xOyyz9oJGdyim76Y4w4MZvQNKeZOBAjdEgX6cXBk15scoM2Vj9ENox+MKZLaKRawXg2U1ujK+bWAQkXiVvPriv05/JtYsNUft8qAsm+69vtohDsUW7Wu0bBIKDL+v0W30ty1PpyNehBB2OquUE7fp53gitOmYl7TyuxktkMY8PXKKU=
- secure: NABCfigMUVM/9TLALYBpQLp/p3rG6MbH5y34/oqCSej/oh2u0nyhFSi8veS0lFpDIcv0TZvxHJXoSA0zeZijb1fUU8jYVNT2azuPWE6Gu7sf0TfBeCvulqbgLMoaA6JuWbEbZwHcxpKHg4vLSMjNk+ZP4v2dffI6A620fxLltxxhTpsYkYYsfKG857CpQtdgN/HqcOaxyvzXFmWWyVWHala1uMcMeXZCwgnlVAqau9o0bsU092txSmHqoesHoAinidSCTCmTlEqp/1AFaYQTbxmnfNC1yLgzxWAlJcS3NWzNo3ellMvKjsiIGn3JJpAjTGcyf3yPsvhs1cY3MZbmJYVyKH5HbnkA5ms6mx0DDJ2UOs5H2dmED82m14+hu62Xb8XN8zAdq+bySNSwgsGzvr1PT74pT4BW1T+D7L1xvUe6k1enZ38GIMJbJPhBybRQazhjKPmXRB30Thxoqe5VqU8UeiXHAEps7JYAWUR1PLZvEYQb6MWurmTxs9be/OTwrUT1LDiqeJZg6XkDGgQwuR2YBaQJHJD17Piq6q1BUX8abhK6wzAAYVqyGvpmUCmQCtHZgenE6ulwcKChzBv4n97OjE21LGWnbNF5ViUhfAbGcKOVufd1chZsfbkJ7a3tHYCfLnxHUIhKvHk26f5Em8h68D0wQkPnkcVVkfh7XpI=
- secure: C93UADV5aR0zhLCLwR6tCyz+fwUYslZbhjBl3PHQp+0boIGS/Be2UQTFHp/NB9mQmhWqbwqHoAVFENZFytV04ePgOuNtMFcjAIfnzm19Am7iRAMFixD45pF/CuYYfLupElkAcSequtAzN0g4G0sQ5KR1hibaDIoz9kfA2YcUAMaZ4T5bhCr8os/xA2nOlmvPDWsRWCFBYkSpnmbsSsgYAhulA/V5bSNAWnp9LPw3CBLibW3WsVP4wuhZAkXznKwn/mHT31kfQlpMH3qNhXpsN9huUkZ/k8QWeakcHJKugung0Z2T1StK8rlI8OrJstVcwueHTa2ses4f5VbhWog/Z8HDkdll9W9RM/QqXjNDtOVBt/SPuhCp4k2rvJixFUxzvSqgSWQvQnbHwjWxIUVVyHtnb0/zc/S9ONZG14TOwB/+Lkgacb85PNszurZ2f3mH0O6slIh1mH+5d9J4+L976ot4nTPlK1OtothagVyKGOrn9HycrPk/MjftIJuElHzo7NEJd/wRPqIb5y12iZN1RSPriU+itg1uSAVP891/o3peJyuqY9WSB7dYwgDJos6dDvbr19emtdyxkQR+eAb5duyH6s4R58wh1kJ1d4zu0X6uSnF4AIc+6teKkN24rSXcqB/hrcojS49jgLy5P0/CVsUbYZPI/tx8E/IJfr8m36E=
- secure: mawwBvllvESc/mp+JHvncq1iUhiC7nyokPgXmOehffc0K3byMLs2L25HjNsU6EnXG9Lcae1cfP8S9bWLquU2C3kpAkLBUpjEbdx7K0654uvs7Rrvb5hcTRHwjzaEVmVaBFX4ROcjUhBYny/Wjj/YENCkSWpkfcMd1esFbVsO+fOLyaAPvrb6auKY7H+pUSqlEwaEnrkYeBBZIHa7KqwL4g5DHbq6K368tjmval/wBzwMB0V8V3dt/ik8RMVDtKPrik4Bu0V9UmXZUIo/a06ii/CM82ekFRh3eUb0DKkdkmYbdH6MBMoLTfQtMa6A4luXaA0oycAnTX3OGB5MWIjK39KhWRavh6ybSIt4aHKoolxzH8Zgmk7xMhFSot/laX5q5IzjZu5KU6F2SmdV0kcQugM8oAjANFySetPvY1q7nZ8pM+NO1xKS/mH0w4vChhdJFD1mw7aCoh8FdeUf0Eym2+pp5Q9uAisWMmNn5XN8/fL5q6PzAxkXmkedfrr1N61FmIL6EKx8qiWpOUNlRRTIMJ4GMhCyckCF6cNxDkBItp52c+Hmkbn+ZEInEyX6gpjYVm3xyEi0Z5kLCi/fMX2nBNczc5BuGLzzmJnITv4ovpeYn2/vPvHbaPgPC4LqDK3AjlpVadMZk/M5Egn+hWY7Mni57CmpZD+SpxUbbsItI0c=
- secure: PJPDkUg1zc57brxUvNpSh+Q3ZEaGpBqZzwDavqslkn0WmjBTLrE6/OG7TFHKNmO+P56qFl+pMEKqThxqR3+4bWEeEx8ykkixDVzxNJMmws+7A7ImJ75iQyB6giMW/4tykVMMHgIPNAdcnI8VOWn0LGHnpFWUd70yoyAGX8s6cspHCKgcuWMA3GS410KJfHpyd0B9/QS7ZyWzSETW7zSPyLPa81SBO95EhOF3TOGZYLt/mBhdtU3YGFs4k9fZ8jDDcm9XmBfqVlUhb8HiZcxJiZDdRvxODERfNnwc47uaJk6+kxGDzIW2uAxrMXXVKkG04GeMOokXoR9kW1Hl2JmoyySLKLZmB7I/XEtVWdzZw16mWi+4zmhjLhfB0phSW+/5I+0VtZZ6jO031J5FL/JqVrcq1ws/aw4QlaOdPUco/x2u4LNHyYYgOi5arD9xSyu6IRy0jCC4Xa1zuqM5adGJX+rZyVfKZ0TxOW661HTxlo8COtkB2i0WR2deZGVN75ooCAEO8DauQoUcFH1OelahmPtzVs1/6ZczuxGdp9ED7ZQq9NHEOsOdUGCj/D79Dm1hWFQsIsslnnGYWitAycNCgEwmlt2Q6fbrv2CJrmLqZ9a9r3AhzxoHn9Qx1GyuyfhZJzm/6Ff2kcOjma2kcz13KUwTxdW+2G5dDCotK3f7aiI=
- secure: FIIZfEEYfjNMKODs33Czh603CYVn6LRrzpFNIiPHYTb8iQWv9qAYhsg4FpHfOjDikokTwb5X/h8G7AX93Z0xKyyDi75ACT11oPeTNTArDdcmdDVlOYBvYHc2Ci7pMW5r8LGejB7Y3mWM8uKyA3oKvneEFutB65vO3JVZvFWrm03Lmqqe7+mA4qNqNqTbN7R7fmk5b7zt7A3DHvDu0JPTbSSUwpso/p2I5WJYjrf71I7YMQwIFLoMfplC1onVA3EFS3lZsF65zE+xVRy34AKa41iZAMbhVDyqUHEnx6L0dwEdn2Z5XLlK0ov1+qLTLlQsBE4Knre6TNkWMfktk7MKA+ch8RYxvEYLODhQkIrOkLSNWhZPhdaT+xD4fr0RCKSHo6uWRC4aofsJx8wSqb8ZL4j2zopUp9VisMOI202UEnvFDBtOkVGJSxxYbFjifIB7NCJBn788w+3k+k4IbOg537VdyoK2PMBR8/TDdjImWhWHY1i7+345ejwmzHL7ZPfb6GTNnQTWkajT77/n6Yk41twR5vvegOSTKuuO++WN/pUks4PGqtcQe9fnSfx2OcOq1ofLiG+JDorJ7z8kHSG13wHLq+QYMDayQbyJEYpDzmn/w3Ou1s2o0a7A41+cIkRzAgH9y3v4lgjp9GcMP2S74ZPA7OecWbFSexM7tL/dYxY=
- secure: DKCGc4E9PKeTX68r9pbbNg5qITsN0bApQ1m0x8xdEoi8GLRKVMYNn6ahoAxvy1YsBXC9Zlt5++gLmUV1I1JyDMyJXMr/lZrp4oarW0xWpTBmn3HzOph/K2W4i/fTGgMFieumPEbQIFOnU3JSjK6UJB8qVGEXD2OqS7A//EdrGDbAYVDL3ZTKE6JUlTNHgaKaNHhn+Dq4aBLTSYPwlLyqo+WNBVUUCKCHOq62ULF8MpX5YGaPFNxKYzircV7HpF1hCbV31dmpkeYT9xztra5V0SIBM27jAcQqGmtHH2mhx1sLu+gjhFJbbtY6cggA9EedzYYLDx/NPmgfyuOJfyVbSwTF3vhDUYfskqc1THWpwOSKO0Ry+8/xYb9crxg+FSwuI5hnfkIFk9woBvRGBhjto3/1buMNY9dSFiWtEbN6Let8e747l0wIGJCpJxSeh7vn7F1mWjixhf9GX1+V9BrUvGTd3XJDNb9cVnafYa1RTj8BLteA4HBza7Z9R3dvG4YWp16L/94UuaTzgAQfERLTZGopQth/hsaVTlYesJmJLF70lGM+W83y3YuNkSaX1zQ5FAIvp7oH0O16t7ISm6GprUFwN2Uox7AAbPZdWHxJbly+D+yCFNcqS3Bz9mV3YCLo690Sy1ePNHr+nCseVfBMo7OYyavSS/EjPWfEy65Wq04=
+31 -29
View File
@@ -1,10 +1,10 @@
| Preview Builds | Release Builds | Tachiyomi Support Server | | Preview Builds | Release Builds | Tachiyomi Support Server |
|-------|----------|----------| |-------|----------|----------|
| [![Preview](https://github.com/jobobby04/TachiyomiSYPreview/workflows/Remote%20Dispatch%20Build%20App/badge.svg)](https://github.com/jobobby04/TachiyomiSYPreview/releases) | [![stable release](https://img.shields.io/github/release/jobobby04/tachiyomisy.svg?maxAge=3600&label=download)](https://github.com/jobobby04/tachiyomisy/releases) | [![Discord](https://img.shields.io/discord/349436576037732353.svg)](https://discord.gg/tachiyomi) | | [![Preview](https://github.com/jobobby04/TachiyomiSYPreview/workflows/Remote%20Dispatch%20Build%20App/badge.svg)](https://github.com/jobobby04/TachiyomiSYPreview/releases) | [![stable release](https://img.shields.io/github/release/jobobby04/tachiyomisy.svg?maxAge=3600&label=download)](https://github.com/jobobby04/tachiyomisy/releases/latest) | [![Discord](https://img.shields.io/discord/349436576037732353.svg)](https://discord.gg/tachiyomi) |
# ![app icon](./.github/readme-images/app-icon.png)TachiyomiSY # ![app icon](./.github/readme-images/app-icon.png)TachiyomiSY
Tachiyomi is a free and open source manga reader for Android 5.0 and above. This version of Tachiyomi, TachiyomiSY was based off TachiyomiAZ. TachiyomiAZ has decided to keep the old UI of the app, this version is meant to push forward in the ways of UI and usability, doing that it takes the new Tachiyomi(original) UI. TachiyomiSY also includes a lot of the up in coming features of the Tachiyomi Preview, as well as features from other forks like J2K, it has quite a few custom features from myself and contributors as well. Tachiyomi is a free and open source manga reader for Android 5.0 and above. This version of Tachiyomi, TachiyomiSY was based off TachiyomiAZ. This version is meant to push forward in the ways of usability and features. TachiyomiSY tries to push forward where it can, but staying in a place where it can easily grab updates and features from the main app, it tries to make new features, or take features from other forks like J2K and Neko.
![screenshots of app](./.github/readme-images/screens.png) ![screenshots of app](./.github/readme-images/screens.png)
@@ -21,50 +21,52 @@ Features of Tachiyomi(original) include:
* Create backups locally to read offline or to your desired cloud service * Create backups locally to read offline or to your desired cloud service
Features of TachiyomiSY include: Features of TachiyomiSY include:
* Uses the new Tachiyomi Stable UI
* Custom manga page, all your needs, such as info and chapters, in front of your face
* Latest tab, store up to 5 sources where you can easily view the latest manga by viewing the tab * Latest tab, store up to 5 sources where you can easily view the latest manga by viewing the tab
* Hentai features enable/disable, in advanced settings
* Automatic webtoon detection, allowing the reader to switch to webtoon mode automatically when viewing one * Automatic webtoon detection, allowing the reader to switch to webtoon mode automatically when viewing one
* Recommendations, from AZ but heavily modified by She11Shocked to use both MAL and Anilist interchangeably * Manga recommendations, uses MAL and Anilist, as well as Neko Similar Manga for Mangadex manga(Thanks to Az, She11Shocked, Carlos, and Goldbattle)
* Lewd filter, hide the lewd manga in your library when you want to * Lewd filter, hide the lewd manga in your library when you want to
* Tracking filter, filter your tracked manga so you can see them or see non-tracked manga, made by She11Shocked * Tracking filter, filter your tracked manga so you can see them or see non-tracked manga, made by She11Shocked
* Search tracking status in library, made by She11Shocked * Search tracking status in library, made by She11Shocked
* Backup saved searches
* New E-Hentai/ExHentai features, such as language settings and watched list settings
* Comfortable grid view
* Custom categories for sources, liked the pinned sources, but you can make your own versions and put any sources in them * Custom categories for sources, liked the pinned sources, but you can make your own versions and put any sources in them
* Manga info edit
Inherited from TachiyomiAZ or TachiyomiEH and are included and possibly modified in TachiyomiSY * Manga Cover view + share and save
* Dynamic Categories, view the library in multiple ways
* Smart background for reading modes like LTR or Vertical, changes the background based on the page color
* Force disable webtoon zoom
* Continue reading button in library
* Hentai features enable/disable, in advanced settings
* Quick clean titles
* Source migration, migrate all your manga from one source to another * Source migration, migrate all your manga from one source to another
* Custom hentai sources:
* * E-Hentai/ExHentai
* * nHentai
* * Hitomi.la
* * 8Muses
* * HBrowse
* * Perv Eden
* Additional features for some extensions, features include custom description, opening in app, batch add to library:
* * Puruin
* * Tsumino
* * HentaiCafe (Foolside)
* Saving searches * Saving searches
* Autoscroll * Autoscroll
* Page preload customization * Page preload customization
* Customize image cache size * Customize image cache size
* Batch import of custom sources and featured extensions * Batch import of custom sources and featured extensions
* Automatic CAPTCHA solving * Automatic CAPTCHA solving
* TriState Filters
* Infinite history page
* Search your history page
* Advanced source settings page, searching, enable/disable all * Advanced source settings page, searching, enable/disable all
* Click tag for local search, long click tag for global search * Click tag for local search, long click tag for global search
* Merge multiple of the same manga from different sources * Merge multiple of the same manga from different sources
* Drag and drop library sorting * Drag and drop library sorting
* Library search engine, includes exclude, quotes as absolute, and a bunch of other ways to search
* New E-Hentai/ExHentai features, such as language settings and watched list settings
* Enhanced views for internal and integrated sources
* Enhanced usability for internal and delegated sources
* Custom sources:
* * E-Hentai/ExHentai
* Additional features for some extensions, features include custom description, opening in app, batch add to library, and a bunch of other things based on the source:
* * 8Muses (EroMuse)
* * HBrowse
* * HentaiCafe (inside Foolside)
* * Hitomi.la
* * Mangadex
* * NHentai
* * PervEden (EN and IT)
* * Puruin
* * Tsumino
## Download ## Download
Get the app from our [releases page](https://github.com/jobobby04/tachiyomisy/releases). Get the app from our [releases page](https://github.com/jobobby04/tachiyomisy/releases/latest).
If you want to try new features before they get to the stable release, you can download the preview version [here](https://github.com/jobobby04/tachiyomisypreview/releases). If you want to try new features before they get to the stable release, you can download the preview version [here](https://github.com/jobobby04/tachiyomisypreview/releases).
@@ -74,14 +76,14 @@ Please make sure to read the full guidelines. Your issue may be closed without w
<details><summary>Issues</summary> <details><summary>Issues</summary>
1. **Before reporting a new issue, take a look at the [FAQ](https://github.com/inorichi/tachiyomi/wiki/FAQ), the [changelog](https://github.com/jobobby04/tachiyomisy/releases) and the already opened [issues](https://github.com/jobobby04/tachiyomisy/issues).** 1. **Before reporting a new issue, take a look at the [FAQ](https://tachiyomi.org/help/faq/), the [changelog](https://github.com/jobobby04/tachiyomisy/releases) and the already opened [issues](https://github.com/jobobby04/tachiyomisy/issues).**
2. If you are unsure, ask here: [![Discord](https://img.shields.io/discord/349436576037732353.svg)](https://discord.gg/tachiyomi) 2. If you are unsure, ask here: [![Discord](https://img.shields.io/discord/349436576037732353.svg)](https://discord.gg/tachiyomi)
</details> </details>
<details><summary>Bugs</summary> <details><summary>Bugs</summary>
* Include version (Setting > About > Version) * Include version (More > About > Version)
* If not latest, try updating, it may have already been solved * If not latest, try updating, it may have already been solved
* Preview version is equal to the number of commits as seen in the main page * Preview version is equal to the number of commits as seen in the main page
* Include steps to reproduce (if not obvious from description) * Include steps to reproduce (if not obvious from description)
@@ -101,7 +103,7 @@ DON'T: https://github.com/inorichi/tachiyomi/issues/75
* Write a detailed issue, explaining what it should do or how. Avoid writing just "like X app does" * Write a detailed issue, explaining what it should do or how. Avoid writing just "like X app does"
* Include screenshot (if needed) * Include screenshot (if needed)
Catalogue requests should be created at https://github.com/inorichi/tachiyomi-extensions, they do not belong in this repository. Source requests should be created at https://github.com/inorichi/tachiyomi-extensions, they do not belong in this repository.
</details> </details>
## FAQ ## FAQ
+71 -86
View File
@@ -7,6 +7,7 @@ apply plugin: 'com.mikepenz.aboutlibraries.plugin'
apply plugin: 'kotlin-android' apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt' apply plugin: 'kotlin-kapt'
apply plugin: 'kotlinx-serialization'
apply plugin: 'com.github.zellius.shortcut-helper' apply plugin: 'com.github.zellius.shortcut-helper'
// Realm (EH) // Realm (EH)
apply plugin: 'realm-android' apply plugin: 'realm-android'
@@ -36,15 +37,15 @@ ext {
android { android {
compileSdkVersion AndroidConfig.compileSdk compileSdkVersion AndroidConfig.compileSdk
buildToolsVersion AndroidConfig.buildTools buildToolsVersion AndroidConfig.buildTools
publishNonDefault true ndkVersion AndroidConfig.ndk
defaultConfig { defaultConfig {
applicationId "eu.kanade.tachiyomi.sy" applicationId "eu.kanade.tachiyomi.sy"
minSdkVersion AndroidConfig.minSdk minSdkVersion AndroidConfig.minSdk
targetSdkVersion AndroidConfig.targetSdk targetSdkVersion AndroidConfig.targetSdk
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
versionCode 2 versionCode 10
versionName "1.0.0" versionName "1.4.0"
buildConfigField "String", "COMMIT_COUNT", "\"${getCommitCount()}\"" buildConfigField "String", "COMMIT_COUNT", "\"${getCommitCount()}\""
buildConfigField "String", "COMMIT_SHA", "\"${getGitSha()}\"" buildConfigField "String", "COMMIT_SHA", "\"${getGitSha()}\""
@@ -66,7 +67,6 @@ android {
debug { debug {
versionNameSuffix "-${getCommitCount()}" versionNameSuffix "-${getCommitCount()}"
applicationIdSuffix ".debug" applicationIdSuffix ".debug"
ext.enableCrashlytics = false
} }
releaseTest { releaseTest {
applicationIdSuffix ".rt" applicationIdSuffix ".rt"
@@ -129,7 +129,7 @@ android {
} }
kotlinOptions { kotlinOptions {
jvmTarget = "1.8" jvmTarget = JavaVersion.VERSION_1_8.toString()
} }
} }
@@ -139,38 +139,35 @@ androidExtensions {
dependencies { dependencies {
// Modified dependencies // Source models and interfaces from Tachiyomi 1.x
implementation 'com.github.inorichi:subsampling-scale-image-view:ac0dae7' implementation 'tachiyomi.sourceapi:source-api:1.1'
implementation 'com.github.inorichi:junrar-android:634c1f5'
// AndroidX libraries // AndroidX libraries
implementation 'androidx.annotation:annotation:1.1.0' implementation 'androidx.annotation:annotation:1.2.0-alpha01'
implementation 'androidx.appcompat:appcompat:1.3.0-alpha01' implementation 'androidx.appcompat:appcompat:1.3.0-alpha02'
implementation 'androidx.biometric:biometric:1.1.0-alpha01' implementation 'androidx.biometric:biometric-ktx:1.2.0-alpha01'
implementation 'androidx.browser:browser:1.2.0' implementation 'androidx.browser:browser:1.3.0'
implementation 'androidx.cardview:cardview:1.0.0' implementation 'androidx.cardview:cardview:1.0.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta7' implementation 'androidx.constraintlayout:constraintlayout:2.1.0-alpha1'
implementation 'androidx.coordinatorlayout:coordinatorlayout:1.1.0' implementation 'androidx.coordinatorlayout:coordinatorlayout:1.1.0'
implementation 'androidx.core:core-ktx:1.5.0-alpha05'
implementation 'androidx.multidex:multidex:2.0.1' implementation 'androidx.multidex:multidex:2.0.1'
implementation 'androidx.preference:preference:1.1.1' implementation 'androidx.preference:preference-ktx:1.1.1'
implementation 'androidx.recyclerview:recyclerview:1.2.0-alpha04' implementation 'androidx.recyclerview:recyclerview:1.2.0-beta01'
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0' implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.2.0-alpha01'
implementation 'androidx.webkit:webkit:1.3.0-rc01'
final lifecycle_version = '2.3.0-alpha05' final lifecycle_version = '2.3.0-beta01'
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version" implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-process:$lifecycle_version" implementation "androidx.lifecycle:lifecycle-process:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version" implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version"
// Job scheduling // Job scheduling
final work_version = '2.4.0-rc01' implementation "androidx.work:work-runtime-ktx:2.5.0-beta02"
implementation "androidx.work:work-runtime:$work_version"
implementation "androidx.work:work-runtime-ktx:$work_version"
// UI library // UI library
implementation 'com.google.android.material:material:1.3.0-alpha01' implementation 'com.google.android.material:material:1.3.0-alpha04'
standardImplementation 'com.google.firebase:firebase-core:17.4.3' standardImplementation 'com.google.firebase:firebase-core:18.0.0'
// ReactiveX // ReactiveX
implementation 'io.reactivex:rxandroid:1.2.1' implementation 'io.reactivex:rxandroid:1.2.1'
@@ -179,22 +176,24 @@ dependencies {
implementation 'com.github.pwittchen:reactivenetwork:0.13.0' implementation 'com.github.pwittchen:reactivenetwork:0.13.0'
// Network client // Network client
final okhttp_version = '4.7.2' final okhttp_version = '4.10.0-RC1'
implementation "com.squareup.okhttp3:okhttp:$okhttp_version" implementation "com.squareup.okhttp3:okhttp:$okhttp_version"
implementation "com.squareup.okhttp3:logging-interceptor:$okhttp_version" implementation "com.squareup.okhttp3:logging-interceptor:$okhttp_version"
implementation "com.squareup.okhttp3:okhttp-dnsoverhttps:$okhttp_version" implementation "com.squareup.okhttp3:okhttp-dnsoverhttps:$okhttp_version"
implementation 'com.squareup.okio:okio:2.6.0' implementation 'com.squareup.okio:okio:2.9.0'
// TLS 1.3 support for Android < 10 // TLS 1.3 support for Android < 10
implementation 'org.conscrypt:conscrypt-android:2.4.0' implementation 'org.conscrypt:conscrypt-android:2.5.1'
// REST // REST
final retrofit_version = '2.9.0' final retrofit_version = '2.9.0'
implementation "com.squareup.retrofit2:retrofit:$retrofit_version" implementation "com.squareup.retrofit2:retrofit:$retrofit_version"
implementation "com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:0.8.0"
implementation "com.squareup.retrofit2:converter-gson:$retrofit_version" implementation "com.squareup.retrofit2:converter-gson:$retrofit_version"
implementation "com.squareup.retrofit2:adapter-rxjava:$retrofit_version" implementation "com.squareup.retrofit2:adapter-rxjava:$retrofit_version"
// JSON // JSON
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.0.1"
implementation 'com.google.code.gson:gson:2.8.6' implementation 'com.google.code.gson:gson:2.8.6'
implementation 'com.github.salomonbrys.kotson:kotson:2.5.0' implementation 'com.github.salomonbrys.kotson:kotson:2.5.0'
@@ -204,6 +203,7 @@ dependencies {
// Disk // Disk
implementation 'com.jakewharton:disklrucache:2.0.2' implementation 'com.jakewharton:disklrucache:2.0.2'
implementation 'com.github.inorichi:unifile:e9ee588' implementation 'com.github.inorichi:unifile:e9ee588'
implementation 'com.github.junrar:junrar:7.4.0'
// HTML parser // HTML parser
implementation 'org.jsoup:jsoup:1.13.1' implementation 'org.jsoup:jsoup:1.13.1'
@@ -215,13 +215,13 @@ dependencies {
implementation 'com.github.gabrielemariotti.changeloglib:changelog:2.1.0' implementation 'com.github.gabrielemariotti.changeloglib:changelog:2.1.0'
// Database // Database
implementation 'androidx.sqlite:sqlite:2.1.0' implementation 'androidx.sqlite:sqlite-ktx:2.1.0'
implementation 'com.github.inorichi.storio:storio-common:8be19de@aar' implementation 'com.github.inorichi.storio:storio-common:8be19de@aar'
implementation 'com.github.inorichi.storio:storio-sqlite:8be19de@aar' implementation 'com.github.inorichi.storio:storio-sqlite:8be19de@aar'
implementation 'io.requery:sqlite-android:3.31.0' implementation 'io.requery:sqlite-android:3.33.0'
// Preferences // Preferences
implementation 'com.github.tfcporciuncula:flow-preferences:1.1.1' implementation 'com.github.tfcporciuncula.flow-preferences:flow-preferences:1.3.3'
// Model View Presenter // Model View Presenter
final nucleus_version = '3.0.0' final nucleus_version = '3.0.0'
@@ -237,12 +237,13 @@ dependencies {
implementation "com.github.bumptech.glide:okhttp3-integration:$glide_version" implementation "com.github.bumptech.glide:okhttp3-integration:$glide_version"
kapt "com.github.bumptech.glide:compiler:$glide_version" kapt "com.github.bumptech.glide:compiler:$glide_version"
implementation 'com.github.tachiyomiorg:subsampling-scale-image-view:6caf219'
// Logging // Logging
implementation 'com.jakewharton.timber:timber:4.7.1' implementation 'com.jakewharton.timber:timber:4.7.1'
// Crash reports // Crash reports
final acra_version = '5.5.0' //implementation 'ch.acra:acra-http:5.7.0'
implementation "ch.acra:acra-http:$acra_version"
// Sort // Sort
implementation 'com.github.gpanther:java-nat-sort:natural-comparator-1.1' implementation 'com.github.gpanther:java-nat-sort:natural-comparator-1.1'
@@ -254,7 +255,6 @@ dependencies {
implementation 'eu.davidea:flexible-adapter-ui:1.0.0' implementation 'eu.davidea:flexible-adapter-ui:1.0.0'
implementation 'com.nononsenseapps:filepicker:2.5.2' implementation 'com.nononsenseapps:filepicker:2.5.2'
implementation 'com.nightlynexus.viewstatepageradapter:viewstatepageradapter:1.1.0' implementation 'com.nightlynexus.viewstatepageradapter:viewstatepageradapter:1.1.0'
implementation 'com.github.mthli:Slice:v1.3'
implementation 'com.github.chrisbanes:PhotoView:2.3.0' implementation 'com.github.chrisbanes:PhotoView:2.3.0'
implementation 'com.github.carlosesco:DirectionalViewPager:a844dbca0a' implementation 'com.github.carlosesco:DirectionalViewPager:a844dbca0a'
@@ -272,7 +272,7 @@ dependencies {
implementation 'com.github.tachiyomiorg:conductor-support-preference:1.1.1' implementation 'com.github.tachiyomiorg:conductor-support-preference:1.1.1'
// FlowBinding // FlowBinding
final flowbinding_version = '0.11.1' final flowbinding_version = '0.12.0'
implementation "io.github.reactivecircus.flowbinding:flowbinding-android:$flowbinding_version" implementation "io.github.reactivecircus.flowbinding:flowbinding-android:$flowbinding_version"
implementation "io.github.reactivecircus.flowbinding:flowbinding-appcompat:$flowbinding_version" implementation "io.github.reactivecircus.flowbinding:flowbinding-appcompat:$flowbinding_version"
implementation "io.github.reactivecircus.flowbinding:flowbinding-recyclerview:$flowbinding_version" implementation "io.github.reactivecircus.flowbinding:flowbinding-recyclerview:$flowbinding_version"
@@ -280,13 +280,11 @@ dependencies {
implementation "io.github.reactivecircus.flowbinding:flowbinding-viewpager:$flowbinding_version" implementation "io.github.reactivecircus.flowbinding:flowbinding-viewpager:$flowbinding_version"
// Licenses // Licenses
final aboutlibraries_version = '8.2.0' implementation "com.mikepenz:aboutlibraries:$BuildPluginsVersion.ABOUTLIB_PLUGIN"
implementation "com.mikepenz:aboutlibraries-core:$aboutlibraries_version"
implementation "com.mikepenz:aboutlibraries:$aboutlibraries_version"
// Tests // Tests
testImplementation 'junit:junit:4.13' testImplementation 'junit:junit:4.13'
testImplementation 'org.assertj:assertj-core:3.12.2' testImplementation 'org.assertj:assertj-core:3.16.1'
testImplementation 'org.mockito:mockito-core:1.10.19' testImplementation 'org.mockito:mockito-core:1.10.19'
final robolectric_version = '3.1.4' final robolectric_version = '3.1.4'
@@ -294,94 +292,81 @@ dependencies {
testImplementation "org.robolectric:shadows-multidex:$robolectric_version" testImplementation "org.robolectric:shadows-multidex:$robolectric_version"
testImplementation "org.robolectric:shadows-play-services:$robolectric_version" testImplementation "org.robolectric:shadows-play-services:$robolectric_version"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-reflect:$BuildPluginsVersion.KOTLIN"
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
final coroutines_version = '1.3.7' final coroutines_version = '1.4.1'
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-reactive:$coroutines_version"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-rx2:$coroutines_version"
implementation 'com.google.android.gms:play-services-oss-licenses:17.0.0' // For detecting memory leaks; see https://square.github.io/leakcanary/
// debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.4'
// SY for mangadex utils
implementation "org.jetbrains.kotlinx:kotlinx-serialization-protobuf:1.0.1"
// Text distance (EH) // Text distance (EH)
implementation 'info.debatty:java-string-similarity:1.2.1' implementation 'info.debatty:java-string-similarity:2.0.0'
// Reprint (EH)
implementation 'com.github.ajalt.reprint:core:3.2.1@aar'
implementation 'com.github.ajalt.reprint:rxjava:3.2.1@aar' // optional: the RxJava 1 interface
// Swirl (EH)
implementation 'com.mattprecious.swirl:swirl:1.2.0'
// RxJava 2 interop for Realm (EH)
implementation 'com.github.akarnokd:rxjava2-interop:0.13.7'
// Firebase (EH) // Firebase (EH)
implementation 'com.crashlytics.sdk.android:crashlytics:2.10.1' implementation 'com.google.firebase:firebase-analytics-ktx:18.0.0'
implementation 'com.google.firebase:firebase-crashlytics-ktx:17.3.0'
// Better logging (EH) // Better logging (EH)
implementation 'com.elvishew:xlog:1.6.1' implementation 'com.elvishew:xlog:1.7.1'
// Time utils (EH)
def typed_time_version = '1.0.2'
implementation "com.github.kizitonwose.time:time:$typed_time_version"
implementation "com.github.kizitonwose.time:time-android:$typed_time_version"
// Debug utils (EH) // Debug utils (EH)
debugImplementation 'com.ms-square:debugoverlay:1.1.3' final def debug_overlay_version = '1.1.3'
releaseTestImplementation 'com.ms-square:debugoverlay:1.1.3' debugImplementation "com.ms-square:debugoverlay:$debug_overlay_version"
releaseImplementation 'com.ms-square:debugoverlay-no-op:1.1.3' releaseTestImplementation "com.ms-square:debugoverlay:$debug_overlay_version"
testImplementation 'com.ms-square:debugoverlay-no-op:1.1.3' releaseImplementation "com.ms-square:debugoverlay-no-op:$debug_overlay_version"
testImplementation "com.ms-square:debugoverlay-no-op:$debug_overlay_version"
// Humanize (EH) // RatingBar (SY)
implementation 'com.github.mfornos:humanize-slim:1.2.2' implementation 'me.zhanghai.android.materialratingbar:library:1.4.0'
// JsonReader for similar manga
implementation 'com.squareup.moshi:moshi:1.11.0'
implementation 'androidx.gridlayout:gridlayout:1.0.0' implementation 'androidx.gridlayout:gridlayout:1.0.0'
final def markwon_version = '4.1.0'
implementation "io.noties.markwon:core:$markwon_version"
implementation "io.noties.markwon:ext-strikethrough:$markwon_version"
implementation "io.noties.markwon:ext-tables:$markwon_version"
implementation "io.noties.markwon:html:$markwon_version"
implementation "io.noties.markwon:image:$markwon_version"
implementation "io.noties.markwon:linkify:$markwon_version"
implementation 'com.google.guava:guava:27.0.1-android'
} }
buildscript { buildscript {
ext.kotlin_version = '1.3.72'
repositories { repositories {
mavenCentral() mavenCentral()
} }
dependencies { dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$BuildPluginsVersion.KOTLIN"
} }
} }
repositories { repositories {
mavenCentral() mavenCentral()
jcenter()
} }
// See https://kotlinlang.org/docs/reference/experimental.html#experimental-status-of-experimental-api-markers // See https://kotlinlang.org/docs/reference/experimental.html#experimental-status-of-experimental-api-markers
tasks.withType(AbstractKotlinCompile).all { tasks.withType(AbstractKotlinCompile).all {
kotlinOptions.freeCompilerArgs += ["-Xuse-experimental=kotlin.Experimental"] kotlinOptions.freeCompilerArgs += [
"-Xopt-in=kotlin.Experimental",
"-Xopt-in=kotlin.RequiresOptIn",
"-Xuse-experimental=kotlin.ExperimentalStdlibApi",
"-Xuse-experimental=kotlinx.coroutines.FlowPreview",
"-Xuse-experimental=kotlinx.coroutines.ExperimentalCoroutinesApi",
"-Xuse-experimental=kotlinx.serialization.ExperimentalSerializationApi",
]
} }
// Duplicating Hebrew string assets due to some locale code issues on different devices // Duplicating Hebrew string assets due to some locale code issues on different devices
task copyResources(type: Copy) { task copyHebrewStrings(type: Copy) {
from './src/main/res/values-he' from './src/main/res/values-he'
into './src/main/res/values-iw' into './src/main/res/values-iw'
include '**/*' include '**/*'
} }
preBuild.dependsOn(ktlintFormat, copyResources) preBuild.dependsOn(formatKotlin, copyHebrewStrings)
if (getGradle().getStartParameter().getTaskRequests().toString().contains("Standard")) { if (!getGradle().getStartParameter().getTaskRequests().toString().contains("Debug")) {
apply plugin: 'com.google.gms.google-services' apply plugin: 'com.google.gms.google-services'
// Firebase (EH) // Firebase Crashlytics
apply plugin: 'io.fabric' apply plugin: 'com.google.firebase.crashlytics'
} }
+44
View File
@@ -30,6 +30,42 @@
<init>(); <init>();
} }
# Kotlin Serialization
-keepattributes *Annotation*, InnerClasses
-dontnote kotlinx.serialization.AnnotationsKt # core serialization annotations
# kotlinx-serialization-json specific. Add this if you have java.lang.NoClassDefFoundError kotlinx.serialization.json.JsonObjectSerializer
-keepclassmembers class kotlinx.serialization.json.** {
*** Companion;
}
-keepclasseswithmembers class kotlinx.serialization.json.** {
kotlinx.serialization.KSerializer serializer(...);
}
-keep,includedescriptorclasses class eu.kanade.tachiyomi.**$$serializer { *; }
-keepclassmembers class eu.kanade.tachiyomi.** {
*** Companion;
}
-keepclasseswithmembers class eu.kanade.tachiyomi.** {
kotlinx.serialization.KSerializer serializer(...);
}
-keep,includedescriptorclasses class exh.**$$serializer { *; }
-keepclassmembers class exh.** {
*** Companion;
}
-keepclasseswithmembers class exh.** {
kotlinx.serialization.KSerializer serializer(...);
}
-keep,includedescriptorclasses class xyz.nulldev.ts.api.http.serializer.**$$serializer { *; }
-keepclassmembers class xyz.nulldev.ts.api.http.serializer.** {
*** Companion;
}
-keepclasseswithmembers class xyz.nulldev.ts.api.http.serializer.** {
kotlinx.serialization.KSerializer serializer(...);
}
# Madokami extension username and password crash fix # Madokami extension username and password crash fix
-keepclassmembers class androidx.preference.EditTextPreference { -keepclassmembers class androidx.preference.EditTextPreference {
*** mOnBindEditTextListener; *** mOnBindEditTextListener;
@@ -37,6 +73,14 @@
public *; public *;
} }
# Hitomi extension crash fix
-keepclassmembers class rx.Single {
*** onSubscribe;
final *;
protected *;
public *;
}
# RxJava 1.1.0 # RxJava 1.1.0
-dontwarn sun.misc.** -dontwarn sun.misc.**
@@ -1,38 +1,30 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" <vector
android:width="108dp" xmlns:android="http://schemas.android.com/apk/res/android"
android:height="108dp" android:width="108dp"
android:viewportWidth="108.0" android:height="108dp"
android:viewportHeight="108.0"> android:viewportWidth="108"
android:viewportHeight="108">
<group android:scaleX="0.07776"
android:scaleY="0.07776"
android:translateX="15.12"
android:translateY="15.12">
<path <path
android:pathData="M14.5,7L86.5,7A7,7 0,0 1,93.5 14L93.5,95A7,7 0,0 1,86.5 102L14.5,102A7,7 0,0 1,7.5 95L7.5,14A7,7 0,0 1,14.5 7z" android:pathData="M474.4,272.2c115.3,-1.4 144.2,48.2 185.2,74.7c21.6,8.3 17.7,16.3 26.2,28.7c2.5,3.5 5.5,5 9.5,7.5c30.3,18.2 -10.8,39.6 -28.2,40.3c7.1,-4.6 13.2,-5.9 17.7,-12.4c-0.3,0 -0.6,0 -0.9,0c0,-0.3 0,-0.6 0,-0.9c-14.6,-4 -13.3,8.8 -29.2,6.2c3.5,-0.4 12.6,-5.8 12.4,-13.3c-11.9,-7.2 -31.6,-15.2 -46.9,-14.2c-0.1,0.4 -0.1,0.4 -0.2,0.8c36.3,24.2 25.7,57.3 47.1,63.8c-11.6,-0.5 -5.9,2.1 0,7.1c-14.6,-3 -16.1,-19.2 -23,-33.6c-7.8,-12.9 -15.4,-28.5 -23.9,-29.2c-2,9.2 2,56.4 14.7,46.6c-10,12.3 4.4,7.2 11,4.7c-23.9,19 -35.1,13.8 -42.8,-13.8c-6.2,-13.4 -14.6,-34.2 -19.5,-46.6c-2.8,-7.1 -7.5,-13.3 -13.6,-17.9c-41.8,-31.2 -72.8,-33.3 -116.9,-26.1c-11.1,-21.4 -27.5,-40.4 -38.9,-61.9C435,277.7 452,272.4 474.4,272.2z"
android:fillType="evenOdd" android:fillColor="#2E84BF"/>
android:fillColor="#000"/>
<path <path
android:pathData="M14.5,7L86.5,7A7,7 0,0 1,93.5 14L93.5,95A7,7 0,0 1,86.5 102L14.5,102A7,7 0,0 1,7.5 95L7.5,14A7,7 0,0 1,14.5 7z" android:pathData="M313.4,366C395.3,524.3 482,472.7 607.1,532.8c109.3,67.9 83.8,212.8 -30.1,257.7c0,-28.3 0,-56.6 0,-84.9c46.4,-45.1 20.7,-112.1 -37.1,-125c-68.8,-15 -145.6,-29.5 -191.7,-62.5C298,480.3 286.6,416.8 313.4,366z"
android:fillType="evenOdd" android:fillColor="#2E84BF"/>
android:fillColor="#455A64"/>
<path <path
android:pathData="M7.5,12.01C7.5,9.24 9.74,7 12.5,7L17.5,7L17.5,102L12.5,102C9.74,102 7.5,99.77 7.5,96.99L7.5,12.01Z" android:pathData="M424.8,720.6c0.1,25.4 1.9,53.9 -0.9,77.8c-94.2,-25.7 -162.5,-103.3 -124.7,-192.8c0,4.7 0,9.4 0,14.2C307.8,680 359.3,712.6 424.8,720.6z"
android:fillType="evenOdd" android:fillColor="#2E84BF"/>
android:fillColor="#607D8B"/>
<path <path
android:name="path_3" android:pathData="M247,228l138.9,37.1L500,444.7l47.8,-72.5c34.5,14.5 37,85.5 55.7,96.4l-23,34.5C477,474.9 387.8,469.9 351.3,394.7C317.9,341.3 247.1,228.1 247,228z"
android:pathData="M 54 54.5 M 28.5 54.5 C 28.5 47.74 31.188 41.249 35.969 36.469 C 40.749 31.688 47.24 29 54 29 C 60.76 29 67.251 31.688 72.031 36.469 C 76.812 41.249 79.5 47.74 79.5 54.5 C 79.5 61.26 76.812 67.751 72.031 72.531 C 67.251 77.312 60.76 80 54 80 C 47.24 80 40.749 77.312 35.969 72.531 C 31.188 67.751 28.5 61.26 28.5 54.5" android:fillColor="#CE2828"/>
android:fillColor="#CE2828"
android:fillType="evenOdd"/>
<path <path
android:name="path_4" android:pathData="M602.6,285.5c16.2,9.6 33.1,19.8 46.5,32.8c7.5,7.2 14.9,12.3 25.3,18.3c3.9,2.2 4.7,2.1 7.8,4.7L753,228l-137.1,37.1L602.6,285.5z"
android:pathData="M 54 54.5 M 34.06 54.5 C 33.964 50.23 35.243 46.04 37.707 42.551 C 40.171 39.062 43.692 36.455 47.748 35.117 C 51.805 33.779 56.185 33.779 60.242 35.117 C 64.298 36.455 67.819 39.062 70.283 42.551 C 72.747 46.04 74.026 50.23 73.93 54.5 C 74.026 58.77 72.747 62.96 70.283 66.449 C 67.819 69.938 64.298 72.545 60.242 73.883 C 56.185 75.221 51.805 75.221 47.748 73.883 C 43.692 72.545 40.171 69.938 37.707 66.449 C 35.243 62.96 33.964 58.77 34.06 54.5" android:fillColor="#CE2828"/>
android:fillColor="#000"
android:fillType="evenOdd"/>
<path <path
android:name="path_5" android:pathData="M500.9,871l61.9,-50.4l0.9,-212.3c0,0 -4.5,-11.4 -85.2,-25.5c-17.1,-3 -29.7,-7.2 -29.8,-7.2l-12.3,-3.6l1.8,248.5L500.9,871z"
android:pathData="M50.953,47.457C51.828,47.457 53.465,44.672 53.465,43.746C53.465,42.82 50.238,40.461 45.684,40.461C39.32,40.461 37.535,44.926 37.535,47.539C37.535,50.238 38.285,53.355 45.152,55.465C46.977,56.055 49.789,56.98 49.789,59.258C49.789,61.195 47.727,62.207 45.34,62.207C38.605,62.207 39.137,55.883 38.605,55.883C38.285,55.883 36.691,57.402 36.691,60.098C36.691,65.07 41.199,67.434 45.652,67.434C52.27,67.434 54.871,62.965 54.871,59.34C54.871,56.391 53.523,53.188 46.941,50.996C45.215,50.406 42.113,49.563 42.113,47.285C42.113,45.434 44.117,44.672 45.684,44.672C48.949,44.672 50.168,47.457 50.953,47.457ZM50.953,47.457" android:fillColor="#CE2828"/>
android:fillColor="#F7D009" </group>
android:fillType="evenOdd" />
<path
android:name="path_6"
android:pathData="M56.734,66.254C56.734,67.012 56.734,67.434 57.496,67.434C64.391,67.434 71.469,58.582 71.191,49.395C71.191,48.047 71.285,47.035 70.688,46.949L67.895,46.949C67.551,46.949 66.766,46.867 66.766,47.371C66.766,47.875 67.113,49.227 67.113,50.742C67.113,53.188 66.27,56.98 65.012,56.98C64.391,56.98 61.313,53.523 61.313,49.816C61.313,48.887 61.598,47.961 61.598,47.457C61.598,46.867 60.906,46.949 60.504,46.949L57.934,46.949C56.711,46.949 56.734,46.949 56.734,48.383C56.734,57.148 62.188,59.34 62.188,60.688C62.188,61.027 61.254,62.207 57.645,62.207C56.805,62.207 56.734,63.133 56.734,63.469ZM56.734,66.254"
android:fillColor="#E40F85"
android:fillType="evenOdd" />
</vector> </vector>
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@android:color/transparent"/> <background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/> <foreground android:drawable="@drawable/ic_launcher_foreground"/>
</adaptive-icon> </adaptive-icon>
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@android:color/transparent"/> <background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/> <foreground android:drawable="@drawable/ic_launcher_foreground"/>
</adaptive-icon> </adaptive-icon>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.4 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.7 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 12 KiB

+70 -40
View File
@@ -25,7 +25,7 @@
android:requestLegacyExternalStorage="true" android:requestLegacyExternalStorage="true"
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"
android:theme="@style/Theme.Tachiyomi.Light" android:theme="@style/Theme.Tachiyomi.Light"
android:usesCleartextTraffic="true"> android:networkSecurityConfig="@xml/network_security_config">
<activity <activity
android:name=".ui.main.MainActivity" android:name=".ui.main.MainActivity"
android:launchMode="singleTop" android:launchMode="singleTop"
@@ -39,15 +39,11 @@
android:name="android.app.shortcuts" android:name="android.app.shortcuts"
android:resource="@xml/shortcuts" /> android:resource="@xml/shortcuts" />
</activity> </activity>
<activity
android:name=".ui.main.ForceCloseActivity"
android:clearTaskOnLaunch="true"
android:noHistory="true"
android:theme="@android:style/Theme.NoDisplay" />
<activity <activity
android:name=".ui.main.DeepLinkActivity" android:name=".ui.main.DeepLinkActivity"
android:launchMode="singleTask" android:launchMode="singleTask"
android:theme="@android:style/Theme.NoDisplay"> android:theme="@android:style/Theme.NoDisplay"
android:label="@string/process_text_action_name">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.SEARCH" /> <action android:name="android.intent.action.SEARCH" />
<action android:name="com.google.android.gms.actions.SEARCH_ACTION" /> <action android:name="com.google.android.gms.actions.SEARCH_ACTION" />
@@ -58,6 +54,11 @@
<action android:name="eu.kanade.tachiyomi.SEARCH" /> <action android:name="eu.kanade.tachiyomi.SEARCH" />
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
</intent-filter> </intent-filter>
<intent-filter>
<action android:name="android.intent.action.PROCESS_TEXT" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
<meta-data <meta-data
android:name="android.app.searchable" android:name="android.app.searchable"
@@ -65,7 +66,14 @@
</activity> </activity>
<activity <activity
android:name=".ui.reader.ReaderActivity" android:name=".ui.reader.ReaderActivity"
android:launchMode="singleTask" /> android:launchMode="singleTask">
<intent-filter>
<action android:name="com.samsung.android.support.REMOTE_ACTION" />
</intent-filter>
<meta-data android:name="com.samsung.android.support.REMOTE_ACTION"
android:resource="@xml/s_pen_actions"/>
</activity>
<activity <activity
android:name=".ui.security.BiometricUnlockActivity" android:name=".ui.security.BiometricUnlockActivity"
android:theme="@style/Theme.Splash" /> android:theme="@style/Theme.Splash" />
@@ -90,6 +98,9 @@
android:scheme="tachiyomi" /> android:scheme="tachiyomi" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity
android:name=".ui.setting.track.MyAnimeListLoginActivity"
android:configChanges="uiMode|orientation|screenSize" />
<activity <activity
android:name=".ui.setting.track.ShikimoriLoginActivity" android:name=".ui.setting.track.ShikimoriLoginActivity"
android:label="Shikimori"> android:label="Shikimori">
@@ -158,6 +169,10 @@
android:exported="false" /> android:exported="false" />
<!-- EH --> <!-- EH -->
<service
android:name="exh.md.similar.SimilarUpdateService"
android:exported="false" />
<service <service
android:name="exh.eh.EHentaiUpdateWorker" android:name="exh.eh.EHentaiUpdateWorker"
android:permission="android.permission.BIND_JOB_SERVICE" android:permission="android.permission.BIND_JOB_SERVICE"
@@ -175,39 +190,39 @@
<!-- EH --> <!-- EH -->
<data <data
android:host="g.e-hentai.org" android:host="g.e-hentai.org"
android:pathPrefix="/g/" android:pathPattern="/g/.*"
android:scheme="http" /> android:scheme="http" />
<data <data
android:host="g.e-hentai.org" android:host="g.e-hentai.org"
android:pathPrefix="/g/" android:pathPattern="/g/.*"
android:scheme="https" /> android:scheme="https" />
<data <data
android:host="e-hentai.org" android:host="e-hentai.org"
android:pathPrefix="/g/" android:pathPattern="/g/.*"
android:scheme="http" /> android:scheme="http" />
<data <data
android:host="e-hentai.org" android:host="e-hentai.org"
android:pathPrefix="/g/" android:pathPattern="/g/.*"
android:scheme="https" /> android:scheme="https" />
<!-- EXH --> <!-- EXH -->
<data <data
android:host="exhentai.org" android:host="exhentai.org"
android:pathPrefix="/g/" android:pathPattern="/g/.*"
android:scheme="http" /> android:scheme="http" />
<data <data
android:host="exhentai.org" android:host="exhentai.org"
android:pathPrefix="/g/" android:pathPattern="/g/.*"
android:scheme="https" /> android:scheme="https" />
<!-- nhentai --> <!-- nhentai -->
<data <data
android:host="nhentai.net" android:host="nhentai.net"
android:pathPrefix="/g/" android:pathPattern="/g/.*"
android:scheme="http" /> android:scheme="http" />
<data <data
android:host="nhentai.net" android:host="nhentai.net"
android:pathPrefix="/g/" android:pathPattern="/g/.*"
android:scheme="https" /> android:scheme="https" />
<!-- Perv Eden --> <!-- Perv Eden -->
@@ -233,76 +248,91 @@
<!-- Tsumino --> <!-- Tsumino -->
<data <data
android:host="www.tsumino.com" android:host="www.tsumino.com"
android:pathPrefix="/Book/Info/" android:pathPattern="/Book/Info/.*"
android:scheme="http" /> android:scheme="http" />
<data <data
android:host="www.tsumino.com" android:host="www.tsumino.com"
android:pathPrefix="/Book/Info/" android:pathPattern="/Book/Info/.*"
android:scheme="https" /> android:scheme="https" />
<data <data
android:host="www.tsumino.com" android:host="www.tsumino.com"
android:pathPrefix="/Read/View/" android:pathPattern="/Read/View/.*"
android:scheme="http" /> android:scheme="http" />
<data <data
android:host="www.tsumino.com" android:host="www.tsumino.com"
android:pathPrefix="/Read/View/" android:pathPattern="/Read/View/.*"
android:scheme="https" /> android:scheme="https" />
<!-- Hitomi.la --> <!-- Hitomi.la -->
<data <data
android:host="hitomi.la" android:host="hitomi.la"
android:pathPrefix="/galleries/" android:pathPattern="/galleries/.*"
android:scheme="http" /> android:scheme="http" />
<data <data
android:host="hitomi.la" android:host="hitomi.la"
android:pathPrefix="/reader/" android:pathPattern="/reader/.*"
android:scheme="http" /> android:scheme="http" />
<data <data
android:host="hitomi.la" android:host="hitomi.la"
android:pathPrefix="/galleries/" android:pathPattern="/galleries/.*"
android:scheme="https" /> android:scheme="https" />
<data <data
android:host="hitomi.la" android:host="hitomi.la"
android:pathPrefix="/reader/" android:pathPattern="/reader/.*"
android:scheme="https" /> android:scheme="https" />
<!-- Pururin.io --> <!-- Pururin.io -->
<data <data
android:host="pururin.io" android:host="pururin.io"
android:pathPrefix="/gallery/" android:pathPattern="/gallery/.*"
android:scheme="http" /> android:scheme="http" />
<data <data
android:host="pururin.io" android:host="pururin.io"
android:pathPrefix="/gallery/" android:pathPattern="/gallery/.*"
android:scheme="https" /> android:scheme="https" />
<!-- HBrowse --> <!-- HBrowse -->
<data <data
android:host="www.hbrowse.com" android:host="www.hbrowse.com"
android:pathPrefix="/"
android:scheme="http" /> android:scheme="http" />
<data <data
android:host="www.hbrowse.com" android:host="www.hbrowse.com"
android:pathPrefix="/"
android:scheme="https" /> android:scheme="https" />
<!-- MangaDex --> <!-- MangaDex -->
<!-- <data
android:host="mangadex.org"
android:pathPattern="\/(title|manga)\/"
android:scheme="http" />
<data
android:host="mangadex.org"
android:pathPattern="\/(title|manga)\/"
android:scheme="https" />
<data <data
android:scheme="https"
android:host="www.mangadex.org" android:host="www.mangadex.org"
android:pathPattern="\/(title|manga)\/" android:pathPattern="/manga/..*" />
android:scheme="http" />
<data <data
android:scheme="https"
android:host="mangadex.org"
android:pathPattern="/manga/..*" />
<data
android:scheme="https"
android:host="www.mangadex.cc"
android:pathPattern="/manga/..*" />
<data
android:scheme="https"
android:host="www.mangadex.cc"
android:pathPattern="/manga/..*" />
<data
android:scheme="https"
android:host="www.mangadex.org" android:host="www.mangadex.org"
android:pathPattern="\/(title|manga)\/" android:pathPattern="/title/..*" />
android:scheme="https" />--> <data
android:scheme="https"
android:host="mangadex.org"
android:pathPattern="/title/..*" />
<data
android:scheme="https"
android:host="www.mangadex.cc"
android:pathPattern="/title/..*" />
<data
android:scheme="https"
android:host="www.mangadex.cc"
android:pathPattern="/title/..*" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity <activity
+72 -36
View File
@@ -6,7 +6,6 @@ import android.content.res.Configuration
import android.graphics.Color import android.graphics.Color
import android.os.Build import android.os.Build
import android.os.Environment import android.os.Environment
import android.widget.Toast
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.OnLifecycleEvent import androidx.lifecycle.OnLifecycleEvent
@@ -17,34 +16,29 @@ import com.elvishew.xlog.LogLevel
import com.elvishew.xlog.XLog import com.elvishew.xlog.XLog
import com.elvishew.xlog.printer.AndroidPrinter import com.elvishew.xlog.printer.AndroidPrinter
import com.elvishew.xlog.printer.Printer import com.elvishew.xlog.printer.Printer
import com.elvishew.xlog.printer.file.FilePrinter
import com.elvishew.xlog.printer.file.backup.NeverBackupStrategy import com.elvishew.xlog.printer.file.backup.NeverBackupStrategy
import com.elvishew.xlog.printer.file.clean.FileLastModifiedCleanStrategy import com.elvishew.xlog.printer.file.clean.FileLastModifiedCleanStrategy
import com.elvishew.xlog.printer.file.naming.DateFileNameGenerator import com.elvishew.xlog.printer.file.naming.DateFileNameGenerator
import com.google.android.gms.common.GooglePlayServicesNotAvailableException import com.google.android.gms.common.GooglePlayServicesNotAvailableException
import com.google.android.gms.common.GooglePlayServicesRepairableException import com.google.android.gms.common.GooglePlayServicesRepairableException
import com.google.android.gms.security.ProviderInstaller import com.google.android.gms.security.ProviderInstaller
import com.kizitonwose.time.days import com.google.firebase.analytics.FirebaseAnalytics
import com.google.firebase.analytics.ktx.analytics
import com.google.firebase.ktx.Firebase
import com.ms_square.debugoverlay.DebugOverlay import com.ms_square.debugoverlay.DebugOverlay
import com.ms_square.debugoverlay.modules.FpsModule import com.ms_square.debugoverlay.modules.FpsModule
import eu.kanade.tachiyomi.data.notification.Notifications import eu.kanade.tachiyomi.data.notification.Notifications
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.ui.main.ForceCloseActivity
import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate
import eu.kanade.tachiyomi.util.system.LocaleHelper import eu.kanade.tachiyomi.util.system.LocaleHelper
import eu.kanade.tachiyomi.util.system.WebViewUtil
import eu.kanade.tachiyomi.util.system.toast
import exh.debug.DebugToggles import exh.debug.DebugToggles
import exh.log.CrashlyticsPrinter import exh.log.CrashlyticsPrinter
import exh.log.EHDebugModeOverlay import exh.log.EHDebugModeOverlay
import exh.log.EHLogLevel import exh.log.EHLogLevel
import exh.log.EnhancedFilePrinter
import exh.syDebugVersion
import io.realm.Realm import io.realm.Realm
import io.realm.RealmConfiguration import io.realm.RealmConfiguration
import java.io.File
import java.security.NoSuchAlgorithmException
import java.security.Security
import javax.net.ssl.SSLContext
import kotlin.concurrent.thread
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.conscrypt.Conscrypt import org.conscrypt.Conscrypt
@@ -53,21 +47,36 @@ import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.InjektScope import uy.kohesive.injekt.api.InjektScope
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import uy.kohesive.injekt.registry.default.DefaultRegistrar import uy.kohesive.injekt.registry.default.DefaultRegistrar
import java.io.File
import java.security.NoSuchAlgorithmException
import java.security.Security
import java.text.SimpleDateFormat
import java.util.Locale
import javax.net.ssl.SSLContext
import kotlin.concurrent.thread
import kotlin.time.ExperimentalTime
import kotlin.time.days
open class App : Application(), LifecycleObserver { open class App : Application(), LifecycleObserver {
private lateinit var firebaseAnalytics: FirebaseAnalytics
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
if (BuildConfig.DEBUG) Timber.plant(Timber.DebugTree()) if (BuildConfig.DEBUG) Timber.plant(Timber.DebugTree())
setupExhLogging() // EXH logging setupExhLogging() // EXH logging
if (!BuildConfig.DEBUG) addAnalytics()
workaroundAndroid7BrokenSSL() workaroundAndroid7BrokenSSL()
// Enforce WebView availability // Debug tool; see https://fbflipper.com/
if (!WebViewUtil.supportsWebView(this)) { // SoLoader.init(this, false)
toast(R.string.information_webview_required, Toast.LENGTH_LONG) // if (BuildConfig.DEBUG && FlipperUtils.shouldEnableFlipper(this)) {
ForceCloseActivity.closeApp(this) // val client = AndroidFlipperClient.getInstance(this)
} // client.addPlugin(InspectorFlipperPlugin(this, DescriptorMapping.withDefaults()))
// client.addPlugin(DatabasesFlipperPlugin(this))
// client.start()
// }
// TLS 1.3 support for Android < 10 // TLS 1.3 support for Android < 10
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
@@ -78,8 +87,8 @@ open class App : Application(), LifecycleObserver {
Injekt.importModule(AppModule(this)) Injekt.importModule(AppModule(this))
setupNotificationChannels() setupNotificationChannels()
Realm.init(this)
GlobalScope.launch { deleteOldMetadataRealm() } // Delete old metadata DB (EH) GlobalScope.launch { deleteOldMetadataRealm() } // Delete old metadata DB (EH)
// Reprint.initialize(this) //Setup fingerprint (EH)
if ((BuildConfig.DEBUG || BuildConfig.BUILD_TYPE == "releaseTest") && DebugToggles.ENABLE_DEBUG_OVERLAY.enabled) { if ((BuildConfig.DEBUG || BuildConfig.BUILD_TYPE == "releaseTest") && DebugToggles.ENABLE_DEBUG_OVERLAY.enabled) {
setupDebugOverlay() setupDebugOverlay()
} }
@@ -106,19 +115,26 @@ open class App : Application(), LifecycleObserver {
try { try {
SSLContext.getInstance("TLSv1.2") SSLContext.getInstance("TLSv1.2")
} catch (e: NoSuchAlgorithmException) { } catch (e: NoSuchAlgorithmException) {
XLog.e("Could not install Android 7 broken SSL workaround!", e) XLog.tag("Init").e("Could not install Android 7 broken SSL workaround!", e)
} }
try { try {
ProviderInstaller.installIfNeeded(applicationContext) ProviderInstaller.installIfNeeded(applicationContext)
} catch (e: GooglePlayServicesRepairableException) { } catch (e: GooglePlayServicesRepairableException) {
XLog.e("Could not install Android 7 broken SSL workaround!", e) XLog.tag("Init").e("Could not install Android 7 broken SSL workaround!", e)
} catch (e: GooglePlayServicesNotAvailableException) { } catch (e: GooglePlayServicesNotAvailableException) {
XLog.e("Could not install Android 7 broken SSL workaround!", e) XLog.tag("Init").e("Could not install Android 7 broken SSL workaround!", e)
} }
} }
} }
private fun addAnalytics() {
firebaseAnalytics = Firebase.analytics
if (syDebugVersion != "0") {
firebaseAnalytics.setUserProperty("preview_version", syDebugVersion)
}
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP) @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
@Suppress("unused") @Suppress("unused")
fun onAppBackgrounded() { fun onAppBackgrounded() {
@@ -134,7 +150,6 @@ open class App : Application(), LifecycleObserver {
// EXH // EXH
private fun deleteOldMetadataRealm() { private fun deleteOldMetadataRealm() {
Realm.init(this)
val config = RealmConfiguration.Builder() val config = RealmConfiguration.Builder()
.name("gallery-metadata.realm") .name("gallery-metadata.realm")
.schemaVersion(3) .schemaVersion(3)
@@ -160,17 +175,16 @@ open class App : Application(), LifecycleObserver {
private fun setupExhLogging() { private fun setupExhLogging() {
EHLogLevel.init(this) EHLogLevel.init(this)
val logLevel = if (EHLogLevel.shouldLog(EHLogLevel.EXTRA)) { val logLevel = when {
LogLevel.ALL EHLogLevel.shouldLog(EHLogLevel.EXTRA) -> LogLevel.ALL
} else { BuildConfig.DEBUG -> LogLevel.DEBUG
LogLevel.WARN else -> LogLevel.WARN
} }
val logConfig = LogConfiguration.Builder() val logConfig = LogConfiguration.Builder()
.logLevel(logLevel) .logLevel(logLevel)
.t() .disableStackTrace()
.st(2) .disableBorder()
.nb()
.build() .build()
val printers = mutableListOf<Printer>(AndroidPrinter()) val printers = mutableListOf<Printer>(AndroidPrinter())
@@ -181,14 +195,25 @@ open class App : Application(), LifecycleObserver {
"logs" "logs"
) )
printers += FilePrinter val dateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.getDefault())
@OptIn(ExperimentalTime::class)
printers += EnhancedFilePrinter
.Builder(logFolder.absolutePath) .Builder(logFolder.absolutePath)
.fileNameGenerator(object : DateFileNameGenerator() { .fileNameGenerator(
override fun generateFileName(logLevel: Int, timestamp: Long): String { object : DateFileNameGenerator() {
return super.generateFileName(logLevel, timestamp) + "-${BuildConfig.BUILD_TYPE}" override fun generateFileName(logLevel: Int, timestamp: Long): String {
return super.generateFileName(
logLevel,
timestamp
) + "-${BuildConfig.BUILD_TYPE}.log"
}
} }
}) )
.cleanStrategy(FileLastModifiedCleanStrategy(7.days.inMilliseconds.longValue)) .flattener { timeMillis, level, tag, message ->
"${dateFormat.format(timeMillis)} ${LogLevel.getShortLevelName(level)}/$tag: $message"
}
.cleanStrategy(FileLastModifiedCleanStrategy(7.days.toLongMilliseconds()))
.backupStrategy(NeverBackupStrategy()) .backupStrategy(NeverBackupStrategy())
.build() .build()
@@ -202,7 +227,18 @@ open class App : Application(), LifecycleObserver {
*printers.toTypedArray() *printers.toTypedArray()
) )
XLog.d("Application booting...") XLog.tag("Init").d("Application booting...")
XLog.tag("Init").disableStackTrace().d(
"App version: ${BuildConfig.VERSION_NAME} (${BuildConfig.FLAVOR}, ${BuildConfig.COMMIT_SHA}, ${BuildConfig.VERSION_CODE})\n" +
"Preview build: $syDebugVersion\n" +
"Android version: ${Build.VERSION.RELEASE} (SDK ${Build.VERSION.SDK_INT}) \n" +
"Android build ID: ${Build.DISPLAY}\n" +
"Device brand: ${Build.BRAND}\n" +
"Device manufacturer: ${Build.MANUFACTURER}\n" +
"Device name: ${Build.DEVICE}\n" +
"Device model: ${Build.MODEL}\n" +
"Device product name: ${Build.PRODUCT}"
)
} }
// EXH // EXH
@@ -217,7 +253,7 @@ open class App : Application(), LifecycleObserver {
.install() .install()
} catch (e: IllegalStateException) { } catch (e: IllegalStateException) {
// Crashes if app is in background // Crashes if app is in background
XLog.e("Failed to initialize debug overlay, app in background?", e) XLog.tag("Init").e("Failed to initialize debug overlay, app in background?", e)
} }
} }
} }
@@ -6,15 +6,16 @@ import eu.kanade.tachiyomi.data.cache.ChapterCache
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.download.DownloadManager import eu.kanade.tachiyomi.data.download.DownloadManager
import eu.kanade.tachiyomi.data.library.CustomMangaManager
import eu.kanade.tachiyomi.data.preference.PreferencesHelper 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.extension.ExtensionManager import eu.kanade.tachiyomi.extension.ExtensionManager
import eu.kanade.tachiyomi.network.NetworkHelper import eu.kanade.tachiyomi.network.NetworkHelper
import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.source.SourceManager
import exh.eh.EHentaiUpdateHelper import exh.eh.EHentaiUpdateHelper
import io.noties.markwon.Markwon
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.serialization.json.Json
import uy.kohesive.injekt.api.InjektModule import uy.kohesive.injekt.api.InjektModule
import uy.kohesive.injekt.api.InjektRegistrar import uy.kohesive.injekt.api.InjektRegistrar
import uy.kohesive.injekt.api.addSingleton import uy.kohesive.injekt.api.addSingleton
@@ -46,10 +47,12 @@ class AppModule(val app: Application) : InjektModule {
addSingletonFactory { Gson() } addSingletonFactory { Gson() }
// SY --> addSingletonFactory { Json { ignoreUnknownKeys = true } }
addSingletonFactory { EHentaiUpdateHelper(app) }
addSingletonFactory { Markwon.create(app) } // SY -->
addSingletonFactory { CustomMangaManager(app) }
addSingletonFactory { EHentaiUpdateHelper(app) }
// SY <-- // SY <--
// Asynchronously init expensive components for a faster cold start // Asynchronously init expensive components for a faster cold start
@@ -63,5 +66,9 @@ class AppModule(val app: Application) : InjektModule {
GlobalScope.launch { get<DatabaseHelper>() } GlobalScope.launch { get<DatabaseHelper>() }
GlobalScope.launch { get<DownloadManager>() } GlobalScope.launch { get<DownloadManager>() }
// SY -->
GlobalScope.launch { get<CustomMangaManager>() }
// SY <--
} }
} }
@@ -1,11 +1,18 @@
package eu.kanade.tachiyomi package eu.kanade.tachiyomi
import androidx.core.content.edit
import androidx.preference.PreferenceManager
import eu.kanade.tachiyomi.data.backup.BackupCreatorJob import eu.kanade.tachiyomi.data.backup.BackupCreatorJob
import eu.kanade.tachiyomi.data.library.LibraryUpdateJob import eu.kanade.tachiyomi.data.library.LibraryUpdateJob
import eu.kanade.tachiyomi.data.preference.PreferenceKeys
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.track.TrackManager
import eu.kanade.tachiyomi.data.updater.UpdaterJob import eu.kanade.tachiyomi.data.updater.UpdaterJob
import eu.kanade.tachiyomi.extension.ExtensionUpdateJob import eu.kanade.tachiyomi.extension.ExtensionUpdateJob
import eu.kanade.tachiyomi.ui.library.LibrarySort import eu.kanade.tachiyomi.ui.library.LibrarySort
import eu.kanade.tachiyomi.widget.ExtendedNavigationView
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import java.io.File import java.io.File
object Migrations { object Migrations {
@@ -20,13 +27,13 @@ object Migrations {
*/ */
fun upgrade(preferences: PreferencesHelper): Boolean { fun upgrade(preferences: PreferencesHelper): Boolean {
val context = preferences.context val context = preferences.context
val oldVersion = preferences.lastVersionCode().get()
// Cancel app updater job for debug builds that don't include it // Cancel app updater job for debug builds that don't include it
if (BuildConfig.DEBUG && !BuildConfig.INCLUDE_UPDATER) { if (BuildConfig.DEBUG && !BuildConfig.INCLUDE_UPDATER) {
UpdaterJob.cancelTask(context) UpdaterJob.cancelTask(context)
} }
val oldVersion = preferences.lastVersionCode().get()
if (oldVersion < BuildConfig.VERSION_CODE) { if (oldVersion < BuildConfig.VERSION_CODE) {
preferences.lastVersionCode().set(BuildConfig.VERSION_CODE) preferences.lastVersionCode().set(BuildConfig.VERSION_CODE)
@@ -87,12 +94,37 @@ object Migrations {
} }
if (oldVersion < 44) { if (oldVersion < 44) {
// Reset sorting preference if using removed sort by source // Reset sorting preference if using removed sort by source
@Suppress("DEPRECATION")
if (preferences.librarySortingMode().get() == LibrarySort.SOURCE) { if (preferences.librarySortingMode().get() == LibrarySort.SOURCE) {
preferences.librarySortingMode().set(LibrarySort.ALPHA) preferences.librarySortingMode().set(LibrarySort.ALPHA)
} }
} }
if (oldVersion < 52) {
// Migrate library filters to tri-state versions
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
fun convertBooleanPrefToTriState(key: String): Int {
val oldPrefValue = prefs.getBoolean(key, false)
return if (oldPrefValue) ExtendedNavigationView.Item.TriStateGroup.State.INCLUDE.value
else ExtendedNavigationView.Item.TriStateGroup.State.IGNORE.value
}
prefs.edit {
putInt(PreferenceKeys.filterDownloaded, convertBooleanPrefToTriState("pref_filter_downloaded_key"))
remove("pref_filter_downloaded_key")
putInt(PreferenceKeys.filterUnread, convertBooleanPrefToTriState("pref_filter_unread_key"))
remove("pref_filter_unread_key")
putInt(PreferenceKeys.filterCompleted, convertBooleanPrefToTriState("pref_filter_completed_key"))
remove("pref_filter_completed_key")
}
// Force MAL log out due to login flow change
val trackManager = Injekt.get<TrackManager>()
trackManager.myAnimeList.logout()
}
return true return true
} }
return false return false
} }
} }
@@ -0,0 +1,5 @@
package eu.kanade.tachiyomi.annotations
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.CLASS)
annotation class Nsfw
@@ -0,0 +1,107 @@
package eu.kanade.tachiyomi.data.backup
import android.content.Context
import android.net.Uri
import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.models.Chapter
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.track.TrackManager
import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.source.online.all.EHentai
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
import exh.eh.EHentaiThrottleManager
import rx.Observable
import uy.kohesive.injekt.injectLazy
abstract class AbstractBackupManager(protected val context: Context) {
internal val databaseHelper: DatabaseHelper by injectLazy()
internal val sourceManager: SourceManager by injectLazy()
internal val trackManager: TrackManager by injectLazy()
protected val preferences: PreferencesHelper by injectLazy()
abstract fun createBackup(uri: Uri, flags: Int, isJob: Boolean): String?
/**
* Returns manga
*
* @return [Manga], null if not found
*/
internal fun getMangaFromDatabase(manga: Manga): Manga? =
databaseHelper.getManga(manga.url, manga.source).executeAsBlocking()
/**
* [Observable] that fetches chapter information
*
* @param source source of manga
* @param manga manga that needs updating
* @param chapters list of chapters in the backup
* @return [Observable] that contains manga
*/
internal open fun restoreChapterFetchObservable(source: Source, manga: Manga, chapters: List<Chapter>, throttleManager: EHentaiThrottleManager): Observable<Pair<List<Chapter>, List<Chapter>>> {
return (
if (source is EHentai) {
source.fetchChapterList(manga, throttleManager::throttle)
} else {
source.fetchChapterList(manga)
}
).map {
syncChaptersWithSource(databaseHelper, it, manga, source)
}
.doOnNext { (first) ->
if (first.isNotEmpty()) {
chapters.forEach { it.manga_id = manga.id }
updateChapters(chapters)
}
}
}
/**
* Returns list containing manga from library
*
* @return [Manga] from library
*/
protected fun getFavoriteManga(): List<Manga> =
databaseHelper.getFavoriteMangas().executeAsBlocking()
// SY -->
/**
* Returns list containing merged manga that are possibly not in the library
*
* @return merged [Manga] that are possibly not in the library
*/
protected fun getMergedManga(): List<Manga> =
databaseHelper.getMergedMangas().executeAsBlocking()
// SY <--
/**
* Inserts manga and returns id
*
* @return id of [Manga], null if not found
*/
internal fun insertManga(manga: Manga): Long? =
databaseHelper.insertManga(manga).executeAsBlocking().insertedId()
/**
* Inserts list of chapters
*/
protected fun insertChapters(chapters: List<Chapter>) {
databaseHelper.insertChapters(chapters).executeAsBlocking()
}
/**
* Updates a list of chapters
*/
protected fun updateChapters(chapters: List<Chapter>) {
databaseHelper.updateChaptersBackup(chapters).executeAsBlocking()
}
/**
* Return number of backups.
*
* @return number of backups selected by user
*/
protected fun numberOfBackups(): Int = preferences.numberOfBackups().get()
}
@@ -0,0 +1,143 @@
package eu.kanade.tachiyomi.data.backup
import android.content.Context
import android.net.Uri
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.models.Chapter
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.database.models.Track
import eu.kanade.tachiyomi.data.track.TrackManager
import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.util.chapter.NoChaptersException
import exh.eh.EHentaiThrottleManager
import kotlinx.coroutines.Job
import rx.Observable
import uy.kohesive.injekt.injectLazy
import java.io.File
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
abstract class AbstractBackupRestore<T : AbstractBackupManager>(protected val context: Context, protected val notifier: BackupNotifier) {
protected val db: DatabaseHelper by injectLazy()
protected val trackManager: TrackManager by injectLazy()
var job: Job? = null
protected lateinit var backupManager: T
protected var restoreAmount = 0
protected var restoreProgress = 0
// SY -->
protected val throttleManager = EHentaiThrottleManager()
// SY <--
/**
* Mapping of source ID to source name from backup data
*/
protected var sourceMapping: Map<Long, String> = emptyMap()
protected val errors = mutableListOf<Pair<Date, String>>()
abstract fun performRestore(uri: Uri): Boolean
fun restoreBackup(uri: Uri): Boolean {
val startTime = System.currentTimeMillis()
restoreProgress = 0
errors.clear()
if (!performRestore(uri)) {
return false
}
val endTime = System.currentTimeMillis()
val time = endTime - startTime
val logFile = writeErrorLog()
notifier.showRestoreComplete(time, errors.size, logFile.parent, logFile.name)
return true
}
/**
* [Observable] that fetches chapter information
*
* @param source source of manga
* @param manga manga that needs updating
* @return [Observable] that contains manga
*/
internal fun chapterFetchObservable(source: Source, manga: Manga, chapters: List<Chapter>): Observable<Pair<List<Chapter>, List<Chapter>>> {
return backupManager.restoreChapterFetchObservable(source, manga, chapters /* SY --> */, throttleManager /* SY <-- */)
// If there's any error, return empty update and continue.
.onErrorReturn {
val errorMessage = if (it is NoChaptersException) {
context.getString(R.string.no_chapters_error)
} else {
it.message
}
errors.add(Date() to "${manga.title} - $errorMessage")
Pair(emptyList(), emptyList())
}
}
/**
* [Observable] that refreshes tracking information
* @param manga manga that needs updating.
* @param tracks list containing tracks from restore file.
* @return [Observable] that contains updated track item
*/
internal fun trackingFetchObservable(manga: Manga, tracks: List<Track>): Observable<Track> {
return Observable.from(tracks)
.flatMap { track ->
val service = trackManager.getService(track.sync_id)
if (service != null && service.isLogged) {
service.refresh(track)
.doOnNext { db.insertTrack(it).executeAsBlocking() }
.onErrorReturn {
errors.add(Date() to "${manga.title} - ${it.message}")
track
}
} else {
errors.add(Date() to "${manga.title} - ${context.getString(R.string.tracker_not_logged_in, service?.name)}")
Observable.empty()
}
}
}
/**
* Called to update dialog in [BackupConst]
*
* @param progress restore progress
* @param amount total restoreAmount of manga
* @param title title of restored manga
*/
internal fun showRestoreProgress(
progress: Int,
amount: Int,
title: String
) {
notifier.showRestoreProgress(title, progress, amount)
}
internal fun writeErrorLog(): File {
try {
if (errors.isNotEmpty()) {
val destFile = File(context.externalCacheDir, "tachiyomi_restore.txt")
val sdf = SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.getDefault())
destFile.bufferedWriter().use { out ->
errors.forEach { (date, message) ->
out.write("[${sdf.format(date)}] $message\n")
}
}
return destFile
}
} catch (e: Exception) {
// Empty
}
return File("")
}
}
@@ -0,0 +1,16 @@
package eu.kanade.tachiyomi.data.backup
import android.content.Context
import android.net.Uri
import eu.kanade.tachiyomi.data.track.TrackManager
import eu.kanade.tachiyomi.source.SourceManager
import uy.kohesive.injekt.injectLazy
abstract class AbstractBackupRestoreValidator {
protected val sourceManager: SourceManager by injectLazy()
protected val trackManager: TrackManager by injectLazy()
abstract fun validate(context: Context, uri: Uri): Results
data class Results(val missingSources: List<String>, val missingTrackers: List<String>)
}
@@ -7,4 +7,9 @@ object BackupConst {
private const val NAME = "BackupRestoreServices" private const val NAME = "BackupRestoreServices"
const val EXTRA_URI = "$ID.$NAME.EXTRA_URI" const val EXTRA_URI = "$ID.$NAME.EXTRA_URI"
const val EXTRA_FLAGS = "$ID.$NAME.EXTRA_FLAGS" const val EXTRA_FLAGS = "$ID.$NAME.EXTRA_FLAGS"
const val EXTRA_MODE = "$ID.$NAME.EXTRA_MODE"
const val EXTRA_TYPE = "$ID.$NAME.EXTRA_TYPE"
const val BACKUP_TYPE_LEGACY = 0
const val BACKUP_TYPE_FULL = 1
} }
@@ -4,10 +4,13 @@ import android.app.Service
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
import android.os.Build
import android.os.IBinder import android.os.IBinder
import android.os.PowerManager import android.os.PowerManager
import androidx.core.content.ContextCompat
import androidx.core.net.toUri
import com.hippo.unifile.UniFile import com.hippo.unifile.UniFile
import eu.kanade.tachiyomi.data.backup.full.FullBackupManager
import eu.kanade.tachiyomi.data.backup.legacy.LegacyBackupManager
import eu.kanade.tachiyomi.data.notification.Notifications import eu.kanade.tachiyomi.data.notification.Notifications
import eu.kanade.tachiyomi.util.system.acquireWakeLock import eu.kanade.tachiyomi.util.system.acquireWakeLock
import eu.kanade.tachiyomi.util.system.isServiceRunning import eu.kanade.tachiyomi.util.system.isServiceRunning
@@ -45,17 +48,14 @@ class BackupCreateService : Service() {
* @param uri path of Uri * @param uri path of Uri
* @param flags determines what to backup * @param flags determines what to backup
*/ */
fun start(context: Context, uri: Uri, flags: Int) { fun start(context: Context, uri: Uri, flags: Int, type: Int) {
if (!isRunning(context)) { if (!isRunning(context)) {
val intent = Intent(context, BackupCreateService::class.java).apply { val intent = Intent(context, BackupCreateService::class.java).apply {
putExtra(BackupConst.EXTRA_URI, uri) putExtra(BackupConst.EXTRA_URI, uri)
putExtra(BackupConst.EXTRA_FLAGS, flags) putExtra(BackupConst.EXTRA_FLAGS, flags)
putExtra(BackupConst.EXTRA_TYPE, type)
} }
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { ContextCompat.startForegroundService(context, intent)
context.startService(intent)
} else {
context.startForegroundService(intent)
}
} }
} }
} }
@@ -65,7 +65,6 @@ class BackupCreateService : Service() {
*/ */
private lateinit var wakeLock: PowerManager.WakeLock private lateinit var wakeLock: PowerManager.WakeLock
private lateinit var backupManager: BackupManager
private lateinit var notifier: BackupNotifier private lateinit var notifier: BackupNotifier
override fun onCreate() { override fun onCreate() {
@@ -104,9 +103,13 @@ class BackupCreateService : Service() {
try { try {
val uri = intent.getParcelableExtra<Uri>(BackupConst.EXTRA_URI) val uri = intent.getParcelableExtra<Uri>(BackupConst.EXTRA_URI)
val backupFlags = intent.getIntExtra(BackupConst.EXTRA_FLAGS, 0) val backupFlags = intent.getIntExtra(BackupConst.EXTRA_FLAGS, 0)
backupManager = BackupManager(this) val backupType = intent.getIntExtra(BackupConst.EXTRA_TYPE, BackupConst.BACKUP_TYPE_LEGACY)
val backupManager = when (backupType) {
BackupConst.BACKUP_TYPE_FULL -> FullBackupManager(this)
else -> LegacyBackupManager(this)
}
val backupFileUri = Uri.parse(backupManager.createBackup(uri, backupFlags, false)) val backupFileUri = backupManager.createBackup(uri, backupFlags, false)?.toUri()
val unifile = UniFile.fromUri(this, backupFileUri) val unifile = UniFile.fromUri(this, backupFileUri)
notifier.showBackupComplete(unifile) notifier.showBackupComplete(unifile)
} catch (e: Exception) { } catch (e: Exception) {
@@ -1,27 +1,31 @@
package eu.kanade.tachiyomi.data.backup package eu.kanade.tachiyomi.data.backup
import android.content.Context import android.content.Context
import android.net.Uri import androidx.core.net.toUri
import androidx.work.ExistingPeriodicWorkPolicy import androidx.work.ExistingPeriodicWorkPolicy
import androidx.work.PeriodicWorkRequestBuilder 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.backup.full.FullBackupManager
import eu.kanade.tachiyomi.data.backup.legacy.LegacyBackupManager
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import java.util.concurrent.TimeUnit
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import java.util.concurrent.TimeUnit
class BackupCreatorJob(private val context: Context, workerParams: WorkerParameters) : class BackupCreatorJob(private val context: Context, workerParams: WorkerParameters) :
Worker(context, workerParams) { Worker(context, workerParams) {
override fun doWork(): Result { override fun doWork(): Result {
val preferences = Injekt.get<PreferencesHelper>() val preferences = Injekt.get<PreferencesHelper>()
val backupManager = BackupManager(context) val uri = preferences.backupsDirectory().get().toUri()
val uri = Uri.parse(preferences.backupsDirectory().get())
val flags = BackupCreateService.BACKUP_ALL val flags = BackupCreateService.BACKUP_ALL
return try { return try {
backupManager.createBackup(uri, flags, true) FullBackupManager(context).createBackup(uri, flags, true)
if (preferences.createLegacyBackup().get()) {
LegacyBackupManager(context).createBackup(uri, flags, true)
}
Result.success() Result.success()
} catch (e: Exception) { } catch (e: Exception) {
Result.failure() Result.failure()
@@ -36,8 +40,10 @@ class BackupCreatorJob(private val context: Context, workerParams: WorkerParamet
val interval = prefInterval ?: preferences.backupInterval().get() val interval = prefInterval ?: preferences.backupInterval().get()
if (interval > 0) { if (interval > 0) {
val request = PeriodicWorkRequestBuilder<BackupCreatorJob>( val request = PeriodicWorkRequestBuilder<BackupCreatorJob>(
interval.toLong(), TimeUnit.HOURS, interval.toLong(),
10, TimeUnit.MINUTES TimeUnit.HOURS,
10,
TimeUnit.MINUTES
) )
.addTag(TAG) .addTag(TAG)
.build() .build()
@@ -11,11 +11,11 @@ import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.util.storage.getUriCompat import eu.kanade.tachiyomi.util.storage.getUriCompat
import eu.kanade.tachiyomi.util.system.notificationBuilder import eu.kanade.tachiyomi.util.system.notificationBuilder
import eu.kanade.tachiyomi.util.system.notificationManager import eu.kanade.tachiyomi.util.system.notificationManager
import uy.kohesive.injekt.injectLazy
import java.io.File import java.io.File
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import uy.kohesive.injekt.injectLazy
internal class BackupNotifier(private val context: Context) { class BackupNotifier(private val context: Context) {
private val preferences: PreferencesHelper by injectLazy() private val preferences: PreferencesHelper by injectLazy()
@@ -65,10 +65,7 @@ internal class BackupNotifier(private val context: Context) {
with(completeNotificationBuilder) { with(completeNotificationBuilder) {
setContentTitle(context.getString(R.string.backup_created)) setContentTitle(context.getString(R.string.backup_created))
setContentText(unifile.filePath ?: unifile.name)
if (unifile.filePath != null) {
setContentText(unifile.filePath)
}
// Clear old actions if they exist // Clear old actions if they exist
if (mActions.isNotEmpty()) { if (mActions.isNotEmpty()) {
@@ -4,53 +4,22 @@ import android.app.Service
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
import android.os.Build
import android.os.IBinder import android.os.IBinder
import android.os.PowerManager import android.os.PowerManager
import com.github.salomonbrys.kotson.fromJson import androidx.core.content.ContextCompat
import com.google.gson.JsonArray
import com.google.gson.JsonElement
import com.google.gson.JsonObject
import com.google.gson.JsonParser
import com.google.gson.stream.JsonReader
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.backup.models.Backup.CATEGORIES import eu.kanade.tachiyomi.data.backup.full.FullBackupRestore
import eu.kanade.tachiyomi.data.backup.models.Backup.CHAPTERS import eu.kanade.tachiyomi.data.backup.legacy.LegacyBackupRestore
import eu.kanade.tachiyomi.data.backup.models.Backup.HISTORY
import eu.kanade.tachiyomi.data.backup.models.Backup.MANGA
import eu.kanade.tachiyomi.data.backup.models.Backup.MANGAS
import eu.kanade.tachiyomi.data.backup.models.Backup.SAVEDSEARCHES
import eu.kanade.tachiyomi.data.backup.models.Backup.TRACK
import eu.kanade.tachiyomi.data.backup.models.Backup.VERSION
import eu.kanade.tachiyomi.data.backup.models.DHistory
import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.models.Chapter
import eu.kanade.tachiyomi.data.database.models.ChapterImpl
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.database.models.MangaImpl
import eu.kanade.tachiyomi.data.database.models.Track
import eu.kanade.tachiyomi.data.database.models.TrackImpl
import eu.kanade.tachiyomi.data.notification.Notifications import eu.kanade.tachiyomi.data.notification.Notifications
import eu.kanade.tachiyomi.data.track.TrackManager
import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.util.system.acquireWakeLock import eu.kanade.tachiyomi.util.system.acquireWakeLock
import eu.kanade.tachiyomi.util.system.isServiceRunning import eu.kanade.tachiyomi.util.system.isServiceRunning
import exh.EXHMigrations
import exh.eh.EHentaiThrottleManager
import java.io.File
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
import kotlinx.coroutines.CoroutineExceptionHandler import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import rx.Observable
import timber.log.Timber import timber.log.Timber
import uy.kohesive.injekt.injectLazy
/** /**
* Restores backup from a JSON file. * Restores backup.
*/ */
class BackupRestoreService : Service() { class BackupRestoreService : Service() {
@@ -71,16 +40,14 @@ class BackupRestoreService : Service() {
* @param context context of application * @param context context of application
* @param uri path of Uri * @param uri path of Uri
*/ */
fun start(context: Context, uri: Uri) { fun start(context: Context, uri: Uri, mode: Int, online: Boolean?) {
if (!isRunning(context)) { if (!isRunning(context)) {
val intent = Intent(context, BackupRestoreService::class.java).apply { val intent = Intent(context, BackupRestoreService::class.java).apply {
putExtra(BackupConst.EXTRA_URI, uri) putExtra(BackupConst.EXTRA_URI, uri)
putExtra(BackupConst.EXTRA_MODE, mode)
online?.let { putExtra(BackupConst.EXTRA_TYPE, it) }
} }
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { ContextCompat.startForegroundService(context, intent)
context.startService(intent)
} else {
context.startForegroundService(intent)
}
} }
} }
@@ -101,45 +68,9 @@ class BackupRestoreService : Service() {
*/ */
private lateinit var wakeLock: PowerManager.WakeLock private lateinit var wakeLock: PowerManager.WakeLock
private var job: Job? = null private var backupRestore: AbstractBackupRestore<*>? = null
// SY -->
private val throttleManager = EHentaiThrottleManager()
// SY <--
/**
* The progress of a backup restore
*/
private var restoreProgress = 0
/**
* Amount of manga in Json file (needed for restore)
*/
private var restoreAmount = 0
// SY -->
private var skippedAmount = 0
private var totalAmount = 0
// SY <--
/**
* Mapping of source ID to source name from backup data
*/
private var sourceMapping: Map<Long, String> = emptyMap()
/**
* List containing errors
*/
private val errors = mutableListOf<Pair<Date, String>>()
private lateinit var backupManager: BackupManager
private lateinit var notifier: BackupNotifier private lateinit var notifier: BackupNotifier
private val db: DatabaseHelper by injectLazy()
private val trackManager: TrackManager by injectLazy()
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
@@ -160,7 +91,7 @@ class BackupRestoreService : Service() {
} }
private fun destroyJob() { private fun destroyJob() {
job?.cancel() backupRestore?.job?.cancel()
if (wakeLock.isHeld) { if (wakeLock.isHeld) {
wakeLock.release() wakeLock.release()
} }
@@ -181,340 +112,32 @@ class BackupRestoreService : Service() {
*/ */
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
val uri = intent?.getParcelableExtra<Uri>(BackupConst.EXTRA_URI) ?: return START_NOT_STICKY val uri = intent?.getParcelableExtra<Uri>(BackupConst.EXTRA_URI) ?: return START_NOT_STICKY
val mode = intent.getIntExtra(BackupConst.EXTRA_MODE, BackupConst.BACKUP_TYPE_FULL)
// SY --> val online = intent.getBooleanExtra(BackupConst.EXTRA_TYPE, true)
throttleManager.resetThrottle()
// SY <--
// Cancel any previous job if needed. // Cancel any previous job if needed.
job?.cancel() backupRestore?.job?.cancel()
backupRestore = when (mode) {
BackupConst.BACKUP_TYPE_FULL -> FullBackupRestore(this, notifier, online)
else -> LegacyBackupRestore(this, notifier)
}
val handler = CoroutineExceptionHandler { _, exception -> val handler = CoroutineExceptionHandler { _, exception ->
Timber.e(exception) Timber.e(exception)
writeErrorLog() backupRestore?.writeErrorLog()
notifier.showRestoreError(exception.message) notifier.showRestoreError(exception.message)
stopSelf(startId) stopSelf(startId)
} }
job = GlobalScope.launch(handler) { backupRestore?.job = GlobalScope.launch(handler) {
if (!restoreBackup(uri)) { if (backupRestore?.restoreBackup(uri) == false) {
notifier.showRestoreError(getString(R.string.restoring_backup_canceled)) notifier.showRestoreError(getString(R.string.restoring_backup_canceled))
} }
} }
job?.invokeOnCompletion { backupRestore?.job?.invokeOnCompletion {
stopSelf(startId) stopSelf(startId)
} }
return START_NOT_STICKY return START_NOT_STICKY
} }
/**
* Restores data from backup file.
*
* @param uri backup file to restore
*/
private fun restoreBackup(uri: Uri): Boolean {
val startTime = System.currentTimeMillis()
val reader = JsonReader(contentResolver.openInputStream(uri)!!.bufferedReader())
val json = JsonParser.parseReader(reader).asJsonObject
// Get parser version
val version = json.get(VERSION)?.asInt ?: 1
// Initialize manager
backupManager = BackupManager(this, version)
val mangasJson = json.get(MANGAS).asJsonArray
// SY -->
val validManga = mangasJson.filter {
var manga = backupManager.parser.fromJson<MangaImpl>(it.asJsonObject.get(MANGA))
// EXH -->
manga = EXHMigrations.migrateBackupEntry(manga)
val sourced = backupManager.sourceManager.get(manga.source) != null
if (!sourced) {
restoreAmount -= 1
}
sourced
}
totalAmount = mangasJson.size()
restoreAmount = validManga.count() + 1 // +1 for categories
skippedAmount = mangasJson.size() - validManga.count()
// SY <--
restoreProgress = 0
errors.clear()
// Restore categories
json.get(CATEGORIES)?.let { restoreCategories(it) }
// SY -->
json.get(SAVEDSEARCHES)?.let { restoreSavedSearches(it) }
// SY <--
// Store source mapping for error messages
sourceMapping = BackupRestoreValidator.getSourceMapping(json)
// Restore individual manga
mangasJson.forEach {
if (job?.isActive != true) {
return false
}
restoreManga(it.asJsonObject)
}
val endTime = System.currentTimeMillis()
val time = endTime - startTime
val logFile = writeErrorLog()
notifier.showRestoreComplete(time, errors.size, logFile.parent, logFile.name)
return true
}
private fun restoreCategories(categoriesJson: JsonElement) {
db.inTransaction {
backupManager.restoreCategories(categoriesJson.asJsonArray)
}
restoreProgress += 1
showRestoreProgress(restoreProgress, restoreAmount, getString(R.string.categories))
}
// SY -->
private fun restoreSavedSearches(savedSearchesJson: JsonElement) {
backupManager.restoreSavedSearches(savedSearchesJson)
restoreProgress += 1
showRestoreProgress(restoreProgress, restoreAmount, getString(R.string.eh_saved_searches))
}
// SY <--
private fun restoreManga(mangaJson: JsonObject) {
/* SY --> */ var /* SY <-- */ manga = backupManager.parser.fromJson<MangaImpl>(mangaJson.get(MANGA))
val chapters = backupManager.parser.fromJson<List<ChapterImpl>>(
mangaJson.get(CHAPTERS)
?: JsonArray()
)
val categories = backupManager.parser.fromJson<List<String>>(
mangaJson.get(CATEGORIES)
?: JsonArray()
)
val history = backupManager.parser.fromJson<List<DHistory>>(
mangaJson.get(HISTORY)
?: JsonArray()
)
val tracks = backupManager.parser.fromJson<List<TrackImpl>>(
mangaJson.get(TRACK)
?: JsonArray()
)
// EXH -->
manga = EXHMigrations.migrateBackupEntry(manga)
// <-- EXH
try {
val source = backupManager.sourceManager.get(manga.source)
if (source != null) {
restoreMangaData(manga, source, chapters, categories, history, tracks)
} else {
val message = if (manga.source in sourceMapping) {
getString(R.string.source_not_found_name, sourceMapping[manga.source])
} else {
getString(R.string.source_not_found)
}
errors.add(Date() to "${manga.title} - $message")
}
} catch (e: Exception) {
errors.add(Date() to "${manga.title} - ${e.message}")
}
restoreProgress += 1
showRestoreProgress(restoreProgress, restoreAmount, manga.title)
}
/**
* Returns a manga restore observable
*
* @param manga manga data from json
* @param source source to get manga data from
* @param chapters chapters data from json
* @param categories categories data from json
* @param history history data from json
* @param tracks tracking data from json
*/
private fun restoreMangaData(
manga: Manga,
source: Source,
chapters: List<Chapter>,
categories: List<String>,
history: List<DHistory>,
tracks: List<Track>
) {
val dbManga = backupManager.getMangaFromDatabase(manga)
db.inTransaction {
if (dbManga == null) {
// Manga not in database
restoreMangaFetch(source, manga, chapters, categories, history, tracks)
} else { // Manga in database
// Copy information from manga already in database
backupManager.restoreMangaNoFetch(manga, dbManga)
// Fetch rest of manga information
restoreMangaNoFetch(source, manga, chapters, categories, history, tracks)
}
}
}
/**
* [Observable] that fetches manga information
*
* @param manga manga that needs updating
* @param chapters chapters of manga that needs updating
* @param categories categories that need updating
*/
private fun restoreMangaFetch(
source: Source,
manga: Manga,
chapters: List<Chapter>,
categories: List<String>,
history: List<DHistory>,
tracks: List<Track>
) {
backupManager.restoreMangaFetchObservable(source, manga)
.onErrorReturn {
errors.add(Date() to "${manga.title} - ${it.message}")
manga
}
.filter { it.id != null }
.flatMap {
chapterFetchObservable(source, it, chapters)
// Convert to the manga that contains new chapters.
.map { manga }
}
.doOnNext {
restoreExtraForManga(it, categories, history, tracks)
}
.flatMap {
trackingFetchObservable(it, tracks)
}
.subscribe()
}
private fun restoreMangaNoFetch(
source: Source,
backupManga: Manga,
chapters: List<Chapter>,
categories: List<String>,
history: List<DHistory>,
tracks: List<Track>
) {
Observable.just(backupManga)
.flatMap { manga ->
if (!backupManager.restoreChaptersForManga(manga, chapters)) {
chapterFetchObservable(source, manga, chapters)
.map { manga }
} else {
Observable.just(manga)
}
}
.doOnNext {
restoreExtraForManga(it, categories, history, tracks)
}
.flatMap { manga ->
trackingFetchObservable(manga, tracks)
}
.subscribe()
}
private fun restoreExtraForManga(manga: Manga, categories: List<String>, history: List<DHistory>, tracks: List<Track>) {
// Restore categories
backupManager.restoreCategoriesForManga(manga, categories)
// Restore history
backupManager.restoreHistoryForManga(history)
// Restore tracking
backupManager.restoreTrackForManga(manga, tracks)
}
/**
* [Observable] that fetches chapter information
*
* @param source source of manga
* @param manga manga that needs updating
* @return [Observable] that contains manga
*/
private fun chapterFetchObservable(source: Source, manga: Manga, chapters: List<Chapter>): Observable<Pair<List<Chapter>, List<Chapter>>> {
return backupManager.restoreChapterFetchObservable(source, manga, chapters /* SY --> */, throttleManager /* SY <-- */)
// If there's any error, return empty update and continue.
.onErrorReturn {
errors.add(Date() to "${manga.title} - ${it.message}")
Pair(emptyList(), emptyList())
}
}
/**
* [Observable] that refreshes tracking information
* @param manga manga that needs updating.
* @param tracks list containing tracks from restore file.
* @return [Observable] that contains updated track item
*/
private fun trackingFetchObservable(manga: Manga, tracks: List<Track>): Observable<Track> {
return Observable.from(tracks)
.flatMap { track ->
val service = trackManager.getService(track.sync_id)
if (service != null && service.isLogged) {
service.refresh(track)
.doOnNext { db.insertTrack(it).executeAsBlocking() }
.onErrorReturn {
errors.add(Date() to "${manga.title} - ${it.message}")
track
}
} else {
errors.add(Date() to "${manga.title} - ${getString(R.string.tracker_not_logged_in, service?.name)}")
Observable.empty()
}
}
}
/**
* Called to update dialog in [BackupConst]
*
* @param progress restore progress
* @param amount total restoreAmount of manga
* @param title title of restored manga
*/
private fun showRestoreProgress(
progress: Int,
amount: Int,
title: String
) {
notifier.showRestoreProgress(title, progress, amount)
}
/**
* Write errors to error log
*/
private fun writeErrorLog(): File {
try {
if (errors.isNotEmpty()) {
val destFile = File(externalCacheDir, "tachiyomi_restore.txt")
val sdf = SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.getDefault())
destFile.bufferedWriter().use { out ->
errors.forEach { (date, message) ->
out.write("[${sdf.format(date)}] $message\n")
}
}
return destFile
}
} catch (e: Exception) {
// Empty
}
return File("")
}
} }
@@ -1,46 +0,0 @@
package eu.kanade.tachiyomi.data.backup
import android.content.Context
import android.net.Uri
import com.google.gson.JsonObject
import com.google.gson.JsonParser
import com.google.gson.stream.JsonReader
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.backup.models.Backup
object BackupRestoreValidator {
/**
* Checks for critical backup file data.
*
* @throws Exception if version or manga cannot be found.
* @return List of required sources.
*/
fun validate(context: Context, uri: Uri): Map<Long, String> {
val reader = JsonReader(context.contentResolver.openInputStream(uri)!!.bufferedReader())
val json = JsonParser.parseReader(reader).asJsonObject
val version = json.get(Backup.VERSION)
val mangasJson = json.get(Backup.MANGAS)
if (version == null || mangasJson == null) {
throw Exception(context.getString(R.string.invalid_backup_file_missing_data))
}
if (mangasJson.asJsonArray.size() == 0) {
throw Exception(context.getString(R.string.invalid_backup_file_missing_manga))
}
return getSourceMapping(json)
}
fun getSourceMapping(json: JsonObject): Map<Long, String> {
val extensionsMapping = json.get(Backup.EXTENSIONS) ?: return emptyMap()
return extensionsMapping.asJsonArray
.map {
val items = it.asString.split(":")
items[0].toLong() to items[1]
}
.toMap()
}
}
@@ -0,0 +1,543 @@
package eu.kanade.tachiyomi.data.backup.full
import android.content.Context
import android.net.Uri
import com.hippo.unifile.UniFile
import eu.kanade.tachiyomi.data.backup.AbstractBackupManager
import eu.kanade.tachiyomi.data.backup.BackupCreateService.Companion.BACKUP_CATEGORY
import eu.kanade.tachiyomi.data.backup.BackupCreateService.Companion.BACKUP_CATEGORY_MASK
import eu.kanade.tachiyomi.data.backup.BackupCreateService.Companion.BACKUP_CHAPTER
import eu.kanade.tachiyomi.data.backup.BackupCreateService.Companion.BACKUP_CHAPTER_MASK
import eu.kanade.tachiyomi.data.backup.BackupCreateService.Companion.BACKUP_HISTORY
import eu.kanade.tachiyomi.data.backup.BackupCreateService.Companion.BACKUP_HISTORY_MASK
import eu.kanade.tachiyomi.data.backup.BackupCreateService.Companion.BACKUP_TRACK
import eu.kanade.tachiyomi.data.backup.BackupCreateService.Companion.BACKUP_TRACK_MASK
import eu.kanade.tachiyomi.data.backup.full.models.Backup
import eu.kanade.tachiyomi.data.backup.full.models.BackupCategory
import eu.kanade.tachiyomi.data.backup.full.models.BackupChapter
import eu.kanade.tachiyomi.data.backup.full.models.BackupFlatMetadata
import eu.kanade.tachiyomi.data.backup.full.models.BackupFull
import eu.kanade.tachiyomi.data.backup.full.models.BackupHistory
import eu.kanade.tachiyomi.data.backup.full.models.BackupManga
import eu.kanade.tachiyomi.data.backup.full.models.BackupMergedMangaReference
import eu.kanade.tachiyomi.data.backup.full.models.BackupSavedSearch
import eu.kanade.tachiyomi.data.backup.full.models.BackupSerializer
import eu.kanade.tachiyomi.data.backup.full.models.BackupSource
import eu.kanade.tachiyomi.data.backup.full.models.BackupTracking
import eu.kanade.tachiyomi.data.database.models.Chapter
import eu.kanade.tachiyomi.data.database.models.History
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.database.models.MangaCategory
import eu.kanade.tachiyomi.data.database.models.Track
import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.source.online.MetadataSource
import eu.kanade.tachiyomi.source.online.all.MergedSource
import exh.MERGED_SOURCE_ID
import exh.metadata.metadata.base.getFlatMetadataForManga
import exh.metadata.metadata.base.insertFlatMetadata
import exh.savedsearches.JsonSavedSearch
import exh.source.getMainSource
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import kotlinx.serialization.protobuf.ProtoBuf
import okio.buffer
import okio.gzip
import okio.sink
import rx.Observable
import timber.log.Timber
import kotlin.math.max
@OptIn(ExperimentalSerializationApi::class)
class FullBackupManager(context: Context) : AbstractBackupManager(context) {
val parser = ProtoBuf
/**
* Create backup Json file from database
*
* @param uri path of Uri
* @param isJob backup called from job
*/
override fun createBackup(uri: Uri, flags: Int, isJob: Boolean): String? {
// Create root object
var backup: Backup? = null
databaseHelper.inTransaction {
val databaseManga = getFavoriteManga() /* SY --> */ + getMergedManga().filterNot { it.source == MERGED_SOURCE_ID } /* SY <-- */
backup = Backup(
backupManga(databaseManga, flags),
backupCategories(),
backupExtensionInfo(databaseManga),
backupSavedSearches()
)
}
try {
val file: UniFile = (
if (isJob) {
// Get dir of file and create
var dir = UniFile.fromUri(context, uri)
dir = dir.createDirectory("automatic")
// Delete older backups
val numberOfBackups = numberOfBackups()
val backupRegex = Regex("""tachiyomi_\d+-\d+-\d+_\d+-\d+.proto.gz""")
dir.listFiles { _, filename -> backupRegex.matches(filename) }
.orEmpty()
.sortedByDescending { it.name }
.drop(numberOfBackups - 1)
.forEach { it.delete() }
// Create new file to place backup
dir.createFile(BackupFull.getDefaultFilename())
} else {
UniFile.fromUri(context, uri)
}
)
?: throw Exception("Couldn't create backup file")
val byteArray = parser.encodeToByteArray(BackupSerializer, backup!!)
file.openOutputStream().sink().gzip().buffer().use { it.write(byteArray) }
return file.uri.toString()
} catch (e: Exception) {
Timber.e(e)
throw e
}
}
private fun backupManga(mangas: List<Manga>, flags: Int): List<BackupManga> {
return mangas.map {
backupMangaObject(it, flags)
}
}
private fun backupExtensionInfo(mangas: List<Manga>): List<BackupSource> {
return mangas
.asSequence()
.map { it.source }
.distinct()
.map { sourceManager.getOrStub(it) }
.map { BackupSource.copyFrom(it) }
.toList()
}
/**
* Backup the categories of library
*
* @return list of [BackupCategory] to be backed up
*/
private fun backupCategories(): List<BackupCategory> {
return databaseHelper.getCategories()
.executeAsBlocking()
.map { BackupCategory.copyFrom(it) }
}
// SY -->
/**
* Backup the saved searches from sources
*
* @return list of [BackupSavedSearch] to be backed up
*/
private fun backupSavedSearches(): List<BackupSavedSearch> {
return preferences.savedSearches().get().map {
val sourceId = it.substringBefore(':').toLong()
val content = Json.decodeFromString<JsonSavedSearch>(it.substringAfter(':'))
BackupSavedSearch(
content.name,
content.query,
content.filters.toString(),
sourceId
)
}
}
// SY <--
/**
* Convert a manga to Json
*
* @param manga manga that gets converted
* @param options options for the backup
* @return [BackupManga] containing manga in a serializable form
*/
private fun backupMangaObject(manga: Manga, options: Int): BackupManga {
// Entry for this manga
val mangaObject = BackupManga.copyFrom(manga)
// SY -->
if (manga.source == MERGED_SOURCE_ID) {
manga.id?.let { mangaId ->
mangaObject.mergedMangaReferences = databaseHelper.getMergedMangaReferences(mangaId)
.executeAsBlocking()
.map { BackupMergedMangaReference.copyFrom(it) }
}
}
val source = sourceManager.get(manga.source)?.getMainSource()
if (source is MetadataSource<*, *>) {
manga.id?.let { mangaId ->
databaseHelper.getFlatMetadataForManga(mangaId).executeAsBlocking()?.let { flatMetadata ->
mangaObject.flatMetadata = BackupFlatMetadata.copyFrom(flatMetadata)
}
}
}
// SY <--
// Check if user wants chapter information in backup
if (options and BACKUP_CHAPTER_MASK == BACKUP_CHAPTER) {
// Backup all the chapters
val chapters = databaseHelper.getChapters(manga).executeAsBlocking()
if (chapters.isNotEmpty()) {
mangaObject.chapters = chapters.map { BackupChapter.copyFrom(it) }
}
}
// Check if user wants category information in backup
if (options and BACKUP_CATEGORY_MASK == BACKUP_CATEGORY) {
// Backup categories for this manga
val categoriesForManga = databaseHelper.getCategoriesForManga(manga).executeAsBlocking()
if (categoriesForManga.isNotEmpty()) {
mangaObject.categories = categoriesForManga.mapNotNull { it.order }
}
}
// Check if user wants track information in backup
if (options and BACKUP_TRACK_MASK == BACKUP_TRACK) {
val tracks = databaseHelper.getTracks(manga).executeAsBlocking()
if (tracks.isNotEmpty()) {
mangaObject.tracking = tracks.map { BackupTracking.copyFrom(it) }
}
}
// Check if user wants history information in backup
if (options and BACKUP_HISTORY_MASK == BACKUP_HISTORY) {
val historyForManga = databaseHelper.getHistoryByMangaId(manga.id!!).executeAsBlocking()
if (historyForManga.isNotEmpty()) {
val history = historyForManga.mapNotNull { history ->
val url = databaseHelper.getChapter(history.chapter_id).executeAsBlocking()?.url
url?.let { BackupHistory(url, history.last_read) }
}
if (history.isNotEmpty()) {
mangaObject.history = history
}
}
}
return mangaObject
}
fun restoreMangaNoFetch(manga: Manga, dbManga: Manga) {
manga.id = dbManga.id
manga.copyFrom(dbManga)
insertManga(manga)
}
/**
* [Observable] that fetches manga information
*
* @param source source of manga
* @param manga manga that needs updating
* @return [Observable] that contains manga
*/
fun restoreMangaFetchObservable(source: Source?, manga: Manga, online: Boolean): Observable<Manga> {
return if (online && source != null /* SY --> */ && source !is MergedSource /* SY <-- */) {
source.fetchMangaDetails(manga)
.map { networkManga ->
manga.copyFrom(networkManga)
manga.favorite = manga.favorite
manga.initialized = true
manga.id = insertManga(manga)
manga
}
} else {
Observable.just(manga)
.map {
it.initialized = it.description != null
it.id = insertManga(it)
it
}
}
}
/**
* Restore the categories from Json
*
* @param backupCategories list containing categories
*/
internal fun restoreCategories(backupCategories: List<BackupCategory>) {
// Get categories from file and from db
val dbCategories = databaseHelper.getCategories().executeAsBlocking()
// Iterate over them
backupCategories.map { it.getCategoryImpl() }.forEach { category ->
// Used to know if the category is already in the db
var found = false
for (dbCategory in dbCategories) {
// If the category is already in the db, assign the id to the file's category
// and do nothing
if (category.name == dbCategory.name) {
category.id = dbCategory.id
found = true
break
}
}
// If the category isn't in the db, remove the id and insert a new category
// Store the inserted id in the category
if (!found) {
// Let the db assign the id
category.id = null
val result = databaseHelper.insertCategory(category).executeAsBlocking()
category.id = result.insertedId()?.toInt()
}
}
}
/**
* Restores the categories a manga is in.
*
* @param manga the manga whose categories have to be restored.
* @param categories the categories to restore.
*/
internal fun restoreCategoriesForManga(manga: Manga, categories: List<Int>, backupCategories: List<BackupCategory>) {
val dbCategories = databaseHelper.getCategories().executeAsBlocking()
val mangaCategoriesToUpdate = mutableListOf<MangaCategory>()
categories.forEach { backupCategoryOrder ->
backupCategories.firstOrNull {
it.order == backupCategoryOrder
}?.let { backupCategory ->
dbCategories.firstOrNull { dbCategory ->
dbCategory.name == backupCategory.name
}?.let { dbCategory ->
mangaCategoriesToUpdate += MangaCategory.create(manga, dbCategory)
}
}
}
// Update database
if (mangaCategoriesToUpdate.isNotEmpty()) {
databaseHelper.deleteOldMangasCategories(listOf(manga)).executeAsBlocking()
databaseHelper.insertMangasCategories(mangaCategoriesToUpdate).executeAsBlocking()
}
}
/**
* Restore history from Json
*
* @param history list containing history to be restored
*/
internal fun restoreHistoryForManga(history: List<BackupHistory>) {
// List containing history to be updated
val historyToBeUpdated = mutableListOf<History>()
for ((url, lastRead) in history) {
val dbHistory = databaseHelper.getHistoryByChapterUrl(url).executeAsBlocking()
// Check if history already in database and update
if (dbHistory != null) {
dbHistory.apply {
last_read = max(lastRead, dbHistory.last_read)
}
historyToBeUpdated.add(dbHistory)
} else {
// If not in database create
databaseHelper.getChapter(url).executeAsBlocking()?.let {
val historyToAdd = History.create(it).apply {
last_read = lastRead
}
historyToBeUpdated.add(historyToAdd)
}
}
}
databaseHelper.updateHistoryLastRead(historyToBeUpdated).executeAsBlocking()
}
/**
* Restores the sync of a manga.
*
* @param manga the manga whose sync have to be restored.
* @param tracks the track list to restore.
*/
internal fun restoreTrackForManga(manga: Manga, tracks: List<Track>) {
// Fix foreign keys with the current manga id
tracks.map { it.manga_id = manga.id!! }
// Get tracks from database
val dbTracks = databaseHelper.getTracks(manga).executeAsBlocking()
val trackToUpdate = mutableListOf<Track>()
tracks.forEach { track ->
val service = trackManager.getService(track.sync_id)
if (service != null && service.isLogged) {
var isInDatabase = false
for (dbTrack in dbTracks) {
if (track.sync_id == dbTrack.sync_id) {
// The sync is already in the db, only update its fields
if (track.media_id != dbTrack.media_id) {
dbTrack.media_id = track.media_id
}
if (track.library_id != dbTrack.library_id) {
dbTrack.library_id = track.library_id
}
dbTrack.last_chapter_read = max(dbTrack.last_chapter_read, track.last_chapter_read)
isInDatabase = true
trackToUpdate.add(dbTrack)
break
}
}
if (!isInDatabase) {
// Insert new sync. Let the db assign the id
track.id = null
trackToUpdate.add(track)
}
}
}
// Update database
if (trackToUpdate.isNotEmpty()) {
databaseHelper.insertTracks(trackToUpdate).executeAsBlocking()
}
}
/**
* Restore the chapters for manga if chapters already in database
*
* @param manga manga of chapters
* @param chapters list containing chapters that get restored
* @return boolean answering if chapter fetch is not needed
*/
internal fun restoreChaptersForManga(manga: Manga, chapters: List<Chapter>): Boolean {
val dbChapters = databaseHelper.getChapters(manga).executeAsBlocking()
// Return if fetch is needed
if (dbChapters.isEmpty() || dbChapters.size < chapters.size) {
return false
}
chapters.forEach { chapter ->
val pos = dbChapters.indexOfFirst { it.url == chapter.url }
if (pos != -1) {
val dbChapter = dbChapters[pos]
chapter.id = dbChapter.id
chapter.copyFrom(dbChapter)
if (dbChapter.read && !chapter.read) {
chapter.read = dbChapter.read
chapter.last_page_read = dbChapter.last_page_read
} else if (chapter.last_page_read == 0 && dbChapter.last_page_read != 0) {
chapter.last_page_read = dbChapter.last_page_read
}
if (!chapter.bookmark && dbChapter.bookmark) {
chapter.bookmark = dbChapter.bookmark
}
}
}
// Filter the chapters that couldn't be found.
chapters.filter { it.id != null }
chapters.map { it.manga_id = manga.id }
updateChapters(chapters)
return true
}
internal fun restoreChaptersForMangaOffline(manga: Manga, chapters: List<Chapter>) {
val dbChapters = databaseHelper.getChapters(manga).executeAsBlocking()
chapters.forEach { chapter ->
val pos = dbChapters.indexOfFirst { it.url == chapter.url }
if (pos != -1) {
val dbChapter = dbChapters[pos]
chapter.id = dbChapter.id
chapter.copyFrom(dbChapter)
if (dbChapter.read && !chapter.read) {
chapter.read = dbChapter.read
chapter.last_page_read = dbChapter.last_page_read
} else if (chapter.last_page_read == 0 && dbChapter.last_page_read != 0) {
chapter.last_page_read = dbChapter.last_page_read
}
if (!chapter.bookmark && dbChapter.bookmark) {
chapter.bookmark = dbChapter.bookmark
}
}
}
chapters.map { it.manga_id = manga.id }
updateChapters(chapters.filter { it.id != null })
insertChapters(chapters.filter { it.id == null })
}
// SY -->
internal fun restoreSavedSearches(backupSavedSearches: List<BackupSavedSearch>) {
val currentSavedSearches = preferences.savedSearches().get().map {
val sourceId = it.substringBefore(':').toLong()
val content = Json.decodeFromString<JsonSavedSearch>(it.substringAfter(':'))
BackupSavedSearch(
content.name,
content.query,
content.filters.toString(),
sourceId
)
}
preferences.savedSearches()
.set(
(
backupSavedSearches.filter { backupSavedSearch -> currentSavedSearches.none { it.name == backupSavedSearch.name && it.source == backupSavedSearch.source } }
.map {
"${it.source}:" + Json.encodeToString(
JsonSavedSearch(
it.name,
it.query,
Json.decodeFromString(it.filterList)
)
)
} + preferences.savedSearches().get()
)
.toSet()
)
}
/**
* Restore the categories from Json
*
* @param manga the merge manga for the references
* @param backupMergedMangaReferences the list of backup manga references for the merged manga
*/
internal fun restoreMergedMangaReferencesForManga(manga: Manga, backupMergedMangaReferences: List<BackupMergedMangaReference>) {
// Get merged manga references from file and from db
val dbMergedMangaReferences = databaseHelper.getMergedMangaReferences().executeAsBlocking()
// Iterate over them
backupMergedMangaReferences.forEach { backupMergedMangaReference ->
// Used to know if the merged manga reference is already in the db
var found = false
for (dbMergedMangaReference in dbMergedMangaReferences) {
// If the backupMergedMangaReference is already in the db, assign the id to the file's backupMergedMangaReference
// and do nothing
if (backupMergedMangaReference.mergeUrl == dbMergedMangaReference.mergeUrl && backupMergedMangaReference.mangaUrl == dbMergedMangaReference.mangaUrl) {
found = true
break
}
}
// If the backupMergedMangaReference isn't in the db, remove the id and insert a new backupMergedMangaReference
// Store the inserted id in the backupMergedMangaReference
if (!found) {
// Let the db assign the id
val mergedManga = databaseHelper.getManga(backupMergedMangaReference.mangaUrl, backupMergedMangaReference.mangaSourceId).executeAsBlocking() ?: return@forEach
val mergedMangaReference = backupMergedMangaReference.getMergedMangaReference()
mergedMangaReference.mergeId = manga.id
mergedMangaReference.mangaId = mergedManga.id
databaseHelper.insertMergedManga(mergedMangaReference).executeAsBlocking()
}
}
}
internal fun restoreFlatMetadata(manga: Manga, backupFlatMetadata: BackupFlatMetadata) {
manga.id?.let { mangaId ->
databaseHelper.getFlatMetadataForManga(mangaId).executeAsBlocking().let {
if (it == null) {
val flatMetadata = backupFlatMetadata.getFlatMetadata(mangaId)
databaseHelper.insertFlatMetadata(flatMetadata).await()
}
}
}
}
// SY <--
}
@@ -0,0 +1,257 @@
package eu.kanade.tachiyomi.data.backup.full
import android.content.Context
import android.net.Uri
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.backup.AbstractBackupRestore
import eu.kanade.tachiyomi.data.backup.BackupNotifier
import eu.kanade.tachiyomi.data.backup.full.models.BackupCategory
import eu.kanade.tachiyomi.data.backup.full.models.BackupFlatMetadata
import eu.kanade.tachiyomi.data.backup.full.models.BackupHistory
import eu.kanade.tachiyomi.data.backup.full.models.BackupManga
import eu.kanade.tachiyomi.data.backup.full.models.BackupMergedMangaReference
import eu.kanade.tachiyomi.data.backup.full.models.BackupSavedSearch
import eu.kanade.tachiyomi.data.backup.full.models.BackupSerializer
import eu.kanade.tachiyomi.data.database.models.Chapter
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.database.models.Track
import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.source.online.all.MergedSource
import exh.EXHMigrations
import exh.MERGED_SOURCE_ID
import kotlinx.serialization.ExperimentalSerializationApi
import okio.buffer
import okio.gzip
import okio.source
import rx.Observable
import java.util.Date
@OptIn(ExperimentalSerializationApi::class)
class FullBackupRestore(context: Context, notifier: BackupNotifier, private val online: Boolean) : AbstractBackupRestore<FullBackupManager>(context, notifier) {
override fun performRestore(uri: Uri): Boolean {
// SY -->
throttleManager.resetThrottle()
// SY <--
backupManager = FullBackupManager(context)
val backupString = context.contentResolver.openInputStream(uri)!!.source().gzip().buffer().use { it.readByteArray() }
val backup = backupManager.parser.decodeFromByteArray(BackupSerializer, backupString)
restoreAmount = backup.backupManga.size + 1 /* SY --> */ + 1 /* SY <-- */ // +1 for categories, +1 for saved searches
// Restore categories
if (backup.backupCategories.isNotEmpty()) {
restoreCategories(backup.backupCategories)
}
// SY -->
if (backup.backupSavedSearches.isNotEmpty()) {
restoreSavedSearches(backup.backupSavedSearches)
}
// SY <--
// Store source mapping for error messages
sourceMapping = backup.backupSources.map { it.sourceId to it.name }.toMap()
// Restore individual manga, sort by merged source so that merged source manga go last and merged references get the proper ids
backup.backupManga /* SY --> */.sortedBy { it.source == MERGED_SOURCE_ID } /* SY <-- */.forEach {
if (job?.isActive != true) {
return false
}
restoreManga(it, backup.backupCategories, online)
}
return true
}
private fun restoreCategories(backupCategories: List<BackupCategory>) {
db.inTransaction {
backupManager.restoreCategories(backupCategories)
}
restoreProgress += 1
showRestoreProgress(restoreProgress, restoreAmount, context.getString(R.string.categories))
}
// SY -->
private fun restoreSavedSearches(backupSavedSearches: List<BackupSavedSearch>) {
backupManager.restoreSavedSearches(backupSavedSearches)
restoreProgress += 1
showRestoreProgress(restoreProgress, restoreAmount, context.getString(R.string.saved_searches))
}
// SY <--
private fun restoreManga(backupManga: BackupManga, backupCategories: List<BackupCategory>, online: Boolean) {
var manga = backupManga.getMangaImpl()
val chapters = backupManga.getChaptersImpl()
val categories = backupManga.categories
val history = backupManga.history
val tracks = backupManga.getTrackingImpl()
// SY -->
val mergedMangaReferences = backupManga.mergedMangaReferences
val flatMetadata = backupManga.flatMetadata
// SY <--
// SY -->
manga = EXHMigrations.migrateBackupEntry(manga)
// SY <--
try {
val source = backupManager.sourceManager.get(manga.source)
if (source != null || !online) {
restoreMangaData(manga, source, chapters, categories, history, tracks, backupCategories, mergedMangaReferences, flatMetadata, online)
} else {
val sourceName = sourceMapping[manga.source] ?: manga.source.toString()
errors.add(Date() to "${manga.title} - ${context.getString(R.string.source_not_found_name, sourceName)}")
}
} catch (e: Exception) {
errors.add(Date() to "${manga.title} - ${e.message}")
}
restoreProgress += 1
showRestoreProgress(restoreProgress, restoreAmount, manga.title)
}
/**
* Returns a manga restore observable
*
* @param manga manga data from json
* @param source source to get manga data from
* @param chapters chapters data from json
* @param categories categories data from json
* @param history history data from json
* @param tracks tracking data from json
*/
private fun restoreMangaData(
manga: Manga,
source: Source?,
chapters: List<Chapter>,
categories: List<Int>,
history: List<BackupHistory>,
tracks: List<Track>,
backupCategories: List<BackupCategory>,
mergedMangaReferences: List<BackupMergedMangaReference>,
flatMetadata: BackupFlatMetadata?,
online: Boolean
) {
val dbManga = backupManager.getMangaFromDatabase(manga)
db.inTransaction {
if (dbManga == null) {
// Manga not in database
restoreMangaFetch(source, manga, chapters, categories, history, tracks, backupCategories, mergedMangaReferences, flatMetadata, online)
} else { // Manga in database
// Copy information from manga already in database
backupManager.restoreMangaNoFetch(manga, dbManga)
// Fetch rest of manga information
restoreMangaNoFetch(source, manga, chapters, categories, history, tracks, backupCategories, mergedMangaReferences, flatMetadata, online)
}
}
}
/**
* [Observable] that fetches manga information
*
* @param manga manga that needs updating
* @param chapters chapters of manga that needs updating
* @param categories categories that need updating
*/
private fun restoreMangaFetch(
source: Source?,
manga: Manga,
chapters: List<Chapter>,
categories: List<Int>,
history: List<BackupHistory>,
tracks: List<Track>,
backupCategories: List<BackupCategory>,
mergedMangaReferences: List<BackupMergedMangaReference>,
flatMetadata: BackupFlatMetadata?,
online: Boolean
) {
backupManager.restoreMangaFetchObservable(source, manga, online)
.doOnError {
errors.add(Date() to "${manga.title} - ${it.message}")
}
.filter { it.id != null }
.flatMap {
if (online && source != null) {
// SY -->
if (source !is MergedSource) {
chapterFetchObservable(source, it, chapters)
// Convert to the manga that contains new chapters.
.map { manga }
} else {
Observable.just(manga)
}
// SY <--
} else {
backupManager.restoreChaptersForMangaOffline(it, chapters)
Observable.just(manga)
}
}
.doOnNext {
restoreExtraForManga(it, categories, history, tracks, backupCategories, mergedMangaReferences, flatMetadata)
}
.flatMap {
trackingFetchObservable(it, tracks)
}
.subscribe()
}
private fun restoreMangaNoFetch(
source: Source?,
backupManga: Manga,
chapters: List<Chapter>,
categories: List<Int>,
history: List<BackupHistory>,
tracks: List<Track>,
backupCategories: List<BackupCategory>,
mergedMangaReferences: List<BackupMergedMangaReference>,
flatMetadata: BackupFlatMetadata?,
online: Boolean
) {
Observable.just(backupManga)
.flatMap { manga ->
if (online && source != null) {
if (/* SY --> */ source !is MergedSource && /* SY <-- */ !backupManager.restoreChaptersForManga(manga, chapters)) {
chapterFetchObservable(source, manga, chapters)
.map { manga }
} else {
Observable.just(manga)
}
} else {
backupManager.restoreChaptersForMangaOffline(manga, chapters)
Observable.just(manga)
}
}
.doOnNext {
restoreExtraForManga(it, categories, history, tracks, backupCategories, mergedMangaReferences, flatMetadata)
}
.flatMap { manga ->
trackingFetchObservable(manga, tracks)
}
.subscribe()
}
private fun restoreExtraForManga(manga: Manga, categories: List<Int>, history: List<BackupHistory>, tracks: List<Track>, backupCategories: List<BackupCategory>, mergedMangaReferences: List<BackupMergedMangaReference>, flatMetadata: BackupFlatMetadata?) {
// Restore categories
backupManager.restoreCategoriesForManga(manga, categories, backupCategories)
// Restore history
backupManager.restoreHistoryForManga(history)
// Restore tracking
backupManager.restoreTrackForManga(manga, tracks)
// SY -->
// Restore merged manga references if its a merged manga
backupManager.restoreMergedMangaReferencesForManga(manga, mergedMangaReferences)
// Restore flat metadata for metadata sources
flatMetadata?.let { backupManager.restoreFlatMetadata(manga, it) }
// SY <--
}
}
@@ -0,0 +1,49 @@
package eu.kanade.tachiyomi.data.backup.full
import android.content.Context
import android.net.Uri
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.backup.AbstractBackupRestoreValidator
import eu.kanade.tachiyomi.data.backup.full.models.BackupSerializer
import kotlinx.serialization.ExperimentalSerializationApi
import okio.buffer
import okio.gzip
import okio.source
@OptIn(ExperimentalSerializationApi::class)
class FullBackupRestoreValidator : AbstractBackupRestoreValidator() {
/**
* Checks for critical backup file data.
*
* @throws Exception if manga cannot be found.
* @return List of missing sources or missing trackers.
*/
override fun validate(context: Context, uri: Uri): Results {
val backupManager = FullBackupManager(context)
val backupString = context.contentResolver.openInputStream(uri)!!.source().gzip().buffer().use { it.readByteArray() }
val backup = backupManager.parser.decodeFromByteArray(BackupSerializer, backupString)
if (backup.backupManga.isEmpty()) {
throw Exception(context.getString(R.string.invalid_backup_file_missing_manga))
}
val sources = backup.backupSources.map { it.sourceId to it.name }.toMap()
val missingSources = sources
.filter { sourceManager.get(it.key) == null }
.values
.sorted()
val trackers = backup.backupManga
.flatMap { it.tracking }
.map { it.syncId }
.distinct()
val missingTrackers = trackers
.mapNotNull { trackManager.getService(it) }
.filter { !it.isLogged }
.map { it.name }
.sorted()
return Results(missingSources, missingTrackers)
}
}
@@ -0,0 +1,14 @@
package eu.kanade.tachiyomi.data.backup.full.models
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class Backup(
@ProtoNumber(1) val backupManga: List<BackupManga>,
@ProtoNumber(2) var backupCategories: List<BackupCategory> = emptyList(),
// Bump by 100 to specify this is a 0.x value
@ProtoNumber(100) var backupSources: List<BackupSource> = emptyList(),
// SY specific values
@ProtoNumber(600) var backupSavedSearches: List<BackupSavedSearch> = emptyList()
)
@@ -0,0 +1,37 @@
package eu.kanade.tachiyomi.data.backup.full.models
import eu.kanade.tachiyomi.data.database.models.Category
import eu.kanade.tachiyomi.data.database.models.CategoryImpl
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
class BackupCategory(
@ProtoNumber(1) var name: String,
@ProtoNumber(2) var order: Int = 0,
// @ProtoNumber(3) val updateInterval: Int = 0, 1.x value not used in 0.x
// Bump by 100 to specify this is a 0.x value
@ProtoNumber(100) var flags: Int = 0,
// SY specific values
@ProtoNumber(600) var mangaOrder: List<Long> = emptyList()
) {
fun getCategoryImpl(): CategoryImpl {
return CategoryImpl().apply {
name = this@BackupCategory.name
flags = this@BackupCategory.flags
order = this@BackupCategory.order
mangaOrder = this@BackupCategory.mangaOrder
}
}
companion object {
fun copyFrom(category: Category): BackupCategory {
return BackupCategory(
name = category.name,
order = category.order,
flags = category.flags,
mangaOrder = category.mangaOrder
)
}
}
}
@@ -0,0 +1,56 @@
package eu.kanade.tachiyomi.data.backup.full.models
import eu.kanade.tachiyomi.data.database.models.Chapter
import eu.kanade.tachiyomi.data.database.models.ChapterImpl
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class BackupChapter(
// in 1.x some of these values have different names
// url is called key in 1.x
@ProtoNumber(1) var url: String,
@ProtoNumber(2) var name: String,
@ProtoNumber(3) var scanlator: String? = null,
@ProtoNumber(4) var read: Boolean = false,
@ProtoNumber(5) var bookmark: Boolean = false,
// lastPageRead is called progress in 1.x
@ProtoNumber(6) var lastPageRead: Int = 0,
@ProtoNumber(7) var dateFetch: Long = 0,
@ProtoNumber(8) var dateUpload: Long = 0,
// chapterNumber is called number is 1.x
@ProtoNumber(9) var chapterNumber: Float = 0F,
@ProtoNumber(10) var sourceOrder: Int = 0,
) {
fun toChapterImpl(): ChapterImpl {
return ChapterImpl().apply {
url = this@BackupChapter.url
name = this@BackupChapter.name
chapter_number = this@BackupChapter.chapterNumber
scanlator = this@BackupChapter.scanlator
read = this@BackupChapter.read
bookmark = this@BackupChapter.bookmark
last_page_read = this@BackupChapter.lastPageRead
date_fetch = this@BackupChapter.dateFetch
date_upload = this@BackupChapter.dateUpload
source_order = this@BackupChapter.sourceOrder
}
}
companion object {
fun copyFrom(chapter: Chapter): BackupChapter {
return BackupChapter(
url = chapter.url,
name = chapter.name,
chapterNumber = chapter.chapter_number,
scanlator = chapter.scanlator,
read = chapter.read,
bookmark = chapter.bookmark,
lastPageRead = chapter.last_page_read,
dateFetch = chapter.date_fetch,
dateUpload = chapter.date_upload,
sourceOrder = chapter.source_order
)
}
}
}
@@ -0,0 +1,33 @@
package eu.kanade.tachiyomi.data.backup.full.models
import eu.kanade.tachiyomi.data.backup.full.models.metadata.BackupSearchMetadata
import eu.kanade.tachiyomi.data.backup.full.models.metadata.BackupSearchTag
import eu.kanade.tachiyomi.data.backup.full.models.metadata.BackupSearchTitle
import exh.metadata.metadata.base.FlatMetadata
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class BackupFlatMetadata(
@ProtoNumber(1) var searchMetadata: BackupSearchMetadata,
@ProtoNumber(2) var searchTags: List<BackupSearchTag> = emptyList(),
@ProtoNumber(3) var searchTitles: List<BackupSearchTitle> = emptyList()
) {
fun getFlatMetadata(mangaId: Long): FlatMetadata {
return FlatMetadata(
metadata = searchMetadata.getSearchMetadata(mangaId),
tags = searchTags.map { it.getSearchTag(mangaId) },
titles = searchTitles.map { it.getSearchTitle(mangaId) }
)
}
companion object {
fun copyFrom(flatMetadata: FlatMetadata): BackupFlatMetadata {
return BackupFlatMetadata(
searchMetadata = BackupSearchMetadata.copyFrom(flatMetadata.metadata),
searchTags = flatMetadata.tags.map { BackupSearchTag.copyFrom(it) },
searchTitles = flatMetadata.titles.map { BackupSearchTitle.copyFrom(it) }
)
}
}
}
@@ -0,0 +1,12 @@
package eu.kanade.tachiyomi.data.backup.full.models
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
object BackupFull {
fun getDefaultFilename(): String {
val date = SimpleDateFormat("yyyy-MM-dd_HH-mm", Locale.getDefault()).format(Date())
return "tachiyomi_$date.proto.gz"
}
}
@@ -0,0 +1,10 @@
package eu.kanade.tachiyomi.data.backup.full.models
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class BackupHistory(
@ProtoNumber(0) var url: String,
@ProtoNumber(1) var lastRead: Long
)
@@ -0,0 +1,90 @@
package eu.kanade.tachiyomi.data.backup.full.models
import eu.kanade.tachiyomi.data.database.models.ChapterImpl
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.database.models.MangaImpl
import eu.kanade.tachiyomi.data.database.models.TrackImpl
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class BackupManga(
// in 1.x some of these values have different names
@ProtoNumber(1) var source: Long,
// url is called key in 1.x
@ProtoNumber(2) var url: String,
@ProtoNumber(3) var title: String = "",
@ProtoNumber(4) var artist: String? = null,
@ProtoNumber(5) var author: String? = null,
@ProtoNumber(6) var description: String? = null,
@ProtoNumber(7) var genre: List<String> = emptyList(),
@ProtoNumber(8) var status: Int = 0,
// thumbnailUrl is called cover in 1.x
@ProtoNumber(9) var thumbnailUrl: String? = null,
// @ProtoNumber(10) val customCover: String = "", 1.x value, not used in 0.x
// @ProtoNumber(11) val lastUpdate: Long = 0, 1.x value, not used in 0.x
// @ProtoNumber(12) val lastInit: Long = 0, 1.x value, not used in 0.x
@ProtoNumber(13) var dateAdded: Long = 0,
@ProtoNumber(14) var viewer: Int = 0,
// @ProtoNumber(15) val flags: Int = 0, 1.x value, not used in 0.x
@ProtoNumber(16) var chapters: List<BackupChapter> = emptyList(),
@ProtoNumber(17) var categories: List<Int> = emptyList(),
@ProtoNumber(18) var tracking: List<BackupTracking> = emptyList(),
// Bump by 100 for values that are not saved/implemented in 1.x but are used in 0.x
@ProtoNumber(100) var favorite: Boolean = true,
@ProtoNumber(101) var chapterFlags: Int = 0,
@ProtoNumber(102) var history: List<BackupHistory> = emptyList(),
// SY specific values
@ProtoNumber(600) var mergedMangaReferences: List<BackupMergedMangaReference> = emptyList(),
@ProtoNumber(601) var flatMetadata: BackupFlatMetadata? = null
) {
fun getMangaImpl(): MangaImpl {
return MangaImpl().apply {
url = this@BackupManga.url
title = this@BackupManga.title
artist = this@BackupManga.artist
author = this@BackupManga.author
description = this@BackupManga.description
genre = this@BackupManga.genre.joinToString()
status = this@BackupManga.status
thumbnail_url = this@BackupManga.thumbnailUrl
favorite = this@BackupManga.favorite
source = this@BackupManga.source
date_added = this@BackupManga.dateAdded
viewer = this@BackupManga.viewer
chapter_flags = this@BackupManga.chapterFlags
}
}
fun getChaptersImpl(): List<ChapterImpl> {
return chapters.map {
it.toChapterImpl()
}
}
fun getTrackingImpl(): List<TrackImpl> {
return tracking.map {
it.getTrackingImpl()
}
}
companion object {
fun copyFrom(manga: Manga): BackupManga {
return BackupManga(
url = manga.url,
title = manga.title,
artist = manga.artist,
author = manga.author,
description = manga.description,
genre = manga.getGenres() ?: emptyList(),
status = manga.status,
thumbnailUrl = manga.thumbnail_url,
favorite = manga.favorite,
source = manga.source,
dateAdded = manga.date_added,
viewer = manga.viewer,
chapterFlags = manga.chapter_flags
)
}
}
}
@@ -0,0 +1,51 @@
package eu.kanade.tachiyomi.data.backup.full.models
import exh.merged.sql.models.MergedMangaReference
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
/*
* SY merged manga backup class
*/
@Serializable
data class BackupMergedMangaReference(
@ProtoNumber(1) var isInfoManga: Boolean,
@ProtoNumber(2) var getChapterUpdates: Boolean,
@ProtoNumber(3) var chapterSortMode: Int,
@ProtoNumber(4) var chapterPriority: Int,
@ProtoNumber(5) var downloadChapters: Boolean,
@ProtoNumber(6) var mergeUrl: String,
@ProtoNumber(7) var mangaUrl: String,
@ProtoNumber(8) var mangaSourceId: Long
) {
fun getMergedMangaReference(): MergedMangaReference {
return MergedMangaReference(
isInfoManga = isInfoManga,
getChapterUpdates = getChapterUpdates,
chapterSortMode = chapterSortMode,
chapterPriority = chapterPriority,
downloadChapters = downloadChapters,
mergeUrl = mergeUrl,
mangaUrl = mangaUrl,
mangaSourceId = mangaSourceId,
mergeId = null,
mangaId = null,
id = null
)
}
companion object {
fun copyFrom(mergedMangaReference: MergedMangaReference): BackupMergedMangaReference {
return BackupMergedMangaReference(
isInfoManga = mergedMangaReference.isInfoManga,
getChapterUpdates = mergedMangaReference.getChapterUpdates,
chapterSortMode = mergedMangaReference.chapterSortMode,
chapterPriority = mergedMangaReference.chapterPriority,
downloadChapters = mergedMangaReference.downloadChapters,
mergeUrl = mergedMangaReference.mergeUrl,
mangaUrl = mergedMangaReference.mangaUrl,
mangaSourceId = mergedMangaReference.mangaSourceId
)
}
}
}
@@ -0,0 +1,15 @@
package eu.kanade.tachiyomi.data.backup.full.models
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
/*
* SY saved searches class
*/
@Serializable
data class BackupSavedSearch(
@ProtoNumber(1) val name: String,
@ProtoNumber(2) val query: String = "",
@ProtoNumber(3) val filterList: String = "",
@ProtoNumber(4) val source: Long = 0
)
@@ -0,0 +1,6 @@
package eu.kanade.tachiyomi.data.backup.full.models
import kotlinx.serialization.Serializer
@Serializer(forClass = Backup::class)
object BackupSerializer
@@ -0,0 +1,20 @@
package eu.kanade.tachiyomi.data.backup.full.models
import eu.kanade.tachiyomi.source.Source
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class BackupSource(
@ProtoNumber(0) var name: String = "",
@ProtoNumber(1) var sourceId: Long
) {
companion object {
fun copyFrom(source: Source): BackupSource {
return BackupSource(
name = source.name,
sourceId = source.id
)
}
}
}
@@ -0,0 +1,66 @@
package eu.kanade.tachiyomi.data.backup.full.models
import eu.kanade.tachiyomi.data.database.models.Track
import eu.kanade.tachiyomi.data.database.models.TrackImpl
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class BackupTracking(
// in 1.x some of these values have different types or names
// syncId is called siteId in 1,x
@ProtoNumber(1) var syncId: Int,
// LibraryId is not null in 1.x
@ProtoNumber(2) var libraryId: Long,
@ProtoNumber(3) var mediaId: Int = 0,
// trackingUrl is called mediaUrl in 1.x
@ProtoNumber(4) var trackingUrl: String = "",
@ProtoNumber(5) var title: String = "",
// lastChapterRead is called last read, and it has been changed to a float in 1.x
@ProtoNumber(6) var lastChapterRead: Float = 0F,
@ProtoNumber(7) var totalChapters: Int = 0,
@ProtoNumber(8) var score: Float = 0F,
@ProtoNumber(9) var status: Int = 0,
// startedReadingDate is called startReadTime in 1.x
@ProtoNumber(10) var startedReadingDate: Long = 0,
// finishedReadingDate is called endReadTime in 1.x
@ProtoNumber(11) var finishedReadingDate: Long = 0,
) {
fun getTrackingImpl(): TrackImpl {
return TrackImpl().apply {
sync_id = this@BackupTracking.syncId
media_id = this@BackupTracking.mediaId
library_id = this@BackupTracking.libraryId
title = this@BackupTracking.title
// convert from float to int because of 1.x types
last_chapter_read = this@BackupTracking.lastChapterRead.toInt()
total_chapters = this@BackupTracking.totalChapters
score = this@BackupTracking.score
status = this@BackupTracking.status
started_reading_date = this@BackupTracking.startedReadingDate
finished_reading_date = this@BackupTracking.finishedReadingDate
tracking_url = this@BackupTracking.trackingUrl
}
}
companion object {
fun copyFrom(track: Track): BackupTracking {
return BackupTracking(
syncId = track.sync_id,
mediaId = track.media_id,
// forced not null so its compatible with 1.x backup system
libraryId = track.library_id!!,
title = track.title,
// convert to float for 1.x
lastChapterRead = track.last_chapter_read.toFloat(),
totalChapters = track.total_chapters,
score = track.score,
status = track.status,
startedReadingDate = track.started_reading_date,
finishedReadingDate = track.finished_reading_date,
trackingUrl = track.tracking_url
)
}
}
}
@@ -0,0 +1,34 @@
package eu.kanade.tachiyomi.data.backup.full.models.metadata
import exh.metadata.sql.models.SearchMetadata
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class BackupSearchMetadata(
@ProtoNumber(1) var uploader: String? = null,
@ProtoNumber(2) var extra: String,
@ProtoNumber(3) var indexedExtra: String? = null,
@ProtoNumber(4) var extraVersion: Int
) {
fun getSearchMetadata(mangaId: Long): SearchMetadata {
return SearchMetadata(
mangaId = mangaId,
uploader = uploader,
extra = extra,
indexedExtra = indexedExtra,
extraVersion = extraVersion
)
}
companion object {
fun copyFrom(searchMetadata: SearchMetadata): BackupSearchMetadata {
return BackupSearchMetadata(
uploader = searchMetadata.uploader,
extra = searchMetadata.extra,
indexedExtra = searchMetadata.indexedExtra,
extraVersion = searchMetadata.extraVersion
)
}
}
}
@@ -0,0 +1,32 @@
package eu.kanade.tachiyomi.data.backup.full.models.metadata
import exh.metadata.sql.models.SearchTag
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class BackupSearchTag(
@ProtoNumber(1) var namespace: String? = null,
@ProtoNumber(2) var name: String,
@ProtoNumber(3) var type: Int
) {
fun getSearchTag(mangaId: Long): SearchTag {
return SearchTag(
id = null,
mangaId = mangaId,
namespace = namespace,
name = name,
type = type
)
}
companion object {
fun copyFrom(searchTag: SearchTag): BackupSearchTag {
return BackupSearchTag(
namespace = searchTag.namespace,
name = searchTag.name,
type = searchTag.type
)
}
}
}
@@ -0,0 +1,29 @@
package eu.kanade.tachiyomi.data.backup.full.models.metadata
import exh.metadata.sql.models.SearchTitle
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class BackupSearchTitle(
@ProtoNumber(1) var title: String,
@ProtoNumber(2) var type: Int
) {
fun getSearchTitle(mangaId: Long): SearchTitle {
return SearchTitle(
id = null,
mangaId = mangaId,
title = title,
type = type
)
}
companion object {
fun copyFrom(searchTitle: SearchTitle): BackupSearchTitle {
return BackupSearchTitle(
title = searchTitle.title,
type = searchTitle.type
)
}
}
}
@@ -1,22 +1,19 @@
package eu.kanade.tachiyomi.data.backup package eu.kanade.tachiyomi.data.backup.legacy
import android.content.Context import android.content.Context
import android.net.Uri import android.net.Uri
import com.github.salomonbrys.kotson.array
import com.github.salomonbrys.kotson.fromJson import com.github.salomonbrys.kotson.fromJson
import com.github.salomonbrys.kotson.jsonObject
import com.github.salomonbrys.kotson.obj
import com.github.salomonbrys.kotson.registerTypeAdapter import com.github.salomonbrys.kotson.registerTypeAdapter
import com.github.salomonbrys.kotson.registerTypeHierarchyAdapter import com.github.salomonbrys.kotson.registerTypeHierarchyAdapter
import com.github.salomonbrys.kotson.set import com.github.salomonbrys.kotson.set
import com.github.salomonbrys.kotson.string
import com.google.gson.Gson import com.google.gson.Gson
import com.google.gson.GsonBuilder import com.google.gson.GsonBuilder
import com.google.gson.JsonArray import com.google.gson.JsonArray
import com.google.gson.JsonElement import com.google.gson.JsonElement
import com.google.gson.JsonObject import com.google.gson.JsonObject
import com.google.gson.JsonParser
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.BackupCreateService.Companion.BACKUP_CATEGORY import eu.kanade.tachiyomi.data.backup.BackupCreateService.Companion.BACKUP_CATEGORY
import eu.kanade.tachiyomi.data.backup.BackupCreateService.Companion.BACKUP_CATEGORY_MASK import eu.kanade.tachiyomi.data.backup.BackupCreateService.Companion.BACKUP_CATEGORY_MASK
import eu.kanade.tachiyomi.data.backup.BackupCreateService.Companion.BACKUP_CHAPTER import eu.kanade.tachiyomi.data.backup.BackupCreateService.Companion.BACKUP_CHAPTER
@@ -25,22 +22,23 @@ import eu.kanade.tachiyomi.data.backup.BackupCreateService.Companion.BACKUP_HIST
import eu.kanade.tachiyomi.data.backup.BackupCreateService.Companion.BACKUP_HISTORY_MASK import eu.kanade.tachiyomi.data.backup.BackupCreateService.Companion.BACKUP_HISTORY_MASK
import eu.kanade.tachiyomi.data.backup.BackupCreateService.Companion.BACKUP_TRACK import eu.kanade.tachiyomi.data.backup.BackupCreateService.Companion.BACKUP_TRACK
import eu.kanade.tachiyomi.data.backup.BackupCreateService.Companion.BACKUP_TRACK_MASK import eu.kanade.tachiyomi.data.backup.BackupCreateService.Companion.BACKUP_TRACK_MASK
import eu.kanade.tachiyomi.data.backup.models.Backup import eu.kanade.tachiyomi.data.backup.legacy.models.Backup
import eu.kanade.tachiyomi.data.backup.models.Backup.CATEGORIES import eu.kanade.tachiyomi.data.backup.legacy.models.Backup.CATEGORIES
import eu.kanade.tachiyomi.data.backup.models.Backup.CHAPTERS import eu.kanade.tachiyomi.data.backup.legacy.models.Backup.CHAPTERS
import eu.kanade.tachiyomi.data.backup.models.Backup.CURRENT_VERSION import eu.kanade.tachiyomi.data.backup.legacy.models.Backup.CURRENT_VERSION
import eu.kanade.tachiyomi.data.backup.models.Backup.EXTENSIONS import eu.kanade.tachiyomi.data.backup.legacy.models.Backup.EXTENSIONS
import eu.kanade.tachiyomi.data.backup.models.Backup.HISTORY import eu.kanade.tachiyomi.data.backup.legacy.models.Backup.HISTORY
import eu.kanade.tachiyomi.data.backup.models.Backup.MANGA import eu.kanade.tachiyomi.data.backup.legacy.models.Backup.MANGA
import eu.kanade.tachiyomi.data.backup.models.Backup.SAVEDSEARCHES import eu.kanade.tachiyomi.data.backup.legacy.models.Backup.MERGEDMANGAREFERENCES
import eu.kanade.tachiyomi.data.backup.models.Backup.TRACK import eu.kanade.tachiyomi.data.backup.legacy.models.Backup.SAVEDSEARCHES
import eu.kanade.tachiyomi.data.backup.models.DHistory import eu.kanade.tachiyomi.data.backup.legacy.models.Backup.TRACK
import eu.kanade.tachiyomi.data.backup.serializer.CategoryTypeAdapter import eu.kanade.tachiyomi.data.backup.legacy.models.DHistory
import eu.kanade.tachiyomi.data.backup.serializer.ChapterTypeAdapter import eu.kanade.tachiyomi.data.backup.legacy.serializer.CategoryTypeAdapter
import eu.kanade.tachiyomi.data.backup.serializer.HistoryTypeAdapter import eu.kanade.tachiyomi.data.backup.legacy.serializer.ChapterTypeAdapter
import eu.kanade.tachiyomi.data.backup.serializer.MangaTypeAdapter import eu.kanade.tachiyomi.data.backup.legacy.serializer.HistoryTypeAdapter
import eu.kanade.tachiyomi.data.backup.serializer.TrackTypeAdapter import eu.kanade.tachiyomi.data.backup.legacy.serializer.MangaTypeAdapter
import eu.kanade.tachiyomi.data.database.DatabaseHelper import eu.kanade.tachiyomi.data.backup.legacy.serializer.MergedMangaReferenceTypeAdapter
import eu.kanade.tachiyomi.data.backup.legacy.serializer.TrackTypeAdapter
import eu.kanade.tachiyomi.data.database.models.CategoryImpl import eu.kanade.tachiyomi.data.database.models.CategoryImpl
import eu.kanade.tachiyomi.data.database.models.Chapter import eu.kanade.tachiyomi.data.database.models.Chapter
import eu.kanade.tachiyomi.data.database.models.ChapterImpl import eu.kanade.tachiyomi.data.database.models.ChapterImpl
@@ -51,40 +49,31 @@ import eu.kanade.tachiyomi.data.database.models.MangaImpl
import eu.kanade.tachiyomi.data.database.models.Track import eu.kanade.tachiyomi.data.database.models.Track
import eu.kanade.tachiyomi.data.database.models.TrackImpl import eu.kanade.tachiyomi.data.database.models.TrackImpl
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.track.TrackManager
import eu.kanade.tachiyomi.source.CatalogueSource
import eu.kanade.tachiyomi.source.LocalSource import eu.kanade.tachiyomi.source.LocalSource
import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.source.online.all.MergedSource
import eu.kanade.tachiyomi.source.online.all.EHentai import eu.kanade.tachiyomi.util.lang.asObservable
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource import exh.MERGED_SOURCE_ID
import exh.EXHSavedSearch
import exh.eh.EHentaiThrottleManager import exh.eh.EHentaiThrottleManager
import java.lang.RuntimeException import exh.merged.sql.models.MergedMangaReference
import kotlin.math.max import exh.savedsearches.JsonSavedSearch
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.runBlocking
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import rx.Observable import rx.Observable
import timber.log.Timber import timber.log.Timber
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy import java.lang.RuntimeException
import xyz.nulldev.ts.api.http.serializer.FilterSerializer import kotlin.math.max
class BackupManager(val context: Context, version: Int = CURRENT_VERSION) { class LegacyBackupManager(context: Context, version: Int = CURRENT_VERSION) : AbstractBackupManager(context) {
internal val databaseHelper: DatabaseHelper by injectLazy() var parserVersion: Int = version
internal val sourceManager: SourceManager by injectLazy()
internal val trackManager: TrackManager by injectLazy()
private val preferences: PreferencesHelper by injectLazy()
/**
* Version of parser
*/
var version: Int = version
private set private set
/**
* Json Parser
*/
var parser: Gson = initParser() var parser: Gson = initParser()
/** /**
@@ -93,12 +82,11 @@ class BackupManager(val context: Context, version: Int = CURRENT_VERSION) {
* @param version version of parser * @param version version of parser
*/ */
internal fun setVersion(version: Int) { internal fun setVersion(version: Int) {
this.version = version this.parserVersion = version
parser = initParser() parser = initParser()
} }
private fun initParser(): Gson = when (version) { private fun initParser(): Gson = when (parserVersion) {
1 -> GsonBuilder().create()
2 -> 2 ->
GsonBuilder() GsonBuilder()
.registerTypeAdapter<MangaImpl>(MangaTypeAdapter.build()) .registerTypeAdapter<MangaImpl>(MangaTypeAdapter.build())
@@ -106,8 +94,11 @@ class BackupManager(val context: Context, version: Int = CURRENT_VERSION) {
.registerTypeAdapter<CategoryImpl>(CategoryTypeAdapter.build()) .registerTypeAdapter<CategoryImpl>(CategoryTypeAdapter.build())
.registerTypeAdapter<DHistory>(HistoryTypeAdapter.build()) .registerTypeAdapter<DHistory>(HistoryTypeAdapter.build())
.registerTypeHierarchyAdapter<TrackImpl>(TrackTypeAdapter.build()) .registerTypeHierarchyAdapter<TrackImpl>(TrackTypeAdapter.build())
// SY -->
.registerTypeAdapter<MergedMangaReference>(MergedMangaReferenceTypeAdapter.build())
// SY <--
.create() .create()
else -> throw Exception("Json version unknown") else -> throw Exception("Unknown backup version")
} }
/** /**
@@ -116,7 +107,7 @@ class BackupManager(val context: Context, version: Int = CURRENT_VERSION) {
* @param uri path of Uri * @param uri path of Uri
* @param isJob backup called from job * @param isJob backup called from job
*/ */
fun createBackup(uri: Uri, flags: Int, isJob: Boolean): String? { override fun createBackup(uri: Uri, flags: Int, isJob: Boolean): String? {
// Create root object // Create root object
val root = JsonObject() val root = JsonObject()
@@ -129,15 +120,20 @@ class BackupManager(val context: Context, version: Int = CURRENT_VERSION) {
// Create extension ID/name mapping // Create extension ID/name mapping
val extensionEntries = JsonArray() val extensionEntries = JsonArray()
// Merged Manga References
val mergedMangaReferenceEntries = JsonArray()
// Add value's to root // Add value's to root
root[Backup.VERSION] = CURRENT_VERSION root[Backup.VERSION] = CURRENT_VERSION
root[Backup.MANGAS] = mangaEntries root[Backup.MANGAS] = mangaEntries
root[CATEGORIES] = categoryEntries root[CATEGORIES] = categoryEntries
root[EXTENSIONS] = extensionEntries root[EXTENSIONS] = extensionEntries
// SY -->
root[MERGEDMANGAREFERENCES] = mergedMangaReferenceEntries
// SY <--
databaseHelper.inTransaction { databaseHelper.inTransaction {
// Get manga from database val mangas = getFavoriteManga()/* SY --> */.filterNot { it.source == MERGED_SOURCE_ID } + getMergedManga().filterNot { it.source == MERGED_SOURCE_ID } /* SY <-- */
val mangas = getFavoriteManga()
val extensions: MutableSet<String> = mutableSetOf() val extensions: MutableSet<String> = mutableSetOf()
@@ -162,44 +158,40 @@ class BackupManager(val context: Context, version: Int = CURRENT_VERSION) {
backupExtensionInfo(extensionEntries, extensions) backupExtensionInfo(extensionEntries, extensions)
// SY --> // SY -->
root[SAVEDSEARCHES] = root[SAVEDSEARCHES] =
Injekt.get<PreferencesHelper>().eh_savedSearches().get().joinToString(separator = "***") Injekt.get<PreferencesHelper>().savedSearches().get().joinToString(separator = "***")
backupMergedMangaReferences(mergedMangaReferenceEntries)
// SY <-- // SY <--
} }
try { try {
// When BackupCreatorJob val file: UniFile = (
if (isJob) { if (isJob) {
// Get dir of file and create // Get dir of file and create
var dir = UniFile.fromUri(context, uri) var dir = UniFile.fromUri(context, uri)
dir = dir.createDirectory("automatic") dir = dir.createDirectory("automatic")
// Delete older backups // Delete older backups
val numberOfBackups = numberOfBackups() val numberOfBackups = numberOfBackups()
val backupRegex = Regex("""tachiyomi_\d+-\d+-\d+_\d+-\d+.json""") val backupRegex = Regex("""tachiyomi_\d+-\d+-\d+_\d+-\d+.json""")
dir.listFiles { _, filename -> backupRegex.matches(filename) } dir.listFiles { _, filename -> backupRegex.matches(filename) }
.orEmpty() .orEmpty()
.sortedByDescending { it.name } .sortedByDescending { it.name }
.drop(numberOfBackups - 1) .drop(numberOfBackups - 1)
.forEach { it.delete() } .forEach { it.delete() }
// Create new file to place backup // Create new file to place backup
val newFile = dir.createFile(Backup.getDefaultFilename()) dir.createFile(Backup.getDefaultFilename())
?: throw Exception("Couldn't create backup file") } else {
UniFile.fromUri(context, uri)
newFile.openOutputStream().bufferedWriter().use {
parser.toJson(root, it)
} }
)
?: throw Exception("Couldn't create backup file")
return newFile.uri.toString() file.openOutputStream().bufferedWriter().use {
} else { parser.toJson(root, it)
val file = UniFile.fromUri(context, uri)
?: throw Exception("Couldn't create backup file")
file.openOutputStream().bufferedWriter().use {
parser.toJson(root, it)
}
return file.uri.toString()
} }
return file.uri.toString()
} catch (e: Exception) { } catch (e: Exception) {
Timber.e(e) Timber.e(e)
throw e throw e
@@ -212,6 +204,13 @@ class BackupManager(val context: Context, version: Int = CURRENT_VERSION) {
} }
} }
// SY -->
private fun backupMergedMangaReferences(root: JsonArray) {
val mergedMangaReferences = databaseHelper.getMergedMangaReferences().executeAsBlocking()
mergedMangaReferences.forEach { root.add(parser.toJsonTree(it)) }
}
// SY <--
/** /**
* Backup the categories of library * Backup the categories of library
* *
@@ -315,31 +314,19 @@ class BackupManager(val context: Context, version: Int = CURRENT_VERSION) {
* @param manga manga that needs updating * @param manga manga that needs updating
* @return [Observable] that contains manga * @return [Observable] that contains manga
*/ */
fun restoreChapterFetchObservable(source: Source, manga: Manga, chapters: List<Chapter>, throttleManager: EHentaiThrottleManager): Observable<Pair<List<Chapter>, List<Chapter>>> { override fun restoreChapterFetchObservable(source: Source, manga: Manga, chapters: List<Chapter>, throttleManager: EHentaiThrottleManager): Observable<Pair<List<Chapter>, List<Chapter>>> {
// SY --> // SY -->
return ( return if (source is MergedSource) {
if (source is EHentai) { val syncedChapters = runBlocking { source.fetchChaptersAndSync(manga, false) }
source.fetchChapterList(manga, throttleManager::throttle) syncedChapters.onEach { pair ->
} else {
source.fetchChapterList(manga)
}
).map {
if (it.last().chapter_number == -99F) {
chapters.forEach { chapter ->
chapter.name = "Chapter ${chapter.chapter_number} restored by dummy source"
}
syncChaptersWithSource(databaseHelper, chapters, manga, source)
} else {
syncChaptersWithSource(databaseHelper, it, manga, source)
}
}
// SY <--
.doOnNext { pair ->
if (pair.first.isNotEmpty()) { if (pair.first.isNotEmpty()) {
chapters.forEach { it.manga_id = manga.id } chapters.forEach { it.manga_id = manga.id }
insertChapters(chapters) updateChapters(chapters)
} }
} }.asObservable()
} else {
super.restoreChapterFetchObservable(source, manga, chapters, throttleManager)
}
} }
/** /**
@@ -359,7 +346,7 @@ class BackupManager(val context: Context, version: Int = CURRENT_VERSION) {
for (dbCategory in dbCategories) { for (dbCategory in dbCategories) {
// If the category is already in the db, assign the id to the file's category // If the category is already in the db, assign the id to the file's category
// and do nothing // and do nothing
if (category.nameLower == dbCategory.nameLower) { if (category.name == dbCategory.name) {
category.id = dbCategory.id category.id = dbCategory.id
found = true found = true
break break
@@ -387,7 +374,7 @@ class BackupManager(val context: Context, version: Int = CURRENT_VERSION) {
val mangaCategoriesToUpdate = mutableListOf<MangaCategory>() val mangaCategoriesToUpdate = mutableListOf<MangaCategory>()
for (backupCategoryStr in categories) { for (backupCategoryStr in categories) {
for (dbCategory in dbCategories) { for (dbCategory in dbCategories) {
if (backupCategoryStr.toLowerCase() == dbCategory.nameLower) { if (backupCategoryStr == dbCategory.name) {
mangaCategoriesToUpdate.add(MangaCategory.create(manga, dbCategory)) mangaCategoriesToUpdate.add(MangaCategory.create(manga, dbCategory))
break break
} }
@@ -504,32 +491,19 @@ class BackupManager(val context: Context, version: Int = CURRENT_VERSION) {
chapters.filter { it.id != null } chapters.filter { it.id != null }
chapters.map { it.manga_id = manga.id } chapters.map { it.manga_id = manga.id }
insertChapters(chapters) updateChapters(chapters)
return true return true
} }
// SY --> // SY -->
internal fun restoreSavedSearches(jsonSavedSearches: JsonElement) { internal fun restoreSavedSearches(jsonSavedSearches: JsonElement) {
val backupSavedSearches = jsonSavedSearches.asString.split("***").toSet() val backupSavedSearches = jsonSavedSearches.asString.split("***").toSet()
val filterSerializer = FilterSerializer()
val newSavedSearches = backupSavedSearches.mapNotNull { val newSavedSearches = backupSavedSearches.mapNotNull {
try { try {
val id = it.substringBefore(':').toLong() val id = it.substringBefore(':').toLong()
val content = JsonParser.parseString(it.substringAfter(':')).obj val content = Json.decodeFromString<JsonSavedSearch>(it.substringAfter(':'))
val source = sourceManager.getOrStub(id) id to content
if (source !is CatalogueSource) return@mapNotNull null
val originalFilters = source.getFilterList()
filterSerializer.deserialize(originalFilters, content["filters"].array)
Pair(
id,
EXHSavedSearch(
content["name"].string,
content["query"].string,
originalFilters
)
)
} catch (t: RuntimeException) { } catch (t: RuntimeException) {
// Load failed // Load failed
Timber.e(t, "Failed to load saved search!") Timber.e(t, "Failed to load saved search!")
@@ -540,24 +514,11 @@ class BackupManager(val context: Context, version: Int = CURRENT_VERSION) {
val currentSources = newSavedSearches.map { it.first }.toSet() val currentSources = newSavedSearches.map { it.first }.toSet()
newSavedSearches += preferences.eh_savedSearches().get().mapNotNull { newSavedSearches += preferences.savedSearches().get().mapNotNull {
try { try {
val id = it.substringBefore(':').toLong() val id = it.substringBefore(':').toLong()
val content = JsonParser.parseString(it.substringAfter(':')).obj val content = Json.decodeFromString<JsonSavedSearch>(it.substringAfter(':'))
if (id !in currentSources) return@mapNotNull null id to content
val source = sourceManager.getOrStub(id)
if (source !is CatalogueSource) return@mapNotNull null
val originalFilters = source.getFilterList()
filterSerializer.deserialize(originalFilters, content["filters"].array)
Pair(
id,
EXHSavedSearch(
content["name"].string,
content["query"].string,
originalFilters
)
)
} catch (t: RuntimeException) { } catch (t: RuntimeException) {
// Load failed // Load failed
Timber.e(t, "Failed to load saved search!") Timber.e(t, "Failed to load saved search!")
@@ -566,61 +527,67 @@ class BackupManager(val context: Context, version: Int = CURRENT_VERSION) {
} }
}.toMutableList() }.toMutableList()
val otherSerialized = preferences.eh_savedSearches().get().mapNotNull { val otherSerialized = preferences.savedSearches().get().mapNotNull {
val sourceId = it.split(":")[0].toLongOrNull() ?: return@mapNotNull null val sourceId = it.split(":")[0].toLongOrNull() ?: return@mapNotNull null
if (sourceId in currentSources) return@mapNotNull null if (sourceId in currentSources) return@mapNotNull null
it it
} }
/*.filter {
!it.startsWith("${newSource.id}:")
}*/
val newSerialized = newSavedSearches.map { val newSerialized = newSavedSearches.map {
"${it.first}:" + jsonObject( "${it.first}:" + Json.encodeToString(it.second)
"name" to it.second.name, }
"query" to it.second.query, preferences.savedSearches().set((otherSerialized + newSerialized).toSet())
"filters" to filterSerializer.serialize(it.second.filterList) }
).toString()
/**
* Restore the categories from Json
*
* @param jsonMergedMangaReferences array containing md manga references
*/
internal fun restoreMergedMangaReferences(jsonMergedMangaReferences: JsonArray) {
// Get merged manga references from file and from db
val dbMergedMangaReferences = databaseHelper.getMergedMangaReferences().executeAsBlocking()
val backupMergedMangaReferences = parser.fromJson<List<MergedMangaReference>>(jsonMergedMangaReferences)
var lastMergeManga: Manga? = null
// Iterate over them
backupMergedMangaReferences.forEach { mergedMangaReference ->
// Used to know if the merged manga reference is already in the db
var found = false
for (dbMergedMangaReference in dbMergedMangaReferences) {
// If the mergedMangaReference is already in the db, assign the id to the file's mergedMangaReference
// and do nothing
if (mergedMangaReference.mergeUrl == dbMergedMangaReference.mergeUrl && mergedMangaReference.mangaUrl == dbMergedMangaReference.mangaUrl) {
mergedMangaReference.id = dbMergedMangaReference.id
mergedMangaReference.mergeId = dbMergedMangaReference.mergeId
mergedMangaReference.mangaId = dbMergedMangaReference.mangaId
found = true
break
}
}
// If the mergedMangaReference isn't in the db, remove the id and insert a new mergedMangaReference
// Store the inserted id in the mergedMangaReference
if (!found) {
// Let the db assign the id
var mergedManga = if (mergedMangaReference.mergeUrl != lastMergeManga?.url) databaseHelper.getManga(mergedMangaReference.mergeUrl, MERGED_SOURCE_ID).executeAsBlocking() else lastMergeManga
if (mergedManga == null) {
mergedManga = Manga.create(MERGED_SOURCE_ID).apply {
url = mergedMangaReference.mergeUrl
title = context.getString(R.string.refresh_merge)
}
mergedManga.id = databaseHelper.insertManga(mergedManga).executeAsBlocking().insertedId()
}
val manga = databaseHelper.getManga(mergedMangaReference.mangaUrl, mergedMangaReference.mangaSourceId).executeAsBlocking() ?: return@forEach
lastMergeManga = mergedManga
mergedMangaReference.mergeId = mergedManga.id
mergedMangaReference.mangaId = manga.id
mergedMangaReference.id = null
val result = databaseHelper.insertMergedManga(mergedMangaReference).executeAsBlocking()
mergedMangaReference.id = result.insertedId()
}
} }
preferences.eh_savedSearches().set((otherSerialized + newSerialized).toSet())
} }
// SY <-- // SY <--
/**
* Returns manga
*
* @return [Manga], null if not found
*/
internal fun getMangaFromDatabase(manga: Manga): Manga? =
databaseHelper.getManga(manga.url, manga.source).executeAsBlocking()
/**
* Returns list containing manga from library
*
* @return [Manga] from library
*/
internal fun getFavoriteManga(): List<Manga> =
databaseHelper.getFavoriteMangas().executeAsBlocking()
/**
* Inserts manga and returns id
*
* @return id of [Manga], null if not found
*/
internal fun insertManga(manga: Manga): Long? =
databaseHelper.insertManga(manga).executeAsBlocking().insertedId()
/**
* Inserts list of chapters
*/
private fun insertChapters(chapters: List<Chapter>) {
databaseHelper.updateChaptersBackup(chapters).executeAsBlocking()
}
/**
* Return number of backups.
*
* @return number of backups selected by user
*/
fun numberOfBackups(): Int = preferences.numberOfBackups().get()
} }
@@ -0,0 +1,241 @@
package eu.kanade.tachiyomi.data.backup.legacy
import android.content.Context
import android.net.Uri
import com.github.salomonbrys.kotson.fromJson
import com.google.gson.JsonArray
import com.google.gson.JsonElement
import com.google.gson.JsonObject
import com.google.gson.JsonParser
import com.google.gson.stream.JsonReader
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.backup.AbstractBackupRestore
import eu.kanade.tachiyomi.data.backup.BackupNotifier
import eu.kanade.tachiyomi.data.backup.legacy.models.Backup
import eu.kanade.tachiyomi.data.backup.legacy.models.Backup.MANGAS
import eu.kanade.tachiyomi.data.backup.legacy.models.DHistory
import eu.kanade.tachiyomi.data.database.models.Chapter
import eu.kanade.tachiyomi.data.database.models.ChapterImpl
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.database.models.MangaImpl
import eu.kanade.tachiyomi.data.database.models.Track
import eu.kanade.tachiyomi.data.database.models.TrackImpl
import eu.kanade.tachiyomi.source.Source
import exh.EXHMigrations
import rx.Observable
import java.util.Date
class LegacyBackupRestore(context: Context, notifier: BackupNotifier) : AbstractBackupRestore<LegacyBackupManager>(context, notifier) {
override fun performRestore(uri: Uri): Boolean {
// SY -->
throttleManager.resetThrottle()
// SY <--
val reader = JsonReader(context.contentResolver.openInputStream(uri)!!.bufferedReader())
val json = JsonParser.parseReader(reader).asJsonObject
val version = json.get(Backup.VERSION)?.asInt ?: 1
backupManager = LegacyBackupManager(context, version)
val mangasJson = json.get(MANGAS).asJsonArray
restoreAmount = mangasJson.size() + 3 // +1 for categories, +1 for saved searches, +1 for merged manga references
// Restore categories
json.get(Backup.CATEGORIES)?.let { restoreCategories(it) }
// SY -->
json.get(Backup.SAVEDSEARCHES)?.let { restoreSavedSearches(it) }
json.get(Backup.MERGEDMANGAREFERENCES)?.let { restoreMergedMangaReferences(it) }
// SY <--
// Store source mapping for error messages
sourceMapping = LegacyBackupRestoreValidator.getSourceMapping(json)
// Restore individual manga
mangasJson.forEach {
if (job?.isActive != true) {
return false
}
restoreManga(it.asJsonObject)
}
return true
}
private fun restoreCategories(categoriesJson: JsonElement) {
db.inTransaction {
backupManager.restoreCategories(categoriesJson.asJsonArray)
}
restoreProgress += 1
showRestoreProgress(restoreProgress, restoreAmount, context.getString(R.string.categories))
}
// SY -->
private fun restoreSavedSearches(savedSearchesJson: JsonElement) {
backupManager.restoreSavedSearches(savedSearchesJson)
restoreProgress += 1
showRestoreProgress(restoreProgress, restoreAmount, context.getString(R.string.saved_searches))
}
private fun restoreMergedMangaReferences(mergedMangaReferencesJson: JsonElement) {
db.inTransaction {
backupManager.restoreMergedMangaReferences(mergedMangaReferencesJson.asJsonArray)
}
restoreProgress += 1
showRestoreProgress(restoreProgress, restoreAmount, context.getString(R.string.merged_references))
}
// SY <--
private fun restoreManga(mangaJson: JsonObject) {
/* SY --> */ var /* SY <-- */ manga = backupManager.parser.fromJson<MangaImpl>(
mangaJson.get(
Backup.MANGA
)
)
val chapters = backupManager.parser.fromJson<List<ChapterImpl>>(
mangaJson.get(Backup.CHAPTERS)
?: JsonArray()
)
val categories = backupManager.parser.fromJson<List<String>>(
mangaJson.get(Backup.CATEGORIES)
?: JsonArray()
)
val history = backupManager.parser.fromJson<List<DHistory>>(
mangaJson.get(Backup.HISTORY)
?: JsonArray()
)
val tracks = backupManager.parser.fromJson<List<TrackImpl>>(
mangaJson.get(Backup.TRACK)
?: JsonArray()
)
// EXH -->
manga = EXHMigrations.migrateBackupEntry(manga)
// <-- EXH
try {
val source = backupManager.sourceManager.get(manga.source)
if (source != null) {
restoreMangaData(manga, source, chapters, categories, history, tracks)
} else {
val sourceName = sourceMapping[manga.source] ?: manga.source.toString()
errors.add(Date() to "${manga.title} - ${context.getString(R.string.source_not_found_name, sourceName)}")
}
} catch (e: Exception) {
errors.add(Date() to "${manga.title} - ${e.message}")
}
restoreProgress += 1
showRestoreProgress(restoreProgress, restoreAmount, manga.title)
}
/**
* Returns a manga restore observable
*
* @param manga manga data from json
* @param source source to get manga data from
* @param chapters chapters data from json
* @param categories categories data from json
* @param history history data from json
* @param tracks tracking data from json
*/
private fun restoreMangaData(
manga: Manga,
source: Source,
chapters: List<Chapter>,
categories: List<String>,
history: List<DHistory>,
tracks: List<Track>
) {
val dbManga = backupManager.getMangaFromDatabase(manga)
db.inTransaction {
if (dbManga == null) {
// Manga not in database
restoreMangaFetch(source, manga, chapters, categories, history, tracks)
} else { // Manga in database
// Copy information from manga already in database
backupManager.restoreMangaNoFetch(manga, dbManga)
// Fetch rest of manga information
restoreMangaNoFetch(source, manga, chapters, categories, history, tracks)
}
}
}
/**
* [Observable] that fetches manga information
*
* @param manga manga that needs updating
* @param chapters chapters of manga that needs updating
* @param categories categories that need updating
*/
private fun restoreMangaFetch(
source: Source,
manga: Manga,
chapters: List<Chapter>,
categories: List<String>,
history: List<DHistory>,
tracks: List<Track>
) {
backupManager.restoreMangaFetchObservable(source, manga)
.onErrorReturn {
errors.add(Date() to "${manga.title} - ${it.message}")
manga
}
.filter { it.id != null }
.flatMap {
chapterFetchObservable(source, it, chapters)
// Convert to the manga that contains new chapters.
.map { manga }
}
.doOnNext {
restoreExtraForManga(it, categories, history, tracks)
}
.flatMap {
trackingFetchObservable(it, tracks)
}
.subscribe()
}
private fun restoreMangaNoFetch(
source: Source,
backupManga: Manga,
chapters: List<Chapter>,
categories: List<String>,
history: List<DHistory>,
tracks: List<Track>
) {
Observable.just(backupManga)
.flatMap { manga ->
if (!backupManager.restoreChaptersForManga(manga, chapters)) {
chapterFetchObservable(source, manga, chapters)
.map { manga }
} else {
Observable.just(manga)
}
}
.doOnNext {
restoreExtraForManga(it, categories, history, tracks)
}
.flatMap { manga ->
trackingFetchObservable(manga, tracks)
}
.subscribe()
}
private fun restoreExtraForManga(manga: Manga, categories: List<String>, history: List<DHistory>, tracks: List<Track>) {
// Restore categories
backupManager.restoreCategoriesForManga(manga, categories)
// Restore history
backupManager.restoreHistoryForManga(history)
// Restore tracking
backupManager.restoreTrackForManga(manga, tracks)
}
}
@@ -0,0 +1,66 @@
package eu.kanade.tachiyomi.data.backup.legacy
import android.content.Context
import android.net.Uri
import com.google.gson.JsonObject
import com.google.gson.JsonParser
import com.google.gson.stream.JsonReader
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.backup.AbstractBackupRestoreValidator
import eu.kanade.tachiyomi.data.backup.legacy.models.Backup
class LegacyBackupRestoreValidator : AbstractBackupRestoreValidator() {
/**
* Checks for critical backup file data.
*
* @throws Exception if version or manga cannot be found.
* @return List of missing sources or missing trackers.
*/
override fun validate(context: Context, uri: Uri): Results {
val reader = JsonReader(context.contentResolver.openInputStream(uri)!!.bufferedReader())
val json = JsonParser.parseReader(reader).asJsonObject
val version = json.get(Backup.VERSION)
val mangasJson = json.get(Backup.MANGAS)
if (version == null || mangasJson == null) {
throw Exception(context.getString(R.string.invalid_backup_file_missing_data))
}
val mangas = mangasJson.asJsonArray
if (mangas.size() == 0) {
throw Exception(context.getString(R.string.invalid_backup_file_missing_manga))
}
val sources = getSourceMapping(json)
val missingSources = sources
.filter { sourceManager.get(it.key) == null }
.values
.sorted()
val trackers = mangas
.filter { it.asJsonObject.has("track") }
.flatMap { it.asJsonObject["track"].asJsonArray }
.map { it.asJsonObject["s"].asInt }
.distinct()
val missingTrackers = trackers
.mapNotNull { trackManager.getService(it) }
.filter { !it.isLogged }
.map { it.name }
.sorted()
return Results(missingSources, missingTrackers)
}
companion object {
fun getSourceMapping(json: JsonObject): Map<Long, String> {
val extensionsMapping = json.get(Backup.EXTENSIONS) ?: return emptyMap()
return extensionsMapping.asJsonArray
.map {
val items = it.asString.split(":")
items[0].toLong() to items[1]
}
.toMap()
}
}
}
@@ -1,4 +1,4 @@
package eu.kanade.tachiyomi.data.backup.models package eu.kanade.tachiyomi.data.backup.legacy.models
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Date import java.util.Date
@@ -17,8 +17,10 @@ object Backup {
const val EXTENSIONS = "extensions" const val EXTENSIONS = "extensions"
const val HISTORY = "history" const val HISTORY = "history"
const val VERSION = "version" const val VERSION = "version"
// SY --> // SY -->
const val SAVEDSEARCHES = "savedsearches" const val SAVEDSEARCHES = "savedsearches"
const val MERGEDMANGAREFERENCES = "mergedmangareferences"
// SY <-- // SY <--
fun getDefaultFilename(): String { fun getDefaultFilename(): String {
@@ -1,3 +1,3 @@
package eu.kanade.tachiyomi.data.backup.models package eu.kanade.tachiyomi.data.backup.legacy.models
data class DHistory(val url: String, val lastRead: Long) data class DHistory(val url: String, val lastRead: Long)
@@ -1,4 +1,4 @@
package eu.kanade.tachiyomi.data.backup.serializer package eu.kanade.tachiyomi.data.backup.legacy.serializer
import com.github.salomonbrys.kotson.typeAdapter import com.github.salomonbrys.kotson.typeAdapter
import com.google.gson.TypeAdapter import com.google.gson.TypeAdapter
@@ -1,4 +1,4 @@
package eu.kanade.tachiyomi.data.backup.serializer package eu.kanade.tachiyomi.data.backup.legacy.serializer
import com.github.salomonbrys.kotson.typeAdapter import com.github.salomonbrys.kotson.typeAdapter
import com.google.gson.TypeAdapter import com.google.gson.TypeAdapter
@@ -1,8 +1,8 @@
package eu.kanade.tachiyomi.data.backup.serializer package eu.kanade.tachiyomi.data.backup.legacy.serializer
import com.github.salomonbrys.kotson.typeAdapter import com.github.salomonbrys.kotson.typeAdapter
import com.google.gson.TypeAdapter import com.google.gson.TypeAdapter
import eu.kanade.tachiyomi.data.backup.models.DHistory import eu.kanade.tachiyomi.data.backup.legacy.models.DHistory
/** /**
* JSON Serializer used to write / read [DHistory] to / from json * JSON Serializer used to write / read [DHistory] to / from json
@@ -1,4 +1,4 @@
package eu.kanade.tachiyomi.data.backup.serializer package eu.kanade.tachiyomi.data.backup.legacy.serializer
import com.github.salomonbrys.kotson.typeAdapter import com.github.salomonbrys.kotson.typeAdapter
import com.google.gson.TypeAdapter import com.google.gson.TypeAdapter
@@ -14,7 +14,9 @@ object MangaTypeAdapter {
write { write {
beginArray() beginArray()
value(it.url) value(it.url)
value(it.title) // SY -->
value(it.originalTitle)
// SY <--
value(it.source) value(it.source)
value(it.viewer) value(it.viewer)
value(it.chapter_flags) value(it.chapter_flags)
@@ -0,0 +1,45 @@
package eu.kanade.tachiyomi.data.backup.legacy.serializer
import com.github.salomonbrys.kotson.typeAdapter
import com.google.gson.TypeAdapter
import exh.merged.sql.models.MergedMangaReference
/**
* JSON Serializer used to write / read [MergedMangaReference] to / from json
*/
object MergedMangaReferenceTypeAdapter {
fun build(): TypeAdapter<MergedMangaReference> {
return typeAdapter {
write {
beginArray()
value(it.mangaUrl)
value(it.mergeUrl)
value(it.mangaSourceId)
value(it.chapterSortMode)
value(it.chapterPriority)
value(it.getChapterUpdates)
value(it.isInfoManga)
value(it.downloadChapters)
endArray()
}
read {
beginArray()
MergedMangaReference(
id = null,
mangaUrl = nextString(),
mergeUrl = nextString(),
mangaSourceId = nextLong(),
chapterSortMode = nextInt(),
chapterPriority = nextInt(),
getChapterUpdates = nextBoolean(),
isInfoManga = nextBoolean(),
downloadChapters = nextBoolean(),
mangaId = null,
mergeId = null
)
}
}
}
}
@@ -1,4 +1,4 @@
package eu.kanade.tachiyomi.data.backup.serializer package eu.kanade.tachiyomi.data.backup.legacy.serializer
import com.github.salomonbrys.kotson.typeAdapter import com.github.salomonbrys.kotson.typeAdapter
import com.google.gson.TypeAdapter import com.google.gson.TypeAdapter
@@ -10,8 +10,6 @@ import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.source.model.Page import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.util.storage.DiskUtil import eu.kanade.tachiyomi.util.storage.DiskUtil
import eu.kanade.tachiyomi.util.storage.saveTo import eu.kanade.tachiyomi.util.storage.saveTo
import java.io.File
import java.io.IOException
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
@@ -22,6 +20,8 @@ import okio.buffer
import okio.sink import okio.sink
import rx.Observable import rx.Observable
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import java.io.File
import java.io.IOException
/** /**
* Class used to create chapter cache * Class used to create chapter cache
@@ -56,10 +56,10 @@ class ChapterCache(private val context: Context) {
/** Cache class used for cache management. */ /** Cache class used for cache management. */
// --> EH // --> EH
private var diskCache = setupDiskCache(prefs.eh_cacheSize().get().toLong()) private var diskCache = setupDiskCache(prefs.cacheSize().get().toLong())
init { init {
prefs.eh_cacheSize().asFlow() prefs.cacheSize().asFlow()
.onEach { .onEach {
// Save old cache for destruction later // Save old cache for destruction later
val oldCache = diskCache val oldCache = diskCache
@@ -21,6 +21,12 @@ import eu.kanade.tachiyomi.data.database.queries.HistoryQueries
import eu.kanade.tachiyomi.data.database.queries.MangaCategoryQueries import eu.kanade.tachiyomi.data.database.queries.MangaCategoryQueries
import eu.kanade.tachiyomi.data.database.queries.MangaQueries import eu.kanade.tachiyomi.data.database.queries.MangaQueries
import eu.kanade.tachiyomi.data.database.queries.TrackQueries import eu.kanade.tachiyomi.data.database.queries.TrackQueries
import exh.md.similar.sql.mappers.SimilarTypeMapping
import exh.md.similar.sql.models.MangaSimilar
import exh.md.similar.sql.queries.SimilarQueries
import exh.merged.sql.mappers.MergedMangaTypeMapping
import exh.merged.sql.models.MergedMangaReference
import exh.merged.sql.queries.MergedQueries
import exh.metadata.sql.mappers.SearchMetadataTypeMapping import exh.metadata.sql.mappers.SearchMetadataTypeMapping
import exh.metadata.sql.mappers.SearchTagTypeMapping import exh.metadata.sql.mappers.SearchTagTypeMapping
import exh.metadata.sql.mappers.SearchTitleTypeMapping import exh.metadata.sql.mappers.SearchTitleTypeMapping
@@ -36,7 +42,7 @@ import io.requery.android.database.sqlite.RequerySQLiteOpenHelperFactory
* This class provides operations to manage the database through its interfaces. * This class provides operations to manage the database through its interfaces.
*/ */
open class DatabaseHelper(context: Context) : open class DatabaseHelper(context: Context) :
MangaQueries, ChapterQueries, TrackQueries, CategoryQueries, MangaCategoryQueries, HistoryQueries /* EXH --> */, SearchMetadataQueries, SearchTagQueries, SearchTitleQueries /* EXH <-- */ { MangaQueries, ChapterQueries, TrackQueries, CategoryQueries, MangaCategoryQueries, HistoryQueries /* SY --> */, SearchMetadataQueries, SearchTagQueries, SearchTitleQueries, MergedQueries, SimilarQueries /* SY <-- */ {
private val configuration = SupportSQLiteOpenHelper.Configuration.builder(context) private val configuration = SupportSQLiteOpenHelper.Configuration.builder(context)
.name(DbOpenCallback.DATABASE_NAME) .name(DbOpenCallback.DATABASE_NAME)
@@ -51,11 +57,13 @@ open class DatabaseHelper(context: Context) :
.addTypeMapping(Category::class.java, CategoryTypeMapping()) .addTypeMapping(Category::class.java, CategoryTypeMapping())
.addTypeMapping(MangaCategory::class.java, MangaCategoryTypeMapping()) .addTypeMapping(MangaCategory::class.java, MangaCategoryTypeMapping())
.addTypeMapping(History::class.java, HistoryTypeMapping()) .addTypeMapping(History::class.java, HistoryTypeMapping())
// EXH --> // SY -->
.addTypeMapping(SearchMetadata::class.java, SearchMetadataTypeMapping()) .addTypeMapping(SearchMetadata::class.java, SearchMetadataTypeMapping())
.addTypeMapping(SearchTag::class.java, SearchTagTypeMapping()) .addTypeMapping(SearchTag::class.java, SearchTagTypeMapping())
.addTypeMapping(SearchTitle::class.java, SearchTitleTypeMapping()) .addTypeMapping(SearchTitle::class.java, SearchTitleTypeMapping())
// EXH <-- .addTypeMapping(MergedMangaReference::class.java, MergedMangaTypeMapping())
.addTypeMapping(MangaSimilar::class.java, SimilarTypeMapping())
// SY <--
.build() .build()
inline fun inTransaction(block: () -> Unit) = db.inTransaction(block) inline fun inTransaction(block: () -> Unit) = db.inTransaction(block)
@@ -7,8 +7,9 @@ import eu.kanade.tachiyomi.data.database.tables.ChapterTable
import eu.kanade.tachiyomi.data.database.tables.HistoryTable import eu.kanade.tachiyomi.data.database.tables.HistoryTable
import eu.kanade.tachiyomi.data.database.tables.MangaCategoryTable import eu.kanade.tachiyomi.data.database.tables.MangaCategoryTable
import eu.kanade.tachiyomi.data.database.tables.MangaTable import eu.kanade.tachiyomi.data.database.tables.MangaTable
import eu.kanade.tachiyomi.data.database.tables.MergedTable
import eu.kanade.tachiyomi.data.database.tables.TrackTable import eu.kanade.tachiyomi.data.database.tables.TrackTable
import exh.md.similar.sql.tables.SimilarTable
import exh.merged.sql.tables.MergedTable
import exh.metadata.sql.tables.SearchMetadataTable import exh.metadata.sql.tables.SearchMetadataTable
import exh.metadata.sql.tables.SearchTagTable import exh.metadata.sql.tables.SearchTagTable
import exh.metadata.sql.tables.SearchTitleTable import exh.metadata.sql.tables.SearchTitleTable
@@ -24,7 +25,7 @@ class DbOpenCallback : SupportSQLiteOpenHelper.Callback(DATABASE_VERSION) {
/** /**
* Version of the database. * Version of the database.
*/ */
const val DATABASE_VERSION = /* SY --> */ 2 /* SY <-- */ const val DATABASE_VERSION = /* SY --> */ 5 /* SY <-- */
} }
override fun onCreate(db: SupportSQLiteDatabase) = with(db) { override fun onCreate(db: SupportSQLiteDatabase) = with(db) {
@@ -34,14 +35,13 @@ class DbOpenCallback : SupportSQLiteOpenHelper.Callback(DATABASE_VERSION) {
execSQL(CategoryTable.createTableQuery) execSQL(CategoryTable.createTableQuery)
execSQL(MangaCategoryTable.createTableQuery) execSQL(MangaCategoryTable.createTableQuery)
execSQL(HistoryTable.createTableQuery) execSQL(HistoryTable.createTableQuery)
// EXH --> // SY -->
execSQL(SearchMetadataTable.createTableQuery) execSQL(SearchMetadataTable.createTableQuery)
execSQL(SearchTagTable.createTableQuery) execSQL(SearchTagTable.createTableQuery)
execSQL(SearchTitleTable.createTableQuery) execSQL(SearchTitleTable.createTableQuery)
// EXH <--
// AZ -->
execSQL(MergedTable.createTableQuery) execSQL(MergedTable.createTableQuery)
// AZ <-- execSQL(SimilarTable.createTableQuery)
// SY <--
// DB indexes // DB indexes
execSQL(MangaTable.createUrlIndexQuery) execSQL(MangaTable.createUrlIndexQuery)
@@ -49,23 +49,35 @@ class DbOpenCallback : SupportSQLiteOpenHelper.Callback(DATABASE_VERSION) {
execSQL(ChapterTable.createMangaIdIndexQuery) execSQL(ChapterTable.createMangaIdIndexQuery)
execSQL(ChapterTable.createUnreadChaptersIndexQuery) execSQL(ChapterTable.createUnreadChaptersIndexQuery)
execSQL(HistoryTable.createChapterIdIndexQuery) execSQL(HistoryTable.createChapterIdIndexQuery)
// EXH --> // SY -->
db.execSQL(SearchMetadataTable.createUploaderIndexQuery) execSQL(SearchMetadataTable.createUploaderIndexQuery)
db.execSQL(SearchMetadataTable.createIndexedExtraIndexQuery) execSQL(SearchMetadataTable.createIndexedExtraIndexQuery)
db.execSQL(SearchTagTable.createMangaIdIndexQuery) execSQL(SearchTagTable.createMangaIdIndexQuery)
db.execSQL(SearchTagTable.createNamespaceNameIndexQuery) execSQL(SearchTagTable.createNamespaceNameIndexQuery)
db.execSQL(SearchTitleTable.createMangaIdIndexQuery) execSQL(SearchTitleTable.createMangaIdIndexQuery)
db.execSQL(SearchTitleTable.createTitleIndexQuery) execSQL(SearchTitleTable.createTitleIndexQuery)
// EXH <--
// AZ -->
execSQL(MergedTable.createIndexQuery) execSQL(MergedTable.createIndexQuery)
// AZ <-- execSQL(SimilarTable.createMangaIdIndexQuery)
// SY <--
} }
override fun onUpgrade(db: SupportSQLiteDatabase, oldVersion: Int, newVersion: Int) { override fun onUpgrade(db: SupportSQLiteDatabase, oldVersion: Int, newVersion: Int) {
if (oldVersion < 2) { if (oldVersion < 2) {
db.execSQL(MangaTable.addCoverLastModified) db.execSQL(MangaTable.addCoverLastModified)
} }
if (oldVersion < 3) {
db.execSQL(MangaTable.addDateAdded)
db.execSQL(MangaTable.backfillDateAdded)
}
if (oldVersion < 4) {
db.execSQL(MergedTable.dropTableQuery)
db.execSQL(MergedTable.createTableQuery)
db.execSQL(MergedTable.createIndexQuery)
}
if (oldVersion < 5) {
db.execSQL(SimilarTable.createTableQuery)
db.execSQL(SimilarTable.createMangaIdIndexQuery)
}
} }
override fun onConfigure(db: SupportSQLiteDatabase) { override fun onConfigure(db: SupportSQLiteDatabase) {
@@ -58,7 +58,7 @@ class CategoryGetResolver : DefaultGetResolver<Category>() {
// SY --> // SY -->
val orderString = cursor.getString(cursor.getColumnIndex(COL_MANGA_ORDER)) val orderString = cursor.getString(cursor.getColumnIndex(COL_MANGA_ORDER))
mangaOrder = orderString?.split("/")?.mapNotNull { it.toLongOrNull() } ?: emptyList() mangaOrder = orderString?.split("/")?.mapNotNull { it.toLongOrNull() }.orEmpty()
// SY <-- // SY <--
} }
} }
@@ -15,6 +15,7 @@ import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_ARTIST
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_AUTHOR import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_AUTHOR
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_CHAPTER_FLAGS import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_CHAPTER_FLAGS
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_COVER_LAST_MODIFIED import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_COVER_LAST_MODIFIED
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_DATE_ADDED
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_DESCRIPTION import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_DESCRIPTION
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_FAVORITE import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_FAVORITE
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_GENRE import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_GENRE
@@ -47,15 +48,17 @@ class MangaPutResolver : DefaultPutResolver<Manga>() {
.whereArgs(obj.id) .whereArgs(obj.id)
.build() .build()
override fun mapToContentValues(obj: Manga) = ContentValues(15).apply { override fun mapToContentValues(obj: Manga) = ContentValues(17).apply {
put(COL_ID, obj.id) put(COL_ID, obj.id)
put(COL_SOURCE, obj.source) put(COL_SOURCE, obj.source)
put(COL_URL, obj.url) put(COL_URL, obj.url)
put(COL_ARTIST, obj.artist) // SY -->
put(COL_AUTHOR, obj.author) put(COL_ARTIST, obj.originalArtist)
put(COL_DESCRIPTION, obj.description) put(COL_AUTHOR, obj.originalAuthor)
put(COL_GENRE, obj.genre) put(COL_DESCRIPTION, obj.originalDescription)
put(COL_TITLE, obj.title) put(COL_GENRE, obj.originalGenre)
put(COL_TITLE, obj.originalTitle)
// SY <--
put(COL_STATUS, obj.status) put(COL_STATUS, obj.status)
put(COL_THUMBNAIL_URL, obj.thumbnail_url) put(COL_THUMBNAIL_URL, obj.thumbnail_url)
put(COL_FAVORITE, obj.favorite) put(COL_FAVORITE, obj.favorite)
@@ -64,6 +67,7 @@ class MangaPutResolver : DefaultPutResolver<Manga>() {
put(COL_VIEWER, obj.viewer) put(COL_VIEWER, obj.viewer)
put(COL_CHAPTER_FLAGS, obj.chapter_flags) put(COL_CHAPTER_FLAGS, obj.chapter_flags)
put(COL_COVER_LAST_MODIFIED, obj.cover_last_modified) put(COL_COVER_LAST_MODIFIED, obj.cover_last_modified)
put(COL_DATE_ADDED, obj.date_added)
} }
} }
@@ -85,6 +89,7 @@ interface BaseMangaGetResolver {
viewer = cursor.getInt(cursor.getColumnIndex(COL_VIEWER)) viewer = cursor.getInt(cursor.getColumnIndex(COL_VIEWER))
chapter_flags = cursor.getInt(cursor.getColumnIndex(COL_CHAPTER_FLAGS)) chapter_flags = cursor.getInt(cursor.getColumnIndex(COL_CHAPTER_FLAGS))
cover_last_modified = cursor.getLong(cursor.getColumnIndex(COL_COVER_LAST_MODIFIED)) cover_last_modified = cursor.getLong(cursor.getColumnIndex(COL_COVER_LAST_MODIFIED))
date_added = cursor.getLong(cursor.getColumnIndex(COL_DATE_ADDED))
} }
} }
@@ -16,9 +16,6 @@ interface Category : Serializable {
var mangaOrder: List<Long> var mangaOrder: List<Long>
// SY <-- // SY <--
val nameLower: String
get() = name.toLowerCase()
companion object { companion object {
fun create(name: String): Category = CategoryImpl().apply { fun create(name: String): Category = CategoryImpl().apply {
@@ -19,7 +19,6 @@ class CategoryImpl : Category {
if (other == null || javaClass != other.javaClass) return false if (other == null || javaClass != other.javaClass) return false
val category = other as Category val category = other as Category
return name == category.name return name == category.name
} }
@@ -31,10 +31,11 @@ class ChapterImpl : Chapter {
if (other == null || javaClass != other.javaClass) return false if (other == null || javaClass != other.javaClass) return false
val chapter = other as Chapter val chapter = other as Chapter
return url == chapter.url if (url != chapter.url) return false
return id == chapter.id
} }
override fun hashCode(): Int { override fun hashCode(): Int {
return url.hashCode() return url.hashCode() + id.hashCode()
} }
} }
@@ -5,4 +5,8 @@ class LibraryManga : MangaImpl() {
var unread: Int = 0 var unread: Int = 0
var category: Int = 0 var category: Int = 0
// SY -->
var read: Int = 0
// SY <--
} }
@@ -1,6 +1,7 @@
package eu.kanade.tachiyomi.data.database.models package eu.kanade.tachiyomi.data.database.models
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import tachiyomi.source.model.MangaInfo
interface Manga : SManga { interface Manga : SManga {
@@ -12,6 +13,8 @@ interface Manga : SManga {
var last_update: Long var last_update: Long
var date_added: Long
var viewer: Int var viewer: Int
var chapter_flags: Int var chapter_flags: Int
@@ -22,10 +25,6 @@ interface Manga : SManga {
setFlags(order, SORT_MASK) setFlags(order, SORT_MASK)
} }
private fun setFlags(flag: Int, mask: Int) {
chapter_flags = chapter_flags and mask.inv() or (flag and mask)
}
fun sortDescending(): Boolean { fun sortDescending(): Boolean {
return chapter_flags and SORT_MASK == SORT_DESC return chapter_flags and SORT_MASK == SORT_DESC
} }
@@ -34,6 +33,16 @@ interface Manga : SManga {
return genre?.split(", ")?.map { it.trim() } return genre?.split(", ")?.map { it.trim() }
} }
// SY -->
fun getOriginalGenres(): List<String>? {
return originalGenre?.split(", ")?.map { it.trim() }
}
// SY <--
private fun setFlags(flag: Int, mask: Int) {
chapter_flags = chapter_flags and mask.inv() or (flag and mask)
}
// Used to display the chapter's title one way or another // Used to display the chapter's title one way or another
var displayMode: Int var displayMode: Int
get() = chapter_flags and DISPLAY_MASK get() = chapter_flags and DISPLAY_MASK
@@ -96,3 +105,16 @@ interface Manga : SManga {
} }
} }
} }
fun Manga.toMangaInfo(): MangaInfo {
return MangaInfo(
artist = this.artist ?: "",
author = this.author ?: "",
cover = this.thumbnail_url ?: "",
description = this.description ?: "",
genres = this.getGenres() ?: emptyList(),
key = this.url,
status = this.status,
title = this.title
)
}
@@ -1,5 +1,8 @@
package eu.kanade.tachiyomi.data.database.models package eu.kanade.tachiyomi.data.database.models
import eu.kanade.tachiyomi.data.library.CustomMangaManager
import uy.kohesive.injekt.injectLazy
open class MangaImpl : Manga { open class MangaImpl : Manga {
override var id: Long? = null override var id: Long? = null
@@ -9,17 +12,36 @@ open class MangaImpl : Manga {
override lateinit var url: String override lateinit var url: String
// SY --> // SY -->
override var title: String = "" private val customMangaManager: CustomMangaManager by injectLazy()
override var title: String
get() = if (favorite) {
val customTitle = customMangaManager.getManga(this)?.title
if (customTitle.isNullOrBlank()) ogTitle else customTitle
} else {
ogTitle
}
set(value) {
ogTitle = value
}
override var author: String?
get() = if (favorite) customMangaManager.getManga(this)?.author ?: ogAuthor else ogAuthor
set(value) { ogAuthor = value }
override var artist: String?
get() = if (favorite) customMangaManager.getManga(this)?.artist ?: ogArtist else ogArtist
set(value) { ogArtist = value }
override var description: String?
get() = if (favorite) customMangaManager.getManga(this)?.description ?: ogDesc else ogDesc
set(value) { ogDesc = value }
override var genre: String?
get() = if (favorite) customMangaManager.getManga(this)?.genre ?: ogGenre else ogGenre
set(value) { ogGenre = value }
// SY <-- // SY <--
override var artist: String? = null
override var author: String? = null
override var description: String? = null
override var genre: String? = null
override var status: Int = 0 override var status: Int = 0
override var thumbnail_url: String? = null override var thumbnail_url: String? = null
@@ -28,6 +50,8 @@ open class MangaImpl : Manga {
override var last_update: Long = 0 override var last_update: Long = 0
override var date_added: Long = 0
override var initialized: Boolean = false override var initialized: Boolean = false
override var viewer: Int = 0 override var viewer: Int = 0
@@ -36,16 +60,29 @@ open class MangaImpl : Manga {
override var cover_last_modified: Long = 0 override var cover_last_modified: Long = 0
// SY -->
lateinit var ogTitle: String
private set
var ogAuthor: String? = null
private set
var ogArtist: String? = null
private set
var ogDesc: String? = null
private set
var ogGenre: String? = null
private set
// SY <--
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
if (this === other) return true if (this === other) return true
if (other == null || javaClass != other.javaClass) return false if (other == null || javaClass != other.javaClass) return false
val manga = other as Manga val manga = other as Manga
if (url != manga.url) return false
return url == manga.url return id == manga.id
} }
override fun hashCode(): Int { override fun hashCode(): Int {
return url.hashCode() return url.hashCode() + id.hashCode()
} }
} }
@@ -15,9 +15,9 @@ import java.util.Date
interface ChapterQueries : DbProvider { interface ChapterQueries : DbProvider {
// SY --> // SY -->
fun getChapters(manga: Manga) = getChaptersByMangaId(manga.id) fun getChapters(manga: Manga) = getChapters(manga.id)
fun getChaptersByMangaId(mangaId: Long?) = db.get() fun getChapters(mangaId: Long?) = db.get()
.listOfObjects(Chapter::class.java) .listOfObjects(Chapter::class.java)
.withQuery( .withQuery(
Query.builder() Query.builder()
@@ -27,15 +27,6 @@ interface ChapterQueries : DbProvider {
.build() .build()
) )
.prepare() .prepare()
fun getChaptersByMergedMangaId(mangaId: Long) = db.get()
.listOfObjects(Chapter::class.java)
.withQuery(
RawQuery.builder()
.query(getMergedChaptersQuery(mangaId))
.build()
)
.prepare()
// SY <-- // SY <--
fun getRecentChapters(date: Date) = db.get() fun getRecentChapters(date: Date) = db.get()
@@ -94,6 +85,17 @@ interface ChapterQueries : DbProvider {
.build() .build()
) )
.prepare() .prepare()
fun getChaptersReadByUrls(urls: List<String>) = db.get()
.listOfObjects(Chapter::class.java)
.withQuery(
Query.builder()
.table(ChapterTable.TABLE)
.where("${ChapterTable.COL_URL} IN (?) AND (${ChapterTable.COL_READ} = 1 OR ${ChapterTable.COL_LAST_PAGE_READ} != 0)")
.whereArgs(urls.joinToString { "\"$it\"" })
.build()
)
.prepare()
// SY <-- // SY <--
fun insertChapter(chapter: Chapter) = db.put().`object`(chapter).prepare() fun insertChapter(chapter: Chapter) = db.put().`object`(chapter).prepare()
@@ -18,41 +18,25 @@ interface HistoryQueries : DbProvider {
*/ */
fun insertHistory(history: History) = db.put().`object`(history).prepare() fun insertHistory(history: History) = db.put().`object`(history).prepare()
// SY -->
/** /**
* Returns history of recent manga containing last read chapter * Returns history of recent manga containing last read chapter
* @param date recent date range * @param date recent date range
* @param limit the limit of manga to grab
* @param offset offset the db by
* @param search what to search in the db history
*/ */
fun getRecentManga(date: Date, offset: Int = 0, search: String = "") = db.get() fun getRecentManga(date: Date, limit: Int = 25, offset: Int = 0, search: String = "") = db.get()
.listOfObjects(MangaChapterHistory::class.java) .listOfObjects(MangaChapterHistory::class.java)
.withQuery( .withQuery(
RawQuery.builder() RawQuery.builder()
.query(getRecentMangasQuery(offset, search)) .query(getRecentMangasQuery(search))
.args(date.time) .args(date.time, limit, offset)
.observesTables(HistoryTable.TABLE) .observesTables(HistoryTable.TABLE)
.build() .build()
) )
.withGetResolver(MangaChapterHistoryGetResolver.INSTANCE) .withGetResolver(MangaChapterHistoryGetResolver.INSTANCE)
.prepare() .prepare()
/**
* Returns history of recent manga containing last read chapter in 25s
* @param date recent date range
* @offset offset the db by
*/
fun getRecentMangaLimit(date: Date, limit: Int = 0, search: String = "") = db.get()
.listOfObjects(MangaChapterHistory::class.java)
.withQuery(
RawQuery.builder()
.query(getRecentMangasLimitQuery(limit, search))
.args(date.time)
.observesTables(HistoryTable.TABLE)
.build()
)
.withGetResolver(MangaChapterHistoryGetResolver.INSTANCE)
.prepare()
// SY <--
fun getHistoryByMangaId(mangaId: Long) = db.get() fun getHistoryByMangaId(mangaId: Long) = db.get()
.listOfObjects(History::class.java) .listOfObjects(History::class.java)
.withQuery( .withQuery(
@@ -10,13 +10,16 @@ import eu.kanade.tachiyomi.data.database.resolvers.LibraryMangaGetResolver
import eu.kanade.tachiyomi.data.database.resolvers.MangaCoverLastModifiedPutResolver import eu.kanade.tachiyomi.data.database.resolvers.MangaCoverLastModifiedPutResolver
import eu.kanade.tachiyomi.data.database.resolvers.MangaFavoritePutResolver import eu.kanade.tachiyomi.data.database.resolvers.MangaFavoritePutResolver
import eu.kanade.tachiyomi.data.database.resolvers.MangaFlagsPutResolver import eu.kanade.tachiyomi.data.database.resolvers.MangaFlagsPutResolver
import eu.kanade.tachiyomi.data.database.resolvers.MangaInfoPutResolver
import eu.kanade.tachiyomi.data.database.resolvers.MangaLastUpdatedPutResolver import eu.kanade.tachiyomi.data.database.resolvers.MangaLastUpdatedPutResolver
import eu.kanade.tachiyomi.data.database.resolvers.MangaMigrationPutResolver
import eu.kanade.tachiyomi.data.database.resolvers.MangaTitlePutResolver import eu.kanade.tachiyomi.data.database.resolvers.MangaTitlePutResolver
import eu.kanade.tachiyomi.data.database.resolvers.MangaViewerPutResolver import eu.kanade.tachiyomi.data.database.resolvers.MangaViewerPutResolver
import eu.kanade.tachiyomi.data.database.tables.CategoryTable import eu.kanade.tachiyomi.data.database.tables.CategoryTable
import eu.kanade.tachiyomi.data.database.tables.ChapterTable import eu.kanade.tachiyomi.data.database.tables.ChapterTable
import eu.kanade.tachiyomi.data.database.tables.MangaCategoryTable import eu.kanade.tachiyomi.data.database.tables.MangaCategoryTable
import eu.kanade.tachiyomi.data.database.tables.MangaTable import eu.kanade.tachiyomi.data.database.tables.MangaTable
import exh.merged.sql.tables.MergedTable
import exh.metadata.sql.tables.SearchMetadataTable import exh.metadata.sql.tables.SearchMetadataTable
interface MangaQueries : DbProvider { interface MangaQueries : DbProvider {
@@ -76,13 +79,19 @@ interface MangaQueries : DbProvider {
.prepare() .prepare()
// SY --> // SY -->
fun getMergedMangas(id: Long) = db.get() fun updateMangaInfo(manga: Manga) = db.put()
.listOfObjects(Manga::class.java) .`object`(manga)
.withQuery( .withPutResolver(MangaInfoPutResolver())
RawQuery.builder() .prepare()
.query(getMergedMangaQuery(id))
.build() fun resetMangaInfo(manga: Manga) = db.put()
) .`object`(manga)
.withPutResolver(MangaInfoPutResolver(true))
.prepare()
fun updateMangaMigrate(manga: Manga) = db.put()
.`object`(manga)
.withPutResolver(MangaMigrationPutResolver())
.prepare() .prepare()
// SY <-- // SY <--
@@ -95,6 +104,11 @@ interface MangaQueries : DbProvider {
.withPutResolver(MangaFlagsPutResolver()) .withPutResolver(MangaFlagsPutResolver())
.prepare() .prepare()
fun updateFlags(mangas: List<Manga>) = db.put()
.objects(mangas)
.withPutResolver(MangaFlagsPutResolver(true))
.prepare()
fun updateLastUpdated(manga: Manga) = db.put() fun updateLastUpdated(manga: Manga) = db.put()
.`object`(manga) .`object`(manga)
.withPutResolver(MangaLastUpdatedPutResolver()) .withPutResolver(MangaLastUpdatedPutResolver())
@@ -128,7 +142,7 @@ interface MangaQueries : DbProvider {
.byQuery( .byQuery(
DeleteQuery.builder() DeleteQuery.builder()
.table(MangaTable.TABLE) .table(MangaTable.TABLE)
.where("${MangaTable.COL_FAVORITE} = ?") .where("${MangaTable.COL_FAVORITE} = ? AND ${MangaTable.COL_ID} NOT IN (SELECT ${MergedTable.COL_MANGA_ID} FROM ${MergedTable.TABLE})")
.whereArgs(0) .whereArgs(0)
.build() .build()
) )
@@ -1,21 +1,48 @@
package eu.kanade.tachiyomi.data.database.queries package eu.kanade.tachiyomi.data.database.queries
import exh.MERGED_SOURCE_ID
import eu.kanade.tachiyomi.data.database.tables.CategoryTable as Category import eu.kanade.tachiyomi.data.database.tables.CategoryTable as Category
import eu.kanade.tachiyomi.data.database.tables.ChapterTable as Chapter import eu.kanade.tachiyomi.data.database.tables.ChapterTable as Chapter
import eu.kanade.tachiyomi.data.database.tables.HistoryTable as History import eu.kanade.tachiyomi.data.database.tables.HistoryTable as History
import eu.kanade.tachiyomi.data.database.tables.MangaCategoryTable as MangaCategory import eu.kanade.tachiyomi.data.database.tables.MangaCategoryTable as MangaCategory
import eu.kanade.tachiyomi.data.database.tables.MangaTable as Manga import eu.kanade.tachiyomi.data.database.tables.MangaTable as Manga
import eu.kanade.tachiyomi.data.database.tables.MergedTable as Merged import exh.merged.sql.tables.MergedTable as Merged
// SY --> // SY -->
/** /**
* Query to get the manga merged into a merged manga * Query to get the manga merged into a merged manga
*/ */
fun getMergedMangaQuery(id: Long) = fun getMergedMangaQuery() =
""" """
SELECT ${Manga.TABLE}.* SELECT ${Manga.TABLE}.*
FROM ( FROM (
SELECT ${Merged.COL_MANGA_ID} FROM ${Merged.TABLE} WHERE $(Merged.COL_MERGE_ID} = $id SELECT ${Merged.COL_MANGA_ID} FROM ${Merged.TABLE} WHERE ${Merged.COL_MERGE_ID} = ?
) AS M
JOIN ${Manga.TABLE}
ON ${Manga.TABLE}.${Manga.COL_ID} = M.${Merged.COL_MANGA_ID}
"""
/**
* Query to get all the manga that are merged into other manga
*/
fun getAllMergedMangaQuery() =
"""
SELECT ${Manga.TABLE}.*
FROM (
SELECT ${Merged.COL_MANGA_ID} FROM ${Merged.TABLE}
) AS M
JOIN ${Manga.TABLE}
ON ${Manga.TABLE}.${Manga.COL_ID} = M.${Merged.COL_MANGA_ID}
"""
/**
* Query to get the manga merged into a merged manga using the Url
*/
fun getMergedMangaFromUrlQuery() =
"""
SELECT ${Manga.TABLE}.*
FROM (
SELECT ${Merged.COL_MANGA_ID} FROM ${Merged.TABLE} WHERE ${Merged.COL_MERGE_URL} = ?
) AS M ) AS M
JOIN ${Manga.TABLE} JOIN ${Manga.TABLE}
ON ${Manga.TABLE}.${Manga.COL_ID} = M.${Merged.COL_MANGA_ID} ON ${Manga.TABLE}.${Manga.COL_ID} = M.${Merged.COL_MANGA_ID}
@@ -24,16 +51,15 @@ fun getMergedMangaQuery(id: Long) =
/** /**
* Query to get the chapters of all manga in a merged manga * Query to get the chapters of all manga in a merged manga
*/ */
fun getMergedChaptersQuery(id: Long) = fun getMergedChaptersQuery() =
""" """
SELECT ${Chapter.TABLE}.* SELECT ${Chapter.TABLE}.*
FROM ( FROM (
SELECT ${Merged.COL_MANGA_ID} FROM ${Merged.TABLE} WHERE $(Merged.COL_MERGE_ID} = $id SELECT ${Merged.COL_MANGA_ID} FROM ${Merged.TABLE} WHERE ${Merged.COL_MERGE_ID} = ?
) AS M ) AS M
JOIN ${Chapter.TABLE} JOIN ${Chapter.TABLE}
ON ${Chapter.TABLE}.${Chapter.COL_MANGA_ID} = M.${Merged.COL_MANGA_ID} ON ${Chapter.TABLE}.${Chapter.COL_MANGA_ID} = M.${Merged.COL_MANGA_ID}
""" """
// SY <--
/** /**
* Query to get the manga from the library, with their categories and unread count. * Query to get the manga from the library, with their categories and unread count.
@@ -42,23 +68,55 @@ val libraryQuery =
""" """
SELECT M.*, COALESCE(MC.${MangaCategory.COL_CATEGORY_ID}, 0) AS ${Manga.COL_CATEGORY} SELECT M.*, COALESCE(MC.${MangaCategory.COL_CATEGORY_ID}, 0) AS ${Manga.COL_CATEGORY}
FROM ( FROM (
SELECT ${Manga.TABLE}.*, COALESCE(C.unread, 0) AS ${Manga.COL_UNREAD} SELECT ${Manga.TABLE}.*, COALESCE(C.unread, 0) AS ${Manga.COL_UNREAD}, COALESCE(R.read, 0) AS ${Manga.COL_READ}
FROM ${Manga.TABLE} FROM ${Manga.TABLE}
LEFT JOIN ( LEFT JOIN (
SELECT ${Chapter.COL_MANGA_ID}, COUNT(*) AS unread SELECT ${Chapter.TABLE}.${Chapter.COL_MANGA_ID}, COUNT(*) AS unread
FROM ${Chapter.TABLE} FROM ${Chapter.TABLE}
WHERE ${Chapter.COL_READ} = 0 WHERE ${Chapter.COL_READ} = 0
GROUP BY ${Chapter.COL_MANGA_ID} GROUP BY ${Chapter.TABLE}.${Chapter.COL_MANGA_ID}
) AS C ) AS C
ON ${Manga.COL_ID} = C.${Chapter.COL_MANGA_ID} ON ${Manga.TABLE}.${Manga.COL_ID} = C.${Chapter.COL_MANGA_ID}
WHERE ${Manga.COL_FAVORITE} = 1 LEFT JOIN (
GROUP BY ${Manga.COL_ID} SELECT ${Chapter.COL_MANGA_ID}, COUNT(*) AS read
FROM ${Chapter.TABLE}
WHERE ${Chapter.COL_READ} = 1
GROUP BY ${Chapter.COL_MANGA_ID}
) AS R
ON ${Manga.TABLE}.${Manga.COL_ID} = R.${Chapter.COL_MANGA_ID}
WHERE ${Manga.COL_FAVORITE} = 1 AND ${Manga.COL_SOURCE} <> $MERGED_SOURCE_ID
GROUP BY ${Manga.TABLE}.${Manga.COL_ID}
UNION
SELECT ${Manga.TABLE}.*, COALESCE(C.unread, 0) AS ${Manga.COL_UNREAD}, COALESCE(R.read, 0) AS ${Manga.COL_READ}
FROM ${Manga.TABLE}
LEFT JOIN (
SELECT ${Merged.TABLE}.${Merged.COL_MERGE_ID}, COUNT(*) as unread
FROM ${Merged.TABLE}
JOIN ${Chapter.TABLE}
ON ${Chapter.TABLE}.${Chapter.COL_MANGA_ID} = ${Merged.TABLE}.${Merged.COL_MANGA_ID}
WHERE ${Chapter.TABLE}.${Chapter.COL_READ} = 0
GROUP BY ${Merged.TABLE}.${Merged.COL_MERGE_ID}
) AS C
ON ${Manga.TABLE}.${Manga.COL_ID} = C.${Merged.COL_MERGE_ID}
LEFT JOIN (
SELECT ${Merged.TABLE}.${Merged.COL_MERGE_ID}, COUNT(*) as read
FROM ${Merged.TABLE}
JOIN ${Chapter.TABLE}
ON ${Chapter.TABLE}.${Chapter.COL_MANGA_ID} = ${Merged.TABLE}.${Merged.COL_MANGA_ID}
WHERE ${Chapter.TABLE}.${Chapter.COL_READ} = 1
GROUP BY ${Merged.TABLE}.${Merged.COL_MERGE_ID}
) AS R
ON ${Manga.TABLE}.${Manga.COL_ID} = R.${Merged.COL_MERGE_ID}
WHERE ${Manga.COL_FAVORITE} = 1 AND ${Manga.COL_SOURCE} = $MERGED_SOURCE_ID
GROUP BY ${Manga.TABLE}.${Manga.COL_ID}
ORDER BY ${Manga.COL_TITLE} ORDER BY ${Manga.COL_TITLE}
) AS M ) AS M
LEFT JOIN ( LEFT JOIN (
SELECT * FROM ${MangaCategory.TABLE}) AS MC SELECT * FROM ${MangaCategory.TABLE}
ON MC.${MangaCategory.COL_MANGA_ID} = M.${Manga.COL_ID} ) AS MC
ON MC.${MangaCategory.COL_MANGA_ID} = M.${Manga.COL_ID};
""" """
// SY <--
/** /**
* Query to get the recent chapters of manga from the library up to a date. * Query to get the recent chapters of manga from the library up to a date.
@@ -67,7 +125,9 @@ fun getRecentsQuery() =
""" """
SELECT ${Manga.TABLE}.${Manga.COL_URL} as mangaUrl, * FROM ${Manga.TABLE} JOIN ${Chapter.TABLE} SELECT ${Manga.TABLE}.${Manga.COL_URL} as mangaUrl, * FROM ${Manga.TABLE} JOIN ${Chapter.TABLE}
ON ${Manga.TABLE}.${Manga.COL_ID} = ${Chapter.TABLE}.${Chapter.COL_MANGA_ID} ON ${Manga.TABLE}.${Manga.COL_ID} = ${Chapter.TABLE}.${Chapter.COL_MANGA_ID}
WHERE ${Manga.COL_FAVORITE} = 1 AND ${Chapter.COL_DATE_UPLOAD} > ? WHERE ${Manga.COL_FAVORITE} = 1
AND ${Chapter.COL_DATE_UPLOAD} > ?
AND ${Chapter.COL_DATE_FETCH} > ${Manga.COL_DATE_ADDED}
ORDER BY ${Chapter.COL_DATE_UPLOAD} DESC ORDER BY ${Chapter.COL_DATE_UPLOAD} DESC
""" """
@@ -76,36 +136,8 @@ fun getRecentsQuery() =
* The max_last_read table contains the most recent chapters grouped by manga * The max_last_read table contains the most recent chapters grouped by manga
* The select statement returns all information of chapters that have the same id as the chapter in max_last_read * The select statement returns all information of chapters that have the same id as the chapter in max_last_read
* and are read after the given time period * and are read after the given time period
* @return return limit is 25
*/ */
// SY --> fun getRecentMangasQuery(search: String = "") =
fun getRecentMangasQuery(offset: Int = 0, search: String = "") =
"""
SELECT ${Manga.TABLE}.${Manga.COL_URL} as mangaUrl, ${Manga.TABLE}.*, ${Chapter.TABLE}.*, ${History.TABLE}.*
FROM ${Manga.TABLE}
JOIN ${Chapter.TABLE}
ON ${Manga.TABLE}.${Manga.COL_ID} = ${Chapter.TABLE}.${Chapter.COL_MANGA_ID}
JOIN ${History.TABLE}
ON ${Chapter.TABLE}.${Chapter.COL_ID} = ${History.TABLE}.${History.COL_CHAPTER_ID}
JOIN (
SELECT ${Chapter.TABLE}.${Chapter.COL_MANGA_ID},${Chapter.TABLE}.${Chapter.COL_ID} as ${History.COL_CHAPTER_ID}, MAX(${History.TABLE}.${History.COL_LAST_READ}) as ${History.COL_LAST_READ}
FROM ${Chapter.TABLE} JOIN ${History.TABLE}
ON ${Chapter.TABLE}.${Chapter.COL_ID} = ${History.TABLE}.${History.COL_CHAPTER_ID}
GROUP BY ${Chapter.TABLE}.${Chapter.COL_MANGA_ID}) AS max_last_read
ON ${Chapter.TABLE}.${Chapter.COL_MANGA_ID} = max_last_read.${Chapter.COL_MANGA_ID}
WHERE ${History.TABLE}.${History.COL_LAST_READ} > ? AND max_last_read.${History.COL_CHAPTER_ID} = ${History.TABLE}.${History.COL_CHAPTER_ID}
AND lower(${Manga.TABLE}.${Manga.COL_TITLE}) LIKE '%$search%'
ORDER BY max_last_read.${History.COL_LAST_READ} DESC
LIMIT 25 OFFSET $offset
"""
/**
* Query to get the recently read chapters of manga from the library up to a date.
* The max_last_read table contains the most recent chapters grouped by manga
* The select statement returns all information of chapters that have the same id as the chapter in max_last_read
* and are read after the given time period
*/
fun getRecentMangasLimitQuery(limit: Int = 25, search: String = "") =
""" """
SELECT ${Manga.TABLE}.${Manga.COL_URL} as mangaUrl, ${Manga.TABLE}.*, ${Chapter.TABLE}.*, ${History.TABLE}.* SELECT ${Manga.TABLE}.${Manga.COL_URL} as mangaUrl, ${Manga.TABLE}.*, ${Chapter.TABLE}.*, ${History.TABLE}.*
FROM ${Manga.TABLE} FROM ${Manga.TABLE}
@@ -123,9 +155,8 @@ fun getRecentMangasLimitQuery(limit: Int = 25, search: String = "") =
AND max_last_read.${History.COL_CHAPTER_ID} = ${History.TABLE}.${History.COL_CHAPTER_ID} AND max_last_read.${History.COL_CHAPTER_ID} = ${History.TABLE}.${History.COL_CHAPTER_ID}
AND lower(${Manga.TABLE}.${Manga.COL_TITLE}) LIKE '%$search%' AND lower(${Manga.TABLE}.${Manga.COL_TITLE}) LIKE '%$search%'
ORDER BY max_last_read.${History.COL_LAST_READ} DESC ORDER BY max_last_read.${History.COL_LAST_READ} DESC
LIMIT $limit LIMIT ? OFFSET ?
""" """
// SY <--
fun getHistoryByMangaId() = fun getHistoryByMangaId() =
""" """
@@ -18,6 +18,9 @@ class LibraryMangaGetResolver : DefaultGetResolver<LibraryManga>(), BaseMangaGet
mapBaseFromCursor(manga, cursor) mapBaseFromCursor(manga, cursor)
manga.unread = cursor.getInt(cursor.getColumnIndex(MangaTable.COL_UNREAD)) manga.unread = cursor.getInt(cursor.getColumnIndex(MangaTable.COL_UNREAD))
manga.category = cursor.getInt(cursor.getColumnIndex(MangaTable.COL_CATEGORY)) manga.category = cursor.getInt(cursor.getColumnIndex(MangaTable.COL_CATEGORY))
// SY -->
manga.read = cursor.getInt(cursor.getColumnIndex(MangaTable.COL_READ))
// SY <--
return manga return manga
} }
@@ -25,7 +25,8 @@ class MangaFavoritePutResolver : PutResolver<Manga>() {
.whereArgs(manga.id) .whereArgs(manga.id)
.build() .build()
fun mapToContentValues(manga: Manga) = ContentValues(1).apply { fun mapToContentValues(manga: Manga) = ContentValues(2).apply {
put(MangaTable.COL_FAVORITE, manga.favorite) put(MangaTable.COL_FAVORITE, manga.favorite)
put(MangaTable.COL_DATE_ADDED, manga.date_added)
} }
} }
@@ -9,7 +9,7 @@ import eu.kanade.tachiyomi.data.database.inTransactionReturn
import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.database.tables.MangaTable import eu.kanade.tachiyomi.data.database.tables.MangaTable
class MangaFlagsPutResolver : PutResolver<Manga>() { class MangaFlagsPutResolver(private val updateAll: Boolean = false) : PutResolver<Manga>() {
override fun performPut(db: StorIOSQLite, manga: Manga) = db.inTransactionReturn { override fun performPut(db: StorIOSQLite, manga: Manga) = db.inTransactionReturn {
val updateQuery = mapToUpdateQuery(manga) val updateQuery = mapToUpdateQuery(manga)
@@ -19,11 +19,21 @@ class MangaFlagsPutResolver : PutResolver<Manga>() {
PutResult.newUpdateResult(numberOfRowsUpdated, updateQuery.table()) PutResult.newUpdateResult(numberOfRowsUpdated, updateQuery.table())
} }
fun mapToUpdateQuery(manga: Manga) = UpdateQuery.builder() fun mapToUpdateQuery(manga: Manga): UpdateQuery {
.table(MangaTable.TABLE) val builder = UpdateQuery.builder()
.where("${MangaTable.COL_ID} = ?")
.whereArgs(manga.id) return if (updateAll) {
.build() builder
.table(MangaTable.TABLE)
.build()
} else {
builder
.table(MangaTable.TABLE)
.where("${MangaTable.COL_ID} = ?")
.whereArgs(manga.id)
.build()
}
}
fun mapToContentValues(manga: Manga) = ContentValues(1).apply { fun mapToContentValues(manga: Manga) = ContentValues(1).apply {
put(MangaTable.COL_CHAPTER_FLAGS, manga.chapter_flags) put(MangaTable.COL_CHAPTER_FLAGS, manga.chapter_flags)
@@ -0,0 +1,44 @@
package eu.kanade.tachiyomi.data.database.resolvers
import android.content.ContentValues
import com.pushtorefresh.storio.sqlite.StorIOSQLite
import com.pushtorefresh.storio.sqlite.operations.put.PutResolver
import com.pushtorefresh.storio.sqlite.operations.put.PutResult
import com.pushtorefresh.storio.sqlite.queries.UpdateQuery
import eu.kanade.tachiyomi.data.database.inTransactionReturn
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.database.tables.MangaTable
class MangaInfoPutResolver(val reset: Boolean = false) : PutResolver<Manga>() {
override fun performPut(db: StorIOSQLite, manga: Manga) = db.inTransactionReturn {
val updateQuery = mapToUpdateQuery(manga)
val contentValues = if (reset) resetToContentValues(manga) else mapToContentValues(manga)
val numberOfRowsUpdated = db.lowLevel().update(updateQuery, contentValues)
PutResult.newUpdateResult(numberOfRowsUpdated, updateQuery.table())
}
fun mapToUpdateQuery(manga: Manga) = UpdateQuery.builder()
.table(MangaTable.TABLE)
.where("${MangaTable.COL_ID} = ?")
.whereArgs(manga.id)
.build()
fun mapToContentValues(manga: Manga) = ContentValues(1).apply {
put(MangaTable.COL_TITLE, manga.originalTitle)
put(MangaTable.COL_GENRE, manga.originalGenre)
put(MangaTable.COL_AUTHOR, manga.originalAuthor)
put(MangaTable.COL_ARTIST, manga.originalArtist)
put(MangaTable.COL_DESCRIPTION, manga.originalDescription)
}
fun resetToContentValues(manga: Manga) = ContentValues(1).apply {
val splitter = "▒ ▒∩▒"
put(MangaTable.COL_TITLE, manga.title.split(splitter).last())
put(MangaTable.COL_GENRE, manga.genre?.split(splitter)?.lastOrNull())
put(MangaTable.COL_AUTHOR, manga.author?.split(splitter)?.lastOrNull())
put(MangaTable.COL_ARTIST, manga.artist?.split(splitter)?.lastOrNull())
put(MangaTable.COL_DESCRIPTION, manga.description?.split(splitter)?.lastOrNull())
}
}
@@ -0,0 +1,35 @@
package eu.kanade.tachiyomi.data.database.resolvers
import android.content.ContentValues
import com.pushtorefresh.storio.sqlite.StorIOSQLite
import com.pushtorefresh.storio.sqlite.operations.put.PutResolver
import com.pushtorefresh.storio.sqlite.operations.put.PutResult
import com.pushtorefresh.storio.sqlite.queries.UpdateQuery
import eu.kanade.tachiyomi.data.database.inTransactionReturn
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.database.tables.MangaTable
class MangaMigrationPutResolver : PutResolver<Manga>() {
override fun performPut(db: StorIOSQLite, manga: Manga) = db.inTransactionReturn {
val updateQuery = mapToUpdateQuery(manga)
val contentValues = mapToContentValues(manga)
val numberOfRowsUpdated = db.lowLevel().update(updateQuery, contentValues)
PutResult.newUpdateResult(numberOfRowsUpdated, updateQuery.table())
}
fun mapToUpdateQuery(manga: Manga) = UpdateQuery.builder()
.table(MangaTable.TABLE)
.where("${MangaTable.COL_ID} = ?")
.whereArgs(manga.id)
.build()
fun mapToContentValues(manga: Manga) = ContentValues(5).apply {
put(MangaTable.COL_FAVORITE, manga.favorite)
put(MangaTable.COL_DATE_ADDED, manga.date_added)
put(MangaTable.COL_TITLE, manga.title)
put(MangaTable.COL_CHAPTER_FLAGS, manga.chapter_flags)
put(MangaTable.COL_VIEWER, manga.viewer)
}
}
@@ -0,0 +1,32 @@
package eu.kanade.tachiyomi.data.database.resolvers
import android.content.ContentValues
import com.pushtorefresh.storio.sqlite.StorIOSQLite
import com.pushtorefresh.storio.sqlite.operations.put.PutResolver
import com.pushtorefresh.storio.sqlite.operations.put.PutResult
import com.pushtorefresh.storio.sqlite.queries.UpdateQuery
import eu.kanade.tachiyomi.data.database.inTransactionReturn
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.database.tables.MangaTable
// [EXH]
class MangaUrlPutResolver : PutResolver<Manga>() {
override fun performPut(db: StorIOSQLite, manga: Manga) = db.inTransactionReturn {
val updateQuery = mapToUpdateQuery(manga)
val contentValues = mapToContentValues(manga)
val numberOfRowsUpdated = db.lowLevel().update(updateQuery, contentValues)
PutResult.newUpdateResult(numberOfRowsUpdated, updateQuery.table())
}
fun mapToUpdateQuery(manga: Manga) = UpdateQuery.builder()
.table(MangaTable.TABLE)
.where("${MangaTable.COL_ID} = ?")
.whereArgs(manga.id)
.build()
fun mapToContentValues(manga: Manga) = ContentValues(1).apply {
put(MangaTable.COL_URL, manga.url)
}
}
@@ -25,6 +25,7 @@ object CategoryTable {
$COL_FLAGS INTEGER NOT NULL, $COL_FLAGS INTEGER NOT NULL,
$COL_MANGA_ORDER TEXT NOT NULL $COL_MANGA_ORDER TEXT NOT NULL
)""" )"""
// SY --> // SY -->
val addMangaOrder: String val addMangaOrder: String
get() = "ALTER TABLE $TABLE ADD COLUMN $COL_MANGA_ORDER TEXT" get() = "ALTER TABLE $TABLE ADD COLUMN $COL_MANGA_ORDER TEXT"
@@ -28,6 +28,8 @@ object MangaTable {
const val COL_LAST_UPDATE = "last_update" const val COL_LAST_UPDATE = "last_update"
const val COL_DATE_ADDED = "date_added"
const val COL_INITIALIZED = "initialized" const val COL_INITIALIZED = "initialized"
const val COL_VIEWER = "viewer" const val COL_VIEWER = "viewer"
@@ -36,6 +38,10 @@ object MangaTable {
const val COL_UNREAD = "unread" const val COL_UNREAD = "unread"
// SY ->>
const val COL_READ = "read"
// SY <--
const val COL_CATEGORY = "category" const val COL_CATEGORY = "category"
const val COL_COVER_LAST_MODIFIED = "cover_last_modified" const val COL_COVER_LAST_MODIFIED = "cover_last_modified"
@@ -58,7 +64,8 @@ object MangaTable {
$COL_INITIALIZED BOOLEAN NOT NULL, $COL_INITIALIZED BOOLEAN NOT NULL,
$COL_VIEWER INTEGER NOT NULL, $COL_VIEWER INTEGER NOT NULL,
$COL_CHAPTER_FLAGS INTEGER NOT NULL, $COL_CHAPTER_FLAGS INTEGER NOT NULL,
$COL_COVER_LAST_MODIFIED LONG NOT NULL $COL_COVER_LAST_MODIFIED LONG NOT NULL,
$COL_DATE_ADDED LONG NOT NULL
)""" )"""
val createUrlIndexQuery: String val createUrlIndexQuery: String
@@ -70,4 +77,17 @@ object MangaTable {
val addCoverLastModified: String val addCoverLastModified: String
get() = "ALTER TABLE $TABLE ADD COLUMN $COL_COVER_LAST_MODIFIED LONG NOT NULL DEFAULT 0" get() = "ALTER TABLE $TABLE ADD COLUMN $COL_COVER_LAST_MODIFIED LONG NOT NULL DEFAULT 0"
val addDateAdded: String
get() = "ALTER TABLE $TABLE ADD COLUMN $COL_DATE_ADDED LONG NOT NULL DEFAULT 0"
/**
* Used with addDateAdded to populate it with the oldest chapter fetch date.
*/
val backfillDateAdded: String
get() = "UPDATE $TABLE SET $COL_DATE_ADDED = " +
"(SELECT MIN(${ChapterTable.COL_DATE_FETCH}) " +
"FROM $TABLE INNER JOIN ${ChapterTable.TABLE} " +
"ON $TABLE.$COL_ID = ${ChapterTable.TABLE}.${ChapterTable.COL_MANGA_ID} " +
"GROUP BY $TABLE.$COL_ID)"
} }
@@ -1,20 +0,0 @@
package eu.kanade.tachiyomi.data.database.tables
object MergedTable {
const val TABLE = "merged"
const val COL_MERGE_ID = "mergeID"
const val COL_MANGA_ID = "mangaID"
val createTableQuery: String
get() =
"""CREATE TABLE $TABLE(
$COL_MERGE_ID INTEGER NOT NULL,
$COL_MANGA_ID INTEGER NOT NULL
)"""
val createIndexQuery: String
get() = "CREATE INDEX ${TABLE}_${COL_MERGE_ID}_index ON $TABLE($COL_MERGE_ID)"
}
@@ -1,16 +1,16 @@
package eu.kanade.tachiyomi.data.download package eu.kanade.tachiyomi.data.download
import android.content.Context import android.content.Context
import android.net.Uri import androidx.core.net.toUri
import com.hippo.unifile.UniFile import com.hippo.unifile.UniFile
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.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.source.SourceManager
import java.util.concurrent.TimeUnit
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import java.util.concurrent.TimeUnit
/** /**
* Cache where we dump the downloads directory from the filesystem. This class is needed because * Cache where we dump the downloads directory from the filesystem. This class is needed because
@@ -59,7 +59,7 @@ class DownloadCache(
*/ */
private fun getDirectoryFromPreference(): UniFile { private fun getDirectoryFromPreference(): UniFile {
val dir = preferences.downloadsDirectory().get() val dir = preferences.downloadsDirectory().get()
return UniFile.fromUri(context, Uri.parse(dir)) return UniFile.fromUri(context, dir.toUri())
} }
/** /**
@@ -81,7 +81,7 @@ class DownloadCache(
if (sourceDir != null) { if (sourceDir != null) {
val mangaDir = sourceDir.files[provider.getMangaDirName(manga)] val mangaDir = sourceDir.files[provider.getMangaDirName(manga)]
if (mangaDir != null) { if (mangaDir != null) {
return provider.getChapterDirName(chapter) in mangaDir.files return provider.getValidChapterDirNames(chapter).any { it in mangaDir.files || "$it.cbz" in mangaDir.files }
} }
} }
return false return false
@@ -122,13 +122,15 @@ class DownloadCache(
* Renews the downloads cache. * Renews the downloads cache.
*/ */
private fun renew() { private fun renew() {
val onlineSources = sourceManager.getOnlineSources() // SY -->
val onlineSources = sourceManager.getVisibleOnlineSources()
// SY <--
val sourceDirs = rootDir.dir.listFiles() val sourceDirs = rootDir.dir.listFiles()
.orEmpty() .orEmpty()
.associate { it.name to SourceDirectory(it) } .associate { it.name to SourceDirectory(it) }
.mapNotNullKeys { entry -> .mapNotNullKeys { entry ->
onlineSources.find { provider.getSourceDirName(it).toLowerCase() == entry.key?.toLowerCase() }?.id onlineSources.find { provider.getSourceDirName(it).equals(entry.key, ignoreCase = true) }?.id
} }
rootDir.files = sourceDirs rootDir.files = sourceDirs
@@ -143,7 +145,7 @@ class DownloadCache(
mangaDirs.values.forEach { mangaDir -> mangaDirs.values.forEach { mangaDir ->
val chapterDirs = mangaDir.dir.listFiles() val chapterDirs = mangaDir.dir.listFiles()
.orEmpty() .orEmpty()
.mapNotNull { it.name } .mapNotNull { it.name?.replace(".cbz", "") }
.toHashSet() .toHashSet()
mangaDir.files = chapterDirs mangaDir.files = chapterDirs
@@ -191,12 +193,27 @@ class DownloadCache(
fun removeChapter(chapter: Chapter, manga: Manga) { fun removeChapter(chapter: Chapter, manga: Manga) {
val sourceDir = rootDir.files[manga.source] ?: return val sourceDir = rootDir.files[manga.source] ?: return
val mangaDir = sourceDir.files[provider.getMangaDirName(manga)] ?: return val mangaDir = sourceDir.files[provider.getMangaDirName(manga)] ?: return
val chapterDirName = provider.getChapterDirName(chapter) provider.getValidChapterDirNames(chapter).forEach {
if (chapterDirName in mangaDir.files) { if (it in mangaDir.files) {
mangaDir.files -= chapterDirName mangaDir.files -= it
} else if ("$it.cbz" in mangaDir.files) {
mangaDir.files -= "$it.cbz"
}
} }
} }
// SY -->
fun removeFolders(folders: List<String>, manga: Manga) {
val sourceDir = rootDir.files[manga.source] ?: return
val mangaDir = sourceDir.files[provider.getMangaDirName(manga)] ?: return
folders.forEach { chapter ->
if (chapter in mangaDir.files) {
mangaDir.files -= chapter
}
}
}
// SY <--
/** /**
* Removes a list of chapters that have been deleted from this cache. * Removes a list of chapters that have been deleted from this cache.
* *
@@ -208,9 +225,12 @@ class DownloadCache(
val sourceDir = rootDir.files[manga.source] ?: return val sourceDir = rootDir.files[manga.source] ?: return
val mangaDir = sourceDir.files[provider.getMangaDirName(manga)] ?: return val mangaDir = sourceDir.files[provider.getMangaDirName(manga)] ?: return
chapters.forEach { chapter -> chapters.forEach { chapter ->
val chapterDirName = provider.getChapterDirName(chapter) provider.getValidChapterDirNames(chapter).forEach {
if (chapterDirName in mangaDir.files) { if (it in mangaDir.files) {
mangaDir.files -= chapterDirName mangaDir.files -= it
} else if ("$it.cbz" in mangaDir.files) {
mangaDir.files -= "$it.cbz"
}
} }
} }
} }

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