Browse Source

add dark light skin

newdev_shunjiawei
wolfplus 2 years ago
parent
commit
d70bcfb68c
  1. 114
      android/app/src/main/kotlin/com/example/deep_voice/AzureAsrHelper.kt
  2. 65
      android/app/src/main/kotlin/com/example/deep_voice/VoiceInteractionService.kt
  3. BIN
      assets/images/headphone_light.png
  4. 29
      lib/app/theme/theme_service.dart
  5. 10
      lib/core/widgets/common_bottom_nav.dart
  6. 6
      lib/main.dart
  7. 52
      lib/modules/explore/controllers/explore_controller.dart
  8. 108
      lib/modules/explore/views/explore_view.dart
  9. 467
      lib/modules/home/views/home_view.dart
  10. 20
      lib/modules/login/controllers/login_controller.dart
  11. 250
      lib/modules/login/views/login_view.dart
  12. 63
      lib/modules/pairing/views/pairing_view.dart
  13. 19
      lib/modules/settings/controllers/settings_controller.dart
  14. 581
      lib/modules/settings/views/settings_view.dart
  15. 18
      lib/modules/splash/controllers/splash_controller.dart
  16. 76
      lib/modules/splash/views/splash_view.dart
  17. 28
      macos/Podfile.lock

114
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)
}
}
// 释放回音消除资源

65
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

BIN
assets/images/headphone_light.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 140 KiB

After

Width:  |  Height:  |  Size: 98 KiB

29
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());
}
}

10
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(

6
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<void> _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,

52
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),
),
];

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

@ -10,13 +10,15 @@ class ExploreView extends GetView<ExploreController> {
@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<ExploreController> {
// 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<ExploreController> {
}
// 标题和搜索
Widget _buildHeaderAndSearch() {
Widget _buildHeaderAndSearch(bool isDarkMode) {
return Padding(
padding: EdgeInsets.all(16.w),
child: Column(
@ -68,18 +70,22 @@ class ExploreView extends GetView<ExploreController> {
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<ExploreController> {
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<ExploreController> {
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<ExploreController> {
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<ExploreController> {
}
// AI功能部分
Widget _buildAIFeaturesSection() {
Widget _buildAIFeaturesSection(bool isDarkMode) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -217,7 +226,7 @@ class ExploreView extends GetView<ExploreController> {
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<ExploreController> {
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<ExploreController> {
}
// 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<ExploreController> {
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<ExploreController> {
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<ExploreController> {
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<ExploreController> {
}
// 热门功能场景部分
Widget _buildFunctionScenesSection() {
Widget _buildFunctionScenesSection(bool isDarkMode) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -331,7 +342,7 @@ class ExploreView extends GetView<ExploreController> {
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<ExploreController> {
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<ExploreController> {
}
// 功能场景项
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<ExploreController> {
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<ExploreController> {
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<ExploreController> {
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<ExploreController> {
}
// 新功能推荐部分
Widget _buildNewFeatureSection() {
Widget _buildNewFeatureSection(bool isDarkMode) {
return Container(
padding: EdgeInsets.all(20.w),
decoration: BoxDecoration(
@ -432,14 +445,16 @@ class ExploreView extends GetView<ExploreController> {
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<ExploreController> {
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<ExploreController> {
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<ExploreController> {
'用你喜欢的歌手声音演唱任何歌曲,甚至是你自己创作的歌曲',
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<ExploreController> {
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<ExploreController> {
style: TextStyle(
fontSize: 14.sp,
fontWeight: FontWeight.w500,
color: isDarkMode ? Colors.white : Colors.grey[800],
),
),
),

467
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<HomeController> {
@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<HomeController> {
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<HomeController> {
);
}
// 页面顶部:状态栏和标题
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<HomeController> {
],
),
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<HomeController> {
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<HomeController> {
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<HomeController> {
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<HomeController> {
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<HomeController> {
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<HomeController> {
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<HomeController> {
'设备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<HomeController> {
'固件版本:${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<HomeController> {
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<HomeController> {
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<HomeController> {
);
}
// 热门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<HomeController> {
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<HomeController> {
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<HomeController> {
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<HomeController> {
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,
),
),
],
],
),
),
],
),
),
);
}

20
lib/modules/login/controllers/login_controller.dart

@ -200,16 +200,16 @@ class LoginController extends GetxController {
// 登录
Future<void> 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;

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

@ -10,53 +10,49 @@ class LoginView extends GetView<LoginController> {
@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<LoginController> {
}
// 验证码页面
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<LoginController> {
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<LoginController> {
);
}
// 状态栏
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<LoginController> {
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<LoginController> {
'连接世界,超越声音',
style: TextStyle(
fontSize: 14.sp,
color: Colors.black54,
color: isDarkMode ? Colors.grey[400] : Colors.black54,
),
),
],
@ -177,7 +148,7 @@ class LoginView extends GetView<LoginController> {
}
// 欢迎文本
Widget _buildWelcomeText() {
Widget _buildWelcomeText(bool isDarkMode) {
return Column(
children: [
Text(
@ -185,7 +156,7 @@ class LoginView extends GetView<LoginController> {
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<LoginController> {
'请使用手机号或邮箱登录/注册',
style: TextStyle(
fontSize: 14.sp,
color: Colors.black54,
color: isDarkMode ? Colors.grey[400] : Colors.black54,
),
),
],
@ -201,10 +172,10 @@ class LoginView extends GetView<LoginController> {
}
// 输入框
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<LoginController> {
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<LoginController> {
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<LoginController> {
}
// 验证码输入框
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<LoginController> {
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<LoginController> {
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<LoginController> {
: 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<LoginController> {
}
// 继续按钮
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<Color>(Colors.white),
height: 20.h,
width: 20.h,
child: CircularProgressIndicator(
strokeWidth: 2.w,
valueColor: const AlwaysStoppedAnimation<Color>(Colors.white),
),
)
: Text(
'登录',
'继续',
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w500,
color: Colors.white,
fontWeight: FontWeight.w600,
),
),
)),
@ -339,32 +316,32 @@ class LoginView extends GetView<LoginController> {
}
// 社交媒体登录部分
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<LoginController> {
}
// 社交媒体按钮
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<LoginController> {
'《用户协议》',
style: TextStyle(
fontSize: 12.sp,
color: const Color(0xFF0066CC),
color: const Color(0xFF3B82F6),
),
),
),
@ -416,7 +404,7 @@ class LoginView extends GetView<LoginController> {
' 和 ',
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<LoginController> {
'《隐私政策》',
style: TextStyle(
fontSize: 12.sp,
color: const Color(0xFF0066CC),
color: const Color(0xFF3B82F6),
),
),
),
@ -436,23 +424,27 @@ class LoginView extends GetView<LoginController> {
}
// 返回按钮
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<LoginController> {
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<LoginController> {
'验证码已发送至 ${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<LoginController> {
}
// 验证码输入框
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<LoginController> {
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<LoginController> {
}
// 重新发送验证码按钮
Widget _buildResendButton() {
Widget _buildResendButton(bool isDarkMode) {
return Center(
child: Obx(() => TextButton.icon(
onPressed: controller.countdownSeconds > 0
@ -533,8 +527,8 @@ class LoginView extends GetView<LoginController> {
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<LoginController> {
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<LoginController> {
}
// 登录按钮
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<Color>(Colors.white),
height: 20.h,
width: 20.h,
child: CircularProgressIndicator(
strokeWidth: 2.w,
valueColor: const AlwaysStoppedAnimation<Color>(Colors.white),
),
)
: Text(
'登录',
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w500,
color: Colors.white,
fontWeight: FontWeight.w600,
),
),
)),
@ -587,7 +583,7 @@ class LoginView extends GetView<LoginController> {
}
// 使用密码登录按钮
Widget _buildUsePasswordButton() {
Widget _buildUsePasswordButton(bool isDarkMode) {
return Center(
child: TextButton(
onPressed: controller.usePasswordLogin,
@ -595,7 +591,7 @@ class LoginView extends GetView<LoginController> {
'使用密码登录',
style: TextStyle(
fontSize: 14.sp,
color: const Color(0xFF0066CC),
color: isDarkMode ? const Color(0xFF3B82F6) : const Color(0xFF3B82F6),
),
),
),

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

@ -10,35 +10,34 @@ class PairingView extends GetView<PairingController> {
@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<PairingController> {
// 搜索状态
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<PairingController> {
}
// 标题部分
Widget _buildHeader() {
Widget _buildHeader(bool isDarkMode) {
return Column(
children: [
Text(
@ -67,7 +66,7 @@ class PairingView extends GetView<PairingController> {
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<PairingController> {
'连接世界,超越声音',
style: TextStyle(
fontSize: 14.sp,
color: Colors.black54,
color: isDarkMode ? Colors.white70 : Colors.black54,
),
),
],
@ -170,7 +169,7 @@ class PairingView extends GetView<PairingController> {
}
// 搜索状态
Widget _buildSearchStatus() {
Widget _buildSearchStatus(bool isDarkMode) {
return Obx(() {
switch (controller.searchStatus) {
case SearchStatus.searching:
@ -181,7 +180,7 @@ class PairingView extends GetView<PairingController> {
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<PairingController> {
'请打开耳机充电盒,将耳机放入您的耳朵',
style: TextStyle(
fontSize: 14.sp,
color: Colors.black54,
color: isDarkMode ? Colors.white70 : Colors.black54,
),
),
],
@ -217,7 +216,7 @@ class PairingView extends GetView<PairingController> {
'正在跳转到主页...',
style: TextStyle(
fontSize: 14.sp,
color: Colors.black54,
color: isDarkMode ? Colors.white70 : Colors.black54,
),
),
],
@ -245,7 +244,7 @@ class PairingView extends GetView<PairingController> {
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<PairingController> {
'请确保耳机已开机并在附近' : 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<PairingController> {
'请在系统设置中配对您的设备' : 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<PairingController> {
}
// 底部按钮
Widget _buildBottomButtons() {
Widget _buildBottomButtons(bool isDarkMode) {
return Column(
children: [
SizedBox(
@ -352,8 +351,8 @@ class PairingView extends GetView<PairingController> {
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),

19
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<String> 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;
}

581
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<SettingsController> {
@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<SettingsController> {
}
// 用户信息卡片
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<SettingsController> {
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<SettingsController> {
}
// 关于应用部分
Widget _buildAboutSection() {
Widget _buildAboutSection(bool isDarkMode) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -289,7 +369,7 @@ class SettingsView extends GetView<SettingsController> {
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<SettingsController> {
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<SettingsController> {
'© 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<SettingsController> {
'连接世界,超越声音',
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<SettingsController> {
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<SettingsController> {
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<SettingsController> {
subtitle,
style: TextStyle(
fontSize: 12.sp,
color: Colors.black54,
color: isDarkMode ? Colors.white70 : Colors.black54,
),
),
],
@ -472,6 +564,7 @@ class SettingsView extends GetView<SettingsController> {
required String value,
TextStyle? valueStyle,
required VoidCallback onTap,
required bool isDarkMode,
}) {
return InkWell(
onTap: onTap,
@ -504,7 +597,7 @@ class SettingsView extends GetView<SettingsController> {
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<SettingsController> {
subtitle,
style: TextStyle(
fontSize: 12.sp,
color: Colors.black54,
color: isDarkMode ? Colors.white70 : Colors.black54,
),
),
],
@ -527,7 +620,7 @@ class SettingsView extends GetView<SettingsController> {
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<SettingsController> {
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<SettingsController> {
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<SettingsController> {
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<SettingsController> {
subtitle,
style: TextStyle(
fontSize: 12.sp,
color: Colors.black54,
color: subtitleColor ?? (isDarkMode ? Colors.white70 : Colors.black54),
),
),
],
@ -614,13 +709,13 @@ class SettingsView extends GetView<SettingsController> {
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],
),
),
],

18
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();
// 当进度条动画完成且资源加载完毕时,跳转到登录页面

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

@ -8,82 +8,46 @@ class SplashView extends GetView<SplashController> {
@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<double>(
tween: Tween<double>(begin: 0.8, end: 1.1),
duration: const Duration(seconds: 2),
@ -130,7 +94,7 @@ class SplashView extends GetView<SplashController> {
}
// 应用标题
Widget _buildAppTitle() {
Widget _buildAppTitle(bool isDarkMode) {
return TweenAnimationBuilder<double>(
tween: Tween<double>(begin: 0.0, end: 1.0),
duration: const Duration(milliseconds: 1500),
@ -145,7 +109,7 @@ class SplashView extends GetView<SplashController> {
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<SplashController> {
}
// 标语
Widget _buildSlogan() {
Widget _buildSlogan(bool isDarkMode) {
return TweenAnimationBuilder<double>(
tween: Tween<double>(begin: 0.0, end: 1.0),
duration: const Duration(milliseconds: 1500),
@ -169,7 +133,7 @@ class SplashView extends GetView<SplashController> {
'连接世界,岂止声音',
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<SplashController> {
}
// 加载进度条
Widget _buildLoadingBar() {
Widget _buildLoadingBar(bool isDarkMode) {
return Padding(
padding: EdgeInsets.symmetric(horizontal: 80.w),
child: Stack(
@ -187,7 +151,7 @@ class SplashView extends GetView<SplashController> {
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<SplashController> {
}
// 额外信息
Widget _buildExtraInfo() {
Widget _buildExtraInfo(bool isDarkMode) {
return TweenAnimationBuilder<double>(
tween: Tween<double>(begin: 0.0, end: 1.0),
duration: const Duration(milliseconds: 1500),
@ -228,7 +192,7 @@ class SplashView extends GetView<SplashController> {
'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<SplashController> {
}
// 版本信息
Widget _buildVersionInfo() {
Widget _buildVersionInfo(bool isDarkMode) {
return Positioned(
bottom: 32.h,
left: 0,
@ -247,7 +211,7 @@ class SplashView extends GetView<SplashController> {
controller.version,
style: TextStyle(
fontSize: 12.sp,
color: Colors.grey[400],
color: isDarkMode ? Colors.grey[500] : Colors.grey[400],
),
),
),

28
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

Loading…
Cancel
Save