mirror of
https://github.com/gedoor/legado.git
synced 2024-08-30 09:23:26 +08:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
ba90882998
@ -5,6 +5,7 @@ import android.content.Context
|
||||
import android.util.SparseArray
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.os.postDelayed
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
@ -160,6 +161,12 @@ abstract class RecyclerAdapter<ITEM, VB : ViewBinding>(protected val context: Co
|
||||
onCurrentListChanged()
|
||||
}
|
||||
}
|
||||
handler.postDelayed(1000) {
|
||||
if (diffJob?.isCompleted == false) {
|
||||
diffJob?.cancel()
|
||||
setItems(items)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -130,6 +130,7 @@ object PreferKey {
|
||||
const val clearWebViewData = "clearWebViewData"
|
||||
const val onlyLatestBackup = "onlyLatestBackup"
|
||||
const val brightnessVwPos = "brightnessVwPos"
|
||||
const val shrinkDatabase = "shrinkDatabase"
|
||||
|
||||
const val cPrimary = "colorPrimary"
|
||||
const val cAccent = "colorAccent"
|
||||
|
@ -3,6 +3,7 @@ package io.legado.app.data.dao
|
||||
import androidx.room.*
|
||||
import io.legado.app.constant.AppPattern
|
||||
import io.legado.app.data.entities.BookSource
|
||||
import io.legado.app.data.entities.BookSourcePart
|
||||
import io.legado.app.utils.cnCompare
|
||||
import io.legado.app.utils.splitNotBlank
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
@ -11,21 +12,29 @@ import kotlinx.coroutines.flow.map
|
||||
@Dao
|
||||
interface BookSourceDao {
|
||||
|
||||
@Query("select * from book_sources order by customOrder asc")
|
||||
fun flowAll(): Flow<List<BookSource>>
|
||||
@Query(
|
||||
"""select bookSourceUrl, bookSourceName, bookSourceGroup, customOrder, enabled, enabledExplore,
|
||||
trim(loginUrl) <> '' hasLoginUrl, lastUpdateTime, respondTime, weight, trim(exploreUrl) <> '' hasExploreUrl
|
||||
from book_sources order by customOrder asc"""
|
||||
)
|
||||
fun flowAll(): Flow<List<BookSourcePart>>
|
||||
|
||||
@Query(
|
||||
"""select * from book_sources
|
||||
"""select bookSourceUrl, bookSourceName, bookSourceGroup, customOrder, enabled, enabledExplore,
|
||||
trim(loginUrl) <> '' hasLoginUrl, lastUpdateTime, respondTime, weight, trim(exploreUrl) <> '' hasExploreUrl
|
||||
from book_sources
|
||||
where bookSourceName like '%' || :searchKey || '%'
|
||||
or bookSourceGroup like '%' || :searchKey || '%'
|
||||
or bookSourceUrl like '%' || :searchKey || '%'
|
||||
or bookSourceComment like '%' || :searchKey || '%'
|
||||
order by customOrder asc"""
|
||||
)
|
||||
fun flowSearch(searchKey: String): Flow<List<BookSource>>
|
||||
fun flowSearch(searchKey: String): Flow<List<BookSourcePart>>
|
||||
|
||||
@Query(
|
||||
"""select * from book_sources
|
||||
"""select bookSourceUrl, bookSourceName, bookSourceGroup, customOrder, enabled, enabledExplore,
|
||||
trim(loginUrl) <> '' hasLoginUrl, lastUpdateTime, respondTime, weight, trim(exploreUrl) <> '' hasExploreUrl
|
||||
from book_sources
|
||||
where enabled = 1 and
|
||||
(bookSourceName like '%' || :searchKey || '%'
|
||||
or bookSourceGroup like '%' || :searchKey || '%'
|
||||
@ -33,32 +42,42 @@ interface BookSourceDao {
|
||||
or bookSourceComment like '%' || :searchKey || '%')
|
||||
order by customOrder asc"""
|
||||
)
|
||||
fun flowSearchEnabled(searchKey: String): Flow<List<BookSource>>
|
||||
fun flowSearchEnabled(searchKey: String): Flow<List<BookSourcePart>>
|
||||
|
||||
@Query(
|
||||
"""select * from book_sources
|
||||
"""select bookSourceUrl, bookSourceName, bookSourceGroup, customOrder, enabled, enabledExplore,
|
||||
trim(loginUrl) <> '' hasLoginUrl, lastUpdateTime, respondTime, weight, trim(exploreUrl) <> '' hasExploreUrl
|
||||
from book_sources
|
||||
where bookSourceGroup = :searchKey
|
||||
or bookSourceGroup like :searchKey || ',%'
|
||||
or bookSourceGroup like '%,' || :searchKey
|
||||
or bookSourceGroup like '%,' || :searchKey || ',%'
|
||||
order by customOrder asc"""
|
||||
)
|
||||
fun flowGroupSearch(searchKey: String): Flow<List<BookSource>>
|
||||
fun flowGroupSearch(searchKey: String): Flow<List<BookSourcePart>>
|
||||
|
||||
@Query("select * from book_sources where enabled = 1 order by customOrder asc")
|
||||
fun flowEnabled(): Flow<List<BookSource>>
|
||||
@Query("""select bookSourceUrl, bookSourceName, bookSourceGroup, customOrder, enabled, enabledExplore,
|
||||
trim(loginUrl) <> '' hasLoginUrl, lastUpdateTime, respondTime, weight, trim(exploreUrl) <> '' hasExploreUrl
|
||||
from book_sources where enabled = 1 order by customOrder asc""")
|
||||
fun flowEnabled(): Flow<List<BookSourcePart>>
|
||||
|
||||
@Query("select * from book_sources where enabled = 0 order by customOrder asc")
|
||||
fun flowDisabled(): Flow<List<BookSource>>
|
||||
@Query("""select bookSourceUrl, bookSourceName, bookSourceGroup, customOrder, enabled, enabledExplore,
|
||||
trim(loginUrl) <> '' hasLoginUrl, lastUpdateTime, respondTime, weight, trim(exploreUrl) <> '' hasExploreUrl
|
||||
from book_sources where enabled = 0 order by customOrder asc""")
|
||||
fun flowDisabled(): Flow<List<BookSourcePart>>
|
||||
|
||||
@Query("select * from book_sources where enabledExplore = 1 and trim(exploreUrl) <> '' order by customOrder asc")
|
||||
fun flowExplore(): Flow<List<BookSource>>
|
||||
|
||||
@Query("select * from book_sources where loginUrl is not null and loginUrl != ''")
|
||||
fun flowLogin(): Flow<List<BookSource>>
|
||||
@Query("""select bookSourceUrl, bookSourceName, bookSourceGroup, customOrder, enabled, enabledExplore,
|
||||
trim(loginUrl) <> '' hasLoginUrl, lastUpdateTime, respondTime, weight, trim(exploreUrl) <> '' hasExploreUrl
|
||||
from book_sources where loginUrl is not null and loginUrl != ''""")
|
||||
fun flowLogin(): Flow<List<BookSourcePart>>
|
||||
|
||||
@Query("select * from book_sources where bookSourceGroup is null or bookSourceGroup = '' or bookSourceGroup like '%未分组%'")
|
||||
fun flowNoGroup(): Flow<List<BookSource>>
|
||||
@Query("""select bookSourceUrl, bookSourceName, bookSourceGroup, customOrder, enabled, enabledExplore,
|
||||
trim(loginUrl) <> '' hasLoginUrl, lastUpdateTime, respondTime, weight, trim(exploreUrl) <> '' hasExploreUrl
|
||||
from book_sources where bookSourceGroup is null or bookSourceGroup = '' or bookSourceGroup like '%未分组%'""")
|
||||
fun flowNoGroup(): Flow<List<BookSourcePart>>
|
||||
|
||||
@Query(
|
||||
"""select * from book_sources
|
||||
@ -155,12 +174,59 @@ interface BookSourceDao {
|
||||
@Query("delete from book_sources where bookSourceUrl = :key")
|
||||
fun delete(key: String)
|
||||
|
||||
@Transaction
|
||||
fun delete(bookSources: List<BookSourcePart>) {
|
||||
for (bs in bookSources) {
|
||||
delete(bs.bookSourceUrl)
|
||||
}
|
||||
}
|
||||
|
||||
@get:Query("select min(customOrder) from book_sources")
|
||||
val minOrder: Int
|
||||
|
||||
@get:Query("select max(customOrder) from book_sources")
|
||||
val maxOrder: Int
|
||||
|
||||
@Query("update book_sources set enabled = :enable where bookSourceUrl = :bookSourceUrl")
|
||||
fun enable(bookSourceUrl: String, enable: Boolean)
|
||||
|
||||
@Transaction
|
||||
fun enable(enable: Boolean, bookSources: List<BookSourcePart>) {
|
||||
for (bs in bookSources) {
|
||||
enable(bs.bookSourceUrl, enable)
|
||||
}
|
||||
}
|
||||
|
||||
@Query("update book_sources set enabledExplore = :enable where bookSourceUrl = :bookSourceUrl")
|
||||
fun enableExplore(bookSourceUrl: String, enable: Boolean)
|
||||
|
||||
@Transaction
|
||||
fun enableExplore(enable: Boolean, bookSources: List<BookSourcePart>) {
|
||||
for (bs in bookSources) {
|
||||
enableExplore(bs.bookSourceUrl, enable)
|
||||
}
|
||||
}
|
||||
|
||||
@Query("update book_sources set customOrder = :customOrder where bookSourceUrl = :bookSourceUrl")
|
||||
fun upOrder(bookSourceUrl: String, customOrder: Int)
|
||||
|
||||
@Transaction
|
||||
fun upOrder(bookSources: List<BookSourcePart>) {
|
||||
for (bs in bookSources) {
|
||||
upOrder(bs.bookSourceUrl, bs.customOrder)
|
||||
}
|
||||
}
|
||||
|
||||
@Query("update book_sources set bookSourceGroup = :bookSourceGroup where bookSourceUrl = :bookSourceUrl")
|
||||
fun upGroup(bookSourceUrl: String, bookSourceGroup: String)
|
||||
|
||||
@Transaction
|
||||
fun upGroup(bookSources: List<BookSourcePart>) {
|
||||
for (bs in bookSources) {
|
||||
bs.bookSourceGroup?.let { upGroup(bs.bookSourceUrl, it) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun dealGroups(list: List<String>): List<String> {
|
||||
val groups = linkedSetOf<String>()
|
||||
list.forEach {
|
||||
|
@ -0,0 +1,73 @@
|
||||
package io.legado.app.data.entities
|
||||
|
||||
import android.text.TextUtils
|
||||
import io.legado.app.constant.AppPattern
|
||||
import io.legado.app.data.appDb
|
||||
import io.legado.app.utils.splitNotBlank
|
||||
|
||||
|
||||
data class BookSourcePart(
|
||||
// 地址,包括 http/https
|
||||
var bookSourceUrl: String = "",
|
||||
// 名称
|
||||
var bookSourceName: String = "",
|
||||
// 分组
|
||||
var bookSourceGroup: String? = null,
|
||||
// 手动排序编号
|
||||
var customOrder: Int = 0,
|
||||
// 是否启用
|
||||
var enabled: Boolean = true,
|
||||
// 启用发现
|
||||
var enabledExplore: Boolean = true,
|
||||
// 是否有登录地址
|
||||
var hasLoginUrl: Boolean = false,
|
||||
// 最后更新时间,用于排序
|
||||
var lastUpdateTime: Long = 0,
|
||||
// 响应时间,用于排序
|
||||
var respondTime: Long = 180000L,
|
||||
// 智能排序的权重
|
||||
var weight: Int = 0,
|
||||
// 是否有发现url
|
||||
var hasExploreUrl: Boolean = false
|
||||
) {
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return bookSourceUrl.hashCode()
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
return if (other is BookSourcePart) other.bookSourceUrl == bookSourceUrl else false
|
||||
}
|
||||
|
||||
fun getDisPlayNameGroup(): String {
|
||||
return if (bookSourceGroup.isNullOrBlank()) {
|
||||
bookSourceName
|
||||
} else {
|
||||
String.format("%s (%s)", bookSourceName, bookSourceGroup)
|
||||
}
|
||||
}
|
||||
|
||||
fun getBookSource(): BookSource? {
|
||||
return appDb.bookSourceDao.getBookSource(bookSourceUrl)
|
||||
}
|
||||
|
||||
fun addGroup(groups: String) {
|
||||
bookSourceGroup?.splitNotBlank(AppPattern.splitGroupRegex)?.toHashSet()?.let {
|
||||
it.addAll(groups.splitNotBlank(AppPattern.splitGroupRegex))
|
||||
bookSourceGroup = TextUtils.join(",", it)
|
||||
}
|
||||
if (bookSourceGroup.isNullOrBlank()) bookSourceGroup = groups
|
||||
}
|
||||
|
||||
fun removeGroup(groups: String) {
|
||||
bookSourceGroup?.splitNotBlank(AppPattern.splitGroupRegex)?.toHashSet()?.let {
|
||||
it.removeAll(groups.splitNotBlank(AppPattern.splitGroupRegex).toSet())
|
||||
bookSourceGroup = TextUtils.join(",", it)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun List<BookSourcePart>.toBookSource(): List<BookSource> {
|
||||
return mapNotNull { it.getBookSource() }
|
||||
}
|
@ -13,6 +13,7 @@ import android.webkit.WebViewClient
|
||||
import io.legado.app.constant.AppConst
|
||||
import io.legado.app.exception.NoStackTraceException
|
||||
import io.legado.app.help.config.AppConfig
|
||||
import io.legado.app.help.coroutine.Coroutine
|
||||
import io.legado.app.utils.runOnUI
|
||||
import kotlinx.coroutines.Runnable
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
@ -80,6 +81,7 @@ class BackstageWebView(
|
||||
} else {
|
||||
webView.loadDataWithBaseURL(url, html, "text/html", getEncoding(), url)
|
||||
}
|
||||
|
||||
else -> if (headerMap == null) {
|
||||
webView.loadUrl(url!!)
|
||||
} else {
|
||||
@ -131,10 +133,15 @@ class BackstageWebView(
|
||||
|
||||
private inner class HtmlWebViewClient : WebViewClient() {
|
||||
|
||||
var runnable: EvalJsRunnable? = null
|
||||
|
||||
override fun onPageFinished(view: WebView, url: String) {
|
||||
setCookie(url)
|
||||
val runnable = EvalJsRunnable(view, url, getJs())
|
||||
mHandler.postDelayed(runnable, 1000)
|
||||
if (runnable == null) {
|
||||
runnable = EvalJsRunnable(view, url, getJs())
|
||||
}
|
||||
mHandler.removeCallbacks(runnable!!)
|
||||
mHandler.postDelayed(runnable!!, 1000)
|
||||
}
|
||||
|
||||
@SuppressLint("WebViewClientOnReceivedSslError")
|
||||
@ -157,30 +164,35 @@ class BackstageWebView(
|
||||
private val mWebView: WeakReference<WebView> = WeakReference(webView)
|
||||
override fun run() {
|
||||
mWebView.get()?.evaluateJavascript(mJavaScript) {
|
||||
if (it.isNotEmpty() && it != "null") {
|
||||
val content = StringEscapeUtils.unescapeJson(it)
|
||||
.replace("^\"|\"$".toRegex(), "")
|
||||
try {
|
||||
val response = StrResponse(url, content)
|
||||
callback?.onResult(response)
|
||||
} catch (e: Exception) {
|
||||
callback?.onError(e)
|
||||
}
|
||||
mHandler.removeCallbacks(this)
|
||||
destroy()
|
||||
return@evaluateJavascript
|
||||
}
|
||||
if (retry > 30) {
|
||||
callback?.onError(NoStackTraceException("js执行超时"))
|
||||
mHandler.removeCallbacks(this)
|
||||
destroy()
|
||||
return@evaluateJavascript
|
||||
}
|
||||
retry++
|
||||
mHandler.removeCallbacks(this)
|
||||
mHandler.postDelayed(this, 1000)
|
||||
handleResult(it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleResult(result: String) = Coroutine.async {
|
||||
if (result.isNotEmpty() && result != "null") {
|
||||
val content = StringEscapeUtils.unescapeJson(result)
|
||||
.replace(quoteRegex, "")
|
||||
try {
|
||||
val response = StrResponse(url, content)
|
||||
callback?.onResult(response)
|
||||
} catch (e: Exception) {
|
||||
callback?.onError(e)
|
||||
}
|
||||
mHandler.post {
|
||||
destroy()
|
||||
}
|
||||
return@async
|
||||
}
|
||||
if (retry > 30) {
|
||||
callback?.onError(NoStackTraceException("js执行超时"))
|
||||
mHandler.post {
|
||||
destroy()
|
||||
}
|
||||
return@async
|
||||
}
|
||||
retry++
|
||||
mHandler.postDelayed(this@EvalJsRunnable, 1000)
|
||||
}
|
||||
}
|
||||
|
||||
private inner class SnifferWebClient : WebViewClient() {
|
||||
@ -231,6 +243,7 @@ class BackstageWebView(
|
||||
|
||||
companion object {
|
||||
const val JS = "document.documentElement.outerHTML"
|
||||
private val quoteRegex = "^\"|\"$".toRegex()
|
||||
}
|
||||
|
||||
abstract class Callback {
|
||||
|
@ -4,6 +4,7 @@ import android.content.Context
|
||||
import io.legado.app.R
|
||||
import io.legado.app.constant.IntentAction
|
||||
import io.legado.app.data.entities.BookSource
|
||||
import io.legado.app.data.entities.BookSourcePart
|
||||
import io.legado.app.help.CacheManager
|
||||
import io.legado.app.help.IntentData
|
||||
import io.legado.app.service.CheckSourceService
|
||||
@ -22,7 +23,7 @@ object CheckSource {
|
||||
var checkContent = CacheManager.get("checkContent")?.toBoolean() ?: true
|
||||
val summary get() = upSummary()
|
||||
|
||||
fun start(context: Context, sources: List<BookSource>) {
|
||||
fun start(context: Context, sources: List<BookSourcePart>) {
|
||||
val selectedIds = sources.map {
|
||||
it.bookSourceUrl
|
||||
}
|
||||
|
@ -56,18 +56,17 @@ class ExploreShowViewModel(application: Application) : BaseViewModel(application
|
||||
fun explore() {
|
||||
val source = bookSource
|
||||
val url = exploreUrl
|
||||
if (source != null && url != null) {
|
||||
WebBook.exploreBook(viewModelScope, source, url, page)
|
||||
.timeout(if (BuildConfig.DEBUG) 0L else 30000L)
|
||||
.onSuccess(IO) { searchBooks ->
|
||||
booksData.postValue(searchBooks)
|
||||
appDb.searchBookDao.insert(*searchBooks.toTypedArray())
|
||||
page++
|
||||
}.onError {
|
||||
it.printOnDebug()
|
||||
errorLiveData.postValue(it.stackTraceStr)
|
||||
}
|
||||
}
|
||||
if (source == null || url == null) return
|
||||
WebBook.exploreBook(viewModelScope, source, url, page)
|
||||
.timeout(if (BuildConfig.DEBUG) 0L else 30000L)
|
||||
.onSuccess(IO) { searchBooks ->
|
||||
booksData.postValue(searchBooks)
|
||||
appDb.searchBookDao.insert(*searchBooks.toTypedArray())
|
||||
page++
|
||||
}.onError {
|
||||
it.printOnDebug()
|
||||
errorLiveData.postValue(it.stackTraceStr)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ import io.legado.app.base.adapter.ItemViewHolder
|
||||
import io.legado.app.base.adapter.RecyclerAdapter
|
||||
import io.legado.app.data.appDb
|
||||
import io.legado.app.data.entities.BookSource
|
||||
import io.legado.app.data.entities.BookSourcePart
|
||||
import io.legado.app.databinding.DialogSourcePickerBinding
|
||||
import io.legado.app.databinding.Item1lineTextBinding
|
||||
import io.legado.app.lib.theme.primaryColor
|
||||
@ -81,7 +82,7 @@ class SourcePickerDialog : BaseDialogFragment(R.layout.dialog_source_picker) {
|
||||
}
|
||||
|
||||
inner class SourceAdapter(context: Context) :
|
||||
RecyclerAdapter<BookSource, Item1lineTextBinding>(context) {
|
||||
RecyclerAdapter<BookSourcePart, Item1lineTextBinding>(context) {
|
||||
|
||||
override fun getViewBinding(parent: ViewGroup): Item1lineTextBinding {
|
||||
return Item1lineTextBinding.inflate(inflater, parent, false).apply {
|
||||
@ -92,7 +93,7 @@ class SourcePickerDialog : BaseDialogFragment(R.layout.dialog_source_picker) {
|
||||
override fun convert(
|
||||
holder: ItemViewHolder,
|
||||
binding: Item1lineTextBinding,
|
||||
item: BookSource,
|
||||
item: BookSourcePart,
|
||||
payloads: MutableList<Any>
|
||||
) {
|
||||
binding.textView.text = item.getDisPlayNameGroup()
|
||||
@ -101,7 +102,9 @@ class SourcePickerDialog : BaseDialogFragment(R.layout.dialog_source_picker) {
|
||||
override fun registerListener(holder: ItemViewHolder, binding: Item1lineTextBinding) {
|
||||
binding.root.onClick {
|
||||
getItemByLayoutPosition(holder.layoutPosition)?.let {
|
||||
callback?.sourceOnClick(it)
|
||||
it.getBookSource()?.let { source ->
|
||||
callback?.sourceOnClick(source)
|
||||
}
|
||||
dismissAllowingStateLoss()
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import androidx.lifecycle.MutableLiveData
|
||||
import io.legado.app.R
|
||||
import io.legado.app.data.appDb
|
||||
import io.legado.app.data.entities.BookSource
|
||||
import io.legado.app.data.entities.BookSourcePart
|
||||
import io.legado.app.help.config.AppConfig
|
||||
import io.legado.app.utils.splitNotBlank
|
||||
import splitties.init.appCtx
|
||||
@ -20,6 +21,10 @@ data class SearchScope(private var scope: String) {
|
||||
"${source.bookSourceName.replace(":", "")}::${source.bookSourceUrl}"
|
||||
)
|
||||
|
||||
constructor(source: BookSourcePart) : this(
|
||||
"${source.bookSourceName.replace(":", "")}::${source.bookSourceUrl}"
|
||||
)
|
||||
|
||||
override fun toString(): String {
|
||||
return scope
|
||||
}
|
||||
|
@ -17,6 +17,8 @@ import io.legado.app.constant.AppLog
|
||||
import io.legado.app.constant.EventBus
|
||||
import io.legado.app.data.appDb
|
||||
import io.legado.app.data.entities.BookSource
|
||||
import io.legado.app.data.entities.BookSourcePart
|
||||
import io.legado.app.data.entities.toBookSource
|
||||
import io.legado.app.databinding.ActivityBookSourceBinding
|
||||
import io.legado.app.databinding.DialogEditTextBinding
|
||||
import io.legado.app.help.DirectLinkUpload
|
||||
@ -143,54 +145,66 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
|
||||
mode = HandleFileContract.FILE
|
||||
allowExtensions = arrayOf("txt", "json")
|
||||
}
|
||||
|
||||
R.id.menu_import_onLine -> showImportDialog()
|
||||
R.id.menu_sort_manual -> {
|
||||
item.isChecked = true
|
||||
sortCheck(Sort.Default)
|
||||
upBookSource(searchView.query?.toString())
|
||||
}
|
||||
|
||||
R.id.menu_sort_auto -> {
|
||||
item.isChecked = true
|
||||
sortCheck(Sort.Weight)
|
||||
upBookSource(searchView.query?.toString())
|
||||
}
|
||||
|
||||
R.id.menu_sort_name -> {
|
||||
item.isChecked = true
|
||||
sortCheck(Sort.Name)
|
||||
upBookSource(searchView.query?.toString())
|
||||
}
|
||||
|
||||
R.id.menu_sort_url -> {
|
||||
item.isChecked = true
|
||||
sortCheck(Sort.Url)
|
||||
upBookSource(searchView.query?.toString())
|
||||
}
|
||||
|
||||
R.id.menu_sort_time -> {
|
||||
item.isChecked = true
|
||||
sortCheck(Sort.Update)
|
||||
upBookSource(searchView.query?.toString())
|
||||
}
|
||||
|
||||
R.id.menu_sort_respondTime -> {
|
||||
item.isChecked = true
|
||||
sortCheck(Sort.Respond)
|
||||
upBookSource(searchView.query?.toString())
|
||||
}
|
||||
|
||||
R.id.menu_sort_enable -> {
|
||||
item.isChecked = true
|
||||
sortCheck(Sort.Enable)
|
||||
upBookSource(searchView.query?.toString())
|
||||
}
|
||||
|
||||
R.id.menu_enabled_group -> {
|
||||
searchView.setQuery(getString(R.string.enabled), true)
|
||||
}
|
||||
|
||||
R.id.menu_disabled_group -> {
|
||||
searchView.setQuery(getString(R.string.disabled), true)
|
||||
}
|
||||
|
||||
R.id.menu_group_login -> {
|
||||
searchView.setQuery(getString(R.string.need_login), true)
|
||||
}
|
||||
|
||||
R.id.menu_group_null -> {
|
||||
searchView.setQuery(getString(R.string.no_group), true)
|
||||
}
|
||||
|
||||
R.id.menu_help -> showHelp()
|
||||
}
|
||||
if (item.groupId == R.id.source_group) {
|
||||
@ -228,22 +242,28 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
|
||||
searchKey.isNullOrEmpty() -> {
|
||||
appDb.bookSourceDao.flowAll()
|
||||
}
|
||||
|
||||
searchKey == getString(R.string.enabled) -> {
|
||||
appDb.bookSourceDao.flowEnabled()
|
||||
}
|
||||
|
||||
searchKey == getString(R.string.disabled) -> {
|
||||
appDb.bookSourceDao.flowDisabled()
|
||||
}
|
||||
|
||||
searchKey == getString(R.string.need_login) -> {
|
||||
appDb.bookSourceDao.flowLogin()
|
||||
}
|
||||
|
||||
searchKey == getString(R.string.no_group) -> {
|
||||
appDb.bookSourceDao.flowNoGroup()
|
||||
}
|
||||
|
||||
searchKey.startsWith("group:") -> {
|
||||
val key = searchKey.substringAfter("group:")
|
||||
appDb.bookSourceDao.flowGroupSearch(key)
|
||||
}
|
||||
|
||||
else -> {
|
||||
appDb.bookSourceDao.flowSearch(searchKey)
|
||||
}
|
||||
@ -253,6 +273,7 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
|
||||
Sort.Name -> data.sortedWith { o1, o2 ->
|
||||
o1.bookSourceName.cnCompare(o2.bookSourceName)
|
||||
}
|
||||
|
||||
Sort.Url -> data.sortedBy { it.bookSourceUrl }
|
||||
Sort.Update -> data.sortedByDescending { it.lastUpdateTime }
|
||||
Sort.Respond -> data.sortedBy { it.respondTime }
|
||||
@ -263,6 +284,7 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
|
||||
}
|
||||
sort
|
||||
}
|
||||
|
||||
else -> data
|
||||
}
|
||||
else when (sort) {
|
||||
@ -270,6 +292,7 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
|
||||
Sort.Name -> data.sortedWith { o1, o2 ->
|
||||
o2.bookSourceName.cnCompare(o1.bookSourceName)
|
||||
}
|
||||
|
||||
Sort.Url -> data.sortedByDescending { it.bookSourceUrl }
|
||||
Sort.Update -> data.sortedBy { it.lastUpdateTime }
|
||||
Sort.Respond -> data.sortedByDescending { it.respondTime }
|
||||
@ -280,6 +303,7 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
|
||||
}
|
||||
sort
|
||||
}
|
||||
|
||||
else -> data.reversed()
|
||||
}
|
||||
}.catch {
|
||||
@ -330,7 +354,7 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
|
||||
|
||||
override fun onClickSelectBarMainAction() {
|
||||
alert(titleResource = R.string.draw, messageResource = R.string.sure_del) {
|
||||
yesButton { viewModel.del(*adapter.selection.toTypedArray()) }
|
||||
yesButton { viewModel.del(adapter.selection) }
|
||||
noButton()
|
||||
}
|
||||
}
|
||||
@ -353,7 +377,7 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
|
||||
R.id.menu_bottom_sel -> viewModel.bottomSource(*adapter.selection.toTypedArray())
|
||||
R.id.menu_add_group -> selectionAddToGroups()
|
||||
R.id.menu_remove_group -> selectionRemoveFromGroups()
|
||||
R.id.menu_export_selection -> viewModel.saveToFile(adapter.selection) { file ->
|
||||
R.id.menu_export_selection -> viewModel.saveToFile(adapter.selection.toBookSource()) { file ->
|
||||
exportDir.launch {
|
||||
mode = HandleFileContract.EXPORT
|
||||
fileData = HandleFileContract.FileData(
|
||||
@ -363,9 +387,11 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
|
||||
)
|
||||
}
|
||||
}
|
||||
R.id.menu_share_source -> viewModel.saveToFile(adapter.selection) {
|
||||
|
||||
R.id.menu_share_source -> viewModel.saveToFile(adapter.selection.toBookSource()) {
|
||||
share(it)
|
||||
}
|
||||
|
||||
R.id.menu_check_selected_interval -> adapter.checkSelectedInterval()
|
||||
}
|
||||
return true
|
||||
@ -386,9 +412,11 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
|
||||
CheckSource.keyword = it
|
||||
}
|
||||
}
|
||||
CheckSource.start(this@BookSourceActivity, adapter.selection)
|
||||
val firstItem = adapter.getItems().indexOf(adapter.selection.firstOrNull())
|
||||
val lastItem = adapter.getItems().indexOf(adapter.selection.lastOrNull())
|
||||
val selectItems = adapter.selection
|
||||
CheckSource.start(this@BookSourceActivity, selectItems)
|
||||
val adapterItems = adapter.getItems()
|
||||
val firstItem = adapterItems.indexOf(selectItems.firstOrNull())
|
||||
val lastItem = adapterItems.indexOf(selectItems.lastOrNull())
|
||||
Debug.isChecking = firstItem >= 0 && lastItem >= 0
|
||||
checkMessageRefreshJob(firstItem, lastItem).start()
|
||||
}
|
||||
@ -587,45 +615,49 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
|
||||
return false
|
||||
}
|
||||
|
||||
override fun del(bookSource: BookSource) {
|
||||
override fun del(bookSource: BookSourcePart) {
|
||||
alert(R.string.draw) {
|
||||
setMessage(getString(R.string.sure_del) + "\n" + bookSource.bookSourceName)
|
||||
noButton()
|
||||
yesButton {
|
||||
viewModel.del(bookSource)
|
||||
viewModel.del(listOf(bookSource))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun update(vararg bookSource: BookSource) {
|
||||
viewModel.update(*bookSource)
|
||||
}
|
||||
|
||||
override fun edit(bookSource: BookSource) {
|
||||
override fun edit(bookSource: BookSourcePart) {
|
||||
startActivity<BookSourceEditActivity> {
|
||||
putExtra("sourceUrl", bookSource.bookSourceUrl)
|
||||
}
|
||||
}
|
||||
|
||||
override fun upOrder(items: List<BookSource>) {
|
||||
override fun upOrder(items: List<BookSourcePart>) {
|
||||
viewModel.upOrder(items)
|
||||
}
|
||||
|
||||
override fun toTop(bookSource: BookSource) {
|
||||
override fun enable(enable: Boolean, bookSource: BookSourcePart) {
|
||||
viewModel.enable(enable, listOf(bookSource))
|
||||
}
|
||||
|
||||
override fun enableExplore(enable: Boolean, bookSource: BookSourcePart) {
|
||||
viewModel.enableExplore(enable, listOf(bookSource))
|
||||
}
|
||||
|
||||
override fun toTop(bookSource: BookSourcePart) {
|
||||
viewModel.topSource(bookSource)
|
||||
}
|
||||
|
||||
override fun toBottom(bookSource: BookSource) {
|
||||
override fun toBottom(bookSource: BookSourcePart) {
|
||||
viewModel.bottomSource(bookSource)
|
||||
}
|
||||
|
||||
override fun searchBook(bookSource: BookSource) {
|
||||
override fun searchBook(bookSource: BookSourcePart) {
|
||||
startActivity<SearchActivity> {
|
||||
putExtra("searchScope", SearchScope(bookSource).toString())
|
||||
}
|
||||
}
|
||||
|
||||
override fun debug(bookSource: BookSource) {
|
||||
override fun debug(bookSource: BookSourcePart) {
|
||||
startActivity<BookSourceDebugActivity> {
|
||||
putExtra("key", bookSource.bookSourceUrl)
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ import androidx.recyclerview.widget.RecyclerView
|
||||
import io.legado.app.R
|
||||
import io.legado.app.base.adapter.ItemViewHolder
|
||||
import io.legado.app.base.adapter.RecyclerAdapter
|
||||
import io.legado.app.data.entities.BookSource
|
||||
import io.legado.app.data.entities.BookSourcePart
|
||||
import io.legado.app.databinding.ItemBookSourceBinding
|
||||
import io.legado.app.lib.theme.backgroundColor
|
||||
import io.legado.app.model.Debug
|
||||
@ -28,34 +28,34 @@ import java.util.*
|
||||
|
||||
|
||||
class BookSourceAdapter(context: Context, val callBack: CallBack) :
|
||||
RecyclerAdapter<BookSource, ItemBookSourceBinding>(context),
|
||||
RecyclerAdapter<BookSourcePart, ItemBookSourceBinding>(context),
|
||||
ItemTouchCallback.Callback {
|
||||
|
||||
private val selected = linkedSetOf<BookSource>()
|
||||
private val selected = linkedSetOf<BookSourcePart>()
|
||||
private val finalMessageRegex = Regex("成功|失败")
|
||||
|
||||
val selection: List<BookSource>
|
||||
val selection: List<BookSourcePart>
|
||||
get() {
|
||||
return getItems().filter {
|
||||
selected.contains(it)
|
||||
}
|
||||
}
|
||||
|
||||
val diffItemCallback = object : DiffUtil.ItemCallback<BookSource>() {
|
||||
val diffItemCallback = object : DiffUtil.ItemCallback<BookSourcePart>() {
|
||||
|
||||
override fun areItemsTheSame(oldItem: BookSource, newItem: BookSource): Boolean {
|
||||
override fun areItemsTheSame(oldItem: BookSourcePart, newItem: BookSourcePart): Boolean {
|
||||
return oldItem.bookSourceUrl == newItem.bookSourceUrl
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(oldItem: BookSource, newItem: BookSource): Boolean {
|
||||
override fun areContentsTheSame(oldItem: BookSourcePart, newItem: BookSourcePart): Boolean {
|
||||
return oldItem.bookSourceName == newItem.bookSourceName
|
||||
&& oldItem.bookSourceGroup == newItem.bookSourceGroup
|
||||
&& oldItem.enabled == newItem.enabled
|
||||
&& oldItem.enabledExplore == newItem.enabledExplore
|
||||
&& oldItem.exploreUrl == newItem.exploreUrl
|
||||
&& oldItem.hasExploreUrl == newItem.hasExploreUrl
|
||||
}
|
||||
|
||||
override fun getChangePayload(oldItem: BookSource, newItem: BookSource): Any? {
|
||||
override fun getChangePayload(oldItem: BookSourcePart, newItem: BookSourcePart): Any? {
|
||||
val payload = Bundle()
|
||||
if (oldItem.bookSourceName != newItem.bookSourceName
|
||||
|| oldItem.bookSourceGroup != newItem.bookSourceGroup
|
||||
@ -66,7 +66,7 @@ class BookSourceAdapter(context: Context, val callBack: CallBack) :
|
||||
payload.putBoolean("enabled", newItem.enabled)
|
||||
}
|
||||
if (oldItem.enabledExplore != newItem.enabledExplore ||
|
||||
oldItem.exploreUrl != newItem.exploreUrl
|
||||
oldItem.hasExploreUrl != newItem.hasExploreUrl
|
||||
) {
|
||||
payload.putBoolean("upExplore", true)
|
||||
}
|
||||
@ -85,7 +85,7 @@ class BookSourceAdapter(context: Context, val callBack: CallBack) :
|
||||
override fun convert(
|
||||
holder: ItemViewHolder,
|
||||
binding: ItemBookSourceBinding,
|
||||
item: BookSource,
|
||||
item: BookSourcePart,
|
||||
payloads: MutableList<Any>
|
||||
) {
|
||||
binding.run {
|
||||
@ -117,7 +117,7 @@ class BookSourceAdapter(context: Context, val callBack: CallBack) :
|
||||
getItem(holder.layoutPosition)?.let {
|
||||
if (view.isPressed) {
|
||||
it.enabled = checked
|
||||
callBack.update(it)
|
||||
callBack.enable(checked, it)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -153,7 +153,7 @@ class BookSourceAdapter(context: Context, val callBack: CallBack) :
|
||||
val popupMenu = PopupMenu(context, view)
|
||||
popupMenu.inflate(R.menu.book_source_item)
|
||||
val qyMenu = popupMenu.menu.findItem(R.id.menu_enable_explore)
|
||||
if (source.exploreUrl.isNullOrEmpty()) {
|
||||
if (!source.hasExploreUrl) {
|
||||
qyMenu.isVisible = false
|
||||
} else {
|
||||
if (source.enabledExplore) {
|
||||
@ -163,7 +163,7 @@ class BookSourceAdapter(context: Context, val callBack: CallBack) :
|
||||
}
|
||||
}
|
||||
val loginMenu = popupMenu.menu.findItem(R.id.menu_login)
|
||||
loginMenu.isVisible = !source.loginUrl.isNullOrBlank()
|
||||
loginMenu.isVisible = source.hasLoginUrl
|
||||
popupMenu.setOnMenuItemClickListener { menuItem ->
|
||||
when (menuItem.itemId) {
|
||||
R.id.menu_top -> callBack.toTop(source)
|
||||
@ -172,14 +172,16 @@ class BookSourceAdapter(context: Context, val callBack: CallBack) :
|
||||
putExtra("type", "bookSource")
|
||||
putExtra("key", source.bookSourceUrl)
|
||||
}
|
||||
|
||||
R.id.menu_search -> callBack.searchBook(source)
|
||||
R.id.menu_debug_source -> callBack.debug(source)
|
||||
R.id.menu_del -> {
|
||||
callBack.del(source)
|
||||
selected.remove(source)
|
||||
}
|
||||
|
||||
R.id.menu_enable_explore -> {
|
||||
callBack.update(source.copy(enabledExplore = !source.enabledExplore))
|
||||
callBack.enableExplore(!source.enabledExplore, source)
|
||||
}
|
||||
}
|
||||
true
|
||||
@ -187,16 +189,18 @@ class BookSourceAdapter(context: Context, val callBack: CallBack) :
|
||||
popupMenu.show()
|
||||
}
|
||||
|
||||
private fun upShowExplore(iv: ImageView, source: BookSource) {
|
||||
private fun upShowExplore(iv: ImageView, source: BookSourcePart) {
|
||||
when {
|
||||
source.exploreUrl.isNullOrEmpty() -> {
|
||||
!source.hasExploreUrl -> {
|
||||
iv.invisible()
|
||||
}
|
||||
|
||||
source.enabledExplore -> {
|
||||
iv.setColorFilter(Color.GREEN)
|
||||
iv.visible()
|
||||
iv.contentDescription = context.getString(R.string.tag_explore_enabled)
|
||||
}
|
||||
|
||||
else -> {
|
||||
iv.setColorFilter(Color.RED)
|
||||
iv.visible()
|
||||
@ -205,7 +209,10 @@ class BookSourceAdapter(context: Context, val callBack: CallBack) :
|
||||
}
|
||||
}
|
||||
|
||||
private fun upCheckSourceMessage(binding: ItemBookSourceBinding, item: BookSource) = binding.run {
|
||||
private fun upCheckSourceMessage(
|
||||
binding: ItemBookSourceBinding,
|
||||
item: BookSourcePart
|
||||
) = binding.run {
|
||||
val msg = Debug.debugMessageMap[item.bookSourceUrl] ?: ""
|
||||
ivDebugText.text = msg
|
||||
val isEmpty = msg.isEmpty()
|
||||
@ -274,7 +281,7 @@ class BookSourceAdapter(context: Context, val callBack: CallBack) :
|
||||
return true
|
||||
}
|
||||
|
||||
private val movedItems = hashSetOf<BookSource>()
|
||||
private val movedItems = hashSetOf<BookSourcePart>()
|
||||
|
||||
override fun onClearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {
|
||||
if (movedItems.isNotEmpty()) {
|
||||
@ -285,19 +292,19 @@ class BookSourceAdapter(context: Context, val callBack: CallBack) :
|
||||
if (movedItems.size > sortNumberSet.size) {
|
||||
callBack.upOrder(getItems())
|
||||
} else {
|
||||
callBack.update(*movedItems.toTypedArray())
|
||||
callBack.upOrder(movedItems.toList())
|
||||
}
|
||||
movedItems.clear()
|
||||
}
|
||||
}
|
||||
|
||||
val dragSelectCallback: DragSelectTouchHelper.Callback =
|
||||
object : DragSelectTouchHelper.AdvanceCallback<BookSource>(Mode.ToggleAndReverse) {
|
||||
override fun currentSelectedId(): MutableSet<BookSource> {
|
||||
object : DragSelectTouchHelper.AdvanceCallback<BookSourcePart>(Mode.ToggleAndReverse) {
|
||||
override fun currentSelectedId(): MutableSet<BookSourcePart> {
|
||||
return selected
|
||||
}
|
||||
|
||||
override fun getItemId(position: Int): BookSource {
|
||||
override fun getItemId(position: Int): BookSourcePart {
|
||||
return getItem(position)!!
|
||||
}
|
||||
|
||||
@ -317,14 +324,15 @@ class BookSourceAdapter(context: Context, val callBack: CallBack) :
|
||||
}
|
||||
|
||||
interface CallBack {
|
||||
fun del(bookSource: BookSource)
|
||||
fun edit(bookSource: BookSource)
|
||||
fun update(vararg bookSource: BookSource)
|
||||
fun toTop(bookSource: BookSource)
|
||||
fun toBottom(bookSource: BookSource)
|
||||
fun searchBook(bookSource: BookSource)
|
||||
fun debug(bookSource: BookSource)
|
||||
fun upOrder(items: List<BookSource>)
|
||||
fun del(bookSource: BookSourcePart)
|
||||
fun edit(bookSource: BookSourcePart)
|
||||
fun toTop(bookSource: BookSourcePart)
|
||||
fun toBottom(bookSource: BookSourcePart)
|
||||
fun searchBook(bookSource: BookSourcePart)
|
||||
fun debug(bookSource: BookSourcePart)
|
||||
fun upOrder(items: List<BookSourcePart>)
|
||||
fun enable(enable: Boolean, bookSource: BookSourcePart)
|
||||
fun enableExplore(enable: Boolean, bookSource: BookSourcePart)
|
||||
fun upCountView()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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.data.entities.BookSourcePart
|
||||
import io.legado.app.help.config.SourceConfig
|
||||
import io.legado.app.utils.*
|
||||
import java.io.File
|
||||
@ -16,31 +17,31 @@ import java.io.FileOutputStream
|
||||
*/
|
||||
class BookSourceViewModel(application: Application) : BaseViewModel(application) {
|
||||
|
||||
fun topSource(vararg sources: BookSource) {
|
||||
fun topSource(vararg sources: BookSourcePart) {
|
||||
execute {
|
||||
sources.sortBy { it.customOrder }
|
||||
val minOrder = appDb.bookSourceDao.minOrder - 1
|
||||
val array = Array(sources.size) {
|
||||
sources[it].copy(customOrder = minOrder - it)
|
||||
val array = sources.mapIndexed { index, it ->
|
||||
it.copy(customOrder = minOrder - index)
|
||||
}
|
||||
appDb.bookSourceDao.update(*array)
|
||||
appDb.bookSourceDao.upOrder(array)
|
||||
}
|
||||
}
|
||||
|
||||
fun bottomSource(vararg sources: BookSource) {
|
||||
fun bottomSource(vararg sources: BookSourcePart) {
|
||||
execute {
|
||||
sources.sortBy { it.customOrder }
|
||||
val maxOrder = appDb.bookSourceDao.maxOrder + 1
|
||||
val array = Array(sources.size) {
|
||||
sources[it].copy(customOrder = maxOrder + it)
|
||||
val array = sources.mapIndexed { index, it ->
|
||||
it.copy(customOrder = maxOrder + index)
|
||||
}
|
||||
appDb.bookSourceDao.update(*array)
|
||||
appDb.bookSourceDao.upOrder(array)
|
||||
}
|
||||
}
|
||||
|
||||
fun del(vararg sources: BookSource) {
|
||||
fun del(sources: List<BookSourcePart>) {
|
||||
execute {
|
||||
appDb.bookSourceDao.delete(*sources)
|
||||
appDb.bookSourceDao.delete(sources)
|
||||
sources.forEach {
|
||||
SourceConfig.removeSource(it.bookSourceUrl)
|
||||
}
|
||||
@ -51,68 +52,72 @@ class BookSourceViewModel(application: Application) : BaseViewModel(application)
|
||||
execute { appDb.bookSourceDao.update(*bookSource) }
|
||||
}
|
||||
|
||||
fun upOrder(items: List<BookSource>) {
|
||||
fun upOrder(items: List<BookSourcePart>) {
|
||||
if (items.isEmpty()) return
|
||||
execute {
|
||||
val firstSortNumber = items[0].customOrder
|
||||
items.forEachIndexed { index, bookSource ->
|
||||
bookSource.customOrder = firstSortNumber + index
|
||||
appDb.bookSourceDao.update(bookSource)
|
||||
}
|
||||
appDb.bookSourceDao.upOrder(items)
|
||||
}
|
||||
}
|
||||
|
||||
fun enableSelection(sources: List<BookSource>) {
|
||||
fun enable(enable: Boolean, items: List<BookSourcePart>) {
|
||||
execute {
|
||||
val array = Array(sources.size) {
|
||||
sources[it].copy(enabled = true)
|
||||
}
|
||||
appDb.bookSourceDao.update(*array)
|
||||
appDb.bookSourceDao.enable(enable, items)
|
||||
}
|
||||
}
|
||||
|
||||
fun disableSelection(sources: List<BookSource>) {
|
||||
fun enableSelection(sources: List<BookSourcePart>) {
|
||||
execute {
|
||||
val array = Array(sources.size) {
|
||||
sources[it].copy(enabled = false)
|
||||
}
|
||||
appDb.bookSourceDao.update(*array)
|
||||
appDb.bookSourceDao.enable(true, sources)
|
||||
}
|
||||
}
|
||||
|
||||
fun enableSelectExplore(sources: List<BookSource>) {
|
||||
fun disableSelection(sources: List<BookSourcePart>) {
|
||||
execute {
|
||||
val array = Array(sources.size) {
|
||||
sources[it].copy(enabledExplore = true)
|
||||
}
|
||||
appDb.bookSourceDao.update(*array)
|
||||
appDb.bookSourceDao.enable(false, sources)
|
||||
}
|
||||
}
|
||||
|
||||
fun disableSelectExplore(sources: List<BookSource>) {
|
||||
fun enableExplore(enable: Boolean, items: List<BookSourcePart>) {
|
||||
execute {
|
||||
val array = Array(sources.size) {
|
||||
sources[it].copy(enabledExplore = false)
|
||||
}
|
||||
appDb.bookSourceDao.update(*array)
|
||||
appDb.bookSourceDao.enableExplore(enable, items)
|
||||
}
|
||||
}
|
||||
|
||||
fun selectionAddToGroups(sources: List<BookSource>, groups: String) {
|
||||
fun enableSelectExplore(sources: List<BookSourcePart>) {
|
||||
execute {
|
||||
val array = Array(sources.size) {
|
||||
sources[it].copy().addGroup(groups)
|
||||
}
|
||||
appDb.bookSourceDao.update(*array)
|
||||
appDb.bookSourceDao.enableExplore(true, sources)
|
||||
}
|
||||
}
|
||||
|
||||
fun selectionRemoveFromGroups(sources: List<BookSource>, groups: String) {
|
||||
fun disableSelectExplore(sources: List<BookSourcePart>) {
|
||||
execute {
|
||||
val array = Array(sources.size) {
|
||||
sources[it].copy().removeGroup(groups)
|
||||
appDb.bookSourceDao.enableExplore(false, sources)
|
||||
}
|
||||
}
|
||||
|
||||
fun selectionAddToGroups(sources: List<BookSourcePart>, groups: String) {
|
||||
execute {
|
||||
val array = sources.map {
|
||||
it.copy().apply {
|
||||
addGroup(groups)
|
||||
}
|
||||
}
|
||||
appDb.bookSourceDao.update(*array)
|
||||
appDb.bookSourceDao.upGroup(array)
|
||||
}
|
||||
}
|
||||
|
||||
fun selectionRemoveFromGroups(sources: List<BookSourcePart>, groups: String) {
|
||||
execute {
|
||||
val array = sources.map {
|
||||
it.copy().apply {
|
||||
removeGroup(groups)
|
||||
}
|
||||
}
|
||||
appDb.bookSourceDao.upGroup(array)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@ import android.app.Application
|
||||
import android.content.Context
|
||||
import io.legado.app.R
|
||||
import io.legado.app.base.BaseViewModel
|
||||
import io.legado.app.data.appDb
|
||||
import io.legado.app.help.AppWebDav
|
||||
import io.legado.app.help.book.BookHelp
|
||||
import io.legado.app.utils.FileUtils
|
||||
@ -34,5 +35,12 @@ class ConfigViewModel(application: Application) : BaseViewModel(application) {
|
||||
}
|
||||
}
|
||||
|
||||
fun shrinkDatabase() {
|
||||
execute {
|
||||
appDb.openHelper.writableDatabase.execSQL("VACUUM")
|
||||
}.onSuccess {
|
||||
context.toastOnUi(R.string.success)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -135,6 +135,7 @@ class OtherConfigFragment : PreferenceFragment(),
|
||||
|
||||
PreferKey.clearWebViewData -> clearWebViewData()
|
||||
"localPassword" -> alertLocalPassword()
|
||||
PreferKey.shrinkDatabase -> shrinkDatabase()
|
||||
}
|
||||
return super.onPreferenceTreeClick(preference)
|
||||
}
|
||||
@ -234,6 +235,15 @@ class OtherConfigFragment : PreferenceFragment(),
|
||||
}
|
||||
}
|
||||
|
||||
private fun shrinkDatabase() {
|
||||
alert(R.string.sure, R.string.shrink_database) {
|
||||
okButton {
|
||||
viewModel.shrinkDatabase()
|
||||
}
|
||||
noButton()
|
||||
}
|
||||
}
|
||||
|
||||
private fun clearWebViewData() {
|
||||
alert(R.string.clear_webview_data, R.string.sure_del) {
|
||||
okButton {
|
||||
|
@ -1110,4 +1110,6 @@
|
||||
<string name="custom_export">Custom Export</string>
|
||||
<string name="file_contains_number">The number of chapters contained in each file</string>
|
||||
<string name="export_chapter_index">The section index that needs to be exported</string>
|
||||
<string name="shrink_database">压缩数据库</string>
|
||||
<string name="shrink_database_summary">减小数据库文件的大小</string>
|
||||
</resources>
|
||||
|
@ -1113,4 +1113,6 @@
|
||||
<string name="custom_export">Custom Export</string>
|
||||
<string name="file_contains_number">The number of chapters contained in each file</string>
|
||||
<string name="export_chapter_index">The section index that needs to be exported</string>
|
||||
<string name="shrink_database">压缩数据库</string>
|
||||
<string name="shrink_database_summary">减小数据库文件的大小</string>
|
||||
</resources>
|
||||
|
@ -1113,4 +1113,6 @@
|
||||
<string name="custom_export">Custom Export</string>
|
||||
<string name="file_contains_number">The index of chapters contained in each file</string>
|
||||
<string name="export_chapter_index">The section index that needs to be exported</string>
|
||||
<string name="shrink_database">压缩数据库</string>
|
||||
<string name="shrink_database_summary">减小数据库文件的大小</string>
|
||||
</resources>
|
||||
|
@ -1110,4 +1110,6 @@
|
||||
<string name="custom_export">自定義導出</string>
|
||||
<string name="file_contains_number">每個文件包含的章節數量</string>
|
||||
<string name="export_chapter_index">需要輸出的章節</string>
|
||||
<string name="shrink_database">压缩数据库</string>
|
||||
<string name="shrink_database_summary">减小数据库文件的大小</string>
|
||||
</resources>
|
||||
|
@ -1112,4 +1112,6 @@
|
||||
<string name="custom_export">自定義導出</string>
|
||||
<string name="file_contains_number">每個文件包含的章節數量</string>
|
||||
<string name="export_chapter_index">需要輸出的章節</string>
|
||||
<string name="shrink_database">压缩数据库</string>
|
||||
<string name="shrink_database_summary">减小数据库文件的大小</string>
|
||||
</resources>
|
||||
|
@ -1112,4 +1112,6 @@
|
||||
<string name="custom_export">自定义导出</string>
|
||||
<string name="file_contains_number">每个文件包含的章节数量</string>
|
||||
<string name="export_chapter_index">需要输出的章节</string>
|
||||
<string name="shrink_database">压缩数据库</string>
|
||||
<string name="shrink_database_summary">减小数据库文件的大小</string>
|
||||
</resources>
|
||||
|
@ -1113,4 +1113,6 @@
|
||||
<string name="custom_export">Custom Export</string>
|
||||
<string name="file_contains_number">The number of chapters contained in each file</string>
|
||||
<string name="export_chapter_index">The section index that needs to be exported</string>
|
||||
<string name="shrink_database">压缩数据库</string>
|
||||
<string name="shrink_database_summary">减小数据库文件的大小</string>
|
||||
</resources>
|
||||
|
@ -156,6 +156,12 @@
|
||||
android:title="@string/clear_webview_data"
|
||||
app:iconSpaceReserved="false" />
|
||||
|
||||
<io.legado.app.lib.prefs.Preference
|
||||
android:key="shrinkDatabase"
|
||||
android:summary="@string/shrink_database_summary"
|
||||
android:title="@string/shrink_database"
|
||||
app:iconSpaceReserved="false" />
|
||||
|
||||
<io.legado.app.lib.prefs.Preference
|
||||
android:key="threadCount"
|
||||
android:title="@string/threads_num_title"
|
||||
|
Loading…
Reference in New Issue
Block a user