Compare commits

...

748 Commits

Author SHA1 Message Date
c1064b1ba7 Fix browse comfortable grid 2020-05-24 16:13:52 -04:00
3a9f59b7a5 Finally a working comfortable grid 2020-05-24 15:59:44 -04:00
ccbe240846 Get Started on new Grid, only layout left 2020-05-24 15:59:44 -04:00
2c0d96917f Add multiline sources info for merged sources 2020-05-24 14:13:04 -04:00
0316cf47ed Fix merge with another crash(because of the kotlin dependency update) 2020-05-24 13:37:43 -04:00
e4c8de1145 Lint 2020-05-24 13:34:35 -04:00
9c978c608d Fix hiding the sync favorites option 2020-05-24 13:34:25 -04:00
b4a88926ed Rename EH Settings to Fork Settings 2020-05-24 13:12:51 -04:00
de593f458f Remove language from manga type detection and ignore casing for tags (#26)
* Remove language detection

* Ignore casing for tag detection

Co-authored-by: she11sh0cked <she11sh0cked@users.noreply.github.com>
2020-05-24 19:09:06 +02:00
f3c8b37928 Last few fixes for J2K Auto Migration 2020-05-23 23:30:07 -04:00
91f22c03c0 Multiple fixes for J2K auto migration 2020-05-23 23:15:42 -04:00
Jay
81ee1ce39a Batch select sources for pre migrations
Select none/all, pinned sources, enabled sources from the list

(cherry picked from commit 59c2da3f91052dfb0a292cb23ccb9d39055aadc7)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/design/PreMigrationController.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigrationListController.kt
#	app/src/main/res/drawable/ic_select_all_24dp.xml
#	app/src/main/res/values/strings.xml
2020-05-23 22:51:34 -04:00
Jay
2ed54eed73 Migration updates
When searching manually, the sources used for auto migration will also be used for searching
Can now migrate to the same source if it is the only source being used for migration (for those who cant stop using kakalot)

(cherry picked from commit a3305171d64a8dc4c2fa52d3e5257f45e92f29f1)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/GlobalSearchPresenter.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/migration/SearchController.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/migration/SearchPresenter.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigrationListController.kt
2020-05-23 22:28:25 -04:00
a9ef4bef8e Small migration change 2020-05-23 22:06:22 -04:00
c9b988aca6 Remove unneded update chapter view 2020-05-23 21:55:56 -04:00
b803dbe3af Update view when chapters read status has changed 2020-05-23 21:39:05 -04:00
35ef07d720 Lint 2020-05-23 16:16:52 -04:00
4f596d68b9 Handle empty thumbnail_url when refreshing covers
(cherry picked from commit ac8f2923e5)
2020-05-23 16:05:05 -04:00
26776f8430 Tweak history card design
(cherry picked from commit e9d3b75e2b)
2020-05-23 16:04:58 -04:00
471eb36a92 Avoid replacing covers with null when updating library (sort of closes #3194)
(cherry picked from commit e6bc181e7a)
2020-05-23 16:04:50 -04:00
8b8b377c29 Group advanced settings
(cherry picked from commit a2ece82197)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAdvancedController.kt
2020-05-23 16:04:21 -04:00
d70d2cdff5 Make metadata updating optional
(cherry picked from commit 259946cf0a)
2020-05-23 15:55:56 -04:00
b0704063f2 Move categories up in library settings
(cherry picked from commit 4fdb4f14a8)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsLibraryController.kt
2020-05-23 15:53:35 -04:00
dde7254dcf Update drag icon
(cherry picked from commit 914f5e569b)
2020-05-23 15:36:20 -04:00
4edb9ed398 Fix recycled icon in source migration list when source isn't installed
(cherry picked from commit 9b4ffd1cd5)
2020-05-23 15:29:40 -04:00
9d764781c3 Update the coroutine dependency and fix issues that were causing the crash 2020-05-23 00:57:41 -04:00
f7d991ab54 Revert coroutines update because of crashes 2020-05-23 00:31:32 -04:00
59b3b7d79d Fix builder 2020-05-22 17:53:00 -04:00
354bf362c0 Lint 2020-05-22 17:50:08 -04:00
69304466a7 Add icons to extension manager so they appear in more views without manually setting them 2020-05-22 17:50:08 -04:00
6e4d4739a6 Add migrate option from manga info view (closes #1903) (doesnt actually do anything in SY)
(cherry picked from commit 035038a0b6)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoController.kt
2020-05-22 17:50:08 -04:00
e8947b3107 Dependency updates
(cherry picked from commit ed87dd89a1)

# Conflicts:
#	app/build.gradle
2020-05-22 17:50:08 -04:00
153641a249 Add explicit refresh icon asset (maybe fixes #3218)
(cherry picked from commit 3b41a78e76)
2020-05-22 17:50:08 -04:00
60706e8b8b Rename downloaded chapters (#3216)
(cherry picked from commit 0fccbbc0ca)
2020-05-22 17:50:08 -04:00
19dc859ef2 Change resume button in history to an icon
(cherry picked from commit 067627b51a)
2020-05-22 17:50:08 -04:00
06ff4444c5 Refactor history_item.xml to use ConstraintLayout
(cherry picked from commit 09816ed5b6)
2020-05-22 17:50:08 -04:00
156cfb0c74 Scroll up/down when tapping top/bottom quarters of webtoon viewer
Includes a fix from J2K: 4e45a337da

(cherry picked from commit b457cdb0c2)
2020-05-22 17:50:08 -04:00
e49a25b604 Add bottom padding to history/sources/extensions (fixes #3192)
(cherry picked from commit 5fd1dec347)
2020-05-22 17:50:08 -04:00
b34a137c07 Make library update error notification optional (closes #3200)
(cherry picked from commit 647391ef73)
2020-05-22 17:50:08 -04:00
1fb6b3775d download new chapters changes (#3193)
* download new chapters changes

* move initialFetchChapters logic into onNextChapters

* refractor download new chapter logic to be more explicit

(cherry picked from commit ed029c52ae)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateService.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersPresenter.kt
2020-05-22 17:50:08 -04:00
b1c9a204c1 Minor edits
(cherry picked from commit d4ffb09a8b)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourceController.kt
2020-05-22 17:50:08 -04:00
8435be1b1f Implemented review changes
Shorter UI text and >= date comparison instead of >

(cherry picked from commit 6ba052d2af)
2020-05-22 17:50:08 -04:00
7affb9ab63 Fix unread badges not hiding in list view
(cherry picked from commit 2fb0969c75)
2020-05-22 17:50:08 -04:00
5627ad0801 Square covers in list view (closes #3121)
(cherry picked from commit 3357e878a5)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryListHolder.kt
2020-05-22 17:50:08 -04:00
08017a0cd1 Move cover card outline clipping code from item to holder classes
(cherry picked from commit 471d5d62d5)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/SourceGridHolder.kt
2020-05-22 17:50:08 -04:00
b6603c3425 Specify charset for ZIP chapters when using Android N+ (fixes #905)
(cherry picked from commit e810b343cf)
2020-05-22 17:50:08 -04:00
f63323feab Remove redundant helper function
(cherry picked from commit 620be2617a)
2020-05-22 17:50:08 -04:00
eea5f0ba6a Add fastscroller to migration lists
(cherry picked from commit b8ffb87f01)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/migration/MigrationController.kt
2020-05-22 17:50:08 -04:00
9f51dfad33 Sort list of sources in migration alphabetically
(cherry picked from commit 39e1e11f99)
2020-05-22 17:50:08 -04:00
c31789c112 Localize tracker not logged in error
(cherry picked from commit 5f9df78ab0)
2020-05-22 17:50:08 -04:00
86043fbb31 Warn about missing sources before restoring backup
(cherry picked from commit a00d11701f)
2020-05-22 17:50:08 -04:00
1136ec2ad4 Add fastscroller to updates and history
(cherry picked from commit 1cf74a5396)
2020-05-22 17:50:07 -04:00
7910f6e420 Minor cleanup
(cherry picked from commit 8cd27a199d)
2020-05-22 17:50:07 -04:00
a087b0bf4b Return job failure if library update actually doesn't start
(cherry picked from commit 772929b5c6)
2020-05-22 17:50:07 -04:00
d0929c1dc5 Slightly simplify AMOLED theme definition
(cherry picked from commit c4ca3606ad)
2020-05-22 17:50:07 -04:00
46500dcb32 Added missing sorting cases handling
Previous commit missed some cases resulting in errors at runtime

(cherry picked from commit 9e830f1c55)
2020-05-22 17:50:07 -04:00
f85c34b807 Added sorting by upload date
Spanish 'strings' contains the proper translation for the new feature.

(cherry picked from commit ee8c71c14a)
2020-05-22 17:50:07 -04:00
dfc3a5df42 Minor show more info button margin adjustment
(cherry picked from commit 39bd823651)
2020-05-22 17:50:07 -04:00
2b78925c68 Add Croatian to settings
(cherry picked from commit a9d16fad34)
2020-05-22 17:50:07 -04:00
eb2fedd669 Fix Chinese plurals
(cherry picked from commit 1da169319d)
2020-05-22 17:50:07 -04:00
b8b5e70151 Translations (Continuous) (#3125)
* Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (531 of 531 strings)

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

Translated using Weblate (Polish)

Currently translated at 100.0% (531 of 531 strings)

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

Translated using Weblate (Sardinian)

Currently translated at 100.0% (531 of 531 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (531 of 531 strings)

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

Translated using Weblate (French)

Currently translated at 100.0% (531 of 531 strings)

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

Translated using Weblate (French)

Currently translated at 100.0% (531 of 531 strings)

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

Translated using Weblate (Japanese)

Currently translated at 76.2% (405 of 531 strings)

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

Translated using Weblate (Turkish)

Currently translated at 100.0% (531 of 531 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (531 of 531 strings)

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

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (531 of 531 strings)

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

Translated using Weblate (Russian)

Currently translated at 100.0% (531 of 531 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (531 of 531 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (531 of 531 strings)

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

Translated using Weblate (Kannada)

Currently translated at 100.0% (531 of 531 strings)

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

Translated using Weblate (Marathi)

Currently translated at 46.8% (249 of 531 strings)

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

Translated using Weblate (Finnish)

Currently translated at 100.0% (531 of 531 strings)

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

Translated using Weblate (Catalan)

Currently translated at 100.0% (531 of 531 strings)

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

Translated using Weblate (Greek)

Currently translated at 100.0% (531 of 531 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (531 of 531 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% (531 of 531 strings)

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

Translated using Weblate (Dutch)

Currently translated at 100.0% (531 of 531 strings)

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

Translated using Weblate (Dutch)

Currently translated at 100.0% (531 of 531 strings)

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

Translated using Weblate (Indonesian)

Currently translated at 100.0% (531 of 531 strings)

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

Translated using Weblate (Hindi)

Currently translated at 100.0% (531 of 531 strings)

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

Translated using Weblate (German)

Currently translated at 100.0% (531 of 531 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (531 of 531 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% (531 of 531 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% (531 of 531 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% (531 of 531 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% (531 of 531 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% (531 of 531 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% (528 of 528 strings)

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

Translated using Weblate (Portuguese)

Currently translated at 99.4% (525 of 528 strings)

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

Translated using Weblate (Malay)

Currently translated at 100.0% (528 of 528 strings)

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

Translated using Weblate (Turkish)

Currently translated at 100.0% (528 of 528 strings)

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

Translated using Weblate (Russian)

Currently translated at 100.0% (528 of 528 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (528 of 528 strings)

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

Translated using Weblate (Dutch)

Currently translated at 100.0% (528 of 528 strings)

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

Translated using Weblate (Kannada)

Currently translated at 100.0% (528 of 528 strings)

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

Translated using Weblate (Finnish)

Currently translated at 100.0% (528 of 528 strings)

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

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (528 of 528 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% (528 of 528 strings)

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

Translated using Weblate (Hindi)

Currently translated at 100.0% (528 of 528 strings)

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

Translated using Weblate (German)

Currently translated at 100.0% (528 of 528 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (528 of 528 strings)

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

Added translation using Weblate (Spanish (Latin America))

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (528 of 528 strings)

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

Translated using Weblate (Romanian)

Currently translated at 100.0% (528 of 528 strings)

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

Translated using Weblate (Italian)

Currently translated at 100.0% (528 of 528 strings)

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

Translated using Weblate (Italian)

Currently translated at 100.0% (528 of 528 strings)

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

Translated using Weblate (Italian)

Currently translated at 93.5% (494 of 528 strings)

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

Translated using Weblate (Italian)

Currently translated at 93.5% (494 of 528 strings)

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

Translated using Weblate (Hungarian)

Currently translated at 34.0% (180 of 528 strings)

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

Translated using Weblate (Hungarian)

Currently translated at 30.1% (159 of 528 strings)

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

Translated using Weblate (Kannada)

Currently translated at 100.0% (528 of 528 strings)

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

Translated using Weblate (Marathi)

Currently translated at 46.5% (246 of 528 strings)

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

Translated using Weblate (Indonesian)

Currently translated at 100.0% (528 of 528 strings)

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

Translated using Weblate (Bengali)

Currently translated at 67.9% (359 of 528 strings)

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

Translated using Weblate (Kannada)

Currently translated at 55.8% (295 of 528 strings)

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

Translated using Weblate (Sardinian)

Currently translated at 99.8% (527 of 528 strings)

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

Translated using Weblate (Portuguese)

Currently translated at 97.9% (517 of 528 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (528 of 528 strings)

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

Translated using Weblate (Indonesian)

Currently translated at 100.0% (528 of 528 strings)

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

Translated using Weblate (Indonesian)

Currently translated at 100.0% (528 of 528 strings)

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

Translated using Weblate (Hindi)

Currently translated at 100.0% (528 of 528 strings)

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

Translated using Weblate (French)

Currently translated at 100.0% (528 of 528 strings)

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

Translated using Weblate (Bulgarian)

Currently translated at 99.8% (527 of 528 strings)

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

Translated using Weblate (Indonesian)

Currently translated at 97.7% (516 of 528 strings)

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

Translated using Weblate (Kannada)

Currently translated at 27.6% (146 of 528 strings)

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

Translated using Weblate (Marathi)

Currently translated at 34.8% (184 of 528 strings)

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

Translated using Weblate (Swedish)

Currently translated at 100.0% (528 of 528 strings)

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

Translated using Weblate (Swedish)

Currently translated at 100.0% (528 of 528 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (528 of 528 strings)

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

Translated using Weblate (German)

Currently translated at 100.0% (528 of 528 strings)

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

Added translation using Weblate (Kannada)

Translated using Weblate (Marathi)

Currently translated at 18.9% (100 of 528 strings)

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

Translated using Weblate (Marathi)

Currently translated at 8.5% (45 of 528 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (528 of 528 strings)

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

Translated using Weblate (Greek)

Currently translated at 100.0% (528 of 528 strings)

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

Translated using Weblate (Finnish)

Currently translated at 100.0% (528 of 528 strings)

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

Translated using Weblate (Catalan)

Currently translated at 100.0% (528 of 528 strings)

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

Translated using Weblate (Turkish)

Currently translated at 100.0% (528 of 528 strings)

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

Translated using Weblate (Russian)

Currently translated at 100.0% (528 of 528 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (528 of 528 strings)

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

Translated using Weblate (Polish)

Currently translated at 100.0% (528 of 528 strings)

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

Translated using Weblate (French)

Currently translated at 99.8% (527 of 528 strings)

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

Translated using Weblate (Spanish)

Currently translated at 100.0% (528 of 528 strings)

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

Translated using Weblate (Romanian)

Currently translated at 100.0% (527 of 527 strings)

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

Translated using Weblate (Greek)

Currently translated at 100.0% (527 of 527 strings)

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

Translated using Weblate (Chinese (Simplified))

Currently translated at 99.8% (526 of 527 strings)

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

Translated using Weblate (Chinese (Simplified))

Currently translated at 99.8% (526 of 527 strings)

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

Translated using Weblate (Finnish)

Currently translated at 100.0% (527 of 527 strings)

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

Translated using Weblate (Chinese (Simplified))

Currently translated at 99.8% (526 of 527 strings)

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

Translated using Weblate (Malay)

Currently translated at 100.0% (527 of 527 strings)

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

Translated using Weblate (Hindi)

Currently translated at 100.0% (527 of 527 strings)

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

Translated using Weblate (German)

Currently translated at 100.0% (527 of 527 strings)

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

Translated using Weblate (Catalan)

Currently translated at 100.0% (527 of 527 strings)

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

Translated using Weblate (Turkish)

Currently translated at 100.0% (527 of 527 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (527 of 527 strings)

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

Translated using Weblate (German)

Currently translated at 100.0% (527 of 527 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (527 of 527 strings)

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

Translated using Weblate (Romanian)

Currently translated at 100.0% (526 of 526 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (526 of 526 strings)

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

Translated using Weblate (German)

Currently translated at 100.0% (526 of 526 strings)

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

Translated using Weblate (Catalan)

Currently translated at 100.0% (526 of 526 strings)

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

Translated using Weblate (Hindi)

Currently translated at 100.0% (526 of 526 strings)

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

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 (Portuguese (Brazil))

Currently translated at 100.0% (528 of 528 strings)

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

Translated using Weblate (Dutch)

Currently translated at 100.0% (528 of 528 strings)

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

Translated using Weblate (Greek)

Currently translated at 100.0% (528 of 528 strings)

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

Translated using Weblate (Turkish)

Currently translated at 100.0% (528 of 528 strings)

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

Translated using Weblate (French)

Currently translated at 100.0% (528 of 528 strings)

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

Translated using Weblate (Finnish)

Currently translated at 100.0% (528 of 528 strings)

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

Translated using Weblate (Catalan)

Currently translated at 100.0% (528 of 528 strings)

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

Translated using Weblate (Swedish)

Currently translated at 100.0% (528 of 528 strings)

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

Translated using Weblate (Malay)

Currently translated at 100.0% (528 of 528 strings)

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

Translated using Weblate (Hindi)

Currently translated at 100.0% (528 of 528 strings)

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

Translated using Weblate (German)

Currently translated at 100.0% (528 of 528 strings)

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

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (528 of 528 strings)

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

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (527 of 527 strings)

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

Translated using Weblate (Sardinian)

Currently translated at 99.8% (526 of 527 strings)

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

Translated using Weblate (French)

Currently translated at 100.0% (527 of 527 strings)

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

Translated using Weblate (Greek)

Currently translated at 100.0% (527 of 527 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (527 of 527 strings)

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

Translated using Weblate (German)

Currently translated at 100.0% (527 of 527 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 (Portuguese (Brazil))

Currently translated at 100.0% (527 of 527 strings)

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

Translated using Weblate (Czech)

Currently translated at 73.4% (387 of 527 strings)

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

* Update translation files

Updated by "Cleanup translation files" hook in Weblate.

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

Co-authored-by: Hosted Weblate <hosted@weblate.org>
(cherry picked from commit 2bb1eea2be)
2020-05-22 17:50:07 -04:00
8c00905c99 Move extension preferences to separate controller
(cherry picked from commit 9cb45b92e1)
2020-05-22 17:50:07 -04:00
598af5ebd5 Add lost Croatian translation (#3176)
(cherry picked from commit 4a8d5098da)
2020-05-22 17:50:07 -04:00
8adedee973 Better distinguish between obsolete and unofficial extensions
(cherry picked from commit d875d5ef74)
2020-05-22 17:50:07 -04:00
4dc2143160 Show notification with error log on update failures
(cherry picked from commit fc4e290c49)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateService.kt
#	app/src/main/java/eu/kanade/tachiyomi/data/notification/Notifications.kt
2020-05-22 17:50:07 -04:00
aded163e0a Reword "Pager" to "Paged"
(cherry picked from commit ccc198e081)
2020-05-22 17:50:07 -04:00
11a553cbf4 Remove unused function
(cherry picked from commit 9f0ed77423)
2020-05-22 17:50:07 -04:00
a0048e9397 Avoid showing uninstalled source as last used
(cherry picked from commit bb3e616890)
2020-05-22 17:50:07 -04:00
a8a22b5803 Null check for local source cover parent dir
(cherry picked from commit 573f3a392a)
2020-05-22 17:50:07 -04:00
Jay
4122af491c Using a float on the progress on app updates
Not sure if needed but I saw some funny behavior with the progress bar

(cherry picked from commit 830a834ea6)
2020-05-22 17:50:07 -04:00
0de42b6654 Don't throw exception to stop restore job
(cherry picked from commit e4ea5d0344)
2020-05-22 17:50:07 -04:00
d7aa1144cf Copy to clipboard when long pressing tracking title (closes #3163)
(cherry picked from commit 97aed045e6)
2020-05-22 17:50:07 -04:00
855f768e29 Add version bumper (#25)
Co-authored-by: she11sh0cked <she11sh0cked@users.noreply.github.com>
2020-05-22 23:39:24 +02:00
87fbda0b29 Recommendations rewrite (#23)
* WIP Rewrite api requests to use a coroutine scope

* Use scope.async instead of scope.launch

* Use onPageReceived to async update Pager; Reimplement api select logic

* Implement seperate classes; Bug fixes

* More bug fixes

* Use timber; Add more logs

Co-authored-by: she11sh0cked <she11sh0cked@users.noreply.github.com>
2020-05-22 11:35:43 -04:00
99dd9a0750 Fix last chapter and last updated info 2020-05-21 21:38:55 -04:00
c8befdd5ea Fix manual refresh for manga, attempt to fix last chapter and last updated 2020-05-21 17:56:58 -04:00
54cf97170d Fix landscape view(jsut replaced it with a minorly edited portrait view) 2020-05-21 15:10:13 -04:00
a5aa89512a Half fixed landscape view 2020-05-21 00:57:49 -04:00
b02813f30a Fix MangaAllInOneHolder lazy vars 2020-05-21 00:57:33 -04:00
51c8430e9c Totally rewrote the all in one manga page, now is a recycler header
It works perfect, there is no lag it all
2020-05-21 00:30:09 -04:00
a846f7da47 Merge pull request #20 from Jacket-Chan/patch-1
Fixed a spelling error
2020-05-20 17:07:37 +02:00
b4e5443e56 Fixed a spelling error
:)
2020-05-19 22:44:37 -10:00
3fdfd91fff Fix the favorite button 2020-05-19 22:57:41 -04:00
e4b52c036a Lint 2020-05-19 22:01:22 -04:00
43098aa61b Added Auto Webtoon Mode 2020-05-19 22:00:58 -04:00
e4d8fea138 Lewd Filter upgrade, almost finished 2020-05-19 18:51:42 -04:00
6da22ea8b0 Fix multiple recommendation bugs (#18)
* Fix multiple recommendation bugs

* Fix typo

* Fix typings

* Remove unused import

Co-authored-by: she11sh0cked <she11sh0cked@users.noreply.github.com>
2020-05-19 18:42:17 -04:00
5e618e0134 Create PullRequestTester.yml 2020-05-19 18:27:40 -04:00
fd09f64fe6 Recommendation bug fixes (#17)
* Return an empty recommendations list instead of throwing an error

* Fix api response find for searched manga

* Fix spelling

Co-authored-by: she11sh0cked <she11sh0cked@users.noreply.github.com>
2020-05-19 16:54:59 -04:00
ef2241e0cb Fix recommendations throwing to early (#16)
* Fix recommendations throwing to early

Co-authored-by: she11sh0cked <she11sh0cked@users.noreply.github.com>
2020-05-19 16:01:48 -04:00
bcfe5af135 Fix filter button 2020-05-19 15:03:49 -04:00
a598afec43 Spelling correction 2020-05-19 13:54:03 -04:00
3c9ec48da3 Implement lewd filter (#15)
Co-authored-by: she11sh0cked <she11sh0cked@users.noreply.github.com>
2020-05-19 13:30:46 -04:00
7ce15caded Improve recommendations (#14)
* Improve anilist recommendations by matching synonyms; Some bug fixes related to anilist

* Fix formatting

* Sort myanimelist results by result.title matching search.title

* Throw an exception if the result is not the manga we searched

Co-authored-by: she11sh0cked <she11sh0cked@users.noreply.github.com>
2020-05-19 13:29:42 -04:00
7e65e0de0e fix tag detection 2020-05-19 00:19:43 -04:00
07a70d8c92 Add a crapton of detection for sources with only a certain type of manga 2020-05-18 21:39:31 -04:00
038574b107 Remove unused val 2020-05-18 20:23:56 -04:00
24067e1e97 Move new smart recommends to use new manga type detection 2020-05-18 20:19:18 -04:00
68b13c6425 Add modified J2k manga type detection 2020-05-18 20:11:09 -04:00
a9de6a123e Smart recommendations (#10)
* Pass manga through to RecommendsPager

* Implement smart recommendations

* Add null checks

* Add more anilistSmart tags

* Add fallback titles

Co-authored-by: she11sh0cked <she11sh0cked@users.noreply.github.com>
2020-05-18 20:10:54 -04:00
b0251b8177 Add support for EH Visited exported data in batch add 2020-05-18 13:00:13 -04:00
c069d75ede Fix Batch Add 2020-05-17 23:22:56 -04:00
5886cb7406 Fix all in one manga page being blank after clicking a button 2020-05-17 21:39:11 -04:00
1713dd4ea0 Made saved searches always available
Replace filtersheet with saved searches version if no filters are avalible
2020-05-17 20:52:51 -04:00
f5f7971cb5 Fix multiple bugs when fetching manga info 2020-05-17 17:11:46 -04:00
5271abbd1f Migrate the rest of the EH prefreches to Flow Prefrences 2020-05-17 17:11:46 -04:00
7d2ded5944 Implement MyAnimeList recommendations (#7)
Co-authored-by: she11sh0cked <she11sh0cked@users.noreply.github.com>
2020-05-17 15:38:38 -04:00
d2b0319d63 Added last debug features, should fix galleries that dont restore properly for the updater 2020-05-16 20:56:45 -04:00
c15f4c7fd0 Update debug functions 2020-05-16 19:44:12 -04:00
3aee05bf26 Enable new tracking features only if tracking is enabled 2020-05-16 18:37:06 -04:00
9d148a70c8 Fix filters 2020-05-16 18:01:11 -04:00
4a64bb250d Mitigate most of the lag problems, should fix all crashes(inspired by J2k code)
Add tracking button the way J2K has it, my own implementation
2020-05-16 17:53:14 -04:00
e6f5ea172a Filter tracker status (#2)
* Implement library filter for tracker status

Co-authored-by: she11sh0cked <she11sh0cked@users.noreply.github.com>
2020-05-13 20:35:01 -04:00
6a0ab3526a Implement library filter for tracked items (#1)
* Implement library filter for tracked items

* Revert formatting

* Move string 'tracked'

Co-authored-by: she11sh0cked <she11sh0cked@users.noreply.github.com>
2020-05-12 14:04:06 -04:00
fa29b914cc Multiple bug fixes and changes
- Fixed options menu

- Fixed merge with another

- Migrate to MaterialFastScroll
2020-05-11 20:10:51 -04:00
3a79f8fb50 Updated E hentai notifications to new system 2020-05-11 17:11:47 -04:00
321eb38f2d Fix Tag searching and Recommendations button 2020-05-11 17:10:29 -04:00
46dccf8a2d Lint fix 2020-05-11 16:31:19 -04:00
7f02a533fa fix regular font family name (#3154)
(cherry picked from commit 46b01c6134)
2020-05-11 16:28:28 -04:00
38d329a601 Temporarily revert concurrent manga updates
(cherry picked from commit e208fa4020)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateService.kt
2020-05-11 16:28:22 -04:00
1c0f08fc5b Cover Update Followup to Address #3139 (#3150)
* update cover logic when thumbnail url becomes null

* always clear cover on refresh even if custom cover is set

* remove concurrency changes

(cherry picked from commit 5723c184b1)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateService.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt
2020-05-11 16:08:30 -04:00
a076deeb5f Move notification logic out of LibraryUpdateService
(cherry picked from commit 530daeaa3a)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateService.kt
2020-05-11 16:05:16 -04:00
a006bc7d93 Rename EH update notifier 2020-05-11 16:03:32 -04:00
2b215524b6 Replace adapterPosition with bindingAdapterPosition in MigrationProcessHolder 2020-05-11 15:58:26 -04:00
f497e605b4 Style the recommendations buttonm 2020-05-11 15:57:40 -04:00
b09f1fff51 New All In One Manga interface, its optional and can be disabled 2020-05-11 15:33:38 -04:00
92af538b0a Fix Search error 2020-05-11 00:50:15 -04:00
f0b821b122 finish off recommendations
(cherry picked from commit 6473bcd32242abf8ba50b3ac76562ae6b931d0cd)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceController.kt
2020-05-11 00:20:51 -04:00
4c5e99142f Display recommendations from AniList
(cherry picked from commit f032667be5d2c9cfa5000ab1e166c7aaedbac701)
2020-05-11 00:05:40 -04:00
b0f39a7d0a add recommendations button to manga info
(cherry picked from commit 0d370004e6c78597957284d67f1af80881e17a49)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceController.kt
#	app/src/main/res/layout/manga_info_controller.xml
#	app/src/main/res/values/strings.xml
2020-05-11 00:05:28 -04:00
38b469755f Add simple hentai features option 2020-05-10 23:55:51 -04:00
3bfda338ef Add basic E/Ex-Hentai watched tag settings, possibly more to come 2020-05-10 22:36:52 -04:00
6e1da22353 Convert EH settings to FlowPrefrences 2020-05-10 19:22:10 -04:00
60a0303d7f Minor edits
(cherry picked from commit dd1b5c7ea7)
2020-05-10 16:26:21 -04:00
6135b4daae Animate in/out ActionToolbar
(cherry picked from commit 3cffc6890d)
2020-05-10 16:26:10 -04:00
2fe38192b4 Show date format examples, migrate to FlowPreferences
(cherry picked from commit 04d44f19f5)
2020-05-10 16:25:39 -04:00
ef3f4c2e17 Convert rotation to FlowPreference, remove some unused subscriptions code
Also remove EH lock code(was broken because of RxController changes)

(cherry picked from commit d46a742a43)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt
2020-05-10 16:25:07 -04:00
e4e069ccca Default unreadBadge setting to true (closes #3138)
(cherry picked from commit a94fd24fa9)
2020-05-10 14:27:32 -04:00
505d2e4274 Minor wording edits
(cherry picked from commit 8a4c4c346a)
2020-05-10 14:27:21 -04:00
4cdf2f468c Manga cover updates (#3101)
* cover caching overhaul

* add ui for removing custom cover

* skip some loading work

* minor cleanup

* allow refresh library metadata to refresh local manga

* rename metadata_date to cover_last_modified

* rearrange removeMangaFromLibrary

* change custom cover directory
add setting for updating cover when refreshing library

* remove toggle and explicit action for updating covers

(cherry picked from commit dc54299e24)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/data/database/DbOpenCallback.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourcePresenter.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryGridHolder.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoController.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoPresenter.kt
2020-05-10 14:27:05 -04:00
8c7a2c4262 Add more info in tracking settings section
(cherry picked from commit 436253dd63)

# Conflicts:
#	app/src/main/res/values/strings.xml
2020-05-10 14:11:52 -04:00
156ce14dd8 Action: Remove Acknowledgement pong 2020-05-10 14:03:08 -04:00
27dc6443ec Fix broken updater 2020-05-10 01:23:41 -04:00
0a5773211d Added preview builds link 2020-05-10 01:19:31 -04:00
b3b0c39163 Fix naming of the preview repo 2020-05-10 01:12:56 -04:00
bc6b4d4be6 Test push 2020-05-10 00:52:02 -04:00
a14e5a99d9 Setup first full beta test 2020-05-10 00:29:43 -04:00
d643b947a9 Add files for new action, should allow automatic updating when finished 2020-05-10 00:20:36 -04:00
2033e82ff0 Update android-debug.yml 2020-05-09 22:16:24 -04:00
c2c872d000 Action: make the file a .apk 2020-05-09 21:44:44 -04:00
ae9377f8be Action: Should Fix uploading 2020-05-09 21:30:44 -04:00
93a84cad34 Action: Test Signed path 2 2020-05-09 21:10:40 -04:00
f9ceb92495 Action: Test this path enviorment variable 2020-05-09 21:09:42 -04:00
bfdd5c9ec3 Action: Remove something I forgot 2020-05-09 20:53:12 -04:00
d800528550 Action: Change write file and attempt to fix app signing 2020-05-09 20:52:27 -04:00
6ec656b094 Action: Change way of attempting to get the needed NDK 2020-05-09 20:30:45 -04:00
29c5da1494 Action: Only assemble release 2020-05-09 20:02:15 -04:00
0a21a9e5f0 Remove validate gson 2020-05-09 19:39:12 -04:00
d3aaa3656b Another way to add the json to the actions 2020-05-09 19:29:32 -04:00
69a8223d06 Fix formatting error in action 2020-05-09 19:18:38 -04:00
6959370087 Use another way to create the file 2020-05-09 19:17:23 -04:00
1d0937397f I think I fixed the actions this time 2020-05-09 19:00:45 -04:00
aeeafe8556 Action for some reason had ; 2020-05-09 18:52:04 -04:00
38c5163ab9 Did removing this break the action? 2020-05-09 18:51:15 -04:00
4646e4b0d9 Hopefully this time fixes it 2020-05-09 18:49:07 -04:00
e9f105c52a Hopfully fix google-services.json copying to app 2020-05-09 18:40:19 -04:00
3b225405cb Add Google-services.json to action 2020-05-09 18:28:35 -04:00
b96a870c4e Attempt to fix build errors 2020-05-09 18:09:21 -04:00
b70d70e82d Make a debug build action 2020-05-09 17:56:45 -04:00
f4d1c27cde Fix tapping manga info button and fix not showing full info when first looking at the manga 2020-05-09 13:10:45 -04:00
4195b00e48 Fix not removing the more button when global search doesnt find anything in that source 2020-05-09 13:06:59 -04:00
0a37dabf4b Release 0.9.2.7 2020-05-09 12:20:57 -04:00
2d5ac20c46 Re-Implement the more button in global search 2020-05-09 12:06:36 -04:00
700fd61f34 Update details metadata along with chapters list
(cherry picked from commit 29feee0095)
2020-05-09 11:49:28 -04:00
a0462fb480 Move DB transaction blocks to only the DB portions of restore logic
(cherry picked from commit 63f3180dff)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestoreService.kt
2020-05-09 11:49:15 -04:00
d9d969406e Revert Nucleus to 3.0.0
Fixes #3028
Fixes #3013
Fixes #3037

(cherry picked from commit 6b3b98cf57)
2020-05-09 11:48:15 -04:00
f19685787f Option to hide unread badges (closes #3095)
(cherry picked from commit 1442e2b53e)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt
#	app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt
2020-05-09 11:48:01 -04:00
60caba86a5 Remove redundant DB call in library settings (closes #3128)
(cherry picked from commit 521ebf0678)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestoreService.kt
2020-05-09 11:43:43 -04:00
80fa7ebe6c String Formatting Fixes (#3118)
String Formatting Fixes

(cherry picked from commit a20874f6a1)
2020-05-09 11:41:45 -04:00
9096edfc92 Concurrently refresh trackers
(cherry picked from commit 40776bdc8d)
2020-05-09 11:41:32 -04:00
f30ad78a4c Do library checks from up to 5 sources concurrently
(cherry picked from commit f853158e6b)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateService.kt
2020-05-09 11:40:32 -04:00
ce0d99b78f Download from up to 5 different sources concurrently (closes #2534)
(cherry picked from commit c9035b5df9)
2020-05-09 11:36:04 -04:00
3ffb80c6f1 Concurrently download up to 5 pages at a time
(cherry picked from commit 150132f4dd)
2020-05-09 11:35:52 -04:00
4e3c407583 Replace restore completion string with plurals
(cherry picked from commit fb97ac47bc)
2020-05-09 11:35:43 -04:00
aaf9fc5d92 Translated using Weblate (Swedish) (#3124)
Translations

(cherry picked from commit 5b53b90495)
2020-05-09 11:35:09 -04:00
5043f840a2 Translated using Weblate (Swedish) (#3043)
Translations (Continuous)

(cherry picked from commit c6513d4450)
2020-05-09 11:34:51 -04:00
fac3bd1edd Show icon when chapter is bookmarked
(cherry picked from commit ce6848b3c0)
2020-05-09 11:34:38 -04:00
976cd41a87 MaterialFastScroll updates
(cherry picked from commit d86d861e4b)
2020-05-09 11:34:24 -04:00
4aeaee65c3 Use borderless buttons everywhere for consistency
(cherry picked from commit 3b45fcdb21)
2020-05-09 11:32:48 -04:00
f880a0f1a3 Do some download deletion in coroutines instead of completable
(cherry picked from commit 3d1250f2f8)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt
2020-05-09 11:32:31 -04:00
3a886e39fb Remove fdroid flavor
(cherry picked from commit eaf1ef831a)
2020-05-09 11:30:54 -04:00
005d43a3ec Minor cleanup of wakelocks, extension ID backup
(cherry picked from commit b4c7992726)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/util/system/ContextExtensions.kt
2020-05-09 11:30:38 -04:00
1d760f4728 Destroy action mode after actioning in chapters list (closes #3004)
(cherry picked from commit 03baa21185)
2020-05-09 11:20:53 -04:00
02e3148efe Adopt MaterialFastScroll from J2K fork
de8cb8c1b0
(cherry picked from commit 694de99a3f)
2020-05-09 11:20:42 -04:00
e9ada7e5fb Increase webtoon setting change page refresh range (closes #3088)
(cherry picked from commit 8383f4fb7b)
2020-05-09 11:20:31 -04:00
2ce01a1c86 Alternative way of reading local manga JSON file
(cherry picked from commit eb3fff6c51)
2020-05-09 11:20:21 -04:00
1af8bc95a8 Tweak about manga heading
(cherry picked from commit 4ff3f0bcba)
2020-05-09 11:20:08 -04:00
0046ed879f Convert app updater to foreground service
(cherry picked from commit 788ea052fc)
2020-05-09 11:18:23 -04:00
4f8c6455bc Fix updates/history section headers in RTL locales
(cherry picked from commit 08ba805bbd)
2020-05-09 11:18:03 -04:00
c80b8c8ce9 Refresh page on 32-bit color setting change
(cherry picked from commit dbd14c6dac)
2020-05-09 11:17:49 -04:00
5435c2fb53 Lighter weight method of rounding cover art and removed rounded covers option
(cherry picked from commit dabca5f09e)
2020-05-09 11:17:07 -04:00
88963758b1 Add specific support for dummy extensions so that read chapter history is able to be freely restored without connecting to the source 2020-05-08 21:18:29 -04:00
e4d40c7693 Made migrate and merge with another only visible if the manga is favorited 2020-05-07 22:01:14 -04:00
2f928ac034 Release 2.9.2.6 2020-05-07 15:11:50 -04:00
509d7b20b4 ReImplement history features 2020-05-07 14:50:24 -04:00
35c4d0bf4e Saved searches now work 2020-05-06 15:19:37 -04:00
5e5f2b0f1a hide 'latest' when merging sources
(cherry picked from commit 40c1967f19d0db475acd04025989ded80571565d)
2020-05-05 15:28:36 -04:00
58135c965c Release 0.9.2.5 2020-05-05 14:34:22 -04:00
5a9b84fe00 Fix issue where some sources just wouldnt work at all (examples are Dynasty and Toonily) 2020-05-05 14:28:21 -04:00
c9a10d9033 Update build.grade and lint fixes 2020-05-05 14:27:28 -04:00
730c316e89 Small brackets change, though I dont think logic will(though knowing my luck this might have been the reason) 2020-05-05 00:54:47 -04:00
29a07429df Release 0.9.2.4 2020-05-04 23:52:34 -04:00
e44616fb3c Fix bottom nav opening if opening manga from updates while in action mode
(cherry picked from commit 5977fca6b9)
2020-05-04 23:41:08 -04:00
cb6ca49607 Remove some unneeded regular tachi stuff 2020-05-04 23:40:46 -04:00
ff8b58ee62 [CI SKIP] Add dev branch deploy script configuration
(cherry picked from commit 018dbce57e)
2020-05-04 23:36:42 -04:00
b1350928ee Remove unused import 2020-05-04 23:35:16 -04:00
52641494d3 Test for saved searches (currently doesnt work) 2020-05-04 21:04:58 -04:00
9bfe4ed829 Remove unneeded backup stuff, now almost everything is from stable 2020-05-04 20:33:09 -04:00
d6f0c0837b Fix downloaded only 2020-05-04 19:20:54 -04:00
074a1bbca4 Implement logic for saved searches 2020-05-04 19:17:14 -04:00
178cd2b52d Add my github 2020-05-04 16:44:29 -04:00
e35f807218 Change source migraton icon 2020-05-04 16:17:32 -04:00
63ca5cc66b Remove dev update checker 2020-05-04 16:17:07 -04:00
6b66d4a34c Move strings to external file 2020-05-04 15:35:25 -04:00
49580a7630 Fixed All Sources in Filter list 2020-05-04 13:58:08 -04:00
0300c1057b Release 0.9.2.3 2020-05-04 02:00:42 -04:00
f5b8d3120d Fix anilist jsonnull issue
41c64b7058
(cherry picked from commit abf47deee3)
2020-05-04 01:40:11 -04:00
fd88db37f7 Bunch of crash fixes
(cherry picked from commit ce0090f0ca)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourceController.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourcePresenter.kt
2020-05-04 01:39:52 -04:00
39e36f957d More extreme method for enforcing WebView availability
(cherry picked from commit 6cd34614f6)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/App.kt
2020-05-04 01:34:02 -04:00
e84c39bf7b Hitomi tag fixes(should now work for most tags) 2020-05-04 01:18:40 -04:00
5641b33bdd Add EH and similar specific tag formatting for global and local search 2020-05-04 00:53:38 -04:00
72681bef83 Fix showing hidden sources like the merged source 2020-05-04 00:16:33 -04:00
6de16125f7 Fix cutoff for new buttons if your screen is small 2020-05-04 00:15:56 -04:00
46478546a8 Implement long click global search for tags 2020-05-04 00:06:20 -04:00
d4659ffaae Fix merge with another crash 2020-05-04 00:05:44 -04:00
e192806950 Fix migration and merge buttons now showing up 2020-05-03 23:09:02 -04:00
1170334fde Fix adding a manga to library crash 2020-05-03 23:05:42 -04:00
d368064549 Possibly fix backup restores 2020-05-03 22:36:30 -04:00
ada0703d17 Remove unneeded variable 2020-05-03 21:46:43 -04:00
06d3a753ac Add manga migration and merge buttons 2020-05-03 21:24:00 -04:00
567c6ea8e7 Merging bugfix 2020-05-03 21:23:33 -04:00
bfc0868721 add built-in source icons
(cherry picked from commit f4533d9c7e0f989095bf40198dda59e58e1a6e01)
2020-05-03 19:35:53 -04:00
f5b7a8db1a Setup for install 2020-05-03 19:33:28 -04:00
bef0a44447 It Builds! 2020-05-03 18:34:46 -04:00
e9ff202851 Basic fixes 2020-05-03 15:03:07 -04:00
4a3323f7d0 Revert to old sorting library (fixes #3034)
(cherry picked from commit e29e94a5a1)
2020-05-03 14:41:17 -04:00
0014a0ca6c Migrate to flow 2020-05-03 14:37:31 -04:00
7e99a9f789 Linting Fixes AZ 2020-05-03 14:36:19 -04:00
03e5c5ca10 Linting fixes
(cherry picked from commit 3f63b320c4)
2020-05-03 14:35:49 -04:00
e4ff988f4d Revert some seekbar event listener changes
(cherry picked from commit 134dbd2f1d)
2020-05-03 14:34:40 -04:00
dde2320afc Replace some listeners with flowbindings
(cherry picked from commit dad010a891)
2020-05-03 14:34:40 -04:00
988d508025 Remove option to turn off app update checks, check every 3 days
(cherry picked from commit 8c1ec43500)
2020-05-03 14:34:11 -04:00
24850450cb Migrate more preferences
(cherry picked from commit 53a3be0703)
2020-05-03 14:33:03 -04:00
e97d1ac257 Replace deprecated adapterPosition with bindingAdapterPosition
(cherry picked from commit c967308859)
2020-05-03 14:31:00 -04:00
bc44eee5b7 Merge branch 'master' of https://github.com/az4521/Tachiyomi
necessary,
2020-05-03 14:29:54 -04:00
7a010e3446 Material Dialogs Eh Part 3 2020-05-03 14:29:11 -04:00
cb4fbb19ed Material Dialogs Eh Part 2 2020-05-03 14:29:10 -04:00
ddf0357c5c Material Dialogs Eh Part 1 2020-05-03 14:28:40 -04:00
800c01ea42 Lint fixes and update build.gradle 2020-05-03 14:27:34 -04:00
68bfba486e Added number of pages to preload configuration 2020-05-03 14:26:05 -04:00
c09f6cb20c Lint fixes 2020-05-03 14:25:41 -04:00
959bad0247 Lint fixes, likely nothing broke 2020-05-03 14:25:24 -04:00
efb8555d76 Update to SDK 29 (Android 10) (#2468)
(cherry picked from commit 83d5e458ca)
2020-05-03 14:24:52 -04:00
a393772083 Move things back into the EH package, no need for them to be in the regular app 2020-05-03 14:24:22 -04:00
b4ade8c15d Lint fixes, likely no visible changes 2020-05-03 14:22:13 -04:00
03502f6533 Merge branch 'master' of https://github.com/az4521/Tachiyomi 2020-05-03 14:21:26 -04:00
42c7669bca database changes for mergedsources 2020-05-03 14:21:26 -04:00
1916751f4f Complete RxBindings to FlowBinding migration
(cherry picked from commit 3d10dad780)
2020-05-03 14:19:54 -04:00
e46dd808e7 Remove unused widget styles and animations
(cherry picked from commit 01dd46c5ed)
2020-05-03 14:16:06 -04:00
5e92664761 Replace some old color attribute usages
(cherry picked from commit 11e10f6eff)
2020-05-03 14:15:36 -04:00
aa5fd22db0 Add confirm exist setting (closes #2615)
(cherry picked from commit 321a4b24b9)
2020-05-03 14:14:45 -04:00
56b1c07f58 Refactor databinding fields to parent abstract classes
(cherry picked from commit 6a532b836d)
2020-05-03 14:12:46 -04:00
2ecac08bcc Round manga info cover
(cherry picked from commit e388f0d563)
2020-05-03 14:11:12 -04:00
95002a6e87 More FlowPreferences migrations
(cherry picked from commit b8152dd7f9)
2020-05-03 14:03:50 -04:00
cea2b42b41 More FlowPreferences migrations
(cherry picked from commit 401210da44)
2020-05-03 14:02:47 -04:00
8bc5a7d746 Migrate some RxSharedPreferences to FlowSharedPreferences
(cherry picked from commit beb81b657e)
2020-05-03 14:00:35 -04:00
85723b975b Lint fix 2020-05-03 13:58:54 -04:00
a2e05cf80b Move bitmap images to nodpi
(cherry picked from commit 7118817df7)
2020-05-03 13:58:29 -04:00
87363e47b0 Remove setting that was accidentally added 2020-05-03 13:57:39 -04:00
aefa7a1a4a Fixes and such for integration to AZ 2020-05-03 13:56:36 -04:00
18f90587f2 Added option to migrate manga from manga details
(cherry picked from commit 3a4780e19b79e9afcb3e830cb02c52bd1c66bddf)
2020-05-03 13:34:42 -04:00
f47e9b6e14 Fixed migration crash when getting chapters
(cherry picked from commit a529667257908ddebaa92d36a83380c3c6c40408)
2020-05-03 13:22:40 -04:00
a7e4c1295d More Plurals
(cherry picked from commit bcd6c33ed8aaa1cf81c027f88ce4a954e379a545)
2020-05-03 13:22:40 -04:00
50097eef9f Fixes for merging from upstream
(cherry picked from commit 5f2eb19ea37ba191d414eee4e8f45f20f1a73e89)
2020-05-03 13:22:39 -04:00
949cdccbae Confirm exit for migrations
(cherry picked from commit 640bd8d9babb3ace1d6a370adad35050271aa008)
2020-05-03 13:22:39 -04:00
3d0dc64de1 Mass Migration now shows progress and total manga in the title
(cherry picked from commit 68c3d28b4bc7b5cc4038648d5f187fe4da9a42a9)
2020-05-03 13:22:18 -04:00
2e0102d689 Migrations now shows how many manual migrations were made after skipping the rest
(cherry picked from commit bac01c98073dbee6c09144b6ebc55b6a0d56d0da)
2020-05-03 13:22:17 -04:00
2557111607 Optimzing Mass-Migration
(cherry picked from commit 504a10a6ebc3f28a5dd761db8a90c709c8794153)
2020-05-03 13:22:17 -04:00
46a626d2c5 Fixed crash when rapidly trying to skip manga
(cherry picked from commit 14c80436fcb92d22f0691b7b68caf524fd09cab5)
2020-05-03 13:22:17 -04:00
fb92b1a0b4 Update MigrationProcessHolder.kt
(cherry picked from commit dbbdc4c62e83328fd5d3623e42e56aa74511c320)
2020-05-03 13:22:16 -04:00
8e6ed194a6 Moved migration icons to main
(cherry picked from commit e89853afcfc2dff47a79a5d5aa67d37b049748cd)
2020-05-03 13:22:16 -04:00
01175e687c Another fix for mass migration
Also fixing some deprecated code

(cherry picked from commit 2535ea92ebc97bad9f30e9e48493629df6db28a3)
2020-05-03 13:22:15 -04:00
00d2d4f969 More refactoring + more bug fixes
Such as when a manga picked has 0 chapters

(cherry picked from commit 332e8c9487b2e5e39a3a90705b2def80183bcc04)
2020-05-03 13:20:57 -04:00
43715f9835 Build fixes and remove possibly unneeded settings? 2020-05-03 13:20:56 -04:00
b99229b033 Refactoring + fixes for auto-migrate
(cherry picked from commit 142dc1c12a95534170517deb077c98896214a2d9)
2020-05-03 13:19:12 -04:00
62df1263b1 Cleanup of olf auto migration
(cherry picked from commit d64754e3e09e92b2e65c181b0b5e84b531490662)
2020-05-03 13:18:47 -04:00
a6f0e7f9b9 Part 2 of Auto-Migration Done
(cherry picked from commit c4321e3adfff1bdfdcd8ba209dd20549348be217)
2020-05-03 13:18:02 -04:00
f1472d4f8b Fixes for this new auto migration ui
(cherry picked from commit 6d6ff9598205e11c767cedf2fbe261f746df0624)
2020-05-03 13:08:47 -04:00
52ad282492 Finished Part 1 of new auto source migration
(cherry picked from commit 10206ae7b30fbd521308a6d725e107e708b97dd0)
2020-05-03 13:08:46 -04:00
e7b39f29f2 Implemented J2K Auto Source Migration
(cherry picked from commit 8ba75831e6f51f6472d85f813405ede3f679cfd8)
2020-05-03 13:07:43 -04:00
c62d3abbc5 Fix Migrations 2020-05-03 02:15:54 -04:00
fb3ce226b5 Made rounded library covers configurable 2020-05-03 02:15:54 -04:00
de5f43713f Rename catalogue classes/layouts -> source
(cherry picked from commit a1e7592bd8)
2020-05-03 02:14:08 -04:00
84aba68b96 Add persistent notch display mode
(cherry picked from commit 444cfa7669166edc874da4994396776a90ded465)
2020-05-03 02:08:53 -04:00
1be0171398 fix fingerprint icon in dark themes 2020-05-03 02:08:33 -04:00
82c49a42c3 fix lockscreen 2020-05-03 02:08:33 -04:00
599a4c7b17 Fix unintended change 2020-05-03 02:08:13 -04:00
895dbbdacb Set needed migrations 2020-05-03 02:07:07 -04:00
77026d4eeb Pure Light Theme fixes and adding eh stuff to strings.xml 2020-05-03 02:06:04 -04:00
256b1881f0 Tweak Button Styles Part 2 2020-05-03 01:57:54 -04:00
2a299485cc Add proper AZ Debug Icon 2020-05-03 01:53:59 -04:00
a6909a76ed Fix common toolbar popup menu text color (fixes #2695)
(cherry picked from commit b9ea6e8d96)
2020-05-03 01:52:05 -04:00
1ecba5bb7e Migrate to MaterialComponents themes
(cherry picked from commit 7d0ea614da)
2020-05-03 01:49:44 -04:00
c381b737d3 Use outlined icons in settings
(cherry picked from commit ace54f8175)
2020-05-03 01:48:03 -04:00
70e7974396 Json build fixes 2020-05-03 01:47:35 -04:00
2104b60b81 Run lint 2020-05-03 01:41:34 -04:00
09dcb8029c Add setting to hide manga content from update/download notifications
(cherry picked from commit f3d69599aa)
2020-05-03 01:41:06 -04:00
f2ed26479f Update for Workmanager 2020-05-03 01:40:53 -04:00
d03d9b344a Reenable Proguard
(cherry picked from commit bb7ed73743)
2020-05-03 01:38:48 -04:00
9b5fbda9a2 move jsoupextensions back pt2 2020-05-03 01:37:58 -04:00
647fbd1f4b Move JsoupExtensions back (fixes #2562) 2020-05-03 01:37:58 -04:00
fa6ed901df Optimize more imports 2020-05-03 01:37:25 -04:00
23ac3d18e5 Optimize imports, disallow wildcard imports because of klint, run linter 2020-05-03 01:36:21 -04:00
f18891a07e Move crash reports setting to advanced
(cherry picked from commit 978ac50015)
2020-05-03 01:34:51 -04:00
c85825f3c7 Run default Android Studio formatter on code
(cherry picked from commit 3ecc883944)
2020-05-03 01:33:58 -04:00
319571edf3 Remove EH custom incognito webview in favor of new activity webview from Dev(I could not get it working with the new system.) 2020-05-03 01:08:08 -04:00
1f20d96191 Convert webview into an activity (#2470)
Based on 65804ebb3a

(cherry picked from commit 797553ce16)
2020-05-03 01:06:07 -04:00
c2e50305eb Converted tachiyomi_circle to webp 2020-05-03 01:05:01 -04:00
d00e1284d6 Convert filter mock image to webp
(cherry picked from commit eb56567812)
2020-05-03 01:04:26 -04:00
ef4430216d fix github updater 2020-05-03 01:00:41 -04:00
643f666178 Notification conflict fix 2020-05-03 01:00:41 -04:00
989b968e5b Merge pull request #7 from jobobby04/Extensions_Overhaul_plus_other
Extensions overhaul plus other
2020-05-03 01:00:27 -04:00
92484e26e5 Set manga last update field based on chapter fetch time (closes #2217)
Based on 3c81f60041 (diff-7e5179d048c3dfaf75b444b7277fc840)

(cherry picked from commit ee8a53188c)
2020-05-03 01:00:27 -04:00
429056f2ca Build fixes 2020-05-03 00:48:34 -04:00
fa2b44eeb3 Move edit categories to library settings 2020-05-03 00:44:30 -04:00
52e742049b Reorganize other util files 2020-05-03 00:39:16 -04:00
97a86269e6 change a dependency to try to fix merged sources 2020-05-03 00:31:59 -04:00
654d98b5c4 unhide merged sources 2020-05-03 00:31:43 -04:00
0509db1935 E-Hentai WatchedList checkbox fix (#2) 2020-05-03 00:31:07 -04:00
acf879d28c Added Ehentai Watched list (#1) 2020-05-03 00:31:07 -04:00
cefe45e8cc fixed double-locking, added secure screen, fixed tsumino for real this time 2020-05-03 00:30:52 -04:00
03b44fff22 update changelog and readme, fix hentaicafe tags 2020-05-03 00:27:44 -04:00
71c373926f lock no longer requires usage access 2020-05-03 00:27:32 -04:00
1af11f076f finish adding drag and drop 2020-05-03 00:25:04 -04:00
Jay
41c99c33a6 cherrypick drag and drop sorting 2020-05-03 00:12:54 -04:00
58cce53746 delegate tsumino 2020-05-02 23:52:58 -04:00
df6cafd6d1 bump version, changelog, hide merged sources 2020-05-02 23:52:21 -04:00
cc6c1b5641 add debug for EH aged flags 2020-05-02 23:51:52 -04:00
d61adc0259 nhentai language filtering, added dev build in settings 2020-05-02 23:51:21 -04:00
9ed7ee65c3 unhide and begin working on merged sources 2020-05-02 23:48:30 -04:00
5f94e230f9 adaptive fingerguns icon 2020-05-02 23:45:00 -04:00
4d8f44ddae merge double upstream 2020-05-02 23:39:46 -04:00
264e04368b Update issue templates 2020-05-02 15:07:47 -04:00
43c11c6ac5 Release 0.9.2 2020-05-02 15:00:10 -04:00
ede42cd6aa Add link to extensions repo 2020-05-02 15:00:03 -04:00
33901dd72f More ActionToolbar tweaks 2020-05-02 14:51:28 -04:00
ac4ae8103e Force FastScrollers to be on right even in RTL (closes #3038) 2020-05-02 14:39:47 -04:00
2c93704b4a Translated using Weblate (Malay) (#3007)
Currently translated at 100.0% (526 of 526 strings)

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

Translated using Weblate (French)

Currently translated at 99.8% (525 of 526 strings)

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

Translated using Weblate (German)

Currently translated at 100.0% (526 of 526 strings)

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

Translated using Weblate (Malay)

Currently translated at 100.0% (525 of 525 strings)

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

Translated using Weblate (Hindi)

Currently translated at 100.0% (525 of 525 strings)

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

Translated using Weblate (French)

Currently translated at 99.6% (523 of 525 strings)

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

Translated using Weblate (German)

Currently translated at 100.0% (525 of 525 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 (Finnish)

Currently translated at 99.8% (522 of 523 strings)

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

Translated using Weblate (Catalan)

Currently translated at 100.0% (523 of 523 strings)

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

Translated using Weblate (Greek)

Currently translated at 100.0% (523 of 523 strings)

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

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (523 of 523 strings)

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

Translated using Weblate (Turkish)

Currently translated at 100.0% (523 of 523 strings)

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

Translated using Weblate (Portuguese)

Currently translated at 100.0% (523 of 523 strings)

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

Translated using Weblate (Malay)

Currently translated at 100.0% (523 of 523 strings)

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

Translated using Weblate (French)

Currently translated at 100.0% (523 of 523 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (523 of 523 strings)

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

Translated using Weblate (Japanese)

Currently translated at 79.3% (415 of 523 strings)

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

Translated using Weblate (German)

Currently translated at 100.0% (523 of 523 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (522 of 522 strings)

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

Translated using Weblate (French)

Currently translated at 100.0% (522 of 522 strings)

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

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 (French)

Currently translated at 100.0% (523 of 523 strings)

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

Translated using Weblate (German)

Currently translated at 100.0% (523 of 523 strings)

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

Translated using Weblate (French)

Currently translated at 99.6% (521 of 523 strings)

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

Translated using Weblate (Russian)

Currently translated at 100.0% (523 of 523 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (523 of 523 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% (523 of 523 strings)

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

Translated using Weblate (French)

Currently translated at 98.8% (517 of 523 strings)

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

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (523 of 523 strings)

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

Translated using Weblate (Russian)

Currently translated at 100.0% (523 of 523 strings)

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

Translated using Weblate (German)

Currently translated at 100.0% (523 of 523 strings)

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

Co-authored-by: Hosted Weblate <hosted@weblate.org>
2020-05-02 12:34:55 -04:00
e2158af592 Swap bottom nav and ActionToolbar when appropriate 2020-05-02 12:27:23 -04:00
b06189ff95 Revert last_updated change 2020-05-02 12:11:51 -04:00
d72c51c8dd Hide app/nav bars on scroll 2020-05-02 11:33:31 -04:00
e29e94a5a1 Revert to old sorting library (fixes #3034) 2020-05-02 10:56:03 -04:00
04d7eccc63 Show number of categories in setting summary 2020-05-02 10:47:21 -04:00
e58896bdfb Separate out series viewer setting to its own group in reader sheet 2020-05-02 10:41:56 -04:00
d2bb4487e1 Move pager-specific settings into proper category, add summary for 32-bit color setting 2020-05-02 10:41:38 -04:00
e8623fbd7d Show 32-bit color setting in reader sheet 2020-05-02 10:40:55 -04:00
0a6de2b3ea Fix backup failing when source isn't installed 2020-05-02 10:24:37 -04:00
23a8e31791 Hide filter FAB when opened (closes #3024) 2020-05-02 10:22:28 -04:00
b20c028566 skip double upstream androidx migration 2020-01-06 10:57:37 -05:00
9b883b1a09 androidx migration
I DID THIS ONE MYSELF WITHOUT TAKING IT FROM THE OTHER FORKS
YEEEEEEEEEEET
2020-01-06 03:26:31 -05:00
53402459f2 library tag searching and reordering downloads 2020-01-05 12:33:28 -05:00
bc6a1a1da6 add tristate library filters, update to dev 2020-01-04 15:16:49 -05:00
690d2fb15b fixed tsumino for real this time really 2019-11-29 01:18:21 -05:00
7ac188709b tsumino half fixed. mostly usable 2019-11-28 22:52:44 -05:00
93c8773e91 Update Tsumino.kt 2019-11-28 18:46:19 -05:00
eefe95c2ee Update TsuminoSearchMetadata.kt 2019-11-28 18:45:04 -05:00
af9825d369 Update TsuminoSearchMetadata.kt 2019-11-28 18:17:04 -05:00
59f38cb343 Update Tsumino.kt 2019-11-28 17:37:24 -05:00
810d2d4776 fix tsumino for real this time 2019-11-28 17:33:55 -05:00
027cb10d0f fix tsumino 2019-11-28 16:35:58 -05:00
24a6eba94e match upstream 2019-11-28 16:24:51 -05:00
c1c43bb6fb Add minimum/maximum pages filter to E-Hentai/ExHentai source 2019-08-31 17:45:40 -04:00
0804550539 Fix strange behavior when using text filters 2019-08-31 17:44:47 -04:00
3156482334 Upgrade Gradle, Kotlin and KotlinX Coroutines 2019-08-31 00:07:26 -04:00
052317b38a Fix HBrowse namespace correction
Fix HBrowse maleBody and femaleBody namespaces
2019-08-31 00:06:58 -04:00
6ff684f638 Migrate old update jobs 2019-08-13 01:43:07 -04:00
6857c8c1fe Use better job ids for EHentai updater 2019-08-13 01:41:31 -04:00
44d563e689 Use better job ids for EHentai updater 2019-08-13 01:39:01 -04:00
6ce2809450 Use better job ids for EHentai updater 2019-08-13 01:38:49 -04:00
0759036536 Use correct HBrowse source id 2019-08-13 01:31:44 -04:00
6f6490b7ac Bump version number and add changelog 2019-08-13 01:16:33 -04:00
da12a4b17f Speed up migration cancellation
Allow migrating an entire source of manga
2019-08-13 01:10:31 -04:00
1302bc84dd Fix auto-migration UI in dark theme 2019-08-13 00:19:26 -04:00
1c4a8046d0 Allow saving of HBrowse queries 2019-08-13 00:13:04 -04:00
141edac99b Fix EHentai reading progress not carrying over 2019-08-13 00:04:02 -04:00
b64ecfb836 Init notifyLockSecurity when idle
Increase idle-until-urgent delay
2019-08-12 21:16:45 -04:00
d5f4db5eb7 Re-schedule EHentai updater job on app boot
Idle-until-urgent some stuff in app init
Close debug menu onStop
2019-08-12 21:09:39 -04:00
7a3f6e9f63 Fix HBrowse pagination 2019-08-12 19:39:35 -04:00
b3ecc91be9 Fix HBrowse tag search 2019-08-12 19:27:11 -04:00
2a27eacf5e Bump version number and add changelog 2019-08-11 16:23:36 -04:00
e747686ad8 Upgrade realm
Update proguard file so we could potentially enable proguard in the future
Update dependencies
Downgrade duktape to fix MangaPlus
Remove useless dependencies
Remove useless tabGravity
Fix debug version crashing in background
2019-08-11 14:40:01 -04:00
282af20146 Upgrade firebase + glide 2019-08-11 11:38:17 -04:00
f25cd9fdbf Add changelog 2019-08-11 03:41:29 -04:00
2369547d59 Version number bump 2019-08-11 02:24:52 -04:00
d86b8cc78c Remove sidebar help button 2019-08-10 20:30:10 -04:00
b4c1e6a44c Add HBrowse 2019-08-10 20:23:43 -04:00
45fc2f2e0e Optimize SmartSearch system 2019-08-10 20:19:59 -04:00
9cfcacf45e Fix smart search algorithm not using smart queries 2019-08-09 14:07:08 -04:00
801fd83649 Hide MergedSource from source selector screen 2019-08-09 10:14:59 -04:00
16f1dcd922 Fix background updater not updating all galleries 2019-08-09 10:04:06 -04:00
8f36d698cf Fix EHentai gallery update notifications for real 2019-08-09 09:48:31 -04:00
a89a36fd4c Version number bump 2019-08-09 05:21:43 -04:00
8a7f8c4068 Fix incorrect label in auto-migration 2019-08-09 05:20:11 -04:00
9c70e69300 Fix select-all button selecting wrong category 2019-08-09 05:11:25 -04:00
a0b490b10f Fix EH gallery updater crashing 2019-08-09 04:40:44 -04:00
d69dc375a3 Add 8muses 2019-08-09 04:40:30 -04:00
ac6dbbcd89 Add update notifications for EH/EXH galleries 2019-08-08 20:04:31 -04:00
14879c4466 Isolate EH and EXH manga redirects 2019-08-08 14:45:40 -04:00
dce08d4922 Fix false update notifications for lewd sources 2019-08-08 13:49:27 -04:00
5195cb8eda Delegate Pururin.io 2019-08-08 13:31:47 -04:00
68de7b516e Transfer commit 2019-08-08 09:40:41 -04:00
10095205d8 Transfer commit 2019-08-07 20:51:44 -04:00
c4c988f7a4 Add Android 7 broken SSL workaround 2019-08-07 15:47:43 -04:00
333dfbc642 Add nhentai search-by-id 2019-08-07 10:48:17 -04:00
e915fd28cb Migrate to new URL import system 2019-08-07 10:21:18 -04:00
46636b537c Add update frequency restriction debug toggle 2019-08-04 22:55:38 -04:00
cd5545284e Fix reading position not being saved when opening multi-versioned EH manga 2019-08-04 21:27:59 -04:00
3dac6366ff Fix uninstall button 2019-08-04 10:55:09 -04:00
054a26cf65 Fix more button always visible 2019-08-04 01:28:00 -04:00
024c76d480 Fix EH version/chapter sorting shenanigans 2019-08-04 00:15:17 -04:00
9abdfeac77 Hide ability to create merged manga 2019-08-03 22:54:22 -04:00
0f12ae0cf7 Revert "Hide ability to create merged manga"
This reverts commit 7fc6d53c
2019-08-03 22:53:26 -04:00
71182e664a Revert "Open all E-Hentai galleries in ExHentai"
This reverts commit 9ff8235d
2019-08-03 22:47:02 -04:00
7fc6d53cae Hide ability to create merged manga 2019-08-03 22:26:53 -04:00
4f2985469c Finish auto-migration feature 2019-08-03 02:23:21 -04:00
9cc24a3be3 Merge branch 'transfer' of https://github.com/NerdNumber9/TachiyomiEH 2019-08-02 22:54:19 -04:00
7ec18861bf Use semaphores instead of channels where possible
Use correct starting title in auto-migrator
2019-08-02 22:54:06 -04:00
3d1c02136a Transfer commit 2019-08-02 22:32:50 -04:00
aca34155b9 Hide "accept migration" button when migration is not offered 2019-08-01 06:50:03 -04:00
d04ffb7ea9 Fix auto-migration target manga opening wrong manga when clicked 2019-07-31 13:24:05 -04:00
5b3e72db54 Completed most of auto-migration UI 2019-07-31 03:39:51 -04:00
f811cc5c87 Initial work on auto-migrate 2019-07-30 19:29:12 -04:00
e7abe27bb6 Hide internal sources from UI
Change wording on migration button in smartsearch
2019-07-30 10:22:46 -04:00
126d875547 Include language when displaying source-specific chapters in MergedManga 2019-07-30 02:08:27 -04:00
a2b7228e95 Fix infinite reloading after merging manga 2019-07-30 01:49:54 -04:00
10d6b3a6ca Initial MergedSource creation UI 2019-07-30 01:41:30 -04:00
4c9be5557d Initial work on merged sources 2019-07-29 19:36:16 -04:00
37e0ac0895 SmartSearch architecture improvements 2019-07-29 13:27:33 -04:00
8934d251d9 Initial work on SmartSearch 2019-07-29 02:12:30 -04:00
b5263a6968 Do not crash if source provides bad prefs 2019-07-28 03:45:50 -04:00
15bd8e964d Dependency updates 2019-07-28 02:53:25 -04:00
d931027067 Catch and ignore reader page sheet launch exception to prevent it from crashing the app
I have no idea why it happens so often but at this point I will just ignore the error
2019-07-28 02:35:53 -04:00
39ffd3c3bc Fix update worker crashing application 2019-07-28 02:32:10 -04:00
9ff8235de4 Open all E-Hentai galleries in ExHentai 2019-07-27 19:30:25 -04:00
54075733b7 Fix crashes when opening Tsumino captcha 2019-07-27 19:04:25 -04:00
2ea0538825 Remove useless long-press-to-change-category setting as it is now enabled by default 2019-07-27 19:03:35 -04:00
275e20eabd Merge branch 'master' of https://github.com/NerdNumber9/TachiyomiEH 2019-07-27 17:58:27 -04:00
7fe742e6ed Upstream merge 2019-07-27 17:56:31 -04:00
9a6bb69df8 Mark previous as unread now works when 'force ascending sort on gallery versions' is enabled 2019-04-22 09:24:57 -04:00
4c93ca6914 Merge pull request #82 from CarlosEsco/patch-1
update readme to new discord channel
2019-04-22 09:00:43 -04:00
51939ea652 update readme to new discord channel 2019-04-22 06:47:12 -04:00
256a4a2e7f Hide sorting options on EH manga when 'force ascending sort on gallery versions' is enabled 2019-04-22 00:34:43 -04:00
c217cab5db Fix reading progress being lost in some rare cases in galleries opened before v8.4.0 2019-04-22 00:16:38 -04:00
c93b6deaf8 Fix changelog sometimes not showing after update 2019-04-22 00:02:48 -04:00
55196b86b3 Fix chapters not being marked as read when transition pages are hidden 2019-04-21 23:52:40 -04:00
c5ab79f618 Improvements to accuracy of universal captcha detection 2019-04-21 23:01:41 -04:00
59fcfbe9d2 Fix universal captcha detection 2019-04-21 20:46:29 -04:00
6ce70296a6 Fix solve captcha activity not appearing (change that caused this was not released) 2019-04-21 17:28:07 -04:00
fdef687f0c Fix advanced login options for users on old devices
Fix ExHentai login and solve-captcha-window not working for users on old devices
Speed up ExHentai login significantly
2019-04-20 17:48:21 -04:00
cdd7f42532 Show warning when enabling applock on phones that cannot launch the grant-usage-stats-window. 2019-04-20 16:41:23 -04:00
65955fd7dc Remove used variable 2019-04-20 16:21:14 -04:00
b785f68154 Fix captcha solve activity sometimes never appearing 2019-04-20 14:07:52 -04:00
895191814e Fix favorites sync and backup/restore crashing on older devices 2019-04-20 14:01:18 -04:00
b06f253f83 Another attempt to fix autoscroll crashing the reader 2019-04-20 13:59:19 -04:00
0814439886 Include async stacktraces even on errors 2019-04-20 13:52:30 -04:00
a978cb90e8 Bump version and update changelog 2019-04-19 23:03:51 -04:00
39e0d434ad Add throttling when restoring E-Hentai/ExHentai galleries. 2019-04-19 22:59:24 -04:00
6ada3cbf59 Slow down favorites sync even more to prevent bands 2019-04-19 19:15:21 -04:00
4aff768b8e Fix multi-select operations crashing when selection is too large 2019-04-19 17:53:41 -04:00
e08e569135 Fix app crashing on startup for some users 2019-04-19 17:46:04 -04:00
8cac0fca67 Fix autoscroll crashing reader when sometimes 2019-04-19 17:40:05 -04:00
f447b06eff Fix incorrect rendering of seekbar on Android 4/5 2019-04-19 14:36:08 -04:00
78b2045b14 Various crash fixes on older Android versions 2019-04-19 14:26:37 -04:00
a427401d66 Fix EHentai and many other sources breaking 2019-04-19 13:14:41 -04:00
6da6ca710e Fix app crashing when updating library 2019-04-19 13:12:01 -04:00
f46c42f522 Add option to force ascending sort on gallery versions 2019-04-19 04:40:13 -04:00
c4df7b496b More optimizations to library search 2019-04-19 04:19:07 -04:00
6c4332f5c2 Disable aggressive page loading by default 2019-04-19 03:41:20 -04:00
86076d890a Fix wrong version number in new changelog 2019-04-19 03:38:33 -04:00
76a041f504 Add changelog for next release 2019-04-19 03:35:17 -04:00
c9bdc72d5d Upstream merge 2019-04-19 03:35:01 -04:00
f6a8b23498 Allow choosing hitomi.la thumbnail quality 2019-04-19 03:16:09 -04:00
2a60c828d7 Add aggressive page loading 2019-04-19 03:02:30 -04:00
ea7ff432b2 Add MangaDex login 2019-04-19 02:46:34 -04:00
5c2fbec80a Add universal captcha detection 2019-04-18 22:08:09 -04:00
f0109aa796 Fix manga info screen completely breaking on some sources 2019-04-18 21:04:20 -04:00
66b92f3eb7 Only auto-update old format galleries 2019-04-18 20:39:34 -04:00
ec4af65c36 Add universal captcha solver 2019-04-18 20:38:04 -04:00
852c1a423d Auto-update galleries in old format 2019-04-18 17:59:39 -04:00
1904be277d Fix auto-updater job never running 2019-04-18 17:59:17 -04:00
ebb1022100 Backup database in next release 2019-04-18 17:47:13 -04:00
8d85ec3cd9 Update gradle 2019-04-18 17:40:22 -04:00
1d36c3269e Add automatic gallery updating 2019-04-18 17:40:13 -04:00
a218f4a48b Gradle version upgrade 2019-04-16 12:25:53 -04:00
b14c3cc49f Logging tweak in ExtensionManager 2019-04-14 21:43:19 -04:00
cbc4a0f3ab Fix rating search 2019-04-14 21:00:42 -04:00
70a024d3de Minor tweak to debug overlay 2019-04-14 20:59:21 -04:00
28d43bbecc Allow searching by title for lewd galleries with missing metadata 2019-04-14 20:04:53 -04:00
55a3b2f3a1 Use different log filenames for different build types 2019-04-14 19:35:02 -04:00
2545b22ab1 Verify library state before syncing 2019-04-14 19:30:41 -04:00
77c07d13c0 Ignore non-existent galleries during favorites sync 2019-04-14 18:53:34 -04:00
98ac8a69c2 Minor type fix 2019-04-14 18:21:11 -04:00
0e22af7ba0 Hide view hierarchy captures from git 2019-04-14 18:21:00 -04:00
6951ce34c7 Fix deadlocks in gallery adder, favorites sync and backup/restore 2019-04-14 18:20:22 -04:00
24e10d6037 Add Discord link in README 2019-04-14 15:25:19 -04:00
f1b08bf56e Never backup log files 2019-04-14 13:57:14 -04:00
3cc3799ebb Ignore debug mode when choosing logger level 2019-04-14 13:54:31 -04:00
aed20a790e Remove extra line in debug overlay 2019-04-14 13:52:27 -04:00
81b20a23bf Add debug overlay
Disable crash workaround, not worth it
2019-04-14 13:51:20 -04:00
bd27cb74a7 Add extension/source blacklist 2019-04-14 12:48:59 -04:00
07fd3575c5 Better debug menu 2019-04-14 12:12:58 -04:00
6da504c999 Fix crash introduced when upgrading support library 2019-04-14 12:12:46 -04:00
23c1827838 Better importing of backups from Tachiyomi containing E-Hentai/ExHentai/nhentai/PervEden 2019-04-14 12:12:26 -04:00
49833fcc48 Migrate HentaiCafe IDs and nhentai URLs in backups 2019-04-14 11:17:21 -04:00
0e4c0fba5c Fix hitomi.la 2019-04-14 10:52:18 -04:00
bfe67f1cdf Add network inspection logging mode 2019-04-14 10:46:06 -04:00
863e349711 Improve logging 2019-04-14 10:09:43 -04:00
5e13df9bd8 Initialize manga when importing them 2019-04-14 09:30:48 -04:00
65abb8fa6c Fix read positions not being preserved 2019-04-14 09:30:29 -04:00
fe5c0295c3 Allow filter menu to be opened even if no filters to allow for search saving 2019-04-14 09:30:07 -04:00
4d15ac2fa3 Insert metadata in sync and when importing galleries 2019-04-14 09:09:24 -04:00
5e4b9fb15b Fix a crash that could occur in the incognito browser 2019-04-14 00:34:49 -04:00
8a70dffae8 Preserve async stack traces of http requests 2019-04-14 00:27:44 -04:00
8119eb4b34 Fix Tsumino source crashing app in some rare cases when network is unreliable 2019-04-14 00:09:19 -04:00
1bae7ba8f5 Fix app crash in some rare cases in reader 2019-04-13 23:56:40 -04:00
d4f1014df6 Improve logging infrastructure 2019-04-13 23:47:57 -04:00
dce685e711 Use app name as image save location 2019-04-13 23:03:20 -04:00
c4e6668c22 Get new URL on retry on EXH sources 2019-04-13 22:35:23 -04:00
9b5608c86d Fix build 2019-04-13 22:35:06 -04:00
2485a00d34 Upstream merge 2019-04-13 12:36:28 -04:00
8abe2d76b0 Support nhentai aliased tags
Better source ID detection
2019-04-13 12:18:42 -04:00
8e9087226f Add ability to hide transition page between chapters 2019-04-12 22:59:49 -04:00
8ccc3c8b0c Upgrade Kotlin coroutines library version 2019-04-12 18:38:13 -04:00
9b3579acf6 Decrease debounce time for library search
Async library search code cleanup
Rename LoadingTools -> LoaderManager
2019-04-12 12:16:52 -04:00
6f2ff6a77e Hide library progress bar by default 2019-04-12 07:14:42 -04:00
f772501159 Library search is now asynchronous
Library will now display progress bar while loading
More optimizations to library search
2019-04-12 06:50:24 -04:00
cadd389658 Remove unused metadata objects and misc code cleanup 2019-04-12 04:18:57 -04:00
6f36331818 Upgrade Kotlin version 2019-04-12 03:41:10 -04:00
d684eb5147 Misc code cleanup 2019-04-12 03:12:16 -04:00
349546cf87 Build speed improvements 2019-04-12 03:07:29 -04:00
352593ebc6 README update 2019-04-11 03:40:20 -04:00
c6b28cbcaf Upgrade dependencies
Remove Firebase Perf for better build speeds
2019-04-09 21:43:47 -04:00
c5e69d2080 Merge pull request #62 from Scrxtchy/image_path
Update Save Image path
2019-04-09 14:22:31 -04:00
cd4964d086 Update Save Image path 2019-04-09 23:57:07 +10:00
ac3967e997 Decrease favorites sync max throttle by 500ms (should be safe) 2019-04-07 05:32:59 -04:00
5df18f2558 Consider EHentai == ExHentai when performing local deletions while syncing 2019-04-07 05:16:34 -04:00
0b054126bc Attempt to fix strange crash occurring on older Android versions 2019-04-07 05:15:40 -04:00
d4740c57be Fix crash when app is closed while migrating metadata 2019-04-07 04:43:10 -04:00
739fc9f95d Sort saved searches in UI 2019-04-06 17:59:18 -04:00
96b1340aec Revert README update 2019-04-06 09:54:04 -04:00
57d83e3d1b Use TachiWeb filter serializer for saving filters 2019-04-06 09:45:28 -04:00
4e2c9dc083 Various fixes to search presets 2019-04-06 09:05:32 -04:00
fa6f60d454 Fix hentai cafe url import 2019-04-06 08:16:48 -04:00
71fe2bda97 Add release changelog 2019-04-06 07:53:27 -04:00
f24c5e944e Fix various proguard issues 2019-04-06 07:40:27 -04:00
603fd84753 Rewrite tag searching to use SQL
Fix EHentai/ExHentai
Fix hitomi.la
Fix hitomi.la crashing application
Rewrite hitomi.la search engine to be faster, use less CPU and require no preloading
Fix nhentai
Add additional filters to nhentai
Fix PervEden
Introduce delegated sources
Rewrite HentaiCafe to be a delegated source
Introduce ability to save/load search presets
Temporarily disable misbehaving native Tachiyomi migrations
Fix tap-to-search-tag breaking on aliased tags
Add debug menu
Add experimental automatic captcha solver
Add app name to wakelock names
Add ability to interrupt metadata migrator
Fix incognito open-in-browser being zoomed in immediately when it's opened
2019-04-06 07:35:36 -04:00
5fbe1a8614 Upstream merge 2019-03-31 00:23:44 -04:00
42169783e1 Merge branch 'master' of https://github.com/inorichi/tachiyomi 2018-08-27 12:43:45 -04:00
90574937df README update 2018-08-27 12:42:43 -04:00
ec0fe2210d Add ability to ask for category on long press 2018-08-04 10:49:29 -04:00
450fcccaa6 Log result in Tsumino and minor code cleanup 2018-08-03 22:03:51 -04:00
72504ca53f Minor typo fix and code cleanup 2018-08-03 21:34:31 -04:00
6bfddb3ece Bump Kotlin version 2018-08-03 21:34:12 -04:00
b62fcbc2ec Update changelog 2018-07-21 23:26:00 -04:00
411dda0e75 Introduce incognito open-in-browser support 2018-07-21 23:16:10 -04:00
d9d71c8745 Various dependency updates 2018-07-21 15:26:14 -04:00
35239af039 Allow preserving reading position even when manga is read 2018-07-18 22:46:47 -04:00
840e571917 Do not retry loading pages
GIF support in non-vertical pagers
Fix cache being double-opened
2018-07-18 22:17:46 -04:00
2fd4204db8 Reader cache + retry improvements 2018-07-17 22:29:49 -04:00
1fd105ac56 Bump version to next release 2018-07-08 19:49:33 -04:00
6ae90e0a7d Add ability to reverse search result order
Actually activate hath perks
2018-07-08 19:44:49 -04:00
43dc12a0f3 Fix hitomi browse/latest 2018-07-08 18:34:22 -04:00
28d05b629f Add additional advanced options to login screen
Add "more" button into global search results
Retry-all button is now more explicit on what was retried
Minor performance fix in hitomi search
2018-07-08 17:53:03 -04:00
30c12fc9de Get rid of outdated changelog 2018-07-08 15:53:59 -04:00
cdb62f502c Bump Realm version 2018-07-08 15:53:36 -04:00
5cfdbbce7a Merge branch 'master' of https://github.com/inorichi/tachiyomi
# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/source/SourceManager.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoController.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt
2018-07-08 15:51:26 -04:00
e2af1af656 Bump version to v7.4.1
Fix changelog
2018-06-10 12:19:53 -04:00
a96c25c37c Add retry all and boost page 2018-06-10 12:15:15 -04:00
c1abec3b4c Fix autoscroll scrolling right on right-to-left reader 2018-06-10 10:46:49 -04:00
c5a488ca3f Move ExHentai login to HTTPS 2018-06-10 01:47:17 -04:00
dd4a18a0b2 Prepare for release 2018-06-10 01:26:18 -04:00
34df0759f3 Improved autoscroll 2018-06-10 01:26:01 -04:00
b6a3f6ebd2 Add autoscroll support 2018-06-10 00:50:17 -04:00
ad2819a3bc Various dependency updates 2018-06-09 23:50:51 -04:00
0f2be86d5a Add ability to tune reader threads and instant retry 2018-06-09 23:12:53 -04:00
4342584c32 Minor code cleanup 2018-06-09 19:54:26 -04:00
71c10df270 Merge branch 'master' of https://github.com/inorichi/tachiyomi
# Conflicts:
#	README.md
#	app/.gitignore
#	app/build.gradle
#	app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAboutController.kt
#	app/src/main/res/raw/changelog_release.xml
2018-06-09 19:52:02 -04:00
db90b5d2cb Minor typo fix in Hitomi.la settings 2018-06-09 19:37:12 -04:00
5cc38c1369 Release v7.2.3 2018-04-18 21:15:11 -04:00
e7c48a98df Fix app locking even if app lock is disabled
Hide fingerprint view if fingerprint is disabled
2018-04-18 10:18:32 -04:00
d03c49db58 Fix app lock crashing app on older devices 2018-04-18 10:11:47 -04:00
b69af710ad Release v7.2.2
Fix SimpleDateFormat crashing application on older Android OSes
Rename preference key (typo)
2018-04-17 15:58:49 -04:00
4d3b469c48 Upgrade realm version 2018-04-16 11:50:46 -04:00
8cc6c0171b Increment realm schema version 2018-04-16 09:53:18 -04:00
8be5be4720 Fix possible crash-on-start from getToolbarNavigationItem 2018-04-16 09:50:57 -04:00
995a1155e4 Update changelogs and add hitomi.la URL importing 2018-04-15 14:35:00 -04:00
234c3bb72a Merge branch 'master' of https://github.com/inorichi/tachiyomi
# Conflicts:
#	README.md
#	app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryAdapter.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt
2018-04-15 13:39:29 -04:00
aafe863774 Add hitomi.la preferences screen
Add hitomi.la early refresh
Fix some typos in comments
2018-04-15 13:35:38 -04:00
fb1db914aa Fix Tsumino page offset (fixes #27) 2018-04-14 23:37:17 -04:00
7aa8abdd98 Add A-B swapping for hitomi.la search database 2018-04-14 23:23:55 -04:00
4bd965a795 Merge branch 'master' of https://github.com/NerdNumber9/TachiyomiEH 2018-04-14 21:17:50 -04:00
df2a4779bf Merge branch 'master' of https://github.com/inorichi/tachiyomi
# Conflicts:
#	.travis.yml
#	README.md
#	app/build.gradle
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoController.kt
#	app/src/main/res/layout/manga_info_controller.xml
#	app/src/main/res/raw/changelog_release.xml
2018-04-14 21:11:29 -04:00
d2dc063c8e More work on Hitomi.la 2018-04-14 15:50:05 -04:00
45f4c63941 Merge branch 'master' of https://github.com/inorichi/tachiyomi 2018-03-15 17:22:49 -04:00
5e968e5651 Fix broken back button in search 2018-03-15 17:04:33 -04:00
3e3c0a1f14 Add option to expand search filters by default 2018-03-15 16:57:16 -04:00
c48bebe0b2 Add option to disable auto lock and add manual locking 2018-03-14 18:39:01 -04:00
0dd9e9e015 Repackage captcha solve activity to UI package 2018-03-14 13:17:55 -04:00
d2a2e17e91 Re-theme lock view to actually match current theme 2018-03-14 13:13:57 -04:00
09dbd723e4 Fix Tsumino captcha appearing multiple times 2018-03-14 12:22:28 -04:00
eb965542cc Update changelog
Code cleanup
2018-03-13 20:49:17 -04:00
615fa05a75 Merge branch 'master' of https://github.com/inorichi/tachiyomi
# Conflicts:
#	README.md
#	app/build.gradle
#	app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoController.kt
#	app/src/main/res/layout/manga_info_controller.xml
#	app/src/main/res/raw/changelog_release.xml
2018-03-13 15:58:47 -04:00
87a2ac7887 Attempt to add hitomi.la source (still broken) and code cleanup 2018-03-13 15:21:31 -04:00
07ce90ab8c Add Tsumino captcha display and merge branch 'master' of upstream
# Conflicts:
#	.github/readme-images/app-icon.png
#	.github/readme-images/screens.png
#	.travis.yml
#	README.md
#	app/build.gradle
#	app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt
#	app/src/main/java/eu/kanade/tachiyomi/source/SourceManager.kt
#	app/src/main/java/eu/kanade/tachiyomi/source/online/YamlHttpSource.kt
#	app/src/main/java/eu/kanade/tachiyomi/source/online/YamlHttpSourceMappings.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt
#	app/src/main/java/eu/kanade/tachiyomi/util/DynamicConcurrentMergeOperator.java
2018-02-25 15:34:19 -05:00
a71ae29c98 Add Tsumino captcha display and merge branch 'master' of upstream
# Conflicts:
#	.github/readme-images/app-icon.png
#	.github/readme-images/screens.png
#	.travis.yml
#	README.md
#	app/build.gradle
#	app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt
#	app/src/main/java/eu/kanade/tachiyomi/source/SourceManager.kt
#	app/src/main/java/eu/kanade/tachiyomi/source/online/YamlHttpSource.kt
#	app/src/main/java/eu/kanade/tachiyomi/source/online/YamlHttpSourceMappings.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt
#	app/src/main/java/eu/kanade/tachiyomi/util/DynamicConcurrentMergeOperator.java
2018-02-24 11:13:43 -05:00
117214c671 Implement lenient sync 2018-02-23 18:57:19 -05:00
c54d26d6ba Fix broken favorites sync
Release v6.8.2
2018-02-15 17:21:33 -05:00
5447bd098b Release v6.8.1 2018-02-14 17:21:29 -05:00
2b7c0e8e80 Fix gallery browsing 2018-02-12 16:22:54 -05:00
47966d89f2 Fix typo in sync throttle message 2018-02-03 11:22:59 -05:00
b28a2c3bd4 Fix sync sometimes crashing when ran multiple times without reopening the app 2018-02-02 12:48:09 -05:00
8f51abfc97 Sync is now essentially fully atomic on the client side
Sync now aborts on most errors instead of continuing
Sync now holds screen, CPU and WIFI locks
2018-02-02 12:11:09 -05:00
e9bea8ed47 Fix minor issue in sync intro screen 2018-02-01 14:39:21 -05:00
c2c1b6d2e8 Update changelog 2018-02-01 14:11:47 -05:00
ded22f1717 Finish favorites sync 2018-02-01 13:46:33 -05:00
126da3979c Merge branch 'master' of https://github.com/inorichi/tachiyomi 2018-01-31 22:40:17 -05:00
d892f2f7f4 Initial implementation of favorites syncing
General code cleanup
Fix some cases of duplicate galleries (not completely fixed)
2018-01-31 22:39:55 -05:00
f18b32626a Rewrite link intercept activity
Fix compatibility issues between lewd sources and manga info screen
2018-01-29 15:39:34 -05:00
8c8f2585aa Merge remote-tracking branch 'upstream/master'
# Conflicts:
#	README.md
#	app/build.gradle
#	app/src/main/java/eu/kanade/tachiyomi/App.kt
#	app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt
#	app/src/main/java/eu/kanade/tachiyomi/data/updater/UpdateDownloaderReceiver.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoPresenter.kt
#	app/src/main/res/menu/library.xml
#	app/src/main/res/values/strings.xml
#	app/src/test/java/eu/kanade/tachiyomi/data/database/ChapterRecognitionTest.kt
2018-01-29 12:16:32 -05:00
1a811d0917 Code cleanup
Release v6.6.0
Cleanup changelog
2017-12-08 18:21:26 -05:00
9af552c15a Merge branch 'master' of https://github.com/inorichi/tachiyomi
# Conflicts:
#	README.md
#	app/build.gradle
#	app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/NoResultsException.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/latest_updates/LatestUpdatesPresenter.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryView.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt
2017-12-07 23:20:27 -05:00
263cc1d97c See CHANGELOG.md for this commit 2017-12-07 22:25:27 -05:00
dec4471871 Second attempt to update changelog
Fix wording in metadata fetch dialog
2017-11-30 21:07:26 -05:00
c8122ebd68 Update changelog 2017-11-29 22:14:02 -05:00
b766ddea54 Merge branch 'master' of https://github.com/inorichi/tachiyomi
Fix back button in library search
2017-11-29 21:41:05 -05:00
5cb219d83e Various changes 2017-11-29 21:44:35 -05:00
908128b55d Merge upstream changes 2017-11-29 21:53:02 -05:00
b240960a8a Update dependencies
Remove travis config as we don't use travis
2017-11-29 21:55:56 -05:00
b91d8e4c19 Release 0.6.5 2017-11-29 18:49:22 +01:00
4853ff7eee Resubscribe to library when a change of type enter occurs. Resolves #1093 2017-11-29 10:05:33 +01:00
e1582bd73a Minor changes to download cache. Also keep the library view, as recreation is expensive 2017-11-28 23:58:37 +01:00
ac17335dbe Fix automatic backups (#1074)
* Fix automatic backups

* Small fixes

* small fixes
2017-11-28 22:55:50 +01:00
7053777997 Release version v6.1.4
Offload metadata check to background thread
Add search cache
2017-08-28 03:20:35 -04:00
1107b95ebd Remove leftover code 2017-08-26 03:52:52 -04:00
36003fd622 Remove leftover TODO 2017-08-26 03:48:12 -04:00
84121ff901 Release v6.1.3
Make search engine synchronous
Offload some search engine tasks to background threads
Minor search engine speedups
2017-08-26 03:40:59 -04:00
bcc2ec1668 Fix migration dialog showing on startup even with no manga 2017-08-25 22:26:57 -04:00
08dffda2a1 Fix NHentai and PervEden sources
Version bump to v6.1.2
2017-08-25 19:08:33 -04:00
9f4540a4f1 Fallback to normal library searching when metadata is not available 2017-08-25 18:52:32 -04:00
f19ef9aa01 Fix proguard rules 2017-08-25 18:51:25 -04:00
f10a06341b More changelog entries 2017-08-25 18:50:57 -04:00
67ac95f15f Merge branch 'master' of https://github.com/inorichi/tachiyomi 2017-08-25 17:39:22 -04:00
cd291f0a27 Migrate to realm for metadata 2017-08-25 17:31:38 -04:00
bb6b88a703 Make drawerArrow private again (as it was in upstream) 2017-08-24 18:31:45 -04:00
239b36c31a Add nhentai URL importing
Allow fast importing of single URLs by inputting the URL into the source's search bar
2017-08-24 18:31:08 -04:00
dcb6ae44dd Fix intercept activity 2017-08-24 17:33:03 -04:00
5ed365cf0d Remove outdated declarations from AndroidManifest 2017-08-24 17:13:09 -04:00
b20b3d6f5c Add fingerprint to lock UI
Migrate login UI to conductor
Fix batch add controller not saving EditText content onResume
Prevent double-locking of lock UI
Remove back button from lock UI
Fix login preference not updating
2017-08-24 17:11:43 -04:00
32d02f9329 Migrate to Tachiyomi 6.1
Rewrite batch add UI
Rewrite lock UI
2017-08-24 12:28:54 -04:00
3da7c47bf5 Merge branch 'master' of https://github.com/inorichi/tachiyomi
# Conflicts:
#	app/build.gradle
#	app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/ActivityMixin.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseActivity.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/base/adapter/FlexibleViewHolder.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/base/adapter/SmartFragmentStatePagerAdapter.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/base/fragment/BaseFragment.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/base/fragment/BaseRxFragment.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/base/fragment/FragmentMixin.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryActivity.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/latest_updates/LatestUpdatesFragment.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryAdapter.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryView.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryFragment.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/main/ChangelogDialogFragment.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaActivity.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaEvent.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersFragment.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/ChapterCountEvent.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaFavoriteEvent.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoFragment.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoPresenter.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackFragment.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/recently_read/RecentlyReadFragment.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAboutFragment.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsActivity.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAdvancedFragment.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsDownloadsFragment.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsFragment.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsGeneralFragment.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsTrackingFragment.kt
#	app/src/main/java/eu/kanade/tachiyomi/util/AndroidComponentUtil.java
#	app/src/main/java/eu/kanade/tachiyomi/widget/preference/LibraryColumnsDialog.kt
#	app/src/main/java/eu/kanade/tachiyomi/widget/preference/SimpleDialogPreference.kt
#	app/src/main/res/layout/activity_download_manager.xml
#	app/src/main/res/layout/activity_edit_categories.xml
#	app/src/main/res/layout/activity_manga.xml
#	app/src/main/res/layout/activity_preferences.xml
#	app/src/main/res/layout/fragment_backup.xml
#	app/src/main/res/layout/fragment_download_queue.xml
#	app/src/main/res/layout/fragment_library.xml
#	app/src/main/res/layout/fragment_library_category.xml
#	app/src/main/res/layout/item_chapter.xml
#	app/src/main/res/layout/item_recent_chapters.xml
#	app/src/main/res/layout/toolbar.xml
#	app/src/main/res/raw/changelog_release.xml
#	app/src/main/res/values/arrays.xml
#	app/src/main/res/xml/pref_about.xml
#	app/src/main/res/xml/pref_advanced.xml
#	app/src/main/res/xml/pref_downloads.xml
#	app/src/main/res/xml/pref_general.xml
#	app/src/main/res/xml/pref_reader.xml
#	app/src/main/res/xml/pref_sources.xml
#	app/src/main/res/xml/pref_tracking.xml

Migrate to Tachiyomi 6.1
Rewrite batch add UI
2017-08-24 11:24:23 -04:00
029f159aea Add the ability to import galleries by specifying the URL of one of it's pages 2017-05-08 20:03:20 -04:00
0a300822a4 Fix NoClassDefFoundError in E-Hentai/ExHentai source. 2017-05-05 00:41:10 -04:00
8d48e0289a Merge origin branch (I messed up the repo) 2017-05-04 23:54:18 -04:00
9dbb59f337 Upstream merge
Internal permission change
Fix url adder
2017-05-04 23:38:17 -04:00
a243aeafba Release v5.0.2. 2017-03-16 23:12:38 -04:00
5c671de29e Fix NHentai source only showing first page. 2017-03-16 22:54:55 -04:00
e161e5d30d Release version 5.0.1. 2017-03-15 15:03:36 -04:00
2fd64d0ca7 Fix download notifier breaking on some weird titles. 2017-03-15 14:56:34 -04:00
d981c75600 Add favorites downloader. 2017-03-15 14:39:09 -04:00
492adb7035 Release version 5.0.0. 2017-03-09 20:53:28 -05:00
811bca18d9 Yolo 2017-03-09 20:47:06 -05:00
3222e0646d Various bug fixes. 2017-03-09 20:46:24 -05:00
fa6790856d Fixed SourceManager creating sources multiple times on app launch. 2017-03-09 18:49:52 -05:00
38a15d4158 Fix lock preference observing on wrong thread. 2017-03-09 18:23:45 -05:00
77cd459c51 Retry button now uses a different H@H server. 2017-03-09 18:18:53 -05:00
fa115ed9a0 Fix null scanlator text.
Fix nhentai "Open in Browser" and "Share" buttons.
2017-03-09 17:31:17 -05:00
30a2b572ab Enable text selection in manga info window. 2017-03-09 17:21:11 -05:00
b1ab77188d Add apk files to gitignore. 2017-03-09 17:17:30 -05:00
e212e4581d Fix user being asked for lock permissions when lock is not enabled. 2017-03-09 17:17:18 -05:00
1b8daa7e09 Another attempt to fix proguard config. 2017-03-09 16:53:13 -05:00
99d126fd3a Fix typo in proguard config. 2017-03-09 16:50:31 -05:00
9fee7c6b19 Fix proguard rules. 2017-03-09 16:47:55 -05:00
1b5a83563f Hopefully fix stackoverflow crash. 2017-03-09 16:31:28 -05:00
c8a8eb0a4d Add nhentai source. 2017-03-09 16:01:34 -05:00
0a7812bb2c Remove old debugging code and useless comments. 2017-03-08 18:58:56 -05:00
061b434687 Fix crashes when opening invalid manga. 2017-03-08 17:14:12 -05:00
f3be1a6d09 Fix crash due to empty page list. 2017-03-07 23:03:07 -05:00
1e797bfe8a Add PIN feature to README.
Remove hint from PIN setup dialog.
2017-03-07 22:50:40 -05:00
97435dbe0f Fix readme. 2017-03-07 22:48:27 -05:00
3fdbb95b15 More documentation. 2017-03-07 22:44:22 -05:00
961a6c0b4f Code cleanup. 2017-03-07 22:44:08 -05:00
c42f011a05 Implement Perv Eden source. 2017-03-07 22:02:16 -05:00
957c50088d Add cancel button to lock preference. 2017-03-05 12:49:56 -05:00
3b129176d6 Code cleanup. 2017-03-05 12:41:34 -05:00
f36327ecc9 Add application lock functionality. 2017-03-05 12:36:52 -05:00
5f48bb8e7d Merge branch 'master' of https://github.com/inorichi/tachiyomi
# Conflicts:
#	README.md
#	app/build.gradle
#	app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt
#	app/src/main/java/eu/kanade/tachiyomi/data/source/SourceManager.kt
#	app/src/main/java/eu/kanade/tachiyomi/source/model/Page.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/backup/BackupPresenter.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/main/ChangelogDialogFragment.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt
#	app/src/main/res/raw/changelog_release.xml
#	app/src/main/res/values/arrays.xml
#	app/src/main/res/values/strings.xml
2017-03-04 22:54:00 -05:00
aba8d01818 Merge branch 'master' of https://github.com/inorichi/tachiyomi 2017-03-04 22:46:56 -05:00
03cb7062f2 Merge branch 'master' of https://github.com/inorichi/tachiyomi
# Conflicts:
#	README.md
#	app/build.gradle
#	app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt
#	app/src/main/java/eu/kanade/tachiyomi/data/source/SourceManager.kt
#	app/src/main/java/eu/kanade/tachiyomi/source/model/Page.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/backup/BackupPresenter.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/main/ChangelogDialogFragment.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt
#	app/src/main/res/raw/changelog_release.xml
#	app/src/main/res/values/arrays.xml
#	app/src/main/res/values/strings.xml
2017-03-04 22:43:06 -05:00
d4b35736c0 Gallery chapter metadata will now be automatically downloaded when importing galleries. 2017-02-28 17:37:51 -05:00
c30aa710f3 Change baseUrl from g.e-hentai.org -> e-hentai.org 2017-02-28 17:21:00 -05:00
0adac4217e Fix share button adding extra "/" onto end of URL
Fixed by removing "/" from end of baseUrl.
2017-02-28 17:09:13 -05:00
7e102edd0a Increase memory allocated to gradle 2017-02-28 16:57:09 -05:00
adefe87129 Minor code cleanup 2017-02-28 16:56:47 -05:00
8a05fc8966 Add local namespace searching. 2017-02-28 16:56:29 -05:00
8fa798cf63 Update README. 2017-01-09 18:11:51 -05:00
01b20b2acb Add some branding. 2017-01-09 18:10:06 -05:00
a8d72dd6f8 Whoops missed the changelog. 2017-01-09 17:37:38 -05:00
84042c61e0 Release 4.0.1. 2017-01-09 17:33:47 -05:00
407ba6c628 Fix duplicate galleries. 2017-01-09 17:27:58 -05:00
16a3c676ef Update README.md 2017-01-07 12:08:32 -05:00
9b3a99432b Update README.md 2017-01-07 12:07:17 -05:00
036f757086 Update README.md 2017-01-07 12:06:47 -05:00
a391529b32 Fix updater. 2017-01-07 11:55:16 -05:00
d10b782308 Merge remote-tracking branch 'origin/master' 2017-01-07 10:47:53 -05:00
a58f780452 Remove ACRA. 2017-01-07 10:07:37 -05:00
606de03c7c Various bug fixes. 2017-01-06 20:57:50 -05:00
2b988c51ad Add migration system. 2017-01-06 18:01:40 -05:00
cb73e55db1 Deduplicate some code.
Change package name.
2017-01-05 18:26:32 -05:00
8fb4093dc6 Various bug fixes and code cleanup. 2017-01-04 23:34:47 -05:00
f5c4535cb0 Add migration ability.
Various bug fixes and code cleanup.
2017-01-04 22:56:24 -05:00
e4f2bffbc2 Various bug fixes and code cleanup. 2017-01-04 20:19:44 -05:00
5c942460f9 Various bug fixes. 2017-01-04 16:24:21 -05:00
cce1f2c20d Finish batch add screen. 2017-01-04 14:37:28 -05:00
516a3bd017 Integrate tag searching into library. 2017-01-04 11:17:12 -05:00
63d58c7a4f Add uploader faux-namespace to search engine. 2017-01-04 10:30:44 -05:00
c49b865ee7 Regexes are now compiled only once by search engine. 2017-01-04 00:06:53 -05:00
097a83e3ba Fix some bugs in the search engine. 2017-01-03 23:45:44 -05:00
02c70d868d Implement search engine. 2017-01-03 16:57:51 -05:00
c836f52460 Implement most gallery settings. 2017-01-03 11:27:10 -05:00
caa1e1ef09 Add EH code. 2017-01-02 18:02:10 -05:00
5c63531066 Add logged in property reporting. 2016-10-18 22:13:43 -04:00
15b2bbc6d1 Merge changes.
Various changes.
2016-10-18 21:58:00 -04:00
3cafbd9141 Merge changes.
Various changes.
2016-10-18 21:50:48 -04:00
dc0405a373 More build fixes. 2016-08-05 20:25:48 -04:00
f84832716a Remove unused classes and clean up build. 2016-08-05 20:19:27 -04:00
200aa4042f Fix table in README. 2016-08-05 20:08:35 -04:00
f44c5adcc0 Update README with correct data. 2016-08-05 20:05:20 -04:00
3c43bebe64 Integrate TachiyomiEH changes. 2016-08-05 19:42:36 -04:00
695 changed files with 31660 additions and 2949 deletions

0
.github/CONTRIBUTING.md vendored Normal file → Executable file
View File

2
.github/ISSUE_TEMPLATE.md vendored Normal file → Executable file
View File

@ -2,7 +2,7 @@
I acknowledge that:
- I have updated to the latest version of the app (stable is v0.9.0)
- I have updated to the latest version of the app (stable is v0.9.2)
- 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

View File

@ -9,7 +9,7 @@ labels: "bug"
I acknowledge that:
- I have updated to the latest version of the app (stable is v0.9.0)
- I have updated to the latest version of the app (stable is v0.9.2)
- 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

View File

@ -9,7 +9,7 @@ labels: "feature"
I acknowledge that:
- I have updated to the latest version of the app (stable is v0.9.0)
- I have updated to the latest version of the app (stable is v0.9.2)
- 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

25
.github/workflows/PullRequestTester.yml vendored Normal file
View File

@ -0,0 +1,25 @@
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;20.0.5594570"
- 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

View File

@ -0,0 +1,31 @@
name: Remote Dispatch Action Initiator
on:
push:
repository_dispatch:
jobs:
ping-pong:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
with:
fetch-depth: '0'
- name: TAG - Bump version and push tag
uses: anothrNick/github-tag-action@1.17.2
if: github.event.action != 'pong'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
WITH_V: true
RELEASE_BRANCHES: master
- name: PING - Dispatch initiating repository event
if: github.event.action != 'pong'
run: |
curl -X POST https://api.github.com/repos/jobobby04/TachiyomiSYPreview/dispatches \
-H 'Accept: application/vnd.github.everest-preview+json' \
-u ${{ secrets.ACCESS_TOKEN }} \
--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 }}'"

7
.gitignore vendored Normal file → Executable file
View File

@ -5,6 +5,8 @@
.idea/
*iml
*.iml
/mainframer
/.mainframer
# Built files
*/build
@ -14,3 +16,8 @@ app/**/output.json
# Hebrew assets are copied on build
app/src/main/res/values-iw/
TODO.md
CHANGELOG.md
/captures
build.sh

View File

@ -62,6 +62,13 @@ deploy:
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:

View File

@ -1,20 +0,0 @@
#!/bin/bash
git fetch --unshallow #required for commit count
if [ -z "$TRAVIS_TAG" ]; then
./gradlew clean assembleStandardDebug
COMMIT_COUNT=$(git rev-list --count HEAD)
export ARTIFACT="tachiyomi-r${COMMIT_COUNT}.apk"
mv app/build/outputs/apk/standard/debug/app-standard-debug.apk $ARTIFACT
else
./gradlew clean assembleStandardRelease
TOOLS="$(ls -d ${ANDROID_HOME}/build-tools/* | tail -1)"
export ARTIFACT="tachiyomi-${TRAVIS_TAG}.apk"
${TOOLS}/zipalign -v -p 4 app/build/outputs/apk/standard/release/app-standard-release-unsigned.apk app-aligned.apk
${TOOLS}/apksigner sign --ks $STORE_PATH --ks-key-alias $STORE_ALIAS --ks-pass env:STORE_PASS --key-pass env:KEY_PASS --out $ARTIFACT app-aligned.apk
fi

View File

@ -1,15 +0,0 @@
#!/bin/bash
pattern="tachiyomi-r*"
files=( $pattern )
export ARTIFACT="${files[0]}"
if [ -z "$ARTIFACT" ]; then
echo "Artifact not found"
exit 1
fi
export SSHOPTIONS="-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i ${DEPLOY_KEY}"
scp $SSHOPTIONS $ARTIFACT $DEPLOY_USER@$DEPLOY_HOST:builds/
ssh $SSHOPTIONS $DEPLOY_USER@$DEPLOY_HOST ln -sf $ARTIFACT builds/latest

Binary file not shown.

0
LICENSE Normal file → Executable file
View File

View File

@ -1,87 +1,3 @@
| Build | Stable | Weekly Preview | Contribute | Support Server |
|-------|----------|---------|------------|---------|
| [![Travis](https://img.shields.io/travis/inorichi/tachiyomi.svg)](https://travis-ci.org/inorichi/tachiyomi) | [![stable release](https://img.shields.io/github/release/inorichi/tachiyomi.svg?maxAge=3600&label=download)](https://github.com/inorichi/tachiyomi/releases) | [![latest weekly build](https://img.shields.io/badge/download-latest%20build-blue.svg)](http://tachiyomi.kanade.eu/latest) | [![Translation status](https://hosted.weblate.org/widgets/tachiyomi/-/svg-badge.svg)](https://hosted.weblate.org/engage/tachiyomi/?utm_source=widget) | [![Discord](https://img.shields.io/discord/349436576037732353.svg)](https://discord.gg/tachiyomi) |
I haven't started a readme
# ![app icon](./.github/readme-images/app-icon.png)Tachiyomi
Tachiyomi is a free and open source manga reader for Android 5.0 and above.
![screenshots of app](./.github/readme-images/screens.png)
## Features
Features include:
* Online reading from sources such as MangaDex, MangaSee, Mangakakalot, [and more](https://github.com/inorichi/tachiyomi-extensions)
* Local reading of downloaded manga
* A configurable reader with multiple viewers, reading directions and other settings.
* [MyAnimeList](https://myanimelist.net/), [AniList](https://anilist.co/), [Kitsu](https://kitsu.io/), [Shikimori](https://shikimori.one), and [Bangumi](https://bgm.tv/) support
* Categories to organize your library
* Light and dark themes
* Schedule updating your library for new chapters
* Create backups locally to read offline or to your desired cloud service
## Download
Get the app from our [releases page](https://github.com/inorichi/tachiyomi/releases).
If you want to try new features before they get to the stable release, you can download the preview version [here](http://tachiyomi.kanade.eu/latest).
## Issues, Feature Requests and Contributing
Please make sure to read the full guidelines. Your issue may be closed without warning if you do not.
<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/inorichi/tachiyomi/releases) and the already opened [issues](https://github.com/inorichi/tachiyomi/issues).**
2. If you are unsure, ask here: [![Discord](https://img.shields.io/discord/349436576037732353.svg)](https://discord.gg/tachiyomi)
</details>
<details><summary>Bugs</summary>
* Include version (Setting > About > Version)
* 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
* Include steps to reproduce (if not obvious from description)
* Include screenshot (if needed)
* If it could be device-dependent, try reproducing on another device (if possible)
* For large logs use http://pastebin.com/ (or similar)
* Don't group unrelated requests into one issue
DO: https://github.com/inorichi/tachiyomi/issues/24 https://github.com/inorichi/tachiyomi/issues/71
DON'T: https://github.com/inorichi/tachiyomi/issues/75
</details>
<details><summary>Feature Requests</summary>
* Write a detailed issue, explaining what it should do or how. Avoid writing just "like X app does"
* Include screenshot (if needed)
Catalogue requests should be created at https://github.com/inorichi/tachiyomi-extensions, they do not belong in this repository.
</details>
## FAQ
[See our website.](https://tachiyomi.org/)
You can also reach out to us on [Discord](https://discord.gg/tachiyomi).
## License
Copyright 2015 Javier Tomás
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
## Disclaimer
The developer of this application does not have any affiliation with the content providers available.
Automated Preview Builds(with updater): https://github.com/jobobby04/TachiyomiSYPreview/releases

2
app/.gitignore vendored Normal file → Executable file
View File

@ -2,3 +2,5 @@
*iml
*.iml
custom.gradle
google-services.json
output.json

119
app/build.gradle Normal file → Executable file
View File

@ -1,3 +1,5 @@
import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile
//noinspection GradleDependency
import java.text.SimpleDateFormat
apply plugin: 'com.android.application'
@ -6,6 +8,8 @@ apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
apply plugin: 'com.github.zellius.shortcut-helper'
// Realm (EH)
apply plugin: 'realm-android'
shortcutHelper.filePath = './shortcuts.xml'
@ -32,19 +36,20 @@ ext {
android {
compileSdkVersion 29
buildToolsVersion '29.0.3'
publishNonDefault true
defaultConfig {
applicationId "eu.kanade.tachiyomi"
applicationId "eu.kanade.tachiyomi.sy"
minSdkVersion 21
targetSdkVersion 29
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
versionCode 44
versionName "0.9.1"
versionCode 1
versionName "0.9.2.7"
buildConfigField "String", "COMMIT_COUNT", "\"${getCommitCount()}\""
buildConfigField "String", "COMMIT_SHA", "\"${getGitSha()}\""
buildConfigField "String", "BUILD_TIME", "\"${getBuildTime()}\""
buildConfigField "boolean", "INCLUDE_UPDATER", "false"
buildConfigField "boolean", "INCLUDE_UPDATER", "true"
multiDexEnabled true
@ -61,12 +66,21 @@ android {
debug {
versionNameSuffix "-${getCommitCount()}"
applicationIdSuffix ".debug"
ext.enableCrashlytics = false
}
// release {
releaseTest {
applicationIdSuffix ".rt"
// minifyEnabled true
// shrinkResources true
// proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
// }
zipAlignEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
release {
minifyEnabled true
shrinkResources true
zipAlignEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
flavorDimensions "default"
@ -76,21 +90,27 @@ android {
buildConfigField "boolean", "INCLUDE_UPDATER", "true"
dimension "default"
}
fdroid {
dimension "default"
}
dev {
resConfigs "en", "xxhdpi"
dimension "default"
}
}
compileOptions {
sourceCompatibility 1.8
targetCompatibility 1.8
}
packagingOptions {
exclude 'META-INF/DEPENDENCIES'
exclude 'LICENSE.txt'
exclude 'META-INF/LICENSE'
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/NOTICE'
exclude 'META-INF/*.kotlin_module'
// Compatibility for two RxJava versions (EXH)
exclude 'META-INF/rxjava.properties'
}
lintOptions {
@ -137,7 +157,7 @@ dependencies {
// UI library
implementation 'com.google.android.material:material:1.1.0'
standardImplementation 'com.google.firebase:firebase-core:17.4.0'
standardImplementation 'com.google.firebase:firebase-core:17.4.1'
// ReactiveX
implementation 'io.reactivex:rxandroid:1.2.1'
@ -146,13 +166,13 @@ dependencies {
implementation 'com.github.pwittchen:reactivenetwork:0.13.0'
// Network client
final okhttp_version = '4.5.0'
final okhttp_version = '4.7.2'
implementation "com.squareup.okhttp3:okhttp:$okhttp_version"
implementation "com.squareup.okhttp3:logging-interceptor:$okhttp_version"
implementation 'com.squareup.okio:okio:2.6.0'
// REST
final retrofit_version = '2.8.1'
final retrofit_version = '2.9.0'
implementation "com.squareup.retrofit2:retrofit:$retrofit_version"
implementation "com.squareup.retrofit2:converter-gson:$retrofit_version"
implementation "com.squareup.retrofit2:adapter-rxjava:$retrofit_version"
@ -162,7 +182,7 @@ dependencies {
implementation 'com.github.salomonbrys.kotson:kotson:2.5.0'
// JavaScript engine
implementation 'com.squareup.duktape:duktape-android:1.3.0'
implementation 'com.squareup.duktape:duktape-android:1.2.0' // Stuck on 1.2.0 to fix MangaPlus extension
// Disk
implementation 'com.jakewharton:disklrucache:2.0.2'
@ -176,6 +196,9 @@ dependencies {
implementation "androidx.work:work-runtime:$work_version"
implementation "androidx.work:work-runtime-ktx:$work_version"
// [EXH] Android 7 SSL Workaround
implementation 'com.google.android.gms:play-services-safetynet:17.0.0'
// Changelog
implementation 'com.github.gabrielemariotti.changeloglib:changelog:2.1.0'
@ -190,7 +213,7 @@ dependencies {
implementation 'com.github.tfcporciuncula:flow-preferences:1.1.1'
// Model View Presenter
final nucleus_version = '6.0.0'
final nucleus_version = '3.0.0'
implementation "info.android15.nucleus:nucleus:$nucleus_version"
implementation "info.android15.nucleus:nucleus-support-v7:$nucleus_version"
@ -198,7 +221,7 @@ dependencies {
implementation "com.github.inorichi.injekt:injekt-core:65b0440"
// Image library
final glide_version = '4.11.0'
final glide_version = '4.10.0'
implementation "com.github.bumptech.glide:glide:$glide_version"
implementation "com.github.bumptech.glide:okhttp3-integration:$glide_version"
kapt "com.github.bumptech.glide:compiler:$glide_version"
@ -210,6 +233,9 @@ dependencies {
final acra_version = '5.5.0'
implementation "ch.acra:acra-http:$acra_version"
// Sort
implementation 'com.github.gpanther:java-nat-sort:natural-comparator-1.1'
// UI
implementation 'com.dmitrymalkovich.android:material-design-dimens:1.4'
implementation 'com.github.dmytrodanylyk.android-process-button:library:1.0.4'
@ -253,15 +279,64 @@ dependencies {
testImplementation "org.robolectric:shadows-play-services:$robolectric_version"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
final coroutines_version = '1.3.5'
final coroutines_version = '1.3.7'
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$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.2'
// Text distance (EH)
implementation 'info.debatty:java-string-similarity:1.2.1'
// Pin lock view (EH)
implementation 'com.github.jawnnypoo:pinlockview:2.2.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)
implementation 'com.crashlytics.sdk.android:crashlytics:2.10.1'
// Better logging (EH)
implementation 'com.elvishew:xlog:1.6.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)
debugImplementation 'com.ms-square:debugoverlay:1.1.3'
releaseTestImplementation 'com.ms-square:debugoverlay:1.1.3'
releaseImplementation 'com.ms-square:debugoverlay-no-op:1.1.3'
testImplementation 'com.ms-square:debugoverlay-no-op:1.1.3'
// Humanize (EH)
implementation 'com.github.mfornos:humanize-slim:1.2.2'
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 {
@ -279,8 +354,8 @@ repositories {
}
// See https://kotlinlang.org/docs/reference/experimental.html#experimental-status-of-experimental-api-markers
tasks.withType(org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile).all {
kotlinOptions.freeCompilerArgs += ["-Xopt-in=kotlin.Experimental"]
tasks.withType(AbstractKotlinCompile).all {
kotlinOptions.freeCompilerArgs += ["-Xuse-experimental=kotlin.Experimental"]
}
// Duplicating Hebrew string assets due to some locale code issues on different devices
@ -294,4 +369,6 @@ preBuild.dependsOn(ktlintFormat, copyResources)
if (getGradle().getStartParameter().getTaskRequests().toString().contains("Standard")) {
apply plugin: 'com.google.gms.google-services'
// Firebase (EH)
apply plugin: 'io.fabric'
}

195
app/proguard-rules.pro vendored
View File

@ -11,6 +11,13 @@
-keep class com.github.salomonbrys.kotson.** { *; }
-keep class com.squareup.duktape.** { *; }
# === Keep EH classes
-keep class exh.** { *; }
-keep class xyz.nulldev.** { *; }
# === Keep RxAndroid, https://github.com/ReactiveX/RxAndroid/issues/350
-keep class rx.android.** { *; }
# Design library
-dontwarn com.google.android.material.**
-keep class com.google.android.material.** { *; }
@ -23,20 +30,6 @@
<init>();
}
# OkHttp
-dontwarn okhttp3.**
-dontwarn okio.**
-dontwarn javax.annotation.**
-dontwarn retrofit2.Platform$Java8
# Glide specific rules #
# https://github.com/bumptech/glide
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public class * extends com.bumptech.glide.AppGlideModule
-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
**[] $VALUES;
public *;
}
# RxJava 1.1.0
-dontwarn sun.misc.**
@ -54,20 +47,186 @@
rx.internal.util.atomic.LinkedQueueNode consumerNode;
}
# ReactiveNetwork
-dontwarn com.github.pwittchen.reactivenetwork.**
-dontnote rx.internal.util.PlatformDependent
## GSON ##
# === Reactive network: https://github.com/pwittchen/ReactiveNetwork/tree/v0.12.4#proguard-configuration
-dontwarn com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
-dontwarn io.reactivex.functions.Function
-dontwarn rx.internal.util.**
-dontwarn sun.misc.Unsafe
# === Okhttp: https://github.com/square/okhttp/blob/3637fc56f70f87da696847defd311dbfb28e87b5/okhttp/src/main/resources/META-INF/proguard/okhttp3.pro
# JSR 305 annotations are for embedding nullability information.
-dontwarn javax.annotation.**
# A resource is loaded with a relative path so the package of this class must be preserved.
-keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase
# Animal Sniffer compileOnly dependency to ensure APIs are compatible with older versions of Java.
-dontwarn org.codehaus.mojo.animal_sniffer.*
# OkHttp platform used only on JVM and when Conscrypt dependency is available.
-dontwarn okhttp3.internal.platform.ConscryptPlatform
# === Okio: https://github.com/square/okio/tree/9b8545e7fa267c9d89753283990f24a35cd69cd6#proguard
-dontwarn okio.**
# === GSON: https://raw.githubusercontent.com/google/gson/master/examples/android-proguard-example/proguard.cfg
# Gson uses generic type information stored in a class file when working with fields. Proguard
# removes such information by default, so configure it to keep all of it.
-keepattributes Signature
# For using GSON @Expose annotation
-keepattributes *Annotation*
# Gson specific classes
-keep class sun.misc.Unsafe { *; }
-dontwarn sun.misc.**
#-keep class com.google.gson.stream.** { *; }
# Application classes that will be serialized/deserialized over Gson
-keep class com.google.gson.examples.android.model.** { <fields>; }
# Prevent proguard from stripping interface information from TypeAdapterFactory,
# JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter)
-keep class * implements com.google.gson.TypeAdapterFactory
-keep class * implements com.google.gson.JsonSerializer
-keep class * implements com.google.gson.JsonDeserializer
# Prevent R8 from leaving Data object members always null
-keepclassmembers,allowobfuscation class * {
@com.google.gson.annotations.SerializedName <fields>;
}
# == Nucleus
-keepclassmembers class * extends nucleus.presenter.Presenter {
<init>();
}
# TODO Changeloglib? Does it need proguard?
# === Injekt
## From original config: "Attempt to fix: java.lang.NoClassDefFoundError: uy.kohesive.injekt.registry.default.DefaultRegistrar$NOKEY$1"
-keep class uy.kohesive.injekt.** { *; }
# === Glide
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public class * extends com.bumptech.glide.module.AppGlideModule
-keep public enum com.bumptech.glide.load.ImageHeaderParser$** {
**[] $VALUES;
public *;
}
-dontwarn com.bumptech.glide.load.resource.bitmap.VideoDecoder
# === Glide-transformations: https://github.com/wasabeef/glide-transformations/blob/3aa8e53c6a51b8351d312f802ba1354c5b115168/transformations/proguard-rules.txt
-dontwarn jp.co.cyberagent.android.gpuimage.**
# === Conductor
# This isn't in the consumer proguard rules yet: https://github.com/bluelinelabs/Conductor/pull/550/files
-keepclassmembers public class * extends com.bluelinelabs.conductor.ControllerChangeHandler {
public <init>();
}
# === RxBinding
-dontwarn com.google.auto.value.AutoValue
# === Crashlytics
-keepattributes *Annotation*
-keepattributes SourceFile,LineNumberTable
-keep class com.crashlytics.** { *; }
-dontwarn com.crashlytics.**
# === Humanize + Guava: https://github.com/google/guava/wiki/UsingProGuardWithGuava
-dontwarn javax.lang.model.element.Modifier
-keep class org.ocpsoft.prettytime.i18n.**
# Note: We intentionally don't add the flags we'd need to make Enums work.
# That's because the Proguard configuration required to make it work on
# optimized code would preclude lots of optimization, like converting enums
# into ints.
# Throwables uses internal APIs for lazy stack trace resolution
-dontnote sun.misc.SharedSecrets
-keep class sun.misc.SharedSecrets {
*** getJavaLangAccess(...);
}
-dontnote sun.misc.JavaLangAccess
-keep class sun.misc.JavaLangAccess {
*** getStackTraceElement(...);
*** getStackTraceDepth(...);
}
# FinalizableReferenceQueue calls this reflectively
# Proguard is intelligent enough to spot the use of reflection onto this, so we
# only need to keep the names, and allow it to be stripped out if
# FinalizableReferenceQueue is unused.
-keepnames class com.google.common.base.internal.Finalizer {
*** startFinalizer(...);
}
# However, it cannot "spot" that this method needs to be kept IF the class is.
-keepclassmembers class com.google.common.base.internal.Finalizer {
*** startFinalizer(...);
}
-keepnames class com.google.common.base.FinalizableReference {
void finalizeReferent();
}
-keepclassmembers class com.google.common.base.FinalizableReference {
void finalizeReferent();
}
# Striped64, LittleEndianByteArray, UnsignedBytes, AbstractFuture
-dontwarn sun.misc.Unsafe
# Striped64 appears to make some assumptions about object layout that
# really might not be safe. This should be investigated.
-keepclassmembers class com.google.common.cache.Striped64 {
*** base;
*** busy;
}
-keepclassmembers class com.google.common.cache.Striped64$Cell {
<fields>;
}
-dontwarn java.lang.SafeVarargs
-keep class java.lang.Throwable {
*** addSuppressed(...);
}
# Futures.getChecked, in both of its variants, is incompatible with proguard.
# Used by AtomicReferenceFieldUpdater and sun.misc.Unsafe
-keepclassmembers class com.google.common.util.concurrent.AbstractFuture** {
*** waiters;
*** value;
*** listeners;
*** thread;
*** next;
}
-keepclassmembers class com.google.common.util.concurrent.AtomicDouble {
*** value;
}
-keepclassmembers class com.google.common.util.concurrent.AggregateFutureState {
*** remaining;
*** seenExceptions;
}
# Since Unsafe is using the field offsets of these inner classes, we don't want
# to have class merging or similar tricks applied to these classes and their
# fields. It's safe to allow obfuscation, since the by-name references are
# already preserved in the -keep statement above.
-keep,allowshrinking,allowobfuscation class com.google.common.util.concurrent.AbstractFuture** {
<fields>;
}
# Futures.getChecked (which often won't work with Proguard anyway) uses this. It
# has a fallback, but again, don't use Futures.getChecked on Android regardless.
-dontwarn java.lang.ClassValue
# MoreExecutors references AppEngine
-dontnote com.google.appengine.api.ThreadManager
-keep class com.google.appengine.api.ThreadManager {
static *** currentRequestThreadFactory(...);
}
-dontnote com.google.apphosting.api.ApiProxy
-keep class com.google.apphosting.api.ApiProxy {
static *** getCurrentEnvironment (...);
}

View File

@ -16,19 +16,82 @@
android:fillType="evenOdd"
android:fillColor="#607D8B"/>
<path
android:pathData="M54,54.5m-25.5,0a25.5,25.5 0,1 1,51 0a25.5,25.5 0,1 1,-51 0"
android:fillType="evenOdd"
android:fillColor="#000"/>
android:name="path_3"
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="#000"
android:fillType="evenOdd"/>
<path
android:pathData="M54,54.5m-25.5,0a25.5,25.5 0,1 1,51 0a25.5,25.5 0,1 1,-51 0"
android:fillType="evenOdd"
android:fillColor="#CE2828"/>
android:name="path_4"
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:fillType="evenOdd"/>
<path
android:pathData="M54,54.5m-19.94,0a19.94,19.94 0,1 1,39.87 0a19.94,19.94 0,1 1,-39.87 0"
android:fillType="evenOdd"
android:fillColor="#FFF"/>
android:name="path_5"
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="#FFF"
android:fillType="evenOdd"/>
<path
android:pathData="M52.04,46.3L47.42,46.3C46.14,46.3 44.93,46.23 44.2,46.14L44.2,49.76C45,49.65 46.16,49.6 47.42,49.6L60.58,49.6C61.86,49.6 63.02,49.65 63.82,49.76L63.82,46.14C63.09,46.23 61.86,46.3 60.58,46.3L55.69,46.3L55.69,45.07C55.69,44.43 55.73,43.95 55.82,43.45L51.9,43.45C51.99,44 52.04,44.43 52.04,45.07L52.04,46.3ZM46.78,60.68C45.46,60.68 44.29,60.63 43.45,60.52L43.45,64.14C44.34,64.03 45.46,63.98 46.78,63.98L61.29,63.98C62.57,63.98 63.71,64.03 64.57,64.14L64.57,60.52C63.73,60.63 62.57,60.68 61.29,60.68L58.24,60.68C59.33,58.06 59.99,56.23 60.7,53.91C61.34,51.81 61.34,51.81 61.56,51.13L57.58,50.06C57.51,50.93 57.37,51.52 56.89,53.41C56.19,56.14 55.32,58.74 54.5,60.68L46.78,60.68ZM46.48,51.36C47.55,54.02 48.28,56.53 49.03,60.15L52.66,58.9C51.65,54.98 50.92,52.66 49.94,50.11L46.48,51.36Z"
android:fillType="evenOdd"
android:fillColor="#000"/>
android:name="path_6"
android:pathData="M 54.174 36.266 C 64.147 36.266 72.234 44.397 72.234 54.426 C 72.234 64.459 64.147 72.593 54.174 72.593 C 44.197 72.593 36.113 64.459 36.113 54.426 C 36.113 44.397 44.197 36.266 54.174 36.266 Z"
android:fillColor="#ffcc4d"
android:strokeColor="#ffcc4d"
android:strokeWidth="4.628571428571428"
android:strokeLineCap="round"
android:strokeLineJoin="round"/>
<path
android:name="path_7"
android:pathData="M 48.774 45.158 C 49.988 45.158 50.973 46.452 50.973 48.05 C 50.973 49.65 49.988 50.946 48.774 50.946 C 47.559 50.946 46.576 49.65 46.576 48.05 C 46.576 46.452 47.559 45.158 48.774 45.158 Z"
android:fillColor="#674600"
android:strokeColor="#674600"
android:strokeWidth="0.1"
android:strokeLineJoin="round"/>
<path
android:name="path_8"
android:pathData="M 62.02 45.158 C 63.235 45.158 64.219 46.452 64.219 48.05 C 64.219 49.65 63.235 50.946 62.02 50.946 C 60.805 50.946 59.821 49.65 59.821 48.05 C 59.821 46.452 60.805 45.158 62.02 45.158 Z"
android:fillColor="#674600"
android:strokeColor="#674600"
android:strokeWidth="0.1"
android:strokeLineJoin="round"/>
<path
android:name="path_9"
android:pathData="M 44.687 42.102 C 44.687 42.102 48.404 40.049 53.119 42.102"
android:strokeColor="#674600"
android:strokeWidth="2"
android:strokeLineCap="round"
android:strokeLineJoin="round"
android:fillType="evenOdd"/>
<path
android:name="path_10"
android:pathData="M 58.035 42.102 C 58.035 42.102 61.751 40.049 66.465 42.102"
android:strokeColor="#674600"
android:strokeWidth="2"
android:strokeLineCap="round"
android:strokeLineJoin="round"
android:fillType="evenOdd"/>
<path
android:name="path_11"
android:pathData="M 49.191 56.685 C 49.191 56.685 51.703 59.685 56.992 59.685"
android:strokeColor="#674600"
android:strokeWidth="2"
android:strokeLineCap="round"
android:strokeLineJoin="round"
android:fillType="evenOdd"/>
<path
android:name="path_12"
android:pathData="M 34.072 67.511 C 34.072 67.511 34.524 66.248 37.476 63.634 C 37.476 63.634 39.143 61.991 37.876 58.114 C 37.876 58.114 37.534 56.06 39.681 57.255 C 39.681 57.255 44.129 60.46 40.871 65 C 40.871 65 40.241 66.117 41.652 65.78 L 53.939 63.103 C 53.939 63.103 55.275 62.752 55.535 64.163 C 55.535 64.163 55.696 65.372 54.641 65.672 L 47.742 67.378 C 47.742 67.378 50.72 69.597 47.742 70.825 C 47.742 70.825 50.294 72.779 47.336 74.268 C 47.336 74.268 49.276 76.015 46.407 77.019 C 46.407 77.019 42.525 78.474 39.209 77.831 C 35.509 77.103 31.947 72.114 34.072 67.511 Z"
android:fillColor="#f4900c"
android:strokeColor="#f4900c"
android:strokeLineCap="round"
android:strokeLineJoin="round"
android:strokeWidth="0.1"
android:fillType="evenOdd"/>
<path
android:name="path_13"
android:pathData="M 56.182 67.511 C 56.182 67.511 56.633 66.248 59.585 63.634 C 59.585 63.634 61.253 61.991 59.985 58.114 C 59.985 58.114 59.642 56.06 61.789 57.255 C 61.789 57.255 66.239 60.46 62.98 65 C 62.98 65 62.351 66.117 63.761 65.78 L 76.066 63.103 C 76.066 63.103 77.386 62.752 77.641 64.163 C 77.641 64.163 77.812 65.372 76.746 65.672 L 69.85 67.378 C 69.85 67.378 72.829 69.597 69.85 70.825 C 69.85 70.825 72.404 72.779 69.446 74.268 C 69.446 74.268 71.387 76.015 68.516 77.019 C 68.516 77.019 64.633 78.474 61.317 77.831 C 57.618 77.103 54.057 72.114 56.182 67.511 Z"
android:fillColor="#f4900c"
android:strokeColor="#f4900c"
android:strokeLineCap="round"
android:strokeLineJoin="round"
android:strokeWidth="0.1"
android:fillType="evenOdd"/>
</vector>

View File

@ -0,0 +1,6 @@
<vector android:height="100dp"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="100dp" xmlns:android="http://schemas.android.com/apk/res/android"
android:tint="?attr/colorControlNormal">
<path android:fillColor="@android:color/white" android:pathData="M7,10l5,5 -5,5z"/>
</vector>

147
app/src/main/AndroidManifest.xml Normal file → Executable file
View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="eu.kanade.tachiyomi">
<uses-permission android:name="android.permission.INTERNET" />
@ -13,6 +14,13 @@
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
<uses-permission android:name="android.permission.GET_TASKS" />
<uses-permission
android:name="android.permission.PACKAGE_USAGE_STATS"
tools:ignore="ProtectedPermissions" />
<!-- Lock vibrate -->
<uses-permission android:name="android.permission.VIBRATE" />
<application
android:name=".App"
@ -25,6 +33,7 @@
android:largeHeap="true"
android:requestLegacyExternalStorage="true"
android:roundIcon="@mipmap/ic_launcher_round"
android:networkSecurityConfig="@xml/network_security_config"
android:theme="@style/Theme.Tachiyomi.Light"
android:usesCleartextTraffic="true">
<activity
@ -40,6 +49,11 @@
android:name="android.app.shortcuts"
android:resource="@xml/shortcuts" />
</activity>
<activity
android:name=".ui.main.ForceCloseActivity"
android:clearTaskOnLaunch="true"
android:noHistory="true"
android:theme="@android:style/Theme.NoDisplay" />
<activity
android:name=".ui.main.DeepLinkActivity"
android:launchMode="singleTask"
@ -160,6 +174,139 @@
android:name=".data.backup.BackupRestoreService"
android:exported="false" />
<!-- EH -->
<service
android:name="exh.eh.EHentaiUpdateWorker"
android:permission="android.permission.BIND_JOB_SERVICE"
android:exported="true" />
<activity
android:name="exh.ui.intercept.InterceptActivity"
android:label="TachiyomiEH"
android:theme="@style/Theme.EHActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<!-- EH -->
<data
android:host="g.e-hentai.org"
android:pathPrefix="/g/"
android:scheme="http" />
<data
android:host="g.e-hentai.org"
android:pathPrefix="/g/"
android:scheme="https" />
<data
android:host="e-hentai.org"
android:pathPrefix="/g/"
android:scheme="http" />
<data
android:host="e-hentai.org"
android:pathPrefix="/g/"
android:scheme="https" />
<!-- EXH -->
<data
android:host="exhentai.org"
android:pathPrefix="/g/"
android:scheme="http" />
<data
android:host="exhentai.org"
android:pathPrefix="/g/"
android:scheme="https" />
<!-- nhentai -->
<data
android:host="nhentai.net"
android:pathPrefix="/g/"
android:scheme="http" />
<data
android:host="nhentai.net"
android:pathPrefix="/g/"
android:scheme="https" />
<!-- Perv Eden -->
<data
android:host="www.perveden.com"
android:pathPattern="/.*/.*-manga/.*"
android:scheme="http" />
<data
android:host="www.perveden.com"
android:pathPattern="/.*/.*-manga/.*"
android:scheme="https" />
<!-- Hentai Cafe -->
<data
android:host="hentai.cafe"
android:pathPattern="/.*/.*"
android:scheme="http" />
<data
android:host="hentai.cafe"
android:pathPattern="/.*/.*"
android:scheme="https" />
<!-- Tsumino -->
<data
android:host="www.tsumino.com"
android:pathPrefix="/Book/Info/"
android:scheme="http" />
<data
android:host="www.tsumino.com"
android:pathPrefix="/Book/Info/"
android:scheme="https" />
<data
android:host="www.tsumino.com"
android:pathPrefix="/Read/View/"
android:scheme="http" />
<data
android:host="www.tsumino.com"
android:pathPrefix="/Read/View/"
android:scheme="https" />
<!-- Hitomi.la -->
<data
android:host="hitomi.la"
android:pathPrefix="/galleries/"
android:scheme="http" />
<data
android:host="hitomi.la"
android:pathPrefix="/reader/"
android:scheme="http" />
<data
android:host="hitomi.la"
android:pathPrefix="/galleries/"
android:scheme="https" />
<data
android:host="hitomi.la"
android:pathPrefix="/reader/"
android:scheme="https" />
<!-- Pururin.io -->
<data
android:host="pururin.io"
android:pathPrefix="/gallery/"
android:scheme="http" />
<data
android:host="pururin.io"
android:pathPrefix="/gallery/"
android:scheme="https" />
<!-- HBrowse -->
<data
android:host="www.hbrowse.com"
android:pathPrefix="/"
android:scheme="http" />
<data
android:host="www.hbrowse.com"
android:pathPrefix="/"
android:scheme="https" />
</intent-filter>
</activity>
<activity
android:name="exh.ui.captcha.BrowserActionActivity"
android:theme="@style/Theme.EHActivity" />
</application>
</manifest>

0
app/src/main/ic_launcher-web.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

174
app/src/main/java/eu/kanade/tachiyomi/App.kt Normal file → Executable file
View File

@ -3,44 +3,79 @@ package eu.kanade.tachiyomi
import android.app.Application
import android.content.Context
import android.content.res.Configuration
import android.graphics.Color
import android.os.Build
import android.os.Environment
import android.widget.Toast
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.OnLifecycleEvent
import androidx.lifecycle.ProcessLifecycleOwner
import androidx.multidex.MultiDex
import com.elvishew.xlog.LogConfiguration
import com.elvishew.xlog.LogLevel
import com.elvishew.xlog.XLog
import com.elvishew.xlog.printer.AndroidPrinter
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.clean.FileLastModifiedCleanStrategy
import com.elvishew.xlog.printer.file.naming.DateFileNameGenerator
import com.google.android.gms.common.GooglePlayServicesNotAvailableException
import com.google.android.gms.common.GooglePlayServicesRepairableException
import com.google.android.gms.security.ProviderInstaller
import com.kizitonwose.time.days
import com.ms_square.debugoverlay.DebugOverlay
import com.ms_square.debugoverlay.modules.FpsModule
import eu.kanade.tachiyomi.data.notification.Notifications
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.util.system.LocaleHelper
import org.acra.ACRA
import org.acra.annotation.AcraCore
import org.acra.annotation.AcraHttpSender
import org.acra.sender.HttpSender
import eu.kanade.tachiyomi.util.system.WebViewUtil
import eu.kanade.tachiyomi.util.system.toast
import exh.debug.DebugToggles
import exh.log.CrashlyticsPrinter
import exh.log.EHDebugModeOverlay
import exh.log.EHLogLevel
import io.realm.Realm
import io.realm.RealmConfiguration
import java.io.File
import java.security.NoSuchAlgorithmException
import javax.net.ssl.SSLContext
import kotlin.concurrent.thread
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import timber.log.Timber
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.InjektScope
import uy.kohesive.injekt.injectLazy
import uy.kohesive.injekt.registry.default.DefaultRegistrar
@AcraCore(
buildConfigClass = BuildConfig::class,
excludeMatchingSharedPreferencesKeys = [".*username.*", ".*password.*", ".*token.*"]
)
@AcraHttpSender(
uri = "https://tachiyomi.kanade.eu/crash_report",
httpMethod = HttpSender.Method.PUT
)
open class App : Application(), LifecycleObserver {
override fun onCreate() {
super.onCreate()
if (BuildConfig.DEBUG) Timber.plant(Timber.DebugTree())
setupExhLogging() // EXH logging
workaroundAndroid7BrokenSSL()
// Enforce WebView availability
if (!WebViewUtil.supportsWebView(this)) {
toast(R.string.information_webview_required, Toast.LENGTH_LONG)
ForceCloseActivity.closeApp(this)
}
Injekt = InjektScope(DefaultRegistrar())
Injekt.importModule(AppModule(this))
setupAcra()
setupNotificationChannels()
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) {
setupDebugOverlay()
}
LocaleHelper.updateConfiguration(this, resources.configuration)
@ -57,6 +92,26 @@ open class App : Application(), LifecycleObserver {
LocaleHelper.updateConfiguration(this, newConfig, true)
}
private fun workaroundAndroid7BrokenSSL() {
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.N ||
Build.VERSION.SDK_INT == Build.VERSION_CODES.N_MR1
) {
try {
SSLContext.getInstance("TLSv1.2")
} catch (e: NoSuchAlgorithmException) {
XLog.e("Could not install Android 7 broken SSL workaround!", e)
}
try {
ProviderInstaller.installIfNeeded(applicationContext)
} catch (e: GooglePlayServicesRepairableException) {
XLog.e("Could not install Android 7 broken SSL workaround!", e)
} catch (e: GooglePlayServicesNotAvailableException) {
XLog.e("Could not install Android 7 broken SSL workaround!", e)
}
}
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
@Suppress("unused")
fun onAppBackgrounded() {
@ -66,11 +121,96 @@ open class App : Application(), LifecycleObserver {
}
}
protected open fun setupAcra() {
ACRA.init(this)
}
protected open fun setupNotificationChannels() {
Notifications.createChannels(this)
}
// EXH
private fun deleteOldMetadataRealm() {
Realm.init(this)
val config = RealmConfiguration.Builder()
.name("gallery-metadata.realm")
.schemaVersion(3)
.deleteRealmIfMigrationNeeded()
.build()
Realm.deleteRealm(config)
// Delete old paper db files
listOf(
File(filesDir, "gallery-ex"),
File(filesDir, "gallery-perveden"),
File(filesDir, "gallery-nhentai")
).forEach {
if (it.exists()) {
thread {
it.deleteRecursively()
}
}
}
}
// EXH
private fun setupExhLogging() {
EHLogLevel.init(this)
val logLevel = if (EHLogLevel.shouldLog(EHLogLevel.EXTRA)) {
LogLevel.ALL
} else {
LogLevel.WARN
}
val logConfig = LogConfiguration.Builder()
.logLevel(logLevel)
.t()
.st(2)
.nb()
.build()
val printers = mutableListOf<Printer>(AndroidPrinter())
val logFolder = File(
Environment.getExternalStorageDirectory().absolutePath + File.separator +
getString(R.string.app_name),
"logs"
)
printers += FilePrinter
.Builder(logFolder.absolutePath)
.fileNameGenerator(object : DateFileNameGenerator() {
override fun generateFileName(logLevel: Int, timestamp: Long): String {
return super.generateFileName(logLevel, timestamp) + "-${BuildConfig.BUILD_TYPE}"
}
})
.cleanStrategy(FileLastModifiedCleanStrategy(7.days.inMilliseconds.longValue))
.backupStrategy(NeverBackupStrategy())
.build()
// Install Crashlytics in prod
if (!BuildConfig.DEBUG) {
printers += CrashlyticsPrinter(LogLevel.ERROR)
}
XLog.init(
logConfig,
*printers.toTypedArray()
)
XLog.d("Application booting...")
}
// EXH
private fun setupDebugOverlay() {
try {
DebugOverlay.Builder(this)
.modules(FpsModule(), EHDebugModeOverlay(this))
.bgColor(Color.parseColor("#7F000000"))
.notification(false)
.allowSystemLayer(false)
.build()
.install()
} catch (e: IllegalStateException) {
// Crashes if app is in background
XLog.e("Failed to initialize debug overlay, app in background?", e)
}
}
}

6
app/src/main/java/eu/kanade/tachiyomi/AppModule.kt Normal file → Executable file
View File

@ -11,6 +11,8 @@ import eu.kanade.tachiyomi.data.track.TrackManager
import eu.kanade.tachiyomi.extension.ExtensionManager
import eu.kanade.tachiyomi.network.NetworkHelper
import eu.kanade.tachiyomi.source.SourceManager
import exh.eh.EHentaiUpdateHelper
import io.noties.markwon.Markwon
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import uy.kohesive.injekt.api.InjektModule
@ -44,6 +46,10 @@ class AppModule(val app: Application) : InjektModule {
addSingletonFactory { Gson() }
addSingletonFactory { EHentaiUpdateHelper(app) }
addSingletonFactory { Markwon.create(app) }
// Asynchronously init expensive components for a faster cold start
GlobalScope.launch { get<PreferencesHelper>() }

View File

@ -10,6 +10,8 @@ import java.io.File
object Migrations {
// TODO NATIVE TACHIYOMI MIGRATIONS ARE FUCKED UP DUE TO DIFFERING VERSION NUMBERS
/**
* Performs a migration when the application is updated.
*

View File

@ -9,6 +9,7 @@ import android.os.IBinder
import android.os.PowerManager
import com.hippo.unifile.UniFile
import eu.kanade.tachiyomi.data.notification.Notifications
import eu.kanade.tachiyomi.util.system.acquireWakeLock
import eu.kanade.tachiyomi.util.system.isServiceRunning
/**
@ -69,14 +70,11 @@ class BackupCreateService : Service() {
override fun onCreate() {
super.onCreate()
notifier = BackupNotifier(this)
wakeLock = acquireWakeLock(javaClass.name)
startForeground(Notifications.ID_BACKUP_PROGRESS, notifier.showBackupProgress().build())
wakeLock = (getSystemService(Context.POWER_SERVICE) as PowerManager).newWakeLock(
PowerManager.PARTIAL_WAKE_LOCK, "${javaClass.name}:WakeLock"
)
wakeLock.acquire()
}
override fun stopService(name: Intent?): Boolean {

View File

@ -46,9 +46,12 @@ import eu.kanade.tachiyomi.data.database.models.Track
import eu.kanade.tachiyomi.data.database.models.TrackImpl
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.track.TrackManager
import eu.kanade.tachiyomi.source.LocalSource
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 kotlin.math.max
import rx.Observable
import timber.log.Timber
@ -131,8 +134,10 @@ class BackupManager(val context: Context, version: Int = CURRENT_VERSION) {
mangaEntries.add(backupMangaObject(manga, flags))
// Maintain set of extensions/sources used (excludes local source)
if (manga.source != 0L) {
extensions.add("${manga.source}:${sourceManager.get(manga.source)!!.name}")
if (manga.source != LocalSource.ID) {
sourceManager.get(manga.source)?.let {
extensions.add("${manga.source}:${it.name}")
}
}
}
@ -294,9 +299,23 @@ class BackupManager(val context: Context, version: Int = CURRENT_VERSION) {
* @param manga manga that needs updating
* @return [Observable] that contains manga
*/
fun restoreChapterFetchObservable(source: Source, manga: Manga, chapters: List<Chapter>): Observable<Pair<List<Chapter>, List<Chapter>>> {
return source.fetchChapterList(manga)
.map { syncChaptersWithSource(databaseHelper, it, manga, source) }
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 {
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)
}
}
.doOnNext { pair ->
if (pair.first.isNotEmpty()) {
chapters.forEach { it.manga_id = manga.id }

View File

@ -41,6 +41,7 @@ internal class BackupNotifier(private val context: Context) {
setContentTitle(context.getString(R.string.creating_backup))
setProgress(0, 0, true)
setOnlyAlertOnce(true)
}
builder.show(Notifications.ID_BACKUP_PROGRESS)
@ -93,6 +94,7 @@ internal class BackupNotifier(private val context: Context) {
}
setProgress(maxAmount, progress, false)
setOnlyAlertOnce(true)
// Clear old actions if they exist
if (mActions.isNotEmpty()) {
@ -135,7 +137,7 @@ internal class BackupNotifier(private val context: Context) {
with(completeNotificationBuilder) {
setContentTitle(context.getString(R.string.restore_completed))
setContentText(context.getString(R.string.restore_completed_content, timeString, errorCount))
setContentText(context.resources.getQuantityString(R.plurals.restore_completed_message, errorCount, timeString, errorCount))
// Clear old actions if they exist
if (mActions.isNotEmpty()) {

View File

@ -32,7 +32,10 @@ import eu.kanade.tachiyomi.data.database.models.TrackImpl
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.isServiceRunning
import exh.EXHMigrations
import exh.eh.EHentaiThrottleManager
import java.io.File
import java.text.SimpleDateFormat
import java.util.Date
@ -99,6 +102,8 @@ class BackupRestoreService : Service() {
private var job: Job? = null
private val throttleManager = EHentaiThrottleManager()
/**
* The progress of a backup restore
*/
@ -109,6 +114,15 @@ class BackupRestoreService : Service() {
*/
private var restoreAmount = 0
private var skippedAmount = 0
private var totalAmount = 0
/**
* Mapping of source ID to source name from backup data
*/
private var sourceMapping: Map<Long, String> = emptyMap()
/**
* List containing errors
*/
@ -123,14 +137,11 @@ class BackupRestoreService : Service() {
override fun onCreate() {
super.onCreate()
notifier = BackupNotifier(this)
wakeLock = acquireWakeLock(javaClass.name)
startForeground(Notifications.ID_RESTORE_PROGRESS, notifier.showRestoreProgress().build())
wakeLock = (getSystemService(Context.POWER_SERVICE) as PowerManager).newWakeLock(
PowerManager.PARTIAL_WAKE_LOCK, "${javaClass.name}:WakeLock"
)
wakeLock.acquire()
}
override fun stopService(name: Intent?): Boolean {
@ -166,6 +177,8 @@ class BackupRestoreService : Service() {
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
val uri = intent?.getParcelableExtra<Uri>(BackupConst.EXTRA_URI) ?: return START_NOT_STICKY
throttleManager.resetThrottle()
// Cancel any previous job if needed.
job?.cancel()
val handler = CoroutineExceptionHandler { _, exception ->
@ -177,7 +190,9 @@ class BackupRestoreService : Service() {
stopSelf(startId)
}
job = GlobalScope.launch(handler) {
restoreBackup(uri)
if (!restoreBackup(uri)) {
notifier.showRestoreError(getString(R.string.restoring_backup_canceled))
}
}
job?.invokeOnCompletion {
stopSelf(startId)
@ -191,7 +206,7 @@ class BackupRestoreService : Service() {
*
* @param uri backup file to restore
*/
private fun restoreBackup(uri: Uri) {
private fun restoreBackup(uri: Uri): Boolean {
val startTime = System.currentTimeMillis()
val reader = JsonReader(contentResolver.openInputStream(uri)!!.bufferedReader())
@ -205,15 +220,35 @@ class BackupRestoreService : Service() {
val mangasJson = json.get(MANGAS).asJsonArray
restoreAmount = mangasJson.size() + 1 // +1 for categories
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()
restoreProgress = 0
errors.clear()
// Restore categories
restoreCategories(json.get(CATEGORIES))
// Store source mapping for error messages
sourceMapping = BackupRestoreValidator.getSourceMapping(json)
// Restore individual manga
mangasJson.forEach {
if (job?.isActive != true) {
return false
}
restoreManga(it.asJsonObject)
}
@ -223,56 +258,67 @@ class BackupRestoreService : Service() {
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))
}
restoreProgress += 1
showRestoreProgress(restoreProgress, restoreAmount, getString(R.string.categories))
}
private fun restoreManga(mangaJson: JsonObject) {
db.inTransaction {
val 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()
)
var 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()
)
if (job?.isActive != true) {
throw Exception(getString(R.string.restoring_backup_canceled))
// 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")
}
try {
restoreMangaData(manga, chapters, categories, history, tracks)
} catch (e: Exception) {
errors.add(Date() to "${manga.title} - ${getString(R.string.source_not_found)}")
}
restoreProgress += 1
showRestoreProgress(restoreProgress, restoreAmount, manga.title)
} 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
@ -280,23 +326,24 @@ class BackupRestoreService : Service() {
*/
private fun restoreMangaData(
manga: Manga,
source: Source,
chapters: List<Chapter>,
categories: List<String>,
history: List<DHistory>,
tracks: List<Track>
) {
// Get source
val source = backupManager.sourceManager.getOrStub(manga.source)
val dbManga = backupManager.getMangaFromDatabase(manga)
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)
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)
}
}
}
@ -380,7 +427,7 @@ class BackupRestoreService : Service() {
* @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)
return backupManager.restoreChapterFetchObservable(source, manga, chapters, throttleManager)
// If there's any error, return empty update and continue.
.onErrorReturn {
errors.add(Date() to "${manga.title} - ${it.message}")
@ -396,7 +443,7 @@ class BackupRestoreService : Service() {
*/
private fun trackingFetchObservable(manga: Manga, tracks: List<Track>): Observable<Track> {
return Observable.from(tracks)
.concatMap { track ->
.flatMap { track ->
val service = trackManager.getService(track.sync_id)
if (service != null && service.isLogged) {
service.refresh(track)
@ -406,7 +453,7 @@ class BackupRestoreService : Service() {
track
}
} else {
errors.add(Date() to "${manga.title} - ${service?.name} not logged in")
errors.add(Date() to "${manga.title} - ${getString(R.string.tracker_not_logged_in, service?.name)}")
Observable.empty()
}
}

View File

@ -0,0 +1,46 @@
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()
}
}

47
app/src/main/java/eu/kanade/tachiyomi/data/cache/ChapterCache.kt vendored Normal file → Executable file
View File

@ -6,11 +6,17 @@ import com.github.salomonbrys.kotson.fromJson
import com.google.gson.Gson
import com.jakewharton.disklrucache.DiskLruCache
import eu.kanade.tachiyomi.data.database.models.Chapter
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.util.storage.DiskUtil
import eu.kanade.tachiyomi.util.storage.saveTo
import java.io.File
import java.io.IOException
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import okhttp3.Response
import okio.buffer
import okio.sink
@ -37,21 +43,32 @@ class ChapterCache(private val context: Context) {
/** The number of values per cache entry. Must be positive. */
const val PARAMETER_VALUE_COUNT = 1
/** The maximum number of bytes this cache should use to store. */
const val PARAMETER_CACHE_SIZE = 100L * 1024 * 1024
}
private val scope = CoroutineScope(Job() + Dispatchers.Main)
/** Google Json class used for parsing JSON files. */
private val gson: Gson by injectLazy()
// --> EH
private val prefs: PreferencesHelper by injectLazy()
// <-- EH
/** Cache class used for cache management. */
private val diskCache = DiskLruCache.open(
File(context.cacheDir, PARAMETER_CACHE_DIRECTORY),
PARAMETER_APP_VERSION,
PARAMETER_VALUE_COUNT,
PARAMETER_CACHE_SIZE
)
// --> EH
private var diskCache = setupDiskCache(prefs.eh_cacheSize().get().toLong())
init {
prefs.eh_cacheSize().asFlow()
.onEach {
// Save old cache for destruction later
val oldCache = diskCache
diskCache = setupDiskCache(it.toLong())
oldCache.close()
}
.launchIn(scope)
}
// <-- EH
/**
* Returns directory of cache.
@ -71,6 +88,18 @@ class ChapterCache(private val context: Context) {
val readableSize: String
get() = Formatter.formatFileSize(context, realSize)
// --> EH
// Cache size is in MB
private fun setupDiskCache(cacheSize: Long): DiskLruCache {
return DiskLruCache.open(
File(context.cacheDir, PARAMETER_CACHE_DIRECTORY),
PARAMETER_APP_VERSION,
PARAMETER_VALUE_COUNT,
cacheSize * 1024 * 1024
)
}
// <-- EH
/**
* Remove file from cache.
*

83
app/src/main/java/eu/kanade/tachiyomi/data/cache/CoverCache.kt vendored Normal file → Executable file
View File

@ -1,6 +1,7 @@
package eu.kanade.tachiyomi.data.cache
import android.content.Context
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.util.storage.DiskUtil
import java.io.File
import java.io.IOException
@ -17,51 +18,89 @@ import java.io.InputStream
*/
class CoverCache(private val context: Context) {
companion object {
private const val COVERS_DIR = "covers"
private const val CUSTOM_COVERS_DIR = "covers/custom"
}
/**
* Cache directory used for cache management.
*/
private val cacheDir = context.getExternalFilesDir("covers")
?: File(context.filesDir, "covers").also { it.mkdirs() }
private val cacheDir = getCacheDir(COVERS_DIR)
private val customCoverCacheDir = getCacheDir(CUSTOM_COVERS_DIR)
/**
* Returns the cover from cache.
*
* @param thumbnailUrl the thumbnail url.
* @param manga the manga.
* @return cover image.
*/
fun getCoverFile(thumbnailUrl: String): File {
return File(cacheDir, DiskUtil.hashKeyForDisk(thumbnailUrl))
fun getCoverFile(manga: Manga): File? {
return manga.thumbnail_url?.let {
File(cacheDir, DiskUtil.hashKeyForDisk(it))
}
}
/**
* Copy the given stream to this cache.
* Returns the custom cover from cache.
*
* @param thumbnailUrl url of the thumbnail.
* @param manga the manga.
* @return cover image.
*/
fun getCustomCoverFile(manga: Manga): File {
return File(customCoverCacheDir, DiskUtil.hashKeyForDisk(manga.id.toString()))
}
/**
* Saves the given stream as the manga's custom cover to cache.
*
* @param manga the manga.
* @param inputStream the stream to copy.
* @throws IOException if there's any error.
*/
@Throws(IOException::class)
fun copyToCache(thumbnailUrl: String, inputStream: InputStream) {
// Get destination file.
val destFile = getCoverFile(thumbnailUrl)
destFile.outputStream().use { inputStream.copyTo(it) }
fun setCustomCoverToCache(manga: Manga, inputStream: InputStream) {
getCustomCoverFile(manga).outputStream().use {
inputStream.copyTo(it)
}
}
/**
* Delete the cover file from the cache.
* Delete the cover files of the manga from the cache.
*
* @param thumbnailUrl the thumbnail url.
* @return status of deletion.
* @param manga the manga.
* @param deleteCustomCover whether the custom cover should be deleted.
* @return number of files that were deleted.
*/
fun deleteFromCache(thumbnailUrl: String?): Boolean {
// Check if url is empty.
if (thumbnailUrl.isNullOrEmpty()) {
return false
fun deleteFromCache(manga: Manga, deleteCustomCover: Boolean = false): Int {
var deleted = 0
getCoverFile(manga)?.let {
if (it.exists() && it.delete()) ++deleted
}
// Remove file.
val file = getCoverFile(thumbnailUrl)
return file.exists() && file.delete()
if (deleteCustomCover) {
if (deleteCustomCover(manga)) ++deleted
}
return deleted
}
/**
* Delete custom cover of the manga from the cache
*
* @param manga the manga.
* @return whether the cover was deleted.
*/
fun deleteCustomCover(manga: Manga): Boolean {
return getCustomCoverFile(manga).let {
it.exists() && it.delete()
}
}
private fun getCacheDir(dir: String): File {
return context.getExternalFilesDir(dir)
?: File(context.filesDir, dir).also { it.mkdirs() }
}
}

View File

@ -21,13 +21,22 @@ import eu.kanade.tachiyomi.data.database.queries.HistoryQueries
import eu.kanade.tachiyomi.data.database.queries.MangaCategoryQueries
import eu.kanade.tachiyomi.data.database.queries.MangaQueries
import eu.kanade.tachiyomi.data.database.queries.TrackQueries
import exh.metadata.sql.mappers.SearchMetadataTypeMapping
import exh.metadata.sql.mappers.SearchTagTypeMapping
import exh.metadata.sql.mappers.SearchTitleTypeMapping
import exh.metadata.sql.models.SearchMetadata
import exh.metadata.sql.models.SearchTag
import exh.metadata.sql.models.SearchTitle
import exh.metadata.sql.queries.SearchMetadataQueries
import exh.metadata.sql.queries.SearchTagQueries
import exh.metadata.sql.queries.SearchTitleQueries
import io.requery.android.database.sqlite.RequerySQLiteOpenHelperFactory
/**
* This class provides operations to manage the database through its interfaces.
*/
open class DatabaseHelper(context: Context) :
MangaQueries, ChapterQueries, TrackQueries, CategoryQueries, MangaCategoryQueries, HistoryQueries {
MangaQueries, ChapterQueries, TrackQueries, CategoryQueries, MangaCategoryQueries, HistoryQueries, /* EXH --> */ SearchMetadataQueries, SearchTagQueries, SearchTitleQueries /* EXH <-- */ {
private val configuration = SupportSQLiteOpenHelper.Configuration.builder(context)
.name(DbOpenCallback.DATABASE_NAME)
@ -42,7 +51,14 @@ open class DatabaseHelper(context: Context) :
.addTypeMapping(Category::class.java, CategoryTypeMapping())
.addTypeMapping(MangaCategory::class.java, MangaCategoryTypeMapping())
.addTypeMapping(History::class.java, HistoryTypeMapping())
// EXH -->
.addTypeMapping(SearchMetadata::class.java, SearchMetadataTypeMapping())
.addTypeMapping(SearchTag::class.java, SearchTagTypeMapping())
.addTypeMapping(SearchTitle::class.java, SearchTitleTypeMapping())
// EXH <--
.build()
inline fun inTransaction(block: () -> Unit) = db.inTransaction(block)
fun lowLevel() = db.lowLevel()
}

View File

View File

@ -7,7 +7,11 @@ import eu.kanade.tachiyomi.data.database.tables.ChapterTable
import eu.kanade.tachiyomi.data.database.tables.HistoryTable
import eu.kanade.tachiyomi.data.database.tables.MangaCategoryTable
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 exh.metadata.sql.tables.SearchMetadataTable
import exh.metadata.sql.tables.SearchTagTable
import exh.metadata.sql.tables.SearchTitleTable
class DbOpenCallback : SupportSQLiteOpenHelper.Callback(DATABASE_VERSION) {
@ -20,7 +24,7 @@ class DbOpenCallback : SupportSQLiteOpenHelper.Callback(DATABASE_VERSION) {
/**
* Version of the database.
*/
const val DATABASE_VERSION = 9
const val DATABASE_VERSION = 2 // [SY]
}
override fun onCreate(db: SupportSQLiteDatabase) = with(db) {
@ -30,6 +34,14 @@ class DbOpenCallback : SupportSQLiteOpenHelper.Callback(DATABASE_VERSION) {
execSQL(CategoryTable.createTableQuery)
execSQL(MangaCategoryTable.createTableQuery)
execSQL(HistoryTable.createTableQuery)
// EXH -->
execSQL(SearchMetadataTable.createTableQuery)
execSQL(SearchTagTable.createTableQuery)
execSQL(SearchTitleTable.createTableQuery)
// EXH <--
// AZ -->
execSQL(MergedTable.createTableQuery)
// AZ <--
// DB indexes
execSQL(MangaTable.createUrlIndexQuery)
@ -37,43 +49,22 @@ class DbOpenCallback : SupportSQLiteOpenHelper.Callback(DATABASE_VERSION) {
execSQL(ChapterTable.createMangaIdIndexQuery)
execSQL(ChapterTable.createUnreadChaptersIndexQuery)
execSQL(HistoryTable.createChapterIdIndexQuery)
// EXH -->
db.execSQL(SearchMetadataTable.createUploaderIndexQuery)
db.execSQL(SearchMetadataTable.createIndexedExtraIndexQuery)
db.execSQL(SearchTagTable.createMangaIdIndexQuery)
db.execSQL(SearchTagTable.createNamespaceNameIndexQuery)
db.execSQL(SearchTitleTable.createMangaIdIndexQuery)
db.execSQL(SearchTitleTable.createTitleIndexQuery)
// EXH <--
// AZ -->
execSQL(MergedTable.createIndexQuery)
// AZ <--
}
override fun onUpgrade(db: SupportSQLiteDatabase, oldVersion: Int, newVersion: Int) {
if (oldVersion < 2) {
db.execSQL(ChapterTable.sourceOrderUpdateQuery)
// Fix kissmanga covers after supporting cloudflare
db.execSQL(
"""UPDATE mangas SET thumbnail_url =
REPLACE(thumbnail_url, '93.174.95.110', 'kissmanga.com') WHERE source = 4"""
)
}
if (oldVersion < 3) {
// Initialize history tables
db.execSQL(HistoryTable.createTableQuery)
db.execSQL(HistoryTable.createChapterIdIndexQuery)
}
if (oldVersion < 4) {
db.execSQL(ChapterTable.bookmarkUpdateQuery)
}
if (oldVersion < 5) {
db.execSQL(ChapterTable.addScanlator)
}
if (oldVersion < 6) {
db.execSQL(TrackTable.addTrackingUrl)
}
if (oldVersion < 7) {
db.execSQL(TrackTable.addLibraryId)
}
if (oldVersion < 8) {
db.execSQL("DROP INDEX IF EXISTS mangas_favorite_index")
db.execSQL(MangaTable.createLibraryIndexQuery)
db.execSQL(ChapterTable.createUnreadChaptersIndexQuery)
}
if (oldVersion < 9) {
db.execSQL(TrackTable.addStartDate)
db.execSQL(TrackTable.addFinishDate)
db.execSQL(MangaTable.addCoverLastModified)
}
}

View File

View File

@ -13,6 +13,7 @@ import eu.kanade.tachiyomi.data.database.models.Category
import eu.kanade.tachiyomi.data.database.models.CategoryImpl
import eu.kanade.tachiyomi.data.database.tables.CategoryTable.COL_FLAGS
import eu.kanade.tachiyomi.data.database.tables.CategoryTable.COL_ID
import eu.kanade.tachiyomi.data.database.tables.CategoryTable.COL_MANGA_ORDER
import eu.kanade.tachiyomi.data.database.tables.CategoryTable.COL_NAME
import eu.kanade.tachiyomi.data.database.tables.CategoryTable.COL_ORDER
import eu.kanade.tachiyomi.data.database.tables.CategoryTable.TABLE
@ -40,6 +41,8 @@ class CategoryPutResolver : DefaultPutResolver<Category>() {
put(COL_NAME, obj.name)
put(COL_ORDER, obj.order)
put(COL_FLAGS, obj.flags)
val orderString = obj.mangaOrder.joinToString("/")
put(COL_MANGA_ORDER, orderString)
}
}
@ -50,6 +53,9 @@ class CategoryGetResolver : DefaultGetResolver<Category>() {
name = cursor.getString(cursor.getColumnIndex(COL_NAME))
order = cursor.getInt(cursor.getColumnIndex(COL_ORDER))
flags = cursor.getInt(cursor.getColumnIndex(COL_FLAGS))
val orderString = cursor.getString(cursor.getColumnIndex(COL_MANGA_ORDER))
mangaOrder = orderString?.split("/")?.mapNotNull { it.toLongOrNull() } ?: emptyList()
}
}

View File

@ -14,6 +14,7 @@ import eu.kanade.tachiyomi.data.database.models.MangaImpl
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_CHAPTER_FLAGS
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_COVER_LAST_MODIFIED
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_GENRE
@ -62,6 +63,7 @@ class MangaPutResolver : DefaultPutResolver<Manga>() {
put(COL_INITIALIZED, obj.initialized)
put(COL_VIEWER, obj.viewer)
put(COL_CHAPTER_FLAGS, obj.chapter_flags)
put(COL_COVER_LAST_MODIFIED, obj.cover_last_modified)
}
}
@ -82,6 +84,7 @@ interface BaseMangaGetResolver {
initialized = cursor.getInt(cursor.getColumnIndex(COL_INITIALIZED)) == 1
viewer = cursor.getInt(cursor.getColumnIndex(COL_VIEWER))
chapter_flags = cursor.getInt(cursor.getColumnIndex(COL_CHAPTER_FLAGS))
cover_last_modified = cursor.getLong(cursor.getColumnIndex(COL_COVER_LAST_MODIFIED))
}
}

View File

@ -12,6 +12,8 @@ interface Category : Serializable {
var flags: Int
var mangaOrder: List<Long>
val nameLower: String
get() = name.toLowerCase()

View File

@ -10,6 +10,8 @@ class CategoryImpl : Category {
override var flags: Int = 0
override var mangaOrder: List<Long> = emptyList()
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || javaClass != other.javaClass) return false

View File

View File

View File

@ -16,6 +16,8 @@ interface Manga : SManga {
var chapter_flags: Int
var cover_last_modified: Long
fun setChapterOrder(order: Int) {
setFlags(order, SORT_MASK)
}
@ -76,7 +78,8 @@ interface Manga : SManga {
const val SORTING_SOURCE = 0x00000000
const val SORTING_NUMBER = 0x00000100
const val SORTING_MASK = 0x00000100
const val SORTING_UPLOAD_DATE = 0x00000200
const val SORTING_MASK = 0x00000300
const val DISPLAY_NAME = 0x00000000
const val DISPLAY_NUMBER = 0x00100000

View File

@ -8,7 +8,7 @@ open class MangaImpl : Manga {
override lateinit var url: String
override lateinit var title: String
override var title: String = ""
override var artist: String? = null
@ -32,6 +32,8 @@ open class MangaImpl : Manga {
override var chapter_flags: Int = 0
override var cover_last_modified: Long = 0
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || javaClass != other.javaClass) return false

View File

View File

@ -15,13 +15,24 @@ import java.util.Date
interface ChapterQueries : DbProvider {
fun getChapters(manga: Manga) = db.get()
fun getChapters(manga: Manga) = getChaptersByMangaId(manga.id)
fun getChaptersByMangaId(mangaId: Long?) = db.get()
.listOfObjects(Chapter::class.java)
.withQuery(
Query.builder()
.table(ChapterTable.TABLE)
.where("${ChapterTable.COL_MANGA_ID} = ?")
.whereArgs(manga.id)
.whereArgs(mangaId)
.build()
)
.prepare()
fun getChaptersByMergedMangaId(mangaId: Long) = db.get()
.listOfObjects(Chapter::class.java)
.withQuery(
RawQuery.builder()
.query(getMergedChaptersQuery(mangaId))
.build()
)
.prepare()
@ -71,6 +82,17 @@ interface ChapterQueries : DbProvider {
)
.prepare()
fun getChapters(url: String) = db.get()
.listOfObjects(Chapter::class.java)
.withQuery(
Query.builder()
.table(ChapterTable.TABLE)
.where("${ChapterTable.COL_URL} = ?")
.whereArgs(url)
.build()
)
.prepare()
fun insertChapter(chapter: Chapter) = db.put().`object`(chapter).prepare()
fun insertChapters(chapters: List<Chapter>) = db.put().objects(chapters).prepare()

View File

@ -22,11 +22,28 @@ interface HistoryQueries : DbProvider {
* Returns history of recent manga containing last read chapter
* @param date recent date range
*/
fun getRecentManga(date: Date) = db.get()
fun getRecentManga(date: Date, offset: Int = 0, search: String = "") = db.get()
.listOfObjects(MangaChapterHistory::class.java)
.withQuery(
RawQuery.builder()
.query(getRecentMangasQuery())
.query(getRecentMangasQuery(offset, search))
.args(date.time)
.observesTables(HistoryTable.TABLE)
.build()
)
.withGetResolver(MangaChapterHistoryGetResolver.INSTANCE)
.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()

View File

@ -26,8 +26,12 @@ interface MangaCategoryQueries : DbProvider {
fun setMangaCategories(mangasCategories: List<MangaCategory>, mangas: List<Manga>) {
db.inTransaction {
deleteOldMangasCategories(mangas).executeAsBlocking()
insertMangasCategories(mangasCategories).executeAsBlocking()
mangas.chunked(100) { chunk ->
deleteOldMangasCategories(chunk).executeAsBlocking()
}
mangasCategories.chunked(100) { chunk ->
insertMangasCategories(chunk).executeAsBlocking()
}
}
}
}

View File

@ -7,6 +7,7 @@ import eu.kanade.tachiyomi.data.database.DbProvider
import eu.kanade.tachiyomi.data.database.models.LibraryManga
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.database.resolvers.LibraryMangaGetResolver
import eu.kanade.tachiyomi.data.database.resolvers.MangaCoverLastModifiedPutResolver
import eu.kanade.tachiyomi.data.database.resolvers.MangaFavoritePutResolver
import eu.kanade.tachiyomi.data.database.resolvers.MangaFlagsPutResolver
import eu.kanade.tachiyomi.data.database.resolvers.MangaLastUpdatedPutResolver
@ -16,6 +17,7 @@ import eu.kanade.tachiyomi.data.database.tables.CategoryTable
import eu.kanade.tachiyomi.data.database.tables.ChapterTable
import eu.kanade.tachiyomi.data.database.tables.MangaCategoryTable
import eu.kanade.tachiyomi.data.database.tables.MangaTable
import exh.metadata.sql.tables.SearchMetadataTable
interface MangaQueries : DbProvider {
@ -73,6 +75,15 @@ interface MangaQueries : DbProvider {
)
.prepare()
fun getMergedMangas(id: Long) = db.get()
.listOfObjects(Manga::class.java)
.withQuery(
RawQuery.builder()
.query(getMergedMangaQuery(id))
.build()
)
.prepare()
fun insertManga(manga: Manga) = db.put().`object`(manga).prepare()
fun insertMangas(mangas: List<Manga>) = db.put().objects(mangas).prepare()
@ -102,6 +113,11 @@ interface MangaQueries : DbProvider {
.withPutResolver(MangaTitlePutResolver())
.prepare()
fun updateMangaCoverLastModified(manga: Manga) = db.put()
.`object`(manga)
.withPutResolver(MangaCoverLastModifiedPutResolver())
.prepare()
fun deleteManga(manga: Manga) = db.delete().`object`(manga).prepare()
fun deleteMangas(mangas: List<Manga>) = db.delete().objects(mangas).prepare()
@ -153,4 +169,54 @@ interface MangaQueries : DbProvider {
.build()
)
.prepare()
fun getMangaWithMetadata() = db.get()
.listOfObjects(Manga::class.java)
.withQuery(
RawQuery.builder()
.query(
"""
SELECT ${MangaTable.TABLE}.* FROM ${MangaTable.TABLE}
INNER JOIN ${SearchMetadataTable.TABLE}
ON ${MangaTable.TABLE}.${MangaTable.COL_ID} = ${SearchMetadataTable.TABLE}.${SearchMetadataTable.COL_MANGA_ID}
ORDER BY ${MangaTable.TABLE}.${MangaTable.COL_ID}
""".trimIndent()
)
.build()
)
.prepare()
fun getFavoriteMangaWithMetadata() = db.get()
.listOfObjects(Manga::class.java)
.withQuery(
RawQuery.builder()
.query(
"""
SELECT ${MangaTable.TABLE}.* FROM ${MangaTable.TABLE}
INNER JOIN ${SearchMetadataTable.TABLE}
ON ${MangaTable.TABLE}.${MangaTable.COL_ID} = ${SearchMetadataTable.TABLE}.${SearchMetadataTable.COL_MANGA_ID}
WHERE ${MangaTable.TABLE}.${MangaTable.COL_FAVORITE} = 1
ORDER BY ${MangaTable.TABLE}.${MangaTable.COL_ID}
""".trimIndent()
)
.build()
)
.prepare()
fun getIdsOfFavoriteMangaWithMetadata() = db.get()
.cursor()
.withQuery(
RawQuery.builder()
.query(
"""
SELECT ${MangaTable.TABLE}.${MangaTable.COL_ID} FROM ${MangaTable.TABLE}
INNER JOIN ${SearchMetadataTable.TABLE}
ON ${MangaTable.TABLE}.${MangaTable.COL_ID} = ${SearchMetadataTable.TABLE}.${SearchMetadataTable.COL_MANGA_ID}
WHERE ${MangaTable.TABLE}.${MangaTable.COL_FAVORITE} = 1
ORDER BY ${MangaTable.TABLE}.${MangaTable.COL_ID}
""".trimIndent()
)
.build()
)
.prepare()
}

View File

@ -5,6 +5,33 @@ 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.MangaCategoryTable as MangaCategory
import eu.kanade.tachiyomi.data.database.tables.MangaTable as Manga
import eu.kanade.tachiyomi.data.database.tables.MergedTable as Merged
/**
* Query to get the manga merged into a merged manga
*/
fun getMergedMangaQuery(id: Long) =
"""
SELECT ${Manga.TABLE}.*
FROM (
SELECT ${Merged.COL_MANGA_ID} FROM ${Merged.TABLE} WHERE $(Merged.COL_MERGE_ID} = $id
) AS M
JOIN ${Manga.TABLE}
ON ${Manga.TABLE}.${Manga.COL_ID} = M.${Merged.COL_MANGA_ID}
"""
/**
* Query to get the chapters of all manga in a merged manga
*/
fun getMergedChaptersQuery(id: Long) =
"""
SELECT ${Chapter.TABLE}.*
FROM (
SELECT ${Merged.COL_MANGA_ID} FROM ${Merged.TABLE} WHERE $(Merged.COL_MERGE_ID} = $id
) AS M
JOIN ${Chapter.TABLE}
ON ${Chapter.TABLE}.${Chapter.COL_MANGA_ID} = M.${Merged.COL_MANGA_ID}
"""
/**
* Query to get the manga from the library, with their categories and unread count.
@ -49,7 +76,7 @@ fun getRecentsQuery() =
* and are read after the given time period
* @return return limit is 25
*/
fun getRecentMangasQuery() =
fun getRecentMangasQuery(offset: Int = 0, search: String = "") =
"""
SELECT ${Manga.TABLE}.${Manga.COL_URL} as mangaUrl, ${Manga.TABLE}.*, ${Chapter.TABLE}.*, ${History.TABLE}.*
FROM ${Manga.TABLE}
@ -64,8 +91,36 @@ fun getRecentMangasQuery() =
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
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}.*
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 $limit
"""
fun getHistoryByMangaId() =

View File

@ -0,0 +1,31 @@
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 MangaCoverLastModifiedPutResolver : 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_COVER_LAST_MODIFIED, manga.cover_last_modified)
}
}

View File

@ -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)
}
}

View File

@ -12,12 +12,18 @@ object CategoryTable {
const val COL_FLAGS = "flags"
const val COL_MANGA_ORDER = "manga_order"
val createTableQuery: String
get() =
"""CREATE TABLE $TABLE(
$COL_ID INTEGER NOT NULL PRIMARY KEY,
$COL_NAME TEXT NOT NULL,
$COL_ORDER INTEGER NOT NULL,
$COL_FLAGS INTEGER NOT NULL
$COL_FLAGS INTEGER NOT NULL,
$COL_MANGA_ORDER TEXT NOT NULL
)"""
val addMangaOrder: String
get() = "ALTER TABLE $TABLE ADD COLUMN $COL_MANGA_ORDER TEXT"
}

View File

@ -38,6 +38,8 @@ object MangaTable {
const val COL_CATEGORY = "category"
const val COL_COVER_LAST_MODIFIED = "cover_last_modified"
val createTableQuery: String
get() =
"""CREATE TABLE $TABLE(
@ -55,7 +57,8 @@ object MangaTable {
$COL_LAST_UPDATE LONG,
$COL_INITIALIZED BOOLEAN 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
)"""
val createUrlIndexQuery: String
@ -64,4 +67,7 @@ object MangaTable {
val createLibraryIndexQuery: String
get() = "CREATE INDEX library_${COL_FAVORITE}_index ON $TABLE($COL_FAVORITE) " +
"WHERE $COL_FAVORITE = 1"
val addCoverLastModified: String
get() = "ALTER TABLE $TABLE ADD COLUMN $COL_COVER_LAST_MODIFIED LONG NOT NULL DEFAULT 0"
}

View File

@ -0,0 +1,20 @@
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)"
}

View File

@ -11,6 +11,7 @@ import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.source.model.Page
import rx.Observable
import timber.log.Timber
import uy.kohesive.injekt.injectLazy
/**
@ -239,4 +240,26 @@ class DownloadManager(private val context: Context) {
deleteChapters(chapters, manga, source)
}
}
/**
* Renames an already downloaded chapter
*
* @param source the source of the manga.
* @param manga the manga of the chapter.
* @param oldChapter the existing chapter with the old name.
* @param newChapter the target chapter with the new name.
*/
fun renameChapter(source: Source, manga: Manga, oldChapter: Chapter, newChapter: Chapter) {
val oldName = provider.getChapterDirName(oldChapter)
val newName = provider.getChapterDirName(newChapter)
val mangaDir = provider.getMangaDir(manga, source)
val oldFolder = mangaDir.findFile(oldName)
if (oldFolder?.renameTo(newName) == true) {
cache.removeChapter(oldChapter, manga)
cache.addChapter(newName, mangaDir, manga)
} else {
Timber.e("Could not rename downloaded chapter: %s.", oldName)
}
}
}

View File

@ -94,8 +94,9 @@ internal class DownloadNotifier(private val context: Context) {
)
}
val downloadingProgressText = context.getString(R.string.chapter_downloading_progress)
.format(download.downloadedImages, download.pages!!.size)
val downloadingProgressText = context.getString(
R.string.chapter_downloading_progress, download.downloadedImages, download.pages!!.size
)
if (preferences.hideNotificationContent()) {
setContentTitle(downloadingProgressText)

View File

@ -16,9 +16,9 @@ import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.notification.Notifications
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.util.lang.plusAssign
import eu.kanade.tachiyomi.util.system.acquireWakeLock
import eu.kanade.tachiyomi.util.system.connectivityManager
import eu.kanade.tachiyomi.util.system.notification
import eu.kanade.tachiyomi.util.system.powerManager
import eu.kanade.tachiyomi.util.system.toast
import rx.android.schedulers.AndroidSchedulers
import rx.schedulers.Schedulers
@ -70,9 +70,7 @@ class DownloadService : Service() {
/**
* Wake lock to prevent the device to enter sleep mode.
*/
private val wakeLock by lazy {
powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "DownloadService:WakeLock")
}
private lateinit var wakeLock: PowerManager.WakeLock
/**
* Subscriptions to store while the service is running.
@ -85,6 +83,7 @@ class DownloadService : Service() {
override fun onCreate() {
super.onCreate()
startForeground(Notifications.ID_DOWNLOAD_CHAPTER, getPlaceholderNotification())
wakeLock = acquireWakeLock(javaClass.name)
runningRelay.call(true)
subscriptions = CompositeSubscription()
listenDownloaderState()

View File

View File

@ -181,7 +181,16 @@ class Downloader(
subscriptions.clear()
subscriptions += downloadsRelay.concatMapIterable { it }
.concatMap { downloadChapter(it).subscribeOn(Schedulers.io()) }
// Concurrently download from 5 different sources
.groupBy { it.source }
.flatMap(
{ bySource ->
bySource.concatMap { download ->
downloadChapter(download).subscribeOn(Schedulers.io())
}
},
5
)
.onBackpressureBuffer()
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
@ -289,7 +298,8 @@ class Downloader(
// Get all the URLs to the source images, fetch pages if necessary
.flatMap { download.source.fetchAllImageUrlsFromPageList(it) }
// Start downloading images, consider we can have downloaded images already
.concatMap { page -> getOrDownloadImage(page, download, tmpDir) }
// Concurrently do 5 pages at a time
.flatMap({ page -> getOrDownloadImage(page, download, tmpDir) }, 5)
// Do when page is downloaded.
.doOnNext { notifier.onProgressChange(download) }
.toList()

View File

View File

@ -12,7 +12,7 @@ import java.io.IOException
import java.io.InputStream
import timber.log.Timber
open class FileFetcher(private val file: File) : DataFetcher<InputStream> {
open class FileFetcher(private val filePath: String = "") : DataFetcher<InputStream> {
private var data: InputStream? = null
@ -20,7 +20,11 @@ open class FileFetcher(private val file: File) : DataFetcher<InputStream> {
loadFromFile(callback)
}
protected fun loadFromFile(callback: DataFetcher.DataCallback<in InputStream>) {
private fun loadFromFile(callback: DataFetcher.DataCallback<in InputStream>) {
loadFromFile(File(filePath), callback)
}
protected fun loadFromFile(file: File, callback: DataFetcher.DataCallback<in InputStream>) {
try {
data = FileInputStream(file)
} catch (e: FileNotFoundException) {

View File

@ -0,0 +1,25 @@
package eu.kanade.tachiyomi.data.glide
import com.bumptech.glide.Priority
import com.bumptech.glide.load.data.DataFetcher
import eu.kanade.tachiyomi.data.cache.CoverCache
import eu.kanade.tachiyomi.data.database.models.Manga
import java.io.File
import java.io.InputStream
import java.lang.Exception
open class LibraryMangaCustomCoverFetcher(
private val manga: Manga,
private val coverCache: CoverCache
) : FileFetcher() {
override fun loadData(priority: Priority, callback: DataFetcher.DataCallback<in InputStream>) {
getCustomCoverFile()?.let {
loadFromFile(it, callback)
} ?: callback.onLoadFailed(Exception("Custom cover file not found"))
}
protected fun getCustomCoverFile(): File? {
return coverCache.getCustomCoverFile(manga).takeIf { it.exists() }
}
}

View File

@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.data.glide
import com.bumptech.glide.Priority
import com.bumptech.glide.load.data.DataFetcher
import eu.kanade.tachiyomi.data.cache.CoverCache
import eu.kanade.tachiyomi.data.database.models.Manga
import java.io.File
import java.io.FileNotFoundException
@ -19,31 +20,41 @@ import java.io.InputStream
class LibraryMangaUrlFetcher(
private val networkFetcher: DataFetcher<InputStream>,
private val manga: Manga,
private val file: File
) :
FileFetcher(file) {
private val coverCache: CoverCache
) : LibraryMangaCustomCoverFetcher(manga, coverCache) {
override fun loadData(priority: Priority, callback: DataFetcher.DataCallback<in InputStream>) {
if (!file.exists()) {
getCustomCoverFile()?.let {
loadFromFile(it, callback)
return
}
val cover = coverCache.getCoverFile(manga)
if (cover == null) {
callback.onLoadFailed(Exception("Null thumbnail url"))
return
}
if (!cover.exists()) {
networkFetcher.loadData(
priority,
object : DataFetcher.DataCallback<InputStream> {
override fun onDataReady(data: InputStream?) {
if (data != null) {
val tmpFile = File(file.path + ".tmp")
val tmpFile = File(cover.path + ".tmp")
try {
// Retrieve destination stream, create parent folders if needed.
val output = try {
tmpFile.outputStream()
} catch (e: FileNotFoundException) {
tmpFile.parentFile.mkdirs()
tmpFile.parentFile!!.mkdirs()
tmpFile.outputStream()
}
// Copy the file and rename to the original.
data.use { output.use { data.copyTo(output) } }
tmpFile.renameTo(file)
loadFromFile(callback)
tmpFile.renameTo(cover)
loadFromFile(cover, callback)
} catch (e: Exception) {
tmpFile.delete()
callback.onLoadFailed(e)
@ -59,7 +70,7 @@ class LibraryMangaUrlFetcher(
}
)
} else {
loadFromFile(callback)
loadFromFile(cover, callback)
}
}

View File

@ -1,27 +0,0 @@
package eu.kanade.tachiyomi.data.glide
import com.bumptech.glide.load.Key
import eu.kanade.tachiyomi.data.database.models.Manga
import java.io.File
import java.security.MessageDigest
class MangaSignature(manga: Manga, file: File) : Key {
private val key = manga.thumbnail_url + file.lastModified()
override fun equals(other: Any?): Boolean {
return if (other is MangaSignature) {
key == other.key
} else {
false
}
}
override fun hashCode(): Int {
return key.hashCode()
}
override fun updateDiskCacheKey(md: MessageDigest) {
md.update(key.toByteArray(Key.CHARSET))
}
}

View File

@ -1,7 +1,15 @@
package eu.kanade.tachiyomi.data.glide
import com.bumptech.glide.load.Key
import eu.kanade.tachiyomi.data.database.models.Manga
import java.security.MessageDigest
data class MangaThumbnail(val manga: Manga, val url: String?)
data class MangaThumbnail(val manga: Manga, val coverLastModified: Long) : Key {
val key = manga.url + coverLastModified
fun Manga.toMangaThumbnail() = MangaThumbnail(this, this.thumbnail_url)
override fun updateDiskCacheKey(messageDigest: MessageDigest) {
messageDigest.update(key.toByteArray(Key.CHARSET))
}
}
fun Manga.toMangaThumbnail() = MangaThumbnail(this, cover_last_modified)

View File

@ -1,6 +1,5 @@
package eu.kanade.tachiyomi.data.glide
import android.util.LruCache
import com.bumptech.glide.integration.okhttp3.OkHttpStreamFetcher
import com.bumptech.glide.load.Options
import com.bumptech.glide.load.model.GlideUrl
@ -14,7 +13,7 @@ import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.network.NetworkHelper
import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.source.online.HttpSource
import java.io.File
import eu.kanade.tachiyomi.util.isLocal
import java.io.InputStream
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
@ -48,12 +47,6 @@ class MangaThumbnailModelLoader : ModelLoader<MangaThumbnail, InputStream> {
*/
private val defaultClient = Injekt.get<NetworkHelper>().client
/**
* LRU cache whose key is the thumbnail url of the manga, and the value contains the request url
* and the file where it should be stored in case the manga is a favorite.
*/
private val lruCache = LruCache<GlideUrl, File>(100)
/**
* Map where request headers are stored for a source.
*/
@ -78,7 +71,7 @@ class MangaThumbnailModelLoader : ModelLoader<MangaThumbnail, InputStream> {
/**
* Returns a fetcher for the given manga or null if the url is empty.
*
* @param manga the model.
* @param mangaThumbnail the model.
* @param width the width of the view where the resource will be loaded.
* @param height the height of the view where the resource will be loaded.
*/
@ -88,13 +81,16 @@ class MangaThumbnailModelLoader : ModelLoader<MangaThumbnail, InputStream> {
height: Int,
options: Options
): ModelLoader.LoadData<InputStream>? {
// Check thumbnail is not null or empty
val url = mangaThumbnail.url
if (url == null || url.isEmpty()) {
return null
}
val manga = mangaThumbnail.manga
val url = manga.thumbnail_url
if (url.isNullOrEmpty()) {
return if (!manga.favorite || manga.isLocal()) {
null
} else {
ModelLoader.LoadData(mangaThumbnail, LibraryMangaCustomCoverFetcher(manga, coverCache))
}
}
if (url.startsWith("http", true)) {
val source = sourceManager.get(manga.source) as? HttpSource
@ -107,19 +103,13 @@ class MangaThumbnailModelLoader : ModelLoader<MangaThumbnail, InputStream> {
return ModelLoader.LoadData(glideUrl, networkFetcher)
}
// Obtain the file for this url from the LRU cache, or retrieve and add it to the cache.
val file = lruCache.getOrPut(glideUrl) { coverCache.getCoverFile(url) }
val libraryFetcher = LibraryMangaUrlFetcher(networkFetcher, manga, file)
val libraryFetcher = LibraryMangaUrlFetcher(networkFetcher, manga, coverCache)
// Return an instance of the fetcher providing the needed elements.
return ModelLoader.LoadData(MangaSignature(manga, file), libraryFetcher)
return ModelLoader.LoadData(mangaThumbnail, libraryFetcher)
} else {
// Get the file from the url, removing the scheme if present.
val file = File(url.substringAfter("file://"))
// Return an instance of the fetcher providing the needed elements.
return ModelLoader.LoadData(MangaSignature(manga, file), FileFetcher(file))
return ModelLoader.LoadData(mangaThumbnail, FileFetcher(url.removePrefix("file://")))
}
}
@ -141,15 +131,4 @@ class MangaThumbnailModelLoader : ModelLoader<MangaThumbnail, InputStream> {
}.build()
}
}
private inline fun <K, V> LruCache<K, V>.getOrPut(key: K, defaultValue: () -> V): V {
val value = get(key)
return if (value == null) {
val answer = defaultValue()
put(key, answer)
answer
} else {
value
}
}
}

View File

@ -36,12 +36,20 @@ class TachiGlideModule : AppGlideModule() {
override fun registerComponents(context: Context, glide: Glide, registry: Registry) {
val networkFactory = OkHttpUrlLoader.Factory(Injekt.get<NetworkHelper>().client)
registry.replace(GlideUrl::class.java, InputStream::class.java, networkFactory)
registry.append(MangaThumbnail::class.java, InputStream::class.java, MangaThumbnailModelLoader.Factory())
registry.replace(
GlideUrl::class.java,
InputStream::class.java,
networkFactory
)
registry.append(
InputStream::class.java, InputStream::class.java,
PassthroughModelLoader
.Factory()
MangaThumbnail::class.java,
InputStream::class.java,
MangaThumbnailModelLoader.Factory()
)
registry.append(
InputStream::class.java,
InputStream::class.java,
PassthroughModelLoader.Factory()
)
}
}

View File

@ -17,8 +17,11 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
Worker(context, workerParams) {
override fun doWork(): Result {
LibraryUpdateService.start(context)
return Result.success()
return if (LibraryUpdateService.start(context)) {
Result.success()
} else {
Result.failure()
}
}
companion object {

View File

@ -0,0 +1,302 @@
package eu.kanade.tachiyomi.data.library
import android.app.Notification
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.net.Uri
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import com.bumptech.glide.Glide
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.models.Chapter
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.glide.toMangaThumbnail
import eu.kanade.tachiyomi.data.notification.NotificationReceiver
import eu.kanade.tachiyomi.data.notification.Notifications
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.ui.main.MainActivity
import eu.kanade.tachiyomi.util.lang.chop
import eu.kanade.tachiyomi.util.system.notification
import eu.kanade.tachiyomi.util.system.notificationBuilder
import eu.kanade.tachiyomi.util.system.notificationManager
import java.text.DecimalFormat
import java.text.DecimalFormatSymbols
import uy.kohesive.injekt.injectLazy
class LibraryUpdateNotifier(private val context: Context) {
private val preferences: PreferencesHelper by injectLazy()
/**
* Pending intent of action that cancels the library update
*/
private val cancelIntent by lazy {
NotificationReceiver.cancelLibraryUpdatePendingBroadcast(context)
}
/**
* Bitmap of the app for notifications.
*/
private val notificationBitmap by lazy {
BitmapFactory.decodeResource(context.resources, R.mipmap.ic_launcher)
}
/**
* Cached progress notification to avoid creating a lot.
*/
val progressNotificationBuilder by lazy {
context.notificationBuilder(Notifications.CHANNEL_LIBRARY) {
setContentTitle(context.getString(R.string.app_name))
setSmallIcon(R.drawable.ic_refresh_24dp)
setLargeIcon(notificationBitmap)
setOngoing(true)
setOnlyAlertOnce(true)
addAction(R.drawable.ic_close_24dp, context.getString(android.R.string.cancel), cancelIntent)
}
}
/**
* Shows the notification containing the currently updating manga and the progress.
*
* @param manga the manga that's being updated.
* @param current the current progress.
* @param total the total progress.
*/
fun showProgressNotification(manga: Manga, current: Int, total: Int) {
val title = if (preferences.hideNotificationContent()) {
context.getString(R.string.notification_check_updates)
} else {
manga.title
}
context.notificationManager.notify(
Notifications.ID_LIBRARY_PROGRESS,
progressNotificationBuilder
.setContentTitle(title)
.setProgress(total, current, false)
.build()
)
}
/**
* Shows notification containing update entries that failed with action to open full log.
*
* @param errors List of entry titles that failed to update.
* @param uri Uri for error log file containing all titles that failed.
*/
fun showUpdateErrorNotification(errors: List<String>, uri: Uri) {
if (errors.isEmpty()) {
return
}
context.notificationManager.notify(
Notifications.ID_LIBRARY_ERROR,
context.notificationBuilder(Notifications.CHANNEL_LIBRARY) {
setContentTitle(context.resources.getQuantityString(R.plurals.notification_update_error, errors.size, errors.size))
setStyle(
NotificationCompat.BigTextStyle().bigText(
errors.joinToString("\n") {
it.chop(NOTIF_TITLE_MAX_LEN)
}
)
)
setSmallIcon(R.drawable.ic_tachi)
addAction(
R.drawable.nnf_ic_file_folder,
context.getString(R.string.action_open_log),
NotificationReceiver.openErrorLogPendingActivity(context, uri)
)
}
.build()
)
}
/**
* Shows the notification containing the result of the update done by the service.
*
* @param updates a list of manga with new updates.
*/
fun showUpdateNotifications(updates: List<Pair<Manga, Array<Chapter>>>) {
if (updates.isEmpty()) {
return
}
NotificationManagerCompat.from(context).apply {
// Parent group notification
notify(
Notifications.ID_NEW_CHAPTERS,
context.notification(Notifications.CHANNEL_NEW_CHAPTERS) {
setContentTitle(context.getString(R.string.notification_new_chapters))
if (updates.size == 1 && !preferences.hideNotificationContent()) {
setContentText(updates.first().first.title.chop(NOTIF_TITLE_MAX_LEN))
} else {
setContentText(context.resources.getQuantityString(R.plurals.notification_new_chapters_summary, updates.size, updates.size))
if (!preferences.hideNotificationContent()) {
setStyle(
NotificationCompat.BigTextStyle().bigText(
updates.joinToString("\n") {
it.first.title.chop(NOTIF_TITLE_MAX_LEN)
}
)
)
}
}
setSmallIcon(R.drawable.ic_tachi)
setLargeIcon(notificationBitmap)
setGroup(Notifications.GROUP_NEW_CHAPTERS)
setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_SUMMARY)
setGroupSummary(true)
priority = NotificationCompat.PRIORITY_HIGH
setContentIntent(getNotificationIntent())
setAutoCancel(true)
}
)
// Per-manga notification
if (!preferences.hideNotificationContent()) {
updates.forEach {
val (manga, chapters) = it
notify(manga.id.hashCode(), createNewChaptersNotification(manga, chapters))
}
}
}
}
private fun createNewChaptersNotification(manga: Manga, chapters: Array<Chapter>): Notification {
return context.notification(Notifications.CHANNEL_NEW_CHAPTERS) {
setContentTitle(manga.title)
val description = getNewChaptersDescription(chapters)
setContentText(description)
setStyle(NotificationCompat.BigTextStyle().bigText(description))
setSmallIcon(R.drawable.ic_tachi)
val icon = getMangaIcon(manga)
if (icon != null) {
setLargeIcon(icon)
}
setGroup(Notifications.GROUP_NEW_CHAPTERS)
setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_SUMMARY)
priority = NotificationCompat.PRIORITY_HIGH
// Open first chapter on tap
setContentIntent(NotificationReceiver.openChapterPendingActivity(context, manga, chapters.first()))
setAutoCancel(true)
// Mark chapters as read action
addAction(
R.drawable.ic_glasses_black_24dp, context.getString(R.string.action_mark_as_read),
NotificationReceiver.markAsReadPendingBroadcast(
context,
manga, chapters, Notifications.ID_NEW_CHAPTERS
)
)
// View chapters action
addAction(
R.drawable.ic_book_24dp, context.getString(R.string.action_view_chapters),
NotificationReceiver.openChapterPendingActivity(
context,
manga, Notifications.ID_NEW_CHAPTERS
)
)
}
}
/**
* Cancels the progress notification.
*/
fun cancelProgressNotification() {
context.notificationManager.cancel(Notifications.ID_LIBRARY_PROGRESS)
}
private fun getMangaIcon(manga: Manga): Bitmap? {
return try {
Glide.with(context)
.asBitmap()
.load(manga.toMangaThumbnail())
.dontTransform()
.centerCrop()
.circleCrop()
.override(
NOTIF_ICON_SIZE,
NOTIF_ICON_SIZE
)
.submit()
.get()
} catch (e: Exception) {
null
}
}
private fun getNewChaptersDescription(chapters: Array<Chapter>): String {
val formatter = DecimalFormat(
"#.###",
DecimalFormatSymbols()
.apply { decimalSeparator = '.' }
)
val displayableChapterNumbers = chapters
.filter { it.isRecognizedNumber }
.sortedBy { it.chapter_number }
.map { formatter.format(it.chapter_number) }
.toSet()
return when (displayableChapterNumbers.size) {
// No sensible chapter numbers to show (i.e. no chapters have parsed chapter number)
0 -> {
// "1 new chapter" or "5 new chapters"
context.resources.getQuantityString(R.plurals.notification_chapters_generic, chapters.size, chapters.size)
}
// Only 1 chapter has a parsed chapter number
1 -> {
val remaining = chapters.size - displayableChapterNumbers.size
if (remaining == 0) {
// "Chapter 2.5"
context.resources.getString(R.string.notification_chapters_single, displayableChapterNumbers.first())
} else {
// "Chapter 2.5 and 10 more"
context.resources.getString(R.string.notification_chapters_single_and_more, displayableChapterNumbers.first(), remaining)
}
}
// Everything else (i.e. multiple parsed chapter numbers)
else -> {
val shouldTruncate = displayableChapterNumbers.size > NOTIF_MAX_CHAPTERS
if (shouldTruncate) {
// "Chapters 1, 2.5, 3, 4, 5 and 10 more"
val remaining = displayableChapterNumbers.size - NOTIF_MAX_CHAPTERS
val joinedChapterNumbers = displayableChapterNumbers.take(NOTIF_MAX_CHAPTERS).joinToString(", ")
context.resources.getQuantityString(R.plurals.notification_chapters_multiple_and_more, remaining, joinedChapterNumbers, remaining)
} else {
// "Chapters 1, 2.5, 3"
context.resources.getString(R.string.notification_chapters_multiple, displayableChapterNumbers.joinToString(", "))
}
}
}
}
/**
* Returns an intent to open the main activity.
*/
private fun getNotificationIntent(): PendingIntent {
val intent = Intent(context, MainActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
action = MainActivity.SHORTCUT_RECENTLY_UPDATED
}
return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
companion object {
private const val NOTIF_MAX_CHAPTERS = 5
private const val NOTIF_TITLE_MAX_LEN = 45
private const val NOTIF_ICON_SIZE = 192
}
}

View File

@ -3,7 +3,7 @@ package eu.kanade.tachiyomi.data.library
import eu.kanade.tachiyomi.data.database.models.Manga
/**
* This class will provide various functions to Rank mangas to efficiently schedule mangas to update.
* This class will provide various functions to rank manga to efficiently schedule manga to update.
*/
object LibraryUpdateRanker {
@ -13,7 +13,7 @@ object LibraryUpdateRanker {
)
/**
* Provides a total ordering over all the Mangas.
* Provides a total ordering over all the [Manga]s.
*
* Assumption: An active [Manga] mActive is expected to have been last updated after an
* inactive [Manga] mInactive.
@ -21,23 +21,19 @@ object LibraryUpdateRanker {
* Using this insight, function returns a Comparator for which mActive appears before mInactive.
* @return a Comparator that ranks manga based on relevance.
*/
fun latestFirstRanking(): Comparator<Manga> {
return Comparator { mangaFirst: Manga,
mangaSecond: Manga ->
compareValues(mangaSecond.last_update, mangaFirst.last_update)
private fun latestFirstRanking(): Comparator<Manga> =
Comparator { first: Manga, second: Manga ->
compareValues(second.last_update, first.last_update)
}
}
/**
* Provides a total ordering over all the Mangas.
* Provides a total ordering over all the [Manga]s.
*
* Order the manga lexicographically.
* @return a Comparator that ranks manga lexicographically based on the title.
*/
fun lexicographicRanking(): Comparator<Manga> {
return Comparator { mangaFirst: Manga,
mangaSecond: Manga ->
compareValues(mangaFirst.title, mangaSecond.title)
private fun lexicographicRanking(): Comparator<Manga> =
Comparator { first: Manga, second: Manga ->
compareValues(first.title, second.title)
}
}
}

View File

@ -1,20 +1,12 @@
package eu.kanade.tachiyomi.data.library
import android.app.Notification
import android.app.PendingIntent
import android.app.Service
import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.os.Build
import android.os.IBinder
import android.os.PowerManager
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationCompat.GROUP_ALERT_SUMMARY
import androidx.core.app.NotificationManagerCompat
import com.bumptech.glide.Glide
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.cache.CoverCache
import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.models.Category
import eu.kanade.tachiyomi.data.database.models.Chapter
@ -22,25 +14,21 @@ import eu.kanade.tachiyomi.data.database.models.LibraryManga
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.download.DownloadManager
import eu.kanade.tachiyomi.data.download.DownloadService
import eu.kanade.tachiyomi.data.glide.toMangaThumbnail
import eu.kanade.tachiyomi.data.library.LibraryUpdateRanker.rankingScheme
import eu.kanade.tachiyomi.data.library.LibraryUpdateService.Companion.start
import eu.kanade.tachiyomi.data.notification.NotificationReceiver
import eu.kanade.tachiyomi.data.notification.Notifications
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.track.TrackManager
import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.HttpSource
import eu.kanade.tachiyomi.ui.main.MainActivity
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
import eu.kanade.tachiyomi.util.lang.chop
import eu.kanade.tachiyomi.util.prepUpdateCover
import eu.kanade.tachiyomi.util.shouldDownloadNewChapters
import eu.kanade.tachiyomi.util.storage.getUriCompat
import eu.kanade.tachiyomi.util.system.acquireWakeLock
import eu.kanade.tachiyomi.util.system.isServiceRunning
import eu.kanade.tachiyomi.util.system.notification
import eu.kanade.tachiyomi.util.system.notificationBuilder
import eu.kanade.tachiyomi.util.system.notificationManager
import java.text.DecimalFormat
import java.text.DecimalFormatSymbols
import exh.LIBRARY_UPDATE_EXCLUDED_SOURCES
import java.io.File
import java.util.ArrayList
import java.util.concurrent.atomic.AtomicInteger
import rx.Observable
@ -63,7 +51,8 @@ class LibraryUpdateService(
val sourceManager: SourceManager = Injekt.get(),
val preferences: PreferencesHelper = Injekt.get(),
val downloadManager: DownloadManager = Injekt.get(),
val trackManager: TrackManager = Injekt.get()
val trackManager: TrackManager = Injekt.get(),
val coverCache: CoverCache = Injekt.get()
) : Service() {
/**
@ -71,45 +60,19 @@ class LibraryUpdateService(
*/
private lateinit var wakeLock: PowerManager.WakeLock
private lateinit var notifier: LibraryUpdateNotifier
/**
* Subscription where the update is done.
*/
private var subscription: Subscription? = null
/**
* Pending intent of action that cancels the library update
*/
private val cancelIntent by lazy {
NotificationReceiver.cancelLibraryUpdatePendingBroadcast(this)
}
/**
* Bitmap of the app for notifications.
*/
private val notificationBitmap by lazy {
BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher)
}
/**
* Cached progress notification to avoid creating a lot.
*/
private val progressNotificationBuilder by lazy {
notificationBuilder(Notifications.CHANNEL_LIBRARY) {
setContentTitle(getString(R.string.app_name))
setSmallIcon(R.drawable.ic_refresh_24dp)
setLargeIcon(notificationBitmap)
setOngoing(true)
setOnlyAlertOnce(true)
addAction(R.drawable.ic_close_24dp, getString(android.R.string.cancel), cancelIntent)
}
}
/**
* Defines what should be updated within a service execution.
*/
enum class Target {
CHAPTERS, // Manga chapters
DETAILS, // Manga metadata
COVERS, // Manga covers
TRACKING // Tracking metadata
}
@ -125,10 +88,6 @@ class LibraryUpdateService(
*/
const val KEY_TARGET = "target"
private const val NOTIF_MAX_CHAPTERS = 5
private const val NOTIF_TITLE_MAX_LEN = 45
private const val NOTIF_ICON_SIZE = 192
/**
* Returns the status of the service.
*
@ -182,11 +141,11 @@ class LibraryUpdateService(
*/
override fun onCreate() {
super.onCreate()
startForeground(Notifications.ID_LIBRARY_PROGRESS, progressNotificationBuilder.build())
wakeLock = (getSystemService(Context.POWER_SERVICE) as PowerManager).newWakeLock(
PowerManager.PARTIAL_WAKE_LOCK, "LibraryUpdateService:WakeLock"
)
wakeLock.acquire()
notifier = LibraryUpdateNotifier(this)
wakeLock = acquireWakeLock(javaClass.name)
startForeground(Notifications.ID_LIBRARY_PROGRESS, notifier.progressNotificationBuilder.build())
}
/**
@ -234,7 +193,7 @@ class LibraryUpdateService(
// Update either chapter list or manga details.
when (target) {
Target.CHAPTERS -> updateChapterList(mangaList)
Target.DETAILS -> updateDetails(mangaList)
Target.COVERS -> updateCovers(mangaList)
Target.TRACKING -> updateTrackings(mangaList)
}
}
@ -298,43 +257,43 @@ class LibraryUpdateService(
// List containing new updates
val newUpdates = ArrayList<Pair<LibraryManga, Array<Chapter>>>()
// List containing failed updates
val failedUpdates = ArrayList<Manga>()
// List containing categories that get included in downloads.
val categoriesToDownload = preferences.downloadNewCategories().get().map(String::toInt)
// Boolean to determine if user wants to automatically download new chapters.
val downloadNew = preferences.downloadNew().get()
val failedUpdates = ArrayList<Pair<Manga, String?>>()
// Boolean to determine if DownloadManager has downloads
var hasDownloads = false
// Emit each manga and update it sequentially.
return Observable.from(mangaToUpdate)
// Notify manga that will update.
.doOnNext { showProgressNotification(it, count.andIncrement, mangaToUpdate.size) }
// Update the chapters of the manga.
.doOnNext { notifier.showProgressNotification(it, count.andIncrement, mangaToUpdate.size) }
// Update the chapters of the manga
.concatMap { manga ->
updateManga(manga)
// If there's any error, return empty update and continue.
.onErrorReturn {
failedUpdates.add(manga)
Pair(emptyList(), emptyList())
}
// Filter out mangas without new chapters (or failed).
.filter { pair -> pair.first.isNotEmpty() }
.doOnNext {
if (downloadNew && (
categoriesToDownload.isEmpty() ||
manga.category in categoriesToDownload
)
) {
downloadChapters(manga, it.first)
hasDownloads = true
if (manga.source in LIBRARY_UPDATE_EXCLUDED_SOURCES) {
// Ignore EXH manga, updating chapters for every manga will get you banned
Observable.empty()
} else {
updateManga(manga)
// If there's any error, return empty update and continue.
.onErrorReturn {
failedUpdates.add(Pair(manga, it.message))
Pair(emptyList(), emptyList())
}
}
// Filter out mangas without new chapters (or failed).
.filter { pair -> pair.first.isNotEmpty() }
.doOnNext {
if (manga.shouldDownloadNewChapters(db, preferences)) {
downloadChapters(manga, it.first)
hasDownloads = true
}
}
}
// Convert to the manga that contains new chapters.
.map {
Pair(
manga,
(it.first.sortedByDescending { ch -> ch.source_order }.toTypedArray())
(
it.first.sortedByDescending { ch -> ch.source_order }
.toTypedArray()
)
)
}
}
@ -345,31 +304,30 @@ class LibraryUpdateService(
}
// Notify result of the overall update.
.doOnCompleted {
notifier.cancelProgressNotification()
if (newUpdates.isNotEmpty()) {
showUpdateNotifications(newUpdates)
if (downloadNew && hasDownloads) {
notifier.showUpdateNotifications(newUpdates)
if (hasDownloads) {
DownloadService.start(this)
}
}
if (failedUpdates.isNotEmpty()) {
Timber.e("Failed updating: ${failedUpdates.map { it.title }}")
if (preferences.showLibraryUpdateErrors() && failedUpdates.isNotEmpty()) {
val errorFile = writeErrorFile(failedUpdates)
notifier.showUpdateErrorNotification(
failedUpdates.map { it.first.title },
errorFile.getUriCompat(this)
)
}
cancelProgressNotification()
}
.map { manga -> manga.first }
}
fun downloadChapters(manga: Manga, chapters: List<Chapter>) {
// we need to get the chapters from the db so we have chapter ids
val mangaChapters = db.getChapters(manga).executeAsBlocking()
val dbChapters = chapters.map {
mangaChapters.find { mangaChapter -> mangaChapter.url == it.url }!!
}
private fun downloadChapters(manga: Manga, chapters: List<Chapter>) {
// We don't want to start downloading while the library is updating, because websites
// may don't like it and they could ban the user.
downloadManager.downloadChapters(manga, dbChapters, false)
downloadManager.downloadChapters(manga, chapters, false)
}
/**
@ -379,41 +337,56 @@ class LibraryUpdateService(
* @return a pair of the inserted and removed chapters.
*/
fun updateManga(manga: Manga): Observable<Pair<List<Chapter>, List<Chapter>>> {
val source = sourceManager.get(manga.source) as? HttpSource ?: return Observable.empty()
val source = sourceManager.get(manga.source) ?: return Observable.empty()
// Update manga details metadata in the background
if (preferences.autoUpdateMetadata()) {
source.fetchMangaDetails(manga)
.map { updatedManga ->
// Avoid "losing" existing cover
if (!updatedManga.thumbnail_url.isNullOrEmpty()) {
manga.prepUpdateCover(coverCache, updatedManga, false)
} else {
updatedManga.thumbnail_url = manga.thumbnail_url
}
manga.copyFrom(updatedManga)
db.insertManga(manga).executeAsBlocking()
manga
}
.onErrorResumeNext { Observable.just(manga) }
.subscribeOn(Schedulers.io())
.subscribe()
}
return source.fetchChapterList(manga)
.map { syncChaptersWithSource(db, it, manga, source) }
}
/**
* Method that updates the details of the given list of manga. It's called in a background
* thread, so it's safe to do heavy operations or network calls here.
*
* @param mangaToUpdate the list to update
* @return an observable delivering the progress of each update.
*/
fun updateDetails(mangaToUpdate: List<LibraryManga>): Observable<LibraryManga> {
// Initialize the variables holding the progress of the updates.
val count = AtomicInteger(0)
private fun updateCovers(mangaToUpdate: List<LibraryManga>): Observable<LibraryManga> {
var count = 0
// Emit each manga and update it sequentially.
return Observable.from(mangaToUpdate)
// Notify manga that will update.
.doOnNext { showProgressNotification(it, count.andIncrement, mangaToUpdate.size) }
// Update the details of the manga.
.concatMap { manga ->
val source = sourceManager.get(manga.source) as? HttpSource
?: return@concatMap Observable.empty<LibraryManga>()
.doOnNext {
notifier.showProgressNotification(it, count++, mangaToUpdate.size)
}
.flatMap { manga ->
val source = sourceManager.get(manga.source)
?: return@flatMap Observable.empty<LibraryManga>()
source.fetchMangaDetails(manga)
.map { networkManga ->
manga.copyFrom(networkManga)
db.insertManga(manga).executeAsBlocking()
manga.prepUpdateCover(coverCache, networkManga, true)
networkManga.thumbnail_url?.let {
manga.thumbnail_url = it
db.insertManga(manga).executeAsBlocking()
}
manga
}
.onErrorReturn { manga }
}
.doOnCompleted {
cancelProgressNotification()
notifier.cancelProgressNotification()
}
}
@ -430,7 +403,7 @@ class LibraryUpdateService(
// Emit each manga and update it sequentially.
return Observable.from(mangaToUpdate)
// Notify manga that will update.
.doOnNext { showProgressNotification(it, count++, mangaToUpdate.size) }
.doOnNext { notifier.showProgressNotification(it, count++, mangaToUpdate.size) }
// Update the tracking details.
.concatMap { manga ->
val tracks = db.getTracks(manga).executeAsBlocking()
@ -449,207 +422,28 @@ class LibraryUpdateService(
.map { manga }
}
.doOnCompleted {
cancelProgressNotification()
notifier.cancelProgressNotification()
}
}
/**
* Shows the notification containing the currently updating manga and the progress.
*
* @param manga the manga that's being updated.
* @param current the current progress.
* @param total the total progress.
* Writes basic file of update errors to cache dir.
*/
private fun showProgressNotification(manga: Manga, current: Int, total: Int) {
val title = if (preferences.hideNotificationContent()) {
getString(R.string.notification_check_updates)
} else {
manga.title
}
private fun writeErrorFile(errors: List<Pair<Manga, String?>>): File {
try {
if (errors.isNotEmpty()) {
val destFile = File(externalCacheDir, "tachiyomi_update_errors.txt")
notificationManager.notify(
Notifications.ID_LIBRARY_PROGRESS,
progressNotificationBuilder
.setContentTitle(title)
.setProgress(total, current, false)
.build()
)
}
/**
* Shows the notification containing the result of the update done by the service.
*
* @param updates a list of manga with new updates.
*/
private fun showUpdateNotifications(updates: List<Pair<Manga, Array<Chapter>>>) {
if (updates.isEmpty()) {
return
}
NotificationManagerCompat.from(this).apply {
// Parent group notification
notify(
Notifications.ID_NEW_CHAPTERS,
notification(Notifications.CHANNEL_NEW_CHAPTERS) {
setContentTitle(getString(R.string.notification_new_chapters))
if (updates.size == 1 && !preferences.hideNotificationContent()) {
setContentText(updates.first().first.title.chop(NOTIF_TITLE_MAX_LEN))
} else {
setContentText(resources.getQuantityString(R.plurals.notification_new_chapters_summary, updates.size, updates.size))
if (!preferences.hideNotificationContent()) {
setStyle(
NotificationCompat.BigTextStyle().bigText(
updates.joinToString("\n") {
it.first.title.chop(NOTIF_TITLE_MAX_LEN)
}
)
)
}
destFile.bufferedWriter().use { out ->
errors.forEach { (manga, error) ->
out.write("${manga.title}: $error\n")
}
setSmallIcon(R.drawable.ic_tachi)
setLargeIcon(notificationBitmap)
setGroup(Notifications.GROUP_NEW_CHAPTERS)
setGroupAlertBehavior(GROUP_ALERT_SUMMARY)
setGroupSummary(true)
priority = NotificationCompat.PRIORITY_HIGH
setContentIntent(getNotificationIntent())
setAutoCancel(true)
}
)
// Per-manga notification
if (!preferences.hideNotificationContent()) {
updates.forEach {
val (manga, chapters) = it
notify(manga.id.hashCode(), createNewChaptersNotification(manga, chapters))
}
return destFile
}
}
}
private fun createNewChaptersNotification(manga: Manga, chapters: Array<Chapter>): Notification {
return notification(Notifications.CHANNEL_NEW_CHAPTERS) {
setContentTitle(manga.title)
val description = getNewChaptersDescription(chapters)
setContentText(description)
setStyle(NotificationCompat.BigTextStyle().bigText(description))
setSmallIcon(R.drawable.ic_tachi)
val icon = getMangaIcon(manga)
if (icon != null) {
setLargeIcon(icon)
}
setGroup(Notifications.GROUP_NEW_CHAPTERS)
setGroupAlertBehavior(GROUP_ALERT_SUMMARY)
priority = NotificationCompat.PRIORITY_HIGH
// Open first chapter on tap
setContentIntent(NotificationReceiver.openChapterPendingActivity(this@LibraryUpdateService, manga, chapters.first()))
setAutoCancel(true)
// Mark chapters as read action
addAction(
R.drawable.ic_glasses_black_24dp, getString(R.string.action_mark_as_read),
NotificationReceiver.markAsReadPendingBroadcast(
this@LibraryUpdateService,
manga, chapters, Notifications.ID_NEW_CHAPTERS
)
)
// View chapters action
addAction(
R.drawable.ic_book_24dp, getString(R.string.action_view_chapters),
NotificationReceiver.openChapterPendingActivity(
this@LibraryUpdateService,
manga, Notifications.ID_NEW_CHAPTERS
)
)
}
}
/**
* Cancels the progress notification.
*/
private fun cancelProgressNotification() {
notificationManager.cancel(Notifications.ID_LIBRARY_PROGRESS)
}
private fun getMangaIcon(manga: Manga): Bitmap? {
return try {
Glide.with(this)
.asBitmap()
.load(manga.toMangaThumbnail())
.dontTransform()
.centerCrop()
.circleCrop()
.override(NOTIF_ICON_SIZE, NOTIF_ICON_SIZE)
.submit()
.get()
} catch (e: Exception) {
null
// Empty
}
}
private fun getNewChaptersDescription(chapters: Array<Chapter>): String {
val formatter = DecimalFormat(
"#.###",
DecimalFormatSymbols()
.apply { decimalSeparator = '.' }
)
val displayableChapterNumbers = chapters
.filter { it.isRecognizedNumber }
.sortedBy { it.chapter_number }
.map { formatter.format(it.chapter_number) }
.toSet()
return when (displayableChapterNumbers.size) {
// No sensible chapter numbers to show (i.e. no chapters have parsed chapter number)
0 -> {
// "1 new chapter" or "5 new chapters"
resources.getQuantityString(R.plurals.notification_chapters_generic, chapters.size, chapters.size)
}
// Only 1 chapter has a parsed chapter number
1 -> {
val remaining = chapters.size - displayableChapterNumbers.size
if (remaining == 0) {
// "Chapter 2.5"
resources.getString(R.string.notification_chapters_single, displayableChapterNumbers.first())
} else {
// "Chapter 2.5 and 10 more"
resources.getString(R.string.notification_chapters_single_and_more, displayableChapterNumbers.first(), remaining)
}
}
// Everything else (i.e. multiple parsed chapter numbers)
else -> {
val shouldTruncate = displayableChapterNumbers.size > NOTIF_MAX_CHAPTERS
if (shouldTruncate) {
// "Chapters 1, 2.5, 3, 4, 5 and 10 more"
val remaining = displayableChapterNumbers.size - NOTIF_MAX_CHAPTERS
val joinedChapterNumbers = displayableChapterNumbers.take(NOTIF_MAX_CHAPTERS).joinToString(", ")
resources.getQuantityString(R.plurals.notification_chapters_multiple_and_more, remaining, joinedChapterNumbers, remaining)
} else {
// "Chapters 1, 2.5, 3"
resources.getString(R.string.notification_chapters_multiple, displayableChapterNumbers.joinToString(", "))
}
}
}
}
/**
* Returns an intent to open the main activity.
*/
private fun getNotificationIntent(): PendingIntent {
val intent = Intent(this, MainActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
action = MainActivity.SHORTCUT_RECENTLY_UPDATED
}
return PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
return File("")
}
}

View File

@ -25,6 +25,7 @@ object Notifications {
*/
const val CHANNEL_LIBRARY = "library_channel"
const val ID_LIBRARY_PROGRESS = -101
const val ID_LIBRARY_ERROR = -102
/**
* Notification channel and ids used by the downloader.

View File

@ -73,10 +73,12 @@ object PreferenceKeys {
const val lastUsedCategory = "last_used_category"
const val catalogueAsList = "pref_display_catalogue_as_list"
const val catalogueViewSetting = "pref_display_catalogue_view_setting"
const val enabledLanguages = "source_languages"
const val sourcesSort = "sources_sort"
const val backupDirectory = "backup_directory"
const val downloadsDirectory = "download_directory"
@ -107,6 +109,10 @@ object PreferenceKeys {
const val filterCompleted = "pref_filter_completed_key"
const val filterTracked = "pref_filter_tracked_key"
const val filterLewd = "pref_filter_lewd_key"
const val librarySortingMode = "library_sorting_mode"
const val automaticExtUpdates = "automatic_ext_updates"
@ -123,11 +129,15 @@ object PreferenceKeys {
const val hideNotificationContent = "hide_notification_content"
const val autoUpdateMetadata = "auto_update_metadata"
const val showLibraryUpdateErrors = "show_library_update_errors"
const val downloadNew = "download_new"
const val downloadNewCategories = "download_new_categories"
const val libraryAsList = "pref_display_library_as_list"
const val libraryViewSetting = "pref_display_library_view_setting"
const val lang = "app_language"
@ -141,6 +151,10 @@ object PreferenceKeys {
const val downloadBadge = "display_download_badge"
const val unreadBadge = "display_unread_badge"
const val skipPreMigration = "skip_pre_migration"
const val alwaysShowChapterTransition = "always_show_chapter_transition"
const val searchPinnedSourcesOnly = "search_pinned_sources_only"
@ -150,4 +164,82 @@ object PreferenceKeys {
fun trackPassword(syncId: Int) = "pref_mangasync_password_$syncId"
fun trackToken(syncId: Int) = "track_token_$syncId"
const val eh_lock_hash = "lock_hash"
const val eh_lock_salt = "lock_salt"
const val eh_lock_length = "lock_length"
const val eh_lock_finger = "lock_finger"
const val eh_lock_manually = "eh_lock_manually"
const val eh_nh_useHighQualityThumbs = "eh_nh_hq_thumbs"
const val eh_showSyncIntro = "eh_show_sync_intro"
const val eh_readOnlySync = "eh_sync_read_only"
const val eh_lenientSync = "eh_lenient_sync"
const val eh_useOrigImages = "eh_useOrigImages"
const val eh_ehSettingsProfile = "eh_ehSettingsProfile"
const val eh_exhSettingsProfile = "eh_exhSettingsProfile"
const val eh_settingsKey = "eh_settingsKey"
const val eh_sessionCookie = "eh_sessionCookie"
const val eh_hathPerksCookie = "eh_hathPerksCookie"
const val eh_enableExHentai = "enable_exhentai"
const val eh_ts_aspNetCookie = "eh_ts_aspNetCookie"
const val eh_showSettingsUploadWarning = "eh_showSettingsUploadWarning2"
const val eh_expandFilters = "eh_expand_filters"
const val eh_readerThreads = "eh_reader_threads"
const val eh_readerInstantRetry = "eh_reader_instant_retry"
const val eh_utilAutoscrollInterval = "eh_util_autoscroll_interval"
const val eh_cacheSize = "eh_cache_size"
const val eh_preserveReadingPosition = "eh_preserve_reading_position"
const val eh_autoSolveCaptchas = "eh_autosolve_captchas"
const val eh_delegateSources = "eh_delegate_sources"
const val eh_logLevel = "eh_log_level"
const val eh_enableSourceBlacklist = "eh_enable_source_blacklist"
const val eh_autoUpdateFrequency = "eh_auto_update_frequency"
const val eh_autoUpdateRestrictions = "eh_auto_update_restrictions"
const val eh_autoUpdateStats = "eh_auto_update_stats"
const val eh_aggressivePageLoading = "eh_aggressive_page_loading"
const val eh_hl_useHighQualityThumbs = "eh_hl_hq_thumbs"
const val eh_preload_size = "eh_preload_size"
const val eh_tag_filtering_value = "eh_tag_filtering_value"
const val eh_tag_watching_value = "eh_tag_watching_value"
const val eh_is_hentai_enabled = "eh_is_hentai_enabled"
const val eh_use_new_manga_interface = "eh_use_new_manga_interface"
const val eh_use_auto_webtoon = "eh_use_auto_webtoon"
}

View File

@ -1,7 +1,6 @@
package eu.kanade.tachiyomi.data.preference
import android.content.Context
import android.content.SharedPreferences
import android.net.Uri
import android.os.Environment
import androidx.preference.PreferenceManager
@ -31,28 +30,12 @@ fun <T> Preference<T>.asImmediateFlow(block: (value: T) -> Unit): Flow<T> {
.onEach { block(it) }
}
private class DateFormatConverter : RxPreference.Adapter<DateFormat> {
override fun get(key: String, preferences: SharedPreferences): DateFormat {
val dateFormat = preferences.getString(Keys.dateFormat, "")!!
if (dateFormat != "") {
return SimpleDateFormat(dateFormat, Locale.getDefault())
}
return DateFormat.getDateInstance(DateFormat.SHORT)
}
override fun set(key: String, value: DateFormat, editor: SharedPreferences.Editor) {
// No-op
}
}
@OptIn(ExperimentalCoroutinesApi::class)
class PreferencesHelper(val context: Context) {
private val prefs = PreferenceManager.getDefaultSharedPreferences(context)
private val rxPrefs = RxSharedPreferences.create(prefs)
private val flowPrefs = FlowSharedPreferences(prefs)
val flowPrefs = FlowSharedPreferences(prefs)
private val defaultDownloadsDir = Uri.fromFile(
File(
@ -84,6 +67,10 @@ class PreferencesHelper(val context: Context) {
fun hideNotificationContent() = prefs.getBoolean(Keys.hideNotificationContent, false)
fun autoUpdateMetadata() = prefs.getBoolean(Keys.autoUpdateMetadata, false)
fun showLibraryUpdateErrors() = prefs.getBoolean(Keys.showLibraryUpdateErrors, false)
fun clear() = prefs.edit().clear().apply()
fun themeMode() = flowPrefs.getString(Keys.themeMode, Values.THEME_MODE_SYSTEM)
@ -92,7 +79,7 @@ class PreferencesHelper(val context: Context) {
fun themeDark() = flowPrefs.getString(Keys.themeDark, Values.THEME_DARK_DEFAULT)
fun rotation() = rxPrefs.getInteger(Keys.rotation, 1)
fun rotation() = flowPrefs.getInt(Keys.rotation, 1)
fun pageTransitions() = flowPrefs.getBoolean(Keys.enableTransitions, true)
@ -156,9 +143,11 @@ class PreferencesHelper(val context: Context) {
fun lastVersionCode() = flowPrefs.getInt("last_version_code", 0)
fun catalogueAsList() = rxPrefs.getBoolean(Keys.catalogueAsList, false)
fun catalogueViewSetting() = flowPrefs.getInt(Keys.catalogueViewSetting, 0)
fun enabledLanguages() = flowPrefs.getStringSet(Keys.enabledLanguages, setOf("en", Locale.getDefault().language))
fun enabledLanguages() = flowPrefs.getStringSet(Keys.enabledLanguages, setOf("all", "en", Locale.getDefault().language))
fun sourceSorting() = flowPrefs.getInt(Keys.sourcesSort, 0)
fun trackUsername(sync: TrackService) = prefs.getString(Keys.trackUsername(sync.id), "")
@ -177,7 +166,10 @@ class PreferencesHelper(val context: Context) {
fun backupsDirectory() = flowPrefs.getString(Keys.backupDirectory, defaultBackupDir.toString())
fun dateFormat() = rxPrefs.getObject(Keys.dateFormat, DateFormat.getDateInstance(DateFormat.SHORT), DateFormatConverter())
fun dateFormat(format: String = flowPrefs.getString(Keys.dateFormat, "").get()): DateFormat = when (format) {
"" -> DateFormat.getDateInstance(DateFormat.SHORT)
else -> SimpleDateFormat(format, Locale.getDefault())
}
fun downloadsDirectory() = flowPrefs.getString(Keys.downloadsDirectory, defaultDownloadsDir.toString())
@ -199,17 +191,24 @@ class PreferencesHelper(val context: Context) {
fun libraryUpdatePrioritization() = flowPrefs.getInt(Keys.libraryUpdatePrioritization, 0)
fun libraryAsList() = flowPrefs.getBoolean(Keys.libraryAsList, false)
fun libraryViewSetting() = flowPrefs.getInt(Keys.libraryViewSetting, 0)
fun downloadBadge() = flowPrefs.getBoolean(Keys.downloadBadge, false)
fun downloadedOnly() = flowPrefs.getBoolean(Keys.downloadedOnly, false)
fun filterDownloaded() = flowPrefs.getBoolean(Keys.filterDownloaded, false)
fun unreadBadge() = flowPrefs.getBoolean(Keys.unreadBadge, true)
fun filterUnread() = flowPrefs.getBoolean(Keys.filterUnread, false)
// J2K converted from boolean to integer
fun filterDownloaded() = flowPrefs.getInt(Keys.filterDownloaded, 0)
fun filterCompleted() = flowPrefs.getBoolean(Keys.filterCompleted, false)
fun filterUnread() = flowPrefs.getInt(Keys.filterUnread, 0)
fun filterCompleted() = flowPrefs.getInt(Keys.filterCompleted, 0)
fun filterTracked() = flowPrefs.getInt(Keys.filterTracked, 0)
fun filterLewd() = flowPrefs.getInt(Keys.filterLewd, 0)
fun librarySortingMode() = flowPrefs.getInt(Keys.librarySortingMode, 0)
@ -223,7 +222,7 @@ class PreferencesHelper(val context: Context) {
fun searchPinnedSourcesOnly() = prefs.getBoolean(Keys.searchPinnedSourcesOnly, false)
fun hiddenCatalogues() = flowPrefs.getStringSet("hidden_catalogues", emptySet())
fun hiddenCatalogues() = flowPrefs.getStringSet("hidden_catalogues", mutableSetOf())
fun pinnedCatalogues() = flowPrefs.getStringSet("pinned_catalogues", emptySet())
@ -242,4 +241,115 @@ class PreferencesHelper(val context: Context) {
fun migrateFlags() = flowPrefs.getInt("migrate_flags", Int.MAX_VALUE)
fun trustedSignatures() = flowPrefs.getStringSet("trusted_signatures", emptySet())
// --> AZ J2K CHERRYPICKING
fun defaultMangaOrder() = flowPrefs.getString("default_manga_order", "")
fun migrationSources() = flowPrefs.getString("migrate_sources", "")
fun smartMigration() = flowPrefs.getBoolean("smart_migrate", false)
fun useSourceWithMost() = flowPrefs.getBoolean("use_source_with_most", false)
fun skipPreMigration() = flowPrefs.getBoolean(Keys.skipPreMigration, false)
fun upgradeFilters() {
val filterDl = flowPrefs.getBoolean(Keys.filterDownloaded, false).get()
val filterUn = flowPrefs.getBoolean(Keys.filterUnread, false).get()
val filterCm = flowPrefs.getBoolean(Keys.filterCompleted, false).get()
filterDownloaded().set(if (filterDl) 1 else 0)
filterUnread().set(if (filterUn) 1 else 0)
filterCompleted().set(if (filterCm) 1 else 0)
}
// <--
// --> EH
fun eh_isHentaiEnabled() = flowPrefs.getBoolean(Keys.eh_is_hentai_enabled, true)
fun enableExhentai() = flowPrefs.getBoolean(Keys.eh_enableExHentai, false)
fun secureEXH() = flowPrefs.getBoolean("secure_exh", true)
fun imageQuality() = flowPrefs.getString("ehentai_quality", "auto")
fun useHentaiAtHome() = flowPrefs.getBoolean("enable_hah", true)
fun useJapaneseTitle() = flowPrefs.getBoolean("use_jp_title", false)
fun eh_useOriginalImages() = flowPrefs.getBoolean(Keys.eh_useOrigImages, false)
fun ehTagFilterValue() = flowPrefs.getInt(Keys.eh_tag_filtering_value, 0)
fun ehTagWatchingValue() = flowPrefs.getInt(Keys.eh_tag_watching_value, 0)
fun ehSearchSize() = flowPrefs.getString("ex_search_size", "rc_0")
fun thumbnailRows() = flowPrefs.getString("ex_thumb_rows", "tr_2")
fun hasPerformedURLMigration() = flowPrefs.getBoolean("performed_url_migration", false)
// EH Cookies
fun memberIdVal() = flowPrefs.getString("eh_ipb_member_id", "")
fun passHashVal() = flowPrefs.getString("eh_ipb_pass_hash", "")
fun igneousVal() = flowPrefs.getString("eh_igneous", "")
fun eh_ehSettingsProfile() = flowPrefs.getInt(Keys.eh_ehSettingsProfile, -1)
fun eh_exhSettingsProfile() = flowPrefs.getInt(Keys.eh_exhSettingsProfile, -1)
fun eh_settingsKey() = flowPrefs.getString(Keys.eh_settingsKey, "")
fun eh_sessionCookie() = flowPrefs.getString(Keys.eh_sessionCookie, "")
fun eh_hathPerksCookies() = flowPrefs.getString(Keys.eh_hathPerksCookie, "")
fun eh_nh_useHighQualityThumbs() = flowPrefs.getBoolean(Keys.eh_nh_useHighQualityThumbs, false)
fun eh_showSyncIntro() = flowPrefs.getBoolean(Keys.eh_showSyncIntro, true)
fun eh_readOnlySync() = flowPrefs.getBoolean(Keys.eh_readOnlySync, false)
fun eh_lenientSync() = flowPrefs.getBoolean(Keys.eh_lenientSync, false)
fun eh_ts_aspNetCookie() = flowPrefs.getString(Keys.eh_ts_aspNetCookie, "")
fun eh_showSettingsUploadWarning() = flowPrefs.getBoolean(Keys.eh_showSettingsUploadWarning, true)
fun eh_expandFilters() = flowPrefs.getBoolean(Keys.eh_expandFilters, false)
fun eh_readerThreads() = flowPrefs.getInt(Keys.eh_readerThreads, 2)
fun eh_readerInstantRetry() = flowPrefs.getBoolean(Keys.eh_readerInstantRetry, true)
fun eh_utilAutoscrollInterval() = flowPrefs.getFloat(Keys.eh_utilAutoscrollInterval, 3f)
fun eh_cacheSize() = flowPrefs.getString(Keys.eh_cacheSize, "75")
fun eh_preserveReadingPosition() = flowPrefs.getBoolean(Keys.eh_preserveReadingPosition, false)
fun eh_autoSolveCaptchas() = flowPrefs.getBoolean(Keys.eh_autoSolveCaptchas, false)
fun eh_delegateSources() = flowPrefs.getBoolean(Keys.eh_delegateSources, true)
fun eh_lastVersionCode() = flowPrefs.getInt("eh_last_version_code", 0)
fun eh_savedSearches() = flowPrefs.getStringSet("eh_saved_searches", emptySet())
fun eh_logLevel() = flowPrefs.getInt(Keys.eh_logLevel, 0)
fun eh_enableSourceBlacklist() = flowPrefs.getBoolean(Keys.eh_enableSourceBlacklist, true)
fun eh_autoUpdateFrequency() = flowPrefs.getInt(Keys.eh_autoUpdateFrequency, 1)
fun eh_autoUpdateRequirements() = prefs.getStringSet(Keys.eh_autoUpdateRestrictions, emptySet())
fun eh_autoUpdateStats() = flowPrefs.getString(Keys.eh_autoUpdateStats, "")
fun eh_aggressivePageLoading() = flowPrefs.getBoolean(Keys.eh_aggressivePageLoading, false)
fun eh_hl_useHighQualityThumbs() = flowPrefs.getBoolean(Keys.eh_hl_useHighQualityThumbs, false)
fun eh_preload_size() = flowPrefs.getInt(Keys.eh_preload_size, 4)
fun eh_useNewMangaInterface() = flowPrefs.getBoolean(Keys.eh_use_new_manga_interface, true)
fun eh_useAutoWebtoon() = flowPrefs.getBoolean(Keys.eh_use_auto_webtoon, true)
}

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