Fix weird issues with file thumbnail loading

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

@ -50,6 +50,11 @@ export class CoreComponent {
}
state.tabs.subscribe(tabs => {
this.tabs = tabs;
const selectedIndex = state.selectedTab.value;
if (selectedIndex) {
this.tabGroup.selectedIndex = selectedIndex;
}
if (this.tabs.length === 0) {
this.addTab();
@ -64,6 +69,9 @@ export class CoreComponent {
public onTabSelectionChange(event: MatTabChangeEvent): void {
this.tabService.setSelectedTab(event.index);
if (event.index > 0 && event.index <= this.tabs.length) {
this.appState.selectedTab.next(event.index);
}
}
public addFilesTab(): void {

@ -57,7 +57,7 @@ export class FilesTabSidebarComponent implements OnInit, OnChanges {
if (this.fileSearch) {
await this.fileSearch.searchForFiles();
}
if (this.tags.length === 0) {
if (this.tags.length === 0 && this.selectedFiles.length === 0) {
this.tags = this.tagsOfFiles;
}
}
@ -102,7 +102,7 @@ export class FilesTabSidebarComponent implements OnInit, OnChanges {
}
private showAllTagsFallback() {
if (this.tags.length === 0) {
if (this.tags.length === 0 && this.selectedFiles.length === 0) {
this.tags = this.tagsOfFiles.sort(
(a, b) => a.getNormalizedOutput()
.localeCompare(b.getNormalizedOutput()));

@ -4,6 +4,7 @@ import {
EventEmitter,
Input,
OnChanges,
OnDestroy,
OnInit,
Output,
SimpleChanges,
@ -11,24 +12,28 @@ import {
} from "@angular/core";
import {File} from "../../../../models/File";
import {Selectable} from "../../../../models/Selectable";
import {
SchedulingService
} from "../../../../services/scheduling/scheduling.service";
const LOADING_WORK_KEY = "FILE_THUMBNAIL_LOADING";
@Component({
selector: "app-file-card",
templateUrl: "./file-card.component.html",
styleUrls: ["./file-card.component.scss"]
})
export class FileCardComponent implements OnInit, OnChanges {
export class FileCardComponent implements OnInit, OnChanges, OnDestroy {
@ViewChild("card") card!: ElementRef;
@Input() public entry!: Selectable<File>;
@Output() clickEvent = new EventEmitter<FileCardComponent>();
@Output() dblClickEvent = new EventEmitter<FileCardComponent>();
private cachedId: number | undefined;
private urlSetTimeout: number | undefined;
private workId: number | undefined;
public loading = false;
constructor() {
constructor(private schedulingService: SchedulingService) {
}
async ngOnInit() {
@ -43,10 +48,21 @@ export class FileCardComponent implements OnInit, OnChanges {
}
}
public ngOnDestroy(): void {
if (this.workId) {
this.schedulingService.cancelWork(LOADING_WORK_KEY, this.workId);
}
}
private setImageDelayed() {
if (this.workId) {
this.schedulingService.cancelWork(LOADING_WORK_KEY, this.workId);
}
this.loading = true;
clearTimeout(this.urlSetTimeout);
this.urlSetTimeout = setTimeout(
() => this.loading = false, 200);
this.workId = this.schedulingService.addWork(LOADING_WORK_KEY,
async () => {
await this.schedulingService.delay(1);
this.loading = false
});
}
}

@ -1,4 +1,5 @@
import {
AfterViewChecked, AfterViewInit,
Component,
ElementRef,
EventEmitter,
@ -15,7 +16,7 @@ import {FileGridComponent} from "./file-grid/file-grid.component";
templateUrl: "./file-multiview.component.html",
styleUrls: ["./file-multiview.component.scss"]
})
export class FileMultiviewComponent {
export class FileMultiviewComponent implements AfterViewInit {
@Input() files!: File[];
@Input() mode: "grid" | "gallery" = "grid";
@ -33,6 +34,13 @@ export class FileMultiviewComponent {
constructor() {
}
public ngAfterViewInit(): void {
if (this.preselectedFile) {
this.fileSelectEvent.emit([this.preselectedFile])
this.selectedFiles = [this.preselectedFile];
}
}
public onFileSelect(files: File[]): void {
this.selectedFiles = files;
this.preselectedFile = files[0];

@ -1,21 +1,24 @@
import {
AfterViewInit,
Component,
Input,
OnChanges,
OnInit,
SimpleChanges
} from "@angular/core";
import {File} from "../../../../models/File";
import {FileService} from "../../../../services/file/file.service";
import {FileHelper} from "../../../../services/file/file.helper";
import {SafeResourceUrl} from "@angular/platform-browser";
import {
SchedulingService
} from "../../../../services/scheduling/scheduling.service";
@Component({
selector: "app-file-thumbnail",
templateUrl: "./file-thumbnail.component.html",
styleUrls: ["./file-thumbnail.component.scss"]
})
export class FileThumbnailComponent implements OnInit, OnChanges {
export class FileThumbnailComponent implements OnChanges, AfterViewInit {
@Input() file!: File;
@ -23,17 +26,17 @@ export class FileThumbnailComponent implements OnInit, OnChanges {
private supportedThumbnailTypes = ["image", "video"]
constructor(private fileService: FileService) {
constructor( private fileService: FileService) {
}
public ngOnInit(): void {
public async ngAfterViewInit() {
this.thumbUrl = this.fileService.buildThumbnailUrl(this.file, 250, 250);
}
public ngOnChanges(changes: SimpleChanges): void {
public async ngOnChanges(changes: SimpleChanges) {
if (changes["file"]) {
this.thumbUrl = this.fileService.buildThumbnailUrl(this.file, 250,
250)
this.thumbUrl = this.fileService.buildThumbnailUrl(this.file,
250, 250);
}
}

@ -33,4 +33,5 @@
</mat-select>
</mat-form-field>
</div>
<app-busy-indicator *ngIf="this.loading" [busy]="this.loading" [blurBackground]="true" [darkenBackground]="true"></app-busy-indicator>
</div>

@ -74,3 +74,12 @@ cdk-virtual-scroll-viewport {
mat-divider {
width: 100%;
}
app-busy-indicator {
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 100%;
z-index: 99;
}

@ -10,6 +10,7 @@ import {File} from "../../../../models/File";
import {Tag} from "../../../../models/Tag";
import {CdkVirtualScrollViewport} from "@angular/cdk/scrolling";
import {TagService} from "../../../../services/tag/tag.service";
import {delay} from "rxjs/operators";
@Component({
selector: "app-tag-edit",
@ -26,6 +27,8 @@ export class TagEditComponent implements OnInit, OnChanges {
@ViewChild("tagScroll") tagScroll!: CdkVirtualScrollViewport;
private fileTags: { [key: number]: Tag[] } = {};
public loading = false;
constructor(
private tagService: TagService,
) {
@ -44,6 +47,7 @@ export class TagEditComponent implements OnInit, OnChanges {
}
public async editTag(tag: string): Promise<void> {
this.loading = true;
if (tag.length > 0) {
let tagInstance = this.allTags.find(
t => t.getNormalizedOutput() === tag);
@ -64,6 +68,7 @@ export class TagEditComponent implements OnInit, OnChanges {
break;
}
}
this.loading = false;
}
async toggleTag(tag: Tag) {
@ -87,7 +92,7 @@ export class TagEditComponent implements OnInit, OnChanges {
async addTag(tag: Tag) {
for (const file of this.files) {
if (this.fileTags[file.id].findIndex(t => t.id === tag.id) < 0) {
if ((this.fileTags[file.id] ?? []).findIndex(t => t.id === tag.id) < 0) {
this.fileTags[file.id] = await this.tagService.changeFileTags(
file.id,
[tag.id], []);
@ -99,6 +104,7 @@ export class TagEditComponent implements OnInit, OnChanges {
}
public async removeTag(tag: Tag) {
this.loading = true;
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(
@ -107,14 +113,23 @@ export class TagEditComponent implements OnInit, OnChanges {
}
}
this.mapFileTagsToTagList();
this.loading = false;
}
private async loadFileTags() {
for (const file of this.files) {
this.loading = true;
const promises = [];
const loadFn = async (file: File) => {
this.fileTags[file.id] = await this.tagService.getTagsForFiles(
[file.hash]);
}
for (const file of this.files) {
promises.push(loadFn(file));
}
await Promise.all(promises);
this.mapFileTagsToTagList();
this.loading = false;
}
private mapFileTagsToTagList() {

@ -7,6 +7,7 @@ export class AppState {
private tabIdCounter = 0;
public tabs = new BehaviorSubject<TabState[]>([]);
public selectedTab = new BehaviorSubject<number | undefined>(undefined);
private readonly fileService: FileService
@ -34,6 +35,7 @@ export class AppState {
appState.tabs.next(tabs);
appState.tabIdCounter = state.tabIdCounter;
appState.selectedTab.next(state.selectedTab);
return appState
}
@ -43,6 +45,7 @@ export class AppState {
return JSON.stringify({
tabs: tabDTOs,
tabIdCounter: this.tabIdCounter,
selectedTab: this.selectedTab.value,
});
}
}

@ -59,6 +59,14 @@ export class RepositoryService {
} else {
await this.disconnectSelectedRepository();
}
} else {
try {
// just to make sure because sometimes there's some weird issues
await this.disconnectSelectedRepository();
} catch (err) {
console.warn(err);
}
}
await invoke("plugin:mediarepo|select_repository", {name: repo.name});
await this.loadRepositories();

@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';
import { SchedulingService } from './scheduling.service';
describe('SchedulingService', () => {
let service: SchedulingService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(SchedulingService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});

@ -0,0 +1,58 @@
import {Injectable} from '@angular/core';
import {BehaviorSubject} from "rxjs";
import {filter} from "rxjs/operators";
@Injectable({
providedIn: 'root'
})
export class SchedulingService {
private workQueue: { [key: string]: {id: number, cancelled: boolean, cb: Function}[] } = {}
private lastWorkId = 0;
constructor() {
}
public addWork(key: string, cb: Function): number {
if (!this.workQueue[key]) {
this.workQueue[key] = [];
setTimeout(() => this.startWork(key), 0); // start in the next tick
}
const id = this.lastWorkId++;
this.workQueue[key].push({id, cb, cancelled: false});
return id;
}
public cancelWork(key: string, id: number) {
const work = this.workQueue[key]?.find(w => w.id === id);
if (work) {
work.cancelled = true;
}
}
private async startWork(key: string) {
while (true) {
if (this.workQueue[key]?.length > 0) {
let work = this.workQueue[key].shift();
let count = 0;
while (work?.cancelled && count++ < 100) {
work = this.workQueue[key].shift();
}
if (work) {
try {
await work.cb();
} catch (err) {
console.error(err);
}
}
}
await this.delay(1);
}
}
public async delay(time: number) {
return new Promise((res, rej) => {
setTimeout(res, time);
})
}
}
Loading…
Cancel
Save