From a7327d6bc64d2599b7f8bf962f61042d62b14552 Mon Sep 17 00:00:00 2001 From: trivernis Date: Sat, 6 Nov 2021 13:33:02 +0100 Subject: [PATCH] Add logic to actually edit tags Signed-off-by: trivernis --- mediarepo-ui/src-tauri/Cargo.lock | 4 +- mediarepo-ui/src-tauri/Cargo.toml | 2 +- .../file-edit/file-edit.component.html | 2 +- .../file-edit/file-edit.component.ts | 76 +++++++++++++++++-- .../file-gallery-entry.component.ts | 2 +- .../file-grid-entry.component.ts | 2 +- .../files-tab-sidebar.component.html | 2 +- .../src/app/services/file/file.service.ts | 6 +- .../src/app/services/tag/tag.service.ts | 22 +++--- 9 files changed, 91 insertions(+), 27 deletions(-) diff --git a/mediarepo-ui/src-tauri/Cargo.lock b/mediarepo-ui/src-tauri/Cargo.lock index 26b0139..f5a784f 100644 --- a/mediarepo-ui/src-tauri/Cargo.lock +++ b/mediarepo-ui/src-tauri/Cargo.lock @@ -1580,8 +1580,8 @@ checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" [[package]] name = "mediarepo-api" -version = "0.2.0" -source = "git+https://github.com/Trivernis/mediarepo-api.git?rev=a86cd413637562987a3940a664b923fd7e726cef#a86cd413637562987a3940a664b923fd7e726cef" +version = "0.3.0" +source = "git+https://github.com/Trivernis/mediarepo-api.git?rev=6cd483a4a7d0a101f391b755b73fa253e70b4a29#6cd483a4a7d0a101f391b755b73fa253e70b4a29" dependencies = [ "async-trait", "chrono", diff --git a/mediarepo-ui/src-tauri/Cargo.toml b/mediarepo-ui/src-tauri/Cargo.toml index 34e8fb6..86590fe 100644 --- a/mediarepo-ui/src-tauri/Cargo.toml +++ b/mediarepo-ui/src-tauri/Cargo.toml @@ -30,7 +30,7 @@ features = ["env-filter"] [dependencies.mediarepo-api] git = "https://github.com/Trivernis/mediarepo-api.git" -rev = "a86cd413637562987a3940a664b923fd7e726cef" +rev = "6cd483a4a7d0a101f391b755b73fa253e70b4a29" features = ["tauri-plugin"] [features] diff --git a/mediarepo-ui/src/app/components/file-edit/file-edit.component.html b/mediarepo-ui/src/app/components/file-edit/file-edit.component.html index 37352c2..e1c3b20 100644 --- a/mediarepo-ui/src/app/components/file-edit/file-edit.component.html +++ b/mediarepo-ui/src/app/components/file-edit/file-edit.component.html @@ -21,7 +21,7 @@
{{modeSelect.value}} tag - + diff --git a/mediarepo-ui/src/app/components/file-edit/file-edit.component.ts b/mediarepo-ui/src/app/components/file-edit/file-edit.component.ts index b11e6bf..b64a0dc 100644 --- a/mediarepo-ui/src/app/components/file-edit/file-edit.component.ts +++ b/mediarepo-ui/src/app/components/file-edit/file-edit.component.ts @@ -1,4 +1,11 @@ -import {Component, Input, OnInit, ViewChild} from '@angular/core'; +import { + Component, + Input, + OnChanges, + OnInit, + SimpleChanges, + ViewChild +} from '@angular/core'; import {FormControl} from "@angular/forms"; import {File} from "../../models/File"; import {Tag} from "../../models/Tag"; @@ -13,12 +20,13 @@ import {TagService} from "../../services/tag/tag.service"; templateUrl: './file-edit.component.html', styleUrls: ['./file-edit.component.scss'] }) -export class FileEditComponent implements OnInit { +export class FileEditComponent implements OnInit, OnChanges { @Input() files: File[] = []; - @Input() tags: Tag[] = []; + public tags: Tag[] = []; private allTags: Tag[] = []; + private fileTags: {[key: number]: Tag[]} = {}; public suggestionTags: Observable; public tagInputForm = new FormControl(""); @@ -38,6 +46,13 @@ export class FileEditComponent implements OnInit { async ngOnInit() { this.tagService.tags.subscribe(tags => this.allTags = tags); await this.tagService.loadTags(); + await this.loadFileTags(); + } + + async ngOnChanges(changes: SimpleChanges) { + if (changes["files"]) { + await this.loadFileTags() + } } public async editTagByAutocomplete($event: MatAutocompleteSelectedEvent) { @@ -45,13 +60,13 @@ export class FileEditComponent implements OnInit { await this.editTag(tag); } - private async editTag(tag: string): Promise { + public async editTag(tag: string): Promise { if (tag.length > 0) { let tagInstance = this.allTags.find(t => t.getNormalizedOutput() === tag); if (!tagInstance) { - // TODO: Create tag - tagInstance = new Tag(0, "", undefined); + tagInstance = (await this.tagService.createTags([tag]))[0]; + this.allTags.push(tagInstance); } switch (this.editMode) { case "Toggle": @@ -69,10 +84,29 @@ export class FileEditComponent implements OnInit { } async toggleTag(tag: Tag) { - + for (const file of this.files) { + const fileTags = this.fileTags[file.id]; + let addedTags = []; + let removedTags = []; + if (fileTags.findIndex(i => i.id === tag.id) < 0) { + addedTags.push(tag.id); + } else { + removedTags.push(tag.id); + } + this.fileTags[file.id] = await this.tagService.changeFileTags(file.id, addedTags, removedTags); + } + this.mapFileTagsToTagList(); + const index = this.tags.indexOf(tag); + index >= 0 && this.tagScroll.scrollToIndex(index); } async addTag(tag: Tag) { + for (const file of this.files) { + if (this.fileTags[file.id].findIndex(t => t.id === tag.id) < 0) { + this.fileTags[file.id] = await this.tagService.changeFileTags(file.id, + [tag.id], []); + } + } if (this.tags.findIndex(t => t.getNormalizedOutput() === tag.getNormalizedOutput()) < 0) { this.tags.push(tag); this.tags = this.tags.sort( @@ -84,6 +118,12 @@ export class FileEditComponent implements OnInit { } public async removeTag(tag: Tag) { + for (const file of this.files) { + if (this.fileTags[file.id].findIndex(t => t.id === tag.id) >= 0) { + this.fileTags[file.id] = await this.tagService.changeFileTags(file.id, + [], [tag.id]); + } + } const index = this.tags.indexOf(tag); if (index >= 0) { this.tags.splice(index, 1); @@ -97,4 +137,26 @@ export class FileEditComponent implements OnInit { t => t.includes(tag)) .slice(0, 20); } + + private async loadFileTags() { + for (const file of this.files) { + this.fileTags[file.id] = await this.tagService.getTagsForFiles([file.hash]); + } + this.mapFileTagsToTagList(); + } + + private mapFileTagsToTagList() { + let tags: Tag[] = []; + for (const file of this.files) { + const fileTags = this.fileTags[file.id]; + tags.push(...fileTags.filter(t => tags.findIndex(tag => tag.id === t.id) < 0)); + } + this.tags = tags.sort((a, b) => a.getNormalizedOutput().localeCompare(b.getNormalizedOutput())); + } + + public async handleTagInputKeydown($event: KeyboardEvent) { + if ($event.key === "Enter") { + await this.editTag(this.tagInputForm.value); + } + } } diff --git a/mediarepo-ui/src/app/components/file-gallery/file-gallery-entry/file-gallery-entry.component.ts b/mediarepo-ui/src/app/components/file-gallery/file-gallery-entry/file-gallery-entry.component.ts index 72f74a2..f987f69 100644 --- a/mediarepo-ui/src/app/components/file-gallery/file-gallery-entry/file-gallery-entry.component.ts +++ b/mediarepo-ui/src/app/components/file-gallery/file-gallery-entry/file-gallery-entry.component.ts @@ -47,7 +47,7 @@ export class FileGalleryEntryComponent implements OnInit, OnChanges { async loadImage() { try { const hash = this.file.data.hash; - const thumbnails = await this.fileService.getThumbnails(hash); + const thumbnails = await this.fileService.getThumbnails(this.file.data); let thumbnail = thumbnails.find( t => (t.height > 250 || t.width > 250) && (t.height < 500 && t.width < 500)); thumbnail = thumbnail ?? thumbnails[0]; 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 e8673ec..a4ba048 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 @@ -47,7 +47,7 @@ export class FileGridEntryComponent implements OnInit, OnChanges { async loadImage() { try { const thumbnails = await this.fileService.getThumbnails( - this.gridEntry.file.hash); + this.gridEntry.file); let thumbnail = thumbnails.find( t => (t.height > 250 || t.width > 250) && (t.height < 500 && t.width < 500)); thumbnail = thumbnail ?? thumbnails[0]; diff --git a/mediarepo-ui/src/app/pages/home/files-tab/files-tab-sidebar/files-tab-sidebar.component.html b/mediarepo-ui/src/app/pages/home/files-tab/files-tab-sidebar/files-tab-sidebar.component.html index a86bcb8..e837b8f 100644 --- a/mediarepo-ui/src/app/pages/home/files-tab/files-tab-sidebar/files-tab-sidebar.component.html +++ b/mediarepo-ui/src/app/pages/home/files-tab/files-tab-sidebar/files-tab-sidebar.component.html @@ -22,7 +22,7 @@
- + diff --git a/mediarepo-ui/src/app/services/file/file.service.ts b/mediarepo-ui/src/app/services/file/file.service.ts index dc406b1..46b514f 100644 --- a/mediarepo-ui/src/app/services/file/file.service.ts +++ b/mediarepo-ui/src/app/services/file/file.service.ts @@ -31,7 +31,7 @@ export class FileService { public async readFile(file: File): Promise { const once_uri = await invoke("plugin:mediarepo|read_file_by_hash", - {hash: file.hash, mimeType: file.mime_type}); + {id: file.id, hash: file.hash, mimeType: file.mime_type}); return this.sanitizer.bypassSecurityTrustResourceUrl(once_uri); } @@ -41,8 +41,8 @@ export class FileService { return this.sanitizer.bypassSecurityTrustResourceUrl(once_uri); } - public async getThumbnails(hash: string): Promise { + public async getThumbnails(file: File): Promise { return await invoke("plugin:mediarepo|get_file_thumbnails", - {hash}); + {id: file.id}); } } diff --git a/mediarepo-ui/src/app/services/tag/tag.service.ts b/mediarepo-ui/src/app/services/tag/tag.service.ts index 2edde2a..a8f566a 100644 --- a/mediarepo-ui/src/app/services/tag/tag.service.ts +++ b/mediarepo-ui/src/app/services/tag/tag.service.ts @@ -2,6 +2,7 @@ import {Injectable} from '@angular/core'; import {invoke} from "@tauri-apps/api/tauri"; import {Tag} from "../../models/Tag"; import {BehaviorSubject} from "rxjs"; +import {File} from "../../models/File"; @Injectable({ providedIn: 'root' @@ -18,21 +19,22 @@ export class TagService { this.tags.next(tags.map(t => new Tag(t.id, t.name, t.namespace))); } - public async getTagsForFile(hash: string): Promise { - const tags = await invoke("plugin:mediarepo|get_tags_for_file", - {hash}); - return tags.map(t => new Tag(t.id, t.name, t.namespace)); - } - public async getTagsForFiles(hashes: string[]): Promise { let tags: Tag[] = [] - if (hashes.length === 1) { - tags = await invoke("plugin:mediarepo|get_tags_for_file", - {hash: hashes[0]}); - } else if (hashes.length > 0) { + if (hashes.length > 0) { tags = await invoke("plugin:mediarepo|get_tags_for_files", {hashes}); } return tags.map(t => new Tag(t.id, t.name, t.namespace)); } + + public async createTags(tags: string[]): Promise { + const resultTags = await invoke("plugin:mediarepo|create_tags", {tags}); + return resultTags.map(t => new Tag(t.id, t.name, t.namespace)); + } + + public async changeFileTags(fileId: number, addedTags: number[], removedTags: number[]): Promise { + const tags = await invoke("plugin:mediarepo|change_file_tags", {id: fileId, addedTags, removedTags}); + return tags.map(t => new Tag(t.id, t.name, t.namespace)); + } }