141 lines
4.9 KiB
TypeScript
141 lines
4.9 KiB
TypeScript
import { Component, inject, input, OnInit, output, signal } from '@angular/core';
|
|
import { MatPaginator, PageEvent } from '@angular/material/paginator';
|
|
import { ImageService } from '../../../../../shared/services/ImageService';
|
|
import { Spinner } from '../../../../../shared/components/spinner/spinner';
|
|
import { ImageView } from '../../../../../shared/models/ImageView.model';
|
|
import { MatCard, MatCardActions, MatCardContent, MatCardImage } from '@angular/material/card';
|
|
import { MatCheckbox } from '@angular/material/checkbox';
|
|
import { MatMenu, MatMenuItem, MatMenuTrigger } from '@angular/material/menu';
|
|
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
|
|
import { faEllipsis } from '@fortawesome/free-solid-svg-icons';
|
|
import { MatButton } from '@angular/material/button';
|
|
import { MatDialog } from '@angular/material/dialog';
|
|
import { EditImageDialog } from './edit-image-dialog/edit-image-dialog';
|
|
import { SliceView } from '../../../../../shared/models/SliceView.model';
|
|
import { ImageViewWithBlobUrl } from '../../../../../shared/client-models/ImageViewWithBlobUrl';
|
|
|
|
@Component({
|
|
selector: 'app-image-select',
|
|
imports: [
|
|
MatPaginator,
|
|
Spinner,
|
|
MatCard,
|
|
MatCardImage,
|
|
MatCardContent,
|
|
MatCardActions,
|
|
MatCheckbox,
|
|
MatMenuTrigger,
|
|
MatMenu,
|
|
FaIconComponent,
|
|
MatButton,
|
|
MatMenuItem,
|
|
],
|
|
templateUrl: './image-select.html',
|
|
styleUrl: './image-select.css',
|
|
})
|
|
export class ImageSelect implements OnInit {
|
|
public readonly select = output<ImageView | null>();
|
|
public readonly selectedUsernameFilename = input<readonly [string, string] | null>(null);
|
|
|
|
protected readonly currentPage = signal(0);
|
|
protected readonly pageSize = signal(9);
|
|
|
|
private readonly imageService = inject(ImageService);
|
|
private readonly dialog = inject(MatDialog);
|
|
|
|
protected readonly loadingImages = signal(false);
|
|
protected readonly loadImagesError = signal<Error | null>(null);
|
|
protected readonly imagesSlice = signal<SliceView<ImageViewWithBlobUrl> | null>(null);
|
|
|
|
protected readonly imageCount = signal(0);
|
|
|
|
protected readonly deleting = signal(false);
|
|
protected readonly deleteError = signal<Error | null>(null);
|
|
|
|
public ngOnInit(): void {
|
|
this.loadImages();
|
|
}
|
|
|
|
private loadImages(): void {
|
|
this.loadingImages.set(true);
|
|
this.imageService
|
|
.getOwnedImageViewsWithBlobUrls({
|
|
page: this.currentPage(),
|
|
size: this.pageSize(),
|
|
sort: [
|
|
{
|
|
property: 'created',
|
|
order: 'DESC',
|
|
},
|
|
],
|
|
})
|
|
.subscribe({
|
|
next: (sliceView) => {
|
|
sliceView.content.sort((a, b) => b.created.valueOf() - a.created.valueOf());
|
|
this.loadingImages.set(false);
|
|
this.imagesSlice.set(sliceView);
|
|
},
|
|
error: (e) => {
|
|
this.loadingImages.set(false);
|
|
this.loadImagesError.set(e);
|
|
},
|
|
});
|
|
this.imageService.getOwnedImagesCount().subscribe({
|
|
next: (count) => {
|
|
this.imageCount.set(count);
|
|
},
|
|
});
|
|
}
|
|
|
|
protected onPage(pageEvent: PageEvent): void {
|
|
if (pageEvent.pageIndex < this.currentPage()) {
|
|
// backward
|
|
this.currentPage.update((old) => Math.max(old - 1, 0));
|
|
} else {
|
|
// forward
|
|
this.currentPage.update((old) => (this.imagesSlice()?.slice.hasNext ? old + 1 : old));
|
|
}
|
|
this.pageSize.set(pageEvent.pageSize);
|
|
this.loadImages();
|
|
}
|
|
|
|
protected onImageClick(imageView: ImageView): void {
|
|
if (this.isSelected(imageView)) {
|
|
this.select.emit(null);
|
|
} else {
|
|
this.select.emit(imageView);
|
|
}
|
|
}
|
|
|
|
protected isSelected(imageView: ImageView): boolean {
|
|
const selectedUsernameFilename = this.selectedUsernameFilename();
|
|
if (selectedUsernameFilename) {
|
|
const [username, filename] = selectedUsernameFilename;
|
|
return imageView.owner.username === username && imageView.filename === filename;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
protected editImage(imageView: ImageView): void {
|
|
this.dialog.open(EditImageDialog, {
|
|
data: [imageView.owner.username, imageView.filename],
|
|
});
|
|
}
|
|
|
|
protected deleteImage(imageView: ImageView): void {
|
|
this.deleting.set(true);
|
|
this.imageService.deleteImage(imageView.owner.username, imageView.filename).subscribe({
|
|
next: () => {
|
|
this.deleting.set(false);
|
|
this.loadImages();
|
|
},
|
|
error: (e) => {
|
|
this.deleting.set(false);
|
|
this.deleteError.set(e);
|
|
},
|
|
});
|
|
}
|
|
|
|
protected readonly faEllipsis = faEllipsis;
|
|
}
|