Browse Source

feat(share): 优化分享功能并增加分享位置支持

- 新增获取分享弹出位置的方法,支持iOS iPad多层兜底定位
- 在调用分享接口时传入分享弹窗位置,提升iPad分享体验
- 分享入口catch异常,失败时显示带错误信息的提示
- PDF导出并分享功能增加异常处理,确保加载失败时仍正确关闭加载提示
- 升级share_plus依赖至12.0.1版本,兼容最新功能和修复问题
weicu
lxm 8 months ago
parent
commit
1b1626f648
  1. 139
      lib/modules/meeting/views/bottomSheet/share_bottom_sheet.dart
  2. 2
      pubspec.yaml

139
lib/modules/meeting/views/bottomSheet/share_bottom_sheet.dart

@ -51,6 +51,28 @@ class _ShareBottomSheetState extends State<ShareBottomSheet> {
/// 包含会议数据、转写列表、总结内容等核心数据 /// 包含会议数据、转写列表、总结内容等核心数据
final _controller = Get.find<MeetingDetailsController>(); final _controller = Get.find<MeetingDetailsController>();
/// 获取分享弹出位置(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界面 /// 构建UI界面
/// ========================================================================== /// ==========================================================================
@ -141,34 +163,37 @@ class _ShareBottomSheetState extends State<ShareBottomSheet> {
// 5. 调用SharePlus分享链接 // 5. 调用SharePlus分享链接
// 6. 分享成功后显示提示 // 6. 分享成功后显示提示
onTap: () async { onTap: () async {
// 在关闭弹窗前捕获分享位置(iPad需要)
final origin = _getSharePositionOrigin();
Get.back(); Get.back();
final GetStorage storage = GetStorage(); try {
String token = storage.read("logintoken") ?? ''; final GetStorage storage = GetStorage();
int id = _controller.meetingData.value.id; 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 serverUrl = DioManager().baseUrl;
final serverHost = serverUrl final result =
.replaceFirst('https://', '') await SharePlus.instance.share(ShareParams(
.replaceFirst('http://', ''); title: _controller.meetingData.value.title,
subject:
final result = 'Voitrans WEB,由DeepSound.Ai提供支持-实时记录会议纪要,多语言翻译。',
await SharePlus.instance.share(ShareParams( uri: Uri.parse(
title: _controller.meetingData.value.title, 'https://share.deepechomeet.com/share/$serverHost/voitrans.net/$id/$token',
subject: ),
'Voitrans WEB,由DeepSound.Ai提供支持-实时记录会议纪要,多语言翻译。', sharePositionOrigin: origin,
uri: Uri.parse( ));
'https://share.deepechomeet.com/share/$serverHost/voitrans.net/$id/$token', if (result.status == ShareResultStatus.success) {
), EasyLoading.showToast(
//previewThumbnail: thumbnail, 'shareSuccess'.tr); // 对应中文:分享完成
)); }
if (result.status == ShareResultStatus.success) { } catch (e) {
EasyLoading.showToast('shareSuccess'.tr); // 对应中文:分享完成 EasyLoading.showToast('shareFailed'.tr.replaceAll(
'{error}', e.toString())); // 对应中文:分享失败
} }
}, },
), ),
@ -525,12 +550,18 @@ class _ShareBottomSheetState extends State<ShareBottomSheet> {
/// ///
/// 返回值:Future<void> - 异步操作 /// 返回值:Future<void> - 异步操作
Future<void> _share(String filepath, String title) async { Future<void> _share(String filepath, String title) async {
final result = await SharePlus.instance.share(ShareParams( try {
text: title, final result = await SharePlus.instance.share(ShareParams(
files: [XFile(filepath)], text: title,
)); files: [XFile(filepath)],
if (result.status == ShareResultStatus.success) { sharePositionOrigin: _getSharePositionOrigin(),
EasyLoading.showToast('shareSuccess'.tr); // 对应中文:分享完成! ));
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<ShareBottomSheet> {
/// 返回值:Future<void> - 异步操作 /// 返回值:Future<void> - 异步操作
Future<void> _exportMarkdownPdf() async { Future<void> _exportMarkdownPdf() async {
EasyLoading.show(status: 'exportingPDF'.tr); // 对应中文:正在导出PDF... EasyLoading.show(status: 'exportingPDF'.tr); // 对应中文:正在导出PDF...
final tempDir = await getTemporaryDirectory(); try {
final file = File( final tempDir = await getTemporaryDirectory();
'${tempDir.path}/${_controller.meetingData.value.title}_summary.pdf'); final file = File(
final List<pdf.Widget> markdownWidgets = '${tempDir.path}/${_controller.meetingData.value.title}_summary.pdf');
await pdf.HTMLToPdf().convertMarkdown( final List<pdf.Widget> markdownWidgets =
_controller.meetingDetails.value.summary, await pdf.HTMLToPdf().convertMarkdown(
fontFallback: [ _controller.meetingDetails.value.summary,
pdf.Font.ttf( fontFallback: [
await rootBundle.load('assets/fonts/NotoSansSC-Regular.ttf')), pdf.Font.ttf(
], await rootBundle.load('assets/fonts/NotoSansSC-Regular.ttf')),
); ],
final markdownPdf = pdf.Document(); );
markdownPdf.addPage(pdf.MultiPage( final markdownPdf = pdf.Document();
build: (context) => markdownWidgets, markdownPdf.addPage(pdf.MultiPage(
)); build: (context) => markdownWidgets,
await file.writeAsBytes(await markdownPdf.save()); ));
await _share(file.path, 'exportSummary'.tr); // 对应中文:分享会议总结 await file.writeAsBytes(await markdownPdf.save());
EasyLoading.dismiss(); await _share(file.path, 'exportSummary'.tr); // 对应中文:分享会议总结
} catch (e) {
EasyLoading.showToast(
'shareFailed'.tr.replaceAll('{error}', e.toString())); // 对应中文:分享失败
} finally {
EasyLoading.dismiss();
}
} }
} }

2
pubspec.yaml

@ -56,7 +56,7 @@ dependencies:
device_info_plus: ^11.5.0 device_info_plus: ^11.5.0
uuid: ^4.3.3 uuid: ^4.3.3
record: ^6.0.0 record: ^6.0.0
share_plus: ^11.0.0 share_plus: ^12.0.1
image_picker: ^1.1.2 image_picker: ^1.1.2
audio_waveforms: ^1.3.0 audio_waveforms: ^1.3.0
font_awesome_flutter: ^10.8.0 font_awesome_flutter: ^10.8.0

Loading…
Cancel
Save