新增设备列表 Compose 页面 #8
+54
@@ -0,0 +1,54 @@
|
|||||||
|
package com.flagship.abox.manager.ui.devicecontrollist
|
||||||
|
|
||||||
|
import androidx.activity.ComponentActivity
|
||||||
|
import androidx.compose.ui.test.assertIsDisplayed
|
||||||
|
import androidx.compose.ui.test.junit4.createAndroidComposeRule
|
||||||
|
import androidx.compose.ui.test.onNodeWithText
|
||||||
|
import androidx.compose.ui.test.performClick
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
|
import com.flagship.abox.manager.R
|
||||||
|
import com.flagship.abox.manager.designsystem.ABoxTheme
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Rule
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
class DeviceListScreenTest {
|
||||||
|
@get:Rule
|
||||||
|
val composeRule = createAndroidComposeRule<ComponentActivity>()
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun deviceListRendersAllDeviceCategoryButtonsAndHandlesClicks() {
|
||||||
|
var socketClicks = 0
|
||||||
|
var tempClicks = 0
|
||||||
|
var infraredClicks = 0
|
||||||
|
|
||||||
|
val context = composeRule.activity
|
||||||
|
val socketTitle = context.getString(R.string.device_socket_title)
|
||||||
|
val tempTitle = context.getString(R.string.device_temperature_humidity_title)
|
||||||
|
val infraredTitle = context.getString(R.string.device_infrared_title)
|
||||||
|
val listTitle = context.getString(R.string.device_list_title)
|
||||||
|
|
||||||
|
composeRule.setContent {
|
||||||
|
ABoxTheme {
|
||||||
|
DeviceListScreen(
|
||||||
|
onSocketClick = { socketClicks++ },
|
||||||
|
onTemperatureHumidityClick = { tempClicks++ },
|
||||||
|
onInfraredClick = { infraredClicks++ },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
composeRule.onNodeWithText(listTitle).assertIsDisplayed()
|
||||||
|
|
||||||
|
composeRule.onNodeWithText(socketTitle).assertIsDisplayed().performClick()
|
||||||
|
assertEquals(1, socketClicks)
|
||||||
|
|
||||||
|
composeRule.onNodeWithText(tempTitle).assertIsDisplayed().performClick()
|
||||||
|
assertEquals(1, tempClicks)
|
||||||
|
|
||||||
|
composeRule.onNodeWithText(infraredTitle).assertIsDisplayed().performClick()
|
||||||
|
assertEquals(1, infraredClicks)
|
||||||
|
}
|
||||||
|
}
|
||||||
+14
-16
@@ -12,18 +12,20 @@ import androidx.compose.material3.Text
|
|||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.flagship.abox.manager.R
|
||||||
import com.flagship.abox.manager.designsystem.ABoxButton
|
import com.flagship.abox.manager.designsystem.ABoxButton
|
||||||
import com.flagship.abox.manager.designsystem.ABoxTheme
|
import com.flagship.abox.manager.designsystem.ABoxTheme
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun DeviceListScreen(
|
fun DeviceListScreen(
|
||||||
onSocketClick: () -> Unit,
|
|
||||||
onTemperatureHumidityClick: () -> Unit,
|
|
||||||
|
alZerNest marked this conversation as resolved
Outdated
|
|||||||
onInfraredClick: () -> Unit,
|
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
|
onSocketClick: () -> Unit = {},
|
||||||
|
onTemperatureHumidityClick: () -> Unit = {},
|
||||||
|
onInfraredClick: () -> Unit = {},
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
@@ -34,29 +36,29 @@ fun DeviceListScreen(
|
|||||||
verticalArrangement = Arrangement.Center,
|
verticalArrangement = Arrangement.Center,
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = "设备列表",
|
text = stringResource(R.string.device_list_title),
|
||||||
style = MaterialTheme.typography.headlineLarge,
|
style = MaterialTheme.typography.headlineLarge,
|
||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center,
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
text = "选择需要控制或查看状态的 ABox 终端设备。",
|
text = stringResource(R.string.device_list_description),
|
||||||
modifier = Modifier.padding(top = 12.dp, bottom = 32.dp),
|
modifier = Modifier.padding(top = 12.dp, bottom = 32.dp),
|
||||||
style = MaterialTheme.typography.bodyLarge,
|
style = MaterialTheme.typography.bodyLarge,
|
||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center,
|
||||||
)
|
)
|
||||||
DeviceEntryButton(
|
DeviceEntryButton(
|
||||||
text = "智能插座",
|
text = stringResource(R.string.device_socket_title),
|
||||||
description = "进入智能插座相关功能。",
|
description = stringResource(R.string.device_socket_description),
|
||||||
onClick = onSocketClick,
|
onClick = onSocketClick,
|
||||||
)
|
)
|
||||||
DeviceEntryButton(
|
DeviceEntryButton(
|
||||||
text = "温湿度传感器",
|
text = stringResource(R.string.device_temperature_humidity_title),
|
||||||
description = "进入温湿度状态相关功能。",
|
description = stringResource(R.string.device_temperature_humidity_description),
|
||||||
onClick = onTemperatureHumidityClick,
|
onClick = onTemperatureHumidityClick,
|
||||||
)
|
)
|
||||||
DeviceEntryButton(
|
DeviceEntryButton(
|
||||||
text = "红外控制器",
|
text = stringResource(R.string.device_infrared_title),
|
||||||
description = "进入红外控制器相关功能。",
|
description = stringResource(R.string.device_infrared_description),
|
||||||
onClick = onInfraredClick,
|
onClick = onInfraredClick,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -88,10 +90,6 @@ private fun DeviceEntryButton(
|
|||||||
@Composable
|
@Composable
|
||||||
private fun DeviceListScreenPreview() {
|
private fun DeviceListScreenPreview() {
|
||||||
ABoxTheme {
|
ABoxTheme {
|
||||||
DeviceListScreen(
|
DeviceListScreen()
|
||||||
onSocketClick = {},
|
|
||||||
onTemperatureHumidityClick = {},
|
|
||||||
onInfraredClick = {},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import com.flagship.abox.manager.R
|
|||||||
import com.flagship.abox.manager.designsystem.ABoxNavigationBar
|
import com.flagship.abox.manager.designsystem.ABoxNavigationBar
|
||||||
import com.flagship.abox.manager.designsystem.ABoxNavigationBarItem
|
import com.flagship.abox.manager.designsystem.ABoxNavigationBarItem
|
||||||
import com.flagship.abox.manager.designsystem.ABoxTopPillBar
|
import com.flagship.abox.manager.designsystem.ABoxTopPillBar
|
||||||
|
import com.flagship.abox.manager.ui.devicecontrollist.DeviceListScreen
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main authenticated application shell.
|
* Main authenticated application shell.
|
||||||
@@ -50,7 +51,7 @@ fun MainAppShell(
|
|||||||
onAddClick: (() -> Unit)? = null,
|
onAddClick: (() -> Unit)? = null,
|
||||||
actionInProgress: Boolean = false,
|
actionInProgress: Boolean = false,
|
||||||
errorMessage: String? = null,
|
errorMessage: String? = null,
|
||||||
devicesSlot: @Composable () -> Unit = { DefaultDevicesSlot() },
|
devicesSlot: @Composable () -> Unit = { DeviceListScreen() },
|
||||||
scenesSlot: @Composable () -> Unit = { DefaultScenesSlot() },
|
scenesSlot: @Composable () -> Unit = { DefaultScenesSlot() },
|
||||||
|
pr-agent-bot
commented
无效入口
**无效入口**
`MainAppShell` 默认直接创建 `DeviceListScreen()`,但没有传入任何点击回调,因此三个设备按钮都会使用空实现。任何未显式覆盖 `devicesSlot` 的调用方都会展示可点击但无响应的入口;应在路由完成前保留占位内容,或由壳层传入实际回调。
<!-- pr-agent-dedup: 5c1093080900 -->
<!-- pr-agent-key-issue-location: 256791003a90 -->
|
|||||||
activitySlot: @Composable () -> Unit = { DefaultActivitySlot() },
|
activitySlot: @Composable () -> Unit = { DefaultActivitySlot() },
|
||||||
) {
|
) {
|
||||||
@@ -133,14 +134,6 @@ fun MainAppShell(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun DefaultDevicesSlot() {
|
|
||||||
SlotPlaceholder(
|
|
||||||
title = stringResource(R.string.devices_placeholder_title),
|
|
||||||
description = stringResource(R.string.devices_placeholder_description),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun DefaultScenesSlot() {
|
private fun DefaultScenesSlot() {
|
||||||
SlotPlaceholder(
|
SlotPlaceholder(
|
||||||
|
|||||||
@@ -42,4 +42,14 @@
|
|||||||
<string name="scenes_placeholder_description">情景动作与执行插槽(由 tzh 模块实现)。</string>
|
<string name="scenes_placeholder_description">情景动作与执行插槽(由 tzh 模块实现)。</string>
|
||||||
<string name="activity_placeholder_title">活动记录</string>
|
<string name="activity_placeholder_title">活动记录</string>
|
||||||
<string name="activity_placeholder_description">未记录任何事件。</string>
|
<string name="activity_placeholder_description">未记录任何事件。</string>
|
||||||
|
|
||||||
|
<!-- 设备列表 -->
|
||||||
|
<string name="device_list_title">设备列表</string>
|
||||||
|
<string name="device_list_description">选择需要控制或查看状态的 ABox 终端设备。</string>
|
||||||
|
<string name="device_socket_title">智能插座</string>
|
||||||
|
<string name="device_socket_description">进入智能插座相关功能。</string>
|
||||||
|
<string name="device_temperature_humidity_title">温湿度传感器</string>
|
||||||
|
<string name="device_temperature_humidity_description">进入温湿度状态相关功能。</string>
|
||||||
|
<string name="device_infrared_title">红外控制器</string>
|
||||||
|
<string name="device_infrared_description">进入红外控制器相关功能。</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -42,4 +42,14 @@
|
|||||||
<string name="scenes_placeholder_description">Scene actions and execution slot for tzh.</string>
|
<string name="scenes_placeholder_description">Scene actions and execution slot for tzh.</string>
|
||||||
<string name="activity_placeholder_title">Activity Log</string>
|
<string name="activity_placeholder_title">Activity Log</string>
|
||||||
<string name="activity_placeholder_description">No recorded events yet.</string>
|
<string name="activity_placeholder_description">No recorded events yet.</string>
|
||||||
|
|
||||||
|
<!-- Device list -->
|
||||||
|
<string name="device_list_title">Device List</string>
|
||||||
|
<string name="device_list_description">Select an ABox terminal device to control or check status.</string>
|
||||||
|
<string name="device_socket_title">Smart Socket</string>
|
||||||
|
<string name="device_socket_description">Access smart socket features.</string>
|
||||||
|
<string name="device_temperature_humidity_title">Temperature & Humidity Sensor</string>
|
||||||
|
<string name="device_temperature_humidity_description">View temperature and humidity status.</string>
|
||||||
|
<string name="device_infrared_title">Infrared Controller</string>
|
||||||
|
<string name="device_infrared_description">Access infrared controller features.</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
Reference in New Issue
Block a user
内容裁剪
根布局使用固定内边距和垂直居中,但未提供滚动能力。在横屏、小尺寸设备或启用较大系统字体时,内容总高度会超过可用空间,导致顶部或底部的设备入口被裁剪且无法访问。建议使用可滚动布局或
LazyColumn。已处理:为 DeviceListScreen 根布局添加了 verticalScroll(rememberScrollState()),避免横屏、小屏或大字体场景下内容被裁剪且无法访问。已本地验证 :android:app:assembleDebug 通过。
Addressed by adding verticalScroll(rememberScrollState()) to the root layout of DeviceListScreen, so the list remains accessible on landscape, small screens, and large font settings. Verified with :android:app:assembleDebug.