Update default favicon drawable
This commit is contained in:
@@ -5,45 +5,67 @@ import android.graphics.Canvas
|
|||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.graphics.ColorFilter
|
import android.graphics.ColorFilter
|
||||||
import android.graphics.Paint
|
import android.graphics.Paint
|
||||||
|
import android.graphics.Path
|
||||||
import android.graphics.PixelFormat
|
import android.graphics.PixelFormat
|
||||||
import android.graphics.Rect
|
import android.graphics.Rect
|
||||||
|
import android.graphics.RectF
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
|
import androidx.annotation.StyleRes
|
||||||
|
import androidx.core.content.withStyledAttributes
|
||||||
import androidx.core.graphics.ColorUtils
|
import androidx.core.graphics.ColorUtils
|
||||||
|
import androidx.core.graphics.withClip
|
||||||
import com.google.android.material.color.MaterialColors
|
import com.google.android.material.color.MaterialColors
|
||||||
|
import org.koitharu.kotatsu.R
|
||||||
import kotlin.math.absoluteValue
|
import kotlin.math.absoluteValue
|
||||||
|
|
||||||
class FaviconFallbackDrawable(
|
class FaviconDrawable(
|
||||||
context: Context,
|
context: Context,
|
||||||
|
@StyleRes styleResId: Int,
|
||||||
name: String,
|
name: String,
|
||||||
) : Drawable() {
|
) : Drawable() {
|
||||||
|
|
||||||
private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
|
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 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 textBounds = Rect()
|
||||||
private val tempRect = Rect()
|
private val tempRect = Rect()
|
||||||
|
private val boundsF = RectF()
|
||||||
|
private val clipPath = Path()
|
||||||
|
|
||||||
init {
|
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.textAlign = Paint.Align.CENTER
|
||||||
paint.isFakeBoldText = true
|
paint.isFakeBoldText = true
|
||||||
|
colorForeground = MaterialColors.harmonize(colorOfString(name), colorBackground)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun draw(canvas: Canvas) {
|
override fun draw(canvas: Canvas) {
|
||||||
val cx = bounds.exactCenterX()
|
if (cornerSize > 0f) {
|
||||||
paint.color = color
|
canvas.withClip(clipPath) {
|
||||||
canvas.drawPaint(paint)
|
doDraw(canvas)
|
||||||
paint.color = Color.WHITE
|
}
|
||||||
val ty = bounds.height() / 2f + textBounds.height() / 2f - textBounds.bottom
|
} else {
|
||||||
canvas.drawText(letter, cx, ty, paint)
|
doDraw(canvas)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBoundsChange(bounds: Rect) {
|
override fun onBoundsChange(bounds: Rect) {
|
||||||
super.onBoundsChange(bounds)
|
super.onBoundsChange(bounds)
|
||||||
|
boundsF.set(bounds)
|
||||||
val innerWidth = bounds.width() - (paint.strokeWidth * 2f)
|
val innerWidth = bounds.width() - (paint.strokeWidth * 2f)
|
||||||
paint.textSize = getTextSizeForWidth(innerWidth, letter) * 0.5f
|
paint.textSize = getTextSizeForWidth(innerWidth, letter) * 0.5f
|
||||||
paint.getTextBounds(letter, 0, letter.length, textBounds)
|
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) {
|
override fun setAlpha(alpha: Int) {
|
||||||
@@ -58,6 +80,24 @@ class FaviconFallbackDrawable(
|
|||||||
@Deprecated("Deprecated in Java")
|
@Deprecated("Deprecated in Java")
|
||||||
override fun getOpacity() = PixelFormat.TRANSPARENT
|
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 {
|
private fun getTextSizeForWidth(width: Float, text: String): Float {
|
||||||
val testTextSize = 48f
|
val testTextSize = 48f
|
||||||
paint.textSize = testTextSize
|
paint.textSize = testTextSize
|
||||||
@@ -8,7 +8,7 @@ import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegate
|
|||||||
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
|
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
|
||||||
import org.koitharu.kotatsu.R
|
import org.koitharu.kotatsu.R
|
||||||
import org.koitharu.kotatsu.core.parser.favicon.faviconUri
|
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.AdapterDelegateClickListenerAdapter
|
||||||
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
|
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
|
||||||
import org.koitharu.kotatsu.core.util.ext.disposeImageRequest
|
import org.koitharu.kotatsu.core.util.ext.disposeImageRequest
|
||||||
@@ -76,7 +76,7 @@ fun exploreSourceListItemAD(
|
|||||||
|
|
||||||
bind {
|
bind {
|
||||||
binding.textViewTitle.text = item.source.title
|
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 {
|
binding.imageViewIcon.newImageRequest(lifecycleOwner, item.source.faviconUri())?.run {
|
||||||
fallback(fallbackIcon)
|
fallback(fallbackIcon)
|
||||||
placeholder(fallbackIcon)
|
placeholder(fallbackIcon)
|
||||||
@@ -107,7 +107,7 @@ fun exploreSourceGridItemAD(
|
|||||||
|
|
||||||
bind {
|
bind {
|
||||||
binding.textViewTitle.text = item.source.title
|
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 {
|
binding.imageViewIcon.newImageRequest(lifecycleOwner, item.source.faviconUri())?.run {
|
||||||
fallback(fallbackIcon)
|
fallback(fallbackIcon)
|
||||||
placeholder(fallbackIcon)
|
placeholder(fallbackIcon)
|
||||||
|
|||||||
@@ -3,8 +3,9 @@ package org.koitharu.kotatsu.search.ui.suggestion.adapter
|
|||||||
import androidx.lifecycle.LifecycleOwner
|
import androidx.lifecycle.LifecycleOwner
|
||||||
import coil.ImageLoader
|
import coil.ImageLoader
|
||||||
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
|
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
|
||||||
|
import org.koitharu.kotatsu.R
|
||||||
import org.koitharu.kotatsu.core.parser.favicon.faviconUri
|
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.disposeImageRequest
|
||||||
import org.koitharu.kotatsu.core.util.ext.enqueueWith
|
import org.koitharu.kotatsu.core.util.ext.enqueueWith
|
||||||
import org.koitharu.kotatsu.core.util.ext.newImageRequest
|
import org.koitharu.kotatsu.core.util.ext.newImageRequest
|
||||||
@@ -31,7 +32,7 @@ fun searchSuggestionSourceAD(
|
|||||||
bind {
|
bind {
|
||||||
binding.textViewTitle.text = item.source.title
|
binding.textViewTitle.text = item.source.title
|
||||||
binding.switchLocal.isChecked = item.isEnabled
|
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 {
|
binding.imageViewCover.newImageRequest(lifecycleOwner, item.source.faviconUri())?.run {
|
||||||
fallback(fallbackIcon)
|
fallback(fallbackIcon)
|
||||||
placeholder(fallbackIcon)
|
placeholder(fallbackIcon)
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegate
|
|||||||
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
|
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
|
||||||
import org.koitharu.kotatsu.R
|
import org.koitharu.kotatsu.R
|
||||||
import org.koitharu.kotatsu.core.parser.favicon.faviconUri
|
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.ui.list.OnTipCloseListener
|
||||||
import org.koitharu.kotatsu.core.util.ext.crossfade
|
import org.koitharu.kotatsu.core.util.ext.crossfade
|
||||||
import org.koitharu.kotatsu.core.util.ext.disposeImageRequest
|
import org.koitharu.kotatsu.core.util.ext.disposeImageRequest
|
||||||
@@ -66,7 +66,7 @@ fun sourceConfigItemCheckableDelegate(
|
|||||||
binding.textViewTitle.text = item.source.title
|
binding.textViewTitle.text = item.source.title
|
||||||
binding.switchToggle.isChecked = item.isEnabled
|
binding.switchToggle.isChecked = item.isEnabled
|
||||||
binding.textViewDescription.textAndVisible = item.summary
|
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 {
|
binding.imageViewIcon.newImageRequest(lifecycleOwner, item.source.faviconUri())?.run {
|
||||||
crossfade(context)
|
crossfade(context)
|
||||||
error(fallbackIcon)
|
error(fallbackIcon)
|
||||||
@@ -107,7 +107,7 @@ fun sourceConfigItemDelegate2(
|
|||||||
binding.imageViewRemove.isVisible = item.isEnabled
|
binding.imageViewRemove.isVisible = item.isEnabled
|
||||||
binding.imageViewConfig.isVisible = item.isEnabled
|
binding.imageViewConfig.isVisible = item.isEnabled
|
||||||
binding.textViewDescription.textAndVisible = item.summary
|
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 {
|
binding.imageViewIcon.newImageRequest(lifecycleOwner, item.source.faviconUri())?.run {
|
||||||
crossfade(context)
|
crossfade(context)
|
||||||
error(fallbackIcon)
|
error(fallbackIcon)
|
||||||
|
|||||||
@@ -18,8 +18,11 @@
|
|||||||
android:layout_height="72dp"
|
android:layout_height="72dp"
|
||||||
android:background="?colorControlHighlight"
|
android:background="?colorControlHighlight"
|
||||||
android:labelFor="@id/textView_title"
|
android:labelFor="@id/textView_title"
|
||||||
|
android:padding="1dp"
|
||||||
android:scaleType="fitCenter"
|
android:scaleType="fitCenter"
|
||||||
app:shapeAppearance="?shapeAppearanceCornerMedium"
|
app:shapeAppearance="?shapeAppearanceCornerMedium"
|
||||||
|
app:strokeColor="?colorOutline"
|
||||||
|
app:strokeWidth="1dp"
|
||||||
tools:src="@tools:sample/avatars" />
|
tools:src="@tools:sample/avatars" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
|||||||
@@ -116,9 +116,16 @@
|
|||||||
<attr name="shapeAppearance" />
|
<attr name="shapeAppearance" />
|
||||||
<attr name="shapeAppearanceOverlay" />
|
<attr name="shapeAppearanceOverlay" />
|
||||||
<attr name="cardBackgroundColor" />
|
<attr name="cardBackgroundColor" />
|
||||||
<attr name="strokeWidth"/>
|
<attr name="strokeWidth" />
|
||||||
<attr name="strokeColor" />
|
<attr name="strokeColor" />
|
||||||
<attr name="elevation" />
|
<attr name="elevation" />
|
||||||
</declare-styleable>
|
</declare-styleable>
|
||||||
|
|
||||||
|
<declare-styleable name="FaviconFallbackDrawable">
|
||||||
|
<attr name="backgroundColor" />
|
||||||
|
<attr name="strokeColor" />
|
||||||
|
<attr name="strokeWidth" />
|
||||||
|
<attr name="cornerSize" />
|
||||||
|
</declare-styleable>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -287,7 +287,7 @@
|
|||||||
<item name="android:selectable">false</item>
|
<item name="android:selectable">false</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<!-- Progress drawable -->
|
<!-- Drawable -->
|
||||||
|
|
||||||
<style name="ProgressDrawable">
|
<style name="ProgressDrawable">
|
||||||
<item name="android:fillAlpha">1</item>
|
<item name="android:fillAlpha">1</item>
|
||||||
@@ -299,4 +299,19 @@
|
|||||||
<item name="autoFitTextSize">true</item>
|
<item name="autoFitTextSize">true</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style name="FaviconDrawable">
|
||||||
|
<item name="backgroundColor">?colorBackgroundFloating</item>
|
||||||
|
<item name="strokeColor">?colorOutline</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="FaviconDrawable.Small">
|
||||||
|
<item name="strokeWidth">1dp</item>
|
||||||
|
<item name="cornerSize">8dp</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="FaviconDrawable.Large">
|
||||||
|
<item name="strokeWidth">1dp</item>
|
||||||
|
<item name="cornerSize">12dp</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
Reference in New Issue
Block a user