Merge remote-tracking branch 'origin/master'

This commit is contained in:
kunfei 2023-10-16 08:04:10 +08:00
commit 715dcd20ba
19 changed files with 98 additions and 40 deletions

View File

@ -137,6 +137,7 @@ object PreferKey {
const val openBookInfoByClickTitle = "openBookInfoByClickTitle" const val openBookInfoByClickTitle = "openBookInfoByClickTitle"
const val defaultHomePage = "defaultHomePage" const val defaultHomePage = "defaultHomePage"
const val showBookshelfFastScroller = "showBookshelfFastScroller" const val showBookshelfFastScroller = "showBookshelfFastScroller"
const val importKeepEnable = "importKeepEnable"
const val cPrimary = "colorPrimary" const val cPrimary = "colorPrimary"
const val cAccent = "colorAccent" const val cAccent = "colorAccent"

View File

@ -420,6 +420,11 @@ object AppConfig : SharedPreferences.OnSharedPreferenceChangeListener {
val importKeepName get() = appCtx.getPrefBoolean(PreferKey.importKeepName) val importKeepName get() = appCtx.getPrefBoolean(PreferKey.importKeepName)
val importKeepGroup get() = appCtx.getPrefBoolean(PreferKey.importKeepGroup) val importKeepGroup get() = appCtx.getPrefBoolean(PreferKey.importKeepGroup)
var importKeepEnable: Boolean
get() = appCtx.getPrefBoolean(PreferKey.importKeepEnable, false)
set(value) {
appCtx.putPrefBoolean(PreferKey.importKeepEnable, value)
}
var preDownloadNum var preDownloadNum
get() = appCtx.getPrefInt(PreferKey.preDownloadNum, 10) get() = appCtx.getPrefInt(PreferKey.preDownloadNum, 10)

View File

@ -142,6 +142,8 @@ class ImportBookSourceDialog() : BaseDialogFragment(R.layout.dialog_recycler_vie
?.isChecked = AppConfig.importKeepName ?.isChecked = AppConfig.importKeepName
binding.toolBar.menu.findItem(R.id.menu_keep_group) binding.toolBar.menu.findItem(R.id.menu_keep_group)
?.isChecked = AppConfig.importKeepGroup ?.isChecked = AppConfig.importKeepGroup
binding.toolBar.menu.findItem(R.id.menu_keep_enable)
?.isChecked = AppConfig.importKeepEnable
} }
@SuppressLint("InflateParams", "NotifyDataSetChanged") @SuppressLint("InflateParams", "NotifyDataSetChanged")
@ -179,6 +181,11 @@ class ImportBookSourceDialog() : BaseDialogFragment(R.layout.dialog_recycler_vie
item.isChecked = !item.isChecked item.isChecked = !item.isChecked
putPrefBoolean(PreferKey.importKeepGroup, item.isChecked) putPrefBoolean(PreferKey.importKeepGroup, item.isChecked)
} }
R.id.menu_keep_enable -> {
item.isChecked = !item.isChecked
AppConfig.importKeepEnable = item.isChecked
}
} }
return false return false
} }

View File

@ -87,6 +87,7 @@ class ImportBookSourceViewModel(app: Application) : BaseViewModel(app) {
val group = groupName?.trim() val group = groupName?.trim()
val keepName = AppConfig.importKeepName val keepName = AppConfig.importKeepName
val keepGroup = AppConfig.importKeepGroup val keepGroup = AppConfig.importKeepGroup
val keepEnable = AppConfig.importKeepEnable
val selectSource = arrayListOf<BookSource>() val selectSource = arrayListOf<BookSource>()
selectStatus.forEachIndexed { index, b -> selectStatus.forEachIndexed { index, b ->
if (b) { if (b) {
@ -98,6 +99,10 @@ class ImportBookSourceViewModel(app: Application) : BaseViewModel(app) {
if (keepGroup) { if (keepGroup) {
source.bookSourceGroup = it.bookSourceGroup source.bookSourceGroup = it.bookSourceGroup
} }
if (keepEnable) {
source.enabled = it.enabled
source.enabledExplore = it.enabledExplore
}
source.customOrder = it.customOrder source.customOrder = it.customOrder
} }
if (!group.isNullOrEmpty()) { if (!group.isNullOrEmpty()) {

View File

@ -36,6 +36,8 @@ class ChangeBookSourceAdapter(
override fun areContentsTheSame(oldItem: SearchBook, newItem: SearchBook): Boolean { override fun areContentsTheSame(oldItem: SearchBook, newItem: SearchBook): Boolean {
return oldItem.originName == newItem.originName return oldItem.originName == newItem.originName
&& oldItem.getDisplayLastChapterTitle() == newItem.getDisplayLastChapterTitle() && oldItem.getDisplayLastChapterTitle() == newItem.getDisplayLastChapterTitle()
&& oldItem.chapterWordCountText == newItem.chapterWordCountText
&& oldItem.respondTime == newItem.respondTime
} }
} }

View File

@ -72,7 +72,8 @@ class ChangeBookSourceDialog() : BaseDialogFragment(R.layout.dialog_book_change_
private val adapter by lazy { ChangeBookSourceAdapter(requireContext(), viewModel, this) } private val adapter by lazy { ChangeBookSourceAdapter(requireContext(), viewModel, this) }
private val editSourceResult = private val editSourceResult =
registerForActivityResult(StartActivityContract(BookSourceEditActivity::class.java)) { registerForActivityResult(StartActivityContract(BookSourceEditActivity::class.java)) {
viewModel.startSearch() val origin = it.data?.getStringExtra("origin") ?: return@registerForActivityResult
viewModel.startSearch(origin)
} }
private val searchFinishCallback: (isEmpty: Boolean) -> Unit = { private val searchFinishCallback: (isEmpty: Boolean) -> Unit = {
if (it) { if (it) {

View File

@ -16,6 +16,7 @@ import io.legado.app.data.entities.BookSource
import io.legado.app.data.entities.SearchBook import io.legado.app.data.entities.SearchBook
import io.legado.app.exception.NoStackTraceException import io.legado.app.exception.NoStackTraceException
import io.legado.app.help.book.BookHelp import io.legado.app.help.book.BookHelp
import io.legado.app.help.book.ContentProcessor
import io.legado.app.help.config.AppConfig import io.legado.app.help.config.AppConfig
import io.legado.app.help.config.SourceConfig import io.legado.app.help.config.SourceConfig
import io.legado.app.help.coroutine.CompositeCoroutine import io.legado.app.help.coroutine.CompositeCoroutine
@ -50,8 +51,25 @@ open class ChangeBookSourceViewModel(application: Application) : BaseViewModel(a
private var searchBookList = arrayListOf<SearchBook>() private var searchBookList = arrayListOf<SearchBook>()
private val searchBooks = Collections.synchronizedList(arrayListOf<SearchBook>()) private val searchBooks = Collections.synchronizedList(arrayListOf<SearchBook>())
private val tocMap = ConcurrentHashMap<String, List<BookChapter>>() private val tocMap = ConcurrentHashMap<String, List<BookChapter>>()
private val contentProcessor by lazy {
ContentProcessor.get(oldBook!!)
}
private var searchCallback: SourceCallback? = null private var searchCallback: SourceCallback? = null
private val emptyBookSource = BookSource() private val emptyBookSource = BookSource()
private val chapterNumRegex = "^\\[(\\d+)]".toRegex()
private val comparatorBase by lazy {
compareByDescending<SearchBook> { getBookScore(it) }
.thenByDescending { SourceConfig.getSourceScore(it.origin) }
}
private val defaultComparator by lazy {
comparatorBase.thenBy { it.originOrder }
}
private val wordCountComparator by lazy {
comparatorBase.thenByDescending { it.chapterWordCount > 1000 }
.thenByDescending { getChapterNum(it.chapterWordCountText) }
.thenByDescending { it.chapterWordCount }
.thenBy { it.originOrder }
}
val bookMap = ConcurrentHashMap<String, Book>() val bookMap = ConcurrentHashMap<String, Book>()
val searchDataFlow = callbackFlow { val searchDataFlow = callbackFlow {
@ -88,26 +106,12 @@ open class ChangeBookSourceViewModel(application: Application) : BaseViewModel(a
} }
}.map { }.map {
kotlin.runCatching { kotlin.runCatching {
searchBooks.sortedWith { o1, o2 -> val comparator = if (AppConfig.changeSourceLoadWordCount) {
val o1bs = SourceConfig.getBookScore(o1.origin, o1.name, o1.author) wordCountComparator
val o2bs = SourceConfig.getBookScore(o2.origin, o2.name, o2.author) } else {
when { defaultComparator
o1bs - o2bs > 0 -> -1
o1bs - o2bs < 0 -> 1
else -> {
val o1ss = SourceConfig.getSourceScore(o1.origin)
val o2ss = SourceConfig.getSourceScore(o2.origin)
when {
o1ss - o2ss > 0 -> -1
o1ss - o2ss < 0 -> 1
else -> {
val n = o1.originOrder - o2.originOrder
if (n == 0) -1 else n
}
}
}
}
} }
searchBooks.sortedWith(comparator)
}.onFailure { }.onFailure {
AppLog.put("换源排序出错\n${it.localizedMessage}", it) AppLog.put("换源排序出错\n${it.localizedMessage}", it)
}.getOrDefault(searchBooks) }.getOrDefault(searchBooks)
@ -153,9 +157,18 @@ open class ChangeBookSourceViewModel(application: Application) : BaseViewModel(a
/** /**
* 搜索书籍 * 搜索书籍
*/ */
fun startSearch() { fun startSearch(origin: String? = null) {
execute { execute {
stopSearch() stopSearch()
origin?.let {
bookSourceList.clear()
bookSourceList.add(appDb.bookSourceDao.getBookSource(origin)!!)
searchStateData.postValue(true)
searchBooks.removeIf { it.origin == origin }
initSearchPool()
search()
return@execute
}
appDb.searchBookDao.clear(name, author) appDb.searchBookDao.clear(name, author)
searchBooks.clear() searchBooks.clear()
searchCallback?.upAdapter() searchCallback?.upAdapter()
@ -182,7 +195,7 @@ open class ChangeBookSourceViewModel(application: Application) : BaseViewModel(a
private fun search() { private fun search() {
val searchIndex = synchronized(this) { val searchIndex = synchronized(this) {
if (searchIndex >= bookSourceList.lastIndex) { if (searchIndex > bookSourceList.lastIndex) {
return return
} }
searchIndex++ searchIndex++
@ -256,17 +269,18 @@ open class ChangeBookSourceViewModel(application: Application) : BaseViewModel(a
) )
} ?: chapters.lastIndex } ?: chapters.lastIndex
} else chapters.lastIndex } else chapters.lastIndex
val bookChapter = chapters.getOrNull(chapterIndex) val bookChapter = chapters[chapterIndex]
val title = bookChapter.title.trim()
val startTime = System.currentTimeMillis() val startTime = System.currentTimeMillis()
val pair = try { val pair = try {
if (bookChapter == null) throw NoStackTraceException("章节缺失,总章节数${chapters.size}")
val nextChapterUrl = chapters.getOrNull(chapterIndex + 1)?.url val nextChapterUrl = chapters.getOrNull(chapterIndex + 1)?.url
WebBook.getContentAwait(source, book, bookChapter, nextChapterUrl, false).length.let { var content = WebBook.getContentAwait(source, book, bookChapter, nextChapterUrl, false)
it to "${chapterIndex + 1}章 字数:${it}" content = contentProcessor.getContent(oldBook!!, bookChapter, content, false).toString()
} val len = content.length
len to "[${chapterIndex + 1}] ${title}\n字数:${len}"
} catch (t: Throwable) { } catch (t: Throwable) {
if (t is CancellationException) throw t if (t is CancellationException) throw t
-1 to "${chapterIndex + 1}获取字数失败:${t.localizedMessage}" -1 to "[${chapterIndex + 1}] ${title}\n获取字数失败:${t.localizedMessage}"
} }
val endTime = System.currentTimeMillis() val endTime = System.currentTimeMillis()
val searchBook = book.toSearchBook().apply { val searchBook = book.toSearchBook().apply {
@ -526,6 +540,11 @@ open class ChangeBookSourceViewModel(application: Application) : BaseViewModel(a
return SourceConfig.getBookScore(searchBook.origin, searchBook.name, searchBook.author) return SourceConfig.getBookScore(searchBook.origin, searchBook.name, searchBook.author)
} }
private fun getChapterNum(wordCountText: String?): Int {
wordCountText ?: return -1
return chapterNumRegex.find(wordCountText)?.groupValues?.get(1)?.toIntOrNull() ?: -1
}
interface SourceCallback { interface SourceCallback {
fun searchSuccess(searchBook: SearchBook) fun searchSuccess(searchBook: SearchBook)

View File

@ -1,6 +1,7 @@
package io.legado.app.ui.book.source.edit package io.legado.app.ui.book.source.edit
import android.app.Activity import android.app.Activity
import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
@ -119,7 +120,7 @@ class BookSourceEditActivity :
override fun onCompatOptionsItemSelected(item: MenuItem): Boolean { override fun onCompatOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) { when (item.itemId) {
R.id.menu_save -> viewModel.save(getSource()) { R.id.menu_save -> viewModel.save(getSource()) {
setResult(Activity.RESULT_OK) setResult(Activity.RESULT_OK, Intent().putExtra("origin", it.bookSourceUrl))
finish() finish()
} }
@ -410,8 +411,8 @@ class BookSourceEditActivity :
"intro" -> searchRule.intro = "intro" -> searchRule.intro =
viewModel.ruleComplete(it.value, searchRule.bookList) viewModel.ruleComplete(it.value, searchRule.bookList)
"updateTime" -> searchRule.updateTime = // "updateTime" -> searchRule.updateTime =
viewModel.ruleComplete(it.value, searchRule.bookList) // viewModel.ruleComplete(it.value, searchRule.bookList)
"wordCount" -> searchRule.wordCount = "wordCount" -> searchRule.wordCount =
viewModel.ruleComplete(it.value, searchRule.bookList) viewModel.ruleComplete(it.value, searchRule.bookList)
@ -442,8 +443,8 @@ class BookSourceEditActivity :
"intro" -> exploreRule.intro = "intro" -> exploreRule.intro =
viewModel.ruleComplete(it.value, exploreRule.bookList) viewModel.ruleComplete(it.value, exploreRule.bookList)
"updateTime" -> exploreRule.updateTime = // "updateTime" -> exploreRule.updateTime =
viewModel.ruleComplete(it.value, exploreRule.bookList) // viewModel.ruleComplete(it.value, exploreRule.bookList)
"wordCount" -> exploreRule.wordCount = "wordCount" -> exploreRule.wordCount =
viewModel.ruleComplete(it.value, exploreRule.bookList) viewModel.ruleComplete(it.value, exploreRule.bookList)
@ -471,8 +472,8 @@ class BookSourceEditActivity :
"intro" -> bookInfoRule.intro = "intro" -> bookInfoRule.intro =
viewModel.ruleComplete(it.value, bookInfoRule.init) viewModel.ruleComplete(it.value, bookInfoRule.init)
"updateTime" -> bookInfoRule.updateTime = // "updateTime" -> bookInfoRule.updateTime =
viewModel.ruleComplete(it.value, bookInfoRule.init) // viewModel.ruleComplete(it.value, bookInfoRule.init)
"wordCount" -> bookInfoRule.wordCount = "wordCount" -> bookInfoRule.wordCount =
viewModel.ruleComplete(it.value, bookInfoRule.init) viewModel.ruleComplete(it.value, bookInfoRule.init)

View File

@ -41,8 +41,8 @@ class BookSourceEditViewModel(application: Application) : BaseViewModel(applicat
if (source.bookSourceUrl.isBlank() || source.bookSourceName.isBlank()) { if (source.bookSourceUrl.isBlank() || source.bookSourceName.isBlank()) {
throw NoStackTraceException(context.getString(R.string.non_null_name_url)) throw NoStackTraceException(context.getString(R.string.non_null_name_url))
} }
if (!source.equal(bookSource ?: BookSource())) { if (source.equal(bookSource ?: BookSource())) {
source.lastUpdateTime = System.currentTimeMillis() return@execute source
} }
bookSource?.let { bookSource?.let {
appDb.bookSourceDao.delete(it) appDb.bookSourceDao.delete(it)
@ -91,6 +91,7 @@ class BookSourceEditViewModel(application: Application) : BaseViewModel(applicat
val text1 = okHttpClient.newCallStrResponse { url(text) }.body val text1 = okHttpClient.newCallStrResponse { url(text) }.body
importSource(text1!!) importSource(text1!!)
} }
text.isJsonArray() -> { text.isJsonArray() -> {
if (text.contains("ruleSearchUrl") || text.contains("ruleFindUrl")) { if (text.contains("ruleSearchUrl") || text.contains("ruleFindUrl")) {
val items: List<Map<String, Any>> = jsonPath.parse(text).read("$") val items: List<Map<String, Any>> = jsonPath.parse(text).read("$")
@ -100,6 +101,7 @@ class BookSourceEditViewModel(application: Application) : BaseViewModel(applicat
GSON.fromJsonArray<BookSource>(text).getOrThrow()[0] GSON.fromJsonArray<BookSource>(text).getOrThrow()[0]
} }
} }
text.isJsonObject() -> { text.isJsonObject() -> {
if (text.contains("ruleSearchUrl") || text.contains("ruleFindUrl")) { if (text.contains("ruleSearchUrl") || text.contains("ruleFindUrl")) {
val jsonItem = jsonPath.parse(text) val jsonItem = jsonPath.parse(text)
@ -108,6 +110,7 @@ class BookSourceEditViewModel(application: Application) : BaseViewModel(applicat
GSON.fromJsonObject<BookSource>(text).getOrThrow() GSON.fromJsonObject<BookSource>(text).getOrThrow()
} }
} }
else -> throw NoStackTraceException("格式不对") else -> throw NoStackTraceException("格式不对")
} }
} }

View File

@ -82,7 +82,7 @@
tools:text="word count" tools:text="word count"
android:textColor="@color/secondaryText" android:textColor="@color/secondaryText"
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" app:layout_constraintRight_toLeftOf="@+id/iv_checked"
app:layout_constraintTop_toBottomOf="@+id/tv_last" /> app:layout_constraintTop_toBottomOf="@+id/tv_last" />
<TextView <TextView
@ -96,7 +96,7 @@
android:textColor="@color/secondaryText" android:textColor="@color/secondaryText"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" app:layout_constraintRight_toLeftOf="@+id/iv_checked"
app:layout_constraintTop_toBottomOf="@+id/tv_current_chapter_word_count" /> app:layout_constraintTop_toBottomOf="@+id/tv_current_chapter_word_count" />
<androidx.appcompat.widget.AppCompatImageView <androidx.appcompat.widget.AppCompatImageView

View File

@ -31,4 +31,10 @@
android:checkable="true" android:checkable="true"
app:showAsAction="never" /> app:showAsAction="never" />
</menu> <item
android:id="@+id/menu_keep_enable"
android:title="@string/keep_enable"
android:checkable="true"
app:showAsAction="never" />
</menu>

View File

@ -1131,4 +1131,5 @@
<string name="default_home_page">默认主页</string> <string name="default_home_page">默认主页</string>
<string name="show_bookshelf_fast_scroller">显示快速滚动条</string> <string name="show_bookshelf_fast_scroller">显示快速滚动条</string>
<string name="export_all_use_book_source">导出所有书的书源</string> <string name="export_all_use_book_source">导出所有书的书源</string>
<string name="keep_enable">保留启用状态</string>
</resources> </resources>

View File

@ -1134,4 +1134,5 @@
<string name="default_home_page">默认主页</string> <string name="default_home_page">默认主页</string>
<string name="show_bookshelf_fast_scroller">显示快速滚动条</string> <string name="show_bookshelf_fast_scroller">显示快速滚动条</string>
<string name="export_all_use_book_source">导出所有书的书源</string> <string name="export_all_use_book_source">导出所有书的书源</string>
<string name="keep_enable">保留启用状态</string>
</resources> </resources>

View File

@ -1134,4 +1134,5 @@
<string name="default_home_page">默认主页</string> <string name="default_home_page">默认主页</string>
<string name="show_bookshelf_fast_scroller">显示快速滚动条</string> <string name="show_bookshelf_fast_scroller">显示快速滚动条</string>
<string name="export_all_use_book_source">导出所有书的书源</string> <string name="export_all_use_book_source">导出所有书的书源</string>
<string name="keep_enable">保留启用状态</string>
</resources> </resources>

View File

@ -1129,4 +1129,5 @@ Còn </string>
<string name="export_wait">等待导出</string> <string name="export_wait">等待导出</string>
<string name="show_bookshelf_fast_scroller">显示快速滚动条</string> <string name="show_bookshelf_fast_scroller">显示快速滚动条</string>
<string name="export_all_use_book_source">导出所有书的书源</string> <string name="export_all_use_book_source">导出所有书的书源</string>
<string name="keep_enable">保留启用状态</string>
</resources> </resources>

View File

@ -1130,4 +1130,5 @@
<string name="export_wait">等待导出</string> <string name="export_wait">等待导出</string>
<string name="show_bookshelf_fast_scroller">显示快速滚动条</string> <string name="show_bookshelf_fast_scroller">显示快速滚动条</string>
<string name="export_all_use_book_source">导出所有书的书源</string> <string name="export_all_use_book_source">导出所有书的书源</string>
<string name="keep_enable">保留启用状态</string>
</resources> </resources>

View File

@ -1132,4 +1132,5 @@
<string name="export_wait">等待导出</string> <string name="export_wait">等待导出</string>
<string name="show_bookshelf_fast_scroller">显示快速滚动条</string> <string name="show_bookshelf_fast_scroller">显示快速滚动条</string>
<string name="export_all_use_book_source">导出所有书的书源</string> <string name="export_all_use_book_source">导出所有书的书源</string>
<string name="keep_enable">保留启用状态</string>
</resources> </resources>

View File

@ -1132,4 +1132,5 @@
<string name="export_wait">等待导出</string> <string name="export_wait">等待导出</string>
<string name="show_bookshelf_fast_scroller">显示快速滚动条</string> <string name="show_bookshelf_fast_scroller">显示快速滚动条</string>
<string name="export_all_use_book_source">导出所有书的书源</string> <string name="export_all_use_book_source">导出所有书的书源</string>
<string name="keep_enable">保留启用状态</string>
</resources> </resources>

View File

@ -1134,4 +1134,5 @@
<string name="default_home_page">默认主页</string> <string name="default_home_page">默认主页</string>
<string name="show_bookshelf_fast_scroller">显示快速滚动条</string> <string name="show_bookshelf_fast_scroller">显示快速滚动条</string>
<string name="export_all_use_book_source">导出所有书的书源</string> <string name="export_all_use_book_source">导出所有书的书源</string>
<string name="keep_enable">保留启用状态</string>
</resources> </resources>