refactor: replace ngx-uploader with own component

This commit is contained in:
4gray committed 2022-09-26 16:34:48 +02:00
1 parent 1716cd0d8b
commit a62073332c
6 files changed
+71 -182

No files matched your search

@@ -1,25 +1,26 @@
<div
class="drop-container"
ngFileDrop
[options]="options"
(uploadOutput)="onUploadOutput($event)"
[uploadInput]="uploadInput"
class="file-upload"
appDragDropFileUpload
(click)="fileField.click()"
(fileDropped)="upload($event)"
>
<mat-icon class="upload-icon">save_alt</mat-icon>
<p class="upload-title">{{ 'HOME.FILE_UPLOAD.DRAG_DROP' | translate }}</p>
<p>{{ 'HOME.FILE_UPLOAD.OR' | translate }}</p>
<mat-icon class="upload-icon">upload_file</mat-icon>
<span class="label"
>{{
('HOME.FILE_UPLOAD.DRAG_DROP' | translate) +
' ' +
('HOME.FILE_UPLOAD.OR' | translate)
}}
<br />
{{ 'HOME.FILE_UPLOAD.CHOOSE_PLAYLIST' | translate }}</span
>
<input
type="file"
ngFileSelect
[options]="options"
(uploadOutput)="onUploadOutput($event)"
class="input-file"
name="file"
id="file"
[uploadInput]="uploadInput"
name="playlist"
#fileField
(change)="upload($any($event).target.files)"
accept=".m3u,.m3u8"
hidden
multiple
/>
<label for="file">{{
'HOME.FILE_UPLOAD.CHOOSE_PLAYLIST' | translate
}}</label>
</div>
@@ -1,48 +1,27 @@
.drop-container {
text-align: center;
color: #666;
}
$electron-title-width: 28px;
#file input {
border-radius: 4px;
border: 1px solid #ccc;
padding: 5px;
}
.upload-title {
font-size: 1.25em;
}
.input-file {
width: 0.1px;
height: 0.1px;
opacity: 0;
overflow: hidden;
position: absolute;
z-index: -1;
}
.input-file + label {
font-size: 1em;
font-weight: 700;
color: white;
background-color: #3f51b5;
display: inline-block;
text-transform: uppercase;
border-radius: 4px;
.file-upload {
height: calc(100vh - 230px);
cursor: pointer;
line-height: 35px;
padding: 3px 10px;
}
border: 1px dashed #999;
border-radius: 5px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
margin: 20px;
gap: 20px;
.input-file:focus + label,
.input-file + label:hover {
background-color: #202b69;
}
.upload-icon {
color: #999;
font-size: 60px;
width: 60px;
height: 60px;
}
.upload-icon {
font-size: 80px;
width: 80px;
height: 80px;
padding-top: 20px;
.label {
display: block;
text-align: center;
color: #999;
}
}
@@ -1,40 +0,0 @@
import { TranslateService, TranslatePipe } from '@ngx-translate/core';
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { FileUploadComponent } from './file-upload.component';
import { MatIconModule } from '@angular/material/icon';
import { MockModule, MockPipe } from 'ng-mocks';
import { NgxUploaderModule } from 'ngx-uploader';
import { TranslateServiceStub } from '../../../testing/translate.stub';
describe('FileUploadComponent', () => {
let component: FileUploadComponent;
let fixture: ComponentFixture<FileUploadComponent>;
beforeEach(
waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [FileUploadComponent, MockPipe(TranslatePipe)],
imports: [
MockModule(MatIconModule),
MockModule(NgxUploaderModule),
],
providers: [
{
provide: TranslateService,
useClass: TranslateServiceStub,
},
],
}).compileComponents();
})
);
beforeEach(() => {
fixture = TestBed.createComponent(FileUploadComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -1,10 +1,4 @@
import { Component, EventEmitter, Output } from '@angular/core';
import {
UploaderOptions,
UploadFile,
UploadOutput,
UploadInput,
} from 'ngx-uploader';
@Component({
selector: 'app-file-upload',
@@ -12,79 +6,36 @@ import {
styleUrls: ['./file-upload.component.scss'],
})
export class FileUploadComponent {
/** Array with uploaded files */
files: UploadFile[] = [];
/** Upload emitter */
uploadInput: EventEmitter<UploadInput> = new EventEmitter<UploadInput>();
/** Drag over flag */
dragOver: boolean;
/** ngx-uploader lib options */
options: UploaderOptions = {
allowedContentTypes: [
'application/x-mpegurl',
'application/octet-stream',
'application/mpegurl',
'application/vnd.apple.mpegurl',
'application/vnd.apple.mpegurl.audio',
'audio/x-mpegurl',
'audio/mpegurl',
],
concurrency: 1,
maxUploads: 1,
};
/** Emits on reject event */
@Output() fileRejected: EventEmitter<string> = new EventEmitter();
/** Emits after successful file selection */
@Output() fileSelected: EventEmitter<{
uploadEvent: Event;
file: UploadFile;
file: File;
}> = new EventEmitter();
/**
* Handles file upload
* @param output
*/
onUploadOutput(output: UploadOutput): void {
if (output.type === 'allAddedToQueue') {
if (this.files.length > 0) {
const fileReader = new FileReader();
fileReader.onload = (uploadEvent) =>
this.fileSelected.emit({
uploadEvent,
file: this.files[0],
});
fileReader.readAsText(this.files[0].nativeFile);
}
} else if (
output.type === 'addedToQueue' &&
typeof output.file !== 'undefined'
) {
this.files.push(output.file);
} else if (
output.type === 'uploading' &&
typeof output.file !== 'undefined'
) {
const index = this.files.findIndex(
(file) =>
typeof output.file !== 'undefined' &&
file.id === output.file.id
);
this.files[index] = output.file;
} else if (output.type === 'cancelled' || output.type === 'removed') {
this.files = this.files.filter(
(file: UploadFile) => file !== output.file
);
} else if (output.type === 'dragOver') {
this.dragOver = true;
} else if (output.type === 'dragOut') {
this.dragOver = false;
} else if (output.type === 'drop') {
this.dragOver = false;
} else if (
output.type === 'rejected' &&
typeof output.file !== 'undefined'
) {
this.fileRejected.emit(output.file.name);
/** Emits on reject event */
@Output() fileRejected: EventEmitter<string> = new EventEmitter();
allowedContentTypes = [
'application/mpegurl',
'application/x-mpegurl',
'application/octet-stream',
'application/vnd.apple.mpegurl',
'application/vnd.apple.mpegurl.audio',
'audio/x-mpegurl',
'audio/mpegurl',
];
upload(fileList: FileList) {
if (!this.allowedContentTypes.includes(fileList[0].type)) {
this.fileRejected.emit(fileList[0].name);
return;
}
const fileReader = new FileReader();
fileReader.onload = (uploadEvent) =>
this.fileSelected.emit({
uploadEvent,
file: fileList[0],
});
fileReader.readAsText(fileList[0]);
}
}
+3 -4
View File
@@ -8,7 +8,6 @@ import { RouterTestingModule } from '@angular/router/testing';
import { TranslatePipe, TranslateService } from '@ngx-translate/core';
import { MockComponent, MockModule, MockPipe, MockProvider } from 'ng-mocks';
import { NgxIndexedDBModule, NgxIndexedDBService } from 'ngx-indexed-db';
import { UploadFile } from 'ngx-uploader';
import { of } from 'rxjs';
import { FileUploadComponent } from '../home/file-upload/file-upload.component';
import { RecentPlaylistsComponent } from '../home/recent-playlists/recent-playlists.component';
@@ -101,10 +100,10 @@ describe('HomeComponent', () => {
const title = 'my-list.m3u';
const path = '/home/user/iptv/' + title;
const playlistContent = 'test';
const file: UploadFile = {
nativeFile: { path },
const file: File = {
path,
name: title,
} as unknown as UploadFile;
} as unknown as File;
const uploadEvent: Event = {
target: { result: playlistContent },
} as unknown as Event;
+2 -3
View File
@@ -1,7 +1,6 @@
import { Component, NgZone } from '@angular/core';
import { MatSnackBar } from '@angular/material/snack-bar';
import { Router } from '@angular/router';
import { UploadFile } from 'ngx-uploader';
import {
PLAYLIST_PARSE,
PLAYLIST_PARSE_BY_URL,
@@ -92,14 +91,14 @@ export class HomeComponent {
* Parse and store uploaded playlist
* @param payload
*/
handlePlaylist(payload: { uploadEvent: Event; file: UploadFile }): void {
handlePlaylist(payload: { uploadEvent: Event; file: File }): void {
this.isLoading = true;
const result = (payload.uploadEvent.target as FileReader).result;
const array = (result as string).split('\n');
this.electronService.sendIpcEvent(PLAYLIST_PARSE, {
title: payload.file.name,
playlist: array,
path: (payload.file.nativeFile as any).path,
path: payload.file.path,
});
}