From 439a01c43f1c3e278c80c5a636f21fc3bae5d8f1 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Tue, 18 Jul 2023 11:43:31 +0300 Subject: [PATCH] Fix bookmark has direct url detection #424 --- .../kotatsu/bookmarks/domain/Bookmark.kt | 4 +- .../bookmarks/ui/adapter/BookmarkListAD.kt | 4 + .../kotatsu/core/ui/drawable/TextDrawable.kt | 100 ++++++++++++++++++ .../koitharu/kotatsu/core/util/ext/Theme.kt | 7 ++ .../kotatsu/local/data/ImageFileFilter.kt | 2 +- 5 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/core/ui/drawable/TextDrawable.kt diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/domain/Bookmark.kt b/app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/domain/Bookmark.kt index 98116f8a4..1dc908cc4 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/domain/Bookmark.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/domain/Bookmark.kt @@ -1,5 +1,6 @@ package org.koitharu.kotatsu.bookmarks.domain +import org.koitharu.kotatsu.local.data.ImageFileFilter import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.MangaPage import java.util.Date @@ -26,7 +27,8 @@ class Bookmark( ) private fun isImageUrlDirect(): Boolean { - return imageUrl.substringAfterLast('.').length in 2..4 + val extension = imageUrl.substringAfterLast('.') + return extension.isNotEmpty() && ImageFileFilter().isExtensionValid(extension) } override fun equals(other: Any?): Boolean { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/ui/adapter/BookmarkListAD.kt b/app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/ui/adapter/BookmarkListAD.kt index 5996df31d..e394d3396 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/ui/adapter/BookmarkListAD.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/ui/adapter/BookmarkListAD.kt @@ -5,15 +5,19 @@ import coil.ImageLoader import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding import org.koitharu.kotatsu.R import org.koitharu.kotatsu.bookmarks.domain.Bookmark +import org.koitharu.kotatsu.core.ui.drawable.TextDrawable 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.disposeImageRequest import org.koitharu.kotatsu.core.util.ext.enqueueWith +import org.koitharu.kotatsu.core.util.ext.getThemeResId import org.koitharu.kotatsu.core.util.ext.newImageRequest import org.koitharu.kotatsu.core.util.ext.source import org.koitharu.kotatsu.databinding.ItemBookmarkBinding +import org.koitharu.kotatsu.parsers.util.format +import com.google.android.material.R as materialR fun bookmarkListAD( coil: ImageLoader, diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/drawable/TextDrawable.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/drawable/TextDrawable.kt new file mode 100644 index 000000000..21b5835e7 --- /dev/null +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/drawable/TextDrawable.kt @@ -0,0 +1,100 @@ +package org.koitharu.kotatsu.core.ui.drawable + +import android.annotation.SuppressLint +import android.content.Context +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.ColorFilter +import android.graphics.Paint +import android.graphics.PixelFormat +import android.graphics.Typeface +import android.graphics.drawable.Drawable +import android.os.Build +import android.text.Layout +import android.text.StaticLayout +import android.text.TextPaint +import androidx.annotation.ColorInt +import androidx.annotation.Px +import androidx.annotation.StyleRes +import androidx.core.graphics.withTranslation +import com.google.android.material.resources.TextAppearance +import com.google.android.material.resources.TextAppearanceFontCallback +import org.koitharu.kotatsu.core.util.ext.getThemeColor + +class TextDrawable( + val text: CharSequence, +) : Drawable() { + + private val paint = TextPaint(Paint.ANTI_ALIAS_FLAG) + private var cachedLayout: StaticLayout? = null + + @SuppressLint("RestrictedApi") + constructor(context: Context, text: CharSequence, @StyleRes textAppearanceId: Int) : this(text) { + val ta = TextAppearance(context, textAppearanceId) + paint.color = ta.textColor?.defaultColor ?: context.getThemeColor(android.R.attr.textColorPrimary, Color.BLACK) + paint.typeface = ta.fallbackFont + ta.getFontAsync( + context, paint, + object : TextAppearanceFontCallback() { + override fun onFontRetrieved(typeface: Typeface?, fontResolvedSynchronously: Boolean) = Unit + override fun onFontRetrievalFailed(reason: Int) = Unit + }, + ) + paint.letterSpacing = ta.letterSpacing + } + + var alignment = Layout.Alignment.ALIGN_NORMAL + + var lineSpacingMultiplier = 1f + + @Px + var lineSpacingExtra = 0f + + @get:ColorInt + var textColor: Int + get() = paint.color + set(@ColorInt value) { + paint.color = value + } + + override fun draw(canvas: Canvas) { + val b = bounds + if (b.isEmpty) { + return + } + canvas.withTranslation(x = b.left.toFloat(), y = b.top.toFloat()) { + obtainLayout().draw(canvas) + } + } + + override fun setAlpha(alpha: Int) { + paint.alpha = alpha + } + + override fun setColorFilter(colorFilter: ColorFilter?) { + paint.setColorFilter(colorFilter) + } + + @Suppress("DeprecatedCallableAddReplaceWith") + @Deprecated("Deprecated in Java") + override fun getOpacity(): Int = PixelFormat.TRANSLUCENT + + private fun obtainLayout(): StaticLayout { + val width = bounds.width() + cachedLayout?.let { + if (it.width == width) { + return it + } + } + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + StaticLayout.Builder.obtain(text, 0, text.length, paint, width) + .setAlignment(alignment) + .setLineSpacing(lineSpacingExtra, lineSpacingMultiplier) + .setIncludePad(true) + .build() + } else { + @Suppress("DEPRECATION") + StaticLayout(text, paint, width, alignment, lineSpacingMultiplier, lineSpacingExtra, true) + }.also { cachedLayout = it } + } +} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Theme.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Theme.kt index dae151af2..75c44715c 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Theme.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Theme.kt @@ -60,3 +60,10 @@ fun Context.getThemeColorStateList( ) = obtainStyledAttributes(intArrayOf(resId)).use { it.getColorStateList(0) } + +fun Context.getThemeResId( + @AttrRes resId: Int, + fallback: Int +): Int = obtainStyledAttributes(intArrayOf(resId)).use { + it.getResourceId(0, fallback) +} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/local/data/ImageFileFilter.kt b/app/src/main/kotlin/org/koitharu/kotatsu/local/data/ImageFileFilter.kt index 29b946b0b..4dc76c9f6 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/local/data/ImageFileFilter.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/local/data/ImageFileFilter.kt @@ -23,7 +23,7 @@ class ImageFileFilter : FilenameFilter, FileFilter { return isExtensionValid(ext) } - private fun isExtensionValid(ext: String): Boolean { + fun isExtensionValid(ext: String): Boolean { return ext == "png" || ext == "jpg" || ext == "jpeg" || ext == "webp" } }