Show battery percentage in reader bar

This commit is contained in:
Koitharu
2024-02-10 16:33:18 +02:00
parent 3125cac4c8
commit 0e4ef32642
2 changed files with 68 additions and 13 deletions

View File

@@ -9,6 +9,8 @@ import android.graphics.Canvas
import android.graphics.Color import android.graphics.Color
import android.graphics.Paint import android.graphics.Paint
import android.graphics.Rect import android.graphics.Rect
import android.graphics.drawable.Drawable
import android.os.BatteryManager
import android.util.AttributeSet import android.util.AttributeSet
import android.view.View import android.view.View
import android.view.WindowInsets import android.view.WindowInsets
@@ -16,6 +18,7 @@ import androidx.annotation.AttrRes
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.content.withStyledAttributes import androidx.core.content.withStyledAttributes
import androidx.core.graphics.ColorUtils import androidx.core.graphics.ColorUtils
import androidx.core.graphics.withScale
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsCompat
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
@@ -29,6 +32,7 @@ import java.time.format.DateTimeFormatter
import java.time.format.FormatStyle import java.time.format.FormatStyle
import com.google.android.material.R as materialR import com.google.android.material.R as materialR
class ReaderInfoBarView @JvmOverloads constructor( class ReaderInfoBarView @JvmOverloads constructor(
context: Context, context: Context,
attrs: AttributeSet? = null, attrs: AttributeSet? = null,
@@ -38,7 +42,7 @@ class ReaderInfoBarView @JvmOverloads constructor(
private val paint = Paint(Paint.ANTI_ALIAS_FLAG) private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
private val textBounds = Rect() private val textBounds = Rect()
private val timeFormat = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT) private val timeFormat = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT)
private val timeReceiver = TimeReceiver() private val systemStateReceiver = SystemStateReceiver()
private var insetLeft: Int = 0 private var insetLeft: Int = 0
private var insetRight: Int = 0 private var insetRight: Int = 0
private var insetTop: Int = 0 private var insetTop: Int = 0
@@ -52,8 +56,10 @@ class ReaderInfoBarView @JvmOverloads constructor(
context.getThemeColor(materialR.attr.colorSurface, Color.WHITE), context.getThemeColor(materialR.attr.colorSurface, Color.WHITE),
200, 200,
) )
private val batteryIcon = ContextCompat.getDrawable(context, R.drawable.ic_battery_outline)
private var timeText = timeFormat.format(LocalTime.now()) private var timeText = timeFormat.format(LocalTime.now())
private var batteryText = ""
private var text: String = "" private var text: String = ""
private var prevTextHeight: Int = 0 private var prevTextHeight: Int = 0
@@ -99,7 +105,8 @@ class ReaderInfoBarView @JvmOverloads constructor(
override fun onDraw(canvas: Canvas) { override fun onDraw(canvas: Canvas) {
super.onDraw(canvas) super.onDraw(canvas)
computeTextHeight() computeTextHeight()
val ty = innerHeight / 2f + textBounds.height() / 2f - textBounds.bottom val h = innerHeight.toFloat()
val ty = h / 2f + textBounds.height() / 2f - textBounds.bottom
paint.textAlign = Paint.Align.LEFT paint.textAlign = Paint.Align.LEFT
canvas.drawTextOutline( canvas.drawTextOutline(
text, text,
@@ -108,11 +115,26 @@ class ReaderInfoBarView @JvmOverloads constructor(
) )
if (isTimeVisible) { if (isTimeVisible) {
paint.textAlign = Paint.Align.RIGHT paint.textAlign = Paint.Align.RIGHT
canvas.drawTextOutline( var endX = (width - paddingRight - insetRight - cutoutInsetRight).toFloat()
timeText, canvas.drawTextOutline(timeText, endX, paddingTop + insetTop + ty)
(width - paddingRight - insetRight - cutoutInsetRight).toFloat(), if (batteryText.isNotEmpty()) {
paddingTop + insetTop + ty, paint.getTextBounds(timeText, 0, timeText.length, textBounds)
) endX -= textBounds.width()
endX -= h * 0.6f
canvas.drawTextOutline(batteryText, endX, paddingTop + insetTop + ty)
batteryIcon?.let {
paint.getTextBounds(batteryText, 0, batteryText.length, textBounds)
endX -= textBounds.width()
val iconCenter = paddingTop + insetTop + textBounds.height() / 2
it.setBounds(
(endX - h).toInt(),
(iconCenter - h / 2).toInt(),
endX.toInt(),
(iconCenter + h / 2).toInt(),
)
it.drawWithOutline(canvas)
}
}
} }
} }
@@ -130,8 +152,11 @@ class ReaderInfoBarView @JvmOverloads constructor(
super.onAttachedToWindow() super.onAttachedToWindow()
ContextCompat.registerReceiver( ContextCompat.registerReceiver(
context, context,
timeReceiver, systemStateReceiver,
IntentFilter(Intent.ACTION_TIME_TICK), IntentFilter().apply {
addAction(Intent.ACTION_TIME_TICK)
addAction(Intent.ACTION_BATTERY_CHANGED)
},
ContextCompat.RECEIVER_EXPORTED, ContextCompat.RECEIVER_EXPORTED,
) )
updateCutoutInsets(ViewCompat.getRootWindowInsets(this)) updateCutoutInsets(ViewCompat.getRootWindowInsets(this))
@@ -139,7 +164,7 @@ class ReaderInfoBarView @JvmOverloads constructor(
override fun onDetachedFromWindow() { override fun onDetachedFromWindow() {
super.onDetachedFromWindow() super.onDetachedFromWindow()
context.unregisterReceiver(timeReceiver) context.unregisterReceiver(systemStateReceiver)
} }
fun update(state: ReaderUiState?) { fun update(state: ReaderUiState?) {
@@ -167,7 +192,7 @@ class ReaderInfoBarView @JvmOverloads constructor(
} }
private fun computeTextHeight(): Int { private fun computeTextHeight(): Int {
val str = text + timeText val str = text + batteryText + timeText
paint.getTextBounds(str, 0, str.length, textBounds) paint.getTextBounds(str, 0, str.length, textBounds)
return textBounds.height() return textBounds.height()
} }
@@ -181,6 +206,20 @@ class ReaderInfoBarView @JvmOverloads constructor(
drawText(text, x, y, paint) drawText(text, x, y, paint)
} }
private fun Drawable.drawWithOutline(canvas: Canvas) {
var requiredScale = (bounds.width() + paint.strokeWidth * 2f) / bounds.width().toFloat()
setTint(colorOutline)
canvas.withScale(requiredScale, requiredScale, bounds.exactCenterX(), bounds.exactCenterY()) {
draw(canvas)
}
requiredScale = 1f / requiredScale
canvas.withScale(requiredScale, requiredScale, bounds.exactCenterX(), bounds.exactCenterY()) {
draw(canvas)
}
setTint(colorText)
draw(canvas)
}
private fun updateCutoutInsets(insetsCompat: WindowInsetsCompat?) { private fun updateCutoutInsets(insetsCompat: WindowInsetsCompat?) {
val cutouts = (insetsCompat ?: return).displayCutout?.boundingRects.orEmpty() val cutouts = (insetsCompat ?: return).displayCutout?.boundingRects.orEmpty()
cutoutInsetLeft = 0 cutoutInsetLeft = 0
@@ -195,9 +234,15 @@ class ReaderInfoBarView @JvmOverloads constructor(
} }
} }
private inner class TimeReceiver : BroadcastReceiver() { private inner class SystemStateReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1)
val scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1)
if (level != -1 && scale != -1) {
batteryText = context.getString(R.string.percent_string_pattern, (level * 100 / scale).toString())
}
override fun onReceive(context: Context?, intent: Intent?) {
timeText = timeFormat.format(LocalTime.now()) timeText = timeFormat.format(LocalTime.now())
if (isTimeVisible) { if (isTimeVisible) {
invalidate() invalidate()

View File

@@ -0,0 +1,10 @@
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#000"
android:pathData="M16,20H8V6H16M16.67,4H15V2H9V4H7.33A1.33,1.33 0 0,0 6,5.33V20.67C6,21.4 6.6,22 7.33,22H16.67A1.33,1.33 0 0,0 18,20.67V5.33C18,4.6 17.4,4 16.67,4Z" />
</vector>