diff --git a/app/src/main/java/com/xiaoqu/watch/ui/task/TaskListFragment.kt b/app/src/main/java/com/xiaoqu/watch/ui/task/TaskListFragment.kt index d35cf15..ae28d89 100644 --- a/app/src/main/java/com/xiaoqu/watch/ui/task/TaskListFragment.kt +++ b/app/src/main/java/com/xiaoqu/watch/ui/task/TaskListFragment.kt @@ -19,6 +19,7 @@ import com.xiaoqu.watch.databinding.FragmentTaskListBinding import com.xiaoqu.watch.network.ApiResult import com.xiaoqu.watch.network.api.TaskApi import com.xiaoqu.watch.network.safeApiCall +import com.xiaoqu.watch.service.manager.EdgeTtsManager import com.xiaoqu.watch.service.manager.NfcTaskManager import com.xiaoqu.watch.ui.common.BaseFragment import com.xiaoqu.watch.ui.widget.QuTipDialog @@ -42,6 +43,7 @@ class TaskListFragment : BaseFragment() { @Inject lateinit var taskApi: TaskApi @Inject lateinit var nfcTaskManager: NfcTaskManager + @Inject lateinit var edgeTtsManager: EdgeTtsManager /** 任务 ID 列表(queryTaskIds 返回) */ @@ -117,12 +119,17 @@ class TaskListFragment : BaseFragment() { false // 不拦截,让 ScrollView 继续处理滚动 } + // TTS 播放按钮 + binding.btnTts.setOnClickListener { toggleTts() } + // 加载任务列表 fetchTaskIds() } override fun onDestroyView() { stopVoice() + edgeTtsManager.stop() + edgeTtsManager.onComplete = null super.onDestroyView() } @@ -237,6 +244,7 @@ class TaskListFragment : BaseFragment() { /** 下一个任务(左滑,内容从右滑入) */ private fun nextTask() { if (taskIndex < taskList.size - 1) { + stopTts() // 切换任务时停止播报 taskIndex++ animateSwitch(fromRight = true) } @@ -245,6 +253,7 @@ class TaskListFragment : BaseFragment() { /** 上一个任务(右滑,内容从左滑入) */ private fun prevTask() { if (taskIndex > 0) { + stopTts() // 切换任务时停止播报 taskIndex-- animateSwitch(fromRight = false) } @@ -1006,4 +1015,62 @@ class TaskListFragment : BaseFragment() { binding.btnAction.visibility = View.GONE binding.tvTitle.text = statusTitle() } + + // ===== TTS 语音播报 ===== + + /** 切换播放/停止 */ + private fun toggleTts() { + if (edgeTtsManager.isPlaying) { + stopTts() + } else { + startTts() + } + } + + /** 开始播报当前任务内容 */ + private fun startTts() { + val detail = currentDetail ?: return + + // 拼接播报文本:有值的字段才读,空字段跳过 + val parts = mutableListOf() + if (detail.name.isNotBlank()) parts.add("任务:${detail.displayName}") + if (detail.positionText.isNotBlank()) parts.add("地点:${detail.positionText}") + if (detail.sendTime.isNotBlank()) parts.add("时间:${detail.sendTime}") + if (detail.point > 0) parts.add("积分:${detail.pointText}") + if (detail.content.isNotBlank()) parts.add("备注:${detail.content}") + + if (parts.isEmpty()) return + + val text = parts.joinToString(",") + Timber.d("TTS 播报: $text") + + // 更新按钮状态为播放中 + updateTtsButton(playing = true) + + // 播放完成回调:恢复按钮 + edgeTtsManager.onComplete = { + activity?.runOnUiThread { updateTtsButton(playing = false) } + } + + edgeTtsManager.speak(text) { errorMsg -> + Timber.w("TTS 播报失败: $errorMsg") + activity?.runOnUiThread { updateTtsButton(playing = false) } + } + } + + /** 停止播报 */ + private fun stopTts() { + edgeTtsManager.stop() + updateTtsButton(playing = false) + } + + /** 更新 TTS 按钮的 UI 状态 */ + private fun updateTtsButton(playing: Boolean) { + binding.btnTts.setImageResource( + if (playing) R.drawable.ic_speaker_stop else R.drawable.ic_speaker + ) + binding.btnTts.setBackgroundResource( + if (playing) R.drawable.bg_tts_button_active else R.drawable.bg_tts_button + ) + } } diff --git a/app/src/main/res/layout/fragment_task_list.xml b/app/src/main/res/layout/fragment_task_list.xml index e70a4a7..b7120d8 100644 --- a/app/src/main/res/layout/fragment_task_list.xml +++ b/app/src/main/res/layout/fragment_task_list.xml @@ -364,6 +364,19 @@ + + + +