diff --git a/lib/modules/meeting/views/bottomSheet/share_bottom_sheet.dart b/lib/modules/meeting/views/bottomSheet/share_bottom_sheet.dart index 81a4d2e63..171aa9e8e 100644 --- a/lib/modules/meeting/views/bottomSheet/share_bottom_sheet.dart +++ b/lib/modules/meeting/views/bottomSheet/share_bottom_sheet.dart @@ -51,6 +51,28 @@ class _ShareBottomSheetState extends State { /// 包含会议数据、转写列表、总结内容等核心数据 final _controller = Get.find(); + /// 获取分享弹出位置(iOS iPad需要) + /// 多层兜底策略:控件真实位置 → 屏幕中心小矩形 + Rect _getSharePositionOrigin() { + // 检查 mounted 状态,避免 context 已释放导致崩溃 + if (mounted) { + try { + final box = context.findRenderObject() as RenderBox?; + if (box != null && box.hasSize) { + return box.localToGlobal(Offset.zero) & box.size; + } + } catch (_) { + // context 可能已失效,使用兜底方案 + } + } + // 兜底:屏幕中心小矩形,符合iOS交互规范 + return Rect.fromCenter( + center: Offset(Get.width / 2, Get.height / 2), + width: 1, + height: 1, + ); + } + /// ========================================================================== /// 构建UI界面 /// ========================================================================== @@ -141,34 +163,37 @@ class _ShareBottomSheetState extends State { // 5. 调用SharePlus分享链接 // 6. 分享成功后显示提示 onTap: () async { + // 在关闭弹窗前捕获分享位置(iPad需要) + final origin = _getSharePositionOrigin(); Get.back(); - final GetStorage storage = GetStorage(); - String token = storage.read("logintoken") ?? ''; - int id = _controller.meetingData.value.id; - - // final thumbnail = await getAssetThumbnailFile( - // 'assets/images/mine-background.png', - // 'share_thumb.png', - // ); - - // 获取动态服务器地址 - final serverUrl = DioManager().baseUrl; - final serverHost = serverUrl - .replaceFirst('https://', '') - .replaceFirst('http://', ''); - - final result = - await SharePlus.instance.share(ShareParams( - title: _controller.meetingData.value.title, - subject: - 'Voitrans WEB,由DeepSound.Ai提供支持-实时记录会议纪要,多语言翻译。', - uri: Uri.parse( - 'https://share.deepechomeet.com/share/$serverHost/voitrans.net/$id/$token', - ), - //previewThumbnail: thumbnail, - )); - if (result.status == ShareResultStatus.success) { - EasyLoading.showToast('shareSuccess'.tr); // 对应中文:分享完成 + try { + final GetStorage storage = GetStorage(); + String token = storage.read("logintoken") ?? ''; + int id = _controller.meetingData.value.id; + + // 获取动态服务器地址 + final serverUrl = DioManager().baseUrl; + final serverHost = serverUrl + .replaceFirst('https://', '') + .replaceFirst('http://', ''); + + final result = + await SharePlus.instance.share(ShareParams( + title: _controller.meetingData.value.title, + subject: + 'Voitrans WEB,由DeepSound.Ai提供支持-实时记录会议纪要,多语言翻译。', + uri: Uri.parse( + 'https://share.deepechomeet.com/share/$serverHost/voitrans.net/$id/$token', + ), + sharePositionOrigin: origin, + )); + if (result.status == ShareResultStatus.success) { + EasyLoading.showToast( + 'shareSuccess'.tr); // 对应中文:分享完成 + } + } catch (e) { + EasyLoading.showToast('shareFailed'.tr.replaceAll( + '{error}', e.toString())); // 对应中文:分享失败 } }, ), @@ -525,12 +550,18 @@ class _ShareBottomSheetState extends State { /// /// 返回值:Future - 异步操作 Future _share(String filepath, String title) async { - final result = await SharePlus.instance.share(ShareParams( - text: title, - files: [XFile(filepath)], - )); - if (result.status == ShareResultStatus.success) { - EasyLoading.showToast('shareSuccess'.tr); // 对应中文:分享完成! + try { + final result = await SharePlus.instance.share(ShareParams( + text: title, + files: [XFile(filepath)], + sharePositionOrigin: _getSharePositionOrigin(), + )); + if (result.status == ShareResultStatus.success) { + EasyLoading.showToast('shareSuccess'.tr); // 对应中文:分享完成! + } + } catch (e) { + EasyLoading.showToast( + 'shareFailed'.tr.replaceAll('{error}', e.toString())); // 对应中文:分享失败 } } @@ -724,23 +755,29 @@ class _ShareBottomSheetState extends State { /// 返回值:Future - 异步操作 Future _exportMarkdownPdf() async { EasyLoading.show(status: 'exportingPDF'.tr); // 对应中文:正在导出PDF... - final tempDir = await getTemporaryDirectory(); - final file = File( - '${tempDir.path}/${_controller.meetingData.value.title}_summary.pdf'); - final List markdownWidgets = - await pdf.HTMLToPdf().convertMarkdown( - _controller.meetingDetails.value.summary, - fontFallback: [ - pdf.Font.ttf( - await rootBundle.load('assets/fonts/NotoSansSC-Regular.ttf')), - ], - ); - final markdownPdf = pdf.Document(); - markdownPdf.addPage(pdf.MultiPage( - build: (context) => markdownWidgets, - )); - await file.writeAsBytes(await markdownPdf.save()); - await _share(file.path, 'exportSummary'.tr); // 对应中文:分享会议总结 - EasyLoading.dismiss(); + try { + final tempDir = await getTemporaryDirectory(); + final file = File( + '${tempDir.path}/${_controller.meetingData.value.title}_summary.pdf'); + final List markdownWidgets = + await pdf.HTMLToPdf().convertMarkdown( + _controller.meetingDetails.value.summary, + fontFallback: [ + pdf.Font.ttf( + await rootBundle.load('assets/fonts/NotoSansSC-Regular.ttf')), + ], + ); + final markdownPdf = pdf.Document(); + markdownPdf.addPage(pdf.MultiPage( + build: (context) => markdownWidgets, + )); + await file.writeAsBytes(await markdownPdf.save()); + await _share(file.path, 'exportSummary'.tr); // 对应中文:分享会议总结 + } catch (e) { + EasyLoading.showToast( + 'shareFailed'.tr.replaceAll('{error}', e.toString())); // 对应中文:分享失败 + } finally { + EasyLoading.dismiss(); + } } } diff --git a/pubspec.yaml b/pubspec.yaml index b4bddf156..bbfe87532 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -56,7 +56,7 @@ dependencies: device_info_plus: ^11.5.0 uuid: ^4.3.3 record: ^6.0.0 - share_plus: ^11.0.0 + share_plus: ^12.0.1 image_picker: ^1.1.2 audio_waveforms: ^1.3.0 font_awesome_flutter: ^10.8.0