Show battery percentage in reader bar
This commit is contained in:
@@ -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()
|
||||||
|
|||||||
10
app/src/main/res/drawable/ic_battery_outline.xml
Normal file
10
app/src/main/res/drawable/ic_battery_outline.xml
Normal 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>
|
||||||
Reference in New Issue
Block a user