Skip to content

Commit 3923b3c

Browse files
committed
feat(share_plus): add support for action_attach_data
Signed-off-by: vauvenal5 <vauvenal5.ndgme@slmails.com>
1 parent 350430a commit 3923b3c

File tree

8 files changed

+103
-5
lines changed

8 files changed

+103
-5
lines changed

packages/share_plus/share_plus/android/src/main/kotlin/dev/fluttercommunity/plus/share/Share.kt

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ internal class Share(
6666
val paths = (arguments["paths"] as List<*>?)?.filterIsInstance<String>()
6767
val mimeTypes = (arguments["mimeTypes"] as List<*>?)?.filterIsInstance<String>()
6868
val fileUris = paths?.let { getUrisForPaths(paths) }
69+
val attach = arguments["attach"] as Boolean? ?: false
6970

7071
// Create Share Intent
7172
val shareIntent = Intent()
@@ -89,10 +90,17 @@ internal class Share(
8990
} else {
9091
"*/*"
9192
}
92-
shareIntent.apply {
93-
action = Intent.ACTION_SEND
94-
type = mimeType
95-
putExtra(Intent.EXTRA_STREAM, fileUris.first())
93+
if (attach) {
94+
shareIntent.apply {
95+
action = Intent.ACTION_ATTACH_DATA
96+
setDataAndType(fileUris.first(), mimeType)
97+
}
98+
} else {
99+
shareIntent.apply {
100+
action = Intent.ACTION_SEND
101+
type = mimeType
102+
putExtra(Intent.EXTRA_STREAM, fileUris.first())
103+
}
96104
}
97105
}
98106

packages/share_plus/share_plus/example/integration_test/share_plus_test.dart

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,17 @@ void main() {
4141
);
4242
expect(SharePlus.instance.share(params), isNotNull);
4343
});
44+
45+
testWidgets('Can attachXFile created using File.fromData()',
46+
(WidgetTester tester) async {
47+
final bytes = Uint8List.fromList([1, 2, 3, 4, 5, 6, 7, 8]);
48+
final XFile file =
49+
XFile.fromData(bytes, name: 'image.jpg', mimeType: 'image/jpeg');
50+
51+
final params = ShareParams(
52+
files: [file],
53+
attach: true,
54+
);
55+
expect(SharePlus.instance.share(params), isNotNull);
56+
}, skip: !Platform.isAndroid);
4457
}

packages/share_plus/share_plus/example/lib/main.dart

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,21 @@ class MyHomePageState extends State<MyHomePage> {
202202
},
203203
),
204204
const SizedBox(height: 16),
205+
Builder(
206+
builder: (BuildContext context) {
207+
return ElevatedButton(
208+
style: ElevatedButton.styleFrom(
209+
foregroundColor: Theme.of(context).colorScheme.onPrimary,
210+
backgroundColor: Theme.of(context).colorScheme.primary,
211+
),
212+
onPressed: () {
213+
_onShareXFileFromAssets(context, attach: true);
214+
},
215+
child: const Text('Attach XFile from Assets'),
216+
);
217+
},
218+
),
219+
const SizedBox(height: 16),
205220
Builder(
206221
builder: (BuildContext context) {
207222
return ElevatedButton(
@@ -293,7 +308,10 @@ class MyHomePageState extends State<MyHomePage> {
293308
scaffoldMessenger.showSnackBar(getResultSnackBar(shareResult));
294309
}
295310

296-
void _onShareXFileFromAssets(BuildContext context) async {
311+
void _onShareXFileFromAssets(
312+
BuildContext context, {
313+
bool attach = false,
314+
}) async {
297315
final box = context.findRenderObject() as RenderBox?;
298316
final scaffoldMessenger = ScaffoldMessenger.of(context);
299317
try {
@@ -311,6 +329,7 @@ class MyHomePageState extends State<MyHomePage> {
311329
sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size,
312330
downloadFallbackEnabled: true,
313331
excludedCupertinoActivities: excludedCupertinoActivityType,
332+
attach: attach,
314333
),
315334
);
316335
scaffoldMessenger.showSnackBar(getResultSnackBar(shareResult));

packages/share_plus/share_plus/lib/share_plus.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,12 @@ class SharePlus {
9999
);
100100
}
101101

102+
if (params.attach && (params.files?.length ?? 0) != 1) {
103+
throw ArgumentError(
104+
'Exactly one file must be provided when attach is true.',
105+
);
106+
}
107+
102108
return _platform.share(params);
103109
}
104110
}

packages/share_plus/share_plus/test/share_plus_test.dart

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,25 @@ void main() {
5656
);
5757
});
5858

59+
test(
60+
'share throws ArgumentError if attach is true but no files are provided',
61+
() async {
62+
expect(
63+
() => sharePlus.share(ShareParams(files: [], attach: true)),
64+
throwsA(isA<ArgumentError>()),
65+
);
66+
});
67+
68+
test(
69+
'share throws ArgumentError if attach is true and more then one file is provided',
70+
() async {
71+
expect(
72+
() => sharePlus.share(
73+
ShareParams(files: [XFile('path'), XFile('path')], attach: true)),
74+
throwsA(isA<ArgumentError>()),
75+
);
76+
});
77+
5978
test('share calls platform share method with correct params', () async {
6079
final params = ShareParams(text: 'text');
6180
final result = await sharePlus.share(params);

packages/share_plus/share_plus_platform_interface/lib/method_channel/method_channel_share.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ class MethodChannelShare extends SharePlatform {
4141
if (params.subject != null) 'subject': params.subject,
4242
if (params.title != null) 'title': params.title,
4343
if (params.uri != null) 'uri': params.uri.toString(),
44+
'attach': params.attach,
4445
};
4546

4647
if (params.sharePositionOrigin != null) {

packages/share_plus/share_plus_platform_interface/lib/platform_interface/share_plus_platform.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,13 @@ class ShareParams {
142142
/// Parameter ignored on other platforms.
143143
final List<CupertinoActivityType>? excludedCupertinoActivities;
144144

145+
/// Whether to attach or share data. Will open ACTION_ATTACH_DATA intent on Android instead of ACTION_SEND.
146+
/// Requires exactly on file to be provided.
147+
///
148+
/// * Supported platforms: Android
149+
/// Parameter ignored on other platforms.
150+
final bool attach;
151+
145152
ShareParams({
146153
this.text,
147154
this.subject,
@@ -154,6 +161,7 @@ class ShareParams {
154161
this.downloadFallbackEnabled = true,
155162
this.mailToFallbackEnabled = true,
156163
this.excludedCupertinoActivities,
164+
this.attach = false,
157165
});
158166
}
159167

packages/share_plus/share_plus_platform_interface/test/share_plus_platform_interface_test.dart

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ void main() {
7676
'originWidth': 3.0,
7777
'originHeight': 4.0,
7878
'excludedCupertinoActivities': ['airDrop'],
79+
'attach': false,
7980
}));
8081

8182
await sharePlatform.share(
@@ -93,6 +94,7 @@ void main() {
9394
'originY': 2.0,
9495
'originWidth': 3.0,
9596
'originHeight': 4.0,
97+
'attach': false,
9698
}));
9799

98100
await withFile('tempfile-83649a.png', (File fd) async {
@@ -116,6 +118,24 @@ void main() {
116118
'originY': 2.0,
117119
'originWidth': 3.0,
118120
'originHeight': 4.0,
121+
'attach': false,
122+
},
123+
));
124+
});
125+
126+
await withFile('tempfile-83649a.png', (File fd) async {
127+
await sharePlatform.share(
128+
ShareParams(
129+
files: [XFile(fd.path)],
130+
attach: true,
131+
),
132+
);
133+
verify(mockChannel.invokeMethod<String>(
134+
'share',
135+
<String, dynamic>{
136+
'paths': [fd.path],
137+
'mimeTypes': ['image/png'],
138+
'attach': true,
119139
},
120140
));
121141
});
@@ -127,6 +147,7 @@ void main() {
127147
verify(mockChannel.invokeMethod<String>('share', <String, dynamic>{
128148
'paths': [fd.path],
129149
'mimeTypes': ['image/png'],
150+
'attach': false,
130151
}));
131152
});
132153
});
@@ -141,6 +162,7 @@ void main() {
141162
verify(mockChannel.invokeMethod<String>('share', <String, dynamic>{
142163
'paths': [fd.path],
143164
'mimeTypes': ['*/*'],
165+
'attach': false,
144166
}));
145167
});
146168
});
@@ -194,6 +216,7 @@ void main() {
194216
'originY': 2.0,
195217
'originWidth': 3.0,
196218
'originHeight': 4.0,
219+
'attach': false,
197220
}));
198221
expect(result, success);
199222

@@ -206,6 +229,7 @@ void main() {
206229
verify(mockChannel.invokeMethod<String>('share', <String, dynamic>{
207230
'paths': [fd.path],
208231
'mimeTypes': ['image/png'],
232+
'attach': false,
209233
}));
210234
expect(result, success);
211235
});

0 commit comments

Comments
 (0)