From 84bcd426445162c973a9a22376859c9b69fd40de Mon Sep 17 00:00:00 2001 From: Horis <8674809+821938089@users.noreply.github.com> Date: Sat, 24 Aug 2024 15:05:53 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/AndroidManifest.xml | 11 +- .../java/io/legado/app/model/AudioPlay.kt | 311 +++++++++++++----- .../io/legado/app/service/AudioPlayService.kt | 104 ++---- .../app/ui/book/audio/AudioPlayActivity.kt | 44 +-- .../app/ui/book/audio/AudioPlayViewModel.kt | 72 ++-- .../main/res/layout/activity_audio_play.xml | 58 +++- app/src/main/res/layout/dialog_wait.xml | 2 +- 7 files changed, 357 insertions(+), 245 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index a345be4fd..a55fcc8d0 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -4,6 +4,7 @@ + @@ -368,12 +369,12 @@ - - + + - - - + + + diff --git a/app/src/main/java/io/legado/app/model/AudioPlay.kt b/app/src/main/java/io/legado/app/model/AudioPlay.kt index 19c035299..5c1dbcf17 100644 --- a/app/src/main/java/io/legado/app/model/AudioPlay.kt +++ b/app/src/main/java/io/legado/app/model/AudioPlay.kt @@ -1,8 +1,9 @@ package io.legado.app.model +import android.annotation.SuppressLint import android.content.Context import android.content.Intent -import androidx.lifecycle.MutableLiveData +import io.legado.app.constant.AppLog import io.legado.app.constant.EventBus import io.legado.app.constant.IntentAction import io.legado.app.constant.Status @@ -12,84 +13,176 @@ import io.legado.app.data.entities.BookChapter import io.legado.app.data.entities.BookSource import io.legado.app.help.book.ContentProcessor import io.legado.app.help.book.getBookSource +import io.legado.app.help.book.readSimulating import io.legado.app.help.book.simulatedTotalChapterNum import io.legado.app.help.coroutine.Coroutine +import io.legado.app.model.webBook.WebBook import io.legado.app.service.AudioPlayService import io.legado.app.utils.postEvent import io.legado.app.utils.startService +import io.legado.app.utils.toastOnUi +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.MainScope +import kotlinx.coroutines.cancelChildren import splitties.init.appCtx +@SuppressLint("StaticFieldLeak") @Suppress("unused") -object AudioPlay { - var titleData = MutableLiveData() - var coverData = MutableLiveData() +object AudioPlay : CoroutineScope by MainScope() { var status = Status.STOP + private var activityContext: Context? = null + private var serviceContext: Context? = null + private val context: Context get() = activityContext ?: serviceContext ?: appCtx + var callback: CallBack? = null var book: Book? = null + var chapterSize = 0 + var simulatedChapterSize = 0 + var durChapterIndex = 0 + var durChapterPos = 0 var durChapter: BookChapter? = null + var durPlayUrl = "" + var durAudioSize = 0 var inBookshelf = false var bookSource: BookSource? = null val loadingChapters = arrayListOf() - var durChapterIndex = 0 - fun upData(context: Context, book: Book) { + fun upData(book: Book) { AudioPlay.book = book - upDurChapter(book) + chapterSize = appDb.bookChapterDao.getChapterCount(book.bookUrl) + simulatedChapterSize = if (book.readSimulating()) { + book.simulatedTotalChapterNum() + } else { + chapterSize + } if (durChapterIndex != book.durChapterIndex) { durChapterIndex = book.durChapterIndex - playNew(context) + durChapterPos = book.durChapterPos + durPlayUrl = "" + durAudioSize = 0 + } + upDurChapter() + } + + fun resetData(book: Book) { + stop() + AudioPlay.book = book + chapterSize = appDb.bookChapterDao.getChapterCount(book.bookUrl) + simulatedChapterSize = if (book.readSimulating()) { + book.simulatedTotalChapterNum() + } else { + chapterSize + } + bookSource = book.getBookSource() + durChapterIndex = book.durChapterIndex + durChapterPos = book.durChapterPos + durPlayUrl = "" + durAudioSize = 0 + upDurChapter() + } + + private fun addLoading(index: Int): Boolean { + synchronized(this) { + if (loadingChapters.contains(index)) return false + loadingChapters.add(index) + return true } } - fun resetData(context: Context, book: Book) { - stop(context) - AudioPlay.book = book - titleData.postValue(book.name) - coverData.postValue(book.getDisplayCover()) - bookSource = book.getBookSource() - durChapterIndex = book.durChapterIndex - upDurChapter(book) + private fun removeLoading(index: Int) { + synchronized(this) { + loadingChapters.remove(index) + } + } + + fun loadOrUpPlayUrl() { + if (durPlayUrl.isEmpty()) { + loadPlayUrl() + } else { + upPlayUrl() + } + } + + /** + * 加载播放URL + */ + private fun loadPlayUrl() { + val index = durChapterIndex + if (addLoading(index)) { + val book = book + val bookSource = bookSource + if (book != null && bookSource != null) { + upDurChapter() + val chapter = durChapter + if (chapter == null) { + removeLoading(index) + return + } + upLoading(true) + WebBook.getContent(this, bookSource, book, chapter) + .onSuccess { content -> + if (content.isEmpty()) { + appCtx.toastOnUi("未获取到资源链接") + } else { + contentLoadFinish(chapter, content) + } + }.onError { + AppLog.put("获取资源链接出错\n$it", it, true) + }.onFinally { + removeLoading(index) + } + } else { + removeLoading(index) + appCtx.toastOnUi("book or source is null") + } + } + } + + /** + * 加载完成 + */ + private fun contentLoadFinish(chapter: BookChapter, content: String) { + if (chapter.index == book?.durChapterIndex) { + durPlayUrl = content + upPlayUrl() + } + } + + private fun upPlayUrl() { + if (isPlayToEnd()) { + playNew() + } else { + play() + } } /** * 播放当前章节 */ - fun play(context: Context) { - book?.let { - if (durChapter == null) { - upDurChapter(it) - } - durChapter?.let { - context.startService { - action = IntentAction.play - } - } + fun play() { + context.startService { + action = IntentAction.play } } /** * 从头播放新章节 */ - fun playNew(context: Context) { - book?.let { - if (durChapter == null) { - upDurChapter(it) - } - durChapter?.let { - context.startService { - action = IntentAction.playNew - } - } + private fun playNew() { + context.startService { + action = IntentAction.playNew } } /** * 更新当前章节 */ - fun upDurChapter(book: Book) { - durChapter = appDb.bookChapterDao.getChapter(book.bookUrl, book.durChapterIndex) + fun upDurChapter() { + val book = book ?: return + durChapter = appDb.bookChapterDao.getChapter(book.bookUrl, durChapterIndex) + durAudioSize = durChapter?.end?.toInt() ?: 0 postEvent(EventBus.AUDIO_SUB_TITLE, durChapter?.title ?: "") - postEvent(EventBus.AUDIO_SIZE, durChapter?.end?.toInt() ?: 0) - postEvent(EventBus.AUDIO_PROGRESS, book.durChapterPos) + postEvent(EventBus.AUDIO_SIZE, durAudioSize) + postEvent(EventBus.AUDIO_PROGRESS, durChapterPos) } fun pause(context: Context) { @@ -108,7 +201,7 @@ object AudioPlay { } } - fun stop(context: Context) { + fun stop() { if (AudioPlayService.isRun) { context.startService { action = IntentAction.stop @@ -116,7 +209,7 @@ object AudioPlay { } } - fun adjustSpeed(context: Context, adjust: Float) { + fun adjustSpeed(adjust: Float) { if (AudioPlayService.isRun) { context.startService { action = IntentAction.adjustSpeed @@ -125,7 +218,9 @@ object AudioPlay { } } - fun adjustProgress(context: Context, position: Int) { + fun adjustProgress(position: Int) { + durChapterPos = position + saveRead() if (AudioPlayService.isRun) { context.startService { action = IntentAction.adjustProgress @@ -134,57 +229,47 @@ object AudioPlay { } } - fun skipTo(context: Context, index: Int) { + fun skipTo(index: Int) { Coroutine.async { - book?.let { book -> - book.durChapterIndex = index - book.durChapterPos = 0 - durChapterIndex = book.durChapterIndex - durChapter = null + stop() + durChapterIndex = index + durChapterPos = 0 + durPlayUrl = "" + saveRead() + loadPlayUrl() + } + } + + fun prev() { + Coroutine.async { + stop() + if (durChapterIndex > 0) { + durChapterIndex -= 1 + durChapterPos = 0 + durPlayUrl = "" saveRead() - playNew(context) + loadPlayUrl() } } } - fun prev(context: Context) { - Coroutine.async { - book?.let { book -> - if (book.durChapterIndex > 0) { - book.durChapterIndex -= 1 - book.durChapterPos = 0 - durChapterIndex = book.durChapterIndex - durChapter = null - saveRead() - play(context) - } else { - stop(context) - } - } - } - } - - fun next(context: Context) { - book?.let { book -> - if (book.durChapterIndex + 1 < book.simulatedTotalChapterNum()) { - book.durChapterIndex += 1 - book.durChapterPos = 0 - durChapterIndex = book.durChapterIndex - durChapter = null - saveRead() - play(context) - } else { - stop(context) - } + fun next() { + stop() + if (durChapterIndex + 1 < simulatedChapterSize) { + durChapterIndex += 1 + durChapterPos = 0 + durPlayUrl = "" + saveRead() + loadPlayUrl() } } fun setTimer(minute: Int) { if (AudioPlayService.isRun) { - val intent = Intent(appCtx, AudioPlayService::class.java) + val intent = Intent(context, AudioPlayService::class.java) intent.action = IntentAction.setTimer intent.putExtra("minute", minute) - appCtx.startService(intent) + context.startService(intent) } else { AudioPlayService.timeMinute = minute postEvent(EventBus.AUDIO_DS, minute) @@ -192,24 +277,28 @@ object AudioPlay { } fun addTimer() { - val intent = Intent(appCtx, AudioPlayService::class.java) + val intent = Intent(context, AudioPlayService::class.java) intent.action = IntentAction.addTimer - appCtx.startService(intent) + context.startService(intent) } fun saveRead() { - book?.let { book -> + val book = book ?: return + Coroutine.async { book.lastCheckCount = 0 book.durChapterTime = System.currentTimeMillis() - Coroutine.async { + val chapterChanged = book.durChapterIndex != durChapterIndex + book.durChapterIndex = durChapterIndex + book.durChapterPos = durChapterPos + if (chapterChanged) { appDb.bookChapterDao.getChapter(book.bookUrl, book.durChapterIndex)?.let { book.durChapterTitle = it.getDisplayTitle( ContentProcessor.get(book.name, book.origin).getTitleReplaceRules(), book.getUseReplaceRule() ) } - book.update() } + book.update() } } @@ -217,11 +306,53 @@ object AudioPlay { * 保存章节长度 */ fun saveDurChapter(audioSize: Long) { + val chapter = durChapter ?: return Coroutine.async { - durChapter?.let { - it.end = audioSize - appDb.bookChapterDao.update(it) - } + durAudioSize = audioSize.toInt() + chapter.end = audioSize + appDb.bookChapterDao.update(chapter) } } + + fun playPositionChanged(position: Int) { + durChapterPos = position + saveRead() + } + + fun upLoading(loading: Boolean) { + callback?.upLoading(loading) + } + + private fun isPlayToEnd(): Boolean { + return durChapterIndex + 1 == simulatedChapterSize + && durChapterPos == durAudioSize + } + + fun register(context: Context) { + activityContext = context + callback = context as CallBack + } + + fun unregister(context: Context) { + if (activityContext === context) { + activityContext = null + callback = null + } + coroutineContext.cancelChildren() + } + + fun registerService(context: Context) { + serviceContext = context + } + + fun unregisterService() { + serviceContext = null + } + + interface CallBack { + + fun upLoading(loading: Boolean) + + } + } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/service/AudioPlayService.kt b/app/src/main/java/io/legado/app/service/AudioPlayService.kt index db07ad1c9..32a780e60 100644 --- a/app/src/main/java/io/legado/app/service/AudioPlayService.kt +++ b/app/src/main/java/io/legado/app/service/AudioPlayService.kt @@ -29,16 +29,12 @@ import io.legado.app.constant.EventBus import io.legado.app.constant.IntentAction import io.legado.app.constant.NotificationId import io.legado.app.constant.Status -import io.legado.app.data.appDb -import io.legado.app.data.entities.Book -import io.legado.app.data.entities.BookChapter import io.legado.app.help.MediaHelp import io.legado.app.help.config.AppConfig import io.legado.app.help.exoplayer.ExoPlayerHelper import io.legado.app.help.glide.ImageLoader import io.legado.app.model.AudioPlay import io.legado.app.model.analyzeRule.AnalyzeUrl -import io.legado.app.model.webBook.WebBook import io.legado.app.receiver.MediaButtonReceiver import io.legado.app.ui.book.audio.AudioPlayActivity import io.legado.app.utils.activityPendingIntent @@ -122,6 +118,7 @@ class AudioPlayService : BaseService(), super.onCreate() isRun = true exoPlayer.addListener(this) + AudioPlay.registerService(this) initMediaSession() initBroadcastReceiver() upMediaSessionPlaybackState(PlaybackStateCompat.STATE_PLAYING) @@ -147,7 +144,8 @@ class AudioPlayService : BaseService(), upPlayProgressJob?.cancel() pause = false position = AudioPlay.book?.durChapterPos ?: 0 - loadContent() + url = AudioPlay.durPlayUrl + play() } IntentAction.playNew -> { @@ -155,13 +153,14 @@ class AudioPlayService : BaseService(), upPlayProgressJob?.cancel() pause = false position = 0 - loadContent() + url = AudioPlay.durPlayUrl + play() } IntentAction.pause -> pause() IntentAction.resume -> resume() - IntentAction.prev -> AudioPlay.prev(this) - IntentAction.next -> AudioPlay.next(this) + IntentAction.prev -> AudioPlay.prev() + IntentAction.next -> AudioPlay.next() IntentAction.adjustSpeed -> upSpeed(intent.getFloatExtra("adjust", 1f)) IntentAction.addTimer -> addTimer() IntentAction.setTimer -> setTimer(intent.getIntExtra("minute", 0)) @@ -189,6 +188,7 @@ class AudioPlayService : BaseService(), upMediaSessionPlaybackState(PlaybackStateCompat.STATE_STOPPED) AudioPlay.status = Status.STOP postEvent(EventBus.AUDIO_STATE, Status.STOP) + AudioPlay.unregisterService() } /** @@ -216,6 +216,7 @@ class AudioPlayService : BaseService(), ) exoPlayer.setMediaItem(analyzeUrl.getMediaItem()) exoPlayer.playWhenReady = true + exoPlayer.seekTo(position.toLong()) exoPlayer.prepare() }.onError { AppLog.put("播放出错\n${it.localizedMessage}", it) @@ -261,7 +262,7 @@ class AudioPlayService : BaseService(), try { pause = false if (url.isEmpty()) { - loadContent() + AudioPlay.loadOrUpPlayUrl() return } if (!exoPlayer.isPlaying) { @@ -317,9 +318,7 @@ class AudioPlayService : BaseService(), Player.STATE_READY -> { // 准备好 - if (exoPlayer.currentPosition != position.toLong()) { - exoPlayer.seekTo(position.toLong()) - } + AudioPlay.upLoading(false) if (exoPlayer.playWhenReady) { AudioPlay.status = Status.PLAY postEvent(EventBus.AUDIO_STATE, Status.PLAY) @@ -336,7 +335,8 @@ class AudioPlayService : BaseService(), Player.STATE_ENDED -> { // 结束 upPlayProgressJob?.cancel() - AudioPlay.next(this) + AudioPlay.playPositionChanged(exoPlayer.duration.toInt()) + AudioPlay.next() } } upAudioPlayNotification() @@ -395,7 +395,7 @@ class AudioPlayService : BaseService(), timeMinute-- } if (timeMinute == 0) { - AudioPlay.stop(this@AudioPlayService) + AudioPlay.stop() } } postEvent(EventBus.AUDIO_DS, timeMinute) @@ -411,81 +411,16 @@ class AudioPlayService : BaseService(), upPlayProgressJob?.cancel() upPlayProgressJob = lifecycleScope.launch { while (isActive) { - AudioPlay.book?.let { - //更新buffer位置 - postEvent(EventBus.AUDIO_BUFFER_PROGRESS, exoPlayer.bufferedPosition.toInt()) - it.durChapterPos = exoPlayer.currentPosition.toInt() - postEvent(EventBus.AUDIO_PROGRESS, it.durChapterPos) - upMediaSessionPlaybackState(PlaybackStateCompat.STATE_PLAYING) - saveProgress(it) - } + //更新buffer位置 + AudioPlay.playPositionChanged(exoPlayer.currentPosition.toInt()) + postEvent(EventBus.AUDIO_BUFFER_PROGRESS, exoPlayer.bufferedPosition.toInt()) + postEvent(EventBus.AUDIO_PROGRESS, AudioPlay.durChapterPos) + upMediaSessionPlaybackState(PlaybackStateCompat.STATE_PLAYING) delay(1000) } } } - /** - * 加载播放URL - */ - private fun loadContent() = with(AudioPlay) { - durChapter?.let { chapter -> - if (addLoading(chapter.index)) { - val book = AudioPlay.book - val bookSource = AudioPlay.bookSource - if (book != null && bookSource != null) { - WebBook.getContent(lifecycleScope, bookSource, book, chapter) - .onSuccess { content -> - if (content.isEmpty()) { - toastOnUi("未获取到资源链接") - } else { - contentLoadFinish(chapter, content) - } - }.onError { - contentLoadFinish(chapter, it.localizedMessage ?: toString()) - }.onFinally { - removeLoading(chapter.index) - } - } else { - removeLoading(chapter.index) - toastOnUi("book or source is null") - } - } - } - } - - private fun addLoading(index: Int): Boolean { - synchronized(this) { - if (AudioPlay.loadingChapters.contains(index)) return false - AudioPlay.loadingChapters.add(index) - return true - } - } - - private fun removeLoading(index: Int) { - synchronized(this) { - AudioPlay.loadingChapters.remove(index) - } - } - - /** - * 加载完成 - */ - private fun contentLoadFinish(chapter: BookChapter, content: String) { - if (chapter.index == AudioPlay.book?.durChapterIndex) { - url = content - play() - } - } - - /** - * 保存播放进度 - */ - private fun saveProgress(book: Book) { - execute { - appDb.bookDao.upProgress(book.bookUrl, book.durChapterPos) - } - } - /** * 更新媒体状态 */ @@ -584,7 +519,6 @@ class AudioPlayService : BaseService(), AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> { AppLog.put("音频焦点暂时丢失并会很快再次获得,暂停播放") - needResumeOnAudioFocusGain = true if (!pause) { needResumeOnAudioFocusGain = true pause(false) diff --git a/app/src/main/java/io/legado/app/ui/book/audio/AudioPlayActivity.kt b/app/src/main/java/io/legado/app/ui/book/audio/AudioPlayActivity.kt index d324afcf7..bd21808f1 100644 --- a/app/src/main/java/io/legado/app/ui/book/audio/AudioPlayActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/audio/AudioPlayActivity.kt @@ -24,7 +24,6 @@ import io.legado.app.data.entities.BookSource import io.legado.app.databinding.ActivityAudioPlayBinding import io.legado.app.help.book.isAudio import io.legado.app.help.book.removeType -import io.legado.app.help.book.simulatedTotalChapterNum import io.legado.app.help.config.AppConfig import io.legado.app.lib.dialogs.alert import io.legado.app.model.AudioPlay @@ -59,7 +58,8 @@ import java.util.Locale @SuppressLint("ObsoleteSdkInt") class AudioPlayActivity : VMBaseActivity(toolBarTheme = Theme.Dark), - ChangeBookSourceDialog.CallBack { + ChangeBookSourceDialog.CallBack, + AudioPlay.CallBack { override val binding by viewBinding(ActivityAudioPlayBinding::inflate) override val viewModel by viewModels() @@ -78,7 +78,7 @@ class AudioPlayActivity : if (it.first != AudioPlay.book?.durChapterIndex || it.second == 0 ) { - AudioPlay.skipTo(this, it.first) + AudioPlay.skipTo(it.first) } } } @@ -91,10 +91,11 @@ class AudioPlayActivity : override fun onActivityCreated(savedInstanceState: Bundle?) { binding.titleBar.setBackgroundResource(R.color.transparent) - AudioPlay.titleData.observe(this) { + AudioPlay.register(this) + viewModel.titleData.observe(this) { binding.titleBar.title = it } - AudioPlay.coverData.observe(this) { + viewModel.coverData.observe(this) { upCover(it) } viewModel.initData(intent) @@ -143,13 +144,13 @@ class AudioPlayActivity : playButton() } binding.fabPlayStop.onLongClick { - AudioPlay.stop(this@AudioPlayActivity) + AudioPlay.stop() } binding.ivSkipNext.setOnClickListener { - AudioPlay.next(this@AudioPlayActivity) + AudioPlay.next() } binding.ivSkipPrevious.setOnClickListener { - AudioPlay.prev(this@AudioPlayActivity) + AudioPlay.prev() } binding.playerProgress.setOnSeekBarChangeListener(object : SeekBarChangeListener { override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) { @@ -162,7 +163,7 @@ class AudioPlayActivity : override fun onStopTrackingTouch(seekBar: SeekBar) { adjustProgress = false - AudioPlay.adjustProgress(this@AudioPlayActivity, seekBar.progress) + AudioPlay.adjustProgress(seekBar.progress) } }) binding.ivChapter.setOnClickListener { @@ -175,10 +176,10 @@ class AudioPlayActivity : binding.ivFastForward.invisible() } binding.ivFastForward.setOnClickListener { - AudioPlay.adjustSpeed(this@AudioPlayActivity, 0.1f) + AudioPlay.adjustSpeed(0.1f) } binding.ivFastRewind.setOnClickListener { - AudioPlay.adjustSpeed(this@AudioPlayActivity, -0.1f) + AudioPlay.adjustSpeed(-0.1f) } binding.ivTimer.setOnClickListener { timerSliderPopup.showAsDropDown(it, 0, (-100).dpToPx(), Gravity.TOP) @@ -196,7 +197,7 @@ class AudioPlayActivity : when (AudioPlay.status) { Status.PLAY -> AudioPlay.pause(this) Status.PAUSE -> AudioPlay.resume(this) - else -> AudioPlay.play(this) + else -> AudioPlay.loadOrUpPlayUrl() } } @@ -207,7 +208,7 @@ class AudioPlayActivity : if (book.isAudio) { viewModel.changeTo(source, book, toc) } else { - AudioPlay.stop(this) + AudioPlay.stop() lifecycleScope.launch { withContext(IO) { AudioPlay.book?.migrateTo(book, toc) @@ -247,8 +248,9 @@ class AudioPlayActivity : override fun onDestroy() { super.onDestroy() if (AudioPlay.status != Status.PLAY) { - AudioPlay.stop(this) + AudioPlay.stop() } + AudioPlay.unregister(this) } @SuppressLint("SetTextI18n") @@ -268,11 +270,9 @@ class AudioPlayActivity : } observeEventSticky(EventBus.AUDIO_SUB_TITLE) { binding.tvSubTitle.text = it - AudioPlay.book?.let { book -> - binding.ivSkipPrevious.isEnabled = book.durChapterIndex > 0 - binding.ivSkipNext.isEnabled = - book.durChapterIndex < book.simulatedTotalChapterNum() - 1 - } + binding.ivSkipPrevious.isEnabled = AudioPlay.durChapterIndex > 0 + binding.ivSkipNext.isEnabled = + AudioPlay.durChapterIndex < AudioPlay.simulatedChapterSize - 1 } observeEventSticky(EventBus.AUDIO_SIZE) { binding.playerProgress.max = it @@ -296,4 +296,10 @@ class AudioPlayActivity : } } + override fun upLoading(loading: Boolean) { + runOnUiThread { + binding.progressLoading.visible(loading) + } + } + } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/book/audio/AudioPlayViewModel.kt b/app/src/main/java/io/legado/app/ui/book/audio/AudioPlayViewModel.kt index b2b6d60a9..a85438906 100644 --- a/app/src/main/java/io/legado/app/ui/book/audio/AudioPlayViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/audio/AudioPlayViewModel.kt @@ -2,9 +2,10 @@ package io.legado.app.ui.book.audio import android.app.Application import android.content.Intent -import androidx.lifecycle.viewModelScope +import androidx.lifecycle.MutableLiveData import io.legado.app.R import io.legado.app.base.BaseViewModel +import io.legado.app.constant.AppLog import io.legado.app.constant.BookType import io.legado.app.constant.EventBus import io.legado.app.data.appDb @@ -13,14 +14,15 @@ import io.legado.app.data.entities.BookChapter import io.legado.app.data.entities.BookSource import io.legado.app.help.book.getBookSource import io.legado.app.help.book.removeType +import io.legado.app.help.book.simulatedTotalChapterNum import io.legado.app.model.AudioPlay -import io.legado.app.model.AudioPlay.durChapter import io.legado.app.model.webBook.WebBook import io.legado.app.utils.postEvent import io.legado.app.utils.toastOnUi -import kotlinx.coroutines.Dispatchers.IO class AudioPlayViewModel(application: Application) : BaseViewModel(application) { + val titleData = MutableLiveData() + val coverData = MutableLiveData() fun initData(intent: Intent) = AudioPlay.apply { execute { @@ -33,37 +35,53 @@ class AudioPlayViewModel(application: Application) : BaseViewModel(application) } } - private fun initBook(book: Book) { + private suspend fun initBook(book: Book) { val isSameBook = AudioPlay.book?.bookUrl == book.bookUrl if (isSameBook) { - AudioPlay.upData(context, book) + AudioPlay.upData(book) } else { - AudioPlay.resetData(context, book) + AudioPlay.resetData(book) } - if (durChapter == null) { - if (book.tocUrl.isEmpty()) { - loadBookInfo(book) + titleData.postValue(book.name) + coverData.postValue(book.getDisplayCover()) + if (book.tocUrl.isEmpty() && !loadBookInfo(book)) { + return + } + if (AudioPlay.chapterSize == 0 && !loadChapterList(book)) { + return + } + } + + private suspend fun loadBookInfo(book: Book): Boolean { + val bookSource = AudioPlay.bookSource ?: return true + try { + WebBook.getBookInfoAwait(bookSource, book) + return true + } catch (e: Exception) { + AppLog.put("详情页出错: ${e.localizedMessage}", e, true) + return false + } + } + + private suspend fun loadChapterList(book: Book): Boolean { + val bookSource = AudioPlay.bookSource ?: return true + try { + val oldBook = book.copy() + val cList = WebBook.getChapterListAwait(bookSource, book).getOrThrow() + if (oldBook.bookUrl == book.bookUrl) { + appDb.bookDao.update(book) } else { - loadChapterList(book) + appDb.bookDao.insert(book) } - } - } - - private fun loadBookInfo(book: Book) { - val bookSource = AudioPlay.bookSource ?: return - WebBook.getBookInfo(viewModelScope, bookSource, book).onSuccess(IO) { - loadChapterList(book) - } - } - - private fun loadChapterList(book: Book) { - val bookSource = AudioPlay.bookSource ?: return - WebBook.getChapterList(viewModelScope, bookSource, book).onSuccess(IO) { cList -> - book.save() + appDb.bookChapterDao.delByBook(book.bookUrl) appDb.bookChapterDao.insert(*cList.toTypedArray()) - AudioPlay.upDurChapter(book) - }.onError { + AudioPlay.chapterSize = cList.size + AudioPlay.simulatedChapterSize = book.simulatedTotalChapterNum() + AudioPlay.upDurChapter() + return true + } catch (e: Exception) { context.toastOnUi(R.string.error_load_toc) + return false } } @@ -83,7 +101,7 @@ class AudioPlayViewModel(application: Application) : BaseViewModel(application) AudioPlay.book = book AudioPlay.bookSource = source appDb.bookChapterDao.insert(*toc.toTypedArray()) - AudioPlay.upDurChapter(book) + AudioPlay.upDurChapter() }.onFinally { postEvent(EventBus.SOURCE_CHANGED, book.bookUrl) } diff --git a/app/src/main/res/layout/activity_audio_play.xml b/app/src/main/res/layout/activity_audio_play.xml index 17b4822e2..7aa5d6f69 100644 --- a/app/src/main/res/layout/activity_audio_play.xml +++ b/app/src/main/res/layout/activity_audio_play.xml @@ -130,9 +130,9 @@ android:id="@+id/iv_timer" android:layout_width="46dp" android:layout_height="46dp" - android:padding="5dp" android:background="@drawable/selector_circle_btn_bg" android:contentDescription="@string/set_timer" + android:padding="5dp" android:src="@drawable/ic_timer_black_24dp" app:tint="@color/md_white_1000" tools:ignore="ImageContrastCheck" /> @@ -146,9 +146,9 @@ android:id="@+id/iv_fast_rewind" android:layout_width="46dp" android:layout_height="46dp" - android:padding="5dp" android:background="@drawable/selector_circle_btn_bg" android:contentDescription="@string/skip_previous" + android:padding="5dp" android:src="@drawable/ic_fast_rewind" app:tint="@color/md_white_1000" tools:ignore="ImageContrastCheck" /> @@ -162,34 +162,56 @@ android:id="@+id/iv_skip_previous" android:layout_width="46dp" android:layout_height="46dp" - android:padding="5dp" android:background="@drawable/selector_circle_btn_bg" android:contentDescription="@string/skip_previous" + android:padding="5dp" android:src="@drawable/ic_skip_previous" app:tint="@color/md_white_1000" tools:ignore="ImageContrastCheck" /> - + android:layout_height="wrap_content"> + + + + + + @@ -203,9 +225,9 @@ android:id="@+id/iv_fast_forward" android:layout_width="46dp" android:layout_height="46dp" - android:padding="5dp" android:background="@drawable/selector_circle_btn_bg" android:contentDescription="@string/skip_next" + android:padding="5dp" android:src="@drawable/ic_fast_forward" app:tint="@color/md_white_1000" tools:ignore="ImageContrastCheck" /> @@ -219,9 +241,9 @@ android:id="@+id/iv_chapter" android:layout_width="46dp" android:layout_height="46dp" - android:padding="5dp" android:background="@drawable/selector_circle_btn_bg" android:contentDescription="@string/chapter_list" + android:padding="5dp" android:src="@drawable/ic_chapter_list" app:tint="@color/md_white_1000" tools:ignore="ImageContrastCheck" /> diff --git a/app/src/main/res/layout/dialog_wait.xml b/app/src/main/res/layout/dialog_wait.xml index bc490a506..9b7e3009e 100644 --- a/app/src/main/res/layout/dialog_wait.xml +++ b/app/src/main/res/layout/dialog_wait.xml @@ -7,7 +7,7 @@ android:padding="20dp" android:orientation="horizontal"> -