@idealyst/files 1.2.96
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +94 -0
- package/src/components/DropZone.native.tsx +96 -0
- package/src/components/DropZone.styles.tsx +99 -0
- package/src/components/DropZone.web.tsx +178 -0
- package/src/components/FilePickerButton.native.tsx +82 -0
- package/src/components/FilePickerButton.styles.tsx +112 -0
- package/src/components/FilePickerButton.web.tsx +84 -0
- package/src/components/UploadProgress.native.tsx +203 -0
- package/src/components/UploadProgress.styles.tsx +90 -0
- package/src/components/UploadProgress.web.tsx +201 -0
- package/src/components/index.native.ts +8 -0
- package/src/components/index.ts +6 -0
- package/src/components/index.web.ts +8 -0
- package/src/constants.ts +336 -0
- package/src/examples/index.ts +181 -0
- package/src/hooks/createUseFilePickerHook.ts +169 -0
- package/src/hooks/createUseFileUploadHook.ts +173 -0
- package/src/hooks/index.native.ts +12 -0
- package/src/hooks/index.ts +12 -0
- package/src/hooks/index.web.ts +12 -0
- package/src/index.native.ts +142 -0
- package/src/index.ts +139 -0
- package/src/index.web.ts +142 -0
- package/src/permissions/index.native.ts +8 -0
- package/src/permissions/index.ts +8 -0
- package/src/permissions/index.web.ts +8 -0
- package/src/permissions/permissions.native.ts +177 -0
- package/src/permissions/permissions.web.ts +96 -0
- package/src/picker/FilePicker.native.ts +407 -0
- package/src/picker/FilePicker.web.ts +366 -0
- package/src/picker/index.native.ts +2 -0
- package/src/picker/index.ts +2 -0
- package/src/picker/index.web.ts +2 -0
- package/src/types.ts +990 -0
- package/src/uploader/ChunkedUploader.ts +312 -0
- package/src/uploader/FileUploader.native.ts +435 -0
- package/src/uploader/FileUploader.web.ts +350 -0
- package/src/uploader/UploadQueue.ts +519 -0
- package/src/uploader/index.native.ts +4 -0
- package/src/uploader/index.ts +4 -0
- package/src/uploader/index.web.ts +4 -0
- package/src/utils.ts +586 -0
|
@@ -0,0 +1,519 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
PickedFile,
|
|
3
|
+
UploadConfig,
|
|
4
|
+
UploadProgressInfo,
|
|
5
|
+
UploadState,
|
|
6
|
+
UploadResult,
|
|
7
|
+
QueueStatus,
|
|
8
|
+
UploadError,
|
|
9
|
+
} from '../types';
|
|
10
|
+
import { INITIAL_QUEUE_STATUS, TIMING } from '../constants';
|
|
11
|
+
import {
|
|
12
|
+
generateId,
|
|
13
|
+
EventEmitter,
|
|
14
|
+
SpeedCalculator,
|
|
15
|
+
calculateETA,
|
|
16
|
+
calculateRetryDelay,
|
|
17
|
+
isRetryableError,
|
|
18
|
+
} from '../utils';
|
|
19
|
+
|
|
20
|
+
type QueueEvents = {
|
|
21
|
+
queueChange: [QueueStatus];
|
|
22
|
+
progress: [string, UploadProgressInfo];
|
|
23
|
+
complete: [UploadResult];
|
|
24
|
+
error: [UploadError, string];
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Manages upload queue with concurrency control, retry logic, and progress tracking.
|
|
29
|
+
*/
|
|
30
|
+
export class UploadQueue {
|
|
31
|
+
private _uploads = new Map<string, UploadProgressInfo>();
|
|
32
|
+
private _queue: string[] = [];
|
|
33
|
+
private _activeUploads = new Set<string>();
|
|
34
|
+
private _speedCalculators = new Map<string, SpeedCalculator>();
|
|
35
|
+
private _events = new EventEmitter<QueueEvents>();
|
|
36
|
+
private _status: QueueStatus = { ...INITIAL_QUEUE_STATUS };
|
|
37
|
+
private _concurrency: number;
|
|
38
|
+
private _isPaused = false;
|
|
39
|
+
private _isProcessing = false;
|
|
40
|
+
private _disposed = false;
|
|
41
|
+
|
|
42
|
+
constructor(concurrency = 3) {
|
|
43
|
+
this._concurrency = concurrency;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
get queueStatus(): QueueStatus {
|
|
47
|
+
return { ...this._status };
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
get uploads(): Map<string, UploadProgressInfo> {
|
|
51
|
+
return new Map(this._uploads);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Add file(s) to the upload queue.
|
|
56
|
+
*/
|
|
57
|
+
add(files: PickedFile | PickedFile[], config: UploadConfig): string[] {
|
|
58
|
+
const fileArray = Array.isArray(files) ? files : [files];
|
|
59
|
+
const ids: string[] = [];
|
|
60
|
+
|
|
61
|
+
for (const file of fileArray) {
|
|
62
|
+
const id = generateId('upload');
|
|
63
|
+
|
|
64
|
+
const progress: UploadProgressInfo = {
|
|
65
|
+
id,
|
|
66
|
+
file,
|
|
67
|
+
state: 'pending',
|
|
68
|
+
bytesUploaded: 0,
|
|
69
|
+
bytesTotal: file.size,
|
|
70
|
+
percentage: 0,
|
|
71
|
+
speed: 0,
|
|
72
|
+
estimatedTimeRemaining: 0,
|
|
73
|
+
retryCount: 0,
|
|
74
|
+
config,
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
this._uploads.set(id, progress);
|
|
78
|
+
this._queue.push(id);
|
|
79
|
+
this._speedCalculators.set(id, new SpeedCalculator(TIMING.SPEED_CALCULATION_WINDOW));
|
|
80
|
+
ids.push(id);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
this._updateQueueStatus();
|
|
84
|
+
return ids;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Start processing the queue.
|
|
89
|
+
*/
|
|
90
|
+
start(): void {
|
|
91
|
+
if (this._disposed || this._isProcessing) return;
|
|
92
|
+
|
|
93
|
+
this._isPaused = false;
|
|
94
|
+
this._isProcessing = true;
|
|
95
|
+
this._processQueue();
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Pause all uploads.
|
|
100
|
+
*/
|
|
101
|
+
pause(): void {
|
|
102
|
+
this._isPaused = true;
|
|
103
|
+
|
|
104
|
+
// Mark active uploads as paused
|
|
105
|
+
for (const id of this._activeUploads) {
|
|
106
|
+
this._updateUploadState(id, 'paused');
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
this._updateQueueStatus();
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Resume paused uploads.
|
|
114
|
+
*/
|
|
115
|
+
resume(): void {
|
|
116
|
+
this._isPaused = false;
|
|
117
|
+
|
|
118
|
+
// Mark paused uploads as pending to be reprocessed
|
|
119
|
+
for (const [id, upload] of this._uploads) {
|
|
120
|
+
if (upload.state === 'paused') {
|
|
121
|
+
this._updateUploadState(id, 'pending');
|
|
122
|
+
if (!this._queue.includes(id)) {
|
|
123
|
+
this._queue.push(id);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
this._updateQueueStatus();
|
|
129
|
+
this._processQueue();
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Cancel a specific upload.
|
|
134
|
+
*/
|
|
135
|
+
cancel(uploadId: string): void {
|
|
136
|
+
const upload = this._uploads.get(uploadId);
|
|
137
|
+
if (!upload) return;
|
|
138
|
+
|
|
139
|
+
this._updateUploadState(uploadId, 'cancelled');
|
|
140
|
+
this._activeUploads.delete(uploadId);
|
|
141
|
+
this._queue = this._queue.filter(id => id !== uploadId);
|
|
142
|
+
this._speedCalculators.delete(uploadId);
|
|
143
|
+
|
|
144
|
+
this._updateQueueStatus();
|
|
145
|
+
this._processQueue();
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Cancel all uploads.
|
|
150
|
+
*/
|
|
151
|
+
cancelAll(): void {
|
|
152
|
+
for (const [id] of this._uploads) {
|
|
153
|
+
this._updateUploadState(id, 'cancelled');
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
this._activeUploads.clear();
|
|
157
|
+
this._queue = [];
|
|
158
|
+
this._speedCalculators.clear();
|
|
159
|
+
|
|
160
|
+
this._updateQueueStatus();
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Retry a failed upload.
|
|
165
|
+
*/
|
|
166
|
+
retry(uploadId: string): void {
|
|
167
|
+
const upload = this._uploads.get(uploadId);
|
|
168
|
+
if (!upload || upload.state !== 'failed') return;
|
|
169
|
+
|
|
170
|
+
// Reset upload state
|
|
171
|
+
this._uploads.set(uploadId, {
|
|
172
|
+
...upload,
|
|
173
|
+
state: 'pending',
|
|
174
|
+
bytesUploaded: 0,
|
|
175
|
+
percentage: 0,
|
|
176
|
+
speed: 0,
|
|
177
|
+
estimatedTimeRemaining: 0,
|
|
178
|
+
error: undefined,
|
|
179
|
+
currentChunk: undefined,
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
this._speedCalculators.set(uploadId, new SpeedCalculator(TIMING.SPEED_CALCULATION_WINDOW));
|
|
183
|
+
this._queue.push(uploadId);
|
|
184
|
+
|
|
185
|
+
this._updateQueueStatus();
|
|
186
|
+
this._processQueue();
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Retry all failed uploads.
|
|
191
|
+
*/
|
|
192
|
+
retryAll(): void {
|
|
193
|
+
for (const [id, upload] of this._uploads) {
|
|
194
|
+
if (upload.state === 'failed') {
|
|
195
|
+
this.retry(id);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Remove an upload from the queue.
|
|
202
|
+
*/
|
|
203
|
+
remove(uploadId: string): void {
|
|
204
|
+
this._uploads.delete(uploadId);
|
|
205
|
+
this._activeUploads.delete(uploadId);
|
|
206
|
+
this._queue = this._queue.filter(id => id !== uploadId);
|
|
207
|
+
this._speedCalculators.delete(uploadId);
|
|
208
|
+
|
|
209
|
+
this._updateQueueStatus();
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Clear completed uploads.
|
|
214
|
+
*/
|
|
215
|
+
clearCompleted(): void {
|
|
216
|
+
for (const [id, upload] of this._uploads) {
|
|
217
|
+
if (upload.state === 'completed' || upload.state === 'cancelled') {
|
|
218
|
+
this._uploads.delete(id);
|
|
219
|
+
this._speedCalculators.delete(id);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
this._updateQueueStatus();
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Get a specific upload.
|
|
228
|
+
*/
|
|
229
|
+
getUpload(uploadId: string): UploadProgressInfo | undefined {
|
|
230
|
+
return this._uploads.get(uploadId);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Update upload progress.
|
|
235
|
+
*/
|
|
236
|
+
updateProgress(
|
|
237
|
+
uploadId: string,
|
|
238
|
+
bytesUploaded: number,
|
|
239
|
+
additionalData?: Partial<Pick<UploadProgressInfo, 'currentChunk' | 'totalChunks'>>
|
|
240
|
+
): void {
|
|
241
|
+
const upload = this._uploads.get(uploadId);
|
|
242
|
+
if (!upload) return;
|
|
243
|
+
|
|
244
|
+
const speedCalc = this._speedCalculators.get(uploadId);
|
|
245
|
+
if (speedCalc) {
|
|
246
|
+
speedCalc.addSample(bytesUploaded);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const speed = speedCalc?.getSpeed() || 0;
|
|
250
|
+
const bytesRemaining = upload.bytesTotal - bytesUploaded;
|
|
251
|
+
const eta = calculateETA(bytesRemaining, speed);
|
|
252
|
+
const percentage = upload.bytesTotal > 0 ? (bytesUploaded / upload.bytesTotal) * 100 : 0;
|
|
253
|
+
|
|
254
|
+
this._uploads.set(uploadId, {
|
|
255
|
+
...upload,
|
|
256
|
+
bytesUploaded,
|
|
257
|
+
percentage,
|
|
258
|
+
speed,
|
|
259
|
+
estimatedTimeRemaining: eta,
|
|
260
|
+
...additionalData,
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
this._events.emit('progress', uploadId, this._uploads.get(uploadId)!);
|
|
264
|
+
this._updateQueueStatus();
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Mark an upload as started.
|
|
269
|
+
*/
|
|
270
|
+
markStarted(uploadId: string): void {
|
|
271
|
+
const upload = this._uploads.get(uploadId);
|
|
272
|
+
if (!upload) return;
|
|
273
|
+
|
|
274
|
+
this._uploads.set(uploadId, {
|
|
275
|
+
...upload,
|
|
276
|
+
state: 'uploading',
|
|
277
|
+
startedAt: Date.now(),
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
this._activeUploads.add(uploadId);
|
|
281
|
+
this._events.emit('progress', uploadId, this._uploads.get(uploadId)!);
|
|
282
|
+
this._updateQueueStatus();
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Mark an upload as completed.
|
|
287
|
+
*/
|
|
288
|
+
markCompleted(uploadId: string, response?: unknown, statusCode?: number): void {
|
|
289
|
+
const upload = this._uploads.get(uploadId);
|
|
290
|
+
if (!upload) return;
|
|
291
|
+
|
|
292
|
+
const updatedUpload: UploadProgressInfo = {
|
|
293
|
+
...upload,
|
|
294
|
+
state: 'completed',
|
|
295
|
+
bytesUploaded: upload.bytesTotal,
|
|
296
|
+
percentage: 100,
|
|
297
|
+
speed: 0,
|
|
298
|
+
estimatedTimeRemaining: 0,
|
|
299
|
+
completedAt: Date.now(),
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
this._uploads.set(uploadId, updatedUpload);
|
|
303
|
+
this._activeUploads.delete(uploadId);
|
|
304
|
+
this._speedCalculators.delete(uploadId);
|
|
305
|
+
|
|
306
|
+
const result: UploadResult = {
|
|
307
|
+
id: uploadId,
|
|
308
|
+
success: true,
|
|
309
|
+
response,
|
|
310
|
+
statusCode,
|
|
311
|
+
progress: updatedUpload,
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
this._events.emit('complete', result);
|
|
315
|
+
this._updateQueueStatus();
|
|
316
|
+
this._processQueue();
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Mark an upload as failed.
|
|
321
|
+
*/
|
|
322
|
+
markFailed(uploadId: string, error: UploadError): void {
|
|
323
|
+
const upload = this._uploads.get(uploadId);
|
|
324
|
+
if (!upload) return;
|
|
325
|
+
|
|
326
|
+
const shouldRetry = upload.config.retryEnabled &&
|
|
327
|
+
upload.retryCount < upload.config.maxRetries &&
|
|
328
|
+
isRetryableError(error);
|
|
329
|
+
|
|
330
|
+
if (shouldRetry) {
|
|
331
|
+
// Schedule retry
|
|
332
|
+
const delay = calculateRetryDelay(
|
|
333
|
+
upload.retryCount + 1,
|
|
334
|
+
upload.config.retryDelay,
|
|
335
|
+
upload.config.retryDelayMs
|
|
336
|
+
);
|
|
337
|
+
|
|
338
|
+
this._uploads.set(uploadId, {
|
|
339
|
+
...upload,
|
|
340
|
+
state: 'pending',
|
|
341
|
+
retryCount: upload.retryCount + 1,
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
this._activeUploads.delete(uploadId);
|
|
345
|
+
|
|
346
|
+
// Add back to queue after delay
|
|
347
|
+
setTimeout(() => {
|
|
348
|
+
if (!this._disposed && this._uploads.has(uploadId)) {
|
|
349
|
+
this._queue.push(uploadId);
|
|
350
|
+
this._processQueue();
|
|
351
|
+
}
|
|
352
|
+
}, delay);
|
|
353
|
+
} else {
|
|
354
|
+
// Mark as failed permanently
|
|
355
|
+
this._uploads.set(uploadId, {
|
|
356
|
+
...upload,
|
|
357
|
+
state: 'failed',
|
|
358
|
+
error,
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
this._activeUploads.delete(uploadId);
|
|
362
|
+
this._speedCalculators.delete(uploadId);
|
|
363
|
+
|
|
364
|
+
const result: UploadResult = {
|
|
365
|
+
id: uploadId,
|
|
366
|
+
success: false,
|
|
367
|
+
error,
|
|
368
|
+
statusCode: error.statusCode,
|
|
369
|
+
progress: this._uploads.get(uploadId)!,
|
|
370
|
+
};
|
|
371
|
+
|
|
372
|
+
this._events.emit('complete', result);
|
|
373
|
+
this._events.emit('error', error, uploadId);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
this._updateQueueStatus();
|
|
377
|
+
this._processQueue();
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* Get the next upload to process.
|
|
382
|
+
*/
|
|
383
|
+
getNextUpload(): UploadProgressInfo | undefined {
|
|
384
|
+
if (this._isPaused || this._disposed) return undefined;
|
|
385
|
+
if (this._activeUploads.size >= this._concurrency) return undefined;
|
|
386
|
+
|
|
387
|
+
while (this._queue.length > 0) {
|
|
388
|
+
const id = this._queue.shift()!;
|
|
389
|
+
const upload = this._uploads.get(id);
|
|
390
|
+
|
|
391
|
+
if (upload && upload.state === 'pending') {
|
|
392
|
+
return upload;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
return undefined;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Subscribe to queue status changes.
|
|
401
|
+
*/
|
|
402
|
+
onQueueChange(callback: (status: QueueStatus) => void): () => void {
|
|
403
|
+
return this._events.on('queueChange', callback);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* Subscribe to individual upload progress.
|
|
408
|
+
*/
|
|
409
|
+
onProgress(uploadId: string, callback: (progress: UploadProgressInfo) => void): () => void {
|
|
410
|
+
return this._events.on('progress', (id, progress) => {
|
|
411
|
+
if (id === uploadId) {
|
|
412
|
+
callback(progress);
|
|
413
|
+
}
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* Subscribe to upload completion.
|
|
419
|
+
*/
|
|
420
|
+
onComplete(callback: (result: UploadResult) => void): () => void {
|
|
421
|
+
return this._events.on('complete', callback);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* Subscribe to upload errors.
|
|
426
|
+
*/
|
|
427
|
+
onError(callback: (error: UploadError, uploadId: string) => void): () => void {
|
|
428
|
+
return this._events.on('error', callback);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
/**
|
|
432
|
+
* Clean up resources.
|
|
433
|
+
*/
|
|
434
|
+
dispose(): void {
|
|
435
|
+
this._disposed = true;
|
|
436
|
+
this._uploads.clear();
|
|
437
|
+
this._queue = [];
|
|
438
|
+
this._activeUploads.clear();
|
|
439
|
+
this._speedCalculators.clear();
|
|
440
|
+
this._events.removeAllListeners();
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
// ============================================
|
|
444
|
+
// PROTECTED METHODS (for subclass extension)
|
|
445
|
+
// ============================================
|
|
446
|
+
|
|
447
|
+
/**
|
|
448
|
+
* Process the queue - to be called after state changes.
|
|
449
|
+
* Override in subclasses to implement actual upload logic.
|
|
450
|
+
*/
|
|
451
|
+
protected _processQueue(): void {
|
|
452
|
+
// Base implementation just updates status
|
|
453
|
+
// Subclasses should override to implement actual upload processing
|
|
454
|
+
this._updateQueueStatus();
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// ============================================
|
|
458
|
+
// PRIVATE METHODS
|
|
459
|
+
// ============================================
|
|
460
|
+
|
|
461
|
+
private _updateUploadState(uploadId: string, state: UploadState): void {
|
|
462
|
+
const upload = this._uploads.get(uploadId);
|
|
463
|
+
if (!upload) return;
|
|
464
|
+
|
|
465
|
+
this._uploads.set(uploadId, {
|
|
466
|
+
...upload,
|
|
467
|
+
state,
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
this._events.emit('progress', uploadId, this._uploads.get(uploadId)!);
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
private _updateQueueStatus(): void {
|
|
474
|
+
let pending = 0;
|
|
475
|
+
let uploading = 0;
|
|
476
|
+
let completed = 0;
|
|
477
|
+
let failed = 0;
|
|
478
|
+
let totalBytes = 0;
|
|
479
|
+
let totalBytesUploaded = 0;
|
|
480
|
+
|
|
481
|
+
for (const [, upload] of this._uploads) {
|
|
482
|
+
totalBytes += upload.bytesTotal;
|
|
483
|
+
totalBytesUploaded += upload.bytesUploaded;
|
|
484
|
+
|
|
485
|
+
switch (upload.state) {
|
|
486
|
+
case 'pending':
|
|
487
|
+
pending++;
|
|
488
|
+
break;
|
|
489
|
+
case 'uploading':
|
|
490
|
+
uploading++;
|
|
491
|
+
break;
|
|
492
|
+
case 'completed':
|
|
493
|
+
completed++;
|
|
494
|
+
break;
|
|
495
|
+
case 'failed':
|
|
496
|
+
failed++;
|
|
497
|
+
break;
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
const total = this._uploads.size;
|
|
502
|
+
const overallProgress = totalBytes > 0 ? (totalBytesUploaded / totalBytes) * 100 : 0;
|
|
503
|
+
|
|
504
|
+
this._status = {
|
|
505
|
+
total,
|
|
506
|
+
pending,
|
|
507
|
+
uploading,
|
|
508
|
+
completed,
|
|
509
|
+
failed,
|
|
510
|
+
isProcessing: this._isProcessing && !this._isPaused && uploading > 0,
|
|
511
|
+
isPaused: this._isPaused,
|
|
512
|
+
overallProgress,
|
|
513
|
+
totalBytesUploaded,
|
|
514
|
+
totalBytes,
|
|
515
|
+
};
|
|
516
|
+
|
|
517
|
+
this._events.emit('queueChange', this._status);
|
|
518
|
+
}
|
|
519
|
+
}
|