Add logic to actually edit tags

Signed-off-by: trivernis <trivernis@protonmail.com>
pull/4/head
trivernis 3 years ago
parent bc74482098
commit a7327d6bc6

@ -1580,8 +1580,8 @@ checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
[[package]] [[package]]
name = "mediarepo-api" name = "mediarepo-api"
version = "0.2.0" version = "0.3.0"
source = "git+https://github.com/Trivernis/mediarepo-api.git?rev=a86cd413637562987a3940a664b923fd7e726cef#a86cd413637562987a3940a664b923fd7e726cef" source = "git+https://github.com/Trivernis/mediarepo-api.git?rev=6cd483a4a7d0a101f391b755b73fa253e70b4a29#6cd483a4a7d0a101f391b755b73fa253e70b4a29"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"chrono", "chrono",

@ -30,7 +30,7 @@ features = ["env-filter"]
[dependencies.mediarepo-api] [dependencies.mediarepo-api]
git = "https://github.com/Trivernis/mediarepo-api.git" git = "https://github.com/Trivernis/mediarepo-api.git"
rev = "a86cd413637562987a3940a664b923fd7e726cef" rev = "6cd483a4a7d0a101f391b755b73fa253e70b4a29"
features = ["tauri-plugin"] features = ["tauri-plugin"]
[features] [features]

@ -21,7 +21,7 @@
<div class="tag-input-field"> <div class="tag-input-field">
<mat-form-field class="form-field-tag-input" appearance="fill"> <mat-form-field class="form-field-tag-input" appearance="fill">
<mat-label>{{modeSelect.value}} tag</mat-label> <mat-label>{{modeSelect.value}} tag</mat-label>
<input [formControl]="tagInputForm" matInput [matAutocomplete]="auto"> <input [formControl]="tagInputForm" matInput [matAutocomplete]="auto" (keydown)="this.handleTagInputKeydown($event)" (submit)="this.editTag(tagInputForm.value)">
</mat-form-field> </mat-form-field>
<mat-autocomplete #auto (optionSelected)="editTagByAutocomplete($event)"> <mat-autocomplete #auto (optionSelected)="editTagByAutocomplete($event)">

@ -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 {FormControl} from "@angular/forms";
import {File} from "../../models/File"; import {File} from "../../models/File";
import {Tag} from "../../models/Tag"; import {Tag} from "../../models/Tag";
@ -13,12 +20,13 @@ import {TagService} from "../../services/tag/tag.service";
templateUrl: './file-edit.component.html', templateUrl: './file-edit.component.html',
styleUrls: ['./file-edit.component.scss'] styleUrls: ['./file-edit.component.scss']
}) })
export class FileEditComponent implements OnInit { export class FileEditComponent implements OnInit, OnChanges {
@Input() files: File[] = []; @Input() files: File[] = [];
@Input() tags: Tag[] = []; public tags: Tag[] = [];
private allTags: Tag[] = []; private allTags: Tag[] = [];
private fileTags: {[key: number]: Tag[]} = {};
public suggestionTags: Observable<string[]>; public suggestionTags: Observable<string[]>;
public tagInputForm = new FormControl(""); public tagInputForm = new FormControl("");
@ -38,6 +46,13 @@ export class FileEditComponent implements OnInit {
async ngOnInit() { async ngOnInit() {
this.tagService.tags.subscribe(tags => this.allTags = tags); this.tagService.tags.subscribe(tags => this.allTags = tags);
await this.tagService.loadTags(); await this.tagService.loadTags();
await this.loadFileTags();
}
async ngOnChanges(changes: SimpleChanges) {
if (changes["files"]) {
await this.loadFileTags()
}
} }
public async editTagByAutocomplete($event: MatAutocompleteSelectedEvent) { public async editTagByAutocomplete($event: MatAutocompleteSelectedEvent) {
@ -45,13 +60,13 @@ export class FileEditComponent implements OnInit {
await this.editTag(tag); await this.editTag(tag);
} }
private async editTag(tag: string): Promise<void> { public async editTag(tag: string): Promise<void> {
if (tag.length > 0) { if (tag.length > 0) {
let tagInstance = this.allTags.find(t => t.getNormalizedOutput() === tag); let tagInstance = this.allTags.find(t => t.getNormalizedOutput() === tag);
if (!tagInstance) { if (!tagInstance) {
// TODO: Create tag tagInstance = (await this.tagService.createTags([tag]))[0];
tagInstance = new Tag(0, "", undefined); this.allTags.push(tagInstance);
} }
switch (this.editMode) { switch (this.editMode) {
case "Toggle": case "Toggle":
@ -69,10 +84,29 @@ export class FileEditComponent implements OnInit {
} }
async toggleTag(tag: Tag) { 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) { 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) { if (this.tags.findIndex(t => t.getNormalizedOutput() === tag.getNormalizedOutput()) < 0) {
this.tags.push(tag); this.tags.push(tag);
this.tags = this.tags.sort( this.tags = this.tags.sort(
@ -84,6 +118,12 @@ export class FileEditComponent implements OnInit {
} }
public async removeTag(tag: Tag) { 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); const index = this.tags.indexOf(tag);
if (index >= 0) { if (index >= 0) {
this.tags.splice(index, 1); this.tags.splice(index, 1);
@ -97,4 +137,26 @@ export class FileEditComponent implements OnInit {
t => t.includes(tag)) t => t.includes(tag))
.slice(0, 20); .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);
}
}
} }

@ -47,7 +47,7 @@ export class FileGalleryEntryComponent implements OnInit, OnChanges {
async loadImage() { async loadImage() {
try { try {
const hash = this.file.data.hash; 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( let thumbnail = thumbnails.find(
t => (t.height > 250 || t.width > 250) && (t.height < 500 && t.width < 500)); t => (t.height > 250 || t.width > 250) && (t.height < 500 && t.width < 500));
thumbnail = thumbnail ?? thumbnails[0]; thumbnail = thumbnail ?? thumbnails[0];

@ -47,7 +47,7 @@ export class FileGridEntryComponent implements OnInit, OnChanges {
async loadImage() { async loadImage() {
try { try {
const thumbnails = await this.fileService.getThumbnails( const thumbnails = await this.fileService.getThumbnails(
this.gridEntry.file.hash); this.gridEntry.file);
let thumbnail = thumbnails.find( let thumbnail = thumbnails.find(
t => (t.height > 250 || t.width > 250) && (t.height < 500 && t.width < 500)); t => (t.height > 250 || t.width > 250) && (t.height < 500 && t.width < 500));
thumbnail = thumbnail ?? thumbnails[0]; thumbnail = thumbnail ?? thumbnails[0];

@ -22,7 +22,7 @@
</div> </div>
</mat-tab> </mat-tab>
<mat-tab label="Edit" *ngIf="this.selectedFiles.length > 0"> <mat-tab label="Edit" *ngIf="this.selectedFiles.length > 0">
<app-file-edit #fileedit [files]="this.selectedFiles" [tags]="tagsOfSelection"></app-file-edit> <app-file-edit #fileedit [files]="this.selectedFiles"></app-file-edit>
</mat-tab> </mat-tab>
</mat-tab-group> </mat-tab-group>
</div> </div>

@ -31,7 +31,7 @@ export class FileService {
public async readFile(file: File): Promise<SafeResourceUrl> { public async readFile(file: File): Promise<SafeResourceUrl> {
const once_uri = await invoke<string>("plugin:mediarepo|read_file_by_hash", const once_uri = await invoke<string>("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); return this.sanitizer.bypassSecurityTrustResourceUrl(once_uri);
} }
@ -41,8 +41,8 @@ export class FileService {
return this.sanitizer.bypassSecurityTrustResourceUrl(once_uri); return this.sanitizer.bypassSecurityTrustResourceUrl(once_uri);
} }
public async getThumbnails(hash: string): Promise<Thumbnail[]> { public async getThumbnails(file: File): Promise<Thumbnail[]> {
return await invoke<Thumbnail[]>("plugin:mediarepo|get_file_thumbnails", return await invoke<Thumbnail[]>("plugin:mediarepo|get_file_thumbnails",
{hash}); {id: file.id});
} }
} }

@ -2,6 +2,7 @@ import {Injectable} from '@angular/core';
import {invoke} from "@tauri-apps/api/tauri"; import {invoke} from "@tauri-apps/api/tauri";
import {Tag} from "../../models/Tag"; import {Tag} from "../../models/Tag";
import {BehaviorSubject} from "rxjs"; import {BehaviorSubject} from "rxjs";
import {File} from "../../models/File";
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
@ -18,21 +19,22 @@ export class TagService {
this.tags.next(tags.map(t => new Tag(t.id, t.name, t.namespace))); this.tags.next(tags.map(t => new Tag(t.id, t.name, t.namespace)));
} }
public async getTagsForFile(hash: string): Promise<Tag[]> {
const tags = await invoke<Tag[]>("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<Tag[]> { public async getTagsForFiles(hashes: string[]): Promise<Tag[]> {
let tags: Tag[] = [] let tags: Tag[] = []
if (hashes.length === 1) { if (hashes.length > 0) {
tags = await invoke<Tag[]>("plugin:mediarepo|get_tags_for_file",
{hash: hashes[0]});
} else if (hashes.length > 0) {
tags = await invoke<Tag[]>("plugin:mediarepo|get_tags_for_files", tags = await invoke<Tag[]>("plugin:mediarepo|get_tags_for_files",
{hashes}); {hashes});
} }
return tags.map(t => new Tag(t.id, t.name, t.namespace)); return tags.map(t => new Tag(t.id, t.name, t.namespace));
} }
public async createTags(tags: string[]): Promise<Tag[]> {
const resultTags = await invoke<Tag[]>("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<Tag[]> {
const tags = await invoke<Tag[]>("plugin:mediarepo|change_file_tags", {id: fileId, addedTags, removedTags});
return tags.map(t => new Tag(t.id, t.name, t.namespace));
}
} }

Loading…
Cancel
Save