优化
This commit is contained in:
@@ -29,6 +29,8 @@ import io.legado.app.ui.book.read.ReadBookActivity
|
|||||||
import io.legado.app.ui.book.read.page.entities.TextChapter
|
import io.legado.app.ui.book.read.page.entities.TextChapter
|
||||||
import io.legado.app.utils.*
|
import io.legado.app.utils.*
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
|
import kotlinx.coroutines.Dispatchers.IO
|
||||||
|
import kotlinx.coroutines.Dispatchers.Main
|
||||||
import splitties.init.appCtx
|
import splitties.init.appCtx
|
||||||
import splitties.systemservices.audioManager
|
import splitties.systemservices.audioManager
|
||||||
import splitties.systemservices.powerManager
|
import splitties.systemservices.powerManager
|
||||||
@@ -71,7 +73,7 @@ abstract class BaseReadAloudService : BaseService(),
|
|||||||
private val mediaSessionCompat: MediaSessionCompat by lazy {
|
private val mediaSessionCompat: MediaSessionCompat by lazy {
|
||||||
MediaSessionCompat(this, "readAloud")
|
MediaSessionCompat(this, "readAloud")
|
||||||
}
|
}
|
||||||
internal val contentList = arrayListOf<String>()
|
internal var contentList = emptyList<String>()
|
||||||
internal var nowSpeak: Int = 0
|
internal var nowSpeak: Int = 0
|
||||||
internal var readAloudNumber: Int = 0
|
internal var readAloudNumber: Int = 0
|
||||||
internal var textChapter: TextChapter? = null
|
internal var textChapter: TextChapter? = null
|
||||||
@@ -132,6 +134,7 @@ abstract class BaseReadAloudService : BaseService(),
|
|||||||
intent.getIntExtra("pageIndex", ReadBook.durPageIndex),
|
intent.getIntExtra("pageIndex", ReadBook.durPageIndex),
|
||||||
intent.getIntExtra("startPos", 0)
|
intent.getIntExtra("startPos", 0)
|
||||||
)
|
)
|
||||||
|
|
||||||
IntentAction.pause -> pauseReadAloud()
|
IntentAction.pause -> pauseReadAloud()
|
||||||
IntentAction.resume -> resumeReadAloud()
|
IntentAction.resume -> resumeReadAloud()
|
||||||
IntentAction.upTtsSpeechRate -> upSpeechRate(true)
|
IntentAction.upTtsSpeechRate -> upSpeechRate(true)
|
||||||
@@ -144,20 +147,17 @@ abstract class BaseReadAloudService : BaseService(),
|
|||||||
return super.onStartCommand(intent, flags, startId)
|
return super.onStartCommand(intent, flags, startId)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun newReadAloud(play: Boolean, pageIndex: Int, startPos: Int) {
|
private fun newReadAloud(play: Boolean, pageIndex: Int, startPos: Int) = launch(IO) {
|
||||||
this.pageIndex = pageIndex
|
this@BaseReadAloudService.pageIndex = pageIndex
|
||||||
textChapter = ReadBook.curTextChapter
|
textChapter = ReadBook.curTextChapter
|
||||||
textChapter?.let { textChapter ->
|
val textChapter = textChapter ?: return@launch
|
||||||
nowSpeak = 0
|
nowSpeak = 0
|
||||||
readAloudNumber = textChapter.getReadLength(pageIndex) + startPos
|
readAloudNumber = textChapter.getReadLength(pageIndex) + startPos
|
||||||
contentList.clear()
|
|
||||||
val readAloudByPage = getPrefBoolean(PreferKey.readAloudByPage)
|
val readAloudByPage = getPrefBoolean(PreferKey.readAloudByPage)
|
||||||
textChapter.getNeedReadAloud(pageIndex, readAloudByPage, startPos)
|
contentList = textChapter.getNeedReadAloud(pageIndex, readAloudByPage, startPos)
|
||||||
.split("\n").forEach { text ->
|
.split("\n")
|
||||||
if (text.isNotEmpty()) {
|
.filter { it.isNotEmpty() }
|
||||||
contentList.add(text)
|
launch(Main) {
|
||||||
}
|
|
||||||
}
|
|
||||||
if (play) play() else pageChanged = true
|
if (play) play() else pageChanged = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -335,10 +335,12 @@ abstract class BaseReadAloudService : BaseService(),
|
|||||||
AppLog.put("音频焦点获得")
|
AppLog.put("音频焦点获得")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioManager.AUDIOFOCUS_LOSS -> {
|
AudioManager.AUDIOFOCUS_LOSS -> {
|
||||||
AppLog.put("音频焦点丢失,暂停朗读")
|
AppLog.put("音频焦点丢失,暂停朗读")
|
||||||
pauseReadAloud()
|
pauseReadAloud()
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> {
|
AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> {
|
||||||
AppLog.put("音频焦点暂时丢失并会很快再次获得,暂停朗读")
|
AppLog.put("音频焦点暂时丢失并会很快再次获得,暂停朗读")
|
||||||
if (!pause) {
|
if (!pause) {
|
||||||
@@ -346,6 +348,7 @@ abstract class BaseReadAloudService : BaseService(),
|
|||||||
pauseReadAloud(false)
|
pauseReadAloud(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> {
|
AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> {
|
||||||
// 短暂丢失焦点,这种情况是被其他应用申请了短暂的焦点希望其他声音能压低音量(或者关闭声音)凸显这个声音(比如短信提示音),
|
// 短暂丢失焦点,这种情况是被其他应用申请了短暂的焦点希望其他声音能压低音量(或者关闭声音)凸显这个声音(比如短信提示音),
|
||||||
AppLog.put("音频焦点短暂丢失,不做处理")
|
AppLog.put("音频焦点短暂丢失,不做处理")
|
||||||
@@ -364,6 +367,7 @@ abstract class BaseReadAloudService : BaseService(),
|
|||||||
R.string.read_aloud_timer,
|
R.string.read_aloud_timer,
|
||||||
timeMinute
|
timeMinute
|
||||||
)
|
)
|
||||||
|
|
||||||
else -> getString(R.string.read_aloud_t)
|
else -> getString(R.string.read_aloud_t)
|
||||||
}
|
}
|
||||||
nTitle += ": ${ReadBook.book?.name}"
|
nTitle += ": ${ReadBook.book?.name}"
|
||||||
|
|||||||
@@ -11,10 +11,12 @@ import io.legado.app.constant.EventBus
|
|||||||
import io.legado.app.exception.NoStackTraceException
|
import io.legado.app.exception.NoStackTraceException
|
||||||
import io.legado.app.help.MediaHelp
|
import io.legado.app.help.MediaHelp
|
||||||
import io.legado.app.help.config.AppConfig
|
import io.legado.app.help.config.AppConfig
|
||||||
|
import io.legado.app.help.coroutine.Coroutine
|
||||||
import io.legado.app.lib.dialogs.SelectItem
|
import io.legado.app.lib.dialogs.SelectItem
|
||||||
import io.legado.app.model.ReadAloud
|
import io.legado.app.model.ReadAloud
|
||||||
import io.legado.app.model.ReadBook
|
import io.legado.app.model.ReadBook
|
||||||
import io.legado.app.utils.*
|
import io.legado.app.utils.*
|
||||||
|
import kotlinx.coroutines.ensureActive
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 本地朗读
|
* 本地朗读
|
||||||
@@ -24,6 +26,7 @@ class TTSReadAloudService : BaseReadAloudService(), TextToSpeech.OnInitListener
|
|||||||
private var textToSpeech: TextToSpeech? = null
|
private var textToSpeech: TextToSpeech? = null
|
||||||
private var ttsInitFinish = false
|
private var ttsInitFinish = false
|
||||||
private val ttsUtteranceListener = TTSUtteranceListener()
|
private val ttsUtteranceListener = TTSUtteranceListener()
|
||||||
|
private var speakJob: Coroutine<*>? = null
|
||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
@@ -74,32 +77,36 @@ class TTSReadAloudService : BaseReadAloudService(), TextToSpeech.OnInitListener
|
|||||||
if (contentList.isEmpty()) {
|
if (contentList.isEmpty()) {
|
||||||
AppLog.putDebug("朗读列表为空")
|
AppLog.putDebug("朗读列表为空")
|
||||||
ReadBook.readAloud()
|
ReadBook.readAloud()
|
||||||
} else {
|
return
|
||||||
|
}
|
||||||
super.play()
|
super.play()
|
||||||
kotlin.runCatching {
|
|
||||||
MediaHelp.playSilentSound(this@TTSReadAloudService)
|
MediaHelp.playSilentSound(this@TTSReadAloudService)
|
||||||
|
speakJob?.cancel()
|
||||||
|
speakJob = execute {
|
||||||
val tts = textToSpeech ?: throw NoStackTraceException("tts is null")
|
val tts = textToSpeech ?: throw NoStackTraceException("tts is null")
|
||||||
var result = tts.speak("", TextToSpeech.QUEUE_FLUSH, null, null)
|
var result = tts.speak("", TextToSpeech.QUEUE_FLUSH, null, null)
|
||||||
if (result == TextToSpeech.ERROR) {
|
if (result == TextToSpeech.ERROR) {
|
||||||
clearTTS()
|
clearTTS()
|
||||||
initTts()
|
initTts()
|
||||||
return
|
return@execute
|
||||||
}
|
}
|
||||||
|
val contentList = contentList
|
||||||
for (i in nowSpeak until contentList.size) {
|
for (i in nowSpeak until contentList.size) {
|
||||||
|
ensureActive()
|
||||||
val text = contentList[i]
|
val text = contentList[i]
|
||||||
if (!text.matches(AppPattern.notReadAloudRegex)) {
|
if (text.matches(AppPattern.notReadAloudRegex)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
result = tts.speak(text, TextToSpeech.QUEUE_ADD, null, AppConst.APP_TAG + i)
|
result = tts.speak(text, TextToSpeech.QUEUE_ADD, null, AppConst.APP_TAG + i)
|
||||||
if (result == TextToSpeech.ERROR) {
|
if (result == TextToSpeech.ERROR) {
|
||||||
AppLog.put("tts朗读出错:$text")
|
AppLog.put("tts朗读出错:$text")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}.onError {
|
||||||
}.onFailure {
|
|
||||||
AppLog.put("tts朗读出错", it)
|
AppLog.put("tts朗读出错", it)
|
||||||
toastOnUi(it.localizedMessage)
|
toastOnUi(it.localizedMessage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
override fun playStop() {
|
override fun playStop() {
|
||||||
textToSpeech?.stop()
|
textToSpeech?.stop()
|
||||||
@@ -125,6 +132,7 @@ class TTSReadAloudService : BaseReadAloudService(), TextToSpeech.OnInitListener
|
|||||||
*/
|
*/
|
||||||
override fun pauseReadAloud(abandonFocus: Boolean) {
|
override fun pauseReadAloud(abandonFocus: Boolean) {
|
||||||
super.pauseReadAloud(abandonFocus)
|
super.pauseReadAloud(abandonFocus)
|
||||||
|
speakJob?.cancel()
|
||||||
textToSpeech?.stop()
|
textToSpeech?.stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -85,6 +85,21 @@ class SpeakEngineDialog(val callBack: CallBack) : BaseDialogFragment(R.layout.di
|
|||||||
recyclerView.setEdgeEffectColor(primaryColor)
|
recyclerView.setEdgeEffectColor(primaryColor)
|
||||||
recyclerView.layoutManager = LinearLayoutManager(requireContext())
|
recyclerView.layoutManager = LinearLayoutManager(requireContext())
|
||||||
recyclerView.adapter = adapter
|
recyclerView.adapter = adapter
|
||||||
|
adapter.addHeaderView {
|
||||||
|
ItemHttpTtsBinding.inflate(layoutInflater, recyclerView, false).apply {
|
||||||
|
sysTtsViews.add(cbName)
|
||||||
|
ivEdit.gone()
|
||||||
|
ivMenuDelete.gone()
|
||||||
|
labelSys.visible()
|
||||||
|
cbName.text = "系统默认"
|
||||||
|
cbName.tag = ""
|
||||||
|
cbName.isChecked = GSON.fromJsonObject<SelectItem<String>>(ttsEngine)
|
||||||
|
.getOrNull()?.value.isNullOrEmpty()
|
||||||
|
cbName.setOnClickListener {
|
||||||
|
upTts(GSON.toJson(SelectItem("系统默认", "")))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
viewModel.sysEngines.forEach { engine ->
|
viewModel.sysEngines.forEach { engine ->
|
||||||
adapter.addHeaderView {
|
adapter.addHeaderView {
|
||||||
ItemHttpTtsBinding.inflate(layoutInflater, recyclerView, false).apply {
|
ItemHttpTtsBinding.inflate(layoutInflater, recyclerView, false).apply {
|
||||||
@@ -147,6 +162,7 @@ class SpeakEngineDialog(val callBack: CallBack) : BaseDialogFragment(R.layout.di
|
|||||||
mode = HandleFileContract.FILE
|
mode = HandleFileContract.FILE
|
||||||
allowExtensions = arrayOf("txt", "json")
|
allowExtensions = arrayOf("txt", "json")
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.menu_import_onLine -> importAlert()
|
R.id.menu_import_onLine -> importAlert()
|
||||||
R.id.menu_export -> exportDirResult.launch {
|
R.id.menu_export -> exportDirResult.launch {
|
||||||
mode = HandleFileContract.EXPORT
|
mode = HandleFileContract.EXPORT
|
||||||
|
|||||||
Reference in New Issue
Block a user