更多的电池模式与带箭头的标题 #185

This commit is contained in:
HapeLee
2025-11-02 00:40:25 +08:00
parent de1ae6f9e4
commit 45b454c4c1
10 changed files with 231 additions and 88 deletions
@@ -19,9 +19,12 @@ object ReadTipConfig {
const val timeBattery = 8
const val timeBatteryPercentage = 9
const val totalProgress1 = 11
const val chapterTitleArrow = 12
const val batteryInside = 13
const val batteryIcon = 14
val tipValues = arrayOf(
none, bookName, chapterTitle, time, battery, batteryPercentage, page,
none, bookName, chapterTitle, chapterTitleArrow, time, battery, batteryInside, batteryIcon, batteryPercentage, page,
totalProgress, totalProgress1, pageAndTotal, timeBattery, timeBatteryPercentage
)
val tipNames get() = appCtx.resources.getStringArray(R.array.read_tip).toList()
@@ -31,7 +31,6 @@ import io.legado.app.utils.applyStatusBarPadding
import io.legado.app.utils.dpToPx
import io.legado.app.utils.gone
import io.legado.app.utils.setOnApplyWindowInsetsListenerCompat
import io.legado.app.utils.setTextIfNotEqual
import io.legado.app.utils.statusBarHeight
import splitties.views.backgroundColor
import java.util.Date
@@ -55,6 +54,9 @@ class PageView(context: Context) : FrameLayout(context) {
private var tvBookName: BatteryView? = null
private var tvTimeBattery: BatteryView? = null
private var tvTimeBatteryP: BatteryView? = null
private var tvTitleArrow: BatteryView? = null
private var tvBatteryInside: BatteryView? = null
private var tvBatteryIcon: BatteryView? = null
private var isMainView = false
var isScroll = false
@@ -183,6 +185,13 @@ class PageView(context: Context) : FrameLayout(context) {
typeface = ChapterProvider.typeface
textSize = 12f
}
tvTitleArrow = getTipView(ReadTipConfig.chapterTitleArrow)?.apply {
tag = ReadTipConfig.chapterTitleArrow
isBattery = false
typeface = ChapterProvider.typeface
textSize = 12f
batteryMode = BatteryView.BatteryMode.ARROW
}
tvTime = getTipView(ReadTipConfig.time)?.apply {
tag = ReadTipConfig.time
isBattery = false
@@ -193,6 +202,19 @@ class PageView(context: Context) : FrameLayout(context) {
tag = ReadTipConfig.battery
isBattery = true
textSize = 11f
batteryMode = BatteryView.BatteryMode.OUTER
}
tvBatteryInside = getTipView(ReadTipConfig.batteryInside)?.apply {
tag = ReadTipConfig.batteryInside
isBattery = true
textSize = 11f
batteryMode = BatteryView.BatteryMode.INNER
}
tvBatteryIcon = getTipView(ReadTipConfig.batteryIcon)?.apply {
tag = ReadTipConfig.batteryIcon
isBattery = true
textSize = 11f
batteryMode = BatteryView.BatteryMode.ICON
}
tvPage = getTipView(ReadTipConfig.page)?.apply {
tag = ReadTipConfig.page
@@ -296,6 +318,8 @@ class PageView(context: Context) : FrameLayout(context) {
fun upBattery(battery: Int) {
this.battery = battery
tvBattery?.setBattery(battery)
tvBatteryInside?.setBattery(battery)
tvBatteryIcon?.setBattery(battery)
tvBatteryP?.text = "$battery%"
upTimeBattery()
}
@@ -307,6 +331,8 @@ class PageView(context: Context) : FrameLayout(context) {
private fun upTimeBattery() {
val time = timeFormat.format(Date(System.currentTimeMillis()))
tvTimeBattery?.setBattery(battery, time)
tvTimeBatteryP?.setBattery(battery, time)
tvTimeBattery?.text = "$time $battery%"
tvTimeBatteryP?.text = "$time $battery%"
}
@@ -352,6 +378,7 @@ class PageView(context: Context) : FrameLayout(context) {
fun setProgress(textPage: TextPage) = textPage.apply {
tvBookName?.setTextIfNotEqual(ReadBook.book?.name)
tvTitle?.setTextIfNotEqual(textPage.title)
tvTitleArrow?.setTextIfNotEqual(textPage.title)
val readProgress = readProgress
tvTotalProgress?.setTextIfNotEqual(readProgress)
tvTotalProgress1?.setTextIfNotEqual("${chapterIndex.plus(1)}/${chapterSize}")
@@ -1,122 +1,140 @@
package io.legado.app.ui.widget
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.Rect
import android.graphics.PorterDuff
import android.graphics.Typeface
import android.os.Build
import android.text.StaticLayout
import android.util.AttributeSet
import android.util.TypedValue
import android.view.LayoutInflater
import androidx.annotation.ColorInt
import androidx.appcompat.widget.AppCompatTextView
import io.legado.app.help.config.AppConfig
import io.legado.app.utils.canvasrecorder.CanvasRecorderFactory
import io.legado.app.utils.canvasrecorder.recordIfNeededThenDraw
import androidx.constraintlayout.widget.ConstraintLayout
import io.legado.app.databinding.ViewBatteryBinding
import io.legado.app.utils.dpToPx
class BatteryView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null
) : AppCompatTextView(context, attrs) {
) : ConstraintLayout(context, attrs) {
private val binding: ViewBatteryBinding =
ViewBatteryBinding.inflate(LayoutInflater.from(context), this, true)
enum class BatteryMode { OUTER, INNER, ICON, ARROW }
private val batteryTypeface by lazy {
Typeface.createFromAsset(context.assets, "font/number.ttf")
}
private val batteryPaint = Paint()
private val outFrame = Rect()
private val polar = Rect()
private val canvasRecorder = CanvasRecorderFactory.create()
var isBattery = false
set(value) {
field = value
if (value && !isInEditMode) {
super.setTypeface(batteryTypeface)
postInvalidate()
}
}
private var battery: Int = 0
init {
setPadding(4.dpToPx(), 3.dpToPx(), 6.dpToPx(), 3.dpToPx())
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
isFallbackLineSpacing = false
}
batteryPaint.strokeWidth = 1f.dpToPx()
batteryPaint.isAntiAlias = true
batteryPaint.color = paint.color
binding.batteryText.typeface = batteryTypeface
binding.batteryTextInner.typeface = batteryTypeface
}
override fun setTypeface(tf: Typeface?) {
if (!isBattery) {
super.setTypeface(tf)
var isBattery = false
set(value) {
field = value
binding.arrowIcon.visibility = if (value) VISIBLE else GONE
binding.batteryTextInner.visibility = if (value) VISIBLE else GONE
binding.batteryTextInner.typeface = if (value) Typeface.DEFAULT else batteryTypeface
binding.batteryText.typeface = if (value) Typeface.DEFAULT else batteryTypeface
binding.batteryIcon.visibility = if (value) VISIBLE else GONE
binding.batteryFill.visibility = if (value) VISIBLE else GONE
}
var text: CharSequence?
get() = binding.batteryText.text
set(value) {
binding.batteryText.text = value
binding.batteryTextInner.text = value
}
var batteryMode: BatteryMode = BatteryMode.OUTER
set(value) {
field = value
updateMode()
}
var typeface: Typeface?
get() = binding.batteryText.typeface
set(value) {
binding.batteryText.typeface = value ?: Typeface.DEFAULT
binding.batteryTextInner.typeface = value ?: Typeface.DEFAULT
}
var textSize: Float
get() = binding.batteryText.textSize / binding.batteryText.resources.displayMetrics.density
set(value) {
binding.batteryText.setTextSize(TypedValue.COMPLEX_UNIT_SP, value)
}
fun setTextColor(@ColorInt color: Int) {
binding.batteryText.setTextColor(color)
binding.batteryTextInner.setTextColor(color)
}
fun setBattery(battery: Int, text: String? = null) {
this.battery = battery.coerceIn(0, 100)
binding.batteryText.text = text?.let { "$it $battery" } ?: battery.toString()
binding.batteryTextInner.text = text?.let { "$it $battery" } ?: battery.toString()
updateFill()
}
fun setColor(@ColorInt color: Int) {
setTextColor(color)
batteryPaint.color = color
invalidate()
binding.batteryText.setTextColor(color)
binding.batteryFill.setCardBackgroundColor(color)
binding.arrowIcon.setColorFilter(color, PorterDuff.Mode.SRC_IN)
binding.batteryIcon.setColorFilter(color, PorterDuff.Mode.SRC_IN)
binding.batteryIcon.alpha = 0.76f
binding.arrowIcon.alpha = 0.76f
}
@SuppressLint("SetTextI18n")
fun setBattery(battery: Int, text: String? = null) {
this.battery = battery
if (text.isNullOrEmpty()) {
setText(battery.toString())
} else {
setText("$text $battery")
fun setTextIfNotEqual(newText: String?) {
if (binding.batteryText.text?.toString() != newText) {
binding.batteryText.text = newText
}
}
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
super.onLayout(changed, left, top, right, bottom)
canvasRecorder.invalidate()
}
override fun onDraw(canvas: Canvas) {
if (AppConfig.optimizeRender) {
canvasRecorder.recordIfNeededThenDraw(canvas, width, height) {
super.onDraw(this)
drawBattery(this)
private fun updateMode() {
when (batteryMode) {
BatteryMode.OUTER -> {
binding.arrowIcon.visibility = GONE
binding.batteryText.visibility = VISIBLE
binding.batteryTextInner.visibility = GONE
binding.batteryFill.visibility = VISIBLE
}
BatteryMode.INNER -> {
binding.arrowIcon.visibility = GONE
binding.batteryText.visibility = GONE
binding.batteryTextInner.visibility = VISIBLE
binding.batteryFill.visibility = GONE
}
BatteryMode.ICON -> {
binding.arrowIcon.visibility = GONE
binding.batteryText.visibility = GONE
binding.batteryTextInner.visibility = GONE
binding.batteryFill.visibility = VISIBLE
}
BatteryMode.ARROW -> {
binding.batteryText.visibility = VISIBLE
binding.batteryTextInner.visibility = GONE
binding.batteryFill.visibility = GONE
binding.arrowIcon.visibility = VISIBLE
}
} else {
super.onDraw(canvas)
drawBattery(canvas)
}
updateFill()
}
private fun drawBattery(canvas: Canvas) {
if (!isBattery) return
layout.getLineBounds(0, outFrame)
val batteryStart = layout
.getPrimaryHorizontal(text.length - battery.toString().length)
.toInt() + 2.dpToPx()
val batteryEnd = batteryStart +
StaticLayout.getDesiredWidth(battery.toString(), paint).toInt() + 4.dpToPx()
outFrame.set(
batteryStart,
2.dpToPx(),
batteryEnd,
height - 2.dpToPx()
)
val dj = (outFrame.bottom - outFrame.top) / 3
polar.set(
batteryEnd,
outFrame.top + dj,
batteryEnd + 2.dpToPx(),
outFrame.bottom - dj
)
batteryPaint.style = Paint.Style.STROKE
canvas.drawRect(outFrame, batteryPaint)
batteryPaint.style = Paint.Style.FILL
canvas.drawRect(polar, batteryPaint)
}
@Suppress("UNNECESSARY_SAFE_CALL")
override fun invalidate() {
super.invalidate()
canvasRecorder?.invalidate()
private fun updateFill() {
post {
val maxWidth = 14.dpToPx()
val params = binding.batteryFill.layoutParams
params.width = (maxWidth * battery / 100f).toInt()
binding.batteryFill.layoutParams = params
}
}
}
+12
View File
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M175.38,680Q135.64,680 107.82,652.18Q80,624.36 80,584.62L80,375.38Q80,335.64 107.82,307.82Q135.64,280 175.38,280L700,280Q739.74,280 767.56,307.82Q795.38,335.64 795.38,375.38L795.38,584.62Q795.38,624.36 767.56,652.18Q739.74,680 700,680L175.38,680ZM175.38,640L700,640Q723.54,640 739.46,624.08Q755.38,608.15 755.38,584.62L755.38,375.38Q755.38,351.85 739.46,335.92Q723.54,320 700,320L175.38,320Q151.85,320 135.92,335.92Q120,351.85 120,375.38L120,584.62Q120,608.15 135.92,624.08Q151.85,640 175.38,640ZM835.38,564.62L835.38,396.15L847.69,396.15Q861.42,396.15 870.71,405.44Q880,414.73 880,428.46L880,532.31Q880,546.04 870.71,555.33Q861.42,564.62 847.69,564.62L835.38,564.62ZM120,640Q120,640 120,624.08Q120,608.15 120,584.62L120,375.38Q120,351.85 120,335.92Q120,320 120,320L120,320Q120,320 120,335.92Q120,351.85 120,375.38L120,584.62Q120,608.15 120,624.08Q120,640 120,640Z"/>
</vector>
+71
View File
@@ -0,0 +1,71 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto">
<ImageView
android:id="@+id/arrow_icon"
android:layout_width="24dp"
android:layout_height="12dp"
android:scaleType="centerCrop"
android:visibility="gone"
android:src="@drawable/ic_arrow_right"
android:rotation="180"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
<TextView
android:id="@+id/battery_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:includeFontPadding="false"
android:textSize="11sp"
android:text="@string/text"
android:textStyle="bold"
app:layout_constraintStart_toEndOf="@id/arrow_icon"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
<TextView
android:id="@+id/battery_text_inner"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="2.4dp"
android:layout_marginBottom="0.8dp"
android:textSize="7sp"
android:text="@string/text"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="@id/battery_icon"
app:layout_constraintEnd_toEndOf="@id/battery_icon"
app:layout_constraintTop_toTopOf="@id/battery_icon"
app:layout_constraintBottom_toBottomOf="@id/battery_icon"
tools:ignore="SmallSp" />
<ImageView
android:id="@+id/battery_icon"
android:layout_width="28dp"
android:layout_height="12dp"
android:layout_marginStart="4dp"
android:scaleType="centerCrop"
android:src="@drawable/ic_battery"
app:layout_constraintStart_toEndOf="@id/battery_text"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
<com.google.android.material.card.MaterialCardView
android:id="@+id/battery_fill"
android:layout_width="14dp"
android:layout_height="8dp"
android:visibility="gone"
android:layout_marginStart="4.2dp"
app:strokeWidth="0dp"
app:cardCornerRadius="1dp"
app:cardBackgroundColor="?attr/colorControlNormal"
app:layout_constraintStart_toStartOf="@id/battery_icon"
app:layout_constraintTop_toTopOf="@id/battery_icon"
app:layout_constraintBottom_toBottomOf="@id/battery_icon"/>
</androidx.constraintlayout.widget.ConstraintLayout>
@@ -51,8 +51,11 @@
<item></item>
<item>書名</item>
<item>標題</item>
<item>標題+箭頭</item>
<item>時間</item>
<item>電量</item>
<item>電量內顯</item>
<item>僅電量圖標</item>
<item>電量%</item>
<item>頁數</item>
<item>進度(%)</item>
@@ -88,8 +88,11 @@
<item></item>
<item>書名</item>
<item>標題</item>
<item>標題+箭頭</item>
<item>時間</item>
<item>電量</item>
<item>電量內顯</item>
<item>僅電量圖標</item>
<item>電量%</item>
<item>頁數</item>
<item>進度(%)</item>
+3
View File
@@ -75,8 +75,11 @@
<item></item>
<item>书名</item>
<item>标题</item>
<item>带箭头的标题</item>
<item>时间</item>
<item>电量</item>
<item>电量内显</item>
<item>仅电量图标</item>
<item>电量%</item>
<item>页数</item>
<item>进度(%)</item>
+3
View File
@@ -142,8 +142,11 @@
<item>Blank</item>
<item>Book name</item>
<item>Title</item>
<item>Title With Arrow</item>
<item>Time</item>
<item>Battery</item>
<item>Battery Inside</item>
<item>Battery Only Icon</item>
<item>Battery%</item>
<item>Pages</item>
<item>Progress(%)</item>
+1 -1
View File
@@ -1,4 +1,4 @@
VERSION_MAJOR=3
VERSION_MINOR=26
VERSION_PATCH=2
VERSION_SUFFIX=-beta.3
VERSION_SUFFIX=-beta.4