使用ProgressBar

This commit is contained in:
HapeLee
2025-09-05 03:38:27 +08:00
parent 3b10cb7ad7
commit ee703523de
24 changed files with 54 additions and 463 deletions
@@ -21,6 +21,7 @@ import io.legato.kazusa.utils.buildMainHandler
import io.legato.kazusa.utils.canRead
import io.legato.kazusa.utils.checkWrite
import io.legato.kazusa.utils.getFile
import io.legato.kazusa.utils.gone
import io.legato.kazusa.utils.isContentScheme
import io.legato.kazusa.utils.readUri
import io.legato.kazusa.utils.showDialogFragment
@@ -28,6 +29,7 @@ import io.legato.kazusa.utils.startActivity
import io.legato.kazusa.utils.startActivityForBook
import io.legato.kazusa.utils.toastOnUi
import io.legato.kazusa.utils.viewbindingdelegate.viewBinding
import io.legato.kazusa.utils.visible
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@@ -216,7 +216,7 @@ class ChangeChapterSourceDialog() : BaseDialogFragment(R.layout.dialog_chapter_c
private fun initLiveData() {
viewModel.searchStateData.observe(viewLifecycleOwner) {
binding.refreshProgressBar.isAutoLoading = it
binding.refreshProgressBar.isVisible = it
if (it) {
startStopMenuItem?.let { item ->
item.setIcon(R.drawable.ic_stop_black_24dp)
@@ -1,5 +1,6 @@
package io.legato.kazusa.ui.book.import.local
//import io.legado.app.lib.theme.backgroundColor
import android.annotation.SuppressLint
import android.net.Uri
import android.os.Bundle
@@ -8,6 +9,8 @@ import android.view.MenuItem
import androidx.activity.addCallback
import androidx.activity.viewModels
import androidx.appcompat.widget.PopupMenu
import androidx.core.net.toUri
import androidx.core.view.isVisible
import androidx.documentfile.provider.DocumentFile
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
@@ -19,7 +22,6 @@ import io.legato.kazusa.help.config.AppConfig
import io.legato.kazusa.lib.dialogs.alert
import io.legato.kazusa.lib.permission.Permissions
import io.legato.kazusa.lib.permission.PermissionsCompat
//import io.legado.app.lib.theme.backgroundColor
import io.legato.kazusa.ui.book.import.BaseImportBookActivity
import io.legato.kazusa.ui.file.HandleFileContract
import io.legato.kazusa.ui.widget.SelectActionBar
@@ -38,7 +40,6 @@ import kotlinx.coroutines.flow.conflate
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File
import androidx.core.net.toUri
/**
* 导入本地书籍界面
@@ -252,12 +253,12 @@ class ImportBookActivity : BaseImportBookActivity<ImportBookViewModel>(),
viewModel.rootDoc?.let { doc ->
adapter.clearItems()
val lastDoc = viewModel.subDocs.lastOrNull() ?: doc
binding.refreshProgressBar.isAutoLoading = true
binding.refreshProgressBar.isVisible = true
scanDocJob?.cancel()
scanDocJob = lifecycleScope.launch(IO) {
viewModel.scanDoc(lastDoc)
withContext(Main) {
binding.refreshProgressBar.isAutoLoading = false
binding.refreshProgressBar.isVisible = false
}
}
}
@@ -9,6 +9,7 @@ import android.view.SubMenu
import androidx.activity.addCallback
import androidx.activity.viewModels
import androidx.core.view.isGone
import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import io.legato.kazusa.R
@@ -59,7 +60,7 @@ class RemoteBookActivity : BaseImportBookActivity<RemoteBookViewModel>(),
initEvent()
launch {
viewModel.dataFlow.conflate().collect { sortedRemoteBooks ->
binding.refreshProgressBar.isAutoLoading = false
binding.refreshProgressBar.isVisible = false
binding.tvEmptyMsg.isGone = sortedRemoteBooks.isNotEmpty()
adapter.setItems(sortedRemoteBooks)
delay(500)
@@ -151,11 +152,11 @@ class RemoteBookActivity : BaseImportBookActivity<RemoteBookViewModel>(),
@SuppressLint("NotifyDataSetChanged")
override fun onClickSelectBarMainAction() {
binding.refreshProgressBar.isAutoLoading = true
binding.refreshProgressBar.isVisible = true
viewModel.addToBookshelf(adapter.selected) {
adapter.selected.clear()
adapter.notifyDataSetChanged()
binding.refreshProgressBar.isAutoLoading = false
binding.refreshProgressBar.isVisible = false
}
}
@@ -184,7 +185,7 @@ class RemoteBookActivity : BaseImportBookActivity<RemoteBookViewModel>(),
viewModel.loadRemoteBookList(
viewModel.dirList.lastOrNull()?.path
) {
binding.refreshProgressBar.isAutoLoading = it
binding.refreshProgressBar.isVisible = it
}
}
@@ -247,9 +248,9 @@ class RemoteBookActivity : BaseImportBookActivity<RemoteBookViewModel>(),
override fun addToBookShelfAgain(remoteBook: RemoteBook) {
alert(getString(R.string.sure), "是否重新加入书架?") {
yesButton {
binding.refreshProgressBar.isAutoLoading = true
binding.refreshProgressBar.isVisible = true
viewModel.addToBookshelf(hashSetOf(remoteBook)) {
binding.refreshProgressBar.isAutoLoading = false
binding.refreshProgressBar.isVisible = false
}
}
noButton()
@@ -1,5 +1,6 @@
package io.legato.kazusa.ui.book.read
//import io.legado.app.lib.theme.primaryColor
import android.app.Application
import android.content.DialogInterface
import android.os.Bundle
@@ -20,13 +21,13 @@ import io.legato.kazusa.help.book.ContentProcessor
import io.legato.kazusa.help.book.isLocal
import io.legato.kazusa.help.coroutine.Coroutine
import io.legato.kazusa.lib.dialogs.alert
//import io.legado.app.lib.theme.primaryColor
import io.legato.kazusa.model.ReadBook
import io.legato.kazusa.model.webBook.WebBook
import io.legato.kazusa.utils.applyTint
import io.legato.kazusa.utils.gone
import io.legato.kazusa.utils.sendToClip
import io.legato.kazusa.utils.setLayout
import io.legato.kazusa.utils.viewbindingdelegate.viewBinding
import io.legato.kazusa.utils.visible
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@@ -10,6 +10,7 @@ import android.widget.EditText
import androidx.activity.viewModels
import androidx.appcompat.widget.SearchView
import androidx.core.view.allViews
import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
import io.legato.kazusa.R
import io.legato.kazusa.base.VMBaseActivity
@@ -210,7 +211,7 @@ class SearchContentActivity :
viewModel.searchResultList.clear()
viewModel.searchResultCounts = 0
viewModel.lastQuery = query
binding.refreshProgressBar.isAutoLoading = true
binding.refreshProgressBar.isVisible = true
binding.fbStop.visible()
searchJob = lifecycleScope.launch(IO) {
initJob?.join()
@@ -246,7 +247,7 @@ class SearchContentActivity :
}
binding.tvCurrentSearchInfo.post {
binding.fbStop.invisible()
binding.refreshProgressBar.isAutoLoading = false
binding.refreshProgressBar.isVisible = false
}
}
}
@@ -19,11 +19,13 @@ import io.legato.kazusa.lib.dialogs.selector
import io.legato.kazusa.ui.qrcode.QrCodeResult
import io.legato.kazusa.ui.widget.dialog.TextDialog
import io.legato.kazusa.utils.applyNavigationBarPadding
import io.legato.kazusa.utils.gone
import io.legato.kazusa.utils.launch
import io.legato.kazusa.utils.showDialogFragment
import io.legato.kazusa.utils.showHelp
import io.legato.kazusa.utils.toastOnUi
import io.legato.kazusa.utils.viewbindingdelegate.viewBinding
import io.legato.kazusa.utils.visible
import kotlinx.coroutines.launch
import splitties.views.onClick
import splitties.views.onLongClick
@@ -218,7 +218,7 @@ class WebViewActivity : VMBaseActivity<ActivityWebViewBinding, WebViewModel>() {
override fun onProgressChanged(view: WebView?, newProgress: Int) {
super.onProgressChanged(view, newProgress)
binding.progressBar.setDurProgress(newProgress)
binding.progressBar.setProgress(newProgress)
binding.progressBar.gone(newProgress == 100)
}
@@ -135,7 +135,7 @@ class WebViewLoginFragment : BaseFragment(R.layout.fragment_web_view_login) {
override fun onProgressChanged(view: WebView?, newProgress: Int) {
super.onProgressChanged(view, newProgress)
binding.progressBar.setDurProgress(newProgress)
binding.progressBar.setProgress(newProgress)
binding.progressBar.gone(newProgress == 100)
}
@@ -359,7 +359,7 @@ class ReadRssActivity : VMBaseActivity<ActivityRssReadBinding, ReadRssViewModel>
override fun onProgressChanged(view: WebView?, newProgress: Int) {
super.onProgressChanged(view, newProgress)
binding.progressBar.setDurProgress(newProgress)
binding.progressBar.setProgress(newProgress)
binding.progressBar.gone(newProgress == 100)
}
@@ -17,6 +17,7 @@ import io.legato.kazusa.utils.gone
import io.legato.kazusa.utils.showDialogFragment
import io.legato.kazusa.utils.toastOnUi
import io.legato.kazusa.utils.viewbindingdelegate.viewBinding
import io.legato.kazusa.utils.visible
import kotlinx.coroutines.launch
@@ -1,195 +0,0 @@
package io.legato.kazusa.ui.widget.anima
import android.content.Context
import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.Rect
import android.graphics.RectF
import android.os.Looper
import android.util.AttributeSet
import android.view.View
import io.legato.kazusa.R
@Suppress("unused", "MemberVisibilityCanBePrivate")
class RefreshProgressBar @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null
) : View(context, attrs) {
private var a = 1
private var durProgress = 0
private var secondDurProgress = 0
var maxProgress = 100
var secondMaxProgress = 100
var bgColor = 0x00000000
var secondColor = -0x3e3e3f
var fontColor = -0xc9c9ca
var speed = 2
var secondFinalProgress = 0
private set
private var paint: Paint = Paint()
private val bgRect = Rect()
private val secondRect = Rect()
private val fontRectF = RectF()
var isAutoLoading: Boolean = false
set(loading) {
field = loading
if (!loading) {
secondDurProgress = 0
secondFinalProgress = 0
}
maxProgress = 0
invalidate()
}
init {
paint.style = Paint.Style.FILL
val a = context.obtainStyledAttributes(attrs, R.styleable.RefreshProgressBar)
speed = a.getDimensionPixelSize(R.styleable.RefreshProgressBar_speed, speed)
maxProgress = a.getInt(R.styleable.RefreshProgressBar_max_progress, maxProgress)
durProgress = a.getInt(R.styleable.RefreshProgressBar_dur_progress, durProgress)
secondDurProgress = a.getDimensionPixelSize(
R.styleable.RefreshProgressBar_second_dur_progress,
secondDurProgress
)
secondFinalProgress = secondDurProgress
secondMaxProgress = a.getDimensionPixelSize(
R.styleable.RefreshProgressBar_second_max_progress,
secondMaxProgress
)
bgColor = a.getColor(R.styleable.RefreshProgressBar_bg_color, bgColor)
secondColor = a.getColor(R.styleable.RefreshProgressBar_second_color, secondColor)
fontColor = a.getColor(R.styleable.RefreshProgressBar_font_color, fontColor)
a.recycle()
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
paint.color = bgColor
bgRect.set(0, 0, measuredWidth, measuredHeight)
canvas.drawRect(bgRect, paint)
if (secondDurProgress > 0 && secondMaxProgress > 0) {
var secondDur = secondDurProgress
if (secondDur > secondMaxProgress) {
secondDur = secondMaxProgress
}
paint.color = secondColor
val tempW =
(measuredWidth.toFloat() * 1.0f * (secondDur * 1.0f / secondMaxProgress)).toInt()
secondRect.set(
measuredWidth / 2 - tempW / 2,
0,
measuredWidth / 2 + tempW / 2,
measuredHeight
)
canvas.drawRect(secondRect, paint)
}
if (durProgress > 0 && maxProgress > 0) {
paint.color = fontColor
fontRectF.set(
0f,
0f,
measuredWidth.toFloat() * 1.0f * (durProgress * 1.0f / maxProgress),
measuredHeight.toFloat()
)
canvas.drawRect(fontRectF, paint)
}
if (this.isAutoLoading) {
if (secondDurProgress >= secondMaxProgress) {
a = -1
} else if (secondDurProgress <= 0) {
a = 1
}
secondDurProgress += a * speed
if (secondDurProgress < 0)
secondDurProgress = 0
else if (secondDurProgress > secondMaxProgress)
secondDurProgress = secondMaxProgress
secondFinalProgress = secondDurProgress
invalidate()
} else {
if (secondDurProgress != secondFinalProgress) {
if (secondDurProgress > secondFinalProgress) {
secondDurProgress -= speed
if (secondDurProgress < secondFinalProgress) {
secondDurProgress = secondFinalProgress
}
} else {
secondDurProgress += speed
if (secondDurProgress > secondFinalProgress) {
secondDurProgress = secondFinalProgress
}
}
this.invalidate()
}
}
}
fun getDurProgress(): Int {
return durProgress
}
fun setDurProgress(durProgress: Int) {
var durProgress1 = durProgress
if (durProgress1 < 0) {
durProgress1 = 0
}
if (durProgress1 > maxProgress) {
durProgress1 = maxProgress
}
this.durProgress = durProgress1
if (Looper.myLooper() == Looper.getMainLooper()) {
this.invalidate()
} else {
this.postInvalidate()
}
}
fun getSecondDurProgress(): Int {
return secondDurProgress
}
fun setSecondDurProgress(secondDur: Int) {
this.secondDurProgress = secondDur
this.secondFinalProgress = secondDurProgress
if (Looper.myLooper() == Looper.getMainLooper()) {
this.invalidate()
} else {
this.postInvalidate()
}
}
fun setSecondDurProgressWithAnim(secondDur: Int) {
var secondDur1 = secondDur
if (secondDur1 < 0) {
secondDur1 = 0
}
if (secondDur1 > secondMaxProgress) {
secondDur1 = secondMaxProgress
}
this.secondFinalProgress = secondDur1
if (Looper.myLooper() == Looper.getMainLooper()) {
this.invalidate()
} else {
this.postInvalidate()
}
}
fun clean() {
durProgress = 0
secondDurProgress = 0
secondFinalProgress = 0
if (Looper.myLooper() == Looper.getMainLooper()) {
this.invalidate()
} else {
this.postInvalidate()
}
}
}
@@ -1,228 +0,0 @@
package io.legato.kazusa.ui.widget.anima
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.RectF
import android.util.AttributeSet
import android.view.View
import io.legato.kazusa.R
//import io.legado.app.lib.theme.accentColor
import io.legato.kazusa.utils.dpToPx
/**
* RotateLoading
* Created by Victor on 2015/4/28.
*/
@Suppress("MemberVisibilityCanBePrivate")
class RotateLoading @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null
) : View(context, attrs) {
private var mPaint: Paint
private var loadingRectF: RectF? = null
private var shadowRectF: RectF? = null
private var topDegree = 10
private var bottomDegree = 190
private var arc: Float = 0.toFloat()
private var thisWidth: Int = 0
private var changeBigger = true
private var shadowPosition: Int = 0
private var hideMode = GONE
var isStarted = false
private set
var loadingColor: Int = 0
set(value) {
field = value
invalidate()
}
private var speedOfDegree: Int = 0
private var speedOfArc: Float = 0.toFloat()
private val shown = Runnable { this.startInternal() }
private val hidden = Runnable { this.stopInternal() }
init {
//loadingColor = context.accentColor
thisWidth = DEFAULT_WIDTH.dpToPx()
shadowPosition = DEFAULT_SHADOW_POSITION.dpToPx()
speedOfDegree = DEFAULT_SPEED_OF_DEGREE
if (null != attrs) {
val typedArray = context.obtainStyledAttributes(attrs, R.styleable.RotateLoading)
loadingColor =
typedArray.getColor(R.styleable.RotateLoading_loading_color, loadingColor)
thisWidth = typedArray.getDimensionPixelSize(
R.styleable.RotateLoading_loading_width,
DEFAULT_WIDTH.dpToPx()
)
shadowPosition = typedArray.getInt(
R.styleable.RotateLoading_shadow_position,
DEFAULT_SHADOW_POSITION
)
speedOfDegree =
typedArray.getInt(R.styleable.RotateLoading_loading_speed, DEFAULT_SPEED_OF_DEGREE)
typedArray.recycle()
}
speedOfArc = (speedOfDegree / 4).toFloat()
mPaint = Paint()
mPaint.color = loadingColor
mPaint.isAntiAlias = true
mPaint.style = Paint.Style.STROKE
mPaint.strokeWidth = thisWidth.toFloat()
mPaint.strokeCap = Paint.Cap.ROUND
}
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
super.onSizeChanged(w, h, oldw, oldh)
arc = 10f
loadingRectF =
RectF(
(2 * thisWidth).toFloat(),
(2 * thisWidth).toFloat(),
(w - 2 * thisWidth).toFloat(),
(h - 2 * thisWidth).toFloat()
)
shadowRectF = RectF(
(2 * thisWidth + shadowPosition).toFloat(),
(2 * thisWidth + shadowPosition).toFloat(),
(w - 2 * thisWidth + shadowPosition).toFloat(),
(h - 2 * thisWidth + shadowPosition).toFloat()
)
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
if (!isStarted) {
return
}
mPaint.color = Color.parseColor("#1a000000")
shadowRectF?.let {
canvas.drawArc(it, topDegree.toFloat(), arc, false, mPaint)
canvas.drawArc(it, bottomDegree.toFloat(), arc, false, mPaint)
}
mPaint.color = loadingColor
loadingRectF?.let {
canvas.drawArc(it, topDegree.toFloat(), arc, false, mPaint)
canvas.drawArc(it, bottomDegree.toFloat(), arc, false, mPaint)
}
topDegree += speedOfDegree
bottomDegree += speedOfDegree
if (topDegree > 360) {
topDegree -= 360
}
if (bottomDegree > 360) {
bottomDegree -= 360
}
if (changeBigger) {
if (arc < 160) {
arc += speedOfArc
invalidate()
}
} else {
if (arc > speedOfDegree) {
arc -= 2 * speedOfArc
invalidate()
}
}
if (arc >= 160 || arc <= 10) {
changeBigger = !changeBigger
invalidate()
}
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
if (visibility == VISIBLE) {
startInternal()
}
}
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
isStarted = false
animate().cancel()
removeCallbacks(shown)
removeCallbacks(hidden)
}
fun visible() {
removeCallbacks(shown)
removeCallbacks(hidden)
post(shown)
}
fun inVisible() {
hideMode = INVISIBLE
removeCallbacks(shown)
removeCallbacks(hidden)
stopInternal()
}
fun gone() {
hideMode = GONE
removeCallbacks(shown)
removeCallbacks(hidden)
stopInternal()
}
private fun startInternal() {
startAnimator()
isStarted = true
invalidate()
}
private fun stopInternal() {
stopAnimator()
invalidate()
}
private fun startAnimator() {
animate().cancel()
animate().scaleX(1.0f)
.scaleY(1.0f)
.setListener(object : AnimatorListenerAdapter() {
override fun onAnimationStart(animation: Animator) {
visibility = VISIBLE
}
})
.start()
}
private fun stopAnimator() {
animate().cancel()
isStarted = false
this.visibility = hideMode
}
companion object {
private const val DEFAULT_WIDTH = 6
private const val DEFAULT_SHADOW_POSITION = 2
private const val DEFAULT_SPEED_OF_DEGREE = 10
}
}