Browse Source

修改多语言

weicu
tanlongsheng 2 years ago
parent
commit
219905382d
  1. 98
      lib/core/translations/app_translations.dart
  2. 155
      lib/core/translations/language/en_us.dart
  3. 150
      lib/core/translations/language/zh_cn.dart
  4. 13
      lib/core/widgets/common_bottom_nav.dart
  5. 12
      lib/main.dart
  6. 127
      lib/modules/chat/views/chat_view.dart
  7. 44
      lib/modules/explore/controllers/explore_controller.dart
  8. 28
      lib/modules/explore/views/explore_view.dart
  9. 37
      lib/modules/home/controllers/home_controller.dart
  10. 378
      lib/modules/home/views/home_view.dart
  11. 277
      lib/modules/login/views/login_view.dart
  12. 50
      lib/modules/pairing/controllers/pairing_controller.dart
  13. 13
      lib/modules/pairing/views/pairing_view.dart
  14. 63
      lib/modules/settings/controllers/settings_controller.dart
  15. 11
      lib/modules/settings/models/language_model.dart
  16. 360
      lib/modules/settings/views/settings_view.dart
  17. 4
      lib/modules/splash/views/splash_view.dart
  18. 112
      lib/modules/translation/views/translation_view.dart
  19. 2
      pubspec.yaml

98
lib/core/translations/app_translations.dart

@ -1,81 +1,29 @@
import 'package:get/get.dart'; import 'dart:ui';
class AppTranslations extends Translations {
@override
Map<String, Map<String, String>> get keys => {
'zh_CN': {
// 通用
'app_name': 'i深音',
'confirm': '确认',
'cancel': '取消',
'retry': '重试',
'error': '错误',
'success': '成功',
// 主页 import 'package:get/get.dart';
'add_device': '添加设备', import 'package:get_storage/get_storage.dart';
'searching': '搜索中',
'searching_hint': '请将设备放在手机附近',
'connected': '已连接',
'device_ready': '设备已就绪',
'connection_failed': '连接失败',
'connection_failed_hint': '未找到设备。请确保蓝牙已开启且设备在5米范围内。尝试重启设备。',
'disconnect': '断开连接',
// 聊天页面
'clear_chat': '清空对话',
'thinking': '正在思考...',
'type_message': '发消息...',
'voice_enabled': '语音已开启',
'voice_disabled': '语音已关闭',
// 设置页面 import 'language/en_us.dart';
'settings': '设置', import 'language/zh_cn.dart';
'language_settings': '语言设置',
'about': '关于',
'check_update': '检查更新',
'clear_cache': '清除缓存',
'home': '首页',
'explore': '发现',
'profile': '我的',
'device': '设备',
},
'en_US': {
// General
'app_name': 'iDeep Voice',
'confirm': 'Confirm',
'cancel': 'Cancel',
'retry': 'Retry',
'error': 'Error',
'success': 'Success',
// Home class AppTranslations extends Translations {
'add_device': '+ Add Device', static const fallbackLocale = Locale('zh', 'CN');
'searching': 'Searching', static final supportedLocales = [
'searching_hint': 'Please place the device near your phone', const Locale('zh', 'CN'),
'connected': 'Connected!', const Locale('en', 'US'),
'device_ready': 'Your device is ready', ];
'connection_failed': 'Connection Failed',
'connection_failed_hint': 'Device not found. Please ensure Bluetooth is enabled and the device is within 5 meters. Try turning the device off and on again.',
'disconnect': 'Disconnect',
// Chat static Locale? deviceLocale() {
'clear_chat': 'Clear Chat', final GetStorage storage = GetStorage();
'thinking': 'Thinking...', Locale? locale = Get.deviceLocale;
'type_message': 'Type a message...', String? language = storage.read('language');
'voice_enabled': 'Voice Enabled', if (language != null && language != 'system') {
'voice_disabled': 'Voice Disabled', List languageList = language.split('_');
locale = Locale(languageList[0], languageList[1]);
}
return locale;
}
// Settings @override
'settings': 'Settings', Map<String, Map<String, String>> get keys => {'en_US': enUS, 'zh_CN': zhCN};
'language_settings': 'Language Settings',
'about': 'About',
'check_update': 'Check for Updates',
'clear_cache': 'Clear Cache',
'home': 'Home',
'explore': 'Explore',
'profile': 'Profile',
'device': 'Device',
},
};
} }

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

@ -0,0 +1,155 @@
const Map<String, String> enUS = {
// 通用
'continue': 'Continue',
'confirm': 'Confirm',
'cancel': 'Cancel',
'retry': 'Retry',
'error': 'Error',
'success': 'Success',
'connected': 'Connected',
'connecting': 'Connecting...',
'connectionFailure': 'Connection Failed',
'unconnected': 'Disconnected',
'search': 'Search',
// 启动页
"slogan": "Connect the World, Beyond Voice",
"sloganInfo": "AI Voice Expert · Anytime, Anywhere",
// 底部导航
"home": "Home",
"explore": "Explore",
"settings": "Settings",
// 语言
"followingSystem": "Following system",
"chinese": "Chinese",
"english": "English",
// 登录页
"welcome": "Welcome",
"loginTips": "Please log in or register with your phone number or email",
"accountNumber": "Phone number or email",
"verificationCode": "Verification Code",
"getCode": "Get Code",
"reacquireAfter": "s Get it again after",
"otherWays": "Or login with",
"expressConsent": "By logging in/registering, you agree to the",
"and": " and ",
"userAgreement": "User Agreement",
"privacyPolicy": "Privacy Policy",
// 首页
"deviceStatus": "Device Status",
"reconnect": "Reconnect",
"connectingDevice": "Connecting to device...",
"connectedTo": "Connected to",
"signal": "Signal",
"deviceId": "Device ID",
"firmwareVersion": "Firmware Version",
"disconnectedDevice": "No device connected, click the button below",
"connectDevice": "Connect Device",
"topAiExperiences": "Top AI Experiences",
"aiAssistant": "AI Assistant",
"aiAssistantInfo": "24/7 personal consultant for questions and advice",
"simultaneousInterpretation": "Real-time Interpretation",
"simultaneousInterpretationInfo": "Real-time translation for 80+ languages",
"aiCompanion": "AI Companion",
"aiCompanionInfo": "Understands you and provides warm companionship",
"homeSlogan": "Connect the World, Beyond Sound",
"turnEarphones":
"Please open the earphone case and put the earbuds in your ears",
"currentlyConnected": "Currently connected:",
"unsystemSetup": "Go to System Settings",
"talkLater": "Remind Later",
"initializing": "Initializing...",
"bluetoothInitializationFailure": "Bluetooth service initialization failed",
"checkingPermissions": "Checking permissions...",
"lackPermissions": "Bluetooth permissions required",
"searchingDevice": "Searching for devices...",
"findConnectedDevice": "Found connected device",
"notFound": "No connected Bluetooth devices found",
"initializationFailure": "Initialization failed",
"connectedDevice": "Connected to device:",
"failedRefreshDevice": "Failed to refresh device",
"noDeviceFound": "No connected devices found",
"failedDeviceInformation": "Failed to get device information",
"unknownEquipment": "Unknown Device",
"zeroSignal": "No Signal",
"good": "Good",
"fine": "Great",
"excellent": "Excellent",
"unknown": "Unknown",
// 发现页
"searchAi": "Search AI features...",
"exploreSlogan": "Smart Earbuds, Infinite Possibilities",
"exploreAi": "Explore AI features provided by DeepVoice",
"aiFunction": "AI Features",
"allRoundAssistant": "All-round Assistant",
"allRoundAssistantInfo": "Helps solve various problems",
"simultaneousTranslation": "Real-time Translation",
"simultaneousTranslationInfo": "Instant translation for 80+ languages",
"aiGirlfriend": "AI Girlfriend",
"aiGirlfriendInfo": "Real-time translation for 80+ languages",
"healthConsultant": "Health Consultant",
"healthConsultantInfo": "Provides scientific health advice",
"conferenceAssistant": "Business Meeting Assistant",
"conferenceAssistantInfo":
"Real-time minutes recording and multilingual translation",
"studyAssistant": "Language Learning Assistant",
"studyAssistantInfo": "Pronunciation correction and speaking practice",
"travelTranslator": "Travel Translator",
"travelTranslatorInfo": "Real-time voice translation and attraction guides",
"beSearching": "Searching for:",
"noAssistantFound": "No corresponding AI assistant found",
"scene": "Scenarios",
"youHaveSelected": "You've selected:",
"newFunction": "New Features",
"youChoseTry": "You've chosen to try",
"aiSinger": "AI Singer Mode",
"aiSingerInfo":
"Sing any song in your favorite artist's voice, even your own creations",
"popularFunction": "Popular Features",
"tryNow": "Try Now",
// 设置页
"premiumMember": "Premium Membership",
"joinDevice": "Connected device:",
"accountId": "Account ID:",
"systemSetting": "System Settings",
"languageSetting": "Language Settings",
"darkMode": "Dark Mode",
"darkModeInfo": "Switch between light/dark themes",
"backups": "Backup & Restore",
"backupsInfo": "Backup settings and AI history",
"lastBackup": "Last backup:",
"privacySettings": "Privacy Settings",
"privacySettingsInfo": "Manage data collection and permissions",
"logout": "Log Out",
"logoutTips": "Are you sure you want to log out of the current account?",
"aboutApplication": "About",
"versions": "Version",
"checkUpdates": "Check Updates",
"selectLanguage": "Select Language",
"voiceService": "Voice Service",
"voiceServiceInfo": "Select speech recognition and synthesis service",
"selectVoiceService": "Select Voice Service",
"azureVoiceService": "Azure Speech Service",
"azureVoiceServiceInfo":
"Microsoft cloud-based service supporting high-quality speech synthesis and recognition",
"flutterVoiceService": "Local voice service",
"flutterVoiceServiceInfo":
"Device-local voice service with no internet required",
// 聊天页
"clearChatHistory": "Clear Chat History",
"online": "Online",
"inputMessage": "Type a message...",
"imListening": "Listening...",
"canStartTalking": "You may start speaking",
// 翻译页
"selectSourceLanguage": "Select Source Language",
"selectTargetLanguage": "Select Target Language",
};

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

@ -0,0 +1,150 @@
const Map<String, String> zhCN = {
// 通用
'continue': '继续',
'confirm': '确认',
'cancel': '取消',
'retry': '重试',
'error': '错误',
'success': '成功',
'connected': '已连接',
'connecting': '连接中...',
'connectionFailure': '连接失败',
'unconnected': '未连接',
'search': '搜索',
// 启动页
"slogan": "连接世界,岂止声音",
"sloganInfo": "AI语音专家 · 随时随地",
// 底部导航
"home": "首页",
"explore": "发现",
"settings": "设置",
// 语言
"followingSystem": "跟随系统",
"chinese": "中文",
"english": "英语",
// 登录页
"welcome": "欢迎使用",
"loginTips": "请使用手机号或邮箱登录/注册",
"accountNumber": "手机号码或邮箱",
"verificationCode": "验证码",
"getCode": "获取验证码",
"reacquireAfter": "s后重新获取",
"otherWays": "或使用以下方式登录",
"expressConsent": "登录/注册即表示你同意",
"and": " 和 ",
"userAgreement": "《用户协议》",
"privacyPolicy": "《隐私政策》",
// 首页
"deviceStatus": "设备状态",
"reconnect": "重新连接",
"connectingDevice": "正在连接设备...",
"connectedTo": "已连接到",
"signal": "信号",
"deviceId": "设备ID",
"firmwareVersion": "固件版本",
"disconnectedDevice": "未连接设备,点击下方按钮连接",
"connectDevice": "连接设备",
"topAiExperiences": "热门AI体验",
"aiAssistant": "AI全能助手",
"aiAssistantInfo": "24小时专属顾问,解答问题、提供建议",
"simultaneousInterpretation": "同声传译",
"simultaneousInterpretationInfo": "80+语言实时翻译,出国无忧",
"aiCompanion": "AI伴侣",
"aiCompanionInfo": "懂你心意,温暖陪伴",
"homeSlogan": "连接世界,超越声音",
"turnEarphones": "请打开耳机充电盒,将耳机放入您的耳朵",
"currentlyConnected": "当前已连接:",
"unsystemSetup": "去系统设置",
"talkLater": "稍后再说",
"initializing": "正在初始化...",
"bluetoothInitializationFailure": "蓝牙服务初始化失败",
"checkingPermissions": "正在检查权限...",
"lackPermissions": "缺少蓝牙权限",
"searchingDevice": "正在搜索设备...",
"findConnectedDevice": "找到已连接的设备",
"notFound": "未找到已连接的蓝牙设备",
"initializationFailure": "初始化失败",
"connectedDevice": "已连接到设备:",
"failedRefreshDevice": "刷新设备失败",
"noDeviceFound": "未找到已连接的设备",
"failedDeviceInformation": "无法获取设备信息",
"unknownEquipment": "未知设备",
"zeroSignal": "无信号",
"good": "良好",
"fine": "很好",
"excellent": "极佳",
"unknown": "未知",
// 发现页
"searchAi": "搜索AI功能...",
"exploreSlogan": "智能耳机,无限可能",
"exploreAi": "探索DeepVoice提供的AI功能",
"aiFunction": "AI功能",
"allRoundAssistant": "全能助理",
"allRoundAssistantInfo": "帮你解决各类问题",
"simultaneousTranslation": "同声翻译",
"simultaneousTranslationInfo": "实时翻译80+种语言",
"aiGirlfriend": "AI女友",
"aiGirlfriendInfo": "实时翻译80+种语言",
"healthConsultant": "健康顾问",
"healthConsultantInfo": "提供科学健康建议",
"conferenceAssistant": "商务会议助手",
"conferenceAssistantInfo": "实时记录会议纪要,多语言翻译",
"studyAssistant": "语言学习助手",
"studyAssistantInfo": "发音纠正,实时练习口语",
"travelTranslator": "旅行翻译助手",
"travelTranslatorInfo": "实时语音翻译,旅游景点介绍",
"beSearching": "正在搜索:",
"noAssistantFound": "未找到对应的AI助手",
"scene": "场景",
"youHaveSelected": "您选择了:",
"newFunction": "新功能",
"youChoseTry": "您选择了尝试",
"aiSinger": "AI歌手模式",
"aiSingerInfo": "用你喜欢的歌手声音演唱任何歌曲,甚至是你自己创作的歌曲",
"popularFunction": "热门功能场景",
"tryNow": "立即尝试",
// 设置页
"premiumMember": "高级会员",
"joinDevice": "已连接设备:",
"accountId": "账号ID:",
"systemSetting": "系统设置",
"languageSetting": "语言设置",
"darkMode": "暗黑模式",
"darkModeInfo": "切换应用的明暗主题",
"backups": "备份与恢复",
"backupsInfo": "备份设置和AI互动历史",
"lastBackup": "上次备份:",
"privacySettings": "隐私设置",
"privacySettingsInfo": "管理数据收集和权限",
"logout": "退出登录",
"logoutTips": "确定要退出当前账号吗?",
"aboutApplication": "关于应用",
"versions": "版本",
"checkUpdates": "检查更新",
"selectLanguage": "选择语言",
"voiceService": "语音服务",
"voiceServiceInfo": "选择语音识别和合成服务",
"selectVoiceService": "选择语音服务",
"azureVoiceService": "Azure 语音服务",
"azureVoiceServiceInfo": "微软云端语音服务,支持高质量语音合成和识别",
"flutterVoiceService": "Flutter 本地语音服务",
"flutterVoiceServiceInfo": "设备本地语音服务,无需联网即可使用",
// 聊天页
"clearChatHistory": "清空聊天记录",
"online": "在线",
"inputMessage": "输入消息...",
"imListening": "正在聆听...",
"canStartTalking": "你可以开始说话",
// 翻译页
"selectSourceLanguage": "选择源语言",
"selectTargetLanguage": "选择目标语言",
};

13
lib/core/widgets/common_bottom_nav.dart

@ -30,23 +30,26 @@ class CommonBottomNav extends StatelessWidget {
break; break;
} }
}, },
backgroundColor: isDarkMode ? Colors.black : const Color(0xFFF9FAFB), // 暗黑模式黑色背景,浅色模式浅灰色背景 backgroundColor: isDarkMode
? Colors.black
: const Color(0xFFF9FAFB), // 暗黑模式黑色背景,浅色模式浅灰色背景
selectedItemColor: const Color(0xFF3B82F6), // 蓝色选中项保持不变 selectedItemColor: const Color(0xFF3B82F6), // 蓝色选中项保持不变
unselectedItemColor: isDarkMode ? Colors.grey[500] : const Color(0xFF6B7280), // 暗黑模式灰色调整 unselectedItemColor:
isDarkMode ? Colors.grey[500] : const Color(0xFF6B7280), // 暗黑模式灰色调整
elevation: isDarkMode ? 0 : 8, // 暗黑模式无阴影,浅色模式保持阴影 elevation: isDarkMode ? 0 : 8, // 暗黑模式无阴影,浅色模式保持阴影
type: BottomNavigationBarType.fixed, type: BottomNavigationBarType.fixed,
items: [ items: [
BottomNavigationBarItem( BottomNavigationBarItem(
icon: const Icon(Icons.home), icon: const Icon(Icons.home),
label: 'home'.tr, label: 'home'.tr, // 首页
), ),
BottomNavigationBarItem( BottomNavigationBarItem(
icon: const Icon(Icons.explore), icon: const Icon(Icons.explore),
label: 'explore'.tr, label: 'explore'.tr, // 发现
), ),
BottomNavigationBarItem( BottomNavigationBarItem(
icon: const Icon(Icons.settings), icon: const Icon(Icons.settings),
label: 'settings'.tr, label: 'settings'.tr, // 设置
), ),
], ],
); );

12
lib/main.dart

@ -1,4 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:get_storage/get_storage.dart'; import 'package:get_storage/get_storage.dart';
@ -71,9 +72,14 @@ class MainApp extends StatelessWidget {
getPages: AppPages.pages, getPages: AppPages.pages,
debugShowCheckedModeBanner: false, debugShowCheckedModeBanner: false,
translations: AppTranslations(), translations: AppTranslations(),
locale: const Locale('zh', 'CN'), localizationsDelegates: const [
fallbackLocale: const Locale('en', 'US'), GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
locale: AppTranslations.deviceLocale(),
fallbackLocale: AppTranslations.fallbackLocale,
supportedLocales: AppTranslations.supportedLocales,
); );
}, },
); );

127
lib/modules/chat/views/chat_view.dart

@ -28,11 +28,8 @@ class ChatView extends GetView<ChatController> {
elevation: 1, elevation: 1,
backgroundColor: isDarkMode ? AppColors.cardBackground : Colors.white, backgroundColor: isDarkMode ? AppColors.cardBackground : Colors.white,
leading: IconButton( leading: IconButton(
icon: Icon( icon: Icon(Icons.arrow_back_ios,
Icons.arrow_back_ios, color: isDarkMode ? Colors.white : Colors.black87, size: 20.r),
color: isDarkMode ? Colors.white : Colors.black87,
size: 20.r
),
onPressed: () => Get.back(), onPressed: () => Get.back(),
), ),
titleSpacing: 0, titleSpacing: 0,
@ -101,7 +98,7 @@ class ChatView extends GetView<ChatController> {
), ),
SizedBox(width: 4.w), SizedBox(width: 4.w),
Text( Text(
'在线', 'online'.tr, // 在线
style: TextStyle( style: TextStyle(
fontSize: 12.sp, fontSize: 12.sp,
color: Colors.green, color: Colors.green,
@ -123,7 +120,9 @@ class ChatView extends GetView<ChatController> {
: Icons.volume_off, : Icons.volume_off,
color: controller.isTtsEnabled.value color: controller.isTtsEnabled.value
? AppColors.primary ? AppColors.primary
: isDarkMode ? Colors.grey[400] : Colors.grey, : isDarkMode
? Colors.grey[400]
: Colors.grey,
), ),
onPressed: controller.toggleTts, onPressed: controller.toggleTts,
)), )),
@ -133,7 +132,8 @@ class ChatView extends GetView<ChatController> {
height: 34.r, height: 34.r,
margin: EdgeInsets.only(right: 8.w), margin: EdgeInsets.only(right: 8.w),
decoration: BoxDecoration( decoration: BoxDecoration(
color: isDarkMode ? Colors.white.withOpacity(0.1) : Colors.grey[100], color:
isDarkMode ? Colors.white.withOpacity(0.1) : Colors.grey[100],
shape: BoxShape.circle, shape: BoxShape.circle,
boxShadow: [ boxShadow: [
if (!isDarkMode) if (!isDarkMode)
@ -145,11 +145,8 @@ class ChatView extends GetView<ChatController> {
], ],
), ),
child: PopupMenuButton( child: PopupMenuButton(
icon: Icon( icon: Icon(Icons.more_vert,
Icons.more_vert, color: isDarkMode ? Colors.white : Colors.black87, size: 20.r),
color: isDarkMode ? Colors.white : Colors.black87,
size: 20.r
),
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12.r), borderRadius: BorderRadius.circular(12.r),
), ),
@ -162,7 +159,7 @@ class ChatView extends GetView<ChatController> {
Icon(Icons.delete_outline, color: Colors.red), Icon(Icons.delete_outline, color: Colors.red),
SizedBox(width: 8.w), SizedBox(width: 8.w),
Text( Text(
'清空聊天记录', 'clearChatHistory'.tr, // 清空聊天记录
style: TextStyle( style: TextStyle(
color: isDarkMode ? Colors.white : Colors.black87, color: isDarkMode ? Colors.white : Colors.black87,
), ),
@ -215,13 +212,15 @@ class ChatView extends GetView<ChatController> {
width: 80.w, width: 80.w,
height: 80.w, height: 80.w,
decoration: BoxDecoration( decoration: BoxDecoration(
color: isDarkMode ? Colors.white.withOpacity(0.1) : Colors.grey[100], color:
isDarkMode ? Colors.white.withOpacity(0.1) : Colors.grey[100],
shape: BoxShape.circle, shape: BoxShape.circle,
), ),
child: Icon( child: Icon(
Icons.chat_bubble_outline, Icons.chat_bubble_outline,
size: 40.w, size: 40.w,
color: isDarkMode ? Colors.white.withOpacity(0.5) : Colors.grey[400], color:
isDarkMode ? Colors.white.withOpacity(0.5) : Colors.grey[400],
), ),
), ),
SizedBox(height: 24.h), SizedBox(height: 24.h),
@ -274,16 +273,16 @@ class ChatView extends GetView<ChatController> {
return Padding( return Padding(
padding: EdgeInsets.only(bottom: 16.h), padding: EdgeInsets.only(bottom: 16.h),
child: Row( child: Row(
mainAxisAlignment: isUser ? MainAxisAlignment.end : MainAxisAlignment.start, mainAxisAlignment:
isUser ? MainAxisAlignment.end : MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
if (!isUser) _buildAvatar(false, isDarkMode), if (!isUser) _buildAvatar(false, isDarkMode),
SizedBox(width: 8.w), SizedBox(width: 8.w),
Flexible( Flexible(
child: Column( child: Column(
crossAxisAlignment: isUser ? CrossAxisAlignment.end : CrossAxisAlignment.start, crossAxisAlignment:
isUser ? CrossAxisAlignment.end : CrossAxisAlignment.start,
children: [ children: [
// 消息气泡 // 消息气泡
Container( Container(
@ -291,7 +290,9 @@ class ChatView extends GetView<ChatController> {
decoration: BoxDecoration( decoration: BoxDecoration(
color: isUser color: isUser
? AppColors.primary ? AppColors.primary
: isDarkMode ? AppColors.cardBackground : Colors.grey[200], : isDarkMode
? AppColors.cardBackground
: Colors.grey[200],
borderRadius: BorderRadius.circular(16.r), borderRadius: BorderRadius.circular(16.r),
), ),
child: Column( child: Column(
@ -304,7 +305,9 @@ class ChatView extends GetView<ChatController> {
style: TextStyle( style: TextStyle(
color: isUser color: isUser
? Colors.white ? Colors.white
: isDarkMode ? Colors.white : Colors.black, : isDarkMode
? Colors.white
: Colors.black,
fontSize: 16.sp, fontSize: 16.sp,
height: 1.5, height: 1.5,
), ),
@ -340,9 +343,7 @@ class ChatView extends GetView<ChatController> {
], ],
), ),
), ),
SizedBox(width: 8.w), SizedBox(width: 8.w),
if (isUser) _buildAvatar(true, isDarkMode), if (isUser) _buildAvatar(true, isDarkMode),
], ],
), ),
@ -351,7 +352,8 @@ class ChatView extends GetView<ChatController> {
// 构建输入区域 // 构建输入区域
Widget _buildInputArea(bool isDarkMode) { Widget _buildInputArea(bool isDarkMode) {
final textController = TextEditingController(text: controller.inputText.value); final textController =
TextEditingController(text: controller.inputText.value);
// 检查是否处于语音识别模式 // 检查是否处于语音识别模式
return Obx(() { return Obx(() {
@ -364,7 +366,8 @@ class ChatView extends GetView<ChatController> {
} }
// 构建文本输入面板 // 构建文本输入面板
Widget _buildTextInputPanel(bool isDarkMode, TextEditingController textController) { Widget _buildTextInputPanel(
bool isDarkMode, TextEditingController textController) {
return Container( return Container(
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 8.h), padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 8.h),
decoration: BoxDecoration( decoration: BoxDecoration(
@ -385,7 +388,9 @@ class ChatView extends GetView<ChatController> {
width: 40.w, width: 40.w,
height: 40.w, height: 40.w,
decoration: BoxDecoration( decoration: BoxDecoration(
color: isDarkMode ? Colors.white.withOpacity(0.1) : Colors.grey[100], color: isDarkMode
? Colors.white.withOpacity(0.1)
: Colors.grey[100],
shape: BoxShape.circle, shape: BoxShape.circle,
), ),
child: IconButton( child: IconButton(
@ -406,12 +411,13 @@ class ChatView extends GetView<ChatController> {
child: TextField( child: TextField(
controller: textController, controller: textController,
decoration: InputDecoration( decoration: InputDecoration(
hintText: '输入消息...', hintText: 'inputMessage'.tr, // 输入消息...
hintStyle: TextStyle( hintStyle: TextStyle(
color: isDarkMode ? Colors.grey[500] : Colors.grey[500] color: isDarkMode ? Colors.grey[500] : Colors.grey[500]),
),
filled: true, filled: true,
fillColor: isDarkMode ? Colors.white.withOpacity(0.1) : Colors.grey[100], fillColor: isDarkMode
? Colors.white.withOpacity(0.1)
: Colors.grey[100],
border: OutlineInputBorder( border: OutlineInputBorder(
borderRadius: BorderRadius.circular(20.r), borderRadius: BorderRadius.circular(20.r),
borderSide: BorderSide.none, borderSide: BorderSide.none,
@ -447,7 +453,9 @@ class ChatView extends GetView<ChatController> {
decoration: BoxDecoration( decoration: BoxDecoration(
color: hasText color: hasText
? AppColors.primary ? AppColors.primary
: isDarkMode ? Colors.white.withOpacity(0.1) : Colors.grey[200], : isDarkMode
? Colors.white.withOpacity(0.1)
: Colors.grey[200],
shape: BoxShape.circle, shape: BoxShape.circle,
), ),
child: IconButton( child: IconButton(
@ -455,7 +463,9 @@ class ChatView extends GetView<ChatController> {
Icons.send, Icons.send,
color: hasText color: hasText
? Colors.white ? Colors.white
: isDarkMode ? Colors.white.withOpacity(0.5) : Colors.grey[400], : isDarkMode
? Colors.white.withOpacity(0.5)
: Colors.grey[400],
size: 18.r, size: 18.r,
), ),
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
@ -501,7 +511,9 @@ class ChatView extends GetView<ChatController> {
width: 60.r, width: 60.r,
height: 60.r, height: 60.r,
decoration: BoxDecoration( decoration: BoxDecoration(
color: isDarkMode ? Colors.white.withOpacity(0.1) : Colors.white, color: isDarkMode
? Colors.white.withOpacity(0.1)
: Colors.white,
shape: BoxShape.circle, shape: BoxShape.circle,
boxShadow: [ boxShadow: [
BoxShadow( BoxShadow(
@ -513,10 +525,14 @@ class ChatView extends GetView<ChatController> {
), ),
child: Center( child: Center(
child: Obx(() => Icon( child: Obx(() => Icon(
controller.isListening.value ? Icons.mic : Icons.mic_none, controller.isListening.value
color: controller.isListening.value ? AppColors.primary : Colors.grey.shade400, ? Icons.mic
size: 28.r, : Icons.mic_none,
)), color: controller.isListening.value
? AppColors.primary
: Colors.grey.shade400,
size: 28.r,
)),
), ),
), ),
@ -553,12 +569,16 @@ class ChatView extends GetView<ChatController> {
duration: Duration(milliseconds: 500), duration: Duration(milliseconds: 500),
width: 2.5.w, width: 2.5.w,
height: height, height: height,
margin: EdgeInsets.symmetric(horizontal: 1.5.w), margin: EdgeInsets.symmetric(
horizontal: 1.5.w),
decoration: BoxDecoration( decoration: BoxDecoration(
color: isSpeaking color: isSpeaking
? AppColors.primary ? AppColors.primary
: isDarkMode ? Colors.grey.shade600 : Colors.grey.shade400, : isDarkMode
borderRadius: BorderRadius.circular(2.r), ? Colors.grey.shade600
: Colors.grey.shade400,
borderRadius:
BorderRadius.circular(2.r),
), ),
), ),
), ),
@ -574,13 +594,17 @@ class ChatView extends GetView<ChatController> {
// 语音状态文本 // 语音状态文本
Obx(() => Text( Obx(() => Text(
controller.isSpeechDetected.value ? '正在聆听...' : '你可以开始说话', controller.isSpeechDetected.value
style: TextStyle( ? 'imListening'.tr // 正在聆听...
fontSize: 14.sp, : 'canStartTalking'.tr, // 你可以开始说话
color: isDarkMode ? Colors.grey[400] : Colors.grey[700], style: TextStyle(
fontWeight: FontWeight.w500, fontSize: 14.sp,
), color: isDarkMode
)), ? Colors.grey[400]
: Colors.grey[700],
fontWeight: FontWeight.w500,
),
)),
], ],
), ),
), ),
@ -590,7 +614,9 @@ class ChatView extends GetView<ChatController> {
width: 60.r, width: 60.r,
height: 60.r, height: 60.r,
decoration: BoxDecoration( decoration: BoxDecoration(
color: isDarkMode ? Colors.white.withOpacity(0.1) : Colors.white, color: isDarkMode
? Colors.white.withOpacity(0.1)
: Colors.white,
shape: BoxShape.circle, shape: BoxShape.circle,
boxShadow: [ boxShadow: [
BoxShadow( BoxShadow(
@ -679,7 +705,8 @@ class ChatView extends GetView<ChatController> {
width: 8.r, width: 8.r,
height: 8.r, height: 8.r,
decoration: BoxDecoration( decoration: BoxDecoration(
color: isDarkMode ? Colors.white.withOpacity(0.5) : Colors.grey[400], color:
isDarkMode ? Colors.white.withOpacity(0.5) : Colors.grey[400],
shape: BoxShape.circle, shape: BoxShape.circle,
), ),
); );

44
lib/modules/explore/controllers/explore_controller.dart

@ -52,8 +52,8 @@ class ExploreController extends GetxController {
// AI功能列表 // AI功能列表
final List<AIFeature> aiFeatures = [ final List<AIFeature> aiFeatures = [
AIFeature( AIFeature(
title: '全能助理', title: 'allRoundAssistant'.tr, // 全能助理
description: '帮你解决各类问题', description: 'allRoundAssistantInfo'.tr, // 帮你解决各类问题
icon: Icons.assistant, icon: Icons.assistant,
startColor: const Color(0xFF0066CC), startColor: const Color(0xFF0066CC),
endColor: const Color(0xFF5E5CE6), endColor: const Color(0xFF5E5CE6),
@ -63,8 +63,8 @@ class ExploreController extends GetxController {
targetRoute: Routes.chat, targetRoute: Routes.chat,
), ),
AIFeature( AIFeature(
title: '同声翻译', title: 'simultaneousTranslation'.tr, // 同声翻译
description: '实时翻译80+种语言', description: 'simultaneousTranslationInfo.tr', // 实时翻译80+种语言
icon: Icons.translate, icon: Icons.translate,
startColor: const Color(0xFF4CAF50), startColor: const Color(0xFF4CAF50),
endColor: const Color(0xFF009688), endColor: const Color(0xFF009688),
@ -74,8 +74,8 @@ class ExploreController extends GetxController {
targetRoute: Routes.translation, targetRoute: Routes.translation,
), ),
AIFeature( AIFeature(
title: 'AI女友', title: 'aiGirlfriend'.tr, // AI女友
description: '智能陪伴,随时聊天', description: 'aiGirlfriendInfo'.tr, // 智能陪伴,随时聊天
icon: Icons.favorite, icon: Icons.favorite,
startColor: const Color(0xFFE91E63), startColor: const Color(0xFFE91E63),
endColor: const Color(0xFFFF5252), endColor: const Color(0xFFFF5252),
@ -85,8 +85,8 @@ class ExploreController extends GetxController {
targetRoute: Routes.chat, targetRoute: Routes.chat,
), ),
AIFeature( AIFeature(
title: '健康顾问', title: 'healthConsultant'.tr, // 健康顾问
description: '提供科学健康建议', description: 'healthConsultantInfo'.tr, // 提供科学健康建议
icon: Icons.healing, icon: Icons.healing,
startColor: const Color(0xFFFFC107), startColor: const Color(0xFFFFC107),
endColor: const Color(0xFFFF9800), endColor: const Color(0xFFFF9800),
@ -100,24 +100,24 @@ class ExploreController extends GetxController {
// 热门功能场景列表 // 热门功能场景列表
final List<FunctionScene> functionScenes = [ final List<FunctionScene> functionScenes = [
FunctionScene( FunctionScene(
title: '商务会议助手', title: 'conferenceAssistant'.tr, // 商务会议助手
description: '实时记录会议纪要,多语言翻译', description: 'conferenceAssistantInfo'.tr, // 实时记录会议纪要,多语言翻译
icon: Icons.people, icon: Icons.people,
startColor: const Color(0xFF3F51B5), startColor: const Color(0xFF3F51B5),
endColor: const Color(0xFF673AB7), endColor: const Color(0xFF673AB7),
iconColor: const Color(0xFF3F51B5), iconColor: const Color(0xFF3F51B5),
), ),
FunctionScene( FunctionScene(
title: '语言学习助手', title: 'studyAssistant'.tr, // 语言学习助手
description: '发音纠正,实时练习口语', description: 'studyAssistantInfo'.tr, // 发音纠正,实时练习口语
icon: Icons.school, icon: Icons.school,
startColor: const Color(0xFF4CAF50), startColor: const Color(0xFF4CAF50),
endColor: const Color(0xFF009688), endColor: const Color(0xFF009688),
iconColor: const Color(0xFF4CAF50), iconColor: const Color(0xFF4CAF50),
), ),
FunctionScene( FunctionScene(
title: '旅行翻译助手', title: 'travelTranslator'.tr, // 旅行翻译助手
description: '实时语音翻译,旅游景点介绍', description: 'travelTranslatorInfo'.tr, // 实时语音翻译,旅游景点介绍
icon: Icons.language, icon: Icons.language,
startColor: const Color(0xFFFFC107), startColor: const Color(0xFFFFC107),
endColor: const Color(0xFFFF9800), endColor: const Color(0xFFFF9800),
@ -130,8 +130,8 @@ class ExploreController extends GetxController {
if (searchController.text.isEmpty) return; if (searchController.text.isEmpty) return;
Get.snackbar( Get.snackbar(
'搜索', 'search'.tr, // 搜索
'正在搜索: ${searchController.text}', '${'beSearching'.tr} ${searchController.text}', // 正在搜索:
snackPosition: SnackPosition.TOP, snackPosition: SnackPosition.TOP,
); );
@ -148,8 +148,8 @@ class ExploreController extends GetxController {
if (agent == null) { if (agent == null) {
Get.snackbar( Get.snackbar(
'错误', 'error'.tr, // 错误
'未找到对应的AI助手', 'noAssistantFound'.tr, // 未找到对应的AI助手
snackPosition: SnackPosition.TOP, snackPosition: SnackPosition.TOP,
); );
return; return;
@ -178,8 +178,8 @@ class ExploreController extends GetxController {
if (index < 0 || index >= functionScenes.length) return; if (index < 0 || index >= functionScenes.length) return;
Get.snackbar( Get.snackbar(
'场景', 'scene'.tr, // 场景
'您选择了: ${functionScenes[index].title}', '${'youHaveSelected'.tr} ${functionScenes[index].title}', // 您选择了:
snackPosition: SnackPosition.TOP, snackPosition: SnackPosition.TOP,
); );
@ -189,8 +189,8 @@ class ExploreController extends GetxController {
// 尝试新功能 // 尝试新功能
void tryNewFeature() { void tryNewFeature() {
Get.snackbar( Get.snackbar(
'新功能', 'newFunction'.tr, // 新功能
'您选择了尝试AI歌手模式', '${'youChoseTry'.tr}${'aiSinger'.tr}', // 您选择了尝试 // AI歌手模式
snackPosition: SnackPosition.TOP, snackPosition: SnackPosition.TOP,
); );

28
lib/modules/explore/views/explore_view.dart

@ -66,7 +66,7 @@ class ExploreView extends GetView<ExploreController> {
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text( Text(
'发现', 'explore'.tr, // 发现
style: TextStyle( style: TextStyle(
fontSize: 24.sp, fontSize: 24.sp,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
@ -77,7 +77,9 @@ class ExploreView extends GetView<ExploreController> {
width: 32.w, width: 32.w,
height: 32.w, height: 32.w,
decoration: BoxDecoration( decoration: BoxDecoration(
color: isDarkMode ? Colors.white.withOpacity(0.1) : Colors.grey[200], color: isDarkMode
? Colors.white.withOpacity(0.1)
: Colors.grey[200],
shape: BoxShape.circle, shape: BoxShape.circle,
), ),
child: IconButton( child: IconButton(
@ -97,13 +99,14 @@ class ExploreView extends GetView<ExploreController> {
SizedBox(height: 16.h), SizedBox(height: 16.h),
Container( Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: isDarkMode ? Colors.white.withOpacity(0.1) : Colors.grey[100], color:
isDarkMode ? Colors.white.withOpacity(0.1) : Colors.grey[100],
borderRadius: BorderRadius.circular(12.r), borderRadius: BorderRadius.circular(12.r),
), ),
child: TextField( child: TextField(
controller: controller.searchController, controller: controller.searchController,
decoration: InputDecoration( decoration: InputDecoration(
hintText: '搜索AI功能...', hintText: 'searchAi'.tr, // 搜索AI功能...
hintStyle: TextStyle( hintStyle: TextStyle(
fontSize: 14.sp, fontSize: 14.sp,
color: isDarkMode ? Colors.grey[400] : Colors.grey[400], color: isDarkMode ? Colors.grey[400] : Colors.grey[400],
@ -193,7 +196,7 @@ class ExploreView extends GetView<ExploreController> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
'智能耳机,无限可能', 'exploreSlogan'.tr, // 智能耳机,无限可能
style: TextStyle( style: TextStyle(
fontSize: 22.sp, fontSize: 22.sp,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
@ -202,7 +205,7 @@ class ExploreView extends GetView<ExploreController> {
), ),
SizedBox(height: 4.h), SizedBox(height: 4.h),
Text( Text(
'探索DeepVoice提供的AI功能', 'exploreAi'.tr, // 探索DeepVoice提供的AI功能
style: TextStyle( style: TextStyle(
fontSize: 14.sp, fontSize: 14.sp,
color: Colors.white.withOpacity(0.8), color: Colors.white.withOpacity(0.8),
@ -222,7 +225,7 @@ class ExploreView extends GetView<ExploreController> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
'AI功能', 'aiFunction'.tr, // AI功能
style: TextStyle( style: TextStyle(
fontSize: 18.sp, fontSize: 18.sp,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
@ -338,7 +341,7 @@ class ExploreView extends GetView<ExploreController> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
'热门功能场景', 'popularFunction'.tr, // 热门功能场景
style: TextStyle( style: TextStyle(
fontSize: 18.sp, fontSize: 18.sp,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
@ -363,7 +366,8 @@ class ExploreView extends GetView<ExploreController> {
} }
// 功能场景项 // 功能场景项
Widget _buildFunctionSceneItem(FunctionScene scene, int index, bool isDarkMode) { Widget _buildFunctionSceneItem(
FunctionScene scene, int index, bool isDarkMode) {
return GestureDetector( return GestureDetector(
onTap: () => controller.onFunctionSceneTap(index), onTap: () => controller.onFunctionSceneTap(index),
child: Container( child: Container(
@ -481,7 +485,7 @@ class ExploreView extends GetView<ExploreController> {
// 标题 // 标题
Text( Text(
'AI歌手模式', 'aiSinger'.tr, // AI歌手模式
style: TextStyle( style: TextStyle(
fontSize: 20.sp, fontSize: 20.sp,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
@ -492,7 +496,7 @@ class ExploreView extends GetView<ExploreController> {
// 描述 // 描述
Text( Text(
'用你喜欢的歌手声音演唱任何歌曲,甚至是你自己创作的歌曲', 'aiSingerInfo'.tr, // 用你喜欢的歌手声音演唱任何歌曲,甚至是你自己创作的歌曲
style: TextStyle( style: TextStyle(
fontSize: 14.sp, fontSize: 14.sp,
color: isDarkMode ? Colors.grey[300] : Colors.grey[600], color: isDarkMode ? Colors.grey[300] : Colors.grey[600],
@ -514,7 +518,7 @@ class ExploreView extends GetView<ExploreController> {
), ),
), ),
child: Text( child: Text(
'立即尝试', 'tryNow'.tr, // 立即尝试
style: TextStyle( style: TextStyle(
fontSize: 14.sp, fontSize: 14.sp,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,

37
lib/modules/home/controllers/home_controller.dart

@ -6,12 +6,13 @@ import 'package:flutter_blue_plus/flutter_blue_plus.dart' hide BluetoothDevice;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../../../data/services/voice_interaction_service.dart'; import '../../../data/services/voice_interaction_service.dart';
import 'package:permission_handler/permission_handler.dart'; import 'package:permission_handler/permission_handler.dart';
// 连接状态枚举 // 连接状态枚举
enum ConnectionStatus { enum ConnectionStatus {
disconnected, // 未连接 disconnected, // 未连接
connecting, // 连接中 connecting, // 连接中
connected, // 已连接 connected, // 已连接
failed // 连接失败 failed // 连接失败
} }
class HomeController extends GetxController { class HomeController extends GetxController {
@ -45,7 +46,8 @@ class HomeController extends GetxController {
// 当前连接的经典蓝牙设备 // 当前连接的经典蓝牙设备
final _connectedClassicDevices = <classic.BluetoothDevice>[].obs; final _connectedClassicDevices = <classic.BluetoothDevice>[].obs;
List<classic.BluetoothDevice> get connectedClassicDevices => _connectedClassicDevices; List<classic.BluetoothDevice> get connectedClassicDevices =>
_connectedClassicDevices;
@override @override
void onInit() { void onInit() {
@ -69,7 +71,6 @@ class HomeController extends GetxController {
// 监听蓝牙连接状态变化 // 监听蓝牙连接状态变化
_setupBluetoothListeners(); _setupBluetoothListeners();
} catch (e) { } catch (e) {
Logger.error('初始化蓝牙服务失败: $e'); Logger.error('初始化蓝牙服务失败: $e');
_connectionStatus.value = ConnectionStatus.failed; _connectionStatus.value = ConnectionStatus.failed;
@ -158,7 +159,7 @@ class HomeController extends GetxController {
Logger.info('刷新设备:未找到设备'); Logger.info('刷新设备:未找到设备');
// 这里可以设置状态变量而不是使用snackbar // 这里可以设置状态变量而不是使用snackbar
_connectionErrorMsg.value = _bluetoothService.errorMessage.value.isEmpty _connectionErrorMsg.value = _bluetoothService.errorMessage.value.isEmpty
? '未找到已连接的设备' ? 'noDeviceFound'.tr // 未找到已连接的设备
: _bluetoothService.errorMessage.value; : _bluetoothService.errorMessage.value;
} else { } else {
_connectionErrorMsg.value = ''; _connectionErrorMsg.value = '';
@ -167,7 +168,7 @@ class HomeController extends GetxController {
} catch (e) { } catch (e) {
Logger.error('刷新设备信息失败: $e'); Logger.error('刷新设备信息失败: $e');
_connectionStatus.value = ConnectionStatus.failed; _connectionStatus.value = ConnectionStatus.failed;
_connectionErrorMsg.value = '无法获取设备信息'; _connectionErrorMsg.value = 'failedDeviceInformation'.tr; // 无法获取设备信息
update(); update();
} }
} }
@ -212,44 +213,44 @@ class HomeController extends GetxController {
String getConnectionStatusText() { String getConnectionStatusText() {
switch (_connectionStatus.value) { switch (_connectionStatus.value) {
case ConnectionStatus.connected: case ConnectionStatus.connected:
return '已连接'; return 'connected'.tr; // 已连接
case ConnectionStatus.connecting: case ConnectionStatus.connecting:
return '连接中...'; return 'connecting'.tr; // 连接中...
case ConnectionStatus.failed: case ConnectionStatus.failed:
return '连接失败'; return 'connectionFailure'.tr; // 连接失败
case ConnectionStatus.disconnected: case ConnectionStatus.disconnected:
default: default:
return '未连接'; return 'unconnected'.tr; // 未连接
} }
} }
// 获取设备名称 // 获取设备名称
String getDeviceName() { String getDeviceName() {
final device = _bluetoothService.currentDevice.value; final device = _bluetoothService.currentDevice.value;
return device?.name ?? '未知设备'; return device?.name ?? 'unknownEquipment'.tr; // 未知设备
} }
// 获取信号强度(模拟数据) // 获取信号强度(模拟数据)
String getSignalStrength() { String getSignalStrength() {
if (!_isConnected.value) { if (!_isConnected.value) {
return '无信号'; return 'zeroSignal'.tr; // 无信号
} }
// 简单模拟信号强度 // 简单模拟信号强度
final random = DateTime.now().millisecondsSinceEpoch % 3; final random = DateTime.now().millisecondsSinceEpoch % 3;
switch (random) { switch (random) {
case 0: case 0:
return '良好'; return 'good'.tr; // 良好
case 1: case 1:
return '很好'; return 'fine'.tr; // 很好
default: default:
return '极佳'; return 'excellent'.tr; // 极佳
} }
} }
// 获取设备ID // 获取设备ID
String getDeviceId() { String getDeviceId() {
final device = _bluetoothService.currentDevice.value; final device = _bluetoothService.currentDevice.value;
return device?.address ?? '未知'; return device?.address ?? 'unknown'.tr; // 未知
} }
} }

378
lib/modules/home/views/home_view.dart

@ -16,7 +16,8 @@ class AnimatedPulsing extends StatefulWidget {
_AnimatedPulsingState createState() => _AnimatedPulsingState(); _AnimatedPulsingState createState() => _AnimatedPulsingState();
} }
class _AnimatedPulsingState extends State<AnimatedPulsing> with SingleTickerProviderStateMixin { class _AnimatedPulsingState extends State<AnimatedPulsing>
with SingleTickerProviderStateMixin {
late AnimationController _controller; late AnimationController _controller;
late Animation<double> _animation; late Animation<double> _animation;
@ -111,43 +112,41 @@ class HomeView extends GetView<HomeController> {
// 顶部标题栏 // 顶部标题栏
Widget _buildAppBar(bool isDarkMode) { Widget _buildAppBar(bool isDarkMode) {
return Row( return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text( Text(
'DeepVoice', 'DeepVoice',
style: TextStyle( style: TextStyle(
fontSize: 20.sp, fontSize: 20.sp,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: isDarkMode ? Colors.white : Colors.grey[800], color: isDarkMode ? Colors.white : Colors.grey[800],
), ),
), ),
Container( Container(
width: 32.w, width: 32.w,
height: 32.w, height: 32.w,
decoration: BoxDecoration( decoration: BoxDecoration(
color: isDarkMode ? Colors.grey[800] : Colors.grey[200], color: isDarkMode ? Colors.grey[800] : Colors.grey[200],
shape: BoxShape.circle, shape: BoxShape.circle,
boxShadow: [ boxShadow: [
BoxShadow( BoxShadow(
color: Colors.grey.withOpacity(0.2), color: Colors.grey.withOpacity(0.2),
blurRadius: 4, blurRadius: 4,
offset: const Offset(0, 2), offset: const Offset(0, 2),
),
],
),
child: IconButton(
icon: Icon(
Icons.settings_outlined,
size: 16.sp,
color: isDarkMode ? Colors.white70 : Colors.grey[600]
),
padding: EdgeInsets.zero,
onPressed: () {
Get.toNamed(Routes.settings);
},
),
), ),
], ],
),
child: IconButton(
icon: Icon(Icons.settings_outlined,
size: 16.sp,
color: isDarkMode ? Colors.white70 : Colors.grey[600]),
padding: EdgeInsets.zero,
onPressed: () {
Get.toNamed(Routes.settings);
},
),
),
],
); );
} }
@ -158,7 +157,9 @@ class HomeView extends GetView<HomeController> {
height: 220.h, height: 220.h,
alignment: Alignment.center, alignment: Alignment.center,
child: Image.asset( child: Image.asset(
isDarkMode ? 'assets/images/headphone_dark.png' : 'assets/images/headphone_light.png', isDarkMode
? 'assets/images/headphone_dark.png'
: 'assets/images/headphone_light.png',
height: 180.h, height: 180.h,
fit: BoxFit.contain, fit: BoxFit.contain,
), ),
@ -187,7 +188,7 @@ class HomeView extends GetView<HomeController> {
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text( Text(
'设备状态', 'deviceStatus'.tr, // 设备状态
style: TextStyle( style: TextStyle(
fontSize: 14.sp, fontSize: 14.sp,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
@ -195,35 +196,36 @@ class HomeView extends GetView<HomeController> {
), ),
), ),
Obx(() => Row( Obx(() => Row(
children: [ children: [
Container( Container(
width: 8.w, width: 8.w,
height: 8.w, height: 8.w,
decoration: BoxDecoration( decoration: BoxDecoration(
color: controller.getConnectionStatusColor(), color: controller.getConnectionStatusColor(),
shape: BoxShape.circle, shape: BoxShape.circle,
), ),
), ),
SizedBox(width: 4.w), SizedBox(width: 4.w),
Text( Text(
controller.getConnectionStatusText(), controller.getConnectionStatusText(),
style: TextStyle( style: TextStyle(
fontSize: 12.sp, fontSize: 12.sp,
color: controller.getConnectionStatusColor(), color: controller.getConnectionStatusColor(),
), ),
), ),
// 添加刷新按钮 // 添加刷新按钮
SizedBox(width: 8.w), SizedBox(width: 8.w),
InkWell( InkWell(
onTap: controller.refreshDeviceInfo, onTap: controller.refreshDeviceInfo,
child: Icon( child: Icon(
Icons.refresh, Icons.refresh,
size: 16.sp, size: 16.sp,
color: isDarkMode ? Colors.grey[400] : Colors.grey[600], color:
), isDarkMode ? Colors.grey[400] : Colors.grey[600],
), ),
], ),
)), ],
)),
], ],
), ),
@ -238,9 +240,13 @@ class HomeView extends GetView<HomeController> {
Container( Container(
padding: EdgeInsets.all(8.w), padding: EdgeInsets.all(8.w),
decoration: BoxDecoration( decoration: BoxDecoration(
color: isDarkMode ? Colors.red[900]!.withOpacity(0.2) : Colors.red[50], color: isDarkMode
? Colors.red[900]!.withOpacity(0.2)
: Colors.red[50],
borderRadius: BorderRadius.circular(8.r), borderRadius: BorderRadius.circular(8.r),
border: Border.all(color: isDarkMode ? Colors.red[800]! : Colors.red[200]!), border: Border.all(
color:
isDarkMode ? Colors.red[800]! : Colors.red[200]!),
), ),
child: Row( child: Row(
children: [ children: [
@ -255,7 +261,9 @@ class HomeView extends GetView<HomeController> {
controller.connectionErrorMsg, controller.connectionErrorMsg,
style: TextStyle( style: TextStyle(
fontSize: 12.sp, fontSize: 12.sp,
color: isDarkMode ? Colors.red[300] : Colors.red[800], color: isDarkMode
? Colors.red[300]
: Colors.red[800],
), ),
), ),
), ),
@ -274,7 +282,7 @@ class HomeView extends GetView<HomeController> {
borderRadius: BorderRadius.circular(8.r), borderRadius: BorderRadius.circular(8.r),
), ),
), ),
child: Text('重新连接'), child: Text('reconnect'.tr), // 重新连接
), ),
], ],
); );
@ -292,12 +300,13 @@ class HomeView extends GetView<HomeController> {
height: 24.w, height: 24.w,
child: CircularProgressIndicator( child: CircularProgressIndicator(
strokeWidth: 2.w, strokeWidth: 2.w,
valueColor: AlwaysStoppedAnimation<Color>(Colors.blue), valueColor:
AlwaysStoppedAnimation<Color>(Colors.blue),
), ),
), ),
SizedBox(height: 8.h), SizedBox(height: 8.h),
Text( Text(
'正在连接设备...', 'connectingDevice'.tr, // 正在连接设备...
style: TextStyle( style: TextStyle(
fontSize: 12.sp, fontSize: 12.sp,
color: Colors.blue, color: Colors.blue,
@ -310,115 +319,131 @@ class HomeView extends GetView<HomeController> {
} }
return controller.isConnected return controller.isConnected
? Column( ? Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Expanded( Expanded(
child: Text( child: Text(
'已连接到:${controller.getDeviceName()}', '${'connectedTo'.tr}:${controller.getDeviceName()}', // 已连接到
style: TextStyle( style: TextStyle(
fontSize: 12.sp, fontSize: 12.sp,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: isDarkMode ? Colors.grey[300] : Colors.grey[700], color: isDarkMode
? Colors.grey[300]
: Colors.grey[700],
),
overflow: TextOverflow.ellipsis,
), ),
overflow: TextOverflow.ellipsis,
), ),
), Container(
Container( padding: EdgeInsets.symmetric(
padding: EdgeInsets.symmetric(horizontal: 6.w, vertical: 2.h), horizontal: 6.w, vertical: 2.h),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.blue.withOpacity(0.1), color: Colors.blue.withOpacity(0.1),
borderRadius: BorderRadius.circular(4.r), borderRadius: BorderRadius.circular(4.r),
), ),
child: Text( child: Text(
'信号: ${controller.getSignalStrength()}', '${'signal'.tr}: ${controller.getSignalStrength()}', // 信号
style: TextStyle( style: TextStyle(
fontSize: 10.sp, fontSize: 10.sp,
color: Colors.blue[700], color: Colors.blue[700],
),
), ),
), ),
), ],
],
),
SizedBox(height: 8.h),
Container(
padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 6.h),
decoration: BoxDecoration(
color: isDarkMode ? Colors.grey[900] : Colors.grey[50],
borderRadius: BorderRadius.circular(8.r),
), ),
child: Column( SizedBox(height: 8.h),
crossAxisAlignment: CrossAxisAlignment.start, Container(
children: [ padding: EdgeInsets.symmetric(
Text( horizontal: 8.w, vertical: 6.h),
'设备ID:${controller.getDeviceId()}', decoration: BoxDecoration(
style: TextStyle( color:
fontSize: 10.sp, isDarkMode ? Colors.grey[900] : Colors.grey[50],
color: isDarkMode ? Colors.grey[400] : Colors.grey[500], borderRadius: BorderRadius.circular(8.r),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'${'deviceId'.tr}:${controller.getDeviceId()}', // 设备ID
style: TextStyle(
fontSize: 10.sp,
color: isDarkMode
? Colors.grey[400]
: Colors.grey[500],
),
), ),
), SizedBox(height: 4.h),
SizedBox(height: 4.h), Text(
Text( '${'firmwareVersion'.tr}:${controller.firmwareVersion}', // 固件版本
'固件版本:${controller.firmwareVersion}', style: TextStyle(
style: TextStyle( fontSize: 10.sp,
fontSize: 10.sp, color: isDarkMode
color: isDarkMode ? Colors.grey[400] : Colors.grey[500], ? Colors.grey[400]
: Colors.grey[500],
),
), ),
), SizedBox(height: 4.h),
SizedBox(height: 4.h), // 显示设备状态(已连接/已配对)
// 显示设备状态(已连接/已配对) Row(
Row( children: [
children: [ Container(
Container( padding: EdgeInsets.symmetric(
padding: EdgeInsets.symmetric(horizontal: 6.w, vertical: 2.h), horizontal: 6.w, vertical: 2.h),
decoration: BoxDecoration( decoration: BoxDecoration(
color: controller.getConnectionStatusColor().withOpacity(0.1), color: controller
borderRadius: BorderRadius.circular(4.r), .getConnectionStatusColor()
), .withOpacity(0.1),
child: Text( borderRadius: BorderRadius.circular(4.r),
controller.getConnectionStatusText(), ),
style: TextStyle( child: Text(
fontSize: 10.sp, controller.getConnectionStatusText(),
color: controller.getConnectionStatusColor(), style: TextStyle(
fontSize: 10.sp,
color:
controller.getConnectionStatusColor(),
),
), ),
), ),
), ],
], ),
), ],
],
),
),
],
)
: Container(
padding: EdgeInsets.symmetric(vertical: 8.h),
alignment: Alignment.center,
decoration: BoxDecoration(
color: isDarkMode ? Colors.grey[900] : Colors.grey[100],
borderRadius: BorderRadius.circular(8.r),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.bluetooth_disabled,
size: 14.sp,
color: isDarkMode ? Colors.grey[400] : Colors.grey[700],
),
SizedBox(width: 4.w),
Text(
'未连接设备,点击下方按钮连接',
style: TextStyle(
fontSize: 12.sp,
color: isDarkMode ? Colors.grey[400] : Colors.grey[700],
), ),
), ),
], ],
), )
); : Container(
padding: EdgeInsets.symmetric(vertical: 8.h),
alignment: Alignment.center,
decoration: BoxDecoration(
color: isDarkMode ? Colors.grey[900] : Colors.grey[100],
borderRadius: BorderRadius.circular(8.r),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.bluetooth_disabled,
size: 14.sp,
color:
isDarkMode ? Colors.grey[400] : Colors.grey[700],
),
SizedBox(width: 4.w),
Text(
'disconnectedDevice'.tr, // 未连接设备,点击下方按钮连接
style: TextStyle(
fontSize: 12.sp,
color: isDarkMode
? Colors.grey[400]
: Colors.grey[700],
),
),
],
),
);
}), }),
// 连接按钮(仅在未连接时显示) // 连接按钮(仅在未连接时显示)
@ -435,10 +460,10 @@ class HomeView extends GetView<HomeController> {
borderRadius: BorderRadius.circular(8.r), borderRadius: BorderRadius.circular(8.r),
), ),
), ),
child: Text('连接设备'), child: Text('connectDevice'.tr), // 连接设备
); );
} else { } else {
return SizedBox(); return const SizedBox();
} }
}), }),
], ],
@ -451,7 +476,7 @@ class HomeView extends GetView<HomeController> {
return Row( return Row(
children: [ children: [
Text( Text(
'热门AI体验', 'topAiExperiences'.tr, // 热门AI体验
style: TextStyle( style: TextStyle(
fontSize: 18.sp, fontSize: 18.sp,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
@ -478,8 +503,8 @@ class HomeView extends GetView<HomeController> {
Expanded( Expanded(
flex: 1, flex: 1,
child: _buildFeatureCard( child: _buildFeatureCard(
title: 'AI全能助手', title: 'aiAssistant'.tr, // AI全能助手
description: '24小时专属顾问,解答问题、提供建议', description: 'aiAssistantInfo'.tr, // 24小时专属顾问,解答问题、提供建议
icon: Icons.assistant, icon: Icons.assistant,
gradient: LinearGradient( gradient: LinearGradient(
begin: Alignment.topLeft, begin: Alignment.topLeft,
@ -506,8 +531,9 @@ class HomeView extends GetView<HomeController> {
children: [ children: [
// 右上卡片 - 同声翻译 // 右上卡片 - 同声翻译
_buildFeatureCard( _buildFeatureCard(
title: '同声传译', title: 'simultaneousInterpretation'.tr, // 同声传译
description: '80+语言实时翻译,出国无忧', description:
'simultaneousInterpretationInfo'.tr, // 80+语言实时翻译,出国无忧
icon: Icons.translate, icon: Icons.translate,
gradient: LinearGradient( gradient: LinearGradient(
begin: Alignment.topLeft, begin: Alignment.topLeft,
@ -527,8 +553,8 @@ class HomeView extends GetView<HomeController> {
// 右下卡片 - AI女友 // 右下卡片 - AI女友
_buildFeatureCard( _buildFeatureCard(
title: 'AI伴侣', title: 'aiCompanion'.tr, // AI伴侣
description: '懂你心意,温暖陪伴', description: 'aiCompanionInfo'.tr, // 懂你心意,温暖陪伴
icon: Icons.favorite, icon: Icons.favorite,
gradient: LinearGradient( gradient: LinearGradient(
begin: Alignment.topLeft, begin: Alignment.topLeft,

277
lib/modules/login/views/login_view.dart

@ -137,7 +137,7 @@ class LoginView extends GetView<LoginController> {
), ),
SizedBox(height: 8.h), SizedBox(height: 8.h),
Text( Text(
'连接世界,超越声音', 'slogan'.tr, // 连接世界,超越声音
style: TextStyle( style: TextStyle(
fontSize: 14.sp, fontSize: 14.sp,
color: isDarkMode ? Colors.grey[400] : Colors.black54, color: isDarkMode ? Colors.grey[400] : Colors.black54,
@ -152,7 +152,7 @@ class LoginView extends GetView<LoginController> {
return Column( return Column(
children: [ children: [
Text( Text(
'欢迎使用', 'welcome'.tr, // 欢迎使用
style: TextStyle( style: TextStyle(
fontSize: 20.sp, fontSize: 20.sp,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
@ -161,7 +161,7 @@ class LoginView extends GetView<LoginController> {
), ),
SizedBox(height: 4.h), SizedBox(height: 4.h),
Text( Text(
'请使用手机号或邮箱登录/注册', 'loginTips'.tr, // 请使用手机号或邮箱登录/注册
style: TextStyle( style: TextStyle(
fontSize: 14.sp, fontSize: 14.sp,
color: isDarkMode ? Colors.grey[400] : Colors.black54, color: isDarkMode ? Colors.grey[400] : Colors.black54,
@ -175,7 +175,9 @@ class LoginView extends GetView<LoginController> {
Widget _buildInputField(bool isDarkMode) { Widget _buildInputField(bool isDarkMode) {
return Container( return Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: isDarkMode ? Colors.grey[900]!.withOpacity(0.4) : Colors.grey.withOpacity(0.1), color: isDarkMode
? Colors.grey[900]!.withOpacity(0.4)
: Colors.grey.withOpacity(0.1),
borderRadius: BorderRadius.circular(16.r), borderRadius: BorderRadius.circular(16.r),
), ),
child: Padding( child: Padding(
@ -192,7 +194,7 @@ class LoginView extends GetView<LoginController> {
child: TextField( child: TextField(
controller: controller.contactController, controller: controller.contactController,
decoration: InputDecoration( decoration: InputDecoration(
hintText: '手机号码或邮箱', hintText: 'accountNumber'.tr, // 手机号码或邮箱
hintStyle: TextStyle( hintStyle: TextStyle(
fontSize: 14.sp, fontSize: 14.sp,
color: isDarkMode ? Colors.grey[600] : Colors.black38, color: isDarkMode ? Colors.grey[600] : Colors.black38,
@ -217,7 +219,9 @@ class LoginView extends GetView<LoginController> {
Widget _buildVerificationInputField(bool isDarkMode) { Widget _buildVerificationInputField(bool isDarkMode) {
return Container( return Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: isDarkMode ? Colors.grey[900]!.withOpacity(0.4) : Colors.grey.withOpacity(0.1), color: isDarkMode
? Colors.grey[900]!.withOpacity(0.4)
: Colors.grey.withOpacity(0.1),
borderRadius: BorderRadius.circular(16.r), borderRadius: BorderRadius.circular(16.r),
), ),
child: Padding( child: Padding(
@ -236,7 +240,7 @@ class LoginView extends GetView<LoginController> {
keyboardType: TextInputType.number, keyboardType: TextInputType.number,
maxLength: 6, maxLength: 6,
decoration: InputDecoration( decoration: InputDecoration(
hintText: '验证码', hintText: 'verificationCode'.tr, // 验证码
hintStyle: TextStyle( hintStyle: TextStyle(
fontSize: 14.sp, fontSize: 14.sp,
color: isDarkMode ? Colors.grey[600] : Colors.black38, color: isDarkMode ? Colors.grey[600] : Colors.black38,
@ -253,25 +257,26 @@ class LoginView extends GetView<LoginController> {
), ),
), ),
Obx(() => TextButton( Obx(() => TextButton(
onPressed: controller.countdownSeconds > 0 onPressed: controller.countdownSeconds > 0
? null ? null
: controller.getVerificationCode, : controller.getVerificationCode,
style: TextButton.styleFrom( style: TextButton.styleFrom(
padding: EdgeInsets.symmetric(horizontal: 16.w), padding: EdgeInsets.symmetric(horizontal: 16.w),
foregroundColor: const Color(0xFF3B82F6), foregroundColor: const Color(0xFF3B82F6),
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
disabledForegroundColor: isDarkMode ? Colors.grey[600] : Colors.grey[400], disabledForegroundColor:
), isDarkMode ? Colors.grey[600] : Colors.grey[400],
child: Text( ),
controller.countdownSeconds > 0 child: Text(
? '${controller.countdownSeconds}s后重新获取' controller.countdownSeconds > 0
: '获取验证码', ? '${controller.countdownSeconds}${'reacquireAfter'.tr}' // s后重新获取
style: TextStyle( : 'getCode'.tr, // 获取验证码
fontSize: 14.sp, style: TextStyle(
fontWeight: FontWeight.w500, fontSize: 14.sp,
), fontWeight: FontWeight.w500,
), ),
)), ),
)),
], ],
), ),
), ),
@ -283,35 +288,36 @@ class LoginView extends GetView<LoginController> {
return SizedBox( return SizedBox(
width: double.infinity, width: double.infinity,
child: Obx(() => ElevatedButton( child: Obx(() => ElevatedButton(
onPressed: controller.isLoading ? null : () => controller.login(), onPressed: controller.isLoading ? null : () => controller.login(),
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF0066CC), backgroundColor: const Color(0xFF0066CC),
foregroundColor: Colors.white, foregroundColor: Colors.white,
padding: EdgeInsets.symmetric(vertical: 14.h), padding: EdgeInsets.symmetric(vertical: 14.h),
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16.r), borderRadius: BorderRadius.circular(16.r),
),
elevation: 0,
disabledBackgroundColor: const Color(0xFF0066CC).withOpacity(0.7),
disabledForegroundColor: Colors.white,
),
child: controller.isLoading
? SizedBox(
height: 20.h,
width: 20.h,
child: CircularProgressIndicator(
strokeWidth: 2.w,
valueColor: const AlwaysStoppedAnimation<Color>(Colors.white),
),
)
: Text(
'继续',
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w600,
),
), ),
)), elevation: 0,
disabledBackgroundColor: const Color(0xFF0066CC).withOpacity(0.7),
disabledForegroundColor: Colors.white,
),
child: controller.isLoading
? SizedBox(
height: 20.h,
width: 20.h,
child: CircularProgressIndicator(
strokeWidth: 2.w,
valueColor:
const AlwaysStoppedAnimation<Color>(Colors.white),
),
)
: Text(
'continue'.tr, // 继续
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w600,
),
),
)),
); );
} }
@ -321,18 +327,22 @@ class LoginView extends GetView<LoginController> {
children: [ children: [
Row( Row(
children: [ children: [
Expanded(child: Divider(color: isDarkMode ? Colors.grey[800] : Colors.grey[300])), Expanded(
child: Divider(
color: isDarkMode ? Colors.grey[800] : Colors.grey[300])),
Padding( Padding(
padding: EdgeInsets.symmetric(horizontal: 16.w), padding: EdgeInsets.symmetric(horizontal: 16.w),
child: Text( child: Text(
'或使用以下方式登录', 'otherWays'.tr, // 或使用以下方式登录
style: TextStyle( style: TextStyle(
fontSize: 12.sp, fontSize: 12.sp,
color: isDarkMode ? Colors.grey[500] : Colors.grey[600], color: isDarkMode ? Colors.grey[500] : Colors.grey[600],
), ),
), ),
), ),
Expanded(child: Divider(color: isDarkMode ? Colors.grey[800] : Colors.grey[300])), Expanded(
child: Divider(
color: isDarkMode ? Colors.grey[800] : Colors.grey[300])),
], ],
), ),
SizedBox(height: 24.h), SizedBox(height: 24.h),
@ -341,7 +351,8 @@ class LoginView extends GetView<LoginController> {
children: [ children: [
_buildSocialButton(FontAwesomeIcons.google, Colors.red, isDarkMode), _buildSocialButton(FontAwesomeIcons.google, Colors.red, isDarkMode),
SizedBox(width: 24.w), SizedBox(width: 24.w),
_buildSocialButton(FontAwesomeIcons.weixin, Colors.green, isDarkMode), _buildSocialButton(
FontAwesomeIcons.weixin, Colors.green, isDarkMode),
], ],
), ),
], ],
@ -356,13 +367,15 @@ class LoginView extends GetView<LoginController> {
decoration: BoxDecoration( decoration: BoxDecoration(
color: isDarkMode ? Colors.grey[800] : Colors.white, color: isDarkMode ? Colors.grey[800] : Colors.white,
borderRadius: BorderRadius.circular(24.r), borderRadius: BorderRadius.circular(24.r),
boxShadow: isDarkMode ? [] : [ boxShadow: isDarkMode
BoxShadow( ? []
color: Colors.grey.withOpacity(0.2), : [
blurRadius: 4, BoxShadow(
offset: const Offset(0, 2), color: Colors.grey.withOpacity(0.2),
), blurRadius: 4,
], offset: const Offset(0, 2),
),
],
), ),
child: IconButton( child: IconButton(
icon: FaIcon( icon: FaIcon(
@ -380,7 +393,7 @@ class LoginView extends GetView<LoginController> {
return Column( return Column(
children: [ children: [
Text( Text(
'登录/注册即表示你同意', 'expressConsent'.tr, // 登录/注册即表示你同意
style: TextStyle( style: TextStyle(
fontSize: 12.sp, fontSize: 12.sp,
color: isDarkMode ? Colors.grey[500] : Colors.grey[600], color: isDarkMode ? Colors.grey[500] : Colors.grey[600],
@ -393,7 +406,7 @@ class LoginView extends GetView<LoginController> {
GestureDetector( GestureDetector(
onTap: () {}, onTap: () {},
child: Text( child: Text(
'《用户协议》', 'userAgreement'.tr, // 《用户协议》
style: TextStyle( style: TextStyle(
fontSize: 12.sp, fontSize: 12.sp,
color: const Color(0xFF3B82F6), color: const Color(0xFF3B82F6),
@ -401,7 +414,7 @@ class LoginView extends GetView<LoginController> {
), ),
), ),
Text( Text(
' 和 ', 'and'.tr, // 和
style: TextStyle( style: TextStyle(
fontSize: 12.sp, fontSize: 12.sp,
color: isDarkMode ? Colors.grey[500] : Colors.grey[600], color: isDarkMode ? Colors.grey[500] : Colors.grey[600],
@ -410,7 +423,7 @@ class LoginView extends GetView<LoginController> {
GestureDetector( GestureDetector(
onTap: () {}, onTap: () {},
child: Text( child: Text(
'《隐私政策》', 'privacyPolicy'.tr, // 《隐私政策》
style: TextStyle( style: TextStyle(
fontSize: 12.sp, fontSize: 12.sp,
color: const Color(0xFF3B82F6), color: const Color(0xFF3B82F6),
@ -458,12 +471,12 @@ class LoginView extends GetView<LoginController> {
), ),
SizedBox(height: 8.h), SizedBox(height: 8.h),
Obx(() => Text( Obx(() => Text(
'验证码已发送至 ${controller.displayContact}', '验证码已发送至 ${controller.displayContact}',
style: TextStyle( style: TextStyle(
fontSize: 14.sp, fontSize: 14.sp,
color: isDarkMode ? Colors.grey[400] : Colors.grey[600], color: isDarkMode ? Colors.grey[400] : Colors.grey[600],
), ),
)), )),
], ],
); );
} }
@ -472,17 +485,21 @@ class LoginView extends GetView<LoginController> {
Widget _buildVerificationInputs(BuildContext context, bool isDarkMode) { Widget _buildVerificationInputs(BuildContext context, bool isDarkMode) {
return Row( return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: List.generate(4, (index) => _buildVerificationInput(index, context, isDarkMode)), children: List.generate(
4, (index) => _buildVerificationInput(index, context, isDarkMode)),
); );
} }
// 单个验证码输入框 // 单个验证码输入框
Widget _buildVerificationInput(int index, BuildContext context, bool isDarkMode) { Widget _buildVerificationInput(
int index, BuildContext context, bool isDarkMode) {
return Container( return Container(
width: 60.w, width: 60.w,
height: 60.w, height: 60.w,
decoration: BoxDecoration( decoration: BoxDecoration(
color: isDarkMode ? Colors.grey[900]!.withOpacity(0.3) : Colors.grey.withOpacity(0.1), color: isDarkMode
? Colors.grey[900]!.withOpacity(0.3)
: Colors.grey.withOpacity(0.1),
borderRadius: BorderRadius.circular(12.r), borderRadius: BorderRadius.circular(12.r),
border: Border.all( border: Border.all(
color: isDarkMode ? Colors.grey[700]! : Colors.grey[300]!, color: isDarkMode ? Colors.grey[700]! : Colors.grey[300]!,
@ -520,28 +537,28 @@ class LoginView extends GetView<LoginController> {
Widget _buildResendButton(bool isDarkMode) { Widget _buildResendButton(bool isDarkMode) {
return Center( return Center(
child: Obx(() => TextButton.icon( child: Obx(() => TextButton.icon(
onPressed: controller.countdownSeconds > 0 onPressed: controller.countdownSeconds > 0
? null ? null
: controller.resendVerificationCode, : controller.resendVerificationCode,
icon: Icon( icon: Icon(
Icons.refresh, Icons.refresh,
size: 14.sp, size: 14.sp,
color: controller.countdownSeconds > 0 color: controller.countdownSeconds > 0
? (isDarkMode ? Colors.grey[600] : Colors.grey[500]) ? (isDarkMode ? Colors.grey[600] : Colors.grey[500])
: const Color(0xFF3B82F6), : const Color(0xFF3B82F6),
), ),
label: Text( label: Text(
controller.countdownSeconds > 0 controller.countdownSeconds > 0
? '重新发送验证码 (${controller.countdownSeconds}s)' ? '重新发送验证码 (${controller.countdownSeconds}s)'
: '重新发送验证码', : '重新发送验证码',
style: TextStyle( style: TextStyle(
fontSize: 14.sp, fontSize: 14.sp,
color: controller.countdownSeconds > 0 color: controller.countdownSeconds > 0
? (isDarkMode ? Colors.grey[600] : Colors.grey[500]) ? (isDarkMode ? Colors.grey[600] : Colors.grey[500])
: const Color(0xFF3B82F6), : const Color(0xFF3B82F6),
), ),
), ),
)), )),
); );
} }
@ -550,35 +567,36 @@ class LoginView extends GetView<LoginController> {
return SizedBox( return SizedBox(
width: double.infinity, width: double.infinity,
child: Obx(() => ElevatedButton( child: Obx(() => ElevatedButton(
onPressed: controller.isLoading ? null : controller.login, onPressed: controller.isLoading ? null : controller.login,
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF3B82F6), backgroundColor: const Color(0xFF3B82F6),
foregroundColor: Colors.white, foregroundColor: Colors.white,
padding: EdgeInsets.symmetric(vertical: 14.h), padding: EdgeInsets.symmetric(vertical: 14.h),
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16.r), borderRadius: BorderRadius.circular(16.r),
),
elevation: 0,
disabledBackgroundColor: const Color(0xFF3B82F6).withOpacity(0.7),
disabledForegroundColor: Colors.white,
),
child: controller.isLoading
? SizedBox(
height: 20.h,
width: 20.h,
child: CircularProgressIndicator(
strokeWidth: 2.w,
valueColor: const AlwaysStoppedAnimation<Color>(Colors.white),
),
)
: Text(
'登录',
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w600,
),
), ),
)), elevation: 0,
disabledBackgroundColor: const Color(0xFF3B82F6).withOpacity(0.7),
disabledForegroundColor: Colors.white,
),
child: controller.isLoading
? SizedBox(
height: 20.h,
width: 20.h,
child: CircularProgressIndicator(
strokeWidth: 2.w,
valueColor:
const AlwaysStoppedAnimation<Color>(Colors.white),
),
)
: Text(
'登录',
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w600,
),
),
)),
); );
} }
@ -591,7 +609,8 @@ class LoginView extends GetView<LoginController> {
'使用密码登录', '使用密码登录',
style: TextStyle( style: TextStyle(
fontSize: 14.sp, fontSize: 14.sp,
color: isDarkMode ? const Color(0xFF3B82F6) : const Color(0xFF3B82F6), color:
isDarkMode ? const Color(0xFF3B82F6) : const Color(0xFF3B82F6),
), ),
), ),
), ),

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

@ -7,7 +7,6 @@ import '../../../core/utils/logger.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart'; import 'package:permission_handler/permission_handler.dart';
/// 简化的配对控制器,仅用于显示已连接经典蓝牙设备和处理基本配对流程 /// 简化的配对控制器,仅用于显示已连接经典蓝牙设备和处理基本配对流程
class PairingController extends GetxController { class PairingController extends GetxController {
static PairingController get to => Get.find(); static PairingController get to => Get.find();
@ -28,10 +27,12 @@ class PairingController extends GetxController {
bool get isBluetoothServiceAvailable => _isBluetoothServiceAvailable.value; bool get isBluetoothServiceAvailable => _isBluetoothServiceAvailable.value;
// 当前连接设备 // 当前连接设备
Rx<classic.BluetoothDevice?> get currentDevice => _bluetoothService.currentDevice; Rx<classic.BluetoothDevice?> get currentDevice =>
_bluetoothService.currentDevice;
// 连接设备列表 // 连接设备列表
RxList<classic.BluetoothDevice> get connectedDevices => _bluetoothService.connectedDevices; RxList<classic.BluetoothDevice> get connectedDevices =>
_bluetoothService.connectedDevices;
// 错误信息 // 错误信息
RxString get errorMessage => _bluetoothService.errorMessage; RxString get errorMessage => _bluetoothService.errorMessage;
@ -43,7 +44,7 @@ class PairingController extends GetxController {
: []; : [];
// 状态描述(用于UI显示) // 状态描述(用于UI显示)
final statusDescription = '正在初始化...'.obs; final statusDescription = 'initializing'.tr.obs; // 正在初始化...
// 加载状态 // 加载状态
final isLoading = false.obs; final isLoading = false.obs;
@ -54,19 +55,14 @@ class PairingController extends GetxController {
_initialize(); _initialize();
} }
/// 完整的初始化流程 /// 完整的初始化流程
Future<void> _initialize() async { Future<void> _initialize() async {
try { try {
VoiceInteractionService.to.initialize(); VoiceInteractionService.to.initialize();
VoiceInteractionService.to.startService(); VoiceInteractionService.to.startService();
isLoading.value = true; isLoading.value = true;
statusDescription.value = '正在初始化...'; statusDescription.value = 'initializing'.tr; // 正在初始化...
// 1. 获取蓝牙服务 // 1. 获取蓝牙服务
_bluetoothService = Get.find<classic.ClassicBluetoothService>(); _bluetoothService = Get.find<classic.ClassicBluetoothService>();
@ -74,48 +70,48 @@ class PairingController extends GetxController {
// 确保蓝牙服务已初始化 // 确保蓝牙服务已初始化
if (!await _bluetoothService.initialize()) { if (!await _bluetoothService.initialize()) {
Logger.error('蓝牙服务初始化失败'); Logger.error('蓝牙服务初始化失败');
statusDescription.value = '蓝牙服务初始化失败'; statusDescription.value =
'bluetoothInitializationFailure'.tr; // 蓝牙服务初始化失败
_isBluetoothServiceAvailable.value = false; _isBluetoothServiceAvailable.value = false;
isLoading.value = false; isLoading.value = false;
return; return;
} }
// 设置连接监听器,确保在页面完全加载后设置,避免过早监听可能导致的问题 // 设置连接监听器,确保在页面完全加载后设置,避免过早监听可能导致的问题
_setupDeviceListeners(); _setupDeviceListeners();
// 2. 检查权限 // 2. 检查权限
statusDescription.value = '正在检查权限...'; statusDescription.value = 'checkingPermissions'.tr; // 正在检查权限...
final hasPermission = await _bluetoothService.checkAndRequestPermissions(); final hasPermission =
await _bluetoothService.checkAndRequestPermissions();
if (!hasPermission) { if (!hasPermission) {
statusDescription.value = '缺少蓝牙权限'; statusDescription.value = 'lackPermissions'.tr; // 缺少蓝牙权限
isLoading.value = false; isLoading.value = false;
return; return;
} }
// 3. 刷新设备列表 // 3. 刷新设备列表
statusDescription.value = '正在搜索设备...'; statusDescription.value = 'searchingDevice'.tr; // 正在搜索设备...
await refreshConnectedDevices(); await refreshConnectedDevices();
// 4. 处理结果 // 4. 处理结果
if (_bluetoothService.connectedDevices.isNotEmpty) { if (_bluetoothService.connectedDevices.isNotEmpty) {
statusDescription.value = '找到已连接的设备'; statusDescription.value = 'findConnectedDevice'.tr; // 找到已连接的设备
// 延迟跳转到主页 // 延迟跳转到主页
_autoNavigateToHome(); _autoNavigateToHome();
} else { } else {
// 没有找到设备 // 没有找到设备
statusDescription.value = '未找到已连接的蓝牙设备'; statusDescription.value = 'notFound'.tr; // 未找到已连接的蓝牙设备
} }
} catch (e) { } catch (e) {
Logger.error('初始化配对控制器失败: $e'); Logger.error('初始化配对控制器失败: $e');
statusDescription.value = '初始化失败'; statusDescription.value = 'initializationFailure'.tr; // 初始化失败
_isBluetoothServiceAvailable.value = false; _isBluetoothServiceAvailable.value = false;
} finally { } finally {
isLoading.value = false; isLoading.value = false;
} }
} }
/// 设置设备监听器 /// 设置设备监听器
void _setupDeviceListeners() { void _setupDeviceListeners() {
try { try {
@ -126,7 +122,8 @@ class PairingController extends GetxController {
Logger.info('检测到蓝牙设备连接: ${device.name}'); Logger.info('检测到蓝牙设备连接: ${device.name}');
// 更新状态并跳转到主页 // 更新状态并跳转到主页
statusDescription.value = '已连接到设备: ${device.name}'; statusDescription.value =
'${'connectedDevice'.tr} ${device.name}'; // 已连接到设备:
// 立即跳转到主页 // 立即跳转到主页
_navigateToHome(); _navigateToHome();
@ -141,26 +138,25 @@ class PairingController extends GetxController {
Get.offAllNamed(Routes.home); Get.offAllNamed(Routes.home);
} }
/// 刷新设备 /// 刷新设备
Future<void> refreshConnectedDevices() async { Future<void> refreshConnectedDevices() async {
try { try {
isLoading.value = true; isLoading.value = true;
statusDescription.value = '正在搜索设备...'; statusDescription.value = 'searchingDevice'.tr; // 正在搜索设备...
final hasDevices = await _bluetoothService.refreshConnectedDevices(); final hasDevices = await _bluetoothService.refreshConnectedDevices();
if (hasDevices) { if (hasDevices) {
statusDescription.value = '找到已连接的设备'; statusDescription.value = 'findConnectedDevice'.tr; // 找到已连接的设备
// 延迟跳转到主页 // 延迟跳转到主页
_autoNavigateToHome(); _autoNavigateToHome();
} else { } else {
// 没有找到设备 // 没有找到设备
statusDescription.value = '未找到已连接的蓝牙设备'; statusDescription.value = 'notFound'.tr; // 未找到已连接的蓝牙设备
} }
} catch (e) { } catch (e) {
Logger.error('刷新设备失败: $e'); Logger.error('刷新设备失败: $e');
statusDescription.value = '刷新设备失败'; statusDescription.value = 'failedRefreshDevice'.tr; // 刷新设备失败
} finally { } finally {
isLoading.value = false; isLoading.value = false;
} }

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

@ -35,7 +35,8 @@ class PairingView extends GetView<PairingController> {
physics: BouncingScrollPhysics(), physics: BouncingScrollPhysics(),
child: ConstrainedBox( child: ConstrainedBox(
constraints: BoxConstraints( constraints: BoxConstraints(
minHeight: MediaQuery.of(Get.context!).size.height - 100.h, // 减去底部导航和状态栏高度 minHeight:
MediaQuery.of(Get.context!).size.height - 100.h, // 减去底部导航和状态栏高度
), ),
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
@ -83,7 +84,7 @@ class PairingView extends GetView<PairingController> {
), ),
SizedBox(height: 8.h), SizedBox(height: 8.h),
Text( Text(
'连接世界,超越声音', 'homeSlogan'.tr, // 连接世界,超越声音
style: TextStyle( style: TextStyle(
fontSize: 16.sp, fontSize: 16.sp,
color: isDarkMode ? Colors.white60 : Colors.black54, color: isDarkMode ? Colors.white60 : Colors.black54,
@ -190,7 +191,7 @@ class PairingView extends GetView<PairingController> {
// 子状态提示文本 // 子状态提示文本
Text( Text(
'请打开耳机充电盒,将耳机放入您的耳朵', 'turnEarphones'.tr, // 请打开耳机充电盒,将耳机放入您的耳朵
style: TextStyle( style: TextStyle(
fontSize: 14.sp, fontSize: 14.sp,
color: isDarkMode ? Colors.white60 : Colors.grey[600], color: isDarkMode ? Colors.white60 : Colors.grey[600],
@ -223,7 +224,7 @@ class PairingView extends GetView<PairingController> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
'当前已连接:', 'currentlyConnected'.tr, // 当前已连接:
style: TextStyle( style: TextStyle(
fontSize: 16.sp, fontSize: 16.sp,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
@ -308,7 +309,7 @@ class PairingView extends GetView<PairingController> {
minimumSize: Size(double.infinity, 56.h), minimumSize: Size(double.infinity, 56.h),
), ),
child: Text( child: Text(
'去系统设置', 'unsystemSetup'.tr, // 去系统设置
style: TextStyle( style: TextStyle(
fontSize: 16.sp, fontSize: 16.sp,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
@ -327,7 +328,7 @@ class PairingView extends GetView<PairingController> {
minimumSize: Size(double.infinity, 48.h), minimumSize: Size(double.infinity, 48.h),
), ),
child: Text( child: Text(
'稍后再说', 'talkLater'.tr, // 稍后再说
style: TextStyle( style: TextStyle(
fontSize: 16.sp, fontSize: 16.sp,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,

63
lib/modules/settings/controllers/settings_controller.dart

@ -1,9 +1,25 @@
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get_storage/get_storage.dart';
import '../../../core/themes/theme_service.dart'; import '../../../core/themes/theme_service.dart';
import '../../../data/services/speech_factory.dart'; import '../../../data/services/speech_factory.dart';
import '../models/language_model.dart';
class SettingsController extends GetxController { class SettingsController extends GetxController {
// 语言设置
final List<LanguageModel> languageList = [
LanguageModel(
name: 'followingSystem', // 跟随系统.tr
alias: 'followingSystem', // 跟随系统.tr
value: 'system'),
LanguageModel(name: 'chinese', alias: '中文', value: 'zh_CN'), // 中文.tr
LanguageModel(name: 'english', alias: 'English', value: 'en_US'), // 英语.tr
];
Rx<LanguageModel> language = LanguageModel().obs;
final GetStorage _storage = GetStorage();
// 主题服务 // 主题服务
final ThemeService _themeService = ThemeService(); final ThemeService _themeService = ThemeService();
@ -13,19 +29,39 @@ class SettingsController extends GetxController {
// 翻译语言对 // 翻译语言对
final RxString sourceLanguage = '中文'.obs; final RxString sourceLanguage = '中文'.obs;
final RxString targetLanguage = '英文'.obs; final RxString targetLanguage = '英文'.obs;
final List<String> availableLanguages = ['中文', '英文', '日文', '韩文', '法文', '德文', '西班牙文', '俄文']; final List<String> availableLanguages = [
'中文',
'英文',
'日文',
'韩文',
'法文',
'德文',
'西班牙文',
'俄文'
];
// 语音服务类型 // 语音服务类型
final Rx<SpeechServiceType> speechServiceType = SpeechServiceType.azure.obs; final Rx<SpeechServiceType> speechServiceType = SpeechServiceType.azure.obs;
final List<Map<String, dynamic>> availableSpeechServices = [ final List<Map<String, dynamic>> availableSpeechServices = [
{'type': SpeechServiceType.azure, 'name': 'Azure 语音服务', 'description': '微软云端语音服务,支持高质量语音合成和识别'}, {
{'type': SpeechServiceType.flutter, 'name': 'Flutter 本地语音服务', 'description': '设备本地语音服务,无需联网即可使用'}, 'type': SpeechServiceType.azure,
'name': 'azureVoiceService', // Azure 语音服务.tr
'description': 'azureVoiceServiceInfo' // 微软云端语音服务,支持高质量语音合成和识别.tr
},
{
'type': SpeechServiceType.flutter,
'name': 'flutterVoiceService', // Flutter 本地语音服务.tr
'description': 'flutterVoiceServiceInfo' // 设备本地语音服务,无需联网即可使用.tr
},
]; ];
@override @override
void onInit() { void onInit() {
super.onInit(); super.onInit();
// 获取系统语言
_getLanguage();
// 从存储中加载上次保存的主题设置 // 从存储中加载上次保存的主题设置
final savedDarkMode = _themeService.isSavedDarkMode(); final savedDarkMode = _themeService.isSavedDarkMode();
@ -36,6 +72,27 @@ class SettingsController extends GetxController {
_loadCurrentSpeechServiceType(); _loadCurrentSpeechServiceType();
} }
void _getLanguage() {
String? languageValue = _storage.read('language');
LanguageModel data = languageList.firstWhere(
(element) => element.value == languageValue,
orElse: () => languageList[0],
);
language.value = data;
}
void setLanguage(LanguageModel data) {
if (data.value != 'system') {
List languageList = data.value.split('_');
Get.updateLocale(Locale(languageList[0], languageList[1]));
} else {
Get.updateLocale(Get.deviceLocale!);
}
language.value = data;
_storage.write('language', data.value);
Get.back();
}
// 加载当前语音服务类型 // 加载当前语音服务类型
void _loadCurrentSpeechServiceType() { void _loadCurrentSpeechServiceType() {
try { try {

11
lib/modules/settings/models/language_model.dart

@ -0,0 +1,11 @@
class LanguageModel {
final String name;
final String alias;
final String value;
LanguageModel({
this.name = '',
this.alias = '',
this.value = '',
});
}

360
lib/modules/settings/views/settings_view.dart

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'dart:ui'; import 'dart:ui';
import '../../../core/theme/app_colors.dart';
import '../controllers/settings_controller.dart'; import '../controllers/settings_controller.dart';
import '../../../core/widgets/common_bottom_nav.dart'; import '../../../core/widgets/common_bottom_nav.dart';
import '../../../routes/app_routes.dart'; import '../../../routes/app_routes.dart';
@ -20,7 +21,7 @@ class SettingsView extends GetView<SettingsController> {
backgroundColor: isDarkMode ? Colors.black : Colors.white, backgroundColor: isDarkMode ? Colors.black : Colors.white,
elevation: 0.5, elevation: 0.5,
title: Text( title: Text(
'设置', 'settings'.tr, // 设置
style: TextStyle( style: TextStyle(
fontSize: 17.sp, fontSize: 17.sp,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
@ -28,7 +29,6 @@ class SettingsView extends GetView<SettingsController> {
), ),
), ),
centerTitle: true, centerTitle: true,
), ),
body: ListView( body: ListView(
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 16.h), padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 16.h),
@ -56,10 +56,7 @@ class SettingsView extends GetView<SettingsController> {
const Color(0xFF1A1A1A).withOpacity(0.7), const Color(0xFF1A1A1A).withOpacity(0.7),
const Color(0xFF2A2A2A).withOpacity(0.7) const Color(0xFF2A2A2A).withOpacity(0.7)
] ]
: [ : [const Color(0xFFE3F2FD), const Color(0xFFF3E5F5)],
const Color(0xFFE3F2FD),
const Color(0xFFF3E5F5)
],
begin: Alignment.topLeft, begin: Alignment.topLeft,
end: Alignment.bottomRight, end: Alignment.bottomRight,
), ),
@ -77,7 +74,9 @@ class SettingsView extends GetView<SettingsController> {
child: ClipRRect( child: ClipRRect(
borderRadius: BorderRadius.circular(16.r), borderRadius: BorderRadius.circular(16.r),
child: BackdropFilter( child: BackdropFilter(
filter: isDarkMode ? ImageFilter.blur(sigmaX: 10, sigmaY: 10) : ImageFilter.blur(sigmaX: 0, sigmaY: 0), filter: isDarkMode
? ImageFilter.blur(sigmaX: 10, sigmaY: 10)
: ImageFilter.blur(sigmaX: 0, sigmaY: 0),
child: Row( child: Row(
children: [ children: [
Container( Container(
@ -119,13 +118,14 @@ class SettingsView extends GetView<SettingsController> {
Row( Row(
children: [ children: [
Container( Container(
padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 2.h), padding: EdgeInsets.symmetric(
horizontal: 8.w, vertical: 2.h),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.blue[600], color: Colors.blue[600],
borderRadius: BorderRadius.circular(10.r), borderRadius: BorderRadius.circular(10.r),
), ),
child: Text( child: Text(
'高级会员', 'premiumMember'.tr, // 高级会员
style: TextStyle( style: TextStyle(
fontSize: 10.sp, fontSize: 10.sp,
color: Colors.white, color: Colors.white,
@ -135,10 +135,11 @@ class SettingsView extends GetView<SettingsController> {
SizedBox(width: 8.w), SizedBox(width: 8.w),
Flexible( Flexible(
child: Text( child: Text(
'已连接设备: DeepVoice Pro', '${'joinDevice'.tr} DeepVoice Pro', // 已连接设备:
style: TextStyle( style: TextStyle(
fontSize: 12.sp, fontSize: 12.sp,
color: isDarkMode ? Colors.white70 : Colors.black54, color:
isDarkMode ? Colors.white70 : Colors.black54,
), ),
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
), ),
@ -147,7 +148,7 @@ class SettingsView extends GetView<SettingsController> {
), ),
SizedBox(height: 4.h), SizedBox(height: 4.h),
Text( Text(
'账号ID: deepvoice_834291', '${'accountId'.tr} deepvoice_834291', // 账号ID:
style: TextStyle( style: TextStyle(
fontSize: 12.sp, fontSize: 12.sp,
color: isDarkMode ? Colors.white70 : Colors.black54, color: isDarkMode ? Colors.white70 : Colors.black54,
@ -193,7 +194,7 @@ class SettingsView extends GetView<SettingsController> {
Padding( Padding(
padding: EdgeInsets.only(left: 4.w, bottom: 8.h), padding: EdgeInsets.only(left: 4.w, bottom: 8.h),
child: Text( child: Text(
'系统设置', 'systemSetting'.tr, // 系统设置
style: TextStyle( style: TextStyle(
fontSize: 12.sp, fontSize: 12.sp,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
@ -219,52 +220,70 @@ class SettingsView extends GetView<SettingsController> {
child: ClipRRect( child: ClipRRect(
borderRadius: BorderRadius.circular(16.r), borderRadius: BorderRadius.circular(16.r),
child: BackdropFilter( child: BackdropFilter(
filter: isDarkMode ? ImageFilter.blur(sigmaX: 5, sigmaY: 5) : ImageFilter.blur(sigmaX: 0, sigmaY: 0), filter: isDarkMode
? ImageFilter.blur(sigmaX: 5, sigmaY: 5)
: ImageFilter.blur(sigmaX: 0, sigmaY: 0),
child: Column( child: Column(
children: [ children: [
// 通知设置 // 语言设置
_buildSimpleNavigationSetting( Obx(
title: '通知设置', () => _buildSimpleNavigationSetting(
subtitle: '管理应用推送和提醒', title: 'languageSetting'.tr, // 语言设置
icon: Icons.notifications_none, subtitle: controller.language.value.name.tr,
iconBgColor: isDarkMode ? Colors.indigo[900]!.withOpacity(0.3) : Colors.indigo[100]!, icon: Icons.language,
iconColor: isDarkMode ? Colors.indigo[300]! : Colors.indigo[600]!, iconBgColor: isDarkMode
titleColor: isDarkMode ? Colors.white : null, ? Colors.indigo[900]!.withOpacity(0.3)
subtitleColor: isDarkMode ? Colors.white70 : null, : Colors.indigo[100]!,
onTap: () { iconColor: isDarkMode
// 打开通知设置页面 ? Colors.indigo[300]!
}, : Colors.indigo[600]!,
isDarkMode: isDarkMode, titleColor: isDarkMode ? Colors.white : null,
subtitleColor: isDarkMode ? Colors.white70 : null,
onTap: () {
_showLanguageSelectionDialog(isDarkMode);
},
isDarkMode: isDarkMode,
),
), ),
Divider(height: 1, color: isDarkMode ? Colors.white.withOpacity(0.1) : Colors.grey[200]), Divider(
height: 1,
color: isDarkMode
? Colors.white.withOpacity(0.1)
: Colors.grey[200]),
// 主题设置 // 主题设置
_buildToggleSetting( _buildToggleSetting(
title: '暗黑模式', title: 'darkMode'.tr, // 暗黑模式
subtitle: '切换应用的明暗主题', subtitle: 'darkModeInfo'.tr, // 切换应用的明暗主题
icon: isDarkMode ? Icons.dark_mode : Icons.light_mode, icon: isDarkMode ? Icons.dark_mode : Icons.light_mode,
iconBgColor: isDarkMode iconBgColor: isDarkMode
? Colors.indigo[900]!.withOpacity(0.3) ? Colors.indigo[900]!.withOpacity(0.3)
: Colors.amber[100]!, : Colors.amber[100]!,
iconColor: isDarkMode iconColor:
? Colors.indigo[300]! isDarkMode ? Colors.indigo[300]! : Colors.amber[600]!,
: Colors.amber[600]!,
value: isDarkMode, value: isDarkMode,
onChanged: (value) { onChanged: (value) {
controller.toggleTheme(); controller.toggleTheme();
}, },
isDarkMode: isDarkMode, isDarkMode: isDarkMode,
), ),
Divider(height: 1, color: isDarkMode ? Colors.white.withOpacity(0.1) : Colors.grey[200]), Divider(
height: 1,
color: isDarkMode
? Colors.white.withOpacity(0.1)
: Colors.grey[200]),
// 备份与恢复 // 备份与恢复
_buildNavigationSetting( _buildNavigationSetting(
title: '备份与恢复', title: 'backups'.tr, // 备份与恢复
subtitle: '备份设置和AI互动历史', subtitle: 'backupsInfo'.tr, // 备份设置和AI互动历史
icon: Icons.cloud_upload_outlined, icon: Icons.cloud_upload_outlined,
iconBgColor: isDarkMode ? Colors.cyan[900]!.withOpacity(0.3) : Colors.cyan[100]!, iconBgColor: isDarkMode
iconColor: isDarkMode ? Colors.cyan[300]! : Colors.cyan[600]!, ? Colors.cyan[900]!.withOpacity(0.3)
value: '上次备份: 今天', : Colors.cyan[100]!,
iconColor:
isDarkMode ? Colors.cyan[300]! : Colors.cyan[600]!,
value: '${'lastBackup'.tr} 今天', // 上次备份:
valueStyle: TextStyle( valueStyle: TextStyle(
fontSize: 12.sp, fontSize: 12.sp,
color: isDarkMode ? Colors.white70 : Colors.grey[500], color: isDarkMode ? Colors.white70 : Colors.grey[500],
@ -274,20 +293,31 @@ class SettingsView extends GetView<SettingsController> {
}, },
isDarkMode: isDarkMode, isDarkMode: isDarkMode,
), ),
Divider(height: 1, color: isDarkMode ? Colors.white.withOpacity(0.1) : Colors.grey[200]), Divider(
height: 1,
color: isDarkMode
? Colors.white.withOpacity(0.1)
: Colors.grey[200]),
// 语音服务选择 // 语音服务选择
_buildSpeechServiceSetting(isDarkMode), _buildSpeechServiceSetting(isDarkMode),
Divider(height: 1, color: isDarkMode ? Colors.white.withOpacity(0.1) : Colors.grey[200]), Divider(
height: 1,
color: isDarkMode
? Colors.white.withOpacity(0.1)
: Colors.grey[200]),
// 隐私设置 // 隐私设置
_buildSimpleNavigationSetting( _buildSimpleNavigationSetting(
title: '隐私设置', title: 'privacySettings'.tr, // 隐私设置
subtitle: '管理数据收集和权限', subtitle: 'privacySettingsInfo'.tr, // 管理数据收集和权限
icon: Icons.shield_outlined, icon: Icons.shield_outlined,
iconBgColor: isDarkMode ? Colors.purple[900]!.withOpacity(0.3) : Colors.purple[100]!, iconBgColor: isDarkMode
iconColor: isDarkMode ? Colors.purple[300]! : Colors.purple[600]!, ? Colors.purple[900]!.withOpacity(0.3)
: Colors.purple[100]!,
iconColor:
isDarkMode ? Colors.purple[300]! : Colors.purple[600]!,
titleColor: isDarkMode ? Colors.white : null, titleColor: isDarkMode ? Colors.white : null,
subtitleColor: isDarkMode ? Colors.white70 : null, subtitleColor: isDarkMode ? Colors.white70 : null,
onTap: () { onTap: () {
@ -295,39 +325,50 @@ class SettingsView extends GetView<SettingsController> {
}, },
isDarkMode: isDarkMode, isDarkMode: isDarkMode,
), ),
Divider(height: 1, color: isDarkMode ? Colors.white.withOpacity(0.1) : Colors.grey[200]), Divider(
height: 1,
color: isDarkMode
? Colors.white.withOpacity(0.1)
: Colors.grey[200]),
// 退出登录 // 退出登录
_buildSimpleNavigationSetting( _buildSimpleNavigationSetting(
title: '退出登录', title: 'logout'.tr, // 退出登录
icon: Icons.logout, icon: Icons.logout,
iconBgColor: isDarkMode ? Colors.red[900]!.withOpacity(0.3) : Colors.red[50]!, iconBgColor: isDarkMode
? Colors.red[900]!.withOpacity(0.3)
: Colors.red[50]!,
iconColor: isDarkMode ? Colors.red[300]! : Colors.red[600]!, iconColor: isDarkMode ? Colors.red[300]! : Colors.red[600]!,
titleColor: isDarkMode ? Colors.red[300]! : Colors.red[600]!, titleColor:
isDarkMode ? Colors.red[300]! : Colors.red[600]!,
onTap: () { onTap: () {
// 退出登录确认对话框 // 退出登录确认对话框
Get.dialog( Get.dialog(
AlertDialog( AlertDialog(
backgroundColor: isDarkMode ? Colors.grey[900] : Colors.white, backgroundColor:
isDarkMode ? Colors.grey[900] : Colors.white,
title: Text( title: Text(
'退出登录', 'logout'.tr, // 退出登录
style: TextStyle( style: TextStyle(
color: isDarkMode ? Colors.white : Colors.black87, color: isDarkMode ? Colors.white : Colors.black87,
), ),
), ),
content: Text( content: Text(
'确定要退出当前账号吗?', 'logoutTips'.tr, // 确定要退出当前账号吗?
style: TextStyle( style: TextStyle(
color: isDarkMode ? Colors.white70 : Colors.black54, color:
isDarkMode ? Colors.white70 : Colors.black54,
), ),
), ),
actions: [ actions: [
TextButton( TextButton(
onPressed: () => Get.back(), onPressed: () => Get.back(),
child: Text( child: Text(
'取消', 'cancel'.tr, // 取消
style: TextStyle( style: TextStyle(
color: isDarkMode ? Colors.white70 : Colors.black54, color: isDarkMode
? Colors.white70
: Colors.black54,
), ),
), ),
), ),
@ -337,9 +378,11 @@ class SettingsView extends GetView<SettingsController> {
controller.signOut(); controller.signOut();
}, },
child: Text( child: Text(
'确定', 'confirm'.tr, // 确定
style: TextStyle( style: TextStyle(
color: isDarkMode ? Colors.red[300] : Colors.red[600], color: isDarkMode
? Colors.red[300]
: Colors.red[600],
), ),
), ),
), ),
@ -366,7 +409,7 @@ class SettingsView extends GetView<SettingsController> {
Padding( Padding(
padding: EdgeInsets.only(left: 4.w, bottom: 8.h), padding: EdgeInsets.only(left: 4.w, bottom: 8.h),
child: Text( child: Text(
'关于应用', 'aboutApplication'.tr, // 关于应用
style: TextStyle( style: TextStyle(
fontSize: 12.sp, fontSize: 12.sp,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
@ -393,7 +436,9 @@ class SettingsView extends GetView<SettingsController> {
child: ClipRRect( child: ClipRRect(
borderRadius: BorderRadius.circular(16.r), borderRadius: BorderRadius.circular(16.r),
child: BackdropFilter( child: BackdropFilter(
filter: isDarkMode ? ImageFilter.blur(sigmaX: 5, sigmaY: 5) : ImageFilter.blur(sigmaX: 0, sigmaY: 0), filter: isDarkMode
? ImageFilter.blur(sigmaX: 5, sigmaY: 5)
: ImageFilter.blur(sigmaX: 0, sigmaY: 0),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
@ -405,8 +450,10 @@ class SettingsView extends GetView<SettingsController> {
decoration: BoxDecoration( decoration: BoxDecoration(
gradient: LinearGradient( gradient: LinearGradient(
colors: [ colors: [
const Color(0xFF2196F3).withOpacity(isDarkMode ? 0.7 : 1.0), const Color(0xFF2196F3)
const Color(0xFF9C27B0).withOpacity(isDarkMode ? 0.7 : 1.0) .withOpacity(isDarkMode ? 0.7 : 1.0),
const Color(0xFF9C27B0)
.withOpacity(isDarkMode ? 0.7 : 1.0)
], ],
begin: Alignment.topLeft, begin: Alignment.topLeft,
end: Alignment.bottomRight, end: Alignment.bottomRight,
@ -433,10 +480,11 @@ class SettingsView extends GetView<SettingsController> {
), ),
SizedBox(height: 2.h), SizedBox(height: 2.h),
Text( Text(
'版本 2.4.1 (Build 87)', '${'versions'.tr} 2.4.1 (Build 87)', // 版本
style: TextStyle( style: TextStyle(
fontSize: 12.sp, fontSize: 12.sp,
color: isDarkMode ? Colors.white70 : Colors.black54, color:
isDarkMode ? Colors.white70 : Colors.black54,
), ),
), ),
], ],
@ -444,13 +492,16 @@ class SettingsView extends GetView<SettingsController> {
], ],
), ),
Container( Container(
padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 6.h), padding:
EdgeInsets.symmetric(horizontal: 12.w, vertical: 6.h),
decoration: BoxDecoration( decoration: BoxDecoration(
color: isDarkMode ? Colors.blue[900]!.withOpacity(0.3) : Colors.blue[100], color: isDarkMode
? Colors.blue[900]!.withOpacity(0.3)
: Colors.blue[100],
borderRadius: BorderRadius.circular(16.r), borderRadius: BorderRadius.circular(16.r),
), ),
child: Text( child: Text(
'检查更新', 'checkUpdates'.tr, // 检查更新
style: TextStyle( style: TextStyle(
fontSize: 12.sp, fontSize: 12.sp,
color: isDarkMode ? Colors.blue[300] : Colors.blue[600], color: isDarkMode ? Colors.blue[300] : Colors.blue[600],
@ -475,7 +526,7 @@ class SettingsView extends GetView<SettingsController> {
), ),
SizedBox(height: 4.h), SizedBox(height: 4.h),
Text( Text(
'连接世界,超越声音', 'homeSlogan'.tr, // 连接世界,超越声音
style: TextStyle( style: TextStyle(
fontSize: 12.sp, fontSize: 12.sp,
color: isDarkMode ? Colors.grey[400] : Colors.grey[500], color: isDarkMode ? Colors.grey[400] : Colors.grey[500],
@ -534,8 +585,7 @@ class SettingsView extends GetView<SettingsController> {
), ),
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
), ),
if (subtitle != null) if (subtitle != null) SizedBox(height: 2.h),
SizedBox(height: 2.h),
if (subtitle != null) if (subtitle != null)
Text( Text(
subtitle, subtitle,
@ -610,14 +660,14 @@ class SettingsView extends GetView<SettingsController> {
), ),
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
), ),
if (subtitle != null) if (subtitle != null) SizedBox(height: 2.h),
SizedBox(height: 2.h),
if (subtitle != null) if (subtitle != null)
Text( Text(
subtitle, subtitle,
style: TextStyle( style: TextStyle(
fontSize: 12.sp, fontSize: 12.sp,
color: isDarkMode ? Colors.white70 : Colors.black54, color:
isDarkMode ? Colors.white70 : Colors.black54,
), ),
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
), ),
@ -633,10 +683,11 @@ class SettingsView extends GetView<SettingsController> {
Flexible( Flexible(
child: Text( child: Text(
value, value,
style: valueStyle ?? TextStyle( style: valueStyle ??
fontSize: 14.sp, TextStyle(
color: isDarkMode ? Colors.white : Colors.black87, fontSize: 14.sp,
), color: isDarkMode ? Colors.white : Colors.black87,
),
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
), ),
), ),
@ -645,7 +696,9 @@ class SettingsView extends GetView<SettingsController> {
width: 32.w, width: 32.w,
height: 32.w, height: 32.w,
decoration: BoxDecoration( decoration: BoxDecoration(
color: isDarkMode ? Colors.white.withOpacity(0.05) : Colors.grey[100], color: isDarkMode
? Colors.white.withOpacity(0.05)
: Colors.grey[100],
borderRadius: BorderRadius.circular(16.r), borderRadius: BorderRadius.circular(16.r),
), ),
child: Icon( child: Icon(
@ -707,18 +760,21 @@ class SettingsView extends GetView<SettingsController> {
style: TextStyle( style: TextStyle(
fontSize: 16.sp, fontSize: 16.sp,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: titleColor ?? (isDarkMode ? Colors.white : Colors.black87), color: titleColor ??
(isDarkMode ? Colors.white : Colors.black87),
), ),
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
), ),
if (subtitle != null) if (subtitle != null) SizedBox(height: 2.h),
SizedBox(height: 2.h),
if (subtitle != null) if (subtitle != null)
Text( Text(
subtitle, subtitle,
style: TextStyle( style: TextStyle(
fontSize: 12.sp, fontSize: 12.sp,
color: subtitleColor ?? (isDarkMode ? Colors.white70 : Colors.black54), color: subtitleColor ??
(isDarkMode
? Colors.white70
: Colors.black54),
), ),
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
), ),
@ -732,7 +788,9 @@ class SettingsView extends GetView<SettingsController> {
width: 32.w, width: 32.w,
height: 32.w, height: 32.w,
decoration: BoxDecoration( decoration: BoxDecoration(
color: isDarkMode ? Colors.white.withOpacity(0.05) : Colors.grey[100], color: isDarkMode
? Colors.white.withOpacity(0.05)
: Colors.grey[100],
borderRadius: BorderRadius.circular(16.r), borderRadius: BorderRadius.circular(16.r),
), ),
child: Icon( child: Icon(
@ -765,7 +823,9 @@ class SettingsView extends GetView<SettingsController> {
width: 32.w, width: 32.w,
height: 32.w, height: 32.w,
decoration: BoxDecoration( decoration: BoxDecoration(
color: isDarkMode ? Colors.teal[900]!.withOpacity(0.3) : Colors.teal[100]!, color: isDarkMode
? Colors.teal[900]!.withOpacity(0.3)
: Colors.teal[100]!,
borderRadius: BorderRadius.circular(16.r), borderRadius: BorderRadius.circular(16.r),
), ),
child: Icon( child: Icon(
@ -780,7 +840,7 @@ class SettingsView extends GetView<SettingsController> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
'语音服务', 'voiceService'.tr, // 语音服务
style: TextStyle( style: TextStyle(
fontSize: 16.sp, fontSize: 16.sp,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
@ -789,7 +849,7 @@ class SettingsView extends GetView<SettingsController> {
), ),
SizedBox(height: 2.h), SizedBox(height: 2.h),
Text( Text(
'选择语音识别和合成服务', 'voiceServiceInfo'.tr, // 选择语音识别和合成服务
style: TextStyle( style: TextStyle(
fontSize: 12.sp, fontSize: 12.sp,
color: isDarkMode ? Colors.white70 : Colors.black54, color: isDarkMode ? Colors.white70 : Colors.black54,
@ -808,11 +868,12 @@ class SettingsView extends GetView<SettingsController> {
Obx(() { Obx(() {
final serviceType = controller.speechServiceType.value; final serviceType = controller.speechServiceType.value;
final serviceName = controller.availableSpeechServices final serviceName = controller.availableSpeechServices
.firstWhere((service) => service['type'] == serviceType)['name']; .firstWhere(
(service) => service['type'] == serviceType)['name'];
return Flexible( return Flexible(
child: Text( child: Text(
serviceName, '$serviceName'.tr,
style: TextStyle( style: TextStyle(
fontSize: 12.sp, fontSize: 12.sp,
color: isDarkMode ? Colors.white70 : Colors.grey[600], color: isDarkMode ? Colors.white70 : Colors.grey[600],
@ -826,7 +887,9 @@ class SettingsView extends GetView<SettingsController> {
width: 32.w, width: 32.w,
height: 32.w, height: 32.w,
decoration: BoxDecoration( decoration: BoxDecoration(
color: isDarkMode ? Colors.white.withOpacity(0.05) : Colors.grey[100], color: isDarkMode
? Colors.white.withOpacity(0.05)
: Colors.grey[100],
borderRadius: BorderRadius.circular(16.r), borderRadius: BorderRadius.circular(16.r),
), ),
child: Icon( child: Icon(
@ -858,7 +921,7 @@ class SettingsView extends GetView<SettingsController> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
'选择语音服务', 'selectVoiceService'.tr, // 选择语音服务
style: TextStyle( style: TextStyle(
fontSize: 18.sp, fontSize: 18.sp,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
@ -868,7 +931,8 @@ class SettingsView extends GetView<SettingsController> {
SizedBox(height: 16.h), SizedBox(height: 16.h),
...controller.availableSpeechServices.map((service) { ...controller.availableSpeechServices.map((service) {
return Obx(() { return Obx(() {
final isSelected = controller.speechServiceType.value == service['type']; final isSelected =
controller.speechServiceType.value == service['type'];
return InkWell( return InkWell(
onTap: () { onTap: () {
@ -880,12 +944,18 @@ class SettingsView extends GetView<SettingsController> {
padding: EdgeInsets.all(12.w), padding: EdgeInsets.all(12.w),
decoration: BoxDecoration( decoration: BoxDecoration(
color: isSelected color: isSelected
? (isDarkMode ? Colors.teal[900]!.withOpacity(0.3) : Colors.teal[50]!) ? (isDarkMode
: (isDarkMode ? Colors.white.withOpacity(0.05) : Colors.grey[100]!), ? Colors.teal[900]!.withOpacity(0.3)
: Colors.teal[50]!)
: (isDarkMode
? Colors.white.withOpacity(0.05)
: Colors.grey[100]!),
borderRadius: BorderRadius.circular(12.r), borderRadius: BorderRadius.circular(12.r),
border: Border.all( border: Border.all(
color: isSelected color: isSelected
? (isDarkMode ? Colors.teal[300]! : Colors.teal[600]!) ? (isDarkMode
? Colors.teal[300]!
: Colors.teal[600]!)
: Colors.transparent, : Colors.transparent,
width: 1, width: 1,
), ),
@ -897,8 +967,12 @@ class SettingsView extends GetView<SettingsController> {
height: 24.w, height: 24.w,
decoration: BoxDecoration( decoration: BoxDecoration(
color: isSelected color: isSelected
? (isDarkMode ? Colors.teal[300] : Colors.teal[600]) ? (isDarkMode
: (isDarkMode ? Colors.white.withOpacity(0.1) : Colors.grey[300]), ? Colors.teal[300]
: Colors.teal[600])
: (isDarkMode
? Colors.white.withOpacity(0.1)
: Colors.grey[300]),
shape: BoxShape.circle, shape: BoxShape.circle,
), ),
child: isSelected child: isSelected
@ -915,20 +989,24 @@ class SettingsView extends GetView<SettingsController> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
service['name'], '${service['name']}'.tr,
style: TextStyle( style: TextStyle(
fontSize: 16.sp, fontSize: 16.sp,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: isDarkMode ? Colors.white : Colors.black87, color: isDarkMode
? Colors.white
: Colors.black87,
), ),
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
), ),
SizedBox(height: 4.h), SizedBox(height: 4.h),
Text( Text(
service['description'], '${service['description']}'.tr,
style: TextStyle( style: TextStyle(
fontSize: 12.sp, fontSize: 12.sp,
color: isDarkMode ? Colors.white70 : Colors.black54, color: isDarkMode
? Colors.white70
: Colors.black54,
), ),
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
maxLines: 2, maxLines: 2,
@ -949,7 +1027,7 @@ class SettingsView extends GetView<SettingsController> {
TextButton( TextButton(
onPressed: () => Get.back(), onPressed: () => Get.back(),
child: Text( child: Text(
'取消', 'cancel'.tr, // 取消
style: TextStyle( style: TextStyle(
color: isDarkMode ? Colors.white70 : Colors.black54, color: isDarkMode ? Colors.white70 : Colors.black54,
), ),
@ -963,4 +1041,86 @@ class SettingsView extends GetView<SettingsController> {
), ),
); );
} }
// 显示语言选择对话框
void _showLanguageSelectionDialog(bool isDarkMode) {
Get.dialog(
Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(24.r),
),
insetPadding: EdgeInsets.symmetric(horizontal: 20.w),
backgroundColor: isDarkMode ? AppColors.cardBackground : Colors.white,
child: Container(
width: 0.9.sw,
padding: EdgeInsets.only(top: 32.h, bottom: 16.h),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.symmetric(horizontal: 24.w),
child: Text(
'selectLanguage'.tr, // 选择语言
style: TextStyle(
fontSize: 20.sp,
fontWeight: FontWeight.bold,
color: isDarkMode ? Colors.white : Colors.black,
),
),
),
SizedBox(height: 16.h),
Container(
constraints: BoxConstraints(maxHeight: 0.5.sh),
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: controller.languageList.map((language) {
return ListTile(
title: Text(
language.name.tr,
style: TextStyle(
color: isDarkMode ? Colors.white : Colors.black,
),
),
trailing:
controller.language.value.value == language.value
? Icon(
Icons.check_circle,
color: isDarkMode
? AppColors.primary
: Colors.blue,
)
: const SizedBox.shrink(),
onTap: () {
controller.setLanguage(language);
},
);
}).toList(),
),
),
),
SizedBox(height: 16.h),
Align(
alignment: Alignment.centerRight,
child: Padding(
padding: EdgeInsets.only(right: 24.w),
child: TextButton(
onPressed: () => Get.back(),
child: Text(
'cancel'.tr, // 取消
style: TextStyle(
color: isDarkMode ? AppColors.primary : Colors.blue,
fontSize: 16.sp,
),
),
),
),
),
],
),
),
),
);
}
} }

4
lib/modules/splash/views/splash_view.dart

@ -130,7 +130,7 @@ class SplashView extends GetView<SplashController> {
child: Padding( child: Padding(
padding: EdgeInsets.only(top: 8.h), padding: EdgeInsets.only(top: 8.h),
child: Text( child: Text(
'连接世界,岂止声音', 'slogan'.tr, // 连接世界,岂止声音
style: TextStyle( style: TextStyle(
fontSize: 14.sp, fontSize: 14.sp,
color: isDarkMode ? Colors.grey[400] : Colors.grey[600], color: isDarkMode ? Colors.grey[400] : Colors.grey[600],
@ -189,7 +189,7 @@ class SplashView extends GetView<SplashController> {
return Opacity( return Opacity(
opacity: value, opacity: value,
child: Text( child: Text(
'AI语音专家 · 随时随地', 'sloganInfo'.tr, // AI语音专家 · 随时随地
style: TextStyle( style: TextStyle(
fontSize: 12.sp, fontSize: 12.sp,
color: isDarkMode ? Colors.grey[500] : Colors.grey[400], color: isDarkMode ? Colors.grey[500] : Colors.grey[400],

112
lib/modules/translation/views/translation_view.dart

@ -47,18 +47,21 @@ class TranslationView extends GetView<TranslationController> {
child: Container( child: Container(
padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 4.h), padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 4.h),
decoration: BoxDecoration( decoration: BoxDecoration(
color: isDarkMode ? Colors.white.withOpacity(0.1) : Colors.grey[100], color: isDarkMode
? Colors.white.withOpacity(0.1)
: Colors.grey[100],
borderRadius: BorderRadius.circular(16.r), borderRadius: BorderRadius.circular(16.r),
), ),
child: Obx(() => Text( child: Obx(() => Text(
controller.sourceLanguage.value.split(' ')[0], // Just show the Chinese part controller.sourceLanguage.value
style: TextStyle( .split(' ')[0], // Just show the Chinese part
fontSize: 16.sp, style: TextStyle(
fontWeight: FontWeight.w600, fontSize: 16.sp,
color: isDarkMode ? Colors.white : Colors.black, fontWeight: FontWeight.w600,
), color: isDarkMode ? Colors.white : Colors.black,
overflow: TextOverflow.ellipsis, ),
)), overflow: TextOverflow.ellipsis,
)),
), ),
), ),
), ),
@ -70,7 +73,9 @@ class TranslationView extends GetView<TranslationController> {
margin: EdgeInsets.symmetric(horizontal: 8.w), margin: EdgeInsets.symmetric(horizontal: 8.w),
padding: EdgeInsets.all(4.r), padding: EdgeInsets.all(4.r),
decoration: BoxDecoration( decoration: BoxDecoration(
color: isDarkMode ? AppColors.primary.withOpacity(0.2) : Colors.blue[50], color: isDarkMode
? AppColors.primary.withOpacity(0.2)
: Colors.blue[50],
shape: BoxShape.circle, shape: BoxShape.circle,
), ),
child: Icon( child: Icon(
@ -88,18 +93,21 @@ class TranslationView extends GetView<TranslationController> {
child: Container( child: Container(
padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 4.h), padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 4.h),
decoration: BoxDecoration( decoration: BoxDecoration(
color: isDarkMode ? Colors.white.withOpacity(0.1) : Colors.grey[100], color: isDarkMode
? Colors.white.withOpacity(0.1)
: Colors.grey[100],
borderRadius: BorderRadius.circular(16.r), borderRadius: BorderRadius.circular(16.r),
), ),
child: Obx(() => Text( child: Obx(() => Text(
controller.targetLanguage.value.split(' ')[0], // Just show the English part controller.targetLanguage.value
style: TextStyle( .split(' ')[0], // Just show the English part
fontSize: 16.sp, style: TextStyle(
fontWeight: FontWeight.w600, fontSize: 16.sp,
color: isDarkMode ? Colors.white : Colors.black, fontWeight: FontWeight.w600,
), color: isDarkMode ? Colors.white : Colors.black,
overflow: TextOverflow.ellipsis, ),
)), overflow: TextOverflow.ellipsis,
)),
), ),
), ),
), ),
@ -109,14 +117,16 @@ class TranslationView extends GetView<TranslationController> {
actions: [ actions: [
// TTS toggle button // TTS toggle button
Obx(() => IconButton( Obx(() => IconButton(
icon: Icon( icon: Icon(
controller.isTtsEnabled.value ? Icons.volume_up : Icons.volume_off, controller.isTtsEnabled.value
color: isDarkMode ? Colors.white : Colors.black, ? Icons.volume_up
size: 24.sp, : Icons.volume_off,
), color: isDarkMode ? Colors.white : Colors.black,
onPressed: controller.toggleTts, size: 24.sp,
tooltip: '自动播放翻译结果', ),
)), onPressed: controller.toggleTts,
tooltip: '自动播放翻译结果',
)),
// 历史记录按钮 // 历史记录按钮
IconButton( IconButton(
@ -159,7 +169,8 @@ class TranslationView extends GetView<TranslationController> {
// 使用 currentItem 来判断是否显示当前项 // 使用 currentItem 来判断是否显示当前项
final hasCurrentItem = controller.currentItem.value != null && final hasCurrentItem = controller.currentItem.value != null &&
controller.currentItem.value!.sourceText.isNotEmpty; // 只有当有实际内容时才显示当前项 controller
.currentItem.value!.sourceText.isNotEmpty; // 只有当有实际内容时才显示当前项
// 计算底部内边距,确保内容不会被底部框遮住 // 计算底部内边距,确保内容不会被底部框遮住
final bottomPadding = controller.bottomBarHeight + 20.h; // 使用控制栏高度加上额外间距 final bottomPadding = controller.bottomBarHeight + 20.h; // 使用控制栏高度加上额外间距
@ -167,11 +178,7 @@ class TranslationView extends GetView<TranslationController> {
return ListView.builder( return ListView.builder(
controller: controller.scrollController, controller: controller.scrollController,
padding: EdgeInsets.only( padding: EdgeInsets.only(
left: 16.w, left: 16.w, right: 16.w, top: 16.h, bottom: bottomPadding),
right: 16.w,
top: 16.h,
bottom: bottomPadding
),
itemCount: itemCount + (hasCurrentItem ? 1 : 0), itemCount: itemCount + (hasCurrentItem ? 1 : 0),
itemBuilder: (context, index) { itemBuilder: (context, index) {
// Current item (being translated) // Current item (being translated)
@ -203,13 +210,11 @@ class TranslationView extends GetView<TranslationController> {
Widget _buildTranslationItemWidget( Widget _buildTranslationItemWidget(
String sourceText, String sourceText,
String translatedText, String translatedText,
bool isCurrent, bool isCurrent, {
{ TranslationItem? item,
TranslationItem? item, bool isIntermediate = false,
bool isIntermediate = false, required bool isDarkMode,
required bool isDarkMode, }) {
}
) {
// 使用AnimatedContainer实现平滑过渡,但恢复原来的视觉样式 // 使用AnimatedContainer实现平滑过渡,但恢复原来的视觉样式
return AnimatedContainer( return AnimatedContainer(
duration: const Duration(milliseconds: 300), duration: const Duration(milliseconds: 300),
@ -240,7 +245,10 @@ class TranslationView extends GetView<TranslationController> {
), ),
// Divider // Divider
Divider(height: 1, thickness: 1, color: isDarkMode ? Colors.grey[800] : Colors.grey[200]), Divider(
height: 1,
thickness: 1,
color: isDarkMode ? Colors.grey[800] : Colors.grey[200]),
// Translated text // Translated text
AnimatedContainer( AnimatedContainer(
@ -252,7 +260,9 @@ class TranslationView extends GetView<TranslationController> {
children: [ children: [
Expanded( Expanded(
child: Text( child: Text(
translatedText.isEmpty && isCurrent ? '翻译结果将显示在这里...' : translatedText, translatedText.isEmpty && isCurrent
? '翻译结果将显示在这里...'
: translatedText,
style: TextStyle( style: TextStyle(
fontSize: 16.sp, fontSize: 16.sp,
color: translatedText.isEmpty && isCurrent color: translatedText.isEmpty && isCurrent
@ -292,7 +302,8 @@ class TranslationView extends GetView<TranslationController> {
// 在构建完成后获取控制栏的高度并设置到控制器中 // 在构建完成后获取控制栏的高度并设置到控制器中
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
if (controlBarKey.currentContext != null) { if (controlBarKey.currentContext != null) {
final RenderBox renderBox = controlBarKey.currentContext!.findRenderObject() as RenderBox; final RenderBox renderBox =
controlBarKey.currentContext!.findRenderObject() as RenderBox;
final height = renderBox.size.height; final height = renderBox.size.height;
controller.setBottomBarHeight(height); controller.setBottomBarHeight(height);
} }
@ -314,8 +325,6 @@ class TranslationView extends GetView<TranslationController> {
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
// 主要控制按钮 - 开始/暂停语音识别 // 主要控制按钮 - 开始/暂停语音识别
Obx(() { Obx(() {
final isRecognizing = controller.isRecognizing.value; final isRecognizing = controller.isRecognizing.value;
@ -368,7 +377,9 @@ class TranslationView extends GetView<TranslationController> {
Padding( Padding(
padding: EdgeInsets.symmetric(horizontal: 24.w), padding: EdgeInsets.symmetric(horizontal: 24.w),
child: Text( child: Text(
isSource ? '选择源语言' : '选择目标语言', isSource
? 'selectSourceLanguage'.tr // 选择源语言
: 'selectTargetLanguage'.tr, // 选择目标语言
style: TextStyle( style: TextStyle(
fontSize: 20.sp, fontSize: 20.sp,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
@ -382,7 +393,8 @@ class TranslationView extends GetView<TranslationController> {
child: SingleChildScrollView( child: SingleChildScrollView(
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: controller.supportedLanguages.keys.map((language) { children:
controller.supportedLanguages.keys.map((language) {
return ListTile( return ListTile(
title: Text( title: Text(
language, language,
@ -397,7 +409,9 @@ class TranslationView extends GetView<TranslationController> {
return currentLanguage == language return currentLanguage == language
? Icon( ? Icon(
Icons.check_circle, Icons.check_circle,
color: isDarkMode ? AppColors.primary : Colors.blue, color: isDarkMode
? AppColors.primary
: Colors.blue,
) )
: const SizedBox.shrink(); : const SizedBox.shrink();
}), }),
@ -422,7 +436,7 @@ class TranslationView extends GetView<TranslationController> {
child: TextButton( child: TextButton(
onPressed: () => Get.back(), onPressed: () => Get.back(),
child: Text( child: Text(
'取消', 'cancel'.tr, // 取消
style: TextStyle( style: TextStyle(
color: isDarkMode ? AppColors.primary : Colors.blue, color: isDarkMode ? AppColors.primary : Colors.blue,
fontSize: 16.sp, fontSize: 16.sp,

2
pubspec.yaml

@ -9,6 +9,8 @@ environment:
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
flutter_localizations:
sdk: flutter
cupertino_icons: ^1.0.6 cupertino_icons: ^1.0.6
get: ^4.6.6 get: ^4.6.6
get_storage: ^2.1.1 get_storage: ^2.1.1

Loading…
Cancel
Save