diff --git a/app/src/main/java/io/legado/app/help/TTS.kt b/app/src/main/java/io/legado/app/help/TTS.kt index 5807e8468..70b819371 100644 --- a/app/src/main/java/io/legado/app/help/TTS.kt +++ b/app/src/main/java/io/legado/app/help/TTS.kt @@ -17,10 +17,14 @@ class TTS { private val clearTtsRunnable = Runnable { clearTts() } + private var speakStateListener: SpeakStateListener? = null + private var textToSpeech: TextToSpeech? = null private var text: String? = null + private var onInit = false + private val initListener by lazy { InitListener() } @@ -29,17 +33,40 @@ class TTS { TTSUtteranceListener() } + val isSpeaking: Boolean + get() { + return textToSpeech?.isSpeaking ?: false + } + + @Suppress("unused") + fun setSpeakStateListener(speakStateListener: SpeakStateListener) { + this.speakStateListener = speakStateListener + } + + @Suppress("unused") + fun removeSpeakStateListener() { + speakStateListener = null + } + @Synchronized fun speak(text: String) { handler.removeCallbacks(clearTtsRunnable) this.text = text + if (onInit) { + return + } if (textToSpeech == null) { + onInit = true textToSpeech = TextToSpeech(appCtx, initListener) } else { addTextToSpeakList() } } + fun stop() { + textToSpeech?.stop() + } + @Synchronized fun clearTts() { textToSpeech?.let { tts -> @@ -80,6 +107,7 @@ class TTS { } else { appCtx.toastOnUi(R.string.tts_init_failed) } + onInit = false } } @@ -92,11 +120,13 @@ class TTS { override fun onStart(utteranceId: String?) { //开始朗读取消释放资源任务 handler.removeCallbacks(clearTtsRunnable) + speakStateListener?.onStart() } override fun onDone(utteranceId: String?) { //一分钟没有朗读释放资源 handler.postDelayed(clearTtsRunnable, 60000L) + speakStateListener?.onDone() } @Deprecated("Deprecated in Java") @@ -105,4 +135,9 @@ class TTS { } } + + interface SpeakStateListener { + fun onStart() + fun onDone() + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt index f8685da13..604f449e3 100644 --- a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt @@ -267,16 +267,15 @@ class ReadRssActivity : VMBaseActivity @SuppressLint("SetJavaScriptEnabled") private fun readAloud() { - if (viewModel.textToSpeech?.isSpeaking == true) { - viewModel.textToSpeech?.stop() + if (viewModel.tts?.isSpeaking == true) { + viewModel.tts?.stop() upTtsMenu(false) } else { binding.webView.settings.javaScriptEnabled = true binding.webView.evaluateJavascript("document.documentElement.outerHTML") { val html = StringEscapeUtils.unescapeJson(it) .replace("^\"|\"$".toRegex(), "") - Jsoup.parse(html).text() - viewModel.readAloud(Jsoup.parse(html).textArray()) + viewModel.readAloud(Jsoup.parse(html).textArray().joinToString("\n")) } } } diff --git a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt index dd1f18116..4be195970 100644 --- a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt @@ -3,20 +3,18 @@ package io.legado.app.ui.rss.read import android.app.Application import android.content.Intent import android.net.Uri -import android.speech.tts.TextToSpeech -import android.speech.tts.UtteranceProgressListener import android.util.Base64 import android.webkit.URLUtil import androidx.documentfile.provider.DocumentFile import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope -import io.legado.app.R import io.legado.app.base.BaseViewModel import io.legado.app.constant.AppConst import io.legado.app.data.appDb import io.legado.app.data.entities.RssArticle import io.legado.app.data.entities.RssSource import io.legado.app.data.entities.RssStar +import io.legado.app.help.TTS import io.legado.app.help.http.newCallResponseBody import io.legado.app.help.http.okHttpClient import io.legado.app.model.analyzeRule.AnalyzeUrl @@ -27,17 +25,14 @@ import java.io.File import java.util.* -class ReadRssViewModel(application: Application) : BaseViewModel(application), - TextToSpeech.OnInitListener { +class ReadRssViewModel(application: Application) : BaseViewModel(application) { var callBack: CallBack? = null var rssSource: RssSource? = null var rssArticle: RssArticle? = null + var tts: TTS? = null val contentLiveData = MutableLiveData() val urlLiveData = MutableLiveData() var rssStar: RssStar? = null - var textToSpeech: TextToSpeech? = null - private var ttsInitFinish = false - private var ttsTextList = arrayListOf() fun initData(intent: Intent) { execute { @@ -192,59 +187,26 @@ class ReadRssViewModel(application: Application) : BaseViewModel(application), } @Synchronized - override fun onInit(status: Int) { - if (status == TextToSpeech.SUCCESS) { - textToSpeech?.setOnUtteranceProgressListener(TTSUtteranceListener()) - ttsInitFinish = true - play() - } else { - context.toastOnUi(R.string.tts_init_failed) - } - } - - @Synchronized - private fun play() { - if (!ttsInitFinish) return - textToSpeech?.stop() - ttsTextList.forEach { - textToSpeech?.speak(it, TextToSpeech.QUEUE_ADD, null, "rss") - } - } + fun readAloud(text: String) { + if (tts == null) { + tts = TTS().apply { + setSpeakStateListener(object : TTS.SpeakStateListener { + override fun onStart() { + callBack?.upTtsMenu(true) + } - fun readAloud(textArray: Array) { - ttsTextList.clear() - ttsTextList.addAll(textArray) - textToSpeech?.let { - play() - } ?: let { - textToSpeech = TextToSpeech(context, this) + override fun onDone() { + callBack?.upTtsMenu(false) + } + }) + } } + tts?.speak(text) } override fun onCleared() { super.onCleared() - textToSpeech?.stop() - textToSpeech?.shutdown() - } - - /** - * 朗读监听 - */ - private inner class TTSUtteranceListener : UtteranceProgressListener() { - - override fun onStart(s: String) { - callBack?.upTtsMenu(true) - } - - override fun onDone(s: String) { - callBack?.upTtsMenu(false) - } - - @Deprecated("Deprecated in Java") - override fun onError(s: String) { - - } - + tts?.clearTts() } interface CallBack {