import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import '../controllers/pairing_controller.dart'; class PairingView extends GetView { const PairingView({Key? key}) : super(key: key); @override Widget build(BuildContext context) { final bool isDarkMode = Theme.of(context).brightness == Brightness.dark; return Scaffold( backgroundColor: isDarkMode ? Colors.black : Colors.white, body: SafeArea( child: _buildMainContent(isDarkMode), ), // bottomNavigationBar: Opacity( // opacity: 0.5, // child: const CommonBottomNav(currentIndex: 0), // ), ); } // 主要内容 Widget _buildMainContent(bool isDarkMode) { return Container( width: double.infinity, height: MediaQuery.of(Get.context!).size.height, padding: EdgeInsets.symmetric(horizontal: 24.w), // 添加SingleChildScrollView以防止溢出 child: SingleChildScrollView( physics: BouncingScrollPhysics(), child: ConstrainedBox( constraints: BoxConstraints( minHeight: MediaQuery.of(Get.context!).size.height - 100.h, // 减去底部导航和状态栏高度 ), child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ SizedBox(height: 20.h), // 顶部间距 // 标题部分 _buildHeader(isDarkMode), SizedBox(height: 20.h), // 设备动画 - 根据状态显示不同动画 _buildDeviceAnimation(isDarkMode), SizedBox(height: 20.h), // 状态信息 _buildStatusInfo(isDarkMode), SizedBox(height: 40.h), // 底部按钮 _buildActionButtons(isDarkMode), SizedBox(height: 20.h), ], ), ), ), ); } // 头部标题 Widget _buildHeader(bool isDarkMode) { return Column( children: [ Text( 'DeepSound', style: TextStyle( fontSize: 30.sp, fontWeight: FontWeight.bold, color: isDarkMode ? Colors.white : Colors.black, ), ), SizedBox(height: 8.h), Text( 'homeSlogan'.tr, // 连接世界,超越声音 style: TextStyle( fontSize: 16.sp, color: isDarkMode ? Colors.white60 : Colors.black54, ), ), ], ); } // 设备动画 - 根据状态显示不同的动画效果 Widget _buildDeviceAnimation(bool isDarkMode) { return Obx(() { final state = controller.currentState; final isLoading = controller.isLoading.value; // 根据状态决定动画颜色 Color primaryColor = Color(0xFF0066CC); Color secondaryColor = Color(0xFF5E5CE6); // 错误状态使用红色 if (state == PairingState.error) { primaryColor = Colors.red; secondaryColor = Colors.redAccent; } // 成功状态使用绿色 else if (state == PairingState.completed) { primaryColor = Colors.green; secondaryColor = Colors.greenAccent; } // 待机状态的特殊处理 if (state == PairingState.idle || state == PairingState.waitingClassic) { return Container( width: 240.w, height: 240.w, child: Stack( alignment: Alignment.center, children: [ // 静态背景圆圈 Container( width: 200.w, height: 200.w, decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [ primaryColor.withOpacity(0.1), secondaryColor.withOpacity(0.1), ], ), shape: BoxShape.circle, ), ), // 设备图标 Container( width: 120.w, height: 120.w, decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [primaryColor, secondaryColor], ), shape: BoxShape.circle, ), child: Icon( Icons.headphones, color: Colors.white, size: 60.w, ), ), ], ), ); } return Container( width: 240.w, height: 240.w, child: Stack( alignment: Alignment.center, children: [ // 脉搏背景 - 只在加载时显示动画 if (isLoading) TweenAnimationBuilder( tween: Tween(begin: 0.8, end: 1.1), duration: const Duration(seconds: 2), curve: Curves.easeInOut, builder: (context, value, child) { return Container( width: 200.w * value, height: 200.w * value, decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [ primaryColor.withOpacity(0.3), secondaryColor.withOpacity(0.3), ], ), shape: BoxShape.circle, ), ); }, onEnd: () { // 重新开始动画 }, ), // 旋转边框 - 只在加载时显示 if (isLoading) SizedBox( width: 100.w, height: 100.w, child: CircularProgressIndicator( strokeWidth: 4.w, valueColor: AlwaysStoppedAnimation(primaryColor), backgroundColor: Colors.grey.withOpacity(0.2), ), ), // 设备图标 Container( width: 120.w, height: 120.w, decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [primaryColor, secondaryColor], ), shape: BoxShape.circle, ), child: Icon( _getIconForState(state), color: Colors.white, size: 60.w, ), ), ], ), ); }); } // 根据状态获取图标 IconData _getIconForState(PairingState state) { switch (state) { case PairingState.completed: return Icons.check_circle; case PairingState.error: final errorType = controller.errorType; switch (errorType) { case ErrorType.bluetoothOff: case ErrorType.noPermission: return Icons.bluetooth_disabled; case ErrorType.noClassicDevice: case ErrorType.deviceNotMatch: return Icons.headphones_outlined; default: return Icons.error_outline; } default: return Icons.headphones; } } // 状态信息 Widget _buildStatusInfo(bool isDarkMode) { return Obx(() { final status = controller.statusText.value; final state = controller.currentState; final device = controller.currentDevice; return Column( children: [ // 状态文本 - 更大更醒目 Text( status, style: TextStyle( fontSize: 20.sp, fontWeight: FontWeight.w600, color: isDarkMode ? Colors.white : Colors.black, ), textAlign: TextAlign.center, ), SizedBox(height: 10.h), // 子状态提示文本 - 根据状态显示不同提示 Text( _getSubtitleForState(state), style: TextStyle( fontSize: 14.sp, color: isDarkMode ? Colors.white60 : Colors.grey[600], ), textAlign: TextAlign.center, ), // 当前连接设备(有设备时才显示) if (device != null && (state == PairingState.verifying || state == PairingState.waitingBle || state == PairingState.completed)) ...[ SizedBox(height: 24.h), _buildConnectedDevice(device, isDarkMode), ], ], ); }); } // 根据状态获取副标题 String _getSubtitleForState(PairingState state) { switch (state) { case PairingState.idle: return '准备开始配对'; case PairingState.checking: return '正在准备配对环境...'; case PairingState.waitingClassic: return '请先通过系统蓝牙连接DeapSound设备'; case PairingState.verifying: return '正在验证设备...'; case PairingState.waitingBle: return '请稍候,正在完成配对...'; case PairingState.completed: return '配对成功!即将跳转到主页...'; case PairingState.error: final errorType = controller.errorType; switch (errorType) { case ErrorType.bluetoothOff: return '请开启蓝牙后重试'; case ErrorType.noPermission: return '需要蓝牙权限才能继续'; case ErrorType.noClassicDevice: return '请先通过系统蓝牙连接DeapSound设备'; case ErrorType.deviceNotMatch: return '请确保连接的是DeapSound设备'; case ErrorType.deviceBound: return '该设备已被其他账号绑定'; case ErrorType.bleTimeout: return '扫描超时,请确保设备在附近'; case ErrorType.networkError: return '网络错误,请检查网络连接'; default: return '配对失败,请重试'; } default: return ''; } } // 已连接设备信息 Widget _buildConnectedDevice(device, bool isDarkMode) { return Container( width: double.infinity, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'currentlyConnected'.tr, // 当前已连接: style: TextStyle( fontSize: 16.sp, fontWeight: FontWeight.w600, color: isDarkMode ? Colors.white70 : Colors.black87, ), ), SizedBox(height: 8.h), _buildDeviceItem(device, isDarkMode), ], ), ); } // 设备项 Widget _buildDeviceItem(device, bool isDarkMode) { return Container( margin: EdgeInsets.only(bottom: 8.h), padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 12.h), decoration: BoxDecoration( color: isDarkMode ? Colors.grey[900] : Colors.grey[100], borderRadius: BorderRadius.circular(8.r), ), child: Row( children: [ Icon( Icons.headphones, color: isDarkMode ? Colors.white70 : Colors.black54, size: 24.w, ), SizedBox(width: 12.w), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( device.name ?? 'unknown'.tr, style: TextStyle( fontSize: 16.sp, fontWeight: FontWeight.w500, color: isDarkMode ? Colors.white : Colors.black, ), ), SizedBox(height: 4.h), Text( device.address ?? '', style: TextStyle( fontSize: 12.sp, color: isDarkMode ? Colors.white54 : Colors.black45, ), ), ], ), ), Icon( Icons.bluetooth_connected, color: Colors.green, size: 20.w, ), ], ), ); } // 获取连接按钮图标 IconData _getConnectButtonIcon() { final buttonText = controller.connectButtonText.value; if (buttonText.contains('蓝牙')) { return Icons.bluetooth; } else if (buttonText.contains('设置')) { return Icons.settings; } return Icons.bluetooth_searching; } // 操作按钮 Widget _buildActionButtons(bool isDarkMode) { return Obx(() { final showConnectButton = controller.showConnectButton.value; final showRetryButton = controller.showRetryButton.value; final showSkipButton = controller.showSkipButton.value; return Container( width: double.infinity, child: Column( children: [ // 显示连接按钮 if (showConnectButton) ElevatedButton( onPressed: () => controller.onConnectTap(), style: ElevatedButton.styleFrom( backgroundColor: Color(0xFF0066CC), foregroundColor: Colors.white, padding: EdgeInsets.symmetric(vertical: 16.h), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16.r), ), elevation: 0, minimumSize: Size(double.infinity, 56.h), ), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(_getConnectButtonIcon(), size: 20.w), SizedBox(width: 8.w), Text( controller.connectButtonText.value, style: TextStyle( fontSize: 16.sp, fontWeight: FontWeight.w600, ), ), ], ), ), // 显示重试按钮 if (showRetryButton) ElevatedButton( onPressed: () => controller.onRetryTap(), style: ElevatedButton.styleFrom( backgroundColor: Colors.red, foregroundColor: Colors.white, padding: EdgeInsets.symmetric(vertical: 16.h), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16.r), ), elevation: 0, minimumSize: Size(double.infinity, 56.h), ), child: Text( controller.retryButtonText.value, style: TextStyle( fontSize: 16.sp, fontWeight: FontWeight.w600, ), ), ), // 跳过按钮 if (showSkipButton) ...[ SizedBox(height: 12.h), TextButton( onPressed: () => controller.onSkipTap(), style: TextButton.styleFrom( foregroundColor: Color(0xFF0066CC), padding: EdgeInsets.symmetric(vertical: 12.h), minimumSize: Size(double.infinity, 48.h), ), child: Text( 'talkLater'.tr, // 稍后再说 style: TextStyle( fontSize: 16.sp, fontWeight: FontWeight.w500, ), ), ), ], ], ), ); }); } }