Przeglądaj źródła

给书源点赞

shen 4 lat temu
rodzic
commit
5115418d0f

+ 2 - 0
app/src/main/java/io/legado/app/api/controller/BookSourceController.kt

@@ -5,6 +5,7 @@ import android.text.TextUtils
 import io.legado.app.api.ReturnData
 import io.legado.app.data.appDb
 import io.legado.app.data.entities.BookSource
+import io.legado.app.help.config.SourceConfig
 import io.legado.app.utils.GSON
 import io.legado.app.utils.fromJsonArray
 
@@ -70,6 +71,7 @@ object BookSourceController {
             GSON.fromJsonArray<BookSource>(postData).getOrThrow()?.let {
                 it.forEach { source ->
                     appDb.bookSourceDao.delete(source)
+                    SourceConfig.removeSource(source.bookSourceUrl)
                 }
             }
         }.onFailure {

+ 45 - 0
app/src/main/java/io/legado/app/help/config/SourceConfig.kt

@@ -0,0 +1,45 @@
+package io.legado.app.help.config
+
+import android.content.Context.MODE_PRIVATE
+import androidx.core.content.edit
+import splitties.init.appCtx
+
+object SourceConfig {
+    private val sp = appCtx.getSharedPreferences("SourceConfig", MODE_PRIVATE)
+    fun setBookScore(origin: String, name: String, author: String, score: Int) {
+        sp.edit {
+            val preScore = getBookScore(origin, name, author)
+            var newScore = score
+            if (preScore != 0) {
+                newScore = score - preScore
+            }
+
+            putInt(origin, getSourceScore(origin) + newScore)
+
+            putInt("${origin}_${name}_${author}", score)
+        }
+    }
+
+    fun getBookScore(origin: String, name: String, author: String): Int {
+        return sp.getInt("${origin}_${name}_${author}", 0)
+    }
+
+    fun getSourceScore(origin: String): Int {
+        return sp.getInt(origin, 0)
+    }
+
+
+    fun removeSource(origin: String) {
+        sp.all.keys.filter {
+            it.startsWith(origin)
+        }.let {
+            sp.edit {
+                it.forEach {
+                    remove(it)
+                }
+            }
+        }
+    }
+
+
+}

+ 50 - 0
app/src/main/java/io/legado/app/ui/book/changesource/ChangeBookSourceAdapter.kt

@@ -1,16 +1,19 @@
 package io.legado.app.ui.book.changesource
 
 import android.content.Context
+import android.graphics.Color
 import android.os.Bundle
 import android.view.View
 import android.view.ViewGroup
 import androidx.appcompat.widget.PopupMenu
+import androidx.core.view.isVisible
 import androidx.recyclerview.widget.DiffUtil
 import io.legado.app.R
 import io.legado.app.base.adapter.DiffRecyclerAdapter
 import io.legado.app.base.adapter.ItemViewHolder
 import io.legado.app.data.entities.SearchBook
 import io.legado.app.databinding.ItemChangeSourceBinding
+import io.legado.app.utils.gone
 import io.legado.app.utils.invisible
 import io.legado.app.utils.visible
 import splitties.views.onLongClick
@@ -68,10 +71,55 @@ class ChangeBookSourceAdapter(
                     }
                 }
             }
+            val score = callBack.getBookScore(item)
+            if (score > 0) {
+                binding.ivBad.gone()
+                binding.ivGood.visible()
+                binding.ivGood.drawable.setTint(Color.parseColor("#D50000"))
+            } else if (score < 0) {
+                binding.ivGood.gone()
+                binding.ivBad.visible()
+                binding.ivBad.drawable.setTint(Color.parseColor("#2962FF"))
+            } else {
+                binding.ivGood.visible()
+                binding.ivBad.visible()
+                binding.ivGood.drawable.setTint(Color.parseColor("#FF8A80"))
+                binding.ivBad.drawable.setTint(Color.parseColor("#82B1FF"))
+            }
         }
     }
 
     override fun registerListener(holder: ItemViewHolder, binding: ItemChangeSourceBinding) {
+        binding.ivGood.setOnClickListener {
+            if (binding.ivBad.isVisible) {
+                binding.ivGood.drawable.setTint(Color.parseColor("#D50000"))
+                binding.ivBad.gone()
+                getItem(holder.layoutPosition)?.let {
+                    callBack.setBookScore(it, 1)
+                }
+            } else {
+                binding.ivGood.drawable.setTint(Color.parseColor("#FF8A80"))
+                binding.ivBad.visible()
+                getItem(holder.layoutPosition)?.let {
+                    callBack.setBookScore(it, 0)
+                }
+            }
+        }
+        binding.ivBad.setOnClickListener {
+            if (binding.ivGood.isVisible) {
+                binding.ivBad.drawable.setTint(Color.parseColor("#2962FF"))
+                binding.ivGood.gone()
+                getItem(holder.layoutPosition)?.let {
+                    callBack.setBookScore(it, -1)
+                }
+            } else {
+                binding.ivBad.drawable.setTint(Color.parseColor("#82B1FF"))
+                binding.ivGood.visible()
+                getItem(holder.layoutPosition)?.let {
+                    callBack.setBookScore(it, 0)
+                }
+            }
+        }
         holder.itemView.setOnClickListener {
             getItem(holder.layoutPosition)?.let {
                 if (it.bookUrl != callBack.bookUrl) {
@@ -120,5 +168,7 @@ class ChangeBookSourceAdapter(
         fun editSource(searchBook: SearchBook)
         fun disableSource(searchBook: SearchBook)
         fun deleteSource(searchBook: SearchBook)
+        fun setBookScore(searchBook: SearchBook, score: Int)
+        fun getBookScore(searchBook: SearchBook): Int
     }
 }

+ 8 - 0
app/src/main/java/io/legado/app/ui/book/changesource/ChangeBookSourceDialog.kt

@@ -294,6 +294,14 @@ class ChangeBookSourceDialog() : BaseDialogFragment(R.layout.dialog_book_change_
         }
     }
 
+    override fun setBookScore(searchBook: SearchBook, score: Int) {
+        viewModel.setBookScore(searchBook,score)
+    }
+
+    override fun getBookScore(searchBook: SearchBook): Int {
+        return viewModel.getBookScore(searchBook)
+    }
+
     private fun changeSource(searchBook: SearchBook, onSuccess: (() -> Unit)? = null) {
         waitDialog.setText(R.string.load_toc)
         waitDialog.show()

+ 34 - 1
app/src/main/java/io/legado/app/ui/book/changesource/ChangeBookSourceViewModel.kt

@@ -16,6 +16,7 @@ import io.legado.app.data.entities.BookSource
 import io.legado.app.data.entities.SearchBook
 import io.legado.app.exception.NoStackTraceException
 import io.legado.app.help.config.AppConfig
+import io.legado.app.help.config.SourceConfig
 import io.legado.app.help.coroutine.CompositeCoroutine
 import io.legado.app.help.coroutine.Coroutine
 import io.legado.app.model.webBook.WebBook
@@ -82,7 +83,27 @@ open class ChangeBookSourceViewModel(application: Application) : BaseViewModel(a
             searchCallback = null
         }
     }.map {
-        searchBooks.sortedBy { it.originOrder }
+        searchBooks.sortedWith(object : Comparator<SearchBook> {
+            override fun compare(o1: SearchBook, o2: SearchBook): Int {
+                val o1bs = SourceConfig.getBookScore(o1.origin, o1.name, o1.author)
+                val o2bs = SourceConfig.getBookScore(o2.origin, o2.name, o2.author)
+                if (o1bs - o2bs > 0) {
+                    return -1
+                } else if (o1bs - o2bs < 0) {
+                    return 1
+                } else {
+                    val o1ss = SourceConfig.getSourceScore(o1.origin)
+                    val o2ss = SourceConfig.getSourceScore(o2.origin)
+                    if (o1ss - o2ss > 0) {
+                        return -1
+                    } else if (o1ss - o2ss < 0) {
+                        return 1
+                    } else {
+                        return o1.originOrder - o2.originOrder
+                    }
+                }
+            }
+        })
     }.flowOn(IO)
 
     @Volatile
@@ -351,6 +372,7 @@ open class ChangeBookSourceViewModel(application: Application) : BaseViewModel(a
             appDb.bookSourceDao.getBookSource(searchBook.origin)?.let { source ->
                 appDb.bookSourceDao.delete(source)
                 appDb.searchBookDao.delete(searchBook)
+                SourceConfig.removeSource(source.bookSourceUrl)
             }
         }
         searchBooks.remove(searchBook)
@@ -379,6 +401,17 @@ open class ChangeBookSourceViewModel(application: Application) : BaseViewModel(a
         }
     }
 
+    fun setBookScore(searchBook: SearchBook, score: Int) {
+        execute {
+            SourceConfig.setBookScore(searchBook.origin, searchBook.name, searchBook.author, score)
+            searchCallback?.upAdapter()
+        }
+    }
+
+    fun getBookScore(searchBook: SearchBook): Int {
+        return SourceConfig.getBookScore(searchBook.origin, searchBook.name, searchBook.author)
+    }
+
     interface SourceCallback {
 
         fun searchSuccess(searchBook: SearchBook)

+ 2 - 0
app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditViewModel.kt

@@ -7,6 +7,7 @@ import io.legado.app.data.appDb
 import io.legado.app.data.entities.BookSource
 import io.legado.app.exception.NoStackTraceException
 import io.legado.app.help.RuleComplete
+import io.legado.app.help.config.SourceConfig
 import io.legado.app.help.http.CookieStore
 import io.legado.app.help.http.newCallStrResponse
 import io.legado.app.help.http.okHttpClient
@@ -40,6 +41,7 @@ class BookSourceEditViewModel(application: Application) : BaseViewModel(applicat
             oldSourceUrl?.let {
                 if (oldSourceUrl != source.bookSourceUrl) {
                     appDb.bookSourceDao.delete(it)
+                    SourceConfig.removeSource(it)
                 }
             }
             oldSourceUrl = source.bookSourceUrl

+ 7 - 1
app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceViewModel.kt

@@ -5,6 +5,7 @@ import android.text.TextUtils
 import io.legado.app.base.BaseViewModel
 import io.legado.app.data.appDb
 import io.legado.app.data.entities.BookSource
+import io.legado.app.help.config.SourceConfig
 import io.legado.app.utils.*
 import java.io.File
 import java.io.FileOutputStream
@@ -38,7 +39,12 @@ class BookSourceViewModel(application: Application) : BaseViewModel(application)
     }
 
     fun del(vararg sources: BookSource) {
-        execute { appDb.bookSourceDao.delete(*sources) }
+        execute {
+            appDb.bookSourceDao.delete(*sources)
+            sources.forEach {
+                SourceConfig.removeSource(it.bookSourceUrl)
+            }
+        }
     }
 
     fun update(vararg bookSource: BookSource) {

+ 2 - 0
app/src/main/java/io/legado/app/ui/main/explore/ExploreAdapter.kt

@@ -15,6 +15,7 @@ import io.legado.app.data.entities.BookSource
 import io.legado.app.data.entities.rule.ExploreKind
 import io.legado.app.databinding.ItemFilletTextBinding
 import io.legado.app.databinding.ItemFindBookBinding
+import io.legado.app.help.config.SourceConfig
 import io.legado.app.help.coroutine.Coroutine
 import io.legado.app.lib.theme.accentColor
 import io.legado.app.ui.login.SourceLoginActivity
@@ -174,6 +175,7 @@ class ExploreAdapter(context: Context, val callBack: CallBack) :
                 }
                 R.id.menu_del -> Coroutine.async(callBack.scope) {
                     appDb.bookSourceDao.delete(source)
+                    SourceConfig.removeSource(source.bookSourceUrl)
                 }
             }
             true

+ 7 - 0
app/src/main/res/drawable/ic_praise.xml

@@ -0,0 +1,7 @@
+<vector android:height="24dp" android:viewportHeight="1024"
+    android:viewportWidth="1024" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillColor="#FF000000" android:pathData="M939.4,423.4c-23,-37.3 -62.9,-60.8 -107,-63.2 -2.8,-0.4 -5.5,-0.6 -8.3,-0.6l-152.2,-0.1c6.6,-29 10,-58.7 10,-88.7 0,-28.2 -3.2,-57.1 -9.6,-86 -0.4,-2 -1.1,-4 -1.9,-5.9 -15.8,-57.3 -67.4,-96.8 -127.3,-96.8 -72.8,0 -132.1,59.3 -132.1,132.1 0,3.3 0.1,6.7 0.4,10 -2.2,57.2 -32.1,109.9 -80.3,141.4 -14.4,9.4 -18.5,28.8 -9.1,43.2 9.4,14.4 28.8,18.5 43.2,9.1 65.8,-42.9 106.4,-115.3 108.7,-193.7 0,-1.3 -0,-2.7 -0.1,-4 -0.2,-2 -0.3,-4 -0.3,-6 0,-38.4 31.2,-69.6 69.6,-69.6 32.6,0 60.5,22.2 67.8,54 0.4,1.5 0.8,3 1.4,4.5 4.7,22.8 7.1,45.6 7.1,67.7 0,37.5 -6.2,74.4 -18.5,109.6 -3.3,9.5 -1.8,20.1 4,28.3 5.9,8.2 15.3,13.1 25.4,13.2l193.2,0.1c1.4,0.3 2.9,0.4 4.3,0.5 24.1,1 45.9,13.6 58.6,34.1 7.8,12.3 11.4,26.8 10.4,41.9 -0.1,0.9 -0.1,1.9 -0.1,2.9 0,0.9 0,1.7 0.1,2.5 0,0.3 -0,0.7 -0.1,1 -0.1,0.4 -0.2,0.8 -0.3,1.2l-75,330.4c-0.9,1.3 -1.7,2.6 -2.4,4 -5.9,11.8 -14.7,21.5 -25.3,28.2 -10.7,6.8 -23.1,10.6 -35.8,11.1 -0.9,-0.1 -513.8,-0.2 -513.8,-0.2 -0.5,-0 -0.9,-0 -1.4,-0 0,0 -111,0.2 -112.7,0.5 -1.9,0 -3.4,-1.5 -3.4,-3.4l0.3,-416.3c0,-1.9 1.5,-3.4 3,-3.5l1.2,0.1c1.2,0.1 2.7,0.3 3.5,0.2l83.8,-0.2 0,339.4c0,17.3 14,31.2 31.2,31.2s31.2,-14 31.2,-31.2L281,435.4c0,-1.8 0,-8.6 0,-10.4 0,-17.3 -14,-30.9 -31.2,-30.9 -1.5,0 -117.5,0.3 -119.4,0.3 -36.3,0 -65.9,29.6 -65.9,65.9l-0.3,416.3c0,36.3 29.6,65.9 65.9,65.9 2.5,0 111.4,-0.5 111.4,-0.5 0.5,0 0.9,0 1.4,0 0,0 511.5,0.3 512.5,0.3 25.5,0 50.3,-7.2 71.6,-20.7 19.6,-12.3 35.8,-29.9 46.8,-51 3.7,-5.6 6.4,-11.9 8.3,-18.6 0.1,-0.4 0.2,-0.8 0.3,-1.2l74.9,-330.3c1.6,-6.2 2.3,-12.6 2,-19C960.9,473.4 953.9,446.3 939.4,423.4z"/>
+    <path android:fillColor="#FF000000" android:pathData="M450,518.7c-17.3,0 -31.2,14 -31.2,31.2l0,30.5c0,17.3 14,31.2 31.2,31.2 17.3,0 31.2,-14 31.2,-31.2l0,-30.5C481.3,532.6 467.3,518.7 450,518.7z"/>
+    <path android:fillColor="#FF000000" android:pathData="M693.8,518.7c-17.3,0 -31.2,14 -31.2,31.2l0,30.5c0,17.3 14,31.2 31.2,31.2 17.3,0 31.2,-14 31.2,-31.2l0,-30.5C725,532.6 711.1,518.7 693.8,518.7z"/>
+    <path android:fillColor="#FF000000" android:pathData="M648.9,660.1c-14.3,-9.4 -33.6,-5.4 -43.2,8.8 -0.1,0.2 -13.6,19.8 -34.2,19.8 -20,0 -32.4,-18.1 -33.3,-19.4 -9.2,-14.4 -28.3,-18.8 -42.8,-9.8 -14.7,9.1 -19.2,28.4 -10.1,43 11.2,18 42,48.6 86.2,48.6 44,0 75.1,-30.3 86.6,-48.2C667.4,688.5 663.2,669.5 648.9,660.1z"/>
+</vector>

+ 44 - 13
app/src/main/res/layout/item_change_source.xml

@@ -1,56 +1,87 @@
 <?xml version="1.0" encoding="utf-8"?>
 <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
     xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
     android:background="?android:attr/selectableItemBackground"
-    android:paddingLeft="10dp"
-    android:paddingTop="10dp"
-    android:paddingBottom="10dp"
     tools:ignore="RtlHardcoded,RtlSymmetry">
 
+    <androidx.appcompat.widget.AppCompatImageView
+        android:id="@+id/iv_good"
+        android:layout_width="40dp"
+        android:layout_height="0dp"
+        android:layout_marginTop="5dp"
+        android:padding="5dp"
+        android:src="@drawable/ic_praise"
+        app:layout_constraintBottom_toTopOf="@+id/iv_bad"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        app:tint="@color/md_red_50" />
+
+    <androidx.appcompat.widget.AppCompatImageView
+        android:id="@+id/iv_bad"
+        android:layout_width="40dp"
+        android:layout_height="0dp"
+        android:layout_marginBottom="5dp"
+        android:padding="5dp"
+        android:rotationX="180"
+        android:src="@drawable/ic_praise"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/iv_good"
+        app:tint="@color/md_blue_50" />
+
     <TextView
         android:id="@+id/tv_origin"
         android:layout_width="0dp"
         android:layout_height="wrap_content"
+        android:layout_marginLeft="40dp"
+        android:layout_marginTop="10dp"
         android:singleLine="true"
         android:textColor="@color/primaryText"
-        app:layout_constraintTop_toTopOf="parent"
         app:layout_constraintLeft_toLeftOf="parent"
-        app:layout_constraintRight_toLeftOf="@+id/tv_author" />
+        app:layout_constraintRight_toLeftOf="@+id/tv_author"
+        app:layout_constraintTop_toTopOf="parent" />
 
     <TextView
         android:id="@+id/tv_author"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
+        android:layout_marginTop="10dp"
+        android:maxWidth="160dp"
         android:singleLine="true"
         android:textColor="@color/secondaryText"
-        android:maxWidth="160dp"
-        app:layout_constraintTop_toTopOf="parent"
-        app:layout_constraintRight_toLeftOf="@+id/iv_checked" />
+        app:layout_constraintRight_toLeftOf="@+id/iv_checked"
+        app:layout_constraintTop_toTopOf="parent" />
 
     <TextView
         android:id="@+id/tv_last"
         android:layout_width="0dp"
         android:layout_height="wrap_content"
+        android:layout_marginLeft="40dp"
+        android:layout_marginBottom="10dp"
         android:singleLine="true"
         android:textColor="@color/secondaryText"
-        app:layout_constraintTop_toBottomOf="@+id/tv_origin"
         app:layout_constraintBottom_toBottomOf="parent"
         app:layout_constraintLeft_toLeftOf="parent"
-        app:layout_constraintRight_toLeftOf="@+id/iv_checked" />
+        app:layout_constraintRight_toLeftOf="@+id/iv_checked"
+        app:layout_constraintTop_toBottomOf="@+id/tv_origin" />
 
     <androidx.appcompat.widget.AppCompatImageView
         android:id="@+id/iv_checked"
         android:layout_width="40dp"
         android:layout_height="40dp"
+        android:layout_marginTop="10dp"
+        android:layout_marginBottom="10dp"
         android:padding="8dp"
         android:src="@drawable/ic_check"
         android:visibility="invisible"
-        app:tint="@color/primaryText"
+        app:layout_constraintBottom_toBottomOf="parent"
         app:layout_constraintRight_toRightOf="parent"
         app:layout_constraintTop_toTopOf="parent"
-        app:layout_constraintBottom_toBottomOf="parent" />
+        app:tint="@color/primaryText"
+        tools:visibility="visible" />
+
 
 </androidx.constraintlayout.widget.ConstraintLayout>