Browse Source

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

- 新增获取分享弹出位置的方法,支持iOS iPad多层兜底定位
- 在调用分享接口时传入分享弹窗位置,提升iPad分享体验
- 分享入口catch异常,失败时显示带错误信息的提示
- PDF导出并分享功能增加异常处理,确保加载失败时仍正确关闭加载提示
- 升级share_plus依赖至12.0.1版本,兼容最新功能和修复问题
weicu
lxm 7 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>();
/// 获取分享弹出位置(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<ShareBottomSheet> {
// 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<ShareBottomSheet> {
///
/// 返回值:Future<void> - 异步操作
Future<void> _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<ShareBottomSheet> {
/// 返回值:Future<void> - 异步操作
Future<void> _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<pdf.Widget> 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<pdf.Widget> 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();
}
}
}

2
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

Loading…
Cancel
Save