Merge branch 'devel' into feature/nextgen

This commit is contained in:
Koitharu
2022-08-08 16:27:21 +03:00
11 changed files with 154 additions and 26 deletions

View File

@@ -1,10 +1,18 @@
package org.koitharu.kotatsu.core.model
import java.util.*
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.util.toTitleCase
import java.util.*
fun MangaSource.getLocaleTitle(): String? {
val lc = Locale(locale ?: return null)
return lc.getDisplayLanguage(lc).toTitleCase(lc)
}
@Suppress("FunctionName")
fun MangaSource(name: String): MangaSource? {
MangaSource.values().forEach {
if (it.name == name) return it
}
return null
}

View File

@@ -45,6 +45,7 @@ import org.koitharu.kotatsu.search.ui.MangaListActivity
import org.koitharu.kotatsu.search.ui.SearchActivity
import org.koitharu.kotatsu.utils.FileSize
import org.koitharu.kotatsu.utils.ext.*
import org.koitharu.kotatsu.utils.image.CoverSizeResolver
@AndroidEntryPoint
class DetailsFragment :
@@ -291,8 +292,10 @@ class DetailsFragment :
override fun onWindowInsetsChanged(insets: Insets) {
binding.root.updatePadding(
bottom = ((activity as? NoModalBottomSheetOwner)?.bsHeader?.measureHeight()
?.plus(insets.bottom)?.plus(resources.resolveDp(16)))
bottom = (
(activity as? NoModalBottomSheetOwner)?.bsHeader?.measureHeight()
?.plus(insets.bottom)?.plus(resources.resolveDp(16))
)
?: insets.bottom,
)
}
@@ -319,16 +322,22 @@ class DetailsFragment :
}
val request = ImageRequest.Builder(context ?: return)
.target(binding.imageViewCover)
.placeholder(R.drawable.ic_placeholder)
.fallback(R.drawable.ic_placeholder)
.error(R.drawable.ic_error_placeholder)
.size(CoverSizeResolver(binding.imageViewCover))
.data(imageUrl)
.crossfade(context)
.referer(manga.publicUrl)
.lifecycle(viewLifecycleOwner)
lastResult?.drawable?.let {
request.fallback(it)
} ?: request.fallback(R.drawable.ic_placeholder)
.placeholderMemoryCacheKey(manga.coverUrl)
val previousDrawable = lastResult?.drawable
if (previousDrawable != null) {
request.fallback(previousDrawable)
.placeholder(previousDrawable)
.error(previousDrawable)
} else {
request.fallback(R.drawable.ic_placeholder)
.placeholder(R.drawable.ic_placeholder)
.error(R.drawable.ic_error_placeholder)
}
request.enqueueWith(coil)
}
}

View File

@@ -1,6 +1,10 @@
package org.koitharu.kotatsu.details.ui
import android.text.Html
import android.text.SpannableString
import android.text.Spanned
import android.text.style.ForegroundColorSpan
import androidx.core.text.getSpans
import androidx.core.text.parseAsHtml
import androidx.lifecycle.LiveData
import androidx.lifecycle.asFlow
@@ -110,8 +114,8 @@ class DetailsViewModel @AssistedInject constructor(
if (description.isNullOrEmpty()) {
emit(null)
} else {
emit(description.parseAsHtml())
emit(description.parseAsHtml(imageGetter = imageGetter))
emit(description.parseAsHtml().filterSpans())
emit(description.parseAsHtml(imageGetter = imageGetter).filterSpans())
}
}.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default, null)
@@ -265,6 +269,15 @@ class DetailsViewModel @AssistedInject constructor(
}
}
private fun Spanned.filterSpans(): CharSequence {
val spannable = SpannableString.valueOf(this)
val spans = spannable.getSpans<ForegroundColorSpan>()
for (span in spans) {
spannable.removeSpan(span)
}
return spannable.trim()
}
@AssistedFactory
interface Factory {

View File

@@ -16,6 +16,7 @@ import org.koitharu.kotatsu.utils.ext.disposeImageRequest
import org.koitharu.kotatsu.utils.ext.enqueueWith
import org.koitharu.kotatsu.utils.ext.newImageRequest
import org.koitharu.kotatsu.utils.ext.referer
import org.koitharu.kotatsu.utils.image.CoverSizeResolver
fun mangaGridItemAD(
coil: ImageLoader,
@@ -40,6 +41,7 @@ fun mangaGridItemAD(
binding.progressView.setPercent(item.progress, MangaListAdapter.PAYLOAD_PROGRESS in payloads)
binding.imageViewCover.newImageRequest(item.coverUrl)?.run {
referer(item.manga.publicUrl)
size(CoverSizeResolver(binding.imageViewCover))
placeholder(R.drawable.ic_placeholder)
fallback(R.drawable.ic_placeholder)
error(R.drawable.ic_error_placeholder)

View File

@@ -12,6 +12,7 @@ import org.koitharu.kotatsu.list.ui.model.ListModel
import org.koitharu.kotatsu.list.ui.model.MangaListDetailedModel
import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.utils.ext.*
import org.koitharu.kotatsu.utils.image.CoverSizeResolver
fun mangaListDetailedItemAD(
coil: ImageLoader,
@@ -35,6 +36,7 @@ fun mangaListDetailedItemAD(
binding.progressView.setPercent(item.progress, MangaListAdapter.PAYLOAD_PROGRESS in payloads)
binding.imageViewCover.newImageRequest(item.coverUrl)?.run {
referer(item.manga.publicUrl)
size(CoverSizeResolver(binding.imageViewCover))
placeholder(R.drawable.ic_placeholder)
fallback(R.drawable.ic_placeholder)
error(R.drawable.ic_error_placeholder)

View File

@@ -6,9 +6,11 @@ import androidx.lifecycle.MutableLiveData
import dagger.hilt.android.lifecycle.HiltViewModel
import java.util.*
import javax.inject.Inject
import kotlin.Comparator
import org.koitharu.kotatsu.base.ui.BaseViewModel
import org.koitharu.kotatsu.core.model.MangaSource
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.util.mapNotNullToSet
import org.koitharu.kotatsu.parsers.util.mapToSet
import org.koitharu.kotatsu.parsers.util.toTitleCase
import org.koitharu.kotatsu.settings.onboard.model.SourceLocale
@@ -30,7 +32,7 @@ class OnboardViewModel @Inject constructor(
init {
if (settings.isSourcesSelected) {
selectedLocales.removeAll(settings.hiddenSources.mapToSet { x -> MangaSource.valueOf(x).locale })
selectedLocales.removeAll(settings.hiddenSources.mapNotNullToSet { x -> MangaSource(x)?.locale })
} else {
val deviceLocales = LocaleListCompat.getDefault().mapToSet { x ->
x.language

View File

@@ -0,0 +1,83 @@
package org.koitharu.kotatsu.utils.image
import android.view.View
import android.view.View.OnLayoutChangeListener
import android.view.ViewGroup
import android.widget.ImageView
import coil.size.Dimension
import coil.size.Size
import coil.size.SizeResolver
import kotlin.coroutines.resume
import kotlin.math.roundToInt
import kotlinx.coroutines.CancellableContinuation
import kotlinx.coroutines.suspendCancellableCoroutine
private const val ASPECT_RATIO_HEIGHT = 18f
private const val ASPECT_RATIO_WIDTH = 13f
class CoverSizeResolver(
private val imageView: ImageView,
) : SizeResolver {
override suspend fun size(): Size {
getSize()?.let { return it }
return suspendCancellableCoroutine { cont ->
val layoutListener = LayoutListener(cont)
imageView.addOnLayoutChangeListener(layoutListener)
cont.invokeOnCancellation {
imageView.removeOnLayoutChangeListener(layoutListener)
}
}
}
private fun getSize(): Size? {
val lp = imageView.layoutParams
var width = getDimension(lp.width, imageView.width, imageView.paddingLeft + imageView.paddingRight)
var height = getDimension(lp.height, imageView.height, imageView.paddingTop + imageView.paddingBottom)
if (width == null && height == null) {
return null
}
if (height == null && width != null) {
height = Dimension((width.px * ASPECT_RATIO_HEIGHT / ASPECT_RATIO_WIDTH).roundToInt())
} else if (width == null && height != null) {
width = Dimension((height.px * ASPECT_RATIO_WIDTH / ASPECT_RATIO_HEIGHT).roundToInt())
}
return Size(checkNotNull(width), checkNotNull(height))
}
private fun getDimension(paramSize: Int, viewSize: Int, paddingSize: Int): Dimension.Pixels? {
if (paramSize == ViewGroup.LayoutParams.WRAP_CONTENT) {
return null
}
val insetParamSize = paramSize - paddingSize
if (insetParamSize > 0) {
return Dimension(insetParamSize)
}
val insetViewSize = viewSize - paddingSize
if (insetViewSize > 0) {
return Dimension(insetViewSize)
}
return null
}
private inner class LayoutListener(
private val continuation: CancellableContinuation<Size>,
) : OnLayoutChangeListener {
override fun onLayoutChange(
v: View,
left: Int,
top: Int,
right: Int,
bottom: Int,
oldLeft: Int,
oldTop: Int,
oldRight: Int,
oldBottom: Int,
) {
val size = getSize() ?: return
v.removeOnLayoutChangeListener(this)
continuation.resume(size)
}
}
}

View File

@@ -1,11 +1,15 @@
package org.koitharu.kotatsu.utils.image
import android.graphics.Bitmap
import androidx.core.graphics.get
import androidx.annotation.ColorInt
import androidx.core.graphics.*
import coil.size.Size
import coil.transform.Transformation
import kotlin.math.abs
class TrimTransformation : Transformation {
class TrimTransformation(
private val tolerance: Int = 20,
) : Transformation {
override val cacheKey: String = javaClass.name
@@ -20,7 +24,7 @@ class TrimTransformation : Transformation {
var isColBlank = true
val prevColor = input[x, 0]
for (y in 1 until input.height) {
if (input[x, y] != prevColor) {
if (!isColorTheSame(input[x, y], prevColor)) {
isColBlank = false
break
}
@@ -39,7 +43,7 @@ class TrimTransformation : Transformation {
var isColBlank = true
val prevColor = input[x, 0]
for (y in 1 until input.height) {
if (input[x, y] != prevColor) {
if (!isColorTheSame(input[x, y], prevColor)) {
isColBlank = false
break
}
@@ -55,7 +59,7 @@ class TrimTransformation : Transformation {
var isRowBlank = true
val prevColor = input[0, y]
for (x in 1 until input.width) {
if (input[x, y] != prevColor) {
if (!isColorTheSame(input[x, y], prevColor)) {
isRowBlank = false
break
}
@@ -71,7 +75,7 @@ class TrimTransformation : Transformation {
var isRowBlank = true
val prevColor = input[0, y]
for (x in 1 until input.width) {
if (input[x, y] != prevColor) {
if (!isColorTheSame(input[x, y], prevColor)) {
isRowBlank = false
break
}
@@ -93,4 +97,11 @@ class TrimTransformation : Transformation {
override fun equals(other: Any?) = other is TrimTransformation
override fun hashCode() = javaClass.hashCode()
private fun isColorTheSame(@ColorInt a: Int, @ColorInt b: Int): Boolean {
return abs(a.red - b.red) <= tolerance &&
abs(a.green - b.green) <= tolerance &&
abs(a.blue - b.blue) <= tolerance &&
abs(a.alpha - b.alpha) <= tolerance
}
}

View File

@@ -12,10 +12,9 @@
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/imageView_cover"
android:layout_width="42dp"
android:layout_height="0dp"
android:layout_height="42dp"
android:scaleType="centerCrop"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="h,1:1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.Kotatsu.Cover.Small"

View File

@@ -12,10 +12,9 @@
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/imageView_cover"
android:layout_width="42dp"
android:layout_height="0dp"
android:layout_height="42dp"
android:scaleType="centerCrop"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="h,1:1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.Kotatsu.Cover.Small"