Move gallery content viewer to separate component

Signed-off-by: trivernis <trivernis@protonmail.com>
pull/4/head
trivernis 3 years ago
parent 09f3225aa3
commit 47738b392d

@ -59,6 +59,8 @@ import { TagFilterListItemComponent } from './components/file-search/filter-dial
import { TagInputComponent } from './components/inputs/tag-input/tag-input.component'; import { TagInputComponent } from './components/inputs/tag-input/tag-input.component';
import { ContextMenuComponent } from './components/context-menu/context-menu.component'; import { ContextMenuComponent } from './components/context-menu/context-menu.component';
import { FileContextMenuComponent } from './components/context-menu/file-context-menu/file-context-menu.component'; import { FileContextMenuComponent } from './components/context-menu/file-context-menu/file-context-menu.component';
import { ContentViewerComponent } from './components/file-gallery/content-viewer/content-viewer.component';
import { ImageViewerComponent } from './components/file-gallery/content-viewer/image-viewer/image-viewer.component';
@NgModule({ @NgModule({
declarations: [ declarations: [
@ -88,6 +90,8 @@ import { FileContextMenuComponent } from './components/context-menu/file-context
TagInputComponent, TagInputComponent,
ContextMenuComponent, ContextMenuComponent,
FileContextMenuComponent, FileContextMenuComponent,
ContentViewerComponent,
ImageViewerComponent,
], ],
imports: [ imports: [
BrowserModule, BrowserModule,

@ -0,0 +1 @@
<app-image-viewer *ngIf="getContentType() === 'image'" [imageUrl]="contentUrl"></app-image-viewer>

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

@ -0,0 +1,37 @@
import {Component, Input, OnInit} from '@angular/core';
import {SafeResourceUrl} from "@angular/platform-browser";
type ContentType = "image" | "video" | "text" | "other";
@Component({
selector: 'app-content-viewer',
templateUrl: './content-viewer.component.html',
styleUrls: ['./content-viewer.component.scss']
})
export class ContentViewerComponent {
@Input() contentUrl!: SafeResourceUrl | string;
@Input() mimeType: string | undefined;
constructor() { }
public getContentType(): ContentType {
if (!this.mimeType) {
return "other";
}
let mimeParts = this.mimeType.split("/");
const type = mimeParts.shift() ?? "other";
const subtype = mimeParts.shift() ?? "*";
switch (type) {
case "image":
return "image";
case "video":
return "video";
case "text":
return "text";
default:
return "other";
}
}
}

@ -0,0 +1,16 @@
<div (mouseenter)="this.mouseInImageView = true" (mouseleave)="this.mouseInImageView = false"
class="image-full-view-inner">
<div class="zoom-slider">
<mat-slider (input)="this.imageZoom=$event.value ?? 1" [value]="this.imageZoom" max="4"
min="0.5" step="0.1" vertical></mat-slider>
<button (click)="this.resetImage()" mat-icon-button>
<mat-icon>refresh</mat-icon>
</button>
</div>
<div (cdkDragMoved)="this.onDragMoved($event)"
[cdkDragFreeDragPosition]="this.imagePosition" cdkDrag class="image-drag-container">
<div [style]="{scale: this.imageZoom}" class="image-scale-container">
<app-content-aware-image [imageSrc]="this.imageUrl" decoding="sync"></app-content-aware-image>
</div>
</div>
</div>

@ -0,0 +1,35 @@
.image-drag-container, .image-scale-container {
height: 100%;
width: 100%;
}
.image-scale-container {
display: block;
}
.zoom-slider {
position: absolute;
display: flex;
flex-direction: column;
right: 1em;
bottom: 1em;
z-index: 10;
opacity: 0.5;
padding: 1em 0.5em;
transition-duration: 0.2s;
}
.zoom-slider:hover {
opacity: 1;
background-color: rgba(0, 0, 0, 0.3);
border-radius: 1em;
}
.image-full-view-inner {
height: 100%;
width: 100%;
display: block;
position: relative;
}

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

@ -0,0 +1,63 @@
import {
Component,
ElementRef,
HostListener,
Input,
OnInit,
ViewChild
} from '@angular/core';
import {CdkDragMove} from "@angular/cdk/drag-drop";
import {SafeResourceUrl} from "@angular/platform-browser";
@Component({
selector: 'app-image-viewer',
templateUrl: './image-viewer.component.html',
styleUrls: ['./image-viewer.component.scss']
})
export class ImageViewerComponent {
@Input() imageUrl!: SafeResourceUrl | string;
public imageZoom = 1;
public imagePosition = {x: 0, y: 0};
public mouseInImageView = false;
constructor() { }
public resetImage() {
this.imageZoom = 1;
this.imagePosition = {x: 0, y: 0};
}
public onDragMoved($event: CdkDragMove<HTMLDivElement>): void {
this.imagePosition.x += $event.delta.x;
this.imagePosition.y += $event.delta.y;
}
@HostListener("window:keydown", ["$event"])
private async handleKeydownEvent(event: KeyboardEvent) {
switch (event.key) {
case "Escape":
this.resetImage();
break;
}
}
@HostListener("mousewheel", ["$event"])
private handleScroll(event: any) {
if (this.mouseInImageView) {
const delta = event.wheelDelta ?? event.detail;
if (delta > 0) {
this.imageZoom += 0.2
if (this.imageZoom > 4) {
this.imageZoom = 4;
}
} else if (delta < 0) {
this.imageZoom -= 0.2
if (this.imageZoom < 0.5) {
this.imageZoom = 0.5;
}
}
}
}
}

@ -4,25 +4,10 @@
</button> </button>
<div (dblclick)="this.selectedFile? this.fileDblClickEvent.emit(this.selectedFile.data) : null" class="file-full-view" <div (dblclick)="this.selectedFile? this.fileDblClickEvent.emit(this.selectedFile.data) : null" class="file-full-view"
fxFlex="80%"> fxFlex="80%">
<div (mouseenter)="this.mouseInImageView = true" (mouseleave)="this.mouseInImageView = false" <div *ngIf="!this.fileContentUrl" class="url-loading-backdrop">
class="file-full-view-inner"> <mat-progress-spinner color="primary" mode="indeterminate"></mat-progress-spinner>
<div *ngIf="!this.fileContentUrl" class="url-loading-backdrop">
<mat-progress-spinner color="primary" mode="indeterminate"></mat-progress-spinner>
</div>
<div class="zoom-slider">
<mat-slider (input)="this.imageZoom=$event.value ?? 1" [value]="this.imageZoom" max="4"
min="0.5" step="0.1" vertical></mat-slider>
<button (click)="this.resetImage()" mat-icon-button>
<mat-icon>refresh</mat-icon>
</button>
</div>
<div #imageDragContainer (cdkDragMoved)="this.onDragMoved($event)" *ngIf="this.fileContentUrl"
[cdkDragFreeDragPosition]="this.imagePosition" cdkDrag class="image-drag-container">
<div #scaledImage [style]="{scale: this.imageZoom}" class="image-scale-container">
<app-content-aware-image (contextmenu)="fileContextMenu.onContextMenu($event, this.selectedFile!.data)" [imageSrc]="this.fileContentUrl" decoding="sync"></app-content-aware-image>
</div>
</div>
</div> </div>
<app-content-viewer *ngIf="this.fileContentUrl" [contentUrl]="this.fileContentUrl" [mimeType]="this.selectedFile!.data.mime_type"></app-content-viewer>
</div> </div>
<mat-divider fxFlex></mat-divider> <mat-divider fxFlex></mat-divider>
<div class="file-scroll-view" fxFlex="20%"> <div class="file-scroll-view" fxFlex="20%">

@ -32,13 +32,6 @@ app-file-gallery-entry {
overflow: hidden; overflow: hidden;
} }
.file-full-view-inner {
height: 100%;
width: 100%;
display: block;
position: relative;
}
app-content-aware-image { app-content-aware-image {
height: 100%; height: 100%;
width: 100%; width: 100%;
@ -66,30 +59,3 @@ app-content-aware-image {
margin: auto; margin: auto;
} }
} }
.image-drag-container, .image-scale-container {
height: 100%;
width: 100%;
}
.image-scale-container {
display: block;
}
.zoom-slider {
position: absolute;
display: flex;
flex-direction: column;
right: 1em;
bottom: 1em;
z-index: 10;
opacity: 0.5;
padding: 1em 0.5em;
transition-duration: 0.2s;
}
.zoom-slider:hover {
opacity: 1;
background-color: rgba(0, 0, 0, 0.3);
border-radius: 1em;
}

@ -1,6 +1,5 @@
import { import {
Component, Component,
ElementRef,
EventEmitter, EventEmitter,
HostListener, HostListener,
Input, Input,
@ -15,7 +14,6 @@ import {FileService} from "../../services/file/file.service";
import {SafeResourceUrl} from "@angular/platform-browser"; import {SafeResourceUrl} from "@angular/platform-browser";
import {Selectable} from "../../models/Selectable"; import {Selectable} from "../../models/Selectable";
import {CdkVirtualScrollViewport} from "@angular/cdk/scrolling"; import {CdkVirtualScrollViewport} from "@angular/cdk/scrolling";
import {CdkDragMove} from "@angular/cdk/drag-drop";
import {TabService} from "../../services/tab/tab.service"; import {TabService} from "../../services/tab/tab.service";
@Component({ @Component({
@ -33,15 +31,9 @@ export class FileGalleryComponent implements OnChanges, OnInit {
entries: Selectable<File>[] = []; entries: Selectable<File>[] = [];
@ViewChild("virtualScroll") virtualScroll!: CdkVirtualScrollViewport; @ViewChild("virtualScroll") virtualScroll!: CdkVirtualScrollViewport;
@ViewChild("scaledImage") scaledImage: ElementRef<HTMLDivElement> | undefined;
@ViewChild(
"imageDragContainer") imageDragContainer: ElementRef<HTMLDivElement> | undefined;
public selectedFile: Selectable<File> | undefined; public selectedFile: Selectable<File> | undefined;
public fileContentUrl: SafeResourceUrl | undefined; public fileContentUrl: SafeResourceUrl | undefined;
public imageZoom = 1;
public imagePosition = {x: 0, y: 0};
public mouseInImageView = false;
private scrollTimeout: number | undefined; private scrollTimeout: number | undefined;
@ -56,7 +48,6 @@ export class FileGalleryComponent implements OnChanges, OnInit {
*/ */
async onEntrySelect(entry: Selectable<File>) { async onEntrySelect(entry: Selectable<File>) {
if (entry) { if (entry) {
this.resetImage();
this.selectedFile?.unselect(); this.selectedFile?.unselect();
entry.select(); entry.select();
this.selectedFile = entry; this.selectedFile = entry;
@ -149,15 +140,6 @@ export class FileGalleryComponent implements OnChanges, OnInit {
} }
} }
public resetImage() {
this.imageZoom = 1;
this.imagePosition = {x: 0, y: 0};
}
public onDragMoved($event: CdkDragMove<HTMLDivElement>): void {
this.imagePosition.x += $event.delta.x;
this.imagePosition.y += $event.delta.y;
}
@HostListener("window:keydown", ["$event"]) @HostListener("window:keydown", ["$event"])
private async handleKeydownEvent(event: KeyboardEvent) { private async handleKeydownEvent(event: KeyboardEvent) {
@ -168,28 +150,6 @@ export class FileGalleryComponent implements OnChanges, OnInit {
case "ArrowLeft": case "ArrowLeft":
await this.previousItem(); await this.previousItem();
break; break;
case "Escape":
this.resetImage();
break;
}
}
@HostListener("mousewheel", ["$event"])
private handleScroll(event: any) {
if (this.mouseInImageView) {
const delta = event.wheelDelta ?? event.detail;
if (delta > 0) {
this.imageZoom += 0.2
if (this.imageZoom > 4) {
this.imageZoom = 4;
}
} else if (delta < 0) {
this.imageZoom -= 0.2
if (this.imageZoom < 0.5) {
this.imageZoom = 0.5;
}
}
} }
} }

Loading…
Cancel
Save