From ddc2ccacb8a70576d356d6f8c04f7b1738758c9d Mon Sep 17 00:00:00 2001 From: tanlongsheng <252620078@qq.com> Date: Sat, 19 Jul 2025 16:04:03 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=86=85=E5=AE=B9?= =?UTF-8?q?=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../meeting_details_controller.dart | 5 +- .../controllers/meeting_mine_controller.dart | 9 +- .../controllers/mind_map_controller.dart | 11 +- .../meeting/views/meeting_details_view.dart | 379 +++++++++--------- .../meeting/views/tabs/summary_tab.dart | 15 +- 5 files changed, 224 insertions(+), 195 deletions(-) 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(); From 72f9eeca41d9f4eedf1208976e4ea5cc6b8c3578 Mon Sep 17 00:00:00 2001 From: tanlongsheng <252620078@qq.com> Date: Sat, 19 Jul 2025 18:58:47 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BC=9A=E8=AE=AE?= =?UTF-8?q?=E5=8A=A9=E6=89=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../views/bottomSheet/more_bottom_sheet.dart | 13 ++++++++----- .../views/bottomSheet/share_bottom_sheet.dart | 14 +++++++++----- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/lib/modules/meeting/views/bottomSheet/more_bottom_sheet.dart b/lib/modules/meeting/views/bottomSheet/more_bottom_sheet.dart index d7d6c6421..187f4bd7f 100644 --- a/lib/modules/meeting/views/bottomSheet/more_bottom_sheet.dart +++ b/lib/modules/meeting/views/bottomSheet/more_bottom_sheet.dart @@ -64,7 +64,7 @@ class _MoreBottomSheetState extends State { return InkWell( onTap: onTap, child: Container( - padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 15.w), + padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 14.w), margin: EdgeInsets.only(bottom: 10.w), decoration: BoxDecoration( color: onTap != null ? Colors.white : Colors.grey[200], @@ -72,9 +72,12 @@ class _MoreBottomSheetState extends State { ), child: Row( children: [ - Icon( - icon, - color: Colors.black87, + Opacity( + opacity: onTap != null ? 1.0 : 0.5, + child: Icon( + icon, + color: Colors.black87, + ), ), 10.horizontalSpace, Expanded( @@ -82,7 +85,7 @@ class _MoreBottomSheetState extends State { title, style: TextStyle( fontSize: 14.sp, - color: Colors.black87, + color: Colors.black87.withOpacity(onTap != null ? 1 : 0.5), ), ), ), diff --git a/lib/modules/meeting/views/bottomSheet/share_bottom_sheet.dart b/lib/modules/meeting/views/bottomSheet/share_bottom_sheet.dart index 0936a5636..bd5b1f26f 100644 --- a/lib/modules/meeting/views/bottomSheet/share_bottom_sheet.dart +++ b/lib/modules/meeting/views/bottomSheet/share_bottom_sheet.dart @@ -218,12 +218,13 @@ class _ShareBottomSheetState extends State { return InkWell( onTap: onTap, child: Container( - padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 15.w), + padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 14.w), decoration: BoxDecoration( color: onTap != null ? null : Colors.grey[200], border: isBorder ? Border( bottom: BorderSide( + width: 0.5, color: Colors.grey[300]!, ), ) @@ -231,9 +232,12 @@ class _ShareBottomSheetState extends State { ), child: Row( children: [ - Icon( - icon, - color: Colors.black87, + Opacity( + opacity: onTap != null ? 1.0 : 0.5, + child: Icon( + icon, + color: Colors.black87, + ), ), 10.horizontalSpace, Expanded( @@ -241,7 +245,7 @@ class _ShareBottomSheetState extends State { title, style: TextStyle( fontSize: 14.sp, - color: Colors.black87, + color: Colors.black87.withOpacity(onTap != null ? 1 : 0.5), ), ), ), From 81caf12f8a80f2ecbe547187354d2391bf67217c Mon Sep 17 00:00:00 2001 From: fdp <1286779656@qq.com> Date: Sun, 20 Jul 2025 00:58:14 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=8F=91=E9=80=81ble?= =?UTF-8?q?=E5=91=BD=E4=BB=A4=E6=B2=A1=E6=9C=89=E5=9B=9E=E5=A4=8D=E3=80=82?= =?UTF-8?q?=E5=AF=BC=E8=87=B4=E5=90=8E=E7=BB=AD=E7=9A=84=E5=91=BD=E4=BB=A4?= =?UTF-8?q?=E5=8F=91=E9=80=81=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yunqiinnovation/ble_service/BleService.kt | 54 ++++++++++++------- 1 file changed, 36 insertions(+), 18 deletions(-) diff --git a/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleService.kt b/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleService.kt index af78e6d49..999dd7efc 100644 --- a/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleService.kt +++ b/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleService.kt @@ -106,6 +106,15 @@ object BleService { // 初始化状态 private var isInitialized = false + private val replyTimeoutHandler = Handler(Looper.getMainLooper()) + private val replyTimeoutRunnable = Runnable { + if (!isReply) { + Log.w(TAG, "命令响应超时,自动重置 isReply 为 true") + isReply = true + processNextCommand() + } + } + /** * 初始化BLE服务 * @param appContext 应用上下文 @@ -471,6 +480,8 @@ object BleService { } catch (e: Exception) { Log.e(TAG, "关闭GATT连接异常: ${e.message}", e) } + isReply = true; + commandQueue.clear() bluetoothGatt = null notifyChar = null writeChar = null @@ -520,6 +531,7 @@ object BleService { newState == BluetoothProfile.STATE_DISCONNECTED -> { updateConnectionState(BleConst.STATE_DISCONNECTED) disconnectGatt() + // otaManager?.onBtDeviceConnection(g.device, StateCode.CONNECTION_CONNECTING) // g.close() // otaManager?.release(); @@ -752,19 +764,10 @@ object BleService { } }" ) - isReply = true; - cmdReplyType = cmdType; - if (!commandQueue.isEmpty()) { - val nextCmd = commandQueue.poll() - writeChar!!.value = nextCmd - var isSeccess = bluetoothGatt?.writeCharacteristic(writeChar) - if (isSeccess == true) { - Log.d( - TAG, - "收到设备响应:" - ) - } - } + isReply = true + cmdReplyType = cmdType + replyTimeoutHandler.removeCallbacks(replyTimeoutRunnable) // 移除超时回调 + processNextCommand() // 根据命令类型处理不同的响应 when (cmdType) { BleConst.CMD_GET_VERSION -> { @@ -1385,13 +1388,16 @@ object BleService { // 加入队列并触发发送 if (isReply) { - var isSeccess = bluetoothGatt?.writeCharacteristic(writeChar) - if (isSeccess == true) { - isReply = false; - cmdType; + val isSuccess = bluetoothGatt?.writeCharacteristic(writeChar) + if (isSuccess == true) { + isReply = false + replyTimeoutHandler.postDelayed(replyTimeoutRunnable, 1000) // 设置1秒超时 return true } else + { + commandQueue.poll() return false + } } else { commandQueue.offer(cmdPacket) } @@ -1403,6 +1409,19 @@ object BleService { } } + private fun processNextCommand() { + if (!commandQueue.isEmpty()) { + val nextCmd = commandQueue.poll() + writeChar!!.value = nextCmd + val isSuccess = bluetoothGatt?.writeCharacteristic(writeChar) + if (isSuccess == true) { + isReply = false + replyTimeoutHandler.postDelayed(replyTimeoutRunnable, 1000) // 设置1秒超时 + Log.d(TAG, "发送队列中的下一个命令") + } + } + } + /** * 计算CRC8/MAXIM校验值 */ @@ -1588,4 +1607,3 @@ class RecordingFile(private val context: Context) { } } } - \ No newline at end of file