feat(infrared): add infrared control, learning, and virtual remote module (#9)

### 概述 / Summary
完整实现红外控制与学习模块(`:android:feature:infrared`),支持红外设备按键学习、实体发射、Room 本地持久化,以及空调 (AC) / 电视 (TV) 虚拟遥控器面板。

### 核心变更 / Key Changes
1. **领域模型与用例 (`:domain`)**:
   - 实现按键学习流程:`LearnInfraredKey`、`ManageInfraredKey`、`InfraredKeyFactory`;
   - 增加虚拟遥控器模型与用例:`CreateVirtualRemote`、`LearnVirtualRemoteKey`、`SendVirtualRemoteAction`、`AcCodeGenerator` 与预置码库 `PresetCodeLibrary`。
2. **数据持久化与仓储 (`:android:feature:infrared`)**:
   - 引入 Room 数据库 `InfraredDatabase` 及 DAO,提供 `RoomInfraredKeyRepository` 与 `RoomVirtualRemoteRepository`;
   - 支持多配置隔离(`ProviderProfileId`)、按键状态管理(`LEARNING` / `READY` / `FAILED`)。
3. **UI 与 ViewModel (`:android:feature:infrared`)**:
   - `InfraredControlScreen`:红外学习与按键调试列表;
   - `RemotePanelScreen` / `AcRemotePanel` / `TvRemotePanel`:空调/电视专属可视化遥控面板;
   - `InfraredHubScreen`:红外中枢与多遥控器管理入口;
   - 在认证后导航栈中将 `DeviceListScreen` 的红外入口无缝对接到 `InfraredHubRoute`。
4. **测试与文档**:
   - 补齐用例、Fakes、Repository、ViewModel 以及 Compose UI 自动化测试;
   - 补充红外控制设计规范与真机硬件验收清单。

Reviewed-on: #9
Co-authored-by: mxhsnd <2049295946@qq.com>
Co-authored-by: KremeCN <3265494849@qq.com>
This commit is contained in:
2026-08-25 15:00:06 +08:00
committed by KremeCN
co-authored by KremeCN
parent 249721be33
commit 0c783ca2f4
78 changed files with 12785 additions and 15 deletions
@@ -0,0 +1,117 @@
<resources>
<string name="infrared_title">Infrared Control</string>
<string name="infrared_mode_fake">Mode: Fake / Simulated</string>
<string name="infrared_mode_real">Mode: Real ABSDK</string>
<string name="infrared_switch_mode">Switch Mode</string>
<string name="infrared_device_name_label">Infrared Device Name</string>
<string name="infrared_device_name_hint">e.g. ir-living</string>
<string name="infrared_saved_device">Saved Device: %1$s</string>
<string name="infrared_no_device_saved">No infrared device configured</string>
<string name="infrared_save_device">Save Device</string>
<string name="infrared_keys_title">Learned Keys</string>
<string name="infrared_no_keys">No infrared keys saved</string>
<string name="infrared_learn_new_key">Learn New Key</string>
<string name="infrared_status_learning">Learning…</string>
<string name="infrared_status_ready">Ready</string>
<string name="infrared_status_failed">Failed</string>
<string name="infrared_send">Send</string>
<string name="infrared_sending">Sending…</string>
<string name="infrared_retry">Retry</string>
<string name="infrared_rename">Rename</string>
<string name="infrared_delete">Delete</string>
<string name="infrared_learn_dialog_title">Learn Infrared Key</string>
<string name="infrared_learn_dialog_prompt">Prepare the physical remote. After starting, point it at the infrared controller and press the target button.</string>
<string name="infrared_learn_dialog_input_label">Key Name (e.g. Power)</string>
<string name="infrared_learn_dialog_slot_label">Key Slot (1-100)</string>
<string name="infrared_key_slot_label">Key Slot: %1$s</string>
<string name="infrared_learn_dialog_start">Start Learning</string>
<string name="infrared_rename_dialog_title">Rename Key</string>
<string name="infrared_rename_dialog_input_label">New Display Name</string>
<string name="infrared_delete_dialog_title">Delete Key</string>
<string name="infrared_delete_dialog_message">Only removes the key locally from this app. ABox server may retain the learned key.</string>
<string name="infrared_dialog_cancel">Cancel</string>
<string name="infrared_dialog_confirm">Confirm</string>
<string name="infrared_back">Back</string>
<string name="infrared_remote_title">Infrared Remote</string>
<string name="infrared_remote_recording">Recording</string>
<string name="infrared_hub_my_remotes">My Remotes</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_scene_ac">❄️ Air Conditioner</string>
<string name="infrared_remote_scene_tv">📺 Television</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_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_key_not_learned">Button [%1$s] is not learned. Enable learn mode to record.</string>
<string name="infrared_msg_signal_sent">Sent: %1$s</string>
<string name="infrared_msg_device_offline">Infrared controller offline (code: %1$s)</string>
<string name="infrared_msg_load_failed">Failed to load data</string>
<string name="infrared_msg_operation_failed">Operation failed</string>
<string name="infrared_label_temp_control">Temp Control</string>
<string name="infrared_label_vol">VOL</string>
<string name="infrared_label_ch">CH</string>
<string name="infrared_label_cool_mode">❄️ Cool Mode</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_temp_up">AC Temp +</string>
<string name="infrared_key_ac_temp_down">AC Temp -</string>
<string name="infrared_key_ac_mode">AC Mode</string>
<string name="infrared_key_ac_fan">AC Fan Speed</string>
<string name="infrared_key_ac_swing">AC Swing</string>
<string name="infrared_key_ac_timer">AC Timer</string>
<string name="infrared_key_tv_power">TV Power</string>
<string name="infrared_key_tv_mute">TV Mute</string>
<string name="infrared_key_tv_nav_up">TV Up</string>
<string name="infrared_key_tv_nav_down">TV Down</string>
<string name="infrared_key_tv_nav_left">TV Left</string>
<string name="infrared_key_tv_nav_right">TV Right</string>
<string name="infrared_key_tv_ok">TV OK</string>
<string name="infrared_key_tv_vol_up">TV Vol +</string>
<string name="infrared_key_tv_vol_down">TV Vol -</string>
<string name="infrared_key_tv_ch_up">TV CH +</string>
<string name="infrared_key_tv_ch_down">TV CH -</string>
<string name="infrared_key_tv_home">TV Home</string>
<string name="infrared_key_tv_back">TV Back</string>
<string name="infrared_key_tv_menu">TV Menu</string>
<string name="infrared_control_title">Device Configuration</string>
<string name="infrared_device_config_section">ABSDK Device Name</string>
<string name="infrared_device_config_desc">ABSDK matches hardware devices by device name (default: 红外控制器). Commands will be dispatched to this target device.</string>
<string name="infrared_device_name_current">Current Bound Device: %1$s</string>
<string name="infrared_device_save_changes">Save Changes</string>
<string name="infrared_device_stats_section">Hardware Slot Budget</string>
<string name="infrared_mode_label">Environment: %1$s</string>
<string name="infrared_mode_local_simulation">Local Experience (Simulation)</string>
<string name="infrared_mode_abox_real">ABox (Real Hardware)</string>
<string name="infrared_msg_device_name_saved">Device name saved successfully</string>
<string name="infrared_msg_device_name_blank">Device name cannot be blank</string>
<string name="infrared_msg_key_name_blank">Key name cannot be blank</string>
<string name="infrared_msg_slot_invalid">Key slot must be between 1 and 100</string>
<string name="infrared_msg_key_renamed">Key renamed</string>
<string name="infrared_msg_key_deleted">Key removed locally</string>
<string name="infrared_msg_key_not_ready">Key is not ready to send</string>
<string name="infrared_hub_title">Infrared Hub</string>
<string name="infrared_hub_slot_quota">Hardware Slots: %1$d / %2$d allocated (%3$d free)</string>
<string name="infrared_hub_static_quota">Static: %1$d</string>
<string name="infrared_hub_dynamic_scratch">Dynamic Buffer: Slot %1$s</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_add_remote">Add Remote</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_create_dialog_title">Add Virtual Remote</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_trans_mode_label">Transmission Mode</string>
<string name="infrared_hub_trans_mode_static_desc">Low latency (~20ms), instant response, occupies ~15 slots</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_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_ac">❄️ Air Conditioner (AC)</string>
<string name="infrared_hub_device_type_fan">🌀 Fan / Air Purifier</string>
<string name="infrared_hub_device_type_custom">🎛️ Custom Panel</string>
</resources>