Cleanup resources and code

This commit is contained in:
Koitharu
2022-03-08 18:58:15 +02:00
parent 148986b454
commit 57f3715128
65 changed files with 202 additions and 506 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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("/[^/]+/?$")
}
}

View File

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

View File

@@ -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,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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