From e0a42b1b0f6083074948987b881e8bed71387aa7 Mon Sep 17 00:00:00 2001 From: trivernis Date: Tue, 19 Oct 2021 19:48:44 +0200 Subject: [PATCH] Fix file grid multiselection Signed-off-by: trivernis --- .../file-grid/file-grid-entry/GridEntry.ts | 6 ++ .../file-grid-entry.component-theme.scss | 2 +- .../file-grid-entry.component.html | 4 +- .../file-grid-entry.component.ts | 7 +- .../file-grid/file-grid.component.html | 6 +- .../file-grid/file-grid.component.ts | 86 ++++++++++++------- .../src/app/pages/home/home.component.html | 2 +- .../src/app/pages/home/home.component.ts | 13 +-- 8 files changed, 72 insertions(+), 54 deletions(-) create mode 100644 mediarepo-ui/src/app/components/file-grid/file-grid-entry/GridEntry.ts diff --git a/mediarepo-ui/src/app/components/file-grid/file-grid-entry/GridEntry.ts b/mediarepo-ui/src/app/components/file-grid/file-grid-entry/GridEntry.ts new file mode 100644 index 0000000..4fadec9 --- /dev/null +++ b/mediarepo-ui/src/app/components/file-grid/file-grid-entry/GridEntry.ts @@ -0,0 +1,6 @@ +import {File} from "../../../models/File"; + +export type GridEntry = { + file: File, + selected: boolean, +} diff --git a/mediarepo-ui/src/app/components/file-grid/file-grid-entry/file-grid-entry.component-theme.scss b/mediarepo-ui/src/app/components/file-grid/file-grid-entry/file-grid-entry.component-theme.scss index e673d08..23a0b11 100644 --- a/mediarepo-ui/src/app/components/file-grid/file-grid-entry/file-grid-entry.component-theme.scss +++ b/mediarepo-ui/src/app/components/file-grid/file-grid-entry/file-grid-entry.component-theme.scss @@ -7,7 +7,7 @@ $warn-palette: map.get($color-config, 'warn'); mat-card.selected { - background-color: mat.get-color-from-palette($primary-palette); + background-color: mat.get-color-from-palette($primary-palette, 'darker'); } } diff --git a/mediarepo-ui/src/app/components/file-grid/file-grid-entry/file-grid-entry.component.html b/mediarepo-ui/src/app/components/file-grid/file-grid-entry/file-grid-entry.component.html index ed5d444..8aec515 100644 --- a/mediarepo-ui/src/app/components/file-grid/file-grid-entry/file-grid-entry.component.html +++ b/mediarepo-ui/src/app/components/file-grid/file-grid-entry/file-grid-entry.component.html @@ -1,5 +1,5 @@ - - {{file?.name}} + + {{gridEntry.file?.name}} File Image diff --git a/mediarepo-ui/src/app/components/file-grid/file-grid-entry/file-grid-entry.component.ts b/mediarepo-ui/src/app/components/file-grid/file-grid-entry/file-grid-entry.component.ts index 1369762..638e0b8 100644 --- a/mediarepo-ui/src/app/components/file-grid/file-grid-entry/file-grid-entry.component.ts +++ b/mediarepo-ui/src/app/components/file-grid/file-grid-entry/file-grid-entry.component.ts @@ -11,6 +11,7 @@ import {ErrorBrokerService} from "../../../services/error-broker/error-broker.se 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', @@ -20,10 +21,9 @@ import {Thumbnail} from "../../../models/Thumbnail"; export class FileGridEntryComponent implements OnInit, OnDestroy { @ViewChild("card") card!: ElementRef; - @Input() public file!: File; + @Input() public gridEntry!: GridEntry; @Output() clickEvent = new EventEmitter(); @Output() dblClickEvent = new EventEmitter(); - public selected: boolean = false; selectedThumbnail: Thumbnail | undefined; contentUrl: SafeResourceUrl | undefined; @@ -43,9 +43,10 @@ export class FileGridEntryComponent implements OnInit, OnDestroy { async loadImage() { try { - const thumbnails = await this.fileService.getThumbnails(this.file.hash); + 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)); this.selectedThumbnail = thumbnail; + if (!thumbnail) { console.log("Thumbnail is empty?!", thumbnails); } else { diff --git a/mediarepo-ui/src/app/components/file-grid/file-grid.component.html b/mediarepo-ui/src/app/components/file-grid/file-grid.component.html index 039bb9e..0f6d782 100644 --- a/mediarepo-ui/src/app/components/file-grid/file-grid.component.html +++ b/mediarepo-ui/src/app/components/file-grid/file-grid.component.html @@ -1,8 +1,8 @@ -
+
- +
diff --git a/mediarepo-ui/src/app/components/file-grid/file-grid.component.ts b/mediarepo-ui/src/app/components/file-grid/file-grid.component.ts index b51dff3..b4782ef 100644 --- a/mediarepo-ui/src/app/components/file-grid/file-grid.component.ts +++ b/mediarepo-ui/src/app/components/file-grid/file-grid.component.ts @@ -2,71 +2,91 @@ import { Component, EventEmitter, HostListener, - Input, + Input, OnChanges, OnInit, - Output, QueryList, ViewChildren + Output, QueryList, SimpleChanges, ViewChildren } from '@angular/core'; import {File} from "../../models/File"; import {FileService} from "../../services/file/file.service"; import {FileGridEntryComponent} from "./file-grid-entry/file-grid-entry.component"; +import {GridEntry} from "./file-grid-entry/GridEntry"; @Component({ selector: 'app-file-grid', templateUrl: './file-grid.component.html', styleUrls: ['./file-grid.component.scss'] }) -export class FileGridComponent { +export class FileGridComponent implements OnChanges { - @Input() fileRows: File[][] = []; + @Input() files: File[] = []; + @Input() columns: number = 6; @Output() fileDblClickEvent = new EventEmitter(); @Output() filesSelectEvent = new EventEmitter(); - @ViewChildren(FileGridEntryComponent) childQuery!: QueryList; - - selectedEntries: FileGridEntryComponent[] = []; + selectedEntries: GridEntry[] = []; private shiftClicked = false; private ctrlClicked = false; + private gridEntries: GridEntry[] = [] + partitionedGridEntries: GridEntry[][] = []; + + constructor() { + } + + ngOnChanges(changes: SimpleChanges): void { + this.gridEntries = this.files.map(file => {return {file, selected: false}}); + this.setPartitionedGridEntries(); + } - constructor() { } + private setPartitionedGridEntries() { + this.partitionedGridEntries = []; + + for (let i = 0; i < (Math.ceil(this.gridEntries.length / this.columns)); i++) { + this.partitionedGridEntries.push(this.gridEntries.slice(i * this.columns, Math.min(this.gridEntries.length, (i + 1) * this.columns))) + } + } /** * File selector logic - * @param {FileGridEntryComponent} entry + * @param {FileGridEntryComponent} clickedEntry */ - setSelectedFile(entry: FileGridEntryComponent) { + setSelectedFile(clickedEntry: GridEntry) { if (!(this.shiftClicked || this.ctrlClicked) && this.selectedEntries.length > 0) { - this.selectedEntries.forEach(entry => entry.selected = false); + this.selectedEntries.forEach(entry => {if (entry !== clickedEntry) entry.selected = false}); this.selectedEntries = []; } - // shift selector (forwards and backwards) if (this.shiftClicked && this.selectedEntries.length > 0) { - const lastEntry = this.selectedEntries[this.selectedEntries.length - 1]; - let found = false; + this.handleShiftSelect(clickedEntry); + } else { + clickedEntry.selected = !clickedEntry.selected; + this.selectedEntries.push(clickedEntry); + } + this.filesSelectEvent.emit(this.selectedEntries.map(entry => entry.file)); + } - // TODO: change to use wrapped entry files instead because of reused components - for (const child of this.childQuery) { + private handleShiftSelect(clickedEntry: GridEntry): void { + const lastEntry = this.selectedEntries[this.selectedEntries.length - 1]; + let found = false; + if (clickedEntry == lastEntry) { + return; + } - if (found) { - child.selected = true; - this.selectedEntries.push(child); - if (child === entry || child == lastEntry) { - break; - } - } else if (child === lastEntry || child === entry) { - found = true; - if (child === entry) { - child.selected = true; - this.selectedEntries.push(child); - } + for (const gridEntry of this.gridEntries) { + if (found) { + gridEntry.selected = true; + this.selectedEntries.push(gridEntry); + if (gridEntry === clickedEntry || gridEntry == lastEntry) { + return; + } + } else if (gridEntry === lastEntry || gridEntry === clickedEntry) { + found = true; + if (gridEntry === clickedEntry) { + gridEntry.selected = true; + this.selectedEntries.push(gridEntry); } - } - } else { - entry.selected = true; - this.selectedEntries.push(entry); + } - this.filesSelectEvent.emit(this.selectedEntries.map(entry => entry.file)); } @HostListener("window:keydown", ["$event"]) diff --git a/mediarepo-ui/src/app/pages/home/home.component.html b/mediarepo-ui/src/app/pages/home/home.component.html index d1cd08a..d770c78 100644 --- a/mediarepo-ui/src/app/pages/home/home.component.html +++ b/mediarepo-ui/src/app/pages/home/home.component.html @@ -7,7 +7,7 @@

Drawer

- + diff --git a/mediarepo-ui/src/app/pages/home/home.component.ts b/mediarepo-ui/src/app/pages/home/home.component.ts index 9ffc107..95f057a 100644 --- a/mediarepo-ui/src/app/pages/home/home.component.ts +++ b/mediarepo-ui/src/app/pages/home/home.component.ts @@ -13,25 +13,16 @@ import {ErrorBrokerService} from "../../services/error-broker/error-broker.servi }) export class HomeComponent implements OnInit { - fileRows: File[][] = []; + files: File[] = []; private openingLightbox = false; constructor(private errorBroker: ErrorBrokerService, private fileService: FileService, private lightbox: Lightbox, private lightboxEvent: LightboxEvent) { } async ngOnInit() { - this.fileService.displayedFiles.subscribe((files) => this.setFileRows(files)); + this.fileService.displayedFiles.subscribe((files) => this.files = files); await this.fileService.getFiles(); } - setFileRows(files: File[]) { - this.fileRows = []; - const filesPerRow = 6; - for (let i = 0; i < (Math.ceil(files.length /filesPerRow )); i++) { - this.fileRows.push(files.slice(i * filesPerRow, Math.min(files.length, (i + 1) * filesPerRow))) - } - console.log(this.fileRows); - } - async openFile(file: File) { if (this.openingLightbox) { return;