diff --git a/lib/modules/meeting/controllers/meeting_details_controller.dart b/lib/modules/meeting/controllers/meeting_details_controller.dart index 65fd39ea2..19a9db30f 100644 --- a/lib/modules/meeting/controllers/meeting_details_controller.dart +++ b/lib/modules/meeting/controllers/meeting_details_controller.dart @@ -25,6 +25,8 @@ class MeetingDetailsController extends GetxController late AnimationController lottieController; + late final Worker _tasktypeListener; + final _meetingUploadService = Get.find(); final _meetingTaskService = Get.find(); @@ -84,7 +86,7 @@ class MeetingDetailsController extends GetxController _meetingTaskService.meetingId = id; _getDataDetails(); _loadJS(); - ever(_meetingTaskService.tasktype, (value) { + _tasktypeListener = ever(_meetingTaskService.tasktype, (value) { meetingDetails.value.tasktype = value; if (_everType <= value) { if (value == 2) { @@ -101,6 +103,7 @@ class MeetingDetailsController extends GetxController @override void onClose() { + _tasktypeListener.dispose(); _currentDurationSubscription?.cancel(); _playerStateSubscription?.cancel(); tabController.dispose(); diff --git a/lib/modules/meeting/controllers/meeting_mine_controller.dart b/lib/modules/meeting/controllers/meeting_mine_controller.dart index 5e2fa8d7d..72f06ab37 100644 --- a/lib/modules/meeting/controllers/meeting_mine_controller.dart +++ b/lib/modules/meeting/controllers/meeting_mine_controller.dart @@ -14,6 +14,9 @@ class MeetingMineController extends GetxController { final ScrollController scrollController = ScrollController(); + late final Worker _pageIndexListener; + late final Worker _originalDataListener; + bool isStatistics = true; Map statistics = {}; @@ -38,18 +41,20 @@ class MeetingMineController extends GetxController { } }); _getStatistics(); - ever(_meetingController.pageIndex, (value) { + _pageIndexListener = ever(_meetingController.pageIndex, (value) { if (isStatistics && value == 2) { _getStatistics(); } }); - ever(_homeController.originalDataList, (value) { + _originalDataListener = ever(_homeController.originalDataList, (value) { isStatistics = true; }); } @override void onClose() { + _pageIndexListener.dispose(); + _originalDataListener.dispose(); scrollController.dispose(); super.onClose(); } diff --git a/lib/modules/meeting/controllers/mind_map_controller.dart b/lib/modules/meeting/controllers/mind_map_controller.dart index b2a229f93..c9d83d25e 100644 --- a/lib/modules/meeting/controllers/mind_map_controller.dart +++ b/lib/modules/meeting/controllers/mind_map_controller.dart @@ -18,6 +18,8 @@ class MindMapController extends GetxController { final double _width = 1.sw - 25.w; bool isWebViewReady = false; + late final Worker _summaryNumberListener; + @override void onInit() { super.onInit(); @@ -150,12 +152,19 @@ class MindMapController extends GetxController { ) ..setBackgroundColor(Colors.transparent) ..loadHtmlString(html); - ever(_meetingDetailsController.summaryNumberModifications, (value) { + _summaryNumberListener = + ever(_meetingDetailsController.summaryNumberModifications, (value) { webViewController.runJavaScript( 'updateMarkmap(`${_meetingDetailsController.meetingDetails.value.summary}`)'); }); } + @override + void onClose() { + _summaryNumberListener.dispose(); + super.onClose(); + } + void _messageReceived(message) async { final String dataUrl = message.message; final String base64Str = dataUrl.split(',').last; diff --git a/lib/modules/meeting/views/meeting_details_view.dart b/lib/modules/meeting/views/meeting_details_view.dart index ab674cdaf..53ffb10bc 100644 --- a/lib/modules/meeting/views/meeting_details_view.dart +++ b/lib/modules/meeting/views/meeting_details_view.dart @@ -25,219 +25,224 @@ class MeetingDetailsView extends GetView { return PopScope( onPopInvokedWithResult: controller.popInvokedWithResult, - child: Obx( - () => Scaffold( - backgroundColor: isDarkMode ? Colors.black : Colors.grey[50], - appBar: _buildAppBar(context, isDarkMode), - body: _buildBody(isDarkMode), - ), + child: Scaffold( + backgroundColor: isDarkMode ? Colors.black : Colors.grey[50], + appBar: _buildAppBar(context, isDarkMode), + body: _buildBody(isDarkMode), ), ); } // 构建应用栏 PreferredSizeWidget _buildAppBar(BuildContext context, bool isDarkMode) { - return AppBar( - backgroundColor: - controller.isTop.value ? Colors.grey[50] : Colors.grey[200], - surfaceTintColor: Colors.transparent, - elevation: 0.5, - leading: controller.isSpeakerText.value - ? GestureDetector( - onTap: () { - controller.isSpeakerText.value = false; - controller.editSpeakerTextId.value = 0; - controller.editSpeakerTextList = []; - }, - child: Center( - child: Text( - 'cancel'.tr, - style: TextStyle( - color: isDarkMode ? Colors.white : Colors.black87, - fontSize: 16.sp, - ), - ), - ), - ) - : IconButton( - icon: Icon( - Icons.arrow_back_ios, - color: isDarkMode ? Colors.white : Colors.black, - size: 20.sp, - ), - onPressed: () => Get.back(), - ), - title: Obx( - () => Opacity( - opacity: (1 - (controller.dragOffset.value / 100.w)).clamp(0.0, 1.0), - child: Container( - width: 170.w, - padding: EdgeInsets.symmetric(horizontal: 2.w, vertical: 3.w), - clipBehavior: Clip.hardEdge, - decoration: BoxDecoration( - color: Colors.grey[200], - borderRadius: BorderRadius.circular(30.r), - ), - child: Row( - children: [ - GestureDetector( + return PreferredSize( + preferredSize: const Size.fromHeight(kToolbarHeight), + child: Obx( + () => AppBar( + backgroundColor: + controller.isTop.value ? Colors.grey[50] : Colors.grey[200], + surfaceTintColor: Colors.transparent, + elevation: 0.5, + leading: controller.isSpeakerText.value + ? GestureDetector( onTap: () { - if (controller.meetingData.value.filepath.isEmpty) { - controller.downloadAudio(); - } else { - if (controller.isPlay.value) { - controller.playerController.pausePlayer(); - } else { - controller.playerController.startPlayer(); - } - } + controller.isSpeakerText.value = false; + controller.editSpeakerTextId.value = 0; + controller.editSpeakerTextList = []; }, - child: Obx( - () => !controller.isLoading.value && - controller.meetingData.value.filepath.isEmpty - ? Obx( - () => Stack( - alignment: Alignment.center, - children: [ - if (controller.isDownload.value) - SizedBox( - width: 26.w, - height: 26.w, - child: CircularProgressIndicator( - value: controller.downloadProgress.value, - valueColor: - const AlwaysStoppedAnimation( - Colors.red), - strokeWidth: 2.w, + child: Center( + child: Text( + 'cancel'.tr, + style: TextStyle( + color: isDarkMode ? Colors.white : Colors.black87, + fontSize: 16.sp, + ), + ), + ), + ) + : IconButton( + icon: Icon( + Icons.arrow_back_ios, + color: isDarkMode ? Colors.white : Colors.black, + size: 20.sp, + ), + onPressed: () => Get.back(), + ), + title: Obx( + () => Opacity( + opacity: + (1 - (controller.dragOffset.value / 100.w)).clamp(0.0, 1.0), + child: Container( + width: 170.w, + padding: EdgeInsets.symmetric(horizontal: 2.w, vertical: 3.w), + clipBehavior: Clip.hardEdge, + decoration: BoxDecoration( + color: Colors.grey[200], + borderRadius: BorderRadius.circular(30.r), + ), + child: Row( + children: [ + GestureDetector( + onTap: () { + if (controller.meetingData.value.filepath.isEmpty) { + controller.downloadAudio(); + } else { + if (controller.isPlay.value) { + controller.playerController.pausePlayer(); + } else { + controller.playerController.startPlayer(); + } + } + }, + child: Obx( + () => !controller.isLoading.value && + controller.meetingData.value.filepath.isEmpty + ? Obx( + () => Stack( + alignment: Alignment.center, + children: [ + if (controller.isDownload.value) + SizedBox( + width: 26.w, + height: 26.w, + child: CircularProgressIndicator( + value: + controller.downloadProgress.value, + valueColor: + const AlwaysStoppedAnimation< + Color>(Colors.red), + strokeWidth: 2.w, + ), + ), + Icon( + Icons.download_for_offline, + color: Colors.black, + size: 30.w, ), - ), - Icon( - Icons.download_for_offline, - color: Colors.black, - size: 30.w, + ], ), - ], + ) + : Icon( + controller.isPlay.value + ? Icons.pause_circle + : Icons.play_circle, + color: Colors.black, + size: 30.w, + ), + ), + ), + 4.horizontalSpace, + GestureDetector( + onTap: () { + if (controller.isSpeakerText.value) return; + controller.dragOffset.value = 210.w; + controller.isTop.value = false; + }, + behavior: HitTestBehavior.translucent, + child: SizedBox( + width: 130.w, + height: 30.w, + child: FittedBox( + fit: BoxFit.scaleDown, + child: AudioFileWaveforms( + size: Size(350.w, 30.w), + playerController: controller.playerController, + waveformData: List.generate(88, (int index) { + return 0.01 + Random().nextDouble() * 0.09; + }), + waveformType: WaveformType.fitWidth, + enableSeekGesture: false, + playerWaveStyle: PlayerWaveStyle( + spacing: 4.w, + waveThickness: 2.w, + fixedWaveColor: Colors.grey[400]!, + liveWaveColor: Colors.red, + seekLineColor: Colors.red, + scaleFactor: 200, ), - ) - : Icon( - controller.isPlay.value - ? Icons.pause_circle - : Icons.play_circle, - color: Colors.black, - size: 30.w, ), - ), - ), - 4.horizontalSpace, - GestureDetector( - onTap: () { - if (controller.isSpeakerText.value) return; - controller.dragOffset.value = 210.w; - controller.isTop.value = false; - }, - behavior: HitTestBehavior.translucent, - child: SizedBox( - width: 130.w, - height: 30.w, - child: FittedBox( - fit: BoxFit.scaleDown, - child: AudioFileWaveforms( - size: Size(350.w, 30.w), - playerController: controller.playerController, - waveformData: List.generate(88, (int index) { - return 0.01 + Random().nextDouble() * 0.09; - }), - waveformType: WaveformType.fitWidth, - enableSeekGesture: false, - playerWaveStyle: PlayerWaveStyle( - spacing: 4.w, - waveThickness: 2.w, - fixedWaveColor: Colors.grey[400]!, - liveWaveColor: Colors.red, - seekLineColor: Colors.red, - scaleFactor: 200, ), ), ), - ), - ), - ], - ), - ), - ), - ), - centerTitle: true, - actions: [ - if (controller.isSpeakerText.value) - GestureDetector( - onTap: controller.editSpeakerText, - child: Padding( - padding: EdgeInsets.symmetric( - horizontal: 12.w, - vertical: 6.w, - ), - child: Text( - 'save'.tr, - style: TextStyle( - color: isDarkMode ? AppColors.primary : Colors.blue, - fontSize: 16.sp, + ], ), ), ), ), - if (!controller.isSpeakerText.value) - IconButton( - icon: Icon( - Icons.ios_share, - color: isDarkMode ? Colors.white : Colors.black, - size: 22.sp, - ), - onPressed: () { - Get.bottomSheet( - const ShareBottomSheet(), - isScrollControlled: true, - backgroundColor: Colors.grey[100], - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.vertical( - top: Radius.circular(12.r), + centerTitle: true, + actions: [ + if (controller.isSpeakerText.value) + GestureDetector( + onTap: controller.editSpeakerText, + child: Padding( + padding: EdgeInsets.symmetric( + horizontal: 12.w, + vertical: 6.w, + ), + child: Text( + 'save'.tr, + style: TextStyle( + color: isDarkMode ? AppColors.primary : Colors.blue, + fontSize: 16.sp, + ), ), ), - ); - }, - ), - if (!controller.isSpeakerText.value) - IconButton( - icon: Container( - width: 22.w, - height: 22.w, - alignment: Alignment.center, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20.r), - border: Border.all( + ), + if (!controller.isSpeakerText.value) + IconButton( + icon: Icon( + Icons.ios_share, color: isDarkMode ? Colors.white : Colors.black, - width: 2, + size: 22.sp, ), + onPressed: () { + Get.bottomSheet( + const ShareBottomSheet(), + isScrollControlled: true, + backgroundColor: Colors.grey[100], + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.vertical( + top: Radius.circular(12.r), + ), + ), + ); + }, ), - child: Icon( - Icons.more_horiz, - color: isDarkMode ? Colors.white : Colors.black, - size: 16.sp, - ), - ), - onPressed: () { - Get.bottomSheet( - const MoreBottomSheet(), - isScrollControlled: true, - backgroundColor: Colors.grey[100], - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.vertical( - top: Radius.circular(12.r), + if (!controller.isSpeakerText.value) + IconButton( + icon: Container( + width: 22.w, + height: 22.w, + alignment: Alignment.center, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20.r), + border: Border.all( + color: isDarkMode ? Colors.white : Colors.black, + width: 2, + ), + ), + child: Icon( + Icons.more_horiz, + color: isDarkMode ? Colors.white : Colors.black, + size: 16.sp, ), ), - ); - }, - ), - ], + onPressed: () { + Get.bottomSheet( + const MoreBottomSheet(), + isScrollControlled: true, + backgroundColor: Colors.grey[100], + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.vertical( + top: Radius.circular(12.r), + ), + ), + ); + }, + ), + ], + ), + ), ); } diff --git a/lib/modules/meeting/views/tabs/summary_tab.dart b/lib/modules/meeting/views/tabs/summary_tab.dart index f29b327af..d9f35d6d7 100644 --- a/lib/modules/meeting/views/tabs/summary_tab.dart +++ b/lib/modules/meeting/views/tabs/summary_tab.dart @@ -20,6 +20,9 @@ class SummaryTab extends StatefulWidget { class _SummaryTabState extends State { final _controller = Get.find(); + + late final Worker _personnelListener; + final String _addressPrefix = '地点:'; String _addressText = ''; final String _personnelPrefix = '与会人员:'; @@ -44,7 +47,8 @@ class _SummaryTabState extends State { _hasFocus = _focusNode.hasFocus; }); }); - ever(_controller.personnelNumberModifications, (value) { + _personnelListener = + ever(_controller.personnelNumberModifications, (value) { _initController(); }); } @@ -60,7 +64,9 @@ class _SummaryTabState extends State { : '[输入与会人员]'); final markdown = const ParchmentMarkdownCodec() .decode(_controller.meetingDetails.value.summary); - _fleatherController = FleatherController(document: markdown); + setState(() { + _fleatherController = FleatherController(document: markdown); + }); } void _handleAddressChanged() { @@ -134,13 +140,14 @@ class _SummaryTabState extends State { _controller.meetingDetails.value.summary = markdown; _controller.summaryNumberModifications.value++; } - _focusNode.dispose(); - _fleatherController?.dispose(); } @override void dispose() { + _personnelListener.dispose(); _saveSummary(); + _fleatherController?.dispose(); + _focusNode.dispose(); _addressController.dispose(); _personnelController.dispose(); super.dispose();