pull/2565/head
Horis 2 years ago
parent 7f4a8b4d5e
commit 8d917c20ec
  1. 1
      app/src/main/AndroidManifest.xml
  2. 2
      app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt
  3. 3
      app/src/main/java/io/legado/app/help/CrashHandler.kt
  4. 3
      app/src/main/java/io/legado/app/model/ReadBook.kt
  5. 6
      app/src/main/java/io/legado/app/ui/book/cache/CacheViewModel.kt
  6. 4
      app/src/main/java/io/legado/app/ui/book/read/page/provider/ChapterProvider.kt
  7. 14
      app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt
  8. 16
      app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt
  9. 35
      app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt
  10. 22
      app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt
  11. 5
      app/src/main/java/io/legado/app/ui/book/toc/rule/TxtTocRuleActivity.kt
  12. 1
      app/src/main/java/io/legado/app/ui/book/toc/rule/TxtTocRuleAdapter.kt
  13. 16
      app/src/main/java/io/legado/app/ui/main/bookshelf/style1/books/BooksFragment.kt
  14. 1
      app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt
  15. 13
      app/src/main/java/io/legado/app/utils/MutableLiveDataExtensions.kt
  16. 7
      app/src/main/java/io/legado/app/utils/SystemUtils.kt
  17. 9
      app/src/main/res/layout/item_search.xml
  18. 5
      app/src/main/res/menu/source_edit.xml
  19. 3
      app/src/main/res/values-zh/arrays.xml
  20. 1
      app/src/main/res/values/array_values.xml
  21. 3
      app/src/main/res/values/arrays.xml

@ -272,6 +272,7 @@
<!-- WebView界面 --> <!-- WebView界面 -->
<activity <activity
android:name=".ui.browser.WebViewActivity" android:name=".ui.browser.WebViewActivity"
android:configChanges="locale|keyboardHidden|orientation|screenSize|smallestScreenSize|screenLayout"
android:launchMode="standard" /> android:launchMode="standard" />
<!-- 书源登录 --> <!-- 书源登录 -->
<activity <activity

@ -116,7 +116,7 @@ interface BookSourceDao {
@Query("select * from book_sources where enabled = 1 and bookSourceType = :type") @Query("select * from book_sources where enabled = 1 and bookSourceType = :type")
fun getEnabledByType(type: Int): List<BookSource> fun getEnabledByType(type: Int): List<BookSource>
@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<BookSource> val hasBookUrlPattern: List<BookSource>
@get:Query("select * from book_sources where bookSourceGroup is null or bookSourceGroup = ''") @get:Query("select * from book_sources where bookSourceGroup is null or bookSourceGroup = ''")

@ -62,6 +62,9 @@ class CrashHandler(val context: Context) : Thread.UncaughtExceptionHandler {
//获取系统信息 //获取系统信息
map["MANUFACTURER"] = Build.MANUFACTURER map["MANUFACTURER"] = Build.MANUFACTURER
map["BRAND"] = Build.BRAND map["BRAND"] = Build.BRAND
map["MODEL"] = Build.MODEL
map["SDK_INT"] = Build.VERSION.SDK_INT.toString()
map["RELEASE"] = Build.VERSION.RELEASE
//获取app版本信息 //获取app版本信息
AppConst.appInfo.let { AppConst.appInfo.let {
map["versionName"] = it.versionName map["versionName"] = it.versionName

@ -464,6 +464,9 @@ object ReadBook : CoroutineScope by MainScope() {
* 预下载 * 预下载
*/ */
private fun preDownload() { private fun preDownload() {
if (AppConfig.preDownloadNum < 2) {
return
}
Coroutine.async { Coroutine.async {
//预下载 //预下载
val maxChapterIndex = durChapterIndex + AppConfig.preDownloadNum val maxChapterIndex = durChapterIndex + AppConfig.preDownloadNum

@ -71,7 +71,7 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
} }
} }
cacheChapters[book.bookUrl] = chapterCaches cacheChapters[book.bookUrl] = chapterCaches
upAdapterLiveData.postValue(book.bookUrl) upAdapterLiveData.sendValue(book.bookUrl)
} }
ensureActive() ensureActive()
} }
@ -97,7 +97,7 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
if (exportProgress.contains(book.bookUrl)) return if (exportProgress.contains(book.bookUrl)) return
exportProgress[book.bookUrl] = 0 exportProgress[book.bookUrl] = 0
exportMsg.remove(book.bookUrl) exportMsg.remove(book.bookUrl)
upAdapterLiveData.postValue(book.bookUrl) upAdapterLiveData.sendValue(book.bookUrl)
execute { execute {
mutex.withLock { mutex.withLock {
while (exportNumber > 0) { while (exportNumber > 0) {
@ -260,7 +260,7 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
if (exportProgress.contains(book.bookUrl)) return if (exportProgress.contains(book.bookUrl)) return
exportProgress[book.bookUrl] = 0 exportProgress[book.bookUrl] = 0
exportMsg.remove(book.bookUrl) exportMsg.remove(book.bookUrl)
upAdapterLiveData.postValue(book.bookUrl) upAdapterLiveData.sendValue(book.bookUrl)
execute { execute {
mutex.withLock { mutex.withLock {
while (exportNumber > 0) { while (exportNumber > 0) {

@ -650,6 +650,10 @@ object ChapterProvider {
"0" -> doublePage = false "0" -> doublePage = false
"1" -> doublePage = true "1" -> doublePage = true
"2" -> { "2" -> {
doublePage = (viewWidth > viewHeight)
&& ReadBook.pageAnim() != 3
}
"3" -> {
doublePage = (viewWidth > viewHeight || appCtx.isPad) doublePage = (viewWidth > viewHeight || appCtx.isPad)
&& ReadBook.pageAnim() != 3 && ReadBook.pageAnim() != 3
} }

@ -17,6 +17,7 @@ import androidx.recyclerview.widget.RecyclerView
import com.google.android.flexbox.FlexboxLayoutManager import com.google.android.flexbox.FlexboxLayoutManager
import io.legado.app.R import io.legado.app.R
import io.legado.app.base.VMBaseActivity import io.legado.app.base.VMBaseActivity
import io.legado.app.constant.AppLog
import io.legado.app.constant.PreferKey import io.legado.app.constant.PreferKey
import io.legado.app.data.appDb import io.legado.app.data.appDb
import io.legado.app.data.entities.Book 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.Dispatchers.IO
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.conflate import kotlinx.coroutines.flow.conflate
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import splitties.init.appCtx import splitties.init.appCtx
@ -288,6 +291,17 @@ class SearchActivity : VMBaseActivity<ActivityBookSearchBinding, SearchViewModel
groups = it groups = it
} }
} }
launch {
appDb.bookDao.flowAll().conflate().map { books ->
books.map { "${it.name}-${it.author}" }
}.catch { e ->
AppLog.put("加载书架数据失败", e)
}.collect {
viewModel.bookshelf.clear()
viewModel.bookshelf.addAll(it)
viewModel.upAdapterLiveData.postValue("isInBookshelf")
}
}
} }
/** /**

@ -10,14 +10,10 @@ import io.legado.app.data.entities.SearchKeyword
import io.legado.app.help.config.AppConfig import io.legado.app.help.config.AppConfig
import io.legado.app.model.webBook.SearchModel import io.legado.app.model.webBook.SearchModel
import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.launch
@OptIn(ExperimentalCoroutinesApi::class)
class SearchViewModel(application: Application) : BaseViewModel(application) { class SearchViewModel(application: Application) : BaseViewModel(application) {
val bookshelf = hashSetOf<String>() val bookshelf = hashSetOf<String>()
val upAdapterLiveData = MutableLiveData<String>() val upAdapterLiveData = MutableLiveData<String>()
@ -61,18 +57,6 @@ class SearchViewModel(application: Application) : BaseViewModel(application) {
} }
}.flowOn(IO) }.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")
}
}
}
/** /**
* 开始搜索 * 开始搜索
*/ */

@ -17,6 +17,7 @@ import io.legado.app.data.appDb
import io.legado.app.data.entities.BookSource import io.legado.app.data.entities.BookSource
import io.legado.app.data.entities.rule.* import io.legado.app.data.entities.rule.*
import io.legado.app.databinding.ActivityBookSourceEditBinding import io.legado.app.databinding.ActivityBookSourceEditBinding
import io.legado.app.databinding.DialogEditTextBinding
import io.legado.app.help.config.LocalConfig import io.legado.app.help.config.LocalConfig
import io.legado.app.lib.dialogs.SelectItem import io.legado.app.lib.dialogs.SelectItem
import io.legado.app.lib.dialogs.alert import io.legado.app.lib.dialogs.alert
@ -140,6 +141,7 @@ class BookSourceEditActivity :
} }
} }
} }
R.id.menu_set_source_variable -> setSourceVariable()
} }
return super.onCompatOptionsItemSelected(item) return super.onCompatOptionsItemSelected(item)
} }
@ -171,7 +173,12 @@ class BookSourceEditActivity :
override fun finish() { override fun finish() {
val source = getSource() 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) { alert(R.string.exit) {
setMessage(R.string.exit_no_save) setMessage(R.string.exit_no_save)
positiveButton(R.string.yes) positiveButton(R.string.yes)
@ -569,4 +576,30 @@ class BookSourceEditActivity :
showDialogFragment(TextDialog(mdText, TextDialog.Mode.MD)) 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)
}
}
}
}
} }

@ -1,12 +1,11 @@
package io.legado.app.ui.book.source.manage package io.legado.app.ui.book.source.manage
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Context
import android.hardware.display.DisplayManager
import android.os.Bundle import android.os.Bundle
import android.view.* import android.view.*
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.PopupMenu import androidx.appcompat.widget.PopupMenu
import androidx.appcompat.widget.SearchView import androidx.appcompat.widget.SearchView
import androidx.core.os.bundleOf import androidx.core.os.bundleOf
@ -70,9 +69,7 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
private var sort = Sort.Default private var sort = Sort.Default
private var sortAscending = true private var sortAscending = true
private var snackBar: Snackbar? = null private var snackBar: Snackbar? = null
private val displayManager by lazy { private var isPaused = false
getSystemService(Context.DISPLAY_SERVICE) as DisplayManager
}
private val qrResult = registerForActivityResult(QrCodeResult()) { private val qrResult = registerForActivityResult(QrCodeResult()) {
it ?: return@registerForActivityResult it ?: return@registerForActivityResult
showDialogFragment(ImportBookSourceDialog(it)) showDialogFragment(ImportBookSourceDialog(it))
@ -516,7 +513,7 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
delay(300L) delay(300L)
} }
}.collect { }.collect {
if (isScreenOn()) { if (SystemUtils.isScreenOn() && !isPaused) {
if (lastItem == 0) { if (lastItem == 0) {
adapter.notifyItemRangeChanged( adapter.notifyItemRangeChanged(
0, 0,
@ -552,11 +549,14 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
} }
} }
private fun isScreenOn(): Boolean { override fun onPause() {
return displayManager.displays.any { super.onPause()
it ?: return@any false isPaused = true
it.state != Display.STATE_OFF }
}
override fun onResume() {
super.onResume()
isPaused = false
} }
override fun upCountView() { override fun upCountView() {

@ -75,6 +75,11 @@ class TxtTocRuleActivity : VMBaseActivity<ActivityTxtTocRuleBinding, TxtTocRuleV
return super.onCompatCreateOptionsMenu(menu) return super.onCompatCreateOptionsMenu(menu)
} }
override fun onPrepareOptionsMenu(menu: Menu?): Boolean {
menu?.findItem(R.id.menu_split_long_chapter)?.isVisible = false
return super.onPrepareOptionsMenu(menu)
}
override fun onCompatOptionsItemSelected(item: MenuItem): Boolean { override fun onCompatOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) { when (item.itemId) {
R.id.menu_add -> showDialogFragment(TxtTocRuleEditDialog()) R.id.menu_add -> showDialogFragment(TxtTocRuleEditDialog())

@ -73,6 +73,7 @@ class TxtTocRuleAdapter(context: Context, private val callBack: CallBack) :
getItem(holder.layoutPosition)?.let { getItem(holder.layoutPosition)?.let {
if (buttonView.isPressed) { if (buttonView.isPressed) {
it.enable = isChecked it.enable = isChecked
callBack.update(it)
} }
} }
} }

@ -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() { private fun startLastUpdateTimeJob() {
upLastUpdateTimeJob?.cancel() upLastUpdateTimeJob?.cancel()
if (!AppConfig.showLastUpdateTime) { if (!AppConfig.showLastUpdateTime) {
@ -159,7 +171,9 @@ class BooksFragment() : BaseFragment(R.layout.fragment_books),
} }
upLastUpdateTimeJob = launch { upLastUpdateTimeJob = launch {
while (isActive) { while (isActive) {
booksAdapter.upLastUpdateTime() if (SystemUtils.isScreenOn()) {
booksAdapter.upLastUpdateTime()
}
delay(30 * 1000) delay(30 * 1000)
} }
} }

@ -215,6 +215,7 @@ class ReadRssActivity : VMBaseActivity<ActivityRssReadBinding, ReadRssViewModel>
} }
override fun upStarMenu() { override fun upStarMenu() {
starMenuItem?.isVisible = viewModel.rssArticle != null
if (viewModel.rssStar != null) { if (viewModel.rssStar != null) {
starMenuItem?.setIcon(R.drawable.ic_star) starMenuItem?.setIcon(R.drawable.ic_star)
starMenuItem?.setTitle(R.string.in_favorites) starMenuItem?.setTitle(R.string.in_favorites)

@ -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 <T> MutableLiveData<T>.sendValue(value: T) {
mainHandler.post {
this@sendValue.value = value
}
}

@ -5,6 +5,8 @@ import android.app.Activity
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
import android.provider.Settings import android.provider.Settings
import android.view.Display
import splitties.systemservices.displayManager
import splitties.systemservices.powerManager import splitties.systemservices.powerManager
@ -28,4 +30,9 @@ object SystemUtils {
} }
} }
fun isScreenOn(): Boolean {
return displayManager.displays.filterNotNull().any {
it.state != Display.STATE_OFF
}
}
} }

@ -27,8 +27,8 @@
android:scaleType="centerCrop" android:scaleType="centerCrop"
android:src="@color/md_green_600" android:src="@color/md_green_600"
android:visibility="invisible" android:visibility="invisible"
app:layout_constraintRight_toRightOf="@id/iv_cover" app:layout_constraintLeft_toRightOf="@id/iv_cover"
app:layout_constraintTop_toTopOf="@id/iv_cover" /> app:layout_constraintTop_toTopOf="@id/tv_name" />
<io.legado.app.ui.widget.text.BadgeView <io.legado.app.ui.widget.text.BadgeView
android:id="@+id/bv_originCount" android:id="@+id/bv_originCount"
@ -48,16 +48,17 @@
android:textColor="@color/primaryText" android:textColor="@color/primaryText"
android:textSize="16sp" android:textSize="16sp"
app:layout_constraintEnd_toStartOf="@id/bv_originCount" app:layout_constraintEnd_toStartOf="@id/bv_originCount"
app:layout_constraintStart_toEndOf="@+id/iv_cover" app:layout_constraintStart_toEndOf="@+id/iv_in_bookshelf"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />
<LinearLayout <LinearLayout
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="0dp" android:layout_height="0dp"
android:layout_marginStart="8dp"
android:orientation="vertical" android:orientation="vertical"
android:layout_marginTop="3dp" android:layout_marginTop="3dp"
app:layout_constraintBottom_toBottomOf="@id/iv_cover" app:layout_constraintBottom_toBottomOf="@id/iv_cover"
app:layout_constraintLeft_toLeftOf="@+id/tv_name" app:layout_constraintLeft_toRightOf="@+id/iv_cover"
app:layout_constraintRight_toRightOf="@id/tv_name" app:layout_constraintRight_toRightOf="@id/tv_name"
app:layout_constraintTop_toBottomOf="@+id/tv_name"> app:layout_constraintTop_toBottomOf="@+id/tv_name">

@ -42,6 +42,11 @@
android:title="@string/paste_source" android:title="@string/paste_source"
app:showAsAction="never" /> app:showAsAction="never" />
<item
android:id="@+id/menu_set_source_variable"
android:title="@string/set_source_variable"
app:showAsAction="never" />
<item <item
android:id="@+id/menu_qr_code_camera" android:id="@+id/menu_qr_code_camera"
android:title="@string/import_by_qr_code" android:title="@string/import_by_qr_code"

@ -28,7 +28,8 @@
<string-array name="double_page_title"> <string-array name="double_page_title">
<item>全局单页</item> <item>全局单页</item>
<item>全局双页</item> <item>全局双页</item>
<item>横屏双页/竖屏单页</item> <item>横屏双页</item>
<item>平板/横屏双页</item>
</string-array> </string-array>
<string-array name="NavBarColors"> <string-array name="NavBarColors">

@ -38,6 +38,7 @@
<item>0</item> <item>0</item>
<item>1</item> <item>1</item>
<item>2</item> <item>2</item>
<item>3</item>
</string-array> </string-array>
<string-array name="progress_bar_behavior_value"> <string-array name="progress_bar_behavior_value">

@ -65,7 +65,8 @@
<string-array name="double_page_title"> <string-array name="double_page_title">
<item>全局单页</item> <item>全局单页</item>
<item>全局双页</item> <item>全局双页</item>
<item>横屏双页 竖屏单页</item> <item>横屏双页</item>
<item>平板/横屏双页</item>
</string-array> </string-array>
<string-array name="progress_bar_behavior_title"> <string-array name="progress_bar_behavior_title">

Loading…
Cancel
Save