From 45b454c4c1955bd5b0537f8e4fd965dc8934516d Mon Sep 17 00:00:00 2001
From: HapeLee <1321903405@qq.com>
Date: Sun, 2 Nov 2025 00:40:25 +0800
Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E5=A4=9A=E7=9A=84=E7=94=B5=E6=B1=A0?=
=?UTF-8?q?=E6=A8=A1=E5=BC=8F=E4=B8=8E=E5=B8=A6=E7=AE=AD=E5=A4=B4=E7=9A=84?=
=?UTF-8?q?=E6=A0=87=E9=A2=98=20#185?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../legado/app/help/config/ReadTipConfig.kt | 5 +-
.../legado/app/ui/book/read/page/PageView.kt | 29 ++-
.../io/legado/app/ui/widget/BatteryView.kt | 188 ++++++++++--------
app/src/main/res/drawable/ic_battery.xml | 12 ++
app/src/main/res/layout/view_battery.xml | 71 +++++++
app/src/main/res/values-zh-rHK/arrays.xml | 3 +
app/src/main/res/values-zh-rTW/arrays.xml | 3 +
app/src/main/res/values-zh/arrays.xml | 3 +
app/src/main/res/values/arrays.xml | 3 +
app/version.properties | 2 +-
10 files changed, 231 insertions(+), 88 deletions(-)
create mode 100644 app/src/main/res/drawable/ic_battery.xml
create mode 100644 app/src/main/res/layout/view_battery.xml
diff --git a/app/src/main/java/io/legado/app/help/config/ReadTipConfig.kt b/app/src/main/java/io/legado/app/help/config/ReadTipConfig.kt
index dc36ffae0..068b99282 100644
--- a/app/src/main/java/io/legado/app/help/config/ReadTipConfig.kt
+++ b/app/src/main/java/io/legado/app/help/config/ReadTipConfig.kt
@@ -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()
diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/PageView.kt b/app/src/main/java/io/legado/app/ui/book/read/page/PageView.kt
index 078c93ee8..f4432c6cc 100644
--- a/app/src/main/java/io/legado/app/ui/book/read/page/PageView.kt
+++ b/app/src/main/java/io/legado/app/ui/book/read/page/PageView.kt
@@ -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}")
diff --git a/app/src/main/java/io/legado/app/ui/widget/BatteryView.kt b/app/src/main/java/io/legado/app/ui/widget/BatteryView.kt
index 1ff8f6fa3..9def47610 100644
--- a/app/src/main/java/io/legado/app/ui/widget/BatteryView.kt
+++ b/app/src/main/java/io/legado/app/ui/widget/BatteryView.kt
@@ -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
+ }
}
}
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_battery.xml b/app/src/main/res/drawable/ic_battery.xml
new file mode 100644
index 000000000..82b1a1e73
--- /dev/null
+++ b/app/src/main/res/drawable/ic_battery.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
diff --git a/app/src/main/res/layout/view_battery.xml b/app/src/main/res/layout/view_battery.xml
new file mode 100644
index 000000000..983cecc44
--- /dev/null
+++ b/app/src/main/res/layout/view_battery.xml
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values-zh-rHK/arrays.xml b/app/src/main/res/values-zh-rHK/arrays.xml
index 89c5005b1..d26dab26c 100644
--- a/app/src/main/res/values-zh-rHK/arrays.xml
+++ b/app/src/main/res/values-zh-rHK/arrays.xml
@@ -51,8 +51,11 @@
- 無
- 書名
- 標題
+ - 標題+箭頭
- 時間
- 電量
+ - 電量內顯
+ - 僅電量圖標
- 電量%
- 頁數
- 進度(%)
diff --git a/app/src/main/res/values-zh-rTW/arrays.xml b/app/src/main/res/values-zh-rTW/arrays.xml
index 3daf623ae..b35aa7b63 100644
--- a/app/src/main/res/values-zh-rTW/arrays.xml
+++ b/app/src/main/res/values-zh-rTW/arrays.xml
@@ -88,8 +88,11 @@
- 無
- 書名
- 標題
+ - 標題+箭頭
- 時間
- 電量
+ - 電量內顯
+ - 僅電量圖標
- 電量%
- 頁數
- 進度(%)
diff --git a/app/src/main/res/values-zh/arrays.xml b/app/src/main/res/values-zh/arrays.xml
index a16050365..6a9ce4b47 100644
--- a/app/src/main/res/values-zh/arrays.xml
+++ b/app/src/main/res/values-zh/arrays.xml
@@ -75,8 +75,11 @@
- 无
- 书名
- 标题
+ - 带箭头的标题
- 时间
- 电量
+ - 电量内显
+ - 仅电量图标
- 电量%
- 页数
- 进度(%)
diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml
index fa25c1488..e8661d7ee 100644
--- a/app/src/main/res/values/arrays.xml
+++ b/app/src/main/res/values/arrays.xml
@@ -142,8 +142,11 @@
- Blank
- Book name
- Title
+ - Title With Arrow
- Time
- Battery
+ - Battery Inside
+ - Battery Only Icon
- Battery%
- Pages
- Progress(%)
diff --git a/app/version.properties b/app/version.properties
index 63e5f0b45..ac3e62489 100644
--- a/app/version.properties
+++ b/app/version.properties
@@ -1,4 +1,4 @@
VERSION_MAJOR=3
VERSION_MINOR=26
VERSION_PATCH=2
-VERSION_SUFFIX=-beta.3
\ No newline at end of file
+VERSION_SUFFIX=-beta.4
\ No newline at end of file