Update reader info bar

This commit is contained in:
Koitharu
2025-01-19 14:53:32 +02:00
parent 914dd9670a
commit 6360731f34
5 changed files with 55 additions and 40 deletions

View File

@@ -1,11 +1,13 @@
package org.koitharu.kotatsu.core.prefs
import android.content.Context
import android.graphics.drawable.Drawable
import android.view.ContextThemeWrapper
import androidx.annotation.Keep
import androidx.core.content.ContextCompat
import androidx.core.graphics.drawable.toDrawable
import org.koitharu.kotatsu.core.util.ext.getThemeDrawable
import org.koitharu.kotatsu.core.util.ext.isNightMode
import com.google.android.material.R as materialR
@Keep
@@ -13,7 +15,7 @@ enum class ReaderBackground {
DEFAULT, LIGHT, DARK, WHITE, BLACK;
fun resolve(context: Context) = when (this) {
fun resolve(context: Context): Drawable? = when (this) {
DEFAULT -> context.getThemeDrawable(android.R.attr.windowBackground)
LIGHT -> ContextThemeWrapper(context, materialR.style.ThemeOverlay_Material3_Light)
.getThemeDrawable(android.R.attr.windowBackground)
@@ -24,4 +26,14 @@ enum class ReaderBackground {
WHITE -> ContextCompat.getColor(context, android.R.color.white).toDrawable()
BLACK -> ContextCompat.getColor(context, android.R.color.black).toDrawable()
}
fun isLight(context: Context): Boolean = when (this) {
DEFAULT -> !context.resources.isNightMode
LIGHT,
WHITE -> true
DARK,
BLACK -> false
}
}

View File

@@ -1,6 +1,8 @@
package org.koitharu.kotatsu.core.util.ext
import android.content.Context
import android.content.res.Configuration
import android.content.res.Resources
import android.content.res.TypedArray
import android.graphics.Color
import android.graphics.drawable.Drawable
@@ -12,6 +14,9 @@ import androidx.core.content.ContextCompat
import androidx.core.content.res.use
import androidx.core.graphics.ColorUtils
val Resources.isNightMode: Boolean
get() = configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES
fun Context.getThemeDrawable(
@AttrRes resId: Int,
) = obtainStyledAttributes(intArrayOf(resId)).use {

View File

@@ -154,6 +154,9 @@ class ReaderActivity :
.setAnchorView(viewBinding.appbarBottom)
.show()
}
viewModel.readerSettings.observe(this) {
viewBinding.infoBar.applyColorScheme(isBlackOnWhite = it.background.isLight(this))
}
viewModel.isZoomControlsEnabled.observe(this) {
viewBinding.zoomControl.isVisible = it
}

View File

@@ -20,11 +20,11 @@ import android.view.WindowInsets
import androidx.annotation.AttrRes
import androidx.core.content.ContextCompat
import androidx.core.content.withStyledAttributes
import androidx.core.graphics.withScale
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.util.ext.getThemeColorStateList
import org.koitharu.kotatsu.core.util.ext.isNightMode
import org.koitharu.kotatsu.core.util.ext.measureDimension
import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug
import org.koitharu.kotatsu.parsers.util.format
@@ -34,6 +34,8 @@ import java.time.format.DateTimeFormatter
import java.time.format.FormatStyle
import com.google.android.material.R as materialR
private const val ALPHA_TEXT = 200
private const val ALPHA_BG = 180
class ReaderInfoBarView @JvmOverloads constructor(
context: Context,
@@ -52,16 +54,16 @@ class ReaderInfoBarView @JvmOverloads constructor(
private val insetRightFallback: Int
private val insetTopFallback: Int
private val insetCornerFallback = getSystemUiDimensionOffset("rounded_corner_content_padding")
private val colorText =
private var colorText =
(context.getThemeColorStateList(materialR.attr.colorOnSurface)
?: ColorStateList.valueOf(Color.BLACK)).withAlpha(200)
private val colorOutline =
?: ColorStateList.valueOf(Color.BLACK)).withAlpha(ALPHA_TEXT)
private var colorBackground =
(context.getThemeColorStateList(materialR.attr.colorSurface)
?: ColorStateList.valueOf(Color.WHITE)).withAlpha(200)
?: ColorStateList.valueOf(Color.WHITE)).withAlpha(ALPHA_BG)
private val batteryIcon = ContextCompat.getDrawable(context, R.drawable.ic_battery_outline)
private var currentTextColor: Int = Color.TRANSPARENT
private var currentOutlineColor: Int = Color.TRANSPARENT
private var currentBackgroundColor: Int = Color.TRANSPARENT
private var timeText = timeFormat.format(LocalTime.now())
private var batteryText = ""
private var text: String = ""
@@ -106,24 +108,28 @@ class ReaderInfoBarView @JvmOverloads constructor(
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
canvas.drawColor(currentBackgroundColor)
computeTextHeight()
val h = innerHeight.toFloat()
val ty = h / 2f + textBounds.height() / 2f - textBounds.bottom
paint.textAlign = Paint.Align.LEFT
canvas.drawTextOutline(
paint.color = currentTextColor
paint.style = Paint.Style.FILL
canvas.drawText(
text,
(paddingLeft + insetLeft).toFloat(),
paddingTop + insetTop + ty,
paint,
)
if (isTimeVisible) {
paint.textAlign = Paint.Align.RIGHT
var endX = (width - paddingRight - insetRight).toFloat()
canvas.drawTextOutline(timeText, endX, paddingTop + insetTop + ty)
canvas.drawText(timeText, endX, paddingTop + insetTop + ty, paint)
if (batteryText.isNotEmpty()) {
paint.getTextBounds(timeText, 0, timeText.length, textBounds)
endX -= textBounds.width()
endX -= h * 0.6f
canvas.drawTextOutline(batteryText, endX, paddingTop + insetTop + ty)
canvas.drawText(batteryText, endX, paddingTop + insetTop + ty, paint)
batteryIcon?.let {
paint.getTextBounds(batteryText, 0, batteryText.length, textBounds)
endX -= textBounds.width()
@@ -134,7 +140,7 @@ class ReaderInfoBarView @JvmOverloads constructor(
endX.toInt(),
(iconCenter + h / 2).toInt(),
)
it.drawWithOutline(canvas)
it.draw(canvas)
}
}
}
@@ -185,13 +191,25 @@ class ReaderInfoBarView @JvmOverloads constructor(
override fun drawableStateChanged() {
currentTextColor = colorText.getColorForState(drawableState, colorText.defaultColor)
currentOutlineColor = colorOutline.getColorForState(drawableState, colorOutline.defaultColor)
currentBackgroundColor = colorBackground.getColorForState(drawableState, colorBackground.defaultColor)
super.drawableStateChanged()
if (batteryIcon != null && batteryIcon.isStateful && batteryIcon.setState(drawableState)) {
invalidateDrawable(batteryIcon)
}
}
fun applyColorScheme(isBlackOnWhite: Boolean) {
val isDarkTheme = resources.isNightMode
colorText = (context.getThemeColorStateList(
if (isBlackOnWhite != isDarkTheme) materialR.attr.colorOnSurface else materialR.attr.colorOnSurfaceInverse,
) ?: ColorStateList.valueOf(if (isBlackOnWhite) Color.BLACK else Color.WHITE)).withAlpha(ALPHA_TEXT)
colorBackground = (context.getThemeColorStateList(
if (isBlackOnWhite != isDarkTheme) materialR.attr.colorSurface else materialR.attr.colorSurfaceInverse,
) ?: ColorStateList.valueOf(if (isBlackOnWhite) Color.WHITE else Color.BLACK)).withAlpha(ALPHA_BG)
drawableStateChanged()
}
@SuppressLint("StringFormatMatches")
fun update(state: ReaderUiState?) {
text = if (state != null) {
context.getString(
@@ -222,32 +240,6 @@ class ReaderInfoBarView @JvmOverloads constructor(
return textBounds.height()
}
private fun Canvas.drawTextOutline(text: String, x: Float, y: Float) {
paint.color = currentOutlineColor
paint.style = Paint.Style.STROKE
drawText(text, x, y, paint)
paint.color = currentTextColor
paint.style = Paint.Style.FILL
drawText(text, x, y, paint)
}
private fun Drawable.drawWithOutline(canvas: Canvas) {
if (bounds.isEmpty) {
return
}
var requiredScale = (bounds.width() + paint.strokeWidth * 2f) / bounds.width().toFloat()
setTint(currentOutlineColor)
canvas.withScale(requiredScale, requiredScale, bounds.exactCenterX(), bounds.exactCenterY()) {
draw(canvas)
}
requiredScale = 1f / requiredScale
canvas.withScale(requiredScale, requiredScale, bounds.exactCenterX(), bounds.exactCenterY()) {
draw(canvas)
}
setTint(currentTextColor)
draw(canvas)
}
private fun updateCutoutInsets(insetsCompat: WindowInsetsCompat?) {
insetLeft = insetLeftFallback
insetRight = insetRightFallback

View File

@@ -18,6 +18,7 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.koitharu.kotatsu.core.model.ZoomMode
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.prefs.ReaderBackground
import org.koitharu.kotatsu.core.prefs.ReaderMode
import org.koitharu.kotatsu.core.util.ext.isLowRamDevice
import org.koitharu.kotatsu.reader.domain.ReaderColorFilter
@@ -34,6 +35,9 @@ class ReaderSettings(
val zoomMode: ZoomMode
get() = settings.zoomMode
val background: ReaderBackground
get() = settings.readerBackground
val colorFilter: ReaderColorFilter?
get() = colorFilterFlow.value?.takeUnless { it.isEmpty } ?: settings.readerColorFilter
@@ -51,8 +55,7 @@ class ReaderSettings(
get() = settings.isPagesNumbersEnabled
fun applyBackground(view: View) {
val bg = settings.readerBackground
view.background = bg.resolve(view.context)
view.background = background.resolve(view.context)
}
fun isPagesCropEnabled(isWebtoon: Boolean) = settings.isPagesCropEnabled(