feat(ui): complete ABox app experience redesign #10
@@ -747,7 +747,7 @@ private fun ActionItemRow(
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun SceneTrigger.describe(): String = when (this) {
|
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.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.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)
|
is SceneTrigger.DeviceState -> stringResource(R.string.scene_trigger_desc_device, deviceName.value, expectedState)
|
||||||
|
|||||||
@@ -68,6 +68,8 @@ import com.flagship.abox.manager.domain.Scene
|
|||||||
import com.flagship.abox.manager.domain.SceneColor
|
import com.flagship.abox.manager.domain.SceneColor
|
||||||
import com.flagship.abox.manager.domain.SceneIcon
|
import com.flagship.abox.manager.domain.SceneIcon
|
||||||
import com.flagship.abox.manager.domain.SceneId
|
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
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@@ -250,9 +252,10 @@ private fun SceneCard(
|
|||||||
),
|
),
|
||||||
contentAlignment = Alignment.Center,
|
contentAlignment = Alignment.Center,
|
||||||
) {
|
) {
|
||||||
Text(
|
ABoxIcon(
|
||||||
text = scene.icon.displayEmoji(),
|
key = scene.icon.toABoxIconKey(),
|
||||||
style = MaterialTheme.typography.titleMedium,
|
contentDescription = scene.name,
|
||||||
|
modifier = Modifier.size(28.dp),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Spacer(Modifier.width(12.dp))
|
Spacer(Modifier.width(12.dp))
|
||||||
@@ -375,10 +378,7 @@ private fun EmptySceneList(modifier: Modifier = Modifier) {
|
|||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
verticalArrangement = Arrangement.Center,
|
verticalArrangement = Arrangement.Center,
|
||||||
) {
|
) {
|
||||||
Text(
|
ABoxIcon(ABoxIconKey.SCENES, contentDescription = "暂无情景", modifier = Modifier.size(48.dp))
|
||||||
text = "⚡",
|
|
||||||
style = MaterialTheme.typography.displayMedium,
|
|
||||||
)
|
|
||||||
Spacer(Modifier.size(8.dp))
|
Spacer(Modifier.size(8.dp))
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(R.string.scene_empty_title),
|
text = stringResource(R.string.scene_empty_title),
|
||||||
@@ -396,19 +396,19 @@ private fun EmptySceneList(modifier: Modifier = Modifier) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun SceneIcon.displayEmoji(): String = when (this) {
|
fun SceneIcon.toABoxIconKey(): ABoxIconKey = when (this) {
|
||||||
SceneIcon.HOME -> "🏠"
|
SceneIcon.HOME -> ABoxIconKey.DEVICES
|
||||||
SceneIcon.OFFICE -> "💼"
|
SceneIcon.OFFICE -> ABoxIconKey.ACTIVITY
|
||||||
SceneIcon.NIGHT -> "🌙"
|
SceneIcon.NIGHT -> ABoxIconKey.PENDING
|
||||||
SceneIcon.MOVIE -> "🎬"
|
SceneIcon.MOVIE -> ABoxIconKey.SCENES
|
||||||
SceneIcon.AWAY -> "🚶"
|
SceneIcon.AWAY -> ABoxIconKey.OFFLINE
|
||||||
SceneIcon.READING -> "📖"
|
SceneIcon.READING -> ABoxIconKey.DEVICES
|
||||||
SceneIcon.DINING -> "🍽️"
|
SceneIcon.DINING -> ABoxIconKey.DEVICES
|
||||||
SceneIcon.GAMING -> "🎮"
|
SceneIcon.GAMING -> ABoxIconKey.SCENES
|
||||||
SceneIcon.THERMOSTAT -> "🌡️"
|
SceneIcon.THERMOSTAT -> ABoxIconKey.TEMPERATURE
|
||||||
SceneIcon.LIGHT -> "💡"
|
SceneIcon.LIGHT -> ABoxIconKey.POWER
|
||||||
SceneIcon.CLEAN -> "🧹"
|
SceneIcon.CLEAN -> ABoxIconKey.REFRESH
|
||||||
SceneIcon.CUSTOM -> "✨"
|
SceneIcon.CUSTOM -> ABoxIconKey.UNKNOWN_DEVICE
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun SceneColor.toColorOrNull(): Color? {
|
internal fun SceneColor.toColorOrNull(): Color? {
|
||||||
|
|||||||
@@ -82,9 +82,9 @@
|
|||||||
<string name="scene_section_other">其他选项与外观</string>
|
<string name="scene_section_other">其他选项与外观</string>
|
||||||
|
|
||||||
<!-- Add Buttons -->
|
<!-- Add Buttons -->
|
||||||
<string name="scene_add_trigger">+ 新增触发器</string>
|
<string name="scene_add_trigger">新增触发器</string>
|
||||||
<string name="scene_add_condition">+ 新增条件</string>
|
<string name="scene_add_condition">新增条件</string>
|
||||||
<string name="scene_add_action_btn">+ 新增动作</string>
|
<string name="scene_add_action_btn">新增动作</string>
|
||||||
<string name="scene_add_action">添加</string>
|
<string name="scene_add_action">添加</string>
|
||||||
<string name="scene_save_action">保存指令</string>
|
<string name="scene_save_action">保存指令</string>
|
||||||
|
|
||||||
@@ -104,10 +104,10 @@
|
|||||||
|
|
||||||
<!-- Trigger Types & Dialog -->
|
<!-- Trigger Types & Dialog -->
|
||||||
<string name="scene_dialog_add_trigger_title">选择触发器类型</string>
|
<string name="scene_dialog_add_trigger_title">选择触发器类型</string>
|
||||||
<string name="scene_trigger_type_time">⏰ 定时时间触发</string>
|
<string name="scene_trigger_type_time">定时时间触发</string>
|
||||||
<string name="scene_trigger_type_temp">🌡️ 环境温度触发</string>
|
<string name="scene_trigger_type_temp">环境温度触发</string>
|
||||||
<string name="scene_trigger_type_humidity">💧 环境湿度触发</string>
|
<string name="scene_trigger_type_humidity">环境湿度触发</string>
|
||||||
<string name="scene_trigger_type_device">🔌 插座状态变更触发</string>
|
<string name="scene_trigger_type_device">插座状态变更触发</string>
|
||||||
<string name="scene_trigger_time_label">触发时间点(如:07:30)</string>
|
<string name="scene_trigger_time_label">触发时间点(如:07:30)</string>
|
||||||
<string name="scene_trigger_temp_threshold">温度阈值 (°C)</string>
|
<string name="scene_trigger_temp_threshold">温度阈值 (°C)</string>
|
||||||
<string name="scene_trigger_humidity_threshold">湿度阈值 (%)</string>
|
<string name="scene_trigger_humidity_threshold">湿度阈值 (%)</string>
|
||||||
@@ -118,19 +118,19 @@
|
|||||||
|
|
||||||
<!-- Condition Types & Dialog -->
|
<!-- Condition Types & Dialog -->
|
||||||
<string name="scene_dialog_add_condition_title">选择限制条件</string>
|
<string name="scene_dialog_add_condition_title">选择限制条件</string>
|
||||||
<string name="scene_condition_type_temp">🌡️ 环境温度范围</string>
|
<string name="scene_condition_type_temp">环境温度范围</string>
|
||||||
<string name="scene_condition_type_humidity">💧 环境湿度范围</string>
|
<string name="scene_condition_type_humidity">环境湿度范围</string>
|
||||||
<string name="scene_condition_type_socket">🔌 插座当前电源状态</string>
|
<string name="scene_condition_type_socket">插座当前电源状态</string>
|
||||||
<string name="scene_condition_type_time_range">🕒 生效时间区间</string>
|
<string name="scene_condition_type_time_range">生效时间区间</string>
|
||||||
<string name="scene_condition_start_time">起始时间(如:22:00)</string>
|
<string name="scene_condition_start_time">起始时间(如:22:00)</string>
|
||||||
<string name="scene_condition_end_time">结束时间(如:07:00)</string>
|
<string name="scene_condition_end_time">结束时间(如:07:00)</string>
|
||||||
|
|
||||||
<!-- Action Types & Dialog -->
|
<!-- Action Types & Dialog -->
|
||||||
<string name="scene_dialog_add_action_title">选择执行动作</string>
|
<string name="scene_dialog_add_action_title">选择执行动作</string>
|
||||||
<string name="scene_action_type_socket">🔌 智能插座控制</string>
|
<string name="scene_action_type_socket">智能插座控制</string>
|
||||||
<string name="scene_action_type_virtual_remote">📺 红外遥控按键</string>
|
<string name="scene_action_type_virtual_remote">红外遥控按键</string>
|
||||||
<string name="scene_action_type_delay">⏱️ 延时等待 (缓冲)</string>
|
<string name="scene_action_type_delay">延时等待(缓冲)</string>
|
||||||
<string name="scene_action_type_notification">🔔 发送系统提示</string>
|
<string name="scene_action_type_notification">发送系统提示</string>
|
||||||
<string name="scene_select_socket">选择目标插座</string>
|
<string name="scene_select_socket">选择目标插座</string>
|
||||||
<string name="scene_socket_power_state">设定电源状态</string>
|
<string name="scene_socket_power_state">设定电源状态</string>
|
||||||
<string name="scene_select_virtual_remote">选择虚拟遥控器</string>
|
<string name="scene_select_virtual_remote">选择虚拟遥控器</string>
|
||||||
@@ -144,8 +144,8 @@
|
|||||||
<string name="scene_action_socket">插座【%1$s】: 设为 %2$s</string>
|
<string name="scene_action_socket">插座【%1$s】: 设为 %2$s</string>
|
||||||
<string name="scene_action_remote">遥控【%1$s】: 发送 %2$s</string>
|
<string name="scene_action_remote">遥控【%1$s】: 发送 %2$s</string>
|
||||||
<string name="scene_action_infrared">红外【%1$s】: 槽位 %2$s</string>
|
<string name="scene_action_infrared">红外【%1$s】: 槽位 %2$s</string>
|
||||||
<string name="scene_action_delay">⏱️ 等待 %1$d 秒</string>
|
<string name="scene_action_delay">等待 %1$d 秒</string>
|
||||||
<string name="scene_action_notification">🔔 提示: %1$s</string>
|
<string name="scene_action_notification">提示:%1$s</string>
|
||||||
|
|
||||||
<!-- Scene: execution -->
|
<!-- Scene: execution -->
|
||||||
<string name="scene_execution_title">执行指令</string>
|
<string name="scene_execution_title">执行指令</string>
|
||||||
@@ -164,13 +164,13 @@
|
|||||||
<!-- 校验与弹窗选项/占位文案 -->
|
<!-- 校验与弹窗选项/占位文案 -->
|
||||||
<string name="scene_trigger_time_error">时间格式无效(请按 HH:mm 格式输入,如 07:30)</string>
|
<string name="scene_trigger_time_error">时间格式无效(请按 HH:mm 格式输入,如 07:30)</string>
|
||||||
<string name="scene_condition_time_error">时间格式无效(请按 HH:mm 格式输入,如 22:00)</string>
|
<string name="scene_condition_time_error">时间格式无效(请按 HH:mm 格式输入,如 22:00)</string>
|
||||||
<string name="scene_chip_time">⏰ 定时</string>
|
<string name="scene_chip_time">定时</string>
|
||||||
<string name="scene_chip_temp">🌡️ 温度</string>
|
<string name="scene_chip_temp">温度</string>
|
||||||
<string name="scene_chip_humidity">💧 湿度</string>
|
<string name="scene_chip_humidity">湿度</string>
|
||||||
<string name="scene_chip_socket">🔌 插座</string>
|
<string name="scene_chip_socket">插座</string>
|
||||||
<string name="scene_chip_remote">📺 遥控</string>
|
<string name="scene_chip_remote">遥控</string>
|
||||||
<string name="scene_chip_delay">⏱️ 延时</string>
|
<string name="scene_chip_delay">延时</string>
|
||||||
<string name="scene_chip_notify">🔔 提示</string>
|
<string name="scene_chip_notify">提示</string>
|
||||||
<string name="scene_chip_above">> 高于</string>
|
<string name="scene_chip_above">> 高于</string>
|
||||||
<string name="scene_chip_below">< 低于</string>
|
<string name="scene_chip_below">< 低于</string>
|
||||||
<string name="scene_chip_power_on">开启</string>
|
<string name="scene_chip_power_on">开启</string>
|
||||||
@@ -184,7 +184,7 @@
|
|||||||
<string name="scene_empty_triggers_hint">尚未添加触发器,请点击下方按钮添加</string>
|
<string name="scene_empty_triggers_hint">尚未添加触发器,请点击下方按钮添加</string>
|
||||||
<string name="scene_empty_conditions_hint">尚未添加限制条件,请点击下方按钮添加</string>
|
<string name="scene_empty_conditions_hint">尚未添加限制条件,请点击下方按钮添加</string>
|
||||||
<string name="scene_empty_actions_hint">尚未添加执行动作,请点击下方按钮添加</string>
|
<string name="scene_empty_actions_hint">尚未添加执行动作,请点击下方按钮添加</string>
|
||||||
<string name="scene_summary_triggers_and_actions">⚡ %1$d 个触发器 • %2$d 个动作</string>
|
<string name="scene_summary_triggers_and_actions">%1$d 个触发器 · %2$d 个动作</string>
|
||||||
<string name="scene_summary_actions_only">%1$d 个执行动作</string>
|
<string name="scene_summary_actions_only">%1$d 个执行动作</string>
|
||||||
<string name="scene_exec_ready_hint">点击下方按钮立即开始执行</string>
|
<string name="scene_exec_ready_hint">点击下方按钮立即开始执行</string>
|
||||||
<string name="scene_exec_rerun">重新执行</string>
|
<string name="scene_exec_rerun">重新执行</string>
|
||||||
|
|||||||
@@ -82,9 +82,9 @@
|
|||||||
<string name="scene_section_other">Other Options & Appearance</string>
|
<string name="scene_section_other">Other Options & Appearance</string>
|
||||||
|
|
||||||
<!-- Add Buttons -->
|
<!-- Add Buttons -->
|
||||||
<string name="scene_add_trigger">+ Add Trigger</string>
|
<string name="scene_add_trigger">Add Trigger</string>
|
||||||
<string name="scene_add_condition">+ Add Condition</string>
|
<string name="scene_add_condition">Add Condition</string>
|
||||||
<string name="scene_add_action_btn">+ Add Action</string>
|
<string name="scene_add_action_btn">Add Action</string>
|
||||||
<string name="scene_add_action">Add</string>
|
<string name="scene_add_action">Add</string>
|
||||||
<string name="scene_save_action">Save Command</string>
|
<string name="scene_save_action">Save Command</string>
|
||||||
|
|
||||||
@@ -104,10 +104,10 @@
|
|||||||
|
|
||||||
<!-- Trigger Types & Dialog -->
|
<!-- Trigger Types & Dialog -->
|
||||||
<string name="scene_dialog_add_trigger_title">Select Trigger Type</string>
|
<string name="scene_dialog_add_trigger_title">Select Trigger Type</string>
|
||||||
<string name="scene_trigger_type_time">⏰ Time / Schedule Trigger</string>
|
<string name="scene_trigger_type_time">Time / Schedule Trigger</string>
|
||||||
<string name="scene_trigger_type_temp">🌡️ Temperature Threshold</string>
|
<string name="scene_trigger_type_temp">Temperature Threshold</string>
|
||||||
<string name="scene_trigger_type_humidity">💧 Humidity Threshold</string>
|
<string name="scene_trigger_type_humidity">Humidity Threshold</string>
|
||||||
<string name="scene_trigger_type_device">🔌 Socket State Changed</string>
|
<string name="scene_trigger_type_device">Socket State Changed</string>
|
||||||
<string name="scene_trigger_time_label">Trigger Time (e.g. 07:30)</string>
|
<string name="scene_trigger_time_label">Trigger Time (e.g. 07:30)</string>
|
||||||
<string name="scene_trigger_temp_threshold">Temperature Threshold (°C)</string>
|
<string name="scene_trigger_temp_threshold">Temperature Threshold (°C)</string>
|
||||||
<string name="scene_trigger_humidity_threshold">Humidity Threshold (%)</string>
|
<string name="scene_trigger_humidity_threshold">Humidity Threshold (%)</string>
|
||||||
@@ -118,19 +118,19 @@
|
|||||||
|
|
||||||
<!-- Condition Types & Dialog -->
|
<!-- Condition Types & Dialog -->
|
||||||
<string name="scene_dialog_add_condition_title">Select Condition</string>
|
<string name="scene_dialog_add_condition_title">Select Condition</string>
|
||||||
<string name="scene_condition_type_temp">🌡️ Temperature Range</string>
|
<string name="scene_condition_type_temp">Temperature Range</string>
|
||||||
<string name="scene_condition_type_humidity">💧 Humidity Range</string>
|
<string name="scene_condition_type_humidity">Humidity Range</string>
|
||||||
<string name="scene_condition_type_socket">🔌 Current Socket Power</string>
|
<string name="scene_condition_type_socket">Current Socket Power</string>
|
||||||
<string name="scene_condition_type_time_range">🕒 Active Time Range</string>
|
<string name="scene_condition_type_time_range">Active Time Range</string>
|
||||||
<string name="scene_condition_start_time">Start Time (e.g. 22:00)</string>
|
<string name="scene_condition_start_time">Start Time (e.g. 22:00)</string>
|
||||||
<string name="scene_condition_end_time">End Time (e.g. 07:00)</string>
|
<string name="scene_condition_end_time">End Time (e.g. 07:00)</string>
|
||||||
|
|
||||||
<!-- Action Types & Dialog -->
|
<!-- Action Types & Dialog -->
|
||||||
<string name="scene_dialog_add_action_title">Select Action</string>
|
<string name="scene_dialog_add_action_title">Select Action</string>
|
||||||
<string name="scene_action_type_socket">🔌 Smart Socket Control</string>
|
<string name="scene_action_type_socket">Smart Socket Control</string>
|
||||||
<string name="scene_action_type_virtual_remote">📺 Infrared Remote Button</string>
|
<string name="scene_action_type_virtual_remote">Infrared Remote Button</string>
|
||||||
<string name="scene_action_type_delay">⏱️ Delay / Buffer Timer</string>
|
<string name="scene_action_type_delay">Delay / Buffer Timer</string>
|
||||||
<string name="scene_action_type_notification">🔔 System Notification</string>
|
<string name="scene_action_type_notification">System Notification</string>
|
||||||
<string name="scene_select_socket">Select Target Socket</string>
|
<string name="scene_select_socket">Select Target Socket</string>
|
||||||
<string name="scene_socket_power_state">Target Power State</string>
|
<string name="scene_socket_power_state">Target Power State</string>
|
||||||
<string name="scene_select_virtual_remote">Select Virtual Remote</string>
|
<string name="scene_select_virtual_remote">Select Virtual Remote</string>
|
||||||
@@ -144,8 +144,8 @@
|
|||||||
<string name="scene_action_socket">Socket [%1$s]: Set %2$s</string>
|
<string name="scene_action_socket">Socket [%1$s]: Set %2$s</string>
|
||||||
<string name="scene_action_remote">Remote [%1$s]: Send %2$s</string>
|
<string name="scene_action_remote">Remote [%1$s]: Send %2$s</string>
|
||||||
<string name="scene_action_infrared">Infrared [%1$s]: Slot %2$s</string>
|
<string name="scene_action_infrared">Infrared [%1$s]: Slot %2$s</string>
|
||||||
<string name="scene_action_delay">⏱️ Delay %1$d seconds</string>
|
<string name="scene_action_delay">Delay %1$d seconds</string>
|
||||||
<string name="scene_action_notification">🔔 Notify: %1$s</string>
|
<string name="scene_action_notification">Notify: %1$s</string>
|
||||||
|
|
||||||
<!-- Scene: execution -->
|
<!-- Scene: execution -->
|
||||||
<string name="scene_execution_title">Execute Command</string>
|
<string name="scene_execution_title">Execute Command</string>
|
||||||
@@ -164,13 +164,13 @@
|
|||||||
<!-- Validation & dialog chips / placeholders -->
|
<!-- Validation & dialog chips / placeholders -->
|
||||||
<string name="scene_trigger_time_error">Invalid time format (use HH:mm, e.g. 07:30)</string>
|
<string name="scene_trigger_time_error">Invalid time format (use HH:mm, e.g. 07:30)</string>
|
||||||
<string name="scene_condition_time_error">Invalid time format (use HH:mm, e.g. 22:00)</string>
|
<string name="scene_condition_time_error">Invalid time format (use HH:mm, e.g. 22:00)</string>
|
||||||
<string name="scene_chip_time">⏰ Schedule</string>
|
<string name="scene_chip_time">Schedule</string>
|
||||||
<string name="scene_chip_temp">🌡️ Temperature</string>
|
<string name="scene_chip_temp">Temperature</string>
|
||||||
<string name="scene_chip_humidity">💧 Humidity</string>
|
<string name="scene_chip_humidity">Humidity</string>
|
||||||
<string name="scene_chip_socket">🔌 Socket</string>
|
<string name="scene_chip_socket">Socket</string>
|
||||||
<string name="scene_chip_remote">📺 Remote</string>
|
<string name="scene_chip_remote">Remote</string>
|
||||||
<string name="scene_chip_delay">⏱️ Delay</string>
|
<string name="scene_chip_delay">Delay</string>
|
||||||
<string name="scene_chip_notify">🔔 Notify</string>
|
<string name="scene_chip_notify">Notify</string>
|
||||||
<string name="scene_chip_above">> Above</string>
|
<string name="scene_chip_above">> Above</string>
|
||||||
<string name="scene_chip_below">< Below</string>
|
<string name="scene_chip_below">< Below</string>
|
||||||
<string name="scene_chip_power_on">Turn ON</string>
|
<string name="scene_chip_power_on">Turn ON</string>
|
||||||
@@ -184,7 +184,7 @@
|
|||||||
<string name="scene_empty_triggers_hint">No triggers configured. Tap + below to add.</string>
|
<string name="scene_empty_triggers_hint">No triggers configured. Tap + below to add.</string>
|
||||||
<string name="scene_empty_conditions_hint">No conditions configured. Tap + below to add.</string>
|
<string name="scene_empty_conditions_hint">No conditions configured. Tap + below to add.</string>
|
||||||
<string name="scene_empty_actions_hint">No actions configured. Tap + below to add.</string>
|
<string name="scene_empty_actions_hint">No actions configured. Tap + below to add.</string>
|
||||||
<string name="scene_summary_triggers_and_actions">⚡ %1$d triggers • %2$d actions</string>
|
<string name="scene_summary_triggers_and_actions">%1$d triggers · %2$d actions</string>
|
||||||
<string name="scene_summary_actions_only">%1$d actions</string>
|
<string name="scene_summary_actions_only">%1$d actions</string>
|
||||||
<string name="scene_exec_ready_hint">Tap the button below to run immediately</string>
|
<string name="scene_exec_ready_hint">Tap the button below to run immediately</string>
|
||||||
<string name="scene_exec_rerun">Re-run</string>
|
<string name="scene_exec_rerun">Re-run</string>
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ dependencies {
|
|||||||
implementation(libs.compose.ui)
|
implementation(libs.compose.ui)
|
||||||
implementation(libs.compose.ui.tooling.preview)
|
implementation(libs.compose.ui.tooling.preview)
|
||||||
implementation(libs.compose.material3)
|
implementation(libs.compose.material3)
|
||||||
|
implementation(libs.compose.material.icons.extended)
|
||||||
|
|
||||||
testImplementation(libs.junit)
|
testImplementation(libs.junit)
|
||||||
testImplementation(libs.kotlinx.coroutines.test)
|
testImplementation(libs.kotlinx.coroutines.test)
|
||||||
|
|||||||
+17
-17
@@ -271,10 +271,10 @@ private fun VirtualRemoteCard(
|
|||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
) {
|
) {
|
||||||
val icon = when (remote.type) {
|
val icon = when (remote.type) {
|
||||||
RemoteDeviceType.TV -> "📺"
|
RemoteDeviceType.TV -> "电视"
|
||||||
RemoteDeviceType.AIR_CONDITIONER -> "❄️"
|
RemoteDeviceType.AIR_CONDITIONER -> "空调"
|
||||||
RemoteDeviceType.FAN -> "🌀"
|
RemoteDeviceType.FAN -> "🌀"
|
||||||
RemoteDeviceType.CUSTOM -> "🎛️"
|
RemoteDeviceType.CUSTOM -> "自定义"
|
||||||
}
|
}
|
||||||
Text(icon, fontSize = 28.sp)
|
Text(icon, fontSize = 28.sp)
|
||||||
IconButton(onClick = onDelete, modifier = Modifier.testTag("delete_remote_${remote.id.value}")) {
|
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) {
|
val modeText = if (remote.type == RemoteDeviceType.AIR_CONDITIONER) {
|
||||||
"❄️ 状态机动态写码"
|
"状态机动态写码"
|
||||||
} else if (remote.transmissionMode == TransmissionMode.STATIC_SLOTS) {
|
} else if (remote.transmissionMode == TransmissionMode.STATIC_SLOTS) {
|
||||||
"🚀 静态独占槽位"
|
"静态独占槽位"
|
||||||
} else {
|
} else {
|
||||||
"📦 动态写码"
|
"动态写码"
|
||||||
}
|
}
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
@@ -430,7 +430,7 @@ private fun CreateVirtualRemoteDialog(
|
|||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
value = name,
|
value = name,
|
||||||
onValueChange = { name = it },
|
onValueChange = { name = it },
|
||||||
label = { Text("遥控器名称(如:客厅电视、我的遥控器)") },
|
label = { Text("遥控器名称(如:电视、我的遥控器)") },
|
||||||
singleLine = true,
|
singleLine = true,
|
||||||
modifier = Modifier.fillMaxWidth().testTag("create_remote_name_input"),
|
modifier = Modifier.fillMaxWidth().testTag("create_remote_name_input"),
|
||||||
)
|
)
|
||||||
@@ -443,10 +443,10 @@ private fun CreateVirtualRemoteDialog(
|
|||||||
) {
|
) {
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
value = when (selectedCustomLayout) {
|
value = when (selectedCustomLayout) {
|
||||||
PanelLayoutStyle.TV_NAV -> "📺 电视导航布局 (内置方向盘/音量/频道)"
|
PanelLayoutStyle.TV_NAV -> "电视导航布局(内置方向盘、音量、频道)"
|
||||||
PanelLayoutStyle.MEDIA_PLAYER -> "🎵 媒体播放器布局 (播放/快进/切歌)"
|
PanelLayoutStyle.MEDIA_PLAYER -> "媒体播放器布局(播放、快进、切歌)"
|
||||||
PanelLayoutStyle.GRID -> "🎛️ 自由网格布局 (可自由增删按键)"
|
PanelLayoutStyle.GRID -> "自由网格布局(可自由增删按键)"
|
||||||
PanelLayoutStyle.AC_COMPACT -> "❄️ 空调布局"
|
PanelLayoutStyle.AC_COMPACT -> "空调布局"
|
||||||
},
|
},
|
||||||
onValueChange = {},
|
onValueChange = {},
|
||||||
readOnly = true,
|
readOnly = true,
|
||||||
@@ -459,21 +459,21 @@ private fun CreateVirtualRemoteDialog(
|
|||||||
onDismissRequest = { layoutDropdownExpanded = false },
|
onDismissRequest = { layoutDropdownExpanded = false },
|
||||||
) {
|
) {
|
||||||
DropdownMenuItem(
|
DropdownMenuItem(
|
||||||
text = { Text("📺 电视导航布局 (内置方向盘/音量/频道)") },
|
text = { Text("电视导航布局(内置方向盘、音量、频道)") },
|
||||||
onClick = {
|
onClick = {
|
||||||
selectedCustomLayout = PanelLayoutStyle.TV_NAV
|
selectedCustomLayout = PanelLayoutStyle.TV_NAV
|
||||||
layoutDropdownExpanded = false
|
layoutDropdownExpanded = false
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
DropdownMenuItem(
|
DropdownMenuItem(
|
||||||
text = { Text("🎵 媒体播放器布局 (播放/快进/切歌)") },
|
text = { Text("媒体播放器布局(播放、快进、切歌)") },
|
||||||
onClick = {
|
onClick = {
|
||||||
selectedCustomLayout = PanelLayoutStyle.MEDIA_PLAYER
|
selectedCustomLayout = PanelLayoutStyle.MEDIA_PLAYER
|
||||||
layoutDropdownExpanded = false
|
layoutDropdownExpanded = false
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
DropdownMenuItem(
|
DropdownMenuItem(
|
||||||
text = { Text("🎛️ 自由网格布局 (可自由增删按键)") },
|
text = { Text("自由网格布局(可自由增删按键)") },
|
||||||
onClick = {
|
onClick = {
|
||||||
selectedCustomLayout = PanelLayoutStyle.GRID
|
selectedCustomLayout = PanelLayoutStyle.GRID
|
||||||
layoutDropdownExpanded = false
|
layoutDropdownExpanded = false
|
||||||
@@ -538,7 +538,7 @@ private fun CreateVirtualRemoteDialog(
|
|||||||
onClick = { transmissionMode = TransmissionMode.STATIC_SLOTS },
|
onClick = { transmissionMode = TransmissionMode.STATIC_SLOTS },
|
||||||
)
|
)
|
||||||
Column {
|
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)
|
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 },
|
onClick = { transmissionMode = TransmissionMode.DYNAMIC_SCRATCH },
|
||||||
)
|
)
|
||||||
Column {
|
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)
|
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(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = "❄️ 空调多维状态自动采用 App 状态机 + 动态缓冲写码,杜绝状态踩踏并节省槽位。",
|
text = "空调多维状态自动采用状态机和动态缓冲写码,避免状态冲突并节省槽位。",
|
||||||
fontSize = 12.sp,
|
fontSize = 12.sp,
|
||||||
modifier = Modifier.padding(10.dp),
|
modifier = Modifier.padding(10.dp),
|
||||||
color = MaterialTheme.colorScheme.onSecondaryContainer,
|
color = MaterialTheme.colorScheme.onSecondaryContainer,
|
||||||
|
|||||||
+35
-25
@@ -41,6 +41,16 @@ import androidx.compose.material3.Surface
|
|||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TextButton
|
import androidx.compose.material3.TextButton
|
||||||
import androidx.compose.material3.TopAppBar
|
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.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
@@ -333,7 +343,7 @@ private fun AcControlPanel(
|
|||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = if (acState.power) "● 运行中" else "○ 已关机",
|
text = if (acState.power) "运行中" else "已关机",
|
||||||
color = if (acState.power) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurfaceVariant,
|
color = if (acState.power) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
fontWeight = FontWeight.Bold,
|
fontWeight = FontWeight.Bold,
|
||||||
)
|
)
|
||||||
@@ -345,7 +355,7 @@ private fun AcControlPanel(
|
|||||||
.background(if (acState.power) Color(0xFFFF5252) else MaterialTheme.colorScheme.outline)
|
.background(if (acState.power) Color(0xFFFF5252) else MaterialTheme.colorScheme.outline)
|
||||||
.testTag("ac_power_toggle"),
|
.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"),
|
modifier = Modifier.size(56.dp).testTag("ac_temp_down"),
|
||||||
shape = CircleShape,
|
shape = CircleShape,
|
||||||
) {
|
) {
|
||||||
Text("-", fontSize = 24.sp, fontWeight = FontWeight.Bold)
|
Icon(Icons.Outlined.Remove, contentDescription = "降低温度")
|
||||||
}
|
}
|
||||||
Button(
|
Button(
|
||||||
onClick = { onAdjustTemp(1) },
|
onClick = { onAdjustTemp(1) },
|
||||||
modifier = Modifier.size(56.dp).testTag("ac_temp_up"),
|
modifier = Modifier.size(56.dp).testTag("ac_temp_up"),
|
||||||
shape = CircleShape,
|
shape = CircleShape,
|
||||||
) {
|
) {
|
||||||
Text("+", fontSize = 24.sp, fontWeight = FontWeight.Bold)
|
Icon(Icons.Outlined.Add, contentDescription = "升高温度")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -421,19 +431,19 @@ private fun AcControlPanel(
|
|||||||
FilterChip(
|
FilterChip(
|
||||||
selected = acState.verticalSwing,
|
selected = acState.verticalSwing,
|
||||||
onClick = onToggleVSwing,
|
onClick = onToggleVSwing,
|
||||||
label = { Text("↕ 上下扫风") },
|
label = { Text("上下扫风") },
|
||||||
modifier = Modifier.weight(1f),
|
modifier = Modifier.weight(1f),
|
||||||
)
|
)
|
||||||
FilterChip(
|
FilterChip(
|
||||||
selected = acState.horizontalSwing,
|
selected = acState.horizontalSwing,
|
||||||
onClick = onToggleHSwing,
|
onClick = onToggleHSwing,
|
||||||
label = { Text("↔ 左右扫风") },
|
label = { Text("左右扫风") },
|
||||||
modifier = Modifier.weight(1f),
|
modifier = Modifier.weight(1f),
|
||||||
)
|
)
|
||||||
FilterChip(
|
FilterChip(
|
||||||
selected = acState.eco,
|
selected = acState.eco,
|
||||||
onClick = onToggleEco,
|
onClick = onToggleEco,
|
||||||
label = { Text("🌱 节能 ECO") },
|
label = { Text("节能") },
|
||||||
modifier = Modifier.weight(1f),
|
modifier = Modifier.weight(1f),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -463,9 +473,9 @@ private fun TvControlPanel(
|
|||||||
horizontalArrangement = Arrangement.SpaceAround,
|
horizontalArrangement = Arrangement.SpaceAround,
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
) {
|
) {
|
||||||
InteractiveRemoteButton("TV_POWER", "⏻ 电源", Color(0xFFFF5252), bindingMap["TV_POWER"], 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_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_SOURCE", "信号源", MaterialTheme.colorScheme.secondary, bindingMap["TV_SOURCE"], isLearnMode, learningButtonId, sendingButtonId, onButtonClick)
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
@@ -482,7 +492,7 @@ private fun TvControlPanel(
|
|||||||
onClick = { onButtonClick("TV_NAV_UP") },
|
onClick = { onButtonClick("TV_NAV_UP") },
|
||||||
modifier = Modifier.align(Alignment.TopCenter).padding(top = 10.dp).testTag("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") },
|
onClick = { onButtonClick("TV_NAV_DOWN") },
|
||||||
modifier = Modifier.align(Alignment.BottomCenter).padding(bottom = 10.dp).testTag("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") },
|
onClick = { onButtonClick("TV_NAV_LEFT") },
|
||||||
modifier = Modifier.align(Alignment.CenterStart).padding(start = 10.dp).testTag("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") },
|
onClick = { onButtonClick("TV_NAV_RIGHT") },
|
||||||
modifier = Modifier.align(Alignment.CenterEnd).padding(end = 10.dp).testTag("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 居中大按钮
|
// OK 居中大按钮
|
||||||
@@ -554,10 +564,10 @@ private fun TvControlPanel(
|
|||||||
) {
|
) {
|
||||||
Text("频道 CH", fontWeight = FontWeight.Bold, fontSize = 12.sp)
|
Text("频道 CH", fontWeight = FontWeight.Bold, fontSize = 12.sp)
|
||||||
Button(onClick = { onButtonClick("TV_CH_UP") }, modifier = Modifier.size(54.dp), shape = RoundedCornerShape(12.dp)) {
|
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)) {
|
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(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
horizontalArrangement = Arrangement.SpaceBetween,
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
) {
|
) {
|
||||||
InteractiveRemoteButton("MEDIA_POWER", "⏻ 电源", Color(0xFFFF5252), bindingMap["MEDIA_POWER"], 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)
|
InteractiveRemoteButton("MEDIA_MUTE", "静音", MaterialTheme.colorScheme.secondary, bindingMap["MEDIA_MUTE"], isLearnMode, learningButtonId, sendingButtonId, onButtonClick)
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
@@ -642,13 +652,13 @@ private fun GenericGridControlPanel(
|
|||||||
) {
|
) {
|
||||||
Text("按键列表 (${bindings.size})", fontWeight = FontWeight.Bold, fontSize = 16.sp)
|
Text("按键列表 (${bindings.size})", fontWeight = FontWeight.Bold, fontSize = 16.sp)
|
||||||
Button(onClick = onAddButton, modifier = Modifier.testTag("grid_add_key_button")) {
|
Button(onClick = onAddButton, modifier = Modifier.testTag("grid_add_key_button")) {
|
||||||
Text("➕ 添加按键")
|
Text("添加按键")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bindings.isEmpty()) {
|
if (bindings.isEmpty()) {
|
||||||
Box(modifier = Modifier.fillMaxWidth().weight(1f), contentAlignment = Alignment.Center) {
|
Box(modifier = Modifier.fillMaxWidth().weight(1f), contentAlignment = Alignment.Center) {
|
||||||
Text("暂无自定义按键,点击上方【➕ 添加按键】新建", color = MaterialTheme.colorScheme.onSurfaceVariant)
|
Text("暂无自定义按键,请使用上方添加操作新建", color = MaterialTheme.colorScheme.onSurfaceVariant)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
LazyVerticalGrid(
|
LazyVerticalGrid(
|
||||||
@@ -697,9 +707,9 @@ private fun GridButtonCard(
|
|||||||
Column(modifier = Modifier.weight(1f)) {
|
Column(modifier = Modifier.weight(1f)) {
|
||||||
Text(binding.displayName, fontWeight = FontWeight.Bold, fontSize = 15.sp)
|
Text(binding.displayName, fontWeight = FontWeight.Bold, fontSize = 15.sp)
|
||||||
val statusText = when {
|
val statusText = when {
|
||||||
isLearning -> "🟡 正在录制信号..."
|
isLearning -> "正在录制信号..."
|
||||||
binding.status == InfraredKeyStatus.READY -> "🟢 已就绪 (Slot ${binding.assignedSlot ?: "动态"})"
|
binding.status == InfraredKeyStatus.READY -> "已就绪(槽位 ${binding.assignedSlot ?: "动态"})"
|
||||||
else -> "⚪ 待录制 (点击录码)"
|
else -> "待录制(点击录码)"
|
||||||
}
|
}
|
||||||
Text(statusText, fontSize = 11.sp, color = MaterialTheme.colorScheme.onSurfaceVariant)
|
Text(statusText, fontSize = 11.sp, color = MaterialTheme.colorScheme.onSurfaceVariant)
|
||||||
}
|
}
|
||||||
@@ -712,7 +722,7 @@ private fun GridButtonCard(
|
|||||||
onClick = onDelete,
|
onClick = onDelete,
|
||||||
modifier = Modifier.size(36.dp).testTag("delete_key_${binding.buttonId}"),
|
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?,
|
sendingButtonId: String?,
|
||||||
) {
|
) {
|
||||||
if (learningButtonId == buttonId) {
|
if (learningButtonId == buttonId) {
|
||||||
Text("🟡 录制中", fontSize = 12.sp, fontWeight = FontWeight.Bold)
|
Text("录制中", fontSize = 12.sp, fontWeight = FontWeight.Bold)
|
||||||
} else if (sendingButtonId == buttonId) {
|
} else if (sendingButtonId == buttonId) {
|
||||||
CircularProgressIndicator(modifier = Modifier.size(16.dp), color = Color.White)
|
CircularProgressIndicator(modifier = Modifier.size(16.dp), color = Color.White)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
+13
-13
@@ -26,24 +26,24 @@ data class RemoteButtonSpec(
|
|||||||
|
|
||||||
object RemoteSceneConfig {
|
object RemoteSceneConfig {
|
||||||
object AirConditioner {
|
object AirConditioner {
|
||||||
val POWER = RemoteButtonSpec("AC_POWER", "1", R.string.infrared_key_ac_power, "空调-电源", "⏻")
|
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_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 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 MODE = RemoteButtonSpec("AC_MODE", "4", R.string.infrared_key_ac_mode, "空调-模式", "模式")
|
||||||
val FAN = RemoteButtonSpec("AC_FAN", "5", R.string.infrared_key_ac_fan, "空调-风速", "风速 💨")
|
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 SWING = RemoteButtonSpec("AC_SWING", "6", R.string.infrared_key_ac_swing, "空调-扫风", "扫风")
|
||||||
val TIMER = RemoteButtonSpec("AC_TIMER", "7", R.string.infrared_key_ac_timer, "空调-定时", "定时 ⏱")
|
val TIMER = RemoteButtonSpec("AC_TIMER", "7", R.string.infrared_key_ac_timer, "空调-定时", "定时")
|
||||||
|
|
||||||
val buttons = listOf(POWER, TEMP_UP, TEMP_DOWN, MODE, FAN, SWING, TIMER)
|
val buttons = listOf(POWER, TEMP_UP, TEMP_DOWN, MODE, FAN, SWING, TIMER)
|
||||||
}
|
}
|
||||||
|
|
||||||
object Television {
|
object Television {
|
||||||
val POWER = RemoteButtonSpec("TV_POWER", "21", R.string.infrared_key_tv_power, "电视-电源", "⏻")
|
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 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_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_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_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 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 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_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 -")
|
val VOL_DOWN = RemoteButtonSpec("TV_VOL_DOWN", "29", R.string.infrared_key_tv_vol_down, "电视-音量-", "VOL -")
|
||||||
|
|||||||
+6
-4
@@ -45,6 +45,8 @@ import androidx.compose.ui.unit.sp
|
|||||||
import androidx.hilt.navigation.compose.hiltViewModel
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import com.flagship.abox.manager.designsystem.ABoxSurface
|
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.R
|
||||||
import com.flagship.abox.manager.infrared.remote.InfraredRemoteUiState
|
import com.flagship.abox.manager.infrared.remote.InfraredRemoteUiState
|
||||||
import com.flagship.abox.manager.infrared.remote.InfraredRemoteViewModel
|
import com.flagship.abox.manager.infrared.remote.InfraredRemoteViewModel
|
||||||
@@ -158,12 +160,12 @@ internal fun InfraredRemoteScreen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 按键管理 / 设置入口按钮
|
// 按键管理 / 设置入口按钮
|
||||||
IconButton(
|
ABoxIconButton(
|
||||||
|
key = ABoxIconKey.EDIT,
|
||||||
|
contentDescription = "打开红外设置",
|
||||||
onClick = onOpenSettings,
|
onClick = onOpenSettings,
|
||||||
modifier = Modifier.testTag("remote_settings_button"),
|
modifier = Modifier.testTag("remote_settings_button"),
|
||||||
) {
|
)
|
||||||
Text("⚙️", fontSize = 20.sp)
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -35,12 +35,12 @@
|
|||||||
<string name="infrared_remote_title">红外遥控器</string>
|
<string name="infrared_remote_title">红外遥控器</string>
|
||||||
<string name="infrared_remote_recording">录制中</string>
|
<string name="infrared_remote_recording">录制中</string>
|
||||||
<string name="infrared_remote_learning_mode">学习模式</string>
|
<string name="infrared_remote_learning_mode">学习模式</string>
|
||||||
<string name="infrared_remote_learning_banner">🔴 学习模式已开启:点击任意按键开始录制实体遥控器信号</string>
|
<string name="infrared_remote_learning_banner">学习模式已开启:点击任意按键开始录制实体遥控器信号</string>
|
||||||
<string name="infrared_remote_scene_ac">❄️ 空调面板</string>
|
<string name="infrared_remote_scene_ac">空调面板</string>
|
||||||
<string name="infrared_remote_scene_tv">📺 电视面板</string>
|
<string name="infrared_remote_scene_tv">电视面板</string>
|
||||||
<string name="infrared_remote_settings">设置</string>
|
<string name="infrared_remote_settings">设置</string>
|
||||||
|
|
||||||
<string name="infrared_msg_learning_mode_enabled">🔴 学习模式已开启:点击任意按键开始录制</string>
|
<string name="infrared_msg_learning_mode_enabled">学习模式已开启:点击任意按键开始录制</string>
|
||||||
<string name="infrared_msg_recording_key">正在录制【%1$s】(槽位 %2$s),请按下实体遥控器按键…</string>
|
<string name="infrared_msg_recording_key">正在录制【%1$s】(槽位 %2$s),请按下实体遥控器按键…</string>
|
||||||
<string name="infrared_msg_learned_success">【%1$s】录制成功</string>
|
<string name="infrared_msg_learned_success">【%1$s】录制成功</string>
|
||||||
<string name="infrared_msg_key_not_learned">按键【%1$s】尚未学习,开启右上角学习模式即可录制</string>
|
<string name="infrared_msg_key_not_learned">按键【%1$s】尚未学习,开启右上角学习模式即可录制</string>
|
||||||
@@ -51,8 +51,8 @@
|
|||||||
<string name="infrared_label_temp_control">温度调节</string>
|
<string name="infrared_label_temp_control">温度调节</string>
|
||||||
<string name="infrared_label_vol">音量</string>
|
<string name="infrared_label_vol">音量</string>
|
||||||
<string name="infrared_label_ch">频道</string>
|
<string name="infrared_label_ch">频道</string>
|
||||||
<string name="infrared_label_cool_mode">❄️ 制冷模式</string>
|
<string name="infrared_label_cool_mode">制冷模式</string>
|
||||||
<string name="infrared_label_ac_status">💨 自动风速 | ↔ 自动扫风</string>
|
<string name="infrared_label_ac_status">自动风速 | 自动扫风</string>
|
||||||
|
|
||||||
<string name="infrared_key_ac_power">空调-电源</string>
|
<string name="infrared_key_ac_power">空调-电源</string>
|
||||||
<string name="infrared_key_ac_temp_up">空调-升温</string>
|
<string name="infrared_key_ac_temp_up">空调-升温</string>
|
||||||
@@ -98,10 +98,10 @@
|
|||||||
<string name="infrared_hub_static_quota">静态占用:%1$d</string>
|
<string name="infrared_hub_static_quota">静态占用:%1$d</string>
|
||||||
<string name="infrared_hub_dynamic_scratch">动态缓冲:Slot %1$s</string>
|
<string name="infrared_hub_dynamic_scratch">动态缓冲:Slot %1$s</string>
|
||||||
<string name="infrared_hub_remotes_title">虚拟遥控器</string>
|
<string name="infrared_hub_remotes_title">虚拟遥控器</string>
|
||||||
<string name="infrared_hub_no_remotes">暂无虚拟遥控器,点击右上角或下方 ➕ 添加</string>
|
<string name="infrared_hub_no_remotes">暂无虚拟遥控器,请使用添加操作</string>
|
||||||
<string name="infrared_hub_add_remote">添加遥控器</string>
|
<string name="infrared_hub_add_remote">添加遥控器</string>
|
||||||
<string name="infrared_hub_mode_static">🚀 静态独占(%1$s 槽位)</string>
|
<string name="infrared_hub_mode_static">静态独占(%1$s 槽位)</string>
|
||||||
<string name="infrared_hub_mode_dynamic">📦 动态缓冲(共用 Slot %1$s)</string>
|
<string name="infrared_hub_mode_dynamic">动态缓冲(共用槽位 %1$s)</string>
|
||||||
<string name="infrared_hub_create_dialog_title">添加虚拟遥控器</string>
|
<string name="infrared_hub_create_dialog_title">添加虚拟遥控器</string>
|
||||||
<string name="infrared_hub_device_type_label">设备类型</string>
|
<string name="infrared_hub_device_type_label">设备类型</string>
|
||||||
<string name="infrared_hub_brand_label">预设码库 / 品牌</string>
|
<string name="infrared_hub_brand_label">预设码库 / 品牌</string>
|
||||||
@@ -110,8 +110,8 @@
|
|||||||
<string name="infrared_hub_trans_mode_dynamic_desc">节省槽位(0 额外槽位),现场写码发射(~80ms)</string>
|
<string name="infrared_hub_trans_mode_dynamic_desc">节省槽位(0 额外槽位),现场写码发射(~80ms)</string>
|
||||||
<string name="infrared_hub_quota_insufficient">硬件槽位不足,请选择动态写码模式</string>
|
<string name="infrared_hub_quota_insufficient">硬件槽位不足,请选择动态写码模式</string>
|
||||||
<string name="infrared_hub_raw_keys_button">硬件槽位与底层按键管理</string>
|
<string name="infrared_hub_raw_keys_button">硬件槽位与底层按键管理</string>
|
||||||
<string name="infrared_hub_device_type_tv">📺 电视机 / 电视盒子</string>
|
<string name="infrared_hub_device_type_tv">电视机 / 电视盒子</string>
|
||||||
<string name="infrared_hub_device_type_ac">❄️ 空调设备</string>
|
<string name="infrared_hub_device_type_ac">空调设备</string>
|
||||||
<string name="infrared_hub_device_type_fan">🌀 电风扇 / 空气净化器</string>
|
<string name="infrared_hub_device_type_fan">🌀 电风扇 / 空气净化器</string>
|
||||||
<string name="infrared_hub_device_type_custom">🎛️ 自定义面板</string>
|
<string name="infrared_hub_device_type_custom">自定义面板</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -36,12 +36,12 @@
|
|||||||
<string name="infrared_remote_recording">Recording</string>
|
<string name="infrared_remote_recording">Recording</string>
|
||||||
<string name="infrared_hub_my_remotes">My Remotes</string>
|
<string name="infrared_hub_my_remotes">My Remotes</string>
|
||||||
<string name="infrared_remote_learning_mode">Learn Mode</string>
|
<string name="infrared_remote_learning_mode">Learn Mode</string>
|
||||||
<string name="infrared_remote_learning_banner">🔴 Learn mode active: tap any button to record</string>
|
<string name="infrared_remote_learning_banner">Learn mode active: tap any button to record</string>
|
||||||
<string name="infrared_remote_scene_ac">❄️ Air Conditioner</string>
|
<string name="infrared_remote_scene_ac">Air Conditioner</string>
|
||||||
<string name="infrared_remote_scene_tv">📺 Television</string>
|
<string name="infrared_remote_scene_tv">Television</string>
|
||||||
<string name="infrared_remote_settings">Settings</string>
|
<string name="infrared_remote_settings">Settings</string>
|
||||||
|
|
||||||
<string name="infrared_msg_learning_mode_enabled">🔴 Learn mode active: tap any button to record</string>
|
<string name="infrared_msg_learning_mode_enabled">Learn mode active: tap any button to record</string>
|
||||||
<string name="infrared_msg_recording_key">Recording [%1$s] (Slot %2$s), press remote button…</string>
|
<string name="infrared_msg_recording_key">Recording [%1$s] (Slot %2$s), press remote button…</string>
|
||||||
<string name="infrared_msg_learned_success">[%1$s] recorded successfully</string>
|
<string name="infrared_msg_learned_success">[%1$s] recorded successfully</string>
|
||||||
<string name="infrared_msg_key_not_learned">Button [%1$s] is not learned. Enable learn mode to record.</string>
|
<string name="infrared_msg_key_not_learned">Button [%1$s] is not learned. Enable learn mode to record.</string>
|
||||||
@@ -52,8 +52,8 @@
|
|||||||
<string name="infrared_label_temp_control">Temp Control</string>
|
<string name="infrared_label_temp_control">Temp Control</string>
|
||||||
<string name="infrared_label_vol">VOL</string>
|
<string name="infrared_label_vol">VOL</string>
|
||||||
<string name="infrared_label_ch">CH</string>
|
<string name="infrared_label_ch">CH</string>
|
||||||
<string name="infrared_label_cool_mode">❄️ Cool Mode</string>
|
<string name="infrared_label_cool_mode">Cool Mode</string>
|
||||||
<string name="infrared_label_ac_status">💨 Auto Fan | ↔ Swing</string>
|
<string name="infrared_label_ac_status">Auto Fan | Swing</string>
|
||||||
|
|
||||||
<string name="infrared_key_ac_power">AC Power</string>
|
<string name="infrared_key_ac_power">AC Power</string>
|
||||||
<string name="infrared_key_ac_temp_up">AC Temp +</string>
|
<string name="infrared_key_ac_temp_up">AC Temp +</string>
|
||||||
@@ -100,8 +100,8 @@
|
|||||||
<string name="infrared_hub_remotes_title">Virtual Remotes</string>
|
<string name="infrared_hub_remotes_title">Virtual Remotes</string>
|
||||||
<string name="infrared_hub_no_remotes">No virtual remotes added yet. Tap + to add one.</string>
|
<string name="infrared_hub_no_remotes">No virtual remotes added yet. Tap + to add one.</string>
|
||||||
<string name="infrared_hub_add_remote">Add Remote</string>
|
<string name="infrared_hub_add_remote">Add Remote</string>
|
||||||
<string name="infrared_hub_mode_static">🚀 Static Mode (%1$s slots)</string>
|
<string name="infrared_hub_mode_static">Static Mode (%1$s slots)</string>
|
||||||
<string name="infrared_hub_mode_dynamic">📦 Dynamic Mode (Scratch Slot %1$s)</string>
|
<string name="infrared_hub_mode_dynamic">Dynamic Mode (Scratch Slot %1$s)</string>
|
||||||
<string name="infrared_hub_create_dialog_title">Add Virtual Remote</string>
|
<string name="infrared_hub_create_dialog_title">Add Virtual Remote</string>
|
||||||
<string name="infrared_hub_device_type_label">Device Type</string>
|
<string name="infrared_hub_device_type_label">Device Type</string>
|
||||||
<string name="infrared_hub_brand_label">Brand / Preset Library</string>
|
<string name="infrared_hub_brand_label">Brand / Preset Library</string>
|
||||||
@@ -110,8 +110,8 @@
|
|||||||
<string name="infrared_hub_trans_mode_dynamic_desc">Saves slots (0 extra slots), writes code on-the-fly (~80ms)</string>
|
<string name="infrared_hub_trans_mode_dynamic_desc">Saves slots (0 extra slots), writes code on-the-fly (~80ms)</string>
|
||||||
<string name="infrared_hub_quota_insufficient">Slot quota exceeded. Please choose Dynamic mode.</string>
|
<string name="infrared_hub_quota_insufficient">Slot quota exceeded. Please choose Dynamic mode.</string>
|
||||||
<string name="infrared_hub_raw_keys_button">Hardware Slot / Raw Key Management</string>
|
<string name="infrared_hub_raw_keys_button">Hardware Slot / Raw Key Management</string>
|
||||||
<string name="infrared_hub_device_type_tv">📺 Television (TV)</string>
|
<string name="infrared_hub_device_type_tv">Television (TV)</string>
|
||||||
<string name="infrared_hub_device_type_ac">❄️ Air Conditioner (AC)</string>
|
<string name="infrared_hub_device_type_ac">Air Conditioner (AC)</string>
|
||||||
<string name="infrared_hub_device_type_fan">🌀 Fan / Air Purifier</string>
|
<string name="infrared_hub_device_type_fan">🌀 Fan / Air Purifier</string>
|
||||||
<string name="infrared_hub_device_type_custom">🎛️ Custom Panel</string>
|
<string name="infrared_hub_device_type_custom">Custom Panel</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
+7
-6
@@ -12,6 +12,7 @@ import com.flagship.abox.manager.domain.infrared.VirtualRemoteRepository
|
|||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
|
import kotlinx.coroutines.flow.update
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
|
||||||
class FakeVirtualRemoteRepository : VirtualRemoteRepository {
|
class FakeVirtualRemoteRepository : VirtualRemoteRepository {
|
||||||
@@ -80,13 +81,13 @@ class FakeVirtualRemoteRepository : VirtualRemoteRepository {
|
|||||||
): DomainResult<VirtualRemoteId> {
|
): DomainResult<VirtualRemoteId> {
|
||||||
remotes[remote.id] = remote
|
remotes[remote.id] = remote
|
||||||
bindings[remote.id] = initialBindings.toMutableList()
|
bindings[remote.id] = initialBindings.toMutableList()
|
||||||
changeTrigger.value = System.currentTimeMillis()
|
changeTrigger.update { it + 1L }
|
||||||
return DomainResult.Success(remote.id)
|
return DomainResult.Success(remote.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun updateRemote(remote: VirtualRemote): DomainResult<Unit> {
|
override suspend fun updateRemote(remote: VirtualRemote): DomainResult<Unit> {
|
||||||
remotes[remote.id] = remote
|
remotes[remote.id] = remote
|
||||||
changeTrigger.value = System.currentTimeMillis()
|
changeTrigger.update { it + 1L }
|
||||||
return DomainResult.Success(Unit)
|
return DomainResult.Success(Unit)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,7 +97,7 @@ class FakeVirtualRemoteRepository : VirtualRemoteRepository {
|
|||||||
): DomainResult<Unit> {
|
): DomainResult<Unit> {
|
||||||
remotes.remove(remoteId)
|
remotes.remove(remoteId)
|
||||||
bindings.remove(remoteId)
|
bindings.remove(remoteId)
|
||||||
changeTrigger.value = System.currentTimeMillis()
|
changeTrigger.update { it + 1L }
|
||||||
return DomainResult.Success(Unit)
|
return DomainResult.Success(Unit)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,7 +110,7 @@ class FakeVirtualRemoteRepository : VirtualRemoteRepository {
|
|||||||
list.add(binding)
|
list.add(binding)
|
||||||
}
|
}
|
||||||
bindings[binding.remoteId] = list
|
bindings[binding.remoteId] = list
|
||||||
changeTrigger.value = System.currentTimeMillis()
|
changeTrigger.update { it + 1L }
|
||||||
return DomainResult.Success(Unit)
|
return DomainResult.Success(Unit)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,7 +121,7 @@ class FakeVirtualRemoteRepository : VirtualRemoteRepository {
|
|||||||
val list = bindings[remoteId] ?: return DomainResult.Success(Unit)
|
val list = bindings[remoteId] ?: return DomainResult.Success(Unit)
|
||||||
list.removeAll { it.buttonId == buttonId }
|
list.removeAll { it.buttonId == buttonId }
|
||||||
bindings[remoteId] = list
|
bindings[remoteId] = list
|
||||||
changeTrigger.value = System.currentTimeMillis()
|
changeTrigger.update { it + 1L }
|
||||||
return DomainResult.Success(Unit)
|
return DomainResult.Success(Unit)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,7 +132,7 @@ class FakeVirtualRemoteRepository : VirtualRemoteRepository {
|
|||||||
): DomainResult<Unit> {
|
): DomainResult<Unit> {
|
||||||
val existing = remotes[remoteId] ?: return DomainResult.Success(Unit)
|
val existing = remotes[remoteId] ?: return DomainResult.Success(Unit)
|
||||||
remotes[remoteId] = existing.copy(acState = state)
|
remotes[remoteId] = existing.copy(acState = state)
|
||||||
changeTrigger.value = System.currentTimeMillis()
|
changeTrigger.update { it + 1L }
|
||||||
return DomainResult.Success(Unit)
|
return DomainResult.Success(Unit)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user