import 'package:flutter/material.dart'; import 'package:flutter_intro/flutter_intro.dart'; import 'package:get/get.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import '../../../core/widgets/intro_overlay_builder.dart'; import '../controllers/home_controller.dart'; import '../../../routes/app_routes.dart'; import '../../../core/widgets/common_bottom_nav.dart'; import '../../../data/models/appconfig_model.dart'; // 呼吸灯动画组件 class AnimatedPulsing extends StatefulWidget { const AnimatedPulsing({Key? key}) : super(key: key); @override _AnimatedPulsingState createState() => _AnimatedPulsingState(); } class _AnimatedPulsingState extends State with SingleTickerProviderStateMixin { late AnimationController _controller; late Animation _animation; @override void initState() { super.initState(); _controller = AnimationController( duration: const Duration(seconds: 2), vsync: this, )..repeat(reverse: true); _animation = Tween(begin: 0.5, end: 0.8).animate( CurvedAnimation(parent: _controller, curve: Curves.easeInOut), ); } @override void dispose() { _controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return AnimatedBuilder( animation: _animation, builder: (context, child) { return Opacity( opacity: _animation.value, child: child, ); }, child: Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(16.r), gradient: RadialGradient( colors: [ Colors.white.withOpacity(0.3), Colors.transparent, ], center: Alignment.topRight, radius: 0.8, stops: const [0.0, 1.0], ), ), ), ); } } // 首页视图 class HomeView extends GetView { const HomeView({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 : const Color(0xFFF9FAFC), body: SafeArea( child: SingleChildScrollView( padding: EdgeInsets.all(16.w), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // 顶部标题栏 _buildAppBar(context, isDarkMode), SizedBox(height: 10.h), // 顶部图片 _buildEarbudsImage(), SizedBox(height: 10.h), // 设备状态卡片 IntroStepBuilder( group: 'home', order: 1, onWidgetLoad: () { controller.noviceGuideService.startHomeGuide(); }, getOverlayPosition: IntroOverlayBuilder.overlayPosition, overlayBuilder: (params) { return IntroOverlayBuilder.aiBuilder( params, 'guideWelcomeWakeAI'.tr, onNext: () { controller.noviceGuideService.startWakeupListen(); }, onTap: () { params.onNext!(); controller.noviceGuideService.startWakeupListen(); }, ); }, builder: (BuildContext context, GlobalKey key) => SizedBox( key: key, child: _buildDeviceStatusCard(isDarkMode), ), ), SizedBox(height: 20.h), IntroStepBuilder( group: 'home', order: 2, getOverlayPosition: IntroOverlayBuilder.overlayPosition, overlayBuilder: (params) { return Obx( () => IntroOverlayBuilder.homeBuilder( params, controller.noviceGuideService.isWakeup.value, onNext: () { controller.noviceGuideService.closeWakeupListen(); }, ), ); }, builder: (BuildContext context, GlobalKey key) => SizedBox( key: key, ), ), // 热门AI体验 _buildSectionTitle(isDarkMode), SizedBox(height: 16.h), _buildPremiumAILayout(), ], ), ), ), bottomNavigationBar: const CommonBottomNav(currentIndex: 0), ); } // 顶部标题栏 Widget _buildAppBar(BuildContext context, bool isDarkMode) { return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Voitrans', style: TextStyle( fontSize: 20.sp, fontWeight: FontWeight.bold, color: isDarkMode ? Colors.white : Colors.grey[800], ), ), // 中文注释:去除菜单模式,直接在同一行展示“语音打断”与开关 Obx(() => Row( mainAxisSize: MainAxisSize.min, // 中文注释:按需占宽,避免占满右侧 mainAxisAlignment: MainAxisAlignment.end, // 中文注释:靠右紧凑排布 children: [ Icon( controller.isTtsInterruptEnabled.value ? Icons.voice_over_off : Icons.voice_over_off_outlined, color: controller.isTtsInterruptEnabled.value ? Colors.blue : (isDarkMode ? Colors.grey[600] : Colors.grey[600]), size: 14.sp, // 中文注释:图标保持较小尺寸,减少占位 ), SizedBox(width: 4.w), // 中文注释:图标与文字间距 Text( 'voice_interrupt'.tr, // 语音打断 style: TextStyle( fontSize: 12.sp, height: 1.0, // 中文注释:降低行高以压缩垂直空间 color: isDarkMode ? Colors.white70 : Colors.grey[800], ), ), SizedBox(width: 2.w), Tooltip( message: 'voice_interrupt_tip' .tr, // 开启后:播报时会降低拾音以减少回声与误触发;需要打断时请按设备按键或说唤醒词。关闭后:播报期间保持拾音,可能出现回声或误触发。 triggerMode: TooltipTriggerMode.tap, preferBelow: true, verticalOffset: 10.h, padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 10.h), margin: EdgeInsets.symmetric(horizontal: 12.w), showDuration: const Duration(seconds: 5), decoration: BoxDecoration( color: isDarkMode ? const Color(0xFF1F1F1F) : const Color(0xFF2A2A2A), borderRadius: BorderRadius.circular(10.r), ), textStyle: TextStyle( fontSize: 12.sp, height: 1.35, color: Colors.white, ), child: Icon( Icons.info_outline, size: 14.sp, color: isDarkMode ? Colors.white54 : Colors.grey[600], ), ), SizedBox(width: 4.w), // 中文注释:文字与开关间距 Transform.scale( scale: 0.7, // 中文注释:缩小开关视觉尺寸,保持紧凑 child: Switch( value: controller.isTtsInterruptEnabled.value, onChanged: (value) => controller.toggleTtsInterrupt(), activeColor: Colors.blue, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, ), ), ], )), ], ); } // 耳机图片 Widget _buildEarbudsImage() { final bool isDarkMode = Get.isDarkMode; return SizedBox( height: 220.h, child: PageView( children: [ Center( child: ClipRRect( // 添加 ClipRRect borderRadius: BorderRadius.circular(20.r), child: GetBuilder( builder: (controller) { final imagePath = controller.getDeviceImagePath(isDarkMode); final isNetwork = controller.isNetworkImage(imagePath); return isNetwork ? Image.network( imagePath, width: double.infinity, height: 220.h, fit: BoxFit.contain, errorBuilder: (context, error, stackTrace) { // 网络图片加载失败时使用默认图片 return Image.asset( 'assets/images/defaultPicture.png', width: double.infinity, height: 220.h, fit: BoxFit.cover, ); }, loadingBuilder: (context, child, loadingProgress) { if (loadingProgress == null) return child; return SizedBox( height: 220.h, child: Center( child: CircularProgressIndicator( value: loadingProgress.expectedTotalBytes != null ? loadingProgress.cumulativeBytesLoaded / loadingProgress.expectedTotalBytes! : null, ), ), ); }, ) : Image.asset( imagePath, width: double.infinity, height: 220.h, fit: BoxFit.cover, errorBuilder: (context, error, stackTrace) { // 本地图片加载失败时使用默认图片 return Image.asset( 'assets/images/defaultPicture.png', width: double.infinity, height: 220.h, fit: BoxFit.cover, ); }, ); }, ), ), ), ], ), ); } // 设备状态卡片 Widget _buildDeviceStatusCard(bool isDarkMode) { return Obx(() { // 使用连接状态作为key,强制在状态改变时重建widget final isConnected = controller.isFullyConnectedRx.value; return Container( key: ValueKey('device_status_$isConnected'), decoration: BoxDecoration( color: isDarkMode ? const Color(0xFF1A1A1A) : Colors.white, borderRadius: BorderRadius.circular(16.r), boxShadow: [ BoxShadow( color: Colors.grey.withOpacity(isDarkMode ? 0.05 : 0.1), blurRadius: 10, offset: const Offset(0, 4), ), ], ), padding: EdgeInsets.fromLTRB(16.w, 16.h, 16.w, 16.h), child: Column( children: [ // 状态标题行 _buildDeviceStatusHeader(isDarkMode), // 设备信息 SizedBox(height: 12.h), Obx(() { // 移除连接失败和连接中的状态判断,直接根据是否完全连接来判断 // 使用响应式访问确保UI更新 return controller.isFullyConnectedRx.value ? _buildConnectedDeviceInfo(isDarkMode) //已连接设备信息 : _buildDisconnectedInfo(isDarkMode); //未连接提示 }), // 连接按钮(仅在未连接时显示) SizedBox(height: 12.h), Obx(() { // 使用响应式访问确保UI更新 if (!controller.isFullyConnectedRx.value) { return _buildConnectButton(); } else { return _buildDeviceButton(isDarkMode); } }), ], ), ); }); } // 设备状态头部 Widget _buildDeviceStatusHeader(bool isDarkMode) { return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Row( children: [ Icon( Icons.headset_outlined, size: 18.sp, color: isDarkMode ? Colors.grey[300] : Colors.grey[700], ), SizedBox(width: 8.w), Text( 'deviceStatus'.tr, // 设备状态 style: TextStyle( fontSize: 14.sp, fontWeight: FontWeight.w500, color: isDarkMode ? Colors.grey[300] : Colors.grey[700], ), ), ], ), Obx(() => Row( children: [ Container( //状态指示灯 width: 8.w, height: 8.w, decoration: BoxDecoration( color: controller.getConnectionStatusColor(), shape: BoxShape.circle, boxShadow: [ BoxShadow( color: controller .getConnectionStatusColor() .withOpacity(0.3), blurRadius: 4, spreadRadius: 1, ), ], ), ), SizedBox(width: 4.w), Text( controller.getConnectionStatusText(), style: TextStyle( fontSize: 12.sp, color: controller.getConnectionStatusColor(), ), ), // 添加刷新按钮 SizedBox(width: 8.w), InkWell( onTap: () => controller.refreshDeviceConnection(), borderRadius: BorderRadius.circular(12.r), child: Container( padding: EdgeInsets.all(4.w), decoration: BoxDecoration( color: isDarkMode ? Colors.grey[800] : Colors.grey[200], shape: BoxShape.circle, ), child: Icon( Icons.refresh, size: 14.sp, color: isDarkMode ? Colors.grey[400] : Colors.grey[600], ), ), ), ], )), ], ); } // 连接错误部分 // 已连接设备信息(新增设备名称 + 信号强度 + 电池信息) Widget _buildConnectedDeviceInfo(bool isDarkMode) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( child: Text( '${'connectedTo'.tr}:${controller.getDeviceName()}', style: TextStyle( fontSize: 13.sp, fontWeight: FontWeight.w500, color: isDarkMode ? Colors.grey[300] : Colors.grey[700], ), overflow: TextOverflow.ellipsis, ), ), Container( padding: EdgeInsets.symmetric(horizontal: 6.w, vertical: 2.h), decoration: BoxDecoration( color: Colors.blue.withOpacity(0.1), borderRadius: BorderRadius.circular(4.r), ), child: Text( '${'signal'.tr}: ${controller.getSignalStrength()}', style: TextStyle( fontSize: 11.sp, color: Colors.blue[700], ), ), ), ], ), SizedBox(height: 12.h), _buildBatteryInfoGrid(isDarkMode), ], ); } // 设备管理按钮 Widget _buildDeviceButton(bool isDarkMode) { return ElevatedButton( onPressed: () { Get.toNamed(Routes.devices); // 跳转到设备管理页面 }, style: ElevatedButton.styleFrom( backgroundColor: Colors.blue, foregroundColor: Colors.white, minimumSize: Size(double.infinity, 44.h), elevation: 2, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10.r), ), ), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.device_hub, size: 16.sp), // 设备图标 SizedBox(width: 8.w), Text( 'deviceManagement'.tr, style: TextStyle( fontSize: 14.sp, fontWeight: FontWeight.w500, ), ), ], ), ); } // 电池信息网格布局 Widget _buildBatteryInfoGrid(bool isDarkMode) { return Obx(() { // 获取各部分电池电量 final leftBattery = HomeController.leftEarBattery.value; final rightBattery = HomeController.rightEarBattery.value; final caseBattery = controller.caseBattery.value; // 获取充电状态 final leftEarCharging = controller.leftEarCharging.value; final rightEarCharging = controller.rightEarCharging.value; final caseCharging = controller.caseCharging.value; final isConnected = controller.isFullyConnectedRx.value; // 判断是否显示充电盒:充电盒电量大于0且设备已连接 final shouldShowCase = caseBattery > 0 && isConnected; // 判断是否为单端耳机 final isSingleHeadset = controller.isSingleHeadset(); // 使用更紧凑的布局 return Container( padding: EdgeInsets.symmetric(vertical: 8.h, horizontal: 4.w), decoration: BoxDecoration( color: isDarkMode ? Colors.grey[900] : Colors.grey[50], borderRadius: BorderRadius.circular(12.r), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ // 单端耳机只显示一个电池信息(优先显示左耳,如果左耳电量为0则显示右耳) if (isSingleHeadset) ...[ _buildCompactBatteryItem( label: controller .getCurrentDeviceType() .displayName, // 根据设备类型动态显示文本 batteryLevel: (leftBattery > 0 || rightBattery == 0) ? leftBattery : rightBattery, isCharging: (leftBattery > 0 || rightBattery == 0) ? leftEarCharging : rightEarCharging, isDarkMode: isDarkMode, ), ] else ...[ // 双端耳机显示左右两个电池信息 // 左耳机 _buildCompactBatteryItem( label: 'left'.tr, // 左 batteryLevel: leftBattery, isCharging: leftEarCharging, isDarkMode: isDarkMode, ), // 分隔线 Container( height: 30.h, width: 1, color: isDarkMode ? Colors.grey[800] : Colors.grey[300], ), // 右耳机 _buildCompactBatteryItem( label: 'right'.tr, // 右 batteryLevel: rightBattery, isCharging: rightEarCharging, isDarkMode: isDarkMode, ), ], // 只有在充电盒电量大于0且设备已连接时才显示充电盒 if (shouldShowCase) ...[ // 分隔线 Container( height: 30.h, width: 1, color: isDarkMode ? Colors.grey[800] : Colors.grey[300], ), // 充电盒 _buildCompactBatteryItem( label: 'chargingCase'.tr, batteryLevel: caseBattery, isCharging: caseCharging, isDarkMode: isDarkMode, ), ] ], ), ); }); } // 紧凑型电池项 Widget _buildCompactBatteryItem({ required String label, required int batteryLevel, required bool isDarkMode, bool isCharging = false, }) { // 获取电池图标和颜色 IconData batteryIcon; Color batteryColor; if (batteryLevel > 75) { batteryIcon = Icons.battery_full; batteryColor = Colors.green[600]!; } else if (batteryLevel > 50) { batteryIcon = Icons.battery_6_bar; batteryColor = Colors.green[600]!; } else if (batteryLevel > 25) { batteryIcon = Icons.battery_4_bar; batteryColor = Colors.orange[600]!; } else if (batteryLevel > 10) { batteryIcon = Icons.battery_3_bar; batteryColor = Colors.orange[600]!; } else { batteryIcon = Icons.battery_alert; batteryColor = Colors.red[600]!; } bool isBatteryZero = batteryLevel == -1 || batteryLevel == 0; return Expanded( child: Padding( padding: EdgeInsets.symmetric(vertical: 6.h), child: Column( mainAxisSize: MainAxisSize.min, children: [ // 标签 Text( label, style: TextStyle( fontSize: 11.sp, color: isDarkMode ? Colors.grey[400] : Colors.grey[500], fontWeight: FontWeight.normal, ), textAlign: TextAlign.center, ), SizedBox(height: 4.h), // 电池指示器 - 当电量为0时,显示横线 isBatteryZero ? Container( width: 20.w, // 横线宽度 height: 12.sp, // 设置与图标相同的高度,确保对齐 alignment: Alignment.center, // 居中对齐 child: Container( width: 10.w, height: 1.5.h, // 实际横线高度 color: isDarkMode ? Colors.grey[600] : Colors.grey[400], // 横线颜色 ), ) : Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( batteryIcon, size: 12.sp, color: batteryColor, ), SizedBox(width: 2.w), Text( '$batteryLevel%', style: TextStyle( fontSize: 11.sp, fontWeight: FontWeight.w500, color: batteryColor, ), ), if (isCharging) Icon( Icons.bolt, size: 10.sp, color: Colors.green[600], ), ], ), ], ), ), ); } // 设备详情卡片 // 未连接信息 Widget _buildDisconnectedInfo(bool isDarkMode) { return Container( padding: EdgeInsets.symmetric(vertical: 10.h, horizontal: 12.w), decoration: BoxDecoration( color: isDarkMode ? Colors.grey[900] : Colors.grey[100], borderRadius: BorderRadius.circular(10.r), border: Border.all( color: isDarkMode ? Colors.grey[800]! : Colors.grey[300]!, width: 1, ), ), child: IntrinsicHeight( child: Row( mainAxisAlignment: MainAxisAlignment.center, // 整体居中对齐 crossAxisAlignment: CrossAxisAlignment.start, // 顶部对齐,适应多行文本 children: [ // 图标容器,与文本第一行基线对齐 Padding( padding: EdgeInsets.only(top: 1.h), // 微调图标位置,与文本第一行基线对齐 child: Icon( Icons.bluetooth_disabled, size: 14.sp, color: isDarkMode ? Colors.grey[400] : Colors.grey[700], ), ), SizedBox(width: 6.w), // 图标和文本间距 // 文本容器,使用Flexible确保自动换行且保持居中效果 Flexible( child: Text( 'disconnectedDevice'.tr, // 未连接设备,点击下方按钮连接 style: TextStyle( fontSize: 12.sp, color: isDarkMode ? Colors.grey[400] : Colors.grey[700], height: 1.4, // 启用行高,提升多行文本可读性 ), textAlign: TextAlign.center, // 文本居中对齐 softWrap: true, // 启用软换行 overflow: TextOverflow.visible, // 确保文本完全显示 ), ), ], ), ), ); } // 连接按钮 Widget _buildConnectButton() { return ElevatedButton( onPressed: controller.rescanDevices, style: ElevatedButton.styleFrom( backgroundColor: Colors.blue, foregroundColor: Colors.white, minimumSize: Size(double.infinity, 44.h), elevation: 2, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10.r), ), ), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.bluetooth_searching, size: 16.sp), SizedBox(width: 8.w), Text( 'connectDevice'.tr, // 连接设备 style: TextStyle( fontSize: 14.sp, fontWeight: FontWeight.w500, ), ), ], ), ); } // 热门AI体验标题 Widget _buildSectionTitle(bool isDarkMode) { return Row( children: [ Text( 'topAiExperiences'.tr, // 热门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: IntroStepBuilder( group: 'home', order: 3, getOverlayPosition: IntroOverlayBuilder.overlayPosition, overlayBuilder: (params) { return IntroOverlayBuilder.aiBuilder( params, 'guideAwakenSuccess'.tr, onTap: () { params.onFinish(); controller.exploreAIFeatures(); }, ); }, builder: (BuildContext context, GlobalKey key) => SizedBox( key: key, child: _buildFeatureCard( title: 'aiAssistant'.tr, // AI全能助手 description: 'aiAssistantInfo'.tr, // 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), ), ), ), ), SizedBox(width: 16.w), // 右侧两个卡片 Expanded( flex: 1, child: Column( children: [ // 右上卡片 - 翻译 _buildFeatureCard( title: 'interpretation'.tr, // 翻译 description: 'simultaneousInterpretationInfo'.tr, // 80+语言实时翻译,出国无忧 icon: Icons.translate, gradient: LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [ const Color(0xFF4CAF50).withOpacity(0.3), const Color(0xFF009688).withOpacity(0.3), ], ), onTap: controller.openTranslation, height: 83.h, // 增加高度 isDarkMode: isDarkMode, iconColor: const Color(0xFF4CAF50), ), SizedBox(height: 5.h), // 减少间距 // 右下卡片 - // 右下卡片 - 会议助手 _buildFeatureCard( title: 'conferenceAssistant'.tr, // 商务会议助手 description: 'conferenceAssistantInfo'.tr, // 实时记录会议纪要,多语言翻译 icon: Icons.people, gradient: LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [ Color(0xFFab47bc).withOpacity(0.3), // 薰衣草紫 Color(0xFFec407a).withOpacity(0.3), // 品红 ], ), onTap: () { // Get.toNamed(Routes.meeting); controller.openMeet(); }, height: 85.h, // 增加高度 isDarkMode: isDarkMode, iconColor: const Color(0xFFd81b60), // 品红 ), ], ), ), ], ); } // 特性卡片构建方法 Widget _buildFeatureCard({ required String title, required String description, required IconData icon, required LinearGradient gradient, required VoidCallback onTap, double? height, bool iconOnTop = false, bool isDarkMode = false, Color iconColor = Colors.white, }) { return GestureDetector( onTap: onTap, child: Container( height: height ?? 175.h, padding: EdgeInsets.all(14.w), decoration: BoxDecoration( gradient: gradient, borderRadius: BorderRadius.circular(16.r), boxShadow: [ BoxShadow( color: isDarkMode ? Colors.black.withOpacity(0.2) : Colors.grey.withOpacity(0.1), blurRadius: 8, offset: const Offset(0, 4), ), ], ), 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, ), 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, ), 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), Flexible( child: Text( description, style: TextStyle( color: isDarkMode ? Colors.grey[400] : Colors.grey[600], fontSize: 12.sp, ), maxLines: 3, overflow: TextOverflow.ellipsis, ), ), ], ), ) 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(height: 2.h), Flexible( child: Text( description, style: TextStyle( color: isDarkMode ? Colors.grey[400] : Colors.grey[600], fontSize: 10.sp, ), maxLines: 2, overflow: TextOverflow.ellipsis, ), ), ], ), ), ], ), ), ); } }