Skip to content

Instantly share code, notes, and snippets.

@komendantaa
Created March 8, 2019 18:56
Show Gist options
  • Save komendantaa/db2a2cebdf14b1d5e8babe259941e537 to your computer and use it in GitHub Desktop.
Save komendantaa/db2a2cebdf14b1d5e8babe259941e537 to your computer and use it in GitHub Desktop.
ionic-imageSourcePopup
import { Injectable } from '@angular/core';
import { ActionSheetController, normalizeURL, Platform } from 'ionic-angular';
import { File, FileEntry, IFile } from '@ionic-native/file';
import { Crop } from '@ionic-native/crop';
import { Camera, CameraOptions } from '@ionic-native/camera';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { IOSFilePicker } from '@ionic-native/file-picker';
export interface ImageData {
imagePath: string;
blob: Blob;
}
export interface FileData {
fileName: string;
blob: Blob;
}
@Injectable()
export class FileTransferProvider {
private _imageSubject: BehaviorSubject<ImageData>;
private _imageData: ImageData = {
imagePath: null,
blob: null,
};
private _fileSubject: BehaviorSubject<FileData>;
private _fileData: FileData = {
fileName: null,
blob: null,
};
constructor(
private actionSheet: ActionSheetController,
private camera: Camera,
private crop: Crop,
private file: File,
private platform: Platform,
private filePicker: IOSFilePicker
) {}
/**
* @description
* Works only for Android, Desktops and iphone 6 and more !!!
*
* upload via input type="file"
*
* @usage
* ```html
*
* <input type="file" (change)="uploadFileProvider.onFileSelected($event, formGroup.get('resumeFileName'))"
* accept="application/pdf">
* ```
*
* @param {event} e
*/
onFileSelected(e): BehaviorSubject<FileData> {
this._fileSubject = new BehaviorSubject<FileData>(null);
if (e.target.files && e.target.files.length > 0) {
let file = e.target.files[0];
// set file data
this._fileData.blob = file;
this._fileData.fileName = file.name;
// pass data
this._fileSubject.next(this._fileData);
}
return this._fileSubject;
}
//TODO file validaors!
/**
* @description
* Workaround for iphone 5 - give ability to browse clouds
*
* @returns {BehaviorSubject<FileData>}
*/
initFileUpload(): BehaviorSubject<FileData> {
this.getFromIosClouds();
this._fileSubject = new BehaviorSubject<FileData>(null);
return this._fileSubject;
}
private getFromIosClouds() {
this.filePicker
.pickFile()
.then(uri => {
console.log('uri', uri);
this.file
.resolveLocalFilesystemUrl('file:///' + uri)
.then(entry => (<FileEntry>entry).file(file => this.readFileIOS(file)))
.catch(err => console.error(' resolveFileSystem ERROR: ', JSON.stringify(err)));
})
.catch(err => console.error('pickFile ERROR: ', JSON.stringify(err)));
}
private readFileIOS(file: IFile) {
const reader = new FileReader();
reader.readAsArrayBuffer(file);
reader.onloadend = () => {
// create blob
const blob: any = new Blob([reader.result], { type: file.type });
blob.name = file.name;
// set file data
this._fileData.blob = blob;
this._fileData.fileName = blob.name;
// pass data
this._fileSubject.next(this._fileData);
// clear data to prevent reusing
this._fileSubject.next(null);
};
}
/**
* @description
* show popup which prefer source for image then pass selected image data to observer
*
* @usage
*
* ```html
* <div class="avatar-wrapp file-upload-block" (click)="uploadAvatar()">
* <img [src]="tempData.avatarImage | sanitizer" alt="avatar">
* </div>
* ```
* Be attentive!
* For debugging on local host you should use sanitizer, because of CORS
*
*
* ```ts
* this.uploadFileProvider.initImageUpload().subscribe((data: ImageData) => {
* this.avatarImage = data.imagePath;
* this.formGroup.get('avatarFileName').setValue(data.blob);
* })
* ```
*
* @returns {BehaviorSubject<ImageData>}
*/
initImageUpload(): BehaviorSubject<ImageData> {
this.popupImageSource();
this._imageSubject = new BehaviorSubject<ImageData>(null);
return this._imageSubject;
}
private popupImageSource() {
let actionSheet = this.actionSheet.create({
buttons: [
{
text: 'Load from gallery',
handler: () => this.addImage(this.camera.PictureSourceType.PHOTOLIBRARY),
},
{
text: 'Take a photo',
handler: () => {
this.addImage(this.camera.PictureSourceType.CAMERA);
},
},
{
text: 'Cancel',
role: 'cancel',
},
],
});
actionSheet.present();
}
private addImage(source) {
const options: CameraOptions = {
sourceType: source,
quality: 100,
targetWidth: 900,
targetHeight: 1600,
destinationType: this.camera.DestinationType.FILE_URI,
encodingType: this.camera.EncodingType.JPEG,
correctOrientation: false,
mediaType: this.camera.MediaType.PICTURE,
};
this.camera
.getPicture(options)
.then(fileUri => {
return this.crop.crop(fileUri, {
quality: 100,
targetWidth: 900,
targetHeight: 1600,
});
})
.then(path => {
// set image path for ios
this.setPicturePreview(path, null);
this.resolveFileSystem(path);
})
.catch(err => console.error(' normalized ERROR: ', JSON.stringify(err)));
}
private resolveFileSystem(imageFileUri: any) {
this.file
.resolveLocalFilesystemUrl(imageFileUri)
.then(entry => {
(<FileEntry>entry).file(file => this.readFile(file));
})
.catch(err => console.error('file ERROR: ', JSON.stringify(err)));
}
private readFile(file: IFile) {
const reader = new FileReader();
reader.readAsArrayBuffer(file);
reader.onloadend = () => {
// create blob
const blob: any = new Blob([reader.result], { type: file.type });
blob.name = file.name;
// set image data
this._imageData.blob = blob;
// set image path for android
this.setPicturePreview(null, blob);
// pass data
this._imageSubject.next(this._imageData);
// clear data to prevent reusing
this._imageSubject.next(null);
};
}
private setPicturePreview(forIos: string, forAndroid: Blob) {
if (this.platform.is('ios')) {
forIos && (this._imageData.imagePath = normalizeURL(forIos));
} else {
forAndroid && (this._imageData.imagePath = URL.createObjectURL(forAndroid));
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment