mirror of
https://github.com/gedoor/legado.git
synced 2024-07-17 00:58:29 +08:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
ab54311d51
@ -18,8 +18,9 @@ abstract class BaseService : LifecycleService(), CoroutineScope by MainScope() {
|
||||
scope: CoroutineScope = this,
|
||||
context: CoroutineContext = Dispatchers.IO,
|
||||
start: CoroutineStart = CoroutineStart.DEFAULT,
|
||||
executeContext: CoroutineContext = Dispatchers.Main,
|
||||
block: suspend CoroutineScope.() -> T
|
||||
) = Coroutine.async(scope, context, start) { block() }
|
||||
) = Coroutine.async(scope, context, start, executeContext, block)
|
||||
|
||||
@CallSuper
|
||||
override fun onCreate() {
|
||||
@ -57,7 +58,7 @@ abstract class BaseService : LifecycleService(), CoroutineScope by MainScope() {
|
||||
/**
|
||||
* 检测通知权限
|
||||
*/
|
||||
private fun checkNotificationPermission() {
|
||||
private fun checkNotificationPermission() {
|
||||
PermissionsCompat.Builder()
|
||||
.addPermissions(Permissions.POST_NOTIFICATIONS)
|
||||
.rationale(R.string.notification_permission_rationale)
|
||||
|
@ -7,6 +7,7 @@ import androidx.lifecycle.viewModelScope
|
||||
import io.legado.app.App
|
||||
import io.legado.app.help.coroutine.Coroutine
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.CoroutineStart
|
||||
import kotlinx.coroutines.Deferred
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
@ -19,9 +20,11 @@ open class BaseViewModel(application: Application) : AndroidViewModel(applicatio
|
||||
fun <T> execute(
|
||||
scope: CoroutineScope = viewModelScope,
|
||||
context: CoroutineContext = Dispatchers.IO,
|
||||
start: CoroutineStart = CoroutineStart.DEFAULT,
|
||||
executeContext: CoroutineContext = Dispatchers.Main,
|
||||
block: suspend CoroutineScope.() -> T
|
||||
): Coroutine<T> {
|
||||
return Coroutine.async(scope, context) { block() }
|
||||
return Coroutine.async(scope, context, start, executeContext, block)
|
||||
}
|
||||
|
||||
fun <R> submit(
|
||||
|
@ -183,7 +183,7 @@ data class BookSource(
|
||||
|
||||
fun getInvalidGroupNames(): String {
|
||||
return bookSourceGroup?.splitNotBlank(AppPattern.splitGroupRegex)?.toHashSet()?.filter {
|
||||
"失效" in it
|
||||
"失效" in it || it == "校验超时"
|
||||
}?.joinToString() ?: ""
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,7 @@ class Coroutine<T>(
|
||||
val scope: CoroutineScope,
|
||||
context: CoroutineContext = Dispatchers.IO,
|
||||
val startOption: CoroutineStart = CoroutineStart.DEFAULT,
|
||||
val executeContext: CoroutineContext = Dispatchers.Main,
|
||||
block: suspend CoroutineScope.() -> T
|
||||
) {
|
||||
|
||||
@ -36,9 +37,10 @@ class Coroutine<T>(
|
||||
scope: CoroutineScope = DEFAULT,
|
||||
context: CoroutineContext = Dispatchers.IO,
|
||||
start: CoroutineStart = CoroutineStart.DEFAULT,
|
||||
executeContext: CoroutineContext = Dispatchers.Main,
|
||||
block: suspend CoroutineScope.() -> T
|
||||
): Coroutine<T> {
|
||||
return Coroutine(scope, context, start, block)
|
||||
return Coroutine(scope, context, start, executeContext, block)
|
||||
}
|
||||
|
||||
}
|
||||
@ -158,7 +160,7 @@ class Coroutine<T>(
|
||||
context: CoroutineContext,
|
||||
block: suspend CoroutineScope.() -> T
|
||||
): Job {
|
||||
return (scope.plus(Dispatchers.Main)).launch(start = startOption) {
|
||||
return (scope.plus(executeContext)).launch(start = startOption) {
|
||||
try {
|
||||
start?.let { dispatchVoidCallback(this, it) }
|
||||
ensureActive()
|
||||
|
@ -57,9 +57,8 @@ object LocalBook {
|
||||
}.firstOrNull()?.let {
|
||||
getBookInputStream(it)
|
||||
}
|
||||
} else if (webDavUrl != null) {
|
||||
} else if (webDavUrl != null && downloadRemoteBook(book)) {
|
||||
// 下载远程链接
|
||||
downloadRemoteBook(book)
|
||||
getBookInputStream(book)
|
||||
} else {
|
||||
null
|
||||
@ -90,12 +89,15 @@ object LocalBook {
|
||||
book.isEpub -> {
|
||||
EpubFile.getChapterList(book)
|
||||
}
|
||||
|
||||
book.isUmd -> {
|
||||
UmdFile.getChapterList(book)
|
||||
}
|
||||
|
||||
book.isPdf -> {
|
||||
PdfFile.getChapterList(book)
|
||||
}
|
||||
|
||||
else -> {
|
||||
TextFile.getChapterList(book)
|
||||
}
|
||||
@ -117,12 +119,15 @@ object LocalBook {
|
||||
book.isEpub -> {
|
||||
EpubFile.getContent(book, chapter)
|
||||
}
|
||||
|
||||
book.isUmd -> {
|
||||
UmdFile.getContent(book, chapter)
|
||||
}
|
||||
|
||||
book.isPdf -> {
|
||||
PdfFile.getContent(book, chapter)
|
||||
}
|
||||
|
||||
else -> {
|
||||
TextFile.getContent(book, chapter)
|
||||
}
|
||||
@ -218,7 +223,7 @@ object LocalBook {
|
||||
}
|
||||
}
|
||||
|
||||
/* 批量导入 支持自动导入压缩包的支持书籍 */
|
||||
/* 批量导入 支持自动导入压缩包的支持书籍 */
|
||||
fun importFiles(uri: Uri): List<Book> {
|
||||
val books = mutableListOf<Book>()
|
||||
val fileDoc = FileDoc.fromUri(uri, false)
|
||||
@ -329,6 +334,7 @@ object LocalBook {
|
||||
Base64.DEFAULT
|
||||
)
|
||||
)
|
||||
|
||||
else -> throw NoStackTraceException("在线导入书籍支持http/https/DataURL")
|
||||
}
|
||||
return saveBookFile(inputStream, fileName)
|
||||
@ -383,7 +389,7 @@ object LocalBook {
|
||||
}
|
||||
|
||||
//下载book对应的远程文件 并更新Book
|
||||
private fun downloadRemoteBook(localBook: Book) {
|
||||
private fun downloadRemoteBook(localBook: Book): Boolean {
|
||||
val webDavUrl = localBook.getRemoteUrl()
|
||||
if (webDavUrl.isNullOrBlank()) throw NoStackTraceException("Book file is not webDav File")
|
||||
try {
|
||||
@ -415,9 +421,11 @@ object LocalBook {
|
||||
localBook.save()
|
||||
}
|
||||
}
|
||||
return true
|
||||
} catch (e: Exception) {
|
||||
e.printOnDebug()
|
||||
AppLog.put("自动下载webDav书籍失败", e)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -122,7 +122,11 @@ class CheckSourceService : BaseService() {
|
||||
*校验书源
|
||||
*/
|
||||
private fun check(source: BookSource) {
|
||||
execute(context = searchCoroutine, start = CoroutineStart.LAZY) {
|
||||
execute(
|
||||
context = searchCoroutine,
|
||||
start = CoroutineStart.LAZY,
|
||||
executeContext = IO
|
||||
) {
|
||||
Debug.startChecking(source)
|
||||
var searchWord = CheckSource.keyword
|
||||
source.ruleSearch?.checkKeyWord?.let {
|
||||
@ -188,7 +192,6 @@ class CheckSourceService : BaseService() {
|
||||
"" else "\n\n${source.bookSourceComment}"
|
||||
Debug.updateFinalMessage(source.bookSourceUrl, "校验失败:${it.localizedMessage}")
|
||||
}.onSuccess(searchCoroutine) {
|
||||
source.removeGroup("校验超时")
|
||||
Debug.updateFinalMessage(source.bookSourceUrl, "校验成功")
|
||||
}.onFinally(IO) {
|
||||
source.respondTime = Debug.getRespondTime(source.bookSourceUrl)
|
||||
|
@ -26,7 +26,7 @@ import io.legado.app.utils.printOnDebug
|
||||
import io.legado.app.utils.servicePendingIntent
|
||||
import io.legado.app.utils.toastOnUi
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
import kotlinx.coroutines.Dispatchers.Main
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.ensureActive
|
||||
@ -68,32 +68,21 @@ class HttpReadAloudService : BaseReadAloudService(),
|
||||
super.onDestroy()
|
||||
downloadTask?.cancel()
|
||||
exoPlayer.release()
|
||||
Coroutine.async {
|
||||
removeCacheFile()
|
||||
}
|
||||
}
|
||||
|
||||
override fun play() {
|
||||
pageChanged = false
|
||||
exoPlayer.stop()
|
||||
if (!requestFocus()) return
|
||||
if (contentList.isEmpty()) {
|
||||
AppLog.putDebug("朗读列表为空")
|
||||
ReadBook.readAloud()
|
||||
} else {
|
||||
super.play()
|
||||
kotlin.runCatching {
|
||||
if (nowSpeak == 0) {
|
||||
downloadAudio()
|
||||
} else {
|
||||
val fileName = md5SpeakFileName(contentList[nowSpeak])
|
||||
val file = getSpeakFileAsMd5(fileName)
|
||||
if (file.exists()) {
|
||||
playAudio(file)
|
||||
} else if (!downloadTaskActiveLock.isLocked) {
|
||||
downloadAudio()
|
||||
}
|
||||
}
|
||||
}.onFailure {
|
||||
toastOnUi("朗读出错:${it.localizedMessage}")
|
||||
AppLog.put("朗读出错:${it.localizedMessage}", it)
|
||||
}
|
||||
downloadAndPlayAudios()
|
||||
}
|
||||
}
|
||||
|
||||
@ -105,21 +94,21 @@ class HttpReadAloudService : BaseReadAloudService(),
|
||||
readAloudNumber += contentList[nowSpeak].length + 1
|
||||
if (nowSpeak < contentList.lastIndex) {
|
||||
nowSpeak++
|
||||
play()
|
||||
} else {
|
||||
nextChapter()
|
||||
}
|
||||
}
|
||||
|
||||
private fun downloadAudio() {
|
||||
private fun downloadAndPlayAudios() {
|
||||
exoPlayer.clearMediaItems()
|
||||
downloadTask?.cancel()
|
||||
downloadTask = execute {
|
||||
downloadTaskActiveLock.withLock {
|
||||
ensureActive()
|
||||
removeCacheFile()
|
||||
val httpTts = ReadAloud.httpTTS ?: throw NoStackTraceException("tts is null")
|
||||
contentList.forEachIndexed { index, content ->
|
||||
ensureActive()
|
||||
if (index < nowSpeak) return@forEachIndexed
|
||||
val fileName = md5SpeakFileName(content)
|
||||
val speakText = content.replace(AppPattern.notReadAloudRegex, "")
|
||||
if (speakText.isEmpty()) {
|
||||
@ -141,13 +130,23 @@ class HttpReadAloudService : BaseReadAloudService(),
|
||||
return@execute
|
||||
}
|
||||
}
|
||||
if (index == nowSpeak) {
|
||||
val file = getSpeakFileAsMd5(fileName)
|
||||
playAudio(file)
|
||||
val file = getSpeakFileAsMd5(fileName)
|
||||
val mediaItem = MediaItem.fromUri(Uri.fromFile(file))
|
||||
launch(Main) {
|
||||
if (exoPlayer.playbackState == Player.STATE_ENDED) {
|
||||
exoPlayer.stop()
|
||||
exoPlayer.clearMediaItems()
|
||||
}
|
||||
exoPlayer.addMediaItem(mediaItem)
|
||||
if (!exoPlayer.isPlaying) {
|
||||
exoPlayer.playWhenReady = !pause
|
||||
exoPlayer.prepare()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}.onError(IO) {
|
||||
}.onError {
|
||||
toastOnUi("朗读出错:${it.localizedMessage}")
|
||||
AppLog.put("朗读下载出错\n${it.localizedMessage}", it)
|
||||
}
|
||||
}
|
||||
@ -193,6 +192,7 @@ class HttpReadAloudService : BaseReadAloudService(),
|
||||
e.printOnDebug()
|
||||
throw e
|
||||
}
|
||||
|
||||
is SocketTimeoutException, is ConnectException -> {
|
||||
downloadErrorNo++
|
||||
if (downloadErrorNo > 5) {
|
||||
@ -202,6 +202,7 @@ class HttpReadAloudService : BaseReadAloudService(),
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
else -> {
|
||||
downloadErrorNo++
|
||||
val msg = "tts下载错误\n${e.localizedMessage}"
|
||||
@ -223,22 +224,6 @@ class HttpReadAloudService : BaseReadAloudService(),
|
||||
return null
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
private fun playAudio(file: File) {
|
||||
if (requestFocus()) {
|
||||
launch {
|
||||
kotlin.runCatching {
|
||||
val mediaItem = MediaItem.fromUri(Uri.fromFile(file))
|
||||
exoPlayer.setMediaItem(mediaItem)
|
||||
exoPlayer.playWhenReady = true
|
||||
exoPlayer.prepare()
|
||||
}.onFailure {
|
||||
it.printOnDebug()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun md5SpeakFileName(content: String): String {
|
||||
return MD5Utils.md5Encode16(textChapter?.title ?: "") + "_" +
|
||||
MD5Utils.md5Encode16("${ReadAloud.httpTTS?.url}-|-$speechRate-|-$content")
|
||||
@ -338,7 +323,7 @@ class HttpReadAloudService : BaseReadAloudService(),
|
||||
downloadTask?.cancel()
|
||||
exoPlayer.stop()
|
||||
speechRate = AppConfig.speechRatePlay + 5
|
||||
downloadAudio()
|
||||
downloadAndPlayAudios()
|
||||
}
|
||||
|
||||
override fun onPlaybackStateChanged(playbackState: Int) {
|
||||
@ -347,15 +332,18 @@ class HttpReadAloudService : BaseReadAloudService(),
|
||||
Player.STATE_IDLE -> {
|
||||
// 空闲
|
||||
}
|
||||
|
||||
Player.STATE_BUFFERING -> {
|
||||
// 缓冲中
|
||||
}
|
||||
|
||||
Player.STATE_READY -> {
|
||||
// 准备好
|
||||
if (pause) return
|
||||
exoPlayer.play()
|
||||
upPlayPos()
|
||||
}
|
||||
|
||||
Player.STATE_ENDED -> {
|
||||
// 结束
|
||||
playErrorNo = 0
|
||||
@ -364,6 +352,12 @@ class HttpReadAloudService : BaseReadAloudService(),
|
||||
}
|
||||
}
|
||||
|
||||
override fun onMediaItemTransition(mediaItem: MediaItem?, reason: Int) {
|
||||
if (reason == Player.MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED) return
|
||||
upPlayPos()
|
||||
playNext()
|
||||
}
|
||||
|
||||
override fun onPlayerError(error: PlaybackException) {
|
||||
super.onPlayerError(error)
|
||||
AppLog.put("朗读错误\n${contentList[nowSpeak]}", error)
|
||||
|
@ -44,6 +44,7 @@ import io.legado.app.utils.viewbindingdelegate.viewBinding
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.conflate
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
/**
|
||||
@ -204,7 +205,7 @@ class ChangeBookSourceDialog() : BaseDialogFragment(R.layout.dialog_book_change_
|
||||
}
|
||||
}
|
||||
launch {
|
||||
appDb.bookSourceDao.flowEnabledGroups().conflate().collect {
|
||||
appDb.bookSourceDao.flowEnabledGroups().flowOn(IO).conflate().collect {
|
||||
groups.clear()
|
||||
groups.addAll(it)
|
||||
upGroupMenu()
|
||||
|
@ -47,8 +47,10 @@ import io.legado.app.utils.startActivity
|
||||
import io.legado.app.utils.toastOnUi
|
||||
import io.legado.app.utils.viewbindingdelegate.viewBinding
|
||||
import io.legado.app.utils.visible
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.conflate
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
|
||||
@ -230,7 +232,7 @@ class ChangeChapterSourceDialog() : BaseDialogFragment(R.layout.dialog_chapter_c
|
||||
}
|
||||
}
|
||||
launch {
|
||||
appDb.bookSourceDao.flowEnabledGroups().conflate().collect {
|
||||
appDb.bookSourceDao.flowEnabledGroups().flowOn(IO).conflate().collect {
|
||||
groups.clear()
|
||||
groups.addAll(it)
|
||||
upGroupMenu()
|
||||
|
@ -108,7 +108,8 @@ abstract class BaseReadBookActivity :
|
||||
*/
|
||||
fun upSystemUiVisibility(
|
||||
isInMultiWindow: Boolean,
|
||||
toolBarHide: Boolean = true
|
||||
toolBarHide: Boolean = true,
|
||||
useBgMeanColor: Boolean = false
|
||||
) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
window.insetsController?.run {
|
||||
@ -129,7 +130,10 @@ abstract class BaseReadBookActivity :
|
||||
setLightStatusBar(ReadBookConfig.durConfig.curStatusIconDark())
|
||||
} else {
|
||||
val statusBarColor =
|
||||
if (AppConfig.readBarStyleFollowPage && ReadBookConfig.durConfig.curBgType() == 0) {
|
||||
if (AppConfig.readBarStyleFollowPage
|
||||
&& ReadBookConfig.durConfig.curBgType() == 0
|
||||
|| useBgMeanColor
|
||||
) {
|
||||
ReadBookConfig.bgMeanColor
|
||||
} else {
|
||||
ThemeStore.statusBarColor(this, AppConfig.isTransparentStatusBar)
|
||||
@ -184,12 +188,14 @@ abstract class BaseReadBookActivity :
|
||||
width = MATCH_PARENT
|
||||
gravity = Gravity.BOTTOM
|
||||
}
|
||||
|
||||
Gravity.LEFT -> layoutParams =
|
||||
(layoutParams as FrameLayout.LayoutParams).apply {
|
||||
height = MATCH_PARENT
|
||||
width = navigationBarHeight
|
||||
gravity = Gravity.LEFT
|
||||
}
|
||||
|
||||
Gravity.RIGHT -> layoutParams =
|
||||
(layoutParams as FrameLayout.LayoutParams).apply {
|
||||
height = MATCH_PARENT
|
||||
|
@ -1044,7 +1044,7 @@ class ReadBookActivity : BaseReadBookActivity(),
|
||||
* 更新状态栏,导航栏
|
||||
*/
|
||||
override fun upSystemUiVisibility() {
|
||||
upSystemUiVisibility(isInMultiWindow, !menuLayoutIsVisible)
|
||||
upSystemUiVisibility(isInMultiWindow, !menuLayoutIsVisible, bottomDialog > 0)
|
||||
upNavigationBarColor()
|
||||
}
|
||||
|
||||
|
@ -93,7 +93,7 @@ class SpeakEngineDialog(val callBack: CallBack) : BaseDialogFragment(R.layout.di
|
||||
labelSys.visible()
|
||||
cbName.text = "系统默认"
|
||||
cbName.tag = ""
|
||||
cbName.isChecked = ttsEngine == null || ttsEngine!!.toIntOrNull() == null
|
||||
cbName.isChecked = ttsEngine == null || ttsEngine!!.isJsonObject()
|
||||
&& GSON.fromJsonObject<SelectItem<String>>(ttsEngine)
|
||||
.getOrNull()?.value.isNullOrEmpty()
|
||||
cbName.setOnClickListener {
|
||||
|
@ -31,6 +31,7 @@ import io.legado.app.utils.viewbindingdelegate.viewBinding
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.conflate
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import splitties.init.appCtx
|
||||
@ -279,7 +280,7 @@ class SearchActivity : VMBaseActivity<ActivityBookSearchBinding, SearchViewModel
|
||||
adapter.setItems(it)
|
||||
}
|
||||
launch {
|
||||
appDb.bookSourceDao.flowEnabledGroups().collect {
|
||||
appDb.bookSourceDao.flowEnabledGroups().flowOn(IO).collect {
|
||||
groups = it
|
||||
}
|
||||
}
|
||||
|
@ -42,9 +42,11 @@ import io.legado.app.ui.widget.recycler.VerticalDivider
|
||||
import io.legado.app.utils.*
|
||||
import io.legado.app.utils.viewbindingdelegate.viewBinding
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.conflate
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
/**
|
||||
@ -321,7 +323,7 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
|
||||
}
|
||||
}.catch {
|
||||
AppLog.put("书源界面更新书源出错", it)
|
||||
}.conflate().collect { data ->
|
||||
}.flowOn(IO).conflate().collect { data ->
|
||||
adapter.setItems(data, adapter.diffItemCallback)
|
||||
itemTouchCallback.isCanDrag = sort == BookSourceSort.Default
|
||||
delay(500)
|
||||
@ -336,10 +338,11 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
|
||||
|
||||
private fun initLiveDataGroup() {
|
||||
launch {
|
||||
appDb.bookSourceDao.flowGroups().conflate().collect {
|
||||
appDb.bookSourceDao.flowGroups().flowOn(IO).conflate().collect {
|
||||
groups.clear()
|
||||
groups.addAll(it)
|
||||
upGroupMenu()
|
||||
delay(500)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,8 @@ import io.legado.app.utils.applyTint
|
||||
import io.legado.app.utils.requestInputMethod
|
||||
import io.legado.app.utils.setLayout
|
||||
import io.legado.app.utils.viewbindingdelegate.viewBinding
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
|
||||
@ -55,7 +57,7 @@ class GroupManageDialog : BaseDialogFragment(R.layout.dialog_recycler_view),
|
||||
|
||||
private fun initData() {
|
||||
launch {
|
||||
appDb.bookSourceDao.flowGroups().collect {
|
||||
appDb.bookSourceDao.flowGroups().flowOn(IO).collect {
|
||||
adapter.setItems(it)
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ import io.legado.app.model.webBook.WebBook
|
||||
import io.legado.app.service.CacheBookService
|
||||
import io.legado.app.utils.postEvent
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
import java.util.concurrent.CopyOnWriteArraySet
|
||||
import java.util.concurrent.Executors
|
||||
import kotlin.math.min
|
||||
@ -85,9 +86,11 @@ class MainViewModel(application: Application) : BaseViewModel(application) {
|
||||
upTocJob?.cancel()
|
||||
upTocJob = null
|
||||
}
|
||||
|
||||
onUpTocBooks.size < threadCount -> {
|
||||
updateToc()
|
||||
}
|
||||
|
||||
else -> {
|
||||
delay(500)
|
||||
}
|
||||
@ -119,7 +122,7 @@ class MainViewModel(application: Application) : BaseViewModel(application) {
|
||||
}
|
||||
waitUpTocBooks.remove(bookUrl)
|
||||
upTocAdd(bookUrl)
|
||||
execute(context = upTocPool) {
|
||||
execute(context = upTocPool, executeContext = IO) {
|
||||
kotlin.runCatching {
|
||||
val oldBook = book.copy()
|
||||
WebBook.runPreUpdateJs(source, book)
|
||||
|
@ -29,9 +29,11 @@ import io.legado.app.utils.setEdgeEffectColor
|
||||
import io.legado.app.utils.startActivity
|
||||
import io.legado.app.utils.viewbindingdelegate.viewBinding
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.conflate
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
/**
|
||||
@ -107,7 +109,7 @@ class ExploreFragment : VMBaseFragment<ExploreViewModel>(R.layout.fragment_explo
|
||||
|
||||
private fun initGroupData() {
|
||||
launch {
|
||||
appDb.bookSourceDao.flowExploreGroups().conflate().collect {
|
||||
appDb.bookSourceDao.flowExploreGroups().flowOn(IO).conflate().collect {
|
||||
groups.clear()
|
||||
groups.addAll(it)
|
||||
upGroupsMenu()
|
||||
|
@ -11,6 +11,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxLines="1"
|
||||
android:singleLine="true"
|
||||
app:layout_constrainedWidth="true"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0"
|
||||
@ -25,12 +26,13 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp"
|
||||
android:singleLine="true"
|
||||
android:textColor="@color/secondaryText"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintHorizontal_chainStyle="packed"
|
||||
app:layout_constraintLeft_toRightOf="@id/cb_source_name"
|
||||
app:layout_constraintRight_toLeftOf="@id/tv_open"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintHorizontal_chainStyle="packed" />
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_open"
|
||||
|
Loading…
Reference in New Issue
Block a user