diff --git a/app/src/main/java/org/koitharu/kotatsu/base/ui/BaseActivity.kt b/app/src/main/java/org/koitharu/kotatsu/base/ui/BaseActivity.kt index b695d0bb2..d032ec3e9 100644 --- a/app/src/main/java/org/koitharu/kotatsu/base/ui/BaseActivity.kt +++ b/app/src/main/java/org/koitharu/kotatsu/base/ui/BaseActivity.kt @@ -15,6 +15,8 @@ import androidx.core.content.ContextCompat import androidx.core.graphics.Insets import androidx.core.view.* import androidx.viewbinding.ViewBinding +import com.google.android.material.appbar.AppBarLayout +import com.google.android.material.appbar.AppBarLayout.LayoutParams.* import org.koin.android.ext.android.get import org.koitharu.kotatsu.BuildConfig import org.koitharu.kotatsu.R @@ -57,7 +59,13 @@ abstract class BaseActivity : AppCompatActivity(), OnApplyWindo this.binding = binding super.setContentView(binding.root) (binding.root.findViewById(R.id.toolbar) as? Toolbar)?.let(this::setSupportActionBar) + val params = (binding.root.findViewById(R.id.toolbar) as? Toolbar)?.layoutParams as AppBarLayout.LayoutParams ViewCompat.setOnApplyWindowInsetsListener(binding.root, this) + if (get().isToolbarHideWhenScrolling) { + params.scrollFlags = SCROLL_FLAG_SCROLL or SCROLL_FLAG_ENTER_ALWAYS + } else { + params.scrollFlags = SCROLL_FLAG_NO_SCROLL + } } override fun onApplyWindowInsets(v: View, insets: WindowInsetsCompat): WindowInsetsCompat { diff --git a/app/src/main/java/org/koitharu/kotatsu/core/model/MangaSource.kt b/app/src/main/java/org/koitharu/kotatsu/core/model/MangaSource.kt index ac67f280d..9d35e9df5 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/model/MangaSource.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/model/MangaSource.kt @@ -30,7 +30,8 @@ enum class MangaSource( // NUDEMOON("Nude-Moon", "ru", NudeMoonRepository::class.java), MANGAREAD("MangaRead", "en", MangareadRepository::class.java), REMANGA("Remanga", "ru", RemangaRepository::class.java), - HENTAILIB("HentaiLib", "ru", HentaiLibRepository::class.java); + HENTAILIB("HentaiLib", "ru", HentaiLibRepository::class.java), + ANIBEL("Anibel", "be", AnibelRepository::class.java); @get:Throws(NoBeanDefFoundException::class) @Deprecated("") diff --git a/app/src/main/java/org/koitharu/kotatsu/core/parser/ParserModule.kt b/app/src/main/java/org/koitharu/kotatsu/core/parser/ParserModule.kt index b5b3f431c..09ae0c43c 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/parser/ParserModule.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/parser/ParserModule.kt @@ -24,4 +24,5 @@ val parserModule factory(named(MangaSource.MANGAREAD)) { MangareadRepository(get()) } factory(named(MangaSource.REMANGA)) { RemangaRepository(get()) } factory(named(MangaSource.HENTAILIB)) { HentaiLibRepository(get()) } + factory(named(MangaSource.ANIBEL)) { AnibelRepository(get()) } } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/core/parser/site/AnibelRepository.kt b/app/src/main/java/org/koitharu/kotatsu/core/parser/site/AnibelRepository.kt new file mode 100644 index 000000000..318fcad02 --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/core/parser/site/AnibelRepository.kt @@ -0,0 +1,161 @@ +package org.koitharu.kotatsu.core.parser.site + +import org.koitharu.kotatsu.base.domain.MangaLoaderContext +import org.koitharu.kotatsu.core.exceptions.ParseException +import org.koitharu.kotatsu.core.model.* +import org.koitharu.kotatsu.core.parser.RemoteMangaRepository +import org.koitharu.kotatsu.utils.ext.* +import java.util.* + +class AnibelRepository(loaderContext: MangaLoaderContext) : RemoteMangaRepository(loaderContext) { + + override val source = MangaSource.ANIBEL + + override val defaultDomain = "anibel.net" + + override val sortOrders: Set = EnumSet.of( + SortOrder.NEWEST + ) + + override suspend fun getList( + offset: Int, + query: String?, + sortOrder: SortOrder?, + tag: MangaTag? + ): List { + if (!query.isNullOrEmpty()) { + return if (offset == 0) search(query) else emptyList() + } + val page = (offset / 12f).toIntUp().inc() + val link = when { + tag != null -> "/manga?genre[]=${tag.key}&page=$page".withDomain() + else -> "/manga?page=$page".withDomain() + } + val doc = loaderContext.httpGet(link).parseHtml() + val root = doc.body().select("div.manga-block") ?: throw ParseException("Cannot find root") + val items = root.select("div.anime-card") + return items.mapNotNull { card -> + val href = card.selectFirst("a").attr("href") + val status = card.select("tr")[2].text() + Manga( + id = generateUid(href), + title = card.selectFirst("h1.anime-card-title").text(), + coverUrl = card.selectFirst("img").attr("data-src").withDomain(), + altTitle = null, + author = null, + rating = Manga.NO_RATING, + url = href, + publicUrl = href.withDomain(), + tags = card.select("p.tupe.tag")?.select("a")?.mapNotNullToSet tags@{ x -> + MangaTag( + title = x.text(), + key = x.attr("href") ?: return@tags null, + source = source + ) + }.orEmpty(), + state = when (status) { + "выпускаецца" -> MangaState.ONGOING + "завершанае" -> MangaState.FINISHED + else -> null + }, + source = source + ) + } + } + + override suspend fun getDetails(manga: Manga): Manga { + val doc = loaderContext.httpGet(manga.publicUrl).parseHtml() + val root = doc.body().select("div.container") ?: throw ParseException("Cannot find root") + return manga.copy( + description = root.select("div.manga-block.grid-12")[2].select("p").text(), + chapters = root.select("ul.series").flatMap { table -> + table.select("li") + }.map { it.selectFirst("a") }.mapIndexedNotNull { i, a -> + val href = a.select("a").first().attr("href").toRelativeUrl(getDomain()) + MangaChapter( + id = generateUid(href), + name = a.select("a").first().text(), + number = i + 1, + url = href, + source = source + ) + } + ) + } + + override suspend fun getPages(chapter: MangaChapter): List { + val fullUrl = chapter.url.withDomain() + val doc = loaderContext.httpGet(fullUrl).parseHtml() + val scripts = doc.select("script") + for (script in scripts) { + val data = script.html() + val pos = data.indexOf("dataSource") + if (pos == -1) { + continue + } + val json = data.substring(pos).substringAfter('[').substringBefore(']') + val domain = getDomain() + return json.split(",").mapNotNull { + it.trim() + .removeSurrounding('"', '\'') + .toRelativeUrl(domain) + .takeUnless(String::isBlank) + }.map { url -> + MangaPage( + id = generateUid(url), + url = url, + referer = fullUrl, + source = source + ) + } + } + throw ParseException("Pages list not found at ${chapter.url.withDomain()}") + } + + override suspend fun getTags(): Set { + val doc = loaderContext.httpGet("https://${getDomain()}/manga").parseHtml() + val root = doc.body().select("div#tabs-genres").select("ul#list.ul-three-colums") + return root.select("p.menu-tags.tupe").mapToSet { a -> + MangaTag( + title = a.select("a").text().capitalize(Locale.ROOT), + key = a.select("a").attr("data-name"), + source = source + ) + } + } + + private suspend fun search(query: String): List { + val domain = getDomain() + val doc = loaderContext.httpGet("https://$domain/search?q=$query").parseHtml() + val root = doc.body().select("div.manga-block").select("article.tab-2") ?: throw ParseException("Cannot find root") + val items = root.select("div.anime-card") + return items.mapNotNull { card -> + val href = card.select("a").attr("href") + val status = card.select("tr")[2].text() + Manga( + id = generateUid(href), + title = card.selectFirst("h1.anime-card-title").text(), + coverUrl = card.selectFirst("img").attr("src").withDomain(), + altTitle = null, + author = null, + rating = Manga.NO_RATING, + url = href, + publicUrl = href.withDomain(), + tags = card.select("p.tupe.tag")?.select("a")?.mapNotNullToSet tags@{ x -> + MangaTag( + title = x.text(), + key = x.attr("href") ?: return@tags null, + source = source + ) + }.orEmpty(), + state = when (status) { + "выпускаецца" -> MangaState.ONGOING + "завершанае" -> MangaState.FINISHED + else -> null + }, + source = source + ) + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/core/parser/site/RemangaRepository.kt b/app/src/main/java/org/koitharu/kotatsu/core/parser/site/RemangaRepository.kt index 79d0d2581..f368db41e 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/parser/site/RemangaRepository.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/parser/site/RemangaRepository.kt @@ -18,10 +18,9 @@ class RemangaRepository(loaderContext: MangaLoaderContext) : RemoteMangaReposito override val defaultDomain = "remanga.org" override val sortOrders: Set = EnumSet.of( + SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.RATING, - SortOrder.ALPHABETICAL, - SortOrder.UPDATED, SortOrder.NEWEST ) @@ -162,7 +161,7 @@ class RemangaRepository(loaderContext: MangaLoaderContext) : RemoteMangaReposito SortOrder.POPULARITY -> "-rating" SortOrder.RATING -> "-votes" SortOrder.NEWEST -> "-id" - else -> "-rating" + else -> "-chapter_date" } private fun parsePage(jo: JSONObject, referer: String) = MangaPage( diff --git a/app/src/main/java/org/koitharu/kotatsu/core/prefs/AppSettings.kt b/app/src/main/java/org/koitharu/kotatsu/core/prefs/AppSettings.kt index 2c2839576..7fc34cc4e 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/prefs/AppSettings.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/prefs/AppSettings.kt @@ -41,6 +41,8 @@ class AppSettings private constructor(private val prefs: SharedPreferences) : val isAmoledTheme by BoolPreferenceDelegate(KEY_THEME_AMOLED, defaultValue = false) + val isToolbarHideWhenScrolling by BoolPreferenceDelegate(KEY_HIDE_TOOLBAR, defaultValue = true) + var gridSize by IntPreferenceDelegate(KEY_GRID_SIZE, defaultValue = 100) val readerPageSwitch by StringSetPreferenceDelegate( @@ -147,6 +149,7 @@ class AppSettings private constructor(private val prefs: SharedPreferences) : const val KEY_APP_SECTION = "app_section" const val KEY_THEME = "theme" const val KEY_THEME_AMOLED = "amoled_theme" + const val KEY_HIDE_TOOLBAR = "hide_toolbar" const val KEY_SOURCES_ORDER = "sources_order" const val KEY_SOURCES_HIDDEN = "sources_hidden" const val KEY_TRAFFIC_WARNING = "traffic_warning" diff --git a/app/src/main/java/org/koitharu/kotatsu/settings/MainSettingsFragment.kt b/app/src/main/java/org/koitharu/kotatsu/settings/MainSettingsFragment.kt index c1a4a104d..388059e99 100644 --- a/app/src/main/java/org/koitharu/kotatsu/settings/MainSettingsFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/settings/MainSettingsFragment.kt @@ -73,6 +73,9 @@ class MainSettingsFragment : BasePreferenceFragment(R.string.settings), AppSettings.KEY_THEME_AMOLED -> { findPreference(key)?.setSummary(R.string.restart_required) } + AppSettings.KEY_HIDE_TOOLBAR -> { + findPreference(key)?.setSummary(R.string.restart_required) + } AppSettings.KEY_LOCAL_STORAGE -> { findPreference(key)?.run { summary = settings.getStorageDir(context)?.getStorageName(context) diff --git a/app/src/main/res/color/stroke_color.xml b/app/src/main/res/color/stroke_color.xml new file mode 100644 index 000000000..daeffa86f --- /dev/null +++ b/app/src/main/res/color/stroke_color.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_manga_grid.xml b/app/src/main/res/layout/item_manga_grid.xml index ea10b632e..9727f3b88 100644 --- a/app/src/main/res/layout/item_manga_grid.xml +++ b/app/src/main/res/layout/item_manga_grid.xml @@ -2,8 +2,12 @@ + android:layout_height="wrap_content" + app:strokeWidth="1dp" + app:strokeColor="@color/stroke_color" + app:cardElevation="0dp"> + android:layout_height="@dimen/manga_list_details_item_height" + app:strokeWidth="1dp" + app:strokeColor="@color/stroke_color" + app:cardElevation="0dp"> Калі ласка, увядзіце пароль, які спатрэбіцца пры запуску прыкладання Пацвярджаць Пароль павінен змяшчаць не менш за 4 сімвалаў + Схаваць загаловак пры прагортцы \ No newline at end of file diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 36eddaf03..3765820e9 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -205,4 +205,5 @@ Введите пароль, который вам понадобится при запуске приложения Confirm Пароль должен содержать не менее 4 символов + Прятать заголовок при прокрутке \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 161e209c5..6f5e7da6f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -207,4 +207,5 @@ Enter password that will be required when the application starts Confirm Password must be at least 4 characters + Hide toolbar when scrolling \ No newline at end of file diff --git a/app/src/main/res/xml/pref_main.xml b/app/src/main/res/xml/pref_main.xml index 9d69e6c5f..a8613f904 100644 --- a/app/src/main/res/xml/pref_main.xml +++ b/app/src/main/res/xml/pref_main.xml @@ -20,6 +20,12 @@ android:title="@string/black_dark_theme" app:iconSpaceReserved="false" /> + +