HapeLee 1 год назад
Родитель
Сommit
76feb9202a

+ 3 - 2
app/src/main/java/io/legado/app/ui/book/explore/ExploreShowActivity.kt

@@ -11,6 +11,7 @@ import io.legado.app.data.entities.SearchBook
 import io.legado.app.databinding.ActivityExploreShowBinding
 import io.legado.app.databinding.ViewLoadMoreBinding
 import io.legado.app.ui.book.info.BookInfoActivity
+import io.legado.app.ui.book.search.BookShelfState
 import io.legado.app.ui.widget.recycler.LoadMoreView
 import io.legado.app.utils.applyNavigationBarPadding
 import io.legado.app.utils.startActivity
@@ -81,8 +82,8 @@ class ExploreShowActivity : VMBaseActivity<ActivityExploreShowBinding, ExploreSh
         }
     }
 
-    override fun isInBookshelf(name: String, author: String): Boolean {
-        return viewModel.isInBookShelf(name, author)
+    override fun getBookShelfState(name: String, author: String, url: String?): BookShelfState {
+        return viewModel.isInBookShelf(name, author, url)
     }
 
     override fun showBookInfo(book: Book) {

+ 30 - 4
app/src/main/java/io/legado/app/ui/book/explore/ExploreShowAdapter.kt

@@ -12,6 +12,7 @@ import io.legado.app.data.entities.Book
 import io.legado.app.data.entities.SearchBook
 import io.legado.app.databinding.ItemSearchBinding
 import io.legado.app.help.config.AppConfig
+import io.legado.app.ui.book.search.BookShelfState
 import io.legado.app.ui.widget.text.AccentBgTextView
 import io.legado.app.utils.dpToPx
 import io.legado.app.utils.gone
@@ -46,7 +47,19 @@ class ExploreShowAdapter(context: Context, val callBack: CallBack) :
         binding.run {
             tvName.text = item.name
             tvAuthor.text = context.getString(R.string.author_show, item.author)
-            ivInBookshelf.isVisible = callBack.isInBookshelf(item.name, item.author)
+            when (callBack.getBookShelfState(item.name, item.author, item.bookUrl)) {
+                BookShelfState.IN_SHELF -> {
+                    ivInBookshelf.isVisible = true
+                    tvBookshelf.text = context.getString(R.string.remove_from_bookshelf)
+                }
+                BookShelfState.SAME_NAME_AUTHOR -> {
+                    ivInBookshelf.isVisible = true
+                    tvBookshelf.text = context.getString(R.string.same_name_book)
+                }
+                BookShelfState.NOT_IN_SHELF -> {
+                    ivInBookshelf.isVisible = false
+                }
+            }
             if (item.latestChapterTitle.isNullOrEmpty()) {
                 tvLasted.gone()
             } else {
@@ -90,8 +103,21 @@ class ExploreShowAdapter(context: Context, val callBack: CallBack) :
         binding.run {
             bundle.keySet().forEach {
                 when (it) {
-                    "isInBookshelf" -> ivInBookshelf.isVisible =
-                        callBack.isInBookshelf(item.name, item.author)
+                    "isInBookshelf" -> {
+                        when (callBack.getBookShelfState(item.name, item.author, item.bookUrl)) {
+                            BookShelfState.IN_SHELF -> {
+                                ivInBookshelf.isVisible = true
+                                tvBookshelf.text = context.getString(R.string.remove_from_bookshelf)
+                            }
+                            BookShelfState.SAME_NAME_AUTHOR -> {
+                                ivInBookshelf.isVisible = true
+                                tvBookshelf.text = context.getString(R.string.same_name_book)
+                            }
+                            BookShelfState.NOT_IN_SHELF -> {
+                                ivInBookshelf.isVisible = false
+                            }
+                        }
+                    }
                 }
             }
         }
@@ -109,7 +135,7 @@ class ExploreShowAdapter(context: Context, val callBack: CallBack) :
         /**
          * 是否已经加入书架
          */
-        fun isInBookshelf(name: String, author: String): Boolean
+        fun getBookShelfState(name: String, author: String, url: String?): BookShelfState
 
         fun showBookInfo(book: Book)
     }

+ 14 - 16
app/src/main/java/io/legado/app/ui/book/explore/ExploreShowViewModel.kt

@@ -12,6 +12,8 @@ import io.legado.app.data.entities.BookSource
 import io.legado.app.data.entities.SearchBook
 import io.legado.app.help.book.isNotShelf
 import io.legado.app.model.webBook.WebBook
+import io.legado.app.ui.book.search.BookKey
+import io.legado.app.ui.book.search.BookShelfState
 import io.legado.app.utils.printOnDebug
 import io.legado.app.utils.stackTraceStr
 import kotlinx.coroutines.Dispatchers.IO
@@ -23,7 +25,7 @@ import java.util.concurrent.ConcurrentHashMap
 
 @OptIn(ExperimentalCoroutinesApi::class)
 class ExploreShowViewModel(application: Application) : BaseViewModel(application) {
-    val bookshelf: MutableSet<String> = ConcurrentHashMap.newKeySet()
+    val bookshelf: MutableSet<BookKey> = ConcurrentHashMap.newKeySet()
     val upAdapterLiveData = MutableLiveData<String>()
     val booksData = MutableLiveData<List<SearchBook>>()
     val errorLiveData = MutableLiveData<String>()
@@ -35,18 +37,12 @@ class ExploreShowViewModel(application: Application) : BaseViewModel(application
     init {
         execute {
             appDb.bookDao.flowAll().mapLatest { books ->
-                val keys = arrayListOf<String>()
                 books.filterNot { it.isNotShelf }
-                    .forEach {
-                        keys.add("${it.name}-${it.author}")
-                        keys.add(it.name)
-                    }
-                keys
             }.catch {
-                AppLog.put("发现列表界面获取书籍数据失败\n${it.localizedMessage}", it)
-            }.collect {
+                AppLog.put("搜索界面获取书籍列表失败\n${it.localizedMessage}", it)
+            }.collect { books ->
                 bookshelf.clear()
-                bookshelf.addAll(it)
+                bookshelf.addAll(books.map { BookKey(it.name, it.author, it.bookUrl) })
                 upAdapterLiveData.postValue("isInBookshelf")
             }
         }.onError {
@@ -82,12 +78,14 @@ class ExploreShowViewModel(application: Application) : BaseViewModel(application
             }
     }
 
-    fun isInBookShelf(name: String, author: String): Boolean {
-        return if (author.isNotBlank()) {
-            bookshelf.contains("$name-$author")
-        } else {
-            bookshelf.contains(name)
-        }
+    fun isInBookShelf(name: String, author: String, url: String?): BookShelfState {
+        val exactMatch = bookshelf.any { it.name == name && it.author == author && it.url == url }
+        if (exactMatch) return BookShelfState.IN_SHELF
+
+        val sameNameAuthor = bookshelf.any { it.name == name && it.author == author && it.url != url }
+        if (sameNameAuthor) return BookShelfState.SAME_NAME_AUTHOR
+
+        return BookShelfState.NOT_IN_SHELF
     }
 
 }

+ 2 - 2
app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt

@@ -576,8 +576,8 @@ class SearchActivity : VMBaseActivity<ActivityBookSearchBinding, SearchViewModel
     /**
      * 是否已经加入书架
      */
-    override fun isInBookshelf(name: String, author: String): Boolean {
-        return viewModel.isInBookShelf(name, author)
+    override fun getBookShelfState(name: String, author: String, url: String?): BookShelfState {
+        return viewModel.isInBookShelf(name, author, url)
     }
 
     /**

+ 29 - 5
app/src/main/java/io/legado/app/ui/book/search/SearchAdapter.kt

@@ -86,8 +86,19 @@ class SearchAdapter(context: Context, val callBack: CallBack) :
         binding.run {
             tvName.text = searchBook.name
             tvAuthor.text = context.getString(R.string.author_show, searchBook.author)
-            ivInBookshelf.isVisible =
-                callBack.isInBookshelf(searchBook.name, searchBook.author)
+            when (callBack.getBookShelfState(searchBook.name, searchBook.author, searchBook.bookUrl)) {
+                BookShelfState.IN_SHELF -> {
+                    ivInBookshelf.isVisible = true
+                    tvBookshelf.text = context.getString(R.string.remove_from_bookshelf)
+                }
+                BookShelfState.SAME_NAME_AUTHOR -> {
+                    ivInBookshelf.isVisible = true
+                    tvBookshelf.text = context.getString(R.string.same_name_book)
+                }
+                BookShelfState.NOT_IN_SHELF -> {
+                    ivInBookshelf.isVisible = false
+                }
+            }
             bvOriginCount.text = searchBook.origins.size.toString()
             upLasted(binding, searchBook.latestChapterTitle)
             tvIntroduce.text = searchBook.trimIntro(context)
@@ -110,8 +121,21 @@ class SearchAdapter(context: Context, val callBack: CallBack) :
                     "last" -> upLasted(binding, searchBook.latestChapterTitle)
                     "intro" -> tvIntroduce.text = searchBook.trimIntro(context)
                     "kind" -> upKind(binding, searchBook.getKindList())
-                    "isInBookshelf" -> ivInBookshelf.isVisible =
-                        callBack.isInBookshelf(searchBook.name, searchBook.author)
+                    "isInBookshelf" -> {
+                        when (callBack.getBookShelfState(searchBook.name, searchBook.author, searchBook.bookUrl)) {
+                            BookShelfState.IN_SHELF -> {
+                                ivInBookshelf.isVisible = true
+                                tvBookshelf.text = context.getString(R.string.remove_from_bookshelf)
+                            }
+                            BookShelfState.SAME_NAME_AUTHOR -> {
+                                ivInBookshelf.isVisible = true
+                                tvBookshelf.text = context.getString(R.string.same_name_book)
+                            }
+                            BookShelfState.NOT_IN_SHELF -> {
+                                ivInBookshelf.isVisible = false
+                            }
+                        }
+                    }
                     "cover" -> ivCover.load(
                         searchBook.coverUrl,
                         searchBook.name,
@@ -165,7 +189,7 @@ class SearchAdapter(context: Context, val callBack: CallBack) :
         /**
          * 是否已经加入书架
          */
-        fun isInBookshelf(name: String, author: String): Boolean
+        fun getBookShelfState(name: String, author: String, url: String?): BookShelfState
 
         /**
          * 显示书籍详情

+ 19 - 15
app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt

@@ -20,10 +20,18 @@ import kotlinx.coroutines.flow.catch
 import kotlinx.coroutines.flow.mapLatest
 import java.util.concurrent.ConcurrentHashMap
 
+enum class BookShelfState {
+    IN_SHELF,
+    SAME_NAME_AUTHOR,
+    NOT_IN_SHELF
+}
+
+data class BookKey(val name: String, val author: String, val url: String?)
+
 @OptIn(ExperimentalCoroutinesApi::class)
 class SearchViewModel(application: Application) : BaseViewModel(application) {
     val handler = Handler(Looper.getMainLooper())
-    val bookshelf: MutableSet<String> = ConcurrentHashMap.newKeySet()
+    val bookshelf: MutableSet<BookKey> = ConcurrentHashMap.newKeySet()
     val upAdapterLiveData = MutableLiveData<String>()
     var searchBookLiveData = ConflateLiveData<List<SearchBook>>(1000)
     val searchScope: SearchScope = SearchScope(AppConfig.searchScope)
@@ -70,18 +78,12 @@ class SearchViewModel(application: Application) : BaseViewModel(application) {
     init {
         execute {
             appDb.bookDao.flowAll().mapLatest { books ->
-                val keys = arrayListOf<String>()
                 books.filterNot { it.isNotShelf }
-                    .forEach {
-                        keys.add("${it.name}-${it.author}")
-                        keys.add(it.name)
-                    }
-                keys
             }.catch {
                 AppLog.put("搜索界面获取书籍列表失败\n${it.localizedMessage}", it)
-            }.collect {
+            }.collect { books ->
                 bookshelf.clear()
-                bookshelf.addAll(it)
+                bookshelf.addAll(books.map { BookKey(it.name, it.author, it.bookUrl) })
                 upAdapterLiveData.postValue("isInBookshelf")
             }
         }.onError {
@@ -89,12 +91,14 @@ class SearchViewModel(application: Application) : BaseViewModel(application) {
         }
     }
 
-    fun isInBookShelf(name: String, author: String): Boolean {
-        return if (author.isNotBlank()) {
-            bookshelf.contains("$name-$author")
-        } else {
-            bookshelf.contains(name)
-        }
+    fun isInBookShelf(name: String, author: String, url: String?): BookShelfState {
+        val exactMatch = bookshelf.any { it.name == name && it.author == author && it.url == url }
+        if (exactMatch) return BookShelfState.IN_SHELF
+
+        val sameNameAuthor = bookshelf.any { it.name == name && it.author == author && it.url != url }
+        if (sameNameAuthor) return BookShelfState.SAME_NAME_AUTHOR
+
+        return BookShelfState.NOT_IN_SHELF
     }
 
     /**

+ 2 - 1
app/src/main/res/layout/item_search.xml

@@ -49,6 +49,7 @@
                 app:strokeWidth="0dp">
 
                 <TextView
+                    android:id="@+id/tv_bookshelf"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
                     android:paddingHorizontal="4dp"
@@ -56,7 +57,7 @@
                     android:text="@string/remove_from_bookshelf"
                     android:textColor="?attr/colorOnTertiaryContainer"
                     android:textStyle="bold"
-                    android:textSize="10sp"
+                    android:textSize="9sp"
                     tools:ignore="SmallSp" />
 
             </com.google.android.material.card.MaterialCardView>