|
@@ -0,0 +1,251 @@
|
|
|
+package com.example.pda.ui
|
|
|
+
|
|
|
+import android.content.Context
|
|
|
+import androidx.compose.foundation.clickable
|
|
|
+import androidx.compose.runtime.*
|
|
|
+import androidx.compose.ui.platform.LocalContext
|
|
|
+import androidx.compose.ui.platform.LocalConfiguration
|
|
|
+import androidx.compose.ui.Modifier
|
|
|
+import androidx.compose.foundation.layout.*
|
|
|
+import androidx.compose.foundation.lazy.LazyColumn
|
|
|
+import androidx.compose.foundation.lazy.itemsIndexed
|
|
|
+import androidx.compose.material.icons.Icons
|
|
|
+import androidx.compose.material.icons.filled.ArrowBack
|
|
|
+import androidx.compose.material.icons.filled.Delete
|
|
|
+import androidx.compose.material3.*
|
|
|
+import androidx.compose.ui.graphics.Color
|
|
|
+import androidx.compose.ui.res.painterResource
|
|
|
+import androidx.compose.ui.unit.dp
|
|
|
+import android.media.AudioManager
|
|
|
+import android.media.ToneGenerator
|
|
|
+import androidx.compose.material.icons.filled.Search
|
|
|
+import com.example.pda.R
|
|
|
+import com.example.pda.function.UBXScan
|
|
|
+import com.example.pda.ui.viewmodel.InventoryViewModel
|
|
|
+import androidx.compose.material3.SnackbarHostState
|
|
|
+import androidx.compose.material3.Scaffold
|
|
|
+import androidx.compose.runtime.Composable
|
|
|
+import androidx.compose.runtime.LaunchedEffect
|
|
|
+import androidx.compose.runtime.collectAsState
|
|
|
+import androidx.compose.runtime.mutableStateOf
|
|
|
+import androidx.compose.runtime.remember
|
|
|
+import androidx.compose.runtime.rememberCoroutineScope
|
|
|
+import androidx.compose.ui.Alignment
|
|
|
+import androidx.lifecycle.viewmodel.compose.viewModel
|
|
|
+import kotlinx.coroutines.launch
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+@OptIn(ExperimentalMaterial3Api::class)
|
|
|
+@Composable
|
|
|
+fun ContainerScreen(
|
|
|
+ onBack: () -> Unit,
|
|
|
+) {
|
|
|
+ val viewModel: InventoryViewModel = viewModel()
|
|
|
+ val uiState = viewModel.uiState.collectAsState()
|
|
|
+ val snackbarHostState = remember { SnackbarHostState() }
|
|
|
+ val coroutineScope = rememberCoroutineScope()
|
|
|
+ // 新增输入状态
|
|
|
+ val inputIp = remember { mutableStateOf("12345678") }
|
|
|
+
|
|
|
+ val context = LocalContext.current
|
|
|
+ val ubxScan = remember { UBXScan() }
|
|
|
+ var isScanning by remember { mutableStateOf(true) }
|
|
|
+ val scannedItems = remember { mutableStateListOf<String>() }
|
|
|
+ val container = remember { mutableStateOf("") }
|
|
|
+ var showinput by remember { mutableStateOf(false) }
|
|
|
+ var showContainer by remember { mutableStateOf(true) }
|
|
|
+ val configuration = LocalConfiguration.current
|
|
|
+ val screenHeight = configuration.screenHeightDp.dp
|
|
|
+ val boxHeight = screenHeight * 0.15f
|
|
|
+
|
|
|
+ // 创建 ToneGenerator
|
|
|
+ val toneGenerator = remember { ToneGenerator(AudioManager.STREAM_NOTIFICATION, 100) }
|
|
|
+
|
|
|
+ LaunchedEffect(uiState.value) {
|
|
|
+ when (val currentState = uiState.value) {
|
|
|
+ is InventoryViewModel.UiState.Success -> {
|
|
|
+ coroutineScope.launch {
|
|
|
+ snackbarHostState.showSnackbar(currentState.message)
|
|
|
+ viewModel.resetState()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ is InventoryViewModel.UiState.Error -> {
|
|
|
+ coroutineScope.launch {
|
|
|
+ snackbarHostState.showSnackbar("错误:${currentState.message}")
|
|
|
+ viewModel.resetState()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else -> {}
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ DisposableEffect(Unit) {
|
|
|
+ startScanning(context, ubxScan) { result ->
|
|
|
+ if (container.value.isEmpty()) {
|
|
|
+ toneGenerator.startTone(ToneGenerator.TONE_PROP_BEEP)
|
|
|
+ container.value = result
|
|
|
+ showContainer = false
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ onDispose {
|
|
|
+ stopScanning(ubxScan)
|
|
|
+ isScanning = false
|
|
|
+ toneGenerator.release()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ Scaffold(
|
|
|
+ snackbarHost = { SnackbarHost(snackbarHostState) },
|
|
|
+ topBar = {
|
|
|
+ TopAppBar(
|
|
|
+ navigationIcon = {
|
|
|
+ IconButton(onClick = onBack) {
|
|
|
+ Icon(
|
|
|
+ imageVector = Icons.Default.ArrowBack,
|
|
|
+ contentDescription = "返回"
|
|
|
+ )
|
|
|
+ }
|
|
|
+ },
|
|
|
+ title = {
|
|
|
+ Row(verticalAlignment = Alignment.CenterVertically) {
|
|
|
+ Icon(
|
|
|
+ painter = painterResource(id = R.drawable.logo),
|
|
|
+ contentDescription = "PDA Logo",
|
|
|
+ modifier = Modifier.size(40.dp),
|
|
|
+ tint = MaterialTheme.colorScheme.surfaceTint
|
|
|
+ )
|
|
|
+ Spacer(Modifier.width(8.dp))
|
|
|
+ Text("信泰PDA—托盘扫描")
|
|
|
+ }
|
|
|
+ },
|
|
|
+ colors = TopAppBarDefaults.topAppBarColors(
|
|
|
+ containerColor = Color(0xFFBCD0C5), // 自定义颜色
|
|
|
+ titleContentColor = MaterialTheme.colorScheme.onPrimary,
|
|
|
+ actionIconContentColor = MaterialTheme.colorScheme.onPrimary
|
|
|
+ )
|
|
|
+ )
|
|
|
+ },
|
|
|
+
|
|
|
+ ) { innerPadding ->
|
|
|
+ Column(
|
|
|
+ modifier = Modifier
|
|
|
+ .padding(innerPadding)
|
|
|
+ .fillMaxSize()
|
|
|
+ .padding(24.dp)
|
|
|
+ ) {
|
|
|
+ // 扫描提示区域
|
|
|
+ Box(
|
|
|
+ modifier = Modifier
|
|
|
+ .height(boxHeight)
|
|
|
+ .fillMaxWidth()
|
|
|
+ .clickable(enabled = isScanning) {
|
|
|
+ container.value = ""
|
|
|
+ showinput = true
|
|
|
+ showContainer = false
|
|
|
+ },
|
|
|
+ contentAlignment = Alignment.Center
|
|
|
+ ) {
|
|
|
+ if (isScanning && showContainer) {
|
|
|
+ Text(text = "托盘条码扫描")
|
|
|
+ } else if (isScanning && showinput) {
|
|
|
+ Text(text = "输入条形码")
|
|
|
+ }
|
|
|
+ else{
|
|
|
+ Text(text = "物料信息")
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (showinput) {
|
|
|
+ Row (
|
|
|
+ modifier = Modifier
|
|
|
+ .fillMaxWidth()
|
|
|
+ .padding(8.dp),
|
|
|
+ verticalAlignment = Alignment.CenterVertically
|
|
|
+
|
|
|
+ ){
|
|
|
+ // 新增输入框
|
|
|
+ TextField(
|
|
|
+ value = inputIp.value,
|
|
|
+ onValueChange = { inputIp.value = it },
|
|
|
+ label = { Text("请输入托盘编码") },
|
|
|
+ )
|
|
|
+
|
|
|
+ IconButton(
|
|
|
+ onClick = {
|
|
|
+ container.value = inputIp.value;
|
|
|
+ viewModel.getData(container.value)
|
|
|
+ },
|
|
|
+ ) {
|
|
|
+ Icon(
|
|
|
+ imageVector = Icons.Default.Search,
|
|
|
+ contentDescription = "确定"
|
|
|
+ )
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ // 添加托盘扫描
|
|
|
+ Row(
|
|
|
+ modifier = Modifier
|
|
|
+ .fillMaxWidth()
|
|
|
+ .padding(8.dp),
|
|
|
+ verticalAlignment = Alignment.CenterVertically
|
|
|
+ ) {
|
|
|
+ Text(
|
|
|
+ text = "托盘编码:${container.value}",
|
|
|
+ modifier = Modifier.weight(1f)
|
|
|
+ )
|
|
|
+
|
|
|
+ IconButton(
|
|
|
+ onClick = { container.value = ""; showContainer = true;showinput=false },
|
|
|
+ ) {
|
|
|
+ Icon(
|
|
|
+ imageVector = Icons.Default.Delete,
|
|
|
+ contentDescription = "删除"
|
|
|
+ )
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 已扫描列表
|
|
|
+ LazyColumn(
|
|
|
+ modifier = Modifier
|
|
|
+ .weight(1f)
|
|
|
+ .padding(8.dp)
|
|
|
+ ) {
|
|
|
+ itemsIndexed(scannedItems) { index, item ->
|
|
|
+ Row(
|
|
|
+ modifier = Modifier
|
|
|
+ .fillMaxWidth()
|
|
|
+ .padding(8.dp),
|
|
|
+ verticalAlignment = Alignment.CenterVertically
|
|
|
+ ) {
|
|
|
+ Text(
|
|
|
+ text = "${index + 1}. $item",
|
|
|
+ modifier = Modifier.weight(1f)
|
|
|
+ )
|
|
|
+
|
|
|
+ }
|
|
|
+ Divider()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// (不再直接调用onResult)
|
|
|
+private fun startScanning(
|
|
|
+ context: Context,
|
|
|
+ ubxScan: UBXScan,
|
|
|
+ onScanned: (String) -> Unit
|
|
|
+) {
|
|
|
+ ubxScan.setOnScanListener(context) { result ->
|
|
|
+ onScanned(result)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+private fun stopScanning(ubxScan: UBXScan) {
|
|
|
+ ubxScan.destroy()
|
|
|
+}
|