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.Paint
import android.graphics.Rect
import android.graphics.drawable.Drawable
import android.os.BatteryManager
import android.util.AttributeSet
import android.view.View
import android.view.WindowInsets
@@ -16,6 +18,7 @@ import androidx.annotation.AttrRes
import androidx.core.content.ContextCompat
import androidx.core.content.withStyledAttributes
import androidx.core.graphics.ColorUtils
import androidx.core.graphics.withScale
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import org.koitharu.kotatsu.R
@@ -29,6 +32,7 @@ import java.time.format.DateTimeFormatter
import java.time.format.FormatStyle
import com.google.android.material.R as materialR
class ReaderInfoBarView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
@@ -38,7 +42,7 @@ class ReaderInfoBarView @JvmOverloads constructor(
private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
private val textBounds = Rect()
private val timeFormat = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT)
private val timeReceiver = TimeReceiver()
private val systemStateReceiver = SystemStateReceiver()
private var insetLeft: Int = 0
private var insetRight: Int = 0
private var insetTop: Int = 0
@@ -52,8 +56,10 @@ class ReaderInfoBarView @JvmOverloads constructor(
context.getThemeColor(materialR.attr.colorSurface, Color.WHITE),
200,
)
private val batteryIcon = ContextCompat.getDrawable(context, R.drawable.ic_battery_outline)
private var timeText = timeFormat.format(LocalTime.now())
private var batteryText = ""
private var text: String = ""
private var prevTextHeight: Int = 0
@@ -99,7 +105,8 @@ class ReaderInfoBarView @JvmOverloads constructor(
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
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
canvas.drawTextOutline(
text,
@@ -108,11 +115,26 @@ class ReaderInfoBarView @JvmOverloads constructor(
)
if (isTimeVisible) {
paint.textAlign = Paint.Align.RIGHT
canvas.drawTextOutline(
timeText,
(width - paddingRight - insetRight - cutoutInsetRight).toFloat(),
paddingTop + insetTop + ty,
)
var endX = (width - paddingRight - insetRight - cutoutInsetRight).toFloat()
canvas.drawTextOutline(timeText, endX, paddingTop + insetTop + ty)
if (batteryText.isNotEmpty()) {
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()
ContextCompat.registerReceiver(
context,
timeReceiver,
IntentFilter(Intent.ACTION_TIME_TICK),
systemStateReceiver,
IntentFilter().apply {
addAction(Intent.ACTION_TIME_TICK)
addAction(Intent.ACTION_BATTERY_CHANGED)
},
ContextCompat.RECEIVER_EXPORTED,
)
updateCutoutInsets(ViewCompat.getRootWindowInsets(this))
@@ -139,7 +164,7 @@ class ReaderInfoBarView @JvmOverloads constructor(
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
context.unregisterReceiver(timeReceiver)
context.unregisterReceiver(systemStateReceiver)
}
fun update(state: ReaderUiState?) {
@@ -167,7 +192,7 @@ class ReaderInfoBarView @JvmOverloads constructor(
}
private fun computeTextHeight(): Int {
val str = text + timeText
val str = text + batteryText + timeText
paint.getTextBounds(str, 0, str.length, textBounds)
return textBounds.height()
}
@@ -181,6 +206,20 @@ class ReaderInfoBarView @JvmOverloads constructor(
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?) {
val cutouts = (insetsCompat ?: return).displayCutout?.boundingRects.orEmpty()
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())
if (isTimeVisible) {
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>