Cleanup resources and code
This commit is contained in:
@@ -7,6 +7,16 @@ import android.view.View
|
||||
import android.view.WindowManager
|
||||
import androidx.viewbinding.ViewBinding
|
||||
|
||||
private const val SYSTEM_UI_FLAGS_SHOWN = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
|
||||
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or
|
||||
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
|
||||
private const val SYSTEM_UI_FLAGS_HIDDEN = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
|
||||
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or
|
||||
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or
|
||||
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or
|
||||
View.SYSTEM_UI_FLAG_FULLSCREEN or
|
||||
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
|
||||
|
||||
abstract class BaseFullscreenActivity<B : ViewBinding> : BaseActivity<B>(),
|
||||
View.OnSystemUiVisibilityChangeListener {
|
||||
@@ -25,6 +35,7 @@ abstract class BaseFullscreenActivity<B : ViewBinding> : BaseActivity<B>(),
|
||||
showSystemUI()
|
||||
}
|
||||
|
||||
@Deprecated("Deprecated in Java")
|
||||
final override fun onSystemUiVisibilityChange(visibility: Int) {
|
||||
onSystemUiVisibilityChanged(visibility and View.SYSTEM_UI_FLAG_FULLSCREEN == 0)
|
||||
}
|
||||
@@ -39,19 +50,4 @@ abstract class BaseFullscreenActivity<B : ViewBinding> : BaseActivity<B>(),
|
||||
}
|
||||
|
||||
protected open fun onSystemUiVisibilityChanged(isVisible: Boolean) = Unit
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
private companion object {
|
||||
|
||||
const val SYSTEM_UI_FLAGS_SHOWN = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
|
||||
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or
|
||||
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
|
||||
const val SYSTEM_UI_FLAGS_HIDDEN = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
|
||||
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or
|
||||
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or
|
||||
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or
|
||||
View.SYSTEM_UI_FLAG_FULLSCREEN or
|
||||
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
|
||||
}
|
||||
}
|
||||
@@ -2,14 +2,21 @@ package org.koitharu.kotatsu.base.ui.widgets
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.LinearLayout.HORIZONTAL
|
||||
import android.widget.LinearLayout.VERTICAL
|
||||
import androidx.annotation.AttrRes
|
||||
import androidx.core.content.withStyledAttributes
|
||||
import com.google.android.material.imageview.ShapeableImageView
|
||||
import org.koitharu.kotatsu.R
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
private const val ASPECT_RATIO_HEIGHT = 18f
|
||||
private const val ASPECT_RATIO_WIDTH = 13f
|
||||
|
||||
class CoverImageView @JvmOverloads constructor(
|
||||
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0,
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
@AttrRes defStyleAttr: Int = 0,
|
||||
) : ShapeableImageView(context, attrs, defStyleAttr) {
|
||||
|
||||
private var orientation: Int = HORIZONTAL
|
||||
@@ -33,13 +40,4 @@ class CoverImageView @JvmOverloads constructor(
|
||||
}
|
||||
setMeasuredDimension(desiredWidth, desiredHeight)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
const val VERTICAL = LinearLayout.VERTICAL
|
||||
const val HORIZONTAL = LinearLayout.HORIZONTAL
|
||||
|
||||
private const val ASPECT_RATIO_HEIGHT = 18f
|
||||
private const val ASPECT_RATIO_WIDTH = 13f
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,10 @@ import androidx.annotation.StringRes
|
||||
import androidx.core.view.postDelayed
|
||||
import org.koitharu.kotatsu.R
|
||||
|
||||
private const val ENTER_DURATION = 300L
|
||||
private const val EXIT_DURATION = 200L
|
||||
private const val SHORT_DURATION = 1_500L
|
||||
private const val LONG_DURATION = 2_750L
|
||||
/**
|
||||
* A custom snackbar implementation allowing more control over placement and entry/exit animations.
|
||||
*
|
||||
@@ -87,11 +91,4 @@ class FadingSnackbar @JvmOverloads constructor(
|
||||
dismissListener()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val ENTER_DURATION = 300L
|
||||
private const val EXIT_DURATION = 200L
|
||||
private const val SHORT_DURATION = 1_500L
|
||||
private const val LONG_DURATION = 2_750L
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ import androidx.core.view.updatePadding
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.base.ui.BaseActivity
|
||||
import org.koitharu.kotatsu.databinding.ActivityBrowserBinding
|
||||
import com.google.android.material.R as materialR
|
||||
|
||||
@SuppressLint("SetJavaScriptEnabled")
|
||||
class BrowserActivity : BaseActivity<ActivityBrowserBinding>(), BrowserCallback {
|
||||
@@ -23,7 +24,7 @@ class BrowserActivity : BaseActivity<ActivityBrowserBinding>(), BrowserCallback
|
||||
setContentView(ActivityBrowserBinding.inflate(layoutInflater))
|
||||
supportActionBar?.run {
|
||||
setDisplayHomeAsUpEnabled(true)
|
||||
setHomeAsUpIndicator(R.drawable.ic_cross)
|
||||
setHomeAsUpIndicator(materialR.drawable.abc_ic_clear_material)
|
||||
}
|
||||
with(binding.webView.settings) {
|
||||
javaScriptEnabled = true
|
||||
|
||||
@@ -6,6 +6,8 @@ import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||
import org.koitharu.kotatsu.core.network.AndroidCookieJar
|
||||
import org.koitharu.kotatsu.core.network.WebViewClientCompat
|
||||
|
||||
private const val CF_CLEARANCE = "cf_clearance"
|
||||
|
||||
class CloudFlareClient(
|
||||
private val cookieJar: AndroidCookieJar,
|
||||
private val callback: CloudFlareCallback,
|
||||
@@ -40,9 +42,4 @@ class CloudFlareClient(
|
||||
return cookieJar.loadForRequest(targetUrl.toHttpUrl())
|
||||
.find { it.name == name }?.value
|
||||
}
|
||||
|
||||
private companion object {
|
||||
|
||||
const val CF_CLEARANCE = "cf_clearance"
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,8 @@ import org.koitharu.kotatsu.favourites.data.FavouriteCategoryEntity
|
||||
import org.koitharu.kotatsu.favourites.data.FavouriteEntity
|
||||
import org.koitharu.kotatsu.history.data.HistoryEntity
|
||||
|
||||
private const val PAGE_SIZE = 10
|
||||
|
||||
class BackupRepository(private val db: MangaDatabase) {
|
||||
|
||||
suspend fun dumpHistory(): BackupEntry {
|
||||
@@ -65,7 +67,7 @@ class BackupRepository(private val db: MangaDatabase) {
|
||||
return entry
|
||||
}
|
||||
|
||||
suspend fun createIndex(): BackupEntry {
|
||||
fun createIndex(): BackupEntry {
|
||||
val entry = BackupEntry(BackupEntry.INDEX, JSONArray())
|
||||
val json = JSONObject()
|
||||
json.put("app_id", BuildConfig.APPLICATION_ID)
|
||||
@@ -129,9 +131,4 @@ class BackupRepository(private val db: MangaDatabase) {
|
||||
jo.put("created_at", createdAt)
|
||||
return jo
|
||||
}
|
||||
|
||||
private companion object {
|
||||
|
||||
const val PAGE_SIZE = 10
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,9 @@ import org.koitharu.kotatsu.core.exceptions.CloudFlareProtectedException
|
||||
import java.net.HttpURLConnection.HTTP_FORBIDDEN
|
||||
import java.net.HttpURLConnection.HTTP_UNAVAILABLE
|
||||
|
||||
private const val HEADER_SERVER = "Server"
|
||||
private const val SERVER_CLOUDFLARE = "cloudflare"
|
||||
|
||||
class CloudFlareInterceptor : Interceptor {
|
||||
|
||||
override fun intercept(chain: Interceptor.Chain): Response {
|
||||
@@ -19,10 +22,4 @@ class CloudFlareInterceptor : Interceptor {
|
||||
}
|
||||
return response
|
||||
}
|
||||
|
||||
private companion object {
|
||||
|
||||
private const val HEADER_SERVER = "Server"
|
||||
private const val SERVER_CLOUDFLARE = "cloudflare"
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,8 @@ import okio.Buffer
|
||||
import java.io.IOException
|
||||
import java.nio.charset.StandardCharsets
|
||||
|
||||
private const val TAG = "CURL"
|
||||
|
||||
class CurlLoggingInterceptor(
|
||||
private val extraCurlOptions: String? = null,
|
||||
) : Interceptor {
|
||||
@@ -51,9 +53,4 @@ class CurlLoggingInterceptor(
|
||||
Log.d(TAG, "╰--- (copy and paste the above line to a terminal)")
|
||||
return chain.proceed(request)
|
||||
}
|
||||
|
||||
private companion object {
|
||||
|
||||
const val TAG = "CURL"
|
||||
}
|
||||
}
|
||||
@@ -11,9 +11,16 @@ import org.koitharu.kotatsu.utils.ext.*
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
private const val PAGE_SIZE = 70
|
||||
private const val PAGE_SIZE_SEARCH = 50
|
||||
|
||||
abstract class GroupleRepository(loaderContext: MangaLoaderContext) :
|
||||
RemoteMangaRepository(loaderContext) {
|
||||
|
||||
private val headers = Headers.Builder()
|
||||
.add("User-Agent", "readmangafun")
|
||||
.build()
|
||||
|
||||
override val sortOrders: Set<SortOrder> = EnumSet.of(
|
||||
SortOrder.UPDATED,
|
||||
SortOrder.POPULARITY,
|
||||
@@ -41,14 +48,14 @@ abstract class GroupleRepository(loaderContext: MangaLoaderContext) :
|
||||
getSortKey(
|
||||
sortOrder
|
||||
)
|
||||
}&offset=${offset upBy PAGE_SIZE}", HEADER
|
||||
}&offset=${offset upBy PAGE_SIZE}", headers
|
||||
)
|
||||
tags.size == 1 -> loaderContext.httpGet(
|
||||
"https://$domain/list/genre/${tags.first().key}?sortType=${
|
||||
getSortKey(
|
||||
sortOrder
|
||||
)
|
||||
}&offset=${offset upBy PAGE_SIZE}", HEADER
|
||||
}&offset=${offset upBy PAGE_SIZE}", headers
|
||||
)
|
||||
offset > 0 -> return emptyList()
|
||||
else -> advancedSearch(domain, tags)
|
||||
@@ -106,7 +113,7 @@ abstract class GroupleRepository(loaderContext: MangaLoaderContext) :
|
||||
}
|
||||
|
||||
override suspend fun getDetails(manga: Manga): Manga {
|
||||
val doc = loaderContext.httpGet(manga.url.withDomain(), HEADER).parseHtml()
|
||||
val doc = loaderContext.httpGet(manga.url.withDomain(), headers).parseHtml()
|
||||
val root = doc.body().getElementById("mangaBox")?.selectFirst("div.leftContent")
|
||||
?: throw ParseException("Cannot find root")
|
||||
val dateFormat = SimpleDateFormat("dd.MM.yy", Locale.US)
|
||||
@@ -150,7 +157,7 @@ abstract class GroupleRepository(loaderContext: MangaLoaderContext) :
|
||||
}
|
||||
|
||||
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
|
||||
val doc = loaderContext.httpGet(chapter.url.withDomain() + "?mtr=1", HEADER).parseHtml()
|
||||
val doc = loaderContext.httpGet(chapter.url.withDomain() + "?mtr=1", headers).parseHtml()
|
||||
val scripts = doc.select("script")
|
||||
for (script in scripts) {
|
||||
val data = script.html()
|
||||
@@ -178,7 +185,7 @@ abstract class GroupleRepository(loaderContext: MangaLoaderContext) :
|
||||
}
|
||||
|
||||
override suspend fun getTags(): Set<MangaTag> {
|
||||
val doc = loaderContext.httpGet("https://${getDomain()}/list/genres/sort_name", HEADER).parseHtml()
|
||||
val doc = loaderContext.httpGet("https://${getDomain()}/list/genres/sort_name", headers).parseHtml()
|
||||
val root = doc.body().getElementById("mangaBox")?.selectFirst("div.leftContent")
|
||||
?.selectFirst("table.table") ?: parseFailed("Cannot find root")
|
||||
return root.select("a.element-link").mapToSet { a ->
|
||||
@@ -203,7 +210,7 @@ abstract class GroupleRepository(loaderContext: MangaLoaderContext) :
|
||||
private suspend fun advancedSearch(domain: String, tags: Set<MangaTag>): Response {
|
||||
val url = "https://$domain/search/advanced"
|
||||
// Step 1: map catalog genres names to advanced-search genres ids
|
||||
val tagsIndex = loaderContext.httpGet(url, HEADER).parseHtml()
|
||||
val tagsIndex = loaderContext.httpGet(url, headers).parseHtml()
|
||||
.body().selectFirst("form.search-form")
|
||||
?.select("div.form-group")
|
||||
?.get(1) ?: parseFailed("Genres filter element not found")
|
||||
@@ -236,14 +243,4 @@ abstract class GroupleRepository(loaderContext: MangaLoaderContext) :
|
||||
payload["+"] = "Искать".urlEncoded()
|
||||
return loaderContext.httpPost(url, payload)
|
||||
}
|
||||
|
||||
private companion object {
|
||||
|
||||
private const val PAGE_SIZE = 70
|
||||
private const val PAGE_SIZE_SEARCH = 50
|
||||
private val HEADER = Headers.Builder()
|
||||
.add("User-Agent", "readmangafun")
|
||||
.build()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
package org.koitharu.kotatsu.core.parser.site
|
||||
|
||||
import org.intellij.lang.annotations.Language
|
||||
import org.koitharu.kotatsu.base.domain.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.core.exceptions.ParseException
|
||||
import org.koitharu.kotatsu.core.model.*
|
||||
@@ -25,6 +24,8 @@ class MangaTownRepository(loaderContext: MangaLoaderContext) :
|
||||
SortOrder.UPDATED
|
||||
)
|
||||
|
||||
private val regexTag = Regex("[^\\-]+-[^\\-]+-[^\\-]+-[^\\-]+-[^\\-]+-[^\\-]+")
|
||||
|
||||
override suspend fun getList2(
|
||||
offset: Int,
|
||||
query: String?,
|
||||
@@ -217,11 +218,5 @@ class MangaTownRepository(loaderContext: MangaLoaderContext) :
|
||||
}
|
||||
}
|
||||
|
||||
private fun String.parseTagKey() = split('/').findLast { TAG_REGEX matches it }
|
||||
|
||||
private companion object {
|
||||
|
||||
@Language("RegExp")
|
||||
val TAG_REGEX = Regex("[^\\-]+-[^\\-]+-[^\\-]+-[^\\-]+-[^\\-]+-[^\\-]+")
|
||||
}
|
||||
private fun String.parseTagKey() = split('/').findLast { regexTag matches it }
|
||||
}
|
||||
@@ -10,6 +10,8 @@ import java.text.DateFormat
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
private const val PAGE_SIZE = 12
|
||||
|
||||
class MangareadRepository(
|
||||
loaderContext: MangaLoaderContext
|
||||
) : RemoteMangaRepository(loaderContext) {
|
||||
@@ -230,16 +232,11 @@ class MangareadRepository(
|
||||
}
|
||||
}
|
||||
|
||||
private companion object {
|
||||
|
||||
private const val PAGE_SIZE = 12
|
||||
|
||||
private fun createRequestTemplate() =
|
||||
"action=madara_load_more&page=1&template=madara-core%2Fcontent%2Fcontent-search&vars%5Bs%5D=&vars%5Borderby%5D=meta_value_num&vars%5Bpaged%5D=1&vars%5Btemplate%5D=search&vars%5Bmeta_query%5D%5B0%5D%5Brelation%5D=AND&vars%5Bmeta_query%5D%5Brelation%5D=OR&vars%5Bpost_type%5D=wp-manga&vars%5Bpost_status%5D=publish&vars%5Bmeta_key%5D=_latest_update&vars%5Border%5D=desc&vars%5Bmanga_archives_item_layout%5D=default"
|
||||
.split('&')
|
||||
.map {
|
||||
val pos = it.indexOf('=')
|
||||
it.substring(0, pos) to it.substring(pos + 1)
|
||||
}.toMutableMap()
|
||||
}
|
||||
private fun createRequestTemplate() =
|
||||
"action=madara_load_more&page=1&template=madara-core%2Fcontent%2Fcontent-search&vars%5Bs%5D=&vars%5Borderby%5D=meta_value_num&vars%5Bpaged%5D=1&vars%5Btemplate%5D=search&vars%5Bmeta_query%5D%5B0%5D%5Brelation%5D=AND&vars%5Bmeta_query%5D%5Brelation%5D=OR&vars%5Bpost_type%5D=wp-manga&vars%5Bpost_status%5D=publish&vars%5Bmeta_key%5D=_latest_update&vars%5Border%5D=desc&vars%5Bmanga_archives_item_layout%5D=default"
|
||||
.split('&')
|
||||
.map {
|
||||
val pos = it.indexOf('=')
|
||||
it.substring(0, pos) to it.substring(pos + 1)
|
||||
}.toMutableMap()
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ import org.koitharu.kotatsu.utils.ext.*
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
private const val PAGE_SIZE = 26
|
||||
|
||||
abstract class NineMangaRepository(
|
||||
loaderContext: MangaLoaderContext,
|
||||
override val source: MangaSource,
|
||||
@@ -20,6 +22,10 @@ abstract class NineMangaRepository(
|
||||
loaderContext.cookieJar.insertCookies(getDomain(), "ninemanga_template_desk=yes")
|
||||
}
|
||||
|
||||
private val headers = Headers.Builder()
|
||||
.add("Accept-Language", "en-US;q=0.7,en;q=0.3")
|
||||
.build()
|
||||
|
||||
override val sortOrders: Set<SortOrder> = EnumSet.of(
|
||||
SortOrder.POPULARITY,
|
||||
)
|
||||
@@ -55,7 +61,7 @@ abstract class NineMangaRepository(
|
||||
append(page)
|
||||
append(".html")
|
||||
}
|
||||
val doc = loaderContext.httpGet(url, PREDEFINED_HEADERS).parseHtml()
|
||||
val doc = loaderContext.httpGet(url, headers).parseHtml()
|
||||
val root = doc.body().selectFirst("ul.direlist")
|
||||
?: throw ParseException("Cannot find root")
|
||||
val baseHost = root.baseUri().toHttpUrl().host
|
||||
@@ -84,7 +90,7 @@ abstract class NineMangaRepository(
|
||||
override suspend fun getDetails(manga: Manga): Manga {
|
||||
val doc = loaderContext.httpGet(
|
||||
manga.url.withDomain() + "?waring=1",
|
||||
PREDEFINED_HEADERS
|
||||
headers
|
||||
).parseHtml()
|
||||
val root = doc.body().selectFirst("div.manga")
|
||||
?: throw ParseException("Cannot find root")
|
||||
@@ -122,7 +128,7 @@ abstract class NineMangaRepository(
|
||||
}
|
||||
|
||||
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
|
||||
val doc = loaderContext.httpGet(chapter.url.withDomain(), PREDEFINED_HEADERS).parseHtml()
|
||||
val doc = loaderContext.httpGet(chapter.url.withDomain(), headers).parseHtml()
|
||||
return doc.body().getElementById("page")?.select("option")?.map { option ->
|
||||
val url = option.attr("value")
|
||||
MangaPage(
|
||||
@@ -136,14 +142,14 @@ abstract class NineMangaRepository(
|
||||
}
|
||||
|
||||
override suspend fun getPageUrl(page: MangaPage): String {
|
||||
val doc = loaderContext.httpGet(page.url.withDomain(), PREDEFINED_HEADERS).parseHtml()
|
||||
val doc = loaderContext.httpGet(page.url.withDomain(), headers).parseHtml()
|
||||
val root = doc.body()
|
||||
return root.selectFirst("a.pic_download")?.absUrl("href")
|
||||
?: throw ParseException("Page image not found")
|
||||
}
|
||||
|
||||
override suspend fun getTags(): Set<MangaTag> {
|
||||
val doc = loaderContext.httpGet("https://${getDomain()}/search/?type=high", PREDEFINED_HEADERS)
|
||||
val doc = loaderContext.httpGet("https://${getDomain()}/search/?type=high", headers)
|
||||
.parseHtml()
|
||||
val root = doc.body().getElementById("search_form")
|
||||
return root?.select("li.cate_list")?.mapNotNullToSet { li ->
|
||||
@@ -242,13 +248,4 @@ abstract class NineMangaRepository(
|
||||
MangaSource.NINEMANGA_FR,
|
||||
"fr.ninemanga.com",
|
||||
)
|
||||
|
||||
private companion object {
|
||||
|
||||
const val PAGE_SIZE = 26
|
||||
|
||||
val PREDEFINED_HEADERS = Headers.Builder()
|
||||
.add("Accept-Language", "en-US;q=0.7,en;q=0.3")
|
||||
.build()
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,10 @@ import java.text.DateFormat
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
private const val PAGE_SIZE = 30
|
||||
private const val STATUS_ONGOING = 1
|
||||
private const val STATUS_FINISHED = 0
|
||||
|
||||
class RemangaRepository(loaderContext: MangaLoaderContext) : RemoteMangaRepository(loaderContext),
|
||||
MangaRepositoryAuthProvider {
|
||||
|
||||
@@ -29,6 +33,8 @@ class RemangaRepository(loaderContext: MangaLoaderContext) : RemoteMangaReposito
|
||||
SortOrder.NEWEST
|
||||
)
|
||||
|
||||
private val regexLastUrlPath = Regex("/[^/]+/?$")
|
||||
|
||||
override suspend fun getList2(
|
||||
offset: Int,
|
||||
query: String?,
|
||||
@@ -86,7 +92,7 @@ class RemangaRepository(loaderContext: MangaLoaderContext) : RemoteMangaReposito
|
||||
override suspend fun getDetails(manga: Manga): Manga {
|
||||
copyCookies()
|
||||
val domain = getDomain()
|
||||
val slug = manga.url.find(LAST_URL_PATH_REGEX)
|
||||
val slug = manga.url.find(regexLastUrlPath)
|
||||
?: throw ParseException("Cannot obtain slug from ${manga.url}")
|
||||
val data = loaderContext.httpGet(
|
||||
url = "https://api.$domain/api/titles/$slug/"
|
||||
@@ -228,14 +234,4 @@ class RemangaRepository(loaderContext: MangaLoaderContext) : RemoteMangaReposito
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private companion object {
|
||||
|
||||
const val PAGE_SIZE = 30
|
||||
|
||||
const val STATUS_ONGOING = 1
|
||||
const val STATUS_FINISHED = 0
|
||||
|
||||
val LAST_URL_PATH_REGEX = Regex("/[^/]+/?$")
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,10 @@ import org.koitharu.kotatsu.utils.ext.referer
|
||||
import org.koitharu.kotatsu.utils.ext.waitForNetwork
|
||||
import java.io.File
|
||||
|
||||
private const val MAX_DOWNLOAD_ATTEMPTS = 3
|
||||
private const val DOWNLOAD_ERROR_DELAY = 500L
|
||||
private const val TEMP_PAGE_FILE = "page.tmp"
|
||||
|
||||
class DownloadManager(
|
||||
private val context: Context,
|
||||
private val imageLoader: ImageLoader,
|
||||
@@ -228,11 +232,4 @@ class DownloadManager(
|
||||
override val cover: Drawable?,
|
||||
) : State
|
||||
}
|
||||
|
||||
private companion object {
|
||||
|
||||
private const val MAX_DOWNLOAD_ATTEMPTS = 3
|
||||
private const val DOWNLOAD_ERROR_DELAY = 500L
|
||||
private const val TEMP_PAGE_FILE = "page.tmp"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import org.koitharu.kotatsu.download.ui.DownloadsActivity
|
||||
import org.koitharu.kotatsu.utils.PendingIntentCompat
|
||||
import org.koitharu.kotatsu.utils.ext.format
|
||||
import org.koitharu.kotatsu.utils.ext.getDisplayMessage
|
||||
import com.google.android.material.R as materialR
|
||||
|
||||
class DownloadNotification(
|
||||
private val context: Context,
|
||||
@@ -26,7 +27,7 @@ class DownloadNotification(
|
||||
|
||||
private val builder = NotificationCompat.Builder(context, CHANNEL_ID)
|
||||
private val cancelAction = NotificationCompat.Action(
|
||||
R.drawable.ic_cross,
|
||||
materialR.drawable.material_ic_clear_black_24dp,
|
||||
context.getString(android.R.string.cancel),
|
||||
PendingIntent.getBroadcast(
|
||||
context,
|
||||
|
||||
@@ -8,6 +8,8 @@ import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.base.ui.dialog.TextInputDialog
|
||||
import org.koitharu.kotatsu.core.model.FavouriteCategory
|
||||
|
||||
private const val MAX_TITLE_LENGTH = 24
|
||||
|
||||
class CategoriesEditDelegate(
|
||||
private val context: Context,
|
||||
private val callback: CategoriesEditCallback
|
||||
@@ -69,9 +71,4 @@ class CategoriesEditDelegate(
|
||||
|
||||
fun onCreateCategory(name: String)
|
||||
}
|
||||
|
||||
private companion object {
|
||||
|
||||
const val MAX_TITLE_LENGTH = 24
|
||||
}
|
||||
}
|
||||
@@ -58,6 +58,9 @@ import org.koitharu.kotatsu.utils.ext.hideKeyboard
|
||||
import org.koitharu.kotatsu.utils.ext.measureHeight
|
||||
import org.koitharu.kotatsu.utils.ext.resolveDp
|
||||
|
||||
private const val TAG_PRIMARY = "primary"
|
||||
private const val TAG_SEARCH = "search"
|
||||
|
||||
class MainActivity : BaseActivity<ActivityMainBinding>(),
|
||||
NavigationView.OnNavigationItemSelectedListener, AppBarOwner,
|
||||
View.OnClickListener, View.OnFocusChangeListener, SearchSuggestionListener {
|
||||
@@ -372,10 +375,4 @@ class MainActivity : BaseActivity<ActivityMainBinding>(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private companion object {
|
||||
|
||||
const val TAG_PRIMARY = "primary"
|
||||
const val TAG_SEARCH = "search"
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,8 @@ import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||
import org.koitharu.kotatsu.utils.SingleLiveEvent
|
||||
import org.koitharu.kotatsu.utils.ext.md5
|
||||
|
||||
private const val PASSWORD_COMPARE_DELAY = 1_000L
|
||||
|
||||
class ProtectViewModel(
|
||||
private val settings: AppSettings,
|
||||
private val protectHelper: AppProtectHelper,
|
||||
@@ -33,9 +35,4 @@ class ProtectViewModel(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private companion object {
|
||||
|
||||
const val PASSWORD_COMPARE_DELAY = 1_000L
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,8 @@ import org.koitharu.kotatsu.reader.domain.PageLoader
|
||||
import org.koitharu.kotatsu.reader.ui.ReaderState
|
||||
import org.koitharu.kotatsu.reader.ui.ReaderViewModel
|
||||
|
||||
private const val KEY_STATE = "state"
|
||||
|
||||
abstract class BaseReader<B : ViewBinding> : BaseFragment<B>() {
|
||||
|
||||
protected val viewModel by sharedViewModel<ReaderViewModel>()
|
||||
@@ -57,9 +59,4 @@ abstract class BaseReader<B : ViewBinding> : BaseFragment<B>() {
|
||||
abstract fun getCurrentState(): ReaderState?
|
||||
|
||||
protected abstract fun onPagesChanged(pages: List<ReaderPage>, pendingState: ReaderState?)
|
||||
|
||||
private companion object {
|
||||
|
||||
const val KEY_STATE = "state"
|
||||
}
|
||||
}
|
||||
@@ -7,13 +7,19 @@ import android.util.AttributeSet
|
||||
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
|
||||
import org.koitharu.kotatsu.utils.ext.toIntUp
|
||||
|
||||
private const val SCROLL_UNKNOWN = -1
|
||||
|
||||
class WebtoonImageView @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attr: AttributeSet? = null,
|
||||
) : SubsamplingScaleImageView(context, attr) {
|
||||
|
||||
private val ct = PointF()
|
||||
private val displayHeight = (context as Activity).window.decorView.height
|
||||
private val displayHeight = if (context is Activity) {
|
||||
context.window.decorView.height
|
||||
} else {
|
||||
context.resources.displayMetrics.heightPixels
|
||||
}
|
||||
|
||||
private var scrollPos = 0
|
||||
private var scrollRange = SCROLL_UNKNOWN
|
||||
@@ -95,9 +101,4 @@ class WebtoonImageView @JvmOverloads constructor(
|
||||
val totalHeight = (sHeight * minScale).toIntUp()
|
||||
scrollRange = (totalHeight - height).coerceAtLeast(0)
|
||||
}
|
||||
|
||||
private companion object {
|
||||
|
||||
const val SCROLL_UNKNOWN = -1
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,12 @@ import org.koitharu.kotatsu.core.model.MangaSource
|
||||
import org.koitharu.kotatsu.search.domain.MangaSearchRepository
|
||||
import org.koitharu.kotatsu.search.ui.suggestion.model.SearchSuggestionItem
|
||||
|
||||
private const val DEBOUNCE_TIMEOUT = 500L
|
||||
private const val SEARCH_THRESHOLD = 3
|
||||
private const val MAX_MANGA_ITEMS = 3
|
||||
private const val MAX_QUERY_ITEMS = 120
|
||||
private const val MAX_SUGGESTION_ITEMS = MAX_MANGA_ITEMS + MAX_QUERY_ITEMS + 1
|
||||
|
||||
class SearchSuggestionViewModel(
|
||||
private val repository: MangaSearchRepository,
|
||||
) : BaseViewModel() {
|
||||
@@ -83,13 +89,4 @@ class SearchSuggestionViewModel(
|
||||
suggestion.postValue(it)
|
||||
}.launchIn(viewModelScope + Dispatchers.Default)
|
||||
}
|
||||
|
||||
private companion object {
|
||||
|
||||
const val DEBOUNCE_TIMEOUT = 500L
|
||||
const val SEARCH_THRESHOLD = 3
|
||||
const val MAX_MANGA_ITEMS = 3
|
||||
const val MAX_QUERY_ITEMS = 120
|
||||
const val MAX_SUGGESTION_ITEMS = MAX_MANGA_ITEMS + MAX_QUERY_ITEMS + 1
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,8 @@ import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.base.ui.BaseActivity
|
||||
import org.koitharu.kotatsu.databinding.ActivitySetupProtectBinding
|
||||
|
||||
private const val MIN_PASSWORD_LENGTH = 4
|
||||
|
||||
class ProtectSetupActivity : BaseActivity<ActivitySetupProtectBinding>(), TextWatcher,
|
||||
View.OnClickListener, TextView.OnEditorActionListener {
|
||||
|
||||
@@ -91,9 +93,4 @@ class ProtectSetupActivity : BaseActivity<ActivitySetupProtectBinding>(), TextWa
|
||||
binding.buttonNext.setText(R.string.next)
|
||||
}
|
||||
}
|
||||
|
||||
private companion object {
|
||||
|
||||
const val MIN_PASSWORD_LENGTH = 4
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ import org.koitharu.kotatsu.core.model.MangaSource
|
||||
import org.koitharu.kotatsu.core.parser.MangaRepositoryAuthProvider
|
||||
import org.koitharu.kotatsu.databinding.ActivityBrowserBinding
|
||||
import org.koitharu.kotatsu.utils.ext.mangaRepositoryOf
|
||||
import com.google.android.material.R as materialR
|
||||
|
||||
class SourceAuthActivity : BaseActivity<ActivityBrowserBinding>(), BrowserCallback {
|
||||
|
||||
@@ -43,7 +44,7 @@ class SourceAuthActivity : BaseActivity<ActivityBrowserBinding>(), BrowserCallba
|
||||
}
|
||||
supportActionBar?.run {
|
||||
setDisplayHomeAsUpEnabled(true)
|
||||
setHomeAsUpIndicator(R.drawable.ic_cross)
|
||||
setHomeAsUpIndicator(materialR.drawable.abc_ic_clear_material)
|
||||
}
|
||||
with(binding.webView.settings) {
|
||||
javaScriptEnabled = true
|
||||
|
||||
@@ -23,6 +23,7 @@ import org.koitharu.kotatsu.databinding.ActivityCategoriesBinding
|
||||
import org.koitharu.kotatsu.utils.ext.getDisplayMessage
|
||||
import org.koitharu.kotatsu.widget.shelf.adapter.CategorySelectAdapter
|
||||
import org.koitharu.kotatsu.widget.shelf.model.CategoryItem
|
||||
import com.google.android.material.R as materialR
|
||||
|
||||
class ShelfConfigActivity : BaseActivity<ActivityCategoriesBinding>(),
|
||||
OnListItemClickListener<CategoryItem> {
|
||||
@@ -35,7 +36,10 @@ class ShelfConfigActivity : BaseActivity<ActivityCategoriesBinding>(),
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(ActivityCategoriesBinding.inflate(layoutInflater))
|
||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||
supportActionBar?.run {
|
||||
setDisplayHomeAsUpEnabled(true)
|
||||
setHomeAsUpIndicator(materialR.drawable.abc_ic_clear_material)
|
||||
}
|
||||
adapter = CategorySelectAdapter(this)
|
||||
binding.recyclerView.addItemDecoration(
|
||||
MaterialDividerItemDecoration(this, RecyclerView.VERTICAL)
|
||||
|
||||
Reference in New Issue
Block a user