parent
2691653274
commit
e6026cfd27
@ -1,10 +1,10 @@
|
||||
<h1 mat-dialog-title>
|
||||
{{title}}
|
||||
{{title}}
|
||||
</h1>
|
||||
<div mat-dialog-content>
|
||||
{{message}}
|
||||
{{message}}
|
||||
</div>
|
||||
<div mat-dialog-actions class="confirm-dialog-actions">
|
||||
<button mat-stroked-button [color]="this.denyColor" (click)="closeDialog(false)">{{denyAction}}</button>
|
||||
<button mat-flat-button [color]="this.confirmColor" (click)="closeDialog(true)">{{confirmAction}}</button>
|
||||
<div class="confirm-dialog-actions" mat-dialog-actions>
|
||||
<button (click)="closeDialog(false)" [color]="this.denyColor" mat-stroked-button>{{denyAction}}</button>
|
||||
<button (click)="closeDialog(true)" [color]="this.confirmColor" mat-flat-button>{{confirmAction}}</button>
|
||||
</div>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<div #imageContainer class="image-container" (window:resize)="this.adjustSize(image, imageContainer)">
|
||||
<img #image [src]="this.imageSrc" alt="" (load)="this.adjustSize(image, imageContainer)"
|
||||
[class.scale-width]="scaleWidth && maximizeWidth" [class.scale-height]="(!scaleWidth) && maximizeHeight"
|
||||
<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"
|
||||
[src]="this.imageSrc" alt=""
|
||||
decoding="async">
|
||||
</div>
|
||||
|
@ -1,4 +1,4 @@
|
||||
<div class="image-wrapper" (click)="fileSelectEvent.emit(this.file)" [class.selected]="this.file.selected">
|
||||
<div (click)="fileSelectEvent.emit(this.file)" [class.selected]="this.file.selected" class="image-wrapper">
|
||||
<mat-progress-spinner *ngIf="!contentUrl"></mat-progress-spinner>
|
||||
<app-content-aware-image *ngIf="contentUrl" [imageSrc]="contentUrl"></app-content-aware-image>
|
||||
</div>
|
||||
|
@ -1,60 +1,65 @@
|
||||
import {
|
||||
Component,
|
||||
Input,
|
||||
OnInit,
|
||||
ViewChild,
|
||||
ElementRef, Output, EventEmitter, OnDestroy, OnChanges
|
||||
Component,
|
||||
ElementRef,
|
||||
EventEmitter,
|
||||
Input,
|
||||
OnChanges,
|
||||
OnInit,
|
||||
Output,
|
||||
ViewChild
|
||||
} from '@angular/core';
|
||||
import {File} from "../../../models/File";
|
||||
import {FileService} from "../../../services/file/file.service";
|
||||
import {ErrorBrokerService} from "../../../services/error-broker/error-broker.service";
|
||||
import {SafeResourceUrl} from "@angular/platform-browser";
|
||||
import {MatCard} from "@angular/material/card";
|
||||
import {Thumbnail} from "../../../models/Thumbnail";
|
||||
import {GridEntry} from "./GridEntry";
|
||||
|
||||
@Component({
|
||||
selector: 'app-file-grid-entry',
|
||||
templateUrl: './file-grid-entry.component.html',
|
||||
styleUrls: ['./file-grid-entry.component.scss']
|
||||
selector: 'app-file-grid-entry',
|
||||
templateUrl: './file-grid-entry.component.html',
|
||||
styleUrls: ['./file-grid-entry.component.scss']
|
||||
})
|
||||
export class FileGridEntryComponent implements OnInit, OnChanges {
|
||||
|
||||
@ViewChild("card") card!: ElementRef;
|
||||
@Input() public gridEntry!: GridEntry;
|
||||
@Output() clickEvent = new EventEmitter<FileGridEntryComponent>();
|
||||
@Output() dblClickEvent = new EventEmitter<FileGridEntryComponent>();
|
||||
@ViewChild("card") card!: ElementRef;
|
||||
@Input() public gridEntry!: GridEntry;
|
||||
@Output() clickEvent = new EventEmitter<FileGridEntryComponent>();
|
||||
@Output() dblClickEvent = new EventEmitter<FileGridEntryComponent>();
|
||||
|
||||
contentUrl: SafeResourceUrl | undefined;
|
||||
private cachedFile: File | undefined;
|
||||
contentUrl: SafeResourceUrl | undefined;
|
||||
private cachedFile: File | undefined;
|
||||
|
||||
constructor(private fileService: FileService, private errorBroker: ErrorBrokerService) { }
|
||||
constructor(private fileService: FileService, private errorBroker: ErrorBrokerService) {
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
this.cachedFile = this.gridEntry.file;
|
||||
await this.loadImage();
|
||||
}
|
||||
async ngOnInit() {
|
||||
this.cachedFile = this.gridEntry.file;
|
||||
await this.loadImage();
|
||||
}
|
||||
|
||||
async ngOnChanges() {
|
||||
if (!this.cachedFile || this.gridEntry.file.hash !== this.cachedFile.hash) {
|
||||
this.cachedFile = this.gridEntry.file;
|
||||
await this.loadImage();
|
||||
async ngOnChanges() {
|
||||
if (!this.cachedFile || this.gridEntry.file.hash !== this.cachedFile.hash) {
|
||||
this.cachedFile = this.gridEntry.file;
|
||||
await this.loadImage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async loadImage() {
|
||||
try {
|
||||
const thumbnails = await this.fileService.getThumbnails(this.gridEntry.file.hash);
|
||||
let thumbnail = thumbnails.find(t => (t.height > 250 || t.width > 250) && (t.height < 500 && t.width < 500));
|
||||
thumbnail = thumbnail ?? thumbnails[0];
|
||||
|
||||
if (!thumbnail) {
|
||||
console.log("Thumbnail is empty?!", thumbnails);
|
||||
} else {
|
||||
this.contentUrl = await this.fileService.readThumbnail(thumbnail!!);
|
||||
|
||||
async loadImage() {
|
||||
try {
|
||||
const thumbnails = await this.fileService.getThumbnails(
|
||||
this.gridEntry.file.hash);
|
||||
let thumbnail = thumbnails.find(
|
||||
t => (t.height > 250 || t.width > 250) && (t.height < 500 && t.width < 500));
|
||||
thumbnail = thumbnail ?? thumbnails[0];
|
||||
|
||||
if (!thumbnail) {
|
||||
console.log("Thumbnail is empty?!", thumbnails);
|
||||
} else {
|
||||
this.contentUrl = await this.fileService.readThumbnail(
|
||||
thumbnail!!);
|
||||
}
|
||||
} catch (err) {
|
||||
this.errorBroker.showError(err);
|
||||
}
|
||||
} catch (err) {
|
||||
this.errorBroker.showError(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,25 +1,25 @@
|
||||
<div class="tag-input-list-and-actions">
|
||||
<div class="tag-input-list" #tagInputList>
|
||||
<div #tagInputList class="tag-input-list">
|
||||
<div class="tag-input-list-inner">
|
||||
<div class="tag-input-item" *ngFor="let tag of searchTags" mat-ripple
|
||||
(click)="removeSearchTag(tag)">{{tag.getNormalizedTag()}}</div>
|
||||
<div (click)="removeSearchTag(tag)" *ngFor="let tag of searchTags" class="tag-input-item"
|
||||
mat-ripple>{{tag.getNormalizedTag()}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<button id="delete-all-tags-button" mat-icon-button (click)="removeAllSearchTags()">
|
||||
<button (click)="removeAllSearchTags()" id="delete-all-tags-button" mat-icon-button>
|
||||
<mat-icon>delete-sweep</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
<mat-form-field class="full-width" appearance="fill">
|
||||
<mat-form-field appearance="fill" class="full-width">
|
||||
<mat-label>Enter tags to filter for</mat-label>
|
||||
<input matInput
|
||||
#tagInput
|
||||
<input #tagInput
|
||||
(keydown)="addSearchTagByInput($event)"
|
||||
[formControl]="formControl"
|
||||
[matAutocomplete]="auto"
|
||||
[formControl]="formControl"/>
|
||||
matInput/>
|
||||
<mat-autocomplete #auto (optionSelected)="addSearchTagByAutocomplete($event)">
|
||||
<mat-option *ngFor="let tag of suggestionTags | async" [value]="tag">
|
||||
{{tag}}
|
||||
</mat-option>
|
||||
</mat-autocomplete>
|
||||
</mat-form-field>
|
||||
<button mat-flat-button id="sort-button" (click)="openSortDialog()">Sort: {{sortExpression.join(", ")}}</button>
|
||||
<button (click)="openSortDialog()" id="sort-button" mat-flat-button>Sort: {{sortExpression.join(", ")}}</button>
|
||||
|
@ -1,40 +1,48 @@
|
||||
<h1 mat-dialog-title>Sort Entries</h1>
|
||||
<div mat-dialog-content>
|
||||
<div cdkDropList class="sort-input-list" (cdkDropListDropped)="this.onSortEntryDrop($event)">
|
||||
<div cdkDrag class="sort-input-row" *ngFor="let sortKey of sortEntries">
|
||||
<div class="drag-placeholder" *cdkDragPlaceholder></div>
|
||||
<div class="drag-handle" cdkDragHandle><mat-icon>drag_handle</mat-icon></div>
|
||||
<mat-form-field>
|
||||
<mat-label>Key</mat-label>
|
||||
<mat-select required [(value)]="sortKey.sortType">
|
||||
<mat-option value="Namespace">Namespace</mat-option>
|
||||
<mat-option value="FileName">File Name</mat-option>
|
||||
<mat-option value="FileSize">File Size</mat-option>
|
||||
<mat-option value="FileImportedTime">Time Imported</mat-option>
|
||||
<mat-option value="FileCreatedTime">Time Created</mat-option>
|
||||
<mat-option value="FileChangeTime">Time Changed</mat-option>
|
||||
<mat-option value="FileType">File Type</mat-option>
|
||||
<mat-option value="NumTags">Number of Tags</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field *ngIf="sortKey.sortType === 'Namespace'">
|
||||
<mat-label>Namespace Name</mat-label>
|
||||
<input #namespaceInput matInput required [value]="sortKey.namespaceName ?? ''" (change)="sortKey.namespaceName = namespaceInput.value">
|
||||
</mat-form-field>
|
||||
<div class="filler" *ngIf="sortKey.sortType !== 'Namespace'"></div>
|
||||
<mat-form-field>
|
||||
<mat-label>Direction</mat-label>
|
||||
<mat-select [(value)]="sortKey.sortDirection" required>
|
||||
<mat-option value="Ascending">Ascending</mat-option>
|
||||
<mat-option value="Descending">Descending</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<button *ngIf="sortEntries.indexOf(sortKey) === sortEntries.length -1" mat-flat-button (click)="addNewSortKey()"><mat-icon>add</mat-icon></button>
|
||||
<button *ngIf="sortEntries.indexOf(sortKey) !== sortEntries.length -1" mat-flat-button (click)="removeSortKey(sortKey)"><mat-icon>remove</mat-icon></button>
|
||||
<div (cdkDropListDropped)="this.onSortEntryDrop($event)" cdkDropList class="sort-input-list">
|
||||
<div *ngFor="let sortKey of sortEntries" cdkDrag class="sort-input-row">
|
||||
<div *cdkDragPlaceholder class="drag-placeholder"></div>
|
||||
<div cdkDragHandle class="drag-handle">
|
||||
<mat-icon>drag_handle</mat-icon>
|
||||
</div>
|
||||
<mat-form-field>
|
||||
<mat-label>Key</mat-label>
|
||||
<mat-select [(value)]="sortKey.sortType" required>
|
||||
<mat-option value="Namespace">Namespace</mat-option>
|
||||
<mat-option value="FileName">File Name</mat-option>
|
||||
<mat-option value="FileSize">File Size</mat-option>
|
||||
<mat-option value="FileImportedTime">Time Imported</mat-option>
|
||||
<mat-option value="FileCreatedTime">Time Created</mat-option>
|
||||
<mat-option value="FileChangeTime">Time Changed</mat-option>
|
||||
<mat-option value="FileType">File Type</mat-option>
|
||||
<mat-option value="NumTags">Number of Tags</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field *ngIf="sortKey.sortType === 'Namespace'">
|
||||
<mat-label>Namespace Name</mat-label>
|
||||
<input #namespaceInput (change)="sortKey.namespaceName = namespaceInput.value" [value]="sortKey.namespaceName ?? ''" matInput
|
||||
required>
|
||||
</mat-form-field>
|
||||
<div *ngIf="sortKey.sortType !== 'Namespace'" class="filler"></div>
|
||||
<mat-form-field>
|
||||
<mat-label>Direction</mat-label>
|
||||
<mat-select [(value)]="sortKey.sortDirection" required>
|
||||
<mat-option value="Ascending">Ascending</mat-option>
|
||||
<mat-option value="Descending">Descending</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<button (click)="addNewSortKey()" *ngIf="sortEntries.indexOf(sortKey) === sortEntries.length -1" mat-flat-button>
|
||||
<mat-icon>add</mat-icon>
|
||||
</button>
|
||||
<button (click)="removeSortKey(sortKey)" *ngIf="sortEntries.indexOf(sortKey) !== sortEntries.length -1"
|
||||
mat-flat-button>
|
||||
<mat-icon>remove</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dialog-actions" mat-dialog-actions>
|
||||
<button mat-flat-button color="primary" (click)="confirmSort()">Sort</button>
|
||||
<button mat-stroked-button color="accent" (click)="cancelSort()">Cancel</button>
|
||||
<button (click)="confirmSort()" color="primary" mat-flat-button>Sort</button>
|
||||
<button (click)="cancelSort()" color="accent" mat-stroked-button>Cancel</button>
|
||||
</div>
|
||||
|
@ -1,4 +1,4 @@
|
||||
<div class="tag-item-wrapper">
|
||||
<span *ngIf="tag.namespace" class="tag-item-namespace" [style]="{color: namespaceColor}">{{tag.namespace}}:</span>
|
||||
<span class="tag-item-name" [style]="{color: tagColor}">{{tag.name}}</span>
|
||||
<span *ngIf="tag.namespace" [style]="{color: namespaceColor}" class="tag-item-namespace">{{tag.namespace}}:</span>
|
||||
<span [style]="{color: tagColor}" class="tag-item-name">{{tag.name}}</span>
|
||||
</div>
|
||||
|
@ -1,19 +1,20 @@
|
||||
<mat-drawer-container class="page">
|
||||
<mat-drawer mode="side" opened disableClose>
|
||||
<mat-drawer disableClose mode="side" opened>
|
||||
<app-files-tab-sidebar (searchEndEvent)="this.contentLoading = false"
|
||||
(searchStartEvent)="this.contentLoading = true" [selectedFiles]="this.selectedFiles"></app-files-tab-sidebar>
|
||||
(searchStartEvent)="this.contentLoading = true"
|
||||
[selectedFiles]="this.selectedFiles"></app-files-tab-sidebar>
|
||||
</mat-drawer>
|
||||
<mat-drawer-content>
|
||||
<div *ngIf="contentLoading" class="spinner-overlay">
|
||||
<mat-progress-spinner color="primary" mode="indeterminate"></mat-progress-spinner>
|
||||
</div>
|
||||
<app-file-grid *ngIf="!this.showGallery" (fileDblClickEvent)="openGallery($event)" [files]="files"
|
||||
(fileSelectEvent)="onFileSelect($event)"
|
||||
<app-file-grid (fileDblClickEvent)="openGallery($event)" (fileMultiselectEvent)="onFileMultiSelect($event)" (fileSelectEvent)="onFileSelect($event)"
|
||||
*ngIf="!this.showGallery"
|
||||
[files]="files"
|
||||
[preselectedFile]="this.preselectedFile"
|
||||
(fileMultiselectEvent)="onFileMultiSelect($event)"
|
||||
></app-file-grid>
|
||||
<app-file-gallery *ngIf="this.showGallery" [files]="files" (fileSelectEvent)="onFileSelect($event)"
|
||||
[preselectedFile]="this.preselectedFile"
|
||||
(closeEvent)="this.closeGallery($event.selectedFile?.data)"></app-file-gallery>
|
||||
<app-file-gallery (closeEvent)="this.closeGallery($event.selectedFile?.data)" (fileSelectEvent)="onFileSelect($event)" *ngIf="this.showGallery"
|
||||
[files]="files"
|
||||
[preselectedFile]="this.preselectedFile"></app-file-gallery>
|
||||
</mat-drawer-content>
|
||||
</mat-drawer-container>
|
||||
|
Loading…
Reference in New Issue