Horis 2 лет назад
Родитель
Сommit
1ce02e2748

+ 47 - 28
app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt

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

+ 10 - 20
app/src/main/java/io/legado/app/ui/main/bookshelf/style1/books/BooksFragment.kt

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

+ 8 - 16
app/src/main/java/io/legado/app/ui/main/explore/ExploreFragment.kt

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

+ 0 - 35
app/src/main/java/io/legado/app/ui/main/rss/RssAdapter.kt

@@ -1,17 +1,11 @@
 package io.legado.app.ui.main.rss
 
 import android.content.Context
-import android.graphics.drawable.Drawable
 import android.view.View
 import android.view.ViewGroup
 import androidx.appcompat.widget.PopupMenu
 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.target.Target
 import io.legado.app.R
 import io.legado.app.base.adapter.ItemViewHolder
 import io.legado.app.base.adapter.RecyclerAdapter
@@ -39,35 +33,6 @@ class RssAdapter(context: Context, val callBack: CallBack, val lifecycle: Lifecy
             val options = RequestOptions()
                 .set(OkHttpModelLoader.sourceOriginOption, item.sourceUrl)
             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)
                 .centerCrop()
                 .placeholder(R.drawable.image_rss)

+ 13 - 10
app/src/main/java/io/legado/app/ui/main/rss/RssFragment.kt

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