From c3c9db5447f53290ea37051d43efb796502cd497 Mon Sep 17 00:00:00 2001 From: Songzex <2402265378@qq.com> Date: Tue, 28 Apr 2026 16:55:58 +0800 Subject: [PATCH] =?UTF-8?q?=E8=BF=9C=E7=A8=8B=E9=81=A5=E6=8E=A7=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2=E4=B8=AD=E9=81=97=E6=BC=8F=E7=9A=84=E8=AF=AD=E8=A8=80?= =?UTF-8?q?=E5=88=87=E6=8D=A2=E6=94=AF=E6=8C=81=E9=83=A8=E5=88=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/languages/en-US.json | 352 +++++++++++++++++ assets/languages/zh-CN.json | 365 ++++++++++++++++++ lib/core/localization/locale_cubit.dart | 36 ++ .../widgets/center_control_area.dart | 44 +-- 4 files changed, 774 insertions(+), 23 deletions(-) create mode 100644 assets/languages/en-US.json create mode 100644 assets/languages/zh-CN.json create mode 100644 lib/core/localization/locale_cubit.dart diff --git a/assets/languages/en-US.json b/assets/languages/en-US.json new file mode 100644 index 00000000..f1f641d5 --- /dev/null +++ b/assets/languages/en-US.json @@ -0,0 +1,352 @@ +{ + "app_name": "Maibu Mowing Robot", + + "common": { + "confirm": "Confirm", + "cancel": "Cancel", + "ok": "OK", + "back": "Back", + "close": "Close", + "loading": "Loading...", + "error": "Error", + "success": "Success", + "unknown": "Unknown" + }, + + "login": { + "title": "Login", + "username": "Username", + "password": "Password", + "login_button": "Login", + "logout": "Logout", + "username_hint": "Enter username", + "password_hint": "Enter password", + "login_success": "Login successful", + "login_failed": "Login failed" + }, + + "home": { + "title": "Home", + "devices": "My Devices", + "no_devices": "No devices", + "add_device": "Add Device", + "device_online": "Online", + "device_offline": "Offline", + "remote_control": "Remote Control", + "route_plan": "Route Plan", + "machine_status": "Machine Status", + "switch_device": "Switch Device", + "loading": "Loading...", + "no_history": "No records", + "work_params": "Work Params", + "view_details": "Details", + "work_area": "Area", + "work_distance": "Distance", + "work_duration": "Duration", + "history_details": "History", + "start_time": "Start", + "end_time": "End", + "working_area": "Area", + "working_distance": "Distance", + "time_spent": "Time", + "click_to_view": "View details", + "in_use": "In Use", + "switch": "Switch", + "details": "Details", + "unknown_device": "Unknown Device", + "no_device_bound": "No device bound" + }, + + "running_status": { + "title": "Device Data Monitor", + "motor_params": "Motor Parameters", + "other_params": "Other Parameters", + "left_wheel": "Left Wheel", + "right_wheel": "Right Wheel", + "target_speed": "Target Speed", + "measure_speed": "Measure Speed", + "current": "Current", + "motor_temp": "Motor Temp", + "pitch_angle": "Pitch", + "roll_angle": "Roll", + "heading_angle": "Heading", + "battery": "Battery", + "chip_temp": "Chip Temp", + "knife_speed": "Knife Speed", + "control_mode": "Control Mode", + "longitude": "Longitude", + "latitude": "Latitude", + "altitude": "Altitude", + "satellite_count": "Satellites", + "heading_status": "Heading Status", + "position_quality": "Position Quality", + "not_initialized": "Not Initialized", + "invalid": "Invalid", + "valid": "Valid", + "local_control": "Local Control", + "remote_control": "Remote Control", + "data_refresh_success": "Data refreshed!", + "no_device": "No device available", + "left_right_measure_speed": "Left/Right Measure Speed", + "left_right_target_speed": "Left/Right Target Speed", + "current_compare": "Current Compare", + "motor_temp_compare": "Motor Temp Compare", + "heading_angle_chart": "Heading Angle", + "card": "Card", + "chart": "Chart", + "name": "Name", + "value": "Value", + "initialized": "Initialized", + "no_data": "No Data", + "voltage": "Voltage" + }, + + "machine_details": { + "title": "Device Details", + "real_time_status": "Real-time Status", + "control_mode": "Control Mode", + "battery_voltage": "Battery Voltage", + "remaining_battery": "Remaining Battery", + "basic_info": "Basic Info", + "device_name": "Device Name", + "device_id": "Device ID", + "resource_center": "Resource Center", + "user_manual": "User Manual", + "product_manual": "Product Manual", + "unbind": "Unbind Device", + "unbind_confirm_title": "Confirm Unbind", + "unbind_confirm_content": "Are you sure to unbind [%s]? You will not be able to manage this device after unbinding.", + "edit_name_title": "Edit Device Name", + "edit_name_hint": "Enter device name", + "name_empty_error": "Name cannot be empty", + "name_updated_success": "Device name updated to: %s", + "unbind_success": "Device '%s' unbound successfully", + "unbind_failed": "Unbind failed: %s", + "update_failed": "Update failed: %s", + "device_info_error": "Device information error, cannot unbind", + "unbind_exception": "Unbind exception: %s", + "update_exception": "Update exception: %s", + "updating_name": "Updating name...", + "unbinding_device": "Unbinding device...", + "edit_name": "Edit Name", + "name_updated": "Name updated", + "remote_mode": "Remote Mode", + "local_mode": "Local Mode", + "copied": "Copied" + }, + + "ai": { + "title": "New Energy PV Agent", + "new_session": "New Session", + "history": "History", + "deep_thinking": "Deep Thinking", + "final_conclusion": "Final Conclusion", + "thinking_hint": "AI is thinking...", + "input_hint": "Enter your thoughts...", + "album": "Album", + "camera": "Camera" + }, + + "my": { + "title": "Profile", + "language": "Language", + "chinese": "中文", + "english": "English", + "settings": "Settings", + "about": "About", + "version": "Version", + "feedback": "Feedback", + "privacy_policy": "Privacy Policy", + "user_agreement": "User Agreement", + "operation_video": "Operation Video", + "rental_service": "Rental Service", + "help_support": "Help & Support", + "after_sales_policy": "After-sales Policy" + }, + + "manual": { + "title": "User Manual", + "detail": "Details", + "no_content": "No content available", + "menu_titles": [ + "Safety Warnings and Precautions", + "Machine Operation Instructions", + "Maintenance and Repair", + "Troubleshooting", + "Transportation Guidelines", + "Warranty and After-sales Service" + ], + "submenus": { + "alert": "Special Warnings", + "alertinstruction": "Warning Label Instructions", + "safety": "Safety Operation Guidelines", + "safetywork": "Safe Driving and Working Practices", + "prepare": "Pre-start Preparation", + "startmethod": "Starting Method", + "work": "Mowing Method", + "stop": "Parking Method", + "controluse": "Remote Control Usage", + "check1": "Regular Inspection Checklist", + "check2": "Walking and Mowing Parts Inspection", + "supply": "Fuel, Water, Lubricant and Grease Schedule", + "check4": "Consumable Parts Replacement List", + "check5": "Engine", + "check6": "Walking Device", + "check7": "Post-use Maintenance", + "breakdown1": "Problem Diagnosis Table", + "starpoint": "Transportation Guidelines", + "about1": "About Warranty", + "about2": "About After-sales Service", + "supplyyear": "Parts Supply Period" + }, + "tables": { + "supply_title": "Fuel, Water, Lubricant and Grease Schedule", + "item": "Item", + "period": "Replenishment/Replacement Period", + "recommend": "Recommended Type", + "capacity": "Capacity", + "problem": "Problem Description", + "reason": "Cause", + "solution": "Solution", + "generator": "Generator", + "walking_device": "Walking Device", + "mowing_device": "Mowing Device" + } + }, + + "remote_control": { + "controlling": "Controlling", + "not_controlling": "Not Controlling", + "permission_request_title": "Permission Change", + "permission_request_content": "Web is requesting control permission. Do you agree to release?", + "refuse": "Refuse", + "agree": "Agree", + "device_disconnected": "Device Disconnected", + "back": "Back", + "switch_view_hint": "Double-tap blank area to switch view", + "chassis": "Chassis", + "mower": "Mower", + "fire_skill": "Fire Skill", + "mode_none": "No Mode", + "remote_mode": "Remote Mode", + "local_mode": "Local Mode", + "forward_backward": "Forward/Backward", + "left_right": "Left/Right", + "emergency_stop": "E-Stop", + "emergency_stopping": "Stopping" + }, + + "route_planning": { + "title": "Route Planning", + "save_plot": "Save Plot", + "plot_name_hint": "Enter plot name (e.g., North Field, Field 1)", + "plot_name_label": "Plot Name", + "save": "Save", + "cancel": "Cancel", + "plot_name_empty": "Plot name cannot be empty!", + "plot_name_too_long": "Plot name cannot exceed 20 characters!", + "saving": "Saving plot", + "save_success": "Saved successfully", + "save_failed": "Save failed", + "user_id_empty": "User ID is empty, cannot save!", + "no_work_points": "No work points to undo", + "no_obstacles": "No obstacles to delete", + "clear_work_area": "Cleared all work area points and paths", + "clear_obstacles": "Cleared all obstacles", + "work_mode": "Work Mode", + "start_work": "Start Work", + "no_plot_data": "No plot data", + "heading_not_init": "Heading angle not initialized, cannot start work", + "switch_remote_mode": "Please switch to remote mode before starting work", + "my_location": "My Location", + "location_permission_denied": "Location permission denied, cannot get current location", + "location_permanently_denied": "Location permission permanently denied, please enable in settings", + "go_to_settings": "Settings", + "location_service_disabled": "Location service disabled, please enable it", + "location_failed": "Location failed", + "retry": "Retry", + "plot_list_title": "Plot List (%d items)", + "route_direction": "Route Direction", + "optimal_heading": "Optimal Heading", + "land": "Land", + "route": "Route", + "crosshair": "Crosshair", + "robot_mode": "Robot Mode", + "work_area": "Work Area", + "obstacle_area": "Obstacle Area", + "delete": "Delete", + "undo": "Undo", + "complete": "Complete", + "work_distance": "Work Distance (m)", + "monitoring": "Monitoring", + "mark_land": "Mark Land", + "list": "List", + "station": "Station", + "location": "Location", + "refresh": "Refresh", + "select_work_mode": "Select Work Mode", + "bow_mode": "Bow Mode", + "bow_mode_subtitle": "Standard full coverage path planning", + "custom_mode": "Custom Mode", + "custom_mode_subtitle": "Manually set work area", + "station_1": "Station 1", + "station_2": "Station 2", + "station_3": "Station 3", + "crosshair": "Crosshair", + "robot_mode": "Robot Mode", + "work_area": "Work Area", + "obstacle_area": "Obstacle Area", + "delete": "Delete", + "undo": "Undo", + "complete": "Complete", + "land": "Land", + "route": "Route", + "route_direction": "Route Direction", + "optimal_heading": "Optimal Heading", + "settings": "Settings", + "clear_cache_success": "Cleared all cache, restored to initial state", + "refresh_failed": "Refresh failed" + }, + + "product": { + "intro": "Product Introduction", + "highlights": "Product Highlights", + "functions": "Features", + "parameters": "Specifications", + "scenes": "Application Scenarios", + "star_points": { + "design": { + "title": "Overall Design", + "content": "Load-bearing body, high-power walking system, tank-type tracks, oil-electric hybrid, anti-slope system, active/passive floating mower deck, air-assisted lifting mechanism, adaptive mowing device." + }, + "control": { + "title": "Control System", + "content": "Automotive-grade control and electrical system, industrial-grade anti-interference remote control, speed control and detection, traction control, manual and automatic driving modes, LCD display for machine status." + }, + "power": { + "title": "Power System", + "content": "Adaptive range extender system, top-tier Honda engine, high-power AC/DC discharge function." + }, + "safety": { + "title": "Safety Features", + "content": "Vehicle stability system, ABS brakes, electronic rollover protection, tilt protection, rapid stop on fall/rollover, auto shutdown when idle." + }, + "smart": { + "title": "Smart Functions", + "content": "Straight-line hold, collision avoidance, collision shutdown." + }, + "expand": { + "title": "Extended Functions", + "content": "Path planning, inspection detection, IoT control." + } + }, + "scenes": { + "orchard": "Orchard & Forestry", + "photovoltaic": "Photovoltaic Energy Storage", + "highway": "Highway Administration", + "agriculture": "Agricultural Production", + "municipal": "Municipal & Riverbank", + "airport": "Airport Facilities" + } + } +} diff --git a/assets/languages/zh-CN.json b/assets/languages/zh-CN.json new file mode 100644 index 00000000..2c752640 --- /dev/null +++ b/assets/languages/zh-CN.json @@ -0,0 +1,365 @@ +{ + "app_name": "麦步割草机器人", + + "common": { + "confirm": "确认", + "cancel": "取消", + "ok": "确定", + "back": "返回", + "close": "关闭", + "loading": "加载中...", + "error": "错误", + "success": "成功", + "unknown": "未知" + }, + + "login": { + "title": "登录", + "username": "用户名", + "password": "密码", + "login_button": "登录", + "logout": "退出登录", + "username_hint": "请输入用户名", + "password_hint": "请输入密码", + "login_success": "登录成功", + "login_failed": "登录失败" + }, + + "home": { + "title": "首页", + "devices": "我的设备", + "no_devices": "暂无设备", + "add_device": "添加设备", + "device_online": "在线", + "device_offline": "离线", + "remote_control": "远程遥控", + "route_plan": "路径规划", + "machine_status": "机器状态", + "switch_device": "切换设备", + "loading": "加载中...", + "no_history": "暂无历史记录", + "work_params": "作业参数", + "view_details": "查看详情", + "work_area": "作业面积", + "work_distance": "作业里程", + "work_duration": "作业时长", + "history_details": "历史记录详情", + "start_time": "开始时间", + "end_time": "结束时间", + "working_area": "工作面积", + "working_distance": "工作距离", + "time_spent": "花费时间", + "click_to_view": "点击查看详情", + "in_use": "使用中", + "switch": "切换", + "details": "详情", + "unknown_device": "未知设备", + "no_device_bound": "暂未绑定设备" + }, + + "running_status": { + "title": "设备数据监控", + "motor_params": "电机参数", + "other_params": "其他参数", + "left_wheel": "左轮", + "right_wheel": "右轮", + "target_speed": "目标速度", + "measure_speed": "测量速度", + "current": "电流", + "motor_temp": "电机温度", + "pitch_angle": "俯仰角", + "roll_angle": "翻滚角", + "heading_angle": "航向角", + "battery": "电量", + "chip_temp": "芯片温度", + "knife_speed": "割刀速度", + "control_mode": "控制模式", + "longitude": "经度", + "latitude": "纬度", + "altitude": "海拔", + "satellite_count": "卫星数", + "heading_status": "航向角状态", + "position_quality": "定位质量", + "not_initialized": "未初始化", + "invalid": "无效", + "valid": "有效", + "local_control": "本地控制", + "remote_control": "远程控制", + "data_refresh_success": "数据刷新成功!", + "no_device": "暂无设备,无法刷新", + "left_right_measure_speed": "左右轮测量速度对比", + "left_right_target_speed": "左右轮目标速度对比", + "current_compare": "电流对比", + "motor_temp_compare": "电机温度对比", + "heading_angle_chart": "航向角", + "card": "卡片", + "chart": "图表", + "name": "名称", + "value": "数值", + "initialized": "已初始化", + "no_data": "暂无数据", + "voltage": "电压" + }, + + "machine_details": { + "title": "设备详情", + "real_time_status": "实时状态", + "control_mode": "控制模式", + "battery_voltage": "电池电压", + "remaining_battery": "剩余电量", + "basic_info": "基本信息", + "device_name": "设备名称", + "device_id": "设备ID", + "resource_center": "资源中心", + "user_manual": "使用说明", + "product_manual": "产品手册", + "unbind": "解绑设备", + "unbind_confirm_title": "确认解绑", + "unbind_confirm_content": "确定要解绑【%s】吗?解绑后将无法管理该设备", + "edit_name_title": "修改设备名称", + "edit_name_hint": "请输入设备名称", + "name_empty_error": "名称不能为空", + "name_updated_success": "设备名称已修改为:%s", + "unbind_success": "设备「%s」解绑成功", + "unbind_failed": "解绑失败:%s", + "update_failed": "修改失败:%s", + "device_info_error": "设备信息异常,无法解绑", + "unbind_exception": "解绑异常:%s", + "update_exception": "修改异常:%s", + "updating_name": "正在修改名称...", + "unbinding_device": "正在解绑设备...", + "edit_name": "修改名称", + "name_updated": "名称已更新", + "remote_mode": "远程模式", + "local_mode": "本地模式", + "copied": "已复制" + }, + + "remote_control": { + "title": "远程控制", + "request_permission": "请求控制权", + "release_permission": "释放控制权", + "emergency_stop": "急停", + "permission_granted": "已获得控制权", + "permission_denied": "未获得控制权", + "voltage": "电压", + "battery": "电量", + "mode": "模式", + "ping": "延迟", + "joystick_instruction": "使用摇杆控制方向" + }, + + "ai": { + "title": "新能源光伏智能体", + "new_session": "开启新的会话", + "history": "历史会话", + "deep_thinking": "深度思考", + "final_conclusion": "最终结论", + "thinking_hint": "AI正在思考中...", + "input_hint": "输入你的想法...", + "album": "相册", + "camera": "拍照" + }, + + "my": { + "title": "我的", + "language": "语言", + "chinese": "中文", + "english": "English", + "settings": "设置", + "about": "关于", + "version": "版本", + "feedback": "反馈", + "privacy_policy": "隐私政策", + "user_agreement": "用户协议", + "operation_video": "操作视频", + "rental_service": "租赁服务", + "help_support": "帮助与支持", + "after_sales_policy": "售后政策" + }, + + "manual": { + "title": "使用说明", + "detail": "详情", + "no_content": "暂无内容", + "menu_titles": [ + "安全警示及使用注意事项", + "机器使用说明", + "保养与维修", + "故障处置", + "本商品搬运的要领", + "关于三包与售后服务" + ], + "submenus": { + "alert": "特别警告", + "alertinstruction": "关于本产品的警告标签说明", + "safety": "安全操作须知", + "safetywork": "安全驾驶·安全作业须知", + "prepare": "发动前的准备", + "startmethod": "启动方法", + "work": "割草方法", + "stop": "停车方法", + "controluse": "遥控器使用", + "check1": "定期检查表", + "check2": "行走部分及割草部分的检查", + "supply": "加油、加水以及上润滑脂、润滑油一览表", + "check4": "消耗零件(更换零件)一览表", + "check5": "发动机", + "check6": "行走装置", + "check7": "使用后的维修", + "breakdown1": "问题诊断表", + "starpoint": "搬运要领", + "about1": "关于三包", + "about2": "关于售后服务", + "supplyyear": "关于零件的补给年限(期间)" + }, + "tables": { + "supply_title": "加油、加水以及上润滑脂、润滑油一览表", + "item": "项目", + "period": "补给(交换)的时期", + "recommend": "推荐品种", + "capacity": "容量", + "problem": "问题现象说明", + "reason": "原因", + "solution": "处理", + "generator": "发电机", + "walking_device": "行走装置", + "mowing_device": "割草装置" + } + }, + + "remote_control": { + "controlling": "正在控制", + "not_controlling": "未在控制", + "permission_request_title": "权限变更", + "permission_request_content": "web端正请求控制权,同意释放吗?", + "refuse": "拒绝", + "agree": "同意", + "device_disconnected": "设备已断开连接", + "back": "返回", + "switch_view_hint": "双击空白处切换视角", + "chassis": "底盘", + "mower": "割刀", + "fire_skill": "火技能按钮", + "mode_none": "无模式", + "remote_mode": "远程模式", + "local_mode": "本地模式", + "forward_backward": "前后控制", + "left_right": "左右控制", + "emergency_stop": "急停", + "emergency_stopping": "急停中" + }, + + "route_planning": { + "title": "路径规划", + "save_plot": "保存地块", + "plot_name_hint": "请输入地块名称(如:北地块、一号田)", + "plot_name_label": "地块名称", + "save": "保存", + "cancel": "取消", + "plot_name_empty": "地块名称不能为空!", + "plot_name_too_long": "地块名称不能超过20个字符!", + "saving": "正在保存地块", + "save_success": "保存成功", + "save_failed": "保存失败", + "user_id_empty": "用户ID为空,无法保存!", + "no_work_points": "暂无作业区域点可撤回", + "no_obstacles": "暂无障碍物可删除", + "clear_work_area": "已清空所有作业区域点和路径", + "clear_obstacles": "已清空所有障碍物", + "work_mode": "作业模式", + "start_work": "开始作业", + "no_plot_data": "暂无地块数据", + "heading_not_init": "航向角未初始化,无法开始作业", + "switch_remote_mode": "请切换到远程模式后再开始作业", + "my_location": "定位到我的位置", + "location_permission_denied": "定位权限被拒绝,无法获取当前位置", + "location_permanently_denied": "定位权限被永久拒绝,请去设置开启", + "go_to_settings": "去设置", + "location_service_disabled": "定位服务未启用,请开启定位服务", + "location_failed": "定位失败", + "retry": "重试", + "plot_list_title": "地块列表(共%d条)", + "route_direction": "航线方向", + "optimal_heading": "最优航向", + "land": "地块", + "route": "航线", + "crosshair": "十字准星", + "robot_mode": "机器人模式", + "work_area": "作业区域", + "obstacle_area": "障碍区域", + "delete": "删除", + "undo": "撤回", + "complete": "完成", + "work_distance": "作业行距(米)", + "monitoring": "监控", + "mark_land": "圈地", + "list": "列表", + "station": "场站", + "location": "定位", + "refresh": "刷新", + "select_work_mode": "选择作业模式", + "bow_mode": "弓字模式", + "bow_mode_subtitle": "标准全覆盖路径规划", + "custom_mode": "自定义模式", + "custom_mode_subtitle": "手动设定作业区域", + "station_1": "一号场站", + "station_2": "二号场站", + "station_3": "三号场站", + "crosshair": "十字准星", + "robot_mode": "机器人模式", + "work_area": "作业区域", + "obstacle_area": "障碍区域", + "delete": "删除", + "undo": "撤回", + "complete": "完成", + "land": "地块", + "route": "航线", + "route_direction": "航线方向", + "optimal_heading": "最优航向", + "settings": "设置", + "clear_cache_success": "已清除所有缓存,恢复初始状态", + "refresh_failed": "刷新失败" + }, + "product": { + "intro": "产品介绍", + "highlights": "产品亮点", + "functions": "功能介绍", + "parameters": "产品参数", + "scenes": "应用场景", + "star_points": { + "design": { + "title": "整机设计", + "content": "承载式车身、高效大功率行走系统、坦克履型、油电混动、防溜坡系统、主被动溜坡浮动式刀盘、空气辅助式提升机构、自适应割草装置" + }, + "control": { + "title": "控制系统", + "content": "车规级控制和电气系统、工业级防干扰遥控系统、车速控制和检测系统、牵引力控制系统、手动和自动行驶操作模式、整机状态液晶显示。" + }, + "power": { + "title": "动力系统", + "content": "自适应增程系统、本田顶级发动机、大功率交直流放电功能。" + }, + "safety": { + "title": "安全配置", + "content": "车身稳定系统、ABS刹车装置、电子防翻滚功能、倾斜保护功能、急速、坠落和翻滚停机功能、无操作自动关机。" + }, + "smart": { + "title": "智能功能", + "content": "直行保持功能、防碰撞功能、碰撞停机功能。" + }, + "expand": { + "title": "扩展功能", + "content": "路径规划、巡检探测、物联控制。" + } + }, + "scenes": { + "orchard": "果园林业", + "photovoltaic": "光伏储能", + "highway": "公路路政", + "agriculture": "农业生产", + "municipal": "市政河堤", + "airport": "机场场所" + } + } +} diff --git a/lib/core/localization/locale_cubit.dart b/lib/core/localization/locale_cubit.dart new file mode 100644 index 00000000..454cd098 --- /dev/null +++ b/lib/core/localization/locale_cubit.dart @@ -0,0 +1,36 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +class LocaleCubit extends Cubit { + static const String _localeKey = 'app_locale'; + + LocaleCubit() : super(const Locale('zh', 'CN')) { + _loadSavedLocale(); + } + + Future _loadSavedLocale() async { + try { + final prefs = await SharedPreferences.getInstance(); + final languageCode = prefs.getString('${_localeKey}_lang') ?? 'zh'; + final countryCode = prefs.getString('${_localeKey}_country') ?? 'CN'; + emit(Locale(languageCode, countryCode)); + } catch (e) { + emit(const Locale('zh', 'CN')); + } + } + + Future setLocale(Locale locale) async { + try { + final prefs = await SharedPreferences.getInstance(); + await prefs.setString('${_localeKey}_lang', locale.languageCode); + await prefs.setString('${_localeKey}_country', locale.countryCode ?? ''); + emit(locale); + } catch (e) { + debugPrint('❌ [LocaleCubit] 保存语言设置失败: $e'); + } + } + + bool get isChinese => state.languageCode == 'zh'; + bool get isEnglish => state.languageCode == 'en'; +} diff --git a/lib/features/remote_control/presentation/widgets/center_control_area.dart b/lib/features/remote_control/presentation/widgets/center_control_area.dart index ca5655a4..86fff675 100644 --- a/lib/features/remote_control/presentation/widgets/center_control_area.dart +++ b/lib/features/remote_control/presentation/widgets/center_control_area.dart @@ -42,7 +42,7 @@ class CenterControlArea extends StatelessWidget { child: Column( mainAxisAlignment: MainAxisAlignment.end, children: [ - _buildSliderBox(expandedWidth, AppLocalizations.of(context).translate('remote_control.chassis'), true,context), + _buildSliderBox(expandedWidth, 'chassis', true,context), SizedBox(height: totalWidth * 0.01), ], ), @@ -72,7 +72,7 @@ class CenterControlArea extends StatelessWidget { width: expandedWidth, child: Column( mainAxisAlignment: MainAxisAlignment.end, - children: [_buildSliderBox(expandedWidth, AppLocalizations.of(context).translate('remote_control.mower'), false,context)], + children: [_buildSliderBox(expandedWidth, 'mower', false,context)], ), ), ], @@ -82,7 +82,12 @@ class CenterControlArea extends StatelessWidget { ); } - Widget _buildSliderBox(double boxWidth, String label, bool isLeft,BuildContext context) { + Widget _buildSliderBox(double boxWidth, String deviceKey, bool isLeft,BuildContext context) { + // 🔥 使用deviceKey作为唯一标识,不依赖显示文本 + final label = deviceKey == 'chassis' + ? AppLocalizations.of(context).translate('remote_control.chassis') + : AppLocalizations.of(context).translate('remote_control.mower'); + return SizedBox( width: boxWidth, child: Center( @@ -92,17 +97,13 @@ class CenterControlArea extends StatelessWidget { child: CCExpandSlider( label: label, svgStart: "assets/svgs/remote_up.svg", - svgCenter: switch (label) { - "割刀" => "assets/svgs/remote_scissors.svg", - "Mower" => "assets/svgs/remote_scissors.svg", - "底盘" => "assets/svgs/remote_layers.svg", - "Chassis" => "assets/svgs/remote_layers.svg", - _ => "assets/svgs/remote_layers.svg", // 下划线表示默认值 - }, + svgCenter: deviceKey == 'mower' + ? "assets/svgs/remote_scissors.svg" + : "assets/svgs/remote_layers.svg", svgEnd: "assets/svgs/remote_down.svg", - onStart: () => _handleSliderAction(label, "start", context), - onCenter: () => _handleSliderAction(label, "center", context), - onEnd: () => _handleSliderAction(label, "end", context), + onStart: () => _handleSliderAction(deviceKey, "start", context), + onCenter: () => _handleSliderAction(deviceKey, "center", context), + onEnd: () => _handleSliderAction(deviceKey, "end", context), iconSize: boxWidth * 0.6 * 0.35, ), ), @@ -111,22 +112,19 @@ class CenterControlArea extends StatelessWidget { } // 🔥 新增:统一的业务逻辑分发方法 - void _handleSliderAction(String label, String action, BuildContext context) { - debugPrint('🎯 [Slider 业务] label: $label, action: $action'); + void _handleSliderAction(String deviceKey, String action, BuildContext context) { + debugPrint('🎯 [Slider 业务] deviceKey: $deviceKey, action: $action'); - final loc = AppLocalizations.of(context); - // 🔥 根据 label 区分不同的设备 - switch (label) { - case "底盘": - case "Chassis": + // 🔥 使用deviceKey进行判断,不依赖显示文本 + switch (deviceKey) { + case 'chassis': _handleChassisAction(action, context); break; - case "割刀": - case "Mower": + case 'mower': _handleMowerAction(action, context); break; default: - debugPrint('⚠️ 未知的 label: $label'); + debugPrint('⚠️ 未知的 deviceKey: $deviceKey'); } // 🔥 在指令执行后触发震动反馈(增强手感) HapticFeedback.mediumImpact();