From d8d9eb4f283c77d3341d35404fadb2c257594978 Mon Sep 17 00:00:00 2001
From: KremeCN <3265494849@qq.com>
Date: Wed, 26 Aug 2026 21:14:09 +0800
Subject: [PATCH] fix: remove legacy text icons and placeholders
---
.../manager/ui/scene/SceneEditorScreen.kt | 2 +-
.../abox/manager/ui/scene/SceneListScreen.kt | 40 ++++++-------
.../src/main/res/values-zh-rCN/strings.xml | 50 ++++++++--------
android/app/src/main/res/values/strings.xml | 50 ++++++++--------
android/feature/infrared/build.gradle.kts | 1 +
.../manager/infrared/hub/InfraredHubScreen.kt | 34 +++++------
.../infrared/panel/RemotePanelScreen.kt | 60 +++++++++++--------
.../manager/infrared/remote/RemoteModels.kt | 26 ++++----
.../remote/ui/InfraredRemoteScreen.kt | 10 ++--
.../src/main/res/values-zh-rCN/strings.xml | 24 ++++----
.../infrared/src/main/res/values/strings.xml | 22 +++----
.../fakes/FakeVirtualRemoteRepository.kt | 13 ++--
12 files changed, 173 insertions(+), 159 deletions(-)
diff --git a/android/app/src/main/kotlin/com/flagship/abox/manager/ui/scene/SceneEditorScreen.kt b/android/app/src/main/kotlin/com/flagship/abox/manager/ui/scene/SceneEditorScreen.kt
index 5c6a765..22f275f 100644
--- a/android/app/src/main/kotlin/com/flagship/abox/manager/ui/scene/SceneEditorScreen.kt
+++ b/android/app/src/main/kotlin/com/flagship/abox/manager/ui/scene/SceneEditorScreen.kt
@@ -747,7 +747,7 @@ private fun ActionItemRow(
@Composable
private fun SceneTrigger.describe(): String = when (this) {
- is SceneTrigger.Time -> "⏰ $timeOfDay"
+ is SceneTrigger.Time -> "定时 $timeOfDay"
is SceneTrigger.Temperature -> stringResource(R.string.scene_trigger_desc_temp, operator.symbol, thresholdCelsius.toInt().toString())
is SceneTrigger.Humidity -> stringResource(R.string.scene_trigger_desc_humidity, operator.symbol, thresholdPercent.toInt().toString())
is SceneTrigger.DeviceState -> stringResource(R.string.scene_trigger_desc_device, deviceName.value, expectedState)
diff --git a/android/app/src/main/kotlin/com/flagship/abox/manager/ui/scene/SceneListScreen.kt b/android/app/src/main/kotlin/com/flagship/abox/manager/ui/scene/SceneListScreen.kt
index 5560346..a2659fd 100644
--- a/android/app/src/main/kotlin/com/flagship/abox/manager/ui/scene/SceneListScreen.kt
+++ b/android/app/src/main/kotlin/com/flagship/abox/manager/ui/scene/SceneListScreen.kt
@@ -68,6 +68,8 @@ import com.flagship.abox.manager.domain.Scene
import com.flagship.abox.manager.domain.SceneColor
import com.flagship.abox.manager.domain.SceneIcon
import com.flagship.abox.manager.domain.SceneId
+import com.flagship.abox.manager.designsystem.icon.ABoxIcon
+import com.flagship.abox.manager.designsystem.icon.ABoxIconKey
import kotlinx.coroutines.flow.collectLatest
@OptIn(ExperimentalMaterial3Api::class)
@@ -250,9 +252,10 @@ private fun SceneCard(
),
contentAlignment = Alignment.Center,
) {
- Text(
- text = scene.icon.displayEmoji(),
- style = MaterialTheme.typography.titleMedium,
+ ABoxIcon(
+ key = scene.icon.toABoxIconKey(),
+ contentDescription = scene.name,
+ modifier = Modifier.size(28.dp),
)
}
Spacer(Modifier.width(12.dp))
@@ -375,10 +378,7 @@ private fun EmptySceneList(modifier: Modifier = Modifier) {
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center,
) {
- Text(
- text = "⚡",
- style = MaterialTheme.typography.displayMedium,
- )
+ ABoxIcon(ABoxIconKey.SCENES, contentDescription = "暂无情景", modifier = Modifier.size(48.dp))
Spacer(Modifier.size(8.dp))
Text(
text = stringResource(R.string.scene_empty_title),
@@ -396,19 +396,19 @@ private fun EmptySceneList(modifier: Modifier = Modifier) {
}
}
-fun SceneIcon.displayEmoji(): String = when (this) {
- SceneIcon.HOME -> "🏠"
- SceneIcon.OFFICE -> "💼"
- SceneIcon.NIGHT -> "🌙"
- SceneIcon.MOVIE -> "🎬"
- SceneIcon.AWAY -> "🚶"
- SceneIcon.READING -> "📖"
- SceneIcon.DINING -> "🍽️"
- SceneIcon.GAMING -> "🎮"
- SceneIcon.THERMOSTAT -> "🌡️"
- SceneIcon.LIGHT -> "💡"
- SceneIcon.CLEAN -> "🧹"
- SceneIcon.CUSTOM -> "✨"
+fun SceneIcon.toABoxIconKey(): ABoxIconKey = when (this) {
+ SceneIcon.HOME -> ABoxIconKey.DEVICES
+ SceneIcon.OFFICE -> ABoxIconKey.ACTIVITY
+ SceneIcon.NIGHT -> ABoxIconKey.PENDING
+ SceneIcon.MOVIE -> ABoxIconKey.SCENES
+ SceneIcon.AWAY -> ABoxIconKey.OFFLINE
+ SceneIcon.READING -> ABoxIconKey.DEVICES
+ SceneIcon.DINING -> ABoxIconKey.DEVICES
+ SceneIcon.GAMING -> ABoxIconKey.SCENES
+ SceneIcon.THERMOSTAT -> ABoxIconKey.TEMPERATURE
+ SceneIcon.LIGHT -> ABoxIconKey.POWER
+ SceneIcon.CLEAN -> ABoxIconKey.REFRESH
+ SceneIcon.CUSTOM -> ABoxIconKey.UNKNOWN_DEVICE
}
internal fun SceneColor.toColorOrNull(): Color? {
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 89d8729..6edd76b 100644
--- a/android/app/src/main/res/values-zh-rCN/strings.xml
+++ b/android/app/src/main/res/values-zh-rCN/strings.xml
@@ -82,9 +82,9 @@
其他选项与外观
- + 新增触发器
- + 新增条件
- + 新增动作
+ 新增触发器
+ 新增条件
+ 新增动作
添加
保存指令
@@ -104,10 +104,10 @@
选择触发器类型
- ⏰ 定时时间触发
- 🌡️ 环境温度触发
- 💧 环境湿度触发
- 🔌 插座状态变更触发
+ 定时时间触发
+ 环境温度触发
+ 环境湿度触发
+ 插座状态变更触发
触发时间点(如:07:30)
温度阈值 (°C)
湿度阈值 (%)
@@ -118,19 +118,19 @@
选择限制条件
- 🌡️ 环境温度范围
- 💧 环境湿度范围
- 🔌 插座当前电源状态
- 🕒 生效时间区间
+ 环境温度范围
+ 环境湿度范围
+ 插座当前电源状态
+ 生效时间区间
起始时间(如:22:00)
结束时间(如:07:00)
选择执行动作
- 🔌 智能插座控制
- 📺 红外遥控按键
- ⏱️ 延时等待 (缓冲)
- 🔔 发送系统提示
+ 智能插座控制
+ 红外遥控按键
+ 延时等待(缓冲)
+ 发送系统提示
选择目标插座
设定电源状态
选择虚拟遥控器
@@ -144,8 +144,8 @@
插座【%1$s】: 设为 %2$s
遥控【%1$s】: 发送 %2$s
红外【%1$s】: 槽位 %2$s
- ⏱️ 等待 %1$d 秒
- 🔔 提示: %1$s
+ 等待 %1$d 秒
+ 提示:%1$s
执行指令
@@ -164,13 +164,13 @@
时间格式无效(请按 HH:mm 格式输入,如 07:30)
时间格式无效(请按 HH:mm 格式输入,如 22:00)
- ⏰ 定时
- 🌡️ 温度
- 💧 湿度
- 🔌 插座
- 📺 遥控
- ⏱️ 延时
- 🔔 提示
+ 定时
+ 温度
+ 湿度
+ 插座
+ 遥控
+ 延时
+ 提示
> 高于
< 低于
开启
@@ -184,7 +184,7 @@
尚未添加触发器,请点击下方按钮添加
尚未添加限制条件,请点击下方按钮添加
尚未添加执行动作,请点击下方按钮添加
- ⚡ %1$d 个触发器 • %2$d 个动作
+ %1$d 个触发器 · %2$d 个动作
%1$d 个执行动作
点击下方按钮立即开始执行
重新执行
diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml
index e3be99b..20b7022 100644
--- a/android/app/src/main/res/values/strings.xml
+++ b/android/app/src/main/res/values/strings.xml
@@ -82,9 +82,9 @@
Other Options & Appearance
- + Add Trigger
- + Add Condition
- + Add Action
+ Add Trigger
+ Add Condition
+ Add Action
Add
Save Command
@@ -104,10 +104,10 @@
Select Trigger Type
- ⏰ Time / Schedule Trigger
- 🌡️ Temperature Threshold
- 💧 Humidity Threshold
- 🔌 Socket State Changed
+ Time / Schedule Trigger
+ Temperature Threshold
+ Humidity Threshold
+ Socket State Changed
Trigger Time (e.g. 07:30)
Temperature Threshold (°C)
Humidity Threshold (%)
@@ -118,19 +118,19 @@
Select Condition
- 🌡️ Temperature Range
- 💧 Humidity Range
- 🔌 Current Socket Power
- 🕒 Active Time Range
+ Temperature Range
+ Humidity Range
+ Current Socket Power
+ Active Time Range
Start Time (e.g. 22:00)
End Time (e.g. 07:00)
Select Action
- 🔌 Smart Socket Control
- 📺 Infrared Remote Button
- ⏱️ Delay / Buffer Timer
- 🔔 System Notification
+ Smart Socket Control
+ Infrared Remote Button
+ Delay / Buffer Timer
+ System Notification
Select Target Socket
Target Power State
Select Virtual Remote
@@ -144,8 +144,8 @@
Socket [%1$s]: Set %2$s
Remote [%1$s]: Send %2$s
Infrared [%1$s]: Slot %2$s
- ⏱️ Delay %1$d seconds
- 🔔 Notify: %1$s
+ Delay %1$d seconds
+ Notify: %1$s
Execute Command
@@ -164,13 +164,13 @@
Invalid time format (use HH:mm, e.g. 07:30)
Invalid time format (use HH:mm, e.g. 22:00)
- ⏰ Schedule
- 🌡️ Temperature
- 💧 Humidity
- 🔌 Socket
- 📺 Remote
- ⏱️ Delay
- 🔔 Notify
+ Schedule
+ Temperature
+ Humidity
+ Socket
+ Remote
+ Delay
+ Notify
> Above
< Below
Turn ON
@@ -184,7 +184,7 @@
No triggers configured. Tap + below to add.
No conditions configured. Tap + below to add.
No actions configured. Tap + below to add.
- ⚡ %1$d triggers • %2$d actions
+ %1$d triggers · %2$d actions
%1$d actions
Tap the button below to run immediately
Re-run
diff --git a/android/feature/infrared/build.gradle.kts b/android/feature/infrared/build.gradle.kts
index 2bf2ebb..38c0709 100644
--- a/android/feature/infrared/build.gradle.kts
+++ b/android/feature/infrared/build.gradle.kts
@@ -57,6 +57,7 @@ dependencies {
implementation(libs.compose.ui)
implementation(libs.compose.ui.tooling.preview)
implementation(libs.compose.material3)
+ implementation(libs.compose.material.icons.extended)
testImplementation(libs.junit)
testImplementation(libs.kotlinx.coroutines.test)
diff --git a/android/feature/infrared/src/main/kotlin/com/flagship/abox/manager/infrared/hub/InfraredHubScreen.kt b/android/feature/infrared/src/main/kotlin/com/flagship/abox/manager/infrared/hub/InfraredHubScreen.kt
index cccbbf1..b8bb0a7 100644
--- a/android/feature/infrared/src/main/kotlin/com/flagship/abox/manager/infrared/hub/InfraredHubScreen.kt
+++ b/android/feature/infrared/src/main/kotlin/com/flagship/abox/manager/infrared/hub/InfraredHubScreen.kt
@@ -271,10 +271,10 @@ private fun VirtualRemoteCard(
verticalAlignment = Alignment.CenterVertically,
) {
val icon = when (remote.type) {
- RemoteDeviceType.TV -> "📺"
- RemoteDeviceType.AIR_CONDITIONER -> "❄️"
+ RemoteDeviceType.TV -> "电视"
+ RemoteDeviceType.AIR_CONDITIONER -> "空调"
RemoteDeviceType.FAN -> "🌀"
- RemoteDeviceType.CUSTOM -> "🎛️"
+ RemoteDeviceType.CUSTOM -> "自定义"
}
Text(icon, fontSize = 28.sp)
IconButton(onClick = onDelete, modifier = Modifier.testTag("delete_remote_${remote.id.value}")) {
@@ -288,11 +288,11 @@ private fun VirtualRemoteCard(
)
val modeText = if (remote.type == RemoteDeviceType.AIR_CONDITIONER) {
- "❄️ 状态机动态写码"
+ "状态机动态写码"
} else if (remote.transmissionMode == TransmissionMode.STATIC_SLOTS) {
- "🚀 静态独占槽位"
+ "静态独占槽位"
} else {
- "📦 动态写码"
+ "动态写码"
}
Text(
@@ -430,7 +430,7 @@ private fun CreateVirtualRemoteDialog(
OutlinedTextField(
value = name,
onValueChange = { name = it },
- label = { Text("遥控器名称(如:客厅电视、我的遥控器)") },
+ label = { Text("遥控器名称(如:电视、我的遥控器)") },
singleLine = true,
modifier = Modifier.fillMaxWidth().testTag("create_remote_name_input"),
)
@@ -443,10 +443,10 @@ private fun CreateVirtualRemoteDialog(
) {
OutlinedTextField(
value = when (selectedCustomLayout) {
- PanelLayoutStyle.TV_NAV -> "📺 电视导航布局 (内置方向盘/音量/频道)"
- PanelLayoutStyle.MEDIA_PLAYER -> "🎵 媒体播放器布局 (播放/快进/切歌)"
- PanelLayoutStyle.GRID -> "🎛️ 自由网格布局 (可自由增删按键)"
- PanelLayoutStyle.AC_COMPACT -> "❄️ 空调布局"
+ PanelLayoutStyle.TV_NAV -> "电视导航布局(内置方向盘、音量、频道)"
+ PanelLayoutStyle.MEDIA_PLAYER -> "媒体播放器布局(播放、快进、切歌)"
+ PanelLayoutStyle.GRID -> "自由网格布局(可自由增删按键)"
+ PanelLayoutStyle.AC_COMPACT -> "空调布局"
},
onValueChange = {},
readOnly = true,
@@ -459,21 +459,21 @@ private fun CreateVirtualRemoteDialog(
onDismissRequest = { layoutDropdownExpanded = false },
) {
DropdownMenuItem(
- text = { Text("📺 电视导航布局 (内置方向盘/音量/频道)") },
+ text = { Text("电视导航布局(内置方向盘、音量、频道)") },
onClick = {
selectedCustomLayout = PanelLayoutStyle.TV_NAV
layoutDropdownExpanded = false
},
)
DropdownMenuItem(
- text = { Text("🎵 媒体播放器布局 (播放/快进/切歌)") },
+ text = { Text("媒体播放器布局(播放、快进、切歌)") },
onClick = {
selectedCustomLayout = PanelLayoutStyle.MEDIA_PLAYER
layoutDropdownExpanded = false
},
)
DropdownMenuItem(
- text = { Text("🎛️ 自由网格布局 (可自由增删按键)") },
+ text = { Text("自由网格布局(可自由增删按键)") },
onClick = {
selectedCustomLayout = PanelLayoutStyle.GRID
layoutDropdownExpanded = false
@@ -538,7 +538,7 @@ private fun CreateVirtualRemoteDialog(
onClick = { transmissionMode = TransmissionMode.STATIC_SLOTS },
)
Column {
- Text("🚀 静态独占槽位模式", fontWeight = FontWeight.Medium)
+ Text("静态独占槽位模式", fontWeight = FontWeight.Medium)
Text(stringResource(R.string.infrared_hub_trans_mode_static_desc), fontSize = 11.sp, color = MaterialTheme.colorScheme.onSurfaceVariant)
}
}
@@ -552,7 +552,7 @@ private fun CreateVirtualRemoteDialog(
onClick = { transmissionMode = TransmissionMode.DYNAMIC_SCRATCH },
)
Column {
- Text("📦 动态写码模式", fontWeight = FontWeight.Medium)
+ Text("动态写码模式", fontWeight = FontWeight.Medium)
Text(stringResource(R.string.infrared_hub_trans_mode_dynamic_desc), fontSize = 11.sp, color = MaterialTheme.colorScheme.onSurfaceVariant)
}
}
@@ -563,7 +563,7 @@ private fun CreateVirtualRemoteDialog(
modifier = Modifier.fillMaxWidth(),
) {
Text(
- text = "❄️ 空调多维状态自动采用 App 状态机 + 动态缓冲写码,杜绝状态踩踏并节省槽位。",
+ text = "空调多维状态自动采用状态机和动态缓冲写码,避免状态冲突并节省槽位。",
fontSize = 12.sp,
modifier = Modifier.padding(10.dp),
color = MaterialTheme.colorScheme.onSecondaryContainer,
diff --git a/android/feature/infrared/src/main/kotlin/com/flagship/abox/manager/infrared/panel/RemotePanelScreen.kt b/android/feature/infrared/src/main/kotlin/com/flagship/abox/manager/infrared/panel/RemotePanelScreen.kt
index cc0a73a..654a178 100644
--- a/android/feature/infrared/src/main/kotlin/com/flagship/abox/manager/infrared/panel/RemotePanelScreen.kt
+++ b/android/feature/infrared/src/main/kotlin/com/flagship/abox/manager/infrared/panel/RemotePanelScreen.kt
@@ -41,6 +41,16 @@ import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.TopAppBar
+import androidx.compose.material.icons.outlined.Add
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.KeyboardArrowDown
+import androidx.compose.material.icons.outlined.KeyboardArrowLeft
+import androidx.compose.material.icons.outlined.KeyboardArrowRight
+import androidx.compose.material.icons.outlined.KeyboardArrowUp
+import androidx.compose.material.icons.outlined.PowerSettingsNew
+import androidx.compose.material.icons.outlined.Remove
+import androidx.compose.material.icons.outlined.VolumeOff
+import androidx.compose.material.icons.outlined.Tv
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
@@ -333,7 +343,7 @@ private fun AcControlPanel(
verticalAlignment = Alignment.CenterVertically,
) {
Text(
- text = if (acState.power) "● 运行中" else "○ 已关机",
+ text = if (acState.power) "运行中" else "已关机",
color = if (acState.power) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurfaceVariant,
fontWeight = FontWeight.Bold,
)
@@ -345,7 +355,7 @@ private fun AcControlPanel(
.background(if (acState.power) Color(0xFFFF5252) else MaterialTheme.colorScheme.outline)
.testTag("ac_power_toggle"),
) {
- Text("⏻", color = Color.White, fontSize = 20.sp, fontWeight = FontWeight.Bold)
+ Icon(Icons.Outlined.PowerSettingsNew, contentDescription = "电源", tint = Color.White)
}
}
@@ -371,14 +381,14 @@ private fun AcControlPanel(
modifier = Modifier.size(56.dp).testTag("ac_temp_down"),
shape = CircleShape,
) {
- Text("-", fontSize = 24.sp, fontWeight = FontWeight.Bold)
+ Icon(Icons.Outlined.Remove, contentDescription = "降低温度")
}
Button(
onClick = { onAdjustTemp(1) },
modifier = Modifier.size(56.dp).testTag("ac_temp_up"),
shape = CircleShape,
) {
- Text("+", fontSize = 24.sp, fontWeight = FontWeight.Bold)
+ Icon(Icons.Outlined.Add, contentDescription = "升高温度")
}
}
}
@@ -421,19 +431,19 @@ private fun AcControlPanel(
FilterChip(
selected = acState.verticalSwing,
onClick = onToggleVSwing,
- label = { Text("↕ 上下扫风") },
+ label = { Text("上下扫风") },
modifier = Modifier.weight(1f),
)
FilterChip(
selected = acState.horizontalSwing,
onClick = onToggleHSwing,
- label = { Text("↔ 左右扫风") },
+ label = { Text("左右扫风") },
modifier = Modifier.weight(1f),
)
FilterChip(
selected = acState.eco,
onClick = onToggleEco,
- label = { Text("🌱 节能 ECO") },
+ label = { Text("节能") },
modifier = Modifier.weight(1f),
)
}
@@ -463,9 +473,9 @@ private fun TvControlPanel(
horizontalArrangement = Arrangement.SpaceAround,
verticalAlignment = Alignment.CenterVertically,
) {
- InteractiveRemoteButton("TV_POWER", "⏻ 电源", Color(0xFFFF5252), bindingMap["TV_POWER"], isLearnMode, learningButtonId, sendingButtonId, onButtonClick)
- InteractiveRemoteButton("TV_MUTE", "🔇 静音", MaterialTheme.colorScheme.secondary, bindingMap["TV_MUTE"], isLearnMode, learningButtonId, sendingButtonId, onButtonClick)
- InteractiveRemoteButton("TV_SOURCE", "📺 信号源", MaterialTheme.colorScheme.secondary, bindingMap["TV_SOURCE"], isLearnMode, learningButtonId, sendingButtonId, onButtonClick)
+ InteractiveRemoteButton("TV_POWER", "电源", Color(0xFFFF5252), bindingMap["TV_POWER"], isLearnMode, learningButtonId, sendingButtonId, onButtonClick)
+ InteractiveRemoteButton("TV_MUTE", "静音", MaterialTheme.colorScheme.secondary, bindingMap["TV_MUTE"], isLearnMode, learningButtonId, sendingButtonId, onButtonClick)
+ InteractiveRemoteButton("TV_SOURCE", "信号源", MaterialTheme.colorScheme.secondary, bindingMap["TV_SOURCE"], isLearnMode, learningButtonId, sendingButtonId, onButtonClick)
}
Spacer(modifier = Modifier.height(8.dp))
@@ -482,7 +492,7 @@ private fun TvControlPanel(
onClick = { onButtonClick("TV_NAV_UP") },
modifier = Modifier.align(Alignment.TopCenter).padding(top = 10.dp).testTag("tv_nav_up"),
) {
- ButtonIndicatorText("TV_NAV_UP", "▲", learningButtonId, sendingButtonId)
+ ButtonIndicatorText("TV_NAV_UP", "上", learningButtonId, sendingButtonId)
}
// 下
@@ -490,7 +500,7 @@ private fun TvControlPanel(
onClick = { onButtonClick("TV_NAV_DOWN") },
modifier = Modifier.align(Alignment.BottomCenter).padding(bottom = 10.dp).testTag("tv_nav_down"),
) {
- ButtonIndicatorText("TV_NAV_DOWN", "▼", learningButtonId, sendingButtonId)
+ ButtonIndicatorText("TV_NAV_DOWN", "下", learningButtonId, sendingButtonId)
}
// 左
@@ -498,7 +508,7 @@ private fun TvControlPanel(
onClick = { onButtonClick("TV_NAV_LEFT") },
modifier = Modifier.align(Alignment.CenterStart).padding(start = 10.dp).testTag("tv_nav_left"),
) {
- ButtonIndicatorText("TV_NAV_LEFT", "◀", learningButtonId, sendingButtonId)
+ ButtonIndicatorText("TV_NAV_LEFT", "左", learningButtonId, sendingButtonId)
}
// 右
@@ -506,7 +516,7 @@ private fun TvControlPanel(
onClick = { onButtonClick("TV_NAV_RIGHT") },
modifier = Modifier.align(Alignment.CenterEnd).padding(end = 10.dp).testTag("tv_nav_right"),
) {
- ButtonIndicatorText("TV_NAV_RIGHT", "▶", learningButtonId, sendingButtonId)
+ ButtonIndicatorText("TV_NAV_RIGHT", "右", learningButtonId, sendingButtonId)
}
// OK 居中大按钮
@@ -554,10 +564,10 @@ private fun TvControlPanel(
) {
Text("频道 CH", fontWeight = FontWeight.Bold, fontSize = 12.sp)
Button(onClick = { onButtonClick("TV_CH_UP") }, modifier = Modifier.size(54.dp), shape = RoundedCornerShape(12.dp)) {
- ButtonIndicatorText("TV_CH_UP", "▲", learningButtonId, sendingButtonId)
+ ButtonIndicatorText("TV_CH_UP", "频道上调", learningButtonId, sendingButtonId)
}
Button(onClick = { onButtonClick("TV_CH_DOWN") }, modifier = Modifier.size(54.dp), shape = RoundedCornerShape(12.dp)) {
- ButtonIndicatorText("TV_CH_DOWN", "▼", learningButtonId, sendingButtonId)
+ ButtonIndicatorText("TV_CH_DOWN", "频道下调", learningButtonId, sendingButtonId)
}
}
}
@@ -583,8 +593,8 @@ private fun MediaPlayerControlPanel(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
) {
- InteractiveRemoteButton("MEDIA_POWER", "⏻ 电源", Color(0xFFFF5252), bindingMap["MEDIA_POWER"], isLearnMode, learningButtonId, sendingButtonId, onButtonClick)
- InteractiveRemoteButton("MEDIA_MUTE", "🔇 静音", MaterialTheme.colorScheme.secondary, bindingMap["MEDIA_MUTE"], isLearnMode, learningButtonId, sendingButtonId, onButtonClick)
+ InteractiveRemoteButton("MEDIA_POWER", "电源", Color(0xFFFF5252), bindingMap["MEDIA_POWER"], isLearnMode, learningButtonId, sendingButtonId, onButtonClick)
+ InteractiveRemoteButton("MEDIA_MUTE", "静音", MaterialTheme.colorScheme.secondary, bindingMap["MEDIA_MUTE"], isLearnMode, learningButtonId, sendingButtonId, onButtonClick)
}
Spacer(modifier = Modifier.height(16.dp))
@@ -642,13 +652,13 @@ private fun GenericGridControlPanel(
) {
Text("按键列表 (${bindings.size})", fontWeight = FontWeight.Bold, fontSize = 16.sp)
Button(onClick = onAddButton, modifier = Modifier.testTag("grid_add_key_button")) {
- Text("➕ 添加按键")
+ Text("添加按键")
}
}
if (bindings.isEmpty()) {
Box(modifier = Modifier.fillMaxWidth().weight(1f), contentAlignment = Alignment.Center) {
- Text("暂无自定义按键,点击上方【➕ 添加按键】新建", color = MaterialTheme.colorScheme.onSurfaceVariant)
+ Text("暂无自定义按键,请使用上方添加操作新建", color = MaterialTheme.colorScheme.onSurfaceVariant)
}
} else {
LazyVerticalGrid(
@@ -697,9 +707,9 @@ private fun GridButtonCard(
Column(modifier = Modifier.weight(1f)) {
Text(binding.displayName, fontWeight = FontWeight.Bold, fontSize = 15.sp)
val statusText = when {
- isLearning -> "🟡 正在录制信号..."
- binding.status == InfraredKeyStatus.READY -> "🟢 已就绪 (Slot ${binding.assignedSlot ?: "动态"})"
- else -> "⚪ 待录制 (点击录码)"
+ isLearning -> "正在录制信号..."
+ binding.status == InfraredKeyStatus.READY -> "已就绪(槽位 ${binding.assignedSlot ?: "动态"})"
+ else -> "待录制(点击录码)"
}
Text(statusText, fontSize = 11.sp, color = MaterialTheme.colorScheme.onSurfaceVariant)
}
@@ -712,7 +722,7 @@ private fun GridButtonCard(
onClick = onDelete,
modifier = Modifier.size(36.dp).testTag("delete_key_${binding.buttonId}"),
) {
- Text("🗑️", fontSize = 15.sp)
+ Text("删除", fontSize = 12.sp)
}
}
}
@@ -756,7 +766,7 @@ private fun ButtonIndicatorText(
sendingButtonId: String?,
) {
if (learningButtonId == buttonId) {
- Text("🟡 录制中", fontSize = 12.sp, fontWeight = FontWeight.Bold)
+ Text("录制中", fontSize = 12.sp, fontWeight = FontWeight.Bold)
} else if (sendingButtonId == buttonId) {
CircularProgressIndicator(modifier = Modifier.size(16.dp), color = Color.White)
} else {
diff --git a/android/feature/infrared/src/main/kotlin/com/flagship/abox/manager/infrared/remote/RemoteModels.kt b/android/feature/infrared/src/main/kotlin/com/flagship/abox/manager/infrared/remote/RemoteModels.kt
index bb50d7a..3d59edb 100644
--- a/android/feature/infrared/src/main/kotlin/com/flagship/abox/manager/infrared/remote/RemoteModels.kt
+++ b/android/feature/infrared/src/main/kotlin/com/flagship/abox/manager/infrared/remote/RemoteModels.kt
@@ -26,24 +26,24 @@ data class RemoteButtonSpec(
object RemoteSceneConfig {
object AirConditioner {
- val POWER = RemoteButtonSpec("AC_POWER", "1", R.string.infrared_key_ac_power, "空调-电源", "⏻")
- val TEMP_UP = RemoteButtonSpec("AC_TEMP_UP", "2", R.string.infrared_key_ac_temp_up, "空调-温度+", "▲")
- val TEMP_DOWN = RemoteButtonSpec("AC_TEMP_DOWN", "3", R.string.infrared_key_ac_temp_down, "空调-温度-", "▼")
- val MODE = RemoteButtonSpec("AC_MODE", "4", R.string.infrared_key_ac_mode, "空调-模式", "模式 ❄/☀")
- val FAN = RemoteButtonSpec("AC_FAN", "5", R.string.infrared_key_ac_fan, "空调-风速", "风速 💨")
- val SWING = RemoteButtonSpec("AC_SWING", "6", R.string.infrared_key_ac_swing, "空调-扫风", "扫风 ↔")
- val TIMER = RemoteButtonSpec("AC_TIMER", "7", R.string.infrared_key_ac_timer, "空调-定时", "定时 ⏱")
+ val POWER = RemoteButtonSpec("AC_POWER", "1", R.string.infrared_key_ac_power, "空调-电源", "电源")
+ val TEMP_UP = RemoteButtonSpec("AC_TEMP_UP", "2", R.string.infrared_key_ac_temp_up, "空调-温度+", "升温")
+ val TEMP_DOWN = RemoteButtonSpec("AC_TEMP_DOWN", "3", R.string.infrared_key_ac_temp_down, "空调-温度-", "降温")
+ val MODE = RemoteButtonSpec("AC_MODE", "4", R.string.infrared_key_ac_mode, "空调-模式", "模式")
+ val FAN = RemoteButtonSpec("AC_FAN", "5", R.string.infrared_key_ac_fan, "空调-风速", "风速")
+ val SWING = RemoteButtonSpec("AC_SWING", "6", R.string.infrared_key_ac_swing, "空调-扫风", "扫风")
+ val TIMER = RemoteButtonSpec("AC_TIMER", "7", R.string.infrared_key_ac_timer, "空调-定时", "定时")
val buttons = listOf(POWER, TEMP_UP, TEMP_DOWN, MODE, FAN, SWING, TIMER)
}
object Television {
- val POWER = RemoteButtonSpec("TV_POWER", "21", R.string.infrared_key_tv_power, "电视-电源", "⏻")
- val MUTE = RemoteButtonSpec("TV_MUTE", "22", R.string.infrared_key_tv_mute, "电视-静音", "🔇")
- val NAV_UP = RemoteButtonSpec("TV_NAV_UP", "23", R.string.infrared_key_tv_nav_up, "电视-上", "▲")
- val NAV_DOWN = RemoteButtonSpec("TV_NAV_DOWN", "24", R.string.infrared_key_tv_nav_down, "电视-下", "▼")
- val NAV_LEFT = RemoteButtonSpec("TV_NAV_LEFT", "25", R.string.infrared_key_tv_nav_left, "电视-左", "◀")
- val NAV_RIGHT = RemoteButtonSpec("TV_NAV_RIGHT", "26", R.string.infrared_key_tv_nav_right, "电视-右", "▶")
+ val POWER = RemoteButtonSpec("TV_POWER", "21", R.string.infrared_key_tv_power, "电视-电源", "电源")
+ val MUTE = RemoteButtonSpec("TV_MUTE", "22", R.string.infrared_key_tv_mute, "电视-静音", "静音")
+ val NAV_UP = RemoteButtonSpec("TV_NAV_UP", "23", R.string.infrared_key_tv_nav_up, "电视-上", "上")
+ val NAV_DOWN = RemoteButtonSpec("TV_NAV_DOWN", "24", R.string.infrared_key_tv_nav_down, "电视-下", "下")
+ val NAV_LEFT = RemoteButtonSpec("TV_NAV_LEFT", "25", R.string.infrared_key_tv_nav_left, "电视-左", "左")
+ val NAV_RIGHT = RemoteButtonSpec("TV_NAV_RIGHT", "26", R.string.infrared_key_tv_nav_right, "电视-右", "右")
val OK = RemoteButtonSpec("TV_OK", "27", R.string.infrared_key_tv_ok, "电视-确定", "OK")
val VOL_UP = RemoteButtonSpec("TV_VOL_UP", "28", R.string.infrared_key_tv_vol_up, "电视-音量+", "VOL +")
val VOL_DOWN = RemoteButtonSpec("TV_VOL_DOWN", "29", R.string.infrared_key_tv_vol_down, "电视-音量-", "VOL -")
diff --git a/android/feature/infrared/src/main/kotlin/com/flagship/abox/manager/infrared/remote/ui/InfraredRemoteScreen.kt b/android/feature/infrared/src/main/kotlin/com/flagship/abox/manager/infrared/remote/ui/InfraredRemoteScreen.kt
index 97ccfc3..57b3678 100644
--- a/android/feature/infrared/src/main/kotlin/com/flagship/abox/manager/infrared/remote/ui/InfraredRemoteScreen.kt
+++ b/android/feature/infrared/src/main/kotlin/com/flagship/abox/manager/infrared/remote/ui/InfraredRemoteScreen.kt
@@ -45,6 +45,8 @@ import androidx.compose.ui.unit.sp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.flagship.abox.manager.designsystem.ABoxSurface
+import com.flagship.abox.manager.designsystem.ABoxIconButton
+import com.flagship.abox.manager.designsystem.icon.ABoxIconKey
import com.flagship.abox.manager.infrared.R
import com.flagship.abox.manager.infrared.remote.InfraredRemoteUiState
import com.flagship.abox.manager.infrared.remote.InfraredRemoteViewModel
@@ -158,12 +160,12 @@ internal fun InfraredRemoteScreen(
}
// 按键管理 / 设置入口按钮
- IconButton(
+ ABoxIconButton(
+ key = ABoxIconKey.EDIT,
+ contentDescription = "打开红外设置",
onClick = onOpenSettings,
modifier = Modifier.testTag("remote_settings_button"),
- ) {
- Text("⚙️", fontSize = 20.sp)
- }
+ )
},
)
},
diff --git a/android/feature/infrared/src/main/res/values-zh-rCN/strings.xml b/android/feature/infrared/src/main/res/values-zh-rCN/strings.xml
index 0a6dae8..b6b5e04 100644
--- a/android/feature/infrared/src/main/res/values-zh-rCN/strings.xml
+++ b/android/feature/infrared/src/main/res/values-zh-rCN/strings.xml
@@ -35,12 +35,12 @@
红外遥控器
录制中
学习模式
- 🔴 学习模式已开启:点击任意按键开始录制实体遥控器信号
- ❄️ 空调面板
- 📺 电视面板
+ 学习模式已开启:点击任意按键开始录制实体遥控器信号
+ 空调面板
+ 电视面板
设置
- 🔴 学习模式已开启:点击任意按键开始录制
+ 学习模式已开启:点击任意按键开始录制
正在录制【%1$s】(槽位 %2$s),请按下实体遥控器按键…
【%1$s】录制成功
按键【%1$s】尚未学习,开启右上角学习模式即可录制
@@ -51,8 +51,8 @@
温度调节
音量
频道
- ❄️ 制冷模式
- 💨 自动风速 | ↔ 自动扫风
+ 制冷模式
+ 自动风速 | 自动扫风
空调-电源
空调-升温
@@ -98,10 +98,10 @@
静态占用:%1$d
动态缓冲:Slot %1$s
虚拟遥控器
- 暂无虚拟遥控器,点击右上角或下方 ➕ 添加
+ 暂无虚拟遥控器,请使用添加操作
添加遥控器
- 🚀 静态独占(%1$s 槽位)
- 📦 动态缓冲(共用 Slot %1$s)
+ 静态独占(%1$s 槽位)
+ 动态缓冲(共用槽位 %1$s)
添加虚拟遥控器
设备类型
预设码库 / 品牌
@@ -110,8 +110,8 @@
节省槽位(0 额外槽位),现场写码发射(~80ms)
硬件槽位不足,请选择动态写码模式
硬件槽位与底层按键管理
- 📺 电视机 / 电视盒子
- ❄️ 空调设备
+ 电视机 / 电视盒子
+ 空调设备
🌀 电风扇 / 空气净化器
- 🎛️ 自定义面板
+ 自定义面板
diff --git a/android/feature/infrared/src/main/res/values/strings.xml b/android/feature/infrared/src/main/res/values/strings.xml
index e9a5a6f..9deb20c 100644
--- a/android/feature/infrared/src/main/res/values/strings.xml
+++ b/android/feature/infrared/src/main/res/values/strings.xml
@@ -36,12 +36,12 @@
Recording
My Remotes
Learn Mode
- 🔴 Learn mode active: tap any button to record
- ❄️ Air Conditioner
- 📺 Television
+ Learn mode active: tap any button to record
+ Air Conditioner
+ Television
Settings
- 🔴 Learn mode active: tap any button to record
+ Learn mode active: tap any button to record
Recording [%1$s] (Slot %2$s), press remote button…
[%1$s] recorded successfully
Button [%1$s] is not learned. Enable learn mode to record.
@@ -52,8 +52,8 @@
Temp Control
VOL
CH
- ❄️ Cool Mode
- 💨 Auto Fan | ↔ Swing
+ Cool Mode
+ Auto Fan | Swing
AC Power
AC Temp +
@@ -100,8 +100,8 @@
Virtual Remotes
No virtual remotes added yet. Tap + to add one.
Add Remote
- 🚀 Static Mode (%1$s slots)
- 📦 Dynamic Mode (Scratch Slot %1$s)
+ Static Mode (%1$s slots)
+ Dynamic Mode (Scratch Slot %1$s)
Add Virtual Remote
Device Type
Brand / Preset Library
@@ -110,8 +110,8 @@
Saves slots (0 extra slots), writes code on-the-fly (~80ms)
Slot quota exceeded. Please choose Dynamic mode.
Hardware Slot / Raw Key Management
- 📺 Television (TV)
- ❄️ Air Conditioner (AC)
+ Television (TV)
+ Air Conditioner (AC)
🌀 Fan / Air Purifier
- 🎛️ Custom Panel
+ Custom Panel
diff --git a/testing/fakes/src/main/kotlin/com/flagship/abox/manager/testing/fakes/FakeVirtualRemoteRepository.kt b/testing/fakes/src/main/kotlin/com/flagship/abox/manager/testing/fakes/FakeVirtualRemoteRepository.kt
index ac183cc..a0b2acf 100644
--- a/testing/fakes/src/main/kotlin/com/flagship/abox/manager/testing/fakes/FakeVirtualRemoteRepository.kt
+++ b/testing/fakes/src/main/kotlin/com/flagship/abox/manager/testing/fakes/FakeVirtualRemoteRepository.kt
@@ -12,6 +12,7 @@ import com.flagship.abox.manager.domain.infrared.VirtualRemoteRepository
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.update
import java.util.concurrent.ConcurrentHashMap
class FakeVirtualRemoteRepository : VirtualRemoteRepository {
@@ -80,13 +81,13 @@ class FakeVirtualRemoteRepository : VirtualRemoteRepository {
): DomainResult {
remotes[remote.id] = remote
bindings[remote.id] = initialBindings.toMutableList()
- changeTrigger.value = System.currentTimeMillis()
+ changeTrigger.update { it + 1L }
return DomainResult.Success(remote.id)
}
override suspend fun updateRemote(remote: VirtualRemote): DomainResult {
remotes[remote.id] = remote
- changeTrigger.value = System.currentTimeMillis()
+ changeTrigger.update { it + 1L }
return DomainResult.Success(Unit)
}
@@ -96,7 +97,7 @@ class FakeVirtualRemoteRepository : VirtualRemoteRepository {
): DomainResult {
remotes.remove(remoteId)
bindings.remove(remoteId)
- changeTrigger.value = System.currentTimeMillis()
+ changeTrigger.update { it + 1L }
return DomainResult.Success(Unit)
}
@@ -109,7 +110,7 @@ class FakeVirtualRemoteRepository : VirtualRemoteRepository {
list.add(binding)
}
bindings[binding.remoteId] = list
- changeTrigger.value = System.currentTimeMillis()
+ changeTrigger.update { it + 1L }
return DomainResult.Success(Unit)
}
@@ -120,7 +121,7 @@ class FakeVirtualRemoteRepository : VirtualRemoteRepository {
val list = bindings[remoteId] ?: return DomainResult.Success(Unit)
list.removeAll { it.buttonId == buttonId }
bindings[remoteId] = list
- changeTrigger.value = System.currentTimeMillis()
+ changeTrigger.update { it + 1L }
return DomainResult.Success(Unit)
}
@@ -131,7 +132,7 @@ class FakeVirtualRemoteRepository : VirtualRemoteRepository {
): DomainResult {
val existing = remotes[remoteId] ?: return DomainResult.Success(Unit)
remotes[remoteId] = existing.copy(acState = state)
- changeTrigger.value = System.currentTimeMillis()
+ changeTrigger.update { it + 1L }
return DomainResult.Success(Unit)
}
}