diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/image/FaviconFallbackDrawable.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/image/FaviconDrawable.kt
similarity index 52%
rename from app/src/main/kotlin/org/koitharu/kotatsu/core/ui/image/FaviconFallbackDrawable.kt
rename to app/src/main/kotlin/org/koitharu/kotatsu/core/ui/image/FaviconDrawable.kt
index ab065e004..492ee9f97 100644
--- a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/image/FaviconFallbackDrawable.kt
+++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/image/FaviconDrawable.kt
@@ -5,45 +5,67 @@ import android.graphics.Canvas
import android.graphics.Color
import android.graphics.ColorFilter
import android.graphics.Paint
+import android.graphics.Path
import android.graphics.PixelFormat
import android.graphics.Rect
+import android.graphics.RectF
import android.graphics.drawable.Drawable
+import androidx.annotation.StyleRes
+import androidx.core.content.withStyledAttributes
import androidx.core.graphics.ColorUtils
+import androidx.core.graphics.withClip
import com.google.android.material.color.MaterialColors
+import org.koitharu.kotatsu.R
import kotlin.math.absoluteValue
-class FaviconFallbackDrawable(
+class FaviconDrawable(
context: Context,
+ @StyleRes styleResId: Int,
name: String,
) : Drawable() {
private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
+ private var colorBackground = Color.WHITE
+ private var colorStroke = Color.LTGRAY
private val letter = name.take(1).uppercase()
- private val color = MaterialColors.harmonizeWithPrimary(context, colorOfString(name))
+ private var cornerSize = 0f
+ private var colorForeground = Color.DKGRAY
private val textBounds = Rect()
private val tempRect = Rect()
+ private val boundsF = RectF()
+ private val clipPath = Path()
init {
- paint.style = Paint.Style.FILL
+ context.withStyledAttributes(styleResId, R.styleable.FaviconFallbackDrawable) {
+ colorBackground = getColor(R.styleable.FaviconFallbackDrawable_backgroundColor, colorBackground)
+ colorStroke = getColor(R.styleable.FaviconFallbackDrawable_strokeColor, colorStroke)
+ cornerSize = getDimension(R.styleable.FaviconFallbackDrawable_cornerSize, cornerSize)
+ paint.strokeWidth = getDimension(R.styleable.FaviconFallbackDrawable_strokeWidth, 0f) * 2f
+ }
paint.textAlign = Paint.Align.CENTER
paint.isFakeBoldText = true
+ colorForeground = MaterialColors.harmonize(colorOfString(name), colorBackground)
}
override fun draw(canvas: Canvas) {
- val cx = bounds.exactCenterX()
- paint.color = color
- canvas.drawPaint(paint)
- paint.color = Color.WHITE
- val ty = bounds.height() / 2f + textBounds.height() / 2f - textBounds.bottom
- canvas.drawText(letter, cx, ty, paint)
+ if (cornerSize > 0f) {
+ canvas.withClip(clipPath) {
+ doDraw(canvas)
+ }
+ } else {
+ doDraw(canvas)
+ }
}
override fun onBoundsChange(bounds: Rect) {
super.onBoundsChange(bounds)
+ boundsF.set(bounds)
val innerWidth = bounds.width() - (paint.strokeWidth * 2f)
paint.textSize = getTextSizeForWidth(innerWidth, letter) * 0.5f
paint.getTextBounds(letter, 0, letter.length, textBounds)
- invalidateSelf()
+ clipPath.reset()
+ clipPath.addRoundRect(boundsF, cornerSize, cornerSize, Path.Direction.CW)
+ clipPath.close()
}
override fun setAlpha(alpha: Int) {
@@ -58,6 +80,24 @@ class FaviconFallbackDrawable(
@Deprecated("Deprecated in Java")
override fun getOpacity() = PixelFormat.TRANSPARENT
+ private fun doDraw(canvas: Canvas) {
+ // background
+ paint.color = colorBackground
+ paint.style = Paint.Style.FILL
+ canvas.drawPaint(paint)
+ // letter
+ paint.color = colorForeground
+ val cx = (boundsF.left + boundsF.right) * 0.6f
+ val ty = boundsF.bottom * 0.7f + textBounds.height() * 0.5f - textBounds.bottom
+ canvas.drawText(letter, cx, ty, paint)
+ if (paint.strokeWidth > 0f) {
+ // stroke
+ paint.color = colorStroke
+ paint.style = Paint.Style.STROKE
+ canvas.drawPath(clipPath, paint)
+ }
+ }
+
private fun getTextSizeForWidth(width: Float, text: String): Float {
val testTextSize = 48f
paint.textSize = testTextSize
diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/explore/ui/adapter/ExploreAdapterDelegates.kt b/app/src/main/kotlin/org/koitharu/kotatsu/explore/ui/adapter/ExploreAdapterDelegates.kt
index 614b5ef78..c440e322a 100644
--- a/app/src/main/kotlin/org/koitharu/kotatsu/explore/ui/adapter/ExploreAdapterDelegates.kt
+++ b/app/src/main/kotlin/org/koitharu/kotatsu/explore/ui/adapter/ExploreAdapterDelegates.kt
@@ -8,7 +8,7 @@ import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegate
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.parser.favicon.faviconUri
-import org.koitharu.kotatsu.core.ui.image.FaviconFallbackDrawable
+import org.koitharu.kotatsu.core.ui.image.FaviconDrawable
import org.koitharu.kotatsu.core.ui.list.AdapterDelegateClickListenerAdapter
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
import org.koitharu.kotatsu.core.util.ext.disposeImageRequest
@@ -76,7 +76,7 @@ fun exploreSourceListItemAD(
bind {
binding.textViewTitle.text = item.source.title
- val fallbackIcon = FaviconFallbackDrawable(context, item.source.name)
+ val fallbackIcon = FaviconDrawable(context, R.style.FaviconDrawable_Small, item.source.name)
binding.imageViewIcon.newImageRequest(lifecycleOwner, item.source.faviconUri())?.run {
fallback(fallbackIcon)
placeholder(fallbackIcon)
@@ -107,7 +107,7 @@ fun exploreSourceGridItemAD(
bind {
binding.textViewTitle.text = item.source.title
- val fallbackIcon = FaviconFallbackDrawable(context, item.source.name)
+ val fallbackIcon = FaviconDrawable(context, R.style.FaviconDrawable_Large, item.source.name)
binding.imageViewIcon.newImageRequest(lifecycleOwner, item.source.faviconUri())?.run {
fallback(fallbackIcon)
placeholder(fallbackIcon)
diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/suggestion/adapter/SearchSuggestionSourceAD.kt b/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/suggestion/adapter/SearchSuggestionSourceAD.kt
index 6552643a1..138a4bff8 100644
--- a/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/suggestion/adapter/SearchSuggestionSourceAD.kt
+++ b/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/suggestion/adapter/SearchSuggestionSourceAD.kt
@@ -3,8 +3,9 @@ package org.koitharu.kotatsu.search.ui.suggestion.adapter
import androidx.lifecycle.LifecycleOwner
import coil.ImageLoader
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
+import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.parser.favicon.faviconUri
-import org.koitharu.kotatsu.core.ui.image.FaviconFallbackDrawable
+import org.koitharu.kotatsu.core.ui.image.FaviconDrawable
import org.koitharu.kotatsu.core.util.ext.disposeImageRequest
import org.koitharu.kotatsu.core.util.ext.enqueueWith
import org.koitharu.kotatsu.core.util.ext.newImageRequest
@@ -31,7 +32,7 @@ fun searchSuggestionSourceAD(
bind {
binding.textViewTitle.text = item.source.title
binding.switchLocal.isChecked = item.isEnabled
- val fallbackIcon = FaviconFallbackDrawable(context, item.source.name)
+ val fallbackIcon = FaviconDrawable(context, R.style.FaviconDrawable_Small, item.source.name)
binding.imageViewCover.newImageRequest(lifecycleOwner, item.source.faviconUri())?.run {
fallback(fallbackIcon)
placeholder(fallbackIcon)
diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/sources/adapter/SourceConfigAdapterDelegates.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/sources/adapter/SourceConfigAdapterDelegates.kt
index bef802851..e407ab2c3 100644
--- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/sources/adapter/SourceConfigAdapterDelegates.kt
+++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/sources/adapter/SourceConfigAdapterDelegates.kt
@@ -9,7 +9,7 @@ import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegate
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.parser.favicon.faviconUri
-import org.koitharu.kotatsu.core.ui.image.FaviconFallbackDrawable
+import org.koitharu.kotatsu.core.ui.image.FaviconDrawable
import org.koitharu.kotatsu.core.ui.list.OnTipCloseListener
import org.koitharu.kotatsu.core.util.ext.crossfade
import org.koitharu.kotatsu.core.util.ext.disposeImageRequest
@@ -66,7 +66,7 @@ fun sourceConfigItemCheckableDelegate(
binding.textViewTitle.text = item.source.title
binding.switchToggle.isChecked = item.isEnabled
binding.textViewDescription.textAndVisible = item.summary
- val fallbackIcon = FaviconFallbackDrawable(context, item.source.name)
+ val fallbackIcon = FaviconDrawable(context, R.style.FaviconDrawable_Small, item.source.name)
binding.imageViewIcon.newImageRequest(lifecycleOwner, item.source.faviconUri())?.run {
crossfade(context)
error(fallbackIcon)
@@ -107,7 +107,7 @@ fun sourceConfigItemDelegate2(
binding.imageViewRemove.isVisible = item.isEnabled
binding.imageViewConfig.isVisible = item.isEnabled
binding.textViewDescription.textAndVisible = item.summary
- val fallbackIcon = FaviconFallbackDrawable(context, item.source.name)
+ val fallbackIcon = FaviconDrawable(context, R.style.FaviconDrawable_Small, item.source.name)
binding.imageViewIcon.newImageRequest(lifecycleOwner, item.source.faviconUri())?.run {
crossfade(context)
error(fallbackIcon)
diff --git a/app/src/main/res/layout/item_explore_source_grid.xml b/app/src/main/res/layout/item_explore_source_grid.xml
index 2f952ffee..e1cef0936 100644
--- a/app/src/main/res/layout/item_explore_source_grid.xml
+++ b/app/src/main/res/layout/item_explore_source_grid.xml
@@ -18,8 +18,11 @@
android:layout_height="72dp"
android:background="?colorControlHighlight"
android:labelFor="@id/textView_title"
+ android:padding="1dp"
android:scaleType="fitCenter"
app:shapeAppearance="?shapeAppearanceCornerMedium"
+ app:strokeColor="?colorOutline"
+ app:strokeWidth="1dp"
tools:src="@tools:sample/avatars" />
-
+
-
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index d9a498bd5..5b6f7a48a 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -287,7 +287,7 @@
- false
-
+
+
+
+
+
+
+