feat(spraying): 添加喷洒完成页面和离线语音命令优化
- 实现了 SprayingFinishActivity 页面用于显示拍摄结果 - 添加了 SprayingPhotoManager 管理器用于管理喷洒照片 - 创建了 SprayingFinishVM 视图模型处理页面数据 - 设计了 activity_spraying_finish.xml 布局文件 - 优化了 OfflineCmdServiceHelper 的初始化逻辑,添加线程安全和单次初始化控制 - 实现了语音命令支持补充照片、确认提交和返回功能 - 添加了照片预览和统计功能,显示实际拍摄数量
这个提交包含在:
父节点
19997b4d54
当前提交
ff6a0c3a33
@ -4,11 +4,17 @@ import com.rokid.security.glass3.open.sdk.GlassSdk
|
||||
import com.rokid.security.glass3.sdk.base.data.offlineCmd.bean.VoiceAction
|
||||
import com.rokid.security.glass3.sdk.base.data.offlineCmd.listener.IVoiceCallback
|
||||
import com.xuqm.base.common.LogHelper
|
||||
import java.util.concurrent.Executors
|
||||
|
||||
data class OfflineCmdBean(val text: String, val pinyin: String)
|
||||
|
||||
object OfflineCmdServiceHelper {
|
||||
private var listenerList = mutableListOf<OfflineCmdListener>()
|
||||
private val initExecutor = Executors.newSingleThreadExecutor()
|
||||
@Volatile
|
||||
private var initialized = false
|
||||
@Volatile
|
||||
private var initializing = false
|
||||
|
||||
private val list = mutableListOf<OfflineCmdBean>().apply {
|
||||
// 首页
|
||||
@ -169,22 +175,34 @@ object OfflineCmdServiceHelper {
|
||||
add(OfflineCmdBean("确认", "que ren"))
|
||||
//
|
||||
}
|
||||
@Synchronized
|
||||
fun init(){
|
||||
val service = GlassSdk.getGlassOfflineCmdService()
|
||||
if (service == null){
|
||||
LogHelper.e("OfflineCmdServiceHelper","service is null")
|
||||
if (initialized || initializing) {
|
||||
return
|
||||
}
|
||||
LogHelper.e("OfflineCmdServiceHelper","service 存在")
|
||||
for (bean in list) {
|
||||
service.add(VoiceAction(bean.text, bean.pinyin, object : IVoiceCallback.Stub() {
|
||||
override fun onVoiceTriggered() {
|
||||
LogHelper.d("onOfflineCmd: ${bean.text}")
|
||||
for (l in listenerList) {
|
||||
l.onOfflineCmd(bean.text)
|
||||
}
|
||||
initializing = true
|
||||
initExecutor.execute {
|
||||
try {
|
||||
val service = GlassSdk.getGlassOfflineCmdService()
|
||||
if (service == null){
|
||||
LogHelper.e("OfflineCmdServiceHelper","service is null")
|
||||
return@execute
|
||||
}
|
||||
}))
|
||||
LogHelper.e("OfflineCmdServiceHelper","service 存在")
|
||||
for (bean in list) {
|
||||
service.add(VoiceAction(bean.text, bean.pinyin, object : IVoiceCallback.Stub() {
|
||||
override fun onVoiceTriggered() {
|
||||
LogHelper.d("onOfflineCmd: ${bean.text}")
|
||||
for (l in listenerList) {
|
||||
l.onOfflineCmd(bean.text)
|
||||
}
|
||||
}
|
||||
}))
|
||||
}
|
||||
initialized = true
|
||||
} finally {
|
||||
initializing = false
|
||||
}
|
||||
}
|
||||
}
|
||||
fun addOnLineListener(listener: OfflineCmdListener){
|
||||
|
||||
@ -0,0 +1,23 @@
|
||||
package com.nova.brain.glass.helper
|
||||
|
||||
object SprayingPhotoManager {
|
||||
private val photoPaths = mutableListOf<String>()
|
||||
|
||||
@Synchronized
|
||||
fun addPhoto(path: String) {
|
||||
photoPaths.add(path)
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun getPhotoCount(): Int = photoPaths.size
|
||||
|
||||
@Synchronized
|
||||
fun getLastPhotos(limit: Int = 3): List<String> {
|
||||
return photoPaths.takeLast(limit)
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun clear() {
|
||||
photoPaths.clear()
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,86 @@
|
||||
package com.nova.brain.glass.ui
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.graphics.BitmapFactory
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.nova.brain.glass.R
|
||||
import com.nova.brain.glass.databinding.ActivitySprayingFinishBinding
|
||||
import com.nova.brain.glass.helper.OfflineCmdListener
|
||||
import com.nova.brain.glass.helper.OfflineCmdServiceHelper
|
||||
import com.nova.brain.glass.helper.SprayingPhotoManager
|
||||
import com.nova.brain.glass.model.ItemItem
|
||||
import com.nova.brain.glass.viewmodel.SprayingFinishVM
|
||||
import com.xuqm.base.adapter.BasePagedAdapter
|
||||
import com.xuqm.base.adapter.CommonPagedAdapter
|
||||
import com.xuqm.base.adapter.ViewHolder
|
||||
import com.xuqm.base.ui.BaseListFormLayoutNormalActivity
|
||||
|
||||
class SprayingFinishActivity :
|
||||
BaseListFormLayoutNormalActivity<ItemItem, SprayingFinishVM, ActivitySprayingFinishBinding>() {
|
||||
override fun getLayoutId(): Int = R.layout.activity_spraying_finish
|
||||
override fun fullscreen(): Boolean = true
|
||||
|
||||
override fun getRecyclerOrientation(): Int = RecyclerView.VERTICAL
|
||||
|
||||
private val listener = object : OfflineCmdListener {
|
||||
override fun onOfflineCmd(cmd: String) {
|
||||
runOnUiThread {
|
||||
when (cmd) {
|
||||
"补充照片", "继续拍摄", "继续拍照" -> finishWithAction(ACTION_SUPPLEMENT)
|
||||
"确认提交", "提交", "确认" -> finishWithAction(ACTION_SUBMIT)
|
||||
"取消", "返回", "退回", "退出" -> finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun initData() {
|
||||
super.initData()
|
||||
OfflineCmdServiceHelper.addOnLineListener(listener)
|
||||
renderPhotos()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
OfflineCmdServiceHelper.removeOnLineListener(listener)
|
||||
}
|
||||
|
||||
private fun renderPhotos() {
|
||||
val photos = SprayingPhotoManager.getLastPhotos()
|
||||
binding.title.text = "本次任务应拍摄3张,实际拍摄${SprayingPhotoManager.getPhotoCount()}张"
|
||||
val imageViews = listOf(binding.photo1, binding.photo2, binding.photo3)
|
||||
imageViews.forEach { it.setImageDrawable(null) }
|
||||
photos.forEachIndexed { index, path ->
|
||||
imageViews.getOrNull(index)?.setImageBitmap(BitmapFactory.decodeFile(path))
|
||||
}
|
||||
}
|
||||
|
||||
private val adapter = object : CommonPagedAdapter<ItemItem>(R.layout.item_manual_result_action) {
|
||||
override fun convert(holder: ViewHolder, item: ItemItem, position: Int) {
|
||||
holder
|
||||
.setText(R.id.text, item.text)
|
||||
.setClickListener(R.id.actionRoot) {
|
||||
when (item.text) {
|
||||
"补充照片" -> finishWithAction(ACTION_SUPPLEMENT)
|
||||
"确认提交" -> finishWithAction(ACTION_SUBMIT)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun adapter(): BasePagedAdapter<ItemItem> = adapter
|
||||
|
||||
private fun finishWithAction(action: String) {
|
||||
setResult(Activity.RESULT_OK, Intent().apply {
|
||||
putExtra(EXTRA_FINISH_ACTION, action)
|
||||
})
|
||||
finish()
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val EXTRA_FINISH_ACTION = "extra_finish_action"
|
||||
const val ACTION_SUPPLEMENT = "supplement"
|
||||
const val ACTION_SUBMIT = "submit"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
package com.nova.brain.glass.viewmodel
|
||||
|
||||
import com.nova.brain.glass.model.ItemItem
|
||||
import com.xuqm.base.viewmodel.BaseListViewModel
|
||||
import com.xuqm.base.viewmodel.callback.Response
|
||||
|
||||
class SprayingFinishVM : BaseListViewModel<ItemItem>() {
|
||||
override fun loadData(
|
||||
page: Int,
|
||||
onResponse: Response<ItemItem>
|
||||
) {
|
||||
onResponse.onResponse(
|
||||
arrayListOf<ItemItem>().apply {
|
||||
add(ItemItem("补充照片"))
|
||||
add(ItemItem("确认提交"))
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,93 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layout>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/app_color_black">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="58dp"
|
||||
android:gravity="center"
|
||||
android:text="本次任务应拍摄3张,实际拍摄0张"
|
||||
android:textColor="#4AFE59"
|
||||
android:textSize="24sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/photoContainer"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="170dp"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginTop="28dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:background="@drawable/bg_item"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal"
|
||||
android:paddingHorizontal="18dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/title">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/photo1"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="130dp"
|
||||
android:layout_weight="1"
|
||||
android:background="#FF3F3F3F"
|
||||
android:scaleType="centerCrop" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/photo2"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="130dp"
|
||||
android:layout_marginStart="14dp"
|
||||
android:layout_weight="1"
|
||||
android:background="#FF3F3F3F"
|
||||
android:scaleType="centerCrop" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/photo3"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="130dp"
|
||||
android:layout_marginStart="14dp"
|
||||
android:layout_weight="1"
|
||||
android:background="#FF3F3F3F"
|
||||
android:scaleType="centerCrop" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/baseRecyclerView"
|
||||
android:layout_width="210dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="24dp"
|
||||
android:overScrollMode="never"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/photoContainer" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/hint"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:gravity="center"
|
||||
android:lineSpacingExtra="6dp"
|
||||
android:text="单击或语音输入“补充照片”,继续拍摄图片 单击或语音输入“确认提交”,提交任务结果至天镜系统"
|
||||
android:textColor="#4AFE59"
|
||||
android:textSize="14sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/baseRecyclerView" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</layout>
|
||||
正在加载...
在新工单中引用
屏蔽一个用户