Browse Source

refactor(i18n): 重构国际化字符串并统一翻译键命名规范

将硬编码的中文字符串替换为国际化翻译键
统一翻译键命名规范,按模块分类组织
添加缺失的英文翻译字符串
优化部分翻译键的命名以更好表达用途
weicu
lxm 1 year ago
parent
commit
09cf33a38f
  1. 199
      lib/core/translations/language/en_us.dart
  2. 176
      lib/core/translations/language/zh_cn.dart
  3. 42
      lib/modules/agent/controllers/agent_controller.dart
  4. 52
      lib/modules/agent/controllers/message_action_controller.dart
  5. 78
      lib/modules/agent/views/agent_view.dart
  6. 2
      lib/modules/agent/views/message_bubble.dart
  7. 10
      lib/modules/agent/views/music_card.dart
  8. 87
      lib/modules/agent/views/navigation_card.dart
  9. 72
      lib/modules/agent/views/weather_card.dart
  10. 5
      lib/modules/agent/widgets/full_screen_editor.dart
  11. 18
      lib/modules/common/widgets/version_update_dialog.dart
  12. 4
      lib/modules/ota_upgrade/views/ota_upgrade_view.dart
  13. 73
      lib/modules/pairing/controllers/pairing_controller.dart
  14. 7
      lib/modules/pairing/views/pairing_view.dart
  15. 85
      lib/modules/profile/controllers/profile_controller.dart

199
lib/core/translations/language/en_us.dart

@ -253,12 +253,123 @@ const Map<String, String> enUS = {
"deviceNotBoundYet": "Device not bound yet", // 还未绑定设备 "deviceNotBoundYet": "Device not bound yet", // 还未绑定设备
"unbind": "Unbind", // 解绑 "unbind": "Unbind", // 解绑
// 聊天页 // Agent模块
//Agent View
"XiaoYan": "XiaoYan",
"clearChatHistory": "Clear Chat History", "clearChatHistory": "Clear Chat History",
"online": "Online", "online": "Online",
"inputMessage": "Type a message...", "inputMessage": "Type a message...",
"imListening": "Listening...", "imListening": "Listening...",
"canStartTalking": "You may start speaking", "canStartTalking": "You may start speaking",
"addQuestionAboutImage": "Add questions or descriptions about the image...",
"summarizeImageContent": "Summarize image content",
"extractImageText": "Extract image text",
"translateImageText": "Translate image text",
"recording": "Recording...",
"holdToSpeak": "Hold to speak",
"takePhoto": "Take Photo",
"photoAlbum": "Photo Album",
"makeCall": "Make Call",
"aiVoiceCall": "AI Voice Call",
"inCall": "In call...",
"aiReplying": "AI is replying...",
"waitingToStart": "Waiting to start...",
"clickToStartCall": "Click to start call",
"listeningToYou": "Listening to you...",
"processing": "Processing...",
"loadMoreMessages": "Load more messages...",
"loadFailedClickRetry": "Load failed, click to retry",
"swipeUpForMore": "Swipe up for more",
// Agent Controller
'welcomeMessage': 'Hello! I\'m **XiaoYan**, I can help you:\n\n'
'• Answer questions and provide information\n\n'
'• Real-time voice translation\n\n'
'• Recommend music and podcasts\n\n'
'• Voice memos and reminders\n\n'
'• Control headset functions\n\n'
'What can I help you with?',
'microphonePermission': 'Microphone',
'voiceRecognitionPermissionText':
'Voice recognition requires microphone access.',
'voiceTranslationPermissionText':
'Voice recognition and translation require microphone access.',
'phoneCallPermissionText':
'Phone call function requires microphone access for voice calls.',
'permissionDeniedText':
'You have permanently denied microphone permission, please go to system settings to enable it.',
'startVoiceInput': 'Start voice input',
'startPhoneCallMode': 'Start phone call mode, begin voice input',
//Agent 全屏编辑器
'fullScreenEditorHint': 'Type your message here...', // 全屏编辑器输入提示
'characterCount': '{count} characters', // 字符计数显示
// 消息长按操作
'copy': 'Copy',
'copySuccess': 'Copy successful',
'report': 'Report',
'submitSuccess': 'Submit successful',
'submitFailed': 'Submit failed',
'reportSubmitted': 'Report submitted, we will process it as soon as possible',
//'networkError': 'Network error, please try again later',
'harmfulUnsafe': 'Harmful/Unsafe',
'pornographicVulgar': 'Pornographic/Vulgar',
'misleadingAttack': 'Misleading/Attack',
'illegalCriminal': 'Illegal/Criminal',
'privacyRelated': 'Privacy Related',
'copyrightViolation': 'Infringement of my copyright, reputation rights, etc.',
'other': 'Other',
'reportDescriptionHint':
'We want to know the reason for your report, you can describe the problem you encountered.',
//'submit': 'Submit',
//Message_bubble
'generatedByAi': 'Generated by AI',
//music_card
'recommendedMusic': 'Here are some recommended music:',
'playlist': 'Playlist',
'moreMusic': 'More music',
//导航卡片 navigation_card
'kilometers': ' km', // 公里单位
'meters': ' m', // 米单位
'hours': ' hours', // 小时单位
'minutes': ' minutes', // 分钟单位
'seconds': ' seconds', // 秒单位
'navigating': 'Navigating', // 导航状态
'currentLocation': 'Current Location', // 当前位置
'approximate': 'About ', // 大约
'enterRoad': ' enter ', // 进入道路
"driving": "Driving",
"walking": "Walking",
"bicycling": "Cycling",
"tsransit": "Transit",
//天气卡片 weather_card
'weatherQuery': 'Weather Query:',
'highest': 'High',
'lowest': 'Low',
'futureForecast': 'Future Forecast',
'hotWeatherTip':
'Hot weather today, please pay attention to heat prevention and cooling, drink more water to avoid heat stroke',
'coldWeatherTip':
'Low temperature today, please keep warm when going out and be careful of catching cold',
'rainyWeatherTip':
'Rainy today, please bring rain gear when going out and pay attention to travel safety',
'snowyWeatherTip':
'Snowy today, roads are slippery, please pay attention to safety and keep warm',
'foggyWeatherTip':
'Foggy and hazy today, low visibility, please wear a mask when going out',
'windyWeatherTip':
'Strong wind today, please pay attention to safety when going out and secure items',
'sunnyWeatherTip':
'Sunny with strong UV rays today, please protect yourself from the sun when going out',
'temperatureDifferenceTip':
'Large temperature difference between day and night today, please adjust clothing accordingly',
'comfortableWeatherTip':
'Pleasant weather today, perfect for outdoor activities',
// 编辑个人信息页 // 编辑个人信息页
"editProfile": "Edit Profile", "editProfile": "Edit Profile",
@ -275,6 +386,38 @@ const Map<String, String> enUS = {
'deleteAccountTips': 'deleteAccountTips':
'Are you sure you want to permanently delete your account? This action cannot be undone.', 'Are you sure you want to permanently delete your account? This action cannot be undone.',
//Profile 错误信息
'networkConnectionFailed':
'Network connection failed, please check network settings and try again',
'serverTemporarilyUnavailable':
'Server temporarily unavailable, please try again later',
'loginExpiredPleaseRelogin': 'Login expired, please log in again',
'noPermissionForThisOperation': 'No permission to perform this operation',
'requestedResourceNotFound': 'Requested resource not found',
'imageProcessingFailedPleaseReselect':
'Image processing failed, please select image again',
'operationFailedPleaseRetry': 'Operation failed, please try again',
'serverReturnedError': 'Server returned error',
'serverError': 'Server error',
'networkConnectionFailedCheckSettings':
'Network connection failed, please check network settings',
'serverInternalErrorRetryLater':
'Server internal error, please try again later',
//Profile 用户交互
//'error': 'Error',
//'success': 'Success',
'imageCompressionFailed': 'Image compression failed',
'avatarUpdateFailed': 'Avatar update failed',
'usernameCannotBeEmpty': 'Username cannot be empty',
'saveSuccess': 'Save Success',
'personalInfoUpdated': 'Personal information updated',
'saveFailed': 'Save Failed',
'loggedOut': 'Logged out',
'logoutFailedRetry': 'Logout failed, please try again',
'accountPermanentlyDeleted': 'Account permanently deleted',
'deleteAccountFailedRetry': 'Delete account failed, please try again',
// 权限管理页面 // 权限管理页面
'getPermissionStatusFailed': 'Failed to get permission status', 'getPermissionStatusFailed': 'Failed to get permission status',
'communicationPermissions': 'Communication Permissions', 'communicationPermissions': 'Communication Permissions',
@ -315,6 +458,17 @@ const Map<String, String> enUS = {
'You have permanently denied {permission} permission, please go to app settings to enable it', 'You have permanently denied {permission} permission, please go to app settings to enable it',
'goToSettings': 'Go to Settings', 'goToSettings': 'Go to Settings',
// 版本更新对话框
'newVersionFound': 'New Version Found', // 版本更新对话框标题
'remindLater': 'Remind Later', // 稍后提醒按钮
'updateNow': 'Update Now', // 立即更新按钮
'checkUpdate': 'Check Update', // 检查更新按钮
'updateFailed': 'Update Failed', // 更新失败提示
'cannotOpenAppStore':
'Cannot open app store, please update manually', // 无法打开应用商店提示
'updateErrorRetry':
'Error occurred during update, please try again later', // 更新错误重试提示
// 国家列表 // 国家列表
"邮箱": "Email", "邮箱": "Email",
"中国": "China", "中国": "China",
@ -423,12 +577,6 @@ const Map<String, String> enUS = {
"斐济": "Fiji", "斐济": "Fiji",
"所罗门群岛": "Solomon Islands", "所罗门群岛": "Solomon Islands",
// 导航
"driving": "Driving",
"walking": "Walking",
"bicycling": "Cycling",
"tsransit": "Transit",
// 翻译模块 // 翻译模块
// 翻译主页 // 翻译主页
"translationHistory": "Translation History", "translationHistory": "Translation History",
@ -500,6 +648,7 @@ const Map<String, String> enUS = {
"confirmBinding": "Confirm Binding", "confirmBinding": "Confirm Binding",
"associatingDevice": "Associating device...", "associatingDevice": "Associating device...",
"goToBluetoothSettings": "Go to Bluetooth Settings", "goToBluetoothSettings": "Go to Bluetooth Settings",
'bluetooth': 'Bluetooth',
// 配对状态文本 // 配对状态文本
"readyToPair": "Ready to pair", "readyToPair": "Ready to pair",
@ -525,6 +674,38 @@ const Map<String, String> enUS = {
"Authorization failed, please check authorization code", "Authorization failed, please check authorization code",
"pairingFailedRetry": "Pairing failed, please retry", "pairingFailedRetry": "Pairing failed, please retry",
//配对控制器相关
//'connectDevice': 'Connect Device',
'pleaseEnableBluetooth': 'Please enable Bluetooth',
'deviceDisconnected': 'Device disconnected',
'readyToStartPairing': 'Ready to start pairing',
'checkingEnvironment': 'Checking environment...',
'ensureHeadsetOnAndPairingMode':
'Please ensure headset is on and in pairing mode',
//'goToBluetoothSettings': 'Go to Bluetooth Settings',
//'verifyingDevice': 'Verifying device...',
//'confirmBinding': 'Confirm Binding',
//'associatingDevice': 'Associating device...',
'establishingSecureConnection': 'Establishing secure connection...',
'needManualBindingAuthCode': 'Manual binding authorization code required...',
'pairingSuccessful': 'Pairing successful!',
'enableBluetooth': 'Enable Bluetooth',
'grantPermissions': 'Grant Permissions',
'retryAssociation': 'Retry Association',
'retryAuthorization': 'Retry Authorization',
'pleaseGrantNecessaryPermissions': 'Please grant necessary permissions',
'checkFailedRetry': 'Check failed, please retry',
'pleaseConnectDeepSoundDevice': 'Please connect DeepSound device',
'verificationFailedRetry': 'Verification failed, please retry',
'invalidDeviceAddress': 'Invalid device address',
'bleDeviceAssociationFailed': 'BLE device association failed',
'deviceAssociationFailedRetry': 'Device association failed, please retry',
'bleConnectionTimeoutRetry': 'BLE connection timeout, please retry',
'blePairingStartupFailed': 'BLE pairing startup failed',
'bleConnectionFailed': 'BLE connection failed',
'deviceAuthorizationFailedCheckCode':
'Device authorization failed, please check authorization code',
// 用户反馈页 // 用户反馈页
"feedback": "Feedback", "feedback": "Feedback",
'feedbackInfo': 'Provide feedback or suggestions', 'feedbackInfo': 'Provide feedback or suggestions',
@ -544,13 +725,13 @@ const Map<String, String> enUS = {
"unknownDevice": "Unknown Device", "unknownDevice": "Unknown Device",
"currentFirmwareVersion": "Current Firmware Version", "currentFirmwareVersion": "Current Firmware Version",
"latestFirmwareVersion": "Latest Firmware Version", "latestFirmwareVersion": "Latest Firmware Version",
"newVersionFound": "New Version Found", "ota_newVersionFound": "New Version Found",
"latestVersion": "Latest Version", "latestVersion": "Latest Version",
"gettingDeviceInfo": "Getting device information...", "gettingDeviceInfo": "Getting device information...",
"keepDeviceConnected": "Please keep device connected", "keepDeviceConnected": "Please keep device connected",
"connectionFailed": "Connection Failed", "connectionFailed": "Connection Failed",
"retryConnection": "Retry Connection", "retryConnection": "Retry Connection",
"updateNow": "Update Now", "ota_updateNow": "Update Now",
"keepConnectedDontClose": "keepConnectedDontClose":
"Please keep device connected, do not close the app", "Please keep device connected, do not close the app",
"doNotDisconnect": "Do not disconnect", "doNotDisconnect": "Do not disconnect",

176
lib/core/translations/language/zh_cn.dart

@ -245,12 +245,109 @@ const Map<String, String> zhCN = {
"deviceNotBoundYet": "还未绑定设备", "deviceNotBoundYet": "还未绑定设备",
"unbind": "解绑", "unbind": "解绑",
// 聊天页 //Agent 模块
// agent View
"XiaoYan": "小言",
"clearChatHistory": "清空聊天记录", "clearChatHistory": "清空聊天记录",
"online": "在线", "online": "在线",
"inputMessage": "输入消息...", "inputMessage": "输入消息...",
"imListening": "正在聆听...", "imListening": "正在聆听...",
"canStartTalking": "你可以开始说话", "canStartTalking": "你可以开始说话",
"addQuestionAboutImage": "添加对图片的问题或描述...",
"summarizeImageContent": "总结图片内容",
"extractImageText": "抽取图像文字",
"translateImageText": "翻译图像文字",
"recording": "正在录音...",
"holdToSpeak": "按住说话",
"takePhoto": "拍照",
"photoAlbum": "相册",
"makeCall": "打电话",
"aiVoiceCall": "AI语音通话",
"inCall": "正在通话中...",
"aiReplying": "AI正在回复...",
"waitingToStart": "等待开始...",
"clickToStartCall": "点击开始通话",
"listeningToYou": "正在听您说话...",
"processing": "正在处理...",
"loadMoreMessages": "加载更多消息...",
"loadFailedClickRetry": "加载失败,点击重试",
"swipeUpForMore": "向上滑动查看更多",
// Agent controller
'welcomeMessage': '你好!我是**小言**,我能帮你:\n\n'
'• 答问题和提供信息\n\n'
'• 实时语音翻译\n\n'
'• 推荐音乐和播客\n\n'
'• 语音备忘录和提醒\n\n'
'• 控制耳机功能\n\n'
'有什么我可以帮你的吗?',
'microphonePermission': '麦克风',
'voiceRecognitionPermissionText': '语音识别功能需要访问麦克风。',
'voiceTranslationPermissionText': '语音识别与翻译功能需要访问麦克风。',
'phoneCallPermissionText': '打电话功能需要访问麦克风进行语音通话。',
'permissionDeniedText': '您已永久拒绝麦克风权限,请前往系统设置开启权限。',
'startVoiceInput': '开始语音输入',
'startPhoneCallMode': '开始打电话模式,开始语音输入',
// Agent 全屏编辑器
'fullScreenEditorHint': '在这里输入你的消息...', // 全屏编辑器输入提示
'characterCount': '{count} 字符', // 字符计数显示
// 消息长按操作
'copy': '复制',
'copySuccess': '复制成功',
'report': '举报',
'submitSuccess': '提交成功',
'submitFailed': '提交失败',
'reportSubmitted': '举报已提交,我们会尽快处理',
//'networkError': '网络错误,请稍后重试',
'harmfulUnsafe': '有害/不安全',
'pornographicVulgar': '色情低俗',
'misleadingAttack': '误导攻击',
'illegalCriminal': '违法犯罪',
'privacyRelated': '隐私相关',
'copyrightViolation': '侵犯我的著作权、名誉权等',
'other': '其他',
'reportDescriptionHint': '我们想知道你举报的原因,你可以描述你遇到的问题。',
//'submit': '提交',
//Message_bubble
'generatedByAi': '由AI生成',
//音乐卡片 music_card
'recommendedMusic': '以下是一些推荐的音乐:',
'playlist': '播放列表',
'moreMusic': '更多音乐',
//导航卡片 navigation_card
'kilometers': '公里', // 公里单位
'meters': '米', // 米单位
'hours': '小时', // 小时单位
'minutes': '分钟', // 分钟单位
'seconds': '秒', // 秒单位
'navigating': '导航中', // 导航状态
'currentLocation': '当前位置', // 当前位置
'approximate': '约', // 大约
'enterRoad': '进入', // 进入道路
"driving": "驾车",
"walking": "步行",
"bicycling": "骑行",
"tsransit": "公交",
//天气卡片 weather_card
'weatherQuery': '查询天气情况:',
'highest': '最高',
'lowest': '最低',
'futureForecast': '未来预报',
'hotWeatherTip': '今日高温炎热,请注意防暑降温,多喝水避免中暑',
'coldWeatherTip': '今日气温较低,外出请注意保暖,小心感冒',
'rainyWeatherTip': '今日有雨,外出请携带雨具,注意出行安全',
'snowyWeatherTip': '今日有雪,路面湿滑请注意安全,做好保暖措施',
'foggyWeatherTip': '今日有雾霾,能见度较低,外出请佩戴口罩',
'windyWeatherTip': '今日风力较大,外出请注意安全,固定好物品',
'sunnyWeatherTip': '今日阳光充足紫外线较强,外出请做好防晒',
'temperatureDifferenceTip': '今日昼夜温差较大,请适时增减衣物',
'comfortableWeatherTip': '今日天气适宜,是外出活动的好时光',
//编辑个人信息页 //编辑个人信息页
"editProfile": "编辑个人信息", "editProfile": "编辑个人信息",
@ -266,6 +363,33 @@ const Map<String, String> zhCN = {
'deleteAccount': '注销账号', 'deleteAccount': '注销账号',
'deleteAccountTips': '确定要永久删除您的账号吗?此操作不可撤销', 'deleteAccountTips': '确定要永久删除您的账号吗?此操作不可撤销',
// Profile 错误信息
'networkConnectionFailed': '网络连接失败,请检查网络设置后重试',
'serverTemporarilyUnavailable': '服务器暂时无法响应,请稍后重试',
'loginExpiredPleaseRelogin': '登录已过期,请重新登录',
'noPermissionForThisOperation': '没有权限执行此操作',
'requestedResourceNotFound': '请求的资源不存在',
'imageProcessingFailedPleaseReselect': '图片处理失败,请重新选择图片',
'operationFailedPleaseRetry': '操作失败,请重试',
'serverReturnedError': '服务器返回错误',
'serverError': '服务器错误',
'networkConnectionFailedCheckSettings': '网络连接失败,请检查网络设置',
'serverInternalErrorRetryLater': '服务器内部错误,请稍后重试',
// Profile 用户交互
//'error': '错误',
//'success': '成功',
'imageCompressionFailed': '图片压缩失败',
'avatarUpdateFailed': '头像更新失败',
'usernameCannotBeEmpty': '用户名不能为空',
'saveSuccess': '保存成功',
'personalInfoUpdated': '个人信息已更新',
'saveFailed': '保存失败',
'loggedOut': '已退出登录',
'logoutFailedRetry': '退出登录失败,请重试',
'accountPermanentlyDeleted': '账号已被永久删除',
'deleteAccountFailedRetry': '删除账号失败,请重试',
// 权限管理页面 // 权限管理页面
'getPermissionStatusFailed': '获取权限状态失败', 'getPermissionStatusFailed': '获取权限状态失败',
'communicationPermissions': '通讯权限', 'communicationPermissions': '通讯权限',
@ -298,6 +422,15 @@ const Map<String, String> zhCN = {
'permanentDenialText': '您已永久拒绝{permission}权限,请前往应用设置开启', 'permanentDenialText': '您已永久拒绝{permission}权限,请前往应用设置开启',
'goToSettings': '去设置', 'goToSettings': '去设置',
// 版本更新对话框
'newVersionFound': '发现新版本', // 版本更新对话框标题
'remindLater': '稍后提醒', // 稍后提醒按钮
'updateNow': '立即更新', // 立即更新按钮
'checkUpdate': '检查更新', // 检查更新按钮
'updateFailed': '更新失败', // 更新失败提示
'cannotOpenAppStore': '无法打开应用商店,请手动前往应用商店更新', // 无法打开应用商店提示
'updateErrorRetry': '更新过程中发生错误,请稍后重试', // 更新错误重试提示
//国家列表 //国家列表
"邮箱": "邮箱", "邮箱": "邮箱",
"中国": "中国", "中国": "中国",
@ -406,12 +539,6 @@ const Map<String, String> zhCN = {
"斐济": "斐济", "斐济": "斐济",
"所罗门群岛": "所罗门群岛", "所罗门群岛": "所罗门群岛",
// 导航
"driving": "驾车",
"walking": "步行",
"bicycling": "骑行",
"tsransit": "公交",
// 翻译模块 // 翻译模块
// 翻译主页 (translation_view.dart) // 翻译主页 (translation_view.dart)
"translationHistory": "翻译历史", "translationHistory": "翻译历史",
@ -478,6 +605,7 @@ const Map<String, String> zhCN = {
"confirmBinding": "确认绑定", "confirmBinding": "确认绑定",
"associatingDevice": "正在关联设备...", "associatingDevice": "正在关联设备...",
"goToBluetoothSettings": "前往蓝牙设置", "goToBluetoothSettings": "前往蓝牙设置",
'bluetooth': '蓝牙',
// 配对状态文本 // 配对状态文本
"readyToPair": "准备开始配对", "readyToPair": "准备开始配对",
@ -497,6 +625,36 @@ const Map<String, String> zhCN = {
"authorizationFailedCheckCode": "授权失败,请检查授权码是否正确", "authorizationFailedCheckCode": "授权失败,请检查授权码是否正确",
"pairingFailedRetry": "配对失败,请重试", "pairingFailedRetry": "配对失败,请重试",
// 配对控制器相关
//'connectDevice': '连接设备',
'pleaseEnableBluetooth': '请开启蓝牙',
'deviceDisconnected': '设备已断开',
'readyToStartPairing': '准备开始配对',
'checkingEnvironment': '正在检查环境...',
'ensureHeadsetOnAndPairingMode': '请确保耳机已开启并进入配对模式',
//'goToBluetoothSettings': '前往蓝牙设置',
//'verifyingDevice': '正在验证设备...',
//'confirmBinding': '确认绑定',
//'associatingDevice': '正在关联设备...',
'establishingSecureConnection': '正在建立安全连接...',
'needManualBindingAuthCode': '需要手动绑定授权码...',
'pairingSuccessful': '配对成功!',
'enableBluetooth': '开启蓝牙',
'grantPermissions': '授予权限',
'retryAssociation': '重新关联',
'retryAuthorization': '重新授权',
'pleaseGrantNecessaryPermissions': '请授予必要权限',
'checkFailedRetry': '检查失败,请重试',
'pleaseConnectDeepSoundDevice': '请连接 DeepSound 设备',
'verificationFailedRetry': '验证失败,请重试',
'invalidDeviceAddress': '设备地址无效',
'bleDeviceAssociationFailed': 'BLE设备关联失败',
'deviceAssociationFailedRetry': '设备关联失败,请重试',
'bleConnectionTimeoutRetry': 'BLE连接超时,请重试',
'blePairingStartupFailed': 'BLE配对启动失败',
'bleConnectionFailed': 'BLE连接失败',
'deviceAuthorizationFailedCheckCode': '设备授权失败,请检查授权码',
//用户反馈页 //用户反馈页
"feedback": "用户反馈", "feedback": "用户反馈",
'feedbackInfo': '提供反馈或建议', 'feedbackInfo': '提供反馈或建议',
@ -515,13 +673,13 @@ const Map<String, String> zhCN = {
"unknownDevice": "未知设备", "unknownDevice": "未知设备",
"currentFirmwareVersion": "当前固件版本", "currentFirmwareVersion": "当前固件版本",
"latestFirmwareVersion": "最新固件版本", "latestFirmwareVersion": "最新固件版本",
"newVersionFound": "发现新版本", "ota_newVersionFound": "发现新版本",
"latestVersion": "已是最新版本", "latestVersion": "已是最新版本",
"gettingDeviceInfo": "正在获取设备信息...", "gettingDeviceInfo": "正在获取设备信息...",
"keepDeviceConnected": "请保持设备连接", "keepDeviceConnected": "请保持设备连接",
"connectionFailed": "连接失败", "connectionFailed": "连接失败",
"retryConnection": "重试连接", "retryConnection": "重试连接",
"updateNow": "立即更新", "ota_updateNow": "立即更新",
"keepConnectedDontClose": "请保持设备连接,不要关闭应用", "keepConnectedDontClose": "请保持设备连接,不要关闭应用",
"doNotDisconnect": "请勿断开连接", "doNotDisconnect": "请勿断开连接",
"charging": "充电中", "charging": "充电中",

42
lib/modules/agent/controllers/agent_controller.dart

@ -447,13 +447,7 @@ class AgentController extends GetxController {
void _addWelcomeMessage() { void _addWelcomeMessage() {
messages.add(Message( messages.add(Message(
isUser: false, isUser: false,
text: '你好!我是**小言**,我能帮你:\n\n' text: 'welcomeMessage'.tr, // 你好!我是**小言**,我能帮你:
'• 答问题和提供信息\n\n'
'• 实时语音翻译\n\n'
'• 推荐音乐和播客\n\n'
'• 语音备忘录和提醒\n\n'
'• 控制耳机功能\n\n'
'有什么我可以帮你的吗?',
)); ));
} }
@ -983,11 +977,11 @@ class AgentController extends GetxController {
final hasPermission = await PermissionUtil.instance.requestPermission( final hasPermission = await PermissionUtil.instance.requestPermission(
// context: Get.context!, // context: Get.context!,
permissionType: Permission.microphone, permissionType: Permission.microphone,
permissionName: '麦克风', permissionName: 'microphonePermission'.tr, // 麦克风
explanationText: '语音识别功能需要访问麦克风。', explanationText: 'voiceRecognitionPermissionText'.tr, // 语音识别功能需要访问麦克风。
permanentDenialText: '您已永久拒绝麦克风权限,请前往系统设置开启权限。', permanentDenialText: 'permissionDeniedText'.tr, // 您已永久拒绝麦克风权限,请前往系统设置开启权限。
settingsButtonText: '去设置', settingsButtonText: 'goToSettings'.tr, // 去设置
cancelButtonText: '取消', cancelButtonText: 'cancel'.tr, // 取消
); );
if (!hasPermission) { if (!hasPermission) {
return; // 权限未获取,保持文本模式 return; // 权限未获取,保持文本模式
@ -1011,15 +1005,15 @@ class AgentController extends GetxController {
// 开始语音输入 // 开始语音输入
Future<void> startVoiceInput() async { Future<void> startVoiceInput() async {
if (isListening.value) return; if (isListening.value) return;
print("开始语音输入"); // 检查麦克风权限 print('startVoiceInput'.tr); // 开始语音输入
final hasPermission = await PermissionUtil.instance.requestPermission( final hasPermission = await PermissionUtil.instance.requestPermission(
// context: Get.context!, // context: Get.context!,
permissionType: Permission.microphone, permissionType: Permission.microphone,
permissionName: '麦克风', permissionName: 'microphonePermission'.tr, // 麦克风
explanationText: '语音识别与翻译功能需要访问麦克风。', explanationText: 'voiceTranslationPermissionText'.tr, // 语音识别与翻译功能需要访问麦克风。
permanentDenialText: '您已永久拒绝麦克风权限,请前往系统设置开启权限。', permanentDenialText: 'permissionDeniedText'.tr, // 您已永久拒绝麦克风权限,请前往系统设置开启权限。
settingsButtonText: '去设置', settingsButtonText: 'goToSettings'.tr, // 去设置
cancelButtonText: '取消', cancelButtonText: 'cancel'.tr, // 取消
); );
if (!hasPermission) { if (!hasPermission) {
isTextInputMode.value = true; // 如果没有权限,切回文本模式 isTextInputMode.value = true; // 如果没有权限,切回文本模式
@ -1286,11 +1280,11 @@ class AgentController extends GetxController {
// 检查麦克风权限 // 检查麦克风权限
final hasPermission = await PermissionUtil.instance.requestPermission( final hasPermission = await PermissionUtil.instance.requestPermission(
permissionType: Permission.microphone, permissionType: Permission.microphone,
permissionName: '麦克风', permissionName: 'microphonePermission'.tr, // 麦克风
explanationText: '打电话功能需要访问麦克风进行语音通话。', explanationText: 'phoneCallPermissionText'.tr, // 打电话功能需要访问麦克风进行语音通话。
permanentDenialText: '您已永久拒绝麦克风权限,请前往系统设置开启权限。', permanentDenialText: 'permissionDeniedText'.tr, // 您已永久拒绝麦克风权限,请前往系统设置开启权限。
settingsButtonText: '去设置', settingsButtonText: 'goToSettings'.tr, // 去设置
cancelButtonText: '取消', cancelButtonText: 'cancel'.tr, // 取消
); );
if (!hasPermission) { if (!hasPermission) {
@ -1305,7 +1299,7 @@ class AgentController extends GetxController {
// 打电话模式不使用按住说话模式,而是持续语音输入 // 打电话模式不使用按住说话模式,而是持续语音输入
//isPushToTalkMode.value = false; //isPushToTalkMode.value = false;
// 开始语音识别 // 开始语音识别
print("开始打电话模式,开始语音输入"); print('startPhoneCallMode'.tr); // 开始打电话模式,开始语音输入
await AgentService.audioContinue(); await AgentService.audioContinue();
} }
} }

52
lib/modules/agent/controllers/message_action_controller.dart

@ -28,9 +28,10 @@ class MessageActionController extends GetxController {
) { ) {
// 触发触觉反馈 // 触发触觉反馈
Haptics.vibrate(HapticsType.success); Haptics.vibrate(HapticsType.success);
// 计算弹出菜单位置 // 计算弹出菜单位置
RenderBox? renderBox = Overlay.of(context).context.findRenderObject() as RenderBox; RenderBox? renderBox =
Overlay.of(context).context.findRenderObject() as RenderBox;
final RelativeRect position = RelativeRect.fromRect( final RelativeRect position = RelativeRect.fromRect(
Rect.fromLTRB( Rect.fromLTRB(
details.globalPosition.dx, details.globalPosition.dx,
@ -67,7 +68,7 @@ class MessageActionController extends GetxController {
size: 20.w, size: 20.w,
color: isDarkMode ? Colors.white : Colors.black87, color: isDarkMode ? Colors.white : Colors.black87,
), ),
'复制', 'copy'.tr, // 复制
isDarkMode ? Colors.white : Colors.black87, isDarkMode ? Colors.white : Colors.black87,
() => _copyMessage(message), () => _copyMessage(message),
), ),
@ -95,7 +96,7 @@ class MessageActionController extends GetxController {
size: 20.w, size: 20.w,
color: isDarkMode ? Colors.red[700] : Colors.red, color: isDarkMode ? Colors.red[700] : Colors.red,
), ),
'举报'.tr, 'report'.tr, //举报
isDarkMode ? Colors.red[700]! : Colors.red, isDarkMode ? Colors.red[700]! : Colors.red,
() => _showReportForm(context, isDarkMode, message), () => _showReportForm(context, isDarkMode, message),
), ),
@ -138,7 +139,7 @@ class MessageActionController extends GetxController {
Clipboard.setData(ClipboardData(text: message.text)).then((_) { Clipboard.setData(ClipboardData(text: message.text)).then((_) {
Get.snackbar( Get.snackbar(
'success'.tr, 'success'.tr,
'复制成功', 'copySuccess'.tr, // 复制成功
backgroundColor: Colors.blue.withOpacity(0.8), backgroundColor: Colors.blue.withOpacity(0.8),
colorText: Colors.white, colorText: Colors.white,
); );
@ -205,7 +206,7 @@ class MessageActionController extends GetxController {
try { try {
// 调用API提交举报 // 调用API提交举报
var response = await Api.reportAiContent(reportData); var response = await Api.reportAiContent(reportData);
if (response != null) { if (response != null) {
print('提交举报响应: $response'); print('提交举报响应: $response');
} }
@ -220,8 +221,8 @@ class MessageActionController extends GetxController {
// 显示成功通知 // 显示成功通知
Get.snackbar( Get.snackbar(
'提交成功', 'submitSuccess'.tr, // 提交成功
'举报已提交,我们会尽快处理', 'reportSubmitted'.tr, // 举报已提交,我们会尽快处理
backgroundColor: Colors.green.withOpacity(0.8), backgroundColor: Colors.green.withOpacity(0.8),
colorText: Colors.white, colorText: Colors.white,
duration: const Duration(seconds: 2), duration: const Duration(seconds: 2),
@ -229,8 +230,8 @@ class MessageActionController extends GetxController {
} catch (e) { } catch (e) {
// 显示错误通知 // 显示错误通知
Get.snackbar( Get.snackbar(
'提交失败', 'submitFailed'.tr, // 提交失败
'网络错误,请稍后重试', 'networkError'.tr, // 网络错误,请稍后重试
backgroundColor: Colors.red.withOpacity(0.8), backgroundColor: Colors.red.withOpacity(0.8),
colorText: Colors.white, colorText: Colors.white,
duration: const Duration(seconds: 2), duration: const Duration(seconds: 2),
@ -242,7 +243,8 @@ class MessageActionController extends GetxController {
/// 举报表单组件 /// 举报表单组件
class _ReportForm extends StatelessWidget { class _ReportForm extends StatelessWidget {
final bool isDarkMode; final bool isDarkMode;
final MessageActionController controller = Get.find<MessageActionController>(); final MessageActionController controller =
Get.find<MessageActionController>();
_ReportForm({required this.isDarkMode}); _ReportForm({required this.isDarkMode});
@ -262,7 +264,7 @@ class _ReportForm extends StatelessWidget {
children: [ children: [
Center( Center(
child: Text( child: Text(
'举报', 'report'.tr, // 举报
style: TextStyle( style: TextStyle(
fontSize: 18.sp, fontSize: 18.sp,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
@ -300,13 +302,20 @@ class _ReportForm extends StatelessWidget {
spacing: 8.w, spacing: 8.w,
runSpacing: 8.h, runSpacing: 8.h,
children: [ children: [
_buildReportChip('有害/不安全', isDarkMode, controller), _buildReportChip(
_buildReportChip('色情低俗', isDarkMode, controller), 'harmfulUnsafe'.tr, isDarkMode, controller), // 有害/不安全
_buildReportChip('误导攻击', isDarkMode, controller), _buildReportChip('pornographicVulgar'.tr, isDarkMode,
_buildReportChip('违法犯罪', isDarkMode, controller), controller), // 色情低俗
_buildReportChip('隐私相关', isDarkMode, controller), _buildReportChip('misleadingAttack'.tr, isDarkMode,
_buildReportChip('侵犯我的著作权、名誉权等', isDarkMode, controller), controller), // 误导攻击
_buildReportChip('其他', isDarkMode, controller), _buildReportChip(
'illegalCriminal'.tr, isDarkMode, controller), // 违法犯罪
_buildReportChip(
'privacyRelated'.tr, isDarkMode, controller), // 隐私相关
_buildReportChip('copyrightViolation'.tr, isDarkMode,
controller), // 侵犯我的著作权、名誉权等
_buildReportChip(
'other'.tr, isDarkMode, controller), // 其他
], ],
); );
}, },
@ -328,7 +337,8 @@ class _ReportForm extends StatelessWidget {
color: isDarkMode ? Colors.white : Colors.black, color: isDarkMode ? Colors.white : Colors.black,
), ),
decoration: InputDecoration( decoration: InputDecoration(
hintText: '我们想知道你举报的原因,你可以描述你遇到的问题。', hintText:
'reportDescriptionHint'.tr, // 我们想知道你举报的原因,你可以描述你遇到的问题。
hintStyle: TextStyle( hintStyle: TextStyle(
color: isDarkMode ? Colors.white70 : Colors.black54, color: isDarkMode ? Colors.white70 : Colors.black54,
fontSize: 14.sp, fontSize: 14.sp,
@ -350,7 +360,7 @@ class _ReportForm extends StatelessWidget {
borderRadius: BorderRadius.circular(8.r), borderRadius: BorderRadius.circular(8.r),
), ),
), ),
child: Text('提交'), child: Text('submit'.tr), // 提交
onPressed: () => controller.submitReport(), onPressed: () => controller.submitReport(),
), ),

78
lib/modules/agent/views/agent_view.dart

@ -92,7 +92,7 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
'小言'.tr, 'XiaoYan'.tr,
style: TextStyle( style: TextStyle(
fontSize: 16, fontSize: 16,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
@ -111,7 +111,7 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver {
), ),
const SizedBox(width: 4), const SizedBox(width: 4),
Text( Text(
'在线'.tr, 'online'.tr,
style: TextStyle( style: TextStyle(
fontSize: 12, fontSize: 12,
color: Colors.green, color: Colors.green,
@ -171,7 +171,7 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver {
children: [ children: [
Icon(Icons.delete_outline, color: primaryColor, size: 20), Icon(Icons.delete_outline, color: primaryColor, size: 20),
const SizedBox(width: 8), const SizedBox(width: 8),
Text('清除聊天记录'.tr, style: TextStyle(fontSize: 14)), Text('clearChatHistory'.tr, style: TextStyle(fontSize: 14)),
], ],
), ),
onTap: () => Future.delayed( onTap: () => Future.delayed(
@ -200,10 +200,12 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver {
reverse: true, reverse: true,
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
vertical: 16, horizontal: 16), vertical: 16, horizontal: 16),
itemCount: controller.messages.length + (controller.hasMoreMessages.value ? 1 : 0), itemCount: controller.messages.length +
(controller.hasMoreMessages.value ? 1 : 0),
itemBuilder: (context, index) { itemBuilder: (context, index) {
// 如果是最后一项且有更多消息,显示加载指示器 // 如果是最后一项且有更多消息,显示加载指示器
if (index == controller.messages.length && controller.hasMoreMessages.value) { if (index == controller.messages.length &&
controller.hasMoreMessages.value) {
return _buildLoadMoreIndicator(); return _buildLoadMoreIndicator();
} }
@ -305,20 +307,20 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver {
children: [ children: [
_buildPromptChip( _buildPromptChip(
context: context, context: context,
label: '总结图片内容'.tr, label: 'summarizeImageContent'.tr,//总结图片内容
onTap: () => controller.summarizeImage(), onTap: () => controller.summarizeImage(),
), ),
const SizedBox(width: 8), const SizedBox(width: 8),
_buildPromptChip( _buildPromptChip(
context: context, context: context,
label: '抽取图像文字'.tr, label: 'extractImageText'.tr,//抽取图像文字
onTap: () => onTap: () =>
controller.extractTextFromImage(), controller.extractTextFromImage(),
), ),
const SizedBox(width: 8), const SizedBox(width: 8),
_buildPromptChip( _buildPromptChip(
context: context, context: context,
label: '翻译图像文字'.tr, label: 'translateImageText'.tr,//翻译图像文字
onTap: () => onTap: () =>
controller.translateImageText(), controller.translateImageText(),
), ),
@ -440,8 +442,10 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver {
), ),
decoration: InputDecoration( decoration: InputDecoration(
hintText: isImageActive hintText: isImageActive
? '添加对图片的问题或描述...' ? 'addQuestionAboutImage'
: '输入消息...', .tr // 添加对图片的问题或描述...
: 'inputMessage'
.tr, // 输入消息...
hintStyle: TextStyle( hintStyle: TextStyle(
color: Colors.grey[500], color: Colors.grey[500],
fontSize: 15, fontSize: 15,
@ -576,8 +580,10 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver {
const SizedBox(width: 6), const SizedBox(width: 6),
Text( Text(
isPushToTalkActive isPushToTalkActive
? '正在录音...' ? 'recording'
: '按住说话', .tr // 正在录音...
: 'holdToSpeak'
.tr, // 按住说话
style: TextStyle( style: TextStyle(
fontSize: 14, fontSize: 14,
fontWeight: fontWeight:
@ -735,7 +741,7 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver {
_buildPlusOptionButton( _buildPlusOptionButton(
context: context, context: context,
icon: Icons.camera_alt, icon: Icons.camera_alt,
label: '拍照', label: 'takePhoto'.tr, // 拍照
onTap: () async { onTap: () async {
//controller.collapsePlusOptions(); //controller.collapsePlusOptions();
await controller.takePhoto(); await controller.takePhoto();
@ -746,7 +752,7 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver {
_buildPlusOptionButton( _buildPlusOptionButton(
context: context, context: context,
icon: Icons.photo_library, icon: Icons.photo_library,
label: '相册', label: 'photoAlbum'.tr, // 相册
onTap: () async { onTap: () async {
//controller.collapsePlusOptions(); //controller.collapsePlusOptions();
await controller.pickImage(); await controller.pickImage();
@ -768,7 +774,7 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver {
_buildPlusOptionButton( _buildPlusOptionButton(
context: context, context: context,
icon: Icons.phone, icon: Icons.phone,
label: '打电话', label: 'makeCall'.tr, // 打电话
onTap: () { onTap: () {
// 启动打电话模式 // 启动打电话模式
controller.startPhoneCall(); controller.startPhoneCall();
@ -945,7 +951,7 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
'AI语音通话', 'aiVoiceCall'.tr, // AI语音通话
style: TextStyle( style: TextStyle(
fontSize: 18, fontSize: 18,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
@ -954,10 +960,10 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver {
), ),
Obx(() { Obx(() {
final status = controller.isListening.value final status = controller.isListening.value
? '正在通话中...' ? 'inCall'.tr // 正在通话中...
: controller.isSpeaking.value : controller.isSpeaking.value
? 'AI正在回复...' ? 'aiReplying'.tr // AI正在回复...
: '等待开始...'; : 'waitingToStart'.tr; // 等待开始...
return Text( return Text(
status, status,
style: TextStyle( style: TextStyle(
@ -1010,13 +1016,13 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver {
// 状态文字 // 状态文字
Obx(() { Obx(() {
String statusText = '点击开始通话'; String statusText = 'clickToStartCall'.tr; // 点击开始通话
if (controller.isListening.value) { if (controller.isListening.value) {
statusText = '正在听您说话...'; statusText = 'listeningToYou'.tr; // 正在听您说话...
} else if (controller.isSpeaking.value) { } else if (controller.isSpeaking.value) {
statusText = 'AI正在回复...'; statusText = 'aiReplying'.tr; // AI正在回复...
} else if (controller.isProcessing.value) { } else if (controller.isProcessing.value) {
statusText = '正在处理...'; statusText = 'processing'.tr; // 正在处理...
} }
return Text( return Text(
@ -1135,21 +1141,21 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver {
// 正在加载状态 // 正在加载状态
return Container( return Container(
padding: const EdgeInsets.symmetric(vertical: 16), padding: const EdgeInsets.symmetric(vertical: 16),
child: const Center( child: Center(
child: Row( child: Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
SizedBox( const SizedBox(
width: 16, width: 16,
height: 16, height: 16,
child: CircularProgressIndicator( child: CircularProgressIndicator(
strokeWidth: 2, strokeWidth: 2,
), ),
), ),
SizedBox(width: 8), const SizedBox(width: 8),
Text( Text(
'加载更多消息...', 'loadMoreMessages'.tr, // 加载更多消息...
style: TextStyle( style: const TextStyle(
fontSize: 14, fontSize: 14,
color: Colors.grey, color: Colors.grey,
), ),
@ -1165,18 +1171,18 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver {
child: Center( child: Center(
child: GestureDetector( child: GestureDetector(
onTap: () => controller.loadMoreMessages(), onTap: () => controller.loadMoreMessages(),
child: const Row( child: Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Icon( const Icon(
Icons.refresh, Icons.refresh,
size: 16, size: 16,
color: Colors.grey, color: Colors.grey,
), ),
SizedBox(width: 8), const SizedBox(width: 8),
Text( Text(
'加载失败,点击重试', 'loadFailedClickRetry'.tr, // 加载失败,点击重试
style: TextStyle( style: const TextStyle(
fontSize: 14, fontSize: 14,
color: Colors.grey, color: Colors.grey,
), ),
@ -1190,10 +1196,10 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver {
// 默认状态(有更多消息但未加载) // 默认状态(有更多消息但未加载)
return Container( return Container(
padding: const EdgeInsets.symmetric(vertical: 8), padding: const EdgeInsets.symmetric(vertical: 8),
child: const Center( child: Center(
child: Text( child: Text(
'向上滑动查看更多', 'swipeUpForMore'.tr, // 向上滑动查看更多
style: TextStyle( style: const TextStyle(
fontSize: 12, fontSize: 12,
color: Colors.grey, color: Colors.grey,
), ),

2
lib/modules/agent/views/message_bubble.dart

@ -110,7 +110,7 @@ class MessageBubble extends GetView<AgentController> {
Padding( Padding(
padding: const EdgeInsets.only(left: 8), padding: const EdgeInsets.only(left: 8),
child: Text( child: Text(
"由AI生成".tr, "generatedByAi".tr,// 由AI生成
style: TextStyle( style: TextStyle(
fontSize: 8, fontSize: 8,
color: Colors.blue[600], color: Colors.blue[600],

10
lib/modules/agent/views/music_card.dart

@ -67,7 +67,9 @@ Widget buildMusicItem(BuildContext context, int id, String name, String url,
style: TextStyle( style: TextStyle(
fontSize: 13.sp, fontSize: 13.sp,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: isDarkMode ? Colors.white.withValues(alpha: 0.9) : Colors.grey[800], color: isDarkMode
? Colors.white.withValues(alpha: 0.9)
: Colors.grey[800],
), ),
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
), ),
@ -146,7 +148,7 @@ Widget buildMusicContent(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
'以下是一些推荐的音乐:', 'recommendedMusic'.tr, //以下是一些推荐的音乐:
style: TextStyle( style: TextStyle(
color: color:
isDarkMode ? Colors.white.withValues(alpha: 0.9) : Colors.black87, isDarkMode ? Colors.white.withValues(alpha: 0.9) : Colors.black87,
@ -184,7 +186,7 @@ Widget buildMusicContent(
), ),
const SizedBox(width: 6), const SizedBox(width: 6),
Text( Text(
'播放列表'.tr, 'playList'.tr, //播放列表
style: TextStyle( style: TextStyle(
fontSize: 13, fontSize: 13,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
@ -235,7 +237,7 @@ Widget buildMusicContent(
tapTargetSize: MaterialTapTargetSize.shrinkWrap, tapTargetSize: MaterialTapTargetSize.shrinkWrap,
), ),
child: Text( child: Text(
'查看更多推荐', 'moreMusic'.tr, //更多音乐,
style: TextStyle( style: TextStyle(
fontSize: 12, fontSize: 12,
color: Theme.of(context).primaryColor, color: Theme.of(context).primaryColor,

87
lib/modules/agent/views/navigation_card.dart

@ -9,9 +9,9 @@ String formatDistance(String distanceStr) {
if (distance >= 1000) { if (distance >= 1000) {
final km = distance / 1000; final km = distance / 1000;
return '${km.toStringAsFixed(1)} 公里'; return '${km.toStringAsFixed(1)} KM';
} else { } else {
return '${distance.toStringAsFixed(0)} 米'; return '${distance.toStringAsFixed(0)} M';
} }
} }
@ -24,9 +24,10 @@ String formatDuration(String secondsStr) {
int seconds = duration.inSeconds.remainder(60); int seconds = duration.inSeconds.remainder(60);
List<String> parts = []; List<String> parts = [];
if (hours > 0) parts.add('$hours小时'); if (hours > 0) parts.add('$hours${'hours'.tr}'); // 小时
if (minutes > 0) parts.add('$minutes分钟'); if (minutes > 0) parts.add('$minutes${'minutes'.tr}'); // 分钟
if (seconds > 0 || parts.isEmpty) parts.add('$seconds秒'); //不需要秒
//if (seconds > 0 || parts.isEmpty) parts.add('$seconds${'seconds'.tr}'); // 秒
return parts.join(''); return parts.join('');
} }
@ -126,7 +127,7 @@ Widget navigationCard(
), ),
SizedBox(width: 4.w), SizedBox(width: 4.w),
Text( Text(
'导航中', 'navigating'.tr, // 导航中
style: TextStyle( style: TextStyle(
color: Colors.white, color: Colors.white,
fontSize: 12.sp, fontSize: 12.sp,
@ -190,24 +191,24 @@ Widget navigationCard(
: Colors.grey, : Colors.grey,
size: 20.sp, size: 20.sp,
), ),
SizedBox(height: 4.h), // SizedBox(height: 4.h),
Text( // Text(
(mode["ntype"] as String).tr, // (mode["ntype"] as String).tr,
textAlign: TextAlign.center, // textAlign: TextAlign.center,
style: TextStyle( // style: TextStyle(
color: isEnabled // color: isEnabled
? (isSelected // ? (isSelected
? Theme.of(context).primaryColor // ? Theme.of(context).primaryColor
: (isDarkMode // : (isDarkMode
? Colors.white70 // ? Colors.white70
: Colors.black87)) // : Colors.black87))
: Colors.grey, // : Colors.grey,
fontSize: 11.sp, // fontSize: 11.sp,
fontWeight: isSelected // fontWeight: isSelected
? FontWeight.w600 // ? FontWeight.w600
: FontWeight.w400, // : FontWeight.w400,
), // ),
), // ),
], ],
), ),
), ),
@ -237,26 +238,25 @@ Widget navigationCard(
size: 16.sp, size: 16.sp,
color: Theme.of(context).primaryColor, color: Theme.of(context).primaryColor,
), ),
SizedBox(width: 6.w), // SizedBox(width: 6.w),
// 当前位置文本 // // 当前位置文本
Text( // Text(
'当前位置', // 'currentLocation'.tr, // 当前位置
style: TextStyle( // style: TextStyle(
fontSize: 14.sp, // fontSize: 14.sp,
fontWeight: FontWeight.w500, // fontWeight: FontWeight.w500,
color: isDarkMode // color: isDarkMode
? Colors.white70 // ? Colors.white70
: Colors.black54, // : Colors.black54,
), // ),
), // ),
SizedBox(width: 8.w), SizedBox(width: 8.w),
// 箭头图标 // 箭头图标
Icon( Icon(
Icons.arrow_forward, Icons.arrow_forward,
size: 16.sp, size: 16.sp,
color: isDarkMode color:
? Colors.white54 isDarkMode ? Colors.white54 : Colors.black45,
: Colors.black45,
), ),
SizedBox(width: 8.w), SizedBox(width: 8.w),
// 目的地图标 // 目的地图标
@ -319,7 +319,7 @@ Widget navigationCard(
), ),
SizedBox(width: 4.w), SizedBox(width: 4.w),
Text( Text(
'约${formatDuration(modes[currentIndex]["duration"])}', '${'approximate'.tr}${formatDuration(modes[currentIndex]["duration"])}', // 约
style: TextStyle( style: TextStyle(
fontSize: 14.sp, fontSize: 14.sp,
color: Theme.of(context).primaryColor, color: Theme.of(context).primaryColor,
@ -343,7 +343,7 @@ Widget navigationCard(
borderRadius: BorderRadius.circular(6.r), borderRadius: BorderRadius.circular(6.r),
), ),
child: Text( child: Text(
"${navigation["distanceText"]}进入${navigation["nextRoad"]}", "${navigation["distanceText"]}${'enterRoad'.tr}${navigation["nextRoad"]}", // 进入
style: TextStyle( style: TextStyle(
fontSize: 12.sp, fontSize: 12.sp,
color: Theme.of(context).primaryColor, color: Theme.of(context).primaryColor,
@ -372,9 +372,8 @@ Widget navigationCard(
borderRadius: BorderRadius.circular(12.r), borderRadius: BorderRadius.circular(12.r),
boxShadow: [ boxShadow: [
BoxShadow( BoxShadow(
color: Theme.of(context) color:
.primaryColor Theme.of(context).primaryColor.withOpacity(0.3),
.withOpacity(0.3),
blurRadius: 8, blurRadius: 8,
offset: const Offset(0, 2), offset: const Offset(0, 2),
), ),

72
lib/modules/agent/views/weather_card.dart

@ -1,6 +1,7 @@
import 'package:common_utils/common_utils.dart'; import 'package:common_utils/common_utils.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
/// 构建天气内容卡片 /// 构建天气内容卡片
Widget buildWeatherContent(BuildContext context, String city, Widget buildWeatherContent(BuildContext context, String city,
@ -11,9 +12,10 @@ Widget buildWeatherContent(BuildContext context, String city,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
'查询天气情况:', 'weatherQuery'.tr, // 翻译键代表的中文文本内容:查询天气情况:
style: TextStyle( style: TextStyle(
color: isDarkMode ? Colors.white.withValues(alpha: 0.9) : Colors.black87, color:
isDarkMode ? Colors.white.withValues(alpha: 0.9) : Colors.black87,
fontSize: 14.sp, fontSize: 14.sp,
height: 1.4, height: 1.4,
fontWeight: FontWeight.w400, fontWeight: FontWeight.w400,
@ -55,8 +57,8 @@ Widget buildWeatherContent(BuildContext context, String city,
children: [ children: [
Text( Text(
"${city} ${now["date"]}", "${city} ${now["date"]}",
style: const TextStyle( style: TextStyle(
fontSize: 16, fontSize: 16.sp,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
color: Colors.white, color: Colors.white,
), ),
@ -85,14 +87,14 @@ Widget buildWeatherContent(BuildContext context, String city,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
'最高: ${now["daytemp"]}°', '${'highest'.tr}: ${now["daytemp"]}°', // 翻译键代表的中文文本内容:最高
style: TextStyle( style: TextStyle(
fontSize: 12.sp, fontSize: 12.sp,
color: Colors.white.withValues(alpha: 0.9), color: Colors.white.withValues(alpha: 0.9),
), ),
), ),
Text( Text(
'最低: ${now["nighttemp"]}°', '${'lowest'.tr}: ${now["nighttemp"]}°', // 翻译键代表的中文文本内容:最低
style: TextStyle( style: TextStyle(
fontSize: 12.sp, fontSize: 12.sp,
color: Colors.white.withValues(alpha: 0.9), color: Colors.white.withValues(alpha: 0.9),
@ -118,7 +120,7 @@ Widget buildWeatherContent(BuildContext context, String city,
), ),
SizedBox(height: 16.h), SizedBox(height: 16.h),
Text( Text(
'未来预报', 'futureForecast'.tr, // 翻译键代表的中文文本内容:未来预报
style: TextStyle( style: TextStyle(
fontSize: 14.sp, fontSize: 14.sp,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
@ -156,7 +158,8 @@ Widget buildWeatherContent(BuildContext context, String city,
} }
/// 构建智能天气提示 /// 构建智能天气提示
Widget _buildWeatherTip(BuildContext context, Map<String, dynamic> now, bool isDarkMode) { Widget _buildWeatherTip(
BuildContext context, Map<String, dynamic> now, bool isDarkMode) {
final weatherTip = _generateWeatherTip(now); final weatherTip = _generateWeatherTip(now);
return Container( return Container(
@ -205,72 +208,79 @@ WeatherTip _generateWeatherTip(Map<String, dynamic> now) {
// 高温提示 (>= 35°C) // 高温提示 (>= 35°C)
if (dayTemp >= 35) { if (dayTemp >= 35) {
return const WeatherTip( return WeatherTip(
icon: Icons.local_fire_department, icon: Icons.local_fire_department,
message: '今日高温炎热,请注意防暑降温,多喝水避免中暑', message: 'hotWeatherTip'.tr, // 翻译键代表的中文文本内容:今日高温炎热,请注意防暑降温,多喝水避免中暑
); );
} }
// 低温提示 (<= 5°C) // 低温提示 (<= 5°C)
if (dayTemp <= 5) { if (dayTemp <= 5) {
return const WeatherTip( return WeatherTip(
icon: Icons.ac_unit, icon: Icons.ac_unit,
message: '今日气温较低,外出请注意保暖,小心感冒', message: 'coldWeatherTip'.tr, // 翻译键代表的中文文本内容:今日气温较低,外出请注意保暖,小心感冒
); );
} }
// 雨天提示 // 雨天提示
if (dayWeather.contains('雨') || ['阵雨', '雷阵雨', '小雨', '中雨', '大雨', '暴雨'].any((rain) => dayWeather.contains(rain))) { if (dayWeather.contains('雨') ||
return const WeatherTip( ['阵雨', '雷阵雨', '小雨', '中雨', '大雨', '暴雨']
.any((rain) => dayWeather.contains(rain))) {
return WeatherTip(
icon: Icons.umbrella, icon: Icons.umbrella,
message: '今日有雨,外出请携带雨具,注意出行安全', message: 'rainyWeatherTip'.tr, // 翻译键代表的中文文本内容:今日有雨,外出请携带雨具,注意出行安全
); );
} }
// 雪天提示 // 雪天提示
if (dayWeather.contains('雪') || ['阵雪', '小雪', '中雪', '大雪', '暴雪'].any((snow) => dayWeather.contains(snow))) { if (dayWeather.contains('雪') ||
return const WeatherTip( ['阵雪', '小雪', '中雪', '大雪', '暴雪'].any((snow) => dayWeather.contains(snow))) {
return WeatherTip(
icon: Icons.ac_unit, icon: Icons.ac_unit,
message: '今日有雪,路面湿滑请注意安全,做好保暖措施', message: 'snowyWeatherTip'.tr, // 翻译键代表的中文文本内容:今日有雪,路面湿滑请注意安全,做好保暖措施
); );
} }
// 雾霾提示 // 雾霾提示
if (dayWeather.contains('雾') || dayWeather.contains('霾') || ['雾', '浓雾', '霾', '中度霾', '重度霾'].any((fog) => dayWeather.contains(fog))) { if (dayWeather.contains('雾') ||
return const WeatherTip( dayWeather.contains('霾') ||
['雾', '浓雾', '霾', '中度霾', '重度霾'].any((fog) => dayWeather.contains(fog))) {
return WeatherTip(
icon: Icons.blur_on, icon: Icons.blur_on,
message: '今日有雾霾,能见度较低,外出请佩戴口罩', message: 'foggyWeatherTip'.tr, // 翻译键代表的中文文本内容:今日有雾霾,能见度较低,外出请佩戴口罩
); );
} }
// 大风提示 // 大风提示
if (dayWeather.contains('风') || ['大风', '强风', '疾风', '烈风'].any((wind) => dayWeather.contains(wind))) { if (dayWeather.contains('风') ||
return const WeatherTip( ['大风', '强风', '疾风', '烈风'].any((wind) => dayWeather.contains(wind))) {
return WeatherTip(
icon: Icons.air, icon: Icons.air,
message: '今日风力较大,外出请注意安全,固定好物品', message: 'windyWeatherTip'.tr, // 翻译键代表的中文文本内容:今日风力较大,外出请注意安全,固定好物品
); );
} }
// 晴天紫外线提示 (温度 >= 25°C) // 晴天紫外线提示 (温度 >= 25°C)
if (['晴', '少云', '晴间多云'].any((sunny) => dayWeather.contains(sunny)) && dayTemp >= 25) { if (['晴', '少云', '晴间多云'].any((sunny) => dayWeather.contains(sunny)) &&
return const WeatherTip( dayTemp >= 25) {
return WeatherTip(
icon: Icons.wb_sunny, icon: Icons.wb_sunny,
message: '今日阳光充足紫外线较强,外出请做好防晒', message: 'sunnyWeatherTip'.tr, // 翻译键代表的中文文本内容:今日阳光充足紫外线较强,外出请做好防晒
); );
} }
// 温差大提示 (>= 10°C) // 温差大提示 (>= 10°C)
if ((dayTemp - nightTemp).abs() >= 10) { if ((dayTemp - nightTemp).abs() >= 10) {
return const WeatherTip( return WeatherTip(
icon: Icons.thermostat, icon: Icons.thermostat,
message: '今日昼夜温差较大,请适时增减衣物', message: 'temperatureDifferenceTip'.tr, // 翻译键代表的中文文本内容:今日昼夜温差较大,请适时增减衣物
); );
} }
// 默认舒适天气提示 // 默认舒适天气提示
return const WeatherTip( return WeatherTip(
icon: Icons.wb_sunny_outlined, icon: Icons.wb_sunny_outlined,
message: '今日天气适宜,是外出活动的好时光', message: 'comfortableWeatherTip'.tr, // 翻译键代表的中文文本内容:今日天气适宜,是外出活动的好时光
); );
} }

5
lib/modules/agent/widgets/full_screen_editor.dart

@ -72,7 +72,7 @@ class _FullScreenEditorState extends State<FullScreenEditor> {
height: 1.5, height: 1.5,
), ),
decoration: InputDecoration( decoration: InputDecoration(
hintText: '在这里输入你的消息...', hintText: 'fullScreenEditorHint'.tr, // 在这里输入你的消息...
hintStyle: TextStyle( hintStyle: TextStyle(
color: isDarkMode ? Colors.white54 : Colors.grey[500], color: isDarkMode ? Colors.white54 : Colors.grey[500],
fontSize: 16.sp, fontSize: 16.sp,
@ -106,7 +106,8 @@ class _FullScreenEditorState extends State<FullScreenEditor> {
valueListenable: _textController, valueListenable: _textController,
builder: (context, value, child) { builder: (context, value, child) {
return Text( return Text(
'${value.text.length} 字符', 'characterCount'.tr.replaceAll('{count}',
'${value.text.length}'), // ${value.text.length} 字符
style: TextStyle( style: TextStyle(
color: isDarkMode color: isDarkMode
? Colors.white60 ? Colors.white60

18
lib/modules/common/widgets/version_update_dialog.dart

@ -70,7 +70,7 @@ class VersionUpdateDialog extends StatelessWidget {
// 标题 // 标题
Text( Text(
'发现新版本', 'newVersionFound'.tr, // 发现新版本
style: TextStyle( style: TextStyle(
fontSize: 20.sp, fontSize: 20.sp,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
@ -135,7 +135,7 @@ class VersionUpdateDialog extends StatelessWidget {
), ),
), ),
child: Text( child: Text(
'稍后提醒', 'remindLater'.tr, // 稍后提醒
style: TextStyle( style: TextStyle(
fontSize: 16.sp, fontSize: 16.sp,
color: color:
@ -185,11 +185,11 @@ class VersionUpdateDialog extends StatelessWidget {
String _getUpdateButtonText() { String _getUpdateButtonText() {
switch (updateInfo.updateType) { switch (updateInfo.updateType) {
case UpdateType.force: case UpdateType.force:
return '立即更新'; return 'updateNow'.tr; // 立即更新
case UpdateType.optional: case UpdateType.optional:
return '立即更新'; return 'updateNow'.tr; // 立即更新
default: default:
return '检查更新'; return 'checkUpdate'.tr; // 检查更新
} }
} }
@ -212,8 +212,8 @@ class VersionUpdateDialog extends StatelessWidget {
if (!success) { if (!success) {
Get.snackbar( Get.snackbar(
'更新失败', 'updateFailed'.tr, // 更新失败
'无法打开应用商店,请手动前往应用商店更新', 'cannotOpenAppStore'.tr, // 无法打开应用商店,请手动前往应用商店更新
snackPosition: SnackPosition.TOP, snackPosition: SnackPosition.TOP,
backgroundColor: Colors.red.withOpacity(0.8), backgroundColor: Colors.red.withOpacity(0.8),
colorText: Colors.white, colorText: Colors.white,
@ -226,8 +226,8 @@ class VersionUpdateDialog extends StatelessWidget {
} }
Get.snackbar( Get.snackbar(
'更新失败', 'updateFailed'.tr, // 更新失败
'更新过程中发生错误,请稍后重试', 'updateErrorRetry'.tr, // 更新过程中发生错误,请稍后重试
snackPosition: SnackPosition.TOP, snackPosition: SnackPosition.TOP,
backgroundColor: Colors.red.withOpacity(0.8), backgroundColor: Colors.red.withOpacity(0.8),
colorText: Colors.white, colorText: Colors.white,

4
lib/modules/ota_upgrade/views/ota_upgrade_view.dart

@ -501,7 +501,7 @@ class OtaUpgradeView extends GetView<OtaUpgradeController> {
), ),
SizedBox(width: 6.w), SizedBox(width: 6.w),
Text( Text(
'newVersionFound'.tr, // 发现新版本 'ota_newVersionFound'.tr, // 发现新版本
style: TextStyle( style: TextStyle(
fontSize: 12.sp, fontSize: 12.sp,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
@ -835,7 +835,7 @@ class OtaUpgradeView extends GetView<OtaUpgradeController> {
), ),
label: Text( label: Text(
controller.isUpdateAvailable.value controller.isUpdateAvailable.value
? 'updateNow'.tr ? 'ota_updateNow'.tr
: 'latestVersion'.tr, // 立即更新 : 已是最新版本 : 'latestVersion'.tr, // 立即更新 : 已是最新版本
style: TextStyle( style: TextStyle(
fontSize: 16.sp, fontSize: 16.sp,

73
lib/modules/pairing/controllers/pairing_controller.dart

@ -70,8 +70,8 @@ class PairingController extends GetxController {
// 增加临时跳过绑定按钮状态 // 增加临时跳过绑定按钮状态
final showSkipBindingButton = false.obs; // 新增临时跳过绑定按钮 final showSkipBindingButton = false.obs; // 新增临时跳过绑定按钮
final connectButtonText = '连接设备'.obs; final connectButtonText = 'connectDevice'.tr.obs; //连接设备
final retryButtonText = '重试'.obs; final retryButtonText = 'retry'.tr.obs;
final deviceCode = ''.obs; final deviceCode = ''.obs;
// ========== 监听器管理 ========== // ========== 监听器管理 ==========
@ -168,8 +168,7 @@ class PairingController extends GetxController {
/// 处理蓝牙开关状态变化 /// 处理蓝牙开关状态变化
void _handleBluetoothStateChange(String state) { void _handleBluetoothStateChange(String state) {
if (state == 'off') { if (state == 'off') {
// 蓝牙关闭,进入错误状态 _setError(ErrorType.bluetoothOff, 'pleaseEnableBluetooth'.tr);
_setError(ErrorType.bluetoothOff, '请开启蓝牙');
} else if (state == 'on' && _errorType.value == ErrorType.bluetoothOff) { } else if (state == 'on' && _errorType.value == ErrorType.bluetoothOff) {
// 蓝牙重新开启,恢复流程 // 蓝牙重新开启,恢复流程
Logger.i(_tag, '检测到蓝牙已开启,自动恢复配对流程'); Logger.i(_tag, '检测到蓝牙已开启,自动恢复配对流程');
@ -210,7 +209,7 @@ class PairingController extends GetxController {
case PairingState.completed: case PairingState.completed:
if (device == null) { if (device == null) {
// 设备断开,返回等待连接状态 // 设备断开,返回等待连接状态
_setError(ErrorType.noClassicDevice, '设备已断开'); _setError(ErrorType.noClassicDevice, 'deviceDisconnected'.tr); //设备已断开
} }
break; break;
@ -260,34 +259,33 @@ class PairingController extends GetxController {
showRetryChectButton.value = false; showRetryChectButton.value = false;
switch (state) { switch (state) {
case PairingState.idle: case PairingState.idle:
statusText.value = '准备开始配对'; statusText.value = 'readyToStartPairing'.tr;
break; break;
case PairingState.checking: case PairingState.checking:
statusText.value = '正在检查环境...'; statusText.value = 'checkingEnvironment'.tr;
isLoading.value = true; isLoading.value = true;
break; break;
case PairingState.waitingClassic: case PairingState.waitingClassic:
statusText.value = '请确保耳机已开启并进入配对模式'; statusText.value = 'ensureHeadsetOnAndPairingMode'.tr;
showConnectButton.value = true; showConnectButton.value = true;
showSkipButton.value = true; showSkipButton.value = true;
connectButtonText.value = 'goToBluetoothSettings'.tr;
connectButtonText.value = '前往蓝牙设置';
break; break;
case PairingState.verifying: case PairingState.verifying:
statusText.value = '正在验证设备...'; statusText.value = 'verifyingDevice'.tr;
isLoading.value = true; isLoading.value = true;
break; break;
case PairingState.binding: case PairingState.binding:
statusText.value = '确认绑定'; statusText.value = 'confirmBinding'.tr;
isLoading.value = true; isLoading.value = true;
showBindButton.value = true; showBindButton.value = true;
showRetryChectButton.value = true; showRetryChectButton.value = true;
break; break;
case PairingState.associating: case PairingState.associating:
statusText.value = '正在关联设备...'; statusText.value = 'associatingDevice'.tr;
isLoading.value = true; isLoading.value = true;
// 延迟执行关联,确保状态已更新 // 延迟执行关联,确保状态已更新
Future.delayed(const Duration(milliseconds: 200), () { Future.delayed(const Duration(milliseconds: 200), () {
@ -296,7 +294,7 @@ class PairingController extends GetxController {
break; break;
case PairingState.waitingBle: case PairingState.waitingBle:
statusText.value = '正在建立安全连接...'; statusText.value = 'establishingSecureConnection'.tr;
isLoading.value = true; isLoading.value = true;
// 延迟一下再调用,给BLE管理器时间更新状态 // 延迟一下再调用,给BLE管理器时间更新状态
Future.delayed(const Duration(milliseconds: 200), () { Future.delayed(const Duration(milliseconds: 200), () {
@ -304,14 +302,14 @@ class PairingController extends GetxController {
}); });
break; break;
case PairingState.manualbinding: case PairingState.manualbinding:
statusText.value = '需要手动绑定授权码...'; statusText.value = 'needManualBindingAuthCode'.tr;
isLoading.value = false; isLoading.value = false;
showAutoCodeInput.value = true; showAutoCodeInput.value = true;
// showSkipButton.value = true; // showSkipButton.value = true;
showSkipBindingButton.value = true; // 显示临时跳过绑定按钮 showSkipBindingButton.value = true; // 显示临时跳过绑定按钮
break; break;
case PairingState.completed: case PairingState.completed:
statusText.value = '配对成功!'; statusText.value = 'pairingSuccessful'.tr;
isLoading.value = false; isLoading.value = false;
_navigateToHome(); _navigateToHome();
break; break;
@ -325,27 +323,27 @@ class PairingController extends GetxController {
switch (_errorType.value) { switch (_errorType.value) {
case ErrorType.bluetoothOff: case ErrorType.bluetoothOff:
showConnectButton.value = true; showConnectButton.value = true;
connectButtonText.value = '开启蓝牙'; connectButtonText.value = 'enableBluetooth'.tr; //开启蓝牙
break; break;
case ErrorType.noClassicDevice: case ErrorType.noClassicDevice:
showConnectButton.value = true; showConnectButton.value = true;
connectButtonText.value = '前往蓝牙设置'; connectButtonText.value = 'goToBluetoothSettings'.tr; //前往蓝牙设备
break; break;
case ErrorType.noPermission: case ErrorType.noPermission:
showRetryButton.value = true; showRetryButton.value = true;
retryButtonText.value = '授予权限'; retryButtonText.value = 'grantPermissions'.tr; //授予权限
break; break;
case ErrorType.associationFailed: case ErrorType.associationFailed:
showRetryButton.value = true; showRetryButton.value = true;
retryButtonText.value = '重新关联'; retryButtonText.value = 'retryAssociation'.tr; //重新关联
break; break;
case ErrorType.authnFailed: case ErrorType.authnFailed:
showRetryButton.value = true; showRetryButton.value = true;
retryButtonText.value = '重新授权'; retryButtonText.value = 'retryAuthorization'.tr; //重新授权
break; break;
default: default:
showRetryButton.value = true; showRetryButton.value = true;
retryButtonText.value = '重试'; retryButtonText.value = 'retry'.tr; //重试
break; break;
} }
break; break;
@ -380,13 +378,13 @@ class PairingController extends GetxController {
try { try {
// 1. 检查蓝牙状态 // 1. 检查蓝牙状态
if (_bluetoothManager.bluetoothState == 'off') { if (_bluetoothManager.bluetoothState == 'off') {
_setError(ErrorType.bluetoothOff, '请开启蓝牙'); _setError(ErrorType.bluetoothOff, 'pleaseEnableBluetooth'.tr);
return; return;
} }
// 2. 检查权限 // 2. 检查权限
if (!await _checkPermissions()) { if (!await _checkPermissions()) {
_setError(ErrorType.noPermission, '请授予必要权限'); _setError(ErrorType.noPermission, 'pleaseGrantNecessaryPermissions'.tr);
return; return;
} }
@ -406,7 +404,7 @@ class PairingController extends GetxController {
await _verifyDevice(classicDevice); await _verifyDevice(classicDevice);
} catch (e) { } catch (e) {
Logger.e(_tag, '状态检查失败: $e'); Logger.e(_tag, '状态检查失败: $e');
_setError(ErrorType.networkError, '检查失败,请重试'); _setError(ErrorType.networkError, 'checkFailedRetry'.tr);
} }
} }
@ -452,12 +450,13 @@ class PairingController extends GetxController {
//验证失败 进入手动授权 //验证失败 进入手动授权
_transition(PairingState.manualbinding); _transition(PairingState.manualbinding);
} else { } else {
_setError(ErrorType.deviceNotMatch, '请连接 DeepSound 设备'); _setError(ErrorType.deviceNotMatch,
'pleaseConnectDeepSoundDevice'.tr); //请连接DeepSound设备
} }
} }
} catch (e) { } catch (e) {
Logger.e(_tag, '设备验证异常: $e'); Logger.e(_tag, '设备验证异常: $e');
_setError(ErrorType.networkError, '验证失败,请重试'); _setError(ErrorType.networkError, 'verificationFailedRetry'.tr); //验证失败请重试
} }
} }
@ -496,7 +495,8 @@ class PairingController extends GetxController {
void _startDeviceAssociation() async { void _startDeviceAssociation() async {
try { try {
if (_verifiedDeviceAddress == null) { if (_verifiedDeviceAddress == null) {
_setError(ErrorType.associationFailed, '设备地址无效'); _setError(
ErrorType.associationFailed, 'invalidDeviceAddress'.tr); //无效的设备地址
return; return;
} }
@ -513,11 +513,13 @@ class PairingController extends GetxController {
// 关联成功后,转到等待BLE连接状态 // 关联成功后,转到等待BLE连接状态
_transition(PairingState.waitingBle); _transition(PairingState.waitingBle);
} else { } else {
_setError(ErrorType.associationFailed, 'BLE设备关联失败'); _setError(ErrorType.associationFailed,
'bleDeviceAssociationFailed'.tr); //BLE设备关联失败
} }
} catch (e) { } catch (e) {
Logger.e(_tag, 'BLE设备关联异常: $e'); Logger.e(_tag, 'BLE设备关联异常: $e');
_setError(ErrorType.associationFailed, '设备关联失败,请重试'); _setError(ErrorType.associationFailed,
'deviceAssociationFailedRetry'.tr); //设备关联失败,请重试
} }
} }
@ -528,7 +530,8 @@ class PairingController extends GetxController {
_bleTimeoutTimer?.cancel(); _bleTimeoutTimer?.cancel();
_bleTimeoutTimer = Timer(const Duration(seconds: 30), () { _bleTimeoutTimer = Timer(const Duration(seconds: 30), () {
if (_currentState.value == PairingState.waitingBle) { if (_currentState.value == PairingState.waitingBle) {
_setError(ErrorType.bleTimeout, 'BLE连接超时,请重试'); _setError(ErrorType.bleTimeout,
'bleConnectionTimeoutRetry'.tr); //BLE连接超时,请重试
} }
}); });
@ -549,12 +552,13 @@ class PairingController extends GetxController {
final success = await _bleManager.registerBackgroundScan( final success = await _bleManager.registerBackgroundScan(
macAddress: _verifiedDeviceAddress); macAddress: _verifiedDeviceAddress);
if (!success && _currentState.value == PairingState.waitingBle) { if (!success && _currentState.value == PairingState.waitingBle) {
_setError(ErrorType.bleTimeout, 'BLE配对启动失败'); _setError(
ErrorType.bleTimeout, 'blePairingStartupFailed'.tr); //BLE配对启动失败
} }
} }
} catch (e) { } catch (e) {
Logger.e(_tag, 'BLE连接失败: $e'); Logger.e(_tag, 'BLE连接失败: $e');
_setError(ErrorType.bleTimeout, 'BLE连接失败'); _setError(ErrorType.bleTimeout, 'bleConnectionFailed'.tr); //BLE连接失败
} }
} }
@ -665,7 +669,8 @@ class PairingController extends GetxController {
_verifyDevice(_currentClassicDevice!); _verifyDevice(_currentClassicDevice!);
} else { } else {
Logger.e(_tag, '手动绑定失败!'); Logger.e(_tag, '手动绑定失败!');
_setError(ErrorType.authnFailed, '设备授权失败,请检查授权码'); _setError(ErrorType.authnFailed,
'deviceAuthorizationFailedCheckCode'.tr); //设备授权失败,请检查授权码
} }
} }

7
lib/modules/pairing/views/pairing_view.dart

@ -328,7 +328,8 @@ class PairingView extends GetView<PairingController> {
case ErrorType.noPermission: case ErrorType.noPermission:
return 'lackPermissions'.tr; // 缺少蓝牙权限 return 'lackPermissions'.tr; // 缺少蓝牙权限
case ErrorType.noClassicDevice: case ErrorType.noClassicDevice:
return 'connectDeepSoundViaSystemBluetooth'.tr; // 请先通过系统蓝牙连接DeapSound设备 return 'connectDeepSoundViaSystemBluetooth'
.tr; // 请先通过系统蓝牙连接DeapSound设备
case ErrorType.deviceNotMatch: case ErrorType.deviceNotMatch:
return 'ensureConnectedDeepSoundDevice'.tr; // 请确保连接的是DeapSound设备 return 'ensureConnectedDeepSoundDevice'.tr; // 请确保连接的是DeapSound设备
case ErrorType.deviceBound: case ErrorType.deviceBound:
@ -424,9 +425,9 @@ class PairingView extends GetView<PairingController> {
// 获取连接按钮图标 // 获取连接按钮图标
IconData _getConnectButtonIcon() { IconData _getConnectButtonIcon() {
final buttonText = controller.connectButtonText.value; final buttonText = controller.connectButtonText.value;
if (buttonText.contains('蓝牙')) { if (buttonText.contains('bluetooth'.tr)) {
return Icons.bluetooth; return Icons.bluetooth;
} else if (buttonText.contains('设置')) { } else if (buttonText.contains('settings'.tr)) {
return Icons.settings; return Icons.settings;
} }
return Icons.bluetooth_searching; return Icons.bluetooth_searching;

85
lib/modules/profile/controllers/profile_controller.dart

@ -50,22 +50,22 @@ class ProfileController extends GetxController {
errorStr.contains('socket') || errorStr.contains('socket') ||
errorStr.contains('timeout') || errorStr.contains('timeout') ||
errorStr.contains('connection')) { errorStr.contains('connection')) {
return '网络连接失败,请检查网络设置后重试'; return 'networkConnectionFailed'.tr; //网络连接失败
} else if (errorStr.contains('server') || } else if (errorStr.contains('server') ||
errorStr.contains('500') || errorStr.contains('500') ||
errorStr.contains('502') || errorStr.contains('502') ||
errorStr.contains('503')) { errorStr.contains('503')) {
return '服务器暂时无法响应,请稍后重试'; return 'serverTemporarilyUnavailable'.tr; //服务器暂时不可用
} else if (errorStr.contains('401') || errorStr.contains('unauthorized')) { } else if (errorStr.contains('401') || errorStr.contains('unauthorized')) {
return '登录已过期,请重新登录'; return 'loginExpiredPleaseRelogin'.tr; //登录过期,请重新登录
} else if (errorStr.contains('403') || errorStr.contains('forbidden')) { } else if (errorStr.contains('403') || errorStr.contains('forbidden')) {
return '没有权限执行此操作'; return 'noPermissionForThisOperation'.tr; //没有权限执行此操作
} else if (errorStr.contains('404')) { } else if (errorStr.contains('404')) {
return '请求的资源不存在'; return 'requestedResourceNotFound'.tr; //请求的资源不存在
} else if (errorStr.contains('file') || errorStr.contains('image')) { } else if (errorStr.contains('file') || errorStr.contains('image')) {
return '图片处理失败,请重新选择图片'; return 'imageProcessingFailedPleaseReselect'.tr; //图片处理失败,请重新选择图片
} else { } else {
return '操作失败,请重试'; return 'operationFailedPleaseRetry'.tr; //操作失败,请重试
} }
} }
@ -236,9 +236,11 @@ class ProfileController extends GetxController {
if (response != null && response is Map<String, dynamic>) { if (response != null && response is Map<String, dynamic>) {
// 检查响应是否包含错误 // 检查响应是否包含错误
if (response.containsKey('error') || response.containsKey('msg')) { if (response.containsKey('error') || response.containsKey('msg')) {
final errorMsg = response['error'] ?? response['msg'] ?? '服务器返回错误'; final errorMsg = response['error'] ??
response['msg'] ??
'serverReturnedError'.tr; //服务器返回错误
Logger().e('服务器返回错误: $errorMsg'); Logger().e('服务器返回错误: $errorMsg');
throw Exception('服务器错误: $errorMsg'); throw Exception('${'serverError'.tr}: $errorMsg'); //服务器错误
} }
Logger().d('更新成功: $response'); Logger().d('更新成功: $response');
@ -252,7 +254,8 @@ class ProfileController extends GetxController {
}); });
// 如果服务器返回了新的头像URL,下载并保存到本地 // 如果服务器返回了新的头像URL,下载并保存到本地
if (response['avatar'] != null && response['avatar'].toString().isNotEmpty) { if (response['avatar'] != null &&
response['avatar'].toString().isNotEmpty) {
final serverAvatar = response['avatar'].toString(); final serverAvatar = response['avatar'].toString();
if (serverAvatar.startsWith('http')) { if (serverAvatar.startsWith('http')) {
// 异步下载新头像,不阻塞当前流程 // 异步下载新头像,不阻塞当前流程
@ -272,10 +275,12 @@ class ProfileController extends GetxController {
if (e.toString().contains('SocketException') || if (e.toString().contains('SocketException') ||
e.toString().contains('TimeoutException') || e.toString().contains('TimeoutException') ||
e.toString().contains('network')) { e.toString().contains('network')) {
throw Exception('network: 网络连接失败,请检查网络设置'); throw Exception(
'network: ${'networkConnectionFailedCheckSettings'.tr}'); //网络连接失败,请检查网络设置
} else if (e.toString().contains('500') || } else if (e.toString().contains('500') ||
e.toString().contains('server')) { e.toString().contains('server')) {
throw Exception('server: 服务器内部错误,请稍后重试'); throw Exception(
'server: ${'serverInternalErrorRetryLater'.tr}'); //服务器内部错误,请稍后重试
} else { } else {
throw Exception('unknown: ${e.toString()}'); throw Exception('unknown: ${e.toString()}');
} }
@ -350,7 +355,8 @@ class ProfileController extends GetxController {
_originalName = userInfo.value.name; _originalName = userInfo.value.name;
_originalAvatar = userInfo.value.avatar; _originalAvatar = userInfo.value.avatar;
_originalLocalAvatar = localAvatar.value; _originalLocalAvatar = localAvatar.value;
Logger().d('已保存原始状态 - 名称: $_originalName, 头像: $_originalAvatar, 本地头像: $_originalLocalAvatar'); Logger().d(
'已保存原始状态 - 名称: $_originalName, 头像: $_originalAvatar, 本地头像: $_originalLocalAvatar');
} }
// 回滚到原始状态 // 回滚到原始状态
@ -377,7 +383,8 @@ class ProfileController extends GetxController {
Logger().e('回滚状态同步到本地存储失败: $e'); Logger().e('回滚状态同步到本地存储失败: $e');
} }
Logger().d('已回滚到原始状态 - 名称: $_originalName, 头像: $_originalAvatar, 本地头像: $_originalLocalAvatar'); Logger().d(
'已回滚到原始状态 - 名称: $_originalName, 头像: $_originalAvatar, 本地头像: $_originalLocalAvatar');
} }
// 开始编辑昵称(内联编辑) // 开始编辑昵称(内联编辑)
@ -509,7 +516,7 @@ class ProfileController extends GetxController {
); );
if (compressedImage == null) { if (compressedImage == null) {
Get.snackbar('错误', '图片压缩失败'); Get.snackbar('error'.tr, 'imageCompressionFailed'.tr); //图片压缩失败
return; return;
} }
@ -535,10 +542,12 @@ class ProfileController extends GetxController {
} catch (e) { } catch (e) {
Logger().e('更新头像失败: $e'); Logger().e('更新头像失败: $e');
final errorMessage = _getErrorMessage(e); final errorMessage = _getErrorMessage(e);
Get.snackbar('头像更新失败', errorMessage, Get.snackbar(
'avatarUpdateFailed'.tr,
errorMessage,
duration: const Duration(seconds: 3), duration: const Duration(seconds: 3),
snackPosition: SnackPosition.TOP, snackPosition: SnackPosition.TOP,
); ); //头像更新失败
// 发生错误时回滚状态 // 发生错误时回滚状态
await _rollbackToOriginalState(); await _rollbackToOriginalState();
} }
@ -549,7 +558,7 @@ class ProfileController extends GetxController {
Future<void> updateUserNameAndAvatar(String name) async { Future<void> updateUserNameAndAvatar(String name) async {
if (name.trim().isEmpty) { if (name.trim().isEmpty) {
Logger().e('无效名称: $name'); Logger().e('无效名称: $name');
Get.snackbar('错误', '用户名不能为空'); Get.snackbar('error'.tr, 'usernameCannotBeEmpty'.tr); //用户名不能为空
return; return;
} }
@ -582,8 +591,8 @@ class ProfileController extends GetxController {
// 显示成功提示 // 显示成功提示
Get.snackbar( Get.snackbar(
'保存成功', 'saveSuccess'.tr,
'个人信息已更新', 'personalInfoUpdated'.tr,
duration: const Duration(seconds: 3), duration: const Duration(seconds: 3),
snackPosition: SnackPosition.TOP, snackPosition: SnackPosition.TOP,
backgroundColor: Colors.green.withOpacity(0.1), backgroundColor: Colors.green.withOpacity(0.1),
@ -596,7 +605,7 @@ class ProfileController extends GetxController {
borderRadius: 8, borderRadius: 8,
isDismissible: true, isDismissible: true,
forwardAnimationCurve: Curves.easeOutBack, forwardAnimationCurve: Curves.easeOutBack,
); ); //个人信息更新成功
Logger().d('成功提示已显示'); Logger().d('成功提示已显示');
@ -604,12 +613,12 @@ class ProfileController extends GetxController {
Future.delayed(const Duration(milliseconds: 100), () { Future.delayed(const Duration(milliseconds: 100), () {
if (Get.context != null) { if (Get.context != null) {
ScaffoldMessenger.of(Get.context!).showSnackBar( ScaffoldMessenger.of(Get.context!).showSnackBar(
const SnackBar( SnackBar(
content: Row( content: Row(
children: [ children: [
Icon(Icons.check_circle, color: Colors.white), Icon(Icons.check_circle, color: Colors.white),
SizedBox(width: 8), SizedBox(width: 8),
Text('个人信息已更新'), Text('personalInfoUpdated'.tr),
], ],
), ),
backgroundColor: Colors.green, backgroundColor: Colors.green,
@ -619,7 +628,6 @@ class ProfileController extends GetxController {
); );
} }
}); });
} catch (e) { } catch (e) {
Logger().e('更新用户名和头像错误: $e'); Logger().e('更新用户名和头像错误: $e');
@ -628,10 +636,12 @@ class ProfileController extends GetxController {
// 显示错误提示 // 显示错误提示
final errorMessage = _getErrorMessage(e); final errorMessage = _getErrorMessage(e);
Get.snackbar('保存失败', errorMessage, Get.snackbar(
'saveFailed'.tr,
errorMessage,
duration: const Duration(seconds: 4), duration: const Duration(seconds: 4),
snackPosition: SnackPosition.TOP, snackPosition: SnackPosition.TOP,
); ); //保存失败
} finally { } finally {
// 隐藏加载状态 // 隐藏加载状态
isUpdating.value = false; isUpdating.value = false;
@ -655,7 +665,7 @@ class ProfileController extends GetxController {
if (result.success) { if (result.success) {
// 先显示成功提示 // 先显示成功提示
Get.snackbar('成功', result.message ?? '已退出登录'); Get.snackbar('success'.tr, result.message ?? 'loggedOut'.tr); //已退出登录
Logger().d('退出登录成功'); Logger().d('退出登录成功');
// 然后导航到登录页面 // 然后导航到登录页面
@ -663,7 +673,8 @@ class ProfileController extends GetxController {
await Get.offAllNamed(Routes.login); await Get.offAllNamed(Routes.login);
} }
} else { } else {
Get.snackbar('错误', result.errorMessage ?? '退出登录失败,请重试'); Get.snackbar('error'.tr,
result.errorMessage ?? 'logoutFailedRetry'.tr); //退出登录失败,请重试
Logger().e('退出登录失败: ${result.errorMessage}'); Logger().e('退出登录失败: ${result.errorMessage}');
} }
} catch (e) { } catch (e) {
@ -671,7 +682,7 @@ class ProfileController extends GetxController {
if (Get.isDialogOpen ?? false) { if (Get.isDialogOpen ?? false) {
Get.back(); Get.back();
} }
Get.snackbar('错误', '退出登录失败,请重试'); Get.snackbar('error'.tr, 'logoutFailedRetry'.tr); //退出登录失败,请重试
Logger().e('退出登录错误: $e'); Logger().e('退出登录错误: $e');
} }
} }
@ -693,7 +704,8 @@ class ProfileController extends GetxController {
if (result.success) { if (result.success) {
// 先显示成功提示 // 先显示成功提示
Get.snackbar('成功', result.message ?? '账号已被永久删除'); Get.snackbar('success'.tr,
result.message ?? 'accountPermanentlyDeleted'.tr); //账号已被永久删除
Logger().d('账号删除成功'); Logger().d('账号删除成功');
// 然后导航到登录页面 // 然后导航到登录页面
@ -701,7 +713,8 @@ class ProfileController extends GetxController {
await Get.offAllNamed(Routes.login); await Get.offAllNamed(Routes.login);
} }
} else { } else {
Get.snackbar('错误', result.errorMessage ?? '删除账号失败,请重试'); Get.snackbar('error'.tr,
result.errorMessage ?? 'deleteAccountFailedRetry'.tr); //删除账号失败,请重试
Logger().e('删除账号失败: ${result.errorMessage}'); Logger().e('删除账号失败: ${result.errorMessage}');
} }
} catch (e) { } catch (e) {
@ -709,7 +722,7 @@ class ProfileController extends GetxController {
if (Get.isDialogOpen ?? false) { if (Get.isDialogOpen ?? false) {
Get.back(); Get.back();
} }
Get.snackbar('错误', '删除账号失败,请重试'); Get.snackbar('error'.tr, 'deleteAccountFailedRetry'.tr); //删除账号失败,请重试
Logger().e('删除账号失败: $e'); Logger().e('删除账号失败: $e');
} }
} }

Loading…
Cancel
Save