refactor(task): 重构复合材料铺贴任务流程

- 将任务列表注释更新为包含决策中心功能
- 移除不必要的导入和枚举定义,简化 CompositeLayupTaskActivity 类结构
- 替换基础 Activity 为 BaseListFormLayoutNormalActivity 以支持分页功能
- 更新适配器实现为 BasePagedAdapter 和 CommonPagedAdapter
- 简化屏幕模式管理,移除复杂的 UI 状态切换逻辑
- 优化拍照和识别流程,直接跳转到结果页面
- 添加 CompositeLayupResultActivity 来处理识别结果和铺贴过程
- 更新视图模型继承自 BaseListViewModel 并优化数据加载逻辑
- 修改布局文件以匹配新的 UI 流程设计
- 在 AndroidManifest 中注册新的结果活动页面
这个提交包含在:
徐勤民 2026-04-22 18:14:53 +08:00
父节点 47fa2c4464
当前提交 089c807340
共有 10 个文件被更改,包括 596 次插入555 次删除

查看文件

@ -56,7 +56,7 @@ android {
buildConfigField("String", "API_COOKIE", "\"__itrace_wid=87125211-8742-4f12-b5ca-32b9b6c860e4; locale=zh-Hans; _webtracing_device_id=t_13501877-b9b303fc-d3f52eb530e026b0\"")
buildConfigField("String", "API_ENVIRONMENT", "\"2\"")
buildConfigField("String", "API_CURRENT_USER_ID", "\"rokid\"")
// ++fo
// ++fo+
buildConfigField("String", "API_BASE_URL_1", "\"http://10.230.4.80:12119\"")
//
buildConfigField("String", "API_BASE_URL_2", "\"http://10.230.4.80\"")

查看文件

@ -78,6 +78,9 @@
<activity
android:name=".ui.CompositeLayupTaskActivity"
android:exported="false" />
<activity
android:name=".ui.CompositeLayupResultActivity"
android:exported="false" />
<activity
android:name=".ui.ChatActivity"
android:exported="false" />

查看文件

@ -0,0 +1,319 @@
package com.nova.brain.glass.ui
import android.content.Intent
import android.os.Environment
import android.os.Handler
import android.os.Looper
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.nova.brain.glass.R
import com.nova.brain.glass.databinding.ActivityCompositeLayupResultBinding
import com.nova.brain.glass.helper.GlassMediaServiceHelper
import com.nova.brain.glass.helper.OfflineCmdListener
import com.nova.brain.glass.helper.OfflineCmdServiceHelper
import com.nova.brain.glass.model.ItemItem
import com.nova.brain.glass.viewmodel.CompositeLayupResultState
import com.nova.brain.glass.viewmodel.CompositeLayupResultVM
import com.rokid.security.glass3.sdk.base.data.media.PhotoResolution
import com.rokid.security.system.server.media.callback.PhotoFileCallback
import com.xuqm.base.adapter.CommonAdapter
import com.xuqm.base.adapter.ViewHolder
import com.xuqm.base.extensions.showMessage
import com.xuqm.base.ui.BaseActivity
import java.io.File
import java.util.UUID
class CompositeLayupResultActivity : BaseActivity<ActivityCompositeLayupResultBinding>() {
override fun getLayoutId(): Int = R.layout.activity_composite_layup_result
override fun fullscreen(): Boolean = true
private val viewModel: CompositeLayupResultVM by lazy {
ViewModelProvider(this)[CompositeLayupResultVM::class.java]
}
private enum class UiMode {
RECOGNIZE_SUCCESS,
RECOGNIZE_FAILED,
LAYUP_PROMPT,
LAYUP_WORKING,
CONFIRM_FINISH,
COMPLETE
}
private val taskNo: String by lazy { intent.getStringExtra(EXTRA_TASK_NO).orEmpty() }
private val taskName: String by lazy { intent.getStringExtra(EXTRA_TASK_NAME).orEmpty() }
private val partNo: String by lazy { intent.getStringExtra(EXTRA_PART_NO).orEmpty() }
private val photoPath: String by lazy { intent.getStringExtra(EXTRA_PHOTO_PATH).orEmpty() }
private val stepSeq: Int by lazy { intent.getIntExtra(EXTRA_STEP_SEQ, 1) }
private val totalSteps: Int by lazy { intent.getIntExtra(EXTRA_TOTAL_STEPS, 1) }
private val direction: String by lazy { intent.getStringExtra(EXTRA_DIRECTION).orEmpty() }
private val vacuum: String by lazy { intent.getStringExtra(EXTRA_VACUUM).orEmpty() }
private val uiHandler = Handler(Looper.getMainLooper())
private var isPhoto = false
private var uiMode = UiMode.RECOGNIZE_SUCCESS
private val layupWorkingRunnable: Runnable = Runnable {
if (uiMode == UiMode.LAYUP_PROMPT) {
applyMode(UiMode.LAYUP_WORKING)
}
}
private val completeRunnable: Runnable = Runnable {
if (uiMode == UiMode.COMPLETE) {
goTaskList()
}
}
private val listener: OfflineCmdListener = object : OfflineCmdListener {
override fun onOfflineCmd(cmd: String) {
runOnUiThread {
when (cmd) {
"退出", "返回", "退回" -> finish()
"重拍", "重新拍照", "重新拍摄" -> if (uiMode == UiMode.RECOGNIZE_FAILED) retake()
"开始铺贴" -> if (uiMode == UiMode.RECOGNIZE_SUCCESS) startLayup()
"确认并继续", "继续" -> if (uiMode == UiMode.CONFIRM_FINISH) confirmAndContinue()
"" -> if (uiMode == UiMode.CONFIRM_FINISH) applyMode(UiMode.LAYUP_WORKING)
"完成", "完成任务" -> if (uiMode == UiMode.CONFIRM_FINISH && stepSeq >= totalSteps) finishCurrentTask()
"返回任务列表" -> if (uiMode == UiMode.COMPLETE) goTaskList()
}
}
}
}
private val photoCallbackId = UUID.randomUUID().toString()
private val photoCallback: PhotoFileCallback = object : PhotoFileCallback.Stub() {
override fun onTakePhoto(path: String) = Unit
override fun getCallbackId(): String = photoCallbackId
override fun onTakePhotoV2(path: String?, width: Int, height: Int) {
if (path == null) {
if (isPhoto) {
isPhoto = false
takePhoto()
} else {
binding.hint.text = "单击或语音输入“重新拍照”,进入下一步"
"相机异常".showMessage()
}
return
}
startActivity(Intent(this@CompositeLayupResultActivity, CompositeLayupResultActivity::class.java).apply {
putExtra(EXTRA_PHOTO_PATH, path)
putExtra(EXTRA_TASK_NO, taskNo)
putExtra(EXTRA_TASK_NAME, taskName)
putExtra(EXTRA_PART_NO, partNo)
putExtra(EXTRA_STEP_SEQ, stepSeq)
putExtra(EXTRA_TOTAL_STEPS, totalSteps)
putExtra(EXTRA_DIRECTION, direction)
putExtra(EXTRA_VACUUM, vacuum)
})
finish()
}
}
override fun initData() {
super.initData()
window.addFlags(android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
binding.baseRecyclerView.layoutManager = LinearLayoutManager(this, RecyclerView.VERTICAL, false)
binding.baseRecyclerView.adapter = actionAdapter
binding.main.setOnClickListener {
if (uiMode == UiMode.LAYUP_WORKING) {
applyMode(UiMode.CONFIRM_FINISH)
}
}
viewModel.resultState.observe(this) { state ->
when (state) {
CompositeLayupResultState.LOADING -> {
binding.hint.text = "OCR识别中,请稍后..."
renderActions(emptyList())
}
CompositeLayupResultState.SUCCESS -> {
val result = viewModel.recognizeResult.value ?: return@observe
if (result.success) {
applyMode(UiMode.RECOGNIZE_SUCCESS)
} else {
applyMode(UiMode.RECOGNIZE_FAILED, result.errorMessage.ifBlank { "识别失败,请重试!" })
}
}
CompositeLayupResultState.FAILED -> {
applyMode(UiMode.RECOGNIZE_FAILED, viewModel.errorMessage.value ?: "识别失败,请重试!")
}
else -> Unit
}
}
if (taskNo.isNotBlank() && photoPath.isNotBlank()) {
viewModel.recognize(taskNo, stepSeq, photoPath)
}
}
private fun applyMode(mode: UiMode, errorMessage: String = "") {
uiMode = mode
uiHandler.removeCallbacks(layupWorkingRunnable)
uiHandler.removeCallbacks(completeRunnable)
binding.icon.visibility = android.view.View.VISIBLE
when (mode) {
UiMode.RECOGNIZE_SUCCESS -> {
binding.icon.setImageResource(R.mipmap.ocr_true)
binding.title.text = "铺贴层与零件信息正确"
binding.subtitle1.text = "识别到这是${stepSeq}/${totalSteps}"
binding.subtitle2.text = buildInstruction()
renderActions(listOf("开始铺贴"))
binding.hint.text = "单击或语音输入“开始铺贴”,进入下一步"
}
UiMode.RECOGNIZE_FAILED -> {
binding.icon.setImageResource(R.mipmap.ocr_false)
binding.title.text = errorMessage
binding.subtitle1.text = "识别到这是${stepSeq}/${totalSteps}"
binding.subtitle2.text = "请重新拿取"
renderActions(listOf("重新拍照"))
binding.hint.text = "单击或语音输入“重新拍照”,进入下一步"
}
UiMode.LAYUP_PROMPT -> {
binding.icon.visibility = android.view.View.INVISIBLE
binding.title.text = "请进行铺贴工作"
binding.subtitle1.text = "完成后,滑动唤醒眼镜!"
binding.subtitle2.text = ""
renderActions(emptyList())
binding.hint.text = ""
uiHandler.postDelayed(layupWorkingRunnable, 5000L)
}
UiMode.LAYUP_WORKING -> {
binding.icon.visibility = android.view.View.INVISIBLE
binding.title.text = "正在铺贴第${stepSeq}"
binding.subtitle1.text = buildWorkingInstruction()
binding.subtitle2.text = ""
renderActions(emptyList())
binding.hint.text = ""
}
UiMode.CONFIRM_FINISH -> {
binding.icon.visibility = android.view.View.INVISIBLE
binding.title.text = "请确认是否已完成第${stepSeq}/${totalSteps}张铺贴"
binding.subtitle1.text = ""
binding.subtitle2.text = ""
renderActions(listOf(if (stepSeq >= totalSteps) "完成" else "确认并继续", ""))
binding.hint.text = "点击或语音输入对应按钮,继续流程"
}
UiMode.COMPLETE -> {
binding.icon.setImageResource(R.mipmap.ocr_true)
binding.title.text = "恭喜完成当前铺贴任务!"
binding.subtitle1.text = "3S后自动返回铺贴任务界面"
binding.subtitle2.text = ""
renderActions(listOf("返回任务列表"))
binding.hint.text = ""
uiHandler.postDelayed(completeRunnable, 3000L)
}
}
}
private fun buildInstruction(): String {
val vacuumText = if (vacuum.isBlank()) "" else "请真空铺贴、"
val directionText = if (direction.isBlank()) "" else "纹理方向:$direction"
return (vacuumText + directionText).ifBlank { "请开始铺贴" }
}
private fun buildWorkingInstruction(): String {
val vacuumText = if (vacuum.isBlank()) "" else "请真空铺贴、"
val directionText = if (direction.isBlank()) "" else "纹理方向$direction"
return "${vacuumText}${directionText}撕衬纸\n完成后,滑动唤醒眼镜!"
}
private fun renderActions(actions: List<String>) {
actionAdapter.setmDatas(actions.map(::ItemItem))
binding.baseRecyclerView.visibility = if (actions.isEmpty()) android.view.View.INVISIBLE else android.view.View.VISIBLE
binding.baseRecyclerView.layoutParams = binding.baseRecyclerView.layoutParams.apply {
height = dpToPx(if (actions.size > 1) 152 else 88)
}
}
private fun startLayup() {
applyMode(UiMode.LAYUP_PROMPT)
}
private fun retake() {
binding.hint.text = "拍照中,请稍后..."
isPhoto = true
takePhoto()
}
private fun takePhoto() {
val fileName = "composite_layup_${System.currentTimeMillis()}.png"
val file = File(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
fileName
)
GlassMediaServiceHelper.takePhoto(PhotoResolution.RESOLUTION_720P, file.absolutePath)
}
private fun confirmAndContinue() {
startActivity(Intent(this, CompositeLayupTaskActivity::class.java).apply {
putExtra(CompositeLayupTaskActivity.EXTRA_TASK_NO, taskNo)
putExtra(CompositeLayupTaskActivity.EXTRA_STEP_SEQ, stepSeq + 1)
})
finish()
}
private fun finishCurrentTask() {
applyMode(UiMode.COMPLETE)
}
private fun goTaskList() {
startActivity(Intent(this, TaskListActivity::class.java).apply {
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP)
})
finish()
}
private fun dpToPx(dp: Int): Int =
(dp * resources.displayMetrics.density).toInt()
override fun onResume() {
super.onResume()
GlassMediaServiceHelper.addPhotoCallback(photoCallback)
OfflineCmdServiceHelper.addListenerCompositeLayup()
OfflineCmdServiceHelper.addOnLineListener(listener)
}
override fun onPause() {
super.onPause()
uiHandler.removeCallbacks(layupWorkingRunnable)
uiHandler.removeCallbacks(completeRunnable)
GlassMediaServiceHelper.removePhotoCallback(photoCallback)
OfflineCmdServiceHelper.removeListenerCompositeLayup()
OfflineCmdServiceHelper.removeOnLineListener(listener)
}
override fun onDestroy() {
super.onDestroy()
window.clearFlags(android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
}
private val actionAdapter: CommonAdapter<ItemItem> =
object : CommonAdapter<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) {
"重新拍照" -> retake()
"开始铺贴" -> startLayup()
"确认并继续" -> confirmAndContinue()
"" -> applyMode(UiMode.LAYUP_WORKING)
"完成" -> finishCurrentTask()
"返回任务列表" -> goTaskList()
}
}
}
}
companion object {
const val EXTRA_PHOTO_PATH = "extra_photo_path"
const val EXTRA_TASK_NO = "extra_task_no"
const val EXTRA_TASK_NAME = "extra_task_name"
const val EXTRA_PART_NO = "extra_part_no"
const val EXTRA_STEP_SEQ = "extra_step_seq"
const val EXTRA_TOTAL_STEPS = "extra_total_steps"
const val EXTRA_DIRECTION = "extra_direction"
const val EXTRA_VACUUM = "extra_vacuum"
}
}

查看文件

@ -2,11 +2,6 @@ package com.nova.brain.glass.ui
import android.content.Intent
import android.os.Environment
import android.os.Handler
import android.os.Looper
import android.view.View
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.nova.brain.glass.R
import com.nova.brain.glass.databinding.ActivityCompositeLayupTaskBinding
@ -14,84 +9,49 @@ import com.nova.brain.glass.helper.GlassMediaServiceHelper
import com.nova.brain.glass.helper.OfflineCmdListener
import com.nova.brain.glass.helper.OfflineCmdServiceHelper
import com.nova.brain.glass.model.ItemItem
import com.nova.brain.glass.viewmodel.CompositeLayupRecognizeState
import com.nova.brain.glass.viewmodel.CompositeLayupTaskVM
import com.rokid.security.glass3.sdk.base.data.media.PhotoResolution
import com.rokid.security.system.server.media.callback.PhotoFileCallback
import com.xuqm.base.adapter.CommonAdapter
import com.xuqm.base.adapter.BasePagedAdapter
import com.xuqm.base.adapter.CommonPagedAdapter
import com.xuqm.base.adapter.ViewHolder
import com.xuqm.base.common.LogHelper
import com.xuqm.base.extensions.showMessage
import com.xuqm.base.ui.BaseActivity
import com.xuqm.base.ui.BaseListFormLayoutNormalActivity
import java.io.File
import java.util.UUID
class CompositeLayupTaskActivity : BaseActivity<ActivityCompositeLayupTaskBinding>() {
class CompositeLayupTaskActivity :
BaseListFormLayoutNormalActivity<ItemItem, CompositeLayupTaskVM, ActivityCompositeLayupTaskBinding>() {
override fun getLayoutId(): Int = R.layout.activity_composite_layup_task
override fun fullscreen(): Boolean = true
override fun getRecyclerOrientation(): Int = RecyclerView.VERTICAL
private enum class ScreenMode {
TASK_INFO,
CAPTURE,
RECOGNIZE_SUCCESS,
RECOGNIZE_FAILED,
LAYUP_PROMPT,
LAYUP_WORKING,
CONFIRM_FINISH,
COMPLETE
}
private val viewModel: CompositeLayupTaskVM by lazy {
ViewModelProvider(this)[CompositeLayupTaskVM::class.java]
}
private val taskNoFromIntent: String by lazy {
intent.getStringExtra(EXTRA_TASK_NO).orEmpty()
}
private val mainHandler = Handler(Looper.getMainLooper())
private val stepSeqFromIntent: Int by lazy {
intent.getIntExtra(EXTRA_STEP_SEQ, 0)
}
private var isPhotoFallback = false
private var isPhoto = false
private var isCaptureInFlight = false
private var screenMode = ScreenMode.TASK_INFO
private var autoReturned = false
private var hasNavigatedNextPage = false
private val layupWorkingRunnable = Runnable {
if (screenMode == ScreenMode.LAYUP_PROMPT) {
applyScreenMode(ScreenMode.LAYUP_WORKING)
}
}
private val completeRunnable = Runnable {
if (screenMode == ScreenMode.COMPLETE && !autoReturned) {
autoReturned = true
goTaskList()
}
}
private val listener = object : OfflineCmdListener {
private val listener: OfflineCmdListener = object : OfflineCmdListener {
override fun onOfflineCmd(cmd: String) {
runOnUiThread {
when (cmd) {
"退出", "返回", "退回" -> finish()
"开始", "开始任务" -> if (screenMode == ScreenMode.TASK_INFO) startCaptureFlow()
"重新拍照", "重拍", "重新拍摄" -> {
if (screenMode == ScreenMode.RECOGNIZE_FAILED) startCaptureFlow()
}
"开始铺贴" -> if (screenMode == ScreenMode.RECOGNIZE_SUCCESS) startLayup()
"确认并继续", "继续" -> if (screenMode == ScreenMode.CONFIRM_FINISH) confirmAndContinue()
"" -> if (screenMode == ScreenMode.CONFIRM_FINISH) backToWorking()
"完成", "完成任务" -> {
if (screenMode == ScreenMode.CONFIRM_FINISH && viewModel.canFinishAfterCurrentStep()) {
finishCurrentTask()
}
}
"返回任务列表" -> if (screenMode == ScreenMode.COMPLETE) goTaskList()
"开始", "拍照", "开始拍照", "开始任务" -> startCapture()
}
}
}
}
private val photoCallbackId = UUID.randomUUID().toString()
private val photoCallback = object : PhotoFileCallback.Stub() {
private val photoCallback: PhotoFileCallback = object : PhotoFileCallback.Stub() {
override fun onTakePhoto(path: String) {
LogHelper.d("CompositeLayupTask onTakePhoto: $path")
}
@ -101,293 +61,128 @@ class CompositeLayupTaskActivity : BaseActivity<ActivityCompositeLayupTaskBindin
override fun onTakePhotoV2(path: String?, width: Int, height: Int) {
LogHelper.d("CompositeLayupTask onTakePhotoV2 width=$width height=$height path=$path")
if (path == null) {
if (isPhotoFallback) {
isPhotoFallback = false
if (isPhoto) {
isPhoto = false
takePhoto()
} else {
isCaptureInFlight = false
runOnUiThread {
val message = "相机异常,请重试"
updateHint(message)
applyScreenMode(ScreenMode.RECOGNIZE_FAILED, message)
binding.hint.text = "单击或语音输入“开始”,进入下一步"
}
"相机异常".showMessage()
}
return
}
if (hasNavigatedNextPage) {
return
}
val taskDetail = viewModel.taskDetail.value
val currentDetail = viewModel.currentDetail()
val currentTaskStepSeq = currentDetail?.stepSeq ?: viewModel.currentStepSeq
isCaptureInFlight = false
runOnUiThread {
updateHint("OCR识别中,请稍后...")
viewModel.recognize(path)
}
}
}
private val actionAdapter = object : CommonAdapter<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) {
"开始任务" -> startCaptureFlow()
"重新拍照" -> startCaptureFlow()
"开始铺贴" -> startLayup()
"确认并继续" -> confirmAndContinue()
"" -> backToWorking()
"完成" -> finishCurrentTask()
"返回任务列表" -> goTaskList()
}
}
hasNavigatedNextPage = true
GlassMediaServiceHelper.removePhotoCallback(photoCallback)
OfflineCmdServiceHelper.removeListenerCompositeLayup()
OfflineCmdServiceHelper.removeOnLineListener(listener)
startActivity(Intent(this@CompositeLayupTaskActivity, CompositeLayupResultActivity::class.java).apply {
putExtra(CompositeLayupResultActivity.EXTRA_PHOTO_PATH, path)
putExtra(CompositeLayupResultActivity.EXTRA_TASK_NO, viewModel.taskNo)
putExtra(CompositeLayupResultActivity.EXTRA_TASK_NAME, taskDetail?.taskName.orEmpty())
putExtra(CompositeLayupResultActivity.EXTRA_PART_NO, taskDetail?.partNo.orEmpty())
putExtra(CompositeLayupResultActivity.EXTRA_STEP_SEQ, currentTaskStepSeq)
putExtra(CompositeLayupResultActivity.EXTRA_TOTAL_STEPS, viewModel.totalSteps)
putExtra(CompositeLayupResultActivity.EXTRA_DIRECTION, currentDetail?.direction.orEmpty())
putExtra(CompositeLayupResultActivity.EXTRA_VACUUM, currentDetail?.vacuum.orEmpty())
})
finish()
}
}
override fun initData() {
super.initData()
window.addFlags(android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
binding.baseRecyclerView.layoutManager = LinearLayoutManager(this, RecyclerView.VERTICAL, false)
binding.baseRecyclerView.adapter = actionAdapter
binding.main.setOnClickListener {
if (screenMode == ScreenMode.LAYUP_WORKING) {
applyScreenMode(ScreenMode.CONFIRM_FINISH)
}
}
observeViewModel()
applyScreenMode(ScreenMode.TASK_INFO)
if (taskNoFromIntent.isBlank()) {
val message = "任务编号缺失"
updateHint(message)
message.showMessage()
} else {
viewModel.loadTaskDetail(taskNoFromIntent)
}
}
private fun observeViewModel() {
binding.tvTaskHeader.text = "复材铺贴任务"
viewModel.taskDetail.observe(this) { detail ->
if (detail != null) {
binding.tvTaskName.text = detail.taskName.ifBlank { "铺贴任务" }
renderTaskInfo()
applyScreenMode(ScreenMode.TASK_INFO)
}
}
viewModel.taskDetailError.observe(this) { msg ->
if (msg.isNotBlank()) {
updateHint(msg)
msg.showMessage()
}
}
viewModel.recognizeState.observe(this) { state ->
when (state) {
CompositeLayupRecognizeState.LOADING -> {
updateHint("OCR识别中,请稍后...")
renderActions(emptyList())
}
CompositeLayupRecognizeState.SUCCESS -> handleRecognizeResult()
CompositeLayupRecognizeState.FAILED -> {
val error = viewModel.recognizeError.value?.ifBlank { "OCR识别失败" } ?: "OCR识别失败"
applyScreenMode(ScreenMode.RECOGNIZE_FAILED, error)
}
else -> Unit
}
}
}
private fun renderTaskInfo() {
val detail = viewModel.taskDetail.value ?: return
if (detail == null) return@observe
val currentDetail = viewModel.currentDetail()
binding.tvTaskName.text = currentDetail?.ply?.ifBlank {
detail.taskName.ifBlank { "铺贴任务" }
} ?: detail.taskName.ifBlank { "铺贴任务" }
binding.content1.text = "零件号:${detail.partNo.ifBlank { "-" }}"
binding.content2.text = "任务编号:${detail.taskNo.ifBlank { taskNoFromIntent }}"
binding.content3.text = "任务进度:${viewModel.currentProgressText()}"
binding.content3.text = "任务进度:${viewModel.currentStepSeq}/${detail.taskSteps}"
binding.hint.text = "单击或语音输入“开始”,进入下一步"
}
private fun handleRecognizeResult() {
val result = viewModel.recognizeResult.value ?: return
if (result.success) {
applyScreenMode(ScreenMode.RECOGNIZE_SUCCESS)
viewModel.taskDetailError.observe(this) { message ->
if (message.isNotBlank()) {
binding.hint.text = "单击或语音输入“开始”,进入下一步"
message.showMessage()
}
}
if (taskNoFromIntent.isBlank()) {
binding.hint.text = "任务编号缺失"
} else {
applyScreenMode(
ScreenMode.RECOGNIZE_FAILED,
result.errorMessage.ifBlank { "识别失败,请重试!" }
)
}
viewModel.resetRecognizeState()
}
private fun startCaptureFlow() {
if (isCaptureInFlight || taskNoFromIntent.isBlank()) {
return
}
isCaptureInFlight = true
applyScreenMode(ScreenMode.CAPTURE)
takePhoto()
}
private fun takePhoto() {
isPhotoFallback = true
val fileName = "composite_layup_${System.currentTimeMillis()}.png"
val file = File(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
fileName
)
GlassMediaServiceHelper.takePhoto(PhotoResolution.RESOLUTION_720P, file.absolutePath)
}
private fun startLayup() {
applyScreenMode(ScreenMode.LAYUP_PROMPT)
}
private fun backToWorking() {
applyScreenMode(ScreenMode.LAYUP_WORKING)
}
private fun confirmAndContinue() {
if (viewModel.canFinishAfterCurrentStep()) {
finishCurrentTask()
return
}
if (viewModel.moveToNextStep()) {
renderTaskInfo()
applyScreenMode(ScreenMode.TASK_INFO)
viewModel.loadTaskDetail(taskNoFromIntent, stepSeqFromIntent.takeIf { it > 0 })
}
}
private fun finishCurrentTask() {
applyScreenMode(ScreenMode.COMPLETE)
}
private fun applyScreenMode(mode: ScreenMode, errorMessage: String = "") {
screenMode = mode
mainHandler.removeCallbacks(layupWorkingRunnable)
mainHandler.removeCallbacks(completeRunnable)
renderTaskInfo()
binding.groupStart.visibility = if (mode == ScreenMode.TASK_INFO) View.VISIBLE else View.GONE
binding.groupCapture.visibility = if (mode == ScreenMode.CAPTURE) View.VISIBLE else View.GONE
binding.groupResult.visibility =
if (mode == ScreenMode.RECOGNIZE_SUCCESS || mode == ScreenMode.RECOGNIZE_FAILED) View.VISIBLE else View.GONE
binding.groupWork.visibility =
if (mode == ScreenMode.LAYUP_PROMPT || mode == ScreenMode.LAYUP_WORKING) View.VISIBLE else View.GONE
binding.groupConfirm.visibility = if (mode == ScreenMode.CONFIRM_FINISH) View.VISIBLE else View.GONE
binding.groupComplete.visibility = if (mode == ScreenMode.COMPLETE) View.VISIBLE else View.GONE
when (mode) {
ScreenMode.TASK_INFO -> {
binding.captureMessage.text = "请对准下一张复材铺贴物料上的字符内容"
binding.startIcon.setImageResource(R.mipmap.ocr_photo)
renderActions(listOf("开始任务"))
updateHint("单击或语音输入\"开始\",进入下一步")
}
ScreenMode.CAPTURE -> {
binding.captureMessage.text = "请对准复材铺贴物料上的字符内容"
renderActions(emptyList())
updateHint("拍照中,请稍后...")
}
ScreenMode.RECOGNIZE_SUCCESS -> {
val currentDetail = viewModel.currentDetail()
binding.resultIcon.setImageResource(R.mipmap.ocr_true)
binding.resultTitle.text = "铺贴层与零件信息正确"
binding.resultSubtitle1.text = "识别到这是${viewModel.currentProgressText()}"
binding.resultSubtitle2.text = buildRecognizeInstruction(currentDetail?.vacuum, currentDetail?.direction)
renderActions(listOf("开始铺贴"))
updateHint("单击或语音输入\"开始铺贴\",进入下一步")
}
ScreenMode.RECOGNIZE_FAILED -> {
binding.resultIcon.setImageResource(R.mipmap.ocr_false)
binding.resultTitle.text = errorMessage.ifBlank { "识别失败,请重试!" }
binding.resultSubtitle1.text = "识别到这是${viewModel.currentProgressText()}"
binding.resultSubtitle2.text = "请重新拿取"
renderActions(listOf("重新拍照"))
updateHint("单击或语音输入\"重新拍照\",进入下一步")
}
ScreenMode.LAYUP_PROMPT -> {
binding.workText.text = "请进行铺贴工作\n完成后,滑动唤醒眼镜!"
renderActions(emptyList())
updateHint("")
mainHandler.postDelayed(layupWorkingRunnable, 5000L)
}
ScreenMode.LAYUP_WORKING -> {
binding.workText.text = buildWorkingInstruction()
renderActions(emptyList())
updateHint("")
}
ScreenMode.CONFIRM_FINISH -> {
binding.confirmTitle.text = "请确认是否已完成第${viewModel.currentProgressText()}张铺贴"
val primary = if (viewModel.canFinishAfterCurrentStep()) "完成" else "确认并继续"
renderActions(listOf(primary, ""))
updateHint("点击或语音输入对应按钮,继续流程")
}
ScreenMode.COMPLETE -> {
autoReturned = false
binding.completeSubtitle.text = "3S后自动返回铺贴任务界面"
renderActions(listOf("返回任务列表"))
updateHint("")
mainHandler.postDelayed(completeRunnable, 3000L)
}
}
}
private fun renderActions(actions: List<String>) {
actionAdapter.setmDatas(actions.map(::ItemItem))
binding.baseRecyclerView.layoutParams = binding.baseRecyclerView.layoutParams.apply {
height = dpToPx(
when {
actions.isEmpty() -> 88
actions.size == 1 -> 88
else -> 152
}
)
}
binding.baseRecyclerView.visibility = if (actions.isEmpty()) View.INVISIBLE else View.VISIBLE
}
private fun updateHint(text: String) {
binding.hint.text = text
binding.hint.visibility = if (text.isBlank()) View.INVISIBLE else View.VISIBLE
}
private fun buildRecognizeInstruction(vacuum: String?, direction: String?): String {
val vacuumText = if (vacuum.isNullOrBlank()) "" else "请真空铺贴、"
val directionText = if (direction.isNullOrBlank()) "" else "纹理方向$direction"
return (vacuumText + directionText).ifBlank { "请开始铺贴" }
}
private fun buildWorkingInstruction(): String {
val detail = viewModel.currentDetail()
val stepText = "正在铺贴第${viewModel.currentStepSeq}"
val vacuumText = if (detail?.vacuum.isNullOrBlank()) "" else "请真空铺贴、"
val directionText = if (detail?.direction.isNullOrBlank()) "" else "纹理方向${detail?.direction}"
return "$stepText\n${vacuumText}${directionText}撕衬纸\n完成后,滑动唤醒眼镜!"
}
private fun goTaskList() {
startActivity(Intent(this, TaskListActivity::class.java).apply {
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP)
})
finish()
}
private fun dpToPx(dp: Int): Int =
(dp * resources.displayMetrics.density).toInt()
override fun onResume() {
super.onResume()
hasNavigatedNextPage = false
isCaptureInFlight = false
GlassMediaServiceHelper.addPhotoCallback(photoCallback)
OfflineCmdServiceHelper.addListenerCompositeLayup()
OfflineCmdServiceHelper.addOnLineListener(listener)
OfflineCmdServiceHelper.addListenerCompositeLayup()
}
override fun onPause() {
super.onPause()
mainHandler.removeCallbacks(layupWorkingRunnable)
mainHandler.removeCallbacks(completeRunnable)
GlassMediaServiceHelper.removePhotoCallback(photoCallback)
OfflineCmdServiceHelper.removeListenerCompositeLayup()
OfflineCmdServiceHelper.removeOnLineListener(listener)
GlassMediaServiceHelper.removePhotoCallback(photoCallback)
}
override fun onDestroy() {
isCaptureInFlight = false
hasNavigatedNextPage = false
super.onDestroy()
window.clearFlags(android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
}
private fun startCapture() {
if (isCaptureInFlight || hasNavigatedNextPage || taskNoFromIntent.isBlank()) {
return
}
binding.hint.text = "拍照中,请稍后..."
isPhoto = true
isCaptureInFlight = true
takePhoto()
}
private fun takePhoto() {
val fileName = "composite_layup_${System.currentTimeMillis()}.png"
val publicPicturesDir =
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
val file = File(publicPicturesDir, fileName)
GlassMediaServiceHelper.takePhoto(PhotoResolution.RESOLUTION_720P, file.absolutePath)
}
private val adapter: BasePagedAdapter<ItemItem> =
object : CommonPagedAdapter<ItemItem>(R.layout.item_photo) {
override fun convert(holder: ViewHolder, item: ItemItem, position: Int) {
holder.setText(R.id.text, item.text)
.setClickListener(R.id.photo) {
if (item.text == "开始任务") {
startCapture()
}
}
}
}
override fun adapter(): BasePagedAdapter<ItemItem> = adapter
companion object {
const val EXTRA_TASK_NO = "extra_task_no"
const val EXTRA_STEP_SEQ = "extra_step_seq"
}
}

查看文件

@ -56,8 +56,8 @@ class WelcomeActivity : BaseActivity<ActivityWelcomeBinding>() {
binding.tv.setOnClickListener {
runWithNetwork {
// triggerRecognize()
// startActivity(Intent(this, TaskListActivity::class.java))
startActivity(Intent(this, ChatActivity::class.java))
startActivity(Intent(this, TaskListActivity::class.java))
// startActivity(Intent(this, ChatActivity::class.java))
}
}
}

查看文件

@ -0,0 +1,68 @@
package com.nova.brain.glass.viewmodel
import androidx.lifecycle.MutableLiveData
import com.nova.brain.glass.MyApplication
import com.nova.brain.glass.model.ItemItem
import com.nova.brain.glass.model.data.CompositeLayupRecognizeResult
import com.nova.brain.glass.repository.Service4
import com.xuqm.base.di.manager.HttpManager
import com.xuqm.base.viewmodel.BaseListViewModel
import com.xuqm.base.viewmodel.callback.Response
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.MultipartBody
import okhttp3.RequestBody.Companion.asRequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import java.io.File
enum class CompositeLayupResultState { IDLE, LOADING, SUCCESS, FAILED }
class CompositeLayupResultVM : BaseListViewModel<ItemItem>() {
val resultState = MutableLiveData(CompositeLayupResultState.IDLE)
val recognizeResult = MutableLiveData<CompositeLayupRecognizeResult?>()
val errorMessage = MutableLiveData<String>()
private val disposables = CompositeDisposable()
override fun loadData(page: Int, onResponse: Response<ItemItem>) {
onResponse.onResponse(arrayListOf())
}
fun recognize(taskNo: String, stepSeq: Int, photoPath: String) {
val file = File(photoPath)
if (!file.exists()) {
resultState.value = CompositeLayupResultState.FAILED
errorMessage.value = "图片不存在"
return
}
resultState.value = CompositeLayupResultState.LOADING
val taskNoBody = taskNo.toRequestBody("text/plain".toMediaTypeOrNull())
val stepSeqBody = stepSeq.toString().toRequestBody("text/plain".toMediaTypeOrNull())
val requestFile = file.asRequestBody("application/octet-stream".toMediaTypeOrNull())
val filePart = MultipartBody.Part.createFormData("file", file.name, requestFile)
val disposable = HttpManager.getApi(MyApplication.appComponent4, Service4::class.java)
.ocrRecognize(taskNoBody, stepSeqBody, filePart)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ response ->
if (response.success && response.data != null) {
recognizeResult.value = response.data
resultState.value = CompositeLayupResultState.SUCCESS
} else {
resultState.value = CompositeLayupResultState.FAILED
errorMessage.value = response.message.ifBlank { "OCR识别失败" }
}
}, { e ->
resultState.value = CompositeLayupResultState.FAILED
errorMessage.value = e.message ?: "OCR识别失败"
})
disposables.add(disposable)
}
override fun onCleared() {
super.onCleared()
disposables.clear()
}
}

查看文件

@ -2,12 +2,14 @@ package com.nova.brain.glass.viewmodel
import androidx.lifecycle.MutableLiveData
import com.nova.brain.glass.MyApplication
import com.nova.brain.glass.model.ItemItem
import com.nova.brain.glass.model.data.CompositeLayupRecognizeResult
import com.nova.brain.glass.model.data.CompositeLayupDetailItem
import com.nova.brain.glass.model.data.CompositeLayupTaskDetail
import com.nova.brain.glass.repository.Service4
import com.xuqm.base.di.manager.HttpManager
import androidx.lifecycle.ViewModel
import com.xuqm.base.viewmodel.BaseListViewModel
import com.xuqm.base.viewmodel.callback.Response
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers
@ -19,7 +21,7 @@ import java.io.File
enum class CompositeLayupRecognizeState { IDLE, LOADING, SUCCESS, FAILED }
class CompositeLayupTaskVM : ViewModel() {
class CompositeLayupTaskVM : BaseListViewModel<ItemItem>() {
val taskDetail = MutableLiveData<CompositeLayupTaskDetail?>()
val taskDetailError = MutableLiveData<String>()
@ -36,15 +38,19 @@ class CompositeLayupTaskVM : ViewModel() {
var lastRecognizeFinished: Boolean = false
private set
fun loadTaskDetail(taskNo: String) {
override fun loadData(page: Int, onResponse: Response<ItemItem>) {
onResponse.onResponse(arrayListOf(ItemItem("开始任务")))
}
fun loadTaskDetail(taskNo: String, stepOverride: Int? = null) {
this.taskNo = taskNo
val disposable = HttpManager.getApi(MyApplication.appComponent4, Service4::class.java)
.queryTask(taskNo)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ response ->
if (response.success && response.data != null) {
bindTaskDetail(response.data)
if (response.code == 200 && response.data != null) {
bindTaskDetail(response.data, stepOverride)
} else {
taskDetailError.value = response.message.ifBlank { "获取任务详情失败" }
}
@ -100,9 +106,6 @@ class CompositeLayupTaskVM : ViewModel() {
fun currentDetail(): CompositeLayupDetailItem? =
taskDetail.value?.detailList
?.sortedBy { it.stepSeq }
?.firstOrNull { it.stepSeq == currentStepSeq }
?: taskDetail.value?.detailList
?.sortedBy { it.stepSeq }
?.getOrNull((currentStepSeq - 1).coerceAtLeast(0))
@ -121,16 +124,13 @@ class CompositeLayupTaskVM : ViewModel() {
return true
}
private fun bindTaskDetail(detail: CompositeLayupTaskDetail) {
private fun bindTaskDetail(detail: CompositeLayupTaskDetail, stepOverride: Int? = null) {
taskDetail.value = detail
this.taskNo = detail.taskNo.ifBlank { taskNo }
totalSteps = detail.taskSteps.coerceAtLeast(detail.detailList?.size ?: 1).coerceAtLeast(1)
currentStepSeq = when {
stepOverride != null && stepOverride > 0 -> stepOverride
detail.taskCurrentStep > 0 -> detail.taskCurrentStep
!detail.detailList.isNullOrEmpty() -> {
detail.detailList.firstOrNull { it.detailStatus != 9 }?.stepSeq
?: detail.detailList.last().stepSeq.coerceAtLeast(1)
}
else -> 1
}.coerceIn(1, totalSteps)
lastRecognizeFinished = currentStepSeq >= totalSteps

查看文件

@ -0,0 +1,85 @@
<?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:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/app_color_black">
<ImageView
android:id="@+id/icon"
android:layout_width="120dp"
android:layout_height="120dp"
android:layout_marginTop="44dp"
android:src="@mipmap/ocr_true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:gravity="center"
android:text="铺贴层与零件信息正确"
android:textColor="#ff40FF5E"
android:textSize="22sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/icon" />
<TextView
android:id="@+id/subtitle1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:gravity="center"
android:text="识别到这是1/12张"
android:textColor="#ff40FF5E"
android:textSize="18sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/title" />
<TextView
android:id="@+id/subtitle2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:gravity="center"
android:text="请真空铺贴、纹理方向+90"
android:textColor="#ff40FF5E"
android:textSize="18sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/subtitle1" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/baseRecyclerView"
android:layout_width="0dp"
android:layout_height="88dp"
android:layout_marginTop="24dp"
android:clipToPadding="false"
android:overScrollMode="never"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/subtitle2" />
<TextView
android:id="@+id/hint"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:gravity="center"
android:text="单击或语音输入“开始铺贴”,进入下一步"
android:textColor="#ff40FF5E"
android:textSize="14sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/baseRecyclerView" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

查看文件

@ -55,7 +55,7 @@
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:layout_marginTop="4dp"
android:text="零件号:20293989-001"
android:text="零件号:"
android:textColor="#ff40FF5E"
android:textSize="14sp" />
@ -65,7 +65,7 @@
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:layout_marginTop="4dp"
android:text="任务编号:PT20260422001"
android:text="任务编号:"
android:textColor="#ff40FF5E"
android:textSize="14sp" />
@ -75,7 +75,7 @@
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:layout_marginVertical="4dp"
android:text="任务进度:1/12"
android:text="任务进度:"
android:textColor="#ff40FF5E"
android:textSize="14sp" />
</LinearLayout>
@ -84,8 +84,8 @@
android:id="@+id/baseRecyclerView"
android:layout_width="0dp"
android:layout_height="88dp"
android:layout_marginTop="24dp"
android:clipToPadding="false"
android:layout_marginTop="12dp"
android:overScrollMode="never"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
@ -93,238 +93,17 @@
<TextView
android:id="@+id/hint"
android:layout_width="0dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:layout_marginStart="15dp"
android:layout_marginTop="10dp"
android:layout_marginVertical="4dp"
android:gravity="center"
android:text="单击或语音输入&#34;开始&#34;,进入下一步"
android:textColor="#ff40FF5E"
android:textSize="14sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/baseRecyclerView" />
<FrameLayout
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="24dp"
android:layout_marginTop="12dp"
android:layout_marginEnd="24dp"
android:layout_marginBottom="12dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/hint">
<LinearLayout
android:id="@+id/groupStart"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<FrameLayout
android:layout_width="128dp"
android:layout_height="128dp"
android:background="@drawable/bg_composite_circle">
<ImageView
android:id="@+id/startIcon"
android:layout_width="52dp"
android:layout_height="52dp"
android:layout_gravity="center"
android:src="@mipmap/ocr_photo" />
</FrameLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/groupCapture"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
android:visibility="gone">
<FrameLayout
android:layout_width="320dp"
android:layout_height="220dp">
<View
android:layout_width="60dp"
android:layout_height="4dp"
android:background="#ff40FF5E" />
<View
android:layout_width="4dp"
android:layout_height="60dp"
android:background="#ff40FF5E" />
<View
android:layout_width="60dp"
android:layout_height="4dp"
android:layout_gravity="top|end"
android:background="#ff40FF5E" />
<View
android:layout_width="4dp"
android:layout_height="60dp"
android:layout_gravity="top|end"
android:background="#ff40FF5E" />
<View
android:layout_width="60dp"
android:layout_height="4dp"
android:layout_gravity="bottom|start"
android:background="#ff40FF5E" />
<View
android:layout_width="4dp"
android:layout_height="60dp"
android:layout_gravity="bottom|start"
android:background="#ff40FF5E" />
<View
android:layout_width="60dp"
android:layout_height="4dp"
android:layout_gravity="bottom|end"
android:background="#ff40FF5E" />
<View
android:layout_width="4dp"
android:layout_height="60dp"
android:layout_gravity="bottom|end"
android:background="#ff40FF5E" />
<TextView
android:id="@+id/captureMessage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:text="请对准复材铺贴物料上的字符内容"
android:textColor="#ff40FF5E"
android:textSize="16sp" />
</FrameLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/groupResult"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
android:visibility="gone">
<ImageView
android:id="@+id/resultIcon"
android:layout_width="120dp"
android:layout_height="120dp"
android:src="@mipmap/ocr_true" />
<TextView
android:id="@+id/resultTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:gravity="center"
android:text="铺贴层与料号信息正确"
android:textColor="#ff40FF5E"
android:textSize="22sp"
android:textStyle="bold" />
<TextView
android:id="@+id/resultSubtitle1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:gravity="center"
android:text="识别到这是1/12张"
android:textColor="#ff40FF5E"
android:textSize="18sp" />
<TextView
android:id="@+id/resultSubtitle2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:gravity="center"
android:text="请真空铺贴、纹理方向+90"
android:textColor="#ff40FF5E"
android:textSize="18sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/groupWork"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
android:visibility="gone">
<TextView
android:id="@+id/workText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:lineSpacingExtra="6dp"
android:text="请进行铺贴工作"
android:textColor="#ff40FF5E"
android:textSize="22sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/groupConfirm"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
android:visibility="gone">
<TextView
android:id="@+id/confirmTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="请确认是否已完成第3/12张铺贴"
android:textColor="#ff40FF5E"
android:textSize="22sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/groupComplete"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
android:visibility="gone">
<ImageView
android:layout_width="120dp"
android:layout_height="120dp"
android:src="@mipmap/ocr_true" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:gravity="center"
android:text="恭喜完成当前铺贴任务!"
android:textColor="#ff40FF5E"
android:textSize="22sp"
android:textStyle="bold" />
<TextView
android:id="@+id/completeSubtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:gravity="center"
android:text="3S后自动返回铺贴任务界面"
android:textColor="#ff40FF5E"
android:textSize="18sp" />
</LinearLayout>
</FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

查看文件

@ -103,13 +103,5 @@
android:text="单击或语音输入“开始”,进入下一步"
android:textColor="#ff40FF5E"
android:textSize="14sp"/>
<ImageView
android:layout_width="120dp"
android:id="@+id/iv"
android:layout_height="150dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/hint"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>