[修复] 偶现的无法退出书源管理的问题
This commit is contained in:
@@ -5,6 +5,7 @@ import android.content.Context
|
||||
import android.util.SparseArray
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.util.size
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
@@ -37,6 +38,8 @@ abstract class RecyclerAdapter<ITEM, VB : ViewBinding>(protected val context: Co
|
||||
|
||||
private var diffJob: Coroutine<*>? = null
|
||||
|
||||
private var isResumed = false
|
||||
|
||||
var itemAnimation: ItemAnimation? = null
|
||||
|
||||
fun setOnItemClickListener(listener: (holder: ItemViewHolder, item: ITEM) -> Unit) {
|
||||
@@ -54,8 +57,8 @@ abstract class RecyclerAdapter<ITEM, VB : ViewBinding>(protected val context: Co
|
||||
@Synchronized
|
||||
fun addHeaderView(header: ((parent: ViewGroup) -> ViewBinding)) {
|
||||
kotlin.runCatching {
|
||||
val index = headerItems.size()
|
||||
headerItems.put(TYPE_HEADER_VIEW + headerItems.size(), header)
|
||||
val index = headerItems.size
|
||||
headerItems.put(TYPE_HEADER_VIEW + headerItems.size, header)
|
||||
notifyItemInserted(index)
|
||||
}
|
||||
}
|
||||
@@ -63,8 +66,8 @@ abstract class RecyclerAdapter<ITEM, VB : ViewBinding>(protected val context: Co
|
||||
@Synchronized
|
||||
fun addFooterView(footer: ((parent: ViewGroup) -> ViewBinding)) {
|
||||
kotlin.runCatching {
|
||||
val index = getActualItemCount() + footerItems.size()
|
||||
footerItems.put(TYPE_FOOTER_VIEW + footerItems.size(), footer)
|
||||
val index = getActualItemCount() + footerItems.size
|
||||
footerItems.put(TYPE_FOOTER_VIEW + footerItems.size, footer)
|
||||
notifyItemInserted(index)
|
||||
}
|
||||
}
|
||||
@@ -113,6 +116,10 @@ abstract class RecyclerAdapter<ITEM, VB : ViewBinding>(protected val context: Co
|
||||
skipDiff: Boolean = false
|
||||
) {
|
||||
kotlin.runCatching {
|
||||
if (!isResumed) { //全量标记更新
|
||||
setItems(items)
|
||||
return@runCatching
|
||||
}
|
||||
val oldItems = this.items.toList()
|
||||
val itemsSize = items?.size ?: 0
|
||||
val headerCount = getHeaderCount()
|
||||
@@ -153,6 +160,10 @@ abstract class RecyclerAdapter<ITEM, VB : ViewBinding>(protected val context: Co
|
||||
return itemCallback.getChangePayload(oldItem, newItem)
|
||||
}
|
||||
}
|
||||
if (!isResumed) {
|
||||
setItems(items)
|
||||
return@runCatching
|
||||
}
|
||||
diffJob?.cancel()
|
||||
diffJob = Coroutine.async {
|
||||
val diffResult = if (skipDiff) withTimeoutOrNullAsync(500L) {
|
||||
@@ -162,7 +173,7 @@ abstract class RecyclerAdapter<ITEM, VB : ViewBinding>(protected val context: Co
|
||||
}
|
||||
ensureActive()
|
||||
handler.post {
|
||||
if (diffResult == null) {
|
||||
if (isResumed || diffResult == null) {
|
||||
setItems(items)
|
||||
return@post
|
||||
}
|
||||
@@ -172,6 +183,10 @@ abstract class RecyclerAdapter<ITEM, VB : ViewBinding>(protected val context: Co
|
||||
if (items != null) {
|
||||
this@RecyclerAdapter.items.addAll(items)
|
||||
}
|
||||
if (!isResumed) {
|
||||
return@post
|
||||
}
|
||||
ensureActive()
|
||||
diffResult.dispatchUpdatesTo(this@RecyclerAdapter)
|
||||
onCurrentListChanged()
|
||||
}
|
||||
@@ -329,10 +344,10 @@ abstract class RecyclerAdapter<ITEM, VB : ViewBinding>(protected val context: Co
|
||||
fun getActualItemCount() = items.size
|
||||
|
||||
|
||||
fun getHeaderCount() = headerItems.size()
|
||||
fun getHeaderCount() = headerItems.size
|
||||
|
||||
|
||||
fun getFooterCount() = footerItems.size()
|
||||
fun getFooterCount() = footerItems.size
|
||||
|
||||
fun getItem(position: Int): ITEM? = items.getOrNull(position)
|
||||
|
||||
@@ -431,6 +446,15 @@ abstract class RecyclerAdapter<ITEM, VB : ViewBinding>(protected val context: Co
|
||||
}
|
||||
}
|
||||
|
||||
fun upResumed(isResumed: Boolean) {
|
||||
if (!isResumed) {
|
||||
diffJob?.cancel()
|
||||
diffJob = null
|
||||
handler.removeCallbacksAndMessages(null)
|
||||
}
|
||||
this.isResumed = isResumed
|
||||
}
|
||||
|
||||
private fun isHeader(position: Int) = position < getHeaderCount()
|
||||
|
||||
private fun isFooter(position: Int) = position >= getActualItemCount() + getHeaderCount()
|
||||
@@ -479,8 +503,4 @@ abstract class RecyclerAdapter<ITEM, VB : ViewBinding>(protected val context: Co
|
||||
private val handler by lazy { buildMainHandler() }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -4,7 +4,6 @@ import android.annotation.SuppressLint
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.MotionEvent
|
||||
import android.view.SubMenu
|
||||
import android.view.WindowManager
|
||||
import androidx.activity.viewModels
|
||||
@@ -31,8 +30,7 @@ import io.legado.app.databinding.DialogEditTextBinding
|
||||
import io.legado.app.help.DirectLinkUpload
|
||||
import io.legado.app.help.config.LocalConfig
|
||||
import io.legado.app.lib.dialogs.alert
|
||||
//import io.legado.app.lib.theme.primaryColor
|
||||
//import io.legado.app.lib.theme.primaryTextColor
|
||||
import io.legado.app.lib.theme.primaryColor
|
||||
import io.legado.app.model.CheckSource
|
||||
import io.legado.app.model.Debug
|
||||
import io.legado.app.ui.association.ImportBookSourceDialog
|
||||
@@ -53,13 +51,12 @@ import io.legado.app.utils.cnCompare
|
||||
import io.legado.app.utils.dpToPx
|
||||
import io.legado.app.utils.flowWithLifecycleAndDatabaseChange
|
||||
import io.legado.app.utils.flowWithLifecycleAndDatabaseChangeFirst
|
||||
import io.legado.app.utils.hideSoftInput
|
||||
import io.legado.app.utils.isAbsUrl
|
||||
import io.legado.app.utils.launch
|
||||
import io.legado.app.utils.observeEvent
|
||||
import io.legado.app.utils.sendToClip
|
||||
import io.legado.app.utils.setEdgeEffectColor
|
||||
import io.legado.app.utils.share
|
||||
import io.legado.app.utils.shouldHideSoftInput
|
||||
import io.legado.app.utils.showDialogFragment
|
||||
import io.legado.app.utils.showHelp
|
||||
import io.legado.app.utils.splitNotBlank
|
||||
@@ -272,7 +269,7 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
|
||||
}
|
||||
|
||||
private fun initRecyclerView() {
|
||||
//binding.recyclerView.setEdgeEffectColor(primaryColor)
|
||||
binding.recyclerView.setEdgeEffectColor(primaryColor)
|
||||
binding.recyclerView.addItemDecoration(VerticalDivider(this))
|
||||
binding.recyclerView.adapter = adapter
|
||||
binding.recyclerView.recycledViewPool.setMaxRecycledViews(0, 15)
|
||||
@@ -286,7 +283,6 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
|
||||
}
|
||||
|
||||
private fun initSearchView() {
|
||||
//searchView.applyTint(primaryTextColor)
|
||||
searchView.queryHint = getString(R.string.search_book_source)
|
||||
searchView.setOnQueryTextListener(this)
|
||||
}
|
||||
@@ -394,6 +390,16 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
adapter.upResumed(true)
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
adapter.upResumed(false)
|
||||
super.onPause()
|
||||
}
|
||||
|
||||
private fun initLiveDataGroup() {
|
||||
lifecycleScope.launch {
|
||||
appDb.bookSourceDao.flowGroups()
|
||||
@@ -472,11 +478,11 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
|
||||
searchView.query?.toString(),
|
||||
sortAscending,
|
||||
sort
|
||||
) { file ->
|
||||
) { file, name ->
|
||||
exportDir.launch {
|
||||
mode = HandleFileContract.EXPORT
|
||||
fileData = HandleFileContract.FileData(
|
||||
"bookSource.json",
|
||||
name,
|
||||
file,
|
||||
"application/json"
|
||||
)
|
||||
@@ -488,8 +494,8 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
|
||||
searchView.query?.toString(),
|
||||
sortAscending,
|
||||
sort
|
||||
) {
|
||||
share(it)
|
||||
) { file, name ->
|
||||
share(file)
|
||||
}
|
||||
|
||||
R.id.menu_check_selected_interval -> adapter.checkSelectedInterval()
|
||||
@@ -594,7 +600,7 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
|
||||
?.toMutableList() ?: mutableListOf()
|
||||
alert(titleResource = R.string.import_on_line) {
|
||||
val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply {
|
||||
editLayout.hint = "URL"
|
||||
editView.hint = "url"
|
||||
editView.setFilterValues(cacheUrls)
|
||||
editView.delCallBack = {
|
||||
cacheUrls.remove(it)
|
||||
|
||||
@@ -12,6 +12,7 @@ import io.legado.app.help.source.SourceHelp
|
||||
import io.legado.app.utils.FileUtils
|
||||
import io.legado.app.utils.GSON
|
||||
import io.legado.app.utils.cnCompare
|
||||
import io.legado.app.utils.normalizeFileName
|
||||
import io.legado.app.utils.outputStream
|
||||
import io.legado.app.utils.splitNotBlank
|
||||
import io.legado.app.utils.stackTraceStr
|
||||
@@ -19,6 +20,8 @@ import io.legado.app.utils.toastOnUi
|
||||
import io.legado.app.utils.writeToOutputStream
|
||||
import splitties.init.appCtx
|
||||
import java.io.File
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
|
||||
/**
|
||||
* 书源管理数据修改
|
||||
@@ -123,7 +126,11 @@ class BookSourceViewModel(application: Application) : BaseViewModel(application)
|
||||
}
|
||||
}
|
||||
|
||||
private fun saveToFile(sources: List<BookSource>, success: (file: File) -> Unit) {
|
||||
private fun saveToFile(
|
||||
sources: List<BookSource>,
|
||||
name: String,
|
||||
success: (file: File, name: String) -> Unit
|
||||
) {
|
||||
execute {
|
||||
val path = "${context.filesDir}/shareBookSource.json"
|
||||
FileUtils.delete(path)
|
||||
@@ -133,7 +140,7 @@ class BookSourceViewModel(application: Application) : BaseViewModel(application)
|
||||
}
|
||||
file
|
||||
}.onSuccess {
|
||||
success.invoke(it)
|
||||
success.invoke(it, name)
|
||||
}.onError {
|
||||
context.toastOnUi(it.stackTraceStr)
|
||||
}
|
||||
@@ -144,11 +151,12 @@ class BookSourceViewModel(application: Application) : BaseViewModel(application)
|
||||
searchKey: String?,
|
||||
sortAscending: Boolean,
|
||||
sort: BookSourceSort,
|
||||
success: (file: File) -> Unit
|
||||
success: (file: File, name: String) -> Unit
|
||||
) {
|
||||
execute {
|
||||
val selection = adapter.selection
|
||||
val selectedRate = selection.size.toFloat() / adapter.itemCount.toFloat()
|
||||
val selectionSize = selection.size
|
||||
val selectedRate = selectionSize.toFloat() / adapter.itemCount.toFloat()
|
||||
val sources = if (selectedRate == 1f) {
|
||||
getBookSources(searchKey, sortAscending, sort)
|
||||
} else if (selectedRate < 0.3) {
|
||||
@@ -160,7 +168,14 @@ class BookSourceViewModel(application: Application) : BaseViewModel(application)
|
||||
keys.contains(it.bookSourceUrl)
|
||||
}
|
||||
}
|
||||
saveToFile(sources, success)
|
||||
val name = if (selectionSize == 1) {
|
||||
"bookSource_${selection.first().bookSourceName.normalizeFileName()}.json"
|
||||
} else {
|
||||
val timestamp =
|
||||
java.text.SimpleDateFormat("yyyyMMddHHmm", Locale.getDefault()).format(Date())
|
||||
"bookSource_$timestamp.json"
|
||||
}
|
||||
saveToFile(sources, name, success)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user