Add thumbnail icons for unsupported mediatypes and thumbnails for non-images

Signed-off-by: trivernis <trivernis@protonmail.com>
pull/4/head
trivernis 3 years ago
parent e49d1a07af
commit 4d7a18b159

@ -65,6 +65,7 @@ import {VideoViewerComponent} from './components/file-gallery/content-viewer/vid
import {HttpClientModule} from "@angular/common/http"; import {HttpClientModule} from "@angular/common/http";
import { AudioViewerComponent } from './components/file-gallery/content-viewer/audio-viewer/audio-viewer.component'; import { AudioViewerComponent } from './components/file-gallery/content-viewer/audio-viewer/audio-viewer.component';
import { BusyIndicatorComponent } from './components/busy-indicator/busy-indicator.component'; import { BusyIndicatorComponent } from './components/busy-indicator/busy-indicator.component';
import { FileThumbnailComponent } from './components/file-thumbnail/file-thumbnail.component';
@NgModule({ @NgModule({
declarations: [ declarations: [
@ -99,6 +100,7 @@ import { BusyIndicatorComponent } from './components/busy-indicator/busy-indicat
VideoViewerComponent, VideoViewerComponent,
AudioViewerComponent, AudioViewerComponent,
BusyIndicatorComponent, BusyIndicatorComponent,
FileThumbnailComponent,
], ],
imports: [ imports: [
BrowserModule, BrowserModule,

@ -1,4 +1,5 @@
<div #imageContainer (window:resize)="this.adjustSize(image, imageContainer)" class="image-container"> <div #imageContainer (window:resize)="this.adjustSize(image, imageContainer)" class="image-container">
<img #image (load)="this.adjustSize(image, imageContainer)" [class.scale-height]="(!scaleWidth) && maximizeHeight" [class.scale-width]="scaleWidth && maximizeWidth" <img #image (load)="this.adjustSize(image, imageContainer)" [class.scale-height]="(!scaleWidth) && maximizeHeight"
[class.scale-width]="scaleWidth && maximizeWidth" [style]="{borderRadius: this.borderRadius}"
[src]="this.imageSrc" alt=""> [src]="this.imageSrc" alt="">
</div> </div>

@ -11,6 +11,7 @@ export class ContentAwareImageComponent implements OnInit {
@Input() imageSrc!: string | SafeResourceUrl; @Input() imageSrc!: string | SafeResourceUrl;
@Input() maximizeHeight: boolean = true; @Input() maximizeHeight: boolean = true;
@Input() maximizeWidth: boolean = true; @Input() maximizeWidth: boolean = true;
@Input() borderRadius: string | undefined;
@Input() decoding: "async" | "sync" | "auto" = "auto"; @Input() decoding: "async" | "sync" | "auto" = "auto";
@ViewChild("image") image: ElementRef<HTMLImageElement> | undefined; @ViewChild("image") image: ElementRef<HTMLImageElement> | undefined;

@ -1,4 +1,4 @@
<div (click)="fileSelectEvent.emit(this.file)" [class.selected]="this.file.selected" class="image-wrapper"> <div (click)="fileSelectEvent.emit(this.file)" [class.selected]="this.file.selected" class="image-wrapper">
<mat-progress-spinner *ngIf="!contentUrl"></mat-progress-spinner> <mat-progress-spinner *ngIf="!contentUrl"></mat-progress-spinner>
<app-content-aware-image decoding="async" *ngIf="contentUrl" [imageSrc]="contentUrl"></app-content-aware-image> <app-file-thumbnail [file]="file.data"></app-file-thumbnail>
</div> </div>

@ -1,6 +1,8 @@
app-content-aware-image { app-file-thumbnail {
height: 100%; height: 100%;
width: 100%; width: 100%;
position: relative;
display: block;
} }
.image-wrapper { .image-wrapper {

@ -1,9 +1,6 @@
<mat-card #card (click)="clickEvent.emit(this)" (dblclick)="dblClickEvent.emit(this)" <mat-card #card (click)="clickEvent.emit(this)" (dblclick)="dblClickEvent.emit(this)"
[ngClass]="{'selected': gridEntry.selected}"> [ngClass]="{'selected': gridEntry.selected}">
<mat-card-content *ngIf="contentUrl !== undefined"> <mat-card-content *ngIf="contentUrl !== undefined">
<app-content-aware-image decoding="async" *ngIf="contentUrl" [imageSrc]="contentUrl" class="entry-image"></app-content-aware-image> <app-file-thumbnail [file]="this.gridEntry.file" class=".entry-image"></app-file-thumbnail>
</mat-card-content> </mat-card-content>
<mat-card-footer>
<mat-progress-bar *ngIf="contentUrl === undefined" mode="indeterminate"></mat-progress-bar>
</mat-card-footer>
</mat-card> </mat-card>

@ -0,0 +1,12 @@
<app-content-aware-image borderRadius="0.25em" *ngIf="this.getThumbnailSupported() && this.thumbUrl"
[imageSrc]="this.thumbUrl"></app-content-aware-image>
<div class="file-icon-overlay" *ngIf="this.getThumbnailSupported() && this.thumbUrl">
<mat-icon *ngIf="getFileType() === 'video'">movie</mat-icon>
<mat-icon *ngIf="this.file.mime_type === 'image/gif'" class="gif-icon">gif</mat-icon>
</div>
<div class="file-type-icon" *ngIf="!this.getThumbnailSupported() || !this.thumbUrl">
<mat-icon *ngIf="getFileType() === 'image'">image</mat-icon>
<mat-icon *ngIf="getFileType() === 'video'">movie</mat-icon>
<mat-icon *ngIf="getFileType() === 'audio'">audiotrack</mat-icon>
<mat-icon *ngIf="getFileType() === 'text'">description</mat-icon>
</div>

@ -0,0 +1,37 @@
app-content-aware-image {
height: 100%;
width: 100%;
}
.file-type-icon {
background-color: #303030;
}
.file-type-icon, .file-icon-overlay {
height: 100%;
width: 100%;
display: flex;
mat-icon {
align-self: center;
margin: auto;
}
}
.file-icon-overlay {
position: absolute;
top: 0;
right: 0;
}
mat-icon.gif-icon {
border-radius: 50%;
background-color: rgba(0, 0, 0, 0.5);
padding: 0.1em;
}
mat-icon {
font-size: 4em;
height: 1em;
width: 1em;
}

@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { FileThumbnailComponent } from './file-thumbnail.component';
describe('FileThumbnailComponent', () => {
let component: FileThumbnailComponent;
let fixture: ComponentFixture<FileThumbnailComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ FileThumbnailComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(FileThumbnailComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

@ -0,0 +1,43 @@
import {Component, Input, OnChanges, OnInit, SimpleChanges} from '@angular/core';
import {File} from "../../models/File";
import {FileService} from "../../services/file/file.service";
import {FileHelper} from "../../services/file/file.helper";
import {SafeResourceUrl} from "@angular/platform-browser";
@Component({
selector: 'app-file-thumbnail',
templateUrl: './file-thumbnail.component.html',
styleUrls: ['./file-thumbnail.component.scss']
})
export class FileThumbnailComponent implements OnInit, OnChanges {
@Input() file!: File;
public thumbUrl: SafeResourceUrl | undefined;
private supportedThumbnailTypes = ["image", "video"]
constructor(private fileService: FileService) {
}
public ngOnInit(): void {
this.thumbUrl = this.fileService.buildThumbnailUrl(this.file, 250, 250);
}
public ngOnChanges(changes: SimpleChanges): void {
if (changes["file"]) {
this.thumbUrl = this.fileService.buildThumbnailUrl(this.file, 250, 250)
}
}
public getThumbnailSupported(): boolean {
const mimeParts = FileHelper.parseMime(this.file.mime_type);
return !!mimeParts && this.supportedThumbnailTypes.includes(mimeParts[0]);
}
public getFileType(): string {
const mimeParts = FileHelper.parseMime(this.file.mime_type);
return (mimeParts && mimeParts[0]) ?? "other";
}
}

@ -20,7 +20,7 @@ export class FilesystemImportComponent {
public files: FileOsMetadata[] = []; public files: FileOsMetadata[] = [];
public importOptions = new AddFileOptions(); public importOptions = new AddFileOptions();
public filters: DialogFilter[] = [ public filters: DialogFilter[] = [
{name: "Images", extensions: ["png", "jpg", "jpeg", "webp", "bmp"]}, {name: "Images", extensions: ["png", "jpg", "jpeg", "webp", "bmp", "gif"]},
{name: "Videos", extensions: ["mp4", "mkv", "wmv", "avi", "webm"]}, {name: "Videos", extensions: ["mp4", "mkv", "wmv", "avi", "webm"]},
{name: "Audio", extensions: ["mp3", "ogg", "wav", "flac", "aac"]}, {name: "Audio", extensions: ["mp3", "ogg", "wav", "flac", "aac"]},
{name: "Documents", extensions: ["pdf", "doc", "docx", "odf"]}, {name: "Documents", extensions: ["pdf", "doc", "docx", "odf"]},

@ -26,6 +26,25 @@ export class FileHelper {
}) })
} }
/**
* Parses a mime into its two components
* @param {string | undefined} mimeType
* @returns {[string, string] | undefined}
*/
public static parseMime(mimeType: string | undefined): [string, string] | undefined {
if (!mimeType) {
return undefined;
}
let mimeParts = mimeType.split("/");
if (mimeParts.length < 2) {
return undefined;
}
const type = mimeParts[0];
const subtype = mimeParts[1];
return [type, subtype];
}
/** /**
* Returns the extension for a mime type * Returns the extension for a mime type
* @param {string} mime * @param {string} mime

Loading…
Cancel
Save