pull/1155/head
gedoor 4 years ago
parent 688ee2e986
commit ed891c3e2b
  1. 1
      app/build.gradle
  2. 16
      app/src/main/java/io/legado/app/data/dao/BookDao.kt
  3. 24
      app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt
  4. 28
      app/src/main/java/io/legado/app/ui/book/arrange/ArrangeBookActivity.kt
  5. 47
      app/src/main/java/io/legado/app/ui/book/cache/CacheActivity.kt
  6. 16
      app/src/main/java/io/legado/app/ui/book/changesource/ChangeSourceDialog.kt
  7. 13
      app/src/main/java/io/legado/app/ui/book/local/ImportBookActivity.kt
  8. 55
      app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt
  9. 83
      app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt
  10. 23
      app/src/main/java/io/legado/app/ui/book/source/manage/GroupManageDialog.kt
  11. 24
      app/src/main/java/io/legado/app/ui/main/bookshelf/style1/books/BooksFragment.kt
  12. 23
      app/src/main/java/io/legado/app/ui/main/bookshelf/style2/BookshelfFragment2.kt
  13. 70
      app/src/main/java/io/legado/app/ui/main/explore/ExploreFragment.kt

@ -169,6 +169,7 @@ dependencies {
//room //room
def room_version = '2.3.0' def room_version = '2.3.0'
implementation("androidx.room:room-runtime:$room_version") implementation("androidx.room:room-runtime:$room_version")
implementation("androidx.room:room-ktx:$room_version")
kapt("androidx.room:room-compiler:$room_version") kapt("androidx.room:room-compiler:$room_version")
testImplementation("androidx.room:room-testing:$room_version") testImplementation("androidx.room:room-testing:$room_version")

@ -1,33 +1,33 @@
package io.legado.app.data.dao package io.legado.app.data.dao
import androidx.lifecycle.LiveData
import androidx.room.* import androidx.room.*
import io.legado.app.constant.BookType import io.legado.app.constant.BookType
import io.legado.app.data.entities.Book import io.legado.app.data.entities.Book
import kotlinx.coroutines.flow.Flow
@Dao @Dao
interface BookDao { interface BookDao {
@Query("SELECT * FROM books order by durChapterTime desc") @Query("SELECT * FROM books order by durChapterTime desc")
fun observeAll(): LiveData<List<Book>> fun observeAll(): Flow<List<Book>>
@Query("SELECT * FROM books WHERE type = ${BookType.audio}") @Query("SELECT * FROM books WHERE type = ${BookType.audio}")
fun observeAudio(): LiveData<List<Book>> fun observeAudio(): Flow<List<Book>>
@Query("SELECT * FROM books WHERE origin = '${BookType.local}'") @Query("SELECT * FROM books WHERE origin = '${BookType.local}'")
fun observeLocal(): LiveData<List<Book>> fun observeLocal(): Flow<List<Book>>
@Query("select * from books where type != ${BookType.audio} and origin != '${BookType.local}' and ((SELECT sum(groupId) FROM book_groups where groupId > 0) & `group`) = 0") @Query("select * from books where type != ${BookType.audio} and origin != '${BookType.local}' and ((SELECT sum(groupId) FROM book_groups where groupId > 0) & `group`) = 0")
fun observeNoGroup(): LiveData<List<Book>> fun observeNoGroup(): Flow<List<Book>>
@Query("SELECT bookUrl FROM books WHERE origin = '${BookType.local}'") @Query("SELECT bookUrl FROM books WHERE origin = '${BookType.local}'")
fun observeLocalUri(): LiveData<List<String>> fun observeLocalUri(): Flow<List<String>>
@Query("SELECT * FROM books WHERE (`group` & :group) > 0") @Query("SELECT * FROM books WHERE (`group` & :group) > 0")
fun observeByGroup(group: Long): LiveData<List<Book>> fun observeByGroup(group: Long): Flow<List<Book>>
@Query("SELECT * FROM books WHERE name like '%'||:key||'%' or author like '%'||:key||'%'") @Query("SELECT * FROM books WHERE name like '%'||:key||'%' or author like '%'||:key||'%'")
fun liveDataSearch(key: String): LiveData<List<Book>> fun liveDataSearch(key: String): Flow<List<Book>>
@Query("SELECT * FROM books WHERE (`group` & :group) > 0") @Query("SELECT * FROM books WHERE (`group` & :group) > 0")
fun getBooksByGroup(group: Long): List<Book> fun getBooksByGroup(group: Long): List<Book>

@ -1,14 +1,14 @@
package io.legado.app.data.dao package io.legado.app.data.dao
import androidx.lifecycle.LiveData
import androidx.room.* import androidx.room.*
import io.legado.app.data.entities.BookSource import io.legado.app.data.entities.BookSource
import kotlinx.coroutines.flow.Flow
@Dao @Dao
interface BookSourceDao { interface BookSourceDao {
@Query("select * from book_sources order by customOrder asc") @Query("select * from book_sources order by customOrder asc")
fun liveDataAll(): LiveData<List<BookSource>> fun liveDataAll(): Flow<List<BookSource>>
@Query( @Query(
""" """
@ -20,19 +20,19 @@ interface BookSourceDao {
order by customOrder asc order by customOrder asc
""" """
) )
fun liveDataSearch(searchKey: String): LiveData<List<BookSource>> fun liveDataSearch(searchKey: String): Flow<List<BookSource>>
@Query("select * from book_sources where bookSourceGroup like :searchKey order by customOrder asc") @Query("select * from book_sources where bookSourceGroup like :searchKey order by customOrder asc")
fun liveDataGroupSearch(searchKey: String): LiveData<List<BookSource>> fun liveDataGroupSearch(searchKey: String): Flow<List<BookSource>>
@Query("select * from book_sources where enabled = 1 order by customOrder asc") @Query("select * from book_sources where enabled = 1 order by customOrder asc")
fun liveDataEnabled(): LiveData<List<BookSource>> fun liveDataEnabled(): Flow<List<BookSource>>
@Query("select * from book_sources where enabled = 0 order by customOrder asc") @Query("select * from book_sources where enabled = 0 order by customOrder asc")
fun liveDataDisabled(): LiveData<List<BookSource>> fun liveDataDisabled(): Flow<List<BookSource>>
@Query("select * from book_sources where enabledExplore = 1 and trim(exploreUrl) <> '' order by customOrder asc") @Query("select * from book_sources where enabledExplore = 1 and trim(exploreUrl) <> '' order by customOrder asc")
fun liveExplore(): LiveData<List<BookSource>> fun liveExplore(): Flow<List<BookSource>>
@Query( @Query(
""" """
@ -43,7 +43,7 @@ interface BookSourceDao {
order by customOrder asc order by customOrder asc
""" """
) )
fun liveExplore(key: String): LiveData<List<BookSource>> fun liveExplore(key: String): Flow<List<BookSource>>
@Query( @Query(
""" """
@ -54,13 +54,13 @@ interface BookSourceDao {
order by customOrder asc order by customOrder asc
""" """
) )
fun liveGroupExplore(key: String): LiveData<List<BookSource>> fun liveGroupExplore(key: String): Flow<List<BookSource>>
@Query("select distinct bookSourceGroup from book_sources where trim(bookSourceGroup) <> ''") @Query("select distinct bookSourceGroup from book_sources where trim(bookSourceGroup) <> ''")
fun liveGroup(): LiveData<List<String>> fun liveGroup(): Flow<List<String>>
@Query("select distinct bookSourceGroup from book_sources where enabled = 1 and trim(bookSourceGroup) <> ''") @Query("select distinct bookSourceGroup from book_sources where enabled = 1 and trim(bookSourceGroup) <> ''")
fun liveGroupEnabled(): LiveData<List<String>> fun liveGroupEnabled(): Flow<List<String>>
@Query( @Query(
""" """
@ -70,7 +70,7 @@ interface BookSourceDao {
and trim(bookSourceGroup) <> '' and trim(bookSourceGroup) <> ''
""" """
) )
fun liveExploreGroup(): LiveData<List<String>> fun liveExploreGroup(): Flow<List<String>>
@Query("select * from book_sources where bookSourceGroup like '%' || :group || '%'") @Query("select * from book_sources where bookSourceGroup like '%' || :group || '%'")
fun getByGroup(group: String): List<BookSource> fun getByGroup(group: String): List<BookSource>

@ -28,6 +28,8 @@ import io.legado.app.utils.cnCompare
import io.legado.app.utils.getPrefInt import io.legado.app.utils.getPrefInt
import io.legado.app.utils.viewbindingdelegate.viewBinding import io.legado.app.utils.viewbindingdelegate.viewBinding
import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
@ -45,7 +47,7 @@ class ArrangeBookActivity : VMBaseActivity<ActivityArrangeBookBinding, ArrangeBo
private val addToGroupRequestCode = 34 private val addToGroupRequestCode = 34
private lateinit var adapter: ArrangeBookAdapter private lateinit var adapter: ArrangeBookAdapter
private var groupLiveData: LiveData<List<BookGroup>>? = null private var groupLiveData: LiveData<List<BookGroup>>? = null
private var booksLiveData: LiveData<List<Book>>? = null private var booksFlowJob: Job? = null
private var menu: Menu? = null private var menu: Menu? = null
private var groupId: Long = -1 private var groupId: Long = -1
@ -118,26 +120,26 @@ class ArrangeBookActivity : VMBaseActivity<ActivityArrangeBookBinding, ArrangeBo
} }
private fun initBookData() { private fun initBookData() {
booksLiveData?.removeObservers(this) booksFlowJob?.cancel()
booksLiveData = booksFlowJob = launch {
when (groupId) { when (groupId) {
AppConst.bookGroupAllId -> appDb.bookDao.observeAll() AppConst.bookGroupAllId -> appDb.bookDao.observeAll()
AppConst.bookGroupLocalId -> appDb.bookDao.observeLocal() AppConst.bookGroupLocalId -> appDb.bookDao.observeLocal()
AppConst.bookGroupAudioId -> appDb.bookDao.observeAudio() AppConst.bookGroupAudioId -> appDb.bookDao.observeAudio()
AppConst.bookGroupNoneId -> appDb.bookDao.observeNoGroup() AppConst.bookGroupNoneId -> appDb.bookDao.observeNoGroup()
else -> appDb.bookDao.observeByGroup(groupId) else -> appDb.bookDao.observeByGroup(groupId)
} }.collect { list ->
booksLiveData?.observe(this, { list -> val books = when (getPrefInt(PreferKey.bookshelfSort)) {
val books = when (getPrefInt(PreferKey.bookshelfSort)) { 1 -> list.sortedByDescending { it.latestChapterTime }
1 -> list.sortedByDescending { it.latestChapterTime } 2 -> list.sortedWith { o1, o2 ->
2 -> list.sortedWith { o1, o2 -> o1.name.cnCompare(o2.name)
o1.name.cnCompare(o2.name) }
3 -> list.sortedBy { it.order }
else -> list.sortedByDescending { it.durChapterTime }
} }
3 -> list.sortedBy { it.order } adapter.setItems(books)
else -> list.sortedByDescending { it.durChapterTime }
} }
adapter.setItems(books) }
})
} }
override fun onCompatOptionsItemSelected(item: MenuItem): Boolean { override fun onCompatOptionsItemSelected(item: MenuItem): Boolean {

@ -31,6 +31,8 @@ import io.legado.app.utils.*
import io.legado.app.utils.viewbindingdelegate.viewBinding import io.legado.app.utils.viewbindingdelegate.viewBinding
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
@ -45,7 +47,7 @@ class CacheActivity : VMBaseActivity<ActivityCacheBookBinding, CacheViewModel>()
private val exportBookPathKey = "exportBookPath" private val exportBookPathKey = "exportBookPath"
lateinit var adapter: CacheAdapter lateinit var adapter: CacheAdapter
private var groupLiveData: LiveData<List<BookGroup>>? = null private var groupLiveData: LiveData<List<BookGroup>>? = null
private var booksLiveData: LiveData<List<Book>>? = null private var booksFlowJob: Job? = null
private var menu: Menu? = null private var menu: Menu? = null
private var exportPosition = -1 private var exportPosition = -1
private val groupList: ArrayList<BookGroup> = arrayListOf() private val groupList: ArrayList<BookGroup> = arrayListOf()
@ -147,29 +149,30 @@ class CacheActivity : VMBaseActivity<ActivityCacheBookBinding, CacheViewModel>()
} }
private fun initBookData() { private fun initBookData() {
booksLiveData?.removeObservers(this) booksFlowJob?.cancel()
booksLiveData = when (groupId) { booksFlowJob = launch {
AppConst.bookGroupAllId -> appDb.bookDao.observeAll() when (groupId) {
AppConst.bookGroupLocalId -> appDb.bookDao.observeLocal() AppConst.bookGroupAllId -> appDb.bookDao.observeAll()
AppConst.bookGroupAudioId -> appDb.bookDao.observeAudio() AppConst.bookGroupLocalId -> appDb.bookDao.observeLocal()
AppConst.bookGroupNoneId -> appDb.bookDao.observeNoGroup() AppConst.bookGroupAudioId -> appDb.bookDao.observeAudio()
else -> appDb.bookDao.observeByGroup(groupId) AppConst.bookGroupNoneId -> appDb.bookDao.observeNoGroup()
} else -> appDb.bookDao.observeByGroup(groupId)
booksLiveData?.observe(this, { list -> }.collect { list ->
val booksDownload = list.filter { val booksDownload = list.filter {
it.isOnLineTxt() it.isOnLineTxt()
} }
val books = when (getPrefInt(PreferKey.bookshelfSort)) { val books = when (getPrefInt(PreferKey.bookshelfSort)) {
1 -> booksDownload.sortedByDescending { it.latestChapterTime } 1 -> booksDownload.sortedByDescending { it.latestChapterTime }
2 -> booksDownload.sortedWith { o1, o2 -> 2 -> booksDownload.sortedWith { o1, o2 ->
o1.name.cnCompare(o2.name) o1.name.cnCompare(o2.name)
}
3 -> booksDownload.sortedBy { it.order }
else -> booksDownload.sortedByDescending { it.durChapterTime }
} }
3 -> booksDownload.sortedBy { it.order } adapter.setItems(books)
else -> booksDownload.sortedByDescending { it.durChapterTime } initCacheSize(books)
} }
adapter.setItems(books) }
initCacheSize(books)
})
} }
private fun initGroupData() { private fun initGroupData() {

@ -22,6 +22,8 @@ import io.legado.app.ui.book.source.manage.BookSourceActivity
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.*
import io.legado.app.utils.viewbindingdelegate.viewBinding import io.legado.app.utils.viewbindingdelegate.viewBinding
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
class ChangeSourceDialog : BaseDialogFragment(), class ChangeSourceDialog : BaseDialogFragment(),
@ -148,13 +150,15 @@ class ChangeSourceDialog : BaseDialogFragment(),
viewModel.searchBooksLiveData.observe(viewLifecycleOwner, { viewModel.searchBooksLiveData.observe(viewLifecycleOwner, {
adapter.setItems(it) adapter.setItems(it)
}) })
appDb.bookSourceDao.liveGroupEnabled().observe(this, { launch {
groups.clear() appDb.bookSourceDao.liveGroupEnabled().collect {
it.map { group -> groups.clear()
groups.addAll(group.splitNotBlank(AppPattern.splitGroupRegex)) it.map { group ->
groups.addAll(group.splitNotBlank(AppPattern.splitGroupRegex))
}
upGroupMenu()
} }
upGroupMenu() }
})
} }
private val stopMenuItem: MenuItem? private val stopMenuItem: MenuItem?

@ -9,7 +9,6 @@ import android.view.MenuItem
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.appcompat.widget.PopupMenu import androidx.appcompat.widget.PopupMenu
import androidx.documentfile.provider.DocumentFile import androidx.documentfile.provider.DocumentFile
import androidx.lifecycle.LiveData
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import io.legado.app.R import io.legado.app.R
import io.legado.app.base.VMBaseActivity import io.legado.app.base.VMBaseActivity
@ -27,6 +26,7 @@ import io.legado.app.utils.*
import io.legado.app.utils.viewbindingdelegate.viewBinding import io.legado.app.utils.viewbindingdelegate.viewBinding
import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import java.io.File import java.io.File
@ -46,7 +46,6 @@ class ImportBookActivity : VMBaseActivity<ActivityImportBookBinding, ImportBookV
private var rootDoc: DocumentFile? = null private var rootDoc: DocumentFile? = null
private val subDocs = arrayListOf<DocumentFile>() private val subDocs = arrayListOf<DocumentFile>()
private lateinit var adapter: ImportBookAdapter private lateinit var adapter: ImportBookAdapter
private var localUriLiveData: LiveData<List<String>>? = null
private var sdPath = FileUtils.getSdCardPath() private var sdPath = FileUtils.getSdCardPath()
private var path = sdPath private var path = sdPath
private val selectFolder = registerForActivityResult(FilePicker()) { uri -> private val selectFolder = registerForActivityResult(FilePicker()) { uri ->
@ -125,11 +124,11 @@ class ImportBookActivity : VMBaseActivity<ActivityImportBookBinding, ImportBookV
} }
private fun initData() { private fun initData() {
localUriLiveData?.removeObservers(this) launch {
localUriLiveData = appDb.bookDao.observeLocalUri() appDb.bookDao.observeLocalUri().collect {
localUriLiveData?.observe(this, { adapter.upBookHas(it)
adapter.upBookHas(it) }
}) }
} }
private fun initRootDoc() { private fun initRootDoc() {

@ -30,6 +30,8 @@ import io.legado.app.ui.widget.recycler.LoadMoreView
import io.legado.app.utils.* import io.legado.app.utils.*
import io.legado.app.utils.viewbindingdelegate.viewBinding import io.legado.app.utils.viewbindingdelegate.viewBinding
import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
@ -47,7 +49,7 @@ class SearchActivity : VMBaseActivity<ActivityBookSearchBinding, SearchViewModel
private lateinit var loadMoreView: LoadMoreView private lateinit var loadMoreView: LoadMoreView
private lateinit var searchView: SearchView private lateinit var searchView: SearchView
private var historyData: LiveData<List<SearchKeyword>>? = null private var historyData: LiveData<List<SearchKeyword>>? = null
private var bookData: LiveData<List<Book>>? = null private var booksFlowJob: Job? = null
private var menu: Menu? = null private var menu: Menu? = null
private var precisionSearchMenuItem: MenuItem? = null private var precisionSearchMenuItem: MenuItem? = null
private var groups = linkedSetOf<String>() private var groups = linkedSetOf<String>()
@ -58,7 +60,7 @@ class SearchActivity : VMBaseActivity<ActivityBookSearchBinding, SearchViewModel
initRecyclerView() initRecyclerView()
initSearchView() initSearchView()
initOtherView() initOtherView()
initLiveData() initData()
receiptIntent(intent) receiptIntent(intent)
} }
@ -189,14 +191,16 @@ class SearchActivity : VMBaseActivity<ActivityBookSearchBinding, SearchViewModel
binding.tvClearHistory.setOnClickListener { viewModel.clearHistory() } binding.tvClearHistory.setOnClickListener { viewModel.clearHistory() }
} }
private fun initLiveData() { private fun initData() {
appDb.bookSourceDao.liveGroupEnabled().observe(this, { launch {
groups.clear() appDb.bookSourceDao.liveGroupEnabled().collect {
it.map { group -> groups.clear()
groups.addAll(group.splitNotBlank(AppPattern.splitGroupRegex)) it.map { group ->
groups.addAll(group.splitNotBlank(AppPattern.splitGroupRegex))
}
upGroupMenu()
} }
upGroupMenu() }
})
viewModel.searchBookLiveData.observe(this, { viewModel.searchBookLiveData.observe(this, {
upSearchItems(it) upSearchItems(it)
}) })
@ -268,23 +272,26 @@ class SearchActivity : VMBaseActivity<ActivityBookSearchBinding, SearchViewModel
* 更新搜索历史 * 更新搜索历史
*/ */
private fun upHistory(key: String? = null) { private fun upHistory(key: String? = null) {
bookData?.removeObservers(this) booksFlowJob?.cancel()
if (key.isNullOrBlank()) { booksFlowJob = launch {
binding.tvBookShow.gone() if (key.isNullOrBlank()) {
binding.rvBookshelfSearch.gone() binding.tvBookShow.gone()
} else { binding.rvBookshelfSearch.gone()
bookData = appDb.bookDao.liveDataSearch(key) } else {
bookData?.observe(this, { val bookFlow = appDb.bookDao.liveDataSearch(key)
if (it.isEmpty()) { bookFlow.collect {
binding.tvBookShow.gone() if (it.isEmpty()) {
binding.rvBookshelfSearch.gone() binding.tvBookShow.gone()
} else { binding.rvBookshelfSearch.gone()
binding.tvBookShow.visible() } else {
binding.rvBookshelfSearch.visible() binding.tvBookShow.visible()
binding.rvBookshelfSearch.visible()
}
bookAdapter.setItems(it)
} }
bookAdapter.setItems(it) }
})
} }
historyData?.removeObservers(this) historyData?.removeObservers(this)
historyData = historyData =
if (key.isNullOrBlank()) { if (key.isNullOrBlank()) {

@ -10,7 +10,6 @@ import androidx.activity.viewModels
import androidx.appcompat.widget.PopupMenu import androidx.appcompat.widget.PopupMenu
import androidx.appcompat.widget.SearchView import androidx.appcompat.widget.SearchView
import androidx.documentfile.provider.DocumentFile import androidx.documentfile.provider.DocumentFile
import androidx.lifecycle.LiveData
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,6 +39,9 @@ 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.*
import io.legado.app.utils.viewbindingdelegate.viewBinding import io.legado.app.utils.viewbindingdelegate.viewBinding
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
import java.io.File import java.io.File
class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceViewModel>(), class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceViewModel>(),
@ -52,7 +54,7 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
private val importRecordKey = "bookSourceRecordKey" private val importRecordKey = "bookSourceRecordKey"
private lateinit var adapter: BookSourceAdapter private lateinit var adapter: BookSourceAdapter
private lateinit var searchView: SearchView private lateinit var searchView: SearchView
private var bookSourceLiveDate: LiveData<List<BookSource>>? = null private var sourceFlowJob: Job? = null
private val groups = linkedSetOf<String>() private val groups = linkedSetOf<String>()
private var groupMenu: SubMenu? = null private var groupMenu: SubMenu? = null
private var sort = Sort.Default private var sort = Sort.Default
@ -94,7 +96,7 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
searchView = binding.titleBar.findViewById(R.id.search_view) searchView = binding.titleBar.findViewById(R.id.search_view)
initRecyclerView() initRecyclerView()
initSearchView() initSearchView()
initLiveDataBookSource() upBookSource()
initLiveDataGroup() initLiveDataGroup()
initSelectActionBar() initSelectActionBar()
if (!LocalConfig.bookSourcesHelpVersionIsLast) { if (!LocalConfig.bookSourcesHelpVersionIsLast) {
@ -134,32 +136,32 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
R.id.menu_sort_manual -> { R.id.menu_sort_manual -> {
item.isChecked = true item.isChecked = true
sortCheck(Sort.Default) sortCheck(Sort.Default)
initLiveDataBookSource(searchView.query?.toString()) upBookSource(searchView.query?.toString())
} }
R.id.menu_sort_auto -> { R.id.menu_sort_auto -> {
item.isChecked = true item.isChecked = true
sortCheck(Sort.Weight) sortCheck(Sort.Weight)
initLiveDataBookSource(searchView.query?.toString()) upBookSource(searchView.query?.toString())
} }
R.id.menu_sort_name -> { R.id.menu_sort_name -> {
item.isChecked = true item.isChecked = true
sortCheck(Sort.Name) sortCheck(Sort.Name)
initLiveDataBookSource(searchView.query?.toString()) upBookSource(searchView.query?.toString())
} }
R.id.menu_sort_url -> { R.id.menu_sort_url -> {
item.isChecked = true item.isChecked = true
sortCheck(Sort.Url) sortCheck(Sort.Url)
initLiveDataBookSource(searchView.query?.toString()) upBookSource(searchView.query?.toString())
} }
R.id.menu_sort_time -> { R.id.menu_sort_time -> {
item.isChecked = true item.isChecked = true
sortCheck(Sort.Update) sortCheck(Sort.Update)
initLiveDataBookSource(searchView.query?.toString()) upBookSource(searchView.query?.toString())
} }
R.id.menu_sort_enable -> { R.id.menu_sort_enable -> {
item.isChecked = true item.isChecked = true
sortCheck(Sort.Enable) sortCheck(Sort.Enable)
initLiveDataBookSource(searchView.query?.toString()) upBookSource(searchView.query?.toString())
} }
R.id.menu_enabled_group -> { R.id.menu_enabled_group -> {
searchView.setQuery(getString(R.string.enabled), true) searchView.setQuery(getString(R.string.enabled), true)
@ -199,27 +201,27 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
searchView.setOnQueryTextListener(this) searchView.setOnQueryTextListener(this)
} }
private fun initLiveDataBookSource(searchKey: String? = null) { private fun upBookSource(searchKey: String? = null) {
bookSourceLiveDate?.removeObservers(this) sourceFlowJob?.cancel()
bookSourceLiveDate = when { sourceFlowJob = launch {
searchKey.isNullOrEmpty() -> { when {
appDb.bookSourceDao.liveDataAll() searchKey.isNullOrEmpty() -> {
} appDb.bookSourceDao.liveDataAll()
searchKey == getString(R.string.enabled) -> { }
appDb.bookSourceDao.liveDataEnabled() searchKey == getString(R.string.enabled) -> {
} appDb.bookSourceDao.liveDataEnabled()
searchKey == getString(R.string.disabled) -> { }
appDb.bookSourceDao.liveDataDisabled() searchKey == getString(R.string.disabled) -> {
} appDb.bookSourceDao.liveDataDisabled()
searchKey.startsWith("group:") -> { }
val key = searchKey.substringAfter("group:") searchKey.startsWith("group:") -> {
appDb.bookSourceDao.liveDataGroupSearch("%$key%") val key = searchKey.substringAfter("group:")
} appDb.bookSourceDao.liveDataGroupSearch("%$key%")
else -> { }
appDb.bookSourceDao.liveDataSearch("%$searchKey%") else -> {
} appDb.bookSourceDao.liveDataSearch("%$searchKey%")
}.apply { }
observe(this@BookSourceActivity, { data -> }.collect { data ->
val sourceList = val sourceList =
if (sortAscending) when (sort) { if (sortAscending) when (sort) {
Sort.Weight -> data.sortedBy { it.weight } Sort.Weight -> data.sortedBy { it.weight }
@ -254,7 +256,7 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
else -> data.reversed() else -> data.reversed()
} }
adapter.setItems(sourceList, adapter.diffItemCallback) adapter.setItems(sourceList, adapter.diffItemCallback)
}) }
} }
} }
@ -273,13 +275,16 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
} }
private fun initLiveDataGroup() { private fun initLiveDataGroup() {
appDb.bookSourceDao.liveGroup().observe(this, { launch {
groups.clear() appDb.bookSourceDao.liveGroup()
it.forEach { group -> .collect {
groups.addAll(group.splitNotBlank(AppPattern.splitGroupRegex)) groups.clear()
} it.forEach { group ->
upGroupMenu() groups.addAll(group.splitNotBlank(AppPattern.splitGroupRegex))
}) }
upGroupMenu()
}
}
} }
override fun selectAll(selectAll: Boolean) { override fun selectAll(selectAll: Boolean) {
@ -453,7 +458,7 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
override fun onQueryTextChange(newText: String?): Boolean { override fun onQueryTextChange(newText: String?): Boolean {
newText?.let { newText?.let {
initLiveDataBookSource(it) upBookSource(it)
} }
return false return false
} }

@ -8,10 +8,10 @@ import android.view.MenuItem
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.appcompat.widget.Toolbar import androidx.appcompat.widget.Toolbar
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import io.legado.app.R import io.legado.app.R
import io.legado.app.base.BaseDialogFragment
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
import io.legado.app.constant.AppPattern import io.legado.app.constant.AppPattern
@ -28,9 +28,11 @@ import io.legado.app.utils.getSize
import io.legado.app.utils.requestInputMethod import io.legado.app.utils.requestInputMethod
import io.legado.app.utils.splitNotBlank import io.legado.app.utils.splitNotBlank
import io.legado.app.utils.viewbindingdelegate.viewBinding import io.legado.app.utils.viewbindingdelegate.viewBinding
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
class GroupManageDialog : DialogFragment(), Toolbar.OnMenuItemClickListener { class GroupManageDialog : BaseDialogFragment(), Toolbar.OnMenuItemClickListener {
private val viewModel: BookSourceViewModel by activityViewModels() private val viewModel: BookSourceViewModel by activityViewModels()
private lateinit var adapter: GroupAdapter private lateinit var adapter: GroupAdapter
private val binding by viewBinding(DialogRecyclerViewBinding::bind) private val binding by viewBinding(DialogRecyclerViewBinding::bind)
@ -49,8 +51,7 @@ class GroupManageDialog : DialogFragment(), Toolbar.OnMenuItemClickListener {
return inflater.inflate(R.layout.dialog_recycler_view, container) return inflater.inflate(R.layout.dialog_recycler_view, container)
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
view.setBackgroundColor(backgroundColor) view.setBackgroundColor(backgroundColor)
binding.toolBar.setBackgroundColor(primaryColor) binding.toolBar.setBackgroundColor(primaryColor)
binding.toolBar.title = getString(R.string.group_manage) binding.toolBar.title = getString(R.string.group_manage)
@ -65,13 +66,15 @@ class GroupManageDialog : DialogFragment(), Toolbar.OnMenuItemClickListener {
} }
private fun initData() { private fun initData() {
appDb.bookSourceDao.liveGroup().observe(viewLifecycleOwner, { launch {
val groups = linkedSetOf<String>() appDb.bookSourceDao.liveGroup().collect {
it.map { group -> val groups = linkedSetOf<String>()
groups.addAll(group.splitNotBlank(AppPattern.splitGroupRegex)) it.map { group ->
groups.addAll(group.splitNotBlank(AppPattern.splitGroupRegex))
}
adapter.setItems(groups.toList())
} }
adapter.setItems(groups.toList()) }
})
} }
override fun onMenuItemClick(item: MenuItem?): Boolean { override fun onMenuItemClick(item: MenuItem?): Boolean {

@ -4,7 +4,6 @@ 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.LiveData
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
@ -29,6 +28,9 @@ import io.legado.app.utils.getPrefInt
import io.legado.app.utils.observeEvent import io.legado.app.utils.observeEvent
import io.legado.app.utils.startActivity import io.legado.app.utils.startActivity
import io.legado.app.utils.viewbindingdelegate.viewBinding import io.legado.app.utils.viewbindingdelegate.viewBinding
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
import kotlin.math.max import kotlin.math.max
/** /**
@ -52,7 +54,7 @@ class BooksFragment : BaseFragment(R.layout.fragment_books),
private val activityViewModel: MainViewModel private val activityViewModel: MainViewModel
by activityViewModels() by activityViewModels()
private lateinit var booksAdapter: BaseBooksAdapter<*> private lateinit var booksAdapter: BaseBooksAdapter<*>
private var bookshelfLiveData: LiveData<List<Book>>? = null private var booksFlowJob: Job? = null
private var position = 0 private var position = 0
private var groupId = -1L private var groupId = -1L
@ -101,15 +103,15 @@ class BooksFragment : BaseFragment(R.layout.fragment_books),
} }
private fun upRecyclerData() { private fun upRecyclerData() {
bookshelfLiveData?.removeObservers(this) booksFlowJob?.cancel()
bookshelfLiveData = when (groupId) { booksFlowJob = launch {
AppConst.bookGroupAllId -> appDb.bookDao.observeAll() when (groupId) {
AppConst.bookGroupLocalId -> appDb.bookDao.observeLocal() AppConst.bookGroupAllId -> appDb.bookDao.observeAll()
AppConst.bookGroupAudioId -> appDb.bookDao.observeAudio() AppConst.bookGroupLocalId -> appDb.bookDao.observeLocal()
AppConst.bookGroupNoneId -> appDb.bookDao.observeNoGroup() AppConst.bookGroupAudioId -> appDb.bookDao.observeAudio()
else -> appDb.bookDao.observeByGroup(groupId) AppConst.bookGroupNoneId -> appDb.bookDao.observeNoGroup()
}.apply { else -> appDb.bookDao.observeByGroup(groupId)
observe(viewLifecycleOwner) { list -> }.collect { list ->
binding.tvEmptyMsg.isGone = list.isNotEmpty() binding.tvEmptyMsg.isGone = list.isNotEmpty()
val books = when (getPrefInt(PreferKey.bookshelfSort)) { val books = when (getPrefInt(PreferKey.bookshelfSort)) {
1 -> list.sortedByDescending { it.latestChapterTime } 1 -> list.sortedByDescending { it.latestChapterTime }

@ -32,6 +32,9 @@ import io.legado.app.utils.getPrefInt
import io.legado.app.utils.observeEvent import io.legado.app.utils.observeEvent
import io.legado.app.utils.startActivity import io.legado.app.utils.startActivity
import io.legado.app.utils.viewbindingdelegate.viewBinding import io.legado.app.utils.viewbindingdelegate.viewBinding
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
import kotlin.math.max import kotlin.math.max
/** /**
@ -46,7 +49,7 @@ class BookshelfFragment2 : BaseBookshelfFragment(R.layout.fragment_bookshelf1),
private lateinit var booksAdapter: BaseBooksAdapter<*> private lateinit var booksAdapter: BaseBooksAdapter<*>
override var groupId = AppConst.bookGroupNoneId override var groupId = AppConst.bookGroupNoneId
private var bookGroupLiveData: LiveData<List<BookGroup>>? = null private var bookGroupLiveData: LiveData<List<BookGroup>>? = null
private var bookshelfLiveData: LiveData<List<Book>>? = null private var booksFlowJob: Job? = null
private var bookGroups: List<BookGroup> = emptyList() private var bookGroups: List<BookGroup> = emptyList()
override var books: List<Book> = emptyList() override var books: List<Book> = emptyList()
@ -130,15 +133,15 @@ class BookshelfFragment2 : BaseBookshelfFragment(R.layout.fragment_bookshelf1),
} }
private fun initBooksData() { private fun initBooksData() {
bookshelfLiveData?.removeObservers(this) booksFlowJob?.cancel()
bookshelfLiveData = when (groupId) { booksFlowJob = launch {
AppConst.bookGroupAllId -> appDb.bookDao.observeAll() when (groupId) {
AppConst.bookGroupLocalId -> appDb.bookDao.observeLocal() AppConst.bookGroupAllId -> appDb.bookDao.observeAll()
AppConst.bookGroupAudioId -> appDb.bookDao.observeAudio() AppConst.bookGroupLocalId -> appDb.bookDao.observeLocal()
AppConst.bookGroupNoneId -> appDb.bookDao.observeNoGroup() AppConst.bookGroupAudioId -> appDb.bookDao.observeAudio()
else -> appDb.bookDao.observeByGroup(groupId) AppConst.bookGroupNoneId -> appDb.bookDao.observeNoGroup()
}.apply { else -> appDb.bookDao.observeByGroup(groupId)
observe(viewLifecycleOwner) { list -> }.collect { list ->
binding.tvEmptyMsg.isGone = list.isNotEmpty() binding.tvEmptyMsg.isGone = list.isNotEmpty()
books = when (getPrefInt(PreferKey.bookshelfSort)) { books = when (getPrefInt(PreferKey.bookshelfSort)) {
1 -> list.sortedByDescending { 1 -> list.sortedByDescending {

@ -8,7 +8,6 @@ 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.LiveData
import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
@ -27,6 +26,9 @@ import io.legado.app.utils.cnCompare
import io.legado.app.utils.splitNotBlank import io.legado.app.utils.splitNotBlank
import io.legado.app.utils.startActivity import io.legado.app.utils.startActivity
import io.legado.app.utils.viewbindingdelegate.viewBinding import io.legado.app.utils.viewbindingdelegate.viewBinding
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
/** /**
* 发现界面 * 发现界面
@ -39,8 +41,7 @@ class ExploreFragment : VMBaseFragment<ExploreViewModel>(R.layout.fragment_explo
private lateinit var linearLayoutManager: LinearLayoutManager private lateinit var linearLayoutManager: LinearLayoutManager
private lateinit var searchView: SearchView private lateinit var searchView: SearchView
private val groups = linkedSetOf<String>() private val groups = linkedSetOf<String>()
private var liveGroup: LiveData<List<String>>? = null private var exploreFlowJob: Job? = null
private var liveExplore: LiveData<List<BookSource>>? = null
private var groupsMenu: SubMenu? = null private var groupsMenu: SubMenu? = null
override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) { override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) {
@ -49,7 +50,7 @@ class ExploreFragment : VMBaseFragment<ExploreViewModel>(R.layout.fragment_explo
initSearchView() initSearchView()
initRecyclerView() initRecyclerView()
initGroupData() initGroupData()
initExploreData() upExploreData()
} }
override fun onCompatCreateOptionsMenu(menu: Menu) { override fun onCompatCreateOptionsMenu(menu: Menu) {
@ -76,7 +77,7 @@ class ExploreFragment : VMBaseFragment<ExploreViewModel>(R.layout.fragment_explo
} }
override fun onQueryTextChange(newText: String?): Boolean { override fun onQueryTextChange(newText: String?): Boolean {
initExploreData(newText) upExploreData(newText)
return false return false
} }
}) })
@ -100,38 +101,41 @@ class ExploreFragment : VMBaseFragment<ExploreViewModel>(R.layout.fragment_explo
} }
private fun initGroupData() { private fun initGroupData() {
liveGroup?.removeObservers(viewLifecycleOwner) launch {
liveGroup = appDb.bookSourceDao.liveExploreGroup() appDb.bookSourceDao.liveExploreGroup()
liveGroup?.observe(viewLifecycleOwner, { .collect {
groups.clear() groups.clear()
it.map { group -> it.map { group ->
groups.addAll(group.splitNotBlank(AppPattern.splitGroupRegex)) groups.addAll(group.splitNotBlank(AppPattern.splitGroupRegex))
} }
upGroupsMenu() upGroupsMenu()
}) }
}
} }
private fun initExploreData(searchKey: String? = null) { private fun upExploreData(searchKey: String? = null) {
liveExplore?.removeObservers(viewLifecycleOwner) exploreFlowJob?.cancel()
liveExplore = when { exploreFlowJob = launch {
searchKey.isNullOrBlank() -> { val exploreFlow = when {
appDb.bookSourceDao.liveExplore() searchKey.isNullOrBlank() -> {
} appDb.bookSourceDao.liveExplore()
searchKey.startsWith("group:") -> { }
val key = searchKey.substringAfter("group:") searchKey.startsWith("group:") -> {
appDb.bookSourceDao.liveGroupExplore("%$key%") val key = searchKey.substringAfter("group:")
appDb.bookSourceDao.liveGroupExplore("%$key%")
}
else -> {
appDb.bookSourceDao.liveExplore("%$searchKey%")
}
} }
else -> { exploreFlow.collect {
appDb.bookSourceDao.liveExplore("%$searchKey%") binding.tvEmptyMsg.isGone = it.isNotEmpty() || searchView.query.isNotEmpty()
val diffResult = DiffUtil
.calculateDiff(ExploreDiffCallBack(ArrayList(adapter.getItems()), it))
adapter.setItems(it)
diffResult.dispatchUpdatesTo(adapter)
} }
} }
liveExplore?.observe(viewLifecycleOwner, {
binding.tvEmptyMsg.isGone = it.isNotEmpty() || searchView.query.isNotEmpty()
val diffResult = DiffUtil
.calculateDiff(ExploreDiffCallBack(ArrayList(adapter.getItems()), it))
adapter.setItems(it)
diffResult.dispatchUpdatesTo(adapter)
})
} }
private fun upGroupsMenu() = groupsMenu?.let { subMenu -> private fun upGroupsMenu() = groupsMenu?.let { subMenu ->
@ -151,7 +155,7 @@ class ExploreFragment : VMBaseFragment<ExploreViewModel>(R.layout.fragment_explo
} }
override fun refreshData() { override fun refreshData() {
initExploreData(searchView.query?.toString()) upExploreData(searchView.query?.toString())
} }
override fun scrollTo(pos: Int) { override fun scrollTo(pos: Int) {

Loading…
Cancel
Save