Switch file preview strip in gallery for static rendered entries

Signed-off-by: trivernis <trivernis@protonmail.com>
pull/14/head
trivernis 2 years ago
parent 3674200c28
commit 4d56e37db2
Signed by: Trivernis
GPG Key ID: DFFFCC2C7A02DB45

@ -130,7 +130,7 @@ export class RepositoriesTabComponent implements OnInit, AfterViewInit {
"Opening repository...");
let dialog = this.dialog.open(BusyDialogComponent, {
data: {
title: `Opening repository ${repository.name}`,
title: `Opening repository '${repository.name}'`,
message: dialogMessage,
allowCancel: true,
}, disableClose: true,

@ -1,4 +1,8 @@
<div #inner (keyDownEvent)="handleKeydownEvent($event)" appInputReceiver class="gallery-container">
<div #inner
(keyDownEvent)="handleKeydownEvent($event)"
(window:resize)="this.onResize()"
appInputReceiver
class="gallery-container">
<button (click)="this.appClose.emit(this)" class="close-button" mat-icon-button>
<ng-icon name="mat-close"></ng-icon>
</button>
@ -15,14 +19,12 @@
</div>
<div
class="file-scroll-view">
<mat-divider></mat-divider>
<cdk-virtual-scroll-viewport #virtualScroll class="file-scroll-viewport" itemSize="260" maxBufferPx="3000"
minBufferPx="1000" orientation="horizontal">
<div *cdkVirtualFor="let entry of entries; trackBy: trackByFileId" class="file-item">
<app-file-card (clickEvent)="onEntrySelect($event.entry)"
<div #previewStripContainer class="file-preview-strip-container">
<div *ngFor="let entry of this.previewedEntries; trackBy: trackByFileId" class="file-item">
<app-file-card (clickEvent)="onEntrySelect($event.entry)" *ngIf="entry"
[entry]="entry" [fileChanged]="this.fileChanged"></app-file-card>
</div>
</cdk-virtual-scroll-viewport>
</div>
</div>
</div>
<app-file-context-menu #fileContextMenu

@ -1,3 +1,5 @@
@import "src/colors";
.file-scroll-viewport {
width: 100%;
height: 100%;
@ -17,16 +19,6 @@
overflow-y: hidden;
}
app-file-gallery-entry, .file-item {
width: 250px;
height: calc(100% - 10px);
padding: 5px;
}
app-file-gallery-entry {
display: block;
}
.file-full-view {
position: relative;
width: 100%;
@ -43,15 +35,33 @@ app-file-gallery-entry {
transition-duration: 1s;
height: 20%;
.file-scroll-viewport {
height: calc(100% - 4px);
}
mat-divider {
height: 2px;
}
}
.file-preview-strip-container {
display: flex;
width: 100%;
height: 100%;
border-top: 2px solid $background-darker-05;
.file-item {
width: 100%;
overflow: hidden;
height: calc(100%);
::ng-deep mat-card {
border-left: 2px solid $background;
border-radius: 0;
}
}
.file-item:first-child {
border-left: none;
}
}
app-content-viewer {
height: 100%;
width: 100%;

@ -1,5 +1,8 @@
import {
AfterViewChecked,
AfterViewInit,
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
ElementRef,
EventEmitter,
@ -14,7 +17,6 @@ import {File} from "../../../../../../api/models/File";
import {FileService} from "../../../../../services/file/file.service";
import {SafeResourceUrl} from "@angular/platform-browser";
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";
@ -22,9 +24,10 @@ import {BehaviorSubject} from "rxjs";
@Component({
selector: "app-file-gallery",
templateUrl: "./file-gallery.component.html",
styleUrls: ["./file-gallery.component.scss"]
styleUrls: ["./file-gallery.component.scss"],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class FileGalleryComponent implements OnChanges, OnInit, AfterViewInit {
export class FileGalleryComponent implements OnChanges, OnInit, AfterViewInit, AfterViewChecked {
@Input() files: File[] = [];
@Input() preselectedFile: File | undefined;
@ -34,9 +37,8 @@ export class FileGalleryComponent implements OnChanges, OnInit, AfterViewInit {
@Output() fileDelete = new EventEmitter<File>();
@Output() fileDeleted = new EventEmitter<File[]>();
@ViewChild("virtualScroll") virtualScroll!: CdkVirtualScrollViewport;
@ViewChild("inner") inner!: ElementRef<HTMLDivElement>;
@ViewChild("previewStripContainer") stripContainer!: ElementRef<HTMLDivElement>;
public entries: Selectable<File>[] = [];
public selectedFile: Selectable<File> | undefined;
@ -45,15 +47,16 @@ export class FileGalleryComponent implements OnChanges, OnInit, AfterViewInit {
public imageViewHeightPercent = 80;
public previewStripVisible = true;
public previewedEntries: (Selectable<File> | undefined)[] = [];
private scrollTimeout: number | undefined;
private previewStripCount = 5;
private escapeCount = 0;
constructor(
private changeDetector: ChangeDetectorRef,
private tabService: TabService,
private fileService: FileService
) {
tabService.selectedTab.subscribe(() => this.adjustElementSizes());
}
async ngOnInit(): Promise<void> {
@ -61,6 +64,8 @@ export class FileGalleryComponent implements OnChanges, OnInit, AfterViewInit {
this.selectedFile.data) < 0) {
await this.onEntrySelect(
this.getPreselectedEntry() ?? this.entries[0]);
} else {
this.buildPreviewedFiles();
}
}
@ -84,6 +89,10 @@ export class FileGalleryComponent implements OnChanges, OnInit, AfterViewInit {
}
}
public ngAfterViewChecked(): void {
this.calculatePreviewCount();
}
/**
* Called when a new entry is selected
* @param {Selectable<File>} entry
@ -96,15 +105,8 @@ export class FileGalleryComponent implements OnChanges, OnInit, AfterViewInit {
this.selectedFile = entry;
await this.loadSelectedFile();
if (this.virtualScroll) {
clearTimeout(this.scrollTimeout);
this.scrollTimeout = setTimeout(
() => this.scrollToSelection(),
0
); // we need to make sure the viewport has rendered
}
this.fileSelect.emit(this.selectedFile.data);
this.buildPreviewedFiles();
}
}
@ -151,13 +153,6 @@ export class FileGalleryComponent implements OnChanges, OnInit, AfterViewInit {
}
}
public adjustElementSizes(): void {
if (this.virtualScroll) {
this.virtualScroll.checkViewportSize();
this.scrollToSelection();
}
}
public focus() {
this.inner.nativeElement.focus();
}
@ -181,8 +176,8 @@ export class FileGalleryComponent implements OnChanges, OnInit, AfterViewInit {
}
}
public trackByFileId(index: number, item: Selectable<File>) {
return item.data.id;
public trackByFileId(index: number, item?: Selectable<File>) {
return item?.data.id;
}
public onFileStatusChange(): void {
@ -199,23 +194,24 @@ export class FileGalleryComponent implements OnChanges, OnInit, AfterViewInit {
}
}
private scrollToSelection(): void {
if (this.selectedFile) {
const selectedIndex = this.entries.indexOf(this.selectedFile);
const viewportSize = this.virtualScroll.getViewportSize();
const indexAdjustment = (viewportSize / 260) / 2; // adjustment to have the selected item centered
this.virtualScroll.scrollToIndex(
Math.max(selectedIndex - indexAdjustment, 0), "smooth");
if (selectedIndex > indexAdjustment) {
this.virtualScroll.scrollToOffset(
this.virtualScroll.measureScrollOffset("left") + 130,
"smooth"
);
public calculatePreviewCount() {
if (this.stripContainer && this.stripContainer.nativeElement) {
const width = Math.abs(this.stripContainer.nativeElement.clientWidth);
const height = Math.abs(this.stripContainer.nativeElement.clientHeight);
const count = Math.floor(Math.floor(width / height) / 2) * 2 + 1;
if (count != this.previewStripCount) {
this.previewStripCount = count;
this.buildPreviewedFiles();
}
}
}
public onResize(): void {
this.changeDetector.markForCheck();
}
private getPreselectedEntry(): Selectable<File> | undefined {
if (this.preselectedFile) {
const entry = this.entries.find(
@ -235,4 +231,26 @@ export class FileGalleryComponent implements OnChanges, OnInit, AfterViewInit {
setTimeout(() => this.escapeCount--, 500);
}
}
private buildPreviewedFiles() {
if (!this.selectedFile) {
if (this.entries) {
this.onEntrySelect(this.entries[0]).catch(console.error);
}
return;
}
const selectedIndex = this.entries.indexOf(this.selectedFile!);
const previewCountLR = Math.floor(this.previewStripCount / 2);
const previewedEntries = [];
for (let i = selectedIndex - previewCountLR; i <= selectedIndex + previewCountLR; i++) {
if (i >= 0 && i < this.entries.length) {
previewedEntries.push(this.entries[i]);
} else {
previewedEntries.push(undefined);
}
}
this.previewedEntries = previewedEntries;
this.changeDetector.markForCheck();
}
}

@ -1,7 +1,7 @@
<div #inner
(keyDownEvent)="handleKeydownEvent($event)"
(keyUpEvent)="handleKeyupEvent($event)"
(window:resize)="this.calculateColumnCount()"
(window:resize)="this.onResize()"
appInputReceiver
class="file-grid-inner">
<cdk-virtual-scroll-viewport #virtualScrollGrid class="file-scroll" itemSize="260" maxBufferPx="2000"

@ -4,11 +4,14 @@ app-file-card {
height: 250px;
width: 100%;
padding: 5px;
display: block;
overflow: hidden;
}
.file-scroll {
height: 100%;
width: 100%;
overflow-x: hidden;
}
.file-grid-inner {
@ -23,4 +26,5 @@ app-file-card {
display: flex;
flex-direction: row;
width: 100%;
overflow-x: hidden;
}

@ -213,6 +213,10 @@ export class FileGridComponent implements OnChanges, OnInit, AfterViewInit, Afte
}
}
public onResize(): void {
this.changeDetector.markForCheck();
}
private setPartitionedGridEntries() {
this.partitionedGridEntries = [];
let scrollToIndex = -1;

Loading…
Cancel
Save