diff --git a/android/app/src/androidTest/kotlin/com/flagship/abox/manager/ui/devicecontrollist/DeviceListScreenTest.kt b/android/app/src/androidTest/kotlin/com/flagship/abox/manager/ui/devicecontrollist/DeviceListScreenTest.kt new file mode 100644 index 0000000..4db7a3b --- /dev/null +++ b/android/app/src/androidTest/kotlin/com/flagship/abox/manager/ui/devicecontrollist/DeviceListScreenTest.kt @@ -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() + + @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) + } +} diff --git a/android/app/src/main/kotlin/com/flagship/abox/manager/ui/devicecontrollist/DeviceListScreen.kt b/android/app/src/main/kotlin/com/flagship/abox/manager/ui/devicecontrollist/DeviceListScreen.kt new file mode 100644 index 0000000..2dfadcc --- /dev/null +++ b/android/app/src/main/kotlin/com/flagship/abox/manager/ui/devicecontrollist/DeviceListScreen.kt @@ -0,0 +1,95 @@ +package com.flagship.abox.manager.ui.devicecontrollist + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +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.ABoxTheme + +@Composable +fun DeviceListScreen( + modifier: Modifier = Modifier, + onSocketClick: () -> Unit = {}, + onTemperatureHumidityClick: () -> Unit = {}, + onInfraredClick: () -> Unit = {}, +) { + Column( + modifier = modifier + .fillMaxSize() + .verticalScroll(rememberScrollState()) + .padding(32.dp), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center, + ) { + Text( + text = stringResource(R.string.device_list_title), + style = MaterialTheme.typography.headlineLarge, + textAlign = TextAlign.Center, + ) + Text( + text = stringResource(R.string.device_list_description), + modifier = Modifier.padding(top = 12.dp, bottom = 32.dp), + style = MaterialTheme.typography.bodyLarge, + textAlign = TextAlign.Center, + ) + DeviceEntryButton( + text = stringResource(R.string.device_socket_title), + description = stringResource(R.string.device_socket_description), + onClick = onSocketClick, + ) + DeviceEntryButton( + text = stringResource(R.string.device_temperature_humidity_title), + description = stringResource(R.string.device_temperature_humidity_description), + onClick = onTemperatureHumidityClick, + ) + DeviceEntryButton( + text = stringResource(R.string.device_infrared_title), + description = stringResource(R.string.device_infrared_description), + onClick = onInfraredClick, + ) + } +} + +@Composable +private fun DeviceEntryButton( + text: String, + description: String, + onClick: () -> Unit, +) { + ABoxButton( + onClick = onClick, + modifier = Modifier + .fillMaxWidth() + .padding(top = 16.dp), + ) { + Column( + modifier = Modifier.padding(vertical = 8.dp), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + Text(text = text, style = MaterialTheme.typography.titleMedium) + Text(text = description, style = MaterialTheme.typography.bodySmall) + } + } +} + +@Preview(showBackground = true) +@Composable +private fun DeviceListScreenPreview() { + ABoxTheme { + DeviceListScreen() + } +} diff --git a/android/app/src/main/kotlin/com/flagship/abox/manager/ui/shell/MainAppShell.kt b/android/app/src/main/kotlin/com/flagship/abox/manager/ui/shell/MainAppShell.kt index 6c2c8ce..d32ebdc 100644 --- a/android/app/src/main/kotlin/com/flagship/abox/manager/ui/shell/MainAppShell.kt +++ b/android/app/src/main/kotlin/com/flagship/abox/manager/ui/shell/MainAppShell.kt @@ -29,6 +29,7 @@ import com.flagship.abox.manager.R import com.flagship.abox.manager.designsystem.ABoxNavigationBar import com.flagship.abox.manager.designsystem.ABoxNavigationBarItem import com.flagship.abox.manager.designsystem.ABoxTopPillBar +import com.flagship.abox.manager.ui.devicecontrollist.DeviceListScreen /** * Main authenticated application shell. @@ -50,7 +51,7 @@ fun MainAppShell( onAddClick: (() -> Unit)? = null, actionInProgress: Boolean = false, errorMessage: String? = null, - devicesSlot: @Composable () -> Unit = { DefaultDevicesSlot() }, + devicesSlot: @Composable () -> Unit = { DeviceListScreen() }, scenesSlot: @Composable () -> Unit = { DefaultScenesSlot() }, 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 private fun DefaultScenesSlot() { SlotPlaceholder( diff --git a/android/app/src/main/res/values-zh-rCN/strings.xml b/android/app/src/main/res/values-zh-rCN/strings.xml index 696dc16..f09dfa4 100644 --- a/android/app/src/main/res/values-zh-rCN/strings.xml +++ b/android/app/src/main/res/values-zh-rCN/strings.xml @@ -42,4 +42,14 @@ 情景动作与执行插槽(由 tzh 模块实现)。 活动记录 未记录任何事件。 + + + 设备列表 + 选择需要控制或查看状态的 ABox 终端设备。 + 智能插座 + 进入智能插座相关功能。 + 温湿度传感器 + 进入温湿度状态相关功能。 + 红外控制器 + 进入红外控制器相关功能。 diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml index c8818bb..f9455e4 100644 --- a/android/app/src/main/res/values/strings.xml +++ b/android/app/src/main/res/values/strings.xml @@ -42,4 +42,14 @@ Scene actions and execution slot for tzh. Activity Log No recorded events yet. + + + Device List + Select an ABox terminal device to control or check status. + Smart Socket + Access smart socket features. + Temperature & Humidity Sensor + View temperature and humidity status. + Infrared Controller + Access infrared controller features. diff --git a/docs/device-control-compose-ui-change-log.md b/docs/device-control-compose-ui-change-log.md new file mode 100644 index 0000000..9cc1428 --- /dev/null +++ b/docs/device-control-compose-ui-change-log.md @@ -0,0 +1,195 @@ +# Device List Compose UI Change Log + +Branch: `feature/device-control-compose-ui` + +## Summary + +This branch adds only the Kotlin Jetpack Compose device list page owned by this feature area. + +The implementation provides a reusable Compose screen that displays the ABox terminal device categories: + +- Smart socket +- Temperature/humidity sensor +- Infrared controller + +This branch intentionally does not modify the app entry point or app shell routing. The app shell, login flow, and detail-feature routing are owned by other feature branches. + +## Added Files + +### `android/app/src/main/kotlin/com/flagship/abox/manager/ui/devicecontrollist/DeviceListScreen.kt` + +Adds the device list page. + +The page displays entries for: + +- Smart socket +- Temperature/humidity sensor +- Infrared controller + +Current scope: + +- Display the device categories as list entry UI. +- Keep the UI in Kotlin Compose. +- Expose click callbacks for each device category. +- Avoid adding app-shell routing, detail routes, or detail control pages in this branch. + +Integration API: + +```kotlin +DeviceListScreen( + onSocketClick = { /* route to socket module later */ }, + onTemperatureHumidityClick = { /* route to temperature/humidity module later */ }, + onInfraredClick = { /* route to infrared controller module later */ }, +) +``` + +Future integration point: + +- The app shell or feature owner responsible for routing can host this screen and connect these callbacks to their own routes/modules later. + +## Architecture Notes + +This branch follows the current repository direction: + +- Kotlin instead of Java +- Jetpack Compose instead of XML layouts +- Single-Activity UI instead of multiple Activities +- Navigation Compose compatibility through external callbacks +- Existing design-system wrappers where practical + +This branch intentionally does not copy the previous Java/XML experiment module into the team repository. + +## Scope Intentionally Not Included + +This branch does not include: + +- App entry point changes +- App shell or login routing changes +- A device-control navigation graph file +- Socket control screen implementation +- Temperature/humidity status screen implementation +- Infrared controller screen implementation +- Shared detail-control component scaffolding +- Direct ABSDK calls from Compose UI +- New Java Activity classes +- XML layout files +- A separate Android module copied from the experiment project +- Full session/login integration for device gateway calls +- Persistent infrared key storage + +These should be added by the corresponding feature owners in later branches or follow-up commits after team architecture review. + +## Verification + +- Built and ran `android.app` from Android Studio successfully during local validation. +- `:android:app:assembleDebug` completed successfully after trimming the feature scope. + +## Files Intended for Commit + +The intended commit scope is limited to: + +```text +android/app/src/main/kotlin/com/flagship/abox/manager/ui/devicecontrollist/DeviceListScreen.kt +docs/device-control-compose-ui-change-log.md +``` + +`settings.gradle.kts` is intentionally excluded from this feature commit. Local Gradle/JDK/toolchain setup should be handled on the developer machine and should not modify the team-provided project configuration in this branch. + +--- + +# 设备列表 Compose UI 修改说明(中文) + +分支:`feature/device-control-compose-ui` + +## 概要 + +本分支只新增当前分工负责的 Kotlin Jetpack Compose 设备列表页面。 + +设备列表展示的设备类别包括: + +- 智能插座 +- 温湿度传感器 +- 红外控制器 + +本分支故意不修改 App 入口或应用壳路由。程序入口、登录流程和各设备详情模块路由由其他功能分支负责。 + +## 新增文件 + +### `android/app/src/main/kotlin/com/flagship/abox/manager/ui/devicecontrollist/DeviceListScreen.kt` + +新增设备列表页面。 + +页面展示三个设备入口: + +- 智能插座 +- 温湿度传感器 +- 红外控制器 + +当前实现范围: + +- 展示设备类别入口 UI。 +- 保持 Kotlin Compose 实现。 +- 为每个设备类别暴露点击回调。 +- 不在本分支实现 App 入口接入、设备详情 route 或设备控制页面。 + +对接 API: + +```kotlin +DeviceListScreen( + onSocketClick = { /* 后续跳转到智能插座模块 */ }, + onTemperatureHumidityClick = { /* 后续跳转到温湿度模块 */ }, + onInfraredClick = { /* 后续跳转到红外控制器模块 */ }, +) +``` + +后续接入点: + +- 由负责 App shell 或对应设备模块的同学,在各自分支中挂载这个页面,并把这些回调连接到他们自己的详情路由或功能模块。 + +## 架构说明 + +本分支遵循当前小组仓库的技术方向: + +- 使用 Kotlin,而不是 Java。 +- 使用 Jetpack Compose,而不是 XML layout。 +- 使用单 Activity 架构,而不是多个 Activity 跳转。 +- 通过外部回调保持与 Navigation Compose 的兼容性。 +- 尽量复用已有 design system 中的组件封装。 + +本分支没有把之前个人实验项目中的 Java/XML 模块直接复制进团队仓库。 + +## 本分支未包含的内容 + +本分支暂不包含: + +- App 入口修改。 +- App shell 或登录路由修改。 +- 设备控制 navigation graph 文件。 +- 智能插座控制页面。 +- 温湿度状态页面。 +- 红外控制器操作页面。 +- 设备详情控制页面共用组件。 +- Compose UI 中直接调用 ABSDK。 +- 新增 Java Activity。 +- 新增 XML layout。 +- 从个人实验项目复制独立 Android 模块。 +- 完整登录/session 与设备 gateway 的联动。 +- 红外学习按键的持久化存储。 + +这些内容建议由对应模块负责人在后续 branch 或后续 commit 中继续实现。 + +## 验证 + +- 本地验证过程中已从 Android Studio 成功 build/run `android.app`。 +- 修剪职责范围后,`:android:app:assembleDebug` 构建成功。 + +## 预期提交范围 + +本次提交范围应限制在: + +```text +android/app/src/main/kotlin/com/flagship/abox/manager/ui/devicecontrollist/DeviceListScreen.kt +docs/device-control-compose-ui-change-log.md +``` + +`settings.gradle.kts` 当前不属于本次设备列表 UI 功能提交范围。本地 Gradle/JDK/toolchain 配置应在开发者本机处理,不应修改团队提供的项目配置文件。 diff --git a/docs/device-list-compose-ui-pr-description.md b/docs/device-list-compose-ui-pr-description.md new file mode 100644 index 0000000..28d50e7 --- /dev/null +++ b/docs/device-list-compose-ui-pr-description.md @@ -0,0 +1,133 @@ +# WIP: Add device list Compose screen + +## Summary + +This MR adds only the reusable Kotlin Jetpack Compose device list screen for my assigned scope. + +The screen displays the three ABox device categories: + +- Smart socket +- Temperature/humidity sensor +- Infrared controller + +This MR intentionally does not modify the app entry point, login flow, app shell routing, or any device detail/control screen. Those parts are handled by other feature branches. + +## Changes + +- Add `DeviceListScreen`. +- Expose click callbacks for each device category: + - `onSocketClick` + - `onTemperatureHumidityClick` + - `onInfraredClick` +- Update the device-list change log document. +- Remove the earlier out-of-scope temporary device control screens from this branch. + +## Scope + +Included: + +- Device list Compose UI component +- Device category entry UI +- Callback API for future route integration + +Not included: + +- App entry point changes +- Login flow changes +- Device control navigation graph +- Smart socket control screen +- Temperature/humidity status screen +- Infrared controller screen +- Direct ABSDK calls +- Java Activity classes +- XML layout files + +## Integration Notes + +The screen is designed to be hosted by the app shell or routing owner later: + +```kotlin +DeviceListScreen( + onSocketClick = { /* route to socket module */ }, + onTemperatureHumidityClick = { /* route to temperature/humidity module */ }, + onInfraredClick = { /* route to infrared controller module */ }, +) +``` + +The current branch keeps these callbacks external so other feature owners can connect their modules without this MR taking ownership of routing. + +## Verification + +- Built and ran `android.app` locally from Android Studio. +- `:android:app:assembleDebug` completed successfully after trimming this branch to the device-list component scope. + +## Notes + +`settings.gradle.kts` is intentionally not part of this MR. Local Gradle/JDK/toolchain setup is handled on the developer machine and should not modify the team-provided project configuration. + +--- + +# WIP: 新增设备列表 Compose 页面 + +## 概要 + +本 MR 只新增我当前分工负责的 Kotlin Jetpack Compose 设备列表页面组件。 + +设备列表展示三类 ABox 设备入口: + +- 智能插座 +- 温湿度传感器 +- 红外控制器 + +本 MR 故意不修改 App 入口、登录流程、应用壳路由,也不实现任何设备详情/控制页面。这些部分由其他功能分支负责。 + +## 修改内容 + +- 新增 `DeviceListScreen`。 +- 为三类设备入口暴露点击回调: + - `onSocketClick` + - `onTemperatureHumidityClick` + - `onInfraredClick` +- 更新设备列表变更说明文档。 +- 从本分支中移除早期临时加入、但不属于当前分工范围的设备控制页面。 + +## 本 MR 包含 + +- 设备列表 Compose UI 组件 +- 设备类别入口 UI +- 后续路由接入所需的 callback API + +## 本 MR 不包含 + +- App 入口修改 +- 登录流程修改 +- 设备控制 navigation graph +- 智能插座控制页面 +- 温湿度状态页面 +- 红外控制器页面 +- Compose UI 中直接调用 ABSDK +- Java Activity +- XML layout + +## 对接说明 + +该页面后续可以由 App shell 或路由负责人挂载: + +```kotlin +DeviceListScreen( + onSocketClick = { /* 后续跳转到智能插座模块 */ }, + onTemperatureHumidityClick = { /* 后续跳转到温湿度模块 */ }, + onInfraredClick = { /* 后续跳转到红外控制器模块 */ }, +) +``` + +当前分支只提供页面和回调 API,不负责具体跳转目标,以便其他模块负责人对接自己的功能页面。 + +## 验证 + +- 已在本地通过 Android Studio 成功 build/run `android.app`。 +- 修剪为设备列表组件范围后,`:android:app:assembleDebug` 构建成功。 + +## 备注 + +`settings.gradle.kts` 不属于本 MR 范围。本地 Gradle/JDK/toolchain 配置在开发者本机处理,不修改团队提供的项目配置文件。