import 'package:common_utils/common_utils.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import '../../../core/theme/app_colors.dart'; import '../../../routes/app_routes.dart'; import '../controllers/meeting_controller.dart'; import '../model/meeting_model.dart'; class MeetingView extends GetView { const MeetingView({super.key}); @override Widget build(BuildContext context) { final isDarkMode = Theme.of(context).brightness == Brightness.dark; return Scaffold( backgroundColor: isDarkMode ? Colors.black : Colors.grey[50], appBar: _buildAppBar(isDarkMode), body: _buildBody(context, isDarkMode), ); } // 构建应用栏 PreferredSizeWidget _buildAppBar(bool isDarkMode) { return AppBar( backgroundColor: isDarkMode ? Colors.black : Colors.white, elevation: 0.5, leading: IconButton( icon: Icon( Icons.arrow_back_ios, color: isDarkMode ? Colors.white : Colors.black, size: 20.sp, ), onPressed: () => Get.back(), ), title: Text( 'conferenceAssistant'.tr, // 商务会议助手 style: TextStyle( fontSize: 17.sp, fontWeight: FontWeight.w600, color: isDarkMode ? Colors.white : Colors.black, ), ), centerTitle: true, ); } // 构建主体内容 Widget _buildBody(BuildContext context, bool isDarkMode) { return Stack( children: [ Obx( () => ListView.builder( itemCount: controller.dataList.length, padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 5.w), itemBuilder: (BuildContext context, int index) { MeetingModel data = MeetingModel.fromJson(controller.dataList[index]); return _item(context, isDarkMode, data); }, ), ), Align( alignment: Alignment.bottomCenter, child: GestureDetector( onTap: () { _bottomSheet(context, isDarkMode); }, child: Container( width: 130.w, height: 48.w, margin: EdgeInsets.symmetric(vertical: 20.w), decoration: BoxDecoration( color: isDarkMode ? AppColors.primary : Colors.blue, borderRadius: BorderRadius.circular(12.w), ), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ const Icon(Icons.keyboard_voice, color: Colors.white), 5.horizontalSpace, Text( '开始会议', style: TextStyle(color: Colors.white, fontSize: 16.sp), ), ], ), ), ), ), ], ); } Widget _item(BuildContext context, bool isDarkMode, MeetingModel data) { return GestureDetector( onTap: () { Get.toNamed(Routes.meetingDetails, arguments: { 'id': data.id, }); }, onLongPressStart: (details) { RenderBox? renderBox = Overlay.of(context).context.findRenderObject() as RenderBox; final RelativeRect position = RelativeRect.fromRect( Rect.fromLTRB( details.globalPosition.dx, details.globalPosition.dy, details.globalPosition.dx + 110, // 菜单显示位置X轴坐标 details.globalPosition.dy - 40, // 菜单显示位置Y轴坐标 ), Offset.zero & renderBox.size, ); showMenu( context: context, position: position, color: isDarkMode ? AppColors.cardBackground : Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12.r), ), items: [ _popupMenuEntry( Icon( Icons.edit_calendar, color: isDarkMode ? Colors.white : Colors.black87, ), '编辑', isDarkMode ? Colors.white : Colors.black87, () { controller.titleController.text = data.title; _bottomSheet(context, isDarkMode, id: data.id); }, ), _popupMenuEntry( const Icon(Icons.delete_outline, color: Colors.red), '删除', isDarkMode ? Colors.white : Colors.black87, () { controller.deleteMeeting(data.id); }, ), ], ); }, child: Container( padding: EdgeInsets.symmetric(horizontal: 15.w, vertical: 8.w), margin: EdgeInsets.symmetric(vertical: 5.w), decoration: BoxDecoration( color: isDarkMode ? Colors.white.withOpacity(0.05) : Colors.white, borderRadius: BorderRadius.circular(12.w), boxShadow: [ BoxShadow( color: isDarkMode ? Colors.black.withOpacity(0.2) : Colors.black.withOpacity(0.05), blurRadius: 10, offset: const Offset(0, 2), ), ], ), child: Column( children: [ Row( children: [ Expanded( child: Text( data.title, style: TextStyle( color: isDarkMode ? Colors.white : Colors.black87, fontSize: 16.sp, ), overflow: TextOverflow.ellipsis, ), ), 10.horizontalSpace, Text( DateUtil.formatDateMs( data.creationtime, format: DateFormats.y_mo_d_h_m, ), style: TextStyle( color: isDarkMode ? Colors.white70 : Colors.black54, fontSize: 12.sp, ), ), ], ), Row( children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( data.content.isNotEmpty ? data.content : '无内容', style: TextStyle( color: isDarkMode ? Colors.white70 : Colors.black54, fontSize: 12.sp, ), overflow: TextOverflow.ellipsis, ), Row( children: [ Icon( Icons.location_on, size: 14.w, color: isDarkMode ? Colors.white70 : Colors.black54, ), Expanded( child: Text( data.address, style: TextStyle( color: isDarkMode ? Colors.white70 : Colors.black54, fontSize: 12.sp, ), overflow: TextOverflow.ellipsis, ), ), ], ), ], ), ), Container( width: 76.w, height: 28.w, margin: EdgeInsets.only(left: 10.w), alignment: Alignment.center, decoration: BoxDecoration( color: isDarkMode ? AppColors.primary : Colors.blue, borderRadius: BorderRadius.circular(28.w), ), child: Text( DateUtil.formatDateMs( data.seconds * 1000, format: 'HH:mm:ss', isUtc: true, ), style: TextStyle(color: Colors.white, fontSize: 14.sp), ), ), ], ), ], ), ), ); } PopupMenuEntry _popupMenuEntry( Icon icon, String title, Color color, Function() onTap, ) { return PopupMenuItem( onTap: onTap, child: SizedBox( width: 120.w, child: Row( children: [ icon, 8.horizontalSpace, Text( title, style: TextStyle(color: color), ), ], ), ), ); } void _bottomSheet( BuildContext context, bool isDarkMode, { int? id, }) { showModalBottomSheet( context: context, isScrollControlled: true, clipBehavior: Clip.hardEdge, builder: (BuildContext context) { return Padding( padding: MediaQuery.of(context).viewInsets, child: Container( padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 20.w), color: isDarkMode ? AppColors.darkBackground : Colors.grey[50], child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ Text( id != null ? '修改会议标题(非必填)' : '会议标题(非必填)', style: TextStyle( color: isDarkMode ? Colors.white : Colors.black87, fontSize: 16.sp, ), ), Container( height: 48.w, margin: EdgeInsets.only(top: 10.w, bottom: 20.w), alignment: Alignment.center, decoration: BoxDecoration( color: isDarkMode ? Colors.white.withOpacity(0.05) : Colors.white, borderRadius: BorderRadius.circular(12.w), boxShadow: [ BoxShadow( color: isDarkMode ? Colors.black.withOpacity(0.2) : Colors.black.withOpacity(0.05), blurRadius: 10, offset: const Offset(0, 2), ), ], ), child: TextField( controller: controller.titleController, style: TextStyle( color: isDarkMode ? Colors.white : Colors.black87, fontSize: 16.sp, ), decoration: InputDecoration( hintText: '最多50个字符', hintStyle: TextStyle( color: isDarkMode ? Colors.white70 : Colors.black54, fontSize: 16.sp, ), fillColor: Colors.transparent, border: InputBorder.none, contentPadding: EdgeInsets.symmetric(horizontal: 10.w), ), ), ), Padding( padding: EdgeInsets.only(top: 30.w), child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ GestureDetector( onTap: () { Get.back(); }, child: Container( width: 120.w, height: 40.w, alignment: Alignment.center, decoration: BoxDecoration( border: Border.all( width: 2.w, color: isDarkMode ? AppColors.primary : Colors.blue, ), borderRadius: BorderRadius.circular(12.w), ), child: Text( '取消', style: TextStyle( fontSize: 14.sp, color: isDarkMode ? AppColors.primary : Colors.blue, ), ), ), ), GestureDetector( onTap: () { int time = DateTime.now().millisecondsSinceEpoch; String title = controller.titleController.text; if (id != null) { controller.editMeetingTitle(id, title); } else { if (title.isEmpty) { title = '${DateUtil.formatDateMs(time, format: DateFormats.y_mo_d)} 会议'; } Get.back(); Get.toNamed(Routes.meetingRecord, arguments: { 'title': title, }); } }, child: Container( width: 120.w, height: 40.w, alignment: Alignment.center, decoration: BoxDecoration( color: isDarkMode ? AppColors.primary : Colors.blue, borderRadius: BorderRadius.circular(12.w), ), child: Text( '确定', style: TextStyle( color: Colors.white, fontSize: 14.sp, ), ), ), ), ], ), ), ], ), ), ); }, ).then((value) { controller.titleController.text = ''; }); } }