Propagate changes to file status

Signed-off-by: trivernis <trivernis@protonmail.com>
pull/3/head
trivernis 2 years ago
parent 6073a6517f
commit d3700932db
Signed by: Trivernis
GPG Key ID: DFFFCC2C7A02DB45

@ -68,7 +68,7 @@
"optimization": {
"fonts": false,
"styles": false,
"scripts": true
"scripts": false
},
"vendorChunk": true,
"extractLicenses": false,

@ -2,7 +2,10 @@
[ngClass]="{'selected': entry.selected}">
<mat-card-content>
<app-busy-indicator [busy]="this.loading">
<app-file-thumbnail *ngIf="!loading" [file]="this.entry.data" class=".entry-image"></app-file-thumbnail>
<app-file-thumbnail *ngIf="!loading"
[fileChanged]="this.fileChanged"
[file]="this.entry.data"
class=".entry-image"></app-file-thumbnail>
</app-busy-indicator>
</mat-card-content>
</mat-card>

@ -16,6 +16,7 @@ import {
import {File} from "../../../../../api/models/File";
import {Selectable} from "../../../../models/Selectable";
import {SchedulingService} from "../../../../services/scheduling/scheduling.service";
import {BehaviorSubject} from "rxjs";
const LOADING_WORK_KEY = "FILE_THUMBNAIL_LOADING";
@ -28,6 +29,7 @@ const LOADING_WORK_KEY = "FILE_THUMBNAIL_LOADING";
export class FileCardComponent implements OnInit, OnChanges, OnDestroy, AfterViewChecked {
@ViewChild("card") card!: ElementRef;
@Input() public entry!: Selectable<File>;
@Input() public fileChanged: BehaviorSubject<void> = new BehaviorSubject<void>(undefined);
@Output() clickEvent = new EventEmitter<FileCardComponent>();
@Output() dblClickEvent = new EventEmitter<FileCardComponent>();
public loading = false;
@ -49,6 +51,9 @@ export class FileCardComponent implements OnInit, OnChanges, OnDestroy, AfterVie
this.cachedId = this.entry.data.id;
this.setImageDelayed();
}
if (changes["fileChanged"]) {
this.fileChanged.subscribe(() => this.changeDetector.markForCheck());
}
}
public ngAfterViewChecked(): void {

@ -1,12 +1,12 @@
<app-context-menu #contextMenu>
<ng-content select="[content-before]"></ng-content>
<ng-container *ngIf="this.files">
<button (click)="this.updateStatus(this.files, 'Archived')" *ngIf="actionArchive" mat-menu-item>Archive
<button (click)="this.changeFileStatus('Archived')" *ngIf="actionArchive" mat-menu-item>Archive
</button>
<button (click)="this.updateStatus(this.files, 'Imported')" *ngIf="actionImported" mat-menu-item>Back to
<button (click)="this.changeFileStatus('Imported')" *ngIf="actionImported" mat-menu-item>Back to
imported
</button>
<button (click)="this.updateStatus(this.files, 'Deleted')"
<button (click)="this.changeFileStatus('Deleted')"
*ngIf="actionDelete"
mat-menu-item>Delete
</button>
@ -14,7 +14,7 @@
*ngIf="actionDeletePermantently"
mat-menu-item>Delete permanently
</button>
<button (click)="this.updateStatus(this.files, 'Archived')" *ngIf="actionRestore" mat-menu-item>Restore</button>
<button (click)="this.changeFileStatus('Archived')" *ngIf="actionRestore" mat-menu-item>Restore</button>
<!-- everything that only applies to a single file -->
<ng-container>

@ -7,6 +7,7 @@ import {MatDialog, MatDialogRef} from "@angular/material/dialog";
import {BusyDialogComponent} from "../../app-common/busy-dialog/busy-dialog.component";
import {BehaviorSubject} from "rxjs";
import {FileActionBaseComponent} from "../../app-base/file-action-base/file-action-base.component";
import {FileStatus} from "../../../../../api/api-types/files";
type ProgressDialogContext = {
dialog: MatDialogRef<BusyDialogComponent>,
@ -31,6 +32,7 @@ export class FileContextMenuComponent extends FileActionBaseComponent implements
@ViewChild("contextMenu") contextMenu!: ContextMenuComponent;
@Output() fileDeleted = new EventEmitter<File[]>();
@Output() fileStatusChange = new EventEmitter<File[]>();
constructor(fileService: FileService, errorBroker: ErrorBrokerService, dialog: MatDialog) {
super(dialog, errorBroker, fileService);
@ -56,6 +58,11 @@ export class FileContextMenuComponent extends FileActionBaseComponent implements
}
}
public async changeFileStatus(status: FileStatus) {
await this.updateStatus(this.files, status);
this.fileStatusChange.emit(this.files);
}
private applyStatus() {
this.actionDeletePermantently = true;
this.actionDelete = this.actionArchive = this.actionImported = this.actionRestore = false;

@ -15,9 +15,11 @@
minBufferPx="1000" orientation="horizontal">
<div *cdkVirtualFor="let entry of entries; trackBy: trackByFileId" class="file-item">
<app-file-card (clickEvent)="onEntrySelect($event.entry)"
[entry]="entry"></app-file-card>
[entry]="entry" [fileChanged]="this.fileChanged"></app-file-card>
</div>
</cdk-virtual-scroll-viewport>
</div>
</div>
<app-file-context-menu #fileContextMenu (fileDeleted)="this.fileDeleted.emit($event)"></app-file-context-menu>
<app-file-context-menu #fileContextMenu
(fileDeleted)="this.fileDeleted.emit($event)"
(fileStatusChange)="this.onFileStatusChange()"></app-file-context-menu>

@ -17,6 +17,7 @@ import {Selectable} from "../../../../../models/Selectable";
import {CdkVirtualScrollViewport} from "@angular/cdk/scrolling";
import {TabService} from "../../../../../services/tab/tab.service";
import {Key} from "w3c-keys";
import {BehaviorSubject} from "rxjs";
@Component({
selector: "app-file-gallery",
@ -40,11 +41,15 @@ export class FileGalleryComponent implements OnChanges, OnInit, AfterViewInit {
public entries: Selectable<File>[] = [];
public selectedFile: Selectable<File> | undefined;
public fileContentUrl: SafeResourceUrl | undefined;
public fileChanged = new BehaviorSubject<void>(undefined);
private scrollTimeout: number | undefined;
private escapeCount = 0;
constructor(private tabService: TabService, private fileService: FileService) {
constructor(
private tabService: TabService,
private fileService: FileService
) {
tabService.selectedTab.subscribe(() => this.adjustElementSizes());
}
@ -177,6 +182,10 @@ export class FileGalleryComponent implements OnChanges, OnInit, AfterViewInit {
return item.data.id;
}
public onFileStatusChange(): void {
this.fileChanged.next();
}
private scrollToSelection(): void {
if (this.selectedFile) {
const selectedIndex = this.entries.indexOf(this.selectedFile);
@ -194,7 +203,6 @@ export class FileGalleryComponent implements OnChanges, OnInit, AfterViewInit {
}
}
private getPreselectedEntry(): Selectable<File> | undefined {
if (this.preselectedFile) {
const entry = this.entries.find(

@ -12,13 +12,13 @@
(contextmenu)="this.selectEntryWhenNotSelected(gridEntry); fileContextMenu.onContextMenu($event, this.getSelectedFiles())"
(dblClickEvent)="fileOpen.emit($event.entry.data)"
*ngFor="let gridEntry of rowEntry; trackBy: trackByFileId"
[entry]="gridEntry"></app-file-card>
[entry]="gridEntry" [fileChanged]="this.fileChanged"></app-file-card>
</div>
</div>
</cdk-virtual-scroll-viewport>
</div>
<app-file-context-menu #fileContextMenu (fileDeleted)="this.fileDeleted.emit($event)">
<app-file-context-menu #fileContextMenu (fileDeleted)="this.fileDeleted.emit($event)" (fileStatusChange)="this.onFileStatusChange()">
<button (click)="this.fileOpen.emit(fileContextMenu.files[0])"
*ngIf="fileContextMenu.files.length === 1"
content-before=""

@ -18,6 +18,7 @@ import {TabService} from "../../../../../services/tab/tab.service";
import {FileService} from "../../../../../services/file/file.service";
import {Selectable} from "../../../../../models/Selectable";
import {Key} from "w3c-keys";
import {BehaviorSubject} from "rxjs";
@Component({
selector: "app-file-grid",
@ -38,8 +39,10 @@ export class FileGridComponent implements OnChanges, OnInit, AfterViewInit {
@ViewChild("virtualScrollGrid") virtualScroll!: CdkVirtualScrollViewport;
@ViewChild("inner") inner!: ElementRef<HTMLDivElement>;
selectedEntries: Selectable<File>[] = [];
partitionedGridEntries: Selectable<File>[][] = [];
public fileChanged = new BehaviorSubject<void>(undefined);
public selectedEntries: Selectable<File>[] = [];
public partitionedGridEntries: Selectable<File>[][] = [];
private shiftClicked = false;
private ctrlClicked = false;
private gridEntries: Selectable<File>[] = [];
@ -179,6 +182,10 @@ export class FileGridComponent implements OnChanges, OnInit, AfterViewInit {
return item.data.id;
}
public onFileStatusChange(): void {
this.fileChanged.next();
}
private setPartitionedGridEntries() {
this.partitionedGridEntries = [];
let scrollToIndex = -1;

@ -1,10 +1,10 @@
<app-content-aware-image *ngIf="this.getThumbnailSupported() && this.thumbUrl" [imageSrc]="this.thumbUrl"
<app-content-aware-image *ngIf="this.thumbnailSupported && this.thumbUrl" [imageSrc]="this.thumbUrl"
borderRadius="0.25em"></app-content-aware-image>
<div *ngIf="this.getThumbnailSupported() && this.thumbUrl" class="file-icon-overlay">
<div *ngIf="this.thumbnailSupported && this.thumbUrl" class="file-icon-overlay">
<ng-icon *ngIf="fileType === 'video'" name="mat-movie"></ng-icon>
<ng-icon *ngIf="this.file.mimeType === 'image/gif'" class="gif-icon" name="mat-gif"></ng-icon>
</div>
<div *ngIf="!this.getThumbnailSupported() || !this.thumbUrl" class="file-type-icon">
<div *ngIf="!this.thumbnailSupported || !this.thumbUrl" class="file-type-icon">
<ng-icon *ngIf="fileType === 'image'" name="mat-image"></ng-icon>
<ng-icon *ngIf="fileType === 'video'" name="mat-movie"></ng-icon>
<ng-icon *ngIf="fileType === 'audio'" name="mat-audiotrack"></ng-icon>

@ -1,25 +1,38 @@
import {AfterViewInit, Component, Input, OnChanges, SimpleChanges} from "@angular/core";
import {
AfterViewChecked,
AfterViewInit,
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
Input,
OnChanges,
SimpleChanges
} from "@angular/core";
import {File} from "../../../../../api/models/File";
import {FileService} from "../../../../services/file/file.service";
import {FileHelper} from "../../../../services/file/file.helper";
import {SafeResourceUrl} from "@angular/platform-browser";
import {BehaviorSubject} from "rxjs";
@Component({
selector: "app-file-thumbnail",
templateUrl: "./file-thumbnail.component.html",
styleUrls: ["./file-thumbnail.component.scss"]
styleUrls: ["./file-thumbnail.component.scss"],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class FileThumbnailComponent implements OnChanges, AfterViewInit {
export class FileThumbnailComponent implements OnChanges, AfterViewInit, AfterViewChecked {
@Input() file!: File;
@Input() public fileChanged: BehaviorSubject<void> = new BehaviorSubject<void>(undefined);
public thumbUrl: SafeResourceUrl | undefined;
public fileType!: string;
public thumbnailSupported: boolean = false;
private supportedThumbnailTypes = ["image", "video"];
private previousStatus = "imported";
constructor(private fileService: FileService) {
constructor(private changeDetector: ChangeDetectorRef, private fileService: FileService) {
}
public async ngAfterViewInit() {
@ -28,6 +41,13 @@ export class FileThumbnailComponent implements OnChanges, AfterViewInit {
}
}
public ngAfterViewChecked(): void {
if (this.file && this.file.status != this.previousStatus) {
this.previousStatus = this.file.status;
this.changeDetector.markForCheck();
}
}
public async ngOnChanges(changes: SimpleChanges) {
if (changes["file"]) {
this.thumbUrl = this.fileService.buildThumbnailUrl(this.file,
@ -36,16 +56,19 @@ export class FileThumbnailComponent implements OnChanges, AfterViewInit {
this.fileType = this.getFileType();
this.thumbnailSupported = this.getThumbnailSupported();
}
if (changes["fileChanged"]) {
this.fileChanged.subscribe(() => this.changeDetector.markForCheck());
}
}
public getThumbnailSupported(): boolean {
private getThumbnailSupported(): boolean {
const mimeParts = FileHelper.parseMime(this.file.mimeType);
return !!mimeParts && this.supportedThumbnailTypes.includes(
mimeParts[0]);
}
public getFileType(): string {
private getFileType(): string {
const mimeParts = FileHelper.parseMime(this.file.mimeType);
return (mimeParts && mimeParts[0]) ?? "other";
}

Loading…
Cancel
Save