feat(ui): complete ABox app experience redesign (#10)

## Summary

- rebuild the authenticated shell, device dashboard, device detail pages, scenes, activity timeline, account sheet, and settings experience
- redesign infrared remote management and controls, including custom remotes, learn-state handling, slot isolation, and safe default content
- add persisted theme controls with internal accent, color-style, and color-standard resolution while keeping dynamic color authoritative
- add ABox profile defaults for the three exact gateway device names, editable starter scenes, and custom infrared remotes
- persist real activity events for device commands, infrared actions, and scene execution
- stabilize navigation and back behavior, including duplicate top-back protection and removal of the unfinished predictive-back option
- update launcher icons and bilingual application name

## Verification

- `:android:app:assembleDebug`
- installed the debug APK on `emulator-5554`
- manually exercised device detail navigation, settings/theme navigation, infrared management, activity records, and repeated back actions

## Notes

- no automated test suite was run during the visual iteration cycle
- `docs/superpowers/**` and local reference repositories are excluded from this PR

Reviewed-on: #10
Co-authored-by: KremeCN <3265494849@qq.com>
This commit was merged in pull request #10.
This commit is contained in:
2026-08-27 23:25:07 +08:00
committed by KremeCN
parent 1570a95f30
commit 86b7e5849b
194 changed files with 11198 additions and 1444 deletions
@@ -29,21 +29,21 @@ class SimulationDeviceCatalog : DeviceCatalog {
private fun defaultDevices(profileId: ProviderProfileId): List<DeviceDescriptor> = listOf(
DeviceDescriptor(
id = DeviceId("${profileId.value}:socket-1"),
id = DeviceId("${profileId.value}:Zigbee插座控制器"),
profileId = profileId,
name = DeviceName("socket-1"),
name = DeviceName("Zigbee插座控制器"),
type = DeviceType.SOCKET,
),
DeviceDescriptor(
id = DeviceId("${profileId.value}:th-1"),
id = DeviceId("${profileId.value}:温湿度传感器"),
profileId = profileId,
name = DeviceName("th-1"),
name = DeviceName("温湿度传感器"),
type = DeviceType.TEMPERATURE_HUMIDITY,
),
DeviceDescriptor(
id = DeviceId("${profileId.value}:ir-1"),
id = DeviceId("${profileId.value}:红外控制器"),
profileId = profileId,
name = DeviceName("ir-1"),
name = DeviceName("红外控制器"),
type = DeviceType.INFRARED,
),
)
@@ -33,6 +33,15 @@ class SimulationSocketGateway : SocketGateway {
states[key] = powerState
return DomainResult.Success(SocketStatus(profileId, deviceName, powerState))
}
override suspend fun commandPower(
profileId: ProviderProfileId,
deviceName: DeviceName,
powerState: SocketPowerState,
): DomainResult<Unit> {
states[DeviceKey(profileId, deviceName)] = powerState
return DomainResult.Success(Unit)
}
}
class SimulationTemperatureHumidityGateway : TemperatureHumidityGateway {