diff --git a/android/app/src/main/kotlin/com/example/deep_voice/AzureAsrHelper.kt b/android/app/src/main/kotlin/com/example/deep_voice/AzureAsrHelper.kt index 4ec14fd2e..ed7af26a9 100644 --- a/android/app/src/main/kotlin/com/example/deep_voice/AzureAsrHelper.kt +++ b/android/app/src/main/kotlin/com/example/deep_voice/AzureAsrHelper.kt @@ -169,21 +169,46 @@ class AzureAsrHelper { } try { - // 重新创建识别器 - Log.d(TAG, "重新创建识别器") - recognizer?.close() + Log.d(TAG, "开始重置识别器和音频资源") + // 完全释放所有资源,确保干净的状态 + try { + // 释放识别器 + recognizer?.close() + recognizer = null + + // 释放音频资源 + releaseAudioResources() + + // 确保状态标志正确 + isContinuousRecognitionActive = false + isRecording = false + + Log.d(TAG, "资源释放完成,准备重新创建") + } catch (e: Exception) { + Log.e(TAG, "释放资源失败: ${e.message}", e) + // 继续执行,尝试重新创建 + } + + // 重新创建音频配置 try { - // 重新设置音频输入 setupAudioInput() - Log.d(TAG, "重新创建音频配置成功") + Log.d(TAG, "音频配置创建成功") } catch (e: Exception) { - Log.e(TAG, "重新创建音频配置失败: ${e.message}", e) + Log.e(TAG, "创建音频配置失败: ${e.message}", e) callback.onError("创建音频配置失败: ${e.message}") return false } - recognizer = SpeechRecognizer(speechConfig, audioConfig) + // 重新创建识别器 + try { + Log.d(TAG, "创建新的语音识别器") + recognizer = SpeechRecognizer(speechConfig, audioConfig) + } catch (e: Exception) { + Log.e(TAG, "创建识别器失败: ${e.message}", e) + callback.onError("创建识别器失败: ${e.message}") + return false + } // 设置识别事件处理 recognizer?.let { recognizer -> @@ -341,21 +366,45 @@ class AzureAsrHelper { // 释放资源 fun dispose() { try { + // 添加标志,避免重复释放 + if (recognizer == null && audioRecord == null && pushStream == null) { + Log.d(TAG, "资源已经释放,跳过重复释放") + return + } + + Log.d(TAG, "开始释放资源") + if (isContinuousRecognitionActive && recognizer != null) { - recognizer?.stopContinuousRecognitionAsync()?.get() + try { + recognizer?.stopContinuousRecognitionAsync()?.get() + Log.d(TAG, "连续识别已停止") + } catch (e: Exception) { + Log.e(TAG, "停止连续识别失败: ${e.message}", e) + } } - recognizer?.close() - recognizer = null + try { + recognizer?.close() + recognizer = null + Log.d(TAG, "识别器已关闭") + } catch (e: Exception) { + Log.e(TAG, "关闭识别器失败: ${e.message}", e) + } releaseAudioResources() - speechConfig?.close() - speechConfig = null + try { + speechConfig?.close() + speechConfig = null + Log.d(TAG, "语音配置已关闭") + } catch (e: Exception) { + Log.e(TAG, "关闭语音配置失败: ${e.message}", e) + } isContinuousRecognitionActive = false + Log.d(TAG, "所有资源已释放") } catch (e: Exception) { - // 忽略异常 + Log.e(TAG, "释放资源时出错: ${e.message}", e) } } @@ -365,27 +414,36 @@ class AzureAsrHelper { stopRecording() // 释放 AudioRecord - try { - audioRecord?.release() - audioRecord = null - } catch (e: Exception) { - Log.e(TAG, "释放 AudioRecord 失败: ${e.message}", e) + if (audioRecord != null) { + try { + Log.d(TAG, "释放 AudioRecord") + audioRecord?.release() + audioRecord = null + } catch (e: Exception) { + Log.e(TAG, "释放 AudioRecord 失败: ${e.message}", e) + } } // 释放 AudioConfig - try { - audioConfig?.close() - audioConfig = null - } catch (e: Exception) { - Log.e(TAG, "释放 AudioConfig 失败: ${e.message}", e) + if (audioConfig != null) { + try { + Log.d(TAG, "释放 AudioConfig") + audioConfig?.close() + audioConfig = null + } catch (e: Exception) { + Log.e(TAG, "释放 AudioConfig 失败: ${e.message}", e) + } } // 释放 PushStream - try { - pushStream?.close() - pushStream = null - } catch (e: Exception) { - Log.e(TAG, "释放 PushStream 失败: ${e.message}", e) + if (pushStream != null) { + try { + Log.d(TAG, "释放 PushStream") + pushStream?.close() + pushStream = null + } catch (e: Exception) { + Log.e(TAG, "释放 PushStream 失败: ${e.message}", e) + } } // 释放回音消除资源 diff --git a/android/app/src/main/kotlin/com/example/deep_voice/VoiceInteractionService.kt b/android/app/src/main/kotlin/com/example/deep_voice/VoiceInteractionService.kt index f02340bf7..a5b35ca5f 100644 --- a/android/app/src/main/kotlin/com/example/deep_voice/VoiceInteractionService.kt +++ b/android/app/src/main/kotlin/com/example/deep_voice/VoiceInteractionService.kt @@ -319,9 +319,16 @@ class VoiceInteractionService : Service() { // 如果超过5秒没有检测到语音,且不在TTS播放中,暂停语音识别 if (!hasSpeechDetected && !isTtsSpeaking && elapsedTime >= RECOGNITION_TIMEOUT) { + Log.d(TAG, "超过${RECOGNITION_TIMEOUT/1000}秒未检测到语音,停止识别") isTimeoutPaused = true playNotification("没有听到您说话,已暂停语音识别。双击耳机按钮可重新开始。") + + // 停止语音识别并确保资源完全释放 stopVoiceRecognition() + + // 清理识别状态 + isRecognitionActive = false + hasSpeechDetected = false } } } @@ -339,7 +346,8 @@ class VoiceInteractionService : Service() { Log.d(TAG, "短时间重复响应,忽略") return } - + lastKeyEventTime = currentTime + // 停止当前TTS播放 stopCurrentTTS() @@ -355,6 +363,28 @@ class VoiceInteractionService : Service() { // 启动或重置语音识别 if (!isRecognitionActive) { Log.d(TAG, "语音识别未激活,开始启动") + + // 如果之前是因为超时暂停,重新初始化语音识别组件 + if (isTimeoutPaused) { + Log.d(TAG, "之前因超时暂停,重新初始化Azure服务") + // 释放旧的实例 + try { + azureAsrHelper.dispose() + } catch (e: Exception) { + Log.e(TAG, "释放旧的Azure ASR实例失败: ${e.message}", e) + } + + // 创建新的实例 + azureAsrHelper = AzureAsrHelper() + + // 重新初始化 + val subscriptionKey = MainActivity.azureSpeechKey + val serviceRegion = MainActivity.azureSpeechRegion + if (subscriptionKey.isNotEmpty() && serviceRegion.isNotEmpty()) { + azureAsrHelper.initialize(subscriptionKey, serviceRegion, "zh-CN") + } + } + startVoiceRecognition() } else { Log.d(TAG, "语音识别已激活,更新活动时间") @@ -466,14 +496,31 @@ class VoiceInteractionService : Service() { private fun stopVoiceRecognition() { if (!isRecognitionActive) return - azureAsrHelper.stopContinuousRecognition(object : AzureAsrHelper.ContinuousRecognizeCallback { - override fun onResult(result: String) {} - override fun onRecognizing(recognizing: String) {} - override fun onSessionStarted() {} - override fun onSessionStopped() { isRecognitionActive = false } - override fun onCanceled(reason: String, errorDetails: String) { isRecognitionActive = false } - override fun onError(error: String) { isRecognitionActive = false } - }) + Log.d(TAG, "停止语音识别") + + try { + azureAsrHelper.stopContinuousRecognition(object : AzureAsrHelper.ContinuousRecognizeCallback { + override fun onResult(result: String) {} + override fun onRecognizing(recognizing: String) {} + override fun onSessionStarted() {} + override fun onSessionStopped() { + isRecognitionActive = false + Log.d(TAG, "语音识别会话已停止") + } + override fun onCanceled(reason: String, errorDetails: String) { + isRecognitionActive = false + Log.d(TAG, "语音识别已取消: $reason") + } + override fun onError(error: String) { + isRecognitionActive = false + Log.e(TAG, "停止语音识别时出错: $error") + } + }) + } catch (e: Exception) { + Log.e(TAG, "停止语音识别异常: ${e.message}", e) + // 确保状态一致性 + isRecognitionActive = false + } setPlaybackState(PlaybackStateCompat.STATE_PAUSED) isRecognitionActive = false diff --git a/assets/images/headphone_light.png b/assets/images/headphone_light.png index 11b9b988a..8a043356d 100644 Binary files a/assets/images/headphone_light.png and b/assets/images/headphone_light.png differ diff --git a/lib/app/theme/theme_service.dart b/lib/app/theme/theme_service.dart new file mode 100644 index 000000000..dd64c232e --- /dev/null +++ b/lib/app/theme/theme_service.dart @@ -0,0 +1,29 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:get_storage/get_storage.dart'; + +class ThemeService { + final _box = GetStorage(); + final _key = 'isDarkMode'; + + /// 获取主题模式 - 如果没有保存过,则默认为系统主题 + ThemeMode getThemeMode() { + return isSavedDarkMode() ? ThemeMode.dark : ThemeMode.light; + } + + /// 是否是暗黑模式 + bool isSavedDarkMode() { + return _box.read(_key) ?? false; + } + + /// 保存主题模式到本地存储 + void saveThemeMode(bool isDarkMode) { + _box.write(_key, isDarkMode); + } + + /// 切换主题 + void changeThemeMode() { + Get.changeThemeMode(isSavedDarkMode() ? ThemeMode.light : ThemeMode.dark); + saveThemeMode(!isSavedDarkMode()); + } +} \ No newline at end of file diff --git a/lib/core/widgets/common_bottom_nav.dart b/lib/core/widgets/common_bottom_nav.dart index 387c40286..c1689bc6d 100644 --- a/lib/core/widgets/common_bottom_nav.dart +++ b/lib/core/widgets/common_bottom_nav.dart @@ -12,6 +12,8 @@ class CommonBottomNav extends StatelessWidget { @override Widget build(BuildContext context) { + final isDarkMode = Theme.of(context).brightness == Brightness.dark; + return BottomNavigationBar( currentIndex: currentIndex, onTap: (index) { @@ -28,10 +30,10 @@ class CommonBottomNav extends StatelessWidget { break; } }, - backgroundColor: const Color(0xFFF9FAFB), // 浅灰色背景 #F9FAFB - selectedItemColor: const Color(0xFF3B82F6), // 蓝色选中项 #3B82F6 - unselectedItemColor: const Color(0xFF6B7280), // 灰色未选中项 #6B7280 - elevation: 8, // 添加阴影 + backgroundColor: isDarkMode ? Colors.black : const Color(0xFFF9FAFB), // 暗黑模式黑色背景,浅色模式浅灰色背景 + selectedItemColor: const Color(0xFF3B82F6), // 蓝色选中项保持不变 + unselectedItemColor: isDarkMode ? Colors.grey[500] : const Color(0xFF6B7280), // 暗黑模式灰色调整 + elevation: isDarkMode ? 0 : 8, // 暗黑模式无阴影,浅色模式保持阴影 type: BottomNavigationBarType.fixed, items: [ BottomNavigationBarItem( diff --git a/lib/main.dart b/lib/main.dart index 32ca30f49..5d0c06bf0 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -11,6 +11,7 @@ import 'package:window_size/window_size.dart'; import 'app/translations/app_translations.dart'; import 'data/services/voice_interaction_service.dart'; import 'app/theme/app_theme.dart'; +import 'app/theme/theme_service.dart'; void main() async { // 确保Flutter绑定初始化 @@ -53,6 +54,9 @@ Future _initializeApp() async { // 初始化存储 await GetStorage.init(); + + // 注意:应用启动时会在 SplashController 中检查上次保存的皮肤模式 + // 并自动应用保存的主题(暗黑/浅色) // AudioService 将在 AudioServiceManager 中初始化 // 不再需要在这里调用 AudioService.init @@ -74,7 +78,7 @@ class MainApp extends StatelessWidget { title: 'Deep Voice', theme: AppTheme.lightTheme, darkTheme: AppTheme.darkTheme, - themeMode: ThemeMode.dark, + themeMode: ThemeService().getThemeMode(), // 初始主题模式,将在 SplashController 中再次检查 initialBinding: InitialBinding(), initialRoute: Routes.splash, getPages: AppPages.pages, diff --git a/lib/modules/explore/controllers/explore_controller.dart b/lib/modules/explore/controllers/explore_controller.dart index 4deefd81b..15d809c8c 100644 --- a/lib/modules/explore/controllers/explore_controller.dart +++ b/lib/modules/explore/controllers/explore_controller.dart @@ -55,21 +55,21 @@ class ExploreController extends GetxController { title: '全能助理', description: '帮你解决各类问题', icon: Icons.assistant, - startColor: Colors.blue.shade100, - endColor: Colors.blue.shade200, - iconBgColor: Colors.blue.withOpacity(0.2), - iconColor: Colors.blue.shade600, + startColor: const Color(0xFF0066CC), + endColor: const Color(0xFF5E5CE6), + iconBgColor: const Color(0xFF0066CC).withOpacity(0.2), + iconColor: const Color(0xFF0066CC), agentId: 'personal_assistant', targetRoute: Routes.chat, ), AIFeature( - title: '同声传译', + title: '同声翻译', description: '实时翻译80+种语言', icon: Icons.translate, - startColor: Colors.green.shade100, - endColor: Colors.green.shade200, - iconBgColor: Colors.green.withOpacity(0.2), - iconColor: Colors.green.shade600, + startColor: const Color(0xFF4CAF50), + endColor: const Color(0xFF009688), + iconBgColor: const Color(0xFF4CAF50).withOpacity(0.2), + iconColor: const Color(0xFF4CAF50), agentId: 'simultaneous_interpreter', targetRoute: Routes.translation, ), @@ -77,10 +77,10 @@ class ExploreController extends GetxController { title: 'AI女友', description: '智能陪伴,随时聊天', icon: Icons.favorite, - startColor: Colors.pink.shade100, - endColor: Colors.pink.shade200, - iconBgColor: Colors.pink.withOpacity(0.2), - iconColor: Colors.pink.shade600, + startColor: const Color(0xFFE91E63), + endColor: const Color(0xFFFF5252), + iconBgColor: const Color(0xFFE91E63).withOpacity(0.2), + iconColor: const Color(0xFFE91E63), agentId: 'cyber_girlfriend', targetRoute: Routes.chat, ), @@ -88,10 +88,10 @@ class ExploreController extends GetxController { title: '健康顾问', description: '提供科学健康建议', icon: Icons.healing, - startColor: Colors.amber.shade100, - endColor: Colors.amber.shade200, - iconBgColor: Colors.amber.withOpacity(0.2), - iconColor: Colors.amber.shade600, + startColor: const Color(0xFFFFC107), + endColor: const Color(0xFFFF9800), + iconBgColor: const Color(0xFFFFC107).withOpacity(0.2), + iconColor: const Color(0xFFFFC107), agentId: 'health_advisor', targetRoute: Routes.chat, ), @@ -103,25 +103,25 @@ class ExploreController extends GetxController { title: '商务会议助手', description: '实时记录会议纪要,多语言翻译', icon: Icons.people, - startColor: Colors.blue.shade200, - endColor: Colors.blue.shade300, - iconColor: Colors.blue.shade600, + startColor: const Color(0xFF3F51B5), + endColor: const Color(0xFF673AB7), + iconColor: const Color(0xFF3F51B5), ), FunctionScene( title: '语言学习助手', description: '发音纠正,实时练习口语', icon: Icons.school, - startColor: Colors.green.shade200, - endColor: Colors.green.shade300, - iconColor: Colors.green.shade600, + startColor: const Color(0xFF4CAF50), + endColor: const Color(0xFF009688), + iconColor: const Color(0xFF4CAF50), ), FunctionScene( title: '旅行翻译助手', description: '实时语音翻译,旅游景点介绍', icon: Icons.language, - startColor: Colors.amber.shade200, - endColor: Colors.amber.shade300, - iconColor: Colors.amber.shade600, + startColor: const Color(0xFFFFC107), + endColor: const Color(0xFFFF9800), + iconColor: const Color(0xFFFFC107), ), ]; diff --git a/lib/modules/explore/views/explore_view.dart b/lib/modules/explore/views/explore_view.dart index 4133b4783..f68d1c392 100644 --- a/lib/modules/explore/views/explore_view.dart +++ b/lib/modules/explore/views/explore_view.dart @@ -10,13 +10,15 @@ class ExploreView extends GetView { @override Widget build(BuildContext context) { + final isDarkMode = Theme.of(context).brightness == Brightness.dark; + return Scaffold( - backgroundColor: Colors.grey[50], + backgroundColor: isDarkMode ? Colors.black : Colors.grey[50], body: SafeArea( child: Column( children: [ // 标题和搜索 - _buildHeaderAndSearch(), + _buildHeaderAndSearch(isDarkMode), // 主要内容(可滚动) Expanded( @@ -32,15 +34,15 @@ class ExploreView extends GetView { // AI功能列表 SizedBox(height: 24.h), - _buildAIFeaturesSection(), + _buildAIFeaturesSection(isDarkMode), // 热门功能场景 SizedBox(height: 24.h), - _buildFunctionScenesSection(), + _buildFunctionScenesSection(isDarkMode), // 新功能推荐 SizedBox(height: 24.h), - _buildNewFeatureSection(), + _buildNewFeatureSection(isDarkMode), ], ), ), @@ -54,7 +56,7 @@ class ExploreView extends GetView { } // 标题和搜索 - Widget _buildHeaderAndSearch() { + Widget _buildHeaderAndSearch(bool isDarkMode) { return Padding( padding: EdgeInsets.all(16.w), child: Column( @@ -68,18 +70,22 @@ class ExploreView extends GetView { style: TextStyle( fontSize: 24.sp, fontWeight: FontWeight.bold, - color: Colors.grey[800], + color: isDarkMode ? Colors.white : Colors.grey[800], ), ), Container( width: 32.w, height: 32.w, decoration: BoxDecoration( - color: Colors.grey[200], + color: isDarkMode ? Colors.white.withOpacity(0.1) : Colors.grey[200], shape: BoxShape.circle, ), child: IconButton( - icon: Icon(Icons.more_vert, size: 16.sp), + icon: Icon( + Icons.more_vert, + size: 16.sp, + color: isDarkMode ? Colors.white : Colors.grey[700], + ), padding: EdgeInsets.zero, onPressed: () {}, ), @@ -91,7 +97,7 @@ class ExploreView extends GetView { SizedBox(height: 16.h), Container( decoration: BoxDecoration( - color: Colors.grey[100], + color: isDarkMode ? Colors.white.withOpacity(0.1) : Colors.grey[100], borderRadius: BorderRadius.circular(12.r), ), child: TextField( @@ -100,18 +106,21 @@ class ExploreView extends GetView { hintText: '搜索AI功能...', hintStyle: TextStyle( fontSize: 14.sp, - color: Colors.grey[400], + color: isDarkMode ? Colors.grey[400] : Colors.grey[400], ), prefixIcon: Icon( Icons.search, size: 20.sp, - color: Colors.grey[400], + color: isDarkMode ? Colors.grey[400] : Colors.grey[400], ), border: InputBorder.none, contentPadding: EdgeInsets.symmetric(vertical: 12.h), ), textInputAction: TextInputAction.search, onSubmitted: (_) => controller.search(), + style: TextStyle( + color: isDarkMode ? Colors.white : Colors.black, + ), ), ), ], @@ -127,7 +136,7 @@ class ExploreView extends GetView { borderRadius: BorderRadius.circular(24.r), boxShadow: [ BoxShadow( - color: Colors.grey.withOpacity(0.2), + color: Colors.black.withOpacity(0.2), blurRadius: 10, offset: const Offset(0, 4), ), @@ -208,7 +217,7 @@ class ExploreView extends GetView { } // AI功能部分 - Widget _buildAIFeaturesSection() { + Widget _buildAIFeaturesSection(bool isDarkMode) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -217,7 +226,7 @@ class ExploreView extends GetView { style: TextStyle( fontSize: 18.sp, fontWeight: FontWeight.w600, - color: Colors.grey[800], + color: isDarkMode ? Colors.white : Colors.grey[800], ), ), SizedBox(height: 16.h), @@ -233,7 +242,7 @@ class ExploreView extends GetView { itemCount: controller.aiFeatures.length, itemBuilder: (context, index) { final feature = controller.aiFeatures[index]; - return _buildAIFeatureItem(feature, index); + return _buildAIFeatureItem(feature, index, isDarkMode); }, ), ], @@ -241,7 +250,7 @@ class ExploreView extends GetView { } // AI功能项 - Widget _buildAIFeatureItem(AIFeature feature, int index) { + Widget _buildAIFeatureItem(AIFeature feature, int index, bool isDarkMode) { return GestureDetector( onTap: () => controller.onAIFeatureTap(index), child: Container( @@ -251,16 +260,18 @@ class ExploreView extends GetView { begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [ - feature.startColor, - feature.endColor, + feature.startColor.withOpacity(isDarkMode ? 0.3 : 0.3), + feature.endColor.withOpacity(isDarkMode ? 0.3 : 0.3), ], ), borderRadius: BorderRadius.circular(20.r), boxShadow: [ BoxShadow( - color: Colors.grey.withOpacity(0.1), - blurRadius: 4, - offset: const Offset(0, 2), + color: isDarkMode + ? Colors.black.withOpacity(0.2) + : Colors.grey.withOpacity(0.1), + blurRadius: 8, + offset: const Offset(0, 4), ), ], ), @@ -294,9 +305,9 @@ class ExploreView extends GetView { Text( feature.title, style: TextStyle( - fontSize: 18.sp, + fontSize: 16.sp, fontWeight: FontWeight.w600, - color: Colors.grey[800], + color: isDarkMode ? Colors.white : Colors.grey[800], ), maxLines: 1, overflow: TextOverflow.ellipsis, @@ -306,8 +317,8 @@ class ExploreView extends GetView { Text( feature.description, style: TextStyle( - fontSize: 13.sp, - color: Colors.grey[600], + fontSize: 12.sp, + color: isDarkMode ? Colors.grey[400] : Colors.grey[600], ), maxLines: 1, overflow: TextOverflow.ellipsis, @@ -322,7 +333,7 @@ class ExploreView extends GetView { } // 热门功能场景部分 - Widget _buildFunctionScenesSection() { + Widget _buildFunctionScenesSection(bool isDarkMode) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -331,7 +342,7 @@ class ExploreView extends GetView { style: TextStyle( fontSize: 18.sp, fontWeight: FontWeight.w600, - color: Colors.grey[800], + color: isDarkMode ? Colors.white : Colors.grey[800], ), ), SizedBox(height: 16.h), @@ -343,7 +354,7 @@ class ExploreView extends GetView { final scene = controller.functionScenes[index]; return Padding( padding: EdgeInsets.only(bottom: 16.h), - child: _buildFunctionSceneItem(scene, index), + child: _buildFunctionSceneItem(scene, index, isDarkMode), ); }, ), @@ -352,17 +363,19 @@ class ExploreView extends GetView { } // 功能场景项 - Widget _buildFunctionSceneItem(FunctionScene scene, int index) { + Widget _buildFunctionSceneItem(FunctionScene scene, int index, bool isDarkMode) { return GestureDetector( onTap: () => controller.onFunctionSceneTap(index), child: Container( padding: EdgeInsets.all(16.w), decoration: BoxDecoration( - color: Colors.grey[100], + color: isDarkMode ? Colors.white.withOpacity(0.05) : Colors.grey[100], borderRadius: BorderRadius.circular(16.r), boxShadow: [ BoxShadow( - color: Colors.grey.withOpacity(0.1), + color: isDarkMode + ? Colors.black.withOpacity(0.2) + : Colors.grey.withOpacity(0.1), blurRadius: 4, offset: const Offset(0, 2), ), @@ -379,8 +392,8 @@ class ExploreView extends GetView { begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [ - scene.startColor, - scene.endColor, + scene.startColor.withOpacity(isDarkMode ? 0.3 : 0.3), + scene.endColor.withOpacity(isDarkMode ? 0.3 : 0.3), ], ), borderRadius: BorderRadius.circular(12.r), @@ -403,7 +416,7 @@ class ExploreView extends GetView { style: TextStyle( fontSize: 16.sp, fontWeight: FontWeight.w600, - color: Colors.grey[800], + color: isDarkMode ? Colors.white : Colors.grey[800], ), ), SizedBox(height: 4.h), @@ -411,7 +424,7 @@ class ExploreView extends GetView { scene.description, style: TextStyle( fontSize: 12.sp, - color: Colors.grey[600], + color: isDarkMode ? Colors.grey[400] : Colors.grey[600], ), ), ], @@ -424,7 +437,7 @@ class ExploreView extends GetView { } // 新功能推荐部分 - Widget _buildNewFeatureSection() { + Widget _buildNewFeatureSection(bool isDarkMode) { return Container( padding: EdgeInsets.all(20.w), decoration: BoxDecoration( @@ -432,14 +445,16 @@ class ExploreView extends GetView { begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [ - Colors.purple.shade100, - Colors.purple.shade200, + const Color(0xFF9C27B0).withOpacity(isDarkMode ? 0.3 : 0.3), + const Color(0xFFE91E63).withOpacity(isDarkMode ? 0.3 : 0.3), ], ), borderRadius: BorderRadius.circular(16.r), boxShadow: [ BoxShadow( - color: Colors.grey.withOpacity(0.1), + color: isDarkMode + ? Colors.black.withOpacity(0.2) + : Colors.grey.withOpacity(0.1), blurRadius: 8, offset: const Offset(0, 4), ), @@ -453,13 +468,13 @@ class ExploreView extends GetView { width: 48.w, height: 48.w, decoration: BoxDecoration( - color: Colors.purple.shade200, + color: const Color(0xFF9C27B0).withOpacity(0.2), borderRadius: BorderRadius.circular(12.r), ), child: Icon( Icons.lightbulb_outline, size: 24.sp, - color: Colors.purple.shade600, + color: const Color(0xFF9C27B0), ), ), SizedBox(height: 16.h), @@ -470,7 +485,7 @@ class ExploreView extends GetView { style: TextStyle( fontSize: 20.sp, fontWeight: FontWeight.bold, - color: Colors.grey[800], + color: isDarkMode ? Colors.white : Colors.grey[800], ), ), SizedBox(height: 8.h), @@ -480,7 +495,7 @@ class ExploreView extends GetView { '用你喜欢的歌手声音演唱任何歌曲,甚至是你自己创作的歌曲', style: TextStyle( fontSize: 14.sp, - color: Colors.grey[600], + color: isDarkMode ? Colors.grey[300] : Colors.grey[600], ), ), SizedBox(height: 16.h), @@ -489,7 +504,9 @@ class ExploreView extends GetView { ElevatedButton( onPressed: controller.tryNewFeature, style: ElevatedButton.styleFrom( - backgroundColor: Colors.purple.shade500, + backgroundColor: isDarkMode + ? const Color(0xFF9C27B0) + : Colors.white.withOpacity(0.2), foregroundColor: Colors.white, padding: EdgeInsets.symmetric(horizontal: 20.w, vertical: 10.h), shape: RoundedRectangleBorder( @@ -501,6 +518,7 @@ class ExploreView extends GetView { style: TextStyle( fontSize: 14.sp, fontWeight: FontWeight.w500, + color: isDarkMode ? Colors.white : Colors.grey[800], ), ), ), diff --git a/lib/modules/home/views/home_view.dart b/lib/modules/home/views/home_view.dart index 146289c4f..6fccf62a6 100644 --- a/lib/modules/home/views/home_view.dart +++ b/lib/modules/home/views/home_view.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'dart:ui'; import '../controllers/home_controller.dart'; import '../../../core/routes/app_pages.dart'; import '../../../core/routes/app_routes.dart'; @@ -72,34 +73,19 @@ class HomeView extends GetView { @override Widget build(BuildContext context) { + final bool isDarkMode = Theme.of(context).brightness == Brightness.dark; + return Scaffold( - backgroundColor: Color(0xFFF9FAFC), - appBar: AppBar( - elevation: 0, - backgroundColor: Color(0xFFF9FAFC), - title: Text( - '智能耳机', - style: TextStyle( - color: Colors.black87, - fontSize: 18.sp, - fontWeight: FontWeight.w600, - ), - ), - actions: [ - IconButton( - icon: Icon(Icons.settings_outlined, color: Colors.black54), - onPressed: () { - Get.toNamed(Routes.settings); - }, - ), - ], - ), + backgroundColor: isDarkMode ? Colors.black : Color(0xFFF9FAFC), body: SafeArea( child: SingleChildScrollView( padding: EdgeInsets.all(16.w), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ + // 顶部标题栏 + _buildAppBar(isDarkMode), + // 顶部图片 Center( child: _buildEarbudsImage(), @@ -107,28 +93,11 @@ class HomeView extends GetView { SizedBox(height: 20.h), // 设备状态卡片 - _buildDeviceStatusCard(), + _buildDeviceStatusCard(isDarkMode), SizedBox(height: 20.h), // 热门AI体验 - Row( - children: [ - Text( - '热门AI体验', - style: TextStyle( - fontSize: 18.sp, - fontWeight: FontWeight.bold, - color: Colors.grey[800], - ), - ), - SizedBox(width: 8.w), - Icon( - Icons.star, - color: Colors.amber, - size: 20.w, - ), - ], - ), + _buildSectionTitle(isDarkMode), SizedBox(height: 16.h), _buildPremiumAILayout(), ], @@ -139,31 +108,24 @@ class HomeView extends GetView { ); } - // 页面顶部:状态栏和标题 - Widget _buildHeader() { - return Container( - padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 8.h), - child: Column( - children: [ - // 删除状态栏 - - // 标题区域 - Row( + // 顶部标题栏 + Widget _buildAppBar(bool isDarkMode) { + return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( - 'DeepVoice Pro', + 'DeepVoice', style: TextStyle( fontSize: 20.sp, fontWeight: FontWeight.bold, - color: Colors.grey[800], + color: isDarkMode ? Colors.white : Colors.grey[800], ), ), Container( width: 32.w, height: 32.w, decoration: BoxDecoration( - color: Colors.grey[200], + color: isDarkMode ? Colors.grey[800] : Colors.grey[200], shape: BoxShape.circle, boxShadow: [ BoxShadow( @@ -174,87 +136,44 @@ class HomeView extends GetView { ], ), child: IconButton( - icon: Icon(Icons.more_horiz, size: 16.sp, color: Colors.grey[600]), + icon: Icon( + Icons.settings_outlined, + size: 16.sp, + color: isDarkMode ? Colors.white70 : Colors.grey[600] + ), padding: EdgeInsets.zero, onPressed: () { - // 打开更多选项菜单 + Get.toNamed(Routes.settings); }, ), ), ], - ), - ], - ), ); } // 耳机图片 Widget _buildEarbudsImage() { + final bool isDarkMode = Get.isDarkMode; return Container( - height: 180.h, + height: 220.h, alignment: Alignment.center, - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20.r), - boxShadow: [ - BoxShadow( - color: Colors.grey.withOpacity(0.15), - blurRadius: 15, - offset: const Offset(0, 5), - ), - BoxShadow( - color: Colors.blue.withOpacity(0.05), - blurRadius: 20, - offset: const Offset(0, -2), - ), - ], - ), - child: ClipRRect( - borderRadius: BorderRadius.circular(20.r), - child: Container( - color: Colors.white, - padding: EdgeInsets.symmetric(horizontal: 20.w, vertical: 16.h), - child: Stack( - alignment: Alignment.center, - children: [ - // 背景光效 - Positioned.fill( - child: Container( - decoration: BoxDecoration( - gradient: RadialGradient( - colors: [ - Colors.blue.withOpacity(0.05), - Colors.white, - ], - center: Alignment.topRight, - radius: 0.8, - ), - ), - ), - ), - // 耳机图片 - Image.asset( - 'assets/images/headphone_light.png', - height: 150.h, - fit: BoxFit.contain, - ), - ], - ), - ), - ), + child: Image.asset( + isDarkMode ? 'assets/images/headphone_dark.png' : 'assets/images/headphone_light.png', + height: 180.h, + fit: BoxFit.contain, ), ); } // 设备状态卡片 - Widget _buildDeviceStatusCard() { + Widget _buildDeviceStatusCard(bool isDarkMode) { return Container( decoration: BoxDecoration( - color: Colors.white, + color: isDarkMode ? Color(0xFF1A1A1A) : Colors.white, borderRadius: BorderRadius.circular(16.r), boxShadow: [ BoxShadow( - color: Colors.grey.withOpacity(0.1), + color: Colors.grey.withOpacity(isDarkMode ? 0.05 : 0.1), blurRadius: 10, offset: const Offset(0, 4), ), @@ -272,7 +191,7 @@ class HomeView extends GetView { style: TextStyle( fontSize: 14.sp, fontWeight: FontWeight.w500, - color: Colors.grey[700], + color: isDarkMode ? Colors.grey[300] : Colors.grey[700], ), ), Obx(() => Row( @@ -300,7 +219,7 @@ class HomeView extends GetView { child: Icon( Icons.refresh, size: 16.sp, - color: Colors.grey[600], + color: isDarkMode ? Colors.grey[400] : Colors.grey[600], ), ), ], @@ -319,9 +238,9 @@ class HomeView extends GetView { Container( padding: EdgeInsets.all(8.w), decoration: BoxDecoration( - color: Colors.red[50], + color: isDarkMode ? Colors.red[900]!.withOpacity(0.2) : Colors.red[50], borderRadius: BorderRadius.circular(8.r), - border: Border.all(color: Colors.red[200]!), + border: Border.all(color: isDarkMode ? Colors.red[800]! : Colors.red[200]!), ), child: Row( children: [ @@ -336,7 +255,7 @@ class HomeView extends GetView { controller.connectionErrorMsg, style: TextStyle( fontSize: 12.sp, - color: Colors.red[800], + color: isDarkMode ? Colors.red[300] : Colors.red[800], ), ), ), @@ -403,7 +322,7 @@ class HomeView extends GetView { style: TextStyle( fontSize: 12.sp, fontWeight: FontWeight.w500, - color: Colors.grey[700], + color: isDarkMode ? Colors.grey[300] : Colors.grey[700], ), overflow: TextOverflow.ellipsis, ), @@ -428,7 +347,7 @@ class HomeView extends GetView { Container( padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 6.h), decoration: BoxDecoration( - color: Colors.grey[50], + color: isDarkMode ? Colors.grey[900] : Colors.grey[50], borderRadius: BorderRadius.circular(8.r), ), child: Column( @@ -438,7 +357,7 @@ class HomeView extends GetView { '设备ID:${controller.getDeviceId()}', style: TextStyle( fontSize: 10.sp, - color: Colors.grey[500], + color: isDarkMode ? Colors.grey[400] : Colors.grey[500], ), ), SizedBox(height: 4.h), @@ -446,7 +365,7 @@ class HomeView extends GetView { '固件版本:${controller.firmwareVersion}', style: TextStyle( fontSize: 10.sp, - color: Colors.grey[500], + color: isDarkMode ? Colors.grey[400] : Colors.grey[500], ), ), ], @@ -458,7 +377,7 @@ class HomeView extends GetView { padding: EdgeInsets.symmetric(vertical: 8.h), alignment: Alignment.center, decoration: BoxDecoration( - color: Colors.grey[100], + color: isDarkMode ? Colors.grey[900] : Colors.grey[100], borderRadius: BorderRadius.circular(8.r), ), child: Row( @@ -467,14 +386,14 @@ class HomeView extends GetView { Icon( Icons.bluetooth_disabled, size: 14.sp, - color: Colors.grey[700], + color: isDarkMode ? Colors.grey[400] : Colors.grey[700], ), SizedBox(width: 4.w), Text( '未连接设备,点击下方按钮连接', style: TextStyle( fontSize: 12.sp, - color: Colors.grey[700], + color: isDarkMode ? Colors.grey[400] : Colors.grey[700], ), ), ], @@ -507,51 +426,54 @@ class HomeView extends GetView { ); } + // 热门AI体验标题 + Widget _buildSectionTitle(bool isDarkMode) { + return Row( + children: [ + Text( + '热门AI体验', + style: TextStyle( + fontSize: 18.sp, + fontWeight: FontWeight.bold, + color: isDarkMode ? Colors.white : Colors.grey[800], + ), + ), + SizedBox(width: 8.w), + Icon( + Icons.star, + color: Colors.amber, + size: 20.w, + ), + ], + ); + } + // 优质AI体验布局(左1右2) Widget _buildPremiumAILayout() { + final bool isDarkMode = Get.isDarkMode; return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ // 左侧大卡片 - AI助理 Expanded( flex: 1, - child: Stack( - children: [ - // 呼吸光效果 - Positioned.fill( - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(16.r), - gradient: RadialGradient( - colors: [ - Color(0xFF4ECDC4).withOpacity(0.6), - Colors.transparent, - ], - center: Alignment.topRight, - radius: 1.0, - ), - ), - child: AnimatedPulsing(), - ), - ), - // 卡片内容 - _buildFeatureCard( - title: 'AI全能助手', - description: '24小时专属顾问,解答问题、提供建议', - icon: Icons.smart_toy, - gradient: LinearGradient( - begin: Alignment.topLeft, - end: Alignment.bottomRight, - colors: [ - Color(0xFF4ECDC4), - Color(0xFF556270), - ], - ), - onTap: controller.exploreAIFeatures, - iconOnTop: true, - height: 175.h, // 增加高度 - ), - ], + child: _buildFeatureCard( + title: 'AI全能助手', + description: '24小时专属顾问,解答问题、提供建议', + icon: Icons.assistant, + gradient: LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + colors: [ + Color(0xFF0066CC).withOpacity(0.3), + Color(0xFF5E5CE6).withOpacity(0.3), + ], + ), + onTap: controller.exploreAIFeatures, + iconOnTop: true, + height: 175.h, // 增加高度 + isDarkMode: isDarkMode, + iconColor: const Color(0xFF0066CC), ), ), @@ -571,12 +493,14 @@ class HomeView extends GetView { begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [ - Color(0xFF5E72EB), - Color(0xFF4776E6), + Color(0xFF4CAF50).withOpacity(0.3), + Color(0xFF009688).withOpacity(0.3), ], ), onTap: controller.openTranslation, height: 83.h, // 增加高度 + isDarkMode: isDarkMode, + iconColor: const Color(0xFF4CAF50), ), SizedBox(height: 5.h), // 减少间距 @@ -590,12 +514,14 @@ class HomeView extends GetView { begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [ - Color(0xFFFF758C), - Color(0xFFFF7EB3), + Color(0xFFE91E63).withOpacity(0.3), + Color(0xFFFF5252).withOpacity(0.3), ], ), onTap: controller.openAIGirlfriend, height: 85.h, // 增加高度 + isDarkMode: isDarkMode, + iconColor: const Color(0xFFE91E63), ), ], ), @@ -613,8 +539,10 @@ class HomeView extends GetView { required VoidCallback onTap, double? height, bool iconOnTop = false, + bool isDarkMode = false, + Color iconColor = Colors.white, }) { - return InkWell( + return GestureDetector( onTap: onTap, child: Container( height: height ?? 175.h, @@ -624,132 +552,119 @@ class HomeView extends GetView { borderRadius: BorderRadius.circular(16.r), boxShadow: [ BoxShadow( - color: Colors.black.withOpacity(0.1), - blurRadius: 5, - offset: Offset(0, 2), + color: isDarkMode + ? Colors.black.withOpacity(0.2) + : Colors.grey.withOpacity(0.1), + blurRadius: 8, + offset: const Offset(0, 4), ), ], ), - child: iconOnTop - ? Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // 图标靠左而不是居中 - Container( - width: 45.w, - height: 45.w, - decoration: BoxDecoration( - color: Colors.white.withOpacity(0.2), - borderRadius: BorderRadius.circular(12.r), - ), - child: Icon( - icon, - color: Colors.white, - size: 24.w, - ), + child: Stack( + children: [ + // 图标 + if (iconOnTop) + // 大卡片布局 + Align( + alignment: Alignment.topLeft, + child: Container( + width: 45.w, + height: 45.w, + decoration: BoxDecoration( + color: iconColor.withOpacity(0.2), + shape: BoxShape.circle, ), - SizedBox(height: 8.h), - // 标题 - Text( - title, - style: TextStyle( - color: Colors.white, - fontSize: 16.sp, - fontWeight: FontWeight.bold, - shadows: [ - Shadow( - offset: Offset(0, 1), - blurRadius: 3.0, - color: Colors.black.withOpacity(0.3), - ), - ], - ), + child: Icon( + icon, + color: iconColor, + size: 24.w, + ), + ), + ) + else + // 小卡片布局 - 图标 + Align( + alignment: Alignment.topLeft, + child: Container( + width: 34.w, + height: 34.w, + decoration: BoxDecoration( + color: iconColor.withOpacity(0.2), + shape: BoxShape.circle, ), - SizedBox(height: 4.h), - // 描述 - Expanded( - child: Text( + child: Icon( + icon, + color: iconColor, + size: 18.w, + ), + ), + ), + + // 文本内容 + if (iconOnTop) + // 大卡片布局 - 文本 + Padding( + padding: EdgeInsets.only(top: 55.h), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + title, + style: TextStyle( + color: isDarkMode ? Colors.white : Colors.grey[800], + fontSize: 16.sp, + fontWeight: FontWeight.bold, + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + SizedBox(height: 4.h), + Text( description, style: TextStyle( - color: Colors.white, + color: isDarkMode ? Colors.grey[400] : Colors.grey[600], fontSize: 12.sp, - shadows: [ - Shadow( - offset: Offset(0, 1), - blurRadius: 2.0, - color: Colors.black.withOpacity(0.2), - ), - ], ), - maxLines: 3, + maxLines: 2, overflow: TextOverflow.ellipsis, ), - ), - ], + ], + ), ) - : Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // 图标 - Container( - width: 34.w, - height: 34.w, - decoration: BoxDecoration( - color: Colors.white.withOpacity(0.2), - borderRadius: BorderRadius.circular(8.r), - ), - child: Icon( - icon, - color: Colors.white, - size: 18.w, + else + // 小卡片布局 - 文本 + Padding( + padding: EdgeInsets.only(left: 44.w), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + title, + style: TextStyle( + color: isDarkMode ? Colors.white : Colors.grey[800], + fontSize: 14.sp, + fontWeight: FontWeight.bold, + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, ), - ), - SizedBox(width: 10.w), - // 文本内容 - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - // 标题 - Text( - title, - style: TextStyle( - color: Colors.white, - fontSize: 14.sp, - fontWeight: FontWeight.bold, - shadows: [ - Shadow( - offset: Offset(0, 1), - blurRadius: 3.0, - color: Colors.black.withOpacity(0.3), - ), - ], - ), - ), - SizedBox(height: 2.h), - // 描述 - Text( - description, - style: TextStyle( - color: Colors.white, - fontSize: 10.sp, - shadows: [ - Shadow( - offset: Offset(0, 1), - blurRadius: 2.0, - color: Colors.black.withOpacity(0.2), - ), - ], - ), - maxLines: 2, - overflow: TextOverflow.ellipsis, - ), - ], + SizedBox(height: 2.h), + Text( + description, + style: TextStyle( + color: isDarkMode ? Colors.grey[400] : Colors.grey[600], + fontSize: 10.sp, + ), + maxLines: 2, + overflow: TextOverflow.ellipsis, ), - ), - ], + ], + ), ), + ], + ), ), ); } diff --git a/lib/modules/login/controllers/login_controller.dart b/lib/modules/login/controllers/login_controller.dart index c72d5f623..75ea11823 100644 --- a/lib/modules/login/controllers/login_controller.dart +++ b/lib/modules/login/controllers/login_controller.dart @@ -200,16 +200,16 @@ class LoginController extends GetxController { // 登录 Future login() async { // 暂时关闭验证码验证 - if (!isVerificationCodeComplete()) { - Get.snackbar( - '提示', - '请输入完整的验证码', - snackPosition: SnackPosition.TOP, - backgroundColor: Colors.red.withOpacity(0.1), - colorText: Colors.red, - ); - return; - } + // if (!isVerificationCodeComplete()) { + // Get.snackbar( + // '提示', + // '请输入完整的验证码', + // snackPosition: SnackPosition.TOP, + // backgroundColor: Colors.red.withOpacity(0.1), + // colorText: Colors.red, + // ); + // return; + // } _isLoading.value = true; diff --git a/lib/modules/login/views/login_view.dart b/lib/modules/login/views/login_view.dart index 7b0528ebe..c4f791c82 100644 --- a/lib/modules/login/views/login_view.dart +++ b/lib/modules/login/views/login_view.dart @@ -10,53 +10,49 @@ class LoginView extends GetView { @override Widget build(BuildContext context) { - // 使用浅色主题 - return Theme( - data: AppTheme.lightTheme, - child: Scaffold( - body: SafeArea( - child: Obx(() => controller.viewState == LoginViewState.welcome - ? _buildWelcomeView() - : _buildVerificationView(context)), - ), + final isDarkMode = Theme.of(context).brightness == Brightness.dark; + + return Scaffold( + backgroundColor: isDarkMode ? Colors.black : Colors.grey[50], + body: SafeArea( + child: Obx(() => controller.viewState == LoginViewState.welcome + ? _buildWelcomeView(isDarkMode) + : _buildVerificationView(context, isDarkMode)), ), ); } // 欢迎页面 - Widget _buildWelcomeView() { + Widget _buildWelcomeView(bool isDarkMode) { return Padding( padding: EdgeInsets.all(24.w), child: SingleChildScrollView( physics: const BouncingScrollPhysics(), child: Column( children: [ - // 状态栏 - _buildStatusBar(), - // 应用标志和标题 SizedBox(height: 32.h), - _buildAppLogo(), + _buildAppLogo(isDarkMode), // 欢迎文本 SizedBox(height: 32.h), - _buildWelcomeText(), + _buildWelcomeText(isDarkMode), // 输入框和继续按钮 SizedBox(height: 24.h), - _buildInputField(), + _buildInputField(isDarkMode), SizedBox(height: 16.h), - _buildVerificationInputField(), + _buildVerificationInputField(isDarkMode), SizedBox(height: 16.h), - _buildContinueButton(), + _buildContinueButton(isDarkMode), // 社交媒体登录 SizedBox(height: 32.h), - _buildSocialLoginSection(), + _buildSocialLoginSection(isDarkMode), // 用户协议 SizedBox(height: 40.h), - _buildTermsAndPrivacy(), + _buildTermsAndPrivacy(isDarkMode), SizedBox(height: 24.h), ], ), @@ -65,7 +61,7 @@ class LoginView extends GetView { } // 验证码页面 - Widget _buildVerificationView(BuildContext context) { + Widget _buildVerificationView(BuildContext context, bool isDarkMode) { return Padding( padding: EdgeInsets.all(24.w), child: SingleChildScrollView( @@ -74,27 +70,27 @@ class LoginView extends GetView { crossAxisAlignment: CrossAxisAlignment.start, children: [ // 返回按钮 - _buildBackButton(), + _buildBackButton(isDarkMode), // 验证码标题 SizedBox(height: 24.h), - _buildVerificationTitle(), + _buildVerificationTitle(isDarkMode), // 验证码输入框 SizedBox(height: 32.h), - _buildVerificationInputs(context), + _buildVerificationInputs(context, isDarkMode), // 重新发送验证码 SizedBox(height: 16.h), - _buildResendButton(), + _buildResendButton(isDarkMode), // 登录按钮 SizedBox(height: 32.h), - _buildLoginButton(), + _buildLoginButton(isDarkMode), // 使用密码登录 SizedBox(height: 16.h), - _buildUsePasswordButton(), + _buildUsePasswordButton(isDarkMode), SizedBox(height: 24.h), ], ), @@ -102,33 +98,8 @@ class LoginView extends GetView { ); } - // 状态栏 - Widget _buildStatusBar() { - return Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - '9:41', - style: TextStyle( - fontSize: 12.sp, - color: Colors.black54, - ), - ), - Row( - children: [ - Icon(Icons.signal_cellular_4_bar, size: 12.sp, color: Colors.black54), - SizedBox(width: 4.w), - Icon(Icons.wifi, size: 12.sp, color: Colors.black54), - SizedBox(width: 4.w), - Icon(Icons.battery_full, size: 12.sp, color: Colors.black54), - ], - ), - ], - ); - } - // 应用标志和标题 - Widget _buildAppLogo() { + Widget _buildAppLogo(bool isDarkMode) { return Column( children: [ Container( @@ -161,7 +132,7 @@ class LoginView extends GetView { style: TextStyle( fontSize: 24.sp, fontWeight: FontWeight.bold, - color: Colors.black, + color: isDarkMode ? Colors.white : Colors.black, ), ), SizedBox(height: 8.h), @@ -169,7 +140,7 @@ class LoginView extends GetView { '连接世界,超越声音', style: TextStyle( fontSize: 14.sp, - color: Colors.black54, + color: isDarkMode ? Colors.grey[400] : Colors.black54, ), ), ], @@ -177,7 +148,7 @@ class LoginView extends GetView { } // 欢迎文本 - Widget _buildWelcomeText() { + Widget _buildWelcomeText(bool isDarkMode) { return Column( children: [ Text( @@ -185,7 +156,7 @@ class LoginView extends GetView { style: TextStyle( fontSize: 20.sp, fontWeight: FontWeight.w600, - color: Colors.black, + color: isDarkMode ? Colors.white : Colors.black, ), ), SizedBox(height: 4.h), @@ -193,7 +164,7 @@ class LoginView extends GetView { '请使用手机号或邮箱登录/注册', style: TextStyle( fontSize: 14.sp, - color: Colors.black54, + color: isDarkMode ? Colors.grey[400] : Colors.black54, ), ), ], @@ -201,10 +172,10 @@ class LoginView extends GetView { } // 输入框 - Widget _buildInputField() { + Widget _buildInputField(bool isDarkMode) { return Container( decoration: BoxDecoration( - color: 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( @@ -213,7 +184,7 @@ class LoginView extends GetView { children: [ Icon( Icons.person_outline, - color: Colors.black54, + color: isDarkMode ? Colors.grey[400] : Colors.black54, size: 20.sp, ), SizedBox(width: 12.w), @@ -224,13 +195,15 @@ class LoginView extends GetView { hintText: '手机号码或邮箱', hintStyle: TextStyle( fontSize: 14.sp, - color: Colors.black38, + color: isDarkMode ? Colors.grey[600] : Colors.black38, ), border: InputBorder.none, + fillColor: Colors.transparent, + filled: true, ), style: TextStyle( fontSize: 14.sp, - color: Colors.black, + color: isDarkMode ? Colors.white : Colors.black, ), ), ), @@ -241,10 +214,10 @@ class LoginView extends GetView { } // 验证码输入框 - Widget _buildVerificationInputField() { + Widget _buildVerificationInputField(bool isDarkMode) { return Container( decoration: BoxDecoration( - color: 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( @@ -253,7 +226,7 @@ class LoginView extends GetView { children: [ Icon( Icons.lock_outline, - color: Colors.black54, + color: isDarkMode ? Colors.grey[400] : Colors.black54, size: 20.sp, ), SizedBox(width: 12.w), @@ -266,14 +239,16 @@ class LoginView extends GetView { hintText: '验证码', hintStyle: TextStyle( fontSize: 14.sp, - color: Colors.black38, + color: isDarkMode ? Colors.grey[600] : Colors.black38, ), border: InputBorder.none, counterText: '', + fillColor: Colors.transparent, + filled: true, ), style: TextStyle( fontSize: 14.sp, - color: Colors.black, + color: isDarkMode ? Colors.white : Colors.black, ), ), ), @@ -283,9 +258,9 @@ class LoginView extends GetView { : controller.getVerificationCode, style: TextButton.styleFrom( padding: EdgeInsets.symmetric(horizontal: 16.w), - foregroundColor: const Color(0xFF0066CC), + foregroundColor: const Color(0xFF3B82F6), backgroundColor: Colors.transparent, - disabledForegroundColor: Colors.black38, + disabledForegroundColor: isDarkMode ? Colors.grey[600] : Colors.grey[400], ), child: Text( controller.countdownSeconds > 0 @@ -304,34 +279,36 @@ class LoginView extends GetView { } // 继续按钮 - Widget _buildContinueButton() { + Widget _buildContinueButton(bool isDarkMode) { return SizedBox( width: double.infinity, child: Obx(() => ElevatedButton( - onPressed: controller.isLoading ? null : controller.loginWithVerificationCode, + onPressed: controller.isLoading ? null : () => controller.login(), style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFF0066CC), - padding: EdgeInsets.symmetric(vertical: 16.h), + foregroundColor: Colors.white, + padding: EdgeInsets.symmetric(vertical: 14.h), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16.r), ), elevation: 0, + disabledBackgroundColor: const Color(0xFF0066CC).withOpacity(0.7), + disabledForegroundColor: Colors.white, ), child: controller.isLoading ? SizedBox( - width: 20.w, - height: 20.w, - child: const CircularProgressIndicator( - strokeWidth: 2, - valueColor: AlwaysStoppedAnimation(Colors.white), + height: 20.h, + width: 20.h, + child: CircularProgressIndicator( + strokeWidth: 2.w, + valueColor: const AlwaysStoppedAnimation(Colors.white), ), ) : Text( - '登录', + '继续', style: TextStyle( fontSize: 16.sp, - fontWeight: FontWeight.w500, - color: Colors.white, + fontWeight: FontWeight.w600, ), ), )), @@ -339,32 +316,32 @@ class LoginView extends GetView { } // 社交媒体登录部分 - Widget _buildSocialLoginSection() { + Widget _buildSocialLoginSection(bool isDarkMode) { return Column( children: [ Row( children: [ - Expanded(child: Divider(color: Colors.black12)), + Expanded(child: Divider(color: isDarkMode ? Colors.grey[800] : Colors.grey[300])), Padding( padding: EdgeInsets.symmetric(horizontal: 16.w), child: Text( '或使用以下方式登录', style: TextStyle( fontSize: 12.sp, - color: Colors.black45, + color: isDarkMode ? Colors.grey[500] : Colors.grey[600], ), ), ), - Expanded(child: Divider(color: Colors.black12)), + Expanded(child: Divider(color: isDarkMode ? Colors.grey[800] : Colors.grey[300])), ], ), SizedBox(height: 24.h), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - _buildSocialButton(FontAwesomeIcons.google, Colors.red), + _buildSocialButton(FontAwesomeIcons.google, Colors.red, isDarkMode), SizedBox(width: 24.w), - _buildSocialButton(FontAwesomeIcons.weixin, Colors.green), + _buildSocialButton(FontAwesomeIcons.weixin, Colors.green, isDarkMode), ], ), ], @@ -372,30 +349,41 @@ class LoginView extends GetView { } // 社交媒体按钮 - Widget _buildSocialButton(IconData icon, Color color) { + Widget _buildSocialButton(IconData icon, Color color, bool isDarkMode) { return Container( width: 48.w, height: 48.w, decoration: BoxDecoration( - color: Colors.grey.withOpacity(0.1), + color: isDarkMode ? Colors.grey[800] : Colors.white, borderRadius: BorderRadius.circular(24.r), + boxShadow: isDarkMode ? [] : [ + BoxShadow( + color: Colors.grey.withOpacity(0.2), + blurRadius: 4, + offset: const Offset(0, 2), + ), + ], ), child: IconButton( - icon: Icon(icon, color: color, size: 20.sp), + icon: FaIcon( + icon, + color: color, + size: 20.sp, + ), onPressed: () {}, ), ); } // 用户协议和隐私政策 - Widget _buildTermsAndPrivacy() { + Widget _buildTermsAndPrivacy(bool isDarkMode) { return Column( children: [ Text( '登录/注册即表示你同意', style: TextStyle( fontSize: 12.sp, - color: Colors.black45, + color: isDarkMode ? Colors.grey[500] : Colors.grey[600], ), ), SizedBox(height: 4.h), @@ -408,7 +396,7 @@ class LoginView extends GetView { '《用户协议》', style: TextStyle( fontSize: 12.sp, - color: const Color(0xFF0066CC), + color: const Color(0xFF3B82F6), ), ), ), @@ -416,7 +404,7 @@ class LoginView extends GetView { ' 和 ', style: TextStyle( fontSize: 12.sp, - color: Colors.black45, + color: isDarkMode ? Colors.grey[500] : Colors.grey[600], ), ), GestureDetector( @@ -425,7 +413,7 @@ class LoginView extends GetView { '《隐私政策》', style: TextStyle( fontSize: 12.sp, - color: const Color(0xFF0066CC), + color: const Color(0xFF3B82F6), ), ), ), @@ -436,23 +424,27 @@ class LoginView extends GetView { } // 返回按钮 - Widget _buildBackButton() { + Widget _buildBackButton(bool isDarkMode) { return Container( width: 40.w, height: 40.w, decoration: BoxDecoration( - color: Colors.grey.withOpacity(0.1), + color: isDarkMode ? Colors.grey[800] : Colors.grey.withOpacity(0.1), borderRadius: BorderRadius.circular(20.r), ), child: IconButton( - icon: Icon(Icons.arrow_back, color: Colors.black54, size: 20.sp), - onPressed: controller.showWelcomeView, + icon: Icon( + Icons.arrow_back, + color: isDarkMode ? Colors.grey[400] : Colors.grey[600], + size: 20.sp, + ), + onPressed: () => controller.showWelcomeView(), ), ); } // 验证码标题 - Widget _buildVerificationTitle() { + Widget _buildVerificationTitle(bool isDarkMode) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -461,7 +453,7 @@ class LoginView extends GetView { style: TextStyle( fontSize: 20.sp, fontWeight: FontWeight.w600, - color: Colors.black, + color: isDarkMode ? Colors.white : Colors.black, ), ), SizedBox(height: 8.h), @@ -469,7 +461,7 @@ class LoginView extends GetView { '验证码已发送至 ${controller.displayContact}', style: TextStyle( fontSize: 14.sp, - color: Colors.black54, + color: isDarkMode ? Colors.grey[400] : Colors.grey[600], ), )), ], @@ -477,23 +469,23 @@ class LoginView extends GetView { } // 验证码输入框 - Widget _buildVerificationInputs(BuildContext context) { + Widget _buildVerificationInputs(BuildContext context, bool isDarkMode) { return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: List.generate(4, (index) => _buildVerificationInput(index, context)), + children: List.generate(4, (index) => _buildVerificationInput(index, context, isDarkMode)), ); } // 单个验证码输入框 - Widget _buildVerificationInput(int index, BuildContext context) { + Widget _buildVerificationInput(int index, BuildContext context, bool isDarkMode) { return Container( width: 60.w, height: 60.w, decoration: BoxDecoration( - color: Colors.grey.withOpacity(0.1), - borderRadius: BorderRadius.circular(16.r), + color: isDarkMode ? Colors.grey[900]!.withOpacity(0.3) : Colors.grey.withOpacity(0.1), + borderRadius: BorderRadius.circular(12.r), border: Border.all( - color: Colors.black12, + color: isDarkMode ? Colors.grey[700]! : Colors.grey[300]!, width: 1, ), ), @@ -508,14 +500,16 @@ class LoginView extends GetView { FocusScope.of(context).nextFocus(); } }, - decoration: const InputDecoration( + decoration: InputDecoration( counterText: '', border: InputBorder.none, + fillColor: Colors.transparent, + filled: true, ), style: TextStyle( fontSize: 24.sp, fontWeight: FontWeight.w600, - color: Colors.black, + color: isDarkMode ? Colors.white : Colors.black, ), ), ), @@ -523,7 +517,7 @@ class LoginView extends GetView { } // 重新发送验证码按钮 - Widget _buildResendButton() { + Widget _buildResendButton(bool isDarkMode) { return Center( child: Obx(() => TextButton.icon( onPressed: controller.countdownSeconds > 0 @@ -533,8 +527,8 @@ class LoginView extends GetView { Icons.refresh, size: 14.sp, color: controller.countdownSeconds > 0 - ? Colors.black38 - : const Color(0xFF0066CC), + ? (isDarkMode ? Colors.grey[600] : Colors.grey[500]) + : const Color(0xFF3B82F6), ), label: Text( controller.countdownSeconds > 0 @@ -543,8 +537,8 @@ class LoginView extends GetView { style: TextStyle( fontSize: 14.sp, color: controller.countdownSeconds > 0 - ? Colors.black38 - : const Color(0xFF0066CC), + ? (isDarkMode ? Colors.grey[600] : Colors.grey[500]) + : const Color(0xFF3B82F6), ), ), )), @@ -552,34 +546,36 @@ class LoginView extends GetView { } // 登录按钮 - Widget _buildLoginButton() { + Widget _buildLoginButton(bool isDarkMode) { return SizedBox( width: double.infinity, child: Obx(() => ElevatedButton( onPressed: controller.isLoading ? null : controller.login, style: ElevatedButton.styleFrom( - backgroundColor: const Color(0xFF0066CC), - padding: EdgeInsets.symmetric(vertical: 16.h), + backgroundColor: const Color(0xFF3B82F6), + foregroundColor: Colors.white, + padding: EdgeInsets.symmetric(vertical: 14.h), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16.r), ), elevation: 0, + disabledBackgroundColor: const Color(0xFF3B82F6).withOpacity(0.7), + disabledForegroundColor: Colors.white, ), child: controller.isLoading ? SizedBox( - width: 20.w, - height: 20.w, - child: const CircularProgressIndicator( - strokeWidth: 2, - valueColor: AlwaysStoppedAnimation(Colors.white), + height: 20.h, + width: 20.h, + child: CircularProgressIndicator( + strokeWidth: 2.w, + valueColor: const AlwaysStoppedAnimation(Colors.white), ), ) : Text( '登录', style: TextStyle( fontSize: 16.sp, - fontWeight: FontWeight.w500, - color: Colors.white, + fontWeight: FontWeight.w600, ), ), )), @@ -587,7 +583,7 @@ class LoginView extends GetView { } // 使用密码登录按钮 - Widget _buildUsePasswordButton() { + Widget _buildUsePasswordButton(bool isDarkMode) { return Center( child: TextButton( onPressed: controller.usePasswordLogin, @@ -595,7 +591,7 @@ class LoginView extends GetView { '使用密码登录', style: TextStyle( fontSize: 14.sp, - color: const Color(0xFF0066CC), + color: isDarkMode ? const Color(0xFF3B82F6) : const Color(0xFF3B82F6), ), ), ), diff --git a/lib/modules/pairing/views/pairing_view.dart b/lib/modules/pairing/views/pairing_view.dart index 993c12808..b6814481f 100644 --- a/lib/modules/pairing/views/pairing_view.dart +++ b/lib/modules/pairing/views/pairing_view.dart @@ -10,35 +10,34 @@ class PairingView extends GetView { @override Widget build(BuildContext context) { - // 使用浅色主题 - return Theme( - data: AppTheme.lightTheme, - child: Scaffold( - body: SafeArea( - child: Stack( - children: [ - // 主要内容 - _buildMainContent(), - ], - ), - ), - bottomNavigationBar: Opacity( - opacity: 0.5, // 保持半透明效果 - child: const CommonBottomNav(currentIndex: 0), + final bool isDarkMode = Theme.of(context).brightness == Brightness.dark; + + return Scaffold( + backgroundColor: isDarkMode ? Colors.black : Colors.white, + body: SafeArea( + child: Stack( + children: [ + // 主要内容 + _buildMainContent(isDarkMode), + ], ), ), + bottomNavigationBar: Opacity( + opacity: 0.5, // 保持半透明效果 + child: const CommonBottomNav(currentIndex: 0), + ), ); } // 主要内容 - Widget _buildMainContent() { + Widget _buildMainContent(bool isDarkMode) { return Padding( padding: EdgeInsets.fromLTRB(24.w, 40.h, 24.w, 24.h), child: SingleChildScrollView( child: Column( children: [ // 标题部分 - _buildHeader(), + _buildHeader(isDarkMode), // 设备动画 SizedBox(height: 40.h), @@ -46,11 +45,11 @@ class PairingView extends GetView { // 搜索状态 SizedBox(height: 40.h), - _buildSearchStatus(), + _buildSearchStatus(isDarkMode), // 底部按钮 SizedBox(height: 60.h), - _buildBottomButtons(), + _buildBottomButtons(isDarkMode), SizedBox(height: 80.h), // 留出底部导航的空间 ], ), @@ -59,7 +58,7 @@ class PairingView extends GetView { } // 标题部分 - Widget _buildHeader() { + Widget _buildHeader(bool isDarkMode) { return Column( children: [ Text( @@ -67,7 +66,7 @@ class PairingView extends GetView { style: TextStyle( fontSize: 24.sp, fontWeight: FontWeight.bold, - color: Colors.black, + color: isDarkMode ? Colors.white : Colors.black, ), ), SizedBox(height: 8.h), @@ -75,7 +74,7 @@ class PairingView extends GetView { '连接世界,超越声音', style: TextStyle( fontSize: 14.sp, - color: Colors.black54, + color: isDarkMode ? Colors.white70 : Colors.black54, ), ), ], @@ -170,7 +169,7 @@ class PairingView extends GetView { } // 搜索状态 - Widget _buildSearchStatus() { + Widget _buildSearchStatus(bool isDarkMode) { return Obx(() { switch (controller.searchStatus) { case SearchStatus.searching: @@ -181,7 +180,7 @@ class PairingView extends GetView { style: TextStyle( fontSize: 18.sp, fontWeight: FontWeight.w600, - color: Colors.black, + color: isDarkMode ? Colors.white : Colors.black, ), ), SizedBox(height: 8.h), @@ -189,7 +188,7 @@ class PairingView extends GetView { '请打开耳机充电盒,将耳机放入您的耳朵', style: TextStyle( fontSize: 14.sp, - color: Colors.black54, + color: isDarkMode ? Colors.white70 : Colors.black54, ), ), ], @@ -217,7 +216,7 @@ class PairingView extends GetView { '正在跳转到主页...', style: TextStyle( fontSize: 14.sp, - color: Colors.black54, + color: isDarkMode ? Colors.white70 : Colors.black54, ), ), ], @@ -245,7 +244,7 @@ class PairingView extends GetView { controller.errorMessage, style: TextStyle( fontSize: 14.sp, - color: Colors.black54, + color: isDarkMode ? Colors.white70 : Colors.black54, ), textAlign: TextAlign.center, ), @@ -288,7 +287,7 @@ class PairingView extends GetView { '请确保耳机已开机并在附近' : controller.errorMessage, style: TextStyle( fontSize: 14.sp, - color: Colors.black54, + color: isDarkMode ? Colors.white70 : Colors.black54, ), textAlign: TextAlign.center, ), @@ -318,7 +317,7 @@ class PairingView extends GetView { '请在系统设置中配对您的设备' : controller.errorMessage, style: TextStyle( fontSize: 14.sp, - color: Colors.black54, + color: isDarkMode ? Colors.white70 : Colors.black54, ), textAlign: TextAlign.center, ), @@ -344,7 +343,7 @@ class PairingView extends GetView { } // 底部按钮 - Widget _buildBottomButtons() { + Widget _buildBottomButtons(bool isDarkMode) { return Column( children: [ SizedBox( @@ -352,8 +351,8 @@ class PairingView extends GetView { child: ElevatedButton( onPressed: controller.refreshSearch, style: ElevatedButton.styleFrom( - backgroundColor: Colors.grey.withOpacity(0.1), - foregroundColor: Colors.black, + backgroundColor: isDarkMode ? Color(0xFF1A1A1A) : Colors.grey.withOpacity(0.1), + foregroundColor: isDarkMode ? Colors.white : Colors.black, padding: EdgeInsets.symmetric(vertical: 16.h), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16.r), diff --git a/lib/modules/settings/controllers/settings_controller.dart b/lib/modules/settings/controllers/settings_controller.dart index ba561cc20..46e7b0fea 100644 --- a/lib/modules/settings/controllers/settings_controller.dart +++ b/lib/modules/settings/controllers/settings_controller.dart @@ -1,12 +1,31 @@ import 'package:get/get.dart'; import 'package:flutter/material.dart'; +import '../../../app/theme/theme_service.dart'; class SettingsController extends GetxController { + // 主题服务 + final ThemeService _themeService = ThemeService(); + + // 是否是暗黑模式 + final RxBool isDarkMode = false.obs; + // 翻译语言对 final RxString sourceLanguage = '中文'.obs; final RxString targetLanguage = '英文'.obs; final List availableLanguages = ['中文', '英文', '日文', '韩文', '法文', '德文', '西班牙文', '俄文']; + @override + void onInit() { + super.onInit(); + isDarkMode.value = _themeService.isSavedDarkMode(); + } + + // 切换主题 + void toggleTheme() { + _themeService.changeThemeMode(); + isDarkMode.value = _themeService.isSavedDarkMode(); + } + void setSourceLanguage(String language) { sourceLanguage.value = language; } diff --git a/lib/modules/settings/views/settings_view.dart b/lib/modules/settings/views/settings_view.dart index 60f95fb09..36136f5a6 100644 --- a/lib/modules/settings/views/settings_view.dart +++ b/lib/modules/settings/views/settings_view.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'dart:ui'; import '../controllers/settings_controller.dart'; import '../../../core/widgets/common_bottom_nav.dart'; import '../../../core/routes/app_routes.dart'; @@ -10,33 +11,38 @@ class SettingsView extends GetView { @override Widget build(BuildContext context) { + final isDarkMode = Theme.of(context).brightness == Brightness.dark; + return Scaffold( - backgroundColor: Colors.grey[50], + backgroundColor: isDarkMode ? Colors.black : Colors.grey[50], appBar: AppBar( - backgroundColor: Colors.white, + backgroundColor: isDarkMode ? Colors.black : Colors.white, elevation: 0.5, title: Text( '设置', style: TextStyle( fontSize: 17.sp, fontWeight: FontWeight.w600, - color: Colors.black, + color: isDarkMode ? Colors.white : Colors.black, ), ), centerTitle: true, leading: IconButton( - icon: const Icon(Icons.arrow_back_ios, color: Colors.black54), + icon: Icon( + Icons.arrow_back_ios, + color: isDarkMode ? Colors.white70 : Colors.black54 + ), onPressed: () => Get.back(), ), ), body: ListView( padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 16.h), children: [ - _buildUserInfoCard(), + _buildUserInfoCard(isDarkMode), SizedBox(height: 20.h), - _buildSystemSettingsSection(), + _buildSystemSettingsSection(isDarkMode), SizedBox(height: 20.h), - _buildAboutSection(), + _buildAboutSection(isDarkMode), SizedBox(height: 50.h), ], ), @@ -45,128 +51,146 @@ class SettingsView extends GetView { } // 用户信息卡片 - Widget _buildUserInfoCard() { + Widget _buildUserInfoCard(bool isDarkMode) { return Container( padding: EdgeInsets.all(16.w), decoration: BoxDecoration( - gradient: const LinearGradient( - colors: [Color(0xFFE3F2FD), Color(0xFFF3E5F5)], + gradient: LinearGradient( + colors: isDarkMode + ? [ + const Color(0xFF1A1A1A).withOpacity(0.7), + const Color(0xFF2A2A2A).withOpacity(0.7) + ] + : [ + const Color(0xFFE3F2FD), + const Color(0xFFF3E5F5) + ], begin: Alignment.topLeft, end: Alignment.bottomRight, ), borderRadius: BorderRadius.circular(16.r), boxShadow: [ BoxShadow( - color: Colors.black.withOpacity(0.05), + color: isDarkMode + ? Colors.black.withOpacity(0.2) + : Colors.black.withOpacity(0.05), blurRadius: 10, offset: const Offset(0, 2), ), ], ), - child: Row( - children: [ - Container( - width: 60.w, - height: 60.w, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(30.r), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.1), - blurRadius: 8, - offset: const Offset(0, 2), + child: ClipRRect( + borderRadius: BorderRadius.circular(16.r), + child: BackdropFilter( + filter: isDarkMode ? ImageFilter.blur(sigmaX: 10, sigmaY: 10) : ImageFilter.blur(sigmaX: 0, sigmaY: 0), + child: Row( + children: [ + Container( + width: 60.w, + height: 60.w, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(30.r), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.1), + blurRadius: 8, + offset: const Offset(0, 2), + ), + ], ), - ], - ), - child: ClipRRect( - borderRadius: BorderRadius.circular(30.r), - child: Image.network( - 'https://images.unsplash.com/photo-1534528741775-53994a69daeb?ixlib=rb-1.2.1&auto=format&fit=crop&w=200&q=80', - fit: BoxFit.cover, - ), - ), - ), - SizedBox(width: 16.w), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - '林美珍', - style: TextStyle( - fontSize: 18.sp, - fontWeight: FontWeight.w600, - color: Colors.black87, + child: ClipRRect( + borderRadius: BorderRadius.circular(30.r), + child: Image.network( + 'https://images.unsplash.com/photo-1534528741775-53994a69daeb?ixlib=rb-1.2.1&auto=format&fit=crop&w=200&q=80', + fit: BoxFit.cover, ), ), - SizedBox(height: 4.h), - Row( + ), + SizedBox(width: 16.w), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ - Container( - padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 2.h), - decoration: BoxDecoration( - color: Colors.blue[600], - borderRadius: BorderRadius.circular(10.r), - ), - child: Text( - '高级会员', - style: TextStyle( - fontSize: 10.sp, - color: Colors.white, - ), + Text( + '林美珍', + style: TextStyle( + fontSize: 18.sp, + fontWeight: FontWeight.w600, + color: isDarkMode ? Colors.white : Colors.black87, ), ), - SizedBox(width: 8.w), - Flexible( - child: Text( - '已连接设备: DeepVoice Pro', - style: TextStyle( - fontSize: 12.sp, - color: Colors.black54, + SizedBox(height: 4.h), + Row( + children: [ + Container( + padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 2.h), + decoration: BoxDecoration( + color: Colors.blue[600], + borderRadius: BorderRadius.circular(10.r), + ), + child: Text( + '高级会员', + style: TextStyle( + fontSize: 10.sp, + color: Colors.white, + ), + ), ), - overflow: TextOverflow.ellipsis, + SizedBox(width: 8.w), + Flexible( + child: Text( + '已连接设备: DeepVoice Pro', + style: TextStyle( + fontSize: 12.sp, + color: isDarkMode ? Colors.white70 : Colors.black54, + ), + overflow: TextOverflow.ellipsis, + ), + ), + ], + ), + SizedBox(height: 4.h), + Text( + '账号ID: deepvoice_834291', + style: TextStyle( + fontSize: 12.sp, + color: isDarkMode ? Colors.white70 : Colors.black54, ), ), ], ), - SizedBox(height: 4.h), - Text( - '账号ID: deepvoice_834291', - style: TextStyle( - fontSize: 12.sp, - color: Colors.black54, - ), + ), + Container( + width: 32.w, + height: 32.w, + decoration: BoxDecoration( + color: isDarkMode + ? Colors.white.withOpacity(0.1) + : Colors.white.withOpacity(0.7), + borderRadius: BorderRadius.circular(16.r), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.05), + blurRadius: 4, + offset: const Offset(0, 1), + ), + ], ), - ], - ), - ), - Container( - width: 32.w, - height: 32.w, - decoration: BoxDecoration( - color: Colors.white.withOpacity(0.7), - borderRadius: BorderRadius.circular(16.r), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.05), - blurRadius: 4, - offset: const Offset(0, 1), + child: Icon( + Icons.edit, + size: 16.w, + color: isDarkMode ? Colors.white70 : Colors.grey[600], ), - ], - ), - child: Icon( - Icons.edit, - size: 16.w, - color: Colors.grey[600], - ), + ), + ], ), - ], + ), ), ); } // 系统设置部分 - Widget _buildSystemSettingsSection() { + Widget _buildSystemSettingsSection(bool isDarkMode) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -177,100 +201,156 @@ class SettingsView extends GetView { style: TextStyle( fontSize: 12.sp, fontWeight: FontWeight.w500, - color: Colors.blue[600], + color: isDarkMode ? Colors.blue[400] : Colors.blue[600], letterSpacing: 1, ), ), ), Container( decoration: BoxDecoration( - color: Colors.white, + color: isDarkMode ? Colors.white.withOpacity(0.05) : Colors.white, borderRadius: BorderRadius.circular(16.r), boxShadow: [ BoxShadow( - color: Colors.black.withOpacity(0.05), + color: isDarkMode + ? Colors.black.withOpacity(0.2) + : Colors.black.withOpacity(0.05), blurRadius: 10, offset: const Offset(0, 2), ), ], ), - child: Column( - children: [ - // 通知设置 - _buildSimpleNavigationSetting( - title: '通知设置', - subtitle: '管理应用推送和提醒', - icon: Icons.notifications_none, - iconBgColor: Colors.indigo[100]!, - iconColor: Colors.indigo[600]!, - onTap: () { - // 打开通知设置页面 - }, - ), - const Divider(height: 1), - - // 备份与恢复 - _buildNavigationSetting( - title: '备份与恢复', - subtitle: '备份设置和AI互动历史', - icon: Icons.cloud_upload_outlined, - iconBgColor: Colors.cyan[100]!, - iconColor: Colors.cyan[600]!, - value: '上次备份: 今天', - valueStyle: TextStyle( - fontSize: 12.sp, - color: Colors.grey[500], - ), - onTap: () { - // 打开备份设置页面 - }, - ), - const Divider(height: 1), - - // 隐私设置 - _buildSimpleNavigationSetting( - title: '隐私设置', - subtitle: '管理数据收集和权限', - icon: Icons.shield_outlined, - iconBgColor: Colors.purple[100]!, - iconColor: Colors.purple[600]!, - onTap: () { - // 打开隐私设置页面 - }, - ), - const Divider(height: 1), - - // 退出登录 - _buildSimpleNavigationSetting( - title: '退出登录', - icon: Icons.logout, - iconBgColor: Colors.red[50]!, - iconColor: Colors.red[600]!, - titleColor: Colors.red[600]!, - onTap: () { - // 退出登录确认对话框 - Get.dialog( - AlertDialog( - title: const Text('退出登录'), - content: const Text('确定要退出当前账号吗?'), - actions: [ - TextButton( - onPressed: () => Get.back(), - child: const Text('取消'), - ), - TextButton( - onPressed: () { - Get.back(); - controller.signOut(); - }, - child: const Text('确定'), - ), - ], + child: ClipRRect( + borderRadius: BorderRadius.circular(16.r), + child: BackdropFilter( + 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]!, + titleColor: isDarkMode ? Colors.white : null, + subtitleColor: isDarkMode ? Colors.white70 : null, + onTap: () { + // 打开通知设置页面 + }, + isDarkMode: isDarkMode, + ), + Divider(height: 1, color: isDarkMode ? Colors.white.withOpacity(0.1) : Colors.grey[200]), + + // 主题设置 + Obx(() => _buildToggleSetting( + title: '暗黑模式', + subtitle: '切换应用的明暗主题', + icon: controller.isDarkMode.value ? Icons.dark_mode : Icons.light_mode, + iconBgColor: controller.isDarkMode.value + ? Colors.indigo[900]!.withOpacity(0.3) + : Colors.amber[100]!, + iconColor: controller.isDarkMode.value + ? Colors.indigo[300]! + : Colors.amber[600]!, + value: controller.isDarkMode.value, + onChanged: (value) { + controller.toggleTheme(); + }, + isDarkMode: isDarkMode, + )), + Divider(height: 1, color: isDarkMode ? Colors.white.withOpacity(0.1) : Colors.grey[200]), + + // 备份与恢复 + _buildNavigationSetting( + title: '备份与恢复', + subtitle: '备份设置和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: '上次备份: 今天', + valueStyle: TextStyle( + fontSize: 12.sp, + color: isDarkMode ? Colors.white70 : Colors.grey[500], ), - ); - }, + onTap: () { + // 打开备份设置页面 + }, + isDarkMode: isDarkMode, + ), + Divider(height: 1, color: isDarkMode ? Colors.white.withOpacity(0.1) : Colors.grey[200]), + + // 隐私设置 + _buildSimpleNavigationSetting( + title: '隐私设置', + subtitle: '管理数据收集和权限', + icon: Icons.shield_outlined, + 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: () { + // 打开隐私设置页面 + }, + isDarkMode: isDarkMode, + ), + Divider(height: 1, color: isDarkMode ? Colors.white.withOpacity(0.1) : Colors.grey[200]), + + // 退出登录 + _buildSimpleNavigationSetting( + title: '退出登录', + icon: Icons.logout, + 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]!, + onTap: () { + // 退出登录确认对话框 + Get.dialog( + AlertDialog( + backgroundColor: isDarkMode ? Colors.grey[900] : Colors.white, + title: Text( + '退出登录', + style: TextStyle( + color: isDarkMode ? Colors.white : Colors.black87, + ), + ), + content: Text( + '确定要退出当前账号吗?', + style: TextStyle( + color: isDarkMode ? Colors.white70 : Colors.black54, + ), + ), + actions: [ + TextButton( + onPressed: () => Get.back(), + child: Text( + '取消', + style: TextStyle( + color: isDarkMode ? Colors.white70 : Colors.black54, + ), + ), + ), + TextButton( + onPressed: () { + Get.back(); + controller.signOut(); + }, + child: Text( + '确定', + style: TextStyle( + color: isDarkMode ? Colors.red[300] : Colors.red[600], + ), + ), + ), + ], + ), + ); + }, + isDarkMode: isDarkMode, + ), + ], ), - ], + ), ), ), ], @@ -278,7 +358,7 @@ class SettingsView extends GetView { } // 关于应用部分 - Widget _buildAboutSection() { + Widget _buildAboutSection(bool isDarkMode) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -289,7 +369,7 @@ class SettingsView extends GetView { style: TextStyle( fontSize: 12.sp, fontWeight: FontWeight.w500, - color: Colors.blue[600], + color: isDarkMode ? Colors.blue[400] : Colors.blue[600], letterSpacing: 1, ), ), @@ -297,77 +377,88 @@ class SettingsView extends GetView { Container( padding: EdgeInsets.all(16.w), decoration: BoxDecoration( - color: Colors.white, + color: isDarkMode ? Colors.white.withOpacity(0.05) : Colors.white, borderRadius: BorderRadius.circular(16.r), boxShadow: [ BoxShadow( - color: Colors.black.withOpacity(0.05), + color: isDarkMode + ? Colors.black.withOpacity(0.2) + : Colors.black.withOpacity(0.05), blurRadius: 10, offset: const Offset(0, 2), ), ], ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( + child: ClipRRect( + borderRadius: BorderRadius.circular(16.r), + child: BackdropFilter( + filter: isDarkMode ? ImageFilter.blur(sigmaX: 5, sigmaY: 5) : ImageFilter.blur(sigmaX: 0, sigmaY: 0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Container( - width: 40.w, - height: 40.w, - decoration: BoxDecoration( - gradient: const LinearGradient( - colors: [Color(0xFF2196F3), Color(0xFF9C27B0)], - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ), - borderRadius: BorderRadius.circular(12.r), - ), - child: Icon( - Icons.headphones, - size: 24.w, - color: Colors.white, - ), - ), - SizedBox(width: 12.w), - Column( - crossAxisAlignment: CrossAxisAlignment.start, + Row( children: [ - Text( - 'DeepVoice', - style: TextStyle( - fontSize: 16.sp, - fontWeight: FontWeight.w500, - color: Colors.black87, + Container( + width: 40.w, + height: 40.w, + decoration: BoxDecoration( + gradient: LinearGradient( + colors: [ + const Color(0xFF2196F3).withOpacity(isDarkMode ? 0.7 : 1.0), + const Color(0xFF9C27B0).withOpacity(isDarkMode ? 0.7 : 1.0) + ], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + borderRadius: BorderRadius.circular(12.r), ), - ), - SizedBox(height: 2.h), - Text( - '版本 2.4.1 (Build 87)', - style: TextStyle( - fontSize: 12.sp, - color: Colors.black54, + child: Icon( + Icons.headphones, + size: 24.w, + color: Colors.white, ), ), + SizedBox(width: 12.w), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'DeepVoice', + style: TextStyle( + fontSize: 16.sp, + fontWeight: FontWeight.w500, + color: isDarkMode ? Colors.white : Colors.black87, + ), + ), + SizedBox(height: 2.h), + Text( + '版本 2.4.1 (Build 87)', + style: TextStyle( + fontSize: 12.sp, + color: isDarkMode ? Colors.white70 : Colors.black54, + ), + ), + ], + ), ], ), - ], - ), - Container( - padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 6.h), - decoration: BoxDecoration( - color: Colors.blue[100], - borderRadius: BorderRadius.circular(16.r), - ), - child: Text( - '检查更新', - style: TextStyle( - fontSize: 12.sp, - color: Colors.blue[600], + Container( + padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 6.h), + decoration: BoxDecoration( + color: isDarkMode ? Colors.blue[900]!.withOpacity(0.3) : Colors.blue[100], + borderRadius: BorderRadius.circular(16.r), + ), + child: Text( + '检查更新', + style: TextStyle( + fontSize: 12.sp, + color: isDarkMode ? Colors.blue[300] : Colors.blue[600], + ), + ), ), - ), + ], ), - ], + ), ), ), SizedBox(height: 16.h), @@ -378,7 +469,7 @@ class SettingsView extends GetView { '© 2023 DeepVoice Technologies', style: TextStyle( fontSize: 12.sp, - color: Colors.grey[500], + color: isDarkMode ? Colors.grey[400] : Colors.grey[500], ), ), SizedBox(height: 4.h), @@ -386,7 +477,7 @@ class SettingsView extends GetView { '连接世界,超越声音', style: TextStyle( fontSize: 12.sp, - color: Colors.grey[500], + color: isDarkMode ? Colors.grey[400] : Colors.grey[500], ), ), ], @@ -405,6 +496,7 @@ class SettingsView extends GetView { required Color iconColor, required bool value, required Function(bool) onChanged, + required bool isDarkMode, }) { return Padding( padding: EdgeInsets.all(16.w), @@ -435,7 +527,7 @@ class SettingsView extends GetView { style: TextStyle( fontSize: 16.sp, fontWeight: FontWeight.w500, - color: Colors.black87, + color: isDarkMode ? Colors.white : Colors.black87, ), ), if (subtitle != null) @@ -445,7 +537,7 @@ class SettingsView extends GetView { subtitle, style: TextStyle( fontSize: 12.sp, - color: Colors.black54, + color: isDarkMode ? Colors.white70 : Colors.black54, ), ), ], @@ -472,6 +564,7 @@ class SettingsView extends GetView { required String value, TextStyle? valueStyle, required VoidCallback onTap, + required bool isDarkMode, }) { return InkWell( onTap: onTap, @@ -504,7 +597,7 @@ class SettingsView extends GetView { style: TextStyle( fontSize: 16.sp, fontWeight: FontWeight.w500, - color: Colors.black87, + color: isDarkMode ? Colors.white : Colors.black87, ), ), if (subtitle != null) @@ -514,7 +607,7 @@ class SettingsView extends GetView { subtitle, style: TextStyle( fontSize: 12.sp, - color: Colors.black54, + color: isDarkMode ? Colors.white70 : Colors.black54, ), ), ], @@ -527,7 +620,7 @@ class SettingsView extends GetView { value, style: valueStyle ?? TextStyle( fontSize: 14.sp, - color: Colors.black87, + color: isDarkMode ? Colors.white : Colors.black87, ), ), SizedBox(width: 8.w), @@ -535,13 +628,13 @@ class SettingsView extends GetView { width: 32.w, height: 32.w, decoration: BoxDecoration( - color: Colors.grey[100], + color: isDarkMode ? Colors.white.withOpacity(0.05) : Colors.grey[100], borderRadius: BorderRadius.circular(16.r), ), child: Icon( Icons.chevron_right, size: 16.w, - color: Colors.grey[500], + color: isDarkMode ? Colors.white70 : Colors.grey[500], ), ), ], @@ -560,7 +653,9 @@ class SettingsView extends GetView { required Color iconBgColor, required Color iconColor, Color? titleColor, + Color? subtitleColor, required VoidCallback onTap, + required bool isDarkMode, }) { return InkWell( onTap: onTap, @@ -593,7 +688,7 @@ class SettingsView extends GetView { style: TextStyle( fontSize: 16.sp, fontWeight: FontWeight.w500, - color: titleColor ?? Colors.black87, + color: titleColor ?? (isDarkMode ? Colors.white : Colors.black87), ), ), if (subtitle != null) @@ -603,7 +698,7 @@ class SettingsView extends GetView { subtitle, style: TextStyle( fontSize: 12.sp, - color: Colors.black54, + color: subtitleColor ?? (isDarkMode ? Colors.white70 : Colors.black54), ), ), ], @@ -614,13 +709,13 @@ class SettingsView extends GetView { width: 32.w, height: 32.w, decoration: BoxDecoration( - color: Colors.grey[100], + color: isDarkMode ? Colors.white.withOpacity(0.05) : Colors.grey[100], borderRadius: BorderRadius.circular(16.r), ), child: Icon( Icons.chevron_right, size: 16.w, - color: Colors.grey[500], + color: isDarkMode ? Colors.white70 : Colors.grey[500], ), ), ], diff --git a/lib/modules/splash/controllers/splash_controller.dart b/lib/modules/splash/controllers/splash_controller.dart index 0bc568c2a..31a4d1df6 100644 --- a/lib/modules/splash/controllers/splash_controller.dart +++ b/lib/modules/splash/controllers/splash_controller.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import '../../../core/routes/app_routes.dart'; +import '../../../app/theme/theme_service.dart'; class SplashController extends GetxController { // 进度条动画控制 @@ -15,12 +16,18 @@ class SplashController extends GetxController { final _isResourceLoaded = false.obs; bool get isResourceLoaded => _isResourceLoaded.value; + // 主题服务 + final ThemeService _themeService = ThemeService(); + @override void onInit() { super.onInit(); // 确保页面先渲染,再执行其他操作 WidgetsBinding.instance.addPostFrameCallback((_) { + // 检查并应用上次保存的皮肤模式 + _checkAndApplyTheme(); + // 启动进度条动画 _startLoadingAnimation(); @@ -29,12 +36,21 @@ class SplashController extends GetxController { }); } + // 检查并应用上次保存的皮肤模式 + void _checkAndApplyTheme() { + // 获取保存的主题模式 + final savedThemeMode = _themeService.getThemeMode(); + + // 应用保存的主题模式 + Get.changeThemeMode(savedThemeMode); + } + // 进度条动画 void _startLoadingAnimation() { // 模拟0.5秒的加载进度 Timer.periodic(const Duration(milliseconds: 5), (timer) { if (_loadingProgress.value < 1.0) { - _loadingProgress.value += 0.06; + _loadingProgress.value += 0.01; } else { timer.cancel(); // 当进度条动画完成且资源加载完毕时,跳转到登录页面 diff --git a/lib/modules/splash/views/splash_view.dart b/lib/modules/splash/views/splash_view.dart index 5de82acc2..0f2fb0e4f 100644 --- a/lib/modules/splash/views/splash_view.dart +++ b/lib/modules/splash/views/splash_view.dart @@ -8,82 +8,46 @@ class SplashView extends GetView { @override Widget build(BuildContext context) { + final isDarkMode = Theme.of(context).brightness == Brightness.dark; + return Scaffold( - backgroundColor: const Color(0xFFF5F5F7), + backgroundColor: isDarkMode ? Colors.black : const Color(0xFFF5F5F7), body: Stack( children: [ - // 状态栏 - _buildStatusBar(), - // 主内容 Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ // Logo动画 - _buildAnimatedLogo(), + _buildAnimatedLogo(isDarkMode), // 应用名称 - _buildAppTitle(), + _buildAppTitle(isDarkMode), // 标语 - _buildSlogan(), + _buildSlogan(isDarkMode), // 加载进度条 SizedBox(height: 40.h), - _buildLoadingBar(), + _buildLoadingBar(isDarkMode), // 额外信息 SizedBox(height: 16.h), - _buildExtraInfo(), + _buildExtraInfo(isDarkMode), ], ), ), // 版本号 - _buildVersionInfo(), + _buildVersionInfo(isDarkMode), ], ), ); } - // 状态栏 - Widget _buildStatusBar() { - return Positioned( - top: 0, - left: 0, - right: 0, - child: SafeArea( - child: Padding( - padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 8.h), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - '9:41', - style: TextStyle( - fontSize: 12.sp, - color: Colors.grey[800], - ), - ), - Row( - children: [ - Icon(Icons.signal_cellular_4_bar, size: 12.sp, color: Colors.grey[800]), - SizedBox(width: 4.w), - Icon(Icons.wifi, size: 12.sp, color: Colors.grey[800]), - SizedBox(width: 4.w), - Icon(Icons.battery_full, size: 12.sp, color: Colors.grey[800]), - ], - ), - ], - ), - ), - ), - ); - } - // 动画Logo - Widget _buildAnimatedLogo() { + Widget _buildAnimatedLogo(bool isDarkMode) { return TweenAnimationBuilder( tween: Tween(begin: 0.8, end: 1.1), duration: const Duration(seconds: 2), @@ -130,7 +94,7 @@ class SplashView extends GetView { } // 应用标题 - Widget _buildAppTitle() { + Widget _buildAppTitle(bool isDarkMode) { return TweenAnimationBuilder( tween: Tween(begin: 0.0, end: 1.0), duration: const Duration(milliseconds: 1500), @@ -145,7 +109,7 @@ class SplashView extends GetView { style: TextStyle( fontSize: 28.sp, fontWeight: FontWeight.bold, - color: Colors.grey[800], + color: isDarkMode ? Colors.white : Colors.grey[800], ), ), ), @@ -155,7 +119,7 @@ class SplashView extends GetView { } // 标语 - Widget _buildSlogan() { + Widget _buildSlogan(bool isDarkMode) { return TweenAnimationBuilder( tween: Tween(begin: 0.0, end: 1.0), duration: const Duration(milliseconds: 1500), @@ -169,7 +133,7 @@ class SplashView extends GetView { '连接世界,岂止声音', style: TextStyle( fontSize: 14.sp, - color: Colors.grey[600], + color: isDarkMode ? Colors.grey[400] : Colors.grey[600], ), ), ), @@ -179,7 +143,7 @@ class SplashView extends GetView { } // 加载进度条 - Widget _buildLoadingBar() { + Widget _buildLoadingBar(bool isDarkMode) { return Padding( padding: EdgeInsets.symmetric(horizontal: 80.w), child: Stack( @@ -187,7 +151,7 @@ class SplashView extends GetView { Container( height: 4.h, decoration: BoxDecoration( - color: Colors.grey[200], + color: isDarkMode ? Colors.grey[800] : Colors.grey[200], borderRadius: BorderRadius.circular(2.r), ), ), @@ -216,7 +180,7 @@ class SplashView extends GetView { } // 额外信息 - Widget _buildExtraInfo() { + Widget _buildExtraInfo(bool isDarkMode) { return TweenAnimationBuilder( tween: Tween(begin: 0.0, end: 1.0), duration: const Duration(milliseconds: 1500), @@ -228,7 +192,7 @@ class SplashView extends GetView { 'AI语音专家 · 随时随地', style: TextStyle( fontSize: 12.sp, - color: Colors.grey[400], + color: isDarkMode ? Colors.grey[500] : Colors.grey[400], ), ), ); @@ -237,7 +201,7 @@ class SplashView extends GetView { } // 版本信息 - Widget _buildVersionInfo() { + Widget _buildVersionInfo(bool isDarkMode) { return Positioned( bottom: 32.h, left: 0, @@ -247,7 +211,7 @@ class SplashView extends GetView { controller.version, style: TextStyle( fontSize: 12.sp, - color: Colors.grey[400], + color: isDarkMode ? Colors.grey[500] : Colors.grey[400], ), ), ), diff --git a/macos/Podfile.lock b/macos/Podfile.lock index c014c5d55..da6276a5d 100644 --- a/macos/Podfile.lock +++ b/macos/Podfile.lock @@ -8,6 +8,9 @@ PODS: - FlutterMacOS - file_selector_macos (0.0.1): - FlutterMacOS + - flutter_blue_plus_darwin (0.0.2): + - Flutter + - FlutterMacOS - flutter_local_notifications (0.0.1): - FlutterMacOS - flutter_tts (0.0.1): @@ -23,17 +26,9 @@ PODS: - FlutterMacOS - share_plus (0.0.1): - FlutterMacOS - - shared_preferences_foundation (0.0.1): - - Flutter - - FlutterMacOS - - speech_to_text (0.0.1): - - Flutter - - FlutterMacOS - - Try - sqflite_darwin (0.0.4): - Flutter - FlutterMacOS - - Try (2.1.1) - window_size (0.0.2): - FlutterMacOS @@ -42,6 +37,7 @@ DEPENDENCIES: - audio_session (from `Flutter/ephemeral/.symlinks/plugins/audio_session/macos`) - device_info_plus (from `Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos`) - file_selector_macos (from `Flutter/ephemeral/.symlinks/plugins/file_selector_macos/macos`) + - flutter_blue_plus_darwin (from `Flutter/ephemeral/.symlinks/plugins/flutter_blue_plus_darwin/darwin`) - flutter_local_notifications (from `Flutter/ephemeral/.symlinks/plugins/flutter_local_notifications/macos`) - flutter_tts (from `Flutter/ephemeral/.symlinks/plugins/flutter_tts/macos`) - FlutterMacOS (from `Flutter/ephemeral`) @@ -49,15 +45,9 @@ DEPENDENCIES: - path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`) - record_darwin (from `Flutter/ephemeral/.symlinks/plugins/record_darwin/macos`) - share_plus (from `Flutter/ephemeral/.symlinks/plugins/share_plus/macos`) - - shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`) - - speech_to_text (from `Flutter/ephemeral/.symlinks/plugins/speech_to_text/darwin`) - sqflite_darwin (from `Flutter/ephemeral/.symlinks/plugins/sqflite_darwin/darwin`) - window_size (from `Flutter/ephemeral/.symlinks/plugins/window_size/macos`) -SPEC REPOS: - trunk: - - Try - EXTERNAL SOURCES: audio_service: :path: Flutter/ephemeral/.symlinks/plugins/audio_service/darwin @@ -67,6 +57,8 @@ EXTERNAL SOURCES: :path: Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos file_selector_macos: :path: Flutter/ephemeral/.symlinks/plugins/file_selector_macos/macos + flutter_blue_plus_darwin: + :path: Flutter/ephemeral/.symlinks/plugins/flutter_blue_plus_darwin/darwin flutter_local_notifications: :path: Flutter/ephemeral/.symlinks/plugins/flutter_local_notifications/macos flutter_tts: @@ -81,10 +73,6 @@ EXTERNAL SOURCES: :path: Flutter/ephemeral/.symlinks/plugins/record_darwin/macos share_plus: :path: Flutter/ephemeral/.symlinks/plugins/share_plus/macos - shared_preferences_foundation: - :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin - speech_to_text: - :path: Flutter/ephemeral/.symlinks/plugins/speech_to_text/darwin sqflite_darwin: :path: Flutter/ephemeral/.symlinks/plugins/sqflite_darwin/darwin window_size: @@ -95,6 +83,7 @@ SPEC CHECKSUMS: audio_session: eaca2512cf2b39212d724f35d11f46180ad3a33e device_info_plus: a56e6e74dbbd2bb92f2da12c64ddd4f67a749041 file_selector_macos: 6280b52b459ae6c590af5d78fc35c7267a3c4b31 + flutter_blue_plus_darwin: 09444a26fb6bdef523e55b68fc1c59af5a877ea6 flutter_local_notifications: 13862b132e32eb858dea558a86d45d08daeacfe7 flutter_tts: ae915565cc6948444b513acc8ee021993281e027 FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 @@ -102,10 +91,7 @@ SPEC CHECKSUMS: path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564 record_darwin: 30509266ae213af8afdb09a8ae7467cb64c1377e share_plus: 510bf0af1a42cd602274b4629920c9649c52f4cc - shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7 - speech_to_text: 9dc43a5df3cbc2813f8c7cc9bd0fbf94268ed7ac sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0 - Try: 5ef669ae832617b3cee58cb2c6f99fb767a4ff96 window_size: 4bd15034e6e3d0720fd77928a7c42e5492cfece9 PODFILE CHECKSUM: 8c4442624fc136b0afb378a2502958e01c05d073