cordova-plugin-background-upload-improved
Version:
Cordova plugin for uploading file in the background
239 lines (207 loc) • 6.38 kB
text/typescript
import { Component, NgZone } from '@angular/core';
import { AlertController, Platform } from '@ionic/angular';
import { ImagePicker } from '@awesome-cordova-plugins/image-picker/ngx';
import { File } from '@awesome-cordova-plugins/file/ngx';
import { FileTransferManager, BackgroundUpload } from '@awesome-cordova-plugins/background-upload/ngx';
const TEST_UPLOAD_URL = 'https://api.2ip.me/api-speedtest/en/dev.null';
const ID_OFFSET = 100;
({
selector: 'app-tab1',
templateUrl: 'tab1.page.html',
styleUrls: ['tab1.page.scss'],
providers: [ImagePicker, File, BackgroundUpload],
})
export class Tab1Page {
uploader: FileTransferManager;
images: Map<number, string> = new Map();
imageUris: Map<number, string> = new Map();
uploadStates: Map<number, UploadState> = new Map();
private isCordova = this.platform.is('cordova');
constructor(
private platform: Platform,
private zone: NgZone,
private alertController: AlertController,
private imagePicker: ImagePicker,
private file: File,
private backgroundUpload: BackgroundUpload
) {
this.platform.ready().then(() => {
this.initUpload();
});
}
async onPickImage() {
if (!this.isCordova) {
return
}
// Check permissions beforehand because if we let imagePicker do it
// he will return nonsense
const hasPermissions = await this.imagePicker.hasReadPermission();
if (!hasPermissions) {
await this.imagePicker.requestReadPermission();
return;
}
const options = {
maximumImagesCount: 100
};
try {
const uris: Array<string> = await this.imagePicker.getPictures(options);
const generatedKeys = this.generateUniqueIds(uris.length);
console.log(uris);
uris.forEach((uri, i) => {
const pathSplit = uri.split('/');
const dir = 'file://' + pathSplit.join('/');
this.imageUris.set(generatedKeys[i], dir);
});
const data = await Promise.all(uris.map((uri) => {
const pathSplit = uri.split('/');
const filename = pathSplit.pop();
const dir = 'file://' + pathSplit.join('/');
return this.file.readAsDataURL(dir, filename);
}));
data.forEach((d, i) => {
this.images.set(generatedKeys[i], d);
});
} catch (err) {
const alert = await this.alertController.create({
header: 'An error occurred',
message: JSON.stringify(err),
buttons: ['Ok'],
});
await alert.present();
}
}
async onClickImage(id: number) {
if (!this.uploadStates.has(id)) {
// Start upload
this.uploadImage(id);
} else {
// Remove download
await this.removeImage(id);
}
}
async onTapUploadButton() {
for (const [key, value] of this.images) {
if (!this.uploadStates.has(key)) {
// Start upload
this.uploadImage(key);
} else {
// Remove download
await this.removeImage(key);
}
}
}
private initUpload(){
if(!this.isCordova){
return;
}
if(this.uploader){
return;
}
this.uploader = this.backgroundUpload.init({
callBack: event => {
console.log(event);
this.zone.run(() => {
const id = Number.parseInt(event.id, 10);
if (!this.uploadStates.has(id)) {
this.uploadStates.set(id, new UploadState());
}
const state = this.uploadStates.get(id);
switch (event.state) {
case 'UPLOADING':
state.status = UploadStatus.InProgress;
state.progress = event.progress / 100.0;
break;
case 'UPLOADED':
state.status = UploadStatus.Done;
state.progress = 1.0;
break;
case 'FAILED':
state.status = UploadStatus.Failed;
this.alertController.create({
header: 'Upload failed',
message: event.error,
buttons: ['Ok'],
})
.then((alert) => alert.present());
break;
}
console.log('New state:', state);
if (event.eventId) {
console.log('ACK');
this.uploader.acknowledgeEvent(event.eventId);
}
});
}
})
}
private uploadImage(id: number) {
for (let i = 0; i < 10; i++) {
const uri = this.imageUris.get(id);
console.log('Upload id', id);
const options = {
serverUrl: TEST_UPLOAD_URL,
filePath: uri,
fileKey: 'file',
id: String(id),
notificationTitle: 'Uploading image'
};
this.uploader.startUpload(options);
console.log('Upload submitted');
}
}
private async removeImage(id: number) {
const state = this.uploadStates.get(id);
const res = await this.uploader.removeUpload(id);
if (res) {
console.log('Remove result:', res);
this.zone.run(() => {
state.status = UploadStatus.Aborted;
state.progress = 1.0;
});
} else {
console.warn('Remove error:', res);
const alert = await this.alertController.create({
header: 'Error removing upload',
});
await alert.present();
}
}
private generateUniqueIds(count: number): Array<number> {
const random = () => Math.round(Math.random() * 10000);
const keys = Array(count).fill(undefined);
for (let i = 0; i < count; i++) {
let key = random();
while (this.imageUris.has(key) || keys.includes(key) || key === 0) {
key = random();
}
keys[i] = key;
}
return keys;
}
}
export enum UploadStatus {
// eslint-disable-next-line @typescript-eslint/naming-convention
InProgress,
// eslint-disable-next-line @typescript-eslint/naming-convention
Done,
// eslint-disable-next-line @typescript-eslint/naming-convention
Failed,
// eslint-disable-next-line @typescript-eslint/naming-convention
Aborted,
}
export class UploadState {
status = UploadStatus.InProgress;
progress = 0.0;
get color(): string {
switch (this.status) {
case UploadStatus.InProgress:
return 'tertiary';
case UploadStatus.Done:
return 'success';
case UploadStatus.Failed:
return 'danger';
case UploadStatus.Aborted:
return 'dark';
}
}
}