Compare commits

...

978 Commits
v7.0 ... v8.1

Author SHA1 Message Date
Koitharu
e3e315e2a6 Skip local directories with .notamanga file 2025-03-30 10:43:05 +03:00
Koitharu
bfc733784f Option to disable dangerous genres highlighting #1348 2025-03-30 10:34:27 +03:00
Koitharu
3ff25de252 Fix crash 2025-03-30 10:21:42 +03:00
Koitharu
3c726c1c56 Update dependencies 2025-03-30 10:21:42 +03:00
Koitharu
9cb7ff691f Merge pull request #1349 from weblate/weblate-kotatsu-strings
Translations update from Hosted Weblate
2025-03-30 10:21:06 +03:00
lenn
645ae3124f Translated using Weblate (Polish)
Currently translated at 96.0% (780 of 812 strings)

Co-authored-by: lenn <l3ennec@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pl/
Translation: Kotatsu/Strings
2025-03-29 14:02:13 +01:00
Ore Ki
a3d1922913 Translated using Weblate (Indonesian)
Currently translated at 100.0% (812 of 812 strings)

Co-authored-by: Ore Ki <ramadrizkyyy@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/id/
Translation: Kotatsu/Strings
2025-03-29 14:02:11 +01:00
gekka
62d2ea8f15 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 99.6% (809 of 812 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 99.5% (808 of 812 strings)

Co-authored-by: gekka <1778962971@qq.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/
Translation: Kotatsu/Strings
2025-03-29 14:02:09 +01:00
Draken
823752076b Translated using Weblate (Vietnamese)
Currently translated at 100.0% (812 of 812 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (812 of 812 strings)

Co-authored-by: Draken <premieregirl26@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/vi/
Translation: Kotatsu/Strings
2025-03-29 14:02:06 +01:00
Lorenzo Stella
3cbd392c72 Translated using Weblate (English)
Currently translated at 100.0% (812 of 812 strings)

Translated using Weblate (English (United Kingdom))

Currently translated at 2.4% (20 of 812 strings)

Translated using Weblate (English)

Currently translated at 100.0% (812 of 812 strings)

Translated using Weblate (English)

Currently translated at 100.0% (812 of 812 strings)

Co-authored-by: Lorenzo Stella <lorenzo.stella.1408@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/en/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/en_GB/
Translation: Kotatsu/Strings
2025-03-29 14:02:04 +01:00
Anonymous
57f62f5860 Translated using Weblate (Malayalam)
Currently translated at 2.8% (23 of 812 strings)

Translated using Weblate (Sinhala)

Currently translated at 2.7% (22 of 812 strings)

Translated using Weblate (Croatian)

Currently translated at 97.5% (792 of 812 strings)

Translated using Weblate (Hungarian)

Currently translated at 76.3% (620 of 812 strings)

Translated using Weblate (Malay)

Currently translated at 38.4% (312 of 812 strings)

Translated using Weblate (Estonian)

Currently translated at 67.6% (549 of 812 strings)

Translated using Weblate (Thai)

Currently translated at 55.7% (453 of 812 strings)

Translated using Weblate (Czech)

Currently translated at 98.0% (796 of 812 strings)

Translated using Weblate (Vietnamese)

Currently translated at 99.1% (805 of 812 strings)

Translated using Weblate (Kazakh)

Currently translated at 66.9% (544 of 812 strings)

Translated using Weblate (Norwegian Nynorsk)

Currently translated at 46.9% (381 of 812 strings)

Translated using Weblate (Filipino)

Currently translated at 98.2% (798 of 812 strings)

Translated using Weblate (Hindi)

Currently translated at 82.2% (668 of 812 strings)

Translated using Weblate (Polish)

Currently translated at 93.1% (756 of 812 strings)

Translated using Weblate (Korean)

Currently translated at 41.9% (341 of 812 strings)

Translated using Weblate (Greek)

Currently translated at 66.2% (538 of 812 strings)

Translated using Weblate (Serbian)

Currently translated at 97.9% (795 of 812 strings)

Translated using Weblate (Arabic)

Currently translated at 98.7% (802 of 812 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 80.9% (657 of 812 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 99.0% (804 of 812 strings)

Translated using Weblate (Ukrainian)

Currently translated at 81.6% (663 of 812 strings)

Translated using Weblate (Russian)

Currently translated at 98.5% (800 of 812 strings)

Translated using Weblate (Japanese)

Currently translated at 57.1% (464 of 812 strings)

Translated using Weblate (Turkish)

Currently translated at 99.6% (809 of 812 strings)

Translated using Weblate (French)

Currently translated at 99.6% (809 of 812 strings)

Translated using Weblate (Portuguese)

Currently translated at 96.6% (785 of 812 strings)

Translated using Weblate (Italian)

Currently translated at 99.5% (808 of 812 strings)

Translated using Weblate (German)

Currently translated at 78.3% (636 of 812 strings)

Translated using Weblate (Spanish)

Currently translated at 94.9% (771 of 812 strings)

Translated using Weblate (Belarusian)

Currently translated at 92.1% (748 of 812 strings)

Co-authored-by: Anonymous <noreply@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ar/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/be/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/cs/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/de/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/el/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/es/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/et/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fil/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fr/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/hi/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/hr/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/hu/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/it/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ja/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/kk/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ko/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ml/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ms/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/nn/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pl/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pt/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ru/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/si/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/sr/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/th/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/tr/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/uk/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/vi/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hant/
Translation: Kotatsu/Strings
2025-03-29 14:02:02 +01:00
Koitharu
648fab6be5 Fix Open online manga variant 2025-03-27 20:39:36 +02:00
Koitharu
817ae68e67 Option to toggle ssiv debug 2025-03-26 19:24:32 +02:00
Koitharu
7c4b91ddc4 UI Fixes 2025-03-26 19:23:06 +02:00
Koitharu
d54e015195 Fix Favorite/Favourite strings 2025-03-25 10:08:16 +02:00
Koitharu
e369d1ba9d Merge remote-tracking branch 'weblate/devel' into devel 2025-03-25 10:01:27 +02:00
Koitharu
1a4358998b Merge pull request #1334 from Arararararagi/patch-1
typos and coherence check in strings
2025-03-25 09:47:37 +02:00
MrCrystallized
c53a833d9d Translated using Weblate (Bengali)
Currently translated at 22.1% (180 of 812 strings)

Translated using Weblate (Bengali)

Currently translated at 88.8% (8 of 9 strings)

Co-authored-by: MrCrystallized <mrcrystallizedbruh@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/plurals/bn/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/bn/
Translation: Kotatsu/Strings
Translation: Kotatsu/plurals
2025-03-24 21:54:54 +01:00
Lorenzo Stella
afff700ad3 Translated using Weblate (Romanian)
Currently translated at 11.0% (90 of 812 strings)

Translated using Weblate (Khmer (Central))

Currently translated at 17.7% (144 of 812 strings)

Translated using Weblate (Latvian)

Currently translated at 21.6% (176 of 812 strings)

Translated using Weblate (Lithuanian)

Currently translated at 5.5% (45 of 812 strings)

Translated using Weblate (Catalan)

Currently translated at 10.9% (89 of 812 strings)

Translated using Weblate (Hungarian)

Currently translated at 76.6% (622 of 812 strings)

Translated using Weblate (Punjabi)

Currently translated at 4.1% (34 of 812 strings)

Translated using Weblate (Malay)

Currently translated at 38.6% (314 of 812 strings)

Translated using Weblate (Thai)

Currently translated at 56.0% (455 of 812 strings)

Translated using Weblate (Kazakh)

Currently translated at 67.2% (546 of 812 strings)

Translated using Weblate (Norwegian Nynorsk)

Currently translated at 47.1% (383 of 812 strings)

Translated using Weblate (Nepali)

Currently translated at 30.5% (248 of 812 strings)

Translated using Weblate (Hindi)

Currently translated at 82.6% (671 of 812 strings)

Translated using Weblate (Polish)

Currently translated at 93.5% (760 of 812 strings)

Translated using Weblate (Korean)

Currently translated at 42.2% (343 of 812 strings)

Translated using Weblate (Greek)

Currently translated at 66.5% (540 of 812 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 81.2% (660 of 812 strings)

Translated using Weblate (Ukrainian)

Currently translated at 82.0% (666 of 812 strings)

Translated using Weblate (Japanese)

Currently translated at 57.3% (466 of 812 strings)

Translated using Weblate (Persian)

Currently translated at 35.5% (289 of 812 strings)

Translated using Weblate (Finnish)

Currently translated at 32.0% (260 of 812 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (812 of 812 strings)

Translated using Weblate (German)

Currently translated at 78.6% (639 of 812 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 35.4% (288 of 812 strings)

Translated using Weblate (Spanish)

Currently translated at 95.4% (775 of 812 strings)

Translated using Weblate (English)

Currently translated at 100.0% (812 of 812 strings)

Co-authored-by: Lorenzo Stella <lorenzo.stella.1408@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ca/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/de/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/el/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/en/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/es/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fa/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fi/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/hi/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/hu/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/it/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ja/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/kk/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/km/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ko/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/lt/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/lv/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ms/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ne/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/nn/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pa/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pl/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ro/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/th/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/uk/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hant/
Translation: Kotatsu/Strings
2025-03-24 21:54:54 +01:00
Anon
5bc00bc7f5 Translated using Weblate (Serbian)
Currently translated at 98.2% (798 of 812 strings)

Co-authored-by: Anon <anonymousprivate76@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/sr/
Translation: Kotatsu/Strings
2025-03-24 21:54:54 +01:00
Dragibus Noir
e2ace90cdb Translated using Weblate (French)
Currently translated at 100.0% (812 of 812 strings)

Co-authored-by: Dragibus Noir <dragibusnoir@pm.me>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fr/
Translation: Kotatsu/Strings
2025-03-24 21:54:54 +01:00
Lumiini
1afbd2b6a8 Translated using Weblate (Finnish)
Currently translated at 66.6% (6 of 9 strings)

Co-authored-by: Lumiini <bennokaynak@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/plurals/fi/
Translation: Kotatsu/plurals
2025-03-24 21:54:53 +01:00
Frosted
d36c5af0c4 Translated using Weblate (Turkish)
Currently translated at 100.0% (812 of 812 strings)

Co-authored-by: Frosted <frosted@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/tr/
Translation: Kotatsu/Strings
2025-03-24 21:54:53 +01:00
Nicola Bortoletto
705bb2b084 Translated using Weblate (Italian)
Currently translated at 100.0% (812 of 812 strings)

Co-authored-by: Nicola Bortoletto <nicola.bortoletto@live.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/it/
Translation: Kotatsu/Strings
2025-03-24 21:54:53 +01:00
gekka
a208d13930 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 99.5% (808 of 812 strings)

Co-authored-by: gekka <1778962971@qq.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/
Translation: Kotatsu/Strings
2025-03-24 21:54:53 +01:00
Kusou
44d8861b7f Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (808 of 808 strings)

Co-authored-by: Kusou <orion26br@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pt_BR/
Translation: Kotatsu/Strings
2025-03-24 21:54:53 +01:00
ruban s
9821f06ca1 Translated using Weblate (Tamil)
Currently translated at 100.0% (808 of 808 strings)

Co-authored-by: ruban s <rubans013@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ta/
Translation: Kotatsu/Strings
2025-03-24 21:54:52 +01:00
Amato Fugosi
92f9f56f59 Translated using Weblate (Bengali)
Currently translated at 19.9% (161 of 808 strings)

Translated using Weblate (Bengali)

Currently translated at 88.8% (8 of 9 strings)

Co-authored-by: Amato Fugosi <fugosiamato@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/plurals/bn/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/bn/
Translation: Kotatsu/Strings
Translation: Kotatsu/plurals
2025-03-24 21:54:52 +01:00
Koitharu
424c4d8827 Multiple authors support 2025-03-24 14:18:04 +02:00
Koitharu
24cf2a2725 Use page preview in reader while loading 2025-03-22 16:18:35 +02:00
Koitharu
1a5c3c1f6f Update dependencies 2025-03-21 09:03:31 +02:00
Koitharu
0b8fbf892a Improve details activity 2025-03-20 18:00:58 +02:00
Koitharu
a2f9356b8a Fix crashes 2025-03-20 08:20:43 +02:00
Koitharu
7003463bac Option to use disabled sources for suggestions 2025-03-20 07:52:08 +02:00
Koitharu
7a663fa9c1 Merge branch 'devel' 2025-03-18 19:36:42 +02:00
Koitharu
a3345d11e7 Update parsers 2025-03-18 19:08:41 +02:00
Koitharu
f1ab65ec32 Fixes 2025-03-18 19:06:46 +02:00
Koitharu
6282d25d3d Merge pull request #1333 from weblate/weblate-kotatsu-strings
Translations update from Hosted Weblate
2025-03-18 19:04:06 +02:00
Saterz_
47c3f9ff3b Translated using Weblate (French)
Currently translated at 99.8% (807 of 808 strings)

Co-authored-by: Saterz_ <saterzstudio@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fr/
Translation: Kotatsu/Strings
2025-03-18 07:39:01 +01:00
gekka
5cd2f1b9e6 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 99.5% (804 of 808 strings)

Co-authored-by: gekka <1778962971@qq.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/
Translation: Kotatsu/Strings
2025-03-18 07:39:01 +01:00
Frosted
5d9b18ec11 Translated using Weblate (Turkish)
Currently translated at 100.0% (808 of 808 strings)

Co-authored-by: Frosted <frosted@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/tr/
Translation: Kotatsu/Strings
2025-03-18 07:39:00 +01:00
Nicola Bortoletto
5aec1f644d Translated using Weblate (Italian)
Currently translated at 100.0% (808 of 808 strings)

Co-authored-by: Nicola Bortoletto <nicola.bortoletto@live.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/it/
Translation: Kotatsu/Strings
2025-03-18 07:39:00 +01:00
Draken
aee092f0b3 Translated using Weblate (Vietnamese)
Currently translated at 100.0% (808 of 808 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (807 of 807 strings)

Co-authored-by: Draken <premieregirl26@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/vi/
Translation: Kotatsu/Strings
2025-03-18 07:39:00 +01:00
I bit my tongue
9cc1cdac62 typos and coherence check 2025-03-16 21:13:54 +00:00
Koitharu
1e73739ddb Synchronized SieveCache wrapper 2025-03-16 12:54:00 +02:00
Koitharu
d1d7cc9adf Fix crashes 2025-03-16 12:43:31 +02:00
Koitharu
6a0ad7f79b Improve FileNotFoundException handling (#1332) 2025-03-15 10:38:41 +02:00
Koitharu
f7c70577ae Fix local chapters names (close #1323) 2025-03-15 09:00:25 +02:00
Koitharu
937ed798cf Update parsers 2025-03-15 08:16:30 +02:00
Koitharu
8da4f0e180 Merge pull request #1309 from weblate/weblate-kotatsu-strings
Translations update from Hosted Weblate
2025-03-15 08:13:53 +02:00
Drama Lover
170d12f143 Translated using Weblate (Arabic)
Currently translated at 88.8% (8 of 9 strings)

Co-authored-by: Drama Lover <loverdrama053@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/plurals/ar/
Translation: Kotatsu/plurals
2025-03-14 19:37:56 +00:00
Akhil Raj
0fe3409577 Translated using Weblate (Malayalam)
Currently translated at 11.1% (1 of 9 strings)

Co-authored-by: Akhil Raj <akhilakae07@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/plurals/ml/
Translation: Kotatsu/plurals
2025-03-14 19:37:55 +00:00
Laura
36e431a1ca Translated using Weblate (French)
Currently translated at 100.0% (805 of 805 strings)

Added translation using Weblate (Arabic (Algerian))

Translated using Weblate (Arabic)

Currently translated at 100.0% (805 of 805 strings)

Co-authored-by: Laura <hankmaroua@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ar/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fr/
Translation: Kotatsu/Strings
2025-03-14 19:37:54 +00:00
Ore Ki
f30ebda851 Translated using Weblate (Indonesian)
Currently translated at 95.5% (769 of 805 strings)

Translated using Weblate (Indonesian)

Currently translated at 95.4% (768 of 805 strings)

Co-authored-by: Ore Ki <ramadrizkyyy@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/id/
Translation: Kotatsu/Strings
2025-03-14 19:37:53 +00:00
Koitharu
0f021a2d6e Translated using Weblate (Russian)
Currently translated at 100.0% (803 of 803 strings)

Co-authored-by: Koitharu <nvasya95@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ru/
Translation: Kotatsu/Strings
2025-03-14 19:37:53 +00:00
Alvoracz
f816c8ca6e Translated using Weblate (Czech)
Currently translated at 99.5% (799 of 803 strings)

Co-authored-by: Alvoracz <sedlor@seznam.cz>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/cs/
Translation: Kotatsu/Strings
2025-03-14 19:37:52 +00:00
Y Ok
fe0c4605f7 Translated using Weblate (Indonesian)
Currently translated at 95.5% (767 of 803 strings)

Co-authored-by: Y Ok <yok111263@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/id/
Translation: Kotatsu/Strings
2025-03-14 19:37:51 +00:00
Milo Ivir
196bbff103 Translated using Weblate (Croatian)
Currently translated at 100.0% (795 of 795 strings)

Co-authored-by: Milo Ivir <mail@milotype.de>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/hr/
Translation: Kotatsu/Strings
2025-03-14 19:37:51 +00:00
Anon
80b26e62e9 Translated using Weblate (Serbian)
Currently translated at 98.6% (784 of 795 strings)

Co-authored-by: Anon <anonymousprivate76@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/sr/
Translation: Kotatsu/Strings
2025-03-14 19:37:50 +00:00
Infy's Tagalog Translations
f877637fd2 Translated using Weblate (Filipino)
Currently translated at 99.7% (801 of 803 strings)

Translated using Weblate (Filipino)

Currently translated at 99.7% (793 of 795 strings)

Co-authored-by: Infy's Tagalog Translations <ced.paltep10@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fil/
Translation: Kotatsu/Strings
2025-03-14 19:37:49 +00:00
Frosted
5037b4ef84 Translated using Weblate (Turkish)
Currently translated at 100.0% (805 of 805 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (803 of 803 strings)

Translated using Weblate (Turkish)

Currently translated at 99.8% (802 of 803 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (799 of 799 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (798 of 798 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (795 of 795 strings)

Co-authored-by: Frosted <frosted@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/tr/
Translation: Kotatsu/Strings
2025-03-14 19:37:49 +00:00
gekka
11b7696d31 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 99.7% (801 of 803 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 99.7% (797 of 799 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 99.7% (796 of 798 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 99.7% (793 of 795 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 99.6% (792 of 795 strings)

Co-authored-by: gekka <1778962971@qq.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/
Translation: Kotatsu/Strings
2025-03-14 19:37:48 +00:00
Draken
4ad361dab8 Translated using Weblate (Vietnamese)
Currently translated at 100.0% (805 of 805 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (803 of 803 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (795 of 795 strings)

Co-authored-by: Draken <premieregirl26@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/vi/
Translation: Kotatsu/Strings
2025-03-14 19:37:47 +00:00
Nicola Bortoletto
1b88857e4d Translated using Weblate (Italian)
Currently translated at 100.0% (805 of 805 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (803 of 803 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (799 of 799 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (795 of 795 strings)

Translated using Weblate (Italian)

Currently translated at 99.8% (794 of 795 strings)

Co-authored-by: Nicola Bortoletto <nicola.bortoletto@live.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/it/
Translation: Kotatsu/Strings
2025-03-14 19:37:46 +00:00
Koitharu
7823bff063 Fixes and improvements batch 2025-03-14 20:59:37 +02:00
Koitharu
947de6c7c9 Fix tags highlighting 2025-03-11 08:44:55 +02:00
Koitharu
f689bf0cf7 Improve manga link sharing 2025-03-11 08:33:11 +02:00
Koitharu
b3028258ca Apply proxy settings to WebView 2025-03-08 18:51:03 +02:00
Koitharu
2c8476cabd Improve alternatives search functionality 2025-03-08 14:33:23 +02:00
Koitharu
5373e58807 UI tuning 2025-03-08 12:26:39 +02:00
Koitharu
4fdb781622 Merge pull request #1320 from dragonx943/patch-2
Update sync domain
2025-03-08 11:45:46 +02:00
Koitharu
0981ba771a Improve window insets handling 2025-03-08 10:40:20 +02:00
Koitharu
7cec7f5359 Fix window insets handling 2025-03-05 16:56:16 +02:00
Draken
8e55739685 Update constants.xml 2025-03-05 17:10:55 +07:00
Koitharu
d4a2d97071 Fixes 2025-03-04 14:33:50 +02:00
Koitharu
d51790811a Update error details dialog 2025-03-04 14:05:45 +02:00
Koitharu
93e8e87b03 Improve global search 2025-03-03 17:38:05 +02:00
Koitharu
09590cfab0 Update reader actions bar 2025-03-03 14:03:47 +02:00
Koitharu
5d91e20844 Update parsers and fix compatibility 2025-03-02 19:31:01 +02:00
Koitharu
d918b1e274 Fix database migration 2025-03-02 13:35:09 +02:00
Koitharu
7fc2d2f36f Fixes 2025-03-01 17:07:02 +02:00
Koitharu
7a01fdd04c Update parsers and adjust database 2025-02-28 15:35:56 +02:00
Koitharu
8724f5b30c Fixes 2025-02-27 09:36:32 +02:00
Koitharu
fcc05e5e5d Merge pull request #1312 from dragonx943/patch-2 2025-02-26 19:34:23 +02:00
Draken
f6284e7107 Use domain for sync server 2025-02-27 00:19:29 +07:00
Koitharu
5e9dc87470 Fixes and improvements batch 2025-02-26 16:51:33 +02:00
Koitharu
b2f0da9245 Fix "Deflater has been closed" error 2025-02-26 08:12:52 +02:00
Koitharu
b27d6dbe9a Refactor: change window insets handling approach 2025-02-26 08:06:57 +02:00
Koitharu
a7caf9848e Dynamic peek height for BS in details 2025-02-25 13:59:41 +02:00
Koitharu
8d44ad8866 Safe way to getQuantityString 2025-02-25 08:53:45 +02:00
Koitharu
e98f5b9d54 Fix locale changing 2025-02-24 19:58:44 +02:00
Koitharu
30d1d47cdc Fixes 2025-02-24 19:42:18 +02:00
Koitharu
8d7f44d2da Fix DateTimeAgo formatting
(cherry picked from commit 5f0514638a)
2025-02-24 18:09:03 +02:00
Koitharu
930d4dfd83 Fix checking for removed manga updates (close #1064)
(cherry picked from commit 1b8d35d424)
2025-02-24 18:07:49 +02:00
Koitharu
290cb652ee Update parsers 2025-02-24 18:05:51 +02:00
Koitharu
1fa470fd00 Option to disable captcha notification for specific source (#1253 #1300) 2025-02-24 14:57:45 +02:00
Koitharu
c835ebff3f Fix scrobbling bs ui (close #1304) 2025-02-24 13:58:14 +02:00
Koitharu
0e76e69aab Update parsers 2025-02-24 13:21:31 +02:00
Koitharu
1857d9f4e9 Merge pull request #1296 from weblate/weblate-kotatsu-strings
Translations update from Hosted Weblate
2025-02-24 12:55:59 +02:00
Макар Разин
34f13ebd52 Translated using Weblate (Russian)
Currently translated at 100.0% (793 of 793 strings)

Translated using Weblate (Belarusian)

Currently translated at 94.7% (751 of 793 strings)

Co-authored-by: Макар Разин <makarrazin14@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/be/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ru/
Translation: Kotatsu/Strings
2025-02-24 11:53:10 +01:00
Draken
2c4a71cbaa Translated using Weblate (Vietnamese)
Currently translated at 100.0% (793 of 793 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (793 of 793 strings)

Co-authored-by: Draken <premieregirl26@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/vi/
Translation: Kotatsu/Strings
2025-02-24 11:53:10 +01:00
Anon
48515a13da Translated using Weblate (Serbian)
Currently translated at 98.6% (782 of 793 strings)

Co-authored-by: Anon <anonymousprivate76@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/sr/
Translation: Kotatsu/Strings
2025-02-24 11:53:10 +01:00
Infy's Tagalog Translations
f42cda1584 Translated using Weblate (Filipino)
Currently translated at 99.7% (791 of 793 strings)

Co-authored-by: Infy's Tagalog Translations <ced.paltep10@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fil/
Translation: Kotatsu/Strings
2025-02-24 11:53:10 +01:00
Sixten Lund
3fbbb01e27 Translated using Weblate (Swedish)
Currently translated at 94.4% (749 of 793 strings)

Translated using Weblate (Swedish)

Currently translated at 100.0% (9 of 9 strings)

Translated using Weblate (Swedish)

Currently translated at 92.5% (734 of 793 strings)

Translated using Weblate (Swedish)

Currently translated at 68.8% (546 of 793 strings)

Translated using Weblate (Swedish)

Currently translated at 66.8% (530 of 793 strings)

Co-authored-by: Sixten Lund <arbitraryindices@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/plurals/sv/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/sv/
Translation: Kotatsu/Strings
Translation: Kotatsu/plurals
2025-02-24 11:53:10 +01:00
Frosted
182b8abd7a Translated using Weblate (Turkish)
Currently translated at 100.0% (793 of 793 strings)

Co-authored-by: Frosted <frosted@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/tr/
Translation: Kotatsu/Strings
2025-02-24 11:53:10 +01:00
Nicola Bortoletto
dd0445ee79 Translated using Weblate (Italian)
Currently translated at 100.0% (793 of 793 strings)

Co-authored-by: Nicola Bortoletto <nicola.bortoletto@live.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/it/
Translation: Kotatsu/Strings
2025-02-24 11:53:10 +01:00
Koitharu
d10b64c17f Merge pull request #1297 from dragonx943/patch-2
Add new sync server (Singapore)
2025-02-24 12:53:06 +02:00
Koitharu
ea13c7dbd8 Use WakeLock for background operations 2025-02-23 19:10:05 +02:00
Koitharu
fc5ad9ff90 Include reader tap settings into backups 2025-02-23 18:48:37 +02:00
Koitharu
4cee432a82 Dim navbar in details 2025-02-23 18:06:35 +02:00
Draken
d7c8b12d66 Update constants.xml 2025-02-22 15:13:40 +07:00
Koitharu
87a05ed28a Fix author search 2025-02-20 18:01:16 +02:00
Koitharu
87c242e2bb Dim navbar in details screen 2025-02-20 17:51:47 +02:00
Koitharu
1a7b9c6969 Fix nightly launcher icon 2025-02-20 16:39:12 +02:00
Koitharu
2786e1a2d5 Revert readme updates 2025-02-18 20:18:48 +02:00
Koitharu
05c37da667 Fix build 2025-02-18 20:14:52 +02:00
Koitharu
ed9ed8e964 Fix warnings 2025-02-18 20:08:03 +02:00
Johan Eliott Liebwert
cb36772fd9 Translated using Weblate (Czech)
Currently translated at 100.0% (789 of 789 strings)

Co-authored-by: Johan Eliott Liebwert <joelli@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/cs/
Translation: Kotatsu/Strings
2025-02-18 20:05:00 +02:00
Sixten Lund
cc8e31995b Translated using Weblate (Swedish)
Currently translated at 66.0% (521 of 789 strings)

Translated using Weblate (Swedish)

Currently translated at 44.4% (351 of 789 strings)

Co-authored-by: Sixten Lund <arbitraryindices@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/sv/
Translation: Kotatsu/Strings
2025-02-18 20:05:00 +02:00
Priit Jõerüüt
82cd8024e9 Translated using Weblate (Estonian)
Currently translated at 69.7% (550 of 789 strings)

Co-authored-by: Priit Jõerüüt <hwlate@joeruut.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/et/
Translation: Kotatsu/Strings
2025-02-18 20:05:00 +02:00
Anon
ffc7222b3f Translated using Weblate (Serbian)
Currently translated at 98.7% (779 of 789 strings)

Co-authored-by: Anon <anonymousprivate76@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/sr/
Translation: Kotatsu/Strings
2025-02-18 20:05:00 +02:00
Master Dwarf
08c48e9997 Translated using Weblate (Portuguese)
Currently translated at 99.8% (788 of 789 strings)

Co-authored-by: Master Dwarf <aoc.anao78@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pt/
Translation: Kotatsu/Strings
2025-02-18 20:05:00 +02:00
Draken
32b6db7343 Translated using Weblate (Vietnamese)
Currently translated at 100.0% (792 of 792 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (790 of 790 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (789 of 789 strings)

Co-authored-by: Draken <premieregirl26@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/vi/
Translation: Kotatsu/Strings
2025-02-18 20:05:00 +02:00
Infy's Tagalog Translations
4dfe0f0d88 Translated using Weblate (Filipino)
Currently translated at 99.8% (788 of 789 strings)

Co-authored-by: Infy's Tagalog Translations <ced.paltep10@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fil/
Translation: Kotatsu/Strings
2025-02-18 20:05:00 +02:00
gekka
0e2224eaf7 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (789 of 789 strings)

Co-authored-by: gekka <1778962971@qq.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/
Translation: Kotatsu/Strings
2025-02-18 20:05:00 +02:00
Koitharu
151777cf61 UI improvements and author search support 2025-02-18 19:29:14 +02:00
Koitharu
47a22064a5 Merge pull request #1295 from MAPKOBKA135/devel
fix 100% problem
2025-02-18 15:29:09 +02:00
Koitharu
1b8d35d424 Fix checking for removed manga updates (close #1064) 2025-02-18 15:27:10 +02:00
Koitharu
604efef832 Improve global search 2025-02-18 15:20:25 +02:00
Koitharu
6f67bd7542 Bring back reader info bar outline 2025-02-18 14:37:34 +02:00
Mac135135
52592ba765 correct display of a fully read manga
shows 100% in the details menu if the manga has actually been read in full.
2025-02-18 01:24:48 +03:00
Mac135135
9bb97c72a1 "Check mark" fix on cover
if the manga has been read in full, the "check mark" will be displayed correctly on the cover
2025-02-18 00:46:03 +03:00
Koitharu
b44cf370aa Fix favorite categories visibility (close #1281) 2025-02-17 18:06:20 +02:00
Koitharu
74900970e1 Advanced global search 2025-02-17 17:56:45 +02:00
Koitharu
4ee52e149e Configurable manga lists badges 2025-02-16 19:20:01 +02:00
Koitharu
4148f4a4b9 Update dependencies 2025-02-16 16:26:41 +02:00
Koitharu
a59b6a418d Merge pull request #1291 from TheBestF22/FutureProofing-Local-indexes
Future-Proofing Local Storage by Updating Local Archive indexes/Padding for Pages and Chapters - devel branch
2025-02-16 16:21:18 +02:00
TheBest_F-22!.
d6ae67ba07 Merge branch 'devel' into FutureProofing-Local-indexes 2025-02-16 07:57:35 +00:00
TheBest_F-22!.
be455bc897 Future-Proofing Chapters and Pages Local Storage indexes.
Closes #1289 .
2025-02-16 07:22:44 +00:00
Koitharu
129035bda3 Fix picking directory on some devices 2025-02-15 11:24:31 +02:00
Koitharu
d558c2fcc0 Saved and favorites indicators in manga lists (Draft implementation)(#1286) 2025-02-15 10:53:29 +02:00
Koitharu
cb5df0d73f UI fixes 2025-02-11 14:39:35 +02:00
Koitharu
19e8e3a618 Update kotlin to 2.1 2025-02-11 14:23:18 +02:00
Koitharu
5f0514638a Fix DateTimeAgo formatting 2025-02-09 17:40:28 +02:00
Koitharu
28ae785142 Fix bottom navigation height 2025-02-09 17:03:46 +02:00
Koitharu
8c59f97b02 Merge branch 'master' into devel 2025-02-09 10:55:55 +02:00
Koitharu
8a26587250 Database migration for downgrade from 24 to 23 (#1269, #1270) 2025-02-09 10:15:24 +02:00
Koitharu
bb68869fe1 Fix crashes 2025-02-09 10:11:24 +02:00
Koitharu
e60ca7115a Update parsers 2025-02-09 10:01:28 +02:00
Koitharu
ee4a780acf Update parsers 2025-02-08 17:04:22 +02:00
gekka
8dd6ce2739 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 99.8% (788 of 789 strings)

Co-authored-by: gekka <1778962971@qq.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/
Translation: Kotatsu/Strings
2025-02-08 16:44:06 +02:00
Deleted User
41ad7e90d3 Translated using Weblate (Italian)
Currently translated at 100.0% (789 of 789 strings)

Co-authored-by: Deleted User <noreply+104791@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/it/
Translation: Kotatsu/Strings
2025-02-08 16:44:06 +02:00
大王叫我来巡山
31be55d67a Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (784 of 784 strings)

Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/
Translation: Kotatsu/Strings
2025-02-08 16:44:06 +02:00
Dragibus Noir
a50b83d876 Translated using Weblate (French)
Currently translated at 99.8% (783 of 784 strings)

Co-authored-by: Dragibus Noir <dragibusnoir@pm.me>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fr/
Translation: Kotatsu/Strings
2025-02-08 16:44:06 +02:00
gekka
68ce789db1 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (782 of 782 strings)

Co-authored-by: gekka <1778962971@qq.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/
Translation: Kotatsu/Strings
2025-02-08 16:44:06 +02:00
urfv ksnph
4702862af3 Translated using Weblate (Indonesian)
Currently translated at 98.2% (768 of 782 strings)

Co-authored-by: urfv ksnph <urfvksnph@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/id/
Translation: Kotatsu/Strings
2025-02-08 16:44:06 +02:00
Frosted
c403705b48 Translated using Weblate (Turkish)
Currently translated at 100.0% (789 of 789 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (784 of 784 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (782 of 782 strings)

Co-authored-by: Frosted <frosted@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/tr/
Translation: Kotatsu/Strings
2025-02-08 16:44:06 +02:00
Nicola Bortoletto
22a5f2d5ee Translated using Weblate (Italian)
Currently translated at 100.0% (782 of 782 strings)

Co-authored-by: Nicola Bortoletto <nicola.bortoletto@live.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/it/
Translation: Kotatsu/Strings
2025-02-08 16:44:06 +02:00
Infy's Tagalog Translations
0f1d8d2835 Translated using Weblate (Filipino)
Currently translated at 99.7% (787 of 789 strings)

Translated using Weblate (Filipino)

Currently translated at 100.0% (781 of 781 strings)

Co-authored-by: Infy's Tagalog Translations <ced.paltep10@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fil/
Translation: Kotatsu/Strings
2025-02-08 16:44:06 +02:00
Bruno Fragoso
1a6b1672b3 Translated using Weblate (Portuguese)
Currently translated at 100.0% (782 of 782 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (781 of 781 strings)

Co-authored-by: Bruno Fragoso <darth_signa@hotmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pt/
Translation: Kotatsu/Strings
2025-02-08 16:44:06 +02:00
Juan Rubin
8e6006177b Translated using Weblate (Portuguese)
Currently translated at 99.7% (779 of 781 strings)

Co-authored-by: Juan Rubin <juancrubin08@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pt/
Translation: Kotatsu/Strings
2025-02-08 16:44:06 +02:00
Draken
4e2f010260 Translated using Weblate (Vietnamese)
Currently translated at 100.0% (789 of 789 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (782 of 782 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (781 of 781 strings)

Co-authored-by: Draken <premieregirl26@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/vi/
Translation: Kotatsu/Strings
2025-02-08 16:44:06 +02:00
Nizar Yazidi
8a191f8f04 Translated using Weblate (Italian)
Currently translated at 100.0% (781 of 781 strings)

Co-authored-by: Nizar Yazidi <fedekikamakeup@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/it/
Translation: Kotatsu/Strings
2025-02-08 16:44:06 +02:00
Milan Bhandari
88aca02234 Translated using Weblate (Nepali)
Currently translated at 31.6% (247 of 781 strings)

Co-authored-by: Milan Bhandari <milanbhandari604@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ne/
Translation: Kotatsu/Strings
2025-02-08 16:44:06 +02:00
Hosted Weblate
9189307d00 Update translation files
Updated by "Remove blank strings" hook in Weblate.

Update translation files

Updated by "Remove blank strings" hook in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/
Translation: Kotatsu/Strings
2025-02-08 16:44:06 +02:00
zmni
00fc579824 Translated using Weblate (Indonesian)
Currently translated at 97.9% (765 of 781 strings)

Translated using Weblate (Indonesian)

Currently translated at 97.9% (765 of 781 strings)

Co-authored-by: zmni <zmni@outlook.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/id/
Translation: Kotatsu/Strings
2025-02-08 16:44:06 +02:00
Anon
7f8d78e0c9 Translated using Weblate (Serbian)
Currently translated at 98.6% (778 of 789 strings)

Translated using Weblate (Serbian)

Currently translated at 99.2% (775 of 781 strings)

Co-authored-by: Anon <anonymousprivate76@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/sr/
Translation: Kotatsu/Strings
2025-02-08 16:44:06 +02:00
Alvoracz
13bd3e918e Translated using Weblate (Czech)
Currently translated at 98.2% (767 of 781 strings)

Translated using Weblate (Czech)

Currently translated at 97.1% (759 of 781 strings)

Co-authored-by: Alvoracz <sedlor@seznam.cz>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/cs/
Translation: Kotatsu/Strings
2025-02-08 16:44:06 +02:00
Koitharu
e1c46f0604 Fix closing welcome bottom sheet 2025-02-05 17:43:02 +02:00
Koitharu
79f3fe196c Update emoji flags mapping 2025-02-05 16:57:18 +02:00
Koitharu
87a47207ab Save page button in reader 2025-02-05 16:06:53 +02:00
Koitharu
772fd5cc6a Screen rotation button in reader 2025-02-05 15:54:54 +02:00
Koitharu
26a2ffcbb1 Reader bottom bar actions configurable 2025-02-05 14:56:41 +02:00
Koitharu
cfecfce51e Update parsers 2025-02-03 18:56:05 +02:00
Koitharu
23c814bf53 Allow to keep user data on app removal 2025-02-03 18:56:04 +02:00
Koitharu
8ca11b214c Reorganize storage usage settings 2025-02-03 18:56:04 +02:00
Koitharu
008f2d705a Restore backups in background 2025-02-03 18:56:00 +02:00
ViAnh
c37f795dac Fix scroller handle being cut off 2025-02-03 18:21:03 +02:00
Koitharu
5d74bdd3b4 Fix reader info bar background settings 2025-02-02 11:56:08 +02:00
Koitharu
382b44accc Transparent reader info bar option 2025-02-01 09:33:11 +02:00
Koitharu
78cd0eff09 Fix reader info bar icon color 2025-02-01 09:33:11 +02:00
Koitharu
12c954600f Merge pull request #1256 from dragonx943/telegram-feature 2025-01-30 09:58:23 +02:00
Talkc0n
a7d4f3b784 Add Telegram backup feature 2025-01-30 14:09:16 +07:00
Koitharu
91f9feba59 Fix details ui 2025-01-30 08:44:01 +02:00
Koitharu
e03a200c32 Fix build 2025-01-25 12:51:13 +02:00
Koitharu
8713faa487 Update parsers 2025-01-25 12:14:01 +02:00
Koitharu
15e99c03a9 Update parsers and adjust imports
(cherry picked from commit 5e8aa4cec7)
2025-01-22 20:21:43 +02:00
Koitharu
b3933848e9 Local manga parsing fixes 2025-01-22 10:15:12 +02:00
Koitharu
e39e5bf9c4 Remove Telegram backup functionality 2025-01-22 09:18:13 +02:00
Koitharu
3a42dce45f Support nested cbz covers 2025-01-19 16:26:00 +02:00
Koitharu
169539f42f Support closing Okio FileSystem 2025-01-19 15:18:07 +02:00
Koitharu
6360731f34 Update reader info bar 2025-01-19 15:02:34 +02:00
Koitharu
914dd9670a Option to disable LeakCanary in debug builds 2025-01-19 13:48:55 +02:00
Koitharu
498b9aed26 Track services using LeakCanary 2025-01-19 13:18:19 +02:00
Koitharu
b425f3e779 Fix nullability for ParcelableManga
(cherry picked from commit b8b601821a)
2025-01-19 12:00:38 +02:00
Koitharu
c6a51d4d08 Increase version 2025-01-19 11:56:26 +02:00
Koitharu
b8b601821a Fix nullability for ParcelableManga 2025-01-19 11:55:13 +02:00
Koitharu
5e8aa4cec7 Update parsers and adjust imports 2025-01-19 11:53:38 +02:00
Koitharu
54bb02937d Merge branch 'master' into devel 2025-01-19 10:33:34 +02:00
Koitharu
74fe786c00 Detect miui 2025-01-19 09:45:51 +02:00
Koitharu
503bff292c Made SyncAuthActivity exported
(cherry picked from commit 663602282a)
2025-01-19 08:28:02 +02:00
Koitharu
0aa78c0d7e Adjust manga fields nullability 2025-01-19 08:24:25 +02:00
Koitharu
8e1d02f356 Update parsers 2025-01-19 08:01:09 +02:00
Koitharu
e8f9d22128 Update dependencies 2025-01-18 15:24:45 +02:00
Draken
fa60ae2947 Add new resources (#1242) 2025-01-17 15:55:35 +02:00
Koitharu
663602282a Made SyncAuthActivity exported 2025-01-13 20:01:22 +02:00
Koitharu
98dbc20cb0 Update parsers and adjust fields nullability 2025-01-13 20:01:22 +02:00
Draken
cc28293bed Update docs (README file) (#1238)
* Update README + Add new images

* [Docs] Tweak + Fixes

* [Docs] Fix image size

* Add some informations + Docs

* [vi] Update screenshots

* Add new counter

* Fix color

* [ru] Add new screenshots

* Update readme

* Update Readme

* Update Readme

* Update Readme

* Refactor images

* Refactor images

* Fix refactor images

* Update descriptions

* Fix themes

* Fix themes

* Final ?

---------

Co-authored-by: Draken <dragonx943@users.noreply.github.com>
2025-01-11 15:36:36 +02:00
Koitharu
1e90d5541b Update parsers 2025-01-11 15:09:21 +02:00
Koitharu
04c7ca7291 Improve local manga chapter names
(cherry picked from commit dddb00d5ef)
2025-01-11 14:59:38 +02:00
Koitharu
8d52cab6d8 Fix manga importing
(cherry picked from commit dcb92ed1af)
2025-01-11 14:59:33 +02:00
Koitharu
efa13df106 Fix crashes 2025-01-11 14:59:25 +02:00
Koitharu
8bc29ac331 Fix local chapters deletion
(cherry picked from commit 25eb05d305)
2025-01-11 14:58:53 +02:00
Koitharu
7991f9ca97 Skip description for ParcelableManga
(cherry picked from commit bf217b3cbf)
2025-01-11 14:58:44 +02:00
Koitharu
eb1eee1681 Fix pages cache usage
(cherry picked from commit 9e2b60e15e)
2025-01-11 14:57:56 +02:00
Koitharu
b3f748c000 Fix crashes
(cherry picked from commit 4dba90361c)
2025-01-11 14:57:49 +02:00
Koitharu
58a9f7b25a Fix settings menu
(cherry picked from commit c51218240e)
2025-01-11 14:56:13 +02:00
Koitharu
dddb00d5ef Improve local manga chapter names 2025-01-11 14:54:02 +02:00
Koitharu
c9d878a0b7 Upgrade agp 2025-01-11 14:37:49 +02:00
Koitharu
dcb92ed1af Fix manga importing 2025-01-11 14:37:30 +02:00
Maple Javora
749bc4a837 Translated using Weblate (Czech)
Currently translated at 97.0% (758 of 781 strings)

Co-authored-by: Maple Javora <jindrous101@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/cs/
Translation: Kotatsu/Strings
2025-01-11 11:21:58 +01:00
Alvoracz
94807b7788 Translated using Weblate (Czech)
Currently translated at 97.0% (758 of 781 strings)

Translated using Weblate (Czech)

Currently translated at 94.2% (736 of 781 strings)

Co-authored-by: Alvoracz <sedlor@seznam.cz>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/cs/
Translation: Kotatsu/Strings
2025-01-11 11:21:58 +01:00
Maple Javora
0fe7c66850 Translated using Weblate (Czech)
Currently translated at 94.3% (737 of 781 strings)

Translated using Weblate (Czech)

Currently translated at 94.2% (736 of 781 strings)

Co-authored-by: Maple Javora <jindrous101@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/cs/
Translation: Kotatsu/Strings
2025-01-11 11:21:58 +01:00
Alvoracz
20cd8413dc Translated using Weblate (Czech)
Currently translated at 94.2% (736 of 781 strings)

Co-authored-by: Alvoracz <sedlor@seznam.cz>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/cs/
Translation: Kotatsu/Strings
2025-01-11 11:21:58 +01:00
தமிழ்நேரம்
30df4ede6c Translated using Weblate (Tamil)
Currently translated at 100.0% (781 of 781 strings)

Translated using Weblate (Tamil)

Currently translated at 100.0% (9 of 9 strings)

Added translation using Weblate (Tamil)

Added translation using Weblate (Tamil)

Co-authored-by: தமிழ்நேரம் <anishprabu.t@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/plurals/ta/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ta/
Translation: Kotatsu/Strings
Translation: Kotatsu/plurals
2025-01-11 11:21:58 +01:00
Milan Bhandari
4aa6baf569 Translated using Weblate (Nepali)
Currently translated at 30.7% (240 of 781 strings)

Co-authored-by: Milan Bhandari <githubmilan@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ne/
Translation: Kotatsu/Strings
2025-01-11 11:21:58 +01:00
abdelbasset jabrane
d8a4303c50 Translated using Weblate (Arabic)
Currently translated at 100.0% (781 of 781 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (781 of 781 strings)

Co-authored-by: abdelbasset jabrane <ribago9317@cubene.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ar/
Translation: Kotatsu/Strings
2025-01-11 11:21:58 +01:00
Макар Разин
b355e2ee88 Translated using Weblate (Russian)
Currently translated at 100.0% (781 of 781 strings)

Co-authored-by: Макар Разин <makarrazin14@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ru/
Translation: Kotatsu/Strings
2025-01-11 11:21:58 +01:00
Infy's Tagalog Translations
55e3b5fb9b Translated using Weblate (Filipino)
Currently translated at 100.0% (781 of 781 strings)

Co-authored-by: Infy's Tagalog Translations <ced.paltep10@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fil/
Translation: Kotatsu/Strings
2025-01-11 11:21:58 +01:00
gekka
a59853e37a Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (781 of 781 strings)

Co-authored-by: gekka <1778962971@qq.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/
Translation: Kotatsu/Strings
2025-01-11 11:21:58 +01:00
Milo Ivir
ccc665d218 Translated using Weblate (Croatian)
Currently translated at 99.7% (776 of 778 strings)

Co-authored-by: Milo Ivir <mail@milotype.de>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/hr/
Translation: Kotatsu/Strings
2025-01-11 11:21:58 +01:00
Anon
02650f5c2a Translated using Weblate (Serbian)
Currently translated at 98.5% (767 of 778 strings)

Co-authored-by: Anon <anonymousprivate76@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/sr/
Translation: Kotatsu/Strings
2025-01-11 11:21:58 +01:00
Hugo Cardoso
24172a1137 Translated using Weblate (Portuguese (Brazil))
Currently translated at 99.4% (774 of 778 strings)

Translated using Weblate (Portuguese)

Currently translated at 99.4% (774 of 778 strings)

Co-authored-by: Hugo Cardoso <hugocardosolopes@hotmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pt/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pt_BR/
Translation: Kotatsu/Strings
2025-01-11 11:21:58 +01:00
Draken
034d69d490 Translated using Weblate (Vietnamese)
Currently translated at 100.0% (781 of 781 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (781 of 781 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (778 of 778 strings)

Co-authored-by: Draken <premieregirl26@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/vi/
Translation: Kotatsu/Strings
2025-01-11 11:21:58 +01:00
Justine Kyle Cobar
12fc0542d3 Translated using Weblate (Filipino)
Currently translated at 100.0% (778 of 778 strings)

Co-authored-by: Justine Kyle Cobar <cobarjustinekyle583@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fil/
Translation: Kotatsu/Strings
2025-01-11 11:21:58 +01:00
Nicola Bortoletto
dcf80ed396 Translated using Weblate (Italian)
Currently translated at 100.0% (781 of 781 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (778 of 778 strings)

Co-authored-by: Nicola Bortoletto <nicola.bortoletto@live.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/it/
Translation: Kotatsu/Strings
2025-01-11 11:21:58 +01:00
Dragibus Noir
28badb7f6c Translated using Weblate (French)
Currently translated at 100.0% (781 of 781 strings)

Translated using Weblate (French)

Currently translated at 100.0% (778 of 778 strings)

Translated using Weblate (French)

Currently translated at 99.8% (777 of 778 strings)

Co-authored-by: Dragibus Noir <dragibusnoir@pm.me>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fr/
Translation: Kotatsu/Strings
2025-01-11 11:21:58 +01:00
Itsmechinmoy
19cc158ef8 Translated using Weblate (Assamese)
Currently translated at 100.0% (9 of 9 strings)

Added translation using Weblate (Assamese)

Co-authored-by: Itsmechinmoy <itsmechinmoy@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/plurals/as/
Translation: Kotatsu/plurals
2025-01-11 11:21:57 +01:00
大王叫我来巡山
a2eeae3319 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (778 of 778 strings)

Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/
Translation: Kotatsu/Strings
2025-01-11 11:21:57 +01:00
Frosted
c9336a753d Translated using Weblate (Turkish)
Currently translated at 100.0% (781 of 781 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (778 of 778 strings)

Co-authored-by: Frosted <frosted@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/tr/
Translation: Kotatsu/Strings
2025-01-11 11:21:57 +01:00
Anonymous
ea23468ecd Translated using Weblate (French)
Currently translated at 99.2% (772 of 778 strings)

Co-authored-by: Anonymous <noreply@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fr/
Translation: Kotatsu/Strings
2025-01-11 11:21:57 +01:00
Koitharu
143643fcd8 Fix crashes 2025-01-11 12:21:40 +02:00
Koitharu
25eb05d305 Fix local chapters deletion 2025-01-09 08:41:27 +02:00
Koitharu
bf217b3cbf Skip description for ParcelableManga 2025-01-09 08:32:53 +02:00
Koitharu
9e2b60e15e Fix pages cache usage 2025-01-09 08:26:43 +02:00
Koitharu
4dba90361c Fix crashes 2025-01-09 08:19:43 +02:00
Koitharu
8dea483f64 Fix drawables state 2025-01-05 10:17:40 +02:00
Koitharu
dc2e603356 Improve drawable and views state management 2025-01-04 16:22:13 +02:00
Koitharu
14973298a0 Emoji flags in details 2025-01-04 13:53:13 +02:00
Koitharu
7efc47724e Improve mime-type handling 2025-01-04 12:01:48 +02:00
Koitharu
c51218240e Fix settings menu 2025-01-02 15:45:17 +02:00
Koitharu
2762caaa8f Option to enable all sources 2025-01-02 15:38:43 +02:00
Koitharu
70d66e5a90 Merge branch 'master' into devel 2025-01-01 15:39:51 +02:00
Koitharu
fc1d704f6f Fix build 2025-01-01 14:24:43 +02:00
Koitharu
c2c3b0f757 Fix details cover corners 2025-01-01 14:00:04 +02:00
Koitharu
8d519dd80f Fix settings search 2025-01-01 13:59:59 +02:00
Koitharu
3b5a9cd2b4 Skip non-existing local chapters 2025-01-01 13:59:54 +02:00
Koitharu
95f4d39893 Update parsers 2025-01-01 13:53:17 +02:00
Koitharu
3173e30caf Fix details cover corners 2025-01-01 13:49:14 +02:00
Koitharu
0dccc66f54 Fix settings search 2025-01-01 13:36:02 +02:00
Koitharu
6b3dd23c01 UI fixes 2025-01-01 12:36:52 +02:00
Koitharu
1c6a125174 Skip non-existing local chapters 2025-01-01 12:16:28 +02:00
Koitharu
f3f269c7fa Fix NPE in SyncSettings 2024-12-30 10:01:08 +02:00
Koitharu
15f37644c0 Update list badges 2024-12-30 09:48:50 +02:00
Koitharu
c2079ebca5 Update dependencies 2024-12-30 07:51:45 +02:00
Koitharu
1146269992 Merge branch 'weblate-kotatsu-strings' of github.com:weblate/Kotatsu into weblate-weblate-kotatsu-strings 2024-12-23 10:43:10 +02:00
Koitharu
099362d198 Update reader ui 2024-12-23 10:38:27 +02:00
Koitharu
22d203fc60 Fix Telegram backups uploading 2024-12-22 09:01:18 +02:00
Anonymous
19602144ef Translated using Weblate (Norwegian Nynorsk)
Currently translated at 48.8% (380 of 778 strings)

Translated using Weblate (Finnish)

Currently translated at 33.0% (257 of 778 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 36.6% (285 of 778 strings)

Co-authored-by: Anonymous <noreply@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fi/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/nn/
Translation: Kotatsu/Strings
2024-12-22 05:01:27 +00:00
Lennard
44bbcd7fe3 Translated using Weblate (Lithuanian)
Currently translated at 5.6% (44 of 778 strings)

Translated using Weblate (Punjabi)

Currently translated at 4.2% (33 of 778 strings)

Translated using Weblate (Czech)

Currently translated at 86.7% (675 of 778 strings)

Translated using Weblate (Arabic)

Currently translated at 85.8% (668 of 778 strings)

Translated using Weblate (English)

Currently translated at 100.0% (778 of 778 strings)

Co-authored-by: Lennard <lennardsdrojek42@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ar/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/cs/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/en/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/lt/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pa/
Translation: Kotatsu/Strings
2024-12-22 05:01:25 +00:00
Frosted
efe5e07c2c Translated using Weblate (Turkish)
Currently translated at 100.0% (778 of 778 strings)

Translated using Weblate (Turkish)

Currently translated at 99.6% (775 of 778 strings)

Translated using Weblate (Turkish)

Currently translated at 98.7% (766 of 776 strings)

Co-authored-by: Frosted <frosted@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/tr/
Translation: Kotatsu/Strings
2024-12-22 05:01:24 +00:00
Geovani Amaral
4e633ff735 Translated using Weblate (Portuguese)
Currently translated at 100.0% (776 of 776 strings)

Co-authored-by: Geovani Amaral <geovani.af4@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pt/
Translation: Kotatsu/Strings
2024-12-22 05:01:21 +00:00
Dragibus Noir
fef8333763 Translated using Weblate (French)
Currently translated at 99.7% (774 of 776 strings)

Co-authored-by: Dragibus Noir <dragibusnoir@pm.me>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fr/
Translation: Kotatsu/Strings
2024-12-22 05:01:20 +00:00
大王叫我来巡山
a741f8451a Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (778 of 778 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (776 of 776 strings)

Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/
Translation: Kotatsu/Strings
2024-12-22 05:01:18 +00:00
Draken
55baf5a3f3 Translated using Weblate (Vietnamese)
Currently translated at 99.8% (777 of 778 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (776 of 776 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (772 of 772 strings)

Co-authored-by: Draken <premieregirl26@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/vi/
Translation: Kotatsu/Strings
2024-12-22 05:01:16 +00:00
Anon
6390774d86 Translated using Weblate (Serbian)
Currently translated at 99.0% (769 of 776 strings)

Translated using Weblate (Serbian)

Currently translated at 99.0% (769 of 776 strings)

Translated using Weblate (Serbian)

Currently translated at 99.2% (766 of 772 strings)

Co-authored-by: Anon <anonymousprivate76@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/sr/
Translation: Kotatsu/Strings
2024-12-22 05:01:13 +00:00
gekka
51a5128e70 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (772 of 772 strings)

Co-authored-by: gekka <1778962971@qq.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/
Translation: Kotatsu/Strings
2024-12-22 05:01:12 +00:00
Erekotr
53d81507e4 Translated using Weblate (Turkish)
Currently translated at 98.9% (764 of 772 strings)

Co-authored-by: Erekotr <ereko1ereko55@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/tr/
Translation: Kotatsu/Strings
2024-12-22 05:01:11 +00:00
gallegonovato
dcf7236ba2 Translated using Weblate (Spanish)
Currently translated at 100.0% (776 of 776 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (772 of 772 strings)

Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/es/
Translation: Kotatsu/Strings
2024-12-22 05:01:09 +00:00
Koitharu
a54744abc6 Option to clear manga database 2024-12-20 12:30:48 +02:00
Koitharu
22e2411c77 Cache chapters list (close #812) 2024-12-20 11:33:16 +02:00
Koitharu
3f66c142b8 Merge branch 'master' into devel 2024-12-19 18:30:16 +02:00
Koitharu
40f262b0ef Update parsers 2024-12-19 17:28:12 +02:00
Koitharu
0f68be9663 Use advanced bitmap decoder for MangaLoaderContext 2024-12-19 17:10:01 +02:00
Koitharu
0b8afe9c40 Fix checking for new chapters in some cases (#1212, #1195, #1190) 2024-12-18 18:26:27 +02:00
Koitharu
734846a018 Fix checking for new chapters in some cases (#1212, #1195, #1190) 2024-12-18 18:24:41 +02:00
Koitharu
754ccc4197 Added url for NoDataReceivedException 2024-12-18 16:26:49 +02:00
Koitharu
ef691b1aed Update parsers 2024-12-18 15:48:57 +02:00
Koitharu
e75035b33a Update parsers 2024-12-18 15:38:56 +02:00
Koitharu
f675c606a2 Refactor navigation 2024-12-18 12:00:25 +02:00
Koitharu
a5199e2f06 New favorite dialog 2024-12-16 19:17:25 +02:00
Koitharu
1b80e48ed4 Telegram backups refactoring stage 2 2024-12-15 09:44:57 +02:00
Koitharu
07e81f21c7 Telegram backups refactoring stage 1 2024-12-14 16:26:37 +02:00
Koitharu
0dbd01f6fc Merge branch 'MAPKOBKA135-devel' into devel 2024-12-14 15:48:18 +02:00
Koitharu
4b453b58dd Fix reader slider visibility 2024-12-14 15:48:09 +02:00
Koitharu
1575bb5242 Merge branch 'devel' of github.com:MAPKOBKA135/Kotatsu into MAPKOBKA135-devel 2024-12-14 15:47:41 +02:00
Infy's Tagalog Translations
55137cf899 Translated using Weblate (Filipino)
Currently translated at 99.4% (762 of 766 strings)

Co-authored-by: Infy's Tagalog Translations <ced.paltep10@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fil/
Translation: Kotatsu/Strings
2024-12-14 15:41:11 +02:00
Lennard
f190ff810e Translated using Weblate (German)
Currently translated at 83.3% (639 of 767 strings)

Translated using Weblate (German)

Currently translated at 83.0% (636 of 766 strings)

Co-authored-by: Lennard <lennardsdrojek42@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/de/
Translation: Kotatsu/Strings
2024-12-14 15:41:11 +02:00
Anon
47c13b46f7 Translated using Weblate (Serbian)
Currently translated at 99.6% (761 of 764 strings)

Translated using Weblate (Serbian)

Currently translated at 99.6% (759 of 762 strings)

Co-authored-by: Anon <anonymousprivate76@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/sr/
Translation: Kotatsu/Strings
2024-12-14 15:41:11 +02:00
Frosted
2ad9f38906 Translated using Weblate (Turkish)
Currently translated at 100.0% (762 of 762 strings)

Co-authored-by: Frosted <frosted@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/tr/
Translation: Kotatsu/Strings
2024-12-14 15:41:11 +02:00
gekka
2783c62ace Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (766 of 766 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (762 of 762 strings)

Co-authored-by: gekka <1778962971@qq.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/
Translation: Kotatsu/Strings
2024-12-14 15:41:11 +02:00
Draken
c1a65f8055 Translated using Weblate (Vietnamese)
Currently translated at 100.0% (766 of 766 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (764 of 764 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (762 of 762 strings)

Co-authored-by: Draken <premieregirl26@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/vi/
Translation: Kotatsu/Strings
2024-12-14 15:41:11 +02:00
大王叫我来巡山
6e5d8e99ca Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (764 of 764 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (762 of 762 strings)

Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/
Translation: Kotatsu/Strings
2024-12-14 15:41:11 +02:00
Dragibus Noir
020c3b8bba Translated using Weblate (French)
Currently translated at 99.8% (763 of 764 strings)

Translated using Weblate (French)

Currently translated at 99.8% (761 of 762 strings)

Translated using Weblate (French)

Currently translated at 99.7% (760 of 762 strings)

Co-authored-by: Dragibus Noir <dragibusnoir@pm.me>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fr/
Translation: Kotatsu/Strings
2024-12-14 15:41:11 +02:00
Koitharu
76162a06e3 Reader ui updates 2024-12-14 15:39:13 +02:00
Koitharu
19f398d309 Merge branch 'master' into devel 2024-12-14 14:25:48 +02:00
Koitharu
1bd916371a Update parsers 2024-12-14 09:36:50 +02:00
Koitharu
25ae23963e Update reader interface 2024-12-14 09:26:01 +02:00
Koitharu
146ba95af6 Details activity improvements 2024-12-11 13:22:07 +02:00
Koitharu
cd40dab8a4 Error handling fixes 2024-12-10 14:29:55 +02:00
Koitharu
ee10b013a1 Branch selection in chapters list 2024-12-08 19:26:18 +02:00
Koitharu
8c79df3d35 Details ui updates 2024-12-08 18:20:46 +02:00
Koitharu
2c2db1ca96 Rollback kotlin 2024-12-08 09:58:18 +02:00
Koitharu
f556c0b127 Merge branch 'master' into devel 2024-12-07 15:55:32 +02:00
Koitharu
d2ed8a1ace Update parsers 2024-12-07 15:18:18 +02:00
حيدر العراقي
024e3c11ee Translated using Weblate (Arabic)
Currently translated at 88.0% (668 of 759 strings)

Co-authored-by: حيدر العراقي <haiderdc12@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ar/
Translation: Kotatsu/Strings
2024-12-07 15:17:34 +02:00
return_null
23ba302df8 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (759 of 759 strings)

Co-authored-by: return_null <demolang@dismail.de>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/
Translation: Kotatsu/Strings
2024-12-07 15:17:34 +02:00
maryush
34e54e43e0 Translated using Weblate (Polish)
Currently translated at 100.0% (759 of 759 strings)

Co-authored-by: maryush <maryush@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pl/
Translation: Kotatsu/Strings
2024-12-07 15:17:34 +02:00
Anon
07a8de6225 Translated using Weblate (Serbian)
Currently translated at 99.6% (756 of 759 strings)

Co-authored-by: Anon <anonymousprivate76@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/sr/
Translation: Kotatsu/Strings
2024-12-07 15:17:34 +02:00
gallegonovato
a3df6f799c Translated using Weblate (Spanish)
Currently translated at 100.0% (759 of 759 strings)

Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/es/
Translation: Kotatsu/Strings
2024-12-07 15:17:34 +02:00
Maple Javora
d5722790ef Translated using Weblate (Czech)
Currently translated at 89.0% (676 of 759 strings)

Co-authored-by: Maple Javora <jindrous101@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/cs/
Translation: Kotatsu/Strings
2024-12-07 15:17:34 +02:00
johan
8bf540abbe Translated using Weblate (Czech)
Currently translated at 89.0% (676 of 759 strings)

Co-authored-by: johan <jqb4@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/cs/
Translation: Kotatsu/Strings
2024-12-07 15:17:34 +02:00
gekka
5241fa0d13 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (759 of 759 strings)

Co-authored-by: gekka <1778962971@qq.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/
Translation: Kotatsu/Strings
2024-12-07 15:17:34 +02:00
Dragibus Noir
87e0c931a2 Translated using Weblate (French)
Currently translated at 100.0% (759 of 759 strings)

Co-authored-by: Dragibus Noir <dragibusnoir@pm.me>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fr/
Translation: Kotatsu/Strings
2024-12-07 15:17:34 +02:00
Infy's Tagalog Translations
a51412801a Translated using Weblate (Filipino)
Currently translated at 100.0% (759 of 759 strings)

Co-authored-by: Infy's Tagalog Translations <ced.paltep10@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fil/
Translation: Kotatsu/Strings
2024-12-07 15:17:34 +02:00
TheOneWhoCares
a6c188d647 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (759 of 759 strings)

Co-authored-by: TheOneWhoCares <266nre4gw@mozmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pt_BR/
Translation: Kotatsu/Strings
2024-12-07 15:17:34 +02:00
Frosted
831632cb8f Translated using Weblate (Turkish)
Currently translated at 100.0% (759 of 759 strings)

Co-authored-by: Frosted <frosted@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/tr/
Translation: Kotatsu/Strings
2024-12-07 15:17:34 +02:00
Koitharu
ad59bf50f4 Fix loading local manga without index #1192 2024-12-05 18:39:31 +02:00
Koitharu
6fe6c05327 Update parsers 2024-12-05 18:38:47 +02:00
Koitharu
66645d93f8 Update parsers 2024-12-05 15:52:16 +02:00
Koitharu
f2582bce1d Update dependencies 2024-12-03 14:36:47 +02:00
Koitharu
b5053b7820 Update parsers 2024-11-29 09:31:46 +02:00
Koitharu
e4df81495d Merge pull request #1184 from weblate/weblate-kotatsu-strings 2024-11-28 16:10:45 +02:00
Anon
295c5bed9f Translated using Weblate (Serbian)
Currently translated at 99.6% (755 of 758 strings)

Co-authored-by: Anon <anonymousprivate76@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/sr/
Translation: Kotatsu/Strings
2024-11-28 12:24:33 +01:00
TheOneWhoCares
5fd1cbadcd Translated using Weblate (Portuguese (Brazil))
Currently translated at 97.4% (739 of 758 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 95.6% (725 of 758 strings)

Co-authored-by: TheOneWhoCares <266nre4gw@mozmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pt_BR/
Translation: Kotatsu/Strings
2024-11-28 12:24:33 +01:00
Gabriel Vasconcelos
9dd86f57e6 Translated using Weblate (Portuguese (Brazil))
Currently translated at 95.6% (725 of 758 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 93.6% (710 of 758 strings)

Co-authored-by: Gabriel Vasconcelos <gabriels.v9@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pt_BR/
Translation: Kotatsu/Strings
2024-11-28 12:24:33 +01:00
TheOneWhoCares
bce6d71743 Translated using Weblate (Portuguese (Brazil))
Currently translated at 93.6% (710 of 758 strings)

Co-authored-by: TheOneWhoCares <266nre4gw@mozmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pt_BR/
Translation: Kotatsu/Strings
2024-11-28 12:24:33 +01:00
Frosted
6367c06f49 Translated using Weblate (Turkish)
Currently translated at 100.0% (758 of 758 strings)

Co-authored-by: Frosted <frosted@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/tr/
Translation: Kotatsu/Strings
2024-11-28 12:24:32 +01:00
Dragibus Noir
3aa8e9d6d3 Translated using Weblate (French)
Currently translated at 100.0% (758 of 758 strings)

Co-authored-by: Dragibus Noir <dragibusnoir@pm.me>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fr/
Translation: Kotatsu/Strings
2024-11-28 12:24:32 +01:00
Draken
ac2b367312 Translated using Weblate (Vietnamese)
Currently translated at 100.0% (758 of 758 strings)

Co-authored-by: Draken <premieregirl26@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/vi/
Translation: Kotatsu/Strings
2024-11-28 12:24:32 +01:00
Justine Kyle Cobar
5cd9b02159 Translated using Weblate (Filipino)
Currently translated at 100.0% (758 of 758 strings)

Co-authored-by: Justine Kyle Cobar <cobarjustinekyle583@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fil/
Translation: Kotatsu/Strings
2024-11-28 12:24:32 +01:00
Infy's Tagalog Translations
0bd62c6925 Translated using Weblate (Filipino)
Currently translated at 100.0% (758 of 758 strings)

Co-authored-by: Infy's Tagalog Translations <ced.paltep10@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fil/
Translation: Kotatsu/Strings
2024-11-28 12:24:32 +01:00
gekka
d657216a69 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (758 of 758 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (758 of 758 strings)

Co-authored-by: gekka <1778962971@qq.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/
Translation: Kotatsu/Strings
2024-11-28 12:24:32 +01:00
大王叫我来巡山
39f91464dc Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (758 of 758 strings)

Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/
Translation: Kotatsu/Strings
2024-11-28 12:24:32 +01:00
gallegonovato
05422b95a1 Translated using Weblate (Spanish)
Currently translated at 100.0% (758 of 758 strings)

Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/es/
Translation: Kotatsu/Strings
2024-11-28 12:24:31 +01:00
arasseo.
554e3c1b61 Change ZERO_MS DNS
Switch to the primary DNS because the performance is better
2024-11-27 10:11:57 +02:00
Koitharu
56ece80f2a Bump version 2024-11-25 10:03:00 +02:00
Koitharu
3ebde0284d Kitsu fixes #1151 2024-11-24 13:42:52 +02:00
Koitharu
c993488fe7 Option to disable link handling #1149 2024-11-24 10:47:06 +02:00
Koitharu
e65a3b43f6 Fixes 2024-11-24 09:37:46 +02:00
Koitharu
f11a9d8235 Update parsers 2024-11-23 15:15:41 +02:00
Koitharu
8a4bd9a19a Fix "Deflater has been closed" error 2024-11-23 13:17:51 +02:00
Koitharu
cffc6cfd39 Fixes 2024-11-23 09:00:06 +02:00
Koitharu
1568a48328 Update parsers 2024-11-21 08:00:53 +02:00
nichind
0b47b113e0 Translated using Weblate (Russian)
Currently translated at 100.0% (755 of 755 strings)

Co-authored-by: nichind <nichinddev@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ru/
Translation: Kotatsu/Strings
2024-11-21 07:56:13 +02:00
Koitharu
67a5ef016c Fix cleaning saved chapters 2024-11-18 18:59:17 +02:00
Anupam Malhotra
09c049ea9d Translated using Weblate (Hindi)
Currently translated at 88.7% (670 of 755 strings)

Co-authored-by: Anupam Malhotra <anpm.malhotra@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/hi/
Translation: Kotatsu/Strings
2024-11-16 17:25:21 +02:00
Gabriel Vasconcelos
0dc1cad52b Translated using Weblate (Portuguese (Brazil))
Currently translated at 93.5% (706 of 755 strings)

Co-authored-by: Gabriel Vasconcelos <gabriels.v9@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pt_BR/
Translation: Kotatsu/Strings
2024-11-16 17:25:21 +02:00
Milo Ivir
782ea0541e Translated using Weblate (Croatian)
Currently translated at 100.0% (755 of 755 strings)

Co-authored-by: Milo Ivir <mail@milotype.de>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/hr/
Translation: Kotatsu/Strings
2024-11-16 17:22:09 +02:00
Anon
b220703dd4 Translated using Weblate (Serbian)
Currently translated at 99.7% (753 of 755 strings)

Co-authored-by: Anon <anonymousprivate76@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/sr/
Translation: Kotatsu/Strings
2024-11-16 17:22:09 +02:00
Paul Schönfisch
c5b6586cf4 Translated using Weblate (German)
Currently translated at 83.5% (631 of 755 strings)

Co-authored-by: Paul Schönfisch <asterdux2@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/de/
Translation: Kotatsu/Strings
2024-11-16 17:22:09 +02:00
gallegonovato
1ba40ea248 Translated using Weblate (Spanish)
Currently translated at 100.0% (755 of 755 strings)

Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/es/
Translation: Kotatsu/Strings
2024-11-16 17:22:09 +02:00
Hosted Weblate
e8fd2b0dcf Update translation files
Updated by "Remove blank strings" hook in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/
Translation: Kotatsu/Strings
2024-11-16 17:22:09 +02:00
Maple Javora
046b7b6ef1 Translated using Weblate (Czech)
Currently translated at 87.2% (657 of 753 strings)

Co-authored-by: Maple Javora <jindrous101@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/cs/
Translation: Kotatsu/Strings
2024-11-16 17:22:09 +02:00
Nicola Bortoletto
907856a0df Translated using Weblate (Italian)
Currently translated at 99.7% (753 of 755 strings)

Translated using Weblate (Italian)

Currently translated at 98.0% (738 of 753 strings)

Co-authored-by: Nicola Bortoletto <nicola.bortoletto@live.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/it/
Translation: Kotatsu/Strings
2024-11-16 17:22:09 +02:00
gekka
071509ecd1 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (755 of 755 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (753 of 753 strings)

Co-authored-by: gekka <1778962971@qq.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/
Translation: Kotatsu/Strings
2024-11-16 17:22:09 +02:00
Frosted
a0cb34b984 Translated using Weblate (Turkish)
Currently translated at 100.0% (755 of 755 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (753 of 753 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (752 of 752 strings)

Co-authored-by: Frosted <frosted@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/tr/
Translation: Kotatsu/Strings
2024-11-16 17:22:09 +02:00
Dragibus Noir
7fe8217f6d Translated using Weblate (French)
Currently translated at 100.0% (755 of 755 strings)

Translated using Weblate (French)

Currently translated at 100.0% (753 of 753 strings)

Translated using Weblate (French)

Currently translated at 100.0% (752 of 752 strings)

Co-authored-by: Dragibus Noir <dragibusnoir@pm.me>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fr/
Translation: Kotatsu/Strings
2024-11-16 17:22:09 +02:00
Infy's Tagalog Translations
58937f9fc6 Translated using Weblate (Filipino)
Currently translated at 100.0% (752 of 752 strings)

Co-authored-by: Infy's Tagalog Translations <ced.paltep10@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fil/
Translation: Kotatsu/Strings
2024-11-16 17:22:09 +02:00
Илья
528b85e9ce Translated using Weblate (Russian)
Currently translated at 100.0% (752 of 752 strings)

Co-authored-by: Илья <ilya.megavolt.37@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ru/
Translation: Kotatsu/Strings
2024-11-16 17:22:09 +02:00
Draken
b57fdd5a99 Translated using Weblate (Vietnamese)
Currently translated at 100.0% (755 of 755 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (753 of 753 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (752 of 752 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (752 of 752 strings)

Co-authored-by: Draken <premieregirl26@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/vi/
Translation: Kotatsu/Strings
2024-11-16 17:22:09 +02:00
大王叫我来巡山
1ad29cebd7 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (752 of 752 strings)

Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/
Translation: Kotatsu/Strings
2024-11-16 17:22:09 +02:00
gekka
7516303b7d Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (752 of 752 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (752 of 752 strings)

Co-authored-by: gekka <1778962971@qq.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/
Translation: Kotatsu/Strings
2024-11-16 17:22:09 +02:00
Koitharu
b2bfebaea2 Update dependencies 2024-11-16 17:09:21 +02:00
Koitharu
9fcff1eac7 Fix crashes 2024-11-16 10:19:42 +02:00
Koitharu
19446db192 Misc improvements 2024-11-13 12:53:58 +02:00
Koitharu
609f2bd134 Fixes 2024-11-12 08:51:23 +02:00
Mac135135
3ef7c6adb0 Added an periodical backup to the telegram bot 2024-11-10 15:11:40 +03:00
Mac135135
62e7e5d8c3 Merge remote-tracking branch 'origin/devel' into devel 2024-11-10 14:19:06 +03:00
Koitharu
644f0af262 Refactor dependencies catalog 2024-11-10 12:58:21 +02:00
Koitharu
a1e5d78877 Update parsers 2024-11-10 10:57:03 +02:00
Koitharu
635839065d Batch pages saving 2024-11-09 11:45:04 +02:00
Koitharu
bb6f7b1e9f Fix external backup crashes 2024-11-09 09:57:15 +02:00
Mac135135
30e43d3bfe Merge remote-tracking branch 'origin/devel' into devel
# Conflicts:
#	app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/PeriodicalBackupSettingsFragment.kt
#	app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/PeriodicalBackupWorker.kt
2024-11-07 23:47:47 +03:00
Koitharu
1f0180d601 Fix periodical backup creation interval 2024-11-07 15:01:09 +02:00
Koitharu
cdce2af4a3 Fix nightly version name parsing 2024-11-07 14:47:52 +02:00
Koitharu
11212ed071 Update readme 2024-11-07 14:34:26 +02:00
Koitharu
e2902fa1ba Fix dependencies 2024-11-07 14:26:36 +02:00
Koitharu
5158f2a70a Merge branch 'CodeWithTamim-add/libs-version-toml-dependency-management' into devel 2024-11-07 13:11:18 +02:00
Koitharu
f9e4752b8c Merge branch 'add/libs-version-toml-dependency-management' of github.com:CodeWithTamim/Kotatsu into CodeWithTamim-add/libs-version-toml-dependency-management 2024-11-07 13:10:41 +02:00
Koitharu
901ffebf97 Change nightly updates repo 2024-11-06 09:54:53 +02:00
Koitharu
dba727bfcb Improvements for nightly build 2024-11-06 09:28:42 +02:00
Koitharu
3ee97a3b99 Fix nightly versionName/versionCode 2024-11-05 13:36:46 +02:00
Koitharu
57d1f54318 Refactor pages saving 2024-11-05 11:46:59 +02:00
Koitharu
02073f6d45 Convert launcher icons to webp 2024-11-05 09:22:30 +02:00
Koitharu
b66a77843e Add nightly build type 2024-11-05 09:21:24 +02:00
Koitharu
03518dd9b4 Update dependencies 2024-11-05 08:43:37 +02:00
Koitharu
d926f334e8 Merge branch 'master' into devel 2024-11-04 16:30:54 +02:00
Koitharu
e2f8d8e022 Fix downloading slowdown 2024-11-04 16:04:18 +02:00
Koitharu
38b342b721 Update dependencies, fix covers restoring 2024-11-04 15:41:16 +02:00
Koitharu
b036a8ed94 Fixes batch 2024-11-04 10:02:08 +02:00
Koitharu
e4fda86bf1 Small fixes 2024-11-02 15:35:01 +02:00
Koitharu
6e20cee972 Fix periodical backups 2024-11-02 15:34:55 +02:00
Claudio Riccio
8901d02dba Update app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt
Co-authored-by: Koitharu <nvasya95@gmail.com>
2024-11-02 13:10:41 +02:00
Claudio Riccio
a87b37ce1c Changes relative to issue#1102
Manga pages now have a proposed name as follow: "MangaName-MangaChapter-MangaPage_yyyy-MM-dd_HHmm.ImageExtension"
2024-11-02 13:10:41 +02:00
Claudio Riccio
4f22e29ad6 Changes relative to issue#1102
Manga pages now have a proposed name as follow: "MangaName-MangaChapter-MangaPage_yyyy-MM-dd_HHmm.ImageExtension"
2024-11-02 13:10:41 +02:00
Draken
6effb928fd Translated using Weblate (Vietnamese)
Currently translated at 100.0% (749 of 749 strings)

Co-authored-by: Draken <premieregirl26@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/vi/
Translation: Kotatsu/Strings
2024-11-02 12:31:21 +02:00
Infy's Tagalog Translations
1b1d0014da Translated using Weblate (Filipino)
Currently translated at 100.0% (749 of 749 strings)

Co-authored-by: Infy's Tagalog Translations <ced.paltep10@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fil/
Translation: Kotatsu/Strings
2024-11-02 12:31:21 +02:00
gekka
a9632f542b Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (749 of 749 strings)

Co-authored-by: gekka <1778962971@qq.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/
Translation: Kotatsu/Strings
2024-11-02 12:31:21 +02:00
gallegonovato
a2c256d47f Translated using Weblate (Spanish)
Currently translated at 100.0% (749 of 749 strings)

Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/es/
Translation: Kotatsu/Strings
2024-11-02 12:31:21 +02:00
Anonymous
f87a75e61e Translated using Weblate (Catalan)
Currently translated at 11.7% (88 of 749 strings)

Co-authored-by: Anonymous <noreply@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ca/
Translation: Kotatsu/Strings
2024-11-02 12:31:21 +02:00
Макар Разин
09354ae31f Translated using Weblate (Russian)
Currently translated at 100.0% (749 of 749 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (749 of 749 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (748 of 748 strings)

Co-authored-by: Макар Разин <makarrazin14@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/be/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ru/
Translation: Kotatsu/Strings
2024-11-02 12:31:21 +02:00
Mahmuod abd alalem Selem abd al amed
fb25b8fb3a Translated using Weblate (Arabic)
Currently translated at 89.0% (666 of 748 strings)

Co-authored-by: Mahmuod abd alalem Selem abd al amed <selemabdalamedmahmuodabdalalem@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ar/
Translation: Kotatsu/Strings
2024-11-02 12:31:21 +02:00
Justine Kyle Cobar
c8b935ccc3 Translated using Weblate (Filipino)
Currently translated at 100.0% (748 of 748 strings)

Co-authored-by: Justine Kyle Cobar <cobarjustinekyle583@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fil/
Translation: Kotatsu/Strings
2024-11-02 12:31:21 +02:00
Anon
7f0376d792 Translated using Weblate (Serbian)
Currently translated at 100.0% (748 of 748 strings)

Co-authored-by: Anon <anonymousprivate76@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/sr/
Translation: Kotatsu/Strings
2024-11-02 12:31:21 +02:00
Koitharu
0c56e730fe Change periodical backup creation 2024-11-02 12:30:04 +02:00
Koitharu
a7138d23ac Small fixes 2024-10-30 12:54:49 +02:00
Koitharu
a0de73a7ed PageSaveHelper refactor 2024-10-27 18:02:31 +02:00
Koitharu
90f0846fb4 Small fixes 2024-10-27 16:28:11 +02:00
Koitharu
9425d29596 Migrate LocalMangaInfo to Okio 2024-10-27 13:49:06 +02:00
Koitharu
9bb76cc0b2 Update parsers (fix json iterator) 2024-10-26 09:03:50 +03:00
Koitharu
ad0452486f Merge branch 'master' into devel 2024-10-24 12:48:06 +03:00
Koitharu
855b55da9d Update parsers 2024-10-23 19:47:27 +03:00
Koitharu
436168b940 Migrate to coil3 2024-10-23 18:55:10 +03:00
Koitharu
681c80dc3e Fix RegionBitmapDecode usage 2024-10-23 09:15:32 +03:00
Koitharu
4855b2c160 Fix RegionBitmapDecode usage 2024-10-23 09:10:43 +03:00
Koitharu
89d395178c Support for AVIF images
(cherry picked from commit c15a0ece3e)
2024-10-23 08:38:52 +03:00
Koitharu
9942ad5e56 Fix pages loading issues
(cherry picked from commit 5bccc595a8)
2024-10-23 08:37:50 +03:00
Koitharu
d59b0626bc Fix webtoon page detection #1140
(cherry picked from commit 985b062218)
2024-10-23 08:37:00 +03:00
Marius Albrecht
63054e55d6 Give "Complete" status only to fully completed Manga
Up until now a progress of >= 99.5% would count a Manga as completed (and show the checkmark icon). This causes manga with 200 chapters or more to be marked as completed even if they have at least one unread chapter.

https://github.com/KotatsuApp/Kotatsu/issues/1105
(cherry picked from commit b6f57e5656)
2024-10-23 08:36:52 +03:00
Koitharu
486daf69bf Update link resolver
(cherry picked from commit c1d577bdf3)
2024-10-23 08:36:38 +03:00
Koitharu
af209d7048 Fix external plugin communication
(cherry picked from commit 2214c20742)
2024-10-23 08:36:26 +03:00
Koitharu
c15a0ece3e Support for AVIF images 2024-10-22 14:20:13 +03:00
Tamim Hossain
6bf034fd37 Add libs.versions.toml for centralized dependency management
- Introduced `libs.versions.toml` to manage dependencies in a centralized and structured manner.
- This improves maintainability and makes it easier to update and manage library versions across the project.
- Follows best practices for Gradle dependency management by separating version definitions from build scripts.
2024-10-22 01:46:26 +06:00
Koitharu
5bccc595a8 Fix pages loading issues 2024-10-21 13:34:33 +03:00
Priit Jõerüüt
9559e148c6 Translated using Weblate (Estonian)
Currently translated at 70.3% (526 of 748 strings)

Co-authored-by: Priit Jõerüüt <hwlate@joeruut.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/et/
Translation: Kotatsu/Strings
2024-10-21 10:17:44 +03:00
J. Lavoie
637a040a0b Translated using Weblate (French)
Currently translated at 99.1% (742 of 748 strings)

Co-authored-by: J. Lavoie <j.lavoie@net-c.ca>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fr/
Translation: Kotatsu/Strings
2024-10-21 10:17:44 +03:00
Yoshi Nizar
2bdf146548 Translated using Weblate (Italian)
Currently translated at 90.9% (680 of 748 strings)

Co-authored-by: Yoshi Nizar <canalefinto@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/it/
Translation: Kotatsu/Strings
2024-10-21 10:17:44 +03:00
shimanchu
22831a9796 Translated using Weblate (Japanese)
Currently translated at 62.1% (464 of 747 strings)

Co-authored-by: shimanchu <shimano@knd.biglobe.ne.jp>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ja/
Translation: Kotatsu/Strings
2024-10-21 10:17:44 +03:00
大王叫我来巡山
b5bc64c89f Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (747 of 747 strings)

Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/
Translation: Kotatsu/Strings
2024-10-21 10:17:44 +03:00
Hosted Weblate
f2ad58bc97 Update translation files
Updated by "Remove blank strings" hook in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/
Translation: Kotatsu/Strings
2024-10-21 10:17:44 +03:00
Akhil Raj
835a1c73b6 Translated using Weblate (Malayalam)
Currently translated at 2.8% (21 of 744 strings)

Co-authored-by: Akhil Raj <89210430+akhi07rx@users.noreply.github.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ml/
Translation: Kotatsu/Strings
2024-10-21 10:17:44 +03:00
Felipe Nascimento
5b8a628715 Translated using Weblate (Portuguese)
Currently translated at 98.7% (735 of 744 strings)

Co-authored-by: Felipe Nascimento <f.kgb@hotmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pt/
Translation: Kotatsu/Strings
2024-10-21 10:17:44 +03:00
Nayuki
4f5418e074 Translated using Weblate (Thai)
Currently translated at 61.0% (454 of 744 strings)

Co-authored-by: Nayuki <me@nayuki.cyou>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/th/
Translation: Kotatsu/Strings
2024-10-21 10:17:44 +03:00
Infy's Tagalog Translations
1cf56b2303 Translated using Weblate (Filipino)
Currently translated at 98.2% (734 of 747 strings)

Translated using Weblate (Filipino)

Currently translated at 98.2% (731 of 744 strings)

Translated using Weblate (Filipino)

Currently translated at 98.2% (731 of 744 strings)

Co-authored-by: Infy's Tagalog Translations <ced.paltep10@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fil/
Translation: Kotatsu/Strings
2024-10-21 10:17:44 +03:00
maryush
a47dcd9ec2 Translated using Weblate (Polish)
Currently translated at 100.0% (744 of 744 strings)

Translated using Weblate (Polish)

Currently translated at 99.8% (737 of 738 strings)

Co-authored-by: maryush <maryush@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pl/
Translation: Kotatsu/Strings
2024-10-21 10:17:44 +03:00
Макар Разин
7873cc4099 Translated using Weblate (Russian)
Currently translated at 100.0% (733 of 733 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (733 of 733 strings)

Co-authored-by: Макар Разин <makarrazin14@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/be/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ru/
Translation: Kotatsu/Strings
2024-10-21 10:17:44 +03:00
gekka
9002915e30 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (744 of 744 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (738 of 738 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (733 of 733 strings)

Co-authored-by: gekka <1778962971@qq.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/
Translation: Kotatsu/Strings
2024-10-21 10:17:44 +03:00
Draken
099d9df84c Translated using Weblate (Vietnamese)
Currently translated at 100.0% (747 of 747 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (744 of 744 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (738 of 738 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (733 of 733 strings)

Co-authored-by: Draken <premieregirl26@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/vi/
Translation: Kotatsu/Strings
2024-10-21 10:17:44 +03:00
大王叫我来巡山
e531e6bcb8 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (733 of 733 strings)

Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/
Translation: Kotatsu/Strings
2024-10-21 10:17:44 +03:00
Oğuz Ersen
77ed44bb08 Translated using Weblate (Turkish)
Currently translated at 100.0% (747 of 747 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (744 of 744 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (738 of 738 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (733 of 733 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/tr/
Translation: Kotatsu/Strings
2024-10-21 10:17:44 +03:00
gallegonovato
1b0b495029 Translated using Weblate (Spanish)
Currently translated at 100.0% (747 of 747 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (744 of 744 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (738 of 738 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (733 of 733 strings)

Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/es/
Translation: Kotatsu/Strings
2024-10-21 10:17:44 +03:00
Anon
b6296fd586 Translated using Weblate (Serbian)
Currently translated at 100.0% (738 of 738 strings)

Translated using Weblate (Serbian)

Currently translated at 100.0% (732 of 732 strings)

Co-authored-by: Anon <anonymousprivate76@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/sr/
Translation: Kotatsu/Strings
2024-10-21 10:17:44 +03:00
Koitharu
985b062218 Fix webtoon page detection #1140 2024-10-21 10:16:54 +03:00
Marius Albrecht
b6f57e5656 Give "Complete" status only to fully completed Manga
Up until now a progress of >= 99.5% would count a Manga as completed (and show the checkmark icon). This causes manga with 200 chapters or more to be marked as completed even if they have at least one unread chapter.

https://github.com/KotatsuApp/Kotatsu/issues/1105
2024-10-21 10:13:14 +03:00
Koitharu
3d285104a4 Search through settings 2024-10-20 17:01:17 +03:00
Koitharu
100073f45e Reader screen orientation settings 2024-10-16 18:16:14 +03:00
Koitharu
c1d577bdf3 Update link resolver 2024-10-16 13:19:34 +03:00
Koitharu
2214c20742 Fix external plugin communication 2024-10-13 18:24:48 +03:00
Koitharu
688a9fe4d5 Option to open manga source in browser 2024-10-13 18:00:05 +03:00
Koitharu
af5df32fbe Merge branch 'master' into devel 2024-10-13 17:22:25 +03:00
Koitharu
d739e30c84 Improve filter 2024-10-13 16:05:52 +03:00
Koitharu
32eb273fa9 Update parsers 2024-10-13 15:47:43 +03:00
Koitharu
8c5231bb3d Fix read chapters deletion 2024-10-13 14:09:03 +03:00
Koitharu
be4fb3e873 Fix saving cover 2024-10-13 14:09:03 +03:00
Koitharu
d28eff7a75 Fix zip closing 2024-10-13 14:09:03 +03:00
Koitharu
b81063910b Fix read chapters deletion 2024-10-13 14:08:25 +03:00
Koitharu
702ee70f70 Fix saving cover 2024-10-13 09:43:01 +03:00
Koitharu
c5bd979645 Fix zip closing 2024-10-13 09:39:28 +03:00
Koitharu
e515069b53 Fix zip closing
(cherry picked from commit 144e66bedb)
2024-10-11 17:16:57 +03:00
Koitharu
3255fba3c4 Ask for download via metered network 2024-10-11 17:16:31 +03:00
Koitharu
144e66bedb Fix zip closing 2024-10-11 10:55:47 +03:00
Koitharu
05d22167c4 Fix skipping download errors 2024-10-11 10:15:29 +03:00
Koitharu
e5c765dd2f Update parsers 2024-10-11 09:57:58 +03:00
Koitharu
557b69d73f New download dialog 2024-10-10 16:30:01 +03:00
Koitharu
1e22e8de45 Improve filter 2024-10-07 20:02:34 +03:00
Koitharu
9ea1122ca0 Fix CloudFlare protection detection (close #1129) 2024-10-07 15:24:02 +03:00
Koitharu
4faef85086 Fix sources suggestion 2024-10-07 14:40:29 +03:00
Koitharu
b46c00f2d0 Fix parsers version 2024-10-05 16:28:29 +03:00
Anon
9358617a3a Translated using Weblate (Serbian)
Currently translated at 100.0% (729 of 729 strings)

Translated using Weblate (Serbian)

Currently translated at 96.4% (703 of 729 strings)

Co-authored-by: Anon <anonymousprivate76@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/sr/
Translation: Kotatsu/Strings
2024-10-05 16:03:55 +03:00
Draken
ba9f31835f Translated using Weblate (Vietnamese)
Currently translated at 100.0% (732 of 732 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (729 of 729 strings)

Co-authored-by: Draken <premieregirl26@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/vi/
Translation: Kotatsu/Strings
2024-10-05 16:03:55 +03:00
abc0922001
357308bfbb Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 90.5% (660 of 729 strings)

Co-authored-by: abc0922001 <abc0922001@hotmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hant/
Translation: Kotatsu/Strings
2024-10-05 16:03:55 +03:00
gekka
cab56209c1 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (732 of 732 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (729 of 729 strings)

Co-authored-by: gekka <1778962971@qq.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/
Translation: Kotatsu/Strings
2024-10-05 16:03:55 +03:00
Oğuz Ersen
e9cd32c870 Translated using Weblate (Turkish)
Currently translated at 100.0% (732 of 732 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (729 of 729 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/tr/
Translation: Kotatsu/Strings
2024-10-05 16:03:55 +03:00
gallegonovato
357517ceac Translated using Weblate (Spanish)
Currently translated at 100.0% (732 of 732 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (729 of 729 strings)

Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/es/
Translation: Kotatsu/Strings
2024-10-05 16:03:55 +03:00
Infy's Tagalog Translations
a57fcce72b Translated using Weblate (Filipino)
Currently translated at 98.3% (717 of 729 strings)

Translated using Weblate (Filipino)

Currently translated at 98.3% (716 of 728 strings)

Co-authored-by: Infy's Tagalog Translations <ced.paltep10@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fil/
Translation: Kotatsu/Strings
2024-10-05 16:03:55 +03:00
Priit Jõerüüt
2e2a818c05 Translated using Weblate (Estonian)
Currently translated at 71.0% (520 of 732 strings)

Translated using Weblate (Estonian)

Currently translated at 67.9% (495 of 728 strings)

Translated using Weblate (Estonian)

Currently translated at 100.0% (9 of 9 strings)

Co-authored-by: Priit Jõerüüt <hwlate@joeruut.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/plurals/et/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/et/
Translation: Kotatsu/Strings
Translation: Kotatsu/plurals
2024-10-05 16:03:55 +03:00
Matt
b6f618101f Translated using Weblate (Portuguese)
Currently translated at 98.7% (719 of 728 strings)

Co-authored-by: Matt <contact.mattdev@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pt/
Translation: Kotatsu/Strings
2024-10-05 16:03:55 +03:00
Koitharu
0ce368751a Merge branch 'devel' of github.com:KotatsuApp/Kotatsu into devel 2024-10-05 16:03:07 +03:00
Koitharu
1d28538893 Fixes batch 2024-10-05 16:02:49 +03:00
Koitharu
4ad2f3f608 Fixes batch 2024-10-04 14:27:01 +03:00
Koitharu
5301cc7f97 Ability to start download paused 2024-10-04 11:20:49 +03:00
Koitharu
1290db4a7c Fixes batch 2024-10-04 10:23:49 +03:00
Koitharu
1f1309d934 Increase source add button size 2024-10-03 14:32:34 +03:00
Koitharu
350f1521a6 Fix warnings and cleanup 2024-10-03 13:08:09 +03:00
mnv
cebce20bed Fix MangaSource import and improve user agent handling
MangaSource class was imported twice from different packages.
2024-10-03 09:16:30 +03:00
Koitharu
e5b6947586 Fix StrictMode errors 2024-10-02 16:39:21 +03:00
Koitharu
ac96c49b60 Strict mode notificaiton for debug build 2024-10-02 15:13:54 +03:00
Koitharu
a4345a40bf Update dependencies 2024-10-02 11:34:51 +03:00
Mac135135
0162eaed97 Merge remote-tracking branch 'origin/devel' into devel
# Conflicts:
#	app/src/main/res/values-es/strings.xml
#	app/src/main/res/values-zh-rCN/strings.xml
2024-09-30 01:10:25 +03:00
Koitharu
15ca4111c0 Reapply "Update sources catalog ui"
This reverts commit 8d5bde6e60.
2024-09-30 01:09:00 +03:00
Koitharu
dc45e0f5df Revert "Update sources catalog ui"
This reverts commit 597ad01e8f.
2024-09-30 01:09:00 +03:00
Koitharu
09b6a967a1 Refactor descrambling bitmap 2024-09-30 01:09:00 +03:00
AwkwardPeak7
1cff0eeac4 implement basic methods for descrambling images 2024-09-30 01:09:00 +03:00
Kristian de Frutos
44349c4ede Translated using Weblate (Czech)
Currently translated at 100.0% (636 of 636 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (636 of 636 strings)

Translated using Weblate (Czech)

Currently translated at 83.0% (528 of 636 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (9 of 9 strings)

Co-authored-by: Kristian de Frutos <kristiandef@hotmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/plurals/cs/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/cs/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/es/
Translation: Kotatsu/Strings
Translation: Kotatsu/plurals
2024-09-30 01:09:00 +03:00
Koitharu
8e8953b07f Skip error for local manga list (close #1113, close #1115) 2024-09-30 01:09:00 +03:00
Felipe Nascimento
150e3d554f Translated using Weblate (Portuguese)
Currently translated at 98.6% (718 of 728 strings)

Co-authored-by: Felipe Nascimento <f.kgb@hotmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pt/
Translation: Kotatsu/Strings
2024-09-30 01:08:58 +03:00
Draken
be3b5a1897 Translated using Weblate (Vietnamese)
Currently translated at 100.0% (728 of 728 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (724 of 724 strings)

Co-authored-by: Draken <premieregirl26@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/vi/
Translation: Kotatsu/Strings
2024-09-30 01:08:58 +03:00
Matt
9be0e8595f Translated using Weblate (Japanese)
Currently translated at 100.0% (9 of 9 strings)

Co-authored-by: Matt <contact.mattdev@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/plurals/ja/
Translation: Kotatsu/plurals
2024-09-30 01:08:56 +03:00
Oğuz Ersen
f38370592e Translated using Weblate (Turkish)
Currently translated at 100.0% (728 of 728 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (724 of 724 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/tr/
Translation: Kotatsu/Strings
2024-09-30 01:08:56 +03:00
Koitharu
6a54d42867 Update SSIV 2024-09-30 01:08:53 +03:00
Mac135135
49d29ae675 Added an periodical backup to the telegram bot 2024-09-30 01:08:53 +03:00
Mac135135
27d7a6a8cb Added an periodical backup to the telegram bot 2024-09-30 01:08:53 +03:00
Koitharu
e8d04644f8 Remove loggers and reorganize settings 2024-09-30 01:08:52 +03:00
Mac135135
26b512d42e Added an periodical backup to the telegram bot 2024-09-30 01:08:48 +03:00
Koitharu
4fb3173185 Update readme 2024-09-30 01:06:32 +03:00
Koitharu
826587b2c9 Translated using Weblate (Russian)
Currently translated at 99.7% (722 of 724 strings)

Co-authored-by: Koitharu <nvasya95@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ru/
Translation: Kotatsu/Strings
2024-09-30 01:06:32 +03:00
Hosted Weblate
4efdb1d8d1 Update translation files
Updated by "Remove blank strings" hook in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/
Translation: Kotatsu/Strings
2024-09-30 01:06:30 +03:00
Infy's Tagalog Translations
1b9f886d1b Translated using Weblate (Filipino)
Currently translated at 98.4% (713 of 724 strings)

Translated using Weblate (Filipino)

Currently translated at 98.8% (712 of 720 strings)

Co-authored-by: Infy's Tagalog Translations <ced.paltep10@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fil/
Translation: Kotatsu/Strings
2024-09-30 01:06:30 +03:00
Felipe Nascimento
3241ae5db5 Translated using Weblate (Portuguese)
Currently translated at 98.7% (711 of 720 strings)

Co-authored-by: Felipe Nascimento <f.kgb@hotmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pt/
Translation: Kotatsu/Strings
2024-09-30 01:06:30 +03:00
Макар Разин
30f1b2c73a Translated using Weblate (Russian)
Currently translated at 100.0% (720 of 720 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (720 of 720 strings)

Co-authored-by: Макар Разин <makarrazin14@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/be/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ru/
Translation: Kotatsu/Strings
2024-09-30 01:06:30 +03:00
Koitharu
8d35101e98 Update parsers 2024-09-30 01:06:30 +03:00
Koitharu
41cfd99d32 Fix applying filter 2024-09-30 01:06:30 +03:00
Koitharu
c8d04e4eb7 Migrate external sources to new filter 2024-09-30 01:06:29 +03:00
Koitharu
956831f9d7 Fix sync auth activity ui 2024-09-30 01:06:29 +03:00
Draken
d65874080b Translated using Weblate (Vietnamese)
Currently translated at 100.0% (720 of 720 strings)

Co-authored-by: Draken <premieregirl26@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/vi/
Translation: Kotatsu/Strings
2024-09-30 01:06:29 +03:00
Infy's Tagalog Translations
bf35a8ffd7 Translated using Weblate (Filipino)
Currently translated at 98.8% (712 of 720 strings)

Co-authored-by: Infy's Tagalog Translations <ced.paltep10@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fil/
Translation: Kotatsu/Strings
2024-09-30 01:06:29 +03:00
Oğuz Ersen
eeb8dd8c5b Translated using Weblate (Turkish)
Currently translated at 100.0% (720 of 720 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/tr/
Translation: Kotatsu/Strings
2024-09-30 01:06:25 +03:00
Faiz Faadhillah
299093f863 Improve Spen integration support 2024-09-30 01:06:25 +03:00
Koitharu
86dea2953a Update parsers 2024-09-30 01:06:25 +03:00
gallegonovato
81794e6eb2 Translated using Weblate (Spanish)
Currently translated at 100.0% (720 of 720 strings)

Translation: Kotatsu/Strings
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/es/
2024-09-30 01:06:25 +03:00
Draken
d43887e288 Translated using Weblate (Vietnamese)
Currently translated at 100.0% (718 of 718 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (718 of 718 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (717 of 717 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (698 of 698 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (692 of 692 strings)

Co-authored-by: Draken <premieregirl26@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/vi/
Translation: Kotatsu/Strings
2024-09-30 01:05:59 +03:00
Oğuz Ersen
e2cf22e054 Translated using Weblate (Turkish)
Currently translated at 100.0% (718 of 718 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (718 of 718 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (717 of 717 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (710 of 710 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (698 of 698 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (692 of 692 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/tr/
Translation: Kotatsu/Strings
2024-09-30 01:05:59 +03:00
Koitharu
5a75fe77fd Various fixes 2024-09-30 01:05:41 +03:00
Koitharu
8c0617c525 Context menus 2024-09-30 01:05:41 +03:00
Anonymous
38b8966c16 Translated using Weblate (Hungarian)
Currently translated at 86.6% (622 of 718 strings)

Translated using Weblate (Nepali)

Currently translated at 32.3% (232 of 718 strings)

Translated using Weblate (Hindi)

Currently translated at 93.0% (668 of 718 strings)

Translated using Weblate (Portuguese)

Currently translated at 92.7% (666 of 718 strings)

Co-authored-by: Anonymous <noreply@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/hi/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/hu/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ne/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pt/
Translation: Kotatsu/Strings
2024-09-30 01:05:41 +03:00
desu sude
59f4ff8a3e Translated using Weblate (Latvian)
Currently translated at 24.4% (175 of 717 strings)

Co-authored-by: desu sude <cobsonslittlecocksleeve@proton.me>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/lv/
Translation: Kotatsu/Strings
2024-09-30 01:05:41 +03:00
Anon
357263b496 Translated using Weblate (Serbian)
Currently translated at 100.0% (698 of 698 strings)

Co-authored-by: Anon <anonymousprivate76@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/sr/
Translation: Kotatsu/Strings
2024-09-30 01:05:41 +03:00
Milo Ivir
4af6fc165b Translated using Weblate (Croatian)
Currently translated at 98.7% (689 of 698 strings)

Co-authored-by: Milo Ivir <mail@milotype.de>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/hr/
Translation: Kotatsu/Strings
2024-09-30 01:05:40 +03:00
Infy's Tagalog Translations
a4de58b9b3 Translated using Weblate (Filipino)
Currently translated at 100.0% (698 of 698 strings)

Translated using Weblate (Filipino)

Currently translated at 100.0% (698 of 698 strings)

Co-authored-by: Infy's Tagalog Translations <ced.paltep10@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fil/
Translation: Kotatsu/Strings
2024-09-30 01:05:40 +03:00
abc0922001
5696ad7fa2 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 92.1% (643 of 698 strings)

Co-authored-by: abc0922001 <abc0922001@hotmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hant/
Translation: Kotatsu/Strings
2024-09-30 01:05:40 +03:00
Amirreza Safavi
63bfca6d3e Translated using Weblate (Persian)
Currently translated at 41.6% (288 of 692 strings)

Co-authored-by: Amirreza Safavi <amirxcatsanddragons@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fa/
Translation: Kotatsu/Strings
2024-09-30 01:05:40 +03:00
gekka
0fecf996e1 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 99.7% (716 of 718 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 99.7% (696 of 698 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 99.7% (696 of 698 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 99.8% (691 of 692 strings)

Co-authored-by: gekka <1778962971@qq.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/
Translation: Kotatsu/Strings
2024-09-30 01:05:40 +03:00
Shayan
3df2682332 Translated using Weblate (Persian)
Currently translated at 41.6% (288 of 692 strings)

Co-authored-by: Shayan <shayans31516@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fa/
Translation: Kotatsu/Strings
2024-09-30 01:05:40 +03:00
Amirreza Safavi
dd9df6e9dc Translated using Weblate (Persian)
Currently translated at 41.6% (288 of 692 strings)

Co-authored-by: Amirreza Safavi <amirxcatsanddragons@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fa/
Translation: Kotatsu/Strings
2024-09-30 01:05:40 +03:00
gallegonovato
0889c2cc28 Translated using Weblate (Spanish)
Currently translated at 100.0% (718 of 718 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (717 of 717 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (698 of 698 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (698 of 698 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (692 of 692 strings)

Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/es/
Translation: Kotatsu/Strings
2024-09-30 01:05:40 +03:00
Draken
010b1264ae Translated using Weblate (Vietnamese)
Currently translated at 100.0% (718 of 718 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (717 of 717 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (698 of 698 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (692 of 692 strings)

Co-authored-by: Draken <premieregirl26@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/vi/
Translation: Kotatsu/Strings
2024-09-30 01:05:40 +03:00
Oğuz Ersen
66ff32e14d Translated using Weblate (Turkish)
Currently translated at 100.0% (718 of 718 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (717 of 717 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (710 of 710 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (698 of 698 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (692 of 692 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/tr/
Translation: Kotatsu/Strings
2024-09-30 01:05:40 +03:00
Fikri Akbar
addb642cc9 Translated using Weblate (Indonesian)
Currently translated at 99.8% (688 of 689 strings)

Co-authored-by: Fikri Akbar <akbarfikri1221@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/id/
Translation: Kotatsu/Strings
2024-09-30 01:05:40 +03:00
Koitharu
720c389dbd Search in history, favorites and local 2024-09-30 01:05:40 +03:00
Koitharu
2191d9c83b Fix sources catalog content types 2024-09-30 01:05:40 +03:00
Koitharu
0ee1cda0e4 Local manga source filter 2024-09-30 01:05:40 +03:00
Koitharu
90226b7b78 Update supported domains 2024-09-30 01:05:39 +03:00
Koitharu
6d84294533 Improve quick filters 2024-09-30 01:05:39 +03:00
Koitharu
36bd3cc438 Local manga index in database 2024-09-30 01:05:39 +03:00
Koitharu
e0c983f4eb Search manga with filters 2024-09-30 01:05:39 +03:00
Koitharu
ea5ce23335 Improve filter 2024-09-30 01:05:39 +03:00
Koitharu
26a33e5d9d Add new filter fields 2024-09-30 01:05:39 +03:00
Koitharu
9ab7159cb9 Update parsers and filters 2024-09-30 01:05:39 +03:00
Koitharu
ad21321a1d Update parsers 2024-09-30 01:05:39 +03:00
Koitharu
fe2bb05895 Update dependencies 2024-09-30 01:05:39 +03:00
Koitharu
e48beae324 Batch manga fix functionality 2024-09-30 01:05:39 +03:00
Amirreza Safavi
10109ab2c0 Translated using Weblate (Persian)
Currently translated at 77.7% (7 of 9 strings)

Translated using Weblate (Persian)

Currently translated at 37.4% (258 of 689 strings)

Co-authored-by: Amirreza Safavi <amirxcatsanddragons@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/plurals/fa/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fa/
Translation: Kotatsu/Strings
Translation: Kotatsu/plurals
2024-09-30 01:05:38 +03:00
Anon
df17bb5af8 Translated using Weblate (Serbian)
Currently translated at 100.0% (689 of 689 strings)

Co-authored-by: Anon <anonymousprivate76@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/sr/
Translation: Kotatsu/Strings
2024-09-30 01:05:38 +03:00
Henrique
b4592015fb Translated using Weblate (Portuguese (Brazil))
Currently translated at 96.6% (666 of 689 strings)

Co-authored-by: Henrique <heluis110@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pt_BR/
Translation: Kotatsu/Strings
2024-09-30 01:05:38 +03:00
Макар Разин
3fe9ec6918 Translated using Weblate (Russian)
Currently translated at 100.0% (689 of 689 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (689 of 689 strings)

Co-authored-by: Макар Разин <makarrazin14@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/be/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ru/
Translation: Kotatsu/Strings
2024-09-30 01:05:38 +03:00
Dilip Patel
23ac9df844 grammar fix 2024-09-30 01:05:38 +03:00
Koitharu
c480992f63 Option to automatically download new chapters (close #425, close #602, close #955) 2024-09-30 01:05:38 +03:00
Koitharu
85d397def0 Update dependencies 2024-09-30 01:05:38 +03:00
Koitharu
f518acb8ee Skip error for local manga list (close #1113, close #1115) 2024-09-29 19:46:48 +03:00
大王叫我来巡山
b39a51d497 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (728 of 728 strings)

Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/
Translation: Kotatsu/Strings
2024-09-29 19:43:34 +03:00
Felipe Nascimento
8819d8b1ee Translated using Weblate (Portuguese)
Currently translated at 98.6% (718 of 728 strings)

Co-authored-by: Felipe Nascimento <f.kgb@hotmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pt/
Translation: Kotatsu/Strings
2024-09-29 19:43:34 +03:00
Draken
05a502b89a Translated using Weblate (Vietnamese)
Currently translated at 100.0% (728 of 728 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (724 of 724 strings)

Co-authored-by: Draken <premieregirl26@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/vi/
Translation: Kotatsu/Strings
2024-09-29 19:43:34 +03:00
gekka
c320e3c26a Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 99.8% (723 of 724 strings)

Co-authored-by: gekka <1778962971@qq.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/
Translation: Kotatsu/Strings
2024-09-29 19:43:34 +03:00
Matt
938849c31e Translated using Weblate (Japanese)
Currently translated at 100.0% (9 of 9 strings)

Co-authored-by: Matt <contact.mattdev@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/plurals/ja/
Translation: Kotatsu/plurals
2024-09-29 19:43:34 +03:00
Oğuz Ersen
95c243daa1 Translated using Weblate (Turkish)
Currently translated at 100.0% (728 of 728 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (724 of 724 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/tr/
Translation: Kotatsu/Strings
2024-09-29 19:43:34 +03:00
gallegonovato
6ce6a02b56 Translated using Weblate (Spanish)
Currently translated at 100.0% (728 of 728 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (724 of 724 strings)

Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/es/
Translation: Kotatsu/Strings
2024-09-29 19:43:34 +03:00
Koitharu
e92e9fb393 Update SSIV 2024-09-29 19:43:09 +03:00
Koitharu
f4186a2787 Remove loggers and reorganize settings 2024-09-27 14:40:31 +03:00
Koitharu
8b93b699d3 Update readme 2024-09-26 16:02:52 +03:00
Koitharu
7e13482ba5 Translated using Weblate (Russian)
Currently translated at 99.7% (722 of 724 strings)

Co-authored-by: Koitharu <nvasya95@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ru/
Translation: Kotatsu/Strings
2024-09-26 15:34:44 +03:00
gallegonovato
04700a22c8 Translated using Weblate (Spanish)
Currently translated at 100.0% (724 of 724 strings)

Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/es/
Translation: Kotatsu/Strings
2024-09-26 15:34:44 +03:00
Hosted Weblate
549d08cc06 Update translation files
Updated by "Remove blank strings" hook in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/
Translation: Kotatsu/Strings
2024-09-26 15:34:44 +03:00
Infy's Tagalog Translations
0fccaf3fbc Translated using Weblate (Filipino)
Currently translated at 98.4% (713 of 724 strings)

Translated using Weblate (Filipino)

Currently translated at 98.8% (712 of 720 strings)

Co-authored-by: Infy's Tagalog Translations <ced.paltep10@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fil/
Translation: Kotatsu/Strings
2024-09-26 15:34:44 +03:00
Felipe Nascimento
c7e0a47bee Translated using Weblate (Portuguese)
Currently translated at 98.7% (711 of 720 strings)

Co-authored-by: Felipe Nascimento <f.kgb@hotmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pt/
Translation: Kotatsu/Strings
2024-09-26 15:34:44 +03:00
Макар Разин
d527b6e390 Translated using Weblate (Russian)
Currently translated at 100.0% (720 of 720 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (720 of 720 strings)

Co-authored-by: Макар Разин <makarrazin14@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/be/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ru/
Translation: Kotatsu/Strings
2024-09-26 15:34:44 +03:00
Koitharu
12b2af6b93 Update parsers 2024-09-26 14:46:36 +03:00
Koitharu
63f4fab40f Fix applying filter 2024-09-26 12:33:35 +03:00
Koitharu
9a444cf965 Migrate external sources to new filter 2024-09-25 12:28:10 +03:00
Koitharu
b8be2f7158 Fix sync auth activity ui 2024-09-25 09:48:17 +03:00
Draken
9e2074040f Translated using Weblate (Vietnamese)
Currently translated at 100.0% (720 of 720 strings)

Co-authored-by: Draken <premieregirl26@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/vi/
Translation: Kotatsu/Strings
2024-09-25 09:47:57 +03:00
Infy's Tagalog Translations
020c151e31 Translated using Weblate (Filipino)
Currently translated at 98.8% (712 of 720 strings)

Co-authored-by: Infy's Tagalog Translations <ced.paltep10@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fil/
Translation: Kotatsu/Strings
2024-09-25 09:47:57 +03:00
gekka
52eb33a992 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 99.8% (719 of 720 strings)

Co-authored-by: gekka <1778962971@qq.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/
Translation: Kotatsu/Strings
2024-09-25 09:47:57 +03:00
大王叫我来巡山
907b8fd0ec Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 99.8% (719 of 720 strings)

Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/
Translation: Kotatsu/Strings
2024-09-25 09:47:57 +03:00
Oğuz Ersen
e35b2088a1 Translated using Weblate (Turkish)
Currently translated at 100.0% (720 of 720 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/tr/
Translation: Kotatsu/Strings
2024-09-25 09:47:57 +03:00
Faiz Faadhillah
fbb4efb3df Improve Spen integration support 2024-09-25 09:47:03 +03:00
Koitharu
7ff47a322e Update parsers 2024-09-24 17:56:11 +03:00
Koitharu
fda1af5500 Merge branch 'devel' of https://hosted.weblate.org/git/kotatsu/strings into devel 2024-09-24 17:51:14 +03:00
Koitharu
d88847d137 Various fixes 2024-09-24 17:48:13 +03:00
Koitharu
063527b240 Context menus 2024-09-24 17:48:12 +03:00
gallegonovato
b0470110a8 Translated using Weblate (Spanish)
Currently translated at 100.0% (720 of 720 strings)

Translation: Kotatsu/Strings
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/es/
2024-09-24 16:46:39 +02:00
Anonymous
5a2a31d1c8 Translated using Weblate (Hungarian)
Currently translated at 86.6% (622 of 718 strings)

Translated using Weblate (Nepali)

Currently translated at 32.3% (232 of 718 strings)

Translated using Weblate (Hindi)

Currently translated at 93.0% (668 of 718 strings)

Translated using Weblate (Portuguese)

Currently translated at 92.7% (666 of 718 strings)

Co-authored-by: Anonymous <noreply@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/hi/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/hu/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ne/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pt/
Translation: Kotatsu/Strings
2024-09-24 17:46:34 +03:00
desu sude
3b009d7c55 Translated using Weblate (Latvian)
Currently translated at 24.4% (175 of 717 strings)

Co-authored-by: desu sude <cobsonslittlecocksleeve@proton.me>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/lv/
Translation: Kotatsu/Strings
2024-09-24 17:46:34 +03:00
Anon
f7e937f2b8 Translated using Weblate (Serbian)
Currently translated at 100.0% (698 of 698 strings)

Co-authored-by: Anon <anonymousprivate76@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/sr/
Translation: Kotatsu/Strings
2024-09-24 17:46:34 +03:00
Milo Ivir
16e23cc1cf Translated using Weblate (Croatian)
Currently translated at 98.7% (689 of 698 strings)

Co-authored-by: Milo Ivir <mail@milotype.de>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/hr/
Translation: Kotatsu/Strings
2024-09-24 17:46:34 +03:00
Infy's Tagalog Translations
d12528d80f Translated using Weblate (Filipino)
Currently translated at 100.0% (698 of 698 strings)

Translated using Weblate (Filipino)

Currently translated at 100.0% (698 of 698 strings)

Co-authored-by: Infy's Tagalog Translations <ced.paltep10@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fil/
Translation: Kotatsu/Strings
2024-09-24 17:46:34 +03:00
abc0922001
9f04c7b148 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 92.1% (643 of 698 strings)

Co-authored-by: abc0922001 <abc0922001@hotmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hant/
Translation: Kotatsu/Strings
2024-09-24 17:46:34 +03:00
Amirreza Safavi
7a3942f100 Translated using Weblate (Persian)
Currently translated at 41.6% (288 of 692 strings)

Co-authored-by: Amirreza Safavi <amirxcatsanddragons@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fa/
Translation: Kotatsu/Strings
2024-09-24 17:46:34 +03:00
gekka
8e46f64f2a Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 99.7% (716 of 718 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 99.7% (696 of 698 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 99.7% (696 of 698 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 99.8% (691 of 692 strings)

Co-authored-by: gekka <1778962971@qq.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/
Translation: Kotatsu/Strings
2024-09-24 17:46:34 +03:00
Shayan
44c50fca2d Translated using Weblate (Persian)
Currently translated at 41.6% (288 of 692 strings)

Co-authored-by: Shayan <shayans31516@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fa/
Translation: Kotatsu/Strings
2024-09-24 17:46:34 +03:00
Amirreza Safavi
55b4d14a93 Translated using Weblate (Persian)
Currently translated at 41.6% (288 of 692 strings)

Co-authored-by: Amirreza Safavi <amirxcatsanddragons@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fa/
Translation: Kotatsu/Strings
2024-09-24 17:46:34 +03:00
gallegonovato
743693299f Translated using Weblate (Spanish)
Currently translated at 100.0% (718 of 718 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (717 of 717 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (698 of 698 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (698 of 698 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (692 of 692 strings)

Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/es/
Translation: Kotatsu/Strings
2024-09-24 17:46:34 +03:00
Draken
7950a685a6 Translated using Weblate (Vietnamese)
Currently translated at 100.0% (718 of 718 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (717 of 717 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (698 of 698 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (692 of 692 strings)

Co-authored-by: Draken <premieregirl26@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/vi/
Translation: Kotatsu/Strings
2024-09-24 17:46:34 +03:00
Oğuz Ersen
97cfcb5c01 Translated using Weblate (Turkish)
Currently translated at 100.0% (718 of 718 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (717 of 717 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (710 of 710 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (698 of 698 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (692 of 692 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/tr/
Translation: Kotatsu/Strings
2024-09-24 17:46:34 +03:00
Fikri Akbar
b2dfcefee8 Translated using Weblate (Indonesian)
Currently translated at 99.8% (688 of 689 strings)

Co-authored-by: Fikri Akbar <akbarfikri1221@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/id/
Translation: Kotatsu/Strings
2024-09-24 17:46:34 +03:00
Anonymous
ee1ade40c3 Translated using Weblate (Hungarian)
Currently translated at 86.6% (622 of 718 strings)

Translated using Weblate (Nepali)

Currently translated at 32.3% (232 of 718 strings)

Translated using Weblate (Hindi)

Currently translated at 93.0% (668 of 718 strings)

Translated using Weblate (Portuguese)

Currently translated at 92.7% (666 of 718 strings)

Co-authored-by: Anonymous <noreply@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/hi/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/hu/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ne/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pt/
Translation: Kotatsu/Strings
2024-09-24 11:03:58 +02:00
desu sude
3690e15cff Translated using Weblate (Latvian)
Currently translated at 24.4% (175 of 717 strings)

Co-authored-by: desu sude <cobsonslittlecocksleeve@proton.me>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/lv/
Translation: Kotatsu/Strings
2024-09-24 11:03:58 +02:00
Anon
a955dfbe50 Translated using Weblate (Serbian)
Currently translated at 100.0% (698 of 698 strings)

Co-authored-by: Anon <anonymousprivate76@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/sr/
Translation: Kotatsu/Strings
2024-09-24 11:03:58 +02:00
Milo Ivir
5e9daa1206 Translated using Weblate (Croatian)
Currently translated at 98.7% (689 of 698 strings)

Co-authored-by: Milo Ivir <mail@milotype.de>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/hr/
Translation: Kotatsu/Strings
2024-09-24 11:03:58 +02:00
Infy's Tagalog Translations
a3c2956a4d Translated using Weblate (Filipino)
Currently translated at 100.0% (698 of 698 strings)

Translated using Weblate (Filipino)

Currently translated at 100.0% (698 of 698 strings)

Co-authored-by: Infy's Tagalog Translations <ced.paltep10@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fil/
Translation: Kotatsu/Strings
2024-09-24 11:03:58 +02:00
abc0922001
10ecd92715 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 92.1% (643 of 698 strings)

Co-authored-by: abc0922001 <abc0922001@hotmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hant/
Translation: Kotatsu/Strings
2024-09-24 11:03:58 +02:00
Amirreza Safavi
37d2d986ef Translated using Weblate (Persian)
Currently translated at 41.6% (288 of 692 strings)

Co-authored-by: Amirreza Safavi <amirxcatsanddragons@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fa/
Translation: Kotatsu/Strings
2024-09-24 11:03:58 +02:00
gekka
0aadd6ebe2 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 99.8% (717 of 718 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 99.7% (716 of 718 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 99.7% (696 of 698 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 99.7% (696 of 698 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 99.8% (691 of 692 strings)

Co-authored-by: gekka <1778962971@qq.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/
Translation: Kotatsu/Strings
2024-09-24 11:03:58 +02:00
Shayan
c23ec9a4b8 Translated using Weblate (Persian)
Currently translated at 41.6% (288 of 692 strings)

Co-authored-by: Shayan <shayans31516@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fa/
Translation: Kotatsu/Strings
2024-09-24 11:03:58 +02:00
Amirreza Safavi
22a37923f9 Translated using Weblate (Persian)
Currently translated at 41.6% (288 of 692 strings)

Co-authored-by: Amirreza Safavi <amirxcatsanddragons@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fa/
Translation: Kotatsu/Strings
2024-09-24 11:03:57 +02:00
gallegonovato
3fc506b438 Translated using Weblate (Spanish)
Currently translated at 100.0% (718 of 718 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (717 of 717 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (698 of 698 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (698 of 698 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (692 of 692 strings)

Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/es/
Translation: Kotatsu/Strings
2024-09-24 11:03:57 +02:00
Draken
e98dbd5069 Translated using Weblate (Vietnamese)
Currently translated at 100.0% (718 of 718 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (718 of 718 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (717 of 717 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (698 of 698 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (692 of 692 strings)

Co-authored-by: Draken <premieregirl26@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/vi/
Translation: Kotatsu/Strings
2024-09-24 11:03:57 +02:00
Oğuz Ersen
2a469b27c5 Translated using Weblate (Turkish)
Currently translated at 100.0% (718 of 718 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (718 of 718 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (717 of 717 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (710 of 710 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (698 of 698 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (692 of 692 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/tr/
Translation: Kotatsu/Strings
2024-09-24 11:03:57 +02:00
Fikri Akbar
0f3ef4559f Translated using Weblate (Indonesian)
Currently translated at 99.8% (688 of 689 strings)

Co-authored-by: Fikri Akbar <akbarfikri1221@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/id/
Translation: Kotatsu/Strings
2024-09-24 11:03:57 +02:00
Koitharu
a87ef0a0a6 Search in history, favorites and local 2024-09-24 11:44:02 +03:00
Koitharu
a7a0a7f0db Fix sources catalog content types 2024-09-24 10:18:10 +03:00
Koitharu
bc4622d610 Local manga source filter 2024-09-23 19:22:48 +03:00
Koitharu
8365603bf1 Update supported domains 2024-09-23 18:28:55 +03:00
Koitharu
b1eabdba79 Improve quick filters 2024-09-23 14:46:29 +03:00
Koitharu
169e31e9ba Local manga index in database 2024-09-23 08:55:17 +03:00
Koitharu
66644d55a4 Search manga with filters 2024-09-22 17:44:36 +03:00
Koitharu
98314960cf Improve filter 2024-09-21 11:58:45 +03:00
Koitharu
b73e44874d Add new filter fields 2024-09-21 09:11:58 +03:00
Koitharu
6f45a44070 Update parsers and filters 2024-09-21 08:22:32 +03:00
Koitharu
d9d11d685e Update parsers 2024-09-15 16:05:52 +03:00
Koitharu
5359267b5a Update dependencies 2024-09-15 15:16:07 +03:00
Koitharu
a6662ab501 Batch manga fix functionality 2024-09-15 15:02:34 +03:00
Amirreza Safavi
699a619c27 Translated using Weblate (Persian)
Currently translated at 77.7% (7 of 9 strings)

Translated using Weblate (Persian)

Currently translated at 37.4% (258 of 689 strings)

Co-authored-by: Amirreza Safavi <amirxcatsanddragons@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/plurals/fa/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fa/
Translation: Kotatsu/Strings
Translation: Kotatsu/plurals
2024-09-14 14:42:29 +03:00
Anon
85ccbbf719 Translated using Weblate (Serbian)
Currently translated at 100.0% (689 of 689 strings)

Co-authored-by: Anon <anonymousprivate76@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/sr/
Translation: Kotatsu/Strings
2024-09-14 14:42:29 +03:00
Henrique
a396b33f3d Translated using Weblate (Portuguese (Brazil))
Currently translated at 96.6% (666 of 689 strings)

Co-authored-by: Henrique <heluis110@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pt_BR/
Translation: Kotatsu/Strings
2024-09-14 14:42:29 +03:00
Макар Разин
6076f775c3 Translated using Weblate (Russian)
Currently translated at 100.0% (689 of 689 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (689 of 689 strings)

Co-authored-by: Макар Разин <makarrazin14@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/be/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ru/
Translation: Kotatsu/Strings
2024-09-14 14:42:29 +03:00
Dilip Patel
379fa88b4e grammar fix 2024-09-14 14:39:36 +03:00
Koitharu
9b24c507c5 Option to automatically download new chapters (close #425, close #602, close #955) 2024-09-14 12:12:55 +03:00
Koitharu
98bd79f0be Update dependencies 2024-09-11 08:50:51 +03:00
Mac135135
7c74c87524 Merge remote-tracking branch 'origin/devel' into devel 2024-09-07 15:26:13 +03:00
Koitharu
f09e28e782 Fix applying global color filter (close #1088) 2024-09-06 12:19:59 +03:00
Koitharu
b601b07586 Optimize the Downloaded quick filter 2024-09-06 11:35:23 +03:00
Koitharu
73cea59691 Change pref key for ProxyType 2024-09-06 07:45:48 +03:00
Koitharu
e2993d47b6 Fix closing ZipFile 2024-09-06 07:44:29 +03:00
Koitharu
2cd67e7cf8 Fix crashes 2024-09-06 07:28:17 +03:00
Koitharu
c51da5a9d5 Update parsers 2024-09-05 12:52:03 +03:00
Justine Kyle Cobar
bcfce29610 Translated using Weblate (Filipino)
Currently translated at 100.0% (689 of 689 strings)

Co-authored-by: Justine Kyle Cobar <cobarjustinekyle583@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fil/
Translation: Kotatsu/Strings
2024-09-05 11:03:14 +03:00
maryush
a87d18fae3 Translated using Weblate (Polish)
Currently translated at 99.8% (688 of 689 strings)

Co-authored-by: maryush <maryush@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pl/
Translation: Kotatsu/Strings
2024-09-05 11:03:14 +03:00
gekka
bbd421445c Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (689 of 689 strings)

Co-authored-by: gekka <1778962971@qq.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/
Translation: Kotatsu/Strings
2024-09-05 11:03:14 +03:00
Oğuz Ersen
f4e3d797dc Translated using Weblate (Turkish)
Currently translated at 100.0% (689 of 689 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/tr/
Translation: Kotatsu/Strings
2024-09-05 11:03:14 +03:00
Denis Bolba
bd65cbb8b8 Translated using Weblate (Romanian)
Currently translated at 12.9% (89 of 689 strings)

Added translation using Weblate (Romanian)

Added translation using Weblate (Romanian)

Co-authored-by: Denis Bolba <bolbadenis4@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ro/
Translation: Kotatsu/Strings
2024-09-05 11:03:14 +03:00
Draken
7d1f81607a Translated using Weblate (Vietnamese)
Currently translated at 100.0% (689 of 689 strings)

Co-authored-by: Draken <premieregirl26@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/vi/
Translation: Kotatsu/Strings
2024-09-05 11:03:14 +03:00
gallegonovato
3b6cd0ea7f Translated using Weblate (Spanish)
Currently translated at 100.0% (689 of 689 strings)

Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/es/
Translation: Kotatsu/Strings
2024-09-05 11:03:14 +03:00
Koitharu
aff70d8519 Update dependencies 2024-09-05 10:30:52 +03:00
Koitharu
8a74faa4f0 Fix Downloaded quick filter (close #1076, close #1079) 2024-09-05 10:16:09 +03:00
Koitharu
c1ac207809 Fix downloading (close #1072) 2024-09-04 14:33:08 +03:00
Koitharu
e34e745c84 Fix reading saved manga offline (close #1081, close #1071) 2024-09-04 13:41:57 +03:00
Koitharu
50dd119ab5 Fixes 2024-09-03 17:47:36 +03:00
Koitharu
d0ef177d56 Fix sort order direction in filter 2024-09-03 14:52:04 +03:00
Infy's Tagalog Translations
9b9c2e49b9 Translated using Weblate (Filipino)
Currently translated at 100.0% (687 of 687 strings)

Co-authored-by: Infy's Tagalog Translations <ced.paltep10@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fil/
Translation: Kotatsu/Strings
2024-09-03 13:44:57 +03:00
Igor
afeb307453 Translated using Weblate (Ukrainian)
Currently translated at 97.3% (667 of 685 strings)

Co-authored-by: Igor <zerrxs@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/uk/
Translation: Kotatsu/Strings
2024-09-03 13:44:57 +03:00
Koitharu
7568b1aedc Translated using Weblate (Russian)
Currently translated at 100.0% (685 of 685 strings)

Co-authored-by: Koitharu <nvasya95@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ru/
Translation: Kotatsu/Strings
2024-09-03 13:44:57 +03:00
yoval keshet
742d8cee00 Translated using Weblate (Hebrew)
Currently translated at 100.0% (9 of 9 strings)

Co-authored-by: yoval keshet <keshetyoval@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/plurals/he/
Translation: Kotatsu/plurals
2024-09-03 13:44:57 +03:00
gallegonovato
d52bef28ff Translated using Weblate (Spanish)
Currently translated at 100.0% (687 of 687 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (685 of 685 strings)

Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/es/
Translation: Kotatsu/Strings
2024-09-03 13:44:57 +03:00
Koitharu
b2f48421c7 Sync unstable warning 2024-09-03 13:37:56 +03:00
Koitharu
22643bf9cc Handle scrobbler authorization errors 2024-09-03 11:09:58 +03:00
Koitharu
861ca63ea9 Manual-only new chapters check option 2024-09-02 13:02:25 +03:00
Koitharu
6e34356b6f Fix grayscale color filter (closes ##1065) 2024-09-02 12:43:26 +03:00
Koitharu
a9b3025724 Fix external sources tags filtering 2024-08-31 16:44:28 +03:00
Koitharu
0cc019ef19 Refactor details and reader ViewModels 2024-08-31 14:13:11 +03:00
Koitharu
eb49b31aeb Inverted filter presets 2024-08-31 09:53:32 +03:00
Koitharu
5ebbfd1c00 Refactor alert dialogs 2024-08-31 09:44:42 +03:00
Koitharu
0df67b86f8 Increase suggestions limit 2024-08-31 08:36:17 +03:00
Koitharu
2df567372e Fix empty lists state with Downloaded filter 2024-08-31 08:35:38 +03:00
Koitharu
0fb3c69e10 Fix release build 2024-08-30 11:17:09 +03:00
Koitharu
44900dbcbe Update AGP 2024-08-30 09:19:54 +03:00
Milo Ivir
89cd295f28 Translated using Weblate (Croatian)
Currently translated at 100.0% (685 of 685 strings)

Co-authored-by: Milo Ivir <mail@milotype.de>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/hr/
Translation: Kotatsu/Strings
2024-08-30 08:05:06 +03:00
Draken
d06811d94d Translated using Weblate (Vietnamese)
Currently translated at 100.0% (685 of 685 strings)

Co-authored-by: Draken <premieregirl26@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/vi/
Translation: Kotatsu/Strings
2024-08-30 08:05:06 +03:00
gekka
ced22ebb0a Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (685 of 685 strings)

Co-authored-by: gekka <1778962971@qq.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/
Translation: Kotatsu/Strings
2024-08-30 08:05:06 +03:00
Oğuz Ersen
3c2ad26f1d Translated using Weblate (Turkish)
Currently translated at 100.0% (685 of 685 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/tr/
Translation: Kotatsu/Strings
2024-08-30 08:05:06 +03:00
Макар Разин
9535e35ba7 Translated using Weblate (Polish)
Currently translated at 99.5% (682 of 685 strings)

Translated using Weblate (Serbian)

Currently translated at 99.5% (682 of 685 strings)

Translated using Weblate (Russian)

Currently translated at 99.8% (684 of 685 strings)

Translated using Weblate (Belarusian)

Currently translated at 99.8% (684 of 685 strings)

Co-authored-by: Макар Разин <makarrazin14@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/be/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pl/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ru/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/sr/
Translation: Kotatsu/Strings
2024-08-30 08:05:06 +03:00
Infy's Tagalog Translations
298e87dce2 Translated using Weblate (Filipino)
Currently translated at 100.0% (685 of 685 strings)

Translated using Weblate (Filipino)

Currently translated at 100.0% (678 of 678 strings)

Co-authored-by: Infy's Tagalog Translations <ced.paltep10@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fil/
Translation: Kotatsu/Strings
2024-08-30 08:05:06 +03:00
Kacper Małecki
165ce61ded Translated using Weblate (Polish)
Currently translated at 99.7% (676 of 678 strings)

Co-authored-by: Kacper Małecki <kacperito887@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pl/
Translation: Kotatsu/Strings
2024-08-30 08:05:06 +03:00
Koitharu
c70e3547d1 Support ascending/descending sort orders 2024-08-29 08:10:16 +03:00
Koitharu
05b5953f35 Fix excluding NSFW 2024-08-28 09:24:49 +03:00
Justine Kyle Cobar
9cba6e694a Translated using Weblate (Filipino)
Currently translated at 100.0% (678 of 678 strings)

Co-authored-by: Justine Kyle Cobar <cobarjustinekyle583@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fil/
Translation: Kotatsu/Strings
2024-08-28 09:21:36 +03:00
Lee Khemrinn Phang
b2c73ec9d8 Translated using Weblate (Khmer (Central))
Currently translated at 21.1% (143 of 677 strings)

Translated using Weblate (Khmer (Central))

Currently translated at 13.7% (92 of 671 strings)

Translated using Weblate (Khmer (Central))

Currently translated at 13.5% (91 of 671 strings)

Added translation using Weblate (Khmer (Central))

Added translation using Weblate (Khmer (Central))

Co-authored-by: Lee Khemrinn Phang <Nihil@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/km/
Translation: Kotatsu/Strings
2024-08-28 09:21:36 +03:00
ALN
cd7620673b Translated using Weblate (Kazakh)
Currently translated at 81.7% (547 of 669 strings)

Translated using Weblate (Kazakh)

Currently translated at 77.7% (7 of 9 strings)

Co-authored-by: ALN <alzhanalan1@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/plurals/kk/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/kk/
Translation: Kotatsu/Strings
Translation: Kotatsu/plurals
2024-08-28 09:21:36 +03:00
maryush
09bfb2b0f4 Translated using Weblate (Polish)
Currently translated at 100.0% (669 of 669 strings)

Co-authored-by: maryush <maryush@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pl/
Translation: Kotatsu/Strings
2024-08-28 09:21:36 +03:00
Anon
6dde7e9535 Translated using Weblate (Serbian)
Currently translated at 100.0% (678 of 678 strings)

Translated using Weblate (Serbian)

Currently translated at 100.0% (667 of 667 strings)

Co-authored-by: Anon <anonymousprivate76@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/sr/
Translation: Kotatsu/Strings
2024-08-28 09:21:36 +03:00
Laura
98e24072ce Translated using Weblate (Arabic)
Currently translated at 100.0% (9 of 9 strings)

Co-authored-by: Laura <hankmaroua@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/plurals/ar/
Translation: Kotatsu/plurals
2024-08-28 09:21:36 +03:00
Felipe Nascimento
fdc67f8f0e Translated using Weblate (Portuguese)
Currently translated at 100.0% (667 of 667 strings)

Co-authored-by: Felipe Nascimento <f.kgb@hotmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pt/
Translation: Kotatsu/Strings
2024-08-28 09:21:36 +03:00
gallegonovato
f8acabcc86 Translated using Weblate (Spanish)
Currently translated at 100.0% (678 of 678 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (677 of 677 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (671 of 671 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (667 of 667 strings)

Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/es/
Translation: Kotatsu/Strings
2024-08-28 09:21:36 +03:00
desu sude
5a0771b751 Translated using Weblate (Latvian)
Currently translated at 6.3% (42 of 666 strings)

Added translation using Weblate (Latvian)

Added translation using Weblate (Latvian)

Co-authored-by: desu sude <cobsonslittlecocksleeve@proton.me>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/lv/
Translation: Kotatsu/Strings
2024-08-28 09:21:36 +03:00
user _425
6a231f76e1 Translated using Weblate (Indonesian)
Currently translated at 98.4% (656 of 666 strings)

Co-authored-by: user _425 <lelcraft96@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/id/
Translation: Kotatsu/Strings
2024-08-28 09:21:36 +03:00
LinCie
d203edbdae Translated using Weblate (Indonesian)
Currently translated at 98.4% (656 of 666 strings)

Translated using Weblate (Indonesian)

Currently translated at 97.2% (648 of 666 strings)

Co-authored-by: LinCie <aldiofernanda@protonmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/id/
Translation: Kotatsu/Strings
2024-08-28 09:21:36 +03:00
user _425
91a5aa8d4c Translated using Weblate (Indonesian)
Currently translated at 97.2% (648 of 666 strings)

Co-authored-by: user _425 <lelcraft96@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/id/
Translation: Kotatsu/Strings
2024-08-28 09:21:36 +03:00
Ahmed seif al-nasr
40076dea36 Translated using Weblate (Arabic)
Currently translated at 100.0% (666 of 666 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (9 of 9 strings)

Co-authored-by: Ahmed seif al-nasr <ahmdsyfalnsr2@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/plurals/ar/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ar/
Translation: Kotatsu/Strings
Translation: Kotatsu/plurals
2024-08-28 09:21:36 +03:00
Eduardo Malaspina
2ab7228727 Translated using Weblate (Spanish)
Currently translated at 100.0% (666 of 666 strings)

Co-authored-by: Eduardo Malaspina <vaio0@swismail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/es/
Translation: Kotatsu/Strings
2024-08-28 09:21:36 +03:00
Eduardo
52e500a5fb Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (665 of 665 strings)

Co-authored-by: Eduardo <edu200399lim@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pt_BR/
Translation: Kotatsu/Strings
2024-08-28 09:21:36 +03:00
Kis Miklós
44734867cc Translated using Weblate (Hungarian)
Currently translated at 93.8% (624 of 665 strings)

Co-authored-by: Kis Miklós <kisbivaly@duck.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/hu/
Translation: Kotatsu/Strings
2024-08-28 09:21:36 +03:00
Макар Разин
6565d05274 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (667 of 667 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (667 of 667 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (667 of 667 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (665 of 665 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (665 of 665 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (665 of 665 strings)

Co-authored-by: Макар Разин <makarrazin14@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/be/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ru/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/uk/
Translation: Kotatsu/Strings
2024-08-28 09:21:36 +03:00
Henrique
204758cbbb Translated using Weblate (Portuguese (Brazil))
Currently translated at 99.8% (664 of 665 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (665 of 665 strings)

Co-authored-by: Henrique <heluis110@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pt/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pt_BR/
Translation: Kotatsu/Strings
2024-08-28 09:21:36 +03:00
Milo Ivir
a60e7e13ca Translated using Weblate (Croatian)
Currently translated at 100.0% (671 of 671 strings)

Translated using Weblate (Croatian)

Currently translated at 100.0% (669 of 669 strings)

Translated using Weblate (Croatian)

Currently translated at 100.0% (665 of 665 strings)

Co-authored-by: Milo Ivir <mail@milotype.de>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/hr/
Translation: Kotatsu/Strings
2024-08-28 09:21:36 +03:00
Infy's Tagalog Translations
3596109249 Translated using Weblate (Filipino)
Currently translated at 99.4% (673 of 677 strings)

Translated using Weblate (Filipino)

Currently translated at 99.7% (669 of 671 strings)

Translated using Weblate (Filipino)

Currently translated at 99.8% (668 of 669 strings)

Translated using Weblate (Filipino)

Currently translated at 99.6% (664 of 666 strings)

Translated using Weblate (Filipino)

Currently translated at 99.8% (664 of 665 strings)

Co-authored-by: Infy's Tagalog Translations <ced.paltep10@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fil/
Translation: Kotatsu/Strings
2024-08-28 09:21:36 +03:00
Draken
3c703d9771 Translated using Weblate (Vietnamese)
Currently translated at 100.0% (678 of 678 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (677 of 677 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (671 of 671 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (669 of 669 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (667 of 667 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (666 of 666 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (666 of 666 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (665 of 665 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (665 of 665 strings)

Co-authored-by: Draken <premieregirl26@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/vi/
Translation: Kotatsu/Strings
2024-08-28 09:21:36 +03:00
Scrambled777
1e87dc4c52 Translated using Weblate (Hindi)
Currently translated at 100.0% (669 of 669 strings)

Translated using Weblate (Hindi)

Currently translated at 100.0% (666 of 666 strings)

Translated using Weblate (Hindi)

Currently translated at 100.0% (665 of 665 strings)

Co-authored-by: Scrambled777 <weblate.scrambled777@simplelogin.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/hi/
Translation: Kotatsu/Strings
2024-08-28 09:21:36 +03:00
gekka
ae61d50a6c Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (678 of 678 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (677 of 677 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (671 of 671 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (669 of 669 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (667 of 667 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (666 of 666 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (665 of 665 strings)

Co-authored-by: gekka <1778962971@qq.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/
Translation: Kotatsu/Strings
2024-08-28 09:21:36 +03:00
Oğuz Ersen
63fb40dd65 Translated using Weblate (Turkish)
Currently translated at 100.0% (678 of 678 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (677 of 677 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (671 of 671 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (669 of 669 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (667 of 667 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (666 of 666 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (665 of 665 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/tr/
Translation: Kotatsu/Strings
2024-08-28 09:21:36 +03:00
gallegonovato
afe2248bb8 Translated using Weblate (Spanish)
Currently translated at 100.0% (665 of 665 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (664 of 664 strings)

Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/es/
Translation: Kotatsu/Strings
2024-08-28 09:21:36 +03:00
Anonymous
b3b82ace3f Translated using Weblate (Chinese (Simplified))
Currently translated at 99.8% (663 of 664 strings)

Translated using Weblate (Swedish)

Currently translated at 40.5% (269 of 664 strings)

Translated using Weblate (Finnish)

Currently translated at 38.8% (258 of 664 strings)

Translated using Weblate (Portuguese)

Currently translated at 95.6% (635 of 664 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 43.0% (286 of 664 strings)

Co-authored-by: Anonymous <noreply@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fi/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pt/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/sv/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/
Translation: Kotatsu/Strings
2024-08-28 09:21:36 +03:00
Koitharu
903fef6791 Apply the Disable NSFW option to all lists (closes #1057) 2024-08-26 17:34:28 +03:00
Koitharu
542ad29cd9 Webtoon reader fixes 2024-08-26 17:00:27 +03:00
Koitharu
d588e8d941 Fix chapters selections 2024-08-26 14:31:39 +03:00
Koitharu
6b786084cf Update parsers 2024-08-24 20:04:05 +03:00
Koitharu
85da41be9a Downloading improvements 2024-08-24 10:10:43 +03:00
Koitharu
6e8a1cd6af Skip nsfw sources for recommendations if disabled 2024-08-20 16:28:39 +03:00
Koitharu
0f28d5de11 Fix switching double-page mode 2024-08-20 15:41:55 +03:00
Koitharu
0d39909d89 Update parsers 2024-08-20 15:32:49 +03:00
Koitharu
e4282a8e9d Improve favorite categories screen (fix #1047) 2024-08-20 15:23:33 +03:00
Koitharu
05a64308ac Dont show favorites from hidden categories in the "All favorites" tab 2024-08-20 13:43:32 +03:00
Koitharu
7b01bafd53 Fix pages downsampling 2024-08-20 13:07:59 +03:00
Koitharu
b521460335 Split url and domain validations #1043 2024-08-20 12:08:51 +03:00
Nicolai Dagestad
249c8377bd Default to http for pre-configured syncs
When a user had configured a sync server before, it had no protocol specified.
This commit "restores" the previous behaviour of using http by default.
2024-08-20 12:03:44 +03:00
Nicolai Dagestad
58cdc9f29a Do not rename the string ressource (+ syntax fix) 2024-08-20 12:03:44 +03:00
Nicolai Dagestad
065beb72e1 First attempt to add https syncing 2024-08-20 12:03:44 +03:00
Koitharu
c00614f17d Improve quick filter behavior 2024-08-20 12:03:20 +03:00
Koitharu
d99bc08e49 Fix release build 2024-08-18 18:13:46 +03:00
Koitharu
9e49b28ac3 Quick filter request refactor 2024-08-18 17:02:15 +03:00
Koitharu
d06b396aec Quick filter for suggestions 2024-08-18 16:03:00 +03:00
Koitharu
65abef1282 Quick filter in feed and updates lists 2024-08-18 14:01:29 +03:00
Koitharu
b66d3ee8d4 Merge branch 'master' into devel 2024-08-17 12:19:55 +03:00
Koitharu
597abdb20c Update parsers and libraries 2024-08-17 11:47:56 +03:00
Koitharu
174fa800be Refactor and cleanup 2024-08-17 09:38:57 +03:00
Koitharu
28670bc7fb Improve favorites dialog 2024-08-15 16:14:24 +03:00
Koitharu
a61e406c91 Fix reading progress indication 2024-08-15 14:46:06 +03:00
Koitharu
20f357cb12 Handle invalid proxy settings 2024-08-15 12:18:41 +03:00
Koitharu
5ba6b81fac Update dependencies 2024-08-15 09:56:18 +03:00
Koitharu
e34bcd47d5 Refactor tracker 2024-08-15 09:34:59 +03:00
Koitharu
62ed8705e8 UI fixes 2024-08-13 08:20:06 +03:00
vianh
de18324798 Hide toolbar for favorites screen only 2024-08-12 19:36:40 +03:00
vianh
a7a943c8dc Hide toolbar when scrolling up 2024-08-12 19:36:40 +03:00
Coding Otaku
6e975b9d66 ix: migrate from kitsu.io to kitsu.app
The [kitsu.io](https://kitsu.io) domain has expired, and the main developers
do not have access to that domain. So they
[migrated](hummingbird-me/kitsu-server#1556)
to the new [kitsu.app](https://kitsu.app) domain.

This commit updates all references of `kitsu.io` to `kitsu.app`.
2024-08-12 18:39:01 +03:00
Koitharu
9e53dc3d5f Merge branch 'master' into devel 2024-08-12 18:35:22 +03:00
Koitharu
809e7d8701 Ability to check proxy connection 2024-08-12 18:22:05 +03:00
Koitharu
0015c5704a Fix ignoring external sources in global search 2024-08-12 17:30:21 +03:00
Koitharu
a7ff1610eb Fix crashes 2024-08-12 17:17:02 +03:00
Koitharu
22c402fc5e Update parers 2024-08-12 16:51:03 +03:00
Koitharu
f3c19f9c02 Add more quick filters 2024-08-12 16:46:07 +03:00
Koitharu
33b4b9fbcb Update incognito mode hint view 2024-08-12 16:07:23 +03:00
Koitharu
00396f2e1b Quick filter for favorites 2024-08-12 15:28:14 +03:00
Koitharu
8b71f99666 Refactor quick filter implementation 2024-08-08 12:10:26 +03:00
Mac135135
f86ee7d5c2 Merge remote-tracking branch 'origin/devel' into devel 2024-08-04 19:46:52 +03:00
Koitharu
d00822a6c3 Quick filter in history draft implementation 2024-08-03 16:22:46 +03:00
Koitharu
6e92d46a63 Update parsers 2024-08-03 15:02:31 +03:00
Koitharu
66ed926ea8 Merge remote-tracking branch 'weblate/devel' into devel 2024-08-03 13:36:12 +03:00
Koitharu
b7741ce2af Allow to use biometric unlock manually (closes #999) 2024-08-03 13:35:28 +03:00
vianh
1a17324d26 Fix reader state not being restored 2024-08-03 12:47:57 +03:00
gekka
4044936481 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (664 of 664 strings)

Co-authored-by: gekka <1778962971@qq.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/
Translation: Kotatsu/Strings
2024-08-03 12:47:46 +03:00
Oğuz Ersen
1efe86421a Translated using Weblate (Turkish)
Currently translated at 100.0% (664 of 664 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/tr/
Translation: Kotatsu/Strings
2024-08-03 12:47:46 +03:00
gallegonovato
34dd080f6c Translated using Weblate (Spanish)
Currently translated at 100.0% (664 of 664 strings)

Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/es/
Translation: Kotatsu/Strings
2024-08-03 12:47:46 +03:00
Scrambled777
f4838afab0 Translated using Weblate (Hindi)
Currently translated at 100.0% (664 of 664 strings)

Translated using Weblate (Hindi)

Currently translated at 100.0% (663 of 663 strings)

Co-authored-by: Scrambled777 <weblate.scrambled777@simplelogin.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/hi/
Translation: Kotatsu/Strings
2024-08-03 12:47:46 +03:00
Anon
b207eebe56 Translated using Weblate (Serbian)
Currently translated at 100.0% (663 of 663 strings)

Co-authored-by: Anon <anonymousprivate76@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/sr/
Translation: Kotatsu/Strings
2024-08-03 12:47:46 +03:00
Draken
4f454ab438 Translated using Weblate (Vietnamese)
Currently translated at 100.0% (663 of 663 strings)

Co-authored-by: Draken <premieregirl26@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/vi/
Translation: Kotatsu/Strings
2024-08-03 12:47:46 +03:00
weedyy
1ecf416113 Translated using Weblate (Arabic)
Currently translated at 99.8% (662 of 663 strings)

Co-authored-by: weedyy <huzskywalker@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ar/
Translation: Kotatsu/Strings
2024-08-03 12:47:46 +03:00
TheOneWhoCares
94670a03ff Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (663 of 663 strings)

Co-authored-by: TheOneWhoCares <266nre4gw@mozmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pt_BR/
Translation: Kotatsu/Strings
2024-08-03 12:47:46 +03:00
Макар Разин
e92f165677 Translated using Weblate (Russian)
Currently translated at 100.0% (663 of 663 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (663 of 663 strings)

Co-authored-by: Макар Разин <makarrazin14@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/be/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ru/
Translation: Kotatsu/Strings
2024-08-03 12:47:46 +03:00
gekka
4a03137a25 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (664 of 664 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (664 of 664 strings)

Co-authored-by: gekka <1778962971@qq.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/
Translation: Kotatsu/Strings
2024-08-03 11:47:41 +02:00
Oğuz Ersen
7e6e1fb6de Translated using Weblate (Turkish)
Currently translated at 100.0% (664 of 664 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/tr/
Translation: Kotatsu/Strings
2024-08-03 11:47:41 +02:00
gallegonovato
f477797823 Translated using Weblate (Spanish)
Currently translated at 100.0% (664 of 664 strings)

Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/es/
Translation: Kotatsu/Strings
2024-08-03 11:47:41 +02:00
Scrambled777
125b6740a6 Translated using Weblate (Hindi)
Currently translated at 100.0% (664 of 664 strings)

Translated using Weblate (Hindi)

Currently translated at 100.0% (663 of 663 strings)

Co-authored-by: Scrambled777 <weblate.scrambled777@simplelogin.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/hi/
Translation: Kotatsu/Strings
2024-08-03 11:47:41 +02:00
Anon
1618a11955 Translated using Weblate (Serbian)
Currently translated at 100.0% (663 of 663 strings)

Co-authored-by: Anon <anonymousprivate76@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/sr/
Translation: Kotatsu/Strings
2024-08-03 11:47:41 +02:00
Draken
966d6e2383 Translated using Weblate (Vietnamese)
Currently translated at 100.0% (663 of 663 strings)

Co-authored-by: Draken <premieregirl26@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/vi/
Translation: Kotatsu/Strings
2024-08-03 11:47:41 +02:00
weedyy
2f33a135fc Translated using Weblate (Arabic)
Currently translated at 99.8% (662 of 663 strings)

Co-authored-by: weedyy <huzskywalker@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ar/
Translation: Kotatsu/Strings
2024-08-03 11:47:41 +02:00
TheOneWhoCares
207ea492d5 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (663 of 663 strings)

Co-authored-by: TheOneWhoCares <266nre4gw@mozmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pt_BR/
Translation: Kotatsu/Strings
2024-08-03 11:47:41 +02:00
Макар Разин
250d5432a0 Translated using Weblate (Russian)
Currently translated at 100.0% (663 of 663 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (663 of 663 strings)

Co-authored-by: Макар Разин <makarrazin14@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/be/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ru/
Translation: Kotatsu/Strings
2024-08-03 11:47:41 +02:00
Koitharu
9768758ecc Optimize external plugin cursor 2024-08-02 12:27:42 +03:00
Koitharu
20852dbd12 Fix query plugin source capabilities 2024-08-01 21:01:40 +03:00
Mac135135
6e5519419d Merge remote-tracking branch 'origin/devel' into devel 2024-07-31 19:16:41 +03:00
Koitharu
2bc632474d Update parsers 2024-07-30 09:34:36 +03:00
gekka
78fd754d91 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (663 of 663 strings)

Co-authored-by: gekka <1778962971@qq.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/
Translation: Kotatsu/Strings
2024-07-30 09:28:04 +03:00
Oğuz Ersen
bfa0045f1d Translated using Weblate (Turkish)
Currently translated at 100.0% (663 of 663 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/tr/
Translation: Kotatsu/Strings
2024-07-30 09:28:04 +03:00
gallegonovato
97e2d58750 Translated using Weblate (Spanish)
Currently translated at 100.0% (663 of 663 strings)

Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/es/
Translation: Kotatsu/Strings
2024-07-30 09:28:04 +03:00
maryush
ff668931ba Translated using Weblate (Polish)
Currently translated at 100.0% (662 of 662 strings)

Co-authored-by: maryush <maryush@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pl/
Translation: Kotatsu/Strings
2024-07-30 09:28:04 +03:00
weedyy
1c0149afc9 Translated using Weblate (Arabic)
Currently translated at 100.0% (662 of 662 strings)

Translated using Weblate (Arabic)

Currently translated at 99.3% (658 of 662 strings)

Co-authored-by: weedyy <huzskywalker@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ar/
Translation: Kotatsu/Strings
2024-07-30 09:28:04 +03:00
Draken
12ee3ef497 Translated using Weblate (Vietnamese)
Currently translated at 100.0% (662 of 662 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (662 of 662 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (9 of 9 strings)

Co-authored-by: Draken <premieregirl26@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/plurals/vi/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/vi/
Translation: Kotatsu/Strings
Translation: Kotatsu/plurals
2024-07-30 09:28:04 +03:00
Koitharu
ae2e38acac Trim description 2024-07-28 14:55:25 +03:00
Koitharu
f25050bce8 Support for manga sources from external APKs 2024-07-28 14:50:41 +03:00
Koitharu
830d500a68 Update dependencies 2024-07-28 07:31:45 +03:00
Anon
960e5d9d29 Translated using Weblate (Serbian)
Currently translated at 100.0% (662 of 662 strings)

Co-authored-by: Anon <anonymousprivate76@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/sr/
Translation: Kotatsu/Strings
2024-07-27 12:20:41 +03:00
Yoshi Nizar
75b9f27761 Translated using Weblate (Italian)
Currently translated at 99.5% (659 of 662 strings)

Co-authored-by: Yoshi Nizar <canalefinto@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/it/
Translation: Kotatsu/Strings
2024-07-27 12:20:41 +03:00
Draken
67af210f07 Translated using Weblate (Vietnamese)
Currently translated at 100.0% (662 of 662 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (9 of 9 strings)

Co-authored-by: Draken <premieregirl26@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/plurals/vi/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/vi/
Translation: Kotatsu/Strings
Translation: Kotatsu/plurals
2024-07-27 12:20:41 +03:00
Koitharu
06cdcac4df Update parsers 2024-07-27 12:13:45 +03:00
Koitharu
10dc1d10ed Dynamic source settings 2024-07-24 15:12:08 +03:00
Koitharu
43c65bf95b Fix global search 2024-07-24 11:40:55 +03:00
Koitharu
cb4ee2dcca Fix manga repository instantiation 2024-07-24 09:43:14 +03:00
Koitharu
bc64a96cc0 Translated using Weblate (Russian)
Currently translated at 100.0% (662 of 662 strings)

Co-authored-by: Koitharu <nvasya95@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ru/
Translation: Kotatsu/Strings
2024-07-23 11:59:13 +03:00
Joe
23dab16afc Translated using Weblate (Belarusian)
Currently translated at 100.0% (9 of 9 strings)

Co-authored-by: Joe <happenstance@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/plurals/be/
Translation: Kotatsu/plurals
2024-07-23 11:59:13 +03:00
Hosted Weblate
8755106fd2 Update translation files
Updated by "Remove blank strings" hook in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/
Translation: Kotatsu/Strings
2024-07-23 11:59:13 +03:00
maryush
b2c6c95dbd Translated using Weblate (Polish)
Currently translated at 100.0% (658 of 658 strings)

Co-authored-by: maryush <maryush@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pl/
Translation: Kotatsu/Strings
2024-07-23 11:59:13 +03:00
Lorenzo Stella
20d5fcd54d Translated using Weblate (Italian)
Currently translated at 98.0% (645 of 658 strings)

Co-authored-by: Lorenzo Stella <lorenzo.stella.1408@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/it/
Translation: Kotatsu/Strings
2024-07-23 11:59:13 +03:00
Draken
0d09233b28 Translated using Weblate (Vietnamese)
Currently translated at 100.0% (658 of 658 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (658 of 658 strings)

Translated using Weblate (Vietnamese)

Currently translated at 99.8% (657 of 658 strings)

Co-authored-by: Draken <premieregirl26@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/vi/
Translation: Kotatsu/Strings
2024-07-23 11:59:13 +03:00
weedyy
1f2700de38 Translated using Weblate (Arabic)
Currently translated at 100.0% (658 of 658 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (658 of 658 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (658 of 658 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (9 of 9 strings)

Translated using Weblate (Arabic)

Currently translated at 88.7% (584 of 658 strings)

Co-authored-by: Hushhush <huzskywalker@gmail.com>
Co-authored-by: weedyy <huzskywalker@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/plurals/ar/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ar/
Translation: Kotatsu/Strings
Translation: Kotatsu/plurals
2024-07-23 11:59:13 +03:00
Ahmed seif al-nasr
d7ebdfbf5a Translated using Weblate (Arabic)
Currently translated at 80.5% (530 of 658 strings)

Co-authored-by: Ahmed seif al-nasr <ahmdsyfalnsr2@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ar/
Translation: Kotatsu/Strings
2024-07-23 11:59:13 +03:00
weedyy
14b70a78ab Translated using Weblate (Arabic)
Currently translated at 78.5% (517 of 658 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (9 of 9 strings)

Co-authored-by: Hushhush <huzskywalker@gmail.com>
Co-authored-by: weedyy <huzskywalker@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/plurals/ar/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ar/
Translation: Kotatsu/Strings
Translation: Kotatsu/plurals
2024-07-23 11:59:13 +03:00
LinCie
dd41af8b8e Translated using Weblate (Indonesian)
Currently translated at 98.1% (646 of 658 strings)

Co-authored-by: LinCie <aldiofernanda@protonmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/id/
Translation: Kotatsu/Strings
2024-07-23 11:59:13 +03:00
Eduardo
5b19d61069 Translated using Weblate (Portuguese (Brazil))
Currently translated at 98.6% (649 of 658 strings)

Co-authored-by: Eduardo <edu200399lim@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pt_BR/
Translation: Kotatsu/Strings
2024-07-23 11:59:13 +03:00
Ahmed seif al-nasr
be3e028f5c Translated using Weblate (Arabic)
Currently translated at 70.2% (462 of 658 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (9 of 9 strings)

Co-authored-by: Ahmed seif al-nasr <ahmdsyfalnsr2@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/plurals/ar/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ar/
Translation: Kotatsu/Strings
Translation: Kotatsu/plurals
2024-07-23 11:59:13 +03:00
gekka
d231436eb0 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (662 of 662 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (658 of 658 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (658 of 658 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (658 of 658 strings)

Co-authored-by: gekka <1778962971@qq.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/
Translation: Kotatsu/Strings
2024-07-23 11:59:13 +03:00
Infy's Tagalog Translations
4c6276d3f6 Translated using Weblate (Filipino)
Currently translated at 100.0% (662 of 662 strings)

Translated using Weblate (Filipino)

Currently translated at 100.0% (658 of 658 strings)

Co-authored-by: Infy's Tagalog Translations <ced.paltep10@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fil/
Translation: Kotatsu/Strings
2024-07-23 11:59:13 +03:00
Scrambled777
583c00d2b7 Translated using Weblate (Hindi)
Currently translated at 100.0% (658 of 658 strings)

Co-authored-by: Scrambled777 <weblate.scrambled777@simplelogin.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/hi/
Translation: Kotatsu/Strings
2024-07-23 11:59:13 +03:00
Oğuz Ersen
060ded3915 Translated using Weblate (Turkish)
Currently translated at 100.0% (662 of 662 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (658 of 658 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/tr/
Translation: Kotatsu/Strings
2024-07-23 11:59:13 +03:00
gallegonovato
8482a8746f Translated using Weblate (Spanish)
Currently translated at 100.0% (662 of 662 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (658 of 658 strings)

Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/es/
Translation: Kotatsu/Strings
2024-07-23 11:59:13 +03:00
Макар Разин
dc12c0e770 Translated using Weblate (Belarusian)
Currently translated at 100.0% (658 of 658 strings)

Co-authored-by: Макар Разин <makarrazin14@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/be/
Translation: Kotatsu/Strings
2024-07-23 11:59:13 +03:00
Koitharu
6338e89507 Improve covers caching 2024-07-23 11:37:26 +03:00
Koitharu
0f97d29f6a Fix CloudFlare activity crash (close #982) 2024-07-23 10:53:38 +03:00
Koitharu
686f746070 Update parsers 2024-07-23 10:32:38 +03:00
Koitharu
5363719643 Show reverse progress and chapters in lists #904 2024-07-22 18:31:04 +03:00
Koitharu
607785dcd4 Refactor manga list model mapping 2024-07-22 15:02:01 +03:00
Koitharu
c14d39c456 Fix rtl paddings 2024-07-21 07:26:28 +03:00
Koitharu
2c9220090a Fix pinned sources order 2024-07-21 06:31:47 +03:00
Koitharu
b17ef8b6ff Fix sources catalog 2024-07-20 12:27:20 +03:00
Koitharu
6ac96747cf Update dependencies and targetSdk 2024-07-20 12:15:57 +03:00
Koitharu
92c8a13f96 Migrate to LongSet in selection controller 2024-07-15 19:36:11 +03:00
Koitharu
6d07c335de Show sources pinned icons 2024-07-15 17:10:31 +03:00
Koitharu
eba1679761 Animated source placeholder 2024-07-15 16:16:46 +03:00
Koitharu
05b05be0bd Fix dynamic sources 2024-07-15 15:46:48 +03:00
Koitharu
287861f5d7 Merge branch 'devel' into feature/dynamic_sources 2024-07-15 15:15:06 +03:00
Koitharu
4102c4a0ae Show last error in tracker log 2024-07-13 06:16:26 +03:00
Mac135135
2c53b63847 Merge remote-tracking branch 'origin/devel' into devel
# Conflicts:
#	app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsActivity.kt
2024-07-11 01:35:18 +03:00
Koitharu
d8fa0e33f1 Update parsers 2024-07-07 12:29:08 +03:00
Koitharu
97bc638f5f Translated using Weblate (Ukrainian)
Currently translated at 100.0% (658 of 658 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (658 of 658 strings)

Co-authored-by: Koitharu <nvasya95@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ru/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/uk/
Translation: Kotatsu/Strings
2024-07-07 12:05:34 +03:00
Scrambled777
064c0ae425 Translated using Weblate (Hindi)
Currently translated at 100.0% (651 of 651 strings)

Co-authored-by: Scrambled777 <weblate.scrambled777@simplelogin.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/hi/
Translation: Kotatsu/Strings
2024-07-07 12:05:34 +03:00
Jesús Hernández santillan
ae7aa52177 Added translation using Weblate (Abkhazian)
Co-authored-by: Jesús Hernández santillan <jesusguibel122@gmail.com>
2024-07-07 12:05:34 +03:00
gallegonovato
6edda72d61 Translated using Weblate (Spanish)
Currently translated at 100.0% (651 of 651 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (650 of 650 strings)

Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/es/
Translation: Kotatsu/Strings
2024-07-07 12:05:34 +03:00
Akhil Raj
2f58f32bdd Translated using Weblate (Malayalam)
Currently translated at 2.6% (17 of 648 strings)

Co-authored-by: Akhil Raj <akhilakae07@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ml/
Translation: Kotatsu/Strings
2024-07-07 12:05:34 +03:00
Eno
0b821db046 Translated using Weblate (Arabic)
Currently translated at 60.4% (392 of 648 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (9 of 9 strings)

Co-authored-by: Eno <msa39716@zbock.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/plurals/ar/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ar/
Translation: Kotatsu/Strings
Translation: Kotatsu/plurals
2024-07-07 12:05:34 +03:00
Tawsif
36472998ee Translated using Weblate (Bengali)
Currently translated at 24.5% (159 of 648 strings)

Co-authored-by: Tawsif <tawsif7492@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/bn/
Translation: Kotatsu/Strings
2024-07-07 12:05:34 +03:00
Abay Emes
c2e7325876 Translated using Weblate (Kazakh)
Currently translated at 84.4% (547 of 648 strings)

Co-authored-by: Abay Emes <abayemes@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/kk/
Translation: Kotatsu/Strings
2024-07-07 12:05:34 +03:00
Zhafran Aziz
28a4a3849c Translated using Weblate (Indonesian)
Currently translated at 99.2% (643 of 648 strings)

Co-authored-by: Zhafran Aziz <aanmts70@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/id/
Translation: Kotatsu/Strings
2024-07-07 12:05:34 +03:00
Biagio Ricci
6e9c934912 Translated using Weblate (Italian)
Currently translated at 94.5% (613 of 648 strings)

Co-authored-by: Biagio Ricci <biagior00@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/it/
Translation: Kotatsu/Strings
2024-07-07 12:05:34 +03:00
Макар Разин
675ef0e629 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (648 of 648 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (648 of 648 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (648 of 648 strings)

Co-authored-by: Макар Разин <makarrazin14@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/be/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ru/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/uk/
Translation: Kotatsu/Strings
2024-07-07 12:05:34 +03:00
Koitharu
484914b2dc Fix detection webtoon mode for local manga 2024-07-07 11:54:24 +03:00
Koitharu
ee85ef50f4 Use image proxy for downloading #897 2024-07-07 11:50:08 +03:00
Koitharu
dcee5542c5 Add recent sources to search suggestions 2024-07-07 11:38:35 +03:00
Koitharu
9b3ce4d849 Ability to pin manga sources (close #830, close #531) 2024-07-07 11:15:44 +03:00
Koitharu
5ab7e586f3 Option to sort manga sources by last used #947 2024-07-07 10:18:18 +03:00
Koitharu
9f5d4ed52c Refactor details title expansion 2024-07-07 09:38:34 +03:00
Koitharu
c3ca734005 Update reader state on chapter switch 2024-07-07 09:05:01 +03:00
Koitharu
a158a488f2 Fix error if manga has no chapters 2024-07-07 09:05:01 +03:00
Mac135135
6048cb917e Add functionality to expand manga title on click 2024-07-07 09:04:40 +03:00
Koitharu
81aac0d431 Pages crop feature #326 #919 2024-07-06 19:25:08 +03:00
Koitharu
dfb50fbddc Add image server option to reader config sheet 2024-07-06 14:21:46 +03:00
Koitharu
1f03e0a84b Update parsers and add image server option support 2024-07-06 12:47:01 +03:00
Mac135135
45b5e48676 Add functionality to expand manga title on click 2024-07-05 21:23:15 +03:00
Koitharu
77e393ae48 Pages crop proof-of-concept 2024-06-29 15:56:32 +03:00
Koitharu
0d8820bcab Dynamic sources support 2024-06-29 07:56:18 +03:00
Koitharu
77bb5c2fcd Support UNKNOWN manga source 2024-06-22 13:19:21 +03:00
Milo Ivir
475a4904a9 Translated using Weblate (Croatian)
Currently translated at 100.0% (648 of 648 strings)

Translated using Weblate (Croatian)

Currently translated at 100.0% (9 of 9 strings)

Co-authored-by: Milo Ivir <mail@milotype.de>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/plurals/hr/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/hr/
Translation: Kotatsu/Strings
Translation: Kotatsu/plurals
2024-06-22 12:56:50 +03:00
lukapiplica
cf43b8ebda Translated using Weblate (Croatian)
Currently translated at 100.0% (648 of 648 strings)

Co-authored-by: lukapiplica <github163007297@protonmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/hr/
Translation: Kotatsu/Strings
2024-06-22 12:56:50 +03:00
Duh051
f34096af98 Translated using Weblate (Arabic)
Currently translated at 60.1% (390 of 648 strings)

Co-authored-by: Duh051 <duhduh272@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ar/
Translation: Kotatsu/Strings
2024-06-22 12:56:50 +03:00
Bela K
d60ff2a052 Translated using Weblate (German)
Currently translated at 95.2% (617 of 648 strings)

Co-authored-by: Bela K <na0341-dev@posteo.org>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/de/
Translation: Kotatsu/Strings
2024-06-22 12:56:50 +03:00
Anon
59d4953554 Translated using Weblate (Serbian)
Currently translated at 100.0% (648 of 648 strings)

Co-authored-by: Anon <anonymousprivate76@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/sr/
Translation: Kotatsu/Strings
2024-06-22 12:56:50 +03:00
acetknan
f76052b1d6 Translated using Weblate (Arabic)
Currently translated at 55.4% (359 of 648 strings)

Translated using Weblate (Arabic)

Currently translated at 88.8% (8 of 9 strings)

Co-authored-by: acetknan <acetknan18@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/plurals/ar/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ar/
Translation: Kotatsu/Strings
Translation: Kotatsu/plurals
2024-06-22 12:56:50 +03:00
Koitharu
26e59b0953 Fix opening reader with specific branch 2024-06-22 12:55:53 +03:00
Koitharu
9ee1164f08 Update parsers 2024-06-22 12:13:52 +03:00
Koitharu
cfc3823593 Improve double-tap zoom in reader 2024-06-22 10:20:48 +03:00
Koitharu
8407a414c5 Fix crashes 2024-06-15 14:03:38 +03:00
Koitharu
a379604974 Transfer scrobbling information within migration #930 2024-06-15 13:49:57 +03:00
Koitharu
c01d80f7da Update dependencies 2024-06-15 10:51:42 +03:00
lukapiplica
7533dce0d2 Translated using Weblate (Croatian)
Currently translated at 100.0% (648 of 648 strings)

Translated using Weblate (Croatian)

Currently translated at 100.0% (9 of 9 strings)

Added translation using Weblate (Croatian)

Added translation using Weblate (Croatian)

Co-authored-by: lukapiplica <github163007297@protonmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/plurals/hr/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/hr/
Translation: Kotatsu/Strings
Translation: Kotatsu/plurals
2024-06-15 10:44:09 +03:00
Fikri Akbar
9f1e97fd54 Translated using Weblate (Indonesian)
Currently translated at 99.0% (642 of 648 strings)

Co-authored-by: Fikri Akbar <akbarfikri1221@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/id/
Translation: Kotatsu/Strings
2024-06-15 10:44:09 +03:00
Johan
382a73310c Translated using Weblate (Czech)
Currently translated at 100.0% (648 of 648 strings)

Translated using Weblate (Czech)

Currently translated at 98.7% (640 of 648 strings)

Co-authored-by: Johan <jakub.bilku@outlook.cz>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/cs/
Translation: Kotatsu/Strings
2024-06-15 10:44:09 +03:00
Infy's Tagalog Translations
5eeab7fd08 Translated using Weblate (Filipino)
Currently translated at 100.0% (648 of 648 strings)

Co-authored-by: Infy's Tagalog Translations <ced.paltep10@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fil/
Translation: Kotatsu/Strings
2024-06-15 10:44:09 +03:00
gekka
bc54e7cfba Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (648 of 648 strings)

Co-authored-by: gekka <1778962971@qq.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/
Translation: Kotatsu/Strings
2024-06-15 10:44:09 +03:00
Koitharu
4502ffb6d2 Update parsers 2024-06-07 09:06:59 +03:00
maryush
b6f9ce824e Translated using Weblate (Polish)
Currently translated at 100.0% (648 of 648 strings)

Co-authored-by: maryush <maryush@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pl/
Translation: Kotatsu/Strings
2024-06-07 08:27:24 +03:00
gallegonovato
d33081c1c7 Translated using Weblate (Spanish)
Currently translated at 100.0% (648 of 648 strings)

Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/es/
Translation: Kotatsu/Strings
2024-06-07 08:27:24 +03:00
Eduardo Malaspina
76c08535d6 Translated using Weblate (Spanish)
Currently translated at 100.0% (646 of 646 strings)

Co-authored-by: Eduardo Malaspina <vaio0@swismail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/es/
Translation: Kotatsu/Strings
2024-06-07 08:27:24 +03:00
Макар Разин
b55fef67e1 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (646 of 646 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (646 of 646 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (646 of 646 strings)

Co-authored-by: Макар Разин <makarrazin14@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/be/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ru/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/uk/
Translation: Kotatsu/Strings
2024-06-07 08:27:24 +03:00
Scrambled777
56798677d5 Translated using Weblate (Hindi)
Currently translated at 100.0% (648 of 648 strings)

Translated using Weblate (Hindi)

Currently translated at 100.0% (646 of 646 strings)

Co-authored-by: Scrambled777 <weblate.scrambled777@simplelogin.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/hi/
Translation: Kotatsu/Strings
2024-06-07 08:27:24 +03:00
gekka
ff30b9c225 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (648 of 648 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (646 of 646 strings)

Co-authored-by: gekka <1778962971@qq.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/
Translation: Kotatsu/Strings
2024-06-07 08:27:24 +03:00
Oğuz Ersen
5c3293ec44 Translated using Weblate (Turkish)
Currently translated at 100.0% (648 of 648 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (646 of 646 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/tr/
Translation: Kotatsu/Strings
2024-06-07 08:27:24 +03:00
Anon
1b17605e0e Translated using Weblate (Serbian)
Currently translated at 99.8% (645 of 646 strings)

Translated using Weblate (Serbian)

Currently translated at 100.0% (645 of 645 strings)

Co-authored-by: Anon <anonymousprivate76@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/sr/
Translation: Kotatsu/Strings
2024-06-07 08:27:24 +03:00
Naga
ba4e4dcf56 Translated using Weblate (French)
Currently translated at 100.0% (646 of 646 strings)

Translated using Weblate (French)

Currently translated at 99.6% (643 of 645 strings)

Co-authored-by: Naga <yz2000.pro@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fr/
Translation: Kotatsu/Strings
2024-06-07 08:27:24 +03:00
Infy's Tagalog Translations
b35d5d4779 Translated using Weblate (Filipino)
Currently translated at 100.0% (646 of 646 strings)

Translated using Weblate (Filipino)

Currently translated at 100.0% (645 of 645 strings)

Co-authored-by: Infy's Tagalog Translations <ced.paltep10@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fil/
Translation: Kotatsu/Strings
2024-06-07 08:27:24 +03:00
Koitharu
124f31ebe1 Global screenshot policy #920 #138 2024-06-06 11:09:44 +03:00
Koitharu
173087ee19 Sources catalog improvements 2024-06-06 11:09:44 +03:00
Koitharu
8d7bad97de Merge pull request #917 from galpt/devel 2024-06-03 17:27:12 +03:00
nya~
188fbfbb95 0ms DNS Large variant
To prevent users from getting rate limited while still receiving the benefits of OISD Big and other security filters, using the "Large" variant is highly recommended for mission-critical applications or big networks.

Recommended to always use DNS-over-HTTPS since Plain is not safe.
2024-06-02 12:15:07 +07:00
nya~
3498a54bdf Change 0ms DNS to Large variant
To prevent users from getting rate limited while still receiving the benefits of OISD Big and other security filters, using the "Large" variant is highly recommended for mission-critical applications or big networks.
2024-06-02 12:11:40 +07:00
Koitharu
18169c2355 Update sources catalog and repository 2024-06-01 17:13:27 +03:00
Koitharu
87beb9442f Respect rounded corners in reader bar #900 2024-06-01 13:09:45 +03:00
Koitharu
e642d54929 Reapply "Update sources catalog ui"
This reverts commit 8d5bde6e60.
2024-06-01 11:55:52 +03:00
Koitharu
59ce5d5e67 Skip hidden files on local storage #910 2024-06-01 08:55:21 +03:00
Koitharu
58d5237692 Update dependencies 2024-06-01 08:50:56 +03:00
Koitharu
8d5bde6e60 Revert "Update sources catalog ui"
This reverts commit 597ad01e8f.
2024-05-27 17:29:31 +03:00
Koitharu
bf740ddc93 Merge branch 'master' into devel 2024-05-27 17:25:57 +03:00
Koitharu
fddbf35e8c Fix up navigation button behavior 2024-05-27 15:54:34 +03:00
Koitharu
a47fea02d1 Update issue templates 2024-05-27 14:07:37 +03:00
Koitharu
250136cfdc Update parsers 2024-05-27 13:55:38 +03:00
Koitharu
597ad01e8f Update sources catalog ui 2024-05-27 13:39:34 +03:00
Koitharu
f7b44f2b0f Update parsers 2024-05-25 17:27:33 +03:00
Koitharu
5aab43ac93 Update settings activity ui 2024-05-25 17:27:32 +03:00
Koitharu
2d278159ea Fix crashes and improve predictive back support 2024-05-25 17:27:32 +03:00
Koitharu
da61462d79 Update parsers 2024-05-25 17:17:30 +03:00
Макар Разин
2ab0912880 Translated using Weblate (Polish)
Currently translated at 100.0% (645 of 645 strings)

Translated using Weblate (Serbian)

Currently translated at 99.3% (641 of 645 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (645 of 645 strings)

Translated using Weblate (Polish)

Currently translated at 99.8% (644 of 645 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (645 of 645 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (645 of 645 strings)

Co-authored-by: Макар Разин <makarrazin14@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/be/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pl/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ru/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/sr/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/uk/
Translation: Kotatsu/Strings
2024-05-25 16:15:06 +03:00
Scrambled777
3914616222 Translated using Weblate (Hindi)
Currently translated at 100.0% (645 of 645 strings)

Translated using Weblate (Hindi)

Currently translated at 100.0% (643 of 643 strings)

Co-authored-by: Scrambled777 <weblate.scrambled777@simplelogin.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/hi/
Translation: Kotatsu/Strings
2024-05-25 16:15:06 +03:00
maryush
a73b2703be Translated using Weblate (Polish)
Currently translated at 100.0% (643 of 643 strings)

Co-authored-by: maryush <maryush@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pl/
Translation: Kotatsu/Strings
2024-05-25 16:15:06 +03:00
gekka
49590f6d02 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (645 of 645 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (643 of 643 strings)

Co-authored-by: gekka <1778962971@qq.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/
Translation: Kotatsu/Strings
2024-05-25 16:15:06 +03:00
Oğuz Ersen
f4a0fcf5ba Translated using Weblate (Turkish)
Currently translated at 100.0% (645 of 645 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (643 of 643 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/tr/
Translation: Kotatsu/Strings
2024-05-25 16:15:06 +03:00
gallegonovato
6ab803e682 Translated using Weblate (Spanish)
Currently translated at 100.0% (645 of 645 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (643 of 643 strings)

Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/es/
Translation: Kotatsu/Strings
2024-05-25 16:15:06 +03:00
Koitharu
0faa97b08c Update settings activity ui 2024-05-25 16:11:21 +03:00
Koitharu
2ae488544b Fix crashes and improve predictive back support 2024-05-25 10:32:02 +03:00
Koitharu
a7e2cfc878 Udpate parsers 2024-05-24 08:30:24 +03:00
Koitharu
da6db9c1b4 Refactor descrambling bitmap 2024-05-23 16:55:41 +03:00
AwkwardPeak7
88b3e5cf34 implement basic methods for descrambling images 2024-05-23 16:28:42 +03:00
Koitharu
7347f0ba10 Pagination in history and favorites 2024-05-23 12:44:10 +03:00
Koitharu
4c55682552 Move tracker debug activity to common code 2024-05-22 16:42:24 +03:00
Koitharu
324031aa2a Update untranslatable strings 2024-05-22 14:13:14 +03:00
Koitharu
1355c3d75c Option to disable nsfw updates notifications 2024-05-22 13:05:33 +03:00
Infy's Tagalog Translations
8533168155 Translated using Weblate (Filipino)
Currently translated at 99.8% (640 of 641 strings)

Co-authored-by: Infy's Tagalog Translations <ced.paltep10@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fil/
Translation: Kotatsu/Strings
2024-05-22 13:05:06 +03:00
Asmodeus
51f6ec6e55 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (641 of 641 strings)

Co-authored-by: Asmodeus <colligare1Asmodeum@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pt_BR/
Translation: Kotatsu/Strings
2024-05-22 13:05:06 +03:00
Deivinni Silva
7e3f67c14d Translated using Weblate (Portuguese (Brazil))
Currently translated at 97.1% (623 of 641 strings)

Co-authored-by: Deivinni Silva <deivinnimds3656@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pt_BR/
Translation: Kotatsu/Strings
2024-05-22 13:05:06 +03:00
gallegonovato
c51320f033 Translated using Weblate (Spanish)
Currently translated at 100.0% (641 of 641 strings)

Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/es/
Translation: Kotatsu/Strings
2024-05-22 13:05:06 +03:00
Hosted Weblate
9c50a47abc Update translation files
Updated by "Remove blank strings" hook in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/
Translation: Kotatsu/Strings
2024-05-22 13:05:06 +03:00
Scrambled777
473d273d18 Translated using Weblate (Hindi)
Currently translated at 100.0% (641 of 641 strings)

Translated using Weblate (Hindi)

Currently translated at 100.0% (639 of 639 strings)

Co-authored-by: Scrambled777 <weblate.scrambled777@simplelogin.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/hi/
Translation: Kotatsu/Strings
2024-05-22 13:05:06 +03:00
gekka
f19b628655 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (641 of 641 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (639 of 639 strings)

Co-authored-by: gekka <1778962971@qq.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/
Translation: Kotatsu/Strings
2024-05-22 13:05:06 +03:00
Oğuz Ersen
fa74d4b27a Translated using Weblate (Turkish)
Currently translated at 100.0% (641 of 641 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (639 of 639 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/tr/
Translation: Kotatsu/Strings
2024-05-22 13:05:06 +03:00
Nicola Bortoletto
cdb6655e37 Translated using Weblate (Italian)
Currently translated at 93.4% (597 of 639 strings)

Co-authored-by: Nicola Bortoletto <nicola.bortoletto@live.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/it/
Translation: Kotatsu/Strings
2024-05-22 13:05:06 +03:00
maryush
4f19f7ebdf Translated using Weblate (Polish)
Currently translated at 100.0% (641 of 641 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (639 of 639 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (638 of 638 strings)

Co-authored-by: maryush <maryush@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pl/
Translation: Kotatsu/Strings
2024-05-22 13:05:06 +03:00
Koitharu
bf8838f943 Save and share manga cover #253 2024-05-22 12:33:23 +03:00
Koitharu
1e1e9fabdc Merge pull request #885 from ranzou06/devel 2024-05-20 18:51:21 +03:00
Koitharu
745972a717 Added 0ms.dev images proxy support #771 2024-05-20 17:03:18 +03:00
Koitharu
6055776329 Fix crashes 2024-05-20 11:31:00 +03:00
Koitharu
4074791f9a Resolve SSL excetpions 2024-05-20 11:18:38 +03:00
Koitharu
b1ab48e912 Option to disable connectivity check 2024-05-17 11:36:42 +03:00
Koitharu
a71e2dd289 Update settings ui and fix crash 2024-05-17 10:31:15 +03:00
Clebio
b8283acd0d feat: Implement Spen integration for enhanced stylus support
TY Alexander!
2024-05-16 22:15:10 -03:00
Koitharu
bbdf1c756e Update dependencies 2024-05-16 11:14:40 +03:00
Koitharu
283878879b Update parsers 2024-05-16 10:44:08 +03:00
Koitharu
b74ec98d68 Merge branch 'devel' of https://hosted.weblate.org/git/kotatsu/strings into devel 2024-05-16 10:13:07 +03:00
Koitharu
3691db8e8e App udpate activity #880 2024-05-15 18:20:58 +03:00
Paing Frow
e25ccf6b25 Added translation using Weblate (Burmese)
Co-authored-by: Paing Frow <paingphyoe66@gmail.com>
2024-05-14 14:48:40 +03:00
Infy's Tagalog Translations
ffebdb0c49 Translated using Weblate (Filipino)
Currently translated at 99.8% (637 of 638 strings)

Translated using Weblate (Filipino)

Currently translated at 99.8% (637 of 638 strings)

Co-authored-by: Infy's Tagalog Translations <ced.paltep10@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fil/
Translation: Kotatsu/Strings
2024-05-14 14:48:40 +03:00
Scrambled777
6accdbced5 Translated using Weblate (Hindi)
Currently translated at 100.0% (638 of 638 strings)

Co-authored-by: Scrambled777 <weblate.scrambled777@simplelogin.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/hi/
Translation: Kotatsu/Strings
2024-05-14 14:48:40 +03:00
Oğuz Ersen
2fcb94e1d7 Translated using Weblate (Turkish)
Currently translated at 100.0% (638 of 638 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/tr/
Translation: Kotatsu/Strings
2024-05-14 14:48:40 +03:00
Carlota-gif
6211ef974d Translated using Weblate (Portuguese)
Currently translated at 99.3% (634 of 638 strings)

Co-authored-by: Carlota-gif <gamefox1407@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pt/
Translation: Kotatsu/Strings
2024-05-14 14:48:40 +03:00
Eduardo Malaspina
0eacf7bb98 Translated using Weblate (Spanish)
Currently translated at 99.8% (637 of 638 strings)

Co-authored-by: Eduardo Malaspina <vaio0@swismail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/es/
Translation: Kotatsu/Strings
2024-05-14 14:48:40 +03:00
Anon
c9b7d650a8 Translated using Weblate (Serbian)
Currently translated at 100.0% (638 of 638 strings)

Translated using Weblate (Serbian)

Currently translated at 100.0% (638 of 638 strings)

Co-authored-by: Anon <anonymousprivate76@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/sr/
Translation: Kotatsu/Strings
2024-05-14 14:48:40 +03:00
Anonymous
a29f7d6533 Translated using Weblate (Hungarian)
Currently translated at 96.7% (617 of 638 strings)

Translated using Weblate (Malay)

Currently translated at 48.4% (309 of 638 strings)

Translated using Weblate (Estonian)

Currently translated at 66.1% (422 of 638 strings)

Translated using Weblate (Kazakh)

Currently translated at 81.5% (520 of 638 strings)

Translated using Weblate (Norwegian Nynorsk)

Currently translated at 59.2% (378 of 638 strings)

Translated using Weblate (Hindi)

Currently translated at 99.5% (635 of 638 strings)

Translated using Weblate (Korean)

Currently translated at 52.8% (337 of 638 strings)

Translated using Weblate (Greek)

Currently translated at 84.1% (537 of 638 strings)

Translated using Weblate (Arabic)

Currently translated at 52.6% (336 of 638 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 97.4% (622 of 638 strings)

Translated using Weblate (Japanese)

Currently translated at 72.1% (460 of 638 strings)

Translated using Weblate (Portuguese)

Currently translated at 96.7% (617 of 638 strings)

Translated using Weblate (Italian)

Currently translated at 84.6% (540 of 638 strings)

Co-authored-by: Anonymous <noreply@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ar/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/el/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/et/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/hi/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/hu/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/it/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ja/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/kk/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ko/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ms/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/nn/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pt/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pt_BR/
Translation: Kotatsu/Strings
2024-05-14 14:48:40 +03:00
Kristian de Frutos
72f8c626d7 Translated using Weblate (Czech)
Currently translated at 100.0% (636 of 636 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (636 of 636 strings)

Translated using Weblate (Czech)

Currently translated at 83.0% (528 of 636 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (9 of 9 strings)

Co-authored-by: Kristian de Frutos <kristiandef@hotmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/plurals/cs/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/cs/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/es/
Translation: Kotatsu/Strings
Translation: Kotatsu/plurals
2024-05-14 14:48:40 +03:00
gekka
f05ef5125d Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (638 of 638 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (638 of 638 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (636 of 636 strings)

Co-authored-by: gekka <1778962971@qq.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/
Translation: Kotatsu/Strings
2024-05-14 14:48:40 +03:00
Макар Разин
40b3d8e6fd Translated using Weblate (Belarusian)
Currently translated at 100.0% (636 of 636 strings)

Co-authored-by: Макар Разин <makarrazin14@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/be/
Translation: Kotatsu/Strings
2024-05-14 14:48:40 +03:00
Paing Frow
a695bdc565 Translated using Weblate (Burmese)
Currently translated at 88.8% (8 of 9 strings)

Added translation using Weblate (Burmese)

Co-authored-by: Paing Frow <paingphyoe66@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/plurals/my/
Translation: Kotatsu/plurals
2024-05-14 11:48:01 +00:00
Infy's Tagalog Translations
9700fabd9a Translated using Weblate (Filipino)
Currently translated at 99.8% (637 of 638 strings)

Translated using Weblate (Filipino)

Currently translated at 99.8% (637 of 638 strings)

Co-authored-by: Infy's Tagalog Translations <ced.paltep10@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fil/
Translation: Kotatsu/Strings
2024-05-14 11:47:59 +00:00
Scrambled777
4877db42f9 Translated using Weblate (Hindi)
Currently translated at 100.0% (638 of 638 strings)

Co-authored-by: Scrambled777 <weblate.scrambled777@simplelogin.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/hi/
Translation: Kotatsu/Strings
2024-05-14 11:47:58 +00:00
Oğuz Ersen
9b418fd63b Translated using Weblate (Turkish)
Currently translated at 100.0% (638 of 638 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/tr/
Translation: Kotatsu/Strings
2024-05-14 11:47:57 +00:00
Carlota-gif
b2eef0df11 Translated using Weblate (Portuguese)
Currently translated at 99.3% (634 of 638 strings)

Co-authored-by: Carlota-gif <gamefox1407@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pt/
Translation: Kotatsu/Strings
2024-05-14 11:47:56 +00:00
Eduardo Malaspina
34462829ff Translated using Weblate (Spanish)
Currently translated at 99.8% (637 of 638 strings)

Co-authored-by: Eduardo Malaspina <vaio0@swismail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/es/
Translation: Kotatsu/Strings
2024-05-14 11:47:55 +00:00
Anon
2afcbef8d0 Translated using Weblate (Serbian)
Currently translated at 100.0% (638 of 638 strings)

Translated using Weblate (Serbian)

Currently translated at 100.0% (638 of 638 strings)

Co-authored-by: Anon <anonymousprivate76@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/sr/
Translation: Kotatsu/Strings
2024-05-14 11:47:53 +00:00
Anonymous
695becbda0 Translated using Weblate (Hungarian)
Currently translated at 96.7% (617 of 638 strings)

Translated using Weblate (Malay)

Currently translated at 48.4% (309 of 638 strings)

Translated using Weblate (Estonian)

Currently translated at 66.1% (422 of 638 strings)

Translated using Weblate (Kazakh)

Currently translated at 81.5% (520 of 638 strings)

Translated using Weblate (Norwegian Nynorsk)

Currently translated at 59.2% (378 of 638 strings)

Translated using Weblate (Hindi)

Currently translated at 99.5% (635 of 638 strings)

Translated using Weblate (Korean)

Currently translated at 52.8% (337 of 638 strings)

Translated using Weblate (Greek)

Currently translated at 84.1% (537 of 638 strings)

Translated using Weblate (Arabic)

Currently translated at 52.6% (336 of 638 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 97.4% (622 of 638 strings)

Translated using Weblate (Japanese)

Currently translated at 72.1% (460 of 638 strings)

Translated using Weblate (Portuguese)

Currently translated at 96.7% (617 of 638 strings)

Translated using Weblate (Italian)

Currently translated at 84.6% (540 of 638 strings)

Co-authored-by: Anonymous <noreply@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ar/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/el/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/et/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/hi/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/hu/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/it/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ja/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/kk/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ko/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ms/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/nn/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pt/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pt_BR/
Translation: Kotatsu/Strings
2024-05-14 11:47:52 +00:00
Kristian de Frutos
5877d8215d Translated using Weblate (Czech)
Currently translated at 100.0% (636 of 636 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (636 of 636 strings)

Translated using Weblate (Czech)

Currently translated at 83.0% (528 of 636 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (9 of 9 strings)

Co-authored-by: Kristian de Frutos <kristiandef@hotmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/plurals/cs/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/cs/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/es/
Translation: Kotatsu/Strings
Translation: Kotatsu/plurals
2024-05-14 11:47:50 +00:00
gekka
48b357dfef Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (638 of 638 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (638 of 638 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (636 of 636 strings)

Co-authored-by: gekka <1778962971@qq.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/
Translation: Kotatsu/Strings
2024-05-14 11:47:49 +00:00
Макар Разин
b20cc7c0d9 Translated using Weblate (Belarusian)
Currently translated at 100.0% (636 of 636 strings)

Co-authored-by: Макар Разин <makarrazin14@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/be/
Translation: Kotatsu/Strings
2024-05-14 11:47:48 +00:00
Koitharu
0f43f02fad Update parsers 2024-05-14 14:47:18 +03:00
Koitharu
9b658cf0b8 Fix offline details loading 2024-05-14 14:47:18 +03:00
MrChocolatine
ce705e12a8 Use format yyyyMMdd for backups
Resolves #791 .
2024-05-12 18:58:55 +03:00
1084 changed files with 37250 additions and 17725 deletions

View File

@@ -2,4 +2,4 @@ blank_issues_enabled: false
contact_links:
- name: ⚠️ Source issue
url: https://github.com/KotatsuApp/kotatsu-parsers/issues/new
about: If you have troubles with a manga parser or want to propose new manga source, please open an issue in the kotatsu-parsers repository instead
about: If you have a problem with a specific **manga source** or want to propose a new one, please open an issue in the kotatsu-parsers repository instead

View File

@@ -60,7 +60,7 @@ body:
attributes:
label: Acknowledgements
options:
- label: I have searched the existing issues and this is a new ticket, **NOT** a duplicate or related to another open issue.
- label: This is not a duplicate of an existing issue. Please look through the list of [open issues](https://github.com/KotatsuApp/Kotatsu/issues) before creating a new one.
required: true
- label: If this is an issue with a parser, I should be opening an issue in the [parsers repository](https://github.com/KotatsuApp/kotatsu-parsers/issues/new/choose).
- label: This is not an issue with a specific manga source. Otherwise, you have to open an issue in the [parsers repository](https://github.com/KotatsuApp/kotatsu-parsers/issues/new/choose).
required: true

View File

@@ -20,5 +20,5 @@ body:
label: Acknowledgements
description: Read this carefully, we will close and ignore your issue if you skimmed through this.
options:
- label: I have searched the existing issues and this is a new ticket, **NOT** a duplicate or related to another open issue.
required: true
- label: This is not a duplicate of an existing issue. Please look through the list of [open issues](https://github.com/KotatsuApp/Kotatsu/issues) before creating a new one.
required: true

BIN
.github/assets/vtuber.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

2
.gitignore vendored
View File

@@ -25,3 +25,5 @@
.externalNativeBuild
.cxx
/.idea/deviceManager.xml
/.kotlin/
/.idea/AndroidProjectSystem.xml

1
.idea/.gitignore generated vendored
View File

@@ -2,3 +2,4 @@
/shelf/
/workspace.xml
/migrations.xml
/runConfigurations.xml

6
.idea/AndroidProjectSystem.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AndroidProjectSystem">
<option name="providerId" value="com.android.tools.idea.GradleProjectSystem" />
</component>
</project>

4
.idea/gradle.xml generated
View File

@@ -4,15 +4,15 @@
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="testRunner" value="CHOOSE_PER_TEST" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" />
<option name="gradleJvm" value="jbr-21" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
<option name="resolveExternalAnnotations" value="false" />
</GradleProjectSettings>
</option>
</component>

110
README.md
View File

@@ -1,57 +1,107 @@
# Kotatsu
<div align="center">
Kotatsu is a free and open source manga reader for Android.
<a href="https://kotatsu.app">
<img src="./.github/assets/vtuber.png" alt="Kotatsu Logo" title="Kotatsu" width="600"/>
</a>
![Android 5.0](https://img.shields.io/badge/android-5.0+-brightgreen) ![Kotlin](https://img.shields.io/github/languages/top/KotatsuApp/Kotatsu) ![License](https://img.shields.io/github/license/KotatsuApp/Kotatsu) [![weblate](https://hosted.weblate.org/widgets/kotatsu/-/strings/svg-badge.svg)](https://hosted.weblate.org/engage/kotatsu/) [![Telegram](https://img.shields.io/badge/chat-telegram-60ACFF)](https://t.me/kotatsuapp) [![Discord](https://img.shields.io/discord/898363402467045416?color=5865f2&label=discord)](https://discord.gg/NNJ5RgVBC5)
# [Kotatsu](https://kotatsu.app)
**[Kotatsu](https://github.com/KotatsuApp/Kotatsu) is a free and open-source manga reader for Android with built-in online content sources.**
![Downloads count](https://img.shields.io/github/downloads/KotatsuApp/Kotatsu/total?color=1976d2) ![Latest Stable version](https://img.shields.io/github/v/release/KotatsuApp/Kotatsu?color=2596be&label=latest) ![Android 5.0](https://img.shields.io/badge/android-5.0+-brightgreen) [![Sources count](https://img.shields.io/badge/dynamic/yaml?url=https%3A%2F%2Fraw.githubusercontent.com%2FKotatsuApp%2Fkotatsu-parsers%2Frefs%2Fheads%2Fmaster%2F.github%2Fsummary.yaml&query=total&label=manga%20sources&color=%23E9321C)](https://github.com/KotatsuApp/kotatsu-parsers) [![weblate](https://hosted.weblate.org/widgets/kotatsu/-/strings/svg-badge.svg)](https://hosted.weblate.org/engage/kotatsu/) [![Discord](https://img.shields.io/discord/898363402467045416?color=5865f2&label=discord)](https://discord.gg/NNJ5RgVBC5) [![Telegram](https://img.shields.io/badge/chat-telegram-60ACFF?)](https://t.me/kotatsuapp) [![License](https://img.shields.io/github/license/KotatsuApp/Kotatsu)](https://github.com/KotatsuApp/Kotatsu/blob/devel/LICENSE)
### Download
- **Recommended:** Download and install APK from **[GitHub Releases](https://github.com/KotatsuApp/Kotatsu/releases/latest)**. Application has a built-in self-updating feature.
- Get it on **[F-Droid](https://f-droid.org/packages/org.koitharu.kotatsu)**. The F-Droid build may be a bit outdated and some fixes might be missing.
<div align="left">
* **Recommended:** Download and install APK from [GitHub Releases](https://github.com/KotatsuApp/Kotatsu/releases/latest). Application has a built-in self-updating feature.
* Get it on [F-Droid](https://f-droid.org/packages/org.koitharu.kotatsu). The F-Droid build may be a bit outdated and some fixes might be missing.
* Also [nightly builds](https://github.com/KotatsuApp/Kotatsu-nightly/releases) are available (very unstable, use at your own risk).
</div>
### Main Features
* Online [manga catalogues](https://github.com/KotatsuApp/kotatsu-parsers)
* Search manga by name and genres
* Reading history and bookmarks
* Favourites organized by user-defined categories
* Downloading manga and reading it offline. Third-party CBZ archives also supported
* Tablet-optimized Material You UI
* Standard and Webtoon-optimized reader
* Notifications about new chapters with updates feed
<div align="left">
* Online [manga catalogues](https://github.com/KotatsuApp/kotatsu-parsers) (with 1100+ manga sources)
* Search manga by name, genres, and more filters
* Favorites organized by user-defined categories
* Reading history, bookmarks, and incognito mode support
* Download manga and read it offline. Third-party CBZ archives are also supported
* Clean and convenient Material You UI, optimized for phones, tablets, and desktop
* Standard and Webtoon-optimized customizable reader, gesture support on reading interface
* Notifications about new chapters with updates feed, manga recommendations (with filters)
* Integration with manga tracking services: Shikimori, AniList, MyAnimeList, Kitsu
* Password/fingerprint protect access to the app
* History and favourites [synchronization](https://github.com/KotatsuApp/kotatsu-syncserver) across devices
* Password / fingerprint-protected access to the app
* Automatically sync app data with other devices on the same account
* Support for older devices running Android 5+
### Screenshots
</div>
| ![Screenshot_20200226-210337](https://github.com/KotatsuApp/Kotatsu/raw/devel/metadata/en-US/images/phoneScreenshots/1.png) | ![](https://github.com/KotatsuApp/Kotatsu/raw/devel/metadata/en-US/images/phoneScreenshots/2.png) | ![Screenshot_20200226-210232](https://github.com/KotatsuApp/Kotatsu/raw/devel/metadata/en-US/images/phoneScreenshots/3.png) |
|-----------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------|
| ![Screenshot_20200226-210405](https://github.com/KotatsuApp/Kotatsu/raw/devel/metadata/en-US/images/phoneScreenshots/4.png) | ![Screenshot_20200226-210151](https://github.com/KotatsuApp/Kotatsu/raw/devel/metadata/en-US/images/phoneScreenshots/5.png) | ![Screenshot_20200226-210223](https://github.com/KotatsuApp/Kotatsu/raw/devel/metadata/en-US/images/phoneScreenshots/6.png) |
### In-App Screenshots
| ![](https://github.com/KotatsuApp/Kotatsu/raw/devel/metadata/en-US/images/tenInchScreenshots/1.png) | ![](https://github.com/KotatsuApp/Kotatsu/raw/devel/metadata/en-US/images/tenInchScreenshots/2.png) |
|-----------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------|
<div align="center">
<img src="./metadata/en-US/images/phoneScreenshots/1.png" alt="Mobile view" width="250"/>
<img src="./metadata/en-US/images/phoneScreenshots/2.png" alt="Mobile view" width="250"/>
<img src="./metadata/en-US/images/phoneScreenshots/3.png" alt="Mobile view" width="250"/>
<img src="./metadata/en-US/images/phoneScreenshots/4.png" alt="Mobile view" width="250"/>
<img src="./metadata/en-US/images/phoneScreenshots/5.png" alt="Mobile view" width="250"/>
<img src="./metadata/en-US/images/phoneScreenshots/6.png" alt="Mobile view" width="250"/>
</div>
<br>
<div align="center">
<img src="./metadata/en-US/images/tenInchScreenshots/1.png" alt="Tablet view" width="400"/>
<img src="./metadata/en-US/images/tenInchScreenshots/2.png" alt="Tablet view" width="400"/>
</div>
### Localization
[<img src="https://hosted.weblate.org/widgets/kotatsu/-/287x66-white.png" alt="Translation status">](https://hosted.weblate.org/engage/kotatsu/)
<a href="https://hosted.weblate.org/engage/kotatsu/">
<img src="https://hosted.weblate.org/widget/kotatsu/horizontal-auto.png" alt="Translation status" />
</a>
Kotatsu is localized in a number of different languages, if you would like to help improve these or add new languages,
please head over to the [Weblate project page](https://hosted.weblate.org/engage/kotatsu/)
**[Kotatsu](https://github.com/KotatsuApp/Kotatsu) is localized in a number of different languages.**<br>
**📌 If you would like to help improve these or add new languages,
please head over to the [Weblate project page](https://hosted.weblate.org/engage/kotatsu/)**
### Contributing
See [CONTRIBUTING.md](./CONTRIBUTING.md) for the guidelines.
<br>
<a href="https://github.com/KotatsuApp/Kotatsu">
<picture>
<source srcset="https://github-readme-stats.vercel.app/api/pin/?username=KotatsuApp&repo=Kotatsu&bg_color=0d1117&text_color=1976d2&title_color=1976d2&icon_color=0877d2&border_radius=10&description_lines_count=2&show_owner=true" media="(prefers-color-scheme: dark)">
<img src="https://github-readme-stats.vercel.app/api/pin/?username=KotatsuApp&repo=Kotatsu&text_color=1976d2&title_color=1976d2&icon_color=0877d2&border_radius=10&description_lines_count=2&show_owner=true" alt="Kotatsu GitHub Repository">
</picture>
</a>
<a href="https://github.com/KotatsuApp/Kotatsu-parsers">
<picture>
<source srcset="https://github-readme-stats.vercel.app/api/pin/?username=KotatsuApp&repo=Kotatsu-parsers&bg_color=0d1117&text_color=1976d2&title_color=1976d2&icon_color=0877d2&border_radius=10&description_lines_count=2&show_owner=true" media="(prefers-color-scheme: dark)">
<img src="https://github-readme-stats.vercel.app/api/pin/?username=KotatsuApp&repo=Kotatsu-parsers&text_color=1976d2&title_color=1976d2&icon_color=0877d2&border_radius=10&description_lines_count=2&show_owner=true" alt="Kotatsu-parsers GitHub Repository">
</picture>
</a><br></br>
</br>
**📌 Pull requests are welcome, if you want: See [CONTRIBUTING.md](https://github.com/KotatsuApp/Kotatsu/blob/devel/CONTRIBUTING.md) for the guidelines**
### License
[![GNU GPLv3 Image](https://www.gnu.org/graphics/gplv3-127x51.png)](http://www.gnu.org/licenses/gpl-3.0.en.html)
You may copy, distribute and modify the software as long as you track changes/dates in source files. Any modifications
to or software including (via compiler) GPL-licensed code must also be made available under the GPL along with build &
install instructions.
<div align="left">
You may copy, distribute and modify the software as long as you track changes/dates in source files. Any modifications to or software including (via compiler) GPL-licensed code must also be made available under the GPL along with build & install instructions.
</div>
### DMCA disclaimer
The developers of this application does not have any affiliation with the content available in the app.
It is collecting from the sources freely available through any web browser.
<div align="left">
The developers of this application do not have any affiliation with the content available in the app. It collects content from sources that are freely available through any web browser.
</div>

View File

@@ -1,3 +1,5 @@
import java.time.LocalDateTime
plugins {
id 'com.android.application'
id 'kotlin-android'
@@ -5,24 +7,24 @@ plugins {
id 'com.google.devtools.ksp'
id 'kotlin-parcelize'
id 'dagger.hilt.android.plugin'
id 'androidx.room'
}
android {
compileSdk = 34
buildToolsVersion = '34.0.0'
compileSdk = 35
buildToolsVersion = '35.0.0'
namespace = 'org.koitharu.kotatsu'
defaultConfig {
applicationId 'org.koitharu.kotatsu'
minSdk = 21
targetSdk = 34
versionCode = 641
versionName = '7.0'
targetSdk = 35
versionCode = 1005
versionName = '8.1'
generatedDensities = []
testInstrumentationRunner 'org.koitharu.kotatsu.HiltTestRunner'
ksp {
arg('room.generateKotlin', 'true')
arg('room.schemaLocation', "$projectDir/schemas")
}
androidResources {
generateLocaleConfig true
@@ -37,33 +39,50 @@ android {
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
nightly {
initWith release
applicationIdSuffix = '.nightly'
}
}
buildFeatures {
viewBinding true
buildConfig true
}
packagingOptions {
resources {
excludes += [
'META-INF/README.md',
'META-INF/NOTICE.md'
]
}
}
sourceSets {
androidTest.assets.srcDirs += files("$projectDir/schemas".toString())
main.java.srcDirs += 'src/main/kotlin/'
}
compileOptions {
coreLibraryDesugaringEnabled true
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_1_8.toString()
jvmTarget = JavaVersion.VERSION_11.toString()
freeCompilerArgs += [
'-opt-in=kotlin.ExperimentalStdlibApi',
'-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi',
'-opt-in=kotlinx.coroutines.ExperimentalForInheritanceCoroutinesApi',
'-opt-in=kotlinx.coroutines.FlowPreview',
'-opt-in=kotlin.contracts.ExperimentalContracts',
'-opt-in=coil.annotation.ExperimentalCoilApi',
'-opt-in=coil3.annotation.ExperimentalCoilApi',
'-opt-in=coil3.annotation.InternalCoilApi',
]
}
room {
schemaDirectory "$projectDir/schemas"
}
lint {
abortOnError true
disable 'MissingTranslation', 'PrivateResource', 'NotifyDataSetChanged', 'SetJavaScriptEnabled'
disable 'MissingTranslation', 'PrivateResource', 'SetJavaScriptEnabled', 'SimpleDateFormat'
}
testOptions {
unitTests.includeAndroidResources true
@@ -72,6 +91,15 @@ android {
freeCompilerArgs += ['-opt-in=org.koitharu.kotatsu.parsers.InternalParsersApi']
}
}
applicationVariants.configureEach { variant ->
if (variant.name == 'nightly') {
variant.outputs.each { output ->
def now = LocalDateTime.now()
output.versionCodeOverride = now.format("yyMMdd").toInteger()
output.versionNameOverride = 'N' + now.format("yyyyMMdd")
}
}
}
}
afterEvaluate {
compileDebugKotlin {
@@ -81,88 +109,92 @@ afterEvaluate {
}
}
dependencies {
//noinspection GradleDependency
implementation('com.github.KotatsuApp:kotatsu-parsers:3e32a6280a') {
def parsersVersion = libs.versions.parsers.get()
if (System.properties.containsKey('parsersVersionOverride')) {
// usage:
// -DparsersVersionOverride=$(curl -s https://api.github.com/repos/kotatsuapp/kotatsu-parsers/commits/master -H "Accept: application/vnd.github.sha" | cut -c -10)
parsersVersion = System.getProperty('parsersVersionOverride')
}
//noinspection UseTomlInstead
implementation("com.github.KotatsuApp:kotatsu-parsers:$parsersVersion") {
exclude group: 'org.json', module: 'json'
}
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4'
implementation 'org.jetbrains.kotlin:kotlin-stdlib:1.9.24'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1'
coreLibraryDesugaring libs.desugar.jdk.libs
implementation libs.kotlin.stdlib
implementation libs.kotlinx.coroutines.android
implementation libs.kotlinx.coroutines.guava
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'androidx.core:core-ktx:1.13.1'
implementation 'androidx.activity:activity-ktx:1.9.0'
implementation 'androidx.fragment:fragment-ktx:1.7.0'
implementation 'androidx.collection:collection-ktx:1.4.0'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0'
implementation 'androidx.lifecycle:lifecycle-service:2.7.0'
implementation 'androidx.lifecycle:lifecycle-process:2.7.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
implementation 'androidx.recyclerview:recyclerview:1.3.2'
implementation 'androidx.viewpager2:viewpager2:1.1.0-rc01'
implementation 'androidx.preference:preference-ktx:1.2.1'
implementation 'androidx.biometric:biometric-ktx:1.2.0-alpha05'
implementation 'com.google.android.material:material:1.12.0'
implementation 'androidx.lifecycle:lifecycle-common-java8:2.7.0'
implementation 'androidx.webkit:webkit:1.11.0'
implementation libs.androidx.appcompat
implementation libs.androidx.core
implementation libs.androidx.activity
implementation libs.androidx.fragment
implementation libs.androidx.transition
implementation libs.androidx.collection
implementation libs.lifecycle.viewmodel
implementation libs.lifecycle.service
implementation libs.lifecycle.process
implementation libs.androidx.constraintlayout
implementation libs.androidx.swiperefreshlayout
implementation libs.androidx.recyclerview
implementation libs.androidx.viewpager2
implementation libs.androidx.preference
implementation libs.androidx.biometric
implementation libs.material
implementation libs.androidx.lifecycle.common.java8
implementation libs.androidx.webkit
implementation 'androidx.work:work-runtime:2.9.0'
//noinspection GradleDependency
implementation('com.google.guava:guava:32.0.1-android') {
exclude group: 'com.google.guava', module: 'failureaccess'
exclude group: 'org.checkerframework', module: 'checker-qual'
exclude group: 'com.google.j2objc', module: 'j2objc-annotations'
}
implementation libs.androidx.work.runtime
implementation libs.guava
implementation 'androidx.room:room-runtime:2.6.1'
implementation 'androidx.room:room-ktx:2.6.1'
ksp 'androidx.room:room-compiler:2.6.1'
implementation libs.androidx.room.runtime
implementation libs.androidx.room.ktx
ksp libs.androidx.room.compiler
implementation 'com.squareup.okhttp3:okhttp:4.12.0'
implementation 'com.squareup.okhttp3:okhttp-tls:4.12.0'
implementation 'com.squareup.okhttp3:okhttp-dnsoverhttps:4.12.0'
implementation 'com.squareup.okio:okio:3.9.0'
implementation libs.okhttp
implementation libs.okhttp.tls
implementation libs.okhttp.dnsoverhttps
implementation libs.okio
implementation 'com.hannesdorfmann:adapterdelegates4-kotlin-dsl:4.3.2'
implementation 'com.hannesdorfmann:adapterdelegates4-kotlin-dsl-viewbinding:4.3.2'
implementation libs.adapterdelegates
implementation libs.adapterdelegates.viewbinding
implementation 'com.google.dagger:hilt-android:2.51.1'
kapt 'com.google.dagger:hilt-compiler:2.51.1'
implementation 'androidx.hilt:hilt-work:1.2.0'
kapt 'androidx.hilt:hilt-compiler:1.2.0'
implementation libs.hilt.android
kapt libs.hilt.compiler
implementation libs.androidx.hilt.work
kapt libs.androidx.hilt.compiler
implementation 'io.coil-kt:coil-base:2.6.0'
implementation 'io.coil-kt:coil-svg:2.6.0'
implementation 'com.github.KotatsuApp:subsampling-scale-image-view:02e6d6cfe9'
implementation 'com.github.solkin:disk-lru-cache:1.4'
implementation 'io.noties.markwon:core:4.6.2'
implementation libs.coil.core
implementation libs.coil.network
implementation libs.coil.gif
implementation libs.coil.svg
implementation libs.avif.decoder
implementation libs.ssiv
implementation libs.disk.lru.cache
implementation libs.markwon
implementation 'ch.acra:acra-http:5.11.3'
implementation 'ch.acra:acra-dialog:5.11.3'
compileOnly 'com.google.auto.service:auto-service-annotations:1.1.1'
ksp 'dev.zacsweers.autoservice:auto-service-ksp:1.1.0'
implementation libs.acra.http
implementation libs.acra.dialog
implementation 'org.conscrypt:conscrypt-android:2.5.2'
implementation libs.conscrypt.android
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.14'
debugImplementation 'com.github.Koitharu:WorkInspector:5778dd1747'
debugImplementation libs.leakcanary.android
debugImplementation libs.workinspector
testImplementation 'junit:junit:4.13.2'
testImplementation 'org.json:json:20240303'
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.8.1'
testImplementation libs.junit
testImplementation libs.json
testImplementation libs.kotlinx.coroutines.test
androidTestImplementation 'androidx.test:runner:1.5.2'
androidTestImplementation 'androidx.test:rules:1.5.0'
androidTestImplementation 'androidx.test:core-ktx:1.5.0'
androidTestImplementation 'androidx.test.ext:junit-ktx:1.1.5'
androidTestImplementation libs.androidx.runner
androidTestImplementation libs.androidx.rules
androidTestImplementation libs.androidx.test.core
androidTestImplementation libs.androidx.junit
androidTestImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.8.1'
androidTestImplementation libs.kotlinx.coroutines.test
androidTestImplementation 'androidx.room:room-testing:2.6.1'
androidTestImplementation 'com.squareup.moshi:moshi-kotlin:1.15.1'
androidTestImplementation libs.androidx.room.testing
androidTestImplementation libs.moshi.kotlin
androidTestImplementation 'com.google.dagger:hilt-android-testing:2.51.1'
kaptAndroidTest 'com.google.dagger:hilt-android-compiler:2.51.1'
androidTestImplementation libs.hilt.android.testing
kaptAndroidTest libs.hilt.android.compiler
}

View File

@@ -14,6 +14,8 @@
-dontwarn org.conscrypt.**
-dontwarn org.bouncycastle.**
-dontwarn org.openjsse.**
-dontwarn com.google.j2objc.annotations.**
-dontwarn coil3.PlatformContext
-keep class org.koitharu.kotatsu.core.exceptions.* { *; }
-keep class org.koitharu.kotatsu.settings.NotificationSettingsLegacyFragment
@@ -21,3 +23,8 @@
-keep class org.koitharu.kotatsu.settings.backup.PeriodicalBackupSettingsFragment { *; }
-keep class org.jsoup.parser.Tag
-keep class org.jsoup.internal.StringUtil
-keep class org.acra.security.NoKeyStoreFactory { *; }
-keep class org.acra.config.DefaultRetryPolicy { *; }
-keep class org.acra.attachment.DefaultAttachmentProvider { *; }
-keep class org.acra.sender.JobSenderService

View File

@@ -1,198 +0,0 @@
package org.koitharu.kotatsu.tracker.domain
import androidx.test.ext.junit.runners.AndroidJUnit4
import dagger.hilt.android.testing.HiltAndroidRule
import dagger.hilt.android.testing.HiltAndroidTest
import junit.framework.TestCase.*
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.koitharu.kotatsu.SampleData
import org.koitharu.kotatsu.core.parser.MangaDataRepository
import org.koitharu.kotatsu.parsers.model.Manga
import javax.inject.Inject
@HiltAndroidTest
@RunWith(AndroidJUnit4::class)
class TrackerTest {
@get:Rule
var hiltRule = HiltAndroidRule(this)
@Inject
lateinit var repository: TrackingRepository
@Inject
lateinit var dataRepository: MangaDataRepository
@Inject
lateinit var tracker: Tracker
@Before
fun setUp() {
hiltRule.inject()
}
@Test
fun noUpdates() = runTest {
val manga = loadManga("full.json")
tracker.deleteTrack(manga.id)
tracker.checkUpdates(manga, commit = true).apply {
assertFalse(isValid)
assert(newChapters.isEmpty())
}
assertEquals(0, repository.getNewChaptersCount(manga.id))
tracker.checkUpdates(manga, commit = true).apply {
assertTrue(isValid)
assert(newChapters.isEmpty())
}
assertEquals(0, repository.getNewChaptersCount(manga.id))
}
@Test
fun hasUpdates() = runTest {
val mangaFirst = loadManga("first_chapters.json")
val mangaFull = loadManga("full.json")
tracker.deleteTrack(mangaFirst.id)
tracker.checkUpdates(mangaFirst, commit = true).apply {
assertFalse(isValid)
assert(newChapters.isEmpty())
}
assertEquals(0, repository.getNewChaptersCount(mangaFirst.id))
tracker.checkUpdates(mangaFull, commit = true).apply {
assertTrue(isValid)
assertEquals(3, newChapters.size)
}
assertEquals(3, repository.getNewChaptersCount(mangaFirst.id))
tracker.checkUpdates(mangaFull, commit = true).apply {
assertTrue(isValid)
assert(newChapters.isEmpty())
}
assertEquals(3, repository.getNewChaptersCount(mangaFirst.id))
}
@Test
fun badIds() = runTest {
val mangaFirst = loadManga("first_chapters.json")
val mangaBad = loadManga("bad_ids.json")
tracker.deleteTrack(mangaFirst.id)
tracker.checkUpdates(mangaFirst, commit = true).apply {
assertFalse(isValid)
assert(newChapters.isEmpty())
}
assertEquals(0, repository.getNewChaptersCount(mangaFirst.id))
tracker.checkUpdates(mangaBad, commit = true).apply {
assertFalse(isValid)
assert(newChapters.isEmpty())
}
assertEquals(0, repository.getNewChaptersCount(mangaFirst.id))
tracker.checkUpdates(mangaFirst, commit = true).apply {
assertFalse(isValid)
assert(newChapters.isEmpty())
}
assertEquals(0, repository.getNewChaptersCount(mangaFirst.id))
}
@Test
fun badIds2() = runTest {
val mangaFirst = loadManga("first_chapters.json")
val mangaBad = loadManga("bad_ids.json")
val mangaFull = loadManga("full.json")
tracker.deleteTrack(mangaFirst.id)
tracker.checkUpdates(mangaFirst, commit = true).apply {
assertFalse(isValid)
assert(newChapters.isEmpty())
}
assertEquals(0, repository.getNewChaptersCount(mangaFirst.id))
tracker.checkUpdates(mangaFull, commit = true).apply {
assertTrue(isValid)
assertEquals(3, newChapters.size)
}
assertEquals(3, repository.getNewChaptersCount(mangaFull.id))
tracker.checkUpdates(mangaBad, commit = true).apply {
assertFalse(isValid)
assert(newChapters.isEmpty())
}
assertEquals(0, repository.getNewChaptersCount(mangaFirst.id))
}
@Test
fun fullReset() = runTest {
val mangaFull = loadManga("full.json")
val mangaFirst = loadManga("first_chapters.json")
val mangaEmpty = loadManga("empty.json")
tracker.deleteTrack(mangaFull.id)
assertEquals(0, repository.getNewChaptersCount(mangaFull.id))
tracker.checkUpdates(mangaFull, commit = true).apply {
assertFalse(isValid)
assert(newChapters.isEmpty())
}
assertEquals(0, repository.getNewChaptersCount(mangaFull.id))
tracker.checkUpdates(mangaEmpty, commit = true).apply {
assert(newChapters.isEmpty())
}
assertEquals(0, repository.getNewChaptersCount(mangaFull.id))
tracker.checkUpdates(mangaFirst, commit = true).apply {
assertFalse(isValid)
assert(newChapters.isEmpty())
}
assertEquals(0, repository.getNewChaptersCount(mangaFull.id))
tracker.checkUpdates(mangaFull, commit = true).apply {
assertTrue(isValid)
assertEquals(3, newChapters.size)
}
assertEquals(3, repository.getNewChaptersCount(mangaFull.id))
tracker.checkUpdates(mangaEmpty, commit = true).apply {
assertFalse(isValid)
assert(newChapters.isEmpty())
}
assertEquals(0, repository.getNewChaptersCount(mangaFull.id))
}
@Test
fun syncWithHistory() = runTest {
val mangaFull = loadManga("full.json")
val mangaFirst = loadManga("first_chapters.json")
tracker.deleteTrack(mangaFull.id)
tracker.checkUpdates(mangaFirst, commit = true).apply {
assertFalse(isValid)
assert(newChapters.isEmpty())
}
assertEquals(0, repository.getNewChaptersCount(mangaFirst.id))
tracker.checkUpdates(mangaFull, commit = true).apply {
assertTrue(isValid)
assertEquals(3, newChapters.size)
}
assertEquals(3, repository.getNewChaptersCount(mangaFirst.id))
var chapter = requireNotNull(mangaFull.chapters).run { get(lastIndex - 1) }
tracker.syncWithHistory(mangaFull, chapter.id)
assertEquals(1, repository.getNewChaptersCount(mangaFirst.id))
chapter = requireNotNull(mangaFull.chapters).run { get(lastIndex) }
tracker.syncWithHistory(mangaFull, chapter.id)
assertEquals(0, repository.getNewChaptersCount(mangaFirst.id))
tracker.checkUpdates(mangaFull, commit = true).apply {
assertTrue(isValid)
assert(newChapters.isEmpty())
}
assertEquals(0, repository.getNewChaptersCount(mangaFirst.id))
}
private suspend fun loadManga(name: String): Manga {
val manga = SampleData.loadAsset("manga/$name", Manga::class)
dataRepository.storeManga(manga)
return manga
}
}

View File

@@ -1,12 +0,0 @@
<manifest
xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<activity
android:name=".tracker.ui.debug.TrackerDebugActivity"
android:label="@string/check_for_new_chapters" />
</application>
</manifest>

View File

@@ -1,8 +1,12 @@
package org.koitharu.kotatsu
import android.content.Context
import android.content.SharedPreferences
import android.os.Build
import android.os.StrictMode
import androidx.core.content.edit
import androidx.fragment.app.strictmode.FragmentStrictMode
import leakcanary.LeakCanary
import org.koitharu.kotatsu.core.BaseApp
import org.koitharu.kotatsu.local.data.LocalMangaRepository
import org.koitharu.kotatsu.local.data.PagesCache
@@ -11,35 +15,83 @@ import org.koitharu.kotatsu.reader.domain.PageLoader
class KotatsuApp : BaseApp() {
var isLeakCanaryEnabled: Boolean
get() = getDebugPreferences(this).getBoolean(KEY_LEAK_CANARY, true)
set(value) {
getDebugPreferences(this).edit { putBoolean(KEY_LEAK_CANARY, value) }
configureLeakCanary()
}
override fun attachBaseContext(base: Context) {
super.attachBaseContext(base)
enableStrictMode()
configureLeakCanary()
}
private fun configureLeakCanary() {
LeakCanary.config = LeakCanary.config.copy(
dumpHeap = isLeakCanaryEnabled,
)
}
private fun enableStrictMode() {
val notifier = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
StrictModeNotifier(this)
} else {
null
}
StrictMode.setThreadPolicy(
StrictMode.ThreadPolicy.Builder()
.detectAll()
.penaltyLog()
.build(),
StrictMode.ThreadPolicy.Builder().apply {
detectNetwork()
detectDiskWrites()
detectCustomSlowCalls()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) detectUnbufferedIo()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) detectResourceMismatches()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) detectExplicitGc()
penaltyLog()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && notifier != null) {
penaltyListener(notifier.executor, notifier)
}
}.build(),
)
StrictMode.setVmPolicy(
StrictMode.VmPolicy.Builder()
.detectAll()
.setClassInstanceLimit(LocalMangaRepository::class.java, 1)
.setClassInstanceLimit(PagesCache::class.java, 1)
.setClassInstanceLimit(MangaLoaderContext::class.java, 1)
.setClassInstanceLimit(PageLoader::class.java, 1)
.penaltyLog()
.build(),
StrictMode.VmPolicy.Builder().apply {
detectActivityLeaks()
detectLeakedSqlLiteObjects()
detectLeakedClosableObjects()
detectLeakedRegistrationObjects()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) detectContentUriWithoutPermission()
detectFileUriExposure()
setClassInstanceLimit(LocalMangaRepository::class.java, 1)
setClassInstanceLimit(PagesCache::class.java, 1)
setClassInstanceLimit(MangaLoaderContext::class.java, 1)
setClassInstanceLimit(PageLoader::class.java, 1)
penaltyLog()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && notifier != null) {
penaltyListener(notifier.executor, notifier)
}
}.build(),
)
FragmentStrictMode.defaultPolicy = FragmentStrictMode.Policy.Builder()
.penaltyDeath()
.detectFragmentReuse()
.detectWrongFragmentContainer()
.detectRetainInstanceUsage()
.detectSetUserVisibleHint()
.detectFragmentTagUsage()
.build()
FragmentStrictMode.defaultPolicy = FragmentStrictMode.Policy.Builder().apply {
detectWrongFragmentContainer()
detectFragmentTagUsage()
detectRetainInstanceUsage()
detectSetUserVisibleHint()
detectWrongNestedHierarchy()
detectFragmentReuse()
penaltyLog()
if (notifier != null) {
penaltyListener(notifier)
}
}.build()
}
private companion object {
const val PREFS_DEBUG = "_debug"
const val KEY_LEAK_CANARY = "leak_canary"
fun getDebugPreferences(context: Context): SharedPreferences =
context.getSharedPreferences(PREFS_DEBUG, MODE_PRIVATE)
}
}

View File

@@ -0,0 +1,73 @@
package org.koitharu.kotatsu
import android.app.Notification
import android.app.Notification.BigTextStyle
import android.app.NotificationChannel
import android.app.NotificationManager
import android.content.Context
import android.os.Build
import android.os.StrictMode
import android.os.strictmode.Violation
import androidx.annotation.RequiresApi
import androidx.core.app.PendingIntentCompat
import androidx.core.content.getSystemService
import androidx.fragment.app.strictmode.FragmentStrictMode
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.asExecutor
import org.koitharu.kotatsu.core.util.ShareHelper
import kotlin.math.absoluteValue
import androidx.fragment.app.strictmode.Violation as FragmentViolation
@RequiresApi(Build.VERSION_CODES.P)
class StrictModeNotifier(
private val context: Context,
) : StrictMode.OnVmViolationListener, StrictMode.OnThreadViolationListener, FragmentStrictMode.OnViolationListener {
val executor = Dispatchers.Default.asExecutor()
private val notificationManager by lazy {
val nm = checkNotNull(context.getSystemService<NotificationManager>())
val channel = NotificationChannel(
CHANNEL_ID,
context.getString(R.string.strict_mode),
NotificationManager.IMPORTANCE_LOW,
)
nm.createNotificationChannel(channel)
nm
}
override fun onVmViolation(v: Violation) = showNotification(v)
override fun onThreadViolation(v: Violation) = showNotification(v)
override fun onViolation(violation: FragmentViolation) = showNotification(violation)
private fun showNotification(violation: Throwable) = Notification.Builder(context, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_bug)
.setContentTitle(context.getString(R.string.strict_mode))
.setContentText(violation.message)
.setStyle(
BigTextStyle()
.setBigContentTitle(context.getString(R.string.strict_mode))
.setSummaryText(violation.message)
.bigText(violation.stackTraceToString()),
).setShowWhen(true)
.setContentIntent(
PendingIntentCompat.getActivity(
context,
violation.hashCode(),
ShareHelper(context).getShareTextIntent(violation.stackTraceToString()),
0,
false,
),
)
.setAutoCancel(true)
.setGroup(CHANNEL_ID)
.build()
.let { notificationManager.notify(CHANNEL_ID, violation.hashCode().absoluteValue, it) }
private companion object {
const val CHANNEL_ID = "strict_mode"
}
}

View File

@@ -2,6 +2,7 @@ package org.koitharu.kotatsu.core.network
import android.util.Log
import okhttp3.Interceptor
import okhttp3.Request
import okhttp3.Response
import okio.Buffer
import org.koitharu.kotatsu.core.network.CommonHeaders.ACCEPT_ENCODING
@@ -12,8 +13,11 @@ class CurlLoggingInterceptor(
private val escapeRegex = Regex("([\\[\\]\"])")
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
override fun intercept(chain: Interceptor.Chain): Response = chain.proceed(chain.request()).also {
logRequest(it.networkResponse?.request ?: it.request)
}
private fun logRequest(request: Request) {
var isCompressed = false
val curlCmd = StringBuilder()
@@ -46,16 +50,11 @@ class CurlLoggingInterceptor(
log("---cURL (" + request.url + ")")
log(curlCmd.toString())
return chain.proceed(request)
}
private fun String.escape() = replace(escapeRegex) { match ->
"\\" + match.value
}
// .replace("\"", "\\\"")
// .replace("[", "\\[")
// .replace("]", "\\]")
private fun log(msg: String) {
Log.d("CURL", msg)

View File

@@ -0,0 +1,21 @@
package org.koitharu.kotatsu.core.ui
import android.content.Context
import androidx.core.content.ContextCompat
import androidx.lifecycle.LifecycleService
import leakcanary.AppWatcher
abstract class BaseService : LifecycleService() {
override fun attachBaseContext(newBase: Context) {
super.attachBaseContext(ContextCompat.getContextForLanguage(newBase))
}
override fun onDestroy() {
super.onDestroy()
AppWatcher.objectWatcher.watch(
watchedObject = this,
description = "${javaClass.simpleName} service received Service#onDestroy() callback",
)
}
}

View File

@@ -0,0 +1,58 @@
package org.koitharu.kotatsu.settings
import android.content.Context
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import androidx.core.view.MenuProvider
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
import leakcanary.LeakCanary
import org.koitharu.kotatsu.KotatsuApp
import org.koitharu.kotatsu.R
import org.koitharu.workinspector.WorkInspector
class SettingsMenuProvider(
private val context: Context,
) : MenuProvider {
private val application: KotatsuApp
get() = context.applicationContext as KotatsuApp
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
menuInflater.inflate(R.menu.opt_settings, menu)
}
override fun onPrepareMenu(menu: Menu) {
super.onPrepareMenu(menu)
menu.findItem(R.id.action_leakcanary).isChecked = application.isLeakCanaryEnabled
menu.findItem(R.id.action_ssiv_debug).isChecked = SubsamplingScaleImageView.isDebug
}
override fun onMenuItemSelected(menuItem: MenuItem): Boolean = when (menuItem.itemId) {
R.id.action_leaks -> {
context.startActivity(LeakCanary.newLeakDisplayActivityIntent())
true
}
R.id.action_works -> {
context.startActivity(WorkInspector.getIntent(context))
true
}
R.id.action_leakcanary -> {
val checked = !menuItem.isChecked
menuItem.isChecked = checked
application.isLeakCanaryEnabled = checked
true
}
R.id.action_ssiv_debug -> {
val checked = !menuItem.isChecked
menuItem.isChecked = checked
SubsamplingScaleImageView.isDebug = checked
true
}
else -> false
}
}

View File

@@ -0,0 +1,15 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#FFFFFF">
<group android:scaleX="0.98150784"
android:scaleY="0.98150784"
android:translateX="0.22190611"
android:translateY="-0.2688478">
<path
android:fillColor="@android:color/white"
android:pathData="M20,8h-2.81c-0.45,-0.78 -1.07,-1.45 -1.82,-1.96L17,4.41 15.59,3l-2.17,2.17C12.96,5.06 12.49,5 12,5c-0.49,0 -0.96,0.06 -1.41,0.17L8.41,3 7,4.41l1.62,1.63C7.88,6.55 7.26,7.22 6.81,8L4,8v2h2.09c-0.05,0.33 -0.09,0.66 -0.09,1v1L4,12v2h2v1c0,0.34 0.04,0.67 0.09,1L4,16v2h2.81c1.04,1.79 2.97,3 5.19,3s4.15,-1.21 5.19,-3L20,18v-2h-2.09c0.05,-0.33 0.09,-0.66 0.09,-1v-1h2v-2h-2v-1c0,-0.34 -0.04,-0.67 -0.09,-1L20,10L20,8zM14,16h-4v-2h4v2zM14,12h-4v-2h4v2z"/>
</group>
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 417 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 308 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 480 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 792 B

View File

@@ -1,21 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<menu
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<item
android:id="@id/action_leaks"
android:id="@+id/action_ssiv_debug"
android:checkable="true"
android:title="SSIV debug"
app:showAsAction="never"
tools:ignore="HardcodedText" />
<item
android:id="@+id/action_leakcanary"
android:checkable="true"
android:title="LeakCanary"
app:showAsAction="never"
tools:ignore="HardcodedText" />
<item
android:id="@+id/action_leaks"
android:title="@string/leak_canary_display_activity_label"
app:showAsAction="never" />
<item
android:id="@id/action_tracker"
android:title="@string/check_for_new_chapters"
app:showAsAction="never" />
<item
android:id="@id/action_works"
android:title="Works"
android:id="@+id/action_works"
android:title="@string/wi_lib_name"
app:showAsAction="never" />
</menu>

View File

@@ -1,3 +1,4 @@
<resources>
<string name="app_name" translatable="false">Kotatsu Dev</string>
</resources>
<string name="strict_mode">Strict mode</string>
</resources>

File diff suppressed because it is too large Load Diff

View File

@@ -3,83 +3,77 @@ package org.koitharu.kotatsu.alternatives.domain
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.channelFlow
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Semaphore
import kotlinx.coroutines.sync.withPermit
import org.koitharu.kotatsu.core.parser.MangaRepository
import org.koitharu.kotatsu.core.util.ext.almostEquals
import org.koitharu.kotatsu.core.util.ext.toLocale
import org.koitharu.kotatsu.explore.data.MangaSourcesRepository
import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaListFilter
import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
import org.koitharu.kotatsu.search.domain.SearchKind
import org.koitharu.kotatsu.search.domain.SearchV2Helper
import java.util.Locale
import javax.inject.Inject
private const val MAX_PARALLELISM = 4
private const val MATCH_THRESHOLD = 0.2f
class AlternativesUseCase @Inject constructor(
private val sourcesRepository: MangaSourcesRepository,
private val searchHelperFactory: SearchV2Helper.Factory,
private val mangaRepositoryFactory: MangaRepository.Factory,
) {
suspend operator fun invoke(manga: Manga): Flow<Manga> {
val sources = getSources(manga.source)
suspend operator fun invoke(manga: Manga, throughDisabledSources: Boolean): Flow<Manga> {
val sources = getSources(manga.source, throughDisabledSources)
if (sources.isEmpty()) {
return emptyFlow()
}
val semaphore = Semaphore(MAX_PARALLELISM)
return channelFlow {
for (source in sources) {
val repository = mangaRepositoryFactory.create(source)
if (!repository.isSearchSupported) {
continue
}
launch {
val searchHelper = searchHelperFactory.create(source)
val list = runCatchingCancellable {
semaphore.withPermit {
repository.getList(offset = 0, filter = MangaListFilter.Search(manga.title))
searchHelper(manga.title, SearchKind.TITLE)?.manga
}
}.getOrDefault(emptyList())
for (item in list) {
if (item.matches(manga)) {
send(item)
}.getOrNull()
list?.forEach { m ->
if (m.id != manga.id) {
launch {
val details = runCatchingCancellable {
mangaRepositoryFactory.create(m.source).getDetails(m)
}.getOrDefault(m)
send(details)
}
}
}
}
}
}.map {
runCatchingCancellable {
mangaRepositoryFactory.create(it.source).getDetails(it)
}.getOrDefault(it)
}
}
private suspend fun getSources(ref: MangaSource): List<MangaSource> {
val result = ArrayList<MangaSource>(MangaSource.entries.size - 2)
result.addAll(sourcesRepository.getEnabledSources())
result.sortByDescending { it.priority(ref) }
result.addAll(sourcesRepository.getDisabledSources().sortedByDescending { it.priority(ref) })
return result
}
private fun Manga.matches(ref: Manga): Boolean {
return matchesTitles(title, ref.title) ||
matchesTitles(title, ref.altTitle) ||
matchesTitles(altTitle, ref.title) ||
matchesTitles(altTitle, ref.altTitle)
}
private fun matchesTitles(a: String?, b: String?): Boolean {
return !a.isNullOrEmpty() && !b.isNullOrEmpty() && a.almostEquals(b, MATCH_THRESHOLD)
}
private suspend fun getSources(ref: MangaSource, disabled: Boolean): List<MangaSource> = if (disabled) {
sourcesRepository.getDisabledSources()
} else {
sourcesRepository.getEnabledSources()
}.sortedByDescending { it.priority(ref) }
private fun MangaSource.priority(ref: MangaSource): Int {
var res = 0
if (locale == ref.locale) res += 2
if (contentType == ref.contentType) res++
if (this is MangaParserSource && ref is MangaParserSource) {
if (locale == ref.locale) {
res += 4
} else if (locale.toLocale() == Locale.getDefault()) {
res += 2
}
if (contentType == ref.contentType) {
res++
}
}
return res
}
}

View File

@@ -0,0 +1,96 @@
package org.koitharu.kotatsu.alternatives.domain
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.channelFlow
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.lastOrNull
import kotlinx.coroutines.flow.runningFold
import kotlinx.coroutines.flow.transformWhile
import kotlinx.coroutines.flow.withIndex
import kotlinx.coroutines.launch
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import org.koitharu.kotatsu.core.model.chaptersCount
import org.koitharu.kotatsu.core.model.parcelable.ParcelableManga
import org.koitharu.kotatsu.core.parser.MangaDataRepository
import org.koitharu.kotatsu.core.parser.MangaRepository
import org.koitharu.kotatsu.core.util.ext.concat
import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
import java.util.concurrent.TimeUnit
import javax.inject.Inject
import kotlin.coroutines.cancellation.CancellationException
class AutoFixUseCase @Inject constructor(
private val mangaRepositoryFactory: MangaRepository.Factory,
private val alternativesUseCase: AlternativesUseCase,
private val migrateUseCase: MigrateUseCase,
private val mangaDataRepository: MangaDataRepository,
) {
suspend operator fun invoke(mangaId: Long): Pair<Manga, Manga?> {
val seed = checkNotNull(
mangaDataRepository.findMangaById(mangaId, withChapters = true),
) { "Manga $mangaId not found" }.getDetailsSafe()
if (seed.isHealthy()) {
return seed to null // no fix required
}
val replacement = alternativesUseCase(seed, throughDisabledSources = false)
.concat(alternativesUseCase(seed, throughDisabledSources = true))
.filter { it.isHealthy() }
.runningFold<Manga, Manga?>(null) { best, candidate ->
if (best == null || best < candidate) {
candidate
} else {
best
}
}.selectLastWithTimeout(4, 40, TimeUnit.SECONDS)
migrateUseCase(seed, replacement ?: throw NoAlternativesException(ParcelableManga(seed)))
return seed to replacement
}
private suspend fun Manga.isHealthy(): Boolean = runCatchingCancellable {
val repo = mangaRepositoryFactory.create(source)
val details = if (this.chapters != null) this else repo.getDetails(this)
val firstChapter = details.chapters?.firstOrNull() ?: return@runCatchingCancellable false
val pageUrl = repo.getPageUrl(repo.getPages(firstChapter).first())
pageUrl.toHttpUrlOrNull() != null
}.getOrDefault(false)
private suspend fun Manga.getDetailsSafe() = runCatchingCancellable {
mangaRepositoryFactory.create(source).getDetails(this)
}.getOrDefault(this)
private operator fun Manga.compareTo(other: Manga) = chaptersCount().compareTo(other.chaptersCount())
@Suppress("UNCHECKED_CAST", "OPT_IN_USAGE")
private suspend fun <T> Flow<T>.selectLastWithTimeout(
minCount: Int,
timeout: Long,
timeUnit: TimeUnit
): T? = channelFlow<T?> {
var lastValue: T? = null
launch {
delay(timeUnit.toMillis(timeout))
close(InternalTimeoutException(lastValue))
}
withIndex().transformWhile { (index, value) ->
lastValue = value
emit(value)
index < minCount && !isClosedForSend
}.collect {
send(it)
}
}.catch { e ->
if (e is InternalTimeoutException) {
emit(e.value as T?)
} else {
throw e
}
}.lastOrNull()
class NoAlternativesException(val seed: ParcelableManga) : NoSuchElementException()
private class InternalTimeoutException(val value: Any?) : CancellationException()
}

View File

@@ -7,34 +7,43 @@ import org.koitharu.kotatsu.core.parser.MangaDataRepository
import org.koitharu.kotatsu.core.parser.MangaRepository
import org.koitharu.kotatsu.details.domain.ProgressUpdateUseCase
import org.koitharu.kotatsu.history.data.HistoryEntity
import org.koitharu.kotatsu.history.data.PROGRESS_NONE
import org.koitharu.kotatsu.history.data.toMangaHistory
import org.koitharu.kotatsu.list.domain.ReadingProgress.Companion.PROGRESS_NONE
import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaChapter
import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
import org.koitharu.kotatsu.scrobbling.common.domain.Scrobbler
import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblingStatus
import org.koitharu.kotatsu.tracker.data.TrackEntity
import javax.inject.Inject
class MigrateUseCase @Inject constructor(
class MigrateUseCase
@Inject
constructor(
private val mangaRepositoryFactory: MangaRepository.Factory,
private val mangaDataRepository: MangaDataRepository,
private val database: MangaDatabase,
private val progressUpdateUseCase: ProgressUpdateUseCase,
private val scrobblers: Set<@JvmSuppressWildcards Scrobbler>,
) {
suspend operator fun invoke(oldManga: Manga, newManga: Manga) {
val oldDetails = if (oldManga.chapters.isNullOrEmpty()) {
runCatchingCancellable {
mangaRepositoryFactory.create(oldManga.source).getDetails(oldManga)
}.getOrDefault(oldManga)
} else {
oldManga
}
val newDetails = if (newManga.chapters.isNullOrEmpty()) {
mangaRepositoryFactory.create(newManga.source).getDetails(newManga)
} else {
newManga
}
suspend operator fun invoke(
oldManga: Manga,
newManga: Manga,
) {
val oldDetails =
if (oldManga.chapters.isNullOrEmpty()) {
runCatchingCancellable {
mangaRepositoryFactory.create(oldManga.source).getDetails(oldManga)
}.getOrDefault(oldManga)
} else {
oldManga
}
val newDetails =
if (newManga.chapters.isNullOrEmpty()) {
mangaRepositoryFactory.create(newManga.source).getDetails(newManga)
} else {
newManga
}
mangaDataRepository.storeManga(newDetails)
database.withTransaction {
// replace favorites
@@ -43,36 +52,69 @@ class MigrateUseCase @Inject constructor(
if (oldFavourites.isNotEmpty()) {
favoritesDao.delete(oldManga.id)
for (f in oldFavourites) {
val e = f.copy(
mangaId = newManga.id,
)
val e =
f.copy(
mangaId = newManga.id,
)
favoritesDao.upsert(e)
}
}
// replace history
val historyDao = database.getHistoryDao()
val oldHistory = historyDao.find(oldDetails.id)
if (oldHistory != null) {
val newHistory = makeNewHistory(oldDetails, newDetails, oldHistory)
historyDao.delete(oldDetails.id)
historyDao.upsert(newHistory)
}
val newHistory =
if (oldHistory != null) {
val newHistory = makeNewHistory(oldDetails, newDetails, oldHistory)
historyDao.delete(oldDetails.id)
historyDao.upsert(newHistory)
newHistory
} else {
null
}
// track
val tracksDao = database.getTracksDao()
val oldTrack = tracksDao.find(oldDetails.id)
if (oldTrack != null) {
val lastChapter = newDetails.chapters?.lastOrNull()
val newTrack = TrackEntity(
mangaId = newDetails.id,
lastChapterId = lastChapter?.id ?: 0L,
newChapters = 0,
lastCheckTime = System.currentTimeMillis(),
lastChapterDate = lastChapter?.uploadDate ?: 0L,
lastResult = TrackEntity.RESULT_EXTERNAL_MODIFICATION,
)
val newTrack =
TrackEntity(
mangaId = newDetails.id,
lastChapterId = lastChapter?.id ?: 0L,
newChapters = 0,
lastCheckTime = System.currentTimeMillis(),
lastChapterDate = lastChapter?.uploadDate ?: 0L,
lastResult = TrackEntity.RESULT_EXTERNAL_MODIFICATION,
lastError = null,
)
tracksDao.delete(oldDetails.id)
tracksDao.upsert(newTrack)
}
// scrobbling
for (scrobbler in scrobblers) {
if (!scrobbler.isEnabled) {
continue
}
val prevInfo = scrobbler.getScrobblingInfoOrNull(oldDetails.id) ?: continue
scrobbler.unregisterScrobbling(oldDetails.id)
scrobbler.linkManga(newDetails.id, prevInfo.targetId)
scrobbler.updateScrobblingInfo(
mangaId = newDetails.id,
rating = prevInfo.rating,
status =
prevInfo.status ?: when {
newHistory == null -> ScrobblingStatus.PLANNED
newHistory.percent == 1f -> ScrobblingStatus.COMPLETED
else -> ScrobblingStatus.READING
},
comment = prevInfo.comment,
)
if (newHistory != null) {
scrobbler.scrobble(
manga = newDetails,
chapterId = newHistory.chapterId,
)
}
}
}
progressUpdateUseCase(newManga)
}
@@ -85,48 +127,53 @@ class MigrateUseCase @Inject constructor(
if (oldManga.chapters.isNullOrEmpty()) { // probably broken manga/source
val branch = newManga.getPreferredBranch(null)
val chapters = checkNotNull(newManga.getChapters(branch))
val currentChapter = if (history.percent in 0f..1f) {
chapters[(chapters.lastIndex * history.percent).toInt()]
} else {
chapters.first()
}
val currentChapter =
if (history.percent in 0f..1f) {
chapters[(chapters.lastIndex * history.percent).toInt()]
} else {
chapters.first()
}
return HistoryEntity(
mangaId = newManga.id,
createdAt = history.createdAt,
updatedAt = System.currentTimeMillis(),
updatedAt = history.updatedAt,
chapterId = currentChapter.id,
page = history.page,
scroll = history.scroll,
percent = history.percent,
deletedAt = 0,
chaptersCount = chapters.size,
chaptersCount = chapters.count { it.branch == currentChapter.branch },
)
}
val branch = oldManga.getPreferredBranch(history.toMangaHistory())
val oldChapters = checkNotNull(oldManga.getChapters(branch))
var index = oldChapters.indexOfFirst { it.id == history.chapterId }
if (index < 0) {
index = if (history.percent in 0f..1f) {
(oldChapters.lastIndex * history.percent).toInt()
} else {
0
}
index =
if (history.percent in 0f..1f) {
(oldChapters.lastIndex * history.percent).toInt()
} else {
0
}
}
val newChapters = checkNotNull(newManga.chapters).groupBy { it.branch }
val newBranch = if (newChapters.containsKey(branch)) {
branch
} else {
newManga.getPreferredBranch(null)
}
val newChapterId = checkNotNull(newChapters[newBranch]).let {
val oldChapter = oldChapters[index]
it.findByNumber(oldChapter.volume, oldChapter.number) ?: it.getOrNull(index) ?: it.last()
}.id
val newBranch =
if (newChapters.containsKey(branch)) {
branch
} else {
newManga.getPreferredBranch(null)
}
val newChapterId =
checkNotNull(newChapters[newBranch])
.let {
val oldChapter = oldChapters[index]
it.findByNumber(oldChapter.volume, oldChapter.number) ?: it.getOrNull(index) ?: it.last()
}.id
return HistoryEntity(
mangaId = newManga.id,
createdAt = history.createdAt,
updatedAt = System.currentTimeMillis(),
updatedAt = history.updatedAt,
chapterId = newChapterId,
page = history.page,
scroll = history.scroll,
@@ -136,11 +183,13 @@ class MigrateUseCase @Inject constructor(
)
}
private fun List<MangaChapter>.findByNumber(volume: Int, number: Float): MangaChapter? {
return if (number <= 0f) {
private fun List<MangaChapter>.findByNumber(
volume: Int,
number: Float,
): MangaChapter? =
if (number <= 0f) {
null
} else {
firstOrNull { it.volume == volume && it.number == number }
}
}
}

View File

@@ -4,12 +4,21 @@ import android.text.style.ForegroundColorSpan
import androidx.core.content.ContextCompat
import androidx.core.text.buildSpannedString
import androidx.core.text.inSpans
import androidx.core.view.isVisible
import androidx.lifecycle.LifecycleOwner
import coil.ImageLoader
import coil.request.ImageRequest
import coil.transform.CircleCropTransformation
import coil3.ImageLoader
import coil3.request.ImageRequest
import coil3.request.allowRgb565
import coil3.request.crossfade
import coil3.request.error
import coil3.request.fallback
import coil3.request.lifecycle
import coil3.request.placeholder
import coil3.request.transformations
import coil3.transform.RoundedCornersTransformation
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.model.getTitle
import org.koitharu.kotatsu.core.parser.favicon.faviconUri
import org.koitharu.kotatsu.core.ui.image.ChipIconTarget
import org.koitharu.kotatsu.core.ui.image.CoverSizeResolver
@@ -18,8 +27,10 @@ import org.koitharu.kotatsu.core.ui.list.AdapterDelegateClickListenerAdapter
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
import org.koitharu.kotatsu.core.util.ext.defaultPlaceholders
import org.koitharu.kotatsu.core.util.ext.enqueueWith
import org.koitharu.kotatsu.core.util.ext.getQuantityStringSafe
import org.koitharu.kotatsu.core.util.ext.mangaExtra
import org.koitharu.kotatsu.core.util.ext.mangaSourceExtra
import org.koitharu.kotatsu.core.util.ext.newImageRequest
import org.koitharu.kotatsu.core.util.ext.source
import org.koitharu.kotatsu.databinding.ItemMangaAlternativeBinding
import org.koitharu.kotatsu.list.ui.ListModelDiffCallback
import org.koitharu.kotatsu.list.ui.model.ListModel
@@ -42,10 +53,22 @@ fun alternativeAD(
binding.chipSource.setOnClickListener(clickListener)
bind { payloads ->
binding.textViewTitle.text = item.manga.title
binding.textViewTitle.text = item.mangaModel.title
with(binding.iconsView) {
clearIcons()
if (item.mangaModel.isSaved) addIcon(R.drawable.ic_storage)
if (item.mangaModel.isFavorite) addIcon(R.drawable.ic_heart_outline)
isVisible = iconsCount > 0
}
binding.textViewSubtitle.text = buildSpannedString {
if (item.chaptersCount > 0) {
append(context.resources.getQuantityString(R.plurals.chapters, item.chaptersCount, item.chaptersCount))
append(
context.resources.getQuantityStringSafe(
R.plurals.chapters,
item.chaptersCount,
item.chaptersCount,
),
)
} else {
append(context.getString(R.string.no_chapters))
}
@@ -61,9 +84,12 @@ fun alternativeAD(
}
}
}
binding.progressView.setPercent(item.progress, ListModelDiffCallback.PAYLOAD_PROGRESS_CHANGED in payloads)
binding.progressView.setProgress(
item.mangaModel.progress,
ListModelDiffCallback.PAYLOAD_PROGRESS_CHANGED in payloads,
)
binding.chipSource.also { chip ->
chip.text = item.manga.source.title
chip.text = item.manga.source.getTitle(chip.context)
ImageRequest.Builder(context)
.data(item.manga.source.faviconUri())
.lifecycle(lifecycleOwner)
@@ -73,8 +99,8 @@ fun alternativeAD(
.placeholder(R.drawable.ic_web)
.fallback(R.drawable.ic_web)
.error(R.drawable.ic_web)
.source(item.manga.source)
.transformations(CircleCropTransformation())
.mangaSourceExtra(item.manga.source)
.transformations(RoundedCornersTransformation(context.resources.getDimension(R.dimen.chip_icon_corner)))
.allowRgb565(true)
.enqueueWith(coil)
}
@@ -83,8 +109,7 @@ fun alternativeAD(
defaultPlaceholders(context)
transformations(TrimTransformation())
allowRgb565(true)
tag(item.manga)
source(item.manga.source)
mangaExtra(item.manga)
enqueueWith(coil)
}
}

View File

@@ -1,40 +1,40 @@
package org.koitharu.kotatsu.alternatives.ui
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.View
import android.widget.Toast
import androidx.activity.viewModels
import androidx.core.graphics.Insets
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding
import coil.ImageLoader
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import coil3.ImageLoader
import dagger.hilt.android.AndroidEntryPoint
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.exceptions.resolve.SnackbarErrorObserver
import org.koitharu.kotatsu.core.model.parcelable.ParcelableManga
import org.koitharu.kotatsu.core.parser.MangaIntent
import org.koitharu.kotatsu.core.model.getTitle
import org.koitharu.kotatsu.core.nav.router
import org.koitharu.kotatsu.core.ui.BaseActivity
import org.koitharu.kotatsu.core.ui.BaseListAdapter
import org.koitharu.kotatsu.core.ui.dialog.buildAlertDialog
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
import org.koitharu.kotatsu.core.util.ext.DIALOG_THEME_CENTERED
import org.koitharu.kotatsu.core.util.ext.consumeAllSystemBarsInsets
import org.koitharu.kotatsu.core.util.ext.observe
import org.koitharu.kotatsu.core.util.ext.observeEvent
import org.koitharu.kotatsu.core.util.ext.systemBarsInsets
import org.koitharu.kotatsu.databinding.ActivityAlternativesBinding
import org.koitharu.kotatsu.details.ui.DetailsActivity
import org.koitharu.kotatsu.list.ui.adapter.ListItemType
import org.koitharu.kotatsu.list.ui.adapter.ListStateHolderListener
import org.koitharu.kotatsu.list.ui.adapter.TypedListSpacingDecoration
import org.koitharu.kotatsu.list.ui.adapter.buttonFooterAD
import org.koitharu.kotatsu.list.ui.adapter.emptyStateListAD
import org.koitharu.kotatsu.list.ui.adapter.loadingFooterAD
import org.koitharu.kotatsu.list.ui.adapter.loadingStateAD
import org.koitharu.kotatsu.list.ui.model.ListModel
import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.search.ui.SearchActivity
import javax.inject.Inject
@AndroidEntryPoint
class AlternativesActivity : BaseActivity<ActivityAlternativesBinding>(),
ListStateHolderListener,
OnListItemClickListener<MangaAlternativeModel> {
@Inject
@@ -54,6 +54,7 @@ class AlternativesActivity : BaseActivity<ActivityAlternativesBinding>(),
.addDelegate(ListItemType.STATE_EMPTY, emptyStateListAD(coil, this, null))
.addDelegate(ListItemType.FOOTER_LOADING, loadingFooterAD())
.addDelegate(ListItemType.STATE_LOADING, loadingStateAD())
.addDelegate(ListItemType.FOOTER_BUTTON, buttonFooterAD(this))
with(viewBinding.recyclerView) {
setHasFixedSize(true)
addItemDecoration(TypedListSpacingDecoration(context, addHorizontalPadding = false))
@@ -61,54 +62,63 @@ class AlternativesActivity : BaseActivity<ActivityAlternativesBinding>(),
}
viewModel.onError.observeEvent(this, SnackbarErrorObserver(viewBinding.recyclerView, null))
viewModel.content.observe(this, listAdapter)
viewModel.list.observe(this, listAdapter)
viewModel.onMigrated.observeEvent(this) {
Toast.makeText(this, R.string.migration_completed, Toast.LENGTH_SHORT).show()
startActivity(DetailsActivity.newIntent(this, it))
router.openDetails(it)
finishAfterTransition()
}
}
override fun onWindowInsetsChanged(insets: Insets) {
viewBinding.root.updatePadding(
left = insets.left,
right = insets.right,
)
override fun onApplyWindowInsets(
v: View,
insets: WindowInsetsCompat
): WindowInsetsCompat {
val barsInsets = insets.systemBarsInsets
viewBinding.recyclerView.updatePadding(
bottom = insets.bottom + viewBinding.recyclerView.paddingTop,
left = barsInsets.left,
right = barsInsets.right,
bottom = barsInsets.bottom,
)
viewBinding.appbar.updatePadding(
left = barsInsets.left,
right = barsInsets.right,
top = barsInsets.top,
)
return insets.consumeAllSystemBarsInsets()
}
override fun onItemClick(item: MangaAlternativeModel, view: View) {
when (view.id) {
R.id.chip_source -> startActivity(SearchActivity.newIntent(this, item.manga.source, viewModel.manga.title))
R.id.chip_source -> router.openSearch(item.manga.source, viewModel.manga.title)
R.id.button_migrate -> confirmMigration(item.manga)
else -> startActivity(DetailsActivity.newIntent(this, item.manga))
else -> router.openDetails(item.manga)
}
}
override fun onRetryClick(error: Throwable) = viewModel.retry()
override fun onEmptyActionClick() = Unit
override fun onFooterButtonClick() = viewModel.continueSearch()
private fun confirmMigration(target: Manga) {
MaterialAlertDialogBuilder(this, DIALOG_THEME_CENTERED)
.setIcon(R.drawable.ic_replace)
.setTitle(R.string.manga_migration)
.setMessage(
buildAlertDialog(this, isCentered = true) {
setIcon(R.drawable.ic_replace)
setTitle(R.string.manga_migration)
setMessage(
getString(
R.string.migrate_confirmation,
viewModel.manga.title,
viewModel.manga.source.title,
viewModel.manga.source.getTitle(context),
target.title,
target.source.title,
target.source.getTitle(context),
),
)
.setNegativeButton(android.R.string.cancel, null)
.setPositiveButton(R.string.migrate) { _, _ ->
setNegativeButton(android.R.string.cancel, null)
setPositiveButton(R.string.migrate) { _, _ ->
viewModel.migrate(target)
}.show()
}
companion object {
fun newIntent(context: Context, manga: Manga) = Intent(context, AlternativesActivity::class.java)
.putExtra(MangaIntent.KEY_MANGA, ParcelableManga(manga))
}
}.show()
}
}

View File

@@ -1,31 +1,40 @@
package org.koitharu.kotatsu.alternatives.ui
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.cancelAndJoin
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEmpty
import kotlinx.coroutines.flow.runningFold
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.plus
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.alternatives.domain.AlternativesUseCase
import org.koitharu.kotatsu.alternatives.domain.MigrateUseCase
import org.koitharu.kotatsu.core.model.chaptersCount
import org.koitharu.kotatsu.core.model.parcelable.ParcelableManga
import org.koitharu.kotatsu.core.parser.MangaIntent
import org.koitharu.kotatsu.core.nav.AppRouter
import org.koitharu.kotatsu.core.parser.MangaRepository
import org.koitharu.kotatsu.core.prefs.ListMode
import org.koitharu.kotatsu.core.ui.BaseViewModel
import org.koitharu.kotatsu.core.util.ext.MutableEventFlow
import org.koitharu.kotatsu.core.util.ext.append
import org.koitharu.kotatsu.core.util.ext.call
import org.koitharu.kotatsu.core.util.ext.require
import org.koitharu.kotatsu.list.domain.ListExtraProvider
import org.koitharu.kotatsu.list.domain.MangaListMapper
import org.koitharu.kotatsu.list.ui.model.ButtonFooter
import org.koitharu.kotatsu.list.ui.model.EmptyState
import org.koitharu.kotatsu.list.ui.model.ListModel
import org.koitharu.kotatsu.list.ui.model.LoadingFooter
import org.koitharu.kotatsu.list.ui.model.LoadingState
import org.koitharu.kotatsu.list.ui.model.MangaGridModel
import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
import org.koitharu.kotatsu.parsers.util.suspendlazy.getOrDefault
import org.koitharu.kotatsu.parsers.util.suspendlazy.suspendLazy
import javax.inject.Inject
@HiltViewModel
@@ -34,45 +43,67 @@ class AlternativesViewModel @Inject constructor(
private val mangaRepositoryFactory: MangaRepository.Factory,
private val alternativesUseCase: AlternativesUseCase,
private val migrateUseCase: MigrateUseCase,
private val extraProvider: ListExtraProvider,
private val mangaListMapper: MangaListMapper,
) : BaseViewModel() {
val manga = savedStateHandle.require<ParcelableManga>(MangaIntent.KEY_MANGA).manga
val manga = savedStateHandle.require<ParcelableManga>(AppRouter.KEY_MANGA).manga
private var includeDisabledSources = MutableStateFlow(false)
private val results = MutableStateFlow<List<MangaAlternativeModel>>(emptyList())
private var migrationJob: Job? = null
private var searchJob: Job? = null
private val mangaDetails = suspendLazy {
mangaRepositoryFactory.create(manga.source).getDetails(manga)
}
val onMigrated = MutableEventFlow<Manga>()
val content = MutableStateFlow<List<ListModel>>(listOf(LoadingState))
private var migrationJob: Job? = null
val list: StateFlow<List<ListModel>> = combine(
results,
isLoading,
includeDisabledSources,
) { list, loading, includeDisabled ->
when {
list.isEmpty() -> listOf(
when {
loading -> LoadingState
else -> EmptyState(
icon = R.drawable.ic_empty_common,
textPrimary = R.string.nothing_found,
textSecondary = R.string.text_search_holder_secondary,
actionStringRes = 0,
)
},
)
loading -> list + LoadingFooter()
includeDisabled -> list
else -> list + ButtonFooter(R.string.search_disabled_sources)
}
}.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, listOf(LoadingState))
init {
launchJob(Dispatchers.Default) {
val ref = runCatchingCancellable {
mangaRepositoryFactory.create(manga.source).getDetails(manga)
}.getOrDefault(manga)
val refCount = ref.chaptersCount()
alternativesUseCase(ref)
.map {
MangaAlternativeModel(
manga = it,
progress = extraProvider.getProgress(it.id),
referenceChapters = refCount,
)
}.runningFold<MangaAlternativeModel, List<ListModel>>(listOf(LoadingState)) { acc, item ->
acc.filterIsInstance<MangaAlternativeModel>() + item + LoadingFooter()
}.onEmpty {
emit(
listOf(
EmptyState(
icon = R.drawable.ic_empty_common,
textPrimary = R.string.nothing_found,
textSecondary = R.string.text_search_holder_secondary,
actionStringRes = 0,
),
),
)
}.collect {
content.value = it
}
content.value = content.value.filterNot { it is LoadingFooter }
doSearch(throughDisabledSources = false)
}
fun retry() {
searchJob?.cancel()
results.value = emptyList()
includeDisabledSources.value = false
doSearch(throughDisabledSources = false)
}
fun continueSearch() {
if (includeDisabledSources.value) {
return
}
val prevJob = searchJob
searchJob = launchLoadingJob(Dispatchers.Default) {
includeDisabledSources.value = true
prevJob?.join()
doSearch(throughDisabledSources = true)
}
}
@@ -86,13 +117,20 @@ class AlternativesViewModel @Inject constructor(
}
}
private suspend fun mapList(list: List<Manga>, refCount: Int): List<MangaAlternativeModel> {
return list.map {
MangaAlternativeModel(
manga = it,
progress = extraProvider.getProgress(it.id),
referenceChapters = refCount,
)
private fun doSearch(throughDisabledSources: Boolean) {
val prevJob = searchJob
searchJob = launchLoadingJob(Dispatchers.Default) {
prevJob?.cancelAndJoin()
val ref = mangaDetails.getOrDefault(manga)
val refCount = ref.chaptersCount()
alternativesUseCase.invoke(ref, throughDisabledSources)
.collect {
val model = MangaAlternativeModel(
mangaModel = mangaListMapper.toListModel(it, ListMode.GRID) as MangaGridModel,
referenceChapters = refCount,
)
results.append(model)
}
}
}
}

View File

@@ -0,0 +1,196 @@
package org.koitharu.kotatsu.alternatives.ui
import android.annotation.SuppressLint
import android.app.Notification
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.content.pm.ServiceInfo
import androidx.core.app.NotificationChannelCompat
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.core.app.PendingIntentCompat
import androidx.core.content.ContextCompat
import coil3.ImageLoader
import coil3.request.ImageRequest
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.runBlocking
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.alternatives.domain.AutoFixUseCase
import org.koitharu.kotatsu.core.ErrorReporterReceiver
import org.koitharu.kotatsu.core.model.getTitle
import org.koitharu.kotatsu.core.nav.AppRouter
import org.koitharu.kotatsu.core.ui.CoroutineIntentService
import org.koitharu.kotatsu.core.util.ext.checkNotificationPermission
import org.koitharu.kotatsu.core.util.ext.getDisplayMessage
import org.koitharu.kotatsu.core.util.ext.mangaSourceExtra
import org.koitharu.kotatsu.core.util.ext.powerManager
import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug
import org.koitharu.kotatsu.core.util.ext.toBitmapOrNull
import org.koitharu.kotatsu.core.util.ext.withPartialWakeLock
import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
import javax.inject.Inject
import com.google.android.material.R as materialR
@AndroidEntryPoint
class AutoFixService : CoroutineIntentService() {
@Inject
lateinit var autoFixUseCase: AutoFixUseCase
@Inject
lateinit var coil: ImageLoader
private lateinit var notificationManager: NotificationManagerCompat
override fun onCreate() {
super.onCreate()
notificationManager = NotificationManagerCompat.from(applicationContext)
}
override suspend fun IntentJobContext.processIntent(intent: Intent) {
val ids = requireNotNull(intent.getLongArrayExtra(DATA_IDS))
startForeground(this)
for (mangaId in ids) {
powerManager.withPartialWakeLock(TAG) {
val result = runCatchingCancellable {
autoFixUseCase.invoke(mangaId)
}
if (applicationContext.checkNotificationPermission(CHANNEL_ID)) {
val notification = buildNotification(result)
notificationManager.notify(TAG, startId, notification)
}
}
}
}
override fun IntentJobContext.onError(error: Throwable) {
if (applicationContext.checkNotificationPermission(CHANNEL_ID)) {
val notification = runBlocking { buildNotification(Result.failure(error)) }
notificationManager.notify(TAG, startId, notification)
}
}
@SuppressLint("InlinedApi")
private fun startForeground(jobContext: IntentJobContext) {
val title = applicationContext.getString(R.string.fixing_manga)
val channel = NotificationChannelCompat.Builder(CHANNEL_ID, NotificationManagerCompat.IMPORTANCE_MIN)
.setName(title)
.setShowBadge(false)
.setVibrationEnabled(false)
.setSound(null, null)
.setLightsEnabled(false)
.build()
notificationManager.createNotificationChannel(channel)
val notification = NotificationCompat.Builder(applicationContext, CHANNEL_ID)
.setContentTitle(title)
.setPriority(NotificationCompat.PRIORITY_MIN)
.setDefaults(0)
.setSilent(true)
.setOngoing(true)
.setProgress(0, 0, true)
.setSmallIcon(R.drawable.ic_stat_auto_fix)
.setForegroundServiceBehavior(NotificationCompat.FOREGROUND_SERVICE_IMMEDIATE)
.setCategory(NotificationCompat.CATEGORY_PROGRESS)
.addAction(
materialR.drawable.material_ic_clear_black_24dp,
applicationContext.getString(android.R.string.cancel),
jobContext.getCancelIntent(),
)
.build()
jobContext.setForeground(
FOREGROUND_NOTIFICATION_ID,
notification,
ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC,
)
}
private suspend fun buildNotification(result: Result<Pair<Manga, Manga?>>): Notification {
val notification = NotificationCompat.Builder(applicationContext, CHANNEL_ID)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setDefaults(0)
.setSilent(true)
.setAutoCancel(true)
result.onSuccess { (seed, replacement) ->
if (replacement != null) {
notification.setLargeIcon(
coil.execute(
ImageRequest.Builder(applicationContext)
.data(replacement.coverUrl)
.mangaSourceExtra(replacement.source)
.build(),
).toBitmapOrNull(),
)
notification.setSubText(replacement.title)
val intent = AppRouter.detailsIntent(applicationContext, replacement)
notification.setContentIntent(
PendingIntentCompat.getActivity(
applicationContext,
replacement.id.toInt(),
intent,
PendingIntent.FLAG_UPDATE_CURRENT,
false,
),
).setVisibility(
if (replacement.isNsfw) NotificationCompat.VISIBILITY_SECRET else NotificationCompat.VISIBILITY_PUBLIC,
)
notification
.setContentTitle(applicationContext.getString(R.string.fixed))
.setContentText(
applicationContext.getString(
R.string.manga_replaced,
seed.title,
seed.source.getTitle(applicationContext),
replacement.title,
replacement.source.getTitle(applicationContext),
),
)
.setSmallIcon(R.drawable.ic_stat_done)
} else {
notification
.setContentTitle(applicationContext.getString(R.string.fixing_manga))
.setContentText(applicationContext.getString(R.string.no_fix_required, seed.title))
.setSmallIcon(android.R.drawable.stat_sys_warning)
}
}.onFailure { error ->
notification
.setContentTitle(applicationContext.getString(R.string.error_occurred))
.setContentText(
if (error is AutoFixUseCase.NoAlternativesException) {
applicationContext.getString(R.string.no_alternatives_found, error.seed.manga.title)
} else {
error.getDisplayMessage(applicationContext.resources)
},
).setSmallIcon(android.R.drawable.stat_notify_error)
ErrorReporterReceiver.getPendingIntent(applicationContext, error)?.let { reportIntent ->
notification.addAction(
R.drawable.ic_alert_outline,
applicationContext.getString(R.string.report),
reportIntent,
)
}
}
return notification.build()
}
companion object {
private const val DATA_IDS = "ids"
private const val TAG = "auto_fix"
private const val CHANNEL_ID = "auto_fix"
private const val FOREGROUND_NOTIFICATION_ID = 38
fun start(context: Context, mangaIds: Collection<Long>): Boolean = try {
val intent = Intent(context, AutoFixService::class.java)
intent.putExtra(DATA_IDS, mangaIds.toLongArray())
ContextCompat.startForegroundService(context, intent)
true
} catch (e: Exception) {
e.printStackTraceDebug()
false
}
}
}

View File

@@ -2,14 +2,17 @@ package org.koitharu.kotatsu.alternatives.ui
import org.koitharu.kotatsu.core.model.chaptersCount
import org.koitharu.kotatsu.list.ui.model.ListModel
import org.koitharu.kotatsu.list.ui.model.MangaGridModel
import org.koitharu.kotatsu.parsers.model.Manga
data class MangaAlternativeModel(
val manga: Manga,
val progress: Float,
val mangaModel: MangaGridModel,
private val referenceChapters: Int,
) : ListModel {
val manga: Manga
get() = mangaModel.manga
val chaptersCount = manga.chaptersCount()
val chaptersDiff: Int
@@ -18,4 +21,10 @@ data class MangaAlternativeModel(
override fun areItemsTheSame(other: ListModel): Boolean {
return other is MangaAlternativeModel && other.manga.id == manga.id
}
override fun getChangePayload(previousState: ListModel): Any? = if (previousState is MangaAlternativeModel) {
mangaModel.getChangePayload(previousState.mangaModel)
} else {
null
}
}

View File

@@ -17,9 +17,6 @@ data class Bookmark(
val percent: Float,
) : ListModel {
val directImageUrl: String?
get() = if (isImageUrlDirect()) imageUrl else null
val imageLoadData: Any
get() = if (isImageUrlDirect()) imageUrl else toMangaPage()

View File

@@ -1,54 +1,5 @@
package org.koitharu.kotatsu.bookmarks.ui
import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.graphics.Insets
import androidx.core.view.updatePadding
import androidx.fragment.app.commit
import com.google.android.material.appbar.AppBarLayout
import dagger.hilt.android.AndroidEntryPoint
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.ui.BaseActivity
import org.koitharu.kotatsu.databinding.ActivityContainerBinding
import org.koitharu.kotatsu.main.ui.owners.AppBarOwner
import org.koitharu.kotatsu.main.ui.owners.SnackbarOwner
import org.koitharu.kotatsu.core.ui.FragmentContainerActivity
@AndroidEntryPoint
class AllBookmarksActivity :
BaseActivity<ActivityContainerBinding>(),
AppBarOwner,
SnackbarOwner {
override val appBar: AppBarLayout
get() = viewBinding.appbar
override val snackbarHost: CoordinatorLayout
get() = viewBinding.root
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(ActivityContainerBinding.inflate(layoutInflater))
supportActionBar?.setDisplayHomeAsUpEnabled(true)
val fm = supportFragmentManager
if (fm.findFragmentById(R.id.container) == null) {
fm.commit {
setReorderingAllowed(true)
replace(R.id.container, AllBookmarksFragment::class.java, null)
}
}
}
override fun onWindowInsetsChanged(insets: Insets) {
viewBinding.root.updatePadding(
left = insets.left,
right = insets.right,
)
}
companion object {
fun newIntent(context: Context) = Intent(context, AllBookmarksActivity::class.java)
}
}
class AllBookmarksActivity : FragmentContainerActivity(AllBookmarksFragment::class.java)

View File

@@ -3,33 +3,35 @@ package org.koitharu.kotatsu.bookmarks.ui
import android.os.Bundle
import android.view.LayoutInflater
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.appcompat.view.ActionMode
import androidx.core.graphics.Insets
import androidx.core.view.updateLayoutParams
import androidx.core.view.updatePadding
import androidx.core.view.WindowInsetsCompat
import androidx.fragment.app.viewModels
import androidx.recyclerview.widget.GridLayoutManager
import coil.ImageLoader
import coil3.ImageLoader
import dagger.hilt.android.AndroidEntryPoint
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.bookmarks.domain.Bookmark
import org.koitharu.kotatsu.bookmarks.ui.adapter.BookmarksAdapter
import org.koitharu.kotatsu.core.exceptions.resolve.SnackbarErrorObserver
import org.koitharu.kotatsu.core.nav.ReaderIntent
import org.koitharu.kotatsu.core.nav.router
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.ui.BaseFragment
import org.koitharu.kotatsu.core.ui.list.ListSelectionController
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
import org.koitharu.kotatsu.core.ui.list.fastscroll.FastScroller
import org.koitharu.kotatsu.core.ui.util.ReversibleActionObserver
import org.koitharu.kotatsu.core.util.ext.consumeAllSystemBarsInsets
import org.koitharu.kotatsu.core.util.ext.findAppCompatDelegate
import org.koitharu.kotatsu.core.util.ext.observe
import org.koitharu.kotatsu.core.util.ext.observeEvent
import org.koitharu.kotatsu.core.util.ext.systemBarsInsets
import org.koitharu.kotatsu.databinding.FragmentListSimpleBinding
import org.koitharu.kotatsu.details.ui.DetailsActivity
import org.koitharu.kotatsu.list.ui.GridSpanResolver
import org.koitharu.kotatsu.list.ui.adapter.ListHeaderClickListener
import org.koitharu.kotatsu.list.ui.adapter.ListItemType
@@ -38,7 +40,6 @@ import org.koitharu.kotatsu.list.ui.adapter.TypedListSpacingDecoration
import org.koitharu.kotatsu.list.ui.model.ListHeader
import org.koitharu.kotatsu.main.ui.owners.AppBarOwner
import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.reader.ui.ReaderActivity
import javax.inject.Inject
@AndroidEntryPoint
@@ -46,7 +47,7 @@ class AllBookmarksFragment :
BaseFragment<FragmentListSimpleBinding>(),
ListStateHolderListener,
OnListItemClickListener<Bookmark>,
ListSelectionController.Callback2,
ListSelectionController.Callback,
FastScroller.FastScrollListener, ListHeaderClickListener {
@Inject
@@ -106,6 +107,18 @@ class AllBookmarksFragment :
viewModel.onActionDone.observeEvent(viewLifecycleOwner, ReversibleActionObserver(binding.recyclerView))
}
override fun onApplyWindowInsets(v: View, insets: WindowInsetsCompat): WindowInsetsCompat {
val barsInsets = insets.systemBarsInsets
val basePadding = resources.getDimensionPixelOffset(R.dimen.list_spacing_normal)
viewBinding?.recyclerView?.setPadding(
barsInsets.left + basePadding,
barsInsets.top + basePadding,
barsInsets.right + basePadding,
barsInsets.bottom + basePadding,
)
return insets.consumeAllSystemBarsInsets()
}
override fun onDestroyView() {
super.onDestroyView()
bookmarksAdapter = null
@@ -114,22 +127,26 @@ class AllBookmarksFragment :
override fun onItemClick(item: Bookmark, view: View) {
if (selectionController?.onItemClick(item.pageId) != true) {
val intent = ReaderActivity.IntentBuilder(view.context)
val intent = ReaderIntent.Builder(view.context)
.bookmark(item)
.incognito(true)
.build()
startActivity(intent)
router.openReader(intent)
Toast.makeText(view.context, R.string.incognito_mode, Toast.LENGTH_SHORT).show()
}
}
override fun onListHeaderClick(item: ListHeader, view: View) {
val manga = item.payload as? Manga ?: return
startActivity(DetailsActivity.newIntent(view.context, manga))
router.openDetails(manga)
}
override fun onItemLongClick(item: Bookmark, view: View): Boolean {
return selectionController?.onItemLongClick(item.pageId) ?: false
return selectionController?.onItemLongClick(view, item.pageId) == true
}
override fun onItemContextClick(item: Bookmark, view: View): Boolean {
return selectionController?.onItemContextClick(view, item.pageId) == true
}
override fun onRetryClick(error: Throwable) = Unit
@@ -148,23 +165,23 @@ class AllBookmarksFragment :
override fun onCreateActionMode(
controller: ListSelectionController,
mode: ActionMode,
menuInflater: MenuInflater,
menu: Menu,
): Boolean {
mode.menuInflater.inflate(R.menu.mode_bookmarks, menu)
menuInflater.inflate(R.menu.mode_bookmarks, menu)
return true
}
override fun onActionItemClicked(
controller: ListSelectionController,
mode: ActionMode,
mode: ActionMode?,
item: MenuItem,
): Boolean {
return when (item.itemId) {
R.id.action_remove -> {
val ids = selectionController?.snapshot() ?: return false
viewModel.removeBookmarks(ids)
mode.finish()
mode?.finish()
true
}
@@ -172,16 +189,6 @@ class AllBookmarksFragment :
}
}
override fun onWindowInsetsChanged(insets: Insets) {
val rv = requireViewBinding().recyclerView
rv.updatePadding(
bottom = insets.bottom + rv.paddingTop,
)
rv.fastScroller.updateLayoutParams<ViewGroup.MarginLayoutParams> {
bottomMargin = insets.bottom
}
}
private inner class SpanSizeLookup : GridLayoutManager.SpanSizeLookup(), Runnable {
init {
@@ -203,16 +210,4 @@ class AllBookmarksFragment :
invalidateSpanIndexCache()
}
}
companion object {
@Deprecated(
"",
ReplaceWith(
"BookmarksFragment()",
"org.koitharu.kotatsu.bookmarks.ui.BookmarksFragment",
),
)
fun newInstance() = AllBookmarksFragment()
}
}

View File

@@ -1,17 +1,18 @@
package org.koitharu.kotatsu.bookmarks.ui.adapter
import androidx.lifecycle.LifecycleOwner
import coil.ImageLoader
import coil3.ImageLoader
import coil3.request.allowRgb565
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
import org.koitharu.kotatsu.bookmarks.domain.Bookmark
import org.koitharu.kotatsu.core.ui.image.CoverSizeResolver
import org.koitharu.kotatsu.core.ui.list.AdapterDelegateClickListenerAdapter
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
import org.koitharu.kotatsu.core.util.ext.bookmarkExtra
import org.koitharu.kotatsu.core.util.ext.decodeRegion
import org.koitharu.kotatsu.core.util.ext.defaultPlaceholders
import org.koitharu.kotatsu.core.util.ext.enqueueWith
import org.koitharu.kotatsu.core.util.ext.newImageRequest
import org.koitharu.kotatsu.core.util.ext.source
import org.koitharu.kotatsu.databinding.ItemBookmarkLargeBinding
import org.koitharu.kotatsu.list.ui.model.ListModel
@@ -22,21 +23,17 @@ fun bookmarkLargeAD(
) = adapterDelegateViewBinding<Bookmark, ListModel, ItemBookmarkLargeBinding>(
{ inflater, parent -> ItemBookmarkLargeBinding.inflate(inflater, parent, false) },
) {
val listener = AdapterDelegateClickListenerAdapter(this, clickListener)
binding.root.setOnClickListener(listener)
binding.root.setOnLongClickListener(listener)
AdapterDelegateClickListenerAdapter(this, clickListener).attach(itemView)
bind {
binding.imageViewThumb.newImageRequest(lifecycleOwner, item.imageLoadData)?.run {
size(CoverSizeResolver(binding.imageViewThumb))
defaultPlaceholders(context)
allowRgb565(true)
tag(item)
bookmarkExtra(item)
decodeRegion(item.scroll)
source(item.manga.source)
enqueueWith(coil)
}
binding.progressView.percent = item.percent
binding.progressView.setProgress(item.percent, false)
}
}

View File

@@ -1,40 +0,0 @@
package org.koitharu.kotatsu.bookmarks.ui.adapter
import androidx.lifecycle.LifecycleOwner
import coil.ImageLoader
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
import org.koitharu.kotatsu.bookmarks.domain.Bookmark
import org.koitharu.kotatsu.core.ui.image.CoverSizeResolver
import org.koitharu.kotatsu.core.ui.list.AdapterDelegateClickListenerAdapter
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
import org.koitharu.kotatsu.core.util.ext.decodeRegion
import org.koitharu.kotatsu.core.util.ext.defaultPlaceholders
import org.koitharu.kotatsu.core.util.ext.enqueueWith
import org.koitharu.kotatsu.core.util.ext.newImageRequest
import org.koitharu.kotatsu.core.util.ext.source
import org.koitharu.kotatsu.databinding.ItemBookmarkBinding
fun bookmarkListAD(
coil: ImageLoader,
lifecycleOwner: LifecycleOwner,
clickListener: OnListItemClickListener<Bookmark>,
) = adapterDelegateViewBinding<Bookmark, Bookmark, ItemBookmarkBinding>(
{ inflater, parent -> ItemBookmarkBinding.inflate(inflater, parent, false) },
) {
val listener = AdapterDelegateClickListenerAdapter(this, clickListener)
binding.root.setOnClickListener(listener)
binding.root.setOnLongClickListener(listener)
bind {
binding.imageViewThumb.newImageRequest(lifecycleOwner, item.imageLoadData)?.run {
size(CoverSizeResolver(binding.imageViewThumb))
defaultPlaceholders(context)
allowRgb565(true)
tag(item)
decodeRegion(item.scroll)
source(item.manga.source)
enqueueWith(coil)
}
}
}

View File

@@ -2,7 +2,7 @@ package org.koitharu.kotatsu.bookmarks.ui.adapter
import android.content.Context
import androidx.lifecycle.LifecycleOwner
import coil.ImageLoader
import coil3.ImageLoader
import org.koitharu.kotatsu.bookmarks.domain.Bookmark
import org.koitharu.kotatsu.core.ui.BaseListAdapter
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
@@ -10,6 +10,7 @@ import org.koitharu.kotatsu.core.ui.list.fastscroll.FastScroller
import org.koitharu.kotatsu.list.ui.adapter.ListHeaderClickListener
import org.koitharu.kotatsu.list.ui.adapter.ListItemType
import org.koitharu.kotatsu.list.ui.adapter.emptyStateListAD
import org.koitharu.kotatsu.list.ui.adapter.errorStateListAD
import org.koitharu.kotatsu.list.ui.adapter.listHeaderAD
import org.koitharu.kotatsu.list.ui.adapter.loadingFooterAD
import org.koitharu.kotatsu.list.ui.adapter.loadingStateAD
@@ -25,6 +26,7 @@ class BookmarksAdapter(
init {
addDelegate(ListItemType.PAGE_THUMB, bookmarkLargeAD(coil, lifecycleOwner, clickListener))
addDelegate(ListItemType.HEADER, listHeaderAD(headerClickListener))
addDelegate(ListItemType.STATE_ERROR, errorStateListAD(null))
addDelegate(ListItemType.FOOTER_LOADING, loadingFooterAD())
addDelegate(ListItemType.STATE_LOADING, loadingStateAD())
addDelegate(ListItemType.STATE_EMPTY, emptyStateListAD(coil, lifecycleOwner, null))

View File

@@ -0,0 +1,85 @@
package org.koitharu.kotatsu.browser
import android.os.Bundle
import android.view.View
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.isVisible
import androidx.core.view.updatePadding
import dagger.hilt.android.AndroidEntryPoint
import org.koitharu.kotatsu.core.network.proxy.ProxyProvider
import org.koitharu.kotatsu.core.ui.BaseActivity
import org.koitharu.kotatsu.core.util.ext.consumeAll
import org.koitharu.kotatsu.databinding.ActivityBrowserBinding
import javax.inject.Inject
@AndroidEntryPoint
abstract class BaseBrowserActivity : BaseActivity<ActivityBrowserBinding>(), BrowserCallback {
@Inject
lateinit var proxyProvider: ProxyProvider
private lateinit var onBackPressedCallback: WebViewBackPressedCallback
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (!setContentViewWebViewSafe { ActivityBrowserBinding.inflate(layoutInflater) }) {
return
}
viewBinding.webView.webChromeClient = ProgressChromeClient(viewBinding.progressBar)
onBackPressedCallback = WebViewBackPressedCallback(viewBinding.webView)
onBackPressedDispatcher.addCallback(onBackPressedCallback)
onCreate2(savedInstanceState)
}
protected abstract fun onCreate2(savedInstanceState: Bundle?)
override fun onApplyWindowInsets(
v: View,
insets: WindowInsetsCompat
): WindowInsetsCompat {
val type = WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.ime()
val barsInsets = insets.getInsets(type)
viewBinding.webView.updatePadding(
left = barsInsets.left,
right = barsInsets.right,
bottom = barsInsets.bottom,
)
viewBinding.appbar.updatePadding(
left = barsInsets.left,
right = barsInsets.right,
top = barsInsets.top,
)
return insets.consumeAll(type)
}
override fun onPause() {
viewBinding.webView.onPause()
super.onPause()
}
override fun onResume() {
super.onResume()
viewBinding.webView.onResume()
}
override fun onDestroy() {
super.onDestroy()
if (hasViewBinding()) {
viewBinding.webView.stopLoading()
viewBinding.webView.destroy()
}
}
override fun onLoadingStateChanged(isLoading: Boolean) {
viewBinding.progressBar.isVisible = isLoading
}
override fun onTitleChanged(title: CharSequence, subtitle: CharSequence?) {
this.title = title
supportActionBar?.subtitle = subtitle
}
override fun onHistoryChanged() {
onBackPressedCallback.onHistoryChanged()
}
}

View File

@@ -1,69 +1,56 @@
package org.koitharu.kotatsu.browser
import android.content.ActivityNotFoundException
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import android.webkit.CookieManager
import androidx.core.graphics.Insets
import androidx.core.view.isVisible
import androidx.core.view.updatePadding
import androidx.lifecycle.lifecycleScope
import com.google.android.material.snackbar.Snackbar
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.model.MangaSource
import org.koitharu.kotatsu.core.nav.AppRouter
import org.koitharu.kotatsu.core.nav.router
import org.koitharu.kotatsu.core.network.CommonHeaders
import org.koitharu.kotatsu.core.parser.MangaRepository
import org.koitharu.kotatsu.core.parser.RemoteMangaRepository
import org.koitharu.kotatsu.core.ui.BaseActivity
import org.koitharu.kotatsu.core.parser.ParserMangaRepository
import org.koitharu.kotatsu.core.util.ext.configureForParser
import org.koitharu.kotatsu.core.util.ext.getSerializableExtraCompat
import org.koitharu.kotatsu.core.util.ext.toUriOrNull
import org.koitharu.kotatsu.databinding.ActivityBrowserBinding
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.core.util.ext.getDisplayMessage
import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug
import javax.inject.Inject
import com.google.android.material.R as materialR
@AndroidEntryPoint
class BrowserActivity : BaseActivity<ActivityBrowserBinding>(), BrowserCallback {
private lateinit var onBackPressedCallback: WebViewBackPressedCallback
class BrowserActivity : BaseBrowserActivity() {
@Inject
lateinit var mangaRepositoryFactory: MangaRepository.Factory
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (!setContentViewWebViewSafe { ActivityBrowserBinding.inflate(layoutInflater) }) {
return
}
supportActionBar?.run {
setDisplayHomeAsUpEnabled(true)
setHomeAsUpIndicator(materialR.drawable.abc_ic_clear_material)
}
val userAgent = intent?.getSerializableExtraCompat<MangaSource>(EXTRA_SOURCE)?.let { source ->
val repository = mangaRepositoryFactory.create(source) as? RemoteMangaRepository
repository?.headers?.get(CommonHeaders.USER_AGENT)
}
override fun onCreate2(savedInstanceState: Bundle?) {
setDisplayHomeAsUp(true, true)
val mangaSource = MangaSource(intent?.getStringExtra(AppRouter.KEY_SOURCE))
val repository = mangaRepositoryFactory.create(mangaSource) as? ParserMangaRepository
val userAgent = repository?.getRequestHeaders()?.get(CommonHeaders.USER_AGENT)
viewBinding.webView.configureForParser(userAgent)
CookieManager.getInstance().setAcceptThirdPartyCookies(viewBinding.webView, true)
viewBinding.webView.webViewClient = BrowserClient(this)
viewBinding.webView.webChromeClient = ProgressChromeClient(viewBinding.progressBar)
onBackPressedCallback = WebViewBackPressedCallback(viewBinding.webView)
onBackPressedDispatcher.addCallback(onBackPressedCallback)
if (savedInstanceState != null) {
return
}
val url = intent?.dataString
if (url.isNullOrEmpty()) {
finishAfterTransition()
} else {
onTitleChanged(
intent?.getStringExtra(EXTRA_TITLE) ?: getString(R.string.loading_),
url,
)
viewBinding.webView.loadUrl(url)
viewBinding.webView.webViewClient = BrowserClient(proxyProvider, this)
lifecycleScope.launch {
try {
proxyProvider.applyWebViewConfig()
} catch (e: Exception) {
e.printStackTraceDebug()
Snackbar.make(viewBinding.webView, e.getDisplayMessage(resources), Snackbar.LENGTH_LONG).show()
}
if (savedInstanceState == null) {
val url = intent?.dataString
if (url.isNullOrEmpty()) {
finishAfterTransition()
} else {
onTitleChanged(
intent?.getStringExtra(AppRouter.KEY_TITLE) ?: getString(R.string.loading_),
url,
)
viewBinding.webView.loadUrl(url)
}
}
}
}
@@ -81,71 +68,12 @@ class BrowserActivity : BaseActivity<ActivityBrowserBinding>(), BrowserCallback
}
R.id.action_browser -> {
val url = viewBinding.webView.url?.toUriOrNull()
if (url != null) {
val intent = Intent(Intent.ACTION_VIEW)
intent.data = url
try {
startActivity(Intent.createChooser(intent, item.title))
} catch (_: ActivityNotFoundException) {
}
if (!router.openExternalBrowser(viewBinding.webView.url.orEmpty(), item.title)) {
Snackbar.make(viewBinding.webView, R.string.operation_not_supported, Snackbar.LENGTH_SHORT).show()
}
true
}
else -> super.onOptionsItemSelected(item)
}
override fun onPause() {
viewBinding.webView.onPause()
super.onPause()
}
override fun onResume() {
super.onResume()
viewBinding.webView.onResume()
}
override fun onDestroy() {
super.onDestroy()
viewBinding.webView.stopLoading()
viewBinding.webView.destroy()
}
override fun onLoadingStateChanged(isLoading: Boolean) {
viewBinding.progressBar.isVisible = isLoading
}
override fun onTitleChanged(title: CharSequence, subtitle: CharSequence?) {
this.title = title
supportActionBar?.subtitle = subtitle
}
override fun onHistoryChanged() {
onBackPressedCallback.onHistoryChanged()
}
override fun onWindowInsetsChanged(insets: Insets) {
viewBinding.appbar.updatePadding(
top = insets.top,
)
viewBinding.root.updatePadding(
left = insets.left,
right = insets.right,
bottom = insets.bottom,
)
}
companion object {
private const val EXTRA_TITLE = "title"
private const val EXTRA_SOURCE = "source"
fun newIntent(context: Context, url: String, source: MangaSource?, title: String?): Intent {
return Intent(context, BrowserActivity::class.java)
.setData(Uri.parse(url))
.putExtra(EXTRA_TITLE, title)
.putExtra(EXTRA_SOURCE, source)
}
}
}

View File

@@ -2,9 +2,13 @@ package org.koitharu.kotatsu.browser
import android.graphics.Bitmap
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.webkit.WebViewClientCompat
import org.koitharu.kotatsu.core.network.proxy.ProxyProvider
open class BrowserClient(private val callback: BrowserCallback) : WebViewClient() {
open class BrowserClient(
private val proxyProvider: ProxyProvider,
private val callback: BrowserCallback
) : WebViewClientCompat() {
override fun onPageFinished(webView: WebView, url: String) {
super.onPageFinished(webView, url)
@@ -16,7 +20,7 @@ open class BrowserClient(private val callback: BrowserCallback) : WebViewClient(
callback.onLoadingStateChanged(isLoading = true)
}
override fun onPageCommitVisible(view: WebView, url: String?) {
override fun onPageCommitVisible(view: WebView, url: String) {
super.onPageCommitVisible(view, url)
callback.onTitleChanged(view.title.orEmpty(), url)
}

View File

@@ -9,25 +9,32 @@ import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.core.app.PendingIntentCompat
import androidx.core.net.toUri
import coil.EventListener
import coil.request.ErrorResult
import coil.request.ImageRequest
import coil3.EventListener
import coil3.Extras
import coil3.request.ErrorResult
import coil3.request.ImageRequest
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.exceptions.CloudFlareProtectedException
import org.koitharu.kotatsu.core.model.getTitle
import org.koitharu.kotatsu.core.model.isNsfw
import org.koitharu.kotatsu.core.nav.AppRouter
import org.koitharu.kotatsu.core.prefs.SourceSettings
import org.koitharu.kotatsu.core.util.ext.checkNotificationPermission
import org.koitharu.kotatsu.parsers.model.ContentType
import org.koitharu.kotatsu.parsers.model.MangaSource
class CaptchaNotifier(
private val context: Context,
) : EventListener {
) : EventListener() {
fun notify(exception: CloudFlareProtectedException) {
if (!context.checkNotificationPermission(CHANNEL_ID)) {
return
}
if (exception.source != null && SourceSettings(context, exception.source).isCaptchaNotificationsDisabled) {
return
}
val manager = NotificationManagerCompat.from(context)
val channel = NotificationChannelCompat.Builder(CHANNEL_ID, NotificationManagerCompat.IMPORTANCE_DEFAULT)
val channel = NotificationChannelCompat.Builder(CHANNEL_ID, NotificationManagerCompat.IMPORTANCE_LOW)
.setName(context.getString(R.string.captcha_required))
.setShowBadge(true)
.setVibrationEnabled(false)
@@ -36,17 +43,17 @@ class CaptchaNotifier(
.build()
manager.createNotificationChannel(channel)
val intent = CloudFlareActivity.newIntent(context, exception)
val intent = AppRouter.cloudFlareResolveIntent(context, exception)
.setData(exception.url.toUri())
val notification = NotificationCompat.Builder(context, CHANNEL_ID)
.setContentTitle(channel.name)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setDefaults(NotificationCompat.DEFAULT_SOUND)
.setSmallIcon(android.R.drawable.stat_notify_error)
.setPriority(NotificationCompat.PRIORITY_LOW)
.setDefaults(0)
.setSmallIcon(R.drawable.ic_bot)
.setGroup(GROUP_CAPTCHA)
.setAutoCancel(true)
.setVisibility(
if (exception.source?.contentType == ContentType.HENTAI) {
if (exception.source?.isNsfw() == true) {
NotificationCompat.VISIBILITY_SECRET
} else {
NotificationCompat.VISIBILITY_PUBLIC
@@ -55,7 +62,7 @@ class CaptchaNotifier(
.setContentText(
context.getString(
R.string.captcha_required_summary,
exception.source?.title ?: context.getString(R.string.app_name),
exception.source?.getTitle(context) ?: context.getString(R.string.app_name),
),
)
.setContentIntent(PendingIntentCompat.getActivity(context, 0, intent, 0, false))
@@ -83,20 +90,19 @@ class CaptchaNotifier(
override fun onError(request: ImageRequest, result: ErrorResult) {
super.onError(request, result)
val e = result.throwable
if (e is CloudFlareProtectedException && request.parameters.value<Boolean>(PARAM_IGNORE_CAPTCHA) != true) {
if (e is CloudFlareProtectedException && request.extras[ignoreCaptchaKey] != true) {
notify(e)
}
}
companion object {
fun ImageRequest.Builder.ignoreCaptchaErrors() = setParameter(
key = PARAM_IGNORE_CAPTCHA,
value = true,
memoryCacheKey = null,
)
fun ImageRequest.Builder.ignoreCaptchaErrors() = apply {
extras[ignoreCaptchaKey] = true
}
val ignoreCaptchaKey = Extras.Key(false)
private const val PARAM_IGNORE_CAPTCHA = "ignore_captcha"
private const val CHANNEL_ID = "captcha"
private const val TAG = CHANNEL_ID
private const val GROUP_CAPTCHA = "org.koitharu.kotatsu.CAPTCHA"

View File

@@ -5,38 +5,30 @@ import android.content.Intent
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import android.webkit.CookieManager
import androidx.activity.result.contract.ActivityResultContract
import androidx.core.graphics.Insets
import androidx.core.net.toUri
import androidx.core.view.isInvisible
import androidx.core.view.isVisible
import androidx.core.view.updatePadding
import androidx.lifecycle.lifecycleScope
import com.google.android.material.snackbar.Snackbar
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.runInterruptible
import kotlinx.coroutines.yield
import okhttp3.Headers
import okhttp3.HttpUrl
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.browser.WebViewBackPressedCallback
import org.koitharu.kotatsu.browser.BaseBrowserActivity
import org.koitharu.kotatsu.core.exceptions.CloudFlareProtectedException
import org.koitharu.kotatsu.core.model.MangaSource
import org.koitharu.kotatsu.core.network.CommonHeaders
import org.koitharu.kotatsu.core.nav.AppRouter
import org.koitharu.kotatsu.core.network.cookies.MutableCookieJar
import org.koitharu.kotatsu.core.ui.BaseActivity
import org.koitharu.kotatsu.core.util.TaggedActivityResult
import org.koitharu.kotatsu.core.util.ext.configureForParser
import org.koitharu.kotatsu.databinding.ActivityBrowserBinding
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.core.util.ext.getDisplayMessage
import org.koitharu.kotatsu.parsers.network.CloudFlareHelper
import javax.inject.Inject
import com.google.android.material.R as materialR
@AndroidEntryPoint
class CloudFlareActivity : BaseActivity<ActivityBrowserBinding>(), CloudFlareCallback {
class CloudFlareActivity : BaseBrowserActivity(), CloudFlareCallback {
private var pendingResult = RESULT_CANCELED
@@ -44,44 +36,28 @@ class CloudFlareActivity : BaseActivity<ActivityBrowserBinding>(), CloudFlareCal
lateinit var cookieJar: MutableCookieJar
private lateinit var cfClient: CloudFlareClient
private var onBackPressedCallback: WebViewBackPressedCallback? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (!setContentViewWebViewSafe { ActivityBrowserBinding.inflate(layoutInflater) }) {
return
}
supportActionBar?.run {
setDisplayHomeAsUpEnabled(true)
setHomeAsUpIndicator(materialR.drawable.abc_ic_clear_material)
}
val url = intent?.dataString.orEmpty()
cfClient = CloudFlareClient(cookieJar, this, url)
viewBinding.webView.configureForParser(intent?.getStringExtra(ARG_UA))
viewBinding.webView.webViewClient = cfClient
onBackPressedCallback = WebViewBackPressedCallback(viewBinding.webView).also {
onBackPressedDispatcher.addCallback(it)
}
CookieManager.getInstance().setAcceptThirdPartyCookies(viewBinding.webView, true)
if (savedInstanceState != null) {
return
}
if (url.isEmpty()) {
override fun onCreate2(savedInstanceState: Bundle?) {
setDisplayHomeAsUp(true, true)
val url = intent?.dataString
if (url.isNullOrEmpty()) {
finishAfterTransition()
} else {
onTitleChanged(getString(R.string.loading_), url)
viewBinding.webView.loadUrl(url)
return
}
}
override fun onDestroy() {
runCatching {
viewBinding.webView
}.onSuccess {
it.stopLoading()
it.destroy()
cfClient = CloudFlareClient(proxyProvider, cookieJar, this, url)
viewBinding.webView.configureForParser(intent?.getStringExtra(AppRouter.KEY_USER_AGENT))
viewBinding.webView.webViewClient = cfClient
lifecycleScope.launch {
try {
proxyProvider.applyWebViewConfig()
} catch (e: Exception) {
Snackbar.make(viewBinding.webView, e.getDisplayMessage(resources), Snackbar.LENGTH_LONG).show()
}
if (savedInstanceState == null) {
onTitleChanged(getString(R.string.loading_), url)
viewBinding.webView.loadUrl(url)
}
}
super.onDestroy()
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
@@ -89,17 +65,6 @@ class CloudFlareActivity : BaseActivity<ActivityBrowserBinding>(), CloudFlareCal
return super.onCreateOptionsMenu(menu)
}
override fun onWindowInsetsChanged(insets: Insets) {
viewBinding.appbar.updatePadding(
top = insets.top,
)
viewBinding.root.updatePadding(
left = insets.left,
right = insets.right,
bottom = insets.bottom,
)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean = when (item.itemId) {
android.R.id.home -> {
viewBinding.webView.stopLoading()
@@ -115,21 +80,13 @@ class CloudFlareActivity : BaseActivity<ActivityBrowserBinding>(), CloudFlareCal
else -> super.onOptionsItemSelected(item)
}
override fun onResume() {
super.onResume()
viewBinding.webView.onResume()
}
override fun onPause() {
viewBinding.webView.onPause()
super.onPause()
}
override fun finish() {
setResult(pendingResult)
super.finish()
}
override fun onLoadingStateChanged(isLoading: Boolean) = Unit
override fun onPageLoaded() {
viewBinding.progressBar.isInvisible = true
}
@@ -140,21 +97,13 @@ class CloudFlareActivity : BaseActivity<ActivityBrowserBinding>(), CloudFlareCal
override fun onCheckPassed() {
pendingResult = RESULT_OK
val source = intent?.getStringExtra(ARG_SOURCE)
val source = intent?.getStringExtra(AppRouter.KEY_SOURCE)
if (source != null) {
CaptchaNotifier(this).dismiss(MangaSource(source))
}
finishAfterTransition()
}
override fun onLoadingStateChanged(isLoading: Boolean) {
viewBinding.progressBar.isVisible = isLoading
}
override fun onHistoryChanged() {
onBackPressedCallback?.onHistoryChanged()
}
override fun onTitleChanged(title: CharSequence, subtitle: CharSequence?) {
setTitle(title)
supportActionBar?.subtitle =
@@ -176,45 +125,22 @@ class CloudFlareActivity : BaseActivity<ActivityBrowserBinding>(), CloudFlareCal
private suspend fun clearCfCookies(url: HttpUrl) = runInterruptible(Dispatchers.Default) {
cookieJar.removeCookies(url) { cookie ->
val name = cookie.name
name.startsWith("cf_") || name.startsWith("_cf") || name.startsWith("__cf") || name == "csrftoken"
CloudFlareHelper.isCloudFlareCookie(cookie.name)
}
}
class Contract : ActivityResultContract<CloudFlareProtectedException, TaggedActivityResult>() {
class Contract : ActivityResultContract<CloudFlareProtectedException, Boolean>() {
override fun createIntent(context: Context, input: CloudFlareProtectedException): Intent {
return newIntent(context, input)
return AppRouter.cloudFlareResolveIntent(context, input)
}
override fun parseResult(resultCode: Int, intent: Intent?): TaggedActivityResult {
return TaggedActivityResult(TAG, resultCode)
override fun parseResult(resultCode: Int, intent: Intent?): Boolean {
return resultCode == RESULT_OK
}
}
companion object {
const val TAG = "CloudFlareActivity"
private const val ARG_UA = "ua"
private const val ARG_SOURCE = "_source"
fun newIntent(context: Context, exception: CloudFlareProtectedException) = newIntent(
context = context,
url = exception.url,
source = exception.source,
headers = exception.headers,
)
private fun newIntent(
context: Context,
url: String,
source: MangaSource?,
headers: Headers?,
) = Intent(context, CloudFlareActivity::class.java).apply {
data = url.toUri()
putExtra(ARG_SOURCE, source?.name)
headers?.get(CommonHeaders.USER_AGENT)?.let {
putExtra(ARG_UA, it)
}
}
}
}

View File

@@ -4,8 +4,6 @@ import org.koitharu.kotatsu.browser.BrowserCallback
interface CloudFlareCallback : BrowserCallback {
override fun onLoadingStateChanged(isLoading: Boolean) = Unit
override fun onTitleChanged(title: CharSequence, subtitle: CharSequence?) = Unit
fun onPageLoaded()

View File

@@ -2,18 +2,19 @@ package org.koitharu.kotatsu.browser.cloudflare
import android.graphics.Bitmap
import android.webkit.WebView
import okhttp3.HttpUrl.Companion.toHttpUrl
import org.koitharu.kotatsu.browser.BrowserClient
import org.koitharu.kotatsu.core.network.cookies.MutableCookieJar
import org.koitharu.kotatsu.core.network.proxy.ProxyProvider
import org.koitharu.kotatsu.parsers.network.CloudFlareHelper
private const val CF_CLEARANCE = "cf_clearance"
private const val LOOP_COUNTER = 3
class CloudFlareClient(
proxyProvider: ProxyProvider,
private val cookieJar: MutableCookieJar,
private val callback: CloudFlareCallback,
private val targetUrl: String,
) : BrowserClient(callback) {
) : BrowserClient(proxyProvider, callback) {
private val oldClearance = getClearance()
private var counter = 0
@@ -23,7 +24,7 @@ class CloudFlareClient(
checkClearance()
}
override fun onPageCommitVisible(view: WebView, url: String?) {
override fun onPageCommitVisible(view: WebView, url: String) {
super.onPageCommitVisible(view, url)
callback.onPageLoaded()
}
@@ -50,8 +51,5 @@ class CloudFlareClient(
}
}
private fun getClearance(): String? {
return cookieJar.loadForRequest(targetUrl.toHttpUrl())
.find { it.name == CF_CLEARANCE }?.value
}
private fun getClearance() = CloudFlareHelper.getClearanceCookie(cookieJar, targetUrl)
}

View File

@@ -2,16 +2,22 @@ package org.koitharu.kotatsu.core
import android.app.Application
import android.content.Context
import android.os.Build
import android.provider.SearchRecentSuggestions
import android.text.Html
import androidx.collection.arraySetOf
import androidx.core.content.ContextCompat
import androidx.room.InvalidationTracker
import androidx.work.WorkManager
import coil.ComponentRegistry
import coil.ImageLoader
import coil.decode.SvgDecoder
import coil.disk.DiskCache
import coil.util.DebugLogger
import coil3.ImageLoader
import coil3.disk.DiskCache
import coil3.disk.directory
import coil3.gif.AnimatedImageDecoder
import coil3.gif.GifDecoder
import coil3.network.okhttp.OkHttpNetworkFetcherFactory
import coil3.request.allowRgb565
import coil3.svg.SvgDecoder
import coil3.util.DebugLogger
import dagger.Binds
import dagger.Module
import dagger.Provides
@@ -27,13 +33,17 @@ import okhttp3.OkHttpClient
import org.koitharu.kotatsu.BuildConfig
import org.koitharu.kotatsu.browser.cloudflare.CaptchaNotifier
import org.koitharu.kotatsu.core.db.MangaDatabase
import org.koitharu.kotatsu.core.network.ImageProxyInterceptor
import org.koitharu.kotatsu.core.image.AvifImageDecoder
import org.koitharu.kotatsu.core.image.CbzFetcher
import org.koitharu.kotatsu.core.image.MangaSourceHeaderInterceptor
import org.koitharu.kotatsu.core.network.MangaHttpClient
import org.koitharu.kotatsu.core.network.imageproxy.ImageProxyInterceptor
import org.koitharu.kotatsu.core.os.AppShortcutManager
import org.koitharu.kotatsu.core.os.NetworkState
import org.koitharu.kotatsu.core.parser.MangaLoaderContextImpl
import org.koitharu.kotatsu.core.parser.MangaRepository
import org.koitharu.kotatsu.core.parser.favicon.FaviconFetcher
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.ui.image.CoilImageGetter
import org.koitharu.kotatsu.core.ui.util.ActivityRecreationHandle
import org.koitharu.kotatsu.core.util.AcraScreenLogger
@@ -42,11 +52,11 @@ import org.koitharu.kotatsu.core.util.ext.isLowRamDevice
import org.koitharu.kotatsu.details.ui.pager.pages.MangaPageFetcher
import org.koitharu.kotatsu.details.ui.pager.pages.MangaPageKeyer
import org.koitharu.kotatsu.local.data.CacheDir
import org.koitharu.kotatsu.local.data.CbzFetcher
import org.koitharu.kotatsu.local.data.LocalStorageChanges
import org.koitharu.kotatsu.local.domain.model.LocalManga
import org.koitharu.kotatsu.main.domain.CoverRestoreInterceptor
import org.koitharu.kotatsu.main.ui.protect.AppProtectHelper
import org.koitharu.kotatsu.main.ui.protect.ScreenshotPolicyHelper
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.search.ui.MangaSuggestionsProvider
import org.koitharu.kotatsu.settings.backup.BackupObserver
@@ -67,29 +77,35 @@ interface AppModule {
companion object {
@Provides
@LocalizedAppContext
fun provideLocalizedContext(
@ApplicationContext context: Context,
): Context = ContextCompat.getContextForLanguage(context)
@Provides
@Singleton
fun provideNetworkState(
@ApplicationContext context: Context
) = NetworkState(context.connectivityManager)
@ApplicationContext context: Context,
settings: AppSettings,
) = NetworkState(context.connectivityManager, settings)
@Provides
@Singleton
fun provideMangaDatabase(
@ApplicationContext context: Context,
): MangaDatabase {
return MangaDatabase(context)
}
): MangaDatabase = MangaDatabase(context)
@Provides
@Singleton
fun provideCoil(
@ApplicationContext context: Context,
@LocalizedAppContext context: Context,
@MangaHttpClient okHttpClientProvider: Provider<OkHttpClient>,
mangaRepositoryFactory: MangaRepository.Factory,
imageProxyInterceptor: ImageProxyInterceptor,
pageFetcherFactory: MangaPageFetcher.Factory,
coverRestoreInterceptor: CoverRestoreInterceptor,
networkStateProvider: Provider<NetworkState>,
): ImageLoader {
val diskCacheFactory = {
val rootDir = context.externalCacheDir ?: context.cacheDir
@@ -101,34 +117,39 @@ interface AppModule {
okHttpClientProvider.get().newBuilder().cache(null).build()
}
return ImageLoader.Builder(context)
.okHttpClient { okHttpClientLazy.value }
.interceptorDispatcher(Dispatchers.Default)
.fetcherDispatcher(Dispatchers.Default)
.decoderDispatcher(Dispatchers.IO)
.transformationDispatcher(Dispatchers.Default)
.interceptorCoroutineContext(Dispatchers.Default)
.diskCache(diskCacheFactory)
.logger(if (BuildConfig.DEBUG) DebugLogger() else null)
.allowRgb565(context.isLowRamDevice())
.eventListener(CaptchaNotifier(context))
.components(
ComponentRegistry.Builder()
.add(SvgDecoder.Factory())
.add(CbzFetcher.Factory())
.add(FaviconFetcher.Factory(context, okHttpClientLazy, mangaRepositoryFactory))
.add(MangaPageKeyer())
.add(pageFetcherFactory)
.add(imageProxyInterceptor)
.add(coverRestoreInterceptor)
.build(),
).build()
.components {
add(
OkHttpNetworkFetcherFactory(
callFactory = okHttpClientLazy::value,
connectivityChecker = { networkStateProvider.get() },
),
)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
add(AnimatedImageDecoder.Factory())
} else {
add(GifDecoder.Factory())
}
add(SvgDecoder.Factory())
add(CbzFetcher.Factory())
add(AvifImageDecoder.Factory())
add(FaviconFetcher.Factory(mangaRepositoryFactory))
add(MangaPageKeyer())
add(pageFetcherFactory)
add(imageProxyInterceptor)
add(coverRestoreInterceptor)
add(MangaSourceHeaderInterceptor())
}.build()
}
@Provides
fun provideSearchSuggestions(
@ApplicationContext context: Context,
): SearchRecentSuggestions {
return MangaSuggestionsProvider.createSuggestions(context)
}
): SearchRecentSuggestions = MangaSuggestionsProvider.createSuggestions(context)
@Provides
@ElementsIntoSet
@@ -150,10 +171,12 @@ interface AppModule {
appProtectHelper: AppProtectHelper,
activityRecreationHandle: ActivityRecreationHandle,
acraScreenLogger: AcraScreenLogger,
screenshotPolicyHelper: ScreenshotPolicyHelper,
): Set<@JvmSuppressWildcards Application.ActivityLifecycleCallbacks> = arraySetOf(
appProtectHelper,
activityRecreationHandle,
acraScreenLogger,
screenshotPolicyHelper,
)
@Provides

View File

@@ -11,8 +11,8 @@ import androidx.work.Configuration
import androidx.work.WorkManager
import dagger.hilt.android.HiltAndroidApp
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.acra.ACRA
import org.acra.ReportField
import org.acra.config.dialog
@@ -25,9 +25,14 @@ import org.koitharu.kotatsu.BuildConfig
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.db.MangaDatabase
import org.koitharu.kotatsu.core.os.AppValidator
import org.koitharu.kotatsu.core.os.RomCompat
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.util.WorkServiceStopHelper
import org.koitharu.kotatsu.core.util.ext.processLifecycleScope
import org.koitharu.kotatsu.local.data.LocalStorageChanges
import org.koitharu.kotatsu.local.data.index.LocalMangaIndex
import org.koitharu.kotatsu.local.domain.model.LocalManga
import org.koitharu.kotatsu.parsers.util.suspendlazy.getOrNull
import org.koitharu.kotatsu.settings.work.WorkScheduleManager
import java.security.Security
import javax.inject.Inject
@@ -60,6 +65,13 @@ open class BaseApp : Application(), Configuration.Provider {
@Inject
lateinit var workManagerProvider: Provider<WorkManager>
@Inject
lateinit var localMangaIndexProvider: Provider<LocalMangaIndex>
@Inject
@LocalStorageChanges
lateinit var localStorageChanges: MutableSharedFlow<LocalManga?>
override val workManagerConfiguration: Configuration
get() = Configuration.Builder()
.setWorkerFactory(workerFactory)
@@ -67,21 +79,22 @@ open class BaseApp : Application(), Configuration.Provider {
override fun onCreate() {
super.onCreate()
if (ACRA.isACRASenderServiceProcess()) {
return
}
AppCompatDelegate.setDefaultNightMode(settings.theme)
AppCompatDelegate.setApplicationLocales(settings.appLocales)
// TLS 1.3 support for Android < 10
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
Security.insertProviderAt(Conscrypt.newProvider(), 1)
}
setupActivityLifecycleCallbacks()
processLifecycleScope.launch {
val isOriginalApp = withContext(Dispatchers.Default) {
appValidator.isOriginalApp
}
ACRA.errorReporter.putCustomData("isOriginalApp", isOriginalApp.toString())
ACRA.errorReporter.putCustomData("isOriginalApp", appValidator.isOriginalApp.getOrNull().toString())
ACRA.errorReporter.putCustomData("isMiui", RomCompat.isMiui.getOrNull().toString())
}
processLifecycleScope.launch(Dispatchers.Default) {
setupDatabaseObservers()
localStorageChanges.collect(localMangaIndexProvider.get())
}
workScheduleManager.init()
WorkServiceStopHelper(workManagerProvider).setup()
@@ -89,6 +102,9 @@ open class BaseApp : Application(), Configuration.Provider {
override fun attachBaseContext(base: Context) {
super.attachBaseContext(base)
if (ACRA.isACRASenderServiceProcess()) {
return
}
initAcra {
buildConfigClass = BuildConfig::class.java
reportFormat = StringFormat.JSON

View File

@@ -5,29 +5,34 @@ import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.BadParcelableException
import androidx.core.app.PendingIntentCompat
import org.koitharu.kotatsu.BuildConfig
import org.koitharu.kotatsu.core.nav.AppRouter
import org.koitharu.kotatsu.core.util.ext.getSerializableExtraCompat
import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug
import org.koitharu.kotatsu.core.util.ext.report
class ErrorReporterReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val e = intent?.getSerializableExtraCompat<Throwable>(EXTRA_ERROR) ?: return
val e = intent?.getSerializableExtraCompat<Throwable>(AppRouter.KEY_ERROR) ?: return
e.report()
}
companion object {
private const val EXTRA_ERROR = "err"
private const val ACTION_REPORT = "${BuildConfig.APPLICATION_ID}.action.REPORT_ERROR"
fun getPendingIntent(context: Context, e: Throwable): PendingIntent {
fun getPendingIntent(context: Context, e: Throwable): PendingIntent? = try {
val intent = Intent(context, ErrorReporterReceiver::class.java)
intent.setAction(ACTION_REPORT)
intent.setData(Uri.parse("err://${e.hashCode()}"))
intent.putExtra(EXTRA_ERROR, e)
return checkNotNull(PendingIntentCompat.getBroadcast(context, 0, intent, 0, false))
intent.putExtra(AppRouter.KEY_ERROR, e)
PendingIntentCompat.getBroadcast(context, 0, intent, 0, false)
} catch (e: BadParcelableException) {
e.printStackTraceDebug()
null
}
}
}

View File

@@ -1,24 +0,0 @@
package org.koitharu.kotatsu.core
import android.content.Context
import com.google.auto.service.AutoService
import org.acra.builder.ReportBuilder
import org.acra.config.CoreConfiguration
import org.acra.config.ReportingAdministrator
@AutoService(ReportingAdministrator::class)
class ErrorReportingAdmin : ReportingAdministrator {
override fun shouldStartCollecting(
context: Context,
config: CoreConfiguration,
reportBuilder: ReportBuilder
): Boolean {
return reportBuilder.exception?.isDeadOs() != true
}
private fun Throwable.isDeadOs(): Boolean {
val className = javaClass.simpleName
return className == "DeadSystemException" || className == "DeadSystemRuntimeException" || cause?.isDeadOs() == true
}
}

View File

@@ -0,0 +1,13 @@
package org.koitharu.kotatsu.core
import javax.inject.Qualifier
@Qualifier
@Target(
AnnotationTarget.FUNCTION,
AnnotationTarget.PROPERTY_GETTER,
AnnotationTarget.PROPERTY_SETTER,
AnnotationTarget.VALUE_PARAMETER,
AnnotationTarget.FIELD,
)
annotation class LocalizedAppContext

View File

@@ -16,6 +16,7 @@ class BackupEntry(
CATEGORIES("categories"),
FAVOURITES("favourites"),
SETTINGS("settings"),
SETTINGS_READER_GRID("reader_grid"),
BOOKMARKS("bookmarks"),
SOURCES("sources"),
}

View File

@@ -0,0 +1,12 @@
package org.koitharu.kotatsu.core.backup
import android.net.Uri
import java.util.Date
data class BackupFile(
val uri: Uri,
val dateTime: Date,
): Comparable<BackupFile> {
override fun compareTo(other: BackupFile): Int = compareValues(dateTime, other.dateTime)
}

View File

@@ -1,15 +1,18 @@
package org.koitharu.kotatsu.core.backup
import androidx.room.withTransaction
import kotlinx.coroutines.flow.FlowCollector
import org.json.JSONArray
import org.json.JSONObject
import org.koitharu.kotatsu.BuildConfig
import org.koitharu.kotatsu.core.db.MangaDatabase
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.parsers.util.json.JSONIterator
import org.koitharu.kotatsu.core.util.progress.Progress
import org.koitharu.kotatsu.parsers.util.json.asTypedList
import org.koitharu.kotatsu.parsers.util.json.getLongOrDefault
import org.koitharu.kotatsu.parsers.util.json.mapJSON
import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
import org.koitharu.kotatsu.reader.data.TapGridSettings
import java.util.Date
import javax.inject.Inject
@@ -18,6 +21,7 @@ private const val PAGE_SIZE = 10
class BackupRepository @Inject constructor(
private val db: MangaDatabase,
private val settings: AppSettings,
private val tapGridSettings: TapGridSettings,
) {
suspend fun dumpHistory(): BackupEntry {
@@ -103,6 +107,14 @@ class BackupRepository @Inject constructor(
return entry
}
fun dumpReaderGridSettings(): BackupEntry {
val entry = BackupEntry(BackupEntry.Name.SETTINGS_READER_GRID, JSONArray())
val settingsDump = tapGridSettings.getAllValues()
val json = JsonSerializer(settingsDump).toJson()
entry.data.put(json)
return entry
}
suspend fun dumpSources(): BackupEntry {
val entry = BackupEntry(BackupEntry.Name.SOURCES, JSONArray())
val all = db.getSourcesDao().findAll()
@@ -128,9 +140,11 @@ class BackupRepository @Inject constructor(
return if (timestamp == 0L) null else Date(timestamp)
}
suspend fun restoreHistory(entry: BackupEntry): CompositeResult {
suspend fun restoreHistory(entry: BackupEntry, outProgress: FlowCollector<Progress>?): CompositeResult {
val result = CompositeResult()
for (item in entry.data.JSONIterator()) {
val list = entry.data.asTypedList<JSONObject>()
outProgress?.emit(Progress(progress = 0, total = list.size))
for ((index, item) in list.withIndex()) {
val mangaJson = item.getJSONObject("manga")
val manga = JsonDeserializer(mangaJson).toMangaEntity()
val tags = mangaJson.getJSONArray("tags").mapJSON {
@@ -144,13 +158,14 @@ class BackupRepository @Inject constructor(
db.getHistoryDao().upsert(history)
}
}
outProgress?.emit(Progress(progress = index, total = list.size))
}
return result
}
suspend fun restoreCategories(entry: BackupEntry): CompositeResult {
val result = CompositeResult()
for (item in entry.data.JSONIterator()) {
for (item in entry.data.asTypedList<JSONObject>()) {
val category = JsonDeserializer(item).toFavouriteCategoryEntity()
result += runCatchingCancellable {
db.getFavouriteCategoriesDao().upsert(category)
@@ -159,9 +174,11 @@ class BackupRepository @Inject constructor(
return result
}
suspend fun restoreFavourites(entry: BackupEntry): CompositeResult {
suspend fun restoreFavourites(entry: BackupEntry, outProgress: FlowCollector<Progress>?): CompositeResult {
val result = CompositeResult()
for (item in entry.data.JSONIterator()) {
val list = entry.data.asTypedList<JSONObject>()
outProgress?.emit(Progress(progress = 0, total = list.size))
for ((index, item) in list.withIndex()) {
val mangaJson = item.getJSONObject("manga")
val manga = JsonDeserializer(mangaJson).toMangaEntity()
val tags = mangaJson.getJSONArray("tags").mapJSON {
@@ -175,13 +192,14 @@ class BackupRepository @Inject constructor(
db.getFavouritesDao().upsert(favourite)
}
}
outProgress?.emit(Progress(progress = index, total = list.size))
}
return result
}
suspend fun restoreBookmarks(entry: BackupEntry): CompositeResult {
val result = CompositeResult()
for (item in entry.data.JSONIterator()) {
for (item in entry.data.asTypedList<JSONObject>()) {
val mangaJson = item.getJSONObject("manga")
val manga = JsonDeserializer(mangaJson).toMangaEntity()
val tags = item.getJSONArray("tags").mapJSON {
@@ -203,7 +221,7 @@ class BackupRepository @Inject constructor(
suspend fun restoreSources(entry: BackupEntry): CompositeResult {
val result = CompositeResult()
for (item in entry.data.JSONIterator()) {
for (item in entry.data.asTypedList<JSONObject>()) {
val source = JsonDeserializer(item).toMangaSourceEntity()
result += runCatchingCancellable {
db.getSourcesDao().upsert(source)
@@ -214,11 +232,21 @@ class BackupRepository @Inject constructor(
fun restoreSettings(entry: BackupEntry): CompositeResult {
val result = CompositeResult()
for (item in entry.data.JSONIterator()) {
for (item in entry.data.asTypedList<JSONObject>()) {
result += runCatchingCancellable {
settings.upsertAll(JsonDeserializer(item).toMap())
}
}
return result
}
fun restoreReaderGridSettings(entry: BackupEntry): CompositeResult {
val result = CompositeResult()
for (item in entry.data.asTypedList<JSONObject>()) {
result += runCatchingCancellable {
tapGridSettings.upsertAll(JsonDeserializer(item).toMap())
}
}
return result
}
}

View File

@@ -1,13 +1,11 @@
package org.koitharu.kotatsu.core.backup
import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.runInterruptible
import okhttp3.internal.closeQuietly
import okio.Closeable
import org.json.JSONArray
import org.koitharu.kotatsu.core.exceptions.BadBackupFormatException
import org.koitharu.kotatsu.core.util.ext.processLifecycleScope
import java.io.File
import java.util.EnumSet
import java.util.zip.ZipException
@@ -35,25 +33,29 @@ class BackupZipInput private constructor(val file: File) : Closeable {
zipFile.close()
}
fun cleanupAsync() {
processLifecycleScope.launch(Dispatchers.IO, CoroutineStart.ATOMIC) {
runCatching {
close()
file.delete()
}
}
fun closeAndDelete() {
closeQuietly()
file.delete()
}
companion object {
fun from(file: File): BackupZipInput = try {
val res = BackupZipInput(file)
if (res.zipFile.getEntry("index") == null) {
throw BadBackupFormatException(null)
fun from(file: File): BackupZipInput {
var res: BackupZipInput? = null
return try {
res = BackupZipInput(file)
if (res.zipFile.getEntry("index") == null) {
throw BadBackupFormatException(null)
}
res
} catch (exception: Throwable) {
res?.closeQuietly()
throw if (exception is ZipException) {
BadBackupFormatException(exception)
} else {
exception
}
}
res
} catch (e: ZipException) {
throw BadBackupFormatException(e)
}
}
}

View File

@@ -5,10 +5,12 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runInterruptible
import okio.Closeable
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug
import org.koitharu.kotatsu.core.zip.ZipOutput
import java.io.File
import java.time.LocalDate
import java.time.format.DateTimeFormatter
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
import java.util.zip.Deflater
@@ -27,20 +29,32 @@ class BackupZipOutput(val file: File) : Closeable {
override fun close() {
output.close()
}
}
const val DIR_BACKUPS = "backups"
companion object {
suspend fun BackupZipOutput(context: Context): BackupZipOutput = runInterruptible(Dispatchers.IO) {
val dir = context.run {
getExternalFilesDir(DIR_BACKUPS) ?: File(filesDir, DIR_BACKUPS)
const val DIR_BACKUPS = "backups"
private val dateTimeFormat = SimpleDateFormat("yyyyMMdd-HHmm")
fun generateFileName(context: Context) = buildString {
append(context.getString(R.string.app_name).replace(' ', '_').lowercase(Locale.ROOT))
append('_')
append(dateTimeFormat.format(Date()))
append(".bk.zip")
}
fun parseBackupDateTime(fileName: String): Date? = try {
dateTimeFormat.parse(fileName.substringAfterLast('_').substringBefore('.'))
} catch (e: ParseException) {
e.printStackTraceDebug()
null
}
suspend fun createTemp(context: Context): BackupZipOutput = runInterruptible(Dispatchers.IO) {
val dir = context.run {
getExternalFilesDir(DIR_BACKUPS) ?: File(filesDir, DIR_BACKUPS)
}
dir.mkdirs()
BackupZipOutput(File(dir, generateFileName(context)))
}
}
dir.mkdirs()
val filename = buildString {
append(context.getString(R.string.app_name).replace(' ', '_').lowercase(Locale.ROOT))
append('_')
append(LocalDate.now().format(DateTimeFormatter.ofPattern("ddMMyyyy")))
append(".bk.zip")
}
BackupZipOutput(File(dir, filename))
}

View File

@@ -27,6 +27,10 @@ class CompositeResult {
}
}
operator fun plusAssign(error: Throwable) {
errors.add(error)
}
operator fun plusAssign(other: CompositeResult) {
this.successCount += other.successCount
this.errors += other.errors

View File

@@ -0,0 +1,91 @@
package org.koitharu.kotatsu.core.backup
import android.content.Context
import android.net.Uri
import androidx.annotation.CheckResult
import androidx.documentfile.provider.DocumentFile
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runInterruptible
import okio.buffer
import okio.sink
import okio.source
import org.jetbrains.annotations.Blocking
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug
import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
import java.io.File
import javax.inject.Inject
class ExternalBackupStorage @Inject constructor(
@ApplicationContext private val context: Context,
private val settings: AppSettings,
) {
suspend fun list(): List<BackupFile> = runInterruptible(Dispatchers.IO) {
getRootOrThrow().listFiles().mapNotNull {
if (it.isFile && it.canRead()) {
BackupFile(
uri = it.uri,
dateTime = it.name?.let { fileName ->
BackupZipOutput.parseBackupDateTime(fileName)
} ?: return@mapNotNull null,
)
} else {
null
}
}.sortedDescending()
}
suspend fun listOrNull() = runCatchingCancellable {
list()
}.onFailure { e ->
e.printStackTraceDebug()
}.getOrNull()
suspend fun put(file: File): Uri = runInterruptible(Dispatchers.IO) {
val out = checkNotNull(getRootOrThrow().createFile("application/zip", file.nameWithoutExtension)) {
"Cannot create target backup file"
}
checkNotNull(context.contentResolver.openOutputStream(out.uri, "wt")).sink().use { sink ->
file.source().buffer().use { src ->
src.readAll(sink)
}
}
out.uri
}
@CheckResult
suspend fun delete(victim: BackupFile) = runInterruptible(Dispatchers.IO) {
val df = DocumentFile.fromSingleUri(context, victim.uri)
df != null && df.delete()
}
suspend fun getLastBackupDate() = listOrNull()?.maxOfOrNull { it.dateTime }
suspend fun trim(maxCount: Int): Boolean {
if (maxCount == Int.MAX_VALUE) {
return false
}
val list = listOrNull()
if (list == null || list.size <= maxCount) {
return false
}
var result = false
for (i in maxCount until list.size) {
if (delete(list[i])) {
result = true
}
}
return result
}
@Blocking
private fun getRootOrThrow(): DocumentFile {
val uri = checkNotNull(settings.periodicalBackupDirectory) {
"Backup directory is not specified"
}
val root = DocumentFile.fromTreeUri(context, uri)
return checkNotNull(root) { "Cannot obtain DocumentFile from $uri" }
}
}

View File

@@ -12,6 +12,7 @@ import org.koitharu.kotatsu.parsers.model.SortOrder
import org.koitharu.kotatsu.parsers.util.json.getBooleanOrDefault
import org.koitharu.kotatsu.parsers.util.json.getFloatOrDefault
import org.koitharu.kotatsu.parsers.util.json.getIntOrDefault
import org.koitharu.kotatsu.parsers.util.json.getLongOrDefault
import org.koitharu.kotatsu.parsers.util.json.getStringOrNull
class JsonDeserializer(private val json: JSONObject) {
@@ -27,15 +28,16 @@ class JsonDeserializer(private val json: JSONObject) {
fun toMangaEntity() = MangaEntity(
id = json.getLong("id"),
title = json.getString("title"),
altTitle = json.getStringOrNull("alt_title"),
altTitles = json.getStringOrNull("alt_title"),
url = json.getString("url"),
publicUrl = json.getStringOrNull("public_url").orEmpty(),
rating = json.getDouble("rating").toFloat(),
isNsfw = json.getBooleanOrDefault("nsfw", false),
contentRating = json.getStringOrNull("content_rating"),
coverUrl = json.getString("cover_url"),
largeCoverUrl = json.getStringOrNull("large_cover_url"),
state = json.getStringOrNull("state"),
author = json.getStringOrNull("author"),
authors = json.getStringOrNull("author"),
source = json.getString("source"),
)
@@ -84,6 +86,9 @@ class JsonDeserializer(private val json: JSONObject) {
source = json.getString("source"),
isEnabled = json.getBoolean("enabled"),
sortKey = json.getInt("sort_key"),
addedIn = json.getIntOrDefault("added_in", 0),
lastUsedAt = json.getLongOrDefault("used_at", 0L),
isPinned = json.getBooleanOrDefault("pinned", false),
)
fun toMap(): Map<String, Any?> {

View File

@@ -58,15 +58,16 @@ class JsonSerializer private constructor(private val json: JSONObject) {
JSONObject().apply {
put("id", e.id)
put("title", e.title)
put("alt_title", e.altTitle)
put("alt_title", e.altTitles)
put("url", e.url)
put("public_url", e.publicUrl)
put("rating", e.rating)
put("nsfw", e.isNsfw)
put("content_rating", e.contentRating)
put("cover_url", e.coverUrl)
put("large_cover_url", e.largeCoverUrl)
put("state", e.state)
put("author", e.author)
put("author", e.authors)
put("source", e.source)
},
)
@@ -89,6 +90,9 @@ class JsonSerializer private constructor(private val json: JSONObject) {
put("source", e.source)
put("enabled", e.isEnabled)
put("sort_key", e.sortKey)
put("added_in", e.addedIn)
put("used_at", e.lastUsedAt)
put("pinned", e.isPinned)
},
)

View File

@@ -0,0 +1,93 @@
package org.koitharu.kotatsu.core.backup
import android.content.Context
import androidx.annotation.CheckResult
import dagger.hilt.android.qualifiers.ApplicationContext
import okhttp3.HttpUrl
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.MultipartBody
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.asRequestBody
import okhttp3.Response
import okhttp3.internal.closeQuietly
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.nav.AppRouter
import org.koitharu.kotatsu.core.network.BaseHttpClient
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.parsers.util.await
import org.koitharu.kotatsu.parsers.util.json.getBooleanOrDefault
import org.koitharu.kotatsu.parsers.util.json.getStringOrNull
import org.koitharu.kotatsu.parsers.util.parseJson
import java.io.File
import javax.inject.Inject
class TelegramBackupUploader @Inject constructor(
private val settings: AppSettings,
@BaseHttpClient private val client: OkHttpClient,
@ApplicationContext private val context: Context,
) {
private val botToken = context.getString(R.string.tg_backup_bot_token)
suspend fun uploadBackup(file: File) {
val requestBody = file.asRequestBody("application/zip".toMediaTypeOrNull())
val multipartBody = MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("chat_id", requireChatId())
.addFormDataPart("document", file.name, requestBody)
.build()
val request = Request.Builder()
.url(urlOf("sendDocument").build())
.post(multipartBody)
.build()
client.newCall(request).await().consume()
}
suspend fun sendTestMessage() {
val request = Request.Builder()
.url(urlOf("getMe").build())
.build()
client.newCall(request).await().consume()
sendMessage(context.getString(R.string.backup_tg_echo))
}
@CheckResult
fun openBotInApp(router: AppRouter): Boolean {
val botUsername = context.getString(R.string.tg_backup_bot_name)
return router.openExternalBrowser("tg://resolve?domain=$botUsername") ||
router.openExternalBrowser("https://t.me/$botUsername")
}
private suspend fun sendMessage(message: String) {
val url = urlOf("sendMessage")
.addQueryParameter("chat_id", requireChatId())
.addQueryParameter("text", message)
.build()
val request = Request.Builder()
.url(url)
.build()
client.newCall(request).await().consume()
}
private fun requireChatId() = checkNotNull(settings.backupTelegramChatId) {
"Telegram chat ID not set in settings"
}
private fun Response.consume() {
if (isSuccessful) {
closeQuietly()
return
}
val jo = parseJson()
if (!jo.getBooleanOrDefault("ok", true)) {
throw RuntimeException(jo.getStringOrNull("description"))
}
}
private fun urlOf(method: String) = HttpUrl.Builder()
.scheme("https")
.host("api.telegram.org")
.addPathSegment("bot$botToken")
.addPathSegment(method)
}

View File

@@ -1,6 +1,7 @@
package org.koitharu.kotatsu.core.cache
import androidx.collection.LruCache
import org.koitharu.kotatsu.core.util.SynchronizedSieveCache
import org.koitharu.kotatsu.parsers.model.MangaSource
import java.util.concurrent.TimeUnit
import org.koitharu.kotatsu.core.cache.MemoryContentCache.Key as CacheKey
@@ -8,11 +9,9 @@ class ExpiringLruCache<T>(
val maxSize: Int,
private val lifetime: Long,
private val timeUnit: TimeUnit,
) : Iterable<CacheKey> {
) {
private val cache = LruCache<CacheKey, ExpiringValue<T>>(maxSize)
override fun iterator(): Iterator<CacheKey> = cache.snapshot().keys.iterator()
private val cache = SynchronizedSieveCache<CacheKey, ExpiringValue<T>>(maxSize)
operator fun get(key: CacheKey): T? {
val value = cache[key] ?: return null
@@ -23,7 +22,8 @@ class ExpiringLruCache<T>(
}
operator fun set(key: CacheKey, value: T) {
cache.put(key, ExpiringValue(value, lifetime, timeUnit))
val value = ExpiringValue(value, lifetime, timeUnit)
cache.put(key, value)
}
fun clear() {
@@ -37,4 +37,8 @@ class ExpiringLruCache<T>(
fun remove(key: CacheKey) {
cache.remove(key)
}
fun removeAll(source: MangaSource) {
cache.removeIf { key, _ -> key.source == source }
}
}

View File

@@ -16,16 +16,16 @@ class MemoryContentCache @Inject constructor(application: Application) : Compone
private val isLowRam = application.isLowRamDevice()
init {
application.registerComponentCallbacks(this)
}
private val detailsCache = ExpiringLruCache<SafeDeferred<Manga>>(if (isLowRam) 1 else 4, 5, TimeUnit.MINUTES)
private val pagesCache =
ExpiringLruCache<SafeDeferred<List<MangaPage>>>(if (isLowRam) 1 else 4, 10, TimeUnit.MINUTES)
private val relatedMangaCache =
ExpiringLruCache<SafeDeferred<List<Manga>>>(if (isLowRam) 1 else 3, 10, TimeUnit.MINUTES)
init {
application.registerComponentCallbacks(this)
}
suspend fun getDetails(source: MangaSource, url: String): Manga? {
return detailsCache[Key(source, url)]?.awaitOrNull()
}
@@ -81,11 +81,7 @@ class MemoryContentCache @Inject constructor(application: Application) : Compone
}
private fun clearCache(cache: ExpiringLruCache<*>, source: MangaSource) {
cache.forEach { key ->
if (key.source == source) {
cache.remove(key)
}
}
cache.removeAll(source)
}
data class Key(

View File

@@ -12,11 +12,13 @@ import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import org.koitharu.kotatsu.bookmarks.data.BookmarkEntity
import org.koitharu.kotatsu.bookmarks.data.BookmarksDao
import org.koitharu.kotatsu.core.db.dao.ChaptersDao
import org.koitharu.kotatsu.core.db.dao.MangaDao
import org.koitharu.kotatsu.core.db.dao.MangaSourcesDao
import org.koitharu.kotatsu.core.db.dao.PreferencesDao
import org.koitharu.kotatsu.core.db.dao.TagsDao
import org.koitharu.kotatsu.core.db.dao.TrackLogsDao
import org.koitharu.kotatsu.core.db.entity.ChapterEntity
import org.koitharu.kotatsu.core.db.entity.MangaEntity
import org.koitharu.kotatsu.core.db.entity.MangaPrefsEntity
import org.koitharu.kotatsu.core.db.entity.MangaSourceEntity
@@ -33,6 +35,12 @@ import org.koitharu.kotatsu.core.db.migrations.Migration17To18
import org.koitharu.kotatsu.core.db.migrations.Migration18To19
import org.koitharu.kotatsu.core.db.migrations.Migration19To20
import org.koitharu.kotatsu.core.db.migrations.Migration1To2
import org.koitharu.kotatsu.core.db.migrations.Migration20To21
import org.koitharu.kotatsu.core.db.migrations.Migration21To22
import org.koitharu.kotatsu.core.db.migrations.Migration22To23
import org.koitharu.kotatsu.core.db.migrations.Migration23To24
import org.koitharu.kotatsu.core.db.migrations.Migration24To23
import org.koitharu.kotatsu.core.db.migrations.Migration24To25
import org.koitharu.kotatsu.core.db.migrations.Migration2To3
import org.koitharu.kotatsu.core.db.migrations.Migration3To4
import org.koitharu.kotatsu.core.db.migrations.Migration4To5
@@ -48,6 +56,8 @@ import org.koitharu.kotatsu.favourites.data.FavouriteEntity
import org.koitharu.kotatsu.favourites.data.FavouritesDao
import org.koitharu.kotatsu.history.data.HistoryDao
import org.koitharu.kotatsu.history.data.HistoryEntity
import org.koitharu.kotatsu.local.data.index.LocalMangaIndexDao
import org.koitharu.kotatsu.local.data.index.LocalMangaIndexEntity
import org.koitharu.kotatsu.scrobbling.common.data.ScrobblingDao
import org.koitharu.kotatsu.scrobbling.common.data.ScrobblingEntity
import org.koitharu.kotatsu.stats.data.StatsDao
@@ -58,14 +68,14 @@ import org.koitharu.kotatsu.tracker.data.TrackEntity
import org.koitharu.kotatsu.tracker.data.TrackLogEntity
import org.koitharu.kotatsu.tracker.data.TracksDao
const val DATABASE_VERSION = 20
const val DATABASE_VERSION = 25
@Database(
entities = [
MangaEntity::class, TagEntity::class, HistoryEntity::class, MangaTagsEntity::class,
FavouriteCategoryEntity::class, FavouriteEntity::class, MangaPrefsEntity::class,
TrackEntity::class, TrackLogEntity::class, SuggestionEntity::class, BookmarkEntity::class,
ScrobblingEntity::class, MangaSourceEntity::class, StatsEntity::class,
MangaEntity::class, TagEntity::class, HistoryEntity::class, MangaTagsEntity::class, ChapterEntity::class,
FavouriteCategoryEntity::class, FavouriteEntity::class, MangaPrefsEntity::class, TrackEntity::class,
TrackLogEntity::class, SuggestionEntity::class, BookmarkEntity::class, ScrobblingEntity::class,
MangaSourceEntity::class, StatsEntity::class, LocalMangaIndexEntity::class,
],
version = DATABASE_VERSION,
)
@@ -96,6 +106,10 @@ abstract class MangaDatabase : RoomDatabase() {
abstract fun getSourcesDao(): MangaSourcesDao
abstract fun getStatsDao(): StatsDao
abstract fun getLocalMangaIndexDao(): LocalMangaIndexDao
abstract fun getChaptersDao(): ChaptersDao
}
fun getDatabaseMigrations(context: Context): Array<Migration> = arrayOf(
@@ -118,6 +132,12 @@ fun getDatabaseMigrations(context: Context): Array<Migration> = arrayOf(
Migration17To18(),
Migration18To19(),
Migration19To20(),
Migration20To21(),
Migration21To22(),
Migration22To23(),
Migration23To24(),
Migration24To23(),
Migration24To25(),
)
fun MangaDatabase(context: Context): MangaDatabase = Room

View File

@@ -0,0 +1,113 @@
package org.koitharu.kotatsu.core.db
import androidx.sqlite.db.SimpleSQLiteQuery
import org.koitharu.kotatsu.list.domain.ListFilterOption
import java.util.LinkedList
class MangaQueryBuilder(
private val table: String,
private val conditionCallback: ConditionCallback
) {
private var filterOptions: Collection<ListFilterOption> = emptyList()
private var whereConditions = LinkedList<String>()
private var orderBy: String? = null
private var groupBy: String? = null
private var extraJoins: String? = null
private var limit: Int = 0
fun filters(options: Collection<ListFilterOption>) = apply {
filterOptions = options
}
fun where(condition: String) = apply {
whereConditions.add(condition)
}
fun orderBy(orderBy: String?) = apply {
this@MangaQueryBuilder.orderBy = orderBy
}
fun groupBy(groupBy: String?) = apply {
this@MangaQueryBuilder.groupBy = groupBy
}
fun limit(limit: Int) = apply {
this@MangaQueryBuilder.limit = limit
}
fun join(join: String?) = apply {
extraJoins = join
}
fun build() = buildString {
append("SELECT * FROM ")
append(table)
extraJoins?.let {
append(' ')
append(it)
}
if (whereConditions.isNotEmpty()) {
whereConditions.joinTo(
buffer = this,
prefix = " WHERE ",
separator = " AND ",
)
}
if (filterOptions.isNotEmpty()) {
if (whereConditions.isEmpty()) {
append(" WHERE")
} else {
append(" AND")
}
var isFirst = true
val groupedOptions = filterOptions.groupBy { it.groupKey }
for ((_, group) in groupedOptions) {
if (group.isEmpty()) {
continue
}
if (isFirst) {
isFirst = false
append(' ')
} else {
append(" AND ")
}
if (group.size > 1) {
group.joinTo(
buffer = this,
separator = " OR ",
prefix = "(",
postfix = ")",
transform = ::getConditionOrThrow,
)
} else {
append(getConditionOrThrow(group.single()))
}
}
}
groupBy?.let {
append(" GROUP BY ")
append(it)
}
orderBy?.let {
append(" ORDER BY ")
append(it)
}
if (limit > 0) {
append(" LIMIT ")
append(limit)
}
}.let { SimpleSQLiteQuery(it) }
private fun getConditionOrThrow(option: ListFilterOption): String = when (option) {
is ListFilterOption.Inverted -> "NOT(${getConditionOrThrow(option.option)})"
else -> requireNotNull(conditionCallback.getCondition(option)) {
"Unsupported filter option $option"
}
}
fun interface ConditionCallback {
fun getCondition(option: ListFilterOption): String?
}
}

View File

@@ -7,3 +7,4 @@ const val TABLE_FAVOURITE_CATEGORIES = "favourite_categories"
const val TABLE_HISTORY = "history"
const val TABLE_MANGA_TAGS = "manga_tags"
const val TABLE_SOURCES = "sources"
const val TABLE_CHAPTERS = "chapters"

View File

@@ -0,0 +1,30 @@
package org.koitharu.kotatsu.core.db.dao
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Transaction
import org.koitharu.kotatsu.core.db.entity.ChapterEntity
@Dao
abstract class ChaptersDao {
@Query("SELECT * FROM chapters WHERE manga_id = :mangaId ORDER BY `index` ASC")
abstract suspend fun findAll(mangaId: Long): List<ChapterEntity>
@Query("DELETE FROM chapters WHERE manga_id = :mangaId")
abstract suspend fun deleteAll(mangaId: Long)
@Query("DELETE FROM chapters WHERE manga_id NOT IN (SELECT manga_id FROM history WHERE deleted_at = 0) AND manga_id NOT IN (SELECT manga_id FROM favourites WHERE deleted_at = 0)")
abstract suspend fun gc()
@Transaction
open suspend fun replaceAll(mangaId: Long, entities: Collection<ChapterEntity>) {
deleteAll(mangaId)
insert(entities)
}
@Insert(onConflict = OnConflictStrategy.REPLACE)
protected abstract suspend fun insert(entities: Collection<ChapterEntity>)
}

View File

@@ -20,6 +20,9 @@ abstract class MangaDao {
@Query("SELECT * FROM manga WHERE manga_id = :id")
abstract suspend fun find(id: Long): MangaWithTags?
@Query("SELECT EXISTS(SELECT * FROM manga WHERE manga_id = :id)")
abstract suspend operator fun contains(id: Long): Boolean
@Transaction
@Query("SELECT * FROM manga WHERE public_url = :publicUrl")
abstract suspend fun findByPublicUrl(publicUrl: String): MangaWithTags?
@@ -55,6 +58,19 @@ abstract class MangaDao {
@Delete
abstract suspend fun delete(subjects: Collection<MangaEntity>)
@Query(
"""
DELETE FROM manga WHERE NOT EXISTS(SELECT * FROM history WHERE history.manga_id == manga.manga_id)
AND NOT EXISTS(SELECT * FROM favourites WHERE favourites.manga_id == manga.manga_id)
AND NOT EXISTS(SELECT * FROM bookmarks WHERE bookmarks.manga_id == manga.manga_id)
AND NOT EXISTS(SELECT * FROM suggestions WHERE suggestions.manga_id == manga.manga_id)
AND NOT EXISTS(SELECT * FROM scrobblings WHERE scrobblings.manga_id == manga.manga_id)
AND NOT EXISTS(SELECT * FROM local_index WHERE local_index.manga_id == manga.manga_id)
AND manga.manga_id NOT IN (:idsToKeep)
""",
)
abstract suspend fun cleanup(idsToKeep: Set<Long>)
@Transaction
open suspend fun upsert(manga: MangaEntity, tags: Iterable<TagEntity>? = null) {
upsert(manga)

View File

@@ -10,20 +10,26 @@ import androidx.room.Upsert
import androidx.sqlite.db.SimpleSQLiteQuery
import androidx.sqlite.db.SupportSQLiteQuery
import kotlinx.coroutines.flow.Flow
import org.intellij.lang.annotations.Language
import org.koitharu.kotatsu.BuildConfig
import org.koitharu.kotatsu.core.db.entity.MangaSourceEntity
import org.koitharu.kotatsu.explore.data.SourcesSortOrder
@Dao
abstract class MangaSourcesDao {
@Query("SELECT * FROM sources ORDER BY sort_key")
@Query("SELECT * FROM sources ORDER BY pinned DESC, sort_key")
abstract suspend fun findAll(): List<MangaSourceEntity>
@Query("SELECT source FROM sources WHERE enabled = 1")
abstract suspend fun findAllEnabledNames(): List<String>
@Query("SELECT * FROM sources ORDER BY sort_key")
@Query("SELECT * FROM sources WHERE added_in >= :version")
abstract suspend fun findAllFromVersion(version: Int): List<MangaSourceEntity>
@Query("SELECT * FROM sources ORDER BY used_at DESC LIMIT :limit")
abstract suspend fun findLastUsed(limit: Int): List<MangaSourceEntity>
@Query("SELECT * FROM sources ORDER BY pinned DESC, sort_key")
abstract fun observeAll(): Flow<List<MangaSourceEntity>>
@Query("SELECT enabled FROM sources WHERE source = :source")
@@ -38,6 +44,12 @@ abstract class MangaSourcesDao {
@Query("UPDATE sources SET sort_key = :sortKey WHERE source = :source")
abstract suspend fun setSortKey(source: String, sortKey: Int)
@Query("UPDATE sources SET used_at = :value WHERE source = :source")
abstract suspend fun setLastUsed(source: String, value: Long)
@Query("UPDATE sources SET pinned = :isPinned WHERE source = :source")
abstract suspend fun setPinned(source: String, isPinned: Boolean)
@Insert(onConflict = OnConflictStrategy.IGNORE)
@Transaction
abstract suspend fun insertIfAbsent(entries: Collection<MangaSourceEntity>)
@@ -45,21 +57,14 @@ abstract class MangaSourcesDao {
@Upsert
abstract suspend fun upsert(entry: MangaSourceEntity)
fun observeEnabled(order: SourcesSortOrder): Flow<List<MangaSourceEntity>> {
val orderBy = getOrderBy(order)
@Query("SELECT * FROM sources WHERE pinned = 1")
abstract suspend fun findAllPinned(): List<MangaSourceEntity>
@Language("RoomSql")
val query = SimpleSQLiteQuery("SELECT * FROM sources WHERE enabled = 1 ORDER BY $orderBy")
return observeImpl(query)
}
fun observeAll(enabledOnly: Boolean, order: SourcesSortOrder): Flow<List<MangaSourceEntity>> =
observeImpl(getQuery(enabledOnly, order))
suspend fun findAllEnabled(order: SourcesSortOrder): List<MangaSourceEntity> {
val orderBy = getOrderBy(order)
@Language("RoomSql")
val query = SimpleSQLiteQuery("SELECT * FROM sources WHERE enabled = 1 ORDER BY $orderBy")
return findAllImpl(query)
}
suspend fun findAll(enabledOnly: Boolean, order: SourcesSortOrder): List<MangaSourceEntity> =
findAllImpl(getQuery(enabledOnly, order))
@Transaction
open suspend fun setEnabled(source: String, isEnabled: Boolean) {
@@ -68,6 +73,9 @@ abstract class MangaSourcesDao {
source = source,
isEnabled = isEnabled,
sortKey = getMaxSortKey() + 1,
addedIn = BuildConfig.VERSION_CODE,
lastUsedAt = 0,
isPinned = false,
)
upsert(entity)
}
@@ -82,9 +90,21 @@ abstract class MangaSourcesDao {
@RawQuery
protected abstract suspend fun findAllImpl(query: SupportSQLiteQuery): List<MangaSourceEntity>
private fun getQuery(enabledOnly: Boolean, order: SourcesSortOrder) = SimpleSQLiteQuery(
buildString {
append("SELECT * FROM sources ")
if (enabledOnly) {
append("WHERE enabled = 1 ")
}
append("ORDER BY pinned DESC, ")
append(getOrderBy(order))
},
)
private fun getOrderBy(order: SourcesSortOrder) = when (order) {
SourcesSortOrder.ALPHABETIC -> "source ASC"
SourcesSortOrder.POPULARITY -> "(SELECT COUNT(*) FROM manga WHERE source = sources.source) DESC"
SourcesSortOrder.MANUAL -> "sort_key ASC"
SourcesSortOrder.LAST_USED -> "used_at DESC"
}
}

View File

@@ -1,6 +1,8 @@
package org.koitharu.kotatsu.core.db.dao
import androidx.room.*
import androidx.room.Dao
import androidx.room.Query
import androidx.room.Upsert
import kotlinx.coroutines.flow.Flow
import org.koitharu.kotatsu.core.db.entity.MangaPrefsEntity
@@ -13,6 +15,9 @@ abstract class PreferencesDao {
@Query("SELECT * FROM preferences WHERE manga_id = :mangaId")
abstract fun observe(mangaId: Long): Flow<MangaPrefsEntity?>
@Query("UPDATE preferences SET cf_brightness = 0, cf_contrast = 0, cf_invert = 0, cf_grayscale = 0")
abstract suspend fun resetColorFilters()
@Upsert
abstract suspend fun upsert(pref: MangaPrefsEntity)
}

View File

@@ -4,36 +4,59 @@ import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.RawQuery
import androidx.room.Transaction
import androidx.sqlite.db.SupportSQLiteQuery
import kotlinx.coroutines.flow.Flow
import org.koitharu.kotatsu.core.db.MangaQueryBuilder
import org.koitharu.kotatsu.list.domain.ListFilterOption
import org.koitharu.kotatsu.tracker.data.TrackLogEntity
import org.koitharu.kotatsu.tracker.data.TrackLogWithManga
@Dao
interface TrackLogsDao {
abstract class TrackLogsDao : MangaQueryBuilder.ConditionCallback {
@Transaction
@Query("SELECT * FROM track_logs ORDER BY created_at DESC LIMIT :limit OFFSET 0")
fun observeAll(limit: Int): Flow<List<TrackLogWithManga>>
fun observeAll(
limit: Int,
filterOptions: Set<ListFilterOption>,
): Flow<List<TrackLogWithManga>> = observeAllImpl(
MangaQueryBuilder("track_logs", this)
.filters(filterOptions)
.limit(limit)
.orderBy("created_at DESC")
.build(),
)
@Query("SELECT COUNT(*) FROM track_logs WHERE unread = 1")
fun observeUnreadCount(): Flow<Int>
abstract fun observeUnreadCount(): Flow<Int>
@Query("DELETE FROM track_logs")
suspend fun clear()
abstract suspend fun clear()
@Query("UPDATE track_logs SET unread = 0 WHERE id = :id")
suspend fun markAsRead(id: Long)
abstract suspend fun markAsRead(id: Long)
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(entity: TrackLogEntity): Long
abstract suspend fun insert(entity: TrackLogEntity): Long
@Query("DELETE FROM track_logs WHERE manga_id NOT IN (SELECT manga_id FROM tracks)")
suspend fun gc()
abstract suspend fun gc()
@Query("DELETE FROM track_logs WHERE id IN (SELECT id FROM track_logs ORDER BY created_at DESC LIMIT 0 OFFSET :size)")
suspend fun trim(size: Int)
abstract suspend fun trim(size: Int)
@Query("SELECT COUNT(*) FROM track_logs")
suspend fun count(): Int
abstract suspend fun count(): Int
@Transaction
@RawQuery(observedEntities = [TrackLogEntity::class])
protected abstract fun observeAllImpl(query: SupportSQLiteQuery): Flow<List<TrackLogWithManga>>
override fun getCondition(option: ListFilterOption): String? = when (option) {
ListFilterOption.Macro.FAVORITE -> "EXISTS(SELECT * FROM favourites WHERE favourites.manga_id = track_logs.manga_id)"
is ListFilterOption.Favorite -> "EXISTS(SELECT * FROM favourites WHERE favourites.manga_id = track_logs.manga_id AND favourites.category_id = ${option.category.id})"
is ListFilterOption.Tag -> "EXISTS(SELECT * FROM manga_tags WHERE manga_tags.manga_id = track_logs.manga_id AND tag_id = ${option.tagId})"
ListFilterOption.Macro.NSFW -> "(SELECT nsfw FROM manga WHERE manga.manga_id = track_logs.manga_id) = 1"
else -> null
}
}

View File

@@ -0,0 +1,32 @@
package org.koitharu.kotatsu.core.db.entity
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.ForeignKey
import org.koitharu.kotatsu.core.db.TABLE_CHAPTERS
@Entity(
tableName = TABLE_CHAPTERS,
primaryKeys = ["manga_id", "chapter_id"],
foreignKeys = [
ForeignKey(
entity = MangaEntity::class,
parentColumns = ["manga_id"],
childColumns = ["manga_id"],
onDelete = ForeignKey.CASCADE,
),
],
)
data class ChapterEntity(
@ColumnInfo(name = "chapter_id") val chapterId: Long,
@ColumnInfo(name = "manga_id") val mangaId: Long,
@ColumnInfo(name = "name") val title: String,
@ColumnInfo(name = "number") val number: Float,
@ColumnInfo(name = "volume") val volume: Int,
@ColumnInfo(name = "url") val url: String,
@ColumnInfo(name = "scanlator") val scanlator: String?,
@ColumnInfo(name = "upload_date") val uploadDate: Long,
@ColumnInfo(name = "branch") val branch: String?,
@ColumnInfo(name = "source") val source: String,
@ColumnInfo(name = "index") val index: Int,
)

View File

@@ -1,14 +1,20 @@
package org.koitharu.kotatsu.core.db.entity
import org.koitharu.kotatsu.core.model.MangaSource
import org.koitharu.kotatsu.core.util.ext.longHashCode
import org.koitharu.kotatsu.parsers.model.ContentRating
import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaChapter
import org.koitharu.kotatsu.parsers.model.MangaState
import org.koitharu.kotatsu.parsers.model.MangaTag
import org.koitharu.kotatsu.parsers.model.SortOrder
import org.koitharu.kotatsu.parsers.util.longHashCode
import org.koitharu.kotatsu.parsers.util.mapToSet
import org.koitharu.kotatsu.parsers.util.nullIfEmpty
import org.koitharu.kotatsu.parsers.util.toArraySet
import org.koitharu.kotatsu.parsers.util.toTitleCase
private const val VALUES_DIVIDER = '\n'
// Entity to model
fun TagEntity.toMangaTag() = MangaTag(
@@ -21,23 +27,41 @@ fun Collection<TagEntity>.toMangaTags() = mapToSet(TagEntity::toMangaTag)
fun Collection<TagEntity>.toMangaTagsList() = map(TagEntity::toMangaTag)
fun MangaEntity.toManga(tags: Set<MangaTag>) = Manga(
fun MangaEntity.toManga(tags: Set<MangaTag>, chapters: List<ChapterEntity>?) = Manga(
id = this.id,
title = this.title,
altTitle = this.altTitle,
altTitles = this.altTitles?.split(VALUES_DIVIDER)?.toArraySet().orEmpty(),
state = this.state?.let { MangaState(it) },
rating = this.rating,
isNsfw = this.isNsfw,
contentRating = ContentRating(this.contentRating)
?: if (isNsfw) ContentRating.ADULT else null,
url = this.url,
publicUrl = this.publicUrl,
coverUrl = this.coverUrl,
largeCoverUrl = this.largeCoverUrl,
author = this.author,
authors = this.authors?.split(VALUES_DIVIDER)?.toArraySet().orEmpty(),
source = MangaSource(this.source),
tags = tags,
chapters = chapters?.toMangaChapters(),
)
fun MangaWithTags.toManga() = manga.toManga(tags.toMangaTags())
fun MangaWithTags.toManga(chapters: List<ChapterEntity>? = null) = manga.toManga(tags.toMangaTags(), chapters)
fun Collection<MangaWithTags>.toMangaList() = map { it.toManga() }
fun ChapterEntity.toMangaChapter() = MangaChapter(
id = chapterId,
title = title.nullIfEmpty(),
number = number,
volume = volume,
url = url,
scanlator = scanlator,
uploadDate = uploadDate,
branch = branch,
source = MangaSource(source),
)
fun Collection<ChapterEntity>.toMangaChapters() = map { it.toMangaChapter() }
// Model to entity
@@ -47,13 +71,14 @@ fun Manga.toEntity() = MangaEntity(
publicUrl = publicUrl,
source = source.name,
largeCoverUrl = largeCoverUrl,
coverUrl = coverUrl,
altTitle = altTitle,
coverUrl = coverUrl.orEmpty(),
altTitles = altTitles.joinToString(VALUES_DIVIDER.toString()),
rating = rating,
isNsfw = isNsfw,
contentRating = contentRating?.name,
state = state?.name,
title = title,
author = author,
authors = authors.joinToString(VALUES_DIVIDER.toString()),
)
fun MangaTag.toEntity() = TagEntity(
@@ -65,6 +90,22 @@ fun MangaTag.toEntity() = TagEntity(
fun Collection<MangaTag>.toEntities() = map(MangaTag::toEntity)
fun Iterable<IndexedValue<MangaChapter>>.toEntities(mangaId: Long) = map { (index, chapter) ->
ChapterEntity(
chapterId = chapter.id,
mangaId = mangaId,
title = chapter.title.orEmpty(),
number = chapter.number,
volume = chapter.volume,
url = chapter.url,
scanlator = chapter.scanlator,
uploadDate = chapter.uploadDate,
branch = chapter.branch,
source = chapter.source.name,
index = index,
)
}
// Other
fun SortOrder(name: String, fallback: SortOrder): SortOrder = runCatching {
@@ -74,3 +115,7 @@ fun SortOrder(name: String, fallback: SortOrder): SortOrder = runCatching {
fun MangaState(name: String): MangaState? = runCatching {
MangaState.valueOf(name)
}.getOrNull()
fun ContentRating(name: String?): ContentRating? = runCatching {
ContentRating.valueOf(name ?: return@runCatching null)
}.getOrNull()

View File

@@ -10,14 +10,15 @@ data class MangaEntity(
@PrimaryKey(autoGenerate = false)
@ColumnInfo(name = "manga_id") val id: Long,
@ColumnInfo(name = "title") val title: String,
@ColumnInfo(name = "alt_title") val altTitle: String?,
@ColumnInfo(name = "alt_title") val altTitles: String?,
@ColumnInfo(name = "url") val url: String,
@ColumnInfo(name = "public_url") val publicUrl: String,
@ColumnInfo(name = "rating") val rating: Float, // normalized value [0..1] or -1
@ColumnInfo(name = "nsfw") val isNsfw: Boolean,
@ColumnInfo(name = "content_rating") val contentRating: String?,
@ColumnInfo(name = "cover_url") val coverUrl: String,
@ColumnInfo(name = "large_cover_url") val largeCoverUrl: String?,
@ColumnInfo(name = "state") val state: String?,
@ColumnInfo(name = "author") val author: String?,
@ColumnInfo(name = "author") val authors: String?,
@ColumnInfo(name = "source") val source: String,
)

View File

@@ -14,4 +14,7 @@ data class MangaSourceEntity(
val source: String,
@ColumnInfo(name = "enabled") val isEnabled: Boolean,
@ColumnInfo(name = "sort_key", index = true) val sortKey: Int,
@ColumnInfo(name = "added_in") val addedIn: Int,
@ColumnInfo(name = "used_at") val lastUsedAt: Long,
@ColumnInfo(name = "pinned") val isPinned: Boolean,
)

View File

@@ -4,7 +4,7 @@ import android.content.Context
import androidx.preference.PreferenceManager
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.model.MangaParserSource
class Migration16To17(context: Context) : Migration(16, 17) {
@@ -15,11 +15,8 @@ class Migration16To17(context: Context) : Migration(16, 17) {
db.execSQL("CREATE INDEX `index_sources_sort_key` ON `sources` (`sort_key`)")
val hiddenSources = prefs.getStringSet("sources_hidden", null).orEmpty()
val order = prefs.getString("sources_order_2", null)?.split('|').orEmpty()
val sources = MangaSource.entries
val sources = MangaParserSource.entries
for (source in sources) {
if (source == MangaSource.LOCAL) {
continue
}
val name = source.name
val isHidden = name in hiddenSources
var sortKey = order.indexOf(name)

View File

@@ -0,0 +1,12 @@
package org.koitharu.kotatsu.core.db.migrations
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
class Migration20To21 : Migration(20, 21) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE tracks ADD COLUMN `last_error` TEXT DEFAULT NULL")
db.execSQL("ALTER TABLE sources ADD COLUMN `added_in` INTEGER NOT NULL DEFAULT 0")
}
}

View File

@@ -0,0 +1,12 @@
package org.koitharu.kotatsu.core.db.migrations
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
class Migration21To22 : Migration(21, 22) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE sources ADD COLUMN `used_at` INTEGER NOT NULL DEFAULT 0")
db.execSQL("ALTER TABLE sources ADD COLUMN `pinned` INTEGER NOT NULL DEFAULT 0")
}
}

View File

@@ -0,0 +1,11 @@
package org.koitharu.kotatsu.core.db.migrations
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
class Migration22To23 : Migration(22, 23) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("CREATE TABLE IF NOT EXISTS `local_index` (`manga_id` INTEGER NOT NULL, `path` TEXT NOT NULL, PRIMARY KEY(`manga_id`), FOREIGN KEY(`manga_id`) REFERENCES `manga`(`manga_id`) ON UPDATE NO ACTION ON DELETE CASCADE )")
}
}

View File

@@ -0,0 +1,11 @@
package org.koitharu.kotatsu.core.db.migrations
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
class Migration23To24 : Migration(23, 24) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("CREATE TABLE IF NOT EXISTS `chapters` (`chapter_id` INTEGER NOT NULL, `manga_id` INTEGER NOT NULL, `name` TEXT NOT NULL, `number` REAL NOT NULL, `volume` INTEGER NOT NULL, `url` TEXT NOT NULL, `scanlator` TEXT, `upload_date` INTEGER NOT NULL, `branch` TEXT, `source` TEXT NOT NULL, `index` INTEGER NOT NULL, PRIMARY KEY(`manga_id`, `chapter_id`), FOREIGN KEY(`manga_id`) REFERENCES `manga`(`manga_id`) ON UPDATE NO ACTION ON DELETE CASCADE )")
}
}

View File

@@ -0,0 +1,11 @@
package org.koitharu.kotatsu.core.db.migrations
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
class Migration24To23 : Migration(24, 23) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("DROP TABLE IF EXISTS `chapters`")
}
}

View File

@@ -0,0 +1,12 @@
package org.koitharu.kotatsu.core.db.migrations
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
class Migration24To25 : Migration(24, 25) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE manga ADD COLUMN content_rating TEXT DEFAULT NULL")
db.execSQL("UPDATE manga SET content_rating = 'ADULT' WHERE nsfw = 1")
}
}

View File

@@ -1,3 +1,5 @@
package org.koitharu.kotatsu.core.exceptions
class CaughtException(cause: Throwable, override val message: String?) : RuntimeException(cause)
class CaughtException(
override val cause: Throwable
) : RuntimeException("${cause.javaClass.simpleName}(${cause.message})", cause)

View File

@@ -1,6 +1,5 @@
package org.koitharu.kotatsu.core.exceptions
import okhttp3.Headers
import okio.IOException
import org.koitharu.kotatsu.parsers.model.MangaSource

View File

@@ -0,0 +1,6 @@
package org.koitharu.kotatsu.core.exceptions
class IncompatiblePluginException(
val name: String?,
cause: Throwable?,
) : RuntimeException(cause)

View File

@@ -3,5 +3,5 @@ package org.koitharu.kotatsu.core.exceptions
import okio.IOException
class NoDataReceivedException(
private val url: String,
val url: String,
) : IOException("No data has been received from $url")

View File

@@ -0,0 +1,5 @@
package org.koitharu.kotatsu.core.exceptions
import java.net.ProtocolException
class ProxyConfigException : ProtocolException("Wrong proxy configuration")

View File

@@ -1,13 +0,0 @@
package org.koitharu.kotatsu.core.exceptions
import okio.IOException
import java.time.Instant
import java.time.temporal.ChronoUnit
class TooManyRequestExceptions(
val url: String,
val retryAt: Instant?,
) : IOException() {
val retryAfter: Long
get() = retryAt?.until(Instant.now(), ChronoUnit.MILLIS) ?: 0
}

View File

@@ -0,0 +1,5 @@
package org.koitharu.kotatsu.core.exceptions
import okio.IOException
class WrapperIOException(override val cause: Exception) : IOException(cause)

View File

@@ -6,8 +6,8 @@ import androidx.core.util.Consumer
import androidx.fragment.app.Fragment
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.ui.dialog.ErrorDetailsDialog
import org.koitharu.kotatsu.core.util.ext.getDisplayMessage
import org.koitharu.kotatsu.core.util.ext.isSerializable
import org.koitharu.kotatsu.parsers.exception.ParseException
class DialogErrorObserver(
@@ -31,10 +31,10 @@ class DialogErrorObserver(
if (canResolve(value)) {
dialogBuilder.setPositiveButton(ExceptionResolver.getResolveStringId(value), listener)
} else if (value is ParseException) {
val fm = fragmentManager
if (fm != null) {
val router = router()
if (router != null && value.isSerializable()) {
dialogBuilder.setPositiveButton(R.string.details) { _, _ ->
ErrorDetailsDialog.show(fm, value, value.url)
router.showErrorDialog(value)
}
}
}

View File

@@ -4,6 +4,7 @@ import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.core.util.Consumer
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.LifecycleCoroutineScope
import androidx.lifecycle.LifecycleOwner
@@ -11,6 +12,7 @@ import androidx.lifecycle.coroutineScope
import kotlinx.coroutines.flow.FlowCollector
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import org.koitharu.kotatsu.core.nav.router
import org.koitharu.kotatsu.core.util.ext.findActivity
import org.koitharu.kotatsu.core.util.ext.viewLifecycleScope
@@ -33,6 +35,8 @@ abstract class ErrorObserver(
return resolver != null && ExceptionResolver.canResolve(error)
}
protected fun router() = fragment?.router ?: (activity as? FragmentActivity)?.router
private fun isAlive(): Boolean {
return when {
fragment != null -> fragment.view != null
@@ -44,7 +48,7 @@ abstract class ErrorObserver(
protected fun resolve(error: Throwable) {
if (isAlive()) {
lifecycleScope.launch {
val isResolved = resolver?.resolve(error) ?: false
val isResolved = resolver?.resolve(error) == true
if (isActive) {
onResolved?.accept(isResolved)
}

View File

@@ -1,61 +1,72 @@
package org.koitharu.kotatsu.core.exceptions.resolve
import androidx.activity.result.ActivityResultCallback
import androidx.activity.result.ActivityResultLauncher
import android.content.Context
import android.widget.Toast
import androidx.activity.result.ActivityResultCaller
import androidx.annotation.StringRes
import androidx.collection.ArrayMap
import androidx.collection.MutableScatterMap
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.FragmentManager
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.alternatives.ui.AlternativesActivity
import org.koitharu.kotatsu.browser.BrowserActivity
import org.koitharu.kotatsu.browser.cloudflare.CloudFlareActivity
import org.koitharu.kotatsu.core.exceptions.CloudFlareProtectedException
import org.koitharu.kotatsu.core.exceptions.ProxyConfigException
import org.koitharu.kotatsu.core.exceptions.UnsupportedSourceException
import org.koitharu.kotatsu.core.ui.dialog.ErrorDetailsDialog
import org.koitharu.kotatsu.core.util.TaggedActivityResult
import org.koitharu.kotatsu.core.nav.AppRouter
import org.koitharu.kotatsu.core.nav.router
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.ui.dialog.buildAlertDialog
import org.koitharu.kotatsu.core.util.ext.restartApplication
import org.koitharu.kotatsu.parsers.exception.AuthRequiredException
import org.koitharu.kotatsu.parsers.exception.NotFoundException
import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.scrobbling.common.domain.ScrobblerAuthRequiredException
import org.koitharu.kotatsu.scrobbling.common.ui.ScrobblerAuthHelper
import org.koitharu.kotatsu.settings.sources.auth.SourceAuthActivity
import java.security.cert.CertPathValidatorException
import javax.inject.Provider
import javax.net.ssl.SSLException
import kotlin.coroutines.Continuation
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
class ExceptionResolver : ActivityResultCallback<TaggedActivityResult> {
class ExceptionResolver @AssistedInject constructor(
@Assisted private val host: Host,
private val settings: AppSettings,
private val scrobblerAuthHelperProvider: Provider<ScrobblerAuthHelper>,
) {
private val continuations = MutableScatterMap<String, Continuation<Boolean>>(1)
private val continuations = ArrayMap<String, Continuation<Boolean>>(1)
private val activity: FragmentActivity?
private val fragment: Fragment?
private val sourceAuthContract: ActivityResultLauncher<MangaSource>
private val cloudflareContract: ActivityResultLauncher<CloudFlareProtectedException>
constructor(activity: FragmentActivity) {
this.activity = activity
fragment = null
sourceAuthContract = activity.registerForActivityResult(SourceAuthActivity.Contract(), this)
cloudflareContract = activity.registerForActivityResult(CloudFlareActivity.Contract(), this)
private val sourceAuthContract = host.registerForActivityResult(SourceAuthActivity.Contract()) {
handleActivityResult(SourceAuthActivity.TAG, it)
}
private val cloudflareContract = host.registerForActivityResult(CloudFlareActivity.Contract()) {
handleActivityResult(CloudFlareActivity.TAG, it)
}
constructor(fragment: Fragment) {
this.fragment = fragment
activity = null
sourceAuthContract = fragment.registerForActivityResult(SourceAuthActivity.Contract(), this)
cloudflareContract = fragment.registerForActivityResult(CloudFlareActivity.Contract(), this)
}
override fun onActivityResult(result: TaggedActivityResult) {
continuations.remove(result.tag)?.resume(result.isSuccess)
}
fun showDetails(e: Throwable, url: String?) {
ErrorDetailsDialog.show(getFragmentManager(), e, url)
fun showErrorDetails(e: Throwable, url: String? = null) {
host.router()?.showErrorDialog(e, url)
}
suspend fun resolve(e: Throwable): Boolean = when (e) {
is CloudFlareProtectedException -> resolveCF(e)
is AuthRequiredException -> resolveAuthException(e.source)
is SSLException,
is CertPathValidatorException -> {
showSslErrorDialog()
false
}
is ProxyConfigException -> {
host.router()?.openProxySettings()
false
}
is NotFoundException -> {
openInBrowser(e.url)
false
@@ -66,6 +77,18 @@ class ExceptionResolver : ActivityResultCallback<TaggedActivityResult> {
false
}
is ScrobblerAuthRequiredException -> {
val authHelper = scrobblerAuthHelperProvider.get()
if (authHelper.isAuthorized(e.scrobbler)) {
true
} else {
host.withContext {
authHelper.startAuth(this, e.scrobbler).onFailure(::showErrorDetails)
}
false
}
}
else -> false
}
@@ -80,25 +103,73 @@ class ExceptionResolver : ActivityResultCallback<TaggedActivityResult> {
}
private fun openInBrowser(url: String) {
val context = activity ?: fragment?.activity ?: return
context.startActivity(BrowserActivity.newIntent(context, url, null, null))
host.router()?.openBrowser(url, null, null)
}
private fun openAlternatives(manga: Manga) {
val context = activity ?: fragment?.activity ?: return
context.startActivity(AlternativesActivity.newIntent(context, manga))
host.router()?.openAlternatives(manga)
}
private fun getFragmentManager() = checkNotNull(fragment?.childFragmentManager ?: activity?.supportFragmentManager)
private fun handleActivityResult(tag: String, result: Boolean) {
continuations.remove(tag)?.resume(result)
}
private fun showSslErrorDialog() {
val ctx = host.getContext() ?: return
if (settings.isSSLBypassEnabled) {
Toast.makeText(ctx, R.string.operation_not_supported, Toast.LENGTH_SHORT).show()
return
}
buildAlertDialog(ctx) {
setTitle(R.string.ignore_ssl_errors)
setMessage(R.string.ignore_ssl_errors_summary)
setPositiveButton(R.string.apply) { _, _ ->
settings.isSSLBypassEnabled = true
Toast.makeText(ctx, R.string.settings_apply_restart_required, Toast.LENGTH_LONG).show()
ctx.restartApplication()
}
setNegativeButton(android.R.string.cancel, null)
}.show()
}
private inline fun Host.withContext(block: Context.() -> Unit) {
getContext()?.apply(block)
}
private fun Host.router(): AppRouter? = when (this) {
is FragmentActivity -> router
is Fragment -> router
else -> null
}
interface Host : ActivityResultCaller {
fun getChildFragmentManager(): FragmentManager
fun getContext(): Context?
}
@AssistedFactory
interface Factory {
fun create(host: Host): ExceptionResolver
}
companion object {
@StringRes
fun getResolveStringId(e: Throwable) = when (e) {
is CloudFlareProtectedException -> R.string.captcha_solve
is ScrobblerAuthRequiredException,
is AuthRequiredException -> R.string.sign_in
is NotFoundException -> if (e.url.isNotEmpty()) R.string.open_in_browser else 0
is UnsupportedSourceException -> if (e.manga != null) R.string.alternatives else 0
is SSLException,
is CertPathValidatorException -> R.string.fix
is ProxyConfigException -> R.string.settings
else -> 0
}

View File

@@ -5,8 +5,8 @@ import androidx.core.util.Consumer
import androidx.fragment.app.Fragment
import com.google.android.material.snackbar.Snackbar
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.ui.dialog.ErrorDetailsDialog
import org.koitharu.kotatsu.core.util.ext.getDisplayMessage
import org.koitharu.kotatsu.core.util.ext.isSerializable
import org.koitharu.kotatsu.main.ui.owners.BottomNavOwner
import org.koitharu.kotatsu.parsers.exception.ParseException
@@ -32,10 +32,10 @@ class SnackbarErrorObserver(
resolve(value)
}
} else if (value is ParseException) {
val fm = fragmentManager
if (fm != null) {
val router = router()
if (router != null && value.isSerializable()) {
snackbar.setAction(R.string.details) {
ErrorDetailsDialog.show(fm, value, value.url)
router.showErrorDialog(value)
}
}
}

View File

@@ -1,20 +1,31 @@
package org.koitharu.kotatsu.core.fs
import android.os.Build
import org.koitharu.kotatsu.core.util.iterator.CloseableIterator
import androidx.annotation.RequiresApi
import org.koitharu.kotatsu.core.util.CloseableSequence
import org.koitharu.kotatsu.core.util.iterator.MappingIterator
import java.io.File
import java.nio.file.Files
import java.nio.file.Path
class FileSequence(private val dir: File) : Sequence<File> {
sealed interface FileSequence : CloseableSequence<File> {
override fun iterator(): Iterator<File> {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val stream = Files.newDirectoryStream(dir.toPath())
CloseableIterator(MappingIterator(stream.iterator(), Path::toFile), stream)
} else {
dir.listFiles().orEmpty().iterator()
}
@RequiresApi(Build.VERSION_CODES.O)
class StreamImpl(dir: File) : FileSequence {
private val stream = Files.newDirectoryStream(dir.toPath())
override fun iterator(): Iterator<File> = MappingIterator(stream.iterator(), Path::toFile)
override fun close() = stream.close()
}
class ListImpl(dir: File) : FileSequence {
private val list = dir.listFiles().orEmpty()
override fun iterator(): Iterator<File> = list.iterator()
override fun close() = Unit
}
}

View File

@@ -1,5 +1,7 @@
package org.koitharu.kotatsu.core.github
import android.content.Context
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
@@ -9,6 +11,7 @@ import okhttp3.Request
import org.json.JSONArray
import org.json.JSONObject
import org.koitharu.kotatsu.BuildConfig
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.network.BaseHttpClient
import org.koitharu.kotatsu.core.os.AppValidator
import org.koitharu.kotatsu.core.prefs.AppSettings
@@ -18,26 +21,37 @@ import org.koitharu.kotatsu.parsers.util.await
import org.koitharu.kotatsu.parsers.util.json.mapJSONNotNull
import org.koitharu.kotatsu.parsers.util.parseJsonArray
import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
import org.koitharu.kotatsu.parsers.util.suspendlazy.getOrNull
import javax.inject.Inject
import javax.inject.Singleton
private const val CONTENT_TYPE_APK = "application/vnd.android.package-archive"
private const val BUILD_TYPE_RELEASE = "release"
@Singleton
class AppUpdateRepository @Inject constructor(
private val appValidator: AppValidator,
private val settings: AppSettings,
@BaseHttpClient private val okHttp: OkHttpClient,
@ApplicationContext context: Context,
) {
private val availableUpdate = MutableStateFlow<AppVersion?>(null)
private val releasesUrl = buildString {
append("https://api.github.com/repos/")
append(context.getString(R.string.github_updates_repo))
append("/releases?page=1&per_page=10")
}
val isUpdateAvailable: Boolean
get() = availableUpdate.value != null
fun observeAvailableUpdate() = availableUpdate.asStateFlow()
suspend fun getAvailableVersions(): List<AppVersion> {
val request = Request.Builder()
.get()
.url("https://api.github.com/repos/KotatsuApp/Kotatsu/releases?page=1&per_page=10")
.url(releasesUrl)
val jsonArray = okHttp.newCall(request.build()).await().parseJsonArray()
return jsonArray.mapJSONNotNull { json ->
val asset = json.optJSONArray("assets")?.find { jo ->
@@ -74,8 +88,9 @@ class AppUpdateRepository @Inject constructor(
}.getOrNull()
}
fun isUpdateSupported(): Boolean {
return BuildConfig.DEBUG || appValidator.isOriginalApp
@Suppress("KotlinConstantConditions")
suspend fun isUpdateSupported(): Boolean {
return BuildConfig.BUILD_TYPE != BUILD_TYPE_RELEASE || appValidator.isOriginalApp.getOrNull() == true
}
suspend fun getCurrentVersionChangelog(): String? {

View File

@@ -1,6 +1,7 @@
package org.koitharu.kotatsu.core.github
import java.util.*
import org.koitharu.kotatsu.parsers.util.digits
import java.util.Locale
data class VersionId(
val major: Int,
@@ -43,6 +44,16 @@ val VersionId.isStable: Boolean
get() = variantType.isEmpty()
fun VersionId(versionName: String): VersionId {
if (versionName.startsWith('n', ignoreCase = true)) {
// Nightly build
return VersionId(
major = 0,
minor = 0,
build = versionName.digits().toIntOrNull() ?: 0,
variantType = "n",
variantNumber = 0,
)
}
val parts = versionName.substringBeforeLast('-').split('.')
val variant = versionName.substringAfterLast('-', "")
return VersionId(

View File

@@ -0,0 +1,66 @@
package org.koitharu.kotatsu.core.image
import android.graphics.Bitmap
import coil3.ImageLoader
import coil3.asImage
import coil3.decode.DecodeResult
import coil3.decode.Decoder
import coil3.decode.ImageSource
import coil3.fetch.SourceFetchResult
import coil3.request.Options
import com.davemorrissey.labs.subscaleview.decoder.ImageDecodeException
import kotlinx.coroutines.runInterruptible
import org.aomedia.avif.android.AvifDecoder
import org.aomedia.avif.android.AvifDecoder.Info
import org.koitharu.kotatsu.core.util.ext.toByteBuffer
class AvifImageDecoder(
private val source: ImageSource,
private val options: Options,
) : Decoder {
override suspend fun decode(): DecodeResult = runInterruptible {
val bytes = source.source().use {
it.inputStream().toByteBuffer()
}
val info = Info()
if (!AvifDecoder.getInfo(bytes, bytes.remaining(), info)) {
throw ImageDecodeException(
null,
"avif",
"Requested to decode byte buffer which cannot be handled by AvifDecoder",
)
}
val config = if (info.depth == 8 || info.alphaPresent) Bitmap.Config.ARGB_8888 else Bitmap.Config.RGB_565
val bitmap = Bitmap.createBitmap(info.width, info.height, config)
if (!AvifDecoder.decode(bytes, bytes.remaining(), bitmap)) {
bitmap.recycle()
throw ImageDecodeException(null, "avif")
}
DecodeResult(
image = bitmap.asImage(),
isSampled = false,
)
}
class Factory : Decoder.Factory {
override fun create(
result: SourceFetchResult,
options: Options,
imageLoader: ImageLoader
): Decoder? = if (isApplicable(result)) {
AvifImageDecoder(result.source, options)
} else {
null
}
override fun equals(other: Any?) = other is Factory
override fun hashCode() = javaClass.hashCode()
private fun isApplicable(result: SourceFetchResult): Boolean {
return result.mimeType == "image/avif"
}
}
}

View File

@@ -0,0 +1,102 @@
package org.koitharu.kotatsu.core.image
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.ImageDecoder
import android.os.Build
import androidx.annotation.RequiresApi
import com.davemorrissey.labs.subscaleview.decoder.ImageDecodeException
import org.aomedia.avif.android.AvifDecoder
import org.aomedia.avif.android.AvifDecoder.Info
import org.jetbrains.annotations.Blocking
import org.koitharu.kotatsu.core.util.MimeTypes
import org.koitharu.kotatsu.core.util.ext.MimeType
import org.koitharu.kotatsu.core.util.ext.toByteBuffer
import org.koitharu.kotatsu.core.util.ext.toMimeTypeOrNull
import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
import java.io.File
import java.io.InputStream
import java.nio.ByteBuffer
object BitmapDecoderCompat {
private const val FORMAT_AVIF = "avif"
@Blocking
fun decode(file: File): Bitmap = when (val format = probeMimeType(file)?.subtype) {
FORMAT_AVIF -> file.inputStream().use { decodeAvif(it.toByteBuffer()) }
else -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
ImageDecoder.decodeBitmap(ImageDecoder.createSource(file))
} else {
checkBitmapNotNull(BitmapFactory.decodeFile(file.absolutePath), format)
}
}
@Blocking
fun decode(stream: InputStream, type: MimeType?, isMutable: Boolean = false): Bitmap {
val format = type?.subtype
if (format == FORMAT_AVIF) {
return decodeAvif(stream.toByteBuffer())
}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
val opts = BitmapFactory.Options()
opts.inMutable = isMutable
return checkBitmapNotNull(BitmapFactory.decodeStream(stream, null, opts), format)
}
val byteBuffer = stream.toByteBuffer()
return if (AvifDecoder.isAvifImage(byteBuffer)) {
decodeAvif(byteBuffer)
} else {
ImageDecoder.decodeBitmap(ImageDecoder.createSource(byteBuffer), DecoderConfigListener(isMutable))
}
}
@Blocking
fun probeMimeType(file: File): MimeType? {
return MimeTypes.probeMimeType(file) ?: detectBitmapType(file)
}
@Blocking
private fun detectBitmapType(file: File): MimeType? = runCatchingCancellable {
val options = BitmapFactory.Options().apply {
inJustDecodeBounds = true
}
BitmapFactory.decodeFile(file.path, options)?.recycle()
return options.outMimeType?.toMimeTypeOrNull()
}.getOrNull()
private fun checkBitmapNotNull(bitmap: Bitmap?, format: String?): Bitmap =
bitmap ?: throw ImageDecodeException(null, format)
private fun decodeAvif(bytes: ByteBuffer): Bitmap {
val info = Info()
if (!AvifDecoder.getInfo(bytes, bytes.remaining(), info)) {
throw ImageDecodeException(
null,
FORMAT_AVIF,
"Requested to decode byte buffer which cannot be handled by AvifDecoder",
)
}
val config = if (info.depth == 8 || info.alphaPresent) Bitmap.Config.ARGB_8888 else Bitmap.Config.RGB_565
val bitmap = Bitmap.createBitmap(info.width, info.height, config)
if (!AvifDecoder.decode(bytes, bytes.remaining(), bitmap)) {
bitmap.recycle()
throw ImageDecodeException(null, FORMAT_AVIF)
}
return bitmap
}
@RequiresApi(Build.VERSION_CODES.P)
private class DecoderConfigListener(
private val isMutable: Boolean,
) : ImageDecoder.OnHeaderDecodedListener {
override fun onHeaderDecoded(
decoder: ImageDecoder,
info: ImageDecoder.ImageInfo,
source: ImageDecoder.Source
) {
decoder.isMutableRequired = isMutable
}
}
}

View File

@@ -0,0 +1,49 @@
package org.koitharu.kotatsu.core.image
import android.net.Uri
import coil3.ImageLoader
import coil3.decode.DataSource
import coil3.decode.ImageSource
import coil3.fetch.Fetcher
import coil3.fetch.SourceFetchResult
import coil3.request.Options
import coil3.toAndroidUri
import kotlinx.coroutines.runInterruptible
import okio.Path.Companion.toPath
import okio.openZip
import org.koitharu.kotatsu.core.util.MimeTypes
import org.koitharu.kotatsu.core.util.ext.isZipUri
import coil3.Uri as CoilUri
class CbzFetcher(
private val uri: Uri,
private val options: Options,
) : Fetcher {
override suspend fun fetch() = runInterruptible {
val filePath = uri.schemeSpecificPart.toPath()
val entryName = requireNotNull(uri.fragment)
val fs = options.fileSystem.openZip(filePath)
SourceFetchResult(
source = ImageSource(entryName.toPath(), fs, closeable = fs),
mimeType = MimeTypes.getMimeTypeFromExtension(entryName)?.toString(),
dataSource = DataSource.DISK,
)
}
class Factory : Fetcher.Factory<CoilUri> {
override fun create(
data: CoilUri,
options: Options,
imageLoader: ImageLoader
): Fetcher? {
val androidUri = data.toAndroidUri()
return if (androidUri.isZipUri()) {
CbzFetcher(androidUri, options)
} else {
null
}
}
}
}

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