diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index c16b1cfe4..f0b344d72 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -272,6 +272,7 @@
- @get:Query("select * from book_sources where trim(bookUrlPattern) <> '' order by enabled desc, customOrder")
+ @get:Query("select * from book_sources where enabled = 1 and trim(bookUrlPattern) <> '' order by enabled desc, customOrder")
val hasBookUrlPattern: List
@get:Query("select * from book_sources where bookSourceGroup is null or bookSourceGroup = ''")
diff --git a/app/src/main/java/io/legado/app/help/CrashHandler.kt b/app/src/main/java/io/legado/app/help/CrashHandler.kt
index 0de9105a7..b72d9c944 100644
--- a/app/src/main/java/io/legado/app/help/CrashHandler.kt
+++ b/app/src/main/java/io/legado/app/help/CrashHandler.kt
@@ -62,6 +62,9 @@ class CrashHandler(val context: Context) : Thread.UncaughtExceptionHandler {
//获取系统信息
map["MANUFACTURER"] = Build.MANUFACTURER
map["BRAND"] = Build.BRAND
+ map["MODEL"] = Build.MODEL
+ map["SDK_INT"] = Build.VERSION.SDK_INT.toString()
+ map["RELEASE"] = Build.VERSION.RELEASE
//获取app版本信息
AppConst.appInfo.let {
map["versionName"] = it.versionName
diff --git a/app/src/main/java/io/legado/app/model/ReadBook.kt b/app/src/main/java/io/legado/app/model/ReadBook.kt
index 9f9a8222c..a3ef50de9 100644
--- a/app/src/main/java/io/legado/app/model/ReadBook.kt
+++ b/app/src/main/java/io/legado/app/model/ReadBook.kt
@@ -464,6 +464,9 @@ object ReadBook : CoroutineScope by MainScope() {
* 预下载
*/
private fun preDownload() {
+ if (AppConfig.preDownloadNum < 2) {
+ return
+ }
Coroutine.async {
//预下载
val maxChapterIndex = durChapterIndex + AppConfig.preDownloadNum
diff --git a/app/src/main/java/io/legado/app/ui/book/cache/CacheViewModel.kt b/app/src/main/java/io/legado/app/ui/book/cache/CacheViewModel.kt
index 980564b18..459921c4a 100644
--- a/app/src/main/java/io/legado/app/ui/book/cache/CacheViewModel.kt
+++ b/app/src/main/java/io/legado/app/ui/book/cache/CacheViewModel.kt
@@ -71,7 +71,7 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
}
}
cacheChapters[book.bookUrl] = chapterCaches
- upAdapterLiveData.postValue(book.bookUrl)
+ upAdapterLiveData.sendValue(book.bookUrl)
}
ensureActive()
}
@@ -97,7 +97,7 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
if (exportProgress.contains(book.bookUrl)) return
exportProgress[book.bookUrl] = 0
exportMsg.remove(book.bookUrl)
- upAdapterLiveData.postValue(book.bookUrl)
+ upAdapterLiveData.sendValue(book.bookUrl)
execute {
mutex.withLock {
while (exportNumber > 0) {
@@ -260,7 +260,7 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
if (exportProgress.contains(book.bookUrl)) return
exportProgress[book.bookUrl] = 0
exportMsg.remove(book.bookUrl)
- upAdapterLiveData.postValue(book.bookUrl)
+ upAdapterLiveData.sendValue(book.bookUrl)
execute {
mutex.withLock {
while (exportNumber > 0) {
diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/provider/ChapterProvider.kt b/app/src/main/java/io/legado/app/ui/book/read/page/provider/ChapterProvider.kt
index 4ced93007..bdcb20df0 100644
--- a/app/src/main/java/io/legado/app/ui/book/read/page/provider/ChapterProvider.kt
+++ b/app/src/main/java/io/legado/app/ui/book/read/page/provider/ChapterProvider.kt
@@ -650,6 +650,10 @@ object ChapterProvider {
"0" -> doublePage = false
"1" -> doublePage = true
"2" -> {
+ doublePage = (viewWidth > viewHeight)
+ && ReadBook.pageAnim() != 3
+ }
+ "3" -> {
doublePage = (viewWidth > viewHeight || appCtx.isPad)
&& ReadBook.pageAnim() != 3
}
diff --git a/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt b/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt
index d48ffc8ad..6bb262baa 100644
--- a/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt
+++ b/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt
@@ -17,6 +17,7 @@ import androidx.recyclerview.widget.RecyclerView
import com.google.android.flexbox.FlexboxLayoutManager
import io.legado.app.R
import io.legado.app.base.VMBaseActivity
+import io.legado.app.constant.AppLog
import io.legado.app.constant.PreferKey
import io.legado.app.data.appDb
import io.legado.app.data.entities.Book
@@ -32,7 +33,9 @@ import io.legado.app.utils.viewbindingdelegate.viewBinding
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
+import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.conflate
+import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import splitties.init.appCtx
@@ -288,6 +291,17 @@ class SearchActivity : VMBaseActivity
+ books.map { "${it.name}-${it.author}" }
+ }.catch { e ->
+ AppLog.put("加载书架数据失败", e)
+ }.collect {
+ viewModel.bookshelf.clear()
+ viewModel.bookshelf.addAll(it)
+ viewModel.upAdapterLiveData.postValue("isInBookshelf")
+ }
+ }
}
/**
diff --git a/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt b/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt
index 95678b484..cb8330bb2 100644
--- a/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt
+++ b/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt
@@ -10,14 +10,10 @@ import io.legado.app.data.entities.SearchKeyword
import io.legado.app.help.config.AppConfig
import io.legado.app.model.webBook.SearchModel
import kotlinx.coroutines.Dispatchers.IO
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.flowOn
-import kotlinx.coroutines.flow.mapLatest
-import kotlinx.coroutines.launch
-@OptIn(ExperimentalCoroutinesApi::class)
class SearchViewModel(application: Application) : BaseViewModel(application) {
val bookshelf = hashSetOf()
val upAdapterLiveData = MutableLiveData()
@@ -61,18 +57,6 @@ class SearchViewModel(application: Application) : BaseViewModel(application) {
}
}.flowOn(IO)
- init {
- viewModelScope.launch {
- appDb.bookDao.flowAll().mapLatest { books ->
- books.map { "${it.name}-${it.author}" }
- }.collect {
- bookshelf.clear()
- bookshelf.addAll(it)
- upAdapterLiveData.postValue("isInBookshelf")
- }
- }
- }
-
/**
* 开始搜索
*/
diff --git a/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt b/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt
index d13483a5c..e18d86807 100644
--- a/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt
+++ b/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt
@@ -17,6 +17,7 @@ import io.legado.app.data.appDb
import io.legado.app.data.entities.BookSource
import io.legado.app.data.entities.rule.*
import io.legado.app.databinding.ActivityBookSourceEditBinding
+import io.legado.app.databinding.DialogEditTextBinding
import io.legado.app.help.config.LocalConfig
import io.legado.app.lib.dialogs.SelectItem
import io.legado.app.lib.dialogs.alert
@@ -140,6 +141,7 @@ class BookSourceEditActivity :
}
}
}
+ R.id.menu_set_source_variable -> setSourceVariable()
}
return super.onCompatOptionsItemSelected(item)
}
@@ -171,7 +173,12 @@ class BookSourceEditActivity :
override fun finish() {
val source = getSource()
- if (!source.equal(viewModel.bookSource ?: BookSource())) {
+ val source2 = viewModel.bookSource ?: BookSource().apply {
+ enabledExplore = true
+ enabledCookieJar = true
+ enabledReview = true
+ }
+ if (!source.equal(source2)) {
alert(R.string.exit) {
setMessage(R.string.exit_no_save)
positiveButton(R.string.yes)
@@ -569,4 +576,30 @@ class BookSourceEditActivity :
showDialogFragment(TextDialog(mdText, TextDialog.Mode.MD))
}
+ private fun setSourceVariable() {
+ launch {
+ val source = viewModel.bookSource
+ if (source == null) {
+ toastOnUi("书源不存在")
+ return@launch
+ }
+ val variable = withContext(IO) { source.getVariable() }
+ alert(R.string.set_source_variable) {
+ setMessage(source.getDisplayVariableComment("源变量可在js中通过source.getVariable()获取"))
+ val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply {
+ editView.hint = "source variable"
+ editView.setText(variable)
+ }
+ customView { alertBinding.root }
+ okButton {
+ viewModel.bookSource?.setVariable(alertBinding.editView.text?.toString())
+ }
+ cancelButton()
+ neutralButton(R.string.delete) {
+ viewModel.bookSource?.setVariable(null)
+ }
+ }
+ }
+ }
+
}
diff --git a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt
index 0863f4382..4663434f6 100644
--- a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt
+++ b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt
@@ -1,12 +1,11 @@
package io.legado.app.ui.book.source.manage
import android.annotation.SuppressLint
-import android.content.Context
-import android.hardware.display.DisplayManager
import android.os.Bundle
import android.view.*
import androidx.activity.viewModels
import androidx.appcompat.app.AlertDialog
+import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.PopupMenu
import androidx.appcompat.widget.SearchView
import androidx.core.os.bundleOf
@@ -70,9 +69,7 @@ class BookSourceActivity : VMBaseActivity showDialogFragment(TxtTocRuleEditDialog())
diff --git a/app/src/main/java/io/legado/app/ui/book/toc/rule/TxtTocRuleAdapter.kt b/app/src/main/java/io/legado/app/ui/book/toc/rule/TxtTocRuleAdapter.kt
index 71da2bfdf..01643e40a 100644
--- a/app/src/main/java/io/legado/app/ui/book/toc/rule/TxtTocRuleAdapter.kt
+++ b/app/src/main/java/io/legado/app/ui/book/toc/rule/TxtTocRuleAdapter.kt
@@ -73,6 +73,7 @@ class TxtTocRuleAdapter(context: Context, private val callBack: CallBack) :
getItem(holder.layoutPosition)?.let {
if (buttonView.isPressed) {
it.enable = isChecked
+ callBack.update(it)
}
}
}
diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/style1/books/BooksFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/style1/books/BooksFragment.kt
index 71952b9f7..3d4d87a0a 100644
--- a/app/src/main/java/io/legado/app/ui/main/bookshelf/style1/books/BooksFragment.kt
+++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/style1/books/BooksFragment.kt
@@ -152,6 +152,18 @@ class BooksFragment() : BaseFragment(R.layout.fragment_books),
}
}
+ override fun onPause() {
+ super.onPause()
+ upLastUpdateTimeJob?.cancel()
+ booksFlowJob?.cancel()
+ }
+
+ override fun onResume() {
+ super.onResume()
+ startLastUpdateTimeJob()
+ upRecyclerData()
+ }
+
private fun startLastUpdateTimeJob() {
upLastUpdateTimeJob?.cancel()
if (!AppConfig.showLastUpdateTime) {
@@ -159,7 +171,9 @@ class BooksFragment() : BaseFragment(R.layout.fragment_books),
}
upLastUpdateTimeJob = launch {
while (isActive) {
- booksAdapter.upLastUpdateTime()
+ if (SystemUtils.isScreenOn()) {
+ booksAdapter.upLastUpdateTime()
+ }
delay(30 * 1000)
}
}
diff --git a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt
index 4e72e0f93..00038de4c 100644
--- a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt
+++ b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt
@@ -215,6 +215,7 @@ class ReadRssActivity : VMBaseActivity
}
override fun upStarMenu() {
+ starMenuItem?.isVisible = viewModel.rssArticle != null
if (viewModel.rssStar != null) {
starMenuItem?.setIcon(R.drawable.ic_star)
starMenuItem?.setTitle(R.string.in_favorites)
diff --git a/app/src/main/java/io/legado/app/utils/MutableLiveDataExtensions.kt b/app/src/main/java/io/legado/app/utils/MutableLiveDataExtensions.kt
new file mode 100644
index 000000000..c4fc6be6e
--- /dev/null
+++ b/app/src/main/java/io/legado/app/utils/MutableLiveDataExtensions.kt
@@ -0,0 +1,13 @@
+package io.legado.app.utils
+
+import android.os.Handler
+import android.os.Looper
+import androidx.lifecycle.MutableLiveData
+
+private val mainHandler by lazy { Handler(Looper.getMainLooper()) }
+
+fun MutableLiveData.sendValue(value: T) {
+ mainHandler.post {
+ this@sendValue.value = value
+ }
+}
diff --git a/app/src/main/java/io/legado/app/utils/SystemUtils.kt b/app/src/main/java/io/legado/app/utils/SystemUtils.kt
index 8d077201f..4ac96eaae 100644
--- a/app/src/main/java/io/legado/app/utils/SystemUtils.kt
+++ b/app/src/main/java/io/legado/app/utils/SystemUtils.kt
@@ -5,6 +5,8 @@ import android.app.Activity
import android.content.Intent
import android.net.Uri
import android.provider.Settings
+import android.view.Display
+import splitties.systemservices.displayManager
import splitties.systemservices.powerManager
@@ -28,4 +30,9 @@ object SystemUtils {
}
}
+ fun isScreenOn(): Boolean {
+ return displayManager.displays.filterNotNull().any {
+ it.state != Display.STATE_OFF
+ }
+ }
}
diff --git a/app/src/main/res/layout/item_search.xml b/app/src/main/res/layout/item_search.xml
index 862f242ce..fcb67d9f9 100644
--- a/app/src/main/res/layout/item_search.xml
+++ b/app/src/main/res/layout/item_search.xml
@@ -27,8 +27,8 @@
android:scaleType="centerCrop"
android:src="@color/md_green_600"
android:visibility="invisible"
- app:layout_constraintRight_toRightOf="@id/iv_cover"
- app:layout_constraintTop_toTopOf="@id/iv_cover" />
+ app:layout_constraintLeft_toRightOf="@id/iv_cover"
+ app:layout_constraintTop_toTopOf="@id/tv_name" />
diff --git a/app/src/main/res/menu/source_edit.xml b/app/src/main/res/menu/source_edit.xml
index 140c935b2..28690ffb5 100644
--- a/app/src/main/res/menu/source_edit.xml
+++ b/app/src/main/res/menu/source_edit.xml
@@ -42,6 +42,11 @@
android:title="@string/paste_source"
app:showAsAction="never" />
+
+
-
- 全局单页
- 全局双页
- - 横屏双页/竖屏单页
+ - 横屏双页
+ - 平板/横屏双页
diff --git a/app/src/main/res/values/array_values.xml b/app/src/main/res/values/array_values.xml
index e0b0a88dc..1b7e135ff 100644
--- a/app/src/main/res/values/array_values.xml
+++ b/app/src/main/res/values/array_values.xml
@@ -38,6 +38,7 @@
- 0
- 1
- 2
+ - 3
diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml
index 6c5608372..72146bce7 100644
--- a/app/src/main/res/values/arrays.xml
+++ b/app/src/main/res/values/arrays.xml
@@ -65,7 +65,8 @@
- 全局单页
- 全局双页
- - 横屏双页 竖屏单页
+ - 横屏双页
+ - 平板/横屏双页