feat: unify device detail presentation
This commit is contained in:
@@ -47,7 +47,11 @@ import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.flagship.abox.manager.R
|
||||
import com.flagship.abox.manager.designsystem.ABoxButton
|
||||
import com.flagship.abox.manager.designsystem.ABoxDeviceDetailScaffold
|
||||
import com.flagship.abox.manager.designsystem.ABoxIconButton
|
||||
import com.flagship.abox.manager.designsystem.ABoxLoadingIndicator
|
||||
import com.flagship.abox.manager.designsystem.icon.ABoxIcon
|
||||
import com.flagship.abox.manager.designsystem.icon.ABoxIconKey
|
||||
import com.flagship.abox.manager.domain.DeviceName
|
||||
import com.flagship.abox.manager.domain.SocketPowerState
|
||||
import java.text.SimpleDateFormat
|
||||
@@ -79,39 +83,10 @@ fun SocketScreen(
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val scrollState = rememberScrollState()
|
||||
var showEditNameDialog by remember { mutableStateOf(false) }
|
||||
|
||||
Scaffold(
|
||||
ABoxDeviceDetailScaffold(
|
||||
modifier = modifier.fillMaxSize(),
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
title = {
|
||||
Text(
|
||||
text = state.deviceName?.value ?: stringResource(R.string.socket_title),
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
)
|
||||
},
|
||||
navigationIcon = {
|
||||
IconButton(onClick = onBackClick) {
|
||||
Text("<", style = MaterialTheme.typography.titleLarge, fontWeight = FontWeight.Bold)
|
||||
}
|
||||
},
|
||||
actions = {
|
||||
IconButton(
|
||||
onClick = { showEditNameDialog = true },
|
||||
enabled = !state.isLoading && !state.isOperating,
|
||||
) {
|
||||
Text("✎", style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.Bold)
|
||||
}
|
||||
IconButton(
|
||||
onClick = { onEvent(SocketUiEvent.Refresh) },
|
||||
enabled = !state.isLoading && !state.isOperating,
|
||||
) {
|
||||
Text("↻", style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.Bold)
|
||||
}
|
||||
},
|
||||
)
|
||||
},
|
||||
title = state.deviceName?.value ?: stringResource(R.string.socket_title),
|
||||
onBack = onBackClick,
|
||||
) { paddingValues ->
|
||||
Column(
|
||||
modifier = Modifier
|
||||
@@ -121,6 +96,17 @@ fun SocketScreen(
|
||||
.verticalScroll(scrollState),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.End,
|
||||
) {
|
||||
ABoxIconButton(
|
||||
key = ABoxIconKey.REFRESH,
|
||||
contentDescription = "刷新插座状态",
|
||||
onClick = { onEvent(SocketUiEvent.Refresh) },
|
||||
enabled = !state.isLoading && !state.isOperating,
|
||||
)
|
||||
}
|
||||
if (state.isOffline) {
|
||||
OfflineBanner(
|
||||
onRetry = { onEvent(SocketUiEvent.Refresh) },
|
||||
@@ -248,41 +234,6 @@ fun SocketScreen(
|
||||
}
|
||||
}
|
||||
|
||||
if (showEditNameDialog) {
|
||||
var inputName by remember(state.deviceName) { mutableStateOf(state.deviceName?.value.orEmpty()) }
|
||||
AlertDialog(
|
||||
onDismissRequest = { showEditNameDialog = false },
|
||||
title = { Text(stringResource(R.string.dialog_edit_device_name_title)) },
|
||||
text = {
|
||||
OutlinedTextField(
|
||||
value = inputName,
|
||||
onValueChange = { inputName = it },
|
||||
label = { Text(stringResource(R.string.dialog_edit_device_name_hint)) },
|
||||
singleLine = true,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
)
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
val trimmed = inputName.trim()
|
||||
if (trimmed.isNotBlank()) {
|
||||
onEvent(SocketUiEvent.ChangeDeviceName(DeviceName(trimmed)))
|
||||
}
|
||||
showEditNameDialog = false
|
||||
},
|
||||
enabled = inputName.isNotBlank(),
|
||||
) {
|
||||
Text(stringResource(R.string.action_confirm))
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(onClick = { showEditNameDialog = false }) {
|
||||
Text(stringResource(R.string.action_cancel))
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@@ -310,10 +261,10 @@ private fun PowerIndicatorBadge(
|
||||
if (isLoading) {
|
||||
ABoxLoadingIndicator(modifier = Modifier.size(36.dp))
|
||||
} else {
|
||||
Text(
|
||||
text = if (powerState == SocketPowerState.ON) "⚡" else "○",
|
||||
style = MaterialTheme.typography.headlineLarge,
|
||||
color = indicatorColor,
|
||||
ABoxIcon(
|
||||
key = if (powerState == SocketPowerState.ON) ABoxIconKey.POWER else ABoxIconKey.SOCKET,
|
||||
contentDescription = if (powerState == SocketPowerState.ON) "插座已开启" else "插座已关闭",
|
||||
modifier = Modifier.size(40.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -377,9 +328,11 @@ private fun ErrorBanner(
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
modifier = Modifier.weight(1f),
|
||||
)
|
||||
TextButton(onClick = onDismiss) {
|
||||
Text("✕")
|
||||
}
|
||||
ABoxIconButton(
|
||||
key = ABoxIconKey.CLOSE,
|
||||
contentDescription = "关闭错误提示",
|
||||
onClick = onDismiss,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+26
-71
@@ -39,7 +39,9 @@ import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.flagship.abox.manager.R
|
||||
import com.flagship.abox.manager.designsystem.ABoxButton
|
||||
import com.flagship.abox.manager.designsystem.ABoxDeviceDetailScaffold
|
||||
import com.flagship.abox.manager.designsystem.ABoxLoadingIndicator
|
||||
import com.flagship.abox.manager.designsystem.ABoxIconButton
|
||||
import com.flagship.abox.manager.designsystem.icon.ABoxIcon
|
||||
import com.flagship.abox.manager.designsystem.icon.ABoxIconKey
|
||||
import com.flagship.abox.manager.domain.DeviceName
|
||||
@@ -72,39 +74,10 @@ fun TemperatureHumidityScreen(
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val scrollState = rememberScrollState()
|
||||
var showEditNameDialog by remember { mutableStateOf(false) }
|
||||
|
||||
Scaffold(
|
||||
ABoxDeviceDetailScaffold(
|
||||
modifier = modifier.fillMaxSize(),
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
title = {
|
||||
Text(
|
||||
text = state.deviceName?.value ?: stringResource(R.string.th_title),
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
)
|
||||
},
|
||||
navigationIcon = {
|
||||
IconButton(onClick = onBackClick) {
|
||||
Text("<", style = MaterialTheme.typography.titleLarge, fontWeight = FontWeight.Bold)
|
||||
}
|
||||
},
|
||||
actions = {
|
||||
IconButton(
|
||||
onClick = { showEditNameDialog = true },
|
||||
enabled = !state.isLoading && !state.isRefreshing,
|
||||
) {
|
||||
Text("✎", style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.Bold)
|
||||
}
|
||||
IconButton(
|
||||
onClick = { onEvent(TemperatureHumidityUiEvent.Refresh) },
|
||||
enabled = !state.isLoading && !state.isRefreshing,
|
||||
) {
|
||||
Text("↻", style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.Bold)
|
||||
}
|
||||
},
|
||||
)
|
||||
},
|
||||
title = state.deviceName?.value ?: stringResource(R.string.th_title),
|
||||
onBack = onBackClick,
|
||||
) { paddingValues ->
|
||||
Column(
|
||||
modifier = Modifier
|
||||
@@ -114,6 +87,17 @@ fun TemperatureHumidityScreen(
|
||||
.verticalScroll(scrollState),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.End,
|
||||
) {
|
||||
ABoxIconButton(
|
||||
key = ABoxIconKey.REFRESH,
|
||||
contentDescription = "刷新温湿度数据",
|
||||
onClick = { onEvent(TemperatureHumidityUiEvent.Refresh) },
|
||||
enabled = !state.isLoading && !state.isRefreshing,
|
||||
)
|
||||
}
|
||||
if (state.isOffline) {
|
||||
OfflineBanner(
|
||||
onRetry = { onEvent(TemperatureHumidityUiEvent.Refresh) },
|
||||
@@ -241,41 +225,6 @@ fun TemperatureHumidityScreen(
|
||||
}
|
||||
}
|
||||
|
||||
if (showEditNameDialog) {
|
||||
var inputName by remember(state.deviceName) { mutableStateOf(state.deviceName?.value.orEmpty()) }
|
||||
AlertDialog(
|
||||
onDismissRequest = { showEditNameDialog = false },
|
||||
title = { Text(stringResource(R.string.dialog_edit_device_name_title)) },
|
||||
text = {
|
||||
OutlinedTextField(
|
||||
value = inputName,
|
||||
onValueChange = { inputName = it },
|
||||
label = { Text(stringResource(R.string.dialog_edit_device_name_hint)) },
|
||||
singleLine = true,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
)
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
val trimmed = inputName.trim()
|
||||
if (trimmed.isNotBlank()) {
|
||||
onEvent(TemperatureHumidityUiEvent.ChangeDeviceName(DeviceName(trimmed)))
|
||||
}
|
||||
showEditNameDialog = false
|
||||
},
|
||||
enabled = inputName.isNotBlank(),
|
||||
) {
|
||||
Text(stringResource(R.string.action_confirm))
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(onClick = { showEditNameDialog = false }) {
|
||||
Text(stringResource(R.string.action_cancel))
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@@ -353,7 +302,11 @@ private fun NoDataCard(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center,
|
||||
) {
|
||||
Text("📭", style = MaterialTheme.typography.displaySmall)
|
||||
ABoxIcon(
|
||||
key = ABoxIconKey.SENSOR,
|
||||
contentDescription = "暂无传感器数据",
|
||||
modifier = Modifier.size(40.dp),
|
||||
)
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
Text(
|
||||
text = stringResource(R.string.th_no_data_title),
|
||||
@@ -432,9 +385,11 @@ private fun ErrorBanner(
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
modifier = Modifier.weight(1f),
|
||||
)
|
||||
TextButton(onClick = onDismiss) {
|
||||
Text("✕")
|
||||
}
|
||||
ABoxIconButton(
|
||||
key = ABoxIconKey.CLOSE,
|
||||
contentDescription = "关闭错误提示",
|
||||
onClick = onDismiss,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user