diff --git a/lib/modules/meeting/controllers/meeting_mine_controller.dart b/lib/modules/meeting/controllers/meeting_mine_controller.dart index 907ae480e..9e0fe905d 100644 --- a/lib/modules/meeting/controllers/meeting_mine_controller.dart +++ b/lib/modules/meeting/controllers/meeting_mine_controller.dart @@ -1,9 +1,16 @@ +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; import 'package:get/get.dart'; -import 'meeting_home_controller.dart'; +import '../../../data/services/db/sqflite_api.dart'; +import '../../profile/controllers/profile_controller.dart'; class MeetingMineController extends GetxController { - final _controller = Get.find(); + final profileCtrl = Get.find(); + + final ScrollController scrollController = ScrollController(); + + Map statistics = {}; RxInt days = 0.obs; RxInt numberFiles = 0.obs; @@ -12,15 +19,83 @@ class MeetingMineController extends GetxController { RxInt maxNumberFiles = 0.obs; RxDouble maxHourage = 0.0.obs; + int averageNumberFiles = 0; + @override void onInit() { super.onInit(); + WidgetsBinding.instance.addPostFrameCallback((_) { + if (scrollController.hasClients) { + final now = DateTime.now(); + if (now.month > 6) { + scrollController.jumpTo(scrollController.position.maxScrollExtent); + } + } + }); _getStatistics(); } - void _getStatistics() { - numberFiles.value = _controller.originalDataList.length; + @override + void onClose() { + scrollController.dispose(); + super.onClose(); + } + + void _getStatistics() async { + List dataList = await SqfliteApi.getMeetingList(); + numberFiles.value = dataList.length; + statistics = {}; + + for (var element in dataList) { + DateTime creationtime = + DateTime.fromMillisecondsSinceEpoch(element['creationtime']); + int dayOfYear = DateUtil.getDayOfYear(creationtime); + + if (!statistics.containsKey(dayOfYear)) { + statistics[dayOfYear] = { + 'creationtime': creationtime, + 'count': 0, + 'seconds': 0, + }; + } + statistics[dayOfYear]['count']++; + statistics[dayOfYear]['seconds'] += element['seconds']; + } + + int currentD = 1; + int maxD = 1; + int previous = 0; + int h = 0; + int maxH = 0; + int maxN = 0; + int minN = 0; + statistics.forEach((key, value) { + h += value['seconds'] as int; + if (key + 1 == previous) { + currentD++; + if (currentD > maxD) { + maxD = currentD; + } + } else { + currentD = 1; + } + previous = key; + if (value['count'] > maxN) { + maxN = value['count']; + } + if (value['count'] < minN || minN == 0) { + minN = value['count']; + } + if (value['seconds'] > maxH) { + maxH = value['seconds']; + } + }); - for (var element in _controller.originalDataList) {} + days.value = statistics.length; + hourage.value = double.parse((h / 60 / 60).toStringAsFixed(2)); + continuousDays.value = maxD; + maxNumberFiles.value = maxN; + maxHourage.value = double.parse((maxH / 60 / 60).toStringAsFixed(2)); + averageNumberFiles = (maxN + minN) ~/ 2; } } diff --git a/lib/modules/meeting/views/bottomSheet/statistics_bottom_sheet.dart b/lib/modules/meeting/views/bottomSheet/statistics_bottom_sheet.dart index 667bf370a..e9cd37d2a 100644 --- a/lib/modules/meeting/views/bottomSheet/statistics_bottom_sheet.dart +++ b/lib/modules/meeting/views/bottomSheet/statistics_bottom_sheet.dart @@ -1,7 +1,10 @@ +import 'dart:io'; + import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; +import '../../../profile/controllers/profile_controller.dart'; import '../../controllers/meeting_mine_controller.dart'; class StatisticsBottomSheet extends StatefulWidget { @@ -13,6 +16,7 @@ class StatisticsBottomSheet extends StatefulWidget { class _StatisticsBottomSheetState extends State { final _mineController = Get.find(); + final _profileCtrl = Get.find(); @override Widget build(BuildContext context) { @@ -49,15 +53,27 @@ class _StatisticsBottomSheetState extends State { margin: EdgeInsets.only(bottom: 10.w), decoration: BoxDecoration( borderRadius: BorderRadius.circular(50.w), - image: const DecorationImage( - image: NetworkImage( - 'https://pic8.iqiyipic.com/image/20250403/ed/a7/a_100013977_m_601_m75_318_424.avif'), - fit: BoxFit.cover, - ), + ), + child: CircleAvatar( + radius: 25.w, + backgroundImage: _profileCtrl.localAvatar.value.isNotEmpty + ? FileImage(File(_profileCtrl.localAvatar.value)) + : (_profileCtrl.userInfo.value.avatar.isNotEmpty + ? NetworkImage(_profileCtrl.userInfo.value.avatar) + : null) as ImageProvider?, + backgroundColor: Colors.grey[200], + child: (_profileCtrl.localAvatar.value.isEmpty && + _profileCtrl.userInfo.value.avatar.isEmpty) + ? Icon( + Icons.person, + size: 25.r, + color: Colors.grey[600], + ) + : null, ), ), Text( - 'tianming liu', + _profileCtrl.userInfo.value.name, style: TextStyle( color: Colors.black87, fontSize: 20.sp, @@ -171,8 +187,26 @@ class _StatisticsBottomSheetState extends State { ), itemCount: 364, itemBuilder: (BuildContext context, int index) { + final col = index % 52; + final row = index ~/ 52; + final vIndex = row + col * 7; + + int type = 0; + if (_mineController.statistics + .containsKey(vIndex + 1)) { + if (_mineController.statistics[vIndex + 1]['count'] <= + _mineController.averageNumberFiles) { + type = 1; + } else { + type = 2; + } + } return Container( - color: Colors.grey[200], + color: type == 0 + ? Colors.grey[200] + : type == 1 + ? Colors.red[100] + : Colors.red, ); }, ), diff --git a/lib/modules/meeting/views/meeting_home_view.dart b/lib/modules/meeting/views/meeting_home_view.dart index 2d79397e5..519273713 100644 --- a/lib/modules/meeting/views/meeting_home_view.dart +++ b/lib/modules/meeting/views/meeting_home_view.dart @@ -11,15 +11,27 @@ import '../model/meeting_model.dart'; import 'bottomSheet/edit_title_bottom_sheet.dart'; import 'bottomSheet/import_audio_bottom_sheet.dart'; -class MeetingHomeView extends GetView { +class MeetingHomeView extends StatefulWidget { const MeetingHomeView({super.key}); + @override + State createState() => _MeetingHomeViewState(); +} + +class _MeetingHomeViewState extends State + with AutomaticKeepAliveClientMixin { + final _controller = Get.put(MeetingHomeController()); + + @override + bool get wantKeepAlive => true; + @override Widget build(BuildContext context) { + super.build(context); final isDarkMode = Theme.of(context).brightness == Brightness.dark; return PopScope( - onPopInvokedWithResult: controller.onPopInvokedWithResult, + onPopInvokedWithResult: _controller.onPopInvokedWithResult, child: Scaffold( backgroundColor: isDarkMode ? Colors.black : Colors.grey[100], appBar: _buildAppBar(isDarkMode), @@ -61,7 +73,7 @@ class MeetingHomeView extends GetView { Widget _buildFiltrate(bool isDarkMode) { return GestureDetector( onTap: () { - controller.meetingController.scaffoldKey.currentState?.openDrawer(); + _controller.meetingController.scaffoldKey.currentState?.openDrawer(); }, behavior: HitTestBehavior.translucent, child: Row( @@ -95,7 +107,7 @@ class MeetingHomeView extends GetView { 5.horizontalSpace, Obx( () => Text( - '${controller.filtrateType.value.isNotEmpty ? controller.filtrateType : '全部文件'}(${controller.dataList.length})', + '${_controller.filtrateType.value.isNotEmpty ? _controller.filtrateType : '全部文件'}(${_controller.dataList.length})', style: TextStyle( color: isDarkMode ? Colors.white : Colors.black87, fontSize: 16.sp, @@ -194,10 +206,11 @@ class MeetingHomeView extends GetView { Widget _buildBody(BuildContext context, bool isDarkMode) { return Obx( () => ListView.builder( - itemCount: controller.dataList.length, + itemCount: _controller.dataList.length, padding: EdgeInsets.fromLTRB(12.w, 5.w, 12.w, 90.w), itemBuilder: (BuildContext context, int index) { - MeetingModel data = MeetingModel.fromJson(controller.dataList[index]); + MeetingModel data = + MeetingModel.fromJson(_controller.dataList[index]); return _item(context, isDarkMode, data); }, ), @@ -298,7 +311,7 @@ class MeetingHomeView extends GetView { const Spacer(), Obx(() { Map uploadData = - controller.meetingUploadService.uploadList.firstWhere( + _controller.meetingUploadService.uploadList.firstWhere( (element) => element['id'] == data.id, orElse: () => {}, ); @@ -307,13 +320,14 @@ class MeetingHomeView extends GetView { alignment: Alignment.center, children: [ if (uploadData['id'] == - controller.meetingUploadService.meetingId.value) + _controller + .meetingUploadService.meetingId.value) Obx( () => SizedBox( width: 20.w, height: 20.w, child: CircularProgressIndicator( - value: controller.meetingUploadService + value: _controller.meetingUploadService .uploadProgress.value, valueColor: const AlwaysStoppedAnimation( @@ -339,7 +353,7 @@ class MeetingHomeView extends GetView { }), Obx(() { Map taskData = - controller.meetingTaskService.taskFinishList.firstWhere( + _controller.meetingTaskService.taskFinishList.firstWhere( (element) => element['id'] == data.id, orElse: () => {}, ); @@ -401,9 +415,9 @@ class MeetingHomeView extends GetView { isDarkMode ? Colors.white : Colors.black87, () { final dotIndex = data.title.lastIndexOf('.'); - controller.titleController.text = + _controller.titleController.text = dotIndex != -1 ? data.title.substring(0, dotIndex) : data.title; - controller.titleCSuffix = + _controller.titleCSuffix = data.title.substring(dotIndex, data.title.length); Get.bottomSheet( EditTitleBottomSheet(data.id), @@ -426,7 +440,7 @@ class MeetingHomeView extends GetView { 'delete'.tr, // 删除 isDarkMode ? Colors.red[700]! : Colors.red, () { - controller.deleteMeeting(data.id, data.filepath); + _controller.deleteMeeting(data.id, data.filepath); }, ), ], diff --git a/lib/modules/meeting/views/meeting_mine_view.dart b/lib/modules/meeting/views/meeting_mine_view.dart index c84d61cf1..6a7549973 100644 --- a/lib/modules/meeting/views/meeting_mine_view.dart +++ b/lib/modules/meeting/views/meeting_mine_view.dart @@ -2,17 +2,28 @@ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import '../../../routes/app_routes.dart'; -import '../../profile/controllers/profile_controller.dart'; import '../../profile/views/unified_avatar.dart'; import '../controllers/meeting_mine_controller.dart'; import 'bottomSheet/statistics_bottom_sheet.dart'; -class MeetingMineView extends GetView { +class MeetingMineView extends StatefulWidget { const MeetingMineView({super.key}); + @override + State createState() => _MeetingMineViewState(); +} + +class _MeetingMineViewState extends State + with AutomaticKeepAliveClientMixin { + final _controller = Get.put(MeetingMineController()); + + @override + bool get wantKeepAlive => true; + @override Widget build(BuildContext context) { + super.build(context); return Scaffold( backgroundColor: Colors.grey[100], body: Container( @@ -96,8 +107,6 @@ class MeetingMineView extends GetView { } Widget _head() { - final ProfileController profileCtrl = - Get.find(); // 从GetX中获取ProfileController实例 return Padding( padding: EdgeInsets.symmetric(vertical: 20.w), child: GestureDetector( @@ -118,7 +127,7 @@ class MeetingMineView extends GetView { Expanded( child: Obx( () => Text( - profileCtrl.userInfo.value.name, + _controller.profileCtrl.userInfo.value.name, style: TextStyle( color: Colors.black87, fontSize: 20.sp, @@ -159,17 +168,17 @@ class MeetingMineView extends GetView { Row( children: [ _statisticsItem( - '${controller.days.value}', + '${_controller.days.value}', '天', Colors.lime, ), _statisticsItem( - '${controller.numberFiles.value}', + '${_controller.numberFiles.value}', '文件', Colors.lightGreen, ), _statisticsItem( - '${controller.hourage.value}', + '${_controller.hourage.value}', '小时', Colors.blueGrey, ), @@ -180,6 +189,7 @@ class MeetingMineView extends GetView { padding: EdgeInsets.symmetric(horizontal: 2.w), margin: EdgeInsets.only(top: 8.w, bottom: 2.w), child: GridView.builder( + controller: _controller.scrollController, scrollDirection: Axis.horizontal, gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 7, @@ -188,9 +198,22 @@ class MeetingMineView extends GetView { ), itemCount: 364, itemBuilder: (BuildContext context, int index) { + int type = 0; + if (_controller.statistics.containsKey(index + 1)) { + if (_controller.statistics[index + 1]['count'] <= + _controller.averageNumberFiles) { + type = 1; + } else { + type = 2; + } + } return Container( decoration: BoxDecoration( - color: Colors.grey[200], + color: type == 0 + ? Colors.grey[200] + : type == 1 + ? Colors.red[100] + : Colors.red, borderRadius: BorderRadius.circular(2.w), ), );