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.bean.VoiceAction
|
||||||
import com.rokid.security.glass3.sdk.base.data.offlineCmd.listener.IVoiceCallback
|
import com.rokid.security.glass3.sdk.base.data.offlineCmd.listener.IVoiceCallback
|
||||||
import com.xuqm.base.common.LogHelper
|
import com.xuqm.base.common.LogHelper
|
||||||
|
import java.util.concurrent.Executors
|
||||||
|
|
||||||
data class OfflineCmdBean(val text: String, val pinyin: String)
|
data class OfflineCmdBean(val text: String, val pinyin: String)
|
||||||
|
|
||||||
object OfflineCmdServiceHelper {
|
object OfflineCmdServiceHelper {
|
||||||
private var listenerList = mutableListOf<OfflineCmdListener>()
|
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 {
|
private val list = mutableListOf<OfflineCmdBean>().apply {
|
||||||
// 首页
|
// 首页
|
||||||
@ -169,11 +175,18 @@ object OfflineCmdServiceHelper {
|
|||||||
add(OfflineCmdBean("确认", "que ren"))
|
add(OfflineCmdBean("确认", "que ren"))
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
@Synchronized
|
||||||
fun init(){
|
fun init(){
|
||||||
|
if (initialized || initializing) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
initializing = true
|
||||||
|
initExecutor.execute {
|
||||||
|
try {
|
||||||
val service = GlassSdk.getGlassOfflineCmdService()
|
val service = GlassSdk.getGlassOfflineCmdService()
|
||||||
if (service == null){
|
if (service == null){
|
||||||
LogHelper.e("OfflineCmdServiceHelper","service is null")
|
LogHelper.e("OfflineCmdServiceHelper","service is null")
|
||||||
return
|
return@execute
|
||||||
}
|
}
|
||||||
LogHelper.e("OfflineCmdServiceHelper","service 存在")
|
LogHelper.e("OfflineCmdServiceHelper","service 存在")
|
||||||
for (bean in list) {
|
for (bean in list) {
|
||||||
@ -186,6 +199,11 @@ object OfflineCmdServiceHelper {
|
|||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
initialized = true
|
||||||
|
} finally {
|
||||||
|
initializing = false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fun addOnLineListener(listener: OfflineCmdListener){
|
fun addOnLineListener(listener: OfflineCmdListener){
|
||||||
this.listenerList.add(listener)
|
this.listenerList.add(listener)
|
||||||
|
|||||||
@ -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>
|
||||||
正在加载...
在新工单中引用
屏蔽一个用户