Browse Source

Merge remote-tracking branch 'onewaygame/tanls' into lxm

newdev_shunjiawei
lxm 2 years ago
parent
commit
140d53e351
  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. 113
      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. 29
      lib/modules/home/controllers/home_controller.dart
  10. 104
      lib/modules/home/views/home_view.dart
  11. 71
      lib/modules/login/views/login_view.dart
  12. 48
      lib/modules/pairing/controllers/pairing_controller.dart
  13. 13
      lib/modules/pairing/views/pairing_view.dart
  14. 66
      lib/modules/settings/controllers/settings_controller.dart
  15. 11
      lib/modules/settings/models/language_model.dart
  16. 344
      lib/modules/settings/views/settings_view.dart
  17. 4
      lib/modules/splash/views/splash_view.dart
  18. 64
      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';
class AppTranslations extends Translations {
@override
Map<String, Map<String, String>> get keys => {
'zh_CN': {
// 通用
'app_name': 'i深音',
'confirm': '确认',
'cancel': '取消',
'retry': '重试',
'error': '错误',
'success': '成功',
// 主页
'add_device': '添加设备',
'searching': '搜索中',
'searching_hint': '请将设备放在手机附近',
'connected': '已连接',
'device_ready': '设备已就绪',
'connection_failed': '连接失败',
'connection_failed_hint': '未找到设备。请确保蓝牙已开启且设备在5米范围内。尝试重启设备。',
'disconnect': '断开连接',
import 'dart:ui';
// 聊天页面
'clear_chat': '清空对话',
'thinking': '正在思考...',
'type_message': '发消息...',
'voice_enabled': '语音已开启',
'voice_disabled': '语音已关闭',
import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
// 设置页面
'settings': '设置',
'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',
import 'language/en_us.dart';
import 'language/zh_cn.dart';
// Home
'add_device': '+ Add Device',
'searching': 'Searching',
'searching_hint': 'Please place the device near your phone',
'connected': 'Connected!',
'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',
class AppTranslations extends Translations {
static const fallbackLocale = Locale('zh', 'CN');
static final supportedLocales = [
const Locale('zh', 'CN'),
const Locale('en', 'US'),
];
// Chat
'clear_chat': 'Clear Chat',
'thinking': 'Thinking...',
'type_message': 'Type a message...',
'voice_enabled': 'Voice Enabled',
'voice_disabled': 'Voice Disabled',
static Locale? deviceLocale() {
final GetStorage storage = GetStorage();
Locale? locale = Get.deviceLocale;
String? language = storage.read('language');
if (language != null && language != 'system') {
List languageList = language.split('_');
locale = Locale(languageList[0], languageList[1]);
}
return locale;
}
// Settings
'settings': 'Settings',
'language_settings': 'Language Settings',
'about': 'About',
'check_update': 'Check for Updates',
'clear_cache': 'Clear Cache',
'home': 'Home',
'explore': 'Explore',
'profile': 'Profile',
'device': 'Device',
},
};
@override
Map<String, Map<String, String>> get keys => {'en_US': enUS, 'zh_CN': zhCN};
}

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;
}
},
backgroundColor: isDarkMode ? Colors.black : const Color(0xFFF9FAFB), // 暗黑模式黑色背景,浅色模式浅灰色背景
backgroundColor: isDarkMode
? Colors.black
: const Color(0xFFF9FAFB), // 暗黑模式黑色背景,浅色模式浅灰色背景
selectedItemColor: const Color(0xFF3B82F6), // 蓝色选中项保持不变
unselectedItemColor: isDarkMode ? Colors.grey[500] : const Color(0xFF6B7280), // 暗黑模式灰色调整
unselectedItemColor:
isDarkMode ? Colors.grey[500] : const Color(0xFF6B7280), // 暗黑模式灰色调整
elevation: isDarkMode ? 0 : 8, // 暗黑模式无阴影,浅色模式保持阴影
type: BottomNavigationBarType.fixed,
items: [
BottomNavigationBarItem(
icon: const Icon(Icons.home),
label: 'home'.tr,
label: 'home'.tr, // 首页
),
BottomNavigationBarItem(
icon: const Icon(Icons.explore),
label: 'explore'.tr,
label: 'explore'.tr, // 发现
),
BottomNavigationBarItem(
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_localizations/flutter_localizations.dart';
import 'package:get/get.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:get_storage/get_storage.dart';
@ -71,9 +72,14 @@ class MainApp extends StatelessWidget {
getPages: AppPages.pages,
debugShowCheckedModeBanner: false,
translations: AppTranslations(),
locale: const Locale('zh', 'CN'),
fallbackLocale: const Locale('en', 'US'),
localizationsDelegates: const [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
locale: AppTranslations.deviceLocale(),
fallbackLocale: AppTranslations.fallbackLocale,
supportedLocales: AppTranslations.supportedLocales,
);
},
);

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

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

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

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

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

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

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

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

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

@ -16,7 +16,8 @@ class AnimatedPulsing extends StatefulWidget {
_AnimatedPulsingState createState() => _AnimatedPulsingState();
}
class _AnimatedPulsingState extends State<AnimatedPulsing> with SingleTickerProviderStateMixin {
class _AnimatedPulsingState extends State<AnimatedPulsing>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _animation;
@ -136,11 +137,9 @@ class HomeView extends GetView<HomeController> {
],
),
child: IconButton(
icon: Icon(
Icons.settings_outlined,
icon: Icon(Icons.settings_outlined,
size: 16.sp,
color: isDarkMode ? Colors.white70 : Colors.grey[600]
),
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,
alignment: Alignment.center,
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,
fit: BoxFit.contain,
),
@ -187,7 +188,7 @@ class HomeView extends GetView<HomeController> {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'设备状态',
'deviceStatus'.tr, // 设备状态
style: TextStyle(
fontSize: 14.sp,
fontWeight: FontWeight.w500,
@ -219,7 +220,8 @@ class HomeView extends GetView<HomeController> {
child: Icon(
Icons.refresh,
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(
padding: EdgeInsets.all(8.w),
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),
border: Border.all(color: isDarkMode ? Colors.red[800]! : Colors.red[200]!),
border: Border.all(
color:
isDarkMode ? Colors.red[800]! : Colors.red[200]!),
),
child: Row(
children: [
@ -255,7 +261,9 @@ class HomeView extends GetView<HomeController> {
controller.connectionErrorMsg,
style: TextStyle(
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),
),
),
child: Text('重新连接'),
child: Text('reconnect'.tr), // 重新连接
),
],
);
@ -292,12 +300,13 @@ class HomeView extends GetView<HomeController> {
height: 24.w,
child: CircularProgressIndicator(
strokeWidth: 2.w,
valueColor: AlwaysStoppedAnimation<Color>(Colors.blue),
valueColor:
AlwaysStoppedAnimation<Color>(Colors.blue),
),
),
SizedBox(height: 8.h),
Text(
'正在连接设备...',
'connectingDevice'.tr, // 正在连接设备...
style: TextStyle(
fontSize: 12.sp,
color: Colors.blue,
@ -318,23 +327,26 @@ class HomeView extends GetView<HomeController> {
children: [
Expanded(
child: Text(
'已连接到:${controller.getDeviceName()}',
'${'connectedTo'.tr}:${controller.getDeviceName()}', // 已连接到
style: TextStyle(
fontSize: 12.sp,
fontWeight: FontWeight.w500,
color: isDarkMode ? Colors.grey[300] : Colors.grey[700],
color: isDarkMode
? Colors.grey[300]
: Colors.grey[700],
),
overflow: TextOverflow.ellipsis,
),
),
Container(
padding: EdgeInsets.symmetric(horizontal: 6.w, vertical: 2.h),
padding: EdgeInsets.symmetric(
horizontal: 6.w, vertical: 2.h),
decoration: BoxDecoration(
color: Colors.blue.withOpacity(0.1),
borderRadius: BorderRadius.circular(4.r),
),
child: Text(
'信号: ${controller.getSignalStrength()}',
'${'signal'.tr}: ${controller.getSignalStrength()}', // 信号
style: TextStyle(
fontSize: 10.sp,
color: Colors.blue[700],
@ -345,27 +357,33 @@ class HomeView extends GetView<HomeController> {
),
SizedBox(height: 8.h),
Container(
padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 6.h),
padding: EdgeInsets.symmetric(
horizontal: 8.w, vertical: 6.h),
decoration: BoxDecoration(
color: isDarkMode ? Colors.grey[900] : Colors.grey[50],
color:
isDarkMode ? Colors.grey[900] : Colors.grey[50],
borderRadius: BorderRadius.circular(8.r),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'设备ID:${controller.getDeviceId()}',
'${'deviceId'.tr}:${controller.getDeviceId()}', // 设备ID
style: TextStyle(
fontSize: 10.sp,
color: isDarkMode ? Colors.grey[400] : Colors.grey[500],
color: isDarkMode
? Colors.grey[400]
: Colors.grey[500],
),
),
SizedBox(height: 4.h),
Text(
'固件版本:${controller.firmwareVersion}',
'${'firmwareVersion'.tr}:${controller.firmwareVersion}', // 固件版本
style: TextStyle(
fontSize: 10.sp,
color: isDarkMode ? Colors.grey[400] : Colors.grey[500],
color: isDarkMode
? Colors.grey[400]
: Colors.grey[500],
),
),
SizedBox(height: 4.h),
@ -373,16 +391,20 @@ class HomeView extends GetView<HomeController> {
Row(
children: [
Container(
padding: EdgeInsets.symmetric(horizontal: 6.w, vertical: 2.h),
padding: EdgeInsets.symmetric(
horizontal: 6.w, vertical: 2.h),
decoration: BoxDecoration(
color: controller.getConnectionStatusColor().withOpacity(0.1),
color: controller
.getConnectionStatusColor()
.withOpacity(0.1),
borderRadius: BorderRadius.circular(4.r),
),
child: Text(
controller.getConnectionStatusText(),
style: TextStyle(
fontSize: 10.sp,
color: controller.getConnectionStatusColor(),
color:
controller.getConnectionStatusColor(),
),
),
),
@ -406,14 +428,17 @@ class HomeView extends GetView<HomeController> {
Icon(
Icons.bluetooth_disabled,
size: 14.sp,
color: isDarkMode ? Colors.grey[400] : Colors.grey[700],
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],
color: isDarkMode
? Colors.grey[400]
: Colors.grey[700],
),
),
],
@ -435,10 +460,10 @@ class HomeView extends GetView<HomeController> {
borderRadius: BorderRadius.circular(8.r),
),
),
child: Text('连接设备'),
child: Text('connectDevice'.tr), // 连接设备
);
} else {
return SizedBox();
return const SizedBox();
}
}),
],
@ -451,7 +476,7 @@ class HomeView extends GetView<HomeController> {
return Row(
children: [
Text(
'热门AI体验',
'topAiExperiences'.tr, // 热门AI体验
style: TextStyle(
fontSize: 18.sp,
fontWeight: FontWeight.bold,
@ -478,8 +503,8 @@ class HomeView extends GetView<HomeController> {
Expanded(
flex: 1,
child: _buildFeatureCard(
title: 'AI全能助手',
description: '24小时专属顾问,解答问题、提供建议',
title: 'aiAssistant'.tr, // AI全能助手
description: 'aiAssistantInfo'.tr, // 24小时专属顾问,解答问题、提供建议
icon: Icons.assistant,
gradient: LinearGradient(
begin: Alignment.topLeft,
@ -506,8 +531,9 @@ class HomeView extends GetView<HomeController> {
children: [
// 右上卡片 - 同声翻译
_buildFeatureCard(
title: '同声传译',
description: '80+语言实时翻译,出国无忧',
title: 'simultaneousInterpretation'.tr, // 同声传译
description:
'simultaneousInterpretationInfo'.tr, // 80+语言实时翻译,出国无忧
icon: Icons.translate,
gradient: LinearGradient(
begin: Alignment.topLeft,
@ -527,8 +553,8 @@ class HomeView extends GetView<HomeController> {
// 右下卡片 - AI女友
_buildFeatureCard(
title: 'AI伴侣',
description: '懂你心意,温暖陪伴',
title: 'aiCompanion'.tr, // AI伴侣
description: 'aiCompanionInfo'.tr, // 懂你心意,温暖陪伴
icon: Icons.favorite,
gradient: LinearGradient(
begin: Alignment.topLeft,

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

@ -137,7 +137,7 @@ class LoginView extends GetView<LoginController> {
),
SizedBox(height: 8.h),
Text(
'连接世界,超越声音',
'slogan'.tr, // 连接世界,超越声音
style: TextStyle(
fontSize: 14.sp,
color: isDarkMode ? Colors.grey[400] : Colors.black54,
@ -152,7 +152,7 @@ class LoginView extends GetView<LoginController> {
return Column(
children: [
Text(
'欢迎使用',
'welcome'.tr, // 欢迎使用
style: TextStyle(
fontSize: 20.sp,
fontWeight: FontWeight.w600,
@ -161,7 +161,7 @@ class LoginView extends GetView<LoginController> {
),
SizedBox(height: 4.h),
Text(
'请使用手机号或邮箱登录/注册',
'loginTips'.tr, // 请使用手机号或邮箱登录/注册
style: TextStyle(
fontSize: 14.sp,
color: isDarkMode ? Colors.grey[400] : Colors.black54,
@ -175,7 +175,9 @@ class LoginView extends GetView<LoginController> {
Widget _buildInputField(bool isDarkMode) {
return Container(
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),
),
child: Padding(
@ -192,7 +194,7 @@ class LoginView extends GetView<LoginController> {
child: TextField(
controller: controller.contactController,
decoration: InputDecoration(
hintText: '手机号码或邮箱',
hintText: 'accountNumber'.tr, // 手机号码或邮箱
hintStyle: TextStyle(
fontSize: 14.sp,
color: isDarkMode ? Colors.grey[600] : Colors.black38,
@ -217,7 +219,9 @@ class LoginView extends GetView<LoginController> {
Widget _buildVerificationInputField(bool isDarkMode) {
return Container(
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),
),
child: Padding(
@ -236,7 +240,7 @@ class LoginView extends GetView<LoginController> {
keyboardType: TextInputType.number,
maxLength: 6,
decoration: InputDecoration(
hintText: '验证码',
hintText: 'verificationCode'.tr, // 验证码
hintStyle: TextStyle(
fontSize: 14.sp,
color: isDarkMode ? Colors.grey[600] : Colors.black38,
@ -260,12 +264,13 @@ class LoginView extends GetView<LoginController> {
padding: EdgeInsets.symmetric(horizontal: 16.w),
foregroundColor: const Color(0xFF3B82F6),
backgroundColor: Colors.transparent,
disabledForegroundColor: isDarkMode ? Colors.grey[600] : Colors.grey[400],
disabledForegroundColor:
isDarkMode ? Colors.grey[600] : Colors.grey[400],
),
child: Text(
controller.countdownSeconds > 0
? '${controller.countdownSeconds}s后重新获取'
: '获取验证码',
? '${controller.countdownSeconds}${'reacquireAfter'.tr}' // s后重新获取
: 'getCode'.tr, // 获取验证码
style: TextStyle(
fontSize: 14.sp,
fontWeight: FontWeight.w500,
@ -301,11 +306,12 @@ class LoginView extends GetView<LoginController> {
width: 20.h,
child: CircularProgressIndicator(
strokeWidth: 2.w,
valueColor: const AlwaysStoppedAnimation<Color>(Colors.white),
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: [
Row(
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: EdgeInsets.symmetric(horizontal: 16.w),
child: Text(
'或使用以下方式登录',
'otherWays'.tr, // 或使用以下方式登录
style: TextStyle(
fontSize: 12.sp,
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),
@ -341,7 +351,8 @@ class LoginView extends GetView<LoginController> {
children: [
_buildSocialButton(FontAwesomeIcons.google, Colors.red, isDarkMode),
SizedBox(width: 24.w),
_buildSocialButton(FontAwesomeIcons.weixin, Colors.green, isDarkMode),
_buildSocialButton(
FontAwesomeIcons.weixin, Colors.green, isDarkMode),
],
),
],
@ -356,7 +367,9 @@ class LoginView extends GetView<LoginController> {
decoration: BoxDecoration(
color: isDarkMode ? Colors.grey[800] : Colors.white,
borderRadius: BorderRadius.circular(24.r),
boxShadow: isDarkMode ? [] : [
boxShadow: isDarkMode
? []
: [
BoxShadow(
color: Colors.grey.withOpacity(0.2),
blurRadius: 4,
@ -380,7 +393,7 @@ class LoginView extends GetView<LoginController> {
return Column(
children: [
Text(
'登录/注册即表示你同意',
'expressConsent'.tr, // 登录/注册即表示你同意
style: TextStyle(
fontSize: 12.sp,
color: isDarkMode ? Colors.grey[500] : Colors.grey[600],
@ -393,7 +406,7 @@ class LoginView extends GetView<LoginController> {
GestureDetector(
onTap: () {},
child: Text(
'《用户协议》',
'userAgreement'.tr, // 《用户协议》
style: TextStyle(
fontSize: 12.sp,
color: const Color(0xFF3B82F6),
@ -401,7 +414,7 @@ class LoginView extends GetView<LoginController> {
),
),
Text(
' 和 ',
'and'.tr, // 和
style: TextStyle(
fontSize: 12.sp,
color: isDarkMode ? Colors.grey[500] : Colors.grey[600],
@ -410,7 +423,7 @@ class LoginView extends GetView<LoginController> {
GestureDetector(
onTap: () {},
child: Text(
'《隐私政策》',
'privacyPolicy'.tr, // 《隐私政策》
style: TextStyle(
fontSize: 12.sp,
color: const Color(0xFF3B82F6),
@ -472,17 +485,21 @@ class LoginView extends GetView<LoginController> {
Widget _buildVerificationInputs(BuildContext context, bool isDarkMode) {
return Row(
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(
width: 60.w,
height: 60.w,
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),
border: Border.all(
color: isDarkMode ? Colors.grey[700]! : Colors.grey[300]!,
@ -568,7 +585,8 @@ class LoginView extends GetView<LoginController> {
width: 20.h,
child: CircularProgressIndicator(
strokeWidth: 2.w,
valueColor: const AlwaysStoppedAnimation<Color>(Colors.white),
valueColor:
const AlwaysStoppedAnimation<Color>(Colors.white),
),
)
: Text(
@ -591,7 +609,8 @@ class LoginView extends GetView<LoginController> {
'使用密码登录',
style: TextStyle(
fontSize: 14.sp,
color: isDarkMode ? const Color(0xFF3B82F6) : const Color(0xFF3B82F6),
color:
isDarkMode ? const Color(0xFF3B82F6) : const Color(0xFF3B82F6),
),
),
),

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

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

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

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

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

@ -1,12 +1,27 @@
import 'package:get/get.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:get_storage/get_storage.dart';
import '../../../core/themes/theme_service.dart';
import '../../../data/services/speech_factory.dart';
import 'package:get_storage/get_storage.dart';
import '../models/language_model.dart';
import '../../../data/models/user_model.dart';
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();
@ -16,18 +31,35 @@ class SettingsController extends GetxController {
// 翻译语言对
final RxString sourceLanguage = '中文'.obs;
final RxString targetLanguage = '英文'.obs;
final List<String> availableLanguages = ['中文', '英文', '日文', '韩文', '法文', '德文', '西班牙文', '俄文'];
final List<String> availableLanguages = [
'中文',
'英文',
'日文',
'韩文',
'法文',
'德文',
'西班牙文',
'俄文'
];
// 语音服务类型
final Rx<SpeechServiceType> speechServiceType = SpeechServiceType.azure.obs;
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
},
];
//用户信息
static const String userKey='user_info';
final _storage=GetStorage();
//final _storage=GetStorage();
final ImagePicker _picker=ImagePicker();
final Rx<UserModel> userInfo=UserModel.defaultUser().obs;
@ -35,6 +67,9 @@ class SettingsController extends GetxController {
void onInit() {
super.onInit();
// 获取系统语言
_getLanguage();
// 从存储中加载上次保存的主题设置
final savedDarkMode = _themeService.isSavedDarkMode();
@ -98,6 +133,27 @@ class SettingsController extends GetxController {
// }
// }
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() {
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 = '',
});
}

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

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'dart:ui';
import '../../../core/theme/app_colors.dart';
import '../controllers/settings_controller.dart';
import '../../../core/widgets/common_bottom_nav.dart';
import '../../../routes/app_routes.dart';
@ -21,7 +22,7 @@ class SettingsView extends GetView<SettingsController> {
backgroundColor: isDarkMode ? Colors.black : Colors.white,
elevation: 0.5,
title: Text(
'设置',
'settings'.tr, // 设置
style: TextStyle(
fontSize: 17.sp,
fontWeight: FontWeight.w600,
@ -29,7 +30,6 @@ class SettingsView extends GetView<SettingsController> {
),
),
centerTitle: true,
),
body: ListView(
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 16.h),
@ -57,10 +57,7 @@ class SettingsView extends GetView<SettingsController> {
const Color(0xFF1A1A1A).withOpacity(0.7),
const Color(0xFF2A2A2A).withOpacity(0.7)
]
: [
const Color(0xFFE3F2FD),
const Color(0xFFF3E5F5)
],
: [const Color(0xFFE3F2FD), const Color(0xFFF3E5F5)],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
@ -77,8 +74,10 @@ class SettingsView extends GetView<SettingsController> {
),
child: ClipRRect(//裁剪圆角矩形
borderRadius: BorderRadius.circular(16.r),
child: BackdropFilter(// 背景滤镜(实现毛玻璃效果)
filter: isDarkMode ? ImageFilter.blur(sigmaX: 10, sigmaY: 10) : ImageFilter.blur(sigmaX: 0, sigmaY: 0),
child: BackdropFilter(
filter: isDarkMode
? ImageFilter.blur(sigmaX: 10, sigmaY: 10)
: ImageFilter.blur(sigmaX: 0, sigmaY: 0),
child: Row(
children: [
Obx(()=>GestureDetector(
@ -127,8 +126,9 @@ class SettingsView extends GetView<SettingsController> {
SizedBox(height: 4.h),
Row(
children: [
Container(// 会员等级
padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 2.h),
Container(
padding: EdgeInsets.symmetric(
horizontal: 8.w, vertical: 2.h),
decoration: BoxDecoration(
color: Colors.blue[600],
borderRadius: BorderRadius.circular(10.r),
@ -144,10 +144,11 @@ class SettingsView extends GetView<SettingsController> {
SizedBox(width: 8.w),
Flexible(
child: Text(
'已连接设备: DeepVoice Pro',
'${'joinDevice'.tr} DeepVoice Pro', // 已连接设备:
style: TextStyle(
fontSize: 12.sp,
color: isDarkMode ? Colors.white70 : Colors.black54,
color:
isDarkMode ? Colors.white70 : Colors.black54,
),
overflow: TextOverflow.ellipsis,
),
@ -206,7 +207,7 @@ class SettingsView extends GetView<SettingsController> {
Padding(
padding: EdgeInsets.only(left: 4.w, bottom: 8.h),
child: Text(
'系统设置',
'systemSetting'.tr, // 系统设置
style: TextStyle(
fontSize: 12.sp,
fontWeight: FontWeight.w500,
@ -232,52 +233,70 @@ class SettingsView extends GetView<SettingsController> {
child: ClipRRect(
borderRadius: BorderRadius.circular(16.r),
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(
children: [
// 通知设置
_buildSimpleNavigationSetting(
title: '通知设置',
subtitle: '管理应用推送和提醒',
icon: Icons.notifications_none,
iconBgColor: isDarkMode ? Colors.indigo[900]!.withOpacity(0.3) : Colors.indigo[100]!,
iconColor: isDarkMode ? Colors.indigo[300]! : Colors.indigo[600]!,
// 语言设置
Obx(
() => _buildSimpleNavigationSetting(
title: 'languageSetting'.tr, // 语言设置
subtitle: controller.language.value.name.tr,
icon: Icons.language,
iconBgColor: isDarkMode
? Colors.indigo[900]!.withOpacity(0.3)
: Colors.indigo[100]!,
iconColor: isDarkMode
? Colors.indigo[300]!
: Colors.indigo[600]!,
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(
title: '暗黑模式',
subtitle: '切换应用的明暗主题',
title: 'darkMode'.tr, // 暗黑模式
subtitle: 'darkModeInfo'.tr, // 切换应用的明暗主题
icon: isDarkMode ? Icons.dark_mode : Icons.light_mode,
iconBgColor: isDarkMode
? Colors.indigo[900]!.withOpacity(0.3)
: Colors.amber[100]!,
iconColor: isDarkMode
? Colors.indigo[300]!
: Colors.amber[600]!,
iconColor:
isDarkMode ? Colors.indigo[300]! : Colors.amber[600]!,
value: isDarkMode,
onChanged: (value) {
controller.toggleTheme();
},
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(
title: '备份与恢复',
subtitle: '备份设置和AI互动历史',
title: 'backups'.tr, // 备份与恢复
subtitle: 'backupsInfo'.tr, // 备份设置和AI互动历史
icon: Icons.cloud_upload_outlined,
iconBgColor: isDarkMode ? Colors.cyan[900]!.withOpacity(0.3) : Colors.cyan[100]!,
iconColor: isDarkMode ? Colors.cyan[300]! : Colors.cyan[600]!,
value: '上次备份: 今天',
iconBgColor: isDarkMode
? Colors.cyan[900]!.withOpacity(0.3)
: Colors.cyan[100]!,
iconColor:
isDarkMode ? Colors.cyan[300]! : Colors.cyan[600]!,
value: '${'lastBackup'.tr} 今天', // 上次备份:
valueStyle: TextStyle(
fontSize: 12.sp,
color: isDarkMode ? Colors.white70 : Colors.grey[500],
@ -287,20 +306,31 @@ class SettingsView extends GetView<SettingsController> {
},
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),
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(
title: '隐私设置',
subtitle: '管理数据收集和权限',
title: 'privacySettings'.tr, // 隐私设置
subtitle: 'privacySettingsInfo'.tr, // 管理数据收集和权限
icon: Icons.shield_outlined,
iconBgColor: isDarkMode ? Colors.purple[900]!.withOpacity(0.3) : Colors.purple[100]!,
iconColor: isDarkMode ? Colors.purple[300]! : Colors.purple[600]!,
iconBgColor: isDarkMode
? Colors.purple[900]!.withOpacity(0.3)
: Colors.purple[100]!,
iconColor:
isDarkMode ? Colors.purple[300]! : Colors.purple[600]!,
titleColor: isDarkMode ? Colors.white : null,
subtitleColor: isDarkMode ? Colors.white70 : null,
onTap: () {
@ -308,39 +338,50 @@ class SettingsView extends GetView<SettingsController> {
},
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(
title: '退出登录',
title: 'logout'.tr, // 退出登录
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]!,
titleColor: isDarkMode ? Colors.red[300]! : Colors.red[600]!,
titleColor:
isDarkMode ? Colors.red[300]! : Colors.red[600]!,
onTap: () {
// 退出登录确认对话框
Get.dialog(
AlertDialog(
backgroundColor: isDarkMode ? Colors.grey[900] : Colors.white,
backgroundColor:
isDarkMode ? Colors.grey[900] : Colors.white,
title: Text(
'退出登录',
'logout'.tr, // 退出登录
style: TextStyle(
color: isDarkMode ? Colors.white : Colors.black87,
),
),
content: Text(
'确定要退出当前账号吗?',
'logoutTips'.tr, // 确定要退出当前账号吗?
style: TextStyle(
color: isDarkMode ? Colors.white70 : Colors.black54,
color:
isDarkMode ? Colors.white70 : Colors.black54,
),
),
actions: [
TextButton(
onPressed: () => Get.back(),
child: Text(
'取消',
'cancel'.tr, // 取消
style: TextStyle(
color: isDarkMode ? Colors.white70 : Colors.black54,
color: isDarkMode
? Colors.white70
: Colors.black54,
),
),
),
@ -350,9 +391,11 @@ class SettingsView extends GetView<SettingsController> {
controller.signOut();
},
child: Text(
'确定',
'confirm'.tr, // 确定
style: TextStyle(
color: isDarkMode ? Colors.red[300] : Colors.red[600],
color: isDarkMode
? Colors.red[300]
: Colors.red[600],
),
),
),
@ -379,7 +422,7 @@ class SettingsView extends GetView<SettingsController> {
Padding(
padding: EdgeInsets.only(left: 4.w, bottom: 8.h),
child: Text(
'关于应用',
'aboutApplication'.tr, // 关于应用
style: TextStyle(
fontSize: 12.sp,
fontWeight: FontWeight.w500,
@ -406,7 +449,9 @@ class SettingsView extends GetView<SettingsController> {
child: ClipRRect(
borderRadius: BorderRadius.circular(16.r),
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(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
@ -418,8 +463,10 @@ class SettingsView extends GetView<SettingsController> {
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
const Color(0xFF2196F3).withOpacity(isDarkMode ? 0.7 : 1.0),
const Color(0xFF9C27B0).withOpacity(isDarkMode ? 0.7 : 1.0)
const Color(0xFF2196F3)
.withOpacity(isDarkMode ? 0.7 : 1.0),
const Color(0xFF9C27B0)
.withOpacity(isDarkMode ? 0.7 : 1.0)
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
@ -446,10 +493,11 @@ class SettingsView extends GetView<SettingsController> {
),
SizedBox(height: 2.h),
Text(
'版本 2.4.1 (Build 87)',
'${'versions'.tr} 2.4.1 (Build 87)', // 版本
style: TextStyle(
fontSize: 12.sp,
color: isDarkMode ? Colors.white70 : Colors.black54,
color:
isDarkMode ? Colors.white70 : Colors.black54,
),
),
],
@ -457,13 +505,16 @@ class SettingsView extends GetView<SettingsController> {
],
),
Container(
padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 6.h),
padding:
EdgeInsets.symmetric(horizontal: 12.w, vertical: 6.h),
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),
),
child: Text(
'检查更新',
'checkUpdates'.tr, // 检查更新
style: TextStyle(
fontSize: 12.sp,
color: isDarkMode ? Colors.blue[300] : Colors.blue[600],
@ -488,7 +539,7 @@ class SettingsView extends GetView<SettingsController> {
),
SizedBox(height: 4.h),
Text(
'连接世界,超越声音',
'homeSlogan'.tr, // 连接世界,超越声音
style: TextStyle(
fontSize: 12.sp,
color: isDarkMode ? Colors.grey[400] : Colors.grey[500],
@ -547,8 +598,7 @@ class SettingsView extends GetView<SettingsController> {
),
overflow: TextOverflow.ellipsis,
),
if (subtitle != null)
SizedBox(height: 2.h),
if (subtitle != null) SizedBox(height: 2.h),
if (subtitle != null)
Text(
subtitle,
@ -623,14 +673,14 @@ class SettingsView extends GetView<SettingsController> {
),
overflow: TextOverflow.ellipsis,
),
if (subtitle != null)
SizedBox(height: 2.h),
if (subtitle != null) SizedBox(height: 2.h),
if (subtitle != null)
Text(
subtitle,
style: TextStyle(
fontSize: 12.sp,
color: isDarkMode ? Colors.white70 : Colors.black54,
color:
isDarkMode ? Colors.white70 : Colors.black54,
),
overflow: TextOverflow.ellipsis,
),
@ -646,7 +696,8 @@ class SettingsView extends GetView<SettingsController> {
Flexible(
child: Text(
value,
style: valueStyle ?? TextStyle(
style: valueStyle ??
TextStyle(
fontSize: 14.sp,
color: isDarkMode ? Colors.white : Colors.black87,
),
@ -658,7 +709,9 @@ class SettingsView extends GetView<SettingsController> {
width: 32.w,
height: 32.w,
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),
),
child: Icon(
@ -720,18 +773,21 @@ class SettingsView extends GetView<SettingsController> {
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w500,
color: titleColor ?? (isDarkMode ? Colors.white : Colors.black87),
color: titleColor ??
(isDarkMode ? Colors.white : Colors.black87),
),
overflow: TextOverflow.ellipsis,
),
if (subtitle != null)
SizedBox(height: 2.h),
if (subtitle != null) SizedBox(height: 2.h),
if (subtitle != null)
Text(
subtitle,
style: TextStyle(
fontSize: 12.sp,
color: subtitleColor ?? (isDarkMode ? Colors.white70 : Colors.black54),
color: subtitleColor ??
(isDarkMode
? Colors.white70
: Colors.black54),
),
overflow: TextOverflow.ellipsis,
),
@ -745,7 +801,9 @@ class SettingsView extends GetView<SettingsController> {
width: 32.w,
height: 32.w,
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),
),
child: Icon(
@ -778,7 +836,9 @@ class SettingsView extends GetView<SettingsController> {
width: 32.w,
height: 32.w,
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),
),
child: Icon(
@ -793,7 +853,7 @@ class SettingsView extends GetView<SettingsController> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'语音服务',
'voiceService'.tr, // 语音服务
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w500,
@ -802,7 +862,7 @@ class SettingsView extends GetView<SettingsController> {
),
SizedBox(height: 2.h),
Text(
'选择语音识别和合成服务',
'voiceServiceInfo'.tr, // 选择语音识别和合成服务
style: TextStyle(
fontSize: 12.sp,
color: isDarkMode ? Colors.white70 : Colors.black54,
@ -821,11 +881,12 @@ class SettingsView extends GetView<SettingsController> {
Obx(() {
final serviceType = controller.speechServiceType.value;
final serviceName = controller.availableSpeechServices
.firstWhere((service) => service['type'] == serviceType)['name'];
.firstWhere(
(service) => service['type'] == serviceType)['name'];
return Flexible(
child: Text(
serviceName,
'$serviceName'.tr,
style: TextStyle(
fontSize: 12.sp,
color: isDarkMode ? Colors.white70 : Colors.grey[600],
@ -839,7 +900,9 @@ class SettingsView extends GetView<SettingsController> {
width: 32.w,
height: 32.w,
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),
),
child: Icon(
@ -871,7 +934,7 @@ class SettingsView extends GetView<SettingsController> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'选择语音服务',
'selectVoiceService'.tr, // 选择语音服务
style: TextStyle(
fontSize: 18.sp,
fontWeight: FontWeight.w600,
@ -881,7 +944,8 @@ class SettingsView extends GetView<SettingsController> {
SizedBox(height: 16.h),
...controller.availableSpeechServices.map((service) {
return Obx(() {
final isSelected = controller.speechServiceType.value == service['type'];
final isSelected =
controller.speechServiceType.value == service['type'];
return InkWell(
onTap: () {
@ -893,12 +957,18 @@ class SettingsView extends GetView<SettingsController> {
padding: EdgeInsets.all(12.w),
decoration: BoxDecoration(
color: isSelected
? (isDarkMode ? Colors.teal[900]!.withOpacity(0.3) : Colors.teal[50]!)
: (isDarkMode ? Colors.white.withOpacity(0.05) : Colors.grey[100]!),
? (isDarkMode
? Colors.teal[900]!.withOpacity(0.3)
: Colors.teal[50]!)
: (isDarkMode
? Colors.white.withOpacity(0.05)
: Colors.grey[100]!),
borderRadius: BorderRadius.circular(12.r),
border: Border.all(
color: isSelected
? (isDarkMode ? Colors.teal[300]! : Colors.teal[600]!)
? (isDarkMode
? Colors.teal[300]!
: Colors.teal[600]!)
: Colors.transparent,
width: 1,
),
@ -910,8 +980,12 @@ class SettingsView extends GetView<SettingsController> {
height: 24.w,
decoration: BoxDecoration(
color: isSelected
? (isDarkMode ? Colors.teal[300] : Colors.teal[600])
: (isDarkMode ? Colors.white.withOpacity(0.1) : Colors.grey[300]),
? (isDarkMode
? Colors.teal[300]
: Colors.teal[600])
: (isDarkMode
? Colors.white.withOpacity(0.1)
: Colors.grey[300]),
shape: BoxShape.circle,
),
child: isSelected
@ -928,20 +1002,24 @@ class SettingsView extends GetView<SettingsController> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
service['name'],
'${service['name']}'.tr,
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w500,
color: isDarkMode ? Colors.white : Colors.black87,
color: isDarkMode
? Colors.white
: Colors.black87,
),
overflow: TextOverflow.ellipsis,
),
SizedBox(height: 4.h),
Text(
service['description'],
'${service['description']}'.tr,
style: TextStyle(
fontSize: 12.sp,
color: isDarkMode ? Colors.white70 : Colors.black54,
color: isDarkMode
? Colors.white70
: Colors.black54,
),
overflow: TextOverflow.ellipsis,
maxLines: 2,
@ -962,7 +1040,7 @@ class SettingsView extends GetView<SettingsController> {
TextButton(
onPressed: () => Get.back(),
child: Text(
'取消',
'cancel'.tr, // 取消
style: TextStyle(
color: isDarkMode ? Colors.white70 : Colors.black54,
),
@ -976,4 +1054,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(
padding: EdgeInsets.only(top: 8.h),
child: Text(
'连接世界,岂止声音',
'slogan'.tr, // 连接世界,岂止声音
style: TextStyle(
fontSize: 14.sp,
color: isDarkMode ? Colors.grey[400] : Colors.grey[600],
@ -189,7 +189,7 @@ class SplashView extends GetView<SplashController> {
return Opacity(
opacity: value,
child: Text(
'AI语音专家 · 随时随地',
'sloganInfo'.tr, // AI语音专家 · 随时随地
style: TextStyle(
fontSize: 12.sp,
color: isDarkMode ? Colors.grey[500] : Colors.grey[400],

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

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

2
pubspec.yaml

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

Loading…
Cancel
Save