| 1 | import 'package:flutter/material.dart'; |
| 2 | import 'package:share_plus/share_plus.dart'; |
| 3 | import 'package:cross_file/cross_file.dart'; |
| 4 | |
| 5 | class ShareUtil { |
| 6 | static void share({required String text, required BuildContext context}) { |
| 7 | Share.share( |
| 8 | text, |
| 9 | sharePositionOrigin: _sharePosition(context), |
| 10 | ); |
| 11 | } |
| 12 | |
| 13 | static Future<void> shareFile({ |
| 14 | required String filePath, |
| 15 | required String fileName, |
| 16 | required BuildContext context, |
| 17 | }) async { |
| 18 | const _mimeType = 'application/*'; |
| 19 | await Share.shareXFiles( |
| 20 | <XFile>[ |
| 21 | XFile( |
| 22 | filePath, |
| 23 | name: fileName, |
| 24 | mimeType: _mimeType, |
| 25 | ) |
| 26 | ], |
| 27 | sharePositionOrigin: _sharePosition(context), |
| 28 | ); |
| 29 | } |
| 30 | |
| 31 | static Rect _sharePosition(BuildContext context) { |
| 32 | if (!context.mounted) { |
| 33 | return const Rect.fromLTWH(0, 0, 1, 1); |
| 34 | } |
| 35 | |
| 36 | final screen = Offset.zero & MediaQuery.of(context).size; |
| 37 | final fallback = Rect.fromCenter(center: screen.center, width: 1, height: 1); |
| 38 | |
| 39 | final renderObject = context.findRenderObject(); |
| 40 | if (renderObject is! RenderBox || !renderObject.hasSize) { |
| 41 | return fallback; |
| 42 | } |
| 43 | |
| 44 | final rect = renderObject.localToGlobal(Offset.zero) & renderObject.size; |
| 45 | final clipped = rect.intersect(screen); |
| 46 | if (clipped.isEmpty) { |
| 47 | return fallback; |
| 48 | } |
| 49 | return clipped; |
| 50 | } |
| 51 | } |