Skip to content

Commit 91e1c38

Browse files
authored
[image_picker] Added maxDuration property to pickVideo method (flutter#2643)
1 parent 8819b21 commit 91e1c38

File tree

11 files changed

+106
-21
lines changed

11 files changed

+106
-21
lines changed

AUTHORS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ Lukasz Piliszczuk <[email protected]>
4444
SoundReply Solutions GmbH <[email protected]>
4545
Rafal Wachol <[email protected]>
4646
Pau Picas <[email protected]>
47+
Alexandru Tuca <[email protected]>
4748
Christian Weder <[email protected]>
4849
Rhodes Davis Jr. <[email protected]>
4950
Luigi Agosti <[email protected]>

packages/image_picker/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
## 0.6.5
2+
3+
* Set maximum duration for video recording.
4+
* Fix some existing XCTests.
5+
16
## 0.6.4
27

38
* Add a new parameter to select preferred camera device.

packages/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerDelegate.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,10 @@ public void takeVideoWithCamera(MethodCall methodCall, MethodChannel.Result resu
291291

292292
private void launchTakeVideoWithCameraIntent() {
293293
Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
294+
if (this.methodCall != null && this.methodCall.argument("maxDuration") != null) {
295+
int maxSeconds = this.methodCall.argument("maxDuration");
296+
intent.putExtra(MediaStore.EXTRA_DURATION_LIMIT, maxSeconds);
297+
}
294298
if (cameraDevice == CameraDevice.FRONT) {
295299
useFrontCamera(intent);
296300
}

packages/image_picker/example/android/app/src/test/java/io/flutter/plugins/imagepicker/ImagePickerDelegateTest.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
public class ImagePickerDelegateTest {
2727
private static final Double WIDTH = 10.0;
2828
private static final Double HEIGHT = 10.0;
29+
private static final Double MAX_DURATION = 10.0;
2930
private static final Integer IMAGE_QUALITY = 90;
3031

3132
@Mock Activity mockActivity;
@@ -373,6 +374,19 @@ public void onActivityResult_WhenImageTakenWithCamera_AndNoResizeNeeded_Finishes
373374
verifyNoMoreInteractions(mockResult);
374375
}
375376

377+
@Test
378+
public void
379+
onActivityResult_WhenVideoTakenWithCamera_AndMaxDurationParametersSupplied_FinishesWithFilePath() {
380+
when(mockMethodCall.argument("maxDuration")).thenReturn(MAX_DURATION);
381+
382+
ImagePickerDelegate delegate = createDelegateWithPendingResultAndMethodCall();
383+
delegate.onActivityResult(
384+
ImagePickerDelegate.REQUEST_CODE_TAKE_VIDEO_WITH_CAMERA, Activity.RESULT_OK, mockIntent);
385+
386+
verify(mockResult).success("pathFromUri");
387+
verifyNoMoreInteractions(mockResult);
388+
}
389+
376390
private ImagePickerDelegate createDelegate() {
377391
return new ImagePickerDelegate(
378392
mockActivity,

packages/image_picker/example/ios/Runner.xcodeproj/project.pbxproj

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,13 @@
88

99
/* Begin PBXBuildFile section */
1010
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
11-
3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; };
12-
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
1311
5C9513011EC38BD300040975 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 5C9513001EC38BD300040975 /* GeneratedPluginRegistrant.m */; };
1412
680049262280D736006DD6AB /* MetaDataUtilTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 680049252280D736006DD6AB /* MetaDataUtilTests.m */; };
1513
680049272280D79A006DD6AB /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
1614
680049382280F2B9006DD6AB /* pngImage.png in Resources */ = {isa = PBXBuildFile; fileRef = 680049352280F2B8006DD6AB /* pngImage.png */; };
1715
680049392280F2B9006DD6AB /* jpgImage.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 680049362280F2B8006DD6AB /* jpgImage.jpg */; };
16+
68B9AF72243E4B3F00927CE4 /* ImagePickerPluginTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 68B9AF71243E4B3F00927CE4 /* ImagePickerPluginTests.m */; };
1817
68F4B464228B3AB500C25614 /* PhotoAssetUtilTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 68F4B463228B3AB500C25614 /* PhotoAssetUtilTests.m */; };
19-
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; };
20-
9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
2118
978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; };
2219
97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; };
2320
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
@@ -46,8 +43,6 @@
4643
dstPath = "";
4744
dstSubfolderSpec = 10;
4845
files = (
49-
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */,
50-
9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */,
5146
);
5247
name = "Embed Frameworks";
5348
runOnlyForDeploymentPostprocessing = 0;
@@ -56,7 +51,6 @@
5651

5752
/* Begin PBXFileReference section */
5853
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
59-
3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = "<group>"; };
6054
5A9D31B91557877A0E8EF3E7 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
6155
5C9512FF1EC38BD300040975 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
6256
5C9513001EC38BD300040975 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
@@ -66,13 +60,13 @@
6660
680049352280F2B8006DD6AB /* pngImage.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = pngImage.png; sourceTree = "<group>"; };
6761
680049362280F2B8006DD6AB /* jpgImage.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = jpgImage.jpg; sourceTree = "<group>"; };
6862
6801632E632668F4349764C9 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
63+
68B9AF71243E4B3F00927CE4 /* ImagePickerPluginTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ImagePickerPluginTests.m; path = ../../../ios/Tests/ImagePickerPluginTests.m; sourceTree = "<group>"; };
6964
68F4B463228B3AB500C25614 /* PhotoAssetUtilTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = PhotoAssetUtilTests.m; path = ../../../ios/Tests/PhotoAssetUtilTests.m; sourceTree = "<group>"; };
7065
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
7166
7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
7267
7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
7368
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
7469
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
75-
9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = "<group>"; };
7670
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
7771
97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
7872
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
@@ -98,8 +92,6 @@
9892
isa = PBXFrameworksBuildPhase;
9993
buildActionMask = 2147483647;
10094
files = (
101-
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */,
102-
3B80C3941E831B6300D905FE /* App.framework in Frameworks */,
10395
F4F7A436CCA4BF276270A3AE /* libPods-Runner.a in Frameworks */,
10496
);
10597
runOnlyForDeploymentPostprocessing = 0;
@@ -116,6 +108,7 @@
116108
68F4B463228B3AB500C25614 /* PhotoAssetUtilTests.m */,
117109
F78AF3172342D9D7008449C7 /* ImagePickerTestImages.h */,
118110
F78AF3182342D9D7008449C7 /* ImagePickerTestImages.m */,
111+
68B9AF71243E4B3F00927CE4 /* ImagePickerPluginTests.m */,
119112
);
120113
path = image_picker_exampleTests;
121114
sourceTree = "<group>";
@@ -142,9 +135,7 @@
142135
9740EEB11CF90186004384FC /* Flutter */ = {
143136
isa = PBXGroup;
144137
children = (
145-
3B80C3931E831B6300D905FE /* App.framework */,
146138
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
147-
9740EEBA1CF902C7004384FC /* Flutter.framework */,
148139
9740EEB21CF90195004384FC /* Debug.xcconfig */,
149140
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
150141
9740EEB31CF90195004384FC /* Generated.xcconfig */,
@@ -331,17 +322,20 @@
331322
);
332323
runOnlyForDeploymentPostprocessing = 0;
333324
shellPath = /bin/sh;
334-
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin";
325+
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
335326
};
336327
95BB15E9E1769C0D146AA592 /* [CP] Embed Pods Frameworks */ = {
337328
isa = PBXShellScriptBuildPhase;
338329
buildActionMask = 2147483647;
339330
files = (
340331
);
341332
inputPaths = (
333+
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
334+
"${PODS_ROOT}/../Flutter/Flutter.framework",
342335
);
343336
name = "[CP] Embed Pods Frameworks";
344337
outputPaths = (
338+
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework",
345339
);
346340
runOnlyForDeploymentPostprocessing = 0;
347341
shellPath = /bin/sh;
@@ -390,6 +384,7 @@
390384
9FC8F0EE229FB90B00C8D58F /* ImageUtilTests.m in Sources */,
391385
F78AF3192342D9D7008449C7 /* ImagePickerTestImages.m in Sources */,
392386
680049262280D736006DD6AB /* MetaDataUtilTests.m in Sources */,
387+
68B9AF72243E4B3F00927CE4 /* ImagePickerPluginTests.m in Sources */,
393388
68F4B464228B3AB500C25614 /* PhotoAssetUtilTests.m in Sources */,
394389
);
395390
runOnlyForDeploymentPostprocessing = 0;
@@ -598,6 +593,7 @@
598593
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
599594
buildSettings = {
600595
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
596+
DEVELOPMENT_TEAM = "";
601597
ENABLE_BITCODE = NO;
602598
FRAMEWORK_SEARCH_PATHS = (
603599
"$(inherited)",
@@ -619,6 +615,7 @@
619615
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
620616
buildSettings = {
621617
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
618+
DEVELOPMENT_TEAM = "";
622619
ENABLE_BITCODE = NO;
623620
FRAMEWORK_SEARCH_PATHS = (
624621
"$(inherited)",

packages/image_picker/example/lib/main.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ class _MyHomePageState extends State<MyHomePage> {
6464
await _controller.setVolume(0.0);
6565
}
6666
if (isVideo) {
67-
final File file = await ImagePicker.pickVideo(source: source);
67+
final File file = await ImagePicker.pickVideo(
68+
source: source, maxDuration: const Duration(seconds: 10));
6869
await _playVideo(file);
6970
} else {
7071
await _displayPickImageDialog(context,

packages/image_picker/ios/Classes/FLTImagePickerPlugin.m

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,10 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result
102102
_arguments = call.arguments;
103103

104104
int imageSource = [[_arguments objectForKey:@"source"] intValue];
105+
if ([[_arguments objectForKey:@"maxDuration"] isKindOfClass:[NSNumber class]]) {
106+
NSTimeInterval max = [[_arguments objectForKey:@"maxDuration"] doubleValue];
107+
_imagePickerController.videoMaximumDuration = max;
108+
}
105109

106110
switch (imageSource) {
107111
case SOURCE_CAMERA:

packages/image_picker/ios/Tests/ImagePickerPluginTests.m

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ @implementation ImagePickerPluginTests
1414

1515
#pragma mark - Test camera devices, no op on simulators
1616
- (void)testPluginPickImageDeviceBack {
17-
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
17+
if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
1818
return;
1919
}
2020
FLTImagePickerPlugin *plugin =
@@ -30,7 +30,7 @@ - (void)testPluginPickImageDeviceBack {
3030
}
3131

3232
- (void)testPluginPickImageDeviceFront {
33-
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
33+
if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
3434
return;
3535
}
3636
FLTImagePickerPlugin *plugin =
@@ -46,7 +46,7 @@ - (void)testPluginPickImageDeviceFront {
4646
}
4747

4848
- (void)testPluginPickVideoDeviceBack {
49-
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
49+
if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
5050
return;
5151
}
5252
FLTImagePickerPlugin *plugin =
@@ -62,7 +62,7 @@ - (void)testPluginPickVideoDeviceBack {
6262
}
6363

6464
- (void)testPluginPickVideoDeviceFront {
65-
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
65+
if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
6666
return;
6767
}
6868
FLTImagePickerPlugin *plugin =
@@ -77,4 +77,17 @@ - (void)testPluginPickVideoDeviceFront {
7777
UIImagePickerControllerCameraDeviceFront);
7878
}
7979

80+
#pragma mark - Test video duration
81+
- (void)testPickingVideoWithDuration {
82+
FLTImagePickerPlugin *plugin =
83+
[[FLTImagePickerPlugin alloc] initWithViewController:[UIViewController new]];
84+
FlutterMethodCall *call = [FlutterMethodCall
85+
methodCallWithMethodName:@"pickVideo"
86+
arguments:@{@"source" : @(0), @"cameraDevice" : @(0), @"maxDuration" : @95}];
87+
[plugin handleMethodCall:call
88+
result:^(id _Nullable r){
89+
}];
90+
XCTAssertEqual([plugin getImagePickerController].videoMaximumDuration, 95);
91+
}
92+
8093
@end

packages/image_picker/lib/image_picker.dart

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,9 @@ class ImagePicker {
101101
/// The [source] argument controls where the video comes from. This can
102102
/// be either [ImageSource.camera] or [ImageSource.gallery].
103103
///
104+
/// The [maxDuration] argument specifies the maximum duration of the captured video. If no [maxDuration] is specified,
105+
/// the maximum duration will be infinite.
106+
///
104107
/// Use `preferredCameraDevice` to specify the camera to use when the `source` is [ImageSource.camera].
105108
/// The `preferredCameraDevice` is ignored when `source` is [ImageSource.gallery]. It is also ignored if the chosen camera is not supported on the device.
106109
/// Defaults to [CameraDevice.rear].
@@ -109,12 +112,14 @@ class ImagePicker {
109112
/// in this call. You can then call [retrieveLostData] when your app relaunches to retrieve the lost data.
110113
static Future<File> pickVideo(
111114
{@required ImageSource source,
112-
CameraDevice preferredCameraDevice = CameraDevice.rear}) async {
115+
CameraDevice preferredCameraDevice = CameraDevice.rear,
116+
Duration maxDuration}) async {
113117
assert(source != null);
114118
final String path = await _channel.invokeMethod<String>(
115119
'pickVideo',
116120
<String, dynamic>{
117121
'source': source.index,
122+
'maxDuration': maxDuration?.inSeconds,
118123
'cameraDevice': preferredCameraDevice.index
119124
},
120125
);

packages/image_picker/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: image_picker
22
description: Flutter plugin for selecting images from the Android and iOS image
33
library, and taking new pictures with the camera.
44
homepage: https://github.com/flutter/plugins/tree/master/packages/image_picker
5-
version: 0.6.4
5+
version: 0.6.5
66

77
flutter:
88
plugin:

0 commit comments

Comments
 (0)