mirror of
https://github.com/gedoor/legado.git
synced 2024-09-01 09:34:25 +08:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
715dcd20ba
@ -137,6 +137,7 @@ object PreferKey {
|
||||
const val openBookInfoByClickTitle = "openBookInfoByClickTitle"
|
||||
const val defaultHomePage = "defaultHomePage"
|
||||
const val showBookshelfFastScroller = "showBookshelfFastScroller"
|
||||
const val importKeepEnable = "importKeepEnable"
|
||||
|
||||
const val cPrimary = "colorPrimary"
|
||||
const val cAccent = "colorAccent"
|
||||
|
@ -420,6 +420,11 @@ object AppConfig : SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
|
||||
val importKeepName get() = appCtx.getPrefBoolean(PreferKey.importKeepName)
|
||||
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
|
||||
get() = appCtx.getPrefInt(PreferKey.preDownloadNum, 10)
|
||||
|
@ -142,6 +142,8 @@ class ImportBookSourceDialog() : BaseDialogFragment(R.layout.dialog_recycler_vie
|
||||
?.isChecked = AppConfig.importKeepName
|
||||
binding.toolBar.menu.findItem(R.id.menu_keep_group)
|
||||
?.isChecked = AppConfig.importKeepGroup
|
||||
binding.toolBar.menu.findItem(R.id.menu_keep_enable)
|
||||
?.isChecked = AppConfig.importKeepEnable
|
||||
}
|
||||
|
||||
@SuppressLint("InflateParams", "NotifyDataSetChanged")
|
||||
@ -179,6 +181,11 @@ class ImportBookSourceDialog() : BaseDialogFragment(R.layout.dialog_recycler_vie
|
||||
item.isChecked = !item.isChecked
|
||||
putPrefBoolean(PreferKey.importKeepGroup, item.isChecked)
|
||||
}
|
||||
|
||||
R.id.menu_keep_enable -> {
|
||||
item.isChecked = !item.isChecked
|
||||
AppConfig.importKeepEnable = item.isChecked
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
@ -87,6 +87,7 @@ class ImportBookSourceViewModel(app: Application) : BaseViewModel(app) {
|
||||
val group = groupName?.trim()
|
||||
val keepName = AppConfig.importKeepName
|
||||
val keepGroup = AppConfig.importKeepGroup
|
||||
val keepEnable = AppConfig.importKeepEnable
|
||||
val selectSource = arrayListOf<BookSource>()
|
||||
selectStatus.forEachIndexed { index, b ->
|
||||
if (b) {
|
||||
@ -98,6 +99,10 @@ class ImportBookSourceViewModel(app: Application) : BaseViewModel(app) {
|
||||
if (keepGroup) {
|
||||
source.bookSourceGroup = it.bookSourceGroup
|
||||
}
|
||||
if (keepEnable) {
|
||||
source.enabled = it.enabled
|
||||
source.enabledExplore = it.enabledExplore
|
||||
}
|
||||
source.customOrder = it.customOrder
|
||||
}
|
||||
if (!group.isNullOrEmpty()) {
|
||||
|
@ -36,6 +36,8 @@ class ChangeBookSourceAdapter(
|
||||
override fun areContentsTheSame(oldItem: SearchBook, newItem: SearchBook): Boolean {
|
||||
return oldItem.originName == newItem.originName
|
||||
&& oldItem.getDisplayLastChapterTitle() == newItem.getDisplayLastChapterTitle()
|
||||
&& oldItem.chapterWordCountText == newItem.chapterWordCountText
|
||||
&& oldItem.respondTime == newItem.respondTime
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -72,7 +72,8 @@ class ChangeBookSourceDialog() : BaseDialogFragment(R.layout.dialog_book_change_
|
||||
private val adapter by lazy { ChangeBookSourceAdapter(requireContext(), viewModel, this) }
|
||||
private val editSourceResult =
|
||||
registerForActivityResult(StartActivityContract(BookSourceEditActivity::class.java)) {
|
||||
viewModel.startSearch()
|
||||
val origin = it.data?.getStringExtra("origin") ?: return@registerForActivityResult
|
||||
viewModel.startSearch(origin)
|
||||
}
|
||||
private val searchFinishCallback: (isEmpty: Boolean) -> Unit = {
|
||||
if (it) {
|
||||
|
@ -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.book.BookHelp
|
||||
import io.legado.app.help.book.ContentProcessor
|
||||
import io.legado.app.help.config.AppConfig
|
||||
import io.legado.app.help.config.SourceConfig
|
||||
import io.legado.app.help.coroutine.CompositeCoroutine
|
||||
@ -50,8 +51,25 @@ open class ChangeBookSourceViewModel(application: Application) : BaseViewModel(a
|
||||
private var searchBookList = arrayListOf<SearchBook>()
|
||||
private val searchBooks = Collections.synchronizedList(arrayListOf<SearchBook>())
|
||||
private val tocMap = ConcurrentHashMap<String, List<BookChapter>>()
|
||||
private val contentProcessor by lazy {
|
||||
ContentProcessor.get(oldBook!!)
|
||||
}
|
||||
private var searchCallback: SourceCallback? = null
|
||||
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 searchDataFlow = callbackFlow {
|
||||
|
||||
@ -88,26 +106,12 @@ open class ChangeBookSourceViewModel(application: Application) : BaseViewModel(a
|
||||
}
|
||||
}.map {
|
||||
kotlin.runCatching {
|
||||
searchBooks.sortedWith { o1, o2 ->
|
||||
val o1bs = SourceConfig.getBookScore(o1.origin, o1.name, o1.author)
|
||||
val o2bs = SourceConfig.getBookScore(o2.origin, o2.name, o2.author)
|
||||
when {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
val comparator = if (AppConfig.changeSourceLoadWordCount) {
|
||||
wordCountComparator
|
||||
} else {
|
||||
defaultComparator
|
||||
}
|
||||
searchBooks.sortedWith(comparator)
|
||||
}.onFailure {
|
||||
AppLog.put("换源排序出错\n${it.localizedMessage}", it)
|
||||
}.getOrDefault(searchBooks)
|
||||
@ -153,9 +157,18 @@ open class ChangeBookSourceViewModel(application: Application) : BaseViewModel(a
|
||||
/**
|
||||
* 搜索书籍
|
||||
*/
|
||||
fun startSearch() {
|
||||
fun startSearch(origin: String? = null) {
|
||||
execute {
|
||||
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)
|
||||
searchBooks.clear()
|
||||
searchCallback?.upAdapter()
|
||||
@ -182,7 +195,7 @@ open class ChangeBookSourceViewModel(application: Application) : BaseViewModel(a
|
||||
|
||||
private fun search() {
|
||||
val searchIndex = synchronized(this) {
|
||||
if (searchIndex >= bookSourceList.lastIndex) {
|
||||
if (searchIndex > bookSourceList.lastIndex) {
|
||||
return
|
||||
}
|
||||
searchIndex++
|
||||
@ -256,17 +269,18 @@ open class ChangeBookSourceViewModel(application: Application) : BaseViewModel(a
|
||||
)
|
||||
} ?: chapters.lastIndex
|
||||
} else chapters.lastIndex
|
||||
val bookChapter = chapters.getOrNull(chapterIndex)
|
||||
val bookChapter = chapters[chapterIndex]
|
||||
val title = bookChapter.title.trim()
|
||||
val startTime = System.currentTimeMillis()
|
||||
val pair = try {
|
||||
if (bookChapter == null) throw NoStackTraceException("章节缺失,总章节数${chapters.size}")
|
||||
val nextChapterUrl = chapters.getOrNull(chapterIndex + 1)?.url
|
||||
WebBook.getContentAwait(source, book, bookChapter, nextChapterUrl, false).length.let {
|
||||
it to "第${chapterIndex + 1}章 字数:${it}"
|
||||
}
|
||||
var content = WebBook.getContentAwait(source, book, bookChapter, nextChapterUrl, false)
|
||||
content = contentProcessor.getContent(oldBook!!, bookChapter, content, false).toString()
|
||||
val len = content.length
|
||||
len to "[${chapterIndex + 1}] ${title}\n字数:${len}"
|
||||
} catch (t: Throwable) {
|
||||
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 searchBook = book.toSearchBook().apply {
|
||||
@ -526,6 +540,11 @@ open class ChangeBookSourceViewModel(application: Application) : BaseViewModel(a
|
||||
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 {
|
||||
|
||||
fun searchSuccess(searchBook: SearchBook)
|
||||
|
@ -1,6 +1,7 @@
|
||||
package io.legado.app.ui.book.source.edit
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
@ -119,7 +120,7 @@ class BookSourceEditActivity :
|
||||
override fun onCompatOptionsItemSelected(item: MenuItem): Boolean {
|
||||
when (item.itemId) {
|
||||
R.id.menu_save -> viewModel.save(getSource()) {
|
||||
setResult(Activity.RESULT_OK)
|
||||
setResult(Activity.RESULT_OK, Intent().putExtra("origin", it.bookSourceUrl))
|
||||
finish()
|
||||
}
|
||||
|
||||
@ -410,8 +411,8 @@ class BookSourceEditActivity :
|
||||
"intro" -> searchRule.intro =
|
||||
viewModel.ruleComplete(it.value, searchRule.bookList)
|
||||
|
||||
"updateTime" -> searchRule.updateTime =
|
||||
viewModel.ruleComplete(it.value, searchRule.bookList)
|
||||
// "updateTime" -> searchRule.updateTime =
|
||||
// viewModel.ruleComplete(it.value, searchRule.bookList)
|
||||
|
||||
"wordCount" -> searchRule.wordCount =
|
||||
viewModel.ruleComplete(it.value, searchRule.bookList)
|
||||
@ -442,8 +443,8 @@ class BookSourceEditActivity :
|
||||
"intro" -> exploreRule.intro =
|
||||
viewModel.ruleComplete(it.value, exploreRule.bookList)
|
||||
|
||||
"updateTime" -> exploreRule.updateTime =
|
||||
viewModel.ruleComplete(it.value, exploreRule.bookList)
|
||||
// "updateTime" -> exploreRule.updateTime =
|
||||
// viewModel.ruleComplete(it.value, exploreRule.bookList)
|
||||
|
||||
"wordCount" -> exploreRule.wordCount =
|
||||
viewModel.ruleComplete(it.value, exploreRule.bookList)
|
||||
@ -471,8 +472,8 @@ class BookSourceEditActivity :
|
||||
"intro" -> bookInfoRule.intro =
|
||||
viewModel.ruleComplete(it.value, bookInfoRule.init)
|
||||
|
||||
"updateTime" -> bookInfoRule.updateTime =
|
||||
viewModel.ruleComplete(it.value, bookInfoRule.init)
|
||||
// "updateTime" -> bookInfoRule.updateTime =
|
||||
// viewModel.ruleComplete(it.value, bookInfoRule.init)
|
||||
|
||||
"wordCount" -> bookInfoRule.wordCount =
|
||||
viewModel.ruleComplete(it.value, bookInfoRule.init)
|
||||
|
@ -41,8 +41,8 @@ class BookSourceEditViewModel(application: Application) : BaseViewModel(applicat
|
||||
if (source.bookSourceUrl.isBlank() || source.bookSourceName.isBlank()) {
|
||||
throw NoStackTraceException(context.getString(R.string.non_null_name_url))
|
||||
}
|
||||
if (!source.equal(bookSource ?: BookSource())) {
|
||||
source.lastUpdateTime = System.currentTimeMillis()
|
||||
if (source.equal(bookSource ?: BookSource())) {
|
||||
return@execute source
|
||||
}
|
||||
bookSource?.let {
|
||||
appDb.bookSourceDao.delete(it)
|
||||
@ -91,6 +91,7 @@ class BookSourceEditViewModel(application: Application) : BaseViewModel(applicat
|
||||
val text1 = okHttpClient.newCallStrResponse { url(text) }.body
|
||||
importSource(text1!!)
|
||||
}
|
||||
|
||||
text.isJsonArray() -> {
|
||||
if (text.contains("ruleSearchUrl") || text.contains("ruleFindUrl")) {
|
||||
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]
|
||||
}
|
||||
}
|
||||
|
||||
text.isJsonObject() -> {
|
||||
if (text.contains("ruleSearchUrl") || text.contains("ruleFindUrl")) {
|
||||
val jsonItem = jsonPath.parse(text)
|
||||
@ -108,6 +110,7 @@ class BookSourceEditViewModel(application: Application) : BaseViewModel(applicat
|
||||
GSON.fromJsonObject<BookSource>(text).getOrThrow()
|
||||
}
|
||||
}
|
||||
|
||||
else -> throw NoStackTraceException("格式不对")
|
||||
}
|
||||
}
|
||||
|
@ -82,7 +82,7 @@
|
||||
tools:text="word count"
|
||||
android:textColor="@color/secondaryText"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintRight_toLeftOf="@+id/iv_checked"
|
||||
app:layout_constraintTop_toBottomOf="@+id/tv_last" />
|
||||
|
||||
<TextView
|
||||
@ -96,7 +96,7 @@
|
||||
android:textColor="@color/secondaryText"
|
||||
app:layout_constraintBottom_toBottomOf="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" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
|
@ -31,4 +31,10 @@
|
||||
android:checkable="true"
|
||||
app:showAsAction="never" />
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_keep_enable"
|
||||
android:title="@string/keep_enable"
|
||||
android:checkable="true"
|
||||
app:showAsAction="never" />
|
||||
|
||||
</menu>
|
@ -1131,4 +1131,5 @@
|
||||
<string name="default_home_page">默认主页</string>
|
||||
<string name="show_bookshelf_fast_scroller">显示快速滚动条</string>
|
||||
<string name="export_all_use_book_source">导出所有书的书源</string>
|
||||
<string name="keep_enable">保留启用状态</string>
|
||||
</resources>
|
||||
|
@ -1134,4 +1134,5 @@
|
||||
<string name="default_home_page">默认主页</string>
|
||||
<string name="show_bookshelf_fast_scroller">显示快速滚动条</string>
|
||||
<string name="export_all_use_book_source">导出所有书的书源</string>
|
||||
<string name="keep_enable">保留启用状态</string>
|
||||
</resources>
|
||||
|
@ -1134,4 +1134,5 @@
|
||||
<string name="default_home_page">默认主页</string>
|
||||
<string name="show_bookshelf_fast_scroller">显示快速滚动条</string>
|
||||
<string name="export_all_use_book_source">导出所有书的书源</string>
|
||||
<string name="keep_enable">保留启用状态</string>
|
||||
</resources>
|
||||
|
@ -1129,4 +1129,5 @@ Còn </string>
|
||||
<string name="export_wait">等待导出</string>
|
||||
<string name="show_bookshelf_fast_scroller">显示快速滚动条</string>
|
||||
<string name="export_all_use_book_source">导出所有书的书源</string>
|
||||
<string name="keep_enable">保留启用状态</string>
|
||||
</resources>
|
||||
|
@ -1130,4 +1130,5 @@
|
||||
<string name="export_wait">等待导出</string>
|
||||
<string name="show_bookshelf_fast_scroller">显示快速滚动条</string>
|
||||
<string name="export_all_use_book_source">导出所有书的书源</string>
|
||||
<string name="keep_enable">保留启用状态</string>
|
||||
</resources>
|
||||
|
@ -1132,4 +1132,5 @@
|
||||
<string name="export_wait">等待导出</string>
|
||||
<string name="show_bookshelf_fast_scroller">显示快速滚动条</string>
|
||||
<string name="export_all_use_book_source">导出所有书的书源</string>
|
||||
<string name="keep_enable">保留启用状态</string>
|
||||
</resources>
|
||||
|
@ -1132,4 +1132,5 @@
|
||||
<string name="export_wait">等待导出</string>
|
||||
<string name="show_bookshelf_fast_scroller">显示快速滚动条</string>
|
||||
<string name="export_all_use_book_source">导出所有书的书源</string>
|
||||
<string name="keep_enable">保留启用状态</string>
|
||||
</resources>
|
||||
|
@ -1134,4 +1134,5 @@
|
||||
<string name="default_home_page">默认主页</string>
|
||||
<string name="show_bookshelf_fast_scroller">显示快速滚动条</string>
|
||||
<string name="export_all_use_book_source">导出所有书的书源</string>
|
||||
<string name="keep_enable">保留启用状态</string>
|
||||
</resources>
|
||||
|
Loading…
Reference in New Issue
Block a user