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界面 -->
<activity
android:name=".ui.browser.WebViewActivity"
android:configChanges="locale|keyboardHidden|orientation|screenSize|smallestScreenSize|screenLayout"
android:launchMode="standard" />
<!-- 书源登录 -->
<activity

@ -116,7 +116,7 @@ interface BookSourceDao {
@Query("select * from book_sources where enabled = 1 and bookSourceType = :type")
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>
@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["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

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

@ -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) {

@ -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
}

@ -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<ActivityBookSearchBinding, SearchViewModel
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.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<String>()
val upAdapterLiveData = MutableLiveData<String>()
@ -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")
}
}
}
/**
* 开始搜索
*/

@ -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)
}
}
}
}
}

@ -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<ActivityBookSourceBinding, BookSourceV
private var sort = Sort.Default
private var sortAscending = true
private var snackBar: Snackbar? = null
private val displayManager by lazy {
getSystemService(Context.DISPLAY_SERVICE) as DisplayManager
}
private var isPaused = false
private val qrResult = registerForActivityResult(QrCodeResult()) {
it ?: return@registerForActivityResult
showDialogFragment(ImportBookSourceDialog(it))
@ -516,7 +513,7 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
delay(300L)
}
}.collect {
if (isScreenOn()) {
if (SystemUtils.isScreenOn() && !isPaused) {
if (lastItem == 0) {
adapter.notifyItemRangeChanged(
0,
@ -552,11 +549,14 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
}
}
private fun isScreenOn(): Boolean {
return displayManager.displays.any {
it ?: return@any false
it.state != Display.STATE_OFF
}
override fun onPause() {
super.onPause()
isPaused = true
}
override fun onResume() {
super.onResume()
isPaused = false
}
override fun upCountView() {

@ -75,6 +75,11 @@ class TxtTocRuleActivity : VMBaseActivity<ActivityTxtTocRuleBinding, TxtTocRuleV
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 {
when (item.itemId) {
R.id.menu_add -> showDialogFragment(TxtTocRuleEditDialog())

@ -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)
}
}
}

@ -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)
}
}

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

@ -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" />
<io.legado.app.ui.widget.text.BadgeView
android:id="@+id/bv_originCount"
@ -48,16 +48,17 @@
android:textColor="@color/primaryText"
android:textSize="16sp"
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" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="8dp"
android:orientation="vertical"
android:layout_marginTop="3dp"
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_constraintTop_toBottomOf="@+id/tv_name">

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

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

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

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

Loading…
Cancel
Save