给书源点赞

pull/2208/head
shen 2 years ago
parent ca90ff24db
commit c613ba61ea
  1. 2
      app/src/main/java/io/legado/app/api/controller/BookSourceController.kt
  2. 45
      app/src/main/java/io/legado/app/help/config/SourceConfig.kt
  3. 50
      app/src/main/java/io/legado/app/ui/book/changesource/ChangeBookSourceAdapter.kt
  4. 8
      app/src/main/java/io/legado/app/ui/book/changesource/ChangeBookSourceDialog.kt
  5. 35
      app/src/main/java/io/legado/app/ui/book/changesource/ChangeBookSourceViewModel.kt
  6. 2
      app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditViewModel.kt
  7. 8
      app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceViewModel.kt
  8. 2
      app/src/main/java/io/legado/app/ui/main/explore/ExploreAdapter.kt
  9. 7
      app/src/main/res/drawable/ic_praise.xml
  10. 57
      app/src/main/res/layout/item_change_source.xml

@ -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 {

@ -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)
}
}
}
}
}

@ -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
}
}

@ -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()

@ -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)

@ -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

@ -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) {

@ -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

@ -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>

@ -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>
Loading…
Cancel
Save