Skip to content

fix(imagepicker): consolidate API / Fix typings #530

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Sep 16, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@
<ListView [items]="imageAssets" *ngIf="!isSingleMode">
<ng-template let-image="item" let-i="index">
<GridLayout columns="auto, *">
<Image [width]="thumbSize" [height]="thumbSize" [src]="image" stretch="aspectFill"></Image>
<Image [width]="thumbSize" [height]="thumbSize" [src]="image.asset" stretch="aspectFill"></Image>
<Label col="1" [text]="'image ' + i"></Label>
</GridLayout>
</ng-template>
46 changes: 25 additions & 21 deletions apps/demo-angular/src/plugin-demos/imagepicker.component.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { Component, NgZone } from '@angular/core';
import { ImageAsset } from '@nativescript/core';
import * as imagepicker from '@nativescript/imagepicker';
import { ImageAsset, ImageSource } from '@nativescript/core';
import { ImagePicker, create, ImagePickerSelection } from '@nativescript/imagepicker';

@Component({
selector: 'demo-imagepicker',
templateUrl: 'imagepicker.component.html',
})
export class ImagepickerComponent {
imageAssets = [];
imageSrc: any;
imageAssets: ImagePickerSelection[] = [];
imageSrc: ImageAsset | ImageSource;
isSingleMode: boolean = true;
thumbSize: number = 80;
previewSize: number = 300;
@@ -18,7 +18,7 @@ export class ImagepickerComponent {
public onSelectMultipleTap() {
this.isSingleMode = false;

let context = imagepicker.create({
let context = create({
mode: 'multiple',
});
this.startSelection(context);
@@ -27,36 +27,40 @@ export class ImagepickerComponent {
public onSelectSingleTap() {
this.isSingleMode = true;

let context = imagepicker.create({
let context = create({
mode: 'single',
});
this.startSelection(context);
}

private startSelection(context) {
private startSelection(context: ImagePicker) {
context
.authorize()
.then(() => {
.then((authResult) => {
this._ngZone.run(() => {
this.imageAssets = [];
this.imageSrc = null;
});
return context.present();
})
.then((selection) => {
this._ngZone.run(() => {
console.log('Selection done: ' + JSON.stringify(selection));
this.imageSrc = this.isSingleMode && selection.length > 0 ? selection[0] : null;
if (authResult.authorized) {
return context.present().then((selection) => {
this._ngZone.run(() => {
console.log('Selection done: ' + JSON.stringify(selection));
this.imageSrc = this.isSingleMode && selection.length > 0 ? selection[0].asset : null;

// set the images to be loaded from the assets with optimal sizes (optimize memory usage)
selection.forEach((el: ImageAsset) => {
el.options.width = this.isSingleMode ? this.previewSize : this.thumbSize;
el.options.height = this.isSingleMode ? this.previewSize : this.thumbSize;
});
// set the images to be loaded from the assets with optimal sizes (optimize memory usage)
selection.forEach((el) => {
el.asset.options.width = this.isSingleMode ? this.previewSize : this.thumbSize;
el.asset.options.height = this.isSingleMode ? this.previewSize : this.thumbSize;
});

this.imageAssets = selection;
});
this.imageAssets = selection;
});
});
} else {
console.log('Unauthorised');
}
})

.catch(function (e) {
console.log(e);
});
38 changes: 23 additions & 15 deletions packages/imagepicker/README.md
Original file line number Diff line number Diff line change
@@ -29,6 +29,11 @@ Install the plugin by running the following command in the root directory of you
npm install @nativescript/imagepicker
```

**Note: Version 3.0 contains breaking changes:**
* authorize() now returns a `Promise<AuthorizationResult>` for both android and ios.
* In the returned result from `present()` each `result[i].thumbnail` is now an `ImageSource`.
* `result[i].duration` is now typed correctly as a `number`.

**Note: Version 2.0 contains breaking changes. In order supply more information about your selection, the ImageSource asset is nested in the response so you'll need to update your code to use `result.asset` instead of `result` as your src for your Images.**

## Android required permissions
@@ -97,22 +102,25 @@ The `present` method resolves with the selected media assets that can you to pro
```ts
imagePickerObj
.authorize()
.then(function() {
return imagePickerObj.present();
})
.then(function(selection) {
selection.forEach(function(selected) {
this.imageSource = selected.asset;
this.type = selected.type;
this.filesize = selected.filesize;
//etc
});
list.items = selection;
}).catch(function (e) {
.then((authResult) => {
if(authResult.authorized) {
return imagePickerObj.present()
.then(function(selection) {
selection.forEach(function(selected) {
this.imageSource = selected.asset;
this.type = selected.type;
this.filesize = selected.filesize;
//etc
});
});
} else {
// process authorization not granted.
}
})
.catch(function (e) {
// process error
});
```
> **Note** To request permissions for Android 6+ (API 23+), use [nativescript-permissions](https://www.npmjs.com/package/nativescript-permissions) plugin.

### Demo
You can play with the plugin on StackBlitz at any of the following links:
@@ -131,8 +139,8 @@ The class that provides the media selection API. It offers the following methods
| Method | Returns | Description
|:-------|:--------|:-----------
| `constructor(options: Options)` | `ImagePicker` | Instanciates the ImagePicker class with the optional `options` parameter. See [Options](#options)
| `authorize()` | `Promise<void>` | Requests the required permissions. Call it before calling `present()`. In case of a failed authorization, consider notifying the user for degraded functionality.
| `present()` | `Promise<ImageAsset[]>` | Presents the image picker UI.
| `authorize()` | `Promise<AuthorizationResult>` | Requests the required permissions. Call it before calling `present()`. In case of a failed authorization, consider notifying the user for degraded functionality. The returned `AuthorizationResult` will have it's `authorized` property set to `true` if permission has been granted.
| `present()` | `Promise<ImagePickerSelection[]>` | Presents the image picker UI.
| `create(options: Options, hostView: View)` | `ImagePicker` | Creates an instance of the ImagePicker class. The `hostView` parameter can be set to the view that hosts the image picker. Intended to be used when opening the picker from a modal page.

### Options
50 changes: 47 additions & 3 deletions packages/imagepicker/common.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { ImageAsset } from '@nativescript/core';
import { ImageAsset, ImageSource } from '@nativescript/core';
import { MultiResult, Result } from '@nativescript-community/perms';

export enum ImagePickerMediaType {
Any = 0,
@@ -40,12 +41,12 @@ export interface ImagePickerSelection {
/**
* The duration of the video. Only passed if type is 'video'
*/
duration?: string;
duration?: number;

/**
* An image to use for the video thumbnail. Only passed if type is 'video'
*/
thumbnail?: ImageAsset;
thumbnail?: ImageSource;
}

/**
@@ -116,3 +117,46 @@ export interface Options {
read_external_storage?: string;
};
}

export interface ImagePickerApi {
/**
* Call this before 'present' to request any additional permissions that may be necessary.
* In case of failed authorization consider notifying the user for degraded functionality.
*/
authorize(): Promise<AuthorizationResult>;

/**
* Present the image picker UI.
* The result will be an array of SelectedAsset instances provided when the promise is fulfilled.
*/
present(): Promise<ImagePickerSelection[]>;
}

export interface AuthorizationResult {
authorized: boolean;
details: MultiResult | Result;
}
const requestingPermissions = ['android.permission.READ_MEDIA_IMAGES', 'android.permission.READ_MEDIA_VIDEO'];

export abstract class ImagePickerBase implements ImagePickerApi {
abstract authorize(): Promise<AuthorizationResult>;
abstract present(): Promise<ImagePickerSelection[]>;
protected mapResult(result: MultiResult | Result): AuthorizationResult {
let authorized = true;
if (Array.isArray(result) && result.length == 2) {
// is of type Result
authorized = result[0] === 'authorized';
} else {
const t = result as MultiResult;
requestingPermissions.forEach((permission) => {
if (t[permission] !== undefined) {
authorized = authorized && t[permission] === 'authorized';
}
});
}
return {
details: result,
authorized,
};
}
}
54 changes: 28 additions & 26 deletions packages/imagepicker/index.android.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { ImageAsset, Application, AndroidApplication, Utils, File, knownFolders } from '@nativescript/core';
import { ImageAsset, Application, AndroidApplication, Utils, File, knownFolders, ImageSource } from '@nativescript/core';
import * as permissions from '@nativescript-community/perms';

import { ImagePickerMediaType, Options } from './common';
import { ImagePickerMediaType, Options, AuthorizationResult, ImagePickerBase, ImagePickerSelection } from './common';
export * from './common';
let copyToAppFolder;
let renameFileTo;
let fileMap = {};
let videoFiles = {

const videoFiles = {
mp4: true,
mov: true,
avi: true,
@@ -22,8 +22,8 @@ let videoFiles = {
};
class UriHelper {
public static _calculateFileUri(uri: android.net.Uri) {
let DocumentsContract = (<any>android.provider).DocumentsContract;
let isKitKat = android.os.Build.VERSION.SDK_INT >= 19; // android.os.Build.VERSION_CODES.KITKAT
const DocumentsContract = (<any>android.provider).DocumentsContract;
const isKitKat = android.os.Build.VERSION.SDK_INT >= 19; // android.os.Build.VERSION_CODES.KITKAT

if (isKitKat && DocumentsContract.isDocumentUri(Utils.android.getApplicationContext(), uri)) {
let docId, id, type;
@@ -56,7 +56,7 @@ class UriHelper {
// MediaProvider
else if (UriHelper.isMediaDocument(uri)) {
docId = DocumentsContract.getDocumentId(uri);
let split = docId.split(':');
const split = docId.split(':');
type = split[0];
id = split[1];

@@ -68,8 +68,8 @@ class UriHelper {
contentUri = android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}

let selection = '_id=?';
let selectionArgs = [id];
const selection = '_id=?';
const selectionArgs = [id];

return UriHelper.getDataColumn(contentUri, selection, selectionArgs, false);
}
@@ -89,13 +89,13 @@ class UriHelper {

private static getDataColumn(uri: android.net.Uri, selection, selectionArgs, isDownload: boolean) {
let cursor = null;
let filePath;
let filePath: string;
if (isDownload) {
let columns = ['_display_name'];
const columns = ['_display_name'];
try {
cursor = this.getContentResolver().query(uri, columns, selection, selectionArgs, null);
if (cursor != null && cursor.moveToFirst()) {
let column_index = cursor.getColumnIndexOrThrow(columns[0]);
const column_index = cursor.getColumnIndexOrThrow(columns[0]);
filePath = cursor.getString(column_index);
if (filePath) {
const dl = android.os.Environment.getExternalStoragePublicDirectory(android.os.Environment.DIRECTORY_DOWNLOADS);
@@ -111,13 +111,13 @@ class UriHelper {
}
}
} else {
let columns = [android.provider.MediaStore.MediaColumns.DATA];
const columns = [android.provider.MediaStore.MediaColumns.DATA];
let filePath;

try {
cursor = this.getContentResolver().query(uri, columns, selection, selectionArgs, null);
if (cursor != null && cursor.moveToFirst()) {
let column_index = cursor.getColumnIndexOrThrow(columns[0]);
const column_index = cursor.getColumnIndexOrThrow(columns[0]);
filePath = cursor.getString(column_index);
if (filePath) {
return filePath;
@@ -151,10 +151,11 @@ class UriHelper {
}
}

export class ImagePicker {
export class ImagePicker extends ImagePickerBase {
private _options: Options;

constructor(options: Options) {
super();
this._options = options;
copyToAppFolder = options.copyToAppFolder;
renameFileTo = options.renameFileTo;
@@ -176,8 +177,8 @@ export class ImagePicker {
}

get mimeTypes() {
let length = this.mediaType === '*/*' ? 2 : 1;
let mimeTypes = Array.create(java.lang.String, length);
const length = this.mediaType === '*/*' ? 2 : 1;
const mimeTypes = Array.create(java.lang.String, length);

if (this.mediaType === '*/*') {
mimeTypes[0] = 'image/*';
@@ -188,9 +189,9 @@ export class ImagePicker {
return mimeTypes;
}

authorize(): Promise<permissions.MultiResult | permissions.Result> {
authorize(): Promise<AuthorizationResult> {
let requested: { [key: string]: permissions.PermissionOptions } = {};
if ((<any>android).os.Build.VERSION.SDK_INT >= 33 && Utils.ad.getApplicationContext().getApplicationInfo().targetSdkVersion >= 33) {
let requested: { [key: string]: permissions.PermissionOptions } = {};
const mediaPerms = {
photo: { reason: 'To pick images from your gallery' },
video: { reason: 'To pick videos from your gallery' },
@@ -203,15 +204,16 @@ export class ImagePicker {
requested = mediaPerms;
}

return permissions.request(requested);
return permissions.request(requested).then((result) => this.mapResult(result));
} else if ((<any>android).os.Build.VERSION.SDK_INT >= 23) {
return permissions.request('storage', { read: true });
requested['storage'] = { read: true, write: false };
return permissions.request(requested).then((result) => this.mapResult(result));
} else {
return Promise.resolve({ storage: 'authorized' });
return Promise.resolve({ details: null, authorized: true });
}
}

present(): Promise<ImageAsset[]> {
present(): Promise<ImagePickerSelection[]> {
return new Promise((resolve, reject) => {
// WARNING: If we want to support multiple pickers we will need to have a range of IDs here:
let RESULT_CODE_PICKER_IMAGES = 9192;
@@ -227,7 +229,7 @@ export class ImagePicker {
const file = File.fromPath(selectedAsset.android);
let copiedFile: any = false;

let item: any = {
const item: ImagePickerSelection = {
asset: selectedAsset,
filename: file.name,
originalFilename: file.name,
@@ -254,10 +256,10 @@ export class ImagePicker {
item.filesize = new java.io.File(item.path).length();
}
if (item.type == 'video') {
let thumb = android.media.ThumbnailUtils.createVideoThumbnail(copiedFile ? copiedFile.path : file.path, android.provider.MediaStore.Video.Thumbnails.MINI_KIND);
const thumb = android.media.ThumbnailUtils.createVideoThumbnail(copiedFile ? copiedFile.path : file.path, android.provider.MediaStore.Video.Thumbnails.MINI_KIND);
let retriever = new android.media.MediaMetadataRetriever();
retriever.setDataSource(item.path);
item.thumbnail = thumb;
item.thumbnail = new ImageSource(thumb);
let time = retriever.extractMetadata(android.media.MediaMetadataRetriever.METADATA_KEY_DURATION);
let duration = parseInt(time) / 1000;
item.duration = duration;
8 changes: 4 additions & 4 deletions packages/imagepicker/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { Observable, ImageSource, ImageAsset, View } from '@nativescript/core';

export class ImagePicker {
import { ImageSource, ImageAsset, View } from '@nativescript/core';
import { AuthorizationResult, ImagePickerApi } from './common';
export class ImagePicker implements ImagePickerApi {
constructor(options?: Options);

/**
* Call this before 'present' to request any additional permissions that may be necessary.
* In case of failed authorization consider notifying the user for degraded functionality.
*/
authorize(): Promise<void>;
authorize(): Promise<AuthorizationResult>;

/**
* Present the image picker UI.
62 changes: 28 additions & 34 deletions packages/imagepicker/index.ios.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import { Observable, ImageAsset, View, Utils, Application, path, knownFolders, Folder, File, ImageSource } from '@nativescript/core';
import { Options, ImagePickerMediaType } from './common';
import { ImageAsset, View, Utils, Application, path, knownFolders, ImageSource } from '@nativescript/core';
import { AuthorizationResult, ImagePickerBase, ImagePickerSelection, Options } from './common';
import { getFile } from '@nativescript/core/http';
import * as permissions from '@nativescript-community/perms';
export * from './common';

type FileMap = {
[key: string]: ImagePickerSelection;
};
const defaultAssetCollectionSubtypes: NSArray<any> = NSArray.arrayWithArray(<any>[PHAssetCollectionSubtype.SmartAlbumRecentlyAdded, PHAssetCollectionSubtype.SmartAlbumUserLibrary, PHAssetCollectionSubtype.AlbumMyPhotoStream, PHAssetCollectionSubtype.SmartAlbumFavorites, PHAssetCollectionSubtype.SmartAlbumPanoramas, PHAssetCollectionSubtype.SmartAlbumBursts, PHAssetCollectionSubtype.AlbumCloudShared, PHAssetCollectionSubtype.SmartAlbumSelfPortraits, PHAssetCollectionSubtype.SmartAlbumScreenshots, PHAssetCollectionSubtype.SmartAlbumLivePhotos]);
let copyToAppFolder;
let renameFileTo;
let fileMap = {};
export class ImagePicker extends Observable {
let fileMap: FileMap = {};
export class ImagePicker extends ImagePickerBase {
_imagePickerController: QBImagePickerController;
_hostView: View;
_delegate: ImagePickerControllerDelegate;
@@ -27,10 +30,9 @@ export class ImagePicker extends Observable {

constructor(options: Options = {}, hostView: View) {
super();

this._hostView = hostView;

let imagePickerController = QBImagePickerController.alloc().init();
const imagePickerController = QBImagePickerController.alloc().init();

imagePickerController.assetCollectionSubtypes = defaultAssetCollectionSubtypes;
imagePickerController.mediaType = options.mediaType ? <QBImagePickerMediaType>options.mediaType.valueOf() : QBImagePickerMediaType.Any;
@@ -46,24 +48,14 @@ export class ImagePicker extends Observable {
this._imagePickerController = imagePickerController;
}

authorize(): Promise<void> {
authorize(): Promise<AuthorizationResult> {
console.log('authorizing...');

return new Promise<void>((resolve, reject) => {
let runloop = CFRunLoopGetCurrent();
PHPhotoLibrary.requestAuthorization(function (result) {
if (result === PHAuthorizationStatus.Authorized) {
resolve();
} else {
reject(new Error('Authorization failed. Status: ' + result));
}
});
});
return permissions.request('photo').then((result) => this.mapResult(result));
}

present() {
present(): Promise<ImagePickerSelection[]> {
fileMap = {};
return new Promise<void>((resolve, reject) => {
return new Promise<ImagePickerSelection[]>((resolve, reject) => {
this._delegate = ImagePickerControllerDelegate.initWithOwner(this, resolve, reject);
this._imagePickerController.delegate = this._delegate;

@@ -99,27 +91,29 @@ class ImagePickerControllerDelegate extends NSObject implements QBImagePickerCon
qb_imagePickerControllerDidFinishPickingAssets?(imagePickerController: QBImagePickerController, iosAssets: NSArray<any>): void {
for (let i = 0; i < iosAssets.count; i++) {
const asset = new ImageAsset(iosAssets.objectAtIndex(i));
let phAssetImage: PHAsset = (<any>asset)._ios;
const phAssetImage: PHAsset = (<any>asset)._ios;
// this fixes the image aspect ratio in tns-core-modules version < 4.0
if (!asset.options) asset.options = { keepAspectRatio: true };
let existingFileName = phAssetImage.valueForKey('filename');
let pickerSelection: any = {
const existingFileName = phAssetImage.valueForKey('filename');
const pickerSelection: ImagePickerSelection = {
asset: asset,
type: phAssetImage.mediaType == 2 ? 'video' : 'image',
filename: existingFileName,
originalFilename: existingFileName,
filesize: 0,
path: '',
};
if (pickerSelection.type == 'video') pickerSelection.duration = parseInt(phAssetImage.duration.toFixed(0));
fileMap[existingFileName] = pickerSelection;
if (pickerSelection.type == 'video') {
let manager = new PHImageManager();
let options = new PHVideoRequestOptions();
const manager = new PHImageManager();
const options = new PHVideoRequestOptions();
options.networkAccessAllowed = true;
manager.requestAVAssetForVideoOptionsResultHandler(phAssetImage, options, (urlAsset: AVURLAsset, audioMix, info) => {
fileMap[existingFileName].path = urlAsset.URL.toString().replace('file://', '');
});
} else {
let imageOptions = new PHContentEditingInputRequestOptions();
const imageOptions = new PHContentEditingInputRequestOptions();
imageOptions.networkAccessAllowed = true;
phAssetImage.requestContentEditingInputWithOptionsCompletionHandler(imageOptions, (thing) => {
fileMap[existingFileName].path = thing.fullSizeImageURL.toString().replace('file://', '');
@@ -129,16 +123,16 @@ class ImagePickerControllerDelegate extends NSObject implements QBImagePickerCon

if (this._resolve) {
setTimeout(() => {
let promises = [];
const promises = [];
let count = 0;
for (var key in fileMap) {
let item = fileMap[key];
for (const key in fileMap) {
const item = fileMap[key];
const folder = knownFolders.documents();
let extension = item.filename.split('.').pop();
const extension = item.filename.split('.').pop();
let filename = renameFileTo ? renameFileTo + '.' + extension : item.filename;
if (iosAssets.count > 1) filename = renameFileTo ? renameFileTo + '-' + count + '.' + extension : item.filename;
fileMap[item.filename].filename = filename;
let fileManager = new NSFileManager();
const fileManager = new NSFileManager();
if (copyToAppFolder) {
const filePath = path.join(folder.path + '/' + copyToAppFolder, filename);
promises.push(
@@ -170,8 +164,8 @@ class ImagePickerControllerDelegate extends NSObject implements QBImagePickerCon
}

Promise.all(promises).then(() => {
let results = [];
for (var key in fileMap) {
const results: ImagePickerSelection[] = [];
for (const key in fileMap) {
results.push(fileMap[key]);
}
this._resolve(results);
Original file line number Diff line number Diff line change
@@ -11,8 +11,7 @@
android:largeScreens="true"
android:xlargeScreens="true"/>

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" tools:replace="android:maxSdkVersion"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
56 changes: 30 additions & 26 deletions tools/demo/imagepicker/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { DemoSharedBase } from '../utils';
import * as imagepicker from '@nativescript/imagepicker';
import { ItemEventData, Label } from '@nativescript/core';
import { ImageAsset, ImageSource, ItemEventData, Label } from '@nativescript/core';

export class DemoSharedImagepicker extends DemoSharedBase {
private _selection: any;
private _imageSrc: any;
private _imageSrc: ImageSource | ImageAsset;
private _imageAssets: Array<any>;
private _isSingleMode: boolean;

@@ -16,11 +16,11 @@ export class DemoSharedImagepicker extends DemoSharedBase {
return 300;
}

get imageSrc(): any {
get imageSrc(): ImageSource | ImageAsset {
return this._imageSrc;
}

set imageSrc(value: any) {
set imageSrc(value: ImageSource | ImageAsset) {
if (this._imageSrc !== value) {
this._imageSrc = value;
this.notifyPropertyChange('imageSrc', value);
@@ -82,31 +82,35 @@ export class DemoSharedImagepicker extends DemoSharedBase {
this.startSelection(context);
}

private startSelection(context) {
private startSelection(context: imagepicker.ImagePicker) {
context
.authorize()
.then(() => {
this.imageAssets = [];
this.imageSrc = null;
this.selection = null;
return context.present();
})
.then((selection: imagepicker.ImagePickerSelection[]) => {
console.log('Selection done: ', selection);
this.imageSrc = this.isSingleMode && selection.length > 0 ? selection[0].asset : null;
if (selection[0].thumbnail) {
this.imageSrc = selection[0].thumbnail;
.then((authResult) => {
console.log(authResult);
if (authResult.authorized) {
this.imageAssets = [];
this.imageSrc = null;
this.selection = null;
return context.present().then((selection: imagepicker.ImagePickerSelection[]) => {
console.log('Selection done: ', selection);
this.imageSrc = this.isSingleMode && selection.length > 0 ? selection[0].asset : null;
if (selection[0].thumbnail) {
this.imageSrc = selection[0].thumbnail;
}
this.selection = this.isSingleMode && selection.length > 0 ? selection[0] : null;

// set the images to be loaded from the assets with optimal sizes (optimize memory usage)
selection.forEach((element) => {
let asset = element.asset;
asset.options.width = this.isSingleMode ? this.previewSize : this.thumbSize;
asset.options.height = this.isSingleMode ? this.previewSize : this.thumbSize;
});

this.imageAssets = selection;
});
} else {
console.log('UnAuthorized');
}
this.selection = this.isSingleMode && selection.length > 0 ? selection[0] : null;

// set the images to be loaded from the assets with optimal sizes (optimize memory usage)
selection.forEach((element) => {
let asset = element.asset;
asset.options.width = this.isSingleMode ? this.previewSize : this.thumbSize;
asset.options.height = this.isSingleMode ? this.previewSize : this.thumbSize;
});

this.imageAssets = selection;
})
.catch(function (e) {
console.log('selection error', e);