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 @@ 全局单页 全局双页 - 横屏双页 竖屏单页 + 横屏双页 + 平板/横屏双页