Merge remote-tracking branch 'origin/master'

pull/2143/head
kunfei 2 years ago
commit f88f6ec1eb
  1. 8
      app/src/main/java/io/legado/app/base/BaseService.kt
  2. 2
      app/src/main/java/io/legado/app/help/config/LocalConfig.kt
  3. 10
      app/src/main/java/io/legado/app/help/coroutine/Coroutine.kt
  4. 6
      app/src/main/java/io/legado/app/model/CheckSource.kt
  5. 2
      app/src/main/java/io/legado/app/receiver/NetworkChangedListener.kt
  6. 11
      app/src/main/java/io/legado/app/service/CheckSourceService.kt
  7. 64
      app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt
  8. 20
      app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceAdapter.kt
  9. 4
      app/src/main/res/layout/item_txt_toc_rule.xml
  10. 5
      app/src/main/res/menu/book_source_sel.xml
  11. 1
      app/src/main/res/values-es-rES/strings.xml
  12. 1
      app/src/main/res/values-ja-rJP/strings.xml
  13. 1
      app/src/main/res/values-pt-rBR/strings.xml
  14. 1
      app/src/main/res/values-zh-rHK/strings.xml
  15. 1
      app/src/main/res/values-zh-rTW/strings.xml
  16. 1
      app/src/main/res/values-zh/strings.xml
  17. 1
      app/src/main/res/values/strings.xml
  18. 6
      epublib/src/main/java/me/ag2s/epublib/epub/EpubReader.java
  19. 8
      epublib/src/main/java/me/ag2s/epublib/epub/ResourcesLoader.java

@ -6,10 +6,7 @@ import android.os.IBinder
import androidx.annotation.CallSuper import androidx.annotation.CallSuper
import io.legado.app.help.LifecycleHelp import io.legado.app.help.LifecycleHelp
import io.legado.app.help.coroutine.Coroutine import io.legado.app.help.coroutine.Coroutine
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.cancel
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
abstract class BaseService : Service(), CoroutineScope by MainScope() { abstract class BaseService : Service(), CoroutineScope by MainScope() {
@ -17,8 +14,9 @@ abstract class BaseService : Service(), CoroutineScope by MainScope() {
fun <T> execute( fun <T> execute(
scope: CoroutineScope = this, scope: CoroutineScope = this,
context: CoroutineContext = Dispatchers.IO, context: CoroutineContext = Dispatchers.IO,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> T block: suspend CoroutineScope.() -> T
) = Coroutine.async(scope, context) { block() } ) = Coroutine.async(scope, context, start) { block() }
@CallSuper @CallSuper
override fun onCreate() { override fun onCreate() {

@ -43,7 +43,7 @@ object LocalConfig :
get() = !isLastVersion(5, "httpTtsVersion") get() = !isLastVersion(5, "httpTtsVersion")
val needUpTxtTocRule: Boolean val needUpTxtTocRule: Boolean
get() = !isLastVersion(1, "txtTocRuleVersion") get() = !isLastVersion(2, "txtTocRuleVersion")
val needUpRssSources: Boolean val needUpRssSources: Boolean
get() = !isLastVersion(4, "rssSourceVersion") get() = !isLastVersion(4, "rssSourceVersion")

@ -12,6 +12,7 @@ import kotlin.coroutines.CoroutineContext
class Coroutine<T>( class Coroutine<T>(
val scope: CoroutineScope, val scope: CoroutineScope,
context: CoroutineContext = Dispatchers.IO, context: CoroutineContext = Dispatchers.IO,
val startOption: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> T block: suspend CoroutineScope.() -> T
) { ) {
@ -22,9 +23,10 @@ class Coroutine<T>(
fun <T> async( fun <T> async(
scope: CoroutineScope = DEFAULT, scope: CoroutineScope = DEFAULT,
context: CoroutineContext = Dispatchers.IO, context: CoroutineContext = Dispatchers.IO,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> T block: suspend CoroutineScope.() -> T
): Coroutine<T> { ): Coroutine<T> {
return Coroutine(scope, context, block) return Coroutine(scope, context, start, block)
} }
} }
@ -135,11 +137,15 @@ class Coroutine<T>(
return job.invokeOnCompletion(handler) return job.invokeOnCompletion(handler)
} }
fun start() {
job.start()
}
private fun executeInternal( private fun executeInternal(
context: CoroutineContext, context: CoroutineContext,
block: suspend CoroutineScope.() -> T block: suspend CoroutineScope.() -> T
): Job { ): Job {
return (scope + Dispatchers.Main).launch { return (scope + Dispatchers.Main).launch(start = startOption) {
try { try {
start?.let { dispatchVoidCallback(this, it) } start?.let { dispatchVoidCallback(this, it) }
ensureActive() ensureActive()

@ -38,6 +38,12 @@ object CheckSource {
} }
} }
fun resume(context: Context) {
context.startService<CheckSourceService> {
action = IntentAction.resume
}
}
fun putConfig() { fun putConfig() {
CacheManager.put("checkSourceTimeout", timeout) CacheManager.put("checkSourceTimeout", timeout)
CacheManager.put("checkSearch", checkSearch) CacheManager.put("checkSearch", checkSearch)

@ -1,5 +1,6 @@
package io.legado.app.receiver package io.legado.app.receiver
import android.annotation.SuppressLint
import android.content.BroadcastReceiver import android.content.BroadcastReceiver
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
@ -34,6 +35,7 @@ class NetworkChangedListener(private val context: Context) {
return@lazy null return@lazy null
} }
@SuppressLint("MissingPermission")
fun register() { fun register() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
networkCallback?.let { networkCallback?.let {

@ -24,10 +24,8 @@ import io.legado.app.utils.activityPendingIntent
import io.legado.app.utils.postEvent import io.legado.app.utils.postEvent
import io.legado.app.utils.servicePendingIntent import io.legado.app.utils.servicePendingIntent
import io.legado.app.utils.toastOnUi import io.legado.app.utils.toastOnUi
import kotlinx.coroutines.*
import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.TimeoutCancellationException
import kotlinx.coroutines.asCoroutineDispatcher
import kotlinx.coroutines.launch
import org.mozilla.javascript.WrappedException import org.mozilla.javascript.WrappedException
import java.util.concurrent.Executors import java.util.concurrent.Executors
import kotlin.math.min import kotlin.math.min
@ -71,6 +69,7 @@ class CheckSourceService : BaseService() {
IntentAction.start -> intent.getStringArrayListExtra("selectIds")?.let { IntentAction.start -> intent.getStringArrayListExtra("selectIds")?.let {
check(it) check(it)
} }
IntentAction.resume -> upNotification()
else -> stopSelf() else -> stopSelf()
} }
return super.onStartCommand(intent, flags, startId) return super.onStartCommand(intent, flags, startId)
@ -122,7 +121,7 @@ class CheckSourceService : BaseService() {
*校验书源 *校验书源
*/ */
private fun check(source: BookSource) { private fun check(source: BookSource) {
execute(context = searchCoroutine) { execute(context = searchCoroutine, start = CoroutineStart.LAZY) {
Debug.startChecking(source) Debug.startChecking(source)
var searchWord = CheckSource.keyword var searchWord = CheckSource.keyword
source.ruleSearch?.checkKeyWord?.let { source.ruleSearch?.checkKeyWord?.let {
@ -162,7 +161,7 @@ class CheckSourceService : BaseService() {
} }
} }
if (url.isNullOrBlank()) { if (url.isNullOrBlank()) {
source.addGroup("发现规则为空") source.addGroup("发现规则为空")
} else { } else {
source.removeGroup("发现规则为空") source.removeGroup("发现规则为空")
val exploreBooks = WebBook.exploreBookAwait(this, source, url) val exploreBooks = WebBook.exploreBookAwait(this, source, url)
@ -194,7 +193,7 @@ class CheckSourceService : BaseService() {
source.respondTime = Debug.getRespondTime(source.bookSourceUrl) source.respondTime = Debug.getRespondTime(source.bookSourceUrl)
appDb.bookSourceDao.update(source) appDb.bookSourceDao.update(source)
onNext(source.bookSourceUrl, source.bookSourceName) onNext(source.bookSourceUrl, source.bookSourceName)
} }.start()
} }
/** /**

@ -1,10 +1,10 @@
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.Menu import android.view.*
import android.view.MenuItem
import android.view.SubMenu
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.appcompat.widget.PopupMenu import androidx.appcompat.widget.PopupMenu
@ -28,6 +28,7 @@ import io.legado.app.lib.theme.primaryColor
import io.legado.app.lib.theme.primaryTextColor import io.legado.app.lib.theme.primaryTextColor
import io.legado.app.model.CheckSource import io.legado.app.model.CheckSource
import io.legado.app.model.Debug import io.legado.app.model.Debug
import io.legado.app.service.CheckSourceService
import io.legado.app.ui.association.ImportBookSourceDialog import io.legado.app.ui.association.ImportBookSourceDialog
import io.legado.app.ui.book.local.rule.TxtTocRuleActivity import io.legado.app.ui.book.local.rule.TxtTocRuleActivity
import io.legado.app.ui.book.source.debug.BookSourceDebugActivity import io.legado.app.ui.book.source.debug.BookSourceDebugActivity
@ -69,6 +70,9 @@ 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 {
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))
@ -108,6 +112,7 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
upBookSource() upBookSource()
initLiveDataGroup() initLiveDataGroup()
initSelectActionBar() initSelectActionBar()
resumeCheckSource()
if (!LocalConfig.bookSourcesHelpVersionIsLast) { if (!LocalConfig.bookSourcesHelpVersionIsLast) {
showHelp() showHelp()
} }
@ -363,6 +368,7 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
R.id.menu_share_source -> viewModel.saveToFile(adapter.selection) { R.id.menu_share_source -> viewModel.saveToFile(adapter.selection) {
share(it) share(it)
} }
R.id.menu_check_selected_interval -> adapter.checkSelectedInterval()
} }
return true return true
} }
@ -376,6 +382,7 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
} }
customView { alertBinding.root } customView { alertBinding.root }
okButton { okButton {
keepScreenOn(true)
alertBinding.editView.text?.toString()?.let { alertBinding.editView.text?.toString()?.let {
if (it.isNotEmpty()) { if (it.isNotEmpty()) {
CheckSource.keyword = it CheckSource.keyword = it
@ -396,6 +403,15 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
} }
} }
private fun resumeCheckSource() {
if (!Debug.isChecking) {
return
}
keepScreenOn(true)
CheckSource.resume(this)
checkMessageRefreshJob(0, 0).start()
}
@SuppressLint("InflateParams") @SuppressLint("InflateParams")
private fun selectionAddToGroups() { private fun selectionAddToGroups() {
alert(titleResource = R.string.add_group) { alert(titleResource = R.string.add_group) {
@ -493,6 +509,7 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
} }
} }
observeEvent<Int>(EventBus.CHECK_SOURCE_DONE) { observeEvent<Int>(EventBus.CHECK_SOURCE_DONE) {
keepScreenOn(false)
snackBar?.dismiss() snackBar?.dismiss()
snackBar = null snackBar = null
groups.map { group -> groups.map { group ->
@ -512,11 +529,21 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
delay(300L) delay(300L)
} }
}.collect { }.collect {
adapter.notifyItemRangeChanged( if (isScreenOn()) {
firstItem, if (lastItem == 0) {
lastItem + 1, adapter.notifyItemRangeChanged(
bundleOf(Pair("checkSourceMessage", null)) 0,
) adapter.itemCount,
bundleOf(Pair("checkSourceMessage", null))
)
} else {
adapter.notifyItemRangeChanged(
firstItem,
lastItem + 1,
bundleOf(Pair("checkSourceMessage", null))
)
}
}
if (!it) { if (!it) {
this.cancel() this.cancel()
} }
@ -524,6 +551,27 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
} }
} }
/**
* 保持亮屏
*/
private fun keepScreenOn(on: Boolean) {
val isScreenOn =
(window.attributes.flags and WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) != 0
if (on == isScreenOn) return
if (on) {
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
} else {
window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
}
}
private fun isScreenOn(): Boolean {
return displayManager.displays.any {
it ?: return@any false
it.state != Display.STATE_OFF
}
}
override fun upCountView() { override fun upCountView() {
binding.selectActionBar binding.selectActionBar
.upCountView(adapter.selection.size, adapter.itemCount) .upCountView(adapter.selection.size, adapter.itemCount)

@ -24,6 +24,7 @@ import io.legado.app.utils.ColorUtils
import io.legado.app.utils.invisible import io.legado.app.utils.invisible
import io.legado.app.utils.startActivity import io.legado.app.utils.startActivity
import io.legado.app.utils.visible import io.legado.app.utils.visible
import java.util.*
class BookSourceAdapter(context: Context, val callBack: CallBack) : class BookSourceAdapter(context: Context, val callBack: CallBack) :
@ -234,6 +235,25 @@ class BookSourceAdapter(context: Context, val callBack: CallBack) :
callBack.upCountView() callBack.upCountView()
} }
fun checkSelectedInterval() {
val selectedPosition = linkedSetOf<Int>()
getItems().forEachIndexed { index, it ->
if (selected.contains(it)) {
selectedPosition.add(index)
}
}
val minPosition = Collections.min(selectedPosition)
val maxPosition = Collections.max(selectedPosition)
val itemCount = maxPosition - minPosition + 1
for (i in minPosition..maxPosition) {
getItem(i)?.let {
selected.add(it)
}
}
notifyItemRangeChanged(minPosition, itemCount, bundleOf(Pair("selected", null)))
callBack.upCountView()
}
override fun swap(srcPosition: Int, targetPosition: Int): Boolean { override fun swap(srcPosition: Int, targetPosition: Int): Boolean {
val srcItem = getItem(srcPosition) val srcItem = getItem(srcPosition)
val targetItem = getItem(targetPosition) val targetItem = getItem(targetPosition)

@ -10,13 +10,13 @@
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent"
android:gravity="center_vertical">
<io.legado.app.lib.theme.view.ThemeCheckBox <io.legado.app.lib.theme.view.ThemeCheckBox
android:id="@+id/cb_source" android:id="@+id/cb_source"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1" android:layout_weight="1"
android:singleLine="true" android:singleLine="true"
android:textColor="@color/primaryText" android:textColor="@color/primaryText"

@ -58,4 +58,9 @@
android:title="@string/check_select_source" android:title="@string/check_select_source"
app:showAsAction="never" /> app:showAsAction="never" />
<item
android:id="@+id/menu_check_selected_interval"
android:title="@string/check_selected_interval"
app:showAsAction="never" />
</menu> </menu>

@ -1007,4 +1007,5 @@
<string name="page_touch_slop_dialog_title">滑动翻页阈值(0 = 系统默认值)</string> <string name="page_touch_slop_dialog_title">滑动翻页阈值(0 = 系统默认值)</string>
<string name="page_touch_slop_summary">滑动多长距离才会触发滑动翻页(系统默认值 %s px)</string> <string name="page_touch_slop_summary">滑动多长距离才会触发滑动翻页(系统默认值 %s px)</string>
<string name="example">Ejemplo</string> <string name="example">Ejemplo</string>
<string name="check_selected_interval">选中所选区间</string>
</resources> </resources>

@ -1010,4 +1010,5 @@
<string name="page_touch_slop_dialog_title">滑动翻页阈值(0 = 系统默认值)</string> <string name="page_touch_slop_dialog_title">滑动翻页阈值(0 = 系统默认值)</string>
<string name="page_touch_slop_summary">滑动多长距离才会触发滑动翻页(系统默认值 %s px)</string> <string name="page_touch_slop_summary">滑动多长距离才会触发滑动翻页(系统默认值 %s px)</string>
<string name="example"></string> <string name="example"></string>
<string name="check_selected_interval">选中所选区间</string>
</resources> </resources>

@ -1010,4 +1010,5 @@
<string name="page_touch_slop_dialog_title">滑动翻页阈值(0 = 系统默认值)</string> <string name="page_touch_slop_dialog_title">滑动翻页阈值(0 = 系统默认值)</string>
<string name="page_touch_slop_summary">滑动多长距离才会触发滑动翻页(系统默认值 %s px)</string> <string name="page_touch_slop_summary">滑动多长距离才会触发滑动翻页(系统默认值 %s px)</string>
<string name="example">Exemplo</string> <string name="example">Exemplo</string>
<string name="check_selected_interval">选中所选区间</string>
</resources> </resources>

@ -1007,4 +1007,5 @@
<string name="page_touch_slop_dialog_title">滑动翻页阈值(0 = 系统默认值)</string> <string name="page_touch_slop_dialog_title">滑动翻页阈值(0 = 系统默认值)</string>
<string name="page_touch_slop_summary">滑动多长距离才会触发滑动翻页(系统默认值 %s px)</string> <string name="page_touch_slop_summary">滑动多长距离才会触发滑动翻页(系统默认值 %s px)</string>
<string name="example">示例</string> <string name="example">示例</string>
<string name="check_selected_interval">选中所选区间</string>
</resources> </resources>

@ -1009,4 +1009,5 @@
<string name="page_touch_slop_dialog_title">滑动翻页阈值(0 = 系统默认值)</string> <string name="page_touch_slop_dialog_title">滑动翻页阈值(0 = 系统默认值)</string>
<string name="page_touch_slop_summary">滑动多长距离才会触发滑动翻页(系统默认值 %s px)</string> <string name="page_touch_slop_summary">滑动多长距离才会触发滑动翻页(系统默认值 %s px)</string>
<string name="example">示例</string> <string name="example">示例</string>
<string name="check_selected_interval">选中所选区间</string>
</resources> </resources>

@ -1009,4 +1009,5 @@
<string name="page_touch_slop_dialog_title">滑动翻页阈值(0 = 系统默认值)</string> <string name="page_touch_slop_dialog_title">滑动翻页阈值(0 = 系统默认值)</string>
<string name="page_touch_slop_summary">滑动多长距离才会触发滑动翻页(系统默认值 %s px)</string> <string name="page_touch_slop_summary">滑动多长距离才会触发滑动翻页(系统默认值 %s px)</string>
<string name="example">示例</string> <string name="example">示例</string>
<string name="check_selected_interval">选中所选区间</string>
</resources> </resources>

@ -1010,4 +1010,5 @@
<string name="page_touch_slop_title">滑动翻页阈值</string> <string name="page_touch_slop_title">滑动翻页阈值</string>
<string name="page_touch_slop_dialog_title">滑动翻页阈值(0 = 系统默认值)</string> <string name="page_touch_slop_dialog_title">滑动翻页阈值(0 = 系统默认值)</string>
<string name="page_touch_slop_summary">滑动多长距离才会触发滑动翻页(系统默认值 %s px)</string> <string name="page_touch_slop_summary">滑动多长距离才会触发滑动翻页(系统默认值 %s px)</string>
<string name="check_selected_interval">选中所选区间</string>
</resources> </resources>

@ -69,8 +69,7 @@ public class EpubReader {
*/ */
public EpubBook readEpubLazy(@NonNull ZipFile zipFile, @NonNull String encoding) public EpubBook readEpubLazy(@NonNull ZipFile zipFile, @NonNull String encoding)
throws IOException { throws IOException {
return readEpubLazy(zipFile, encoding, return readEpubLazy(zipFile, encoding, Arrays.asList(MediaTypes.mediaTypes));
Arrays.asList(MediaTypes.mediaTypes));
} }
public EpubBook readEpub(@NonNull ZipInputStream in, @NonNull String encoding) throws IOException { public EpubBook readEpub(@NonNull ZipInputStream in, @NonNull String encoding) throws IOException {
@ -107,8 +106,7 @@ public class EpubReader {
} }
handleMimeType(result, resources); handleMimeType(result, resources);
String packageResourceHref = getPackageResourceHref(resources); String packageResourceHref = getPackageResourceHref(resources);
Resource packageResource = processPackageResource(packageResourceHref, Resource packageResource = processPackageResource(packageResourceHref, result, resources);
result, resources);
result.setOpfResource(packageResource); result.setOpfResource(packageResource);
Resource ncxResource = processNcxResource(packageResource, result); Resource ncxResource = processNcxResource(packageResource, result);
result.setNcxResource(ncxResource); result.setNcxResource(ncxResource);

@ -46,9 +46,11 @@ public class ResourcesLoader {
* @return Resources * @return Resources
* @throws IOException IOException * @throws IOException IOException
*/ */
public static Resources loadResources(ZipFile zipFile, public static Resources loadResources(
String defaultHtmlEncoding, ZipFile zipFile,
List<MediaType> lazyLoadedTypes) throws IOException { String defaultHtmlEncoding,
List<MediaType> lazyLoadedTypes
) throws IOException {
LazyResourceProvider resourceProvider = LazyResourceProvider resourceProvider =
new EpubResourceProvider(zipFile.getName()); new EpubResourceProvider(zipFile.getName());

Loading…
Cancel
Save