This commit is contained in:
Horis 2024-01-24 10:07:07 +08:00
parent 9b49200a85
commit 5324dfcec3
5 changed files with 78 additions and 109 deletions

View File

@ -2,14 +2,21 @@ package io.legado.app.ui.book.source.manage
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.os.Bundle import android.os.Bundle
import android.view.* import android.view.Menu
import android.view.MenuItem
import android.view.MotionEvent
import android.view.SubMenu
import android.view.WindowManager
import android.widget.EditText import android.widget.EditText
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.appcompat.widget.PopupMenu import androidx.appcompat.widget.PopupMenu
import androidx.appcompat.widget.SearchView import androidx.appcompat.widget.SearchView
import androidx.core.os.bundleOf import androidx.core.os.bundleOf
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.flowWithLifecycle
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.ItemTouchHelper
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import io.legado.app.R import io.legado.app.R
@ -40,15 +47,31 @@ import io.legado.app.ui.widget.dialog.TextDialog
import io.legado.app.ui.widget.recycler.DragSelectTouchHelper import io.legado.app.ui.widget.recycler.DragSelectTouchHelper
import io.legado.app.ui.widget.recycler.ItemTouchCallback import io.legado.app.ui.widget.recycler.ItemTouchCallback
import io.legado.app.ui.widget.recycler.VerticalDivider import io.legado.app.ui.widget.recycler.VerticalDivider
import io.legado.app.utils.* import io.legado.app.utils.ACache
import io.legado.app.utils.applyTint
import io.legado.app.utils.cnCompare
import io.legado.app.utils.dpToPx
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.showDialogFragment
import io.legado.app.utils.splitNotBlank
import io.legado.app.utils.startActivity
import io.legado.app.utils.toastOnUi
import io.legado.app.utils.viewbindingdelegate.viewBinding import io.legado.app.utils.viewbindingdelegate.viewBinding
import kotlinx.coroutines.*
import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.conflate import kotlinx.coroutines.flow.conflate
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
/** /**
* 书源管理界面 * 书源管理界面
@ -67,6 +90,7 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
binding.titleBar.findViewById(R.id.search_view) binding.titleBar.findViewById(R.id.search_view)
} }
private var sourceFlowJob: Job? = null private var sourceFlowJob: Job? = null
private var checkMessageRefreshJob: Job? = null
private val groups = linkedSetOf<String>() private val groups = linkedSetOf<String>()
private var groupMenu: SubMenu? = null private var groupMenu: SubMenu? = null
override var sort = BookSourceSort.Default override var sort = BookSourceSort.Default
@ -75,7 +99,6 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
private set private set
private var snackBar: Snackbar? = null private var snackBar: Snackbar? = null
private var isPaused = false private var isPaused = false
private var searchKey: String? = null
private val qrResult = registerForActivityResult(QrCodeResult()) { private val qrResult = registerForActivityResult(QrCodeResult()) {
it ?: return@registerForActivityResult it ?: return@registerForActivityResult
showDialogFragment(ImportBookSourceDialog(it)) showDialogFragment(ImportBookSourceDialog(it))
@ -256,7 +279,6 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
private fun upBookSource(searchKey: String? = null) { private fun upBookSource(searchKey: String? = null) {
this.searchKey = searchKey
sourceFlowJob?.cancel() sourceFlowJob?.cancel()
sourceFlowJob = lifecycleScope.launch { sourceFlowJob = lifecycleScope.launch {
when { when {
@ -338,7 +360,7 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
else -> data.reversed() else -> data.reversed()
} }
} }
}.catch { }.flowWithLifecycle(lifecycle).catch {
AppLog.put("书源界面更新书源出错", it) AppLog.put("书源界面更新书源出错", it)
}.flowOn(IO).conflate().collect { data -> }.flowOn(IO).conflate().collect { data ->
adapter.setItems(data, adapter.diffItemCallback, !Debug.isChecking) adapter.setItems(data, adapter.diffItemCallback, !Debug.isChecking)
@ -403,7 +425,7 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
R.id.menu_remove_group -> selectionRemoveFromGroups() R.id.menu_remove_group -> selectionRemoveFromGroups()
R.id.menu_export_selection -> viewModel.saveToFile( R.id.menu_export_selection -> viewModel.saveToFile(
adapter, adapter,
searchKey, searchView.query?.toString(),
sortAscending, sortAscending,
sort sort
) { file -> ) { file ->
@ -419,7 +441,7 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
R.id.menu_share_source -> viewModel.saveToFile( R.id.menu_share_source -> viewModel.saveToFile(
adapter, adapter,
searchKey, searchView.query?.toString(),
sortAscending, sortAscending,
sort sort
) { ) {
@ -452,7 +474,7 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
val firstItem = adapterItems.indexOf(selectItems.firstOrNull()) val firstItem = adapterItems.indexOf(selectItems.firstOrNull())
val lastItem = adapterItems.indexOf(selectItems.lastOrNull()) val lastItem = adapterItems.indexOf(selectItems.lastOrNull())
Debug.isChecking = firstItem >= 0 && lastItem >= 0 Debug.isChecking = firstItem >= 0 && lastItem >= 0
checkMessageRefreshJob(firstItem, lastItem).start() startCheckMessageRefreshJob(firstItem, lastItem)
} }
neutralButton(R.string.check_source_config) neutralButton(R.string.check_source_config)
cancelButton() cancelButton()
@ -469,7 +491,7 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
} }
keepScreenOn(true) keepScreenOn(true)
CheckSource.resume(this) CheckSource.resume(this)
checkMessageRefreshJob(0, 0).start() startCheckMessageRefreshJob(0, 0)
} }
@SuppressLint("InflateParams") @SuppressLint("InflateParams")
@ -558,11 +580,6 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
.setAction(R.string.cancel) { .setAction(R.string.cancel) {
CheckSource.stop(this) CheckSource.stop(this)
Debug.finishChecking() Debug.finishChecking()
adapter.notifyItemRangeChanged(
0,
adapter.itemCount,
bundleOf(Pair("checkSourceMessage", null))
)
}.apply { show() } }.apply { show() }
} }
} }
@ -570,6 +587,11 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
keepScreenOn(false) keepScreenOn(false)
snackBar?.dismiss() snackBar?.dismiss()
snackBar = null snackBar = null
adapter.notifyItemRangeChanged(
0,
adapter.itemCount,
bundleOf(Pair("checkSourceMessage", null))
)
groups.map { group -> groups.map { group ->
if (group.contains("失效") && searchView.query.isEmpty()) { if (group.contains("失效") && searchView.query.isEmpty()) {
searchView.setQuery("失效", true) searchView.setQuery("失效", true)
@ -579,15 +601,11 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
} }
} }
private fun checkMessageRefreshJob(firstItem: Int, lastItem: Int): Job { private fun startCheckMessageRefreshJob(firstItem: Int, lastItem: Int) {
return lifecycleScope.async(start = CoroutineStart.LAZY) { checkMessageRefreshJob?.cancel()
flow { checkMessageRefreshJob = lifecycleScope.launch {
while (true) { repeatOnLifecycle(Lifecycle.State.STARTED) {
emit(Debug.isChecking) while (isActive) {
delay(300L)
}
}.collect {
if (SystemUtils.isScreenOn() && !isPaused) {
if (lastItem == 0) { if (lastItem == 0) {
adapter.notifyItemRangeChanged( adapter.notifyItemRangeChanged(
0, 0,
@ -601,9 +619,10 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
bundleOf(Pair("checkSourceMessage", null)) bundleOf(Pair("checkSourceMessage", null))
) )
} }
if (!Debug.isChecking) {
checkMessageRefreshJob?.cancel()
} }
if (!it) { delay(300L)
this.cancel()
} }
} }
} }

View File

@ -5,7 +5,10 @@ import android.os.Bundle
import android.view.View import android.view.View
import androidx.core.view.isGone import androidx.core.view.isGone
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.flowWithLifecycle
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
@ -25,7 +28,6 @@ import io.legado.app.ui.book.audio.AudioPlayActivity
import io.legado.app.ui.book.info.BookInfoActivity import io.legado.app.ui.book.info.BookInfoActivity
import io.legado.app.ui.book.read.ReadBookActivity import io.legado.app.ui.book.read.ReadBookActivity
import io.legado.app.ui.main.MainViewModel import io.legado.app.ui.main.MainViewModel
import io.legado.app.utils.SystemUtils
import io.legado.app.utils.cnCompare import io.legado.app.utils.cnCompare
import io.legado.app.utils.observeEvent import io.legado.app.utils.observeEvent
import io.legado.app.utils.setEdgeEffectColor import io.legado.app.utils.setEdgeEffectColor
@ -62,7 +64,7 @@ class BooksFragment() : BaseFragment(R.layout.fragment_books),
private val bookshelfLayout by lazy { AppConfig.bookshelfLayout } private val bookshelfLayout by lazy { AppConfig.bookshelfLayout }
private val booksAdapter: BaseBooksAdapter<*> by lazy { private val booksAdapter: BaseBooksAdapter<*> by lazy {
if (bookshelfLayout == 0) { if (bookshelfLayout == 0) {
BooksAdapterList(requireContext(), this, lifecycle) BooksAdapterList(requireContext(), this, viewLifecycleOwner.lifecycle)
} else { } else {
BooksAdapterGrid(requireContext(), this) BooksAdapterGrid(requireContext(), this)
} }
@ -154,7 +156,7 @@ class BooksFragment() : BaseFragment(R.layout.fragment_books),
*/ */
private fun upRecyclerData() { private fun upRecyclerData() {
booksFlowJob?.cancel() booksFlowJob?.cancel()
booksFlowJob = lifecycleScope.launch { booksFlowJob = viewLifecycleOwner.lifecycleScope.launch {
appDb.bookDao.flowByGroup(groupId).map { list -> appDb.bookDao.flowByGroup(groupId).map { list ->
//排序 //排序
when (bookSort) { when (bookSort) {
@ -172,9 +174,9 @@ class BooksFragment() : BaseFragment(R.layout.fragment_books),
else -> list.sortedByDescending { it.durChapterTime } else -> list.sortedByDescending { it.durChapterTime }
} }
}.flowOn(Dispatchers.Default).catch { }.flowWithLifecycle(viewLifecycleOwner.lifecycle, Lifecycle.State.RESUMED).catch {
AppLog.put("书架更新出错", it) AppLog.put("书架更新出错", it)
}.conflate().collect { list -> }.conflate().flowOn(Dispatchers.Default).collect { list ->
binding.tvEmptyMsg.isGone = list.isNotEmpty() binding.tvEmptyMsg.isGone = list.isNotEmpty()
binding.refreshLayout.isEnabled = enableRefresh && list.isNotEmpty() binding.refreshLayout.isEnabled = enableRefresh && list.isNotEmpty()
booksAdapter.setItems(list) booksAdapter.setItems(list)
@ -197,32 +199,20 @@ class BooksFragment() : BaseFragment(R.layout.fragment_books),
} }
} }
override fun onPause() {
super.onPause()
upLastUpdateTimeJob?.cancel()
booksFlowJob?.cancel()
}
override fun onResume() {
super.onResume()
startLastUpdateTimeJob()
upRecyclerData()
}
private fun startLastUpdateTimeJob() { private fun startLastUpdateTimeJob() {
upLastUpdateTimeJob?.cancel() upLastUpdateTimeJob?.cancel()
if (!AppConfig.showLastUpdateTime) { if (!AppConfig.showLastUpdateTime) {
return return
} }
upLastUpdateTimeJob = lifecycleScope.launch { upLastUpdateTimeJob = lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) {
while (isActive) { while (isActive) {
if (SystemUtils.isScreenOn()) {
booksAdapter.upLastUpdateTime() booksAdapter.upLastUpdateTime()
}
delay(30 * 1000) delay(30 * 1000)
} }
} }
} }
}
fun getBooks(): List<Book> { fun getBooks(): List<Book> {
return booksAdapter.getItems() return booksAdapter.getItems()

View File

@ -8,6 +8,8 @@ import android.view.View
import androidx.appcompat.widget.SearchView import androidx.appcompat.widget.SearchView
import androidx.core.view.isGone import androidx.core.view.isGone
import androidx.fragment.app.viewModels import androidx.fragment.app.viewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.flowWithLifecycle
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
@ -34,7 +36,6 @@ import io.legado.app.utils.viewbindingdelegate.viewBinding
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.cancel
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.conflate import kotlinx.coroutines.flow.conflate
@ -67,14 +68,13 @@ class ExploreFragment() : VMBaseFragment<ExploreViewModel>(R.layout.fragment_exp
private val groups = linkedSetOf<String>() private val groups = linkedSetOf<String>()
private var exploreFlowJob: Job? = null private var exploreFlowJob: Job? = null
private var groupsMenu: SubMenu? = null private var groupsMenu: SubMenu? = null
private var searchKey: String? = null
override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) { override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) {
setSupportToolbar(binding.titleBar.toolbar) setSupportToolbar(binding.titleBar.toolbar)
initSearchView() initSearchView()
initRecyclerView() initRecyclerView()
initGroupData() initGroupData()
upExploreData(once = true) upExploreData()
} }
override fun onCompatCreateOptionsMenu(menu: Menu) { override fun onCompatCreateOptionsMenu(menu: Menu) {
@ -87,7 +87,6 @@ class ExploreFragment() : VMBaseFragment<ExploreViewModel>(R.layout.fragment_exp
override fun onPause() { override fun onPause() {
super.onPause() super.onPause()
searchView.clearFocus() searchView.clearFocus()
exploreFlowJob?.cancel()
} }
private fun initSearchView() { private fun initSearchView() {
@ -126,7 +125,7 @@ class ExploreFragment() : VMBaseFragment<ExploreViewModel>(R.layout.fragment_exp
} }
private fun initGroupData() { private fun initGroupData() {
lifecycleScope.launch { viewLifecycleOwner.lifecycleScope.launch {
appDb.bookSourceDao.flowExploreGroups().conflate().collect { appDb.bookSourceDao.flowExploreGroups().conflate().collect {
groups.clear() groups.clear()
groups.addAll(it) groups.addAll(it)
@ -135,10 +134,9 @@ class ExploreFragment() : VMBaseFragment<ExploreViewModel>(R.layout.fragment_exp
} }
} }
private fun upExploreData(searchKey: String? = null, once: Boolean = false) { private fun upExploreData(searchKey: String? = null) {
this.searchKey = searchKey
exploreFlowJob?.cancel() exploreFlowJob?.cancel()
exploreFlowJob = lifecycleScope.launch { exploreFlowJob = viewLifecycleOwner.lifecycleScope.launch {
when { when {
searchKey.isNullOrBlank() -> { searchKey.isNullOrBlank() -> {
appDb.bookSourceDao.flowExplore() appDb.bookSourceDao.flowExplore()
@ -152,12 +150,11 @@ class ExploreFragment() : VMBaseFragment<ExploreViewModel>(R.layout.fragment_exp
else -> { else -> {
appDb.bookSourceDao.flowExplore(searchKey) appDb.bookSourceDao.flowExplore(searchKey)
} }
}.catch { }.flowWithLifecycle(viewLifecycleOwner.lifecycle, Lifecycle.State.RESUMED).catch {
AppLog.put("发现界面更新数据出错", it) AppLog.put("发现界面更新数据出错", it)
}.conflate().flowOn(IO).collect { }.conflate().flowOn(IO).collect {
binding.tvEmptyMsg.isGone = it.isNotEmpty() || searchView.query.isNotEmpty() binding.tvEmptyMsg.isGone = it.isNotEmpty() || searchView.query.isNotEmpty()
adapter.setItems(it, diffItemCallBack) adapter.setItems(it, diffItemCallBack)
if (once) cancel()
delay(500) delay(500)
} }
} }
@ -173,7 +170,7 @@ class ExploreFragment() : VMBaseFragment<ExploreViewModel>(R.layout.fragment_exp
} }
override val scope: CoroutineScope override val scope: CoroutineScope
get() = lifecycleScope get() = viewLifecycleOwner.lifecycleScope
override fun onCompatOptionsItemSelected(item: MenuItem) { override fun onCompatOptionsItemSelected(item: MenuItem) {
super.onCompatOptionsItemSelected(item) super.onCompatOptionsItemSelected(item)
@ -231,9 +228,4 @@ class ExploreFragment() : VMBaseFragment<ExploreViewModel>(R.layout.fragment_exp
} }
} }
override fun onResume() {
super.onResume()
upExploreData(searchKey)
}
} }

View File

@ -1,17 +1,11 @@
package io.legado.app.ui.main.rss package io.legado.app.ui.main.rss
import android.content.Context import android.content.Context
import android.graphics.drawable.Drawable
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.appcompat.widget.PopupMenu import androidx.appcompat.widget.PopupMenu
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.engine.GlideException
import com.bumptech.glide.load.resource.gif.GifDrawable
import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.RequestOptions import com.bumptech.glide.request.RequestOptions
import com.bumptech.glide.request.target.Target
import io.legado.app.R import io.legado.app.R
import io.legado.app.base.adapter.ItemViewHolder import io.legado.app.base.adapter.ItemViewHolder
import io.legado.app.base.adapter.RecyclerAdapter import io.legado.app.base.adapter.RecyclerAdapter
@ -39,35 +33,6 @@ class RssAdapter(context: Context, val callBack: CallBack, val lifecycle: Lifecy
val options = RequestOptions() val options = RequestOptions()
.set(OkHttpModelLoader.sourceOriginOption, item.sourceUrl) .set(OkHttpModelLoader.sourceOriginOption, item.sourceUrl)
ImageLoader.load(lifecycle, item.sourceIcon) ImageLoader.load(lifecycle, item.sourceIcon)
.listener(object : RequestListener<Drawable> {
override fun onLoadFailed(
e: GlideException?,
model: Any?,
target: Target<Drawable>,
isFirstResource: Boolean
): Boolean {
return false
}
override fun onResourceReady(
resource: Drawable,
model: Any,
target: Target<Drawable>?,
dataSource: DataSource,
isFirstResource: Boolean
): Boolean {
if (resource is GifDrawable
&& !lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED)
) {
ivIcon.post {
resource.stop()
}
}
return false
}
})
.apply(options) .apply(options)
.centerCrop() .centerCrop()
.placeholder(R.drawable.image_rss) .placeholder(R.drawable.image_rss)

View File

@ -7,6 +7,8 @@ import android.view.SubMenu
import android.view.View import android.view.View
import androidx.appcompat.widget.SearchView import androidx.appcompat.widget.SearchView
import androidx.fragment.app.viewModels import androidx.fragment.app.viewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.flowWithLifecycle
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import io.legado.app.R import io.legado.app.R
import io.legado.app.base.VMBaseFragment import io.legado.app.base.VMBaseFragment
@ -58,7 +60,7 @@ class RssFragment() : VMBaseFragment<RssViewModel>(R.layout.fragment_rss),
private val binding by viewBinding(FragmentRssBinding::bind) private val binding by viewBinding(FragmentRssBinding::bind)
override val viewModel by viewModels<RssViewModel>() override val viewModel by viewModels<RssViewModel>()
private val adapter by lazy { RssAdapter(requireContext(), this, lifecycle) } private val adapter by lazy { RssAdapter(requireContext(), this, viewLifecycleOwner.lifecycle) }
private val searchView: SearchView by lazy { private val searchView: SearchView by lazy {
binding.titleBar.findViewById(R.id.search_view) binding.titleBar.findViewById(R.id.search_view)
} }
@ -142,10 +144,11 @@ class RssFragment() : VMBaseFragment<RssViewModel>(R.layout.fragment_rss),
private fun initGroupData() { private fun initGroupData() {
groupsFlowJob?.cancel() groupsFlowJob?.cancel()
groupsFlowJob = lifecycleScope.launch { groupsFlowJob = viewLifecycleOwner.lifecycleScope.launch {
appDb.rssSourceDao.flowGroupEnabled().catch { appDb.rssSourceDao.flowGroupEnabled().catch {
AppLog.put("订阅界面获取分组数据失败\n${it.localizedMessage}", it) AppLog.put("订阅界面获取分组数据失败\n${it.localizedMessage}", it)
}.flowOn(IO).conflate().collect { }.flowWithLifecycle(viewLifecycleOwner.lifecycle, Lifecycle.State.RESUMED)
.flowOn(IO).conflate().collect {
groups.clear() groups.clear()
it.map { group -> it.map { group ->
groups.addAll(group.splitNotBlank(AppPattern.splitGroupRegex)) groups.addAll(group.splitNotBlank(AppPattern.splitGroupRegex))
@ -157,7 +160,7 @@ class RssFragment() : VMBaseFragment<RssViewModel>(R.layout.fragment_rss),
private fun upRssFlowJob(searchKey: String? = null) { private fun upRssFlowJob(searchKey: String? = null) {
rssFlowJob?.cancel() rssFlowJob?.cancel()
rssFlowJob = lifecycleScope.launch { rssFlowJob = viewLifecycleOwner.lifecycleScope.launch {
when { when {
searchKey.isNullOrEmpty() -> appDb.rssSourceDao.flowEnabled() searchKey.isNullOrEmpty() -> appDb.rssSourceDao.flowEnabled()
searchKey.startsWith("group:") -> { searchKey.startsWith("group:") -> {
@ -166,7 +169,7 @@ class RssFragment() : VMBaseFragment<RssViewModel>(R.layout.fragment_rss),
} }
else -> appDb.rssSourceDao.flowEnabled(searchKey) else -> appDb.rssSourceDao.flowEnabled(searchKey)
}.catch { }.flowWithLifecycle(viewLifecycleOwner.lifecycle, Lifecycle.State.RESUMED).catch {
AppLog.put("订阅界面更新数据出错", it) AppLog.put("订阅界面更新数据出错", it)
}.flowOn(IO).collect { }.flowOn(IO).collect {
adapter.setItems(it) adapter.setItems(it)